91 lines, 3 of them comments ยท 2,109 tokens, written in 33 seconds for $0.0011


 1  let particles = [];
 2  const PARTICLE_COUNT = 950;
 3  
 4  function setup() {
 5    createCanvas(windowWidth, windowHeight);
 6    pixelDensity(1);
 7    colorMode(HSB, 360, 100, 100, 100);
 8    background(228, 55, 8);
 9    for (let i = 0; i < PARTICLE_COUNT; i++) particles.push(makeParticle());
10  }
11  
12  function makeParticle() {
13    const x = random(width);
14    const y = random(height);
15    return { x, y, px: x, py: y, vx: 0, vy: 0, seed: random(1000) };
16  }
17  
18  function draw() {
19    // A transparent veil keeps old strokes lingering as soft trails.
20    blendMode(BLEND);
21    noStroke();
22    fill(228, 55, 8, 11);
23    rect(0, 0, width, height);
24  
25    const cx = width * 0.5;
26    const cy = height * 0.5;
27    const t = frameCount * 0.008;
28  
29    blendMode(ADD);
30    for (const p of particles) {
31      p.px = p.x;
32      p.py = p.y;
33  
34      const dx = p.x - cx;
35      const dy = p.y - cy;
36      const radius = sqrt(dx * dx + dy * dy);
37      const angle = atan2(dy, dx);
38  
39      // A rotating field, gently rippled into nested tidal bands.
40      const ripple = 0.85 * sin(radius * 0.012 - t + 3 * angle + p.seed);
41      const flowAngle = angle + HALF_PI + ripple + 0.22 * cos(5 * angle - t * 1.4);
42      let ax = cos(flowAngle);
43      let ay = sin(flowAngle);
44  
45      if (mouseIsPressed) {
46        const mx = mouseX - p.x;
47        const my = mouseY - p.y;
48        const md = sqrt(mx * mx + my * my) + 1;
49        const influence = 180 / (180 + md);
50        ax += (mx / md) * influence * 1.8;
51        ay += (my / md) * influence * 1.8;
52      }
53  
54      const speed = 0.8 + 0.75 * (0.5 + 0.5 * sin(radius * 0.009 + p.seed));
55      const targetVx = ax * speed;
56      const targetVy = ay * speed;
57      p.vx = lerp(p.vx, targetVx, 0.12);
58      p.vy = lerp(p.vy, targetVy, 0.12);
59      p.x += p.vx;
60      p.y += p.vy;
61  
62      const hue = (190 + 95 * (0.5 + 0.5 * sin(angle * 2 + radius * 0.003 - t * 2)) + 360) % 360;
63      const alpha = 22 + 38 * (0.5 + 0.5 * sin(p.seed + t));
64      stroke(hue, 72, 100, alpha);
65      strokeWeight(0.7 + 0.65 * (0.5 + 0.5 * sin(p.seed * 2)));
66      line(p.px, p.py, p.x, p.y);
67  
68      if (p.x < -10 || p.x > width + 10 || p.y < -10 || p.y > height + 10) {
69        Object.assign(p, makeParticle());
70      }
71    }
72  
73    // A small, breathing pearl of light at the heart of the current.
74    const pulse = 1 + 0.12 * sin(frameCount * 0.035);
75    noStroke();
76    for (let i = 7; i >= 1; i--) {
77      fill(190 + i * 5, 65, 100, 2.5);
78      circle(cx, cy, i * 11 * pulse);
79    }
80    noFill();
81    stroke(188, 35, 100, 32);
82    strokeWeight(0.8);
83    circle(cx, cy, 28 * pulse);
84    blendMode(BLEND);
85  }
86  
87  function windowResized() {
88    resizeCanvas(windowWidth, windowHeight);
89    background(228, 55, 8);
90    for (const p of particles) Object.assign(p, makeParticle());
91  }