156 lines, no comments ยท 1,632 tokens, written in 16 seconds for $0.049


  1  let particles = [];
  2  let palette;
  3  let zoff = 0;
  4  let paused = false;
  5  let seed;
  6  
  7  function setup() {
  8    createCanvas(windowWidth, windowHeight);
  9    pixelDensity(1);
 10    colorMode(HSB, 360, 100, 100, 100);
 11    seed = floor(random(100000));
 12    resetSketch();
 13  }
 14  
 15  function resetSketch() {
 16    randomSeed(seed);
 17    noiseSeed(seed);
 18    background(230, 45, 5);
 19  
 20    palette = [
 21      color(178, 85, 95, 18),
 22      color(205, 90, 100, 16),
 23      color(265, 75, 98, 14),
 24      color(315, 70, 100, 12),
 25      color(55, 80, 100, 10)
 26    ];
 27  
 28    particles = [];
 29    let count = floor((width * height) / 5200);
 30    count = constrain(count, 120, 420);
 31  
 32    for (let i = 0; i < count; i++) {
 33      particles.push(new FlowParticle(random(width), random(height)));
 34    }
 35  }
 36  
 37  function draw() {
 38    if (paused) return;
 39  
 40    noStroke();
 41    fill(232, 45, 5, 5);
 42    rect(0, 0, width, height);
 43  
 44    drawGlowBands();
 45  
 46    blendMode(ADD);
 47    for (let p of particles) {
 48      p.update();
 49      p.display();
 50    }
 51    blendMode(BLEND);
 52  
 53    zoff += 0.003;
 54  }
 55  
 56  function drawGlowBands() {
 57    blendMode(ADD);
 58    noFill();
 59    for (let j = 0; j < 4; j++) {
 60      let hue = 175 + j * 28 + sin(frameCount * 0.01 + j) * 15;
 61      stroke(hue, 70, 95, 3.5);
 62      strokeWeight(18 + j * 7);
 63      beginShape();
 64      for (let x = -40; x <= width + 40; x += 32) {
 65        let n = noise(x * 0.0025, j * 20, zoff * 0.8);
 66        let y = height * (0.32 + j * 0.115) + map(n, 0, 1, -90, 90);
 67        curveVertex(x, y);
 68      }
 69      endShape();
 70    }
 71    blendMode(BLEND);
 72  }
 73  
 74  class FlowParticle {
 75    constructor(x, y) {
 76      this.pos = createVector(x, y);
 77      this.prev = this.pos.copy();
 78      this.vel = p5.Vector.random2D().mult(random(0.2, 1.4));
 79      this.acc = createVector(0, 0);
 80      this.maxSpeed = random(1.0, 3.2);
 81      this.weight = random(0.4, 2.1);
 82      this.life = random(120, 520);
 83      this.age = random(this.life);
 84      this.col = random(palette);
 85      this.noiseScale = random(0.0015, 0.0045);
 86    }
 87  
 88    update() {
 89      this.prev.set(this.pos);
 90  
 91      let n = noise(this.pos.x * this.noiseScale, this.pos.y * this.noiseScale, zoff);
 92      let angle = n * TWO_PI * 4.0 + sin(zoff * 3 + this.pos.y * 0.004) * 0.8;
 93      let force = p5.Vector.fromAngle(angle).mult(0.08);
 94  
 95      let centerPull = createVector(width / 2, height / 2).sub(this.pos);
 96      centerPull.setMag(0.002);
 97  
 98      this.acc.add(force);
 99      this.acc.add(centerPull);
100      this.vel.add(this.acc);
101      this.vel.limit(this.maxSpeed);
102      this.pos.add(this.vel);
103      this.acc.mult(0);
104  
105      this.age++;
106      if (this.pos.x < -20 || this.pos.x > width + 20 || this.pos.y < -20 || this.pos.y > height + 20 || this.age > this.life) {
107        this.rebirth();
108      }
109    }
110  
111    display() {
112      let alphaPulse = map(sin(this.age * 0.06), -1, 1, 5, 25);
113      let c = color(hue(this.col), saturation(this.col), brightness(this.col), alphaPulse);
114      stroke(c);
115      strokeWeight(this.weight);
116      line(this.prev.x, this.prev.y, this.pos.x, this.pos.y);
117  
118      if (random() < 0.025) {
119        noStroke();
120        fill(hue(this.col), 70, 100, 18);
121        circle(this.pos.x, this.pos.y, random(1, 5));
122      }
123    }
124  
125    rebirth() {
126      if (random() < 0.55) {
127        this.pos.set(random(width), random(height));
128      } else {
129        let side = floor(random(4));
130        if (side === 0) this.pos.set(random(width), -5);
131        if (side === 1) this.pos.set(width + 5, random(height));
132        if (side === 2) this.pos.set(random(width), height + 5);
133        if (side === 3) this.pos.set(-5, random(height));
134      }
135      this.prev.set(this.pos);
136      this.vel = p5.Vector.random2D().mult(random(0.2, 1.2));
137      this.life = random(120, 520);
138      this.age = 0;
139      this.col = random(palette);
140    }
141  }
142  
143  function mousePressed() {
144    seed = floor(random(100000));
145    resetSketch();
146  }
147  
148  function keyPressed() {
149    if (key === ' ') paused = !paused;
150    if (key === 's' || key === 'S') saveCanvas('aurora-flow-garden', 'png');
151  }
152  
153  function windowResized() {
154    resizeCanvas(windowWidth, windowHeight);
155    resetSketch();
156  }