hypeorcode
Network offOpen alone (new tab)

Run details

Model
claude-fable-5-1
Route
Claude Code CLI
Reasoning
provider default
Limits
60 min · 128,000 output tokens
Date
21 Oct 2026
Time
2 min 16 s
Size
21 kB
Tokens
98 in, 12,019 out
List price
$0.60 ($10 in / $50 out per M)
Paid
Not billed per run (CLI plan)

Raw files: output · meta.json

Exact prompt

Draw a mechanical wristwatch that shows the current local time, with a sweeping seconds hand and a date window. Make it look expensive.

It must be one complete, self-contained HTML file: inline all CSS and JavaScript, and make no network requests of any kind (no CDNs, web fonts or remote images). Save it as index.html in the current directory, then stop. Do not ask questions.

Source

21 kB 460 lines Raw

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Calibre 1876 — Mechanical Wristwatch</title>
<style>
  :root {
    --bg: #0b0b0d;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  html, body {
    height: 100%;
    background: var(--bg);
    overflow: hidden;
    font-family: "Didot", "Bodoni 72", "Bodoni MT", "Georgia", "Times New Roman", serif;
    color: #cfc9bb;
  }
  body {
    display: flex;
    align-items: center;
    justify-content: center;
    background:
      radial-gradient(ellipse 70% 60% at 50% 40%, #1c1b1f 0%, #0b0b0d 70%),
      var(--bg);
  }
  .stage {
    position: relative;
    width: min(92vmin, 760px);
    height: min(92vmin, 760px);
  }
  svg { width: 100%; height: 100%; display: block; }
  .caption {
    position: absolute;
    left: 0; right: 0; bottom: -1.6em;
    text-align: center;
    font-size: clamp(10px, 1.4vmin, 14px);
    letter-spacing: 0.35em;
    text-transform: uppercase;
    color: #6b665b;
    user-select: none;
  }
  .date-text {
    font-family: "Helvetica Neue", "Arial Narrow", Arial, sans-serif;
    font-weight: 700;
    fill: #121212;
  }
  .brand {
    font-family: "Didot", "Bodoni 72", "Bodoni MT", "Georgia", serif;
    fill: #e8e2d2;
    letter-spacing: 0.22em;
  }
  .sub {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    fill: #b6afa0;
    letter-spacing: 0.3em;
  }
  .caseback {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    fill: #8a8375;
    letter-spacing: 0.25em;
  }
</style>
</head>
<body>
<div class="stage">
<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" aria-label="Mechanical wristwatch showing current local time">
  <defs>
    <!-- Metals -->
    <linearGradient id="goldCase" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0%"  stop-color="#fff2c7"/>
      <stop offset="18%" stop-color="#d9b86a"/>
      <stop offset="38%" stop-color="#8d6a2b"/>
      <stop offset="52%" stop-color="#f4dd9a"/>
      <stop offset="68%" stop-color="#a47d35"/>
      <stop offset="85%" stop-color="#5d4418"/>
      <stop offset="100%" stop-color="#e3c47b"/>
    </linearGradient>
    <linearGradient id="goldBezel" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0%"  stop-color="#ffefc0"/>
      <stop offset="25%" stop-color="#b8903f"/>
      <stop offset="50%" stop-color="#fbe6a8"/>
      <stop offset="75%" stop-color="#7a5a1f"/>
      <stop offset="100%" stop-color="#d8b566"/>
    </linearGradient>
    <linearGradient id="goldHand" x1="0" y1="0" x2="1" y2="0">
      <stop offset="0%"  stop-color="#6b4f1a"/>
      <stop offset="35%" stop-color="#f6e2a3"/>
      <stop offset="50%" stop-color="#fff6d6"/>
      <stop offset="65%" stop-color="#e5c674"/>
      <stop offset="100%" stop-color="#7a5c22"/>
    </linearGradient>
    <linearGradient id="goldIndex" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0%"  stop-color="#fff3cf"/>
      <stop offset="45%" stop-color="#cfae5c"/>
      <stop offset="55%" stop-color="#7d5f23"/>
      <stop offset="100%" stop-color="#e9cd84"/>
    </linearGradient>
    <linearGradient id="steelBlue" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0%"  stop-color="#8fb5ff"/>
      <stop offset="40%" stop-color="#1b3a8f"/>
      <stop offset="60%" stop-color="#0d2060"/>
      <stop offset="100%" stop-color="#5e8de8"/>
    </linearGradient>

    <!-- Dial: deep sunburst -->
    <radialGradient id="dialBase" cx="50%" cy="42%" r="65%">
      <stop offset="0%"  stop-color="#1d2a3d"/>
      <stop offset="55%" stop-color="#0d1626"/>
      <stop offset="100%" stop-color="#05080f"/>
    </radialGradient>
    <linearGradient id="sunburstGlint" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0%"  stop-color="#ffffff" stop-opacity="0.22"/>
      <stop offset="35%" stop-color="#ffffff" stop-opacity="0.02"/>
      <stop offset="60%" stop-color="#ffffff" stop-opacity="0"/>
      <stop offset="100%" stop-color="#9ab" stop-opacity="0.08"/>
    </linearGradient>
    <radialGradient id="dialVignette" cx="50%" cy="50%" r="50%">
      <stop offset="70%" stop-color="#000" stop-opacity="0"/>
      <stop offset="100%" stop-color="#000" stop-opacity="0.75"/>
    </radialGradient>
    <!-- Crystal reflection -->
    <linearGradient id="crystal" x1="0" y1="0" x2="0.6" y2="1">
      <stop offset="0%"  stop-color="#ffffff" stop-opacity="0.26"/>
      <stop offset="22%" stop-color="#ffffff" stop-opacity="0.08"/>
      <stop offset="45%" stop-color="#ffffff" stop-opacity="0"/>
      <stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>
    </linearGradient>
    <radialGradient id="crystalEdge" cx="50%" cy="50%" r="50%">
      <stop offset="90%" stop-color="#fff" stop-opacity="0"/>
      <stop offset="97%" stop-color="#fff" stop-opacity="0.12"/>
      <stop offset="100%" stop-color="#fff" stop-opacity="0.02"/>
    </radialGradient>
    <!-- Leather strap -->
    <linearGradient id="leather" x1="0" y1="0" x2="1" y2="0">
      <stop offset="0%"  stop-color="#1a0d08"/>
      <stop offset="20%" stop-color="#4a2415"/>
      <stop offset="50%" stop-color="#5b2d1a"/>
      <stop offset="80%" stop-color="#3d1c0f"/>
      <stop offset="100%" stop-color="#160a06"/>
    </linearGradient>
    <pattern id="grain" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(35)">
      <rect width="6" height="6" fill="transparent"/>
      <circle cx="1.5" cy="1.5" r="0.7" fill="#000" opacity="0.35"/>
      <circle cx="4.5" cy="4" r="0.5" fill="#fff" opacity="0.08"/>
    </pattern>
    <pattern id="stitch" width="18" height="6" patternUnits="userSpaceOnUse">
      <rect x="2" y="2" width="10" height="2" rx="1" fill="#d8c08a" opacity="0.85"/>
    </pattern>
    <!-- Lume -->
    <linearGradient id="lume" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0%" stop-color="#f3f7e6"/>
      <stop offset="100%" stop-color="#cfd9b8"/>
    </linearGradient>

    <!-- Filters -->
    <filter id="dropCase" x="-30%" y="-30%" width="160%" height="160%">
      <feGaussianBlur in="SourceAlpha" stdDeviation="22"/>
      <feOffset dx="0" dy="26" result="o"/>
      <feComponentTransfer><feFuncA type="linear" slope="0.8"/></feComponentTransfer>
      <feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
    </filter>
    <filter id="handShadow" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
      <feOffset dx="3" dy="5" result="o"/>
      <feComponentTransfer><feFuncA type="linear" slope="0.55"/></feComponentTransfer>
      <feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
    </filter>
    <filter id="indexShadow" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur in="SourceAlpha" stdDeviation="1.4"/>
      <feOffset dx="1.5" dy="2.5" result="o"/>
      <feComponentTransfer><feFuncA type="linear" slope="0.6"/></feComponentTransfer>
      <feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
    </filter>
    <filter id="innerShade" x="-20%" y="-20%" width="140%" height="140%">
      <feGaussianBlur stdDeviation="6"/>
    </filter>
    <filter id="softBlur"><feGaussianBlur stdDeviation="1.2"/></filter>
    <filter id="brushed" x="0" y="0" width="100%" height="100%">
      <feTurbulence type="fractalNoise" baseFrequency="0.9 0.004" numOctaves="2" seed="7" result="n"/>
      <feColorMatrix in="n" type="matrix" values="0 0 0 0 1  0 0 0 0 0.92  0 0 0 0 0.7  0 0 0 0.22 0"/>
    </filter>

    <clipPath id="dialClip"><circle cx="500" cy="500" r="330"/></clipPath>
    <clipPath id="dateClip"><rect x="660" y="482" width="62" height="40" rx="3"/></clipPath>
  </defs>

  <!-- Ambient floor reflection -->
  <ellipse cx="500" cy="880" rx="300" ry="26" fill="#000" opacity="0.6" filter="url(#innerShade)"/>

  <!-- Strap -->
  <g id="strap">
    <!-- top -->
    <path d="M400 0 L600 0 L592 170 Q500 150 408 170 Z" fill="url(#leather)"/>
    <path d="M400 0 L600 0 L592 170 Q500 150 408 170 Z" fill="url(#grain)"/>
    <path d="M414 6 L414 160" stroke="url(#stitch)" stroke-width="6" fill="none" transform="rotate(90 414 83) translate(-77 0)" opacity="0"/>
    <path d="M418 10 Q416 90 420 158" fill="none" stroke="#d8c08a" stroke-width="2.2" stroke-dasharray="9 7" opacity="0.8"/>
    <path d="M582 10 Q584 90 580 158" fill="none" stroke="#d8c08a" stroke-width="2.2" stroke-dasharray="9 7" opacity="0.8"/>
    <!-- bottom -->
    <path d="M408 830 Q500 850 592 830 L600 1000 L400 1000 Z" fill="url(#leather)"/>
    <path d="M408 830 Q500 850 592 830 L600 1000 L400 1000 Z" fill="url(#grain)"/>
    <path d="M420 842 Q416 920 418 990" fill="none" stroke="#d8c08a" stroke-width="2.2" stroke-dasharray="9 7" opacity="0.8"/>
    <path d="M580 842 Q584 920 582 990" fill="none" stroke="#d8c08a" stroke-width="2.2" stroke-dasharray="9 7" opacity="0.8"/>
    <!-- keeper -->
    <rect x="404" y="905" width="192" height="30" rx="6" fill="#2a1309"/>
    <rect x="404" y="905" width="192" height="30" rx="6" fill="url(#grain)"/>
    <rect x="404" y="905" width="192" height="4" fill="#000" opacity="0.4"/>
    <!-- buckle hint -->
    <rect x="380" y="965" width="240" height="18" rx="6" fill="url(#goldCase)"/>
  </g>

  <!-- Case with lugs -->
  <g id="case" filter="url(#dropCase)">
    <!-- lugs -->
    <path d="M392 150 L420 118 L580 118 L608 150 L620 250 L380 250 Z" fill="url(#goldCase)"/>
    <path d="M380 750 L620 750 L608 850 L580 882 L420 882 L392 850 Z" fill="url(#goldCase)"/>
    <!-- spring-bar grooves on lugs -->
    <rect x="404" y="128" width="192" height="6" rx="3" fill="#3b2a0e" opacity="0.7"/>
    <rect x="404" y="866" width="192" height="6" rx="3" fill="#3b2a0e" opacity="0.7"/>
    <!-- crown -->
    <g transform="translate(905 500)">
      <rect x="-20" y="-26" width="40" height="52" rx="6" fill="url(#goldCase)"/>
      <rect x="4" y="-30" width="30" height="60" rx="9" fill="url(#goldBezel)"/>
      <g stroke="#4d3610" stroke-width="2.4" opacity="0.8">
        <line x1="8" y1="-24" x2="30" y2="-24"/><line x1="8" y1="-16" x2="30" y2="-16"/>
        <line x1="8" y1="-8"  x2="30" y2="-8"/> <line x1="8" y1="0"   x2="30" y2="0"/>
        <line x1="8" y1="8"   x2="30" y2="8"/>  <line x1="8" y1="16"  x2="30" y2="16"/>
        <line x1="8" y1="24"  x2="30" y2="24"/>
      </g>
      <circle cx="19" cy="0" r="7" fill="#1a1a1a"/>
      <circle cx="19" cy="0" r="4.5" fill="url(#goldIndex)"/>
    </g>
    <!-- crown guards -->
    <path d="M860 450 Q900 460 905 500 Q900 540 860 550 Z" fill="url(#goldCase)"/>
    <!-- main case body -->
    <circle cx="500" cy="500" r="420" fill="url(#goldCase)"/>
    <circle cx="500" cy="500" r="420" fill="none" stroke="#2b1d06" stroke-width="2" opacity="0.6"/>
    <!-- brushed flank -->
    <circle cx="500" cy="500" r="405" fill="none" stroke="#f7e7b7" stroke-width="10" opacity="0.18"/>
    <circle cx="500" cy="500" r="398" fill="none" stroke="#000" stroke-width="2" opacity="0.35"/>
  </g>

  <!-- Bezel -->
  <g id="bezel">
    <circle cx="500" cy="500" r="392" fill="url(#goldBezel)"/>
    <circle cx="500" cy="500" r="392" fill="none" stroke="#fff6d8" stroke-width="1.5" opacity="0.5"/>
    <circle cx="500" cy="500" r="365" fill="#1a1206"/>
    <circle cx="500" cy="500" r="362" fill="url(#goldCase)" transform="rotate(180 500 500)"/>
    <circle cx="500" cy="500" r="352" fill="#0a0806"/>
    <!-- fluted bezel notches -->
    <g id="flutes" stroke="#3a2a0b" stroke-width="2.6" opacity="0.55"></g>
  </g>

  <!-- Dial -->
  <g id="dial" clip-path="url(#dialClip)">
    <circle cx="500" cy="500" r="340" fill="url(#dialBase)"/>
    <!-- sunburst rays -->
    <g id="rays" opacity="0.5"></g>
    <circle cx="500" cy="500" r="340" fill="url(#sunburstGlint)"/>
    <circle cx="500" cy="500" r="340" fill="url(#dialVignette)"/>
    <!-- chapter ring / rehaut -->
    <circle cx="500" cy="500" r="328" fill="none" stroke="#ffffff" stroke-width="1" opacity="0.08"/>
    <circle cx="500" cy="500" r="300" fill="none" stroke="#ffffff" stroke-width="0.8" opacity="0.10"/>
    <!-- minute track -->
    <g id="minuteTrack"></g>
    <!-- branding -->
    <text x="500" y="368" text-anchor="middle" class="brand" font-size="30">AURELIAN</text>
    <text x="500" y="392" text-anchor="middle" class="sub" font-size="10.5">GENÈVE</text>
    <text x="500" y="640" text-anchor="middle" class="sub" font-size="11">AUTOMATIC</text>
    <text x="500" y="660" text-anchor="middle" class="sub" font-size="9" opacity="0.8">CHRONOMÈTRE · SWISS MADE</text>
    <!-- applied indices -->
    <g id="indices" filter="url(#indexShadow)"></g>
    <!-- date window -->
    <g id="dateWindow">
      <rect x="656" y="478" width="70" height="48" rx="5" fill="#000" opacity="0.5" filter="url(#softBlur)"/>
      <rect x="660" y="482" width="62" height="40" rx="3" fill="#f3efe4"/>
      <g clip-path="url(#dateClip)">
        <rect x="660" y="482" width="62" height="40" fill="#efe9da"/>
        <rect x="660" y="482" width="62" height="12" fill="#fff" opacity="0.5"/>
        <rect x="660" y="510" width="62" height="12" fill="#c9c3b3" opacity="0.5"/>
        <text id="dateText" x="691" y="512" text-anchor="middle" class="date-text" font-size="30">01</text>
      </g>
      <rect x="658" y="480" width="66" height="44" rx="4" fill="none" stroke="url(#goldIndex)" stroke-width="3.5"/>
      <rect x="658" y="480" width="66" height="44" rx="4" fill="none" stroke="#000" stroke-width="1" opacity="0.45"/>
    </g>
  </g>

  <!-- Hands -->
  <g id="hands" filter="url(#handShadow)">
    <!-- Hour hand (dauphine) -->
    <g id="hourHand" transform="rotate(0 500 500)">
      <polygon points="500,290 513,500 500,540 487,500" fill="url(#goldHand)"/>
      <polygon points="500,290 500,540 487,500" fill="#000" opacity="0.28"/>
      <polygon points="501,318 507,470 501,470" fill="url(#lume)" opacity="0.9"/>
    </g>
    <!-- Minute hand (dauphine, longer) -->
    <g id="minuteHand" transform="rotate(0 500 500)">
      <polygon points="500,195 511,500 500,548 489,500" fill="url(#goldHand)"/>
      <polygon points="500,195 500,548 489,500" fill="#000" opacity="0.28"/>
      <polygon points="501,225 506,470 501,470" fill="url(#lume)" opacity="0.9"/>
    </g>
    <!-- Seconds hand (blued steel) -->
    <g id="secondHand" transform="rotate(0 500 500)">
      <rect x="498.4" y="178" width="3.2" height="392" rx="1.6" fill="url(#steelBlue)"/>
      <circle cx="500" cy="585" r="9" fill="url(#steelBlue)"/>
      <circle cx="500" cy="585" r="4" fill="#0a1434"/>
      <rect x="497" y="560" width="6" height="50" rx="3" fill="url(#steelBlue)"/>
      <!-- counterweight -->
      <polygon points="500,172 503.5,186 496.5,186" fill="#dde8ff"/>
    </g>
    <!-- Cannon pinion / cap -->
    <circle cx="500" cy="500" r="16" fill="url(#goldIndex)"/>
    <circle cx="500" cy="500" r="16" fill="none" stroke="#5a4010" stroke-width="1" opacity="0.7"/>
    <circle cx="500" cy="500" r="7" fill="url(#steelBlue)"/>
    <circle cx="500" cy="500" r="2.6" fill="#0a1434"/>
  </g>

  <!-- Crystal -->
  <g id="crystal" pointer-events="none">
    <circle cx="500" cy="500" r="352" fill="url(#crystalEdge)"/>
    <path d="M190 420 A 320 320 0 0 1 560 160 A 420 420 0 0 0 200 480 Z" fill="url(#crystal)" opacity="0.9"/>
    <ellipse cx="380" cy="300" rx="130" ry="70" fill="#fff" opacity="0.045" transform="rotate(-35 380 300)"/>
    <path d="M700 790 A 330 330 0 0 0 810 560 A 300 300 0 0 1 690 770 Z" fill="#fff" opacity="0.06"/>
  </g>
  <!-- Bezel top highlight -->
  <circle cx="500" cy="500" r="392" fill="none" stroke="url(#crystal)" stroke-width="18" opacity="0.5"/>

  <!-- Caseback inscription (below strap-visible area, subtle on lug) -->
  <text x="500" y="864" text-anchor="middle" class="caseback" font-size="8" opacity="0.65">CAL. 1876 · 28 800 A/h · 18K</text>
</svg>
<div class="caption" id="caption">Aurelian · Calibre 1876</div>
</div>

<script>
(function () {
  const NS = 'http://www.w3.org/2000/svg';
  const CX = 500, CY = 500;
  const el = (tag, attrs) => {
    const n = document.createElementNS(NS, tag);
    for (const k in attrs) n.setAttribute(k, attrs[k]);
    return n;
  };
  const rad = d => (d - 90) * Math.PI / 180;
  const pt = (r, deg) => [CX + r * Math.cos(rad(deg)), CY + r * Math.sin(rad(deg))];

  /* ---------- Fluted bezel ---------- */
  const flutes = document.getElementById('flutes');
  for (let i = 0; i < 120; i++) {
    const a = i * 3;
    const [x1, y1] = pt(366, a), [x2, y2] = pt(390, a);
    flutes.appendChild(el('line', { x1, y1, x2, y2 }));
  }

  /* ---------- Sunburst rays ---------- */
  const rays = document.getElementById('rays');
  for (let i = 0; i < 360; i += 1.5) {
    const [x2, y2] = pt(345, i);
    const light = (i > 290 || i < 40);   // highlight toward upper-left light source
    const op = light ? 0.10 + 0.08 * Math.cos(rad(i) - rad(330)) : 0.025;
    rays.appendChild(el('line', {
      x1: CX, y1: CY, x2, y2,
      stroke: i % 3 === 0 ? '#cfe0ff' : '#000',
      'stroke-width': 0.9, opacity: op
    }));
  }

  /* ---------- Minute track ---------- */
  const track = document.getElementById('minuteTrack');
  for (let i = 0; i < 60; i++) {
    const a = i * 6;
    const major = i % 5 === 0;
    const [x1, y1] = pt(major ? 300 : 306, a), [x2, y2] = pt(318, a);
    track.appendChild(el('line', {
      x1, y1, x2, y2, stroke: major ? '#ead9a8' : '#b9b3a4',
      'stroke-width': major ? 2.2 : 1, 'stroke-linecap': 'round', opacity: major ? 0.95 : 0.7
    }));
  }
  // 240 fine ticks on the rehaut
  for (let i = 0; i < 240; i++) {
    const a = i * 1.5;
    if (i % 4 === 0) continue;
    const [x1, y1] = pt(321, a), [x2, y2] = pt(326, a);
    track.appendChild(el('line', { x1, y1, x2, y2, stroke: '#9d978a', 'stroke-width': 0.6, opacity: 0.45 }));
  }

  /* ---------- Applied indices ---------- */
  const indices = document.getElementById('indices');
  for (let h = 0; h < 12; h++) {
    if (h === 3) continue;                   // date window at 3 o'clock
    const a = h * 30;
    const g = el('g', { transform: `rotate(${a} ${CX} ${CY})` });
    if (h === 0) {
      // Double baton at 12
      [-9, 9].forEach(dx => {
        g.appendChild(el('rect', { x: CX + dx - 5, y: 196, width: 10, height: 58, rx: 1.5, fill: 'url(#goldIndex)' }));
        g.appendChild(el('rect', { x: CX + dx - 1.8, y: 202, width: 3.6, height: 46, rx: 1, fill: 'url(#lume)', opacity: 0.9 }));
        g.appendChild(el('rect', { x: CX + dx - 5, y: 196, width: 4, height: 58, fill: '#000', opacity: 0.25 }));
      });
    } else {
      g.appendChild(el('rect', { x: CX - 6, y: 196, width: 12, height: 58, rx: 1.5, fill: 'url(#goldIndex)' }));
      g.appendChild(el('rect', { x: CX - 2, y: 202, width: 4, height: 46, rx: 1, fill: 'url(#lume)', opacity: 0.9 }));
      g.appendChild(el('rect', { x: CX - 6, y: 196, width: 4.5, height: 58, fill: '#000', opacity: 0.25 }));
    }
    indices.appendChild(g);
  }
  // Small applied dots between indices (at the minute track)
  for (let h = 0; h < 12; h++) {
    if (h === 3) continue;
    const [cx, cy] = pt(286, h * 30);
    indices.appendChild(el('circle', { cx, cy, r: 2.4, fill: 'url(#goldIndex)' }));
  }

  /* ---------- Movement ---------- */
  const hourHand = document.getElementById('hourHand');
  const minuteHand = document.getElementById('minuteHand');
  const secondHand = document.getElementById('secondHand');
  const dateText = document.getElementById('dateText');
  const caption = document.getElementById('caption');

  const BEATS = 8;                  // 28,800 A/h → 8 beats per second
  let lastDate = -1;

  function tick() {
    const now = new Date();
    const ms = now.getMilliseconds();
    const s = now.getSeconds();
    const m = now.getMinutes();
    const h = now.getHours() % 12;

    // Mechanical sweep: 8 discrete beats per second, each with a tiny
    // settle-in so the motion reads as a sweep rather than a stutter.
    const beat = Math.floor(ms / (1000 / BEATS));
    const frac = (ms % (1000 / BEATS)) / (1000 / BEATS);
    const settle = 1 - Math.pow(1 - Math.min(frac * 2.2, 1), 3);
    const secAngle = (s + (beat + settle) / BEATS) * 6;

    const minAngle = (m + s / 60 + ms / 60000) * 6;
    const hourAngle = (h + m / 60 + s / 3600) * 30;

    secondHand.setAttribute('transform', `rotate(${secAngle} ${CX} ${CY})`);
    minuteHand.setAttribute('transform', `rotate(${minAngle} ${CX} ${CY})`);
    hourHand.setAttribute('transform', `rotate(${hourAngle} ${CX} ${CY})`);

    const d = now.getDate();
    if (d !== lastDate) {
      lastDate = d;
      dateText.textContent = String(d).padStart(2, '0');
    }
    if (ms < 40 || caption.dataset.set !== String(m)) {
      caption.dataset.set = String(m);
      caption.textContent = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
        + ' · ' + now.toLocaleDateString([], { weekday: 'long', day: 'numeric', month: 'long' });
    }
    requestAnimationFrame(tick);
  }
  requestAnimationFrame(tick);
})();
</script>
</body>
</html>

Compare with

Claude Fable 5.1: other attempts