Source of: Aurora Ribbons, by Grok 4.5
100 lines, 5 of them comments ยท 1,319 tokens, written in 15 seconds for $0.0082
1 let ribbons = [];
2 const RIBBON_COUNT = 14;
3
4 function setup() {
5 createCanvas(windowWidth, windowHeight);
6 colorMode(HSB, 360, 100, 100, 100);
7 background(230, 40, 8);
8 for (let i = 0; i < RIBBON_COUNT; i++) {
9 ribbons.push(new Ribbon(i));
10 }
11 }
12
13 function draw() {
14 // Fade trails
15 noStroke();
16 fill(230, 40, 8, 8);
17 rect(0, 0, width, height);
18
19 for (let r of ribbons) {
20 r.update();
21 r.display();
22 }
23 }
24
25 function windowResized() {
26 resizeCanvas(windowWidth, windowHeight);
27 background(230, 40, 8);
28 }
29
30 class Ribbon {
31 constructor(idx) {
32 this.idx = idx;
33 this.reset();
34 }
35
36 reset() {
37 this.points = [];
38 this.xoff = random(1000);
39 this.yoff = random(1000);
40 this.zoff = random(1000);
41 this.hue = random(140, 220);
42 this.weight = random(1.5, 4.5);
43 this.speed = random(0.002, 0.006);
44 this.len = floor(random(40, 90));
45 // seed a starting trail
46 let x = random(width);
47 let y = random(height);
48 for (let i = 0; i < this.len; i++) {
49 this.points.push(createVector(x, y));
50 }
51 }
52
53 update() {
54 let last = this.points[this.points.length - 1];
55 let angle = noise(this.xoff, this.yoff, this.zoff) * TWO_PI * 2;
56
57 // subtle mouse influence
58 let mx = map(mouseX, 0, width, -0.4, 0.4);
59 let my = map(mouseY, 0, height, -0.4, 0.4);
60 angle += mx + my;
61
62 let step = map(noise(this.zoff + 50), 0, 1, 1.5, 4);
63 let nx = last.x + cos(angle) * step;
64 let ny = last.y + sin(angle) * step;
65
66 // wrap softly
67 if (nx < -50) nx = width + 50;
68 if (nx > width + 50) nx = -50;
69 if (ny < -50) ny = height + 50;
70 if (ny > height + 50) ny = -50;
71
72 this.points.push(createVector(nx, ny));
73 if (this.points.length > this.len) this.points.shift();
74
75 this.xoff += this.speed;
76 this.yoff += this.speed * 0.7;
77 this.zoff += this.speed * 0.3;
78 this.hue = (this.hue + 0.05) % 360;
79 }
80
81 display() {
82 noFill();
83 strokeWeight(this.weight);
84 beginShape();
85 for (let i = 0; i < this.points.length; i++) {
86 let p = this.points[i];
87 let t = i / this.points.length;
88 let alpha = map(t, 0, 1, 0, 55);
89 stroke(this.hue, 70, 90, alpha);
90 curveVertex(p.x, p.y);
91 }
92 endShape();
93
94 // soft glow dots at the head
95 let head = this.points[this.points.length - 1];
96 noStroke();
97 fill(this.hue, 60, 100, 30);
98 circle(head.x, head.y, this.weight * 3);
99 }
100 }