A live GLSL simulation of Rayleigh–Bénard convection — a fluid heated from below tiling itself into breathing hexagonal cells. This page documents the palette, the type, the shader, and the three iteration passes. Everything is procedural: no video, no images, one <canvas>.
Bénard is the fictional subject-site for the physics of self-organising heat. Its single job: let a visitor watch an invisible field become pattern. Warm a shallow fluid layer from below and, past a critical Rayleigh number (~1708), conduction gives way to convection — buoyant plumes rise, cool sheets sink, and the layer packs itself into hexagons roughly as wide as it is deep. Audience: anyone who has stared into a cooling bowl of soup and wondered why the skin cracks into cells. The page is cinematic and top-down — heat seen from directly above the plate.
Every colour is argued from the physics: a cold blue-black plate for the sinking sheets, warming through ember to a gold plume core. The bright accent is reserved for lines and marks; body copy uses a derived warm-ash ink that clears 4.5:1 on the dark ground.
Bricolage Grotesque carries the display: its slightly irregular, humanist grotesque shapes feel poured and settled rather than engineered — the right voice for a pattern the fluid chooses for itself. It runs at weight 800 for the wordmark and headline, 500–600 for sub-heads. Chivo Mono handles all readouts and body copy; a monospace reads as instrumentation, and its tabular figures keep the live Rayleigh number and ΔT gradient from jittering as they tick.
The convection field is a single full-screen fragment shader (raw WebGL, no library). Hexagonal cells come from a Voronoi diagram of a triangular lattice — the Voronoi of a triangular point set is a tiling of regular hexagons. Each pixel is transformed into lattice coordinates by the inverse basis Binv, and the nine surrounding lattice nodes are searched for the nearest jittered feature point (the plume centre).
A second 5×5 pass computes distance to the nearest Voronoi edge with the classic border metric dot(0.5·(a+b), normalise(b−a)) — that distance is the sinking sheet, drawn dark and cool. The temperature field is high at each cell centre, pulses per-cell on an independent phase, flickers with fbm to read as molten fluid, and occasionally flares into a brighter super-plume. The whole domain is advected by a slow curl-like fbm warp, so cells churn, merge and re-knit — the field never finishes reorganising. Temperature maps through the ramp above; a warm shoulder-ridge sharpens each hexagon wall.
Everything is guarded: DPR capped at 2 (rendered at ×0.9), sized to its container, resize-aware, the rAF loop pauses on document.hidden and out of view, WebGL context loss falls back to a static molten-gradient scene, and prefers-reduced-motion paints one settled frame with no loop.
overflow:hidden on the hero — scrollWidth back to 375.<h1>, no fallback, two-frame passive hash diff confirms the cells evolve on their own.