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.

Scroll
I · The claim

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.

II · The solver

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.

III · The bodies

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.

— bodies drawn this frame, out of a fixed pool of 65,536. The pool never changes size; a quality governor changes how much of it is drawn, and the number above is read from the same function that draws them, so it cannot disagree with the picture.
IV · The colour

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.

V · The 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.

EMBERFALL · Navier–Stokes particle forge · WebGL 2 · single file · zero network requests
solver: 19 programs · ping-pong RGBA32F/16F · vorticity confinement · Jacobi Poisson
palette: GiveMePrompts spine — cyan leads, green edges, pink punctuates, prussian as air
every figure on this page is read from the running engine, never from a constant

Emberfall

— of — drawn
— grid · — · —

Commission a build admin@givemeprompts.com
Recipe
Parameters
Frame time

now — worst — —

—

last 58 frameshalf-scale —

Engine
Frames / s
—
Frame
—
Bodies drawn
—
Bodies in pool
—
Solver grid
—
Jacobi sweeps
—
Draw calls / frame
—
Shader programs
—
Device pixel ratio
—
Quality tier
—
Sim time
—
Renderer
—

true-black ground —
art-only framebuffer · Rec.709 luma < 0.05

Keys
Htake the wordmark away
Prainbow ⇄ ember
spacehold the simulation
1 – 4load a recipe
Sexport a PNG plate
Rreignite the pool

← Lab