87 lines, no comments ยท 1,180 tokens, written in 13 seconds for $0.031


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