92 lines, no comments ยท 1,229 tokens, written in 12 seconds for $0.032


 1  let particles = [];
 2  let numParticles = 600;
 3  let zoff = 0;
 4  const scl = 20;
 5  let cols, rows;
 6  
 7  function setup() {
 8    createCanvas(windowWidth, windowHeight);
 9    cols = floor(width / scl) + 1;
10    rows = floor(height / scl) + 1;
11    colorMode(HSB, 360, 100, 100, 100);
12    for (let i = 0; i < numParticles; i++) {
13      particles.push(new Particle());
14    }
15    background(0);
16  }
17  
18  function draw() {
19    background(0, 6);
20    let yoff = 0;
21    for (let y = 0; y < rows; y++) {
22      let xoff = 0;
23      for (let x = 0; x < cols; x++) {
24        let angle = noise(xoff, yoff, zoff) * TWO_PI * 2;
25        let v = p5.Vector.fromAngle(angle);
26        let idx = x + y * cols;
27        flowfield[idx] = v;
28        xoff += 0.1;
29      }
30      yoff += 0.1;
31    }
32    zoff += 0.003;
33  
34    for (let p of particles) {
35      p.follow();
36      p.update();
37      p.edges();
38      p.show();
39    }
40  }
41  
42  let flowfield = [];
43  
44  class Particle {
45    constructor() {
46      this.pos = createVector(random(width), random(height));
47      this.vel = createVector(0, 0);
48      this.acc = createVector(0, 0);
49      this.maxSpeed = 3;
50      this.hue = random(360);
51      this.prev = this.pos.copy();
52    }
53    follow() {
54      let x = floor(this.pos.x / scl);
55      let y = floor(this.pos.y / scl);
56      let idx = x + y * cols;
57      let force = flowfield[idx];
58      if (force) this.applyForce(force);
59    }
60    applyForce(f) {
61      this.acc.add(f);
62    }
63    update() {
64      this.vel.add(this.acc);
65      this.vel.limit(this.maxSpeed);
66      this.pos.add(this.vel);
67      this.acc.mult(0);
68      this.hue = (this.hue + 0.3) % 360;
69    }
70    show() {
71      stroke(this.hue, 70, 100, 40);
72      strokeWeight(1.5);
73      line(this.pos.x, this.pos.y, this.prev.x, this.prev.y);
74      this.prev = this.pos.copy();
75    }
76    edges() {
77      let wrapped = false;
78      if (this.pos.x > width) { this.pos.x = 0; wrapped = true; }
79      if (this.pos.x < 0) { this.pos.x = width; wrapped = true; }
80      if (this.pos.y > height) { this.pos.y = 0; wrapped = true; }
81      if (this.pos.y < 0) { this.pos.y = height; wrapped = true; }
82      if (wrapped) this.prev = this.pos.copy();
83    }
84  }
85  
86  function windowResized() {
87    resizeCanvas(windowWidth, windowHeight);
88    cols = floor(width / scl) + 1;
89    rows = floor(height / scl) + 1;
90    background(0);
91  }
92