93 lines, 3 of them comments ยท 1,111 tokens, written in 15 seconds for $0.0049


 1  const PARTICLE_COUNT = 1500;
 2    const NOISE_SCALE = 0.005;
 3    const SPEED = 2.5;
 4    const FADE = 15;
 5  
 6    let particles = [];
 7    let zoff = 0;
 8  
 9    function setup() {
10      createCanvas(windowWidth, windowHeight);
11      background(0);
12      for (let i = 0; i < PARTICLE_COUNT; i++) {
13        particles.push(new Particle());
14      }
15    }
16  
17    function draw() {
18      // Fade previous frame for trails
19      noStroke();
20      fill(0, FADE);
21      rect(0, 0, width, height);
22  
23      for (let p of particles) {
24        p.follow();
25        p.update();
26        p.edges();
27        p.show();
28      }
29  
30      zoff += 0.001;
31    }
32  
33    class Particle {
34      constructor() {
35        this.pos = createVector(random(width), random(height));
36        this.vel = createVector(0, 0);
37        this.acc = createVector(0, 0);
38        this.maxSpeed = SPEED;
39        this.hue = random(360);
40      }
41  
42      follow() {
43        // Perlin noise flow field, distorted by mouse position
44        let dx = mouseX - this.pos.x;
45        let dy = mouseY - this.pos.y;
46        let distMouse = sqrt(dx * dx + dy * dy);
47        let mouseInfluence = constrain(1 - distMouse / 200, 0, 1);
48  
49        let angle = noise(this.pos.x * NOISE_SCALE,
50                          this.pos.y * NOISE_SCALE,
51                          zoff) * TWO_PI * 4;
52        angle += mouseInfluence * atan2(dy, dx) * 0.5;
53  
54        let force = p5.Vector.fromAngle(angle);
55        force.setMag(0.2);
56        this.acc.add(force);
57      }
58  
59      update() {
60        this.vel.add(this.acc);
61        this.vel.limit(this.maxSpeed);
62        this.pos.add(this.vel);
63        this.acc.mult(0);
64        this.hue = (this.hue + 0.3) % 360;
65      }
66  
67      edges() {
68        if (this.pos.x > width)  this.pos.x = 0;
69        if (this.pos.x < 0)      this.pos.x = width;
70        if (this.pos.y > height) this.pos.y = 0;
71        if (this.pos.y < 0)      this.pos.y = height;
72      }
73  
74      show() {
75        colorMode(HSB, 360, 100, 100, 100);
76        stroke(this.hue, 80, 95, 60);
77        strokeWeight(1.2);
78        point(this.pos.x, this.pos.y);
79      }
80    }
81  
82    function windowResized() {
83      resizeCanvas(windowWidth, windowHeight);
84      background(0);
85    }
86  
87    function mousePressed() {
88      // Reset canvas on click
89      background(0);
90      for (let p of particles) {
91        p.pos = createVector(random(width), random(height));
92      }
93    }