87 lines, 6 of them comments ยท 1,550 tokens, written in 8 seconds for $0.0009


 1  let particles = [];
 2  const NUM = 1200;
 3  const NOISE_SCALE = 0.0025;
 4  let zOff = 0;
 5  
 6  function setup() {
 7    createCanvas(windowWidth, windowHeight);
 8    colorMode(HSB, 360, 100, 100, 100);
 9    background(0, 0, 3);
10  
11    for (let i = 0; i < NUM; i++) {
12      particles.push(new Particle());
13    }
14  }
15  
16  function draw() {
17    // Soft fade instead of clearing -> creates trailing streams
18    noStroke();
19    fill(0, 0, 3, 7);
20    rect(0, 0, width, height);
21  
22    zOff += 0.0015;
23  
24    for (const p of particles) {
25      p.update();
26      p.display();
27    }
28  
29    // Reset the field occasionally to keep it fresh
30    if (frameCount % 1800 === 0) {
31      for (let i = 0; i < NUM; i++) particles[i] = new Particle();
32      background(0, 0, 3);
33    }
34  }
35  
36  class Particle {
37    constructor() {
38      this.pos = createVector(random(width), random(height));
39      this.prev = this.pos.copy();
40      this.speed = random(0.8, 2.6);
41      this.hue = random(360);
42    }
43  
44    update() {
45      this.prev.set(this.pos);
46  
47      // Direction from Perlin noise (rotates smoothly over time)
48      const angle = noise(
49        this.pos.x * NOISE_SCALE,
50        this.pos.y * NOISE_SCALE,
51        zOff
52      ) * TAU * 2;
53  
54      this.pos.x += cos(angle) * this.speed;
55      this.pos.y += sin(angle) * this.speed;
56  
57      // Mouse repulsion
58      const dx = this.pos.x - mouseX;
59      const dy = this.pos.y - mouseY;
60      const distSq = dx * dx + dy * dy;
61      if (distSq < 12000) {
62        const f = (12000 - distSq) / 12000;
63        this.pos.x += dx * f * 0.05;
64        this.pos.y += dy * f * 0.05;
65      }
66  
67      // Wrap around the edges
68      if (this.pos.x < 0)      { this.pos.x = width;  this.prev.x = width;  }
69      if (this.pos.x > width)  { this.pos.x = 0;      this.prev.x = 0;      }
70      if (this.pos.y < 0)      { this.pos.y = height; this.prev.y = height; }
71      if (this.pos.y > height) { this.pos.y = 0;      this.prev.y = 0;      }
72  
73      // Slowly shift hue
74      this.hue = (this.hue + 0.25) % 360;
75    }
76  
77    display() {
78      stroke(this.hue, 85, 100, 35);
79      strokeWeight(1.2);
80      line(this.prev.x, this.prev.y, this.pos.x, this.pos.y);
81    }
82  }
83  
84  function windowResized() {
85    resizeCanvas(windowWidth, windowHeight);
86    background(0, 0, 3);
87  }