// Flow family: curtains of light standing above the track's horizon. // // Distinct from Curl Flow (a full-frame advected field) and Silk Ribbon (one // strand): this is several tall vertical sheets, each rippling on its own phase, // dense at the base and dissolving upward. The rippling is a sum of sines rather // than noise, which is what gives an aurora its folded-sheet look instead of a // smoky one — noise curtains read as fog. // // The horizon is the track's, so this stands in the same place as every other // scene that has ground. export const auroraVeil = { name: 'Aurora Veil', family: 'flow', kind: 'fragment', // Paints 13% of the frame — see checks/phase12 coverage. surface: 'composable', consumes: ['ink'], traits: ['camera', 'space', 'style'], params: { curtains: { type: 'int', range: [2, 9], default: 4, uniform: 'u_curtains', bias: 'density' }, height: { type: 'float', range: [0.4, 1.8], default: 1.0, uniform: 'u_height' }, fold: { type: 'float', range: [0.1, 1.4], default: 0.55, uniform: 'u_fold', bias: 'density' }, speed: { type: 'float', range: [0.03, 0.5], default: 0.15, uniform: 'u_speed', bias: 'motion', rate: true }, ground: { type: 'float', range: [0, 0.8], default: 0.3, uniform: 'u_ground' }, palette: { type: 'palette', count: 5 }, }, reactive: { fold: { feature: 'bandLow', amount: 0.3, response: 'smooth' }, }, shader: ` vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_speed + u_seed; p = sigCamera(p); float horizon = sigHorizonY() * 0.8 - 0.55; float above = p.y - horizon; vec3 col = pal(0) * 0.06; for (int i = 0; i < 9; i++) { if (i >= u_curtains) break; float fi = float(i); float s = u_seed + fi * 37.13; // Each sheet is a vertical line whose x wanders as a sum of three sines. // Three is the fewest that stops reading as a single wobble. float x = (fract(s * 0.61) - 0.5) * 2.2 + sin(above * 1.7 + t * 1.3 + s) * u_fold * 0.35 + sin(above * 3.1 - t * 0.8 + s * 1.7) * u_fold * 0.18 + sin(above * 0.7 + t * 0.4 + s * 2.3) * u_fold * 0.5; float d = abs(p.x - x); float widthAt = 0.05 + above * 0.06 + u_sigLine * 0.05; // Bright and tight at the base, wide and faint at the top: the vertical // falloff is what makes it a curtain rather than a stripe. float rise = smoothstep(-0.05, 0.0, above) * exp(-max(above, 0.0) / max(u_height, 0.05)); float sheet = exp(-d * d / max(widthAt * widthAt, 1e-5)) * rise; vec3 tint = palRamp(fract(s) * 0.5 + above * 0.12 + 0.1); col += tint * sheet * (0.55 + 0.5 * 0.6); } // Ground: the curtains reflected, dim and compressed. if (u_ground > 0.01 && above < 0.0) { float below = -above; col += pal(2) * u_ground * exp(-below * 6.0) * 0.35; } col = sigAir(col, p, smoothstep(0.0, 1.6, abs(p.x))); return vec4(inkValue(col), 1.0); } `, }; export default auroraVeil;