technique

Flow field

Build a grid of direction vectors (from noise, or from an attractor like the mouse), then advect many particles through it and draw their traced paths.

Also called: Noise-driven vector field · flow field · Flow Fields · flow fields

Run it

Tracing curves through a noise angle field field construction · Euler integration · step size vs. cell size
What it looks like when it goes wrong (4)
  • The integration step is larger than one field cell, so each step skips the field it was supposed to follow. The curves stop being smooth and break into straight dashes at odd angles.
  • Neighbouring cells decorrelate. A flow field only reads as flow when nearby points agree about direction — past that point it is just noise with extra steps.
  • Density without length. The field is invisible because no curve travels far enough to reveal where it is going; you get texture instead of structure.
  • The whole canvas samples nearly one value, so every curve points the same way. The result is combed hair — the classic sign the field is under-scaled rather than the algorithm being wrong.

Clean-room implementation — written from the described algorithm, not from source. Reuse policy

What it is

A grid covering the canvas, with an angle stored at each point. Drop a curve somewhere on it, look up the nearest grid angle, take a small step that way, look up again, repeat. Do that from many starting points and you get the sweeping, combed, current-like structure. Flow field is the parent technique here — everything else on this page (a fixed Perlin noise source, a distorted grid, a spaced-out curve set) is that same loop with exactly one piece changed.

How it works

Tyler Hobbs describes the loop directly:

We pick a starting point. We find a corresponding nearby point in the grid. We take the angle from that point in the grid, and take a small step in the direction of that angle. In our new location, we perform another lookup in the grid, and then repeat this process in a loop.

So there are three separable decisions, and only the first is about the field:

  1. Fill the grid. Any function of position that yields an angle works. Smooth noise is the common choice — Perlin Noise Flow Field is that choice fixed, and is written up as its own page — but noise isn’t required: varun.ca’s first attempt built the grid by rotating each vector toward the mouse location instead, scaled down by the distance from it. Swapping this fill rule changes the output’s character too; the lookup-and-step loop after it doesn’t care where the angle came from.
  2. Choose starting points. Hobbs treats this as its own design decision with several standard answers, not an afterthought: “All of your curves have to start somewhere.”
  3. Walk the field and draw each path as a polyline.

Parameters & tuning

Hobbs gives one number by name — “I usually use around 0.5% of the image width for my resolution.” He calls it “resolution” and states it as a percentage of image width, but the excerpt doesn’t say what the resolution is of; nothing here confirms it’s grid spacing, so don’t read that in.

He also states a second number the same way — “that’s usually around 0.1% to 0.5% of the image width” — but the sentence naming what “that’s” refers to isn’t in the excerpt this page has. It reads naturally as step length, since that’s the other per-step quantity the loop needs, but this page won’t assign a source’s number to a parameter it can’t confirm from what it was given. If you need the labelled figure, the source is linked below.

Hobbs also names a parameter directly — num_steps — and the excerpt says only that “The value of num_steps will affect the texture of the result.” It doesn’t say what num_steps counts or how the texture changes as you raise or lower it, so treat it as a knob worth sweeping experimentally rather than a documented one.

Where it’s been used

Fidenza is Tyler Hobbs’ 2021 Art Blocks series: thick, non-colliding curved rectangles traced through a flow field, coloured from 14 probabilistic palettes. Tyler Hobbs is also the author of the flow-fields essay this page’s algorithm and figures come from.

Variants & neighbours

The variations that matter divide by which of the three decisions they change, which is why the loop above is worth separating out:

Go deeper

Related, in brief

Covered here rather than as pages of their own — each is described by a single source, and gets promoted the moment a second one corroborates it.

enforce a minimum distance between curves

Stop growing a flow-field curve the moment it comes too close to any other already-drawn curve, to keep curves evenly spaced.

insert objects that distort the grid around them

Embed solid objects in the canvas that locally redirect nearby flow-field vectors, so traced curves wrap around them like fluid around an obstacle.

Inter-pass grid distortion

Perturb a flow field's angle grid slightly between successive drawing passes, so each pass's curves overlap the last without exactly repeating it.

Neighbouring-curve outline blending

Interpolate between two adjacent flow-field curves (with optional easing) to build a smooth polygon outline instead of a plain line stroke.

Connected to

Used in: Fidenza

Used to build: enforce a minimum distance between curves · Inter-pass grid distortion · Neighbouring-curve outline blending

Variants: insert objects that distort the grid around them · Perlin Noise Flow Field

Try it yourself

Hobbs states a number he calls "resolution": "I usually use around 0.5% of the image width for my resolution." Elsewhere in the same essay he gives another number the same way — "that's usually around 0.1% to 0.5% of the image width" — but the sentence naming what that number measures isn't part of the excerpt this page has. What would you guess it's measuring, and how would you find out for certain rather than assume?

Step length is a plausible guess, since it's the other per-step quantity the loop needs — but 'plausible' isn't 'confirmed', and this page states the number as a bare quote instead of a labelled row in a table precisely because assigning it to a parameter the excerpt never names would be an inference dressed as a fact. To settle it for real: read the source essay directly (linked below), where the antecedent is intact.

Replace the stored angles with `angle = atan2(y - h/2, x - w/2)` and run it. Then add a constant to the result: `+ 1.4`.

The first gives a radial burst — every curve flees the centre. Adding roughly a quarter turn rotates every direction off-radial by the same amount and the burst becomes a spiral. The traversal loop never changed; only the angle stored at each grid point did. That is the whole shape of the technique: a field of angles, plus a loop that follows them.


Revision 7 · 2 sources · Something wrong? Tell us.