Source of: Flowing Particle Field, by Claude Opus 4.8
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