Rainbow Jelly Lego

jellylego

OpusTerra
Opus$14.85 · 1h04m43s
Claude Opus 5.5$14.85 · 1h04m43s
Claude Opus 5.5 $14.85 · 1h04m43s
Winner
Terra$3.50 · 32m00s
ChatGPT-6.1 Terra$3.50 · 32m00s
ChatGPT-6.1 Terra $3.50 · 32m00s
CheapestFastest

Opus wins.

Remix in Claude

The prompt

Build **"Rainbow Jelly Lego"**: a real-time, interactive 3D set of **translucent rainbow jelly Lego bricks** on a baseplate that people **snap together**, **stack into towers**, **poke**, **smash** and **pour by the hundred**, as ONE self-contained HTML file with **synthesised sound**.

It should feel like a glossy toy commercial shot in macro: every brick is a real Lego brick in shape (studs, tubes, exact proportions), but made of gummy jelly. Snapping one on should be deeply satisfying (a click and a little squash), and a tall tower should sway like a stack of jelly, not stand like plastic.

## Tech

- three.js r170 with `WebGPURenderer` (automatic WebGL2 fallback). Load it with an importmap from jsDelivr: map "three", "three/webgpu" and "three/tsl" to `https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.webgpu.min.js`, and "three/addons/" to `https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/`. These are the **only** network requests allowed: no other libraries, fonts, images, models, textures or audio files. Use TSL node materials. Physics and simulation are your own code (no physics libraries).
- Start with `<!doctype html>`, `<meta charset="utf-8">` and a viewport meta tag. System font stacks only.
- It must run inside `<iframe sandbox="allow-scripts allow-pointer-lock">` (no `allow-same-origin`): `localStorage` and cookies throw there, so wrap every storage access in `try/catch` and keep values in memory. No `alert`, pop-ups, microphone or top-level navigation.
- Fixed simulation timestep (120 Hz) with bounded substeps, decoupled from frame rate; on a slow frame, drop simulation time rather than exploding. Let every brick and every built structure sleep once at rest (skip the solver); wake on any input or contact.
- Preallocate every buffer, geometry and material at start-up, sized for the caps below (300 bricks); nothing is created during interaction, pouring and smashing included.
- A quality scaler that lowers pixel ratio, then shadows, then post effects, then the loose-brick cap when frames get slow, never the physics feel. Target 60 fps on a mid-range phone **with 300 bricks on screen**.
- Known three r170 pitfalls, avoid them:
  - the scene background is drawn after transparent objects: draw the backdrop as a mesh (or give transparent objects `depthWrite: true`);
  - never `.clone()` a `CanvasTexture` (the clone uploads black);
  - create every `InstancedMesh` at its full count and never draw one with fewer than 2 instances (wrong-size uniform buffer, black screen): park unused instances out of sight at scale 0 instead of lowering `count`;
  - never let a helper overwrite a shared temp vector its caller still uses;
  - on WebGL2 an `InstancedMesh` of roughly 250-1000 instances keeps its matrices in a 16 KB uniform block and fails to compile: keep each instanced mesh under 250 (one per brick shape works).

## 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 skyscraper (Build) and the Earthquake; snapping bricks together (grid-exact, a click and a squash); the jelly sway of built structures; the jelly material (translucent, glossy, colour deepening with thickness); the rain of bricks piling up without jitter; the demo mode.
2. **Must work:** Stack, Smash, Tower, Pour, Shake, Empty, picking up and throwing bricks, rotating a brick before placing it, the sliders and colour presets, sound, the interface, the height record.
3. **Polish:** coloured light through the jelly, the Classic plastic switch, the Easter egg, the cinema mode.

Never ship a feature half-working: if something from tier 3 can't be done well, leave it out cleanly.

## The bricks

- **Real Lego proportions:** stud pitch 8 mm, brick height 9.6 mm, plate height 3.2 mm, stud diameter 4.8 mm and height 1.7 mm, wall thickness 1.2 mm, hollow underside with tubes (2-wide bricks) or a centre pin (1-wide). Gently rounded edges (0.4 mm), never razor sharp. Plain studs (no logo).
- **Shapes:** 2x4, 2x2, 1x4, 1x2, 1x1 bricks, plus 2x4 and 2x2 plates. One instanced mesh per shape, sharing one material.
- **Rainbow:** red, orange, yellow, green, blue, purple. A tower built with Tower or Stack cycles through them from the bottom up, so every tall build reads as a rainbow.
- **Baseplate:** a 32x32-stud plate (about 25.6 cm square) in a soft, slightly desaturated mint, opaque, matte plastic with studs, sitting on a light warm-oak table. The studs on the baseplate are real geometry (instanced), the snap grid.
- **Caps:** 300 bricks in total; past the cap the oldest loose brick at rest shrinks away smoothly. A brick that leaves the baseplate falls off the table edge and fades out.

## Physics

- **Bricks are rigid bodies with a jelly skin.** Each brick is a rigid box collider (plus its studs as a low lip) with mass, spin, friction and a little restitution, solved with PBD/XPBD at 120 Hz. The jelly feel is a **render-time squash spring** per brick: on every impact or snap it squashes along the contact normal and bulges sideways (volume kept), then springs back in about 200 ms with 2-3 visible wobbles. Never a full soft-body simulation per brick.
- **Snapping:** a brick released within about 3 mm of a valid grid position (studs aligned, rotation a multiple of 90°) on top of the baseplate or another brick is pulled into place over ~80 ms and **clicks**: it joins that structure. Bricks may overlap several bricks below (bridges, staircases, walls in a running bond) and connect to all of them.
- **Built structures sway like jelly:** every snapped connection is a **springy joint** (XPBD with compliance, angular and linear, at the stud contact area: a 1x1 connection is much weaker than a 2x4 overlap). A tower bends and wobbles as one soft column: a poke at the top makes it sway 4-6 times with decreasing amplitude and settle in 2-4 s; tall towers sag a little under their own weight. Low-frequency, heavy, no high-frequency jitter.
- **Breaking:** a joint whose strain passes a threshold (set by the **Grip** slider) unsnaps with a soft pop and the part above becomes a free body that tumbles, bounces and squashes. A strong poke or a smash breaks a structure into chunks, never all into single bricks at once (weak joints go first).
- **Loose bricks** collide with the baseplate, the studs, each other (spatial hash) and built structures. A loose brick landing exactly aligned on studs does not snap by itself (only placed bricks snap), so a pile stays a pile.
- **Piles are calm:** a pile of 300 bricks settles in 1-2 s and then sleeps completely: no jitter, no creeping, no slow sinking. Fast bricks never tunnel through the plate or a tower (cap their speed or sweep).
- **Stability is not optional:** no explosions, no bricks interpenetrating, no tower drifting across the plate. An untouched tower of 40 bricks stands forever (swaying settles, it sleeps).
- **Jelly** slider: how soft the joints and the squash spring are (stiff = quick small sway; soft = slow, deep sway, towers lean). **Grip** slider: how strong the joints are before they break.

## Tools

A tool picker with **Hand** (`1`), **Stack** (`2`) and **Smash** (`3`), plus a big round **Pour** button. A press that ends within 6 px and 450 ms counts as a tap. One finger acts; two fingers or right-drag orbit. Nothing is hover-only.

- **Hand:** tap any brick to poke it (the structure sways). Press and drag a loose brick to pick it up (it dangles a little and squashes in your fingers) and show a ghost of where it would snap; release to snap it there, or fling it (it flies with your release speed). Drag a brick that is part of a structure to tug it: the structure bends towards your finger and, pulled far enough, the brick unsnaps with everything on top of it. `F` (or a rotate button) turns the held brick 90°.
- **Stack:** tap a stud (on the plate or on a brick) to drop the next brick from the rainbow queue there: it falls a short way, snaps and squashes. The queue shows the next three bricks (shape and colour); a shape selector picks the shape (default 2x4).
- **Smash:** tap to punch: a soft shockwave at that point that pushes bricks away with force falling off over about 5 cm and breaks joints near it. A tap on the base of a tower makes it lean, hesitate and fall in a cascade.
- **Build:** `B` (or a big button) builds a **beautiful skyscraper** in the middle of the plate, by itself: about 150-170 bricks fly in from all around (each on its own short arc, slightly staggered) and click into place floor by floor, bottom to top, in about 8 seconds, the camera rising with it. The design is a slender **Art Deco setback tower**, about 30 cm tall: a hollow 8x8-stud base of 6 floors, a plate slab, a 6x6 shaft of 10 floors, a slab, a 4x4 upper section of 8 floors, a slab, a 2x2 crown of 4 bricks and a 1x1 spire of 4 bricks whose tip glows softly. Walls in a running bond (joints alternate floor to floor, like real masonry, so it holds together); the colours climb the rainbow section by section (red and orange base, yellow, green and blue shaft, blue and purple upper section, purple crown); the corner bricks and the slabs are **clear jelly** like glass, so every floor has glass corners. It must look like a real, elegant skyscraper in a toy commercial, not a stack of blocks. Build again with one already standing: it builds a second one beside it if there is room.
- **Earthquake:** `Q` (or a button) shakes the baseplate side to side at about the skyscraper's own sway frequency for 4 seconds, rising and fading, with a magnitude shown in a toast ("Magnitude 4.1"). Each press during or right after a quake goes one step stronger: the first makes everything sway like spaghetti and settle; the second cracks off the spire and crown; the third folds the skyscraper down floor by floor into a jiggling heap. Loose bricks hop and dance on the plate.
- **Tower:** `T` (or a button) builds a rainbow tower of 24 2x2 bricks at the centre of the plate, one brick every 0.12 s, each clicking on, the tower swaying more as it grows. A second `T` builds another next to it.
- **Pour:** tap the button (or `P`) to drop a handful of about 25 mixed bricks from above; hold it for a steady stream (about 40 per second) until you let go. They bounce, squash and pile up.
- **Shake:** `S` (or a button) jolts the table: everything jumps, towers sway hard, weak joints break.
- **Empty:** `E` (or a button) tilts the baseplate and sweeps every brick off the edge, out of frame; built structures slide off whole.

## Game

- **Height record:** the tallest standing structure (measured in bricks, standing for 2 s at rest) is shown live ("Tallest: 18") with the best of the session ("Record: 31"). Toasts once each: first snap, first tower of 10, 25 and 40, first collapse ("Timber."), 100 bricks on the plate.

## Easter egg

- **Rainbow chord:** stack six bricks by hand in rainbow order (red to purple, bottom to top) on one column: each snap plays the next note of a rising scale, and when the purple one clicks on the column does a bouncy wave from bottom to top, plays a chord and every brick glows for a moment. Toast: "Perfect rainbow." Once per column.

## Sound

- Synthesize everything with WebAudio; create the `AudioContext` on the first gesture only; a mute button and `M`.
- Snap: a crisp plastic click with a soft wet squish behind it, pitch rising a little with the tower height; unsnap: a soft pop; poke: a jelly boing whose pitch drops with Jelly; sway: a quiet low "wub" that fades with the motion; brick on brick: a light clack; on the plate: a muffled tap; Pour: a rattle made of many tiny clacks (aggregate them: never one voice per brick); Smash: a deep thud and a scatter; collapse: a cascade of clacks; Shake: a big rattle; Build: a quick rising run of snaps (aggregated: never one voice per brick) ending in a bright chime when the spire clicks on; Earthquake: a deep rumble that follows the magnitude; the Easter egg: the rising scale and a chord. Nothing clips or piles up (voice limit).

## Look

Aim for a premium toy commercial in macro, not a game asset.

- **Colour:** sRGB output, **AgX** tone mapping, exposure about 1.0, HDR internally: the jelly colours stay saturated and juicy, never washed out.
- **Lighting:** a procedural environment (`RoomEnvironment` through `PMREMGenerator`, no HDR files) for the glossy reflections, a large soft warm key from the front-left (daylight from a window), a soft fill, and a cool rim from behind that outlines the studs and edges and makes thin parts glow. Soft shadows (PCF soft, 2048, 1024 on phones) and a contact shadow under every brick and structure.
- **Coloured light through the jelly:** the shadows of bricks and towers on the baseplate are **tinted** by their colours, not grey (a cheap projected colour pattern blended into the shadow, brighter under thin parts), so a rainbow tower casts a rainbow shadow.
- **Materials:**
  - **Jelly bricks:** a translucent gummy look **without** a transmission pass per brick: physical with clearcoat 0.6, roughness about 0.15, a strong Fresnel sheen at grazing angles, a soft back-lit glow tinted by the brick colour, brighter where thin (stud tops, walls, edges) and deeper where thick (corners, the tube inside, overlapping bricks), so the hollow underside and tubes show faintly through the walls. Tiny surface dimples and faint roughness variation so it never looks CG-perfect. Never glass-hard, never opaque plastic.
  - **Classic plastic** (switch): the bricks turn into solid glossy ABS in the same colours (opaque, clearcoat, crisp highlights) but keep the jelly sway, which looks funnier.
  - **Baseplate:** matte mint plastic with a faint mould texture; **table:** light warm oak, matte.
- **Post:** a light vignette only. No full-screen bloom (glossy highlights would haze the scene milky), no heavy chromatic aberration or grain.
- **Saturation:** the six colours stay clearly distinct at the default exposure (yellow reads yellow, purple reads purple, not blue); never milky or pastel in the Rainbow preset.
- **Backdrop:** a soft studio gradient (warm cream to dusty peach) in a **mid-light tone, never pure white or pure black**.
- **Framing:** the default camera shows the baseplate and a 24-brick tower filling about 75% of a **square** frame, three-quarter view from slightly above.
- **Motion:** everything eases, overshoots a little and settles; nothing pops or teleports.

## Interface

- **Top left:** a big bold heading "Rainbow Jelly Lego." with a small subtitle "Snap it. Stack it. Watch it wobble."
- **Right:** a rounded control card "Brick box": the three tools as tiles with a small drawn icon and their key; the shape selector (seven small brick icons) and the rainbow queue (next three); a big **Build** button and an **Earthquake** button side by side; a big round glossy **Pour** button (hold for a stream); **Tower**, **Shake** and **Empty** buttons; **Jelly** (stiff to soft) and **Grip** (weak to strong) sliders with live values; **Colours** pills: Rainbow, Pastel, Neon (all bricks change together, smoothly cross-fading); switches for **Classic plastic** and **Slow motion** (¼ speed); **Reset** (empty baseplate, nothing else).
- **Bottom:** a one-line hint "Tap a stud to stack. Drag to build. Hold Pour." that changes with the tool (Smash: "Tap the base. Timber?") and fades after a few uses. A small counter "Bricks: 143 · Tallest: 18 · Record: 31".
- A status pill `WEBGPU · LIVE` or `WEBGL2 · LIVE`; toasts for milestones, each once. Collapses to a compact bottom sheet at phone width with Build, Earthquake and Pour always reachable; the UI never covers the tower.
- If neither WebGPU nor WebGL2 works, a clear, designed message.

## Camera and keys

- Orbit around the baseplate within limits (never under the table), zoom within limits; the camera eases up as towers grow so the top stays in frame. `R` reset, `Space` pause, `C` cinema (hide UI, slow orbit), `M` mute, `B` build, `Q` earthquake, `P` pour (hold for a stream), `T` tower, `S` shake, `E` empty, `F` rotate, `1`-`3` tools.
- Respect `prefers-reduced-motion`: softer UI transitions, slower cinema orbit; the physics still responds fully.

## Test hook

If the URL has `?test=1`, expose `window.__toy` with no visible change: `poke(x, y)`, `stack(gx, gz, shape)`, `smash(x, y)`, `build()`, `quake()`, `tower()`, `pour(n)`, `shake()`, `empty()`, `reset()`, and `getState()` returning `{ renderer, fps, bricks, awake, structures, joints, tallest, record, kineticEnergy, asleep }`.

## 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 and the cursor. Never create an `AudioContext`.
- One fixed quality preset, fixed seed, default camera, Rainbow colours, Classic plastic off.
- A deterministic loop restarting every 4.0 s of real time from the identical state (empty baseplate):
  - **0.0 to 2.0 s:** the skyscraper builds itself as a time-lapse: bricks fly in and click together floor by floor, bottom to top, the spire last.
  - **2.0 to 3.3 s:** a strong earthquake: the skyscraper sways like spaghetti, the spire and crown crack off and tumble down its side, bouncing on the plate.
  - **3.3 to 4.0 s:** everything shrinks away smoothly, back to the empty baseplate of 0.0 s.
- Frame the demo a little closer than the default camera so the skyscraper fills the square.
- Start moving within 1 s of load; the action must read clearly at 15 fps (the demo is recorded in a slow software renderer).
- Support `?demo=1&t=<seconds>` to freeze the demo at that time.

## Before you finish

Self-check against this list and fix anything that fails:
- Snap every shape by hand, rotated both ways, on the plate and on other bricks, bridging two bricks below: always grid-exact, never floating, never overlapping, always a click and a squash.
- Build the skyscraper: every brick lands exactly on its grid place, the walls interlock, it looks elegant from every angle and stands forever untouched. Earthquake it three times: sway, then cracks, then the fold-down; never an explosion.
- Build a 40-brick tower with Tower and by hand at Jelly stiff and soft, Grip weak and strong: it sways like jelly, settles and stands forever; poke it, tug a middle brick, smash the base: it breaks into chunks and collapses in a cascade, never explodes.
- Hold Pour until 300 bricks: still 60 fps on a mid-range phone, the pile settles and sleeps, nothing jitters, creeps or sinks, nothing falls through the plate, the oldest bricks fade out gracefully at the cap. Shake and Empty with a full plate.
- Every tool, slider, switch, colour preset, button and key; the height record; pause and resume; Cinema; resizing to phone width with touch.
- Sound: every action has its effect, Pour never turns into noise, nothing plays before the first gesture, mute works.
- It works inside `<iframe sandbox="allow-scripts allow-pointer-lock">` with storage blocked.
- `?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 the skyscraper, the snap and the jelly sway first. Watching the rainbow skyscraper click itself together and then wobble through an earthquake should be the best part.

More like this