← all topics

Flow Field

Canvas

Particles follow directions sampled from a Perlin noise field. The field evolves over time — increase evolution speed to watch it shift. Toggle the vector grid to see the underlying field.

Controls
mouse mode
6
1.5
1500
0.0003

concepts

Perlin noise

Smooth, continuous random function where nearby inputs give similar outputs. Generated by interpolating between gradient vectors at integer lattice points — no harsh jumps like Math.random().

noise → angle

The scalar noise output (−1 to 1) is multiplied by 4π to map onto angles. Larger multipliers create tighter swirls; smaller values produce wide, sweeping curves.

time evolution

Adding a slowly-incrementing offset to the noise Y-coordinate creates smooth temporal change — equivalent to moving through a 3D noise volume one horizontal slice at a time.

trails via alpha fill

A semi-transparent fill each frame leaves fading echoes of past positions. Lower alpha = longer memory. clearRect erases everything; fillStyle rgba(…, 0.08) fades it gradually.

mouse forces

Repel pushes particles radially outward from the cursor. Attract reverses that. Vortex applies the tangent vector — perpendicular to the radial direction — creating a local swirl that fights the noise field.

core pattern

// Each frame, move particle along the noise angle
const scale = detail * 0.0005;
time += evolution;

const angle = perlinNoise(
  p.x * scale,
  p.y * scale + time  // time offset drives evolution
) * Math.PI * 4;

p.x += Math.cos(angle) * speed;
p.y += Math.sin(angle) * speed;

// Trail: fade previous frame instead of clearing
ctx.fillStyle = "rgba(10,10,15, 0.08)";
ctx.fillRect(0, 0, w, h);