1precision highp float;
2
3uniform float uTime;
4uniform vec2 uResolution;
5
6const vec3 COL_CYAN = vec3(0.0, 0.9, 1.0);
7const vec3 COL_MAGENTA = vec3(1.0, 0.17, 0.84);
8const vec3 COL_VIOLET = vec3(0.71, 0.31, 1.0);
9const vec3 COL_TEAL = vec3(0.24, 1.0, 0.78);
10
11float hash(vec2 p) {
12 return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
13}
14
15float hash1(float n) {
16 return fract(sin(n) * 43758.5453);
17}
18
19mat2 rot(float a) {
20 float c = cos(a);
21 float s = sin(a);
22 return mat2(c, -s, s, c);
23}
24
25float noise(vec2 p) {
26 vec2 i = floor(p);
27 vec2 f = fract(p);
28 f = f * f * (3.0 - 2.0 * f);
29 float a = hash(i);
30 float b = hash(i + vec2(1.0, 0.0));
31 float c = hash(i + vec2(0.0, 1.0));
32 float d = hash(i + vec2(1.0, 1.0));
33 return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
34}
35
36float fbm(vec2 p) {
37 float v = 0.0;
38 float a = 0.5;
39 mat2 m = mat2(1.6, 1.2, -1.2, 1.6);
40 for (int i = 0; i < 5; i++) {
41 v += a * noise(p);
42 p = m * p;
43 a *= 0.5;
44 }
45 return v;
46}
47
48vec3 nebulaLayer(vec2 p, float t, float spin) {
49 vec2 q = rot(t * spin) * p;
50 q += vec2(sin(t * 0.17), cos(t * 0.13)) * 0.06;
51 float n1 = fbm(q * 2.2 + t * 0.05);
52 float n2 = fbm(q * 1.6 - t * 0.04 + 3.7);
53 float mask = smoothstep(0.2, 0.82, n1) * smoothstep(0.12, 0.72, n2);
54 vec3 tint = mix(COL_VIOLET, COL_MAGENTA, n2);
55 tint = mix(tint, COL_TEAL, n1 * 0.55);
56 return tint * mask;
57}
58
59vec3 skyColor(vec2 p) {
60 float y = p.y + 0.38;
61 vec3 zenith = vec3(0.012, 0.018, 0.075);
62 vec3 mid = vec3(0.028, 0.04, 0.15);
63 vec3 low = vec3(0.055, 0.045, 0.17);
64 vec3 col = mix(zenith, mid, smoothstep(-0.45, 0.05, y));
65 col = mix(col, low, smoothstep(-0.02, 0.42, y));
66 col += vec3(0.28, 0.12, 0.06) * exp(-abs(y - 0.28) * 4.5) * 0.22;
67 col += vec3(0.035, 0.045, 0.09) * exp(-length(p - vec2(0.0, -0.42)) * 2.6) * 0.32;
68 return col;
69}
70
71vec3 aurora(vec2 world, float t) {
72 float skyBand = smoothstep(-0.2, 0.3, world.y) * smoothstep(0.65, 0.0, world.y);
73
74 float rays = pow(
75 sin(world.x * 9.0 + sin(world.y * 2.8 + t * 0.38) * 2.2 + t * 0.22) * 0.5 + 0.5,
76 2.2
77 );
78
79 vec2 flow = world;
80 flow.x += t * 0.025;
81 float wave = fbm(vec2(flow.x * 1.1 + t * 0.05, flow.y * 2.8));
82 float curtain = smoothstep(0.2, 0.8, wave) * rays * skyBand;
83
84 vec3 green = vec3(0.15, 0.95, 0.5);
85 vec3 tint = mix(green, COL_TEAL, sin(world.x * 2.5 + t * 0.28) * 0.5 + 0.5);
86 tint = mix(tint, COL_VIOLET, smoothstep(-0.2, 0.5, world.x) * 0.35);
87
88 return tint * curtain;
89}
90
91float vortexEnergy(vec2 p, float t) {
92 float r = length(p);
93 float a = atan(p.y, p.x) + t * 0.35 + r * 4.0;
94 return sin(a * 6.0 + r * 14.0 - t * 1.4) * exp(-r * 2.2) * 0.5 + 0.5;
95}
96
97float starGlow(vec2 d, float size) {
98 float dist = length(d);
99 float core = exp(-dist / size);
100 float rays = exp(-abs(d.x) * (90.0 / size)) * exp(-abs(d.y) * (90.0 / size));
101 return core + rays * 0.22;
102}
103
104float clusterCrossFlare(vec2 d, float size, float id) {
105 vec2 ad = abs(d);
106
107 float horiz = exp(-ad.y / (size * 0.055)) * exp(-ad.x / (size * 3.4));
108 float vert = exp(-ad.x / (size * 0.055)) * exp(-ad.y / (size * 3.4));
109 float cross = horiz + vert;
110
111 float paired = 0.0;
112 if (mod(id, 3.0) < 1.6) {
113 float sep = size * (0.1 + hash1(id + 5.0) * 0.08);
114 paired += exp(-abs(d.y - sep) / (size * 0.048)) * exp(-ad.x / (size * 2.0));
115 paired += exp(-abs(d.y + sep) / (size * 0.048)) * exp(-ad.x / (size * 2.0));
116 paired *= 0.42;
117 }
118
119 return cross + paired;
120}
121
122float clusterStarCore(vec2 d, float size) {
123 float r = length(d);
124 return smoothstep(size * 0.62, size * 0.04, r);
125}
126
127float clusterStarHalo(vec2 d, float size) {
128 float r = length(d);
129 return exp(-r / (size * 3.6)) * (1.0 - smoothstep(size * 2.2, size * 5.0, r));
130}
131
132void addClusterStar(
133 inout vec3 col,
134 vec2 p,
135 vec2 pos,
136 float size,
137 float warmth,
138 float bri,
139 float t,
140 float id
141) {
142 vec2 d = p - pos;
143 float tw = 0.82 + 0.18 * sin(t * (1.0 + hash1(id) * 1.5) + hash1(id + 17.3) * 6.283);
144 float scale = bri * tw;
145
146 float core = clusterStarCore(d, size);
147 float halo = clusterStarHalo(d, size);
148 float flare = clusterCrossFlare(d, size, id);
149
150 vec3 coreWhite = mix(vec3(1.0), vec3(1.0, 0.97, 0.9), warmth * 0.35);
151 vec3 haloCyan = vec3(0.48, 0.84, 1.0);
152
153 col += haloCyan * halo * scale * 0.42;
154 col += coreWhite * (core * 1.15 + flare * 1.05) * scale;
155}
156
157float twinkle(float id, float t) {
158 float speed = 1.2 + hash1(id) * 2.4;
159 float phase = hash1(id + 17.3) * 6.283;
160 return 0.65 + 0.35 * sin(t * speed + phase);
161}
162
163vec3 starTint(float warmth) {
164 return mix(vec3(0.82, 0.9, 1.0), vec3(1.0, 0.92, 0.72), warmth);
165}
166
167float fieldStarGlow(vec2 d, float size) {
168 float dist = length(d);
169 float core = exp(-dist / size);
170 float rays = exp(-abs(d.x) * (110.0 / size)) * exp(-abs(d.y) * (110.0 / size));
171 return core + rays * 0.12;
172}
173
174vec3 fieldStars(vec2 p, float t) {
175 vec3 col = vec3(0.0);
176
177 float s1 = 58.0;
178 vec2 g1 = p * s1;
179 vec2 id1 = floor(g1);
180 vec2 f1 = fract(g1) - 0.5;
181 float n1 = hash(id1);
182 if (n1 > 0.976) {
183 float sz = 0.0015 + n1 * 0.0013;
184 col += starTint(n1 * 0.35) * fieldStarGlow(f1 / s1, sz) * (0.18 + n1 * 0.22) * twinkle(n1 * 90.0, t);
185 }
186
187 float s2 = 82.0;
188 vec2 g2 = p * s2 + 17.3;
189 vec2 id2 = floor(g2);
190 vec2 f2 = fract(g2) - 0.5;
191 float n2 = hash(id2 + 4.1);
192 if (n2 > 0.982) {
193 float sz = 0.0012 + n2 * 0.001;
194 col += starTint(n2 * 0.3) * fieldStarGlow(f2 / s2, sz) * (0.12 + n2 * 0.16) * twinkle(n2 * 110.0, t);
195 }
196
197 float s3 = 118.0;
198 vec2 g3 = p * s3 + 41.7;
199 vec2 id3 = floor(g3);
200 vec2 f3 = fract(g3) - 0.5;
201 float n3 = hash(id3 + 9.2);
202 if (n3 > 0.988) {
203 float sz = 0.0009 + n3 * 0.0008;
204 float dist = length(f3 / s3);
205 col += starTint(n3 * 0.25) * exp(-dist / sz) * (0.08 + n3 * 0.1) * twinkle(n3 * 130.0, t);
206 }
207
208 return col;
209}
210
211void main() {
212 vec2 uv = gl_FragCoord.xy / uResolution.xy;
213 vec2 world = (uv - 0.5) * vec2(uResolution.x / uResolution.y, 1.0);
214 float t = uTime * 0.45;
215
216 vec2 cluster = vec2(0.05, 0.08);
217 const float CLUSTER_ZOOM = 3.5;
218 vec2 p = (world - cluster) / CLUSTER_ZOOM;
219
220 vec3 col = skyColor(p);
221
222 float worldClusterDist = length(world - cluster);
223 float auroraMask = smoothstep(0.0, 0.07, worldClusterDist);
224 col += aurora(world, t) * auroraMask * 0.75;
225 col += aurora(world * 1.05 + vec2(0.12, -0.04), t * 1.08) * auroraMask * 0.35;
226
227 vec2 c = p;
228 float clusterDist = length(c);
229 float clusterClear = smoothstep(0.04, 0.18, clusterDist);
230 float fieldMask = smoothstep(0.04, 0.18, clusterDist);
231
232 vec2 np = rot(t * 0.06) * p;
233 col += nebulaLayer(np, t, 0.11) * 0.2 * clusterClear;
234 col += nebulaLayer(np * 1.25 + 2.1, t * 1.05, -0.08) * 0.12 * clusterClear;
235 col += nebulaLayer(np * 0.85 - 1.4, t * 0.8, 0.15) * 0.08 * clusterClear;
236
237 float vor = vortexEnergy(c, t);
238 col += mix(COL_CYAN, COL_MAGENTA, vor) * exp(-clusterDist * 2.4) * 0.12 * clusterClear;
239
240 float tendrils = fbm(c * 2.8 + vec2(0.0, t * 0.22));
241 col += COL_TEAL * smoothstep(0.52, 0.78, tendrils) * exp(-clusterDist * 2.6) * 0.1 * clusterClear;
242 col += COL_MAGENTA * smoothstep(0.58, 0.82, fbm(c * 3.4 - t * 0.18)) * exp(-clusterDist * 3.2) * 0.06 * clusterClear;
243
244 float portal = exp(-clusterDist * 5.5);
245 col += mix(COL_VIOLET, COL_MAGENTA, sin(t * 0.9) * 0.5 + 0.5) * portal * 0.08 * clusterClear;
246
247 col += fieldStars(p, t) * fieldMask * 0.85;
248
249 addClusterStar(col, c, vec2(-0.055, 0.075), 0.0026, 0.35, 1.1, t, 41.0);
250 addClusterStar(col, c, vec2(-0.038, 0.018), 0.003, 0.45, 1.3, t, 42.0);
251 addClusterStar(col, c, vec2(0.0, 0.0), 0.005, 0.58, 2.4, t, 43.0);
252 addClusterStar(col, c, vec2(0.032, -0.022), 0.0028, 0.4, 1.2, t, 44.0);
253 addClusterStar(col, c, vec2(0.058, 0.012), 0.0032, 0.5, 1.4, t, 45.0);
254 addClusterStar(col, c, vec2(-0.048, -0.048), 0.0022, 0.25, 0.85, t, 46.0);
255 addClusterStar(col, c, vec2(0.042, -0.058), 0.0024, 0.3, 0.9, t, 47.0);
256 addClusterStar(col, c, vec2(0.078, 0.058), 0.0021, 0.2, 0.72, t, 48.0);
257 addClusterStar(col, c, vec2(-0.072, 0.048), 0.002, 0.22, 0.68, t, 49.0);
258
259 float pulse = 0.5 + 0.5 * sin(t * 3.0);
260 col += COL_CYAN * pulse * 0.02 * sin(clusterDist * 24.0 - t * 4.0) * clusterClear;
261 col += COL_MAGENTA * pulse * 0.02 * cos(clusterDist * 20.0 + t * 3.5) * clusterClear;
262
263 col *= 1.0 - dot(p * 0.2, p * 0.2);
264 gl_FragColor = vec4(col, 1.0);
265}
266