Source of: Aurora Currents, by GPT-6 Astra
101 lines, 1 of them comments ยท 1,288 tokens, written in 25 seconds for $0.065
1 let particles = [];
2 let time = 0;
3 let hueOffset = 0;
4 let paused = false;
5
6 function setup() {
7 createCanvas(windowWidth, windowHeight);
8 pixelDensity(Math.min(window.devicePixelRatio || 1, 2));
9 colorMode(HSB, 360, 100, 100, 1);
10 strokeCap(ROUND);
11 regenerate();
12 }
13
14 function regenerate() {
15 noiseSeed(floor(random(100000)));
16 hueOffset = random(360);
17 time = 0;
18 background(230, 45, 5);
19 const count = constrain(floor(width * height / 850), 350, 1600);
20 particles = Array.from({ length: count }, () => makeParticle());
21 }
22
23 function makeParticle() {
24 return {
25 x: random(width),
26 y: random(height),
27 vx: 0,
28 vy: 0,
29 speed: random(0.8, 2.6),
30 weight: random(0.6, 1.7),
31 age: 0,
32 life: random(160, 600),
33 hue: random(75)
34 };
35 }
36
37 function draw() {
38 if (paused) return;
39
40 background(230, 45, 5, 0.065);
41 const step = Math.min(deltaTime / 16.667, 2);
42 const scale = 0.0018;
43 const pointerInside = mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height;
44
45 for (let i = 0; i < particles.length; i++) {
46 const p = particles[i];
47 const previousX = p.x;
48 const previousY = p.y;
49 const field = noise(p.x * scale, p.y * scale, time);
50 const angle = field * TWO_PI * 2.5;
51 let fx = cos(angle);
52 let fy = sin(angle);
53
54 // A soft vortex lets the pointer comb and twist the trails.
55 if (pointerInside) {
56 const dx = p.x - mouseX;
57 const dy = p.y - mouseY;
58 const distance = sqrt(dx * dx + dy * dy);
59 const influence = 2.8 * exp(-distance * distance / 24000);
60 const divisor = Math.max(distance, 20);
61 fx += (-dy / divisor) * influence;
62 fy += (dx / divisor) * influence;
63 }
64
65 p.vx = lerp(p.vx, fx * p.speed, 0.09);
66 p.vy = lerp(p.vy, fy * p.speed, 0.09);
67 p.x += p.vx * step;
68 p.y += p.vy * step;
69 p.age += step;
70
71 if (p.x < 0 || p.x > width || p.y < 0 || p.y > height || p.age > p.life) {
72 particles[i] = makeParticle();
73 continue;
74 }
75
76 const fade = Math.min(p.age / 25, (p.life - p.age) / 45, 1);
77 const hue = (hueOffset + p.hue + field * 95 + time * 18) % 360;
78 stroke(hue, 62, 100, 0.52 * fade);
79 strokeWeight(p.weight);
80 line(previousX, previousY, p.x, p.y);
81 }
82
83 time += 0.002 * step;
84 }
85
86 function mousePressed() {
87 regenerate();
88 }
89
90 function keyPressed() {
91 if (key === ' ') {
92 paused = !paused;
93 return false;
94 }
95 }
96
97 function windowResized() {
98 resizeCanvas(windowWidth, windowHeight);
99 regenerate();
100 }
101