Skip to content

No.133 · Backgrounds

Ripple Tank

A shallow tank of water running a real wave equation: move across it to leave a wake, click to drop a stone, and every ring spreads, reflects and bends the tiled floor from exactly where it started.

The prompt

Written for the variant you picked above: Ink

Build an interactive water background from a real 2D wave equation. Simulation (CPU): a heightfield grid at one cell per 5 CSS px, two Float32Arrays swapped each step, a Verlet step next = (2h − previous + 0.3 × L) × 0.993, where L is the isotropic 9-point Laplacian (4 × edges + corners − 20h) / 6 so rings stay round. Step at a fixed 8ms rate (catching up at most 5 steps a frame) so waves travel at the same speed on any display. Disturbances push a Gaussian disc down: the pointer leaves a wake along its path (samples every 1.5 cells, amplitude growing with speed), a click drops a stone (radius 2.6, amplitude 2.2), and when idle a small raindrop falls every 0.65–1.55s. Edges are fixed at zero, so rings reflect. Rendering (WebGL1): upload the heightfield each frame as a 16-bit value split across a LUMINANCE_ALPHA texture (high byte, low byte — 8 bits alone shows as grid noise in the shading) with LINEAR filtering, so a coarse grid renders smoothly at full resolution. In the fragment shader take central differences for the slope and a Laplacian for curvature. Draw a tile grid on the floor, displaced by the slope (refraction); brighten where the surface curves inward (light focusing) and darken where it spreads; add a specular highlight from a fixed light. Vignette and dither. Pause entirely offscreen or in a hidden tab. Under reduced motion, place three stones, advance 150 steps and draw one still frame. Colours are a prop [deep, floor, tile, highlight]; a light flag inverts the caustic shading so troughs darken instead of brighten on light grounds. Selected variant — Ink: Colours [#05070b, #0f1724, #2a3a52, #cfe0ff], light=false: dark ink water with pale blue highlights.

Notes

Interaction
Move across the surface to leave a wake; click or tap to drop a stone. Raindrops fall while you're idle.
Motion
Wave equation at 125 steps/s with 0.993 damping; rings take about 3s to die away.
Accessibility
The canvas is aria-hidden and decorative, with content above it. Reduced motion shows one still frame of settled rings.
Responsive
The grid follows the container size at 5px cells; rendering is capped at 1× DPR (0.75× on touch).
On touch
Tap to drop a stone; dragging leaves a wake until the browser takes over the scroll.

Featured

301 components