136 lines, 2 of them comments ยท 1,395 tokens, written in 14 seconds for $0.042


  1  let particles = [];
  2  let seed;
  3  let palette;
  4  
  5  function setup() {
  6    createCanvas(windowWidth, windowHeight);
  7    pixelDensity(1);
  8    colorMode(HSB, 360, 100, 100, 100);
  9    blendMode(ADD);
 10    resetSketch();
 11  }
 12  
 13  function resetSketch() {
 14    seed = floor(random(100000));
 15    randomSeed(seed);
 16    noiseSeed(seed);
 17  
 18    palette = [
 19      color(175, 85, 95, 18),
 20      color(205, 90, 100, 16),
 21      color(265, 70, 95, 13),
 22      color(320, 70, 100, 12),
 23      color(95, 70, 95, 10)
 24    ];
 25  
 26    particles = [];
 27    const count = floor((width * height) / 5200);
 28    for (let i = 0; i < count; i++) {
 29      particles.push(new Particle(random(width), random(height)));
 30    }
 31  
 32    background(230, 55, 5);
 33  }
 34  
 35  function draw() {
 36    // Soft fade for trails
 37    blendMode(BLEND);
 38    noStroke();
 39    fill(230, 55, 5, 7);
 40    rect(0, 0, width, height);
 41  
 42    blendMode(ADD);
 43    for (let p of particles) {
 44      p.update();
 45      p.display();
 46    }
 47  
 48    // Central glow near mouse
 49    const mx = mouseX || width / 2;
 50    const my = mouseY || height / 2;
 51    noStroke();
 52    for (let r = 80; r > 0; r -= 10) {
 53      fill(185, 90, 100, map(r, 80, 0, 0.8, 5));
 54      circle(mx, my, r);
 55    }
 56  }
 57  
 58  class Particle {
 59    constructor(x, y) {
 60      this.pos = createVector(x, y);
 61      this.prev = this.pos.copy();
 62      this.vel = p5.Vector.random2D().mult(random(0.5, 2));
 63      this.life = random(80, 260);
 64      this.maxLife = this.life;
 65      this.size = random(0.8, 2.7);
 66      this.col = random(palette);
 67      this.wander = random(0.002, 0.006);
 68    }
 69  
 70    update() {
 71      this.prev.set(this.pos);
 72  
 73      const n = noise(this.pos.x * this.wander, this.pos.y * this.wander, frameCount * 0.003);
 74      const angle = n * TWO_PI * 4.0;
 75      const flow = p5.Vector.fromAngle(angle).mult(0.16);
 76  
 77      const mouse = createVector(mouseX || width / 2, mouseY || height / 2);
 78      const away = p5.Vector.sub(this.pos, mouse);
 79      const d = away.mag();
 80      if (d < 180) {
 81        away.normalize().mult(map(d, 0, 180, 0.55, 0.0));
 82        flow.add(away);
 83      }
 84  
 85      this.vel.add(flow);
 86      this.vel.limit(2.6);
 87      this.pos.add(this.vel);
 88      this.life--;
 89  
 90      if (this.pos.x < -40 || this.pos.x > width + 40 || this.pos.y < -40 || this.pos.y > height + 40 || this.life <= 0) {
 91        this.respawn();
 92      }
 93    }
 94  
 95    display() {
 96      const a = map(this.life, 0, this.maxLife, 0, alpha(this.col));
 97      stroke(hue(this.col), saturation(this.col), brightness(this.col), a);
 98      strokeWeight(this.size);
 99      line(this.prev.x, this.prev.y, this.pos.x, this.pos.y);
100  
101      if (random() < 0.025) {
102        noStroke();
103        fill(hue(this.col), saturation(this.col), 100, a * 1.8);
104        circle(this.pos.x, this.pos.y, this.size * random(2, 5));
105      }
106    }
107  
108    respawn() {
109      const edge = floor(random(4));
110      if (edge === 0) this.pos.set(random(width), -10);
111      if (edge === 1) this.pos.set(width + 10, random(height));
112      if (edge === 2) this.pos.set(random(width), height + 10);
113      if (edge === 3) this.pos.set(-10, random(height));
114  
115      this.prev.set(this.pos);
116      this.vel = p5.Vector.random2D().mult(random(0.5, 2));
117      this.life = random(90, 280);
118      this.maxLife = this.life;
119      this.size = random(0.8, 2.7);
120      this.col = random(palette);
121    }
122  }
123  
124  function mousePressed() {
125    resetSketch();
126  }
127  
128  function keyPressed() {
129    if (key === 's' || key === 'S') saveCanvas('bioluminescent-flow-garden', 'png');
130    if (key === 'r' || key === 'R') resetSketch();
131  }
132  
133  function windowResized() {
134    resizeCanvas(windowWidth, windowHeight);
135    resetSketch();
136  }