There is something deeply satisfying about writing mathematical formulas that blossom into generative artwork on an HTML5 canvas.

Flow Fields and Perlin Noise

By computing directional angles based on 2D noise coordinates, particles trace organic, ribbon-like trajectories:

function drawFlow(ctx, width, height) {
  for (let x = 0; x < width; x += 20) {
    for (let y = 0; y < height; y += 20) {
      const angle = noise(x * 0.005, y * 0.005) * Math.PI * 2
      ctx.beginPath()
      ctx.moveTo(x, y)
      ctx.lineTo(x + Math.cos(angle) * 15, y + Math.sin(angle) * 15)
      ctx.stroke()
    }
  }
}

The interplay of randomness and structure produces endless variations.