Flow Field
CanvasParticles 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.
concepts
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().
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.
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.
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.
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);