134 lines, no comments ยท 1,341 tokens, written in 13 seconds for $0.027


  1  const particles = [];
  2  const PARTICLE_COUNT = 900;
  3  let fieldScale = 0.0028;
  4  let timeOffset = 0;
  5  
  6  function setup() {
  7    createCanvas(windowWidth, windowHeight);
  8    pixelDensity(1);
  9    colorMode(HSB, 360, 100, 100, 100);
 10    background(225, 45, 7);
 11    blendMode(ADD);
 12  
 13    for (let i = 0; i < PARTICLE_COUNT; i++) {
 14      particles.push(new Particle(random(width), random(height)));
 15    }
 16  }
 17  
 18  function draw() {
 19    blendMode(BLEND);
 20    noStroke();
 21    fill(225, 45, 7, 7);
 22    rect(0, 0, width, height);
 23    blendMode(ADD);
 24  
 25    const pointerActive = mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height;
 26  
 27    for (const p of particles) {
 28      p.followFlow();
 29      if (pointerActive) p.reactToPointer();
 30      p.update();
 31      p.display();
 32      p.wrap();
 33    }
 34  
 35    timeOffset += 0.0025;
 36  }
 37  
 38  class Particle {
 39    constructor(x, y) {
 40      this.pos = createVector(x, y);
 41      this.prev = this.pos.copy();
 42      this.vel = p5.Vector.random2D().mult(random(0.2, 1.2));
 43      this.acc = createVector();
 44      this.maxSpeed = random(1.2, 3.4);
 45      this.hueShift = random(-28, 28);
 46      this.weight = random(0.35, 1.45);
 47    }
 48  
 49    followFlow() {
 50      const n = noise(
 51        this.pos.x * fieldScale,
 52        this.pos.y * fieldScale,
 53        timeOffset
 54      );
 55      const angle = n * TAU * 3.2 + sin(timeOffset * 3) * 0.3;
 56      const force = p5.Vector.fromAngle(angle).mult(0.055);
 57      this.acc.add(force);
 58    }
 59  
 60    reactToPointer() {
 61      const pointer = createVector(mouseX, mouseY);
 62      const delta = p5.Vector.sub(pointer, this.pos);
 63      const d = delta.mag();
 64  
 65      if (d < 180 && d > 1) {
 66        delta.normalize();
 67        const strength = map(d, 0, 180, 0.16, 0);
 68        const tangent = createVector(-delta.y, delta.x).mult(strength * 1.8);
 69        delta.mult(mouseIsPressed ? -strength * 2.2 : strength * 0.55);
 70        this.acc.add(delta).add(tangent);
 71      }
 72    }
 73  
 74    update() {
 75      this.prev.set(this.pos);
 76      this.vel.add(this.acc);
 77      this.vel.limit(this.maxSpeed);
 78      this.pos.add(this.vel);
 79      this.acc.mult(0);
 80    }
 81  
 82    display() {
 83      const speed = this.vel.mag();
 84      const baseHue = map(this.pos.x, 0, width, 175, 315);
 85      const hue = (baseHue + this.hueShift + frameCount * 0.08) % 360;
 86      const alpha = map(speed, 0, this.maxSpeed, 15, 55);
 87  
 88      stroke(hue, 65, 100, alpha);
 89      strokeWeight(this.weight);
 90      line(this.prev.x, this.prev.y, this.pos.x, this.pos.y);
 91  
 92      if (random() < 0.008) {
 93        noStroke();
 94        fill(hue, 35, 100, 30);
 95        circle(this.pos.x, this.pos.y, random(2, 6));
 96      }
 97    }
 98  
 99    wrap() {
100      let wrapped = false;
101      if (this.pos.x < 0) { this.pos.x = width; wrapped = true; }
102      if (this.pos.x > width) { this.pos.x = 0; wrapped = true; }
103      if (this.pos.y < 0) { this.pos.y = height; wrapped = true; }
104      if (this.pos.y > height) { this.pos.y = 0; wrapped = true; }
105      if (wrapped) this.prev.set(this.pos);
106    }
107  }
108  
109  function mousePressed() {
110    for (const p of particles) {
111      const burst = p5.Vector.sub(p.pos, createVector(mouseX, mouseY));
112      const d = burst.mag();
113      if (d < 240 && d > 1) {
114        burst.normalize().mult(map(d, 0, 240, 5, 0));
115        p.vel.add(burst);
116      }
117    }
118  }
119  
120  function keyPressed() {
121    if (key === 'r' || key === 'R') {
122      background(225, 45, 7);
123      for (const p of particles) {
124        p.pos.set(random(width), random(height));
125        p.prev.set(p.pos);
126        p.vel = p5.Vector.random2D();
127      }
128    }
129  }
130  
131  function windowResized() {
132    resizeCanvas(windowWidth, windowHeight);
133    background(225, 45, 7);
134  }