TITLE: Lava Lamp — gel dynamics on a dark shelf PROMPT: Build a single self-contained HTML page that simulates a lava lamp at 60fps on a full-viewport canvas. Room background is a vertical gradient #150a1e to #2b0f3a to #0c0612 with a large radial warm bloom behind the glass whose radius and alpha scale with the heat value. The lamp is drawn in a local coordinate frame pivoted at the base: a chrome trapezoid base filled with a multi-stop silver gradient (#5a5f66, #f5f5f5, #a9aeb6, #eceef1, #8b9098, #f5f5f5, #4c5157), a #12121a plinth, an amber heater ring at 20-75 percent alpha, a chrome cap with three dark vent slots, and a stadium-shaped glass vessel (hand-written capsule path with two arcs) stroked at rgba(245,245,245,.34) with an inner vertical shading gradient, a soft left highlight ellipse and top/bottom ellipses. Inside the glass, 7-16 gel blobs are integrated with soft-body physics in local coordinates: gravity is rotated by the lamp tilt so the blobs genuinely slosh, each blob has a warm value that rises near the heater and falls at the top, buoyancy equals (warm - 0.44) times a heat-scaled constant, there is a damping drag of pow(0.12, dt), wall collisions against the capsule half-width, floor and ceiling bounces, volume-conserving merges when two blobs overlap by more than half their combined radius, and splits above 0.44R. The blobs are rendered as metaballs without filters: each is an additive white radial gradient with a near-solid core drawn with globalCompositeOperation lighter onto an offscreen canvas, the union is then recoloured with source-in using a vertical #ff6b9d to #ffb020 gradient, a hot amber core is added with source-atop, and the buffer is drawn twice into the clipped glass (once additively at 30-58 percent for bloom, once normally). Below the lamp, a mirrored, faded copy of the whole lamp plus a gradient fade creates a floor reflection; a contact shadow ellipse and a hairline shelf gradient sit at the base. Overlay chrome: a Georgia italic display title with the second word gradient-clipped in pink to amber, monospace kickers, a bottom-left control panel with a custom heat range input (0-1, updates the readout and the palette/speed), a pause button, live blob-count and fps readouts, and a right-side hint block. Interactions: pointer-drag tilts the lamp with a damped spring and real sloshing; clicking a blob pops it into six droplets that shrink and drift; space toggles pause. All shared state is declared before the boot calls; canvas is DPR-scaled with ctx.setTransform and resized. Respect prefers-reduced-motion by freezing the simulation. DESCRIPTION: A warm object in a dark room. The lamp stands on an implied shelf with its own faint reflection beneath it, chrome catching the light, glass edges softly rimmed. Inside, pink and amber gel masses rise slowly from the heater, swell, merge into one another, stretch, split, and sink again — never quite repeating. The heat control changes both the tempo and the colour temperature, from a cool rose simmer to a fast amber boil. Grabbing the lamp tilts the whole vessel and the gel visibly leans into the motion before settling back with a wobble. TECHNIQUES: filter-free metaballs via additive radial gradients on an offscreen canvas, recoloured with source-in and source-atop composite passes; soft-body blob physics with rotated gravity, buoyancy from a per-blob temperature field, volume-conserving merge and split; capsule collision solved analytically against a stadium half-width function; mirrored reflection pass with a gradient fade; chrome gradients built from multi-stop linear ramps; DPR-scaled canvas with setTransform; damped angular spring for lamp sway; pointer hit-testing through the inverse of the render transform; reduced-motion freeze. INTERACTION: Drag the lamp sideways to tilt and slosh it — release and it wobbles back to rest. Click any gel blob to pop it into a burst of droplets that shrink and drift through the vessel. Drag the heat slider to change buoyancy speed, blob colour temperature, the warm bloom and the heater ring. Press the pause button or the spacebar to freeze and resume the simulation; the blob count and fps readouts update live.