Domino Run
dominorun
SonnetOpus
Winner
CheapestFastest
Sonnet wins. Sonnet's dominoes look like the real thing, pips and all, and fall on honest physics in a wide rainbow spiral; Opus's chain never stalls because it nudges each struck domino over the edge, and it cost much less.
Who won? You pick
Pick the build you liked best to see what everyone else thinks.
Scorecard
Sonnet2Opus1
| Criterion | Sonnet | Opus |
|---|---|---|
| Looks like dominoes | Real dominoes with white pips, a wide rainbow spiral | Clean coloured blocks on a wooden table |
| Honest chain reaction | Pure contact physics; rests in a neat shingle at the right angle | Each struck domino gets a little spin over its tipping point, so it never stalls |
| Tested runs | Spirals of 380 to 1,000 dominoes and every material reach the end | 72 size, spacing and material combinations all reach the end; a 1,000-domino spiral falls |
| Pieces | Stairs, fork, bell, giant, cannon, word runs; no bridge | Stairs, fork, bell, giant, cannon with confetti; no bridge |
| Easter egg | A closed loop rings the bell with fireworks | A closed loop rings a golden bell with fireworks |
| Cost | $21.80 | $12.93 |
| Time | 2h33m39s | 1h44m37s |
| Overall | Winner | – |
The prompt
Build **"Domino Run"**: a real-time, interactive 3D tabletop where people **draw** lines of dominoes with a finger, **flick** the first one and watch the **chain reaction** run, then **erase**, **move** pieces by hand, add **stairs, forks, bells and giant dominoes**, and switch the dominoes between **Wood**, **Jelly** and **Glass**, with **synthesised sound**, as ONE self-contained HTML file.
It should feel like the most satisfying domino video you have ever watched, except you set it up yourself in ten seconds: draw a spiral, tap once, and the clacks start slow, speed up and race around the curve without ever stalling.
## Priorities
Build it in this order, and finish each tier properly before starting the next. A polished tier 1 beats a broken everything.
1. **Must be excellent:** the chain reaction itself (never stalls on a valid layout, never explodes, fallen dominoes come to rest in a neat shingle), the accelerating clack rhythm, Draw (correct spacing, rotated to the curve, popping in), Flick, the Wood look; the demo mode.
2. **Must work:** Erase, Hand, Pieces (Stairs, Fork, Bell, Giant), Jelly and Glass, Follow camera, Reset standing, Random run, Undo, sound, the control card, the WebGL2 fallback, the Easter egg.
3. **Polish:** Bridge and Cannon, glass chips, confetti, text runs in Random run, tilt-shift depth of field.
Never ship a feature half-working: if something from tier 3 can't be done well, leave it out cleanly.
## Deliverable
- One self-contained `.html` file with all JavaScript, WGSL, GLSL and CSS inline. Start the file with `<!doctype html>`, `<meta charset="utf-8">` and a viewport meta tag.
- **No external requests of any kind**: no libraries, CDNs, web fonts, images, textures or audio files. Generate everything procedurally in code (sound included, see Sound). Use system font stacks.
- It must run inside a sandboxed iframe (`sandbox="allow-scripts allow-pointer-lock"`). Do not use `localStorage`, cookies, `alert`, pop-ups or top-level navigation, and wrap any storage access in `try/catch`.
- This must be a live simulation, not a video, a pre-baked animation, a static render or a 2D fake.
- **Test hook:** if the URL has `?test=1`, expose `window.__toy` with functions that drive every tool and read the key state, with no visible change to the page: `drawPath(points)` (table coordinates), `flick(index, angleDeg, strength)`, `erase(x, z, radius)`, `placePiece(type, x, z, angleDeg)`, `moveDomino(index, x, z, angleDeg)`, `resetStanding()`, `clearTable()`, `randomRun(kind)`, `undo()`, `setMaterial("wood" | "jelly" | "glass")`, `setSpacing(v)`, `setSize(v)`, `step(seconds)` (advance the simulation while paused) and `getState()` returning `{ renderer, material, total, standing, fallen, chainSpeed, longestChain, awake }`.
## The table
- A large, warm, pale maple tabletop (subtle procedural grain, a soft satin sheen, rounded edges visible when zoomed out) in a calm, softly lit room that fades to a warm blur. Seen from a three-quarter view above, like leaning over the table. The table fills most of a square frame.
- **Dominoes:** real toppling-domino proportions, height : width : thickness = 1 : 0.5 : 0.16 (a 48 mm domino by default), with softly bevelled edges that catch the light. Each line is painted in a smooth colour gradient along its length (a cheerful palette per line, never two neighbouring lines alike), so a running wave reads clearly from far away.
- Up to **1,500 dominoes** on desktop (scale the cap down on phones and slow GPUs, never below 500). Hitting the cap shows a gentle toast and simply stops placing.
## Physics
- Simulate every domino as a **rigid body**: either a general solver (box contacts with friction, sequential impulses or XPBD) or a specialised domino solver (each domino pivots and slides on its edges, with domino-domino and domino-table contacts). Mass, gravity at real scale, friction about 0.4 between dominoes and 0.5 on the table.
- **Toppling must be physical:** a domino falls slowly at first and accelerates as its centre of mass passes over its edge; its top edge strikes the next domino's face and **slides down it** while pushing; the fallen ones come to rest each leaning on the one ahead in a **neat shingle**, the last one lying flat. A gap that is too wide stops the chain, with a little rock of the last domino.
- **The wave:** after a flick, the chain **accelerates and settles to a steady speed** (about 25 to 50 dominoes per second at the default size and spacing, like real ones), faster with taller dominoes and wider spacing. The **Spacing** slider's range (0.3 to 0.8 of the height) always propagates, for every material, size and curve.
- **Curves:** lines turn down to a radius of about two domino heights and the wave follows without stalling. **Forks** split one wave into two. A domino can topple one up to 1.5 times its own size (the Giant piece relies on this).
- **Stability is not optional:** standing dominoes are perfectly still (no creeping, no jitter, even right next to a falling one), a resting shingle never vibrates, nothing tunnels through the table or another domino at any speed, and nothing explodes, even when a 1,000-domino run falls in one go or the Hand drops a domino into a crowd.
- **Scale:** put resting bodies to **sleep** and wake them only on contact, use a spatial hash for neighbours, and only simulate the awake band around each wave front, so 1,500 dominoes cost almost nothing at rest and a running wave stays smooth.
- **Fixed simulation timestep** (for example 1/240 s) with bounded substeps (at most 8 per frame), decoupled from frame rate. On a slow frame, drop simulation time rather than exploding. The same layout and the same flick always give the same run.
### Materials (switchable at any time, even mid-run)
- **Wood:** lacquered, rigid, crisp. The reference feel.
- **Jelly:** translucent gummy dominoes that **squash on impact, bend as they fall, bounce a little on landing and wobble** when a neighbour falls (soft deformation in the vertex shader around the rigid core, so propagation stays reliable). The wave runs a bit slower and squishier, but it always propagates.
- **Glass:** heavy, slippery (friction about 0.2), sparkling. Hard impacts (a fast flick, a Giant domino, the Cannon) **chip a corner**: the domino swaps to a preallocated chipped shape and throws a few tiny shards that tinkle on the table. Chips stay until Clear table.
## Tools
A tool picker with **Draw**, **Flick**, **Erase**, **Pieces** and **Hand** (keys `1` to `5`). The default tool is Draw. A press that ends within 6 px and 450 ms counts as a tap. Right-drag or two fingers orbit the camera. Use pointer events with **pointer capture** so drags never drop, and support mouse, pen and touch.
### Draw
- Drag across the table to draw a path: it is smoothed, resampled at the current spacing, and dominoes **rise in along it with a pop** (scale up with a small overshoot) right behind the finger, each turned to the curve's tangent, with a soft rising tick. A ghost domino shows where the next one will go.
- Curves tighter than the minimum radius are smoothed out. Dominoes that would overlap an existing domino or piece are skipped. Starting within one spacing of the end of a standing line **continues that line** seamlessly.
- The draw direction is the line's forward direction. Size and Spacing apply to lines drawn next.
### Flick
- **Tap** a standing domino to tip it forward along its line. **Swipe** across one to push it in the swipe direction (so you can run a line backwards), harder with a faster swipe (capped). A small fingertip appears for a moment at the touch.
### Erase
- Drag a soft circular brush (about 1.5 domino heights): dominoes and pieces inside shrink away with a little pop. A tap erases one.
### Pieces
- A small row of piece chips appears in the card: **Stairs**, **Fork**, **Bridge**, **Bell**, **Cannon**, **Giant**. Drag on the table to place and aim the piece (start point and direction); placed pieces snap to nearby line ends.
- **Stairs:** a wooden flight of five steps with a domino on each, which the wave climbs (or descends; tap a placed staircase to flip it).
- **Fork:** a Y junction, one trunk domino angled to hit two branches of eight dominoes splaying at about 30 degrees. Extend the branches with Draw.
- **Bridge:** a small wooden arch over an existing line; dominoes drawn across it stand on its deck, so two lines can cross.
- **Bell:** a little brass bell on a stand that rings when a domino strikes it.
- **Cannon:** a tiny confetti cannon that fires a burst of a few hundred paper pieces when hit; they flutter, tumble and settle on the table, then fade after about 10 s.
- **Giant:** a growth sequence of six dominoes, each 1.5 times taller than the last, so a tiny domino topples a huge one with a deep thud and a small camera shake.
### Hand
- Press a domino or piece to lift it (it rises, its shadow shows where it will land, neighbours stay put), drag to move, turn it with the wheel, a two-finger twist or `Q` / `E` (15 degree steps), release to set it down upright with a soft tap. A fallen domino picked up stands up when placed. Dropping onto others nudges it to the nearest free spot.
## Goal, milestones and Easter egg
- No levels. The challenge is the **longest chain** (dominoes toppled from one flick); the best of the session is shown in the readouts.
- Toasts top centre: "First run!", "100 in a row", "500 in a row", "1,000 in a row", "It forked!", "Ding!" (first bell), "Up the stairs", "Giant down".
- **Easter egg (never hinted):** a single drawn line of at least 40 dominoes that ends exactly where it began (a closed heart, circle or spiral back to its start). When its wave comes all the way round and the last domino falls against the first, a small golden bell rises from the centre of the loop, rings a warm three-note chord, and fireworks burst softly above the table.
## Sound
Every action has a **synthesised sound effect**, generated live with the **Web Audio API** (oscillators, filtered noise, envelopes). **No audio files, no samples, no external requests.**
- **Clacks:** one per real contact event, so **the rhythm is the physics**: you hear it start slow, accelerate and settle into a steady fast patter. Wood: a crisp hollow click (noise burst through a resonant band-pass, pitched by domino size). Jelly: a soft squelchy "blup" with a little pitch bend. Glass: a bright clink with inharmonic partials.
- At high wave rates, individual clacks blend into a continuous rattle whose loudness follows the rate, instead of piling up voices.
- **Landing:** the last domino's flat thud; a deep boom for the Giant.
- **Draw:** a soft tick per domino as it pops in, rising along a pentatonic scale while you draw.
- **Flick:** a small finger tick. **Erase:** a tiny reverse pop. **Hand:** a lift tick and a set-down tap.
- **Pieces:** a wooden knock on placement; the Bell rings with a long decay; the Cannon pops with a papery hiss; glass chips crack and tinkle.
- **Reset standing:** a quick rising zip as the dominoes stand back up. **Clear table:** a soft sweep.
- **Easter egg:** a warm three-note bell chord and soft firework crackles.
Rules:
- Create the `AudioContext` only after the first user gesture, never before. Resume a `suspended` context on interaction, and wrap every audio call in `try/catch` so a failure can never break the toy.
- A **mute button** with a speaker icon, **sound on by default**, and the `M` key toggles it. Master gain into a compressor, no clipping.
- Limit simultaneous voices (about 16) so a 1,000-domino run never turns into noise or glitches.
## Camera and keys
- **Camera:** right-drag or two fingers orbit (elevation 15 to 80 degrees); middle-drag or Shift-drag pans within the table; the wheel or a pinch zooms from the whole table down to a close-up at domino level. Double-clicking empty table or `0` resets the view.
- **Follow camera:** when on, the camera glides after the wave front at the Follow speed, a little lower for drama, and eases back to the user's view when the run ends.
- **Keyboard:** `1` to `5` tools, `T` cycles the material, `F` Follow camera, `S` Slow motion, `G` Random run, `R` Reset standing, Shift+`R` Clear table, Ctrl/Cmd+`Z` Undo, `Q` / `E` rotate (Hand), `C` Cinema, `M` mute, Space pauses or resumes, `0` resets the view.
## Rendering (WebGPU with a WebGL2 fallback)
- **WebGPU (WGSL) when available, with an automatic WebGL2 fallback that looks the same.** Detect at start; if WebGPU is missing or adapter / device creation fails, use WebGL2. No libraries: write both paths yourself, sharing the scene data and the simulation. Show which one runs in the status pill: `WEBGPU · LIVE` or `WEBGL2 · LIVE`.
- Aim for a warm product photograph of a toy on a table, not a physics debug view.
- **Instanced dominoes:** one bevelled box mesh (plus the chipped variants) drawn from an instance buffer of transforms and colours, a few draw calls in total.
- **Wood:** glossy painted lacquer with a crisp specular highlight on the bevels and faint grain showing through. **Jelly:** translucent, glowing where light passes through (cheap subsurface), coloured soft shadows, a wet highlight. **Glass:** clear with green-tinted thick edges, strong Fresnel reflections of the room, refraction of the table behind it and sparkling glints.
- **Light:** a soft warm key light from upper left with a real shadow map (long soft shadows from standing dominoes, crisp contact shadows), gentle ambient occlusion under every domino and in the shingles, a cool fill from the other side.
- **Post-processing:** HDR with filmic tone mapping, light bloom on glass glints, the bell and confetti, a light vignette, and (polish) a subtle tilt-shift depth of field in close-ups. 4x MSAA or equivalent. Keep the image crisp.
- Build pipelines, shaders and buffers once at start-up for every cap (dominoes, pieces, shards, confetti). Never create shaders, pipelines or geometry during interaction. Handle resize and device-pixel ratio (cap at 2).
- Include an automatic **quality scaler**: if the frame rate drops, reduce resolution, shadow resolution, refraction and bloom before ever touching the physics.
- Only if neither WebGPU nor WebGL2 exists, show a clear, well-designed message explaining what the piece needs.
## Interface
A calm, light interface that stays out of the way. The table is the hero, and UI must never cover it on desktop or mobile.
**Top left**
- Small caps: `POKEABLE · SPECIMEN 009`
- A large italic serif heading on two lines: *Domino* / *Run.*
- Caption lines: "Draw a line." / "Flick the first one." / "Don't blink."
**Top right:** a small live status dot with `WEBGPU · LIVE` or `WEBGL2 · LIVE`, a **speaker icon button** (`ON` / `MUTED`), and `PAUSED` when paused.
**Right panel: control card "Dominoes"**
A **floating control card**: about 240px wide, 20px corners, soft off-white, a soft drop shadow, no hairline borders, the plain system sans-serif font, and one **tomato red** accent. A bold sentence-case title and section labels, tools as rounded tiles with small drawn icons and key numbers (the active one tinted and ringed in the accent), chunky sliders (a 6px rounded track filled with the accent and a round white thumb) with live values in small rounded monospace chips, secondary buttons as light-grey chips without borders, on/off switches (label left, switch right), and **Pause / Resume** as a solid dark full-width pill. The card collapses to a small button; on narrow screens it becomes a bottom sheet with rounded top corners.
- Tools: **Draw**, **Flick**, **Erase**, **Pieces**, **Hand**; with Pieces active, the piece chips (Stairs, Fork, Bridge, Bell, Cannon, Giant).
- **Material:** a three-way segmented control, Wood / Jelly / Glass.
- Sliders: **Spacing** (0.3 to 0.8 of the height), **Domino size** (30 to 80 mm), **Follow speed**, **Sound** (master volume), each with its live value.
- Switches: **Follow camera**, **Slow motion** (¼ speed), **Cinema**.
- Buttons: **Reset standing** (every domino rises back to where it was placed in a quick reverse ripple), **Clear table**, **Random run** (cycles through a big spiral, a wave, a forked tree with bells, and a short word written in dominoes, always fitting the table and the cap), **Undo** (last draw, erase, piece or move).
- A **Pause / Resume** button.
**Bottom left:** a one-line hint that changes with the tool:
- Draw: "Drag to draw a line of dominoes."
- Flick: "Tap a domino to tip it. Swipe to aim."
- Erase: "Drag over dominoes to clear them."
- Pieces: "Pick a piece, then drag to place and aim it."
- Hand: "Drag a domino to move it. Scroll to turn it."
Under it, live readouts from the simulation: **standing**, **fallen**, **chain speed** (dominoes per second), **longest chain** (session best). Values update smoothly, not every frame.
**Bottom right:** a collapsible **"How it falls"** section, 4 to 6 plain-English lines: each domino is a rigid body that tips once its centre of mass passes its edge, the falling top slides down the next one and pushes it, the wave settles to a steady speed set by height and spacing, resting dominoes sleep until touched, and every clack is synthesised from a real contact.
**Toasts** top centre for milestones. **Cinema** (`C`) hides every piece of UI and the cursor for clean screen recordings; a tap (without a drag), `C` or Esc brings everything back.
Respect `prefers-reduced-motion`: soften UI transitions, disable camera shake and make Follow camera glide more gently. The dominoes still respond fully.
## Demo mode (required)
If the URL has `?demo=1`, auto-play a 4-second loop with no user input: the object drops in, wobbles, gets poked or sliced once, then settles.
For this toy that means:
- **Hide all UI** (text, panel, status, hint, readouts, toasts, cursor). Only the table and the dominoes.
- One **fixed demo quality preset** (no quality scaler), Wood material, chunky dominoes, a fixed camera at the default three-quarter view with the whole spiral filling about 70% of the square frame.
- **Sound is completely off:** never create an `AudioContext`.
- Deterministic: a fixed layout, no randomness. Drive the simulation from real elapsed time with the fixed timestep, so the loop lasts 4 s even at low frame rates, and restart every 4.0 s of real time from the identical state.
- Timeline:
- **0.0 to 0.4 s:** a rainbow spiral of about 60 standing dominoes, perfectly still.
- **0.4 s:** an invisible flick tips the outermost domino.
- **0.5 to 3.2 s:** the wave runs around the spiral towards the centre, visibly accelerating then steady, a bright moving front of falling colour; the last domino lands flat by 3.2 s (tune spacing so the timing holds).
- **3.2 to 4.0 s:** every domino stands back up in a smooth, eased reverse ripple, ending exactly in the starting poses by 4.0 s, so the loop restarts cleanly.
- Recorded in a slow software renderer: **the wave front must still read clearly at 15 fps**. Keep counts modest and shadows simple in demo mode.
- Start moving within 1 second of the page loading.
- Also support `?demo=1&t=<seconds>`: freeze the demo at that time (for screenshots).
## Before you finish
Self-check against this list and fix anything that fails:
- Draw straight lines, tight curves, a 1,000-domino spiral and a fork; flick them at every Spacing, Domino size and material: the chain never stalls (except at a real gap), never explodes, and every shingle rests perfectly still.
- Try every tool and piece, every slider at both extremes, every switch, Undo, Reset standing mid-run, Clear table, Random run (all kinds), pause and resume, Slow motion, Follow camera, Cinema, every key, and resizing to phone width with two-finger orbit on touch.
- Hit the Giant, chip some glass, ring the bell, fire the cannon, and trigger the Easter egg.
- Sound: every action has its effect, the clack rhythm accelerates with the wave, nothing plays before the first gesture, mute and volume work, a huge run never clips or piles up voices.
- `?demo=1` matches the timeline, loops cleanly, shows no UI and plays no sound; `?demo=1&t=2` freezes; `?test=1` exposes `window.__toy`.
- No console errors or WebGPU validation errors on WebGPU, and none on WebGL2 (force the fallback to check it looks the same). Smooth on a mid-range phone.
Put the chain reaction first: the moment after the flick, when the clacks speed up and the colour races around the curve, has to be perfect.