Source of: Tidal Bloom, by GPT-6 Luna
196 lines, 2 of them comments ยท 2,907 tokens, written in 41 seconds for $0.0015
1 let stars = [];
2 let palette;
3
4 function setup() {
5 createCanvas(windowWidth, windowHeight);
6 pixelDensity(1);
7 angleMode(RADIANS);
8 palette = [
9 [72, 220, 203],
10 [103, 161, 255],
11 [180, 126, 255],
12 [255, 151, 194],
13 [255, 209, 132]
14 ];
15
16 randomSeed(12);
17 for (let i = 0; i < 180; i++) {
18 stars.push({
19 x: random(),
20 y: random(),
21 size: random(0.7, 2.2),
22 phase: random(TWO_PI),
23 speed: random(0.5, 1.8)
24 });
25 }
26 }
27
28 function draw() {
29 background(7, 13, 29);
30
31 const t = millis() * 0.00018;
32 const cx = width * 0.5;
33 const cy = height * 0.5;
34 const unit = min(width, height);
35 const scale = unit * 0.39;
36
37 drawAtmosphere(cx, cy, unit);
38 drawStars(t);
39
40 push();
41 translate(cx, cy);
42 drawOrbitLines(scale, t);
43 drawPetals(scale, t);
44 drawContours(scale, t);
45 drawCore(scale, t);
46 pop();
47
48 drawFrameDetails(cx, cy, unit, t);
49 }
50
51 function drawAtmosphere(cx, cy, unit) {
52 noStroke();
53 for (let i = 18; i >= 0; i--) {
54 const r = unit * (0.08 + i * 0.025);
55 const a = map(i, 18, 0, 1, 7);
56 fill(26, 53, 91, a);
57 circle(cx, cy, r * 2);
58 }
59 }
60
61 function drawStars(t) {
62 noStroke();
63 for (const s of stars) {
64 const twinkle = 0.35 + 0.65 * (0.5 + 0.5 * sin(t * 7 * s.speed + s.phase));
65 fill(164, 207, 255, 50 + 150 * twinkle);
66 circle(s.x * width, s.y * height, s.size * twinkle);
67 }
68 }
69
70 function drawOrbitLines(r, t) {
71 noFill();
72 for (let i = 0; i < 5; i++) {
73 const rr = r * (0.78 + i * 0.075) + sin(t * 4 + i) * 3;
74 stroke(113, 177, 215, 24 + i * 3);
75 strokeWeight(0.8);
76 circle(0, 0, rr * 2);
77 }
78
79 // Small marks along the outer orbit give the bloom a quiet celestial rhythm.
80 for (let i = 0; i < 72; i++) {
81 const a = TWO_PI * i / 72 + t * 0.12;
82 const inner = r * 0.91;
83 const outer = inner + (i % 6 === 0 ? 9 : 3);
84 stroke(141, 200, 229, i % 6 === 0 ? 100 : 40);
85 line(cos(a) * inner, sin(a) * inner, cos(a) * outer, sin(a) * outer);
86 }
87 }
88
89 function drawPetals(r, t) {
90 const count = 12;
91 for (let i = 0; i < count; i++) {
92 const a = TWO_PI * i / count + t * 0.22;
93 const pulse = 1 + 0.035 * sin(t * 5 + i * 0.8);
94 const len = r * 0.77 * pulse;
95 const w = r * (0.19 + 0.025 * sin(i * 2.3));
96 const c = palette[i % palette.length];
97
98 push();
99 rotate(a);
100 noStroke();
101 fill(c[0], c[1], c[2], 22);
102 beginShape();
103 vertex(0, 0);
104 bezierVertex(-w * 0.95, -len * 0.28, -w * 0.75, -len * 0.82, 0, -len);
105 bezierVertex(w * 0.75, -len * 0.82, w * 0.95, -len * 0.28, 0, 0);
106 endShape(CLOSE);
107
108 noFill();
109 stroke(c[0], c[1], c[2], 95);
110 strokeWeight(1);
111 beginShape();
112 vertex(0, 0);
113 bezierVertex(-w * 0.95, -len * 0.28, -w * 0.75, -len * 0.82, 0, -len);
114 bezierVertex(w * 0.75, -len * 0.82, w * 0.95, -len * 0.28, 0, 0);
115 endShape();
116
117 stroke(c[0], c[1], c[2], 45);
118 strokeWeight(0.7);
119 bezier(0, -len * 0.04, -w * 0.12, -len * 0.4, w * 0.12, -len * 0.72, 0, -len * 0.96);
120 pop();
121 }
122 }
123
124 function drawContours(r, t) {
125 const layers = 28;
126 const points = 220;
127 noFill();
128
129 for (let layer = 0; layer < layers; layer++) {
130 const f = layer / (layers - 1);
131 const base = r * (0.17 + f * 0.76);
132 const color = palette[(layer + 1) % palette.length];
133 const alpha = 42 + 40 * (0.5 + 0.5 * sin(layer * 0.7 + t * 2));
134 stroke(color[0], color[1], color[2], alpha);
135 strokeWeight(layer % 4 === 0 ? 1.15 : 0.65);
136 beginShape();
137
138 for (let j = 0; j <= points; j++) {
139 const a = TWO_PI * j / points;
140 const lobes = 1 + 0.105 * cos(12 * a + t * 0.8) + 0.035 * sin(7 * a - t * 0.5);
141 const ripple = 1 + 0.018 * sin(3 * a + layer * 0.43 + t * 1.8);
142 const rNow = base * lobes * ripple;
143 vertex(cos(a) * rNow, sin(a) * rNow);
144 }
145 endShape(CLOSE);
146 }
147 }
148
149 function drawCore(r, t) {
150 const pulse = 1 + 0.08 * sin(t * 6);
151 noStroke();
152 for (let i = 8; i >= 0; i--) {
153 const d = r * (0.19 + i * 0.045) * pulse;
154 fill(98, 187, 221, 8 + i * 2);
155 circle(0, 0, d);
156 }
157
158 stroke(191, 238, 242, 150);
159 strokeWeight(1);
160 noFill();
161 circle(0, 0, r * 0.2 * pulse);
162 noStroke();
163 fill(235, 247, 226, 220);
164 circle(0, 0, r * 0.035 * pulse);
165
166 // A few fine rays radiate from the luminous center.
167 stroke(186, 231, 238, 85);
168 strokeWeight(0.7);
169 for (let i = 0; i < 24; i++) {
170 const a = TWO_PI * i / 24 + t * 0.3;
171 line(cos(a) * r * 0.12, sin(a) * r * 0.12,
172 cos(a) * r * 0.2, sin(a) * r * 0.2);
173 }
174 }
175
176 function drawFrameDetails(cx, cy, unit, t) {
177 const margin = max(22, unit * 0.045);
178 noFill();
179 stroke(115, 177, 205, 70);
180 strokeWeight(1);
181 const len = 13;
182 const corners = [
183 [margin, margin, 1, 1],
184 [width - margin, margin, -1, 1],
185 [margin, height - margin, 1, -1],
186 [width - margin, height - margin, -1, -1]
187 ];
188 for (const [x, y, sx, sy] of corners) {
189 line(x, y, x + sx * len, y);
190 line(x, y, x, y + sy * len);
191 }
192 }
193
194 function windowResized() {
195 resizeCanvas(windowWidth, windowHeight);
196 }