Escapement

Opens when the drums read 00.

Fig. 1 — Escapement, live captureOpen the live demo ↗10 s loop · recorded frame by frame on GPU

Field notes

A launch countdown that is a skeleton watch movement. Jumping drums read the days, hours and minutes, a tourbillon turns once a minute, typing your email winds the crown, and scrolling takes the whole movement apart.

  • 3D
  • Scroll-driven
  • Pointer interaction
  • Dark theme

Escapement is the launch page of Tickwell, a fictional calendar app, drawn as an open skeleton watch movement in a dark room. The countdown is not text over a picture: six ivory drums under a display bridge read the days, hours and minutes, and jump with a small overshoot when a minute runs out. Beneath them the going train beats once a second, dead-beat, and a tourbillon at six o'clock turns once a minute with its blue seconds hand. The sign-up form is the winding: each keystroke turns the crown and clicks the ratchet, a power-reserve gauge fills, and joining winds it full.

Scroll and the movement comes apart into six labelled layers, from the mainplate to the display bridge, and goes back together when you scroll up. On launch day the drums roll to 00 00 00, the train rushes, the display bridge lifts away and the page becomes the product's front door; "Preview launch day" plays it on demand. The launch date and every string live in one file, your list provider plugs into one function, a tiny synth ticks only if you turn sound on, and reduced motion, phones and browsers without WebGL each get a page that still works.

How it's built

  • The movement is built only from primitives and extruded 2D shapes: each wheel is a toothed outline with its spoke windows cut as holes, the bridges are capsule bars, and the drums are cylinders wrapped in a canvas texture of the digits 0–9 drawn after the mono font loads. There is no model, texture file or HDR.
  • The gear train is real arithmetic: each arbor sits exactly one wheel radius plus one pinion radius from the last, and each speed follows from the teeth it meshes with, back from a cage that turns once a minute. The check proves every pair meshes and turns the opposite way.
  • Every frame comes from one pure function of the time and the moments things were asked for (keystrokes, the join, a preview launch, a replay). The drums roll the short way round from the digits they showed at the last minute boundary, with an overshoot that ends at exactly the next digit.
  • The 10-second tour takes the movement apart, runs out the last seconds, launches, and then winds every wheel back by exactly the turns it made, so second 10 is second 0. When a visitor moves, the tour hands over to the real clock by blending each wheel the short way round.
  • The page follows the scene through CSS variables (how far it has come apart, the launch fade, the gauge, each label's position), so React only re-renders when text changes. The sign-up message comes from the backend seam, never from the copy.

Inside the prompt

Every file below is written out in full, so your agent creates the project exactly — no guessing, no missing pieces.

escapement-countdown/
├─ .gitignore
├─ check.ts
├─ index.html
├─ package.json
├─ tsconfig.json
├─ vite.config.ts
└─ src/
   ├─ App.tsx
   ├─ index.css
   ├─ main.tsx
   ├─ vite-env.d.ts
   ├─ components/
   │  ├─ Page.tsx
   │  └─ Scene.tsx
   ├─ lib/
   │  ├─ copy.ts
   │  ├─ countdown.ts
   │  ├─ layout.ts
   │  ├─ live.ts
   │  ├─ look.ts
   │  ├─ loop.ts
   │  ├─ time.ts
   │  ├─ timeline.ts
   │  ├─ train.ts
   │  └─ waitlist.ts
   └─ scene/
      ├─ movement.ts
      └─ shapes.ts

Recut it

  • Rename the product, set the launch date and rewrite every stringsrc/lib/copy.ts + index.html → PRODUCT / LAUNCH_AT / COPY / <title>
  • Connect your own list providersrc/lib/waitlist.ts → subscribe
  • Re-colour the metals, the drums and the pagesrc/lib/look.ts + src/index.css → COLOR / --bg …
  • Change how far each layer moves when it comes apartsrc/lib/look.ts → EXPLODE_Z / EXPLODE_TILT
  • Re-tooth or move the gear trainsrc/lib/train.ts → SPEC
  • Rename or relabel the exploded view's layerssrc/lib/copy.ts → LAYERS
  • Turn the sounds offsrc/lib/look.ts → LOOK.sound
  • Retime the 10-second toursrc/lib/timeline.ts → tourFrame
  • Check the loop still closes and the copy fitscheck.ts → pnpm check