Glyph Field
Glyph Field

Glyph Field — an interactive monospace cursor field

Canvas 2D · stable fluid · no dependencies

A monospace grid samples a slow-moving field and picks one character per cell. The pointer doesn't paint on that grid — it pushes a fluid underneath it. The flow carries the picture, curls around itself, and lets go.

Move to stir the flow  ·  Click to burst a ring

14 px
34 px
1.6 s
0.50
Response
Glyph set

Anatomy

A field, a fluid, a character

Nothing here is a particle system, and nothing is stamped. Every frame evaluates a scalar field, advances a fluid simulation that the pointer has pushed forces into, and turns the sum in each cell into a character. The grid never moves — only what is printed in it changes, which is why the whole thing reads as type rather than as graphics.

The canvas is fixed to the viewport and the page floats above it on a perforated veil, so the field never stops below the hero — it keeps running under the text, and the small openings punched through the veil are live windows onto it. The pointer is tracked page-wide, so the field answers wherever you move, including here.

Pass 1 — Field

A continuous value

Two sine waves warp a third. Each cell asks the field for a number between −1 and 1 at its own coordinates and the current time.

Pass 2 — Fluid

Velocity carries density

The pointer injects velocity over a small radius. Advection carries the density along it, a pressure solve keeps the flow divergence free, and dissipation drains both.

Pass 3 — Glyph

Quantised to a character

The field is sampled through the flow — the velocity drags the sampling point — then the density is added and the sum is mapped onto the glyph ramp.

Parameters

What each dial actually changes

Every dial remembers what it shipped with: a control that is off its default turns blue in the head, and a double-click on it — or Esc while it has focus — puts it back. The deck writes straight into the render state — no rebuild, no re-layout except when the cell size changes, which resizes the fluid grid with it. The fixed constants live in the source: velocity dissipation 1.25/s, diffusion 0.16, six Jacobi iterations, force scale 0.5.

ControlVariableRangeEffect
Cell sizefontSize8 – 26 pxSets the type size; the column width is then measured from the font, so the grid stays exactly monospaced.
Force radiusradius12 – 90 pxHow wide a patch of velocity each splat writes. Small is the point: the spread you see is the fluid's, not the brush's. Falloff is smoothstepped to zero, so the injection has no rim.
Wake lifelife0.2 – 5 sDissipation time for the density, applied as 1 / (1 + dt / life) so it is the same wake at 30fps and at 120.
Driftflow0 – 1.5Time multiplier for the field. Zero freezes the background and leaves only the pointer alive.
Responsemode3 modesWake pushes along the stroke; Repel pushes radially outward from it; Reveal darkens the field so only what the flow carries prints.
Glyph setramp4 setsThe ordered string of characters. Index 0 is a space, so low values leave the cell empty.

Source

Forces in, glyphs out

The pointer never touches a cell directly. It writes velocity into a grid; advection, a pressure solve and dissipation do the rest, and the glyph pass reads the picture back through that flow. Rows are printed one string per glyph-and-colour bucket rather than one fillText per cell — dozens of calls a frame instead of thousands.

glyph-field.js — core