Source of: Interactive Flow Field Particle System, by Qwen3.6 35B A3B
99 lines, 14 of them comments ยท 2,656 tokens, written in 21 seconds for $0.0024
1 // Interactive Flow Field Particle System
2 // Uses Perlin noise to create organic, flowing movement
3 // Click to change color scheme, move mouse Y to adjust flow density
4
5 let particles = [];
6 const PARTICLE_COUNT = 800;
7 let noiseScale = 0.005;
8 let hueOffset = 0;
9
10 function setup() {
11 createCanvas(windowWidth, windowHeight);
12 colorMode(HSB, 360, 100, 100, 100);
13 frameRate(60);
14
15 // Initialize particles with random positions
16 for (let i = 0; i < PARTICLE_COUNT; i++) {
17 particles.push(new Particle());
18 }
19
20 // Clear canvas initially
21 background(0);
22 }
23
24 function draw() {
25 // Fade effect for trails
26 fill(0, 0, 0, 3);
27 noStroke();
28 rect(0, 0, width, height);
29
30 // Update and draw all particles
31 for (let p of particles) {
32 // Generate noise-based angle for flow direction
33 let nx = p.pos.x * noiseScale;
34 let ny = p.pos.y * noiseScale;
35 let nz = frameCount * 0.002;
36 let angle = noise(nx, ny, nz) * TWO_PI * 1.5;
37
38 // Create force vector from angle
39 let force = p5.Vector.fromAngle(angle);
40 p.applyForce(force);
41
42 p.update();
43 p.display();
44 p.checkEdges();
45 }
46 }
47
48 function windowResized() {
49 resizeCanvas(windowWidth, windowHeight);
50 background(0);
51 }
52
53 // Interactive features
54 function mousePressed() {
55 hueOffset = random(360);
56 }
57
58 function mouseMoved() {
59 // Adjust flow field scale based on mouse Y position
60 noiseScale = map(mouseY, 0, height, 0.002, 0.015);
61 }
62
63 // Particle class for managing individual behavior
64 class Particle {
65 constructor() {
66 this.pos = createVector(random(width), random(height));
67 this.vel = createVector(0, 0);
68 this.acc = createVector(0, 0);
69 this.maxSpeed = random(1.5, 3);
70 this.size = random(1.5, 3);
71 this.alpha = random(40, 80);
72 }
73
74 applyForce(force) {
75 this.acc.add(force);
76 }
77
78 update() {
79 this.vel.add(this.acc);
80 this.vel.limit(this.maxSpeed);
81 this.pos.add(this.vel);
82 this.acc.set(0, 0); // Reset acceleration each frame
83 }
84
85 display() {
86 let h = (hueOffset + this.pos.x * 0.1 + frameCount * 0.1) % 360;
87 stroke(h, 80, 100, this.alpha);
88 strokeWeight(this.size);
89 point(this.pos.x, this.pos.y);
90 }
91
92 checkEdges() {
93 // Wrap around canvas edges
94 if (this.pos.x < 0) this.pos.x = width;
95 if (this.pos.x > width) this.pos.x = 0;
96 if (this.pos.y < 0) this.pos.y = height;
97 if (this.pos.y > height) this.pos.y = 0;
98 }
99 }