Tearable Jelly

jellyblock

SonnetOpus
Sonnet$4.34 · 44m55s
Claude Sonnet 5.5$4.34 · 44m55s
Claude Sonnet 5.5 $4.34 · 44m55s
WinnerCheapestFastest
Opus$13.03 · 1h17m21s
Claude Opus 5.5$13.03 · 1h17m21s
Claude Opus 5.5 $13.03 · 1h17m21s

Sonnet wins. Both cubes stretch, rip, slice and smoosh back together. Sonnet looks more like real jelly (softer, see-through, bubbles, a rough torn hole) for a third of the cost; Opus pulls a better taffy neck before the rip but reads closer to a dense gummy.

Remix in Claude

Scorecard

Sonnet1Opus1

CriterionSonnetOpus
Looks like jellySoft and see-through with bubbles and a pale rimDeep glossy red, closer to a dense gummy; long glassy top highlight
Stretch and ripChunk rips off and leaves a rough, frosty holeCorner pulls into a thinning taffy neck, then rips
KnifeClean glassy halves that slump apart, slight stair-steppingFlat glassy cut faces, small notches at the rounded edges
Colour modesAll modes; Clear is faint, Glow looks flatAll modes; Clear looks more like glass or ice
Cost$4.34$13.03
Time44m55s1h17m21s
OverallWinner–

The prompt

Build **"Tearable Jelly"**: a real-time, interactive 3D **jelly cube** that people **poke**, **stretch**, **tear**, **slice**, **fling** and **smoosh back together**. Pull a face and it stretches out like taffy, pull too far and a ragged chunk rips off, drag a knife across it and it splits clean, throw the pieces and they bounce and keep wobbling, drop a piece back on the cube and it merges in, with **synthesised sound**, as ONE self-contained HTML file rendered with **WebGPU (WGSL)** and an automatic **WebGL2** fallback.

It should feel like the best block of jelly you were never allowed to play with at dinner: soft enough to dent, stretchy enough to pull, and so satisfying when it finally gives way that you immediately want to do it again.

**It must read as real jelly, never plastic.** This is the single most important requirement. Someone seeing one still frame, with no motion, must say "jelly" before anything else. A cube that looks like a shiny plastic toy, a glass block or a rubber eraser is a failed build, however well everything else works. See "Real jelly, not plastic" below.

## 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 material and a motion that read unmistakably as real jelly, never plastic (see "Real jelly, not plastic"); a stable volumetric jelly cube that wobbles believably and never explodes; Stretch that pulls out like taffy and Tear that rips off a ragged chunk at the right moment; torn pieces that are real soft bodies with their own wobble; translucent jelly that reads as a glossy dessert; the demo mode.
2. **Must work:** Poke, Knife, Fling and Smoosh, Reset, every setting (softness, tear strength, wobble, gravity, size, colours), sound, both renderers, the control card, the Easter egg.
3. **Polish:** stringy strands that thin and snap as a tear lets go, coloured light through the jelly on the floor, suspended fruit bits, Glow mode bloom, slow motion on a tear.

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 it with `<!doctype html>`, `<meta charset="utf-8">` and a viewport meta.
- **No external requests of any kind**: no libraries, CDNs, web fonts, images, textures or audio files. Generate everything procedurally in code (sound included). 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`. Records 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.
- **Test hook:** if the URL has `?test=1`, expose `window.__toy` (no visible change) with: `setTool(name)`, `poke(x, y, strength)`, `drag(x0, y0, x1, y1, ms)` (a drag through the same code path as a real pointer drag with the current tool, in canvas pixels), `cut(x0, y0, x1, y1)` (a knife stroke), `fling(piece, vx, vy, vz)`, `reset()`, `set(name, value)` for every slider, switch and colour option, and `state()` returning `{ backend, tool, pieces, pieceSizes, bondsBroken, volume, maxStretch, kinetic, busy, fps }` where `volume` is total jelly volume as % of the starting cube and `busy` is true while anything is still moving.

## The cube

- A single **jelly cube** with softly rounded edges (corner radius about 8% of the edge), sitting on a **glossy white plate** on a pale table in a soft studio (a seamless backdrop in a very light tint of the active colour), seen from a three-quarter view from above so the **top, front and right faces** all show. At the default size the cube fills about 50% of a square frame, leaving room for flung pieces.
- Translucent and wet looking, never plastic-shiny: colour deepens where the jelly is thicker, thin edges glow, a faint internal grain and a few tiny suspended air bubbles.
- **Cut and torn faces look different:** a knife face is flat, smooth and glassy; a torn face is ragged and lumpy, with little peaks where strands pulled out, slightly frosted and catching the light. Both are lit and coloured as jelly (the inside is the same jelly as the outside, never hollow, never an untextured cap).

## Real jelly, not plastic

Get this right before any feature beyond Stretch and Tear. Study how real gelatin dessert looks and moves, and build for that.

**How it looks**
- **Light passes through it.** Real jelly is translucent all the way through: you see the plate, the table and the backdrop through it, bent and blurred by refraction (index of refraction about 1.34 to 1.36, like water, not glass at 1.5). Thin parts (edges, corners, stretched strands, small chunks) are pale and almost clear; thick parts are deep and saturated. Colour comes from **absorption through the volume** (Beer-Lambert), never from a flat surface colour or a diffuse albedo.
- **It glows from inside.** Light entering the jelly scatters a little and comes out the far side, so the side away from the key light glows softly in the jelly's colour, and a bright caustic of coloured light lands on the plate in its shadow. The shadow itself is coloured and soft, never solid grey.
- **The surface is wet, not lacquered.** A thin, very smooth wet film: highlights are small, sharp and bright, with a strong Fresnel sheen at grazing angles, but **no broad glossy "clearcoat" sheen across whole faces**, no uniform specular over the body, no plastic rim of white along every edge. Keep the base surface dark and clear between the highlights so the colour inside does the work.
- **It is not perfect.** A very faint surface wobble in the normals (as if the top is still settling), tiny suspended air bubbles at different depths, a few faint internal streaks or grain, slightly rounded and softened edges that are never razor sharp. The cube is a moulded dessert, not a CAD box.
- **It sits like jelly.** Under its own weight the cube is a little wider at the base and its top edges very slightly rounded and slumped; it presses into the plate with a soft flat contact patch. A cube that balances perfectly crisp and rigid at rest reads as plastic.
- **Torn faces** look like real torn gelatin: lumpy, irregular, with a slightly frosted, light-scattering surface and little wet peaks; **knife faces** are flat and glassy with a wet sheen. Both are the same translucent jelly inside, never opaque, never hollow.

**How it moves**
- **Slow, heavy jiggle, not springy bounce.** Jelly wobbles at a low frequency (about 2 to 5 Hz for the default cube, lower when softer or bigger) with a visible lag between the base and the top: the bottom stops first and the top keeps swaying. Never the fast, tight "boing" of rubber or a bouncy ball.
- **It keeps its volume.** Pressed down, it bulges out at the sides; pulled up, it thins at the waist. Never shrinks or inflates.
- **It is soft everywhere.** A poke makes a deep, rounded dent with a ripple running across the surface. Every impact, landing and tear sends a wobble through the whole piece. Nothing moves as a rigid block, ever, except during Reset's final snap to the cube.
- **Bounces are dead and squashy.** A dropped piece splats, squashes a lot, rebounds only a little, then wobbles on the spot. It never bounces high like a rubber ball.

**Never**
- Opaque or near-opaque jelly (Clear, Glow and every preset stay translucent; cola is the darkest and still lets light through at its edges).
- A broad plastic sheen, Phong-looking blobby highlights, or a white specular rim on every edge.
- Grey or black shadows under the jelly, or a body lit like a diffuse solid.
- Crisp, rigid, perfectly square edges at rest.

## Jelly physics

- **A volumetric soft body that can break.** Build the cube from a lattice of small jelly cells (about 10 x 10 x 10 at the default size, roughly 1,000 to 4,000 tets or cells) connected by **bonds**, solved with **XPBD** (or shape matching) with volume preservation. Render a smooth, high-resolution surface skinned to the lattice (barycentric or trilinear embedding), never the lattice itself, except in X-ray mode.
- **Pieces:** whenever broken bonds separate a connected group of cells, that group becomes its own **piece**: its own soft body with its own surface, wobbling, colliding and bouncing independently. Find pieces with a connected-components pass on the bond graph after each break, never every frame.
- **Tearing:** each bond has a strength with a little seeded noise so tears run ragged instead of straight. A bond breaks when its stretch passes the **Tear strength** limit for long enough (a few ms), never from one bad frame. Breaks cascade naturally along the most stretched bonds, so a tear runs through the jelly rather than everything snapping at once. When the last bonds of a tear go, they thin into **sticky strands** that stretch and snap back (tier 3).
- **Stability is not optional:** no inverted cells (detect and recover), no explosions, no jitter at rest, no slow creep, no tunnelling through the plate, table or other pieces. Total jelly volume stays within a few percent of what it was before a break.
- **Fixed simulation timestep** (about 1/120 s) with bounded substeps, decoupled from frame rate. On a slow frame, drop simulation time rather than exploding.
- **Contact:** pieces collide with the plate, the table and each other with friction, a soft damped bounce and slight squash. Pieces that slide off the plate land on the table.
- **Wobble:** after release a piece wobbles several times with decreasing amplitude; the **Wobble** setting controls how long. Small pieces wobble faster and settle sooner than big ones.
- **Limits:** at most **48 pieces**. A tear or cut that would go past that, or would leave a piece smaller than one cell, merges the crumb into its nearest neighbour instead. Keep the simulation budget fixed: preallocate for the largest size and the piece cap.

## Tools

A tool picker with **Poke**, **Stretch**, **Knife**, **Fling** and **Smoosh**. The default tool is Stretch. A press that ends within 6 px and 450 ms counts as a tap. Right-drag or two fingers orbit the camera with any tool. Use pointer events with **pointer capture** so drags never drop, and support mouse, pen and touch.

### 1 Poke
- A tap presses a dent into the jelly under the finger that springs back with a wobble that ripples out across the piece. Holding presses deeper and the jelly bulges around the finger (volume preserved). Poke never tears.

### 2 Stretch (and Tear)
- Press on any surface point of any piece to grab it, then drag: the jelly pulls out locally like **taffy**, thinning near the grab point and bulging back at the base. The deformation must be local and follow the finger, never move or scale the piece rigidly.
- Pull further than the **Tear strength** limit and it **rips**: a ragged chunk the size of what you grabbed comes away in your hand, with strands snapping between it and the cube. Keep holding to carry the chunk; release to drop it, or release during a fast drag to throw it.
- Pulling gently and letting go always springs back. Grabbing near an edge or corner tears off smaller chunks than grabbing the middle of a face.
- Dragging the empty background with Stretch orbits the camera.

### 3 Knife
- Drag a line across the screen: a thin knife trail follows the finger, and on release the knife **slices clean through every piece it crossed** along the plane through the stroke and the camera's view direction. The cut breaks exactly the bonds crossing that plane and caps both sides with flat glassy faces. The two halves sag apart under their own weight and wobble.
- Strokes shorter than about 30 px do nothing. Cut pieces can be torn, flung or smooshed like any other.

### 4 Fling
- Grab any piece and throw it: it keeps the drag momentum, flies, squashes on impact, bounces, rolls and keeps wobbling once it lands. Pieces knock into each other. A piece flung off the edge of the table drops out of view and returns as a small jelly hop onto the plate a moment later, so nothing is lost.

### 5 Smoosh
- Grab a piece and drop it onto another piece (or tap two touching pieces): where they press together they **merge**, the seam softens and disappears over about half a second, and the two become one piece with re-formed bonds across the contact. A merged piece keeps its shape, wobbles once, and can be torn again.
- Pieces that rest pressed together for more than 3 seconds merge on their own only when Smoosh is the active tool.

### Reset
- `R` or the **Reset** button: all pieces slump, slide together into the middle of the plate and pull themselves back into one perfect cube with a squishy hop. Undo is not needed.

## Settings

- **Softness:** firm gummy to barely-set jelly. Changes stiffness smoothly without resetting anything; barely-set jelly sags a little under its own weight and stretches much further before tearing.
- **Tear strength:** how far it stretches before ripping, from "tears if you look at it" to "stretches to twice its length".
- **Wobble:** how long it keeps jiggling, from a quick settle to a long, lazy wobble.
- **Gravity:** from low (slow-motion, floaty bounces for clips) to normal.
- **Cube size:** small, medium, large. Changing it makes the old jelly slump into the plate and a fresh cube rise up out of it.
- **Colour**, as a section of its own:
  - **Clear:** colourless jelly with a faint blue-green tint at the thickest parts.
  - **Single tint** with a small colour picker (a hue wheel or a row of swatches drawn in code, plus a hue slider).
  - **Rainbow layers:** horizontal bands through the whole volume, so a tear or cut shows the layers inside.
  - **Rainbow swirl:** a 3D marbled swirl through the volume.
  - **Two-tone split:** two colours meeting along a diagonal plane through the cube.
  - **Presets:** strawberry, lime, blue raspberry, grape, orange, cola (cola is dark amber with tiny rising bubbles).
  - **Glow mode** (switch): neon jelly on a dark background, the jelly lit from inside with soft bloom, the plate and table dim.
  - **Fruit bits** (switch): small suspended pieces (berries, citrus segments, cherry halves) embedded in the volume. They move with the jelly, end up in whichever piece they were in, and are exposed on cut and torn faces. They never float free or stay fixed in space.
- Colour is a property of the **volume**, not the surface: every piece, cut face and torn face shows the colour of the jelly that was at that point.

## Easter egg

- If the user tears or cuts the cube into **at least 20 pieces** and then puts it back into **one piece purely by smooshing** (no Reset), the jelly gives a proud shiver, re-forms into a perfect cube with a glossy shimmer running over it, and a small badge appears: "Good as new. Nobody will know." Never hint at it in the UI.

## Sound

Every action has a **synthesised sound**, generated live with the **Web Audio API** (oscillators, filtered noise, envelopes). **No audio files, no samples.**

- **Poke:** a soft squish, deeper when held. **Stretch:** a rising wet creak following how far it is pulled.
- **Tear:** a ragged wet rip (crackly filtered noise) with a sticky snap as the last strands go; bigger tears sound deeper.
- **Knife:** a clean swish along the stroke and a soft schlup as the halves part.
- **Fling:** a whoosh, a wobbly thud on landing, and smaller bloops per bounce. **Smoosh:** a squelchy merge and a little pop as the seam closes.
- **Reset:** a slump, a slurp as the pieces slide together, and a bouncy hop. **Easter egg:** a happy wobbly chord.

Rules: create the `AudioContext` only on the first user gesture and never before; resume a `suspended` context on interaction; master gain into a compressor, no clipping; cap at about 16 voices so a cascade of breaks never turns into noise; wrap every audio call in `try/catch` so a failure can never break the toy. Sound is on by default; a **speaker button** and `M` mute it.

## Camera and keys

- **Camera:** right-drag or two fingers orbit within limits (never below the table), the wheel or a pinch zooms within limits, double-click the background or `0` resets the view.
- **Keyboard:** `1` Poke, `2` Stretch, `3` Knife, `4` Fling, `5` Smoosh, `G` Glow mode, `F` fruit bits, `X` X-ray, `C` Cinema, `M` mute, Space pauses or resumes, `R` resets.

## 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 or 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.

Aim for a close-up food photo of real gelatin dessert, not plastic and not glass. Everything in "Real jelly, not plastic" is a rendering requirement; this is how to get there.

- **Jelly:** render the jelly with **real thickness**: draw back faces into a depth or thickness buffer first, then front faces, and compute absorption from the distance light travels through the jelly (Beer-Lambert), so colour deepens where the jelly is thicker and thin edges and stretched strands go pale and bright. **Screen-space refraction** of the plate and backdrop through the jelly (IOR about 1.35, offset scaled by thickness), a soft wrap-around subsurface term for the back-lit glow, wet specular with Schlick Fresnel and a tight highlight (no broad sheen), a faint internal grain and a few tiny suspended bubbles at different depths. Opaque shading with an alpha value is not acceptable.
- **Caustics and shadow:** a soft, coloured, slightly brighter patch of light on the plate where light comes through the jelly, inside a soft coloured shadow (a cheap projected approximation is fine).
- **Volume colour:** sample colour from a 3D function of each vertex's **rest position** in the original cube, so layers, swirls, the two-tone split and fruit bits stay put inside the jelly however it is torn, stretched or merged.
- **Torn faces:** procedural ragged displacement and a slightly frosted, lumpy normal; **knife faces:** flat and glassy.
- **Light:** a large soft key light from upper left, a rim light, filmic tone mapping that never blows out the highlights, light bloom on the glints (stronger in Glow mode).
- **Plate and table:** glossy white ceramic on a pale table, with soft contact shadows that stay attached to every piece as it squashes and bounces, and (tier 3) coloured light through the jelly tinting the plate.
- Rebuild a piece's surface mesh only when its bonds change (a tear, cut or merge), never every frame, into preallocated buffers. Never create shaders or pipelines during interaction. DPR capped at 2. An automatic **quality scaler** lowers resolution, refraction and bloom before it ever touches the jelly feel.
- Only if neither WebGPU nor WebGL2 exists, show a clear, well-designed message explaining why.

## Interface

A light interface that stays out of the way; the jelly is the hero and UI never covers it.

**Top left:** small caps `POKEABLE · SPECIMEN 014`, a large italic serif heading on two lines: *Tearable* / *Jelly.*, and caption lines "Pull it." / "Rip it." / "Put it back."

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

**Right panel: control card "Jelly"**, a floating card about 240px wide with 20px corners, soft off-white (dark charcoal in Glow mode), a soft shadow, no hairlines, plain system sans, bold sentence-case title and section labels, and an accent colour taken from the active jelly colour. 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 monospace chips, colour options as round swatches and rounded pills, secondary buttons as light-grey chips, on/off switches with the label on the left, and **Pause / Resume** as a solid dark full-width pill. Collapsible to a small button; a bottom sheet with rounded top corners on narrow screens.

- Tools: **Poke**, **Stretch**, **Knife**, **Fling**, **Smoosh**.
- Sliders: **Softness**, **Tear strength**, **Wobble**, **Gravity**, **Sound**.
- **Cube size:** small / medium / large segmented control.
- **Colour:** Clear / Tint (with picker) / Layers / Swirl / Two-tone, the six presets as swatches, switches for **Glow mode** and **Fruit bits**.
- Switches: **Slow motion** (1/4 speed), **X-ray** (the lattice and broken bonds), **Cinema**.
- Buttons: **Reset**, **Pause / Resume**.

**Bottom left:** a one-line hint per tool:
- Poke: "Tap to poke. Hold to squish."
- Stretch: "Grab and pull. Pull too far and it rips."
- Knife: "Drag a line across the jelly to slice it."
- Fling: "Grab a piece and throw it."
- Smoosh: "Drop a piece onto another to merge them."

Under it, live readouts from the simulation: **pieces**, **volume** (% of the starting cube), **stretch** (maximum bond strain, %), and **record** (most pieces this session). Values update smoothly, not every frame.

**Bottom right:** a collapsible **"How it tears"** panel, 4 to 6 plain-English lines: the lattice of cells and bonds inside, how a bond breaks when stretched too far, how the knife cuts along a plane, how pieces are found, how smooshing re-forms bonds, how the sound is made.

**Toasts** top centre for firsts: "First tear!", "First slice!", "10 pieces", "Back in one piece". **Cinema** (`C`) hides all UI and the cursor; a tap without drag, `C` or Esc brings it back. Respect `prefers-reduced-motion` (soften UI transitions and camera moves); the jelly still responds 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** and the cursor. One fixed quality preset (no quality scaler), medium size, default softness and tear strength, the **strawberry** preset with **Rainbow layers** off and Fruit bits off, the fixed default camera with the top, front and right faces showing.
- **Never create an `AudioContext`**, play nothing.
- Deterministic, no randomness (fixed seeds for bond noise); restart every 4.0 s of real time from the identical state; drive the simulation from real elapsed time with the fixed timestep so the loop lasts 4 s at any frame rate.
- Timeline:
  - **0.0 to 0.7 s:** the cube drops a short way onto the plate, squashes and wobbles.
  - **0.9 s:** a poke dents the front face; the ripple spreads across the cube.
  - **1.4 to 2.4 s:** an invisible hand grabs the top-right front corner and pulls it up and outward like taffy; at about **2.2 s** it rips off with strands snapping, the most satisfying moment.
  - **2.4 to 3.2 s:** the torn chunk is released, falls onto the plate beside the cube, bounces and wobbles; the cube jiggles from losing its corner.
  - **3.2 to 3.8 s:** the chunk hops back onto the cube's torn corner and smooshes in, the seam closing.
  - **3.8 to 4.0 s:** everything settles to exact rest, matching 0.0 s.
- Start moving within 1 s. It is recorded in a slow software renderer: **the stretch, the rip and the bounce must read clearly at 15 fps**.
- 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:
- **The jelly test:** take still frames at rest, mid-wobble and right after a tear, in Clear, strawberry, cola, Rainbow layers and Glow mode. Each must read instantly as real jelly: the plate visible and bent through it, colour deep in thick parts and pale at thin edges, a coloured glow on the far side, small wet highlights and no plastic sheen, a slightly slumped base. If any frame could pass for plastic, glass or rubber, fix the material before anything else. Watch the motion too: slow, heavy, lagging jiggle and squashy, dead bounces, never a springy boing.
- Stretch from the middle of every face, every edge and every corner, gently (always springs back) and hard (always tears). Tear the same cube 30 times, slice it 10 times, fling everything, smoosh it all back: never an inverted cell, an exploded or hollow piece, a piece through the plate, jitter at rest or a crash. The piece cap and crumb merging hold.
- Knife strokes from every camera angle, across one piece and across several at once.
- Every setting at both extremes (barely-set and firm, weak and strong tear, short and long wobble, low and normal gravity), every size, every colour mode and preset, Glow mode and Fruit bits on torn and cut faces.
- Every tool, slider, switch, button and key (1 to 5, G, F, X, C, M, 0, Space, R), pause and resume, Slow motion, Cinema, resizing to phone width with touch, the Easter egg by hand.
- Sound: every action has its effect, nothing before the first gesture, mute and volume work, a cascade of tears 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=2.2` freezes mid-rip; `?test=1` exposes `window.__toy`.
- No console errors or WebGPU validation errors on WebGPU AND on the WebGL2 path, and it stays smooth on a mid-range phone with 48 pieces.

Put the real-jelly look and feel first, then the stretch and the rip. It should be the jelly people keep tearing apart just to put it back together.

More like this