Code

D3.js

Generative Art

Expert Animated flow-field using sine-harmonic noise to steer 600 particles across a dark canvas. Each particle draws a short line per frame — colour mapped to its Y position via d3.scaleSequential and stroke-width by distance from centre via d3.scalePow. DOM is pruned automatically to keep rendering smooth.

// Colour: D3 sequential scale over palette
const color = d3.scaleSequential(
  d3.interpolateRgbBasis(palette)
).domain([0, height]);

// Stroke-width: power scale from centre
const strokeScale = d3.scalePow()
  .exponent(0.6)
  .domain([0, maxDist])
  .range([0.3, 1.8]);

// Flow-field angle at (x, y, time)
const angle = (x, y, t) =>
  Math.sin(x / W * 3.1 + t * 0.007) * Math.PI +
  Math.cos(y / H * 2.7 + t * 0.005) * Math.PI +
  Math.sin((x/W + y/H) * 4.3
           + t * 0.009) * Math.PI * 0.5;

// Animate — draw trail segments each frame
const animate = () => {
  for (const p of particles) {
    const a = angle(p.x, p.y, frame);
    p.x += Math.cos(a) * speed;
    p.y += Math.sin(a) * speed;

    svg.append('line')
      .attr('x1', px).attr('y1', py)
      .attr('x2', p.x).attr('y2', p.y)
      .attr('stroke', color(p.y))
      .attr('stroke-width',
            strokeScale(dist));
  }
  requestAnimationFrame(animate);
};
Key APIs & Techniques
  • d3.scaleSequential(interpolator) — maps a continuous domain to a colour interpolator
  • d3.interpolateRgbBasis(colours) — smooth spline interpolation through an array of colours
  • d3.scalePow().exponent() — power scale for non-linear stroke-width mapping
  • Flow-field — each pixel has an angle derived from overlapping sine waves; particles follow it
  • Trail rendering — one <line> per particle per frame accumulates into a painting
  • DOM pruningd3.selectAll().filter().remove() keeps the SVG node count bounded
  • NgZone.runOutsideAngular() — avoids triggering Angular change detection on every animation frame