Crank

Your place in line comes in a capsule.

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

Field notes

A waitlist page that is a capsule-toy machine. Your email is the coin: drop it in, turn the knob, and your place in line rolls out in a capsule with a tiny toy inside.

  • 3D
  • Pointer interaction
  • Light theme
  • Product

Crank is the waitlist page for Twistbit, a fictional app that drops a tiny desk toy into your dock each morning, drawn as a glossy red capsule-toy machine with a clear dome full of capsules. The sign-up form is the machine's front label, beside the coin slot: type your email and it drops in as a coin, turn the knob a full turn and the capsules churn, then one rolls out of the chute, pops open and shows a little toy, a dino, a mushroom, a rocket or a cat, with your ticket: your place in line, an invite link, and how far each friend moves you up.

While you watch, other people join and new capsules fall in through the top. Drag the body to shake the machine and the pile lags behind it; tap the dome and the capsules hop. A tiny synth ticks, clinks and pops. Your place, your invite code, an early-bird gold capsule and every move up come from one small backend seam, with a working stub, so the page never promises what your backend did not say. On a phone the form sits under the machine and a tap turns the knob; the keyboard path is Enter, then Enter; reduced motion opens the capsule at once; and without WebGL the form and the ticket are the page.

How it's built

  • The machine is a few rounded boxes, cylinders and spheres: a glossy red base with the coin slot, the knob and the chute on its front, a cream collar, a clear dome and a red cap. The form is the machine's front label: its two top corners are projected through the machine's own matrix every frame, so the label scales, rocks and leans with the body.
  • The 40 capsules rest in slots settled once from a seed: dropped in one by one under gravity, then parted until none overlap. Churning the pile is a rotation of the whole pile by the knob's angle, and each shell spins whole turns per knob turn, so one full turn leaves exactly the same pile.
  • The state keeps only when things were asked for (a tick of the knob, a drop-in, a dispense, a coin, a shake) and frame(state, t) derives every lift, fall, roll and wobble from it. Lifts and shakes use (1 − u)² envelopes that end at exactly zero, so the tour closes with second 10 equal to second 0.
  • The backend seam is two calls, join and status, shaped like Threshold's. The place, the invite code, the early-bird perk and how far a friend moves you up all come from it, so the page never promises what the backend did not say. The shipped stub works in memory: others join every few seconds, every 10th place is early-bird, and a friend moves you up once.
  • The sounds are a tiny Web Audio synth (ticks, a coin, clacks, a thud, a pop and a ding) that starts only after a real click or key. A Node check proves the slots never overlap, the loop closes, nothing jumps in 1 ms steps, the tour hands over without a jump, and the stub keeps its promises.

Inside the prompt

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

crank-waitlist/
├─ .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
   │  ├─ layout.ts
   │  ├─ live.ts
   │  ├─ look.ts
   │  ├─ loop.ts
   │  ├─ pile.ts
   │  ├─ time.ts
   │  ├─ timeline.ts
   │  └─ waitlist.ts
   └─ scene/
      ├─ capsule.ts
      └─ machine.ts

Recut it

  • Rename the product and rewrite every stringsrc/lib/copy.ts + index.html → PRODUCT / COPY / <title>
  • Connect your own waitlist backendsrc/lib/waitlist.ts → join / status
  • Rename or swap the toyssrc/lib/copy.ts + src/scene/capsule.ts → TOYS / TOY_BUILDERS
  • Re-colour the machine, the capsules and the pagesrc/lib/look.ts + src/index.css → COLOR / PALETTE / --bg …
  • Retime the coin, the turn, the capsule and the shakesrc/lib/look.ts → TIMING
  • Turn the sounds offsrc/lib/look.ts → LOOK.sound
  • Retime the 10-second toursrc/lib/timeline.ts → TOUR
  • Check the loop still closes and the copy fitscheck.ts → pnpm check