Emberfall
Sixty-five thousand bodies, advected by an incompressible velocity field that is solved on the GPU every single frame. Nothing here is a recording. The picture you are about to scroll through is being computed while you read it.
Drag anywhere to stir the field. Press H to take the type away.
A fluid is the only thing that draws itself.
Most of what looks like generative art on the web is a recording being replayed, or a noise function being sampled once per frame and thrown away. This is neither. There is a velocity field here, and it is real: a grid of vectors, integrated, made divergence-free, and read back by every body in the pool each frame. The bodies do not decide where to go. The field decides, and they go.
That distinction is the whole piece. A noise function sampled per frame has no history — the frame before this one did not constrain it. A solved field does. The filaments in the upper right of this plate are not a texture; they are the visible residue of a computation that happened sixty times a second while you were reading the last sentence.
Seven passes, and one of them is the reason it moves.
It is Stam's stable-fluids loop, run on a grid deliberately decoupled from the display. Each step: semi-Lagrangian advection, a vorticity-confinement pass, then divergence, Jacobi sweeps of the Poisson equation, and a gradient subtract.
The step worth naming is confinement. Semi-Lagrangian advection is stable but diffusive — it eats exactly the small, fast structure that makes fluid look like fluid. Confinement measures the curl and feeds its gradient back in as a force, so the fine swirls are restored every frame instead of dissolving. Without it this is smoke. With it, it folds.
The pressure solve is the other load-bearing piece. It is what makes the field divergence-free to solver tolerance, and that is why trails fold into one another instead of draining into sinks. You can see the seam where two fronts meet and pass through; nothing collapses.
Two textures, and no read-back.
Every particle lives in two floating-point textures — position, age and lifetime in one; velocity, seed, species and heat in the other. A single fullscreen pass reads the velocity field and an analytic curl field, integrates, and respawns spent bodies on an inflow cone rather than on a ring around a point.
Nothing is read back to JavaScript. The host's per-frame work is a few uniform writes and a draw-call count. The simulation is not a CPU job that a frame budget is fighting; it is nineteen shader programs on textures, and the page you are reading is just the window it is visible through.
The hue is a decision, not a temperature.
A blackbody ramp makes hue a scalar of temperature, which means the coolest, largest region of the image sets the dominant hue and no accent can outrank its neighbours. The ramp's own shape forbids a hierarchy that doubles back. This is not that.
Each body carries a permanent species id, a fixed share of the pool is keyed to each band, and hue is assigned by the species rather than by the heat. Proximity to the source does not move it. The flow decides where the colour is; it does not decide what the colour is.
Cyan leads and holds the broadest band. Acid green is the edge — a hard thin band, not a fill. Pink is narrow and loud, and stays narrow on purpose: an accent that owns the frame stops being the thing the eye goes to. Prussian survives only as air, a thin desaturated rim over the true-black ground.
What is measurable is printed. What is a judgement is not.
The plate is composited against a true-black ground, and the number of pixels that sit below perceptual black is a live reading — it opens up as the plume develops and floods as it is stirred, because this is a running simulation and not a picture of one. It is reported, with its definition, every time it is asked for.
Frame time gets the same treatment: one unit, one axis, with the axis printed next to the reading so the two can be checked against each other. An instrument that cannot be checked against itself is decoration.
There is a forge behind the corner of this page. Ten parameters, four recipes, the full telemetry, the scope and a PNG plate at the drawing buffer's own resolution. It is closed by default, on every screen, because a page that opens with its own settings dialog is a settings dialog.