Stone Balance
stonebalance
OpusSonnet
WinnerCheapest
Fastest
Opus wins. Both cairns balance on real centres of mass and topple honestly; Opus sets them on a misty dawn lake that looks like a nature film, for less money than Sonnet's plainer riverbank.
Who won? You pick
Pick the build you liked best to see what everyone else thinks.
Scorecard
Opus1Sonnet1
| Criterion | Opus | Sonnet |
|---|---|---|
| Dawn riverbank | Mist, reeds, tree line and sun reflections on still water | Hazy light, a blocky boulder and a plain sand path |
| Balance physics | Real tipping; a 5-stone cairn held with zero drift | Real tipping to the millimetre; a 10-stone stack held with zero drift for 60 s |
| Topple and splash | A breath tips the top stones into the water with splashes and ripples | Bigger splash with foam rings and buoyant stones |
| Placing stones | Ghost preview, gentle hover-and-lower, centre-of-mass overlay | Ghost preview follows the pointer ray; nudge-and-hold builds force |
| Easter egg | A heron lands on a tall cairn and stands on one leg | A heron lands, perches and leaves with a croak |
| Cost | $16.24 | $19.68 |
| Time | 2h18m47s | 2h10m41s |
| Overall | Winner | – |
The prompt
Build **"Stone Balance"**: a real-time, interactive 3D riverbank at dawn where people **pick up river stones**, **turn** them, **stack** them into a cairn, **nudge** them and **breathe** on them until the balance fails and the cairn **topples** into the water with **splashes**, rendered with **WebGPU** (with a WebGL2 fallback) and **synthesised sound**, as ONE self-contained HTML file.
It should feel quiet and absorbing, like stacking stones by a real river: every stone is different, a few millimetres decide whether it holds, and the moment it holds on an impossible corner should make people hold their breath. When it falls, the fall itself should be beautiful.
## 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:** stable stacking of irregular stones (no jitter, no creep, no sinking), honest tipping when the centre of mass leaves the support, gentle placing with the ghost preview, the topple and splash, the dawn light; the demo mode.
2. **Must work:** the five tools, the centre-of-mass helper, rolling down the bank, water drag and ripples, readouts, milestones, sound, the control card, the WebGL2 fallback, the Easter egg.
3. **Polish:** mist that bends around your breath, wet-stone darkening and drying, drips, dragonflies over the water, the stones reflected in the river.
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.
- If the URL has `?test=1`, expose `window.__toy` (no visible change) with functions to drive every tool and read the key state: `setTool(n)`, `pick(id)`, `moveHeld(x, z)`, `turnHeld(yawDeg, tiltDeg)`, `release()`, `nudge(id, dx, dz)`, `breathe(x, y, seconds)`, `newStone()`, `collapse()`, `clear()`, `reroll(seed)`, `setSlider(name, value)`, `setSwitch(name, on)`, `step(seconds)` and `state()` returning `{ stones: [{ id, shape, mass, pos, quat, sleeping, inWater, inCairn }], height, stacked, balance, best, renderer, fps, toasts }`.
## The riverbank
- A real scale scene (metres, gravity 9.81). In the foreground, a shore of small pebbles and wet sand sloping down into a **calm, slow stream** about 6 m wide; the far bank has reeds, alders and willows as soft silhouettes in **drifting dawn mist**. The sky is pale peach to rose near a low sun just above the trees, cool blue overhead.
- **The base:** a broad, flat-topped bedrock boulder at the water's edge (about 60 cm across, its top 25 cm above the water) where the cairn is built. Its top is slightly uneven, so the first stone matters too.
- **The stones:** about **8 stones lie on the shore** in a loose row in front of the boulder, each generated from a seed: **flat** (slabs, thin and wide), **round** (slightly squashed spheres), **egg** (one end fatter), **wedge** (tapered, one thick side), and the odd lumpy one. Sizes 6 to 24 cm, density 2.6 g/cm³, so masses from about 0.2 to 5 kg. Materials vary: grey granite with speckles, dark basalt, banded sandstone, slate, white quartz veins, a few lichen spots. No two stones look or behave the same.
- **Framing:** a low three-quarter view, as if crouching on the shore; the boulder sits a little left of centre of a square frame with room above it for a tall cairn, the river and its reflections behind.
## Physics
- **Rigid bodies with real shapes:** every stone is a smooth convex shape. Compute its **mass, centre of mass and full inertia tensor from its actual volume** (egg and wedge stones have off-centre centres of mass, which is the whole game). Collision uses the same surface you render: gaps or overlaps at contacts never exceed 1 mm, so stones never visibly float or sink into each other.
- **Contacts:** convex-convex collision (GJK / EPA, SAT on a dense hull, or similar) with a **contact manifold of up to 4 points per pair**, persistent contacts with warm starting, Coulomb friction with static friction that genuinely holds (no slow creep on a 20 degree slope), a little rolling resistance, and soft but very stiff penetration correction that never adds energy.
- **Stacking must be rock solid:** a 10-stone cairn standing on small contact patches stays perfectly still for minutes: no jitter, no drift, no sinking, no slow rotation. Use sleeping (a still stone sleeps after about 0.5 s and wakes on any touch, breath, wind gust or change to a neighbour) but the stack must also be stable while awake.
- **Honest balance:** a stone balances exactly while the combined centre of mass of it and everything above it lies over its support polygon, and **tips** as soon as it leaves it. Tipping starts slowly and accelerates like a real inverted pendulum, a stone rocks on a rounded base before settling, and a stone set on its tip can really stand if, and only if, it is placed within a millimetre or two. Never glue stones together and never fake balance.
- **Falling and rolling:** toppled stones bounce with a little restitution (about 0.15), chip-free, then **roll and tumble down the shore**: round stones roll far, eggs roll in wobbly curves, slabs slide and flop. Whatever reaches the river splashes in.
- **Water:** at the water line a stone makes a **splash** (droplets plus a crown for big stones), a **ripple ring** that spreads on the water surface (a heightfield simulation that also reflects off the bank), and air bubbles. Under water it gets buoyancy, strong drag and a gentle push from the current, then sinks to the gravel bed, visible through the water.
- **Fixed simulation timestep** (about 240 Hz, enough iterations for tall stacks) with bounded substeps, decoupled from frame rate. On a slow frame, drop simulation time rather than exploding. Nothing ever tunnels through the boulder, the shore or another stone, even after a fast fall.
- When a cairn of 3 or more stones topples, time eases to about half speed for 1.5 s so the fall reads as a slow, graceful collapse, then back to normal.
## Tools
A tool picker with **1 Place**, **2 Rotate**, **3 Nudge**, **4 Breath** and **5 New stone**. The default tool is Place. Right-drag or two fingers (when no stone is held) orbit the camera. A press that ends within 6 px and 450 ms counts as a tap. Use pointer events with **pointer capture** so drags never drop, and support mouse, pen and touch.
### Place
- Press a stone that has nothing resting on it (on the shore, on top of the cairn or in the shallows) to **pick it up**: it lifts with a soft ease and hovers about 5 cm above whatever is under the pointer, following it smoothly. A stone with others on top gives a tiny shake instead, and the hint reads "Something's resting on it."
- A **ghost preview** (a translucent copy plus a soft contact shadow) shows exactly where the stone will touch down if released now, found by sweeping its shape straight down.
- **Release to set it down gently:** the stone lowers at about 4 cm/s until it touches, then the invisible hand lets go over 0.3 s with zero velocity. No drop, no impulse: whether it holds is down to balance alone.
- The held stone is moved by a stiff, speed-limited spring, so bumping the cairn with it pushes physically but gently and never teleports through anything.
### Rotate
- Turns the held stone, or the topmost stone under the pointer, in small steps: drag sideways to turn it about the vertical axis, drag up and down to tilt it; the wheel turns by 5 degrees, Shift for 1 degree. Two fingers twisting rotates a held stone on touch. A resting stone rotates in place, lifted a hair while it turns, and settles again.
- `Q` / `E` turn by 5 degrees and `Shift+Q` / `Shift+E` tilt, with any tool while a stone is held.
### Nudge
- A tap pushes the stone under it by a few millimetres, away from the camera or along a short swipe. Holding pushes with a slowly growing force. Nudge the bottom stone and the whole cairn shifts and sways.
### Breath
- Hold to **blow gently** from the camera towards the pointer: a soft cone of air (about 25 cm wide at the cairn) whose force ramps up over 1.5 s while held and depends on each stone's exposed area. You see it in the mist streaming and swirling, dark catspaw ripples on the water and the cairn starting to rock. Release and it stops. This is the test: does it hold?
### New stone
- Tap the river (or the button) to fish out a **new random stone**: it rises dripping from the water and lands on the shore in the next free spot. Up to 8 stones on the shore, 24 in total (the oldest stone at the river bottom gives way gracefully).
**Buttons:** **Collapse** (a gentle push at the cairn's base topples it on purpose), **Clear** (every stone glides back to the shore), **Reroll stones** (a new set of shore stones from a new seed). Clicking a stone in the water with Place picks it out, dripping.
## Challenge and milestones
- Live goal: build tall. Toasts top centre for **First stack** (2 stones), **Five-stone cairn**, **Seven-stone cairn**, **Ten-stone cairn**, **Half a metre** (cairn height 50 cm), **Impossible balance** (a stone resting on a contact patch under 1 cm across, standing with its long axis within 30 degrees of vertical, still for 3 s) and **New best** whenever the tallest height this session is beaten. A toast only counts a cairn that has stood still for 2 s.
## Easter egg
- When a cairn of **7 or more stones** stands perfectly still for **5 seconds**, a **grey heron** glides in low from upstream, lands on the top stone with a few wingbeats, folds its wings and stands on one leg, silhouetted against the dawn. It stays until the cairn is touched, blown or falls, then lifts off with a croak and flaps away downstream. Its weight is ignored by the physics. Never hint at it in the UI.
## 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.**
- **Stone on stone:** a hard, short "tok" made of a click plus 3 or 4 damped inharmonic partials, pitched by the masses involved (small stones bright, big ones deep), loudness by impact speed. Rate-limit per pair so resting contacts never chatter.
- **Scrape:** a gritty band-passed noise while stones slide against each other or the boulder, following slip speed.
- **Place / pick up:** a soft lift (a faint gravel crunch) and a quiet, satisfying settle tok when a stone lands and holds.
- **Wobble:** tiny ticks as a rocking stone touches down on each side.
- **Topple:** a cascade of heavier clunks and rolls on the pebbles.
- **Splash:** a noise burst plus a quick rising "plop" chirp and a few bubbly sine blips, pitched by stone size.
- **Breath:** a soft, airy exhale that swells while held. **New stone:** a slosh and drips.
- **Ambience:** a very quiet river murmur (slowly modulated low noise) and occasional distant dawn birds; a soft croak and wingbeats for the heron.
- **Milestones:** a struck singing-bowl tone (a few slowly beating partials), soft and short.
Rules:
- Create the `AudioContext` only after the first user gesture, never before. Handle a `suspended` context by resuming it on interaction, and wrap every audio call in `try/catch` so a failure can never break the toy.
- Master gain into a compressor / limiter, no clipping. Limit simultaneous voices to about 16 so a big collapse never turns into noise.
- A **mute button** with a speaker icon, **sound on by default**, and `M` toggles it.
## Camera and keys
- **Camera:** orbit within limits (about 100 degrees around the cairn, from just above the water to a 50 degree look down), wheel or pinch zooms from a wide view of the bank to a close-up of a single contact; the camera target rises smoothly with the cairn's height. Double-click the sky or press `0` to reset the view.
- **Keyboard:** `1` Place, `2` Rotate, `3` Nudge, `4` Breath, `5` New stone, `Q` / `E` turn (Shift tilts), `H` centre-of-mass helper, `0` reset view, `C` Cinema, `M` mute, Space pauses or resumes, `R` resets the bank to its starting stones.
## Rendering (WebGPU with WebGL2 fallback)
Aim for the look of a quiet nature photograph at dawn, not a game level.
- **WebGPU (WGSL) when available, with an automatic WebGL2 fallback that looks the same.** Detect at start; if WebGPU, the adapter or device creation fails, use WebGL2. No libraries: write both render paths yourself, sharing the scene data and the simulation. Show which one runs in the status pill: `WEBGPU · LIVE` or `WEBGL2 · LIVE`. Only if neither exists, show a clear, well-designed message.
- **Stones:** physically based shading with procedural detail (speckle, grain, quartz veins, banding, lichen) in object space so it moves with the stone. **Wet stones** are darker and glossy and dry slowly from the edges after leaving the water; the Friction slider's wet end makes all stones look damp.
- **Contact shadows matter:** a soft shadow map from the low sun plus ambient occlusion where stones touch, so you can read every contact patch and every hair-thin gap.
- **Water:** a calm surface with the ripple heightfield, reflections of the sky, far bank and cairn, Fresnel, soft refraction of the gravel bed in the shallows, and droplet particles for splashes.
- **Air:** layered mist over the water that drifts with the wind and swirls with your breath, warm sun haze, a few dragonflies.
- **Post:** HDR with filmic tone mapping, gentle bloom on the sun and its glitter on the water, a light vignette. Keep it crisp.
- Build pipelines once at start-up and preallocate buffers for every cap (stones, particles, ripples). Never create shaders, pipelines or geometry during interaction. Handle resize; cap device-pixel ratio at 2.
- Include an automatic **quality scaler**: if the frame rate drops, reduce resolution, shadow size, reflections and mist before ever touching the physics.
## Interface
A calm, light interface that stays out of the way. The cairn is the hero, and UI must never cover it on desktop or mobile.
**Top left:** small caps `POKEABLE · SPECIMEN 012`, a large italic serif heading on two lines: *Stone* / *Balance.*, and the captions "Breathe in." / "Small moves." / "Let it hold."
**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 "Cairn"**, a floating card about 240px wide with 20px corners, soft off-white, a soft drop shadow, no hairline borders, plain system sans-serif, and one accent colour: a warm river-clay terracotta (around `#C46A43`). 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 (6px rounded track filled with the accent, round white thumb) with live values in small rounded monospace chips; secondary buttons as light-grey chips; on/off switches; a solid dark full-width **Pause / Resume** pill. Collapsible to a small button; a bottom sheet with rounded top corners on narrow screens.
- Tools: **Place**, **Rotate**, **Nudge**, **Breath**, **New stone**.
- Sliders: **Wind** (still to gusty), **Friction** (wet to dry, about 0.45 to 0.9), **Sound** (master volume).
- Buttons: **Collapse**, **Clear**, **Reroll stones**.
- Switches: **Centre of mass** (draws each stone's centre of mass as a small dot, the combined centre of mass above each contact, its plumb line, and the support polygon as a glowing outline on the contact patch: green when safely inside, amber near the edge, red outside), **Slow motion** (¼ speed), **Cinema** (`C`: hides all UI and the cursor; a tap without dragging, `C` or Esc brings it back).
**Bottom left:** a one-line hint per tool:
- Place: "Pick a stone from the shore. Lower it slowly."
- Rotate: "Drag or scroll to turn it. Small moves matter."
- Nudge: "Tap a stone to nudge it. Gently."
- Breath: "Hold to breathe on the cairn. Does it hold?"
- New stone: "Tap the river to fish out a new stone."
Under it, live readouts computed from the simulation: **Height** (cm, top of the cairn above the boulder), **Stacked** (stones resting on the boulder through the cairn), **Balance** (%: for every stone in the cairn, the distance from the combined centre of mass above its contact to the nearest edge of its support polygon, relative to the polygon's size; show the smallest, 0% means about to tip) and **Best** (tallest this session). Update smoothly, not every frame.
**Bottom right:** a collapsible **"How it stands"** panel, 4 to 6 plain-English lines: each stone's weight acts at its centre of mass; a stone holds while the weight above it falls inside where it touches; friction stops it sliding; breath and wind push hardest on big flat faces; every sound is synthesised.
**Toasts** top centre for milestones. Respect `prefers-reduced-motion`: soften UI transitions and camera moves; the stones still behave 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, hints, readouts, helper, cursor). Only the bank, the cairn and the river are visible; the hand is invisible.
- One **fixed demo quality preset** (no quality scaler), a fixed camera at the default view, no wind gusts, no heron.
- **Sound is completely off:** never create an `AudioContext`, play nothing.
- A fixed seed, no randomness. Restart every 4.0 s of real time from the identical state, driving the simulation from real elapsed time with the fixed timestep, so the loop lasts 4 s even at low frame rates. Also support `?demo=1&t=<seconds>` to freeze the demo at that moment (simulate up to `t`, then hold) for screenshots.
- Timeline, starting with **three stones already stacked** on the boulder (a flat slab, a round stone, an egg):
- **0.0 to 0.4 s:** stillness, mist drifting, faint ripples.
- **0.4 to 1.0 s:** a fourth stone, a wedge, descends from above the frame and is lowered slowly onto the egg.
- **1.0 to 2.0 s:** it touches down **on one corner**, rocks two or three times with shrinking swings, and **holds** at a daring angle.
- **2.4 s:** a breath sweeps in from the left (the mist streams, the water darkens in a catspaw), the top two stones tip over together, bounce once on the boulder's edge and **splash into the river around 3.0 s** with droplets and spreading rings.
- **3.2 to 4.0 s:** the ripples fade, the wedge sinks out of sight into the deeper water, and the egg glides smoothly back up onto the stack, dripping, settling into its exact starting pose by 4.0 s, so the loop restarts cleanly.
- Pre-set the poses and the breath so the real physics gives this result every time; blending to the start poses in the last 0.8 s is allowed.
- Start moving within 1 second of loading. The demo is recorded in a slow software renderer: **the corner balance, the topple and the splash must read clearly at 15 fps**; keep particle counts modest in demo mode.
## Before you finish
Self-check against this list and fix anything that fails:
- Build a 10-stone cairn and leave it for 2 minutes: nothing jitters, creeps, sinks or rotates. Stand an egg on its tip: it holds only when it is truly centred.
- Push a stone's centre of mass just past its edge with Nudge and Rotate: it tips slowly then falls, never pops. Drop a cairn of 10: nothing tunnels, explodes or vanishes; everything rolls, splashes and sinks.
- Try every tool, slider (both extremes), switch and button, plus keys 1 to 5, Q, E, H, 0, C, M, Space and R, Pause, Slow motion, Cinema, and resizing to phone width with touch.
- Reach every milestone and trigger the heron.
- Sound: every action has its effect, nothing plays before the first gesture, mute and volume work, a big collapse never clips, a failing audio call never breaks the toy.
- `?demo=1` matches the timeline, loops cleanly, shows no UI and plays no sound; `?demo=1&t=1.5` freezes; `?test=1` exposes `window.__toy`.
- No console errors on WebGPU AND on WebGL2 (force the fallback to test it), and it stays smooth on a mid-range phone.
Put the honest balance and the gentle placing first. The moment a stone holds on a corner it shouldn't, and the moment it doesn't, is the whole toy.