A full-screen fluid simulation: the pointer pours luminous ink into dark water. Until you touch it, an idle "ghost hand" draws slow curls and an occasional burst, so the page is alive at first sight.
How it works
- Stable fluids on the GPU. The approach from GPU Gems chapter 38 (Jos Stam's stable fluids), written from scratch in raw WebGL2 and GLSL ES 3.00 with no engine. Velocity, pressure and ink live in half-float textures that are rendered into in turn ("ping-pong"), and every pass is one full-screen triangle.
- Per frame: curl, vorticity confinement (keeps small eddies alive), divergence, pressure (20 Jacobi iterations on the high tier, 10 on the light tier, with the previous pressure decayed as a warm start), gradient subtraction, then semi-Lagrangian advection of velocity and of the ink. Where only 32-bit float textures render and they cannot be filtered, advection does its bilinear filtering by hand.
- Splats: every pointer and every touch point adds a Gaussian push of velocity along its motion and a drop of ink in the palette colour; the faster the stroke, the brighter the ink (capped). Mirror copies each splat into a 2, 4 or 6-segment kaleidoscope around the centre.
- Light: the ink is read as a height field to get fake normals, lit by a key light with a tight specular and a rim term for a glossy, wet look. A bloom (soft-knee bright pass and a mip chain blurred down and back up) and radial light shafts are added, then a filmic curve, gamma and dithering against banding in the dark gradients.
Performance
- Grid 256 cells on the short side (128 on the light tier), ink 1024 (512). Pixel ratio capped at 2 (1 on the light tier); the light tier also skips the light shafts.
- A small governor watches frame times and drops to the light tier once the smoothed frame time stays over 22 ms for 2 seconds. The time step is capped at 1/60 s.
- The loop runs only while the canvas is on screen and the tab is visible. A lost graphics context shows a "Tap to restart the ink" state that rebuilds the simulation.
- The palette, splat, mirror, grid-size and governor maths are pure functions with unit tests.
Reduced motion
No ghost hand and no automatic bursts. The page opens on a still, composed ink bloom (the opening splats are settled offscreen), and the water moves only while you draw or press a key, then stops.