Jelly Jenga

jellytower

OpusSonnet
Opus$27.17 · 2h10m09s
Claude Opus 5.5$27.17 · 2h10m09s
Claude Opus 5.5 $27.17 · 2h10m09s
Winner
Sonnet$10.42 · 2h00m55s
Claude Sonnet 5.5$10.42 · 2h00m55s
Claude Sonnet 5.5 $10.42 · 2h00m55s
CheapestFastest

Opus wins. Opus builds the clearer, glossier tower and pulls blocks out cleanly while it sways; Sonnet's jelly is softer and simulated as real soft bodies, but its view is hazy, at well under half the cost.

Remix in Claude

Scorecard

Opus2Sonnet1

CriterionOpusSonnet
Looks like jelly JengaCrisp glossy blocks, warm light, coloured light pooling on the tableBright translucent blocks, but a soft focus haze over the whole view
Pulling a blockSlides out level with suction and a pop; tight blocks drag the towerSuck-pop pull; a few blocks near the bottom are stuck at normal speed
Jelly physicsRigid boxes with a visual wobble lattice on topSoft-body blocks with friction and a wet film when pulled slowly
CollapseSettles in 2.5 to 3 s, never through the tableCascades into a heap that rests in 5 to 6 s
Easter eggA gummy bear wriggles out, sits up and wavesA gummy bear block
Cost$27.17$10.42
Time2h10m09s2h00m55s
OverallWinner–

The prompt

Build **"Jelly Jenga"**: a real-time, interactive 3D Jenga tower of **54 translucent jelly blocks** that people **pull**, **poke**, **stack**, **shake** and **squish**, where every block wobbles, sticks and squelches against its neighbours, until the whole tower **sways, gives way and collapses into a jiggling heap**, as ONE self-contained HTML file with **synthesised sound**, rendered with **WebGPU** (WGSL) and an automatic **WebGL2** fallback.

It should feel like the real game made of gummy candy: the held breath of a slow pull, the tower leaning just a little, the suck-pop of a block coming free, and a collapse that is a joy to watch rather than a disappointment.

## 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:** a full 18-level tower that stands perfectly still at rest (no jitter, no sinking, no creep), jelly blocks that wobble and squish believably, the Pull tool with friction and suction, a dramatic but stable collapse; the demo mode.
2. **Must work:** Poke, Stack, Shake and Squish, Rebuild and Undo, blocks-pulled scoring with milestones, X-ray, sound, the control card, the Easter egg.
3. **Polish:** coloured light through the jelly onto the table, tiny suspended air bubbles, slow motion on collapse, the rebuild animation.

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, shaders (WGSL and GLSL) and CSS inline.
- **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`. Personal bests live in memory for the session.
- This must be a live simulation, not a video, a pre-baked animation, a static render or a 2D fake.
- Start the file with `<!doctype html>`, `<meta charset="utf-8">` and a viewport meta tag.

## The tower

- A classic Jenga tower: **18 levels of 3 blocks**, each level rotated 90 degrees to the one below, on a warm wooden table (oiled oak with visible grain, a soft edge falling away into a blurred, warm background).
- **Blocks:** proportions of a real Jenga block (length 3x its width, width 1.67x its height), with softly rounded edges. Each is a translucent fruit jelly: strawberry, lime, orange, grape, lemon, blueberry and cherry, assigned in a pleasing seeded pattern (never two identical neighbours). Colour deepens where the jelly is thicker, with a few tiny suspended air bubbles inside each block.
- Like real Jenga, blocks vary very slightly in height (about ±1.5%, seeded), so some are loose and some carry the load. Tight blocks are hard to pull; loose ones slide out easily. This is the game.
- Framing: a low three-quarter view, slightly above the table, the whole tower filling about 75% of the height of a square frame, with room on both sides for it to sway and fall.

## Physics

- **Every block is a soft body.** For example a small particle lattice per block (about 4x2x2 to 6x3x3 particles) solved with **XPBD** using shape matching or distance plus volume constraints, so blocks bend, bulge and wobble while keeping their shape. Render a smooth surface skinned to the lattice. Other methods are fine if they look and behave as described.
- **Contacts between all blocks and the table** with real friction (static and kinetic, set by the Table friction slider for the table and a fixed jelly-on-jelly value) and a light **adhesion / suction** between touching faces: a face resists peeling away, stretches a little, then lets go with a visible snap-back wobble.
- **Resting contact is the hard part.** An untouched tower must stand indefinitely with **no jitter, no sinking into the blocks below, no slow sliding and no drift**, at every softness setting (the softest setting sags and sways more but still stands). Let settled blocks sleep once at rest (skip the solver) and wake on any nearby contact or input.
- **Load:** the weight of the tower is carried through the contacts, so pulling a block that carries load drags its neighbours and the levels above, while a loose block slides out with almost no reaction.
- **Collapse:** when the tower loses support it should lean, hesitate, then fall in a satisfying cascade: blocks tumble, bounce softly, slide and pile into a jiggling heap that comes to rest within about 5 seconds. Never an explosion, never blocks interpenetrating, tunnelling through the table or flying off at speed.
- The tower counts as **down** when any block from level 2 or higher touches the table (except a block you placed there) or the tilt passes about 15 degrees and keeps growing.
- **Fixed simulation timestep** (for example 120 Hz) with bounded substeps, decoupled from frame rate. On a slow frame, drop simulation time rather than exploding.

## Tools

A tool picker with **Pull** (`1`), **Poke** (`2`), **Stack** (`3`), **Shake** (`4`) and **Squish** (`5`). The default tool is Pull. A press that ends within 6 px and 450 ms counts as a tap. Right-drag or two fingers orbit the camera; dragging the empty background orbits too.

### Pull
- Press on a block's end face to grab it there; drag to slide it out along its long axis (drag direction projected onto that axis). The hand pulls through a capped spring, never by teleporting the block.
- **Pull speed matters:** a slow, steady pull lets the block slip out while friction tugs gently at the blocks above; a fast yank drags neighbours with it and makes the tower sway, and a hard yank on a tight block can topple it.
- While sliding, the block squishes and stretches at the contact faces, the faces above and below visibly cling and peel (suction), and the block's free end wobbles.
- Once fully out, it comes free with a **suck-pop** and stays in your hand, dangling and wobbling. Release it over the top of the tower to place it (as Stack), anywhere else to set it down on the table.
- You may only pull from below the top complete level, as in the real game. Trying the top level gives a small shake of the block and a gentle "Not the top level" toast.
- Each fully pulled block adds 1 to **blocks pulled**.

### Poke
- Tap a block's end to push it in a few millimetres with a jiggle; hold and drag to push it further, until it pops out the other side. Pushing a tight block shoves the tower.

### Stack
- Drag a loose block (one you pulled and set on the table) onto the top of the tower, or tap the top to stack the most recent loose block. A translucent ghost shows the next free slot, crossed correctly over the level below. On release the block drops into place, squishes and wobbles, and the tower answers with a small sway.

### Shake
- Drag the table sideways: it slides on a spring and the tower sways, lags and catches up. A tap thumps the table: a short vertical knock that makes every block jump and jiggle. A strong shake can bring it down.

### Squish
- Press any block to squash it locally: it dents under the finger and bulges at the sides, neighbours jiggle, and pressing on the top level compresses the whole tower like a spring. Release rebounds with a wobble. Squishing never tears, never inverts and is always elastic.

Use pointer events with **pointer capture** so drags never drop, and support mouse, pen and touch (including a second finger on mobile without breaking the first drag).

## Game

- **Blocks pulled** is the score; the session's **best** shows next to it. When the tower goes down: toast **"Timber! 14 blocks."** (with the real count), plus **"New best"** when beaten, and the Rebuild button gently pulses.
- Milestone toasts (once per tower): "First block out", "5 blocks", "10 blocks", "Taller than it started" (level 19 begun), "18 blocks: you've done this before".
- **Rebuild:** blocks spring back level by level from the bottom with a soft plop each, in about 1.5 s. **Undo last pull:** restores the exact state before the last pull (snapshot of all bodies), including after a collapse caused by it.

## Easter egg

- One block per tower (seeded, never in the top three or bottom two levels) is a slightly cloudier jelly with a faint shape inside. Pull it fully out and hold it in the air: a tiny **gummy bear** wriggles out onto the block's end, sits up and **waves** at the camera with a small squeak, then climbs back in. X-ray never reveals it. 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.**

- **Pull:** a wet, rubbery squelch while sliding whose pitch and grain follow the pull speed; a high friction squeak on tight blocks; a round **suck-pop** ("thwop") when it comes free.
- **Poke:** a soft "blub" per tap. **Squish:** a low squelch that follows the press, a wobbly boing on release.
- **Stack:** a plop as it lands, then a low wobbling tone that decays with the block's actual wobble.
- **Shake:** a woody table rumble while dragging; a hollow wooden knock for each thump.
- **Collapse:** a cascade of plops and slaps, pitched by block size and impact speed, and one final big "splat" into the heap.
- **Game:** a soft two-note chime for milestones; a squeaky "hi!" for the gummy bear.

Rules:
- Create the `AudioContext` only after the first user gesture and 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 master gain into a compressor / limiter, no clipping. Cap simultaneous voices at about 16 so a 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 around the tower within limits (never below the table, never straight down); the wheel or a pinch zooms from the whole table down to a close-up of a single level. Double-click the background or press `0` to reset the view. The camera never moves on its own except in demo mode.
- **Keyboard:** `1` Pull, `2` Poke, `3` Stack, `4` Shake, `5` Squish, `X` X-ray, `U` (or Ctrl+Z) undo last pull, `R` rebuild, `S` slow motion, `C` Cinema, `M` mute, Space pauses or resumes, `0` resets the view.

## Rendering (WebGPU with WebGL2 fallback)

**Use 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. Show which one in the status pill: `WEBGPU · LIVE` or `WEBGL2 · LIVE`. No libraries: write both paths yourself, sharing scene data and simulation. Only if neither exists, show a clear, well-designed message.

Aim for a glossy candy macro photograph, not a game asset.

- **Jelly:** thickness-dependent absorption (Beer-Lambert style), screen-space refraction of the table and the blocks behind, Fresnel reflections, a crisp but controlled specular highlight that slides as the block deforms, and a soft inner glow where light passes through thin edges. Blocks seen through other blocks must look right, with no sorting pops (for example a thickness pass plus refraction of the opaque scene, or weighted blended order-independent transparency).
- **Light:** a warm key light from one side and a soft fill, soft shadows that stay attached as blocks wobble and fall, and **coloured light** cast through the jelly onto the table (a cheap caustic tint is fine).
- **X-ray:** blocks turn to a soft frosted look tinted by the load each one carries (cool blue for loose, through yellow, to hot red for most loaded), updated live from the contact forces, so you can see which blocks are safe to pull.
- **Post:** HDR with filmic tone mapping, a light bloom on highlights, a subtle depth of field on the far background, a light vignette. Keep the tower crisp.
- Build pipelines and preallocate every buffer at start-up (all blocks, contacts, particles). Never create shaders, pipelines or geometry during interaction. Handle resize; cap device-pixel ratio at 2.
- An automatic **quality scaler**: if the frame rate drops, reduce resolution, refraction, shadow and post-effect quality before ever touching the physics feel.

## Interface

A calm, light interface that stays out of the way. The tower is the hero, and UI must never cover it on desktop or mobile.

**Top left**
- Small caps: `POKEABLE · SPECIMEN 008`
- A large italic serif heading on two lines: *Jelly* / *Jenga.*
- Caption lines: "Slow hands." / "Steady table." / "It always falls."

**Top right:** a small live status dot with `WEBGPU · LIVE` or `WEBGL2 · LIVE`, a **speaker icon button** (with `ON` / `MUTED`), and `PAUSED` when paused.

**Right panel: control card "Tower"**

A **floating control card** about 240px wide, 20px corners, soft off-white, soft drop shadow, no hairline borders, plain system sans-serif, with a **strawberry-red accent**. 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; switches with the label left and the switch right; **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: **Pull**, **Poke**, **Stack**, **Shake**, **Squish**.
- Sliders: **Jelly softness** (firm to floppy), **Table friction** (slick to grippy), **Sound** (master volume), each with its live value.
- Buttons: **Rebuild**, **Undo last pull**, **Mute**.
- Switches: **Slow motion** (¼ speed), **X-ray**, **Cinema**.
- **Pause / Resume**.

**Bottom left:** a one-line hint per tool:
- Pull: "Grab a block's end and slide it out. Slow hands win."
- Poke: "Tap a block's end to push it through."
- Stack: "Drop a pulled block on top. Cross the layers."
- Shake: "Drag the table, or tap it for a thump."
- Squish: "Press any block. It always bounces back."

Under it, live readouts computed from the simulation: **blocks pulled** (and best), **height** (levels), **tilt** (degrees, from the top level's centre over the base). Values update smoothly, not every frame.

**Bottom right:** a collapsible **"How it wobbles"** section, 4 to 6 plain-English lines on the soft-body blocks, friction and suction, how the load travels down the tower, why loose blocks slide and tight ones drag, and how the sounds are synthesised.

**Toasts** appear top centre for milestones. **Cinema** (`C`) hides every piece of UI and the cursor; a tap without dragging, `C` or Esc brings it back. Respect `prefers-reduced-motion`: soften UI transitions and camera moves; the tower still responds fully.

## Test hook

If the URL has `?test=1`, expose `window.__toy` with no visible change: `setTool(name)`, `pull(level, index, distance, speed)`, `poke(level, index, depth)`, `stack()`, `shake(dx)`, `thump()`, `squish(level, index, amount)`, `rebuild()`, `undo()`, `setSlider(name, value)`, `setSwitch(name, on)`, and `getState()` returning `{ renderer, pulled, best, levels, tiltDeg, down, maxPenetration, maxSpeed, sleeping, fps }`.

## 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 tower, table and background are visible.
- One **fixed demo quality preset** (no quality scaler), X-ray off, default softness.
- **Sound is completely off:** never create an `AudioContext`, play nothing.
- A fixed camera at the default view, the tower filling the square frame.
- A deterministic loop (fixed seed, no randomness) that restarts every 4.0 s of real time from the identical state:
  - **0.0 to 0.6 s:** the full tower at rest, a faint jelly shimmer, light glowing through the blocks.
  - **0.6 to 2.0 s:** an invisible hand slowly pulls the block on the camera-facing side of level 8 straight out: it squishes, the faces above and below cling and peel, the tower above leans a few degrees with it.
  - **2.0 s:** the block comes free with a visible suck-pop wobble and hangs in the air beside the tower, jiggling; the tower sways back and forth twice.
  - **2.8 to 3.6 s:** the block glides smoothly back into its slot (a guided demo-only motion) and the tower settles.
  - **3.6 to 4.0 s:** everything at rest, identical to 0.0 s, so the loop restarts cleanly.
- Drive the simulation from real elapsed time with the fixed timestep, so the loop lasts 4 s even at low frame rates. Start moving within 1 second of the page loading.
- The demo is recorded in a slow software renderer: **the pull and the sway must read clearly at 15 fps**. Keep the demo cheap (lower lattice resolution and effect quality are fine if it still looks the same).
- Support `?demo=1&t=<seconds>` to freeze the demo at that time (for screenshots).

## Before you finish

Self-check against this list and fix anything that fails:
- Leave the untouched tower for 60 s at both softness extremes: zero jitter, zero sinking, zero drift, and it sleeps.
- Pull loose and tight blocks slowly and fast; pull 10+ blocks in a row carefully and stack them all; poke blocks through; squish the top; shake and thump the table; knock the tower down at least 10 times: every collapse is a cascade, nothing explodes, interpenetrates or leaves the table at speed, and the heap settles within about 5 s.
- Every tool, slider and switch at both extremes, Rebuild, Undo after a collapse, X-ray, Slow motion, pause and resume, Cinema, every key, the top-level rule, milestones, best score, the Easter egg, and resizing to phone width with touch.
- Sound: every action has its effect, nothing plays before the first gesture, mute and volume work, a collapse never clips or piles up, and a failing audio call never breaks the toy.
- `?demo=1` matches the timeline, loops cleanly, shows no UI and plays no sound; `?test=1` exposes `window.__toy`.
- No console errors or WebGPU validation errors on WebGPU **and** on WebGL2 (force the fallback to check), and it stays smooth on a mid-range phone.

Put a tower that stands perfectly still and the squelch of a slow pull first. The collapse should be the best part of losing.

More like this