Source of: Colorful Particle Flow, by Claude Opus 4.1
122 lines, 5 of them comments ยท 1,136 tokens, written in 52 seconds for $0.092
1 let particles = [];
2 let flowfield = [];
3 let cols, rows;
4 let zoff = 0;
5 let scl = 20;
6 let inc = 0.1;
7
8 function setup() {
9 createCanvas(windowWidth, windowHeight);
10 colorMode(HSB, 360, 100, 100, 100);
11
12 cols = floor(width / scl);
13 rows = floor(height / scl);
14 flowfield = new Array(cols * rows);
15
16 // Create particles
17 for (let i = 0; i < 500; i++) {
18 particles.push(new Particle());
19 }
20
21 background(0, 0, 10);
22 }
23
24 function draw() {
25 // Semi-transparent background for trail effect
26 fill(0, 0, 10, 10);
27 noStroke();
28 rect(0, 0, width, height);
29
30 // Calculate flow field vectors
31 let yoff = 0;
32 for (let y = 0; y < rows; y++) {
33 let xoff = 0;
34 for (let x = 0; x < cols; x++) {
35 let index = x + y * cols;
36 let angle = noise(xoff, yoff, zoff) * TWO_PI * 2;
37 let v = p5.Vector.fromAngle(angle);
38 v.setMag(1);
39 flowfield[index] = v;
40 xoff += inc;
41 }
42 yoff += inc;
43 }
44 zoff += 0.003;
45
46 // Update and display particles
47 for (let particle of particles) {
48 particle.follow(flowfield);
49 particle.update();
50 particle.edges();
51 particle.show();
52 }
53 }
54
55 class Particle {
56 constructor() {
57 this.pos = createVector(random(width), random(height));
58 this.vel = createVector(0, 0);
59 this.acc = createVector(0, 0);
60 this.maxspeed = 4;
61 this.hue = random(360);
62 this.prevPos = this.pos.copy();
63 }
64
65 follow(vectors) {
66 let x = floor(this.pos.x / scl);
67 let y = floor(this.pos.y / scl);
68 let index = x + y * cols;
69 let force = vectors[index];
70 if (force) {
71 this.applyForce(force);
72 }
73 }
74
75 applyForce(force) {
76 this.acc.add(force);
77 }
78
79 update() {
80 this.vel.add(this.acc);
81 this.vel.limit(this.maxspeed);
82 this.pos.add(this.vel);
83 this.acc.mult(0);
84 }
85
86 show() {
87 stroke(this.hue, 80, 100, 25);
88 strokeWeight(1);
89 line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
90 this.prevPos = this.pos.copy();
91
92 // Slowly shift hue
93 this.hue = (this.hue + 0.1) % 360;
94 }
95
96 edges() {
97 if (this.pos.x > width) {
98 this.pos.x = 0;
99 this.prevPos = this.pos.copy();
100 }
101 if (this.pos.x < 0) {
102 this.pos.x = width;
103 this.prevPos = this.pos.copy();
104 }
105 if (this.pos.y > height) {
106 this.pos.y = 0;
107 this.prevPos = this.pos.copy();
108 }
109 if (this.pos.y < 0) {
110 this.pos.y = height;
111 this.prevPos = this.pos.copy();
112 }
113 }
114 }
115
116 function windowResized() {
117 resizeCanvas(windowWidth, windowHeight);
118 cols = floor(width / scl);
119 rows = floor(height / scl);
120 flowfield = new Array(cols * rows);
121 background(0, 0, 10);
122 }