The aurora shader
One fullscreen triangle, raw WebGL 1, one fragment shader, three uniforms:
uRes, uTime, and uProg — smoothed scroll
progress from 0 (night) to 1 (dawn). The foundation is value-noise fbm:
float fbm(vec2 p) {
float v = 0.0, a = 0.5;
mat2 r = mat2(0.8, -0.6, 0.6, 0.8); // rotate each octave
for (int i = 0; i < 5; i++) {
v += a * noise(p);
p = r * p * 2.03;
a *= 0.55;
}
return v;
}
An aurora curtain is built from four ingredients, all driven by fbm: a horizontal
bend that warps x so the arc snakes across the sky; a broad brightness
wave along the arc; sharpened rays (noise taken to a high power)
for the vertical folds; and a wandering base altitude the curtain hangs from.
The vertical envelope is the auroral signature — a bright lower rim that decays upward:
float base = 0.30 + 0.20 * fbm(vec2(uv.x * 1.1, t * 0.025));
float h = uv.y - base;
float env = smoothstep(-0.02, 0.07, h) * exp(-max(h, 0.0) * 2.7);
Three curtain layers at different scales and time multipliers overlap into depth.
Color is a two-stop ramp — emerald core at the rim, violet fringe above — and both
stops are themselves interpolated by uProg, so the aurora cools from
emerald/violet to cyan/blue as the sky turns teal, then dissolves entirely as dawn
arrives and hands the sky to rose-gold cirrus and a rising sun disc.
Scroll-hue interpolation
The sky itself is three vertical gradients — night, teal, dawn — blended by smoothstep
weights of uProg. Stars live on a hashed grid, twinkle on per-star phase,
drift slowly west, and fade out between 35% and 72% scroll. A shooting star fires on a
nine-second cycle with a 55% chance, night only. Banding is killed with a ±1/255 hash dither.
Motion choreography
Scroll progress is lerped (smooth += (target - smooth) * dt * 3.2) so the
sky always arrives a beat after you do. DOM motion follows the same philosophy: headline
lines rise out of overflow-hidden wrappers with a blur that clears — light through fog —
on 1.2s expo-out curves. Parallax is depth-tagged (data-depth) and computed
in one rAF pass. With prefers-reduced-motion, the shader renders a single
still frame (repainted on scroll so the palette journey survives), parallax is off, and
reveals are instant.