Motion: Fluids

Create beginner-friendly fluid-like visuals with soft field blending.

Example 1: Metaball Field

Code

let blobs = [];

function setup() {
  createCanvas(400, 400);
  noStroke();
  for (let i = 0; i < 4; i++) {
    blobs.push({ x: random(width), y: random(height), vx: random(-1.4, 1.4), vy: random(-1.4, 1.4), r: random(40, 70) });
  }
}

function draw() {
  background(20, 22, 30);
  for (const b of blobs) {
    b.x += b.vx; b.y += b.vy;
    if (b.x < 0 || b.x > width) b.vx *= -1;
    if (b.y < 0 || b.y > height) b.vy *= -1;
  }

  loadPixels();
  for (let y = 0; y < height; y += 4) {
    for (let x = 0; x < width; x += 4) {
      let field = 0;
      for (const b of blobs) {
        let d = dist(x, y, b.x, b.y);
        field += (b.r * b.r) / max(1, d * d);
      }
      let on = field > 1.1;
      const c = on ? color(255, 50, 145) : color(25, 27, 36);
      for (let oy = 0; oy < 4; oy++) {
        for (let ox = 0; ox < 4; ox++) {
          let i = 4 * ((y + oy) * width + (x + ox));
          pixels[i] = red(c); pixels[i + 1] = green(c); pixels[i + 2] = blue(c); pixels[i + 3] = 255;
        }
      }
    }
  }
  updatePixels();
}

Try this: Use more blobs and lower threshold for smoother merge.

Open sketch in new tab

Example 2: Advection-lite Trails

Code

let pts = [];

function setup() {
  createCanvas(400, 400);
  for (let i = 0; i < 300; i++) pts.push(createVector(random(width), random(height)));
  background(245);
}

function draw() {
  fill(245, 245, 245, 14);
  noStroke();
  rect(0, 0, width, height);

  stroke(255, 45, 140, 80);
  for (let p of pts) {
    let px = p.x, py = p.y;
    let a = noise(p.x * 0.008, p.y * 0.008, frameCount * 0.004) * TAU * 2;
    p.x += cos(a) * 1.8;
    p.y += sin(a) * 1.8;
    line(px, py, p.x, p.y);
    if (p.x < 0 || p.x > width || p.y < 0 || p.y > height) p.set(random(width), random(height));
  }
}

Try this: Change noise Z speed to alter fluid swirl tempo.

Open sketch in new tab

Resources