export declare const PASSTHROUGH_VERT_SRC = "#version 300 es\nprecision highp float;\nout highp vec2 vUv;\nvoid main() {\n vec2 p = vec2(float((gl_VertexID & 1) << 1), float(gl_VertexID & 2));\n vUv = p * 0.5;\n gl_Position = vec4(p - 1.0, 0.0, 1.0);\n}\n"; export declare const COMPOSITE_CAMERA_FRAG_SRC = "#version 300 es\nprecision highp float;\nuniform sampler2D uCamera;\nin highp vec2 vUv;\nout vec4 oColor;\nvoid main() {\n oColor = vec4(texture(uCamera, vUv).rgb, 1.0);\n}\n"; export declare const COMPOSITE_BLUR_FRAG_SRC = "#version 300 es\nprecision highp float;\nuniform sampler2D uTex;\nuniform vec2 uDir;\nuniform float uSigma;\nin highp vec2 vUv;\nout vec4 oColor;\nvoid main() {\n float s2 = 2.0 * uSigma * uSigma;\n float w[7];\n float sum = 0.0;\n for (int i = 0; i < 7; i++) {\n w[i] = exp(-(float(i) * float(i)) / s2);\n sum += (i == 0) ? w[i] : 2.0 * w[i];\n }\n float spread = uSigma * 0.25;\n vec4 acc = texture(uTex, vUv) * (w[0] / sum);\n for (int i = 1; i < 7; i++) {\n vec2 off = uDir * float(i) * spread;\n acc += texture(uTex, vUv + off) * (w[i] / sum);\n acc += texture(uTex, vUv - off) * (w[i] / sum);\n }\n oColor = acc;\n}\n"; export declare const COMPOSITE_IMAGE_FRAG_SRC = "#version 300 es\nprecision highp float;\nuniform sampler2D uTex;\nuniform vec2 uCoverScale;\nin highp vec2 vUv;\nout vec4 oColor;\nvoid main() {\n vec2 uv = (vUv - 0.5) * uCoverScale + 0.5;\n vec4 c = texture(uTex, uv);\n oColor = vec4(c.rgb * c.a, c.a);\n}\n"; export declare const COMPOSITE_SUBJECT_FRAG_SRC = "#version 300 es\nprecision highp float;\nuniform sampler2D uCamera;\nuniform sampler2D uMask;\nuniform vec2 uMaskUvScale;\nuniform vec2 uMaskUvOffset;\nuniform float uMaskLo;\nuniform float uMaskHi;\nin highp vec2 vUv;\nout vec4 oColor;\nvoid main() {\n vec3 cam = texture(uCamera, vUv).rgb;\n float raw = texture(uMask, vUv * uMaskUvScale + uMaskUvOffset).r;\n float safeHi = max(uMaskHi, uMaskLo + 0.001);\n float a = clamp(smoothstep(uMaskLo, safeHi, raw), 0.0, 1.0);\n oColor = vec4(cam * a, a);\n}\n"; export declare const COMPOSITE_MASKED_FRAG_SRC = "#version 300 es\nprecision highp float;\nuniform sampler2D uTex;\nuniform sampler2D uMask;\nuniform vec2 uMaskUvScale;\nuniform vec2 uMaskUvOffset;\nuniform float uMaskLo;\nuniform float uMaskHi;\nin highp vec2 vUv;\nout vec4 oColor;\nvoid main() {\n vec4 c = texture(uTex, vUv);\n float raw = texture(uMask, vUv * uMaskUvScale + uMaskUvOffset).r;\n float safeHi = max(uMaskHi, uMaskLo + 0.001);\n float a = clamp(smoothstep(uMaskLo, safeHi, raw), 0.0, 1.0);\n oColor = c * a;\n}\n"; export declare const PLASMA_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uColorA; // first palette color, linear-ish RGB in [0, 1]\nuniform vec3 uColorB; // second palette color, linear-ish RGB in [0, 1]\nuniform float uSpeed; // animation rate multiplier; 0 freezes the field\nuniform float uScale; // spatial frequency; higher = more, tighter cells\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nvoid main() {\n // Aspect-correct, screen-centered coordinates (matches nebula.frag): divide\n // by the height so uScale reads the same regardless of aspect ratio.\n vec2 fragCoord = vUv * uResolution;\n vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;\n\n float t = uTime * uSpeed;\n\n // Classic demoscene plasma: a few sines of position and time. The radial\n // term (length(uv)) gives the field an organic, non-grid-aligned drift.\n float v = sin(uv.x * uScale + t);\n v += sin(uv.y * uScale + t * 0.8);\n v += sin((uv.x + uv.y) * uScale * 0.7 + t * 1.3);\n v += sin(length(uv) * uScale * 1.2 - t);\n\n // v ranges roughly [-4, 4]; fold through sin to a smooth [0, 1] mix factor.\n float mixT = 0.5 + 0.5 * sin(v);\n\n // Opaque procedural background; the person is composited over it downstream.\n oColor = vec4(mix(uColorA, uColorB, mixT), 1.0);\n}\n"; export declare const KALEIDOSCOPE_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uColorA; // base palette color (also the calm midpoint pole)\nuniform vec3 uColorB; // second palette color\nuniform vec3 uColorC; // accent color, layered over the A/B field\nuniform float uSegments; // mirror segment count; floor()ed, clamped >= 3\nuniform float uSpeed; // source-field drift rate; 0 freezes the pattern\nuniform float uRotate; // whole-field rotation rate; sign sets direction\nuniform float uZoom; // pattern scale; higher = more rings of detail\nuniform float uCalm; // 0..1 eases contrast at frame center (face zone)\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nconst float TAU = 6.28318530718;\n\nvoid main() {\n // Aspect-correct, screen-centered coordinates (matches plasma/nebula).\n vec2 fragCoord = vUv * uResolution;\n vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;\n float centerDist = length(uv);\n\n // Whole-field rotation: the slow \"turning the scope\" motion.\n float ra = uTime * uRotate;\n float cs = cos(ra);\n float sn = sin(ra);\n uv = mat2(cs, -sn, sn, cs) * uv;\n\n // Mirrored polar fold. The 1e-5 nudge keeps atan() off the undefined (0,0)\n // input under Metal; it is far below one pixel at any resolution.\n float r = centerDist * uZoom * (1.0 + 0.06 * sin(uTime * 0.23));\n float seg = TAU / max(3.0, floor(uSegments));\n float a = atan(uv.y, uv.x + 1e-5);\n a = mod(a, seg);\n a = abs(a - seg * 0.5);\n vec2 p = r * vec2(cos(a), sin(a));\n\n float t = uTime * uSpeed;\n\n // Drifting source field, plasma-class: a few sines of folded position and\n // time. The off-axis moving center in the length() term keeps the pattern\n // evolving (non-repeating) rather than pulsing in place.\n float f1 = sin(p.x * 6.0 + t)\n + sin((p.x + p.y) * 4.2 - t * 0.7)\n + sin(length(p - vec2(0.9 + 0.25 * sin(t * 0.31), 0.0)) * 7.0 + t * 1.1);\n float f2 = sin(p.y * 5.0 - t * 0.9 + sin(p.x * 3.1 + t * 0.4));\n float m1 = 0.5 + 0.5 * sin(f1);\n float m2 = smoothstep(0.25, 0.9, 0.5 + 0.5 * sin(f2 + f1 * 0.5));\n\n vec3 color = mix(uColorA, uColorB, m1);\n color = mix(color, uColorC, m2 * 0.65);\n\n // Thin darkening along both mirror lines sells the cut-glass facets.\n float seam = smoothstep(0.035, 0.0, abs(a - seg * 0.5)) + smoothstep(0.035, 0.0, a);\n color *= 1.0 - 0.18 * seam;\n\n // uCalm: ease toward the palette midpoint near frame center. Spatial-only\n // (never scales time per pixel, which would shear the field across the\n // falloff ring).\n vec3 mid = 0.5 * (uColorA + uColorB);\n float calm = uCalm * (1.0 - smoothstep(0.15, 0.62, centerDist));\n color = mix(color, mid, calm * 0.6);\n\n // Opaque procedural background; the person is composited over it downstream.\n oColor = vec4(color, 1.0);\n}\n"; export declare const NEO_MEMPHIS_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uBgColor; // field color behind the shapes\nuniform vec3 uColorA; // shape palette color 1\nuniform vec3 uColorB; // shape palette color 2\nuniform vec3 uColorC; // shape palette color 3\nuniform float uScale; // hero-grid cells across frame height\nuniform float uDensity; // probability a cell draws its shape, 0..1\nuniform float uOutline; // probability a shape renders outlined, 0..1\nuniform float uDrift; // scroll + rotation rate; 0 freezes\nuniform float uCalm; // 0..1 fades shapes near frame center (face zone)\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nconst float TAU = 6.28318530718;\n// Antialias half-width in cell units; ~1px at the default pitch.\nconst float AA = 0.012;\n\nfloat hash21(vec2 p) {\n p = fract(p * vec2(234.34, 435.345));\n p += dot(p, p + 34.23);\n return fract(p.x * p.y);\n}\n\nfloat sdBox(vec2 p, vec2 b) {\n vec2 d = abs(p) - b;\n return length(max(d, vec2(0.0))) + min(max(d.x, d.y), 0.0);\n}\n\n// iq's equilateral triangle, point up, circumradius r.\nfloat sdTriangle(vec2 p, float r) {\n const float k = 1.7320508;\n p.x = abs(p.x) - r;\n p.y = p.y + r / k;\n if (p.x + k * p.y > 0.0) {\n p = vec2(p.x - k * p.y, -k * p.x - p.y) * 0.5;\n }\n p.x -= clamp(p.x, -2.0 * r, 0.0);\n return -length(p) * sign(p.y);\n}\n\n// One cell layer: returns the shape coverage and writes its color.\n// luv is the layer's scrolled cell-space coordinate; backfill restricts the\n// shape menu to dots and crosses and draws smaller.\nfloat memphisCell(vec2 luv, float seed, float backfill, float t, out vec3 shapeColor) {\n vec2 id = floor(luv);\n vec2 gv = fract(luv) - 0.5;\n float h = hash21(id + seed);\n shapeColor = uBgColor;\n // Density gate: empty cells cost one hash.\n if (h > uDensity) return 0.0;\n\n float h2 = fract(h * 57.31);\n float h3 = fract(h * 113.77);\n float h4 = fract(h * 431.13);\n float h5 = fract(h * 891.71);\n\n // Per-cell slow spin and a small bob; both bounded so the shape stays\n // inside its cell (max extent 0.34 + 0.04 < 0.5).\n float ang = h2 * TAU + t * (h3 - 0.5) * 0.8;\n float cs = cos(ang);\n float sn = sin(ang);\n gv -= 0.04 * vec2(sin(t * 0.6 + h * TAU), cos(t * 0.8 + h * TAU));\n gv = mat2(cs, -sn, sn, cs) * gv;\n\n float r = mix(0.14, 0.30, h3) * mix(1.0, 0.6, backfill);\n float pick = h4 * 6.0;\n float d;\n if (backfill > 0.5) {\n // Backfill texture: dots and crosses only.\n d = (pick < 3.0)\n ? length(gv) - r * 0.45\n : min(sdBox(gv, vec2(r, r * 0.22)), sdBox(gv, vec2(r * 0.22, r)));\n } else if (pick < 1.0) {\n d = length(gv) - r; // disc\n } else if (pick < 2.0) {\n d = abs(length(gv) - r * 0.8) - r * 0.18; // ring\n } else if (pick < 3.0) {\n d = sdTriangle(gv, r); // triangle\n } else if (pick < 4.0) {\n d = min(sdBox(gv, vec2(r, r * 0.24)), sdBox(gv, vec2(r * 0.24, r))); // cross\n } else if (pick < 5.0) {\n d = sdBox(gv, vec2(r * 0.78, r * 0.78)); // box\n } else {\n // Squiggle: a sine-displaced band, clipped to its run length.\n d = max(abs(gv.y - 0.4 * r * sin(gv.x / r * 6.5)) - r * 0.17, abs(gv.x) - r);\n }\n\n float fill = smoothstep(AA, -AA, d);\n float ring = smoothstep(AA, -AA, abs(d + r * 0.06) - r * 0.09);\n float m = (h5 < uOutline) ? ring : fill;\n\n float colorPick = fract(h * 769.23) * 3.0;\n shapeColor = (colorPick < 1.0) ? uColorA : (colorPick < 2.0) ? uColorB : uColorC;\n return m;\n}\n\nvoid main() {\n // Aspect-correct, screen-centered coordinates (matches plasma/nebula).\n vec2 fragCoord = vUv * uResolution;\n vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;\n float centerDist = length(uv);\n\n float t = uTime * uDrift;\n vec3 color = uBgColor;\n vec3 shapeColor;\n\n // Backfill layer first (under the hero shapes): smaller, denser, dimmer.\n vec2 luv1 = uv * uScale * 2.3 + vec2(t * 0.045, t * -0.03) + 51.7;\n float m1 = memphisCell(luv1, 7.0, 1.0, t, shapeColor);\n color = mix(color, mix(uBgColor, shapeColor, 0.55), m1);\n\n // Hero layer: the big shapes, scrolling the other way.\n vec2 luv0 = uv * uScale + vec2(t * -0.06, t * 0.04);\n float m0 = memphisCell(luv0, 0.0, 0.0, t, shapeColor);\n\n // uCalm: fade shapes (not the field) near frame center.\n float calm = 1.0 - uCalm * (1.0 - smoothstep(0.15, 0.62, centerDist));\n color = mix(color, shapeColor, m0 * calm);\n\n // Opaque procedural background; the person is composited over it downstream.\n oColor = vec4(color, 1.0);\n}\n"; export declare const HALFTONE_WAVES_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uPaper; // field color (behind the dots)\nuniform vec3 uInk; // dot color\nuniform float uPitch; // dot-grid cells across frame height\nuniform float uDotSize; // base dot radius in cell units, 0..0.5\nuniform float uWaveAmp; // radius modulation depth, 0..1\nuniform float uSpeed; // wave travel rate; 0 freezes\nuniform float uShape; // dot shape: 0 diamond, 1 circle, 2 square\nuniform float uAngle; // wave direction, radians\nuniform float uCalm; // 0..1 eases the waves at frame center (face zone)\n\nin highp vec2 vUv;\nout vec4 oColor;\n\n// Antialias half-width in cell units; ~1px at the default pitch.\nconst float AA = 0.06;\n\nvoid main() {\n // Aspect-correct, screen-centered coordinates (matches plasma/nebula).\n vec2 fragCoord = vUv * uResolution;\n vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;\n float centerDist = length(uv);\n\n vec2 luv = uv * uPitch;\n vec2 id = floor(luv);\n vec2 gv = fract(luv) - 0.5;\n // Wave phase is sampled at the CELL CENTER so a dot's radius is uniform\n // across its own pixels (true halftone, not a warped field).\n vec2 c = (id + 0.5) / uPitch;\n\n float t = uTime * uSpeed;\n vec2 dir1 = vec2(cos(uAngle), sin(uAngle));\n vec2 dir2 = vec2(cos(uAngle + 2.2), sin(uAngle + 2.2));\n // Two traveling waves at incommensurate frequencies: interference patterns\n // that drift forever without visibly repeating.\n float w = 0.5 + 0.25 * sin(dot(c, dir1) * 3.1 + t) + 0.25 * sin(dot(c, dir2) * 4.7 - t * 0.77);\n\n // uCalm: flatten the modulation toward its midpoint near frame center.\n float calm = uCalm * (1.0 - smoothstep(0.15, 0.62, centerDist));\n w = mix(w, 0.5, calm);\n\n float radius = uDotSize * mix(1.0 - uWaveAmp, 1.0 + uWaveAmp, w);\n\n // Blended distance metric, pow-free (variable-exponent pow lowers to\n // exp2+log2 on mobile): diamond (L1) -> circle (L2) -> square (Linf).\n vec2 q = abs(gv);\n float dDiamond = (q.x + q.y) * 0.7071;\n float dCircle = length(q);\n float dSquare = max(q.x, q.y);\n float d = (uShape < 1.0)\n ? mix(dDiamond, dCircle, clamp(uShape, 0.0, 1.0))\n : mix(dCircle, dSquare, clamp(uShape - 1.0, 0.0, 1.0));\n\n float m = smoothstep(radius + AA, radius - AA, d);\n vec3 color = mix(uPaper, uInk, m);\n\n // Opaque procedural background; the person is composited over it downstream.\n oColor = vec4(color, 1.0);\n}\n"; export declare const AURORA_SILK_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uColorLow; // gradient color at the flow's low side\nuniform vec3 uColorHigh; // gradient color at the flow's high side\nuniform vec3 uRibbonColor; // ribbon tint; shades blend toward uColorHigh\nuniform float uRibbons; // visible ribbon count, 1..5 (MAX_RIBBONS)\nuniform float uSoftness; // ribbon edge softness, 0..1\nuniform float uAngle; // flow direction, radians\nuniform float uSpeed; // drift rate; 0 freezes\nuniform float uStyle; // 0 flat paper-cut .. 1 glowing silk\nuniform float uCalm; // 0..1 eases ribbons at frame center (face zone)\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nconst int MAX_RIBBONS = 5;\n\nfloat hash11(float n) {\n return fract(sin(n) * 43758.5453123);\n}\n\n// 1D value noise: smooth, cheap, non-repeating drift source per ribbon.\nfloat vnoise(float x, float seed) {\n float i = floor(x);\n float f = fract(x);\n float a = hash11(i + seed);\n float b = hash11(i + 1.0 + seed);\n return mix(a, b, f * f * (3.0 - 2.0 * f));\n}\n\nvoid main() {\n // Aspect-correct, screen-centered coordinates (matches plasma/nebula).\n vec2 fragCoord = vUv * uResolution;\n vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;\n float centerDist = length(uv);\n\n // Rotate into flow space: ribbons run along q.x, stack along q.y.\n float cs = cos(uAngle);\n float sn = sin(uAngle);\n vec2 q = mat2(cs, -sn, sn, cs) * uv;\n\n float t = uTime * uSpeed;\n\n // Base: soft two-stop gradient across the stacking axis, with a slow\n // breathing tilt so the field is alive even at uRibbons = 0 edge cases.\n float g = clamp(q.y * 0.85 + 0.5 + 0.04 * sin(t * 0.17), 0.0, 1.0);\n vec3 color = mix(uColorLow, uColorHigh, g);\n\n float ribbons = clamp(uRibbons, 0.0, float(MAX_RIBBONS));\n float calm = 1.0 - uCalm * (1.0 - smoothstep(0.15, 0.62, centerDist));\n\n for (int i = 0; i < MAX_RIBBONS; i++) {\n float fi = float(i);\n if (fi >= ribbons) break;\n\n // Stack centers across the frame, each with its own slow vertical sway.\n float center = -0.42 + 0.84 * (fi + 0.5) / ribbons + 0.07 * sin(t * 0.19 + fi * 1.7);\n // Lateral warp: low-frequency noise plus one sine, per-ribbon phase and\n // rate so the bands never move in lockstep.\n float warp = (vnoise(q.x * 1.4 + t * (0.1 + 0.04 * fi), fi * 17.0) - 0.5) * 0.5\n + 0.1 * sin(q.x * 2.3 + t * (0.26 + 0.06 * fi) + fi * 2.1);\n float dy = abs(q.y - (center + warp));\n\n float widthR = mix(0.06, 0.15, hash11(fi * 7.3 + 1.0));\n float soft = mix(0.008, widthR * 1.6, uSoftness);\n float band = (1.0 - smoothstep(widthR - soft, widthR + soft, dy)) * calm;\n\n // Ribbon shade: deeper tints at the back of the stack.\n vec3 rc = mix(uRibbonColor, uColorHigh, fi / float(MAX_RIBBONS) * 0.6);\n\n // uStyle blends two composites of the same band: flat paint-over vs\n // additive glow.\n vec3 flat_ = mix(color, rc, band * 0.85);\n vec3 glow = color + rc * band * 0.4;\n color = mix(flat_, glow, uStyle);\n }\n\n // Opaque procedural background; the person is composited over it downstream.\n oColor = vec4(color, 1.0);\n}\n"; export declare const OUTRUN_GRID_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uSkyTop; // sky gradient color at the top of frame\nuniform vec3 uSkyHorizon; // sky gradient color at the horizon\nuniform vec3 uSunTop; // sun gradient color at its top\nuniform vec3 uSunBottom; // sun gradient color at its bottom\nuniform vec3 uGridColor; // neon grid line tint (also the horizon seam)\nuniform float uGridDensity; // grid cells across the floor; higher = finer\nuniform float uGridGlow; // line glow width/softness, 0..1\nuniform float uSpeed; // grid scroll rate toward the viewer; 0 freezes\nuniform float uSunSize; // sun radius in vUv.y units\nuniform float uSunBands; // horizontal slit count cut into the sun's lower half\nuniform float uHorizon; // horizon height in vUv.y, 0..1 (floor below, sky above)\nuniform float uCalm; // 0..1 eases the additive glow at frame center (face zone)\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nvoid main() {\n float aspect = uResolution.x / uResolution.y;\n float fx = (vUv.x - 0.5) * aspect; // aspect-correct, screen-centered x\n float fy = vUv.y; // 0 bottom .. 1 top\n float h = clamp(uHorizon, 0.05, 0.95);\n\n // Ease additive glow near the frame center (the subject's face sits there).\n float calm = 1.0 - uCalm * (1.0 - smoothstep(0.18, 0.62, length(vec2(fx, fy - 0.5))));\n\n vec3 col;\n\n if (fy > h) {\n // --- SKY ---\n float skyT = (fy - h) / (1.0 - h); // 0 at horizon, 1 at the top of frame\n col = mix(uSkyHorizon, uSkyTop, skyT);\n\n // --- SUN --- centered just above the horizon so its lower arc sinks below\n // it and is occluded by the floor (the half-set sun, for free).\n float sunCY = h + uSunSize * 0.55;\n vec2 sd = vec2(fx, fy - sunCY);\n float r = length(sd) / max(uSunSize, 1e-3); // normalized radius, 1 at the edge\n\n // Soft glow halo bleeding into the sky around the disc.\n float halo = exp(-max(r - 1.0, 0.0) * 5.5);\n col += uSunTop * halo * 0.55 * calm;\n\n // Sun body: vertical gradient, with horizontal bands cut from the lower half\n // (each gap thickening toward the bottom, the iconic retrowave slit pattern).\n float disc = smoothstep(1.0, 0.985, r);\n float vy = clamp(sd.y / max(uSunSize, 1e-3) * 0.5 + 0.5, 0.0, 1.0);\n vec3 sunCol = mix(uSunBottom, uSunTop, vy);\n\n float below = max(-sd.y / max(uSunSize, 1e-3), 0.0); // 0 above center, grows downward\n // Drift the slit phase over time so the sun's scanlines crawl downward.\n float slit = fract(below * uSunBands - uTime * 0.18);\n float gapW = clamp(below, 0.0, 1.0) * 0.85; // gap fraction grows downward\n float cut = step(slit, gapW) * smoothstep(0.04, 0.12, below); // keep upper sun whole\n float sunBody = disc * (1.0 - cut);\n\n col = mix(col, sunCol, sunBody);\n } else {\n // --- FLOOR --- perspective grid, a faithful port of a known-good community\n // outrun grid (prior versions read as a too-dense, flickering sheet). Work in\n // the reference's centered frame: cx is full-width centered x, dy is the\n // centered distance BELOW the horizon. The additive offset caps the depth at\n // the horizon, and putting big cells in the near field (low min depth) is what\n // keeps the line spacing above a pixel, so it neither sheets nor shimmers.\n float cx = 2.0 * fx; // = (2*vUv.x - 1) * aspect\n float dy = 2.0 * (h - fy); // centered distance below the horizon (> 0)\n\n // Cell count: uGridDensity 4 -> numerator 1.0 (sparse, big near cells). x\n // widens with depth (the 0.7 factor); scroll is a slow drift toward the viewer.\n float num = uGridDensity * 0.25;\n float depth = num / (dy + 0.05);\n vec2 g = vec2(cx * depth * 0.7, depth);\n g.y += uTime * uSpeed * 0.3;\n vec2 e = abs(fract(g) - 0.5);\n\n // PIXEL-CALIBRATED line width: each line core is a fixed ~px wide in SCREEN\n // PIXELS (via uResolution), the same at every depth and every resolution. The\n // old depth^2*const width was constant in theory but landed sub-pixel, so\n // discrete sampling rendered some rungs thick and others thin -> the uneven\n // rungs that read as flicker. Solving sz so screen thickness == px: the rungs\n // (g.y, compression ~depth^2/num) need sz.y = depth^2 * pf / num; the verticals\n // (g.x) need sz.x = depth * 0.7 * pf. uGridGlow sets px (0.5 -> 2 px).\n float pf = (uGridGlow * 4.0) / uResolution.y;\n vec2 sz = vec2(depth * 0.7 * pf, depth * depth * pf / num);\n vec2 lines = 1.0 - smoothstep(vec2(0.0), sz, e);\n lines += (1.0 - smoothstep(vec2(0.0), sz * 4.0, e)) * 0.5;\n float gridVal = clamp(lines.x + lines.y, 0.0, 1.0);\n\n // Fade the grid out BEFORE rung spacing goes sub-pixel near the horizon: that\n // zone moires/shimmers as it scrolls no matter how clean each line is (a second\n // flicker source, separate from line width). subpx is the depth at which rungs\n // are ~2 px apart, derived from uResolution; the seam glow below covers the\n // faded edge so the horizon still reads as a bright line.\n float subpx = sqrt(num * uResolution.y * 0.25);\n gridVal *= 1.0 - smoothstep(subpx * 0.55, subpx, depth);\n\n vec3 floorBase = uSkyHorizon * 0.06;\n col = mix(floorBase, uGridColor, gridVal * calm);\n }\n\n // Glowing horizon seam where floor meets sky.\n float seam = exp(-abs(fy - h) * 90.0);\n col += uGridColor * seam * 0.5 * calm;\n\n oColor = vec4(col, 1.0);\n}\n"; export declare const CLOUDS_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform vec3 uSkyLowColor;\nuniform vec3 uSkyHighColor;\nuniform vec3 uCloudLightColor;\nuniform vec3 uCloudDarkColor;\nuniform float uExposure;\nuniform float uStepSize;\nuniform float uCloudSpeed;\nuniform float uCloudScale;\nuniform float uDensity;\nuniform float uCoverage;\nuniform float uSoftness;\n\nin highp vec2 vUv;\nout vec4 oColor;\n\n// STEPS must stay a compile-time constant (GLSL ES loop bound).\n// 32 (was 48; issue #37): the distance-growing step in main() keeps the\n// marched range, so fewer steps buys speed instead of clipping the horizon.\n#define STEPS 32\n\nfloat hash(vec3 p) {\n p = fract(p * 0.3183099 + 0.1);\n p *= 17.0;\n return fract(p.x * p.y * p.z * (p.x + p.y + p.z));\n}\n\nfloat rand(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\nfloat noise(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n return mix(\n mix(\n mix(hash(i + vec3(0,0,0)), hash(i + vec3(1,0,0)), f.x),\n mix(hash(i + vec3(0,1,0)), hash(i + vec3(1,1,0)), f.x),\n f.y),\n mix(\n mix(hash(i + vec3(0,0,1)), hash(i + vec3(1,0,1)), f.x),\n mix(hash(i + vec3(0,1,1)), hash(i + vec3(1,1,1)), f.x),\n f.y),\n f.z);\n}\n\n// 4 octaves (was 5; issue #37): the 5th octave is fine wisp detail the\n// smoothstep(uCoverage, uCoverage + uSoftness, n) threshold mostly eats; each\n// octave is 8 hash() calls per sample, so this is a flat -20% on the march.\nfloat fbm(vec3 p) {\n float v = 0.0;\n float a = 0.5;\n for (int i = 0; i < 4; i++) {\n v += a * noise(p);\n p *= 2.03;\n a *= 0.5;\n }\n return v;\n}\n\nfloat cloudDensity(vec3 p) {\n p += vec3(uTime * uCloudSpeed, 0.0, uTime * uCloudSpeed * 0.35);\n // Outside the slab the height mask is 0, so the sample is 0; bail before fbm.\n if (p.y <= 0.0 || p.y >= 3.0) return 0.0;\n float n = fbm(p * uCloudScale);\n float bottom = smoothstep(0.0, 0.7, p.y);\n float top = smoothstep(3.0, 1.2, p.y);\n float heightMask = bottom * top;\n float cloud = smoothstep(uCoverage, uCoverage + uSoftness, n);\n return cloud * heightMask;\n}\n\nvoid main() {\n vec2 fragCoord = vUv * uResolution;\n vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;\n vec3 ro = vec3(0.0, 1.2, -4.0);\n vec3 rd = normalize(vec3(uv, 1.5));\n float skyGradient = clamp(rd.y * 0.5 + 0.5, 0.0, 1.0);\n vec3 skyColor = mix(uSkyLowColor, uSkyHighColor, skyGradient);\n vec3 accum = vec3(0.0);\n float alpha = 0.0;\n float t = rand(fragCoord) * uStepSize;\n for (int i = 0; i < STEPS; i++) {\n vec3 p = ro + rd * t;\n // The slab is crossed monotonically in t; once past it, all samples are 0.\n if (rd.y > 0.0 && p.y >= 3.0) break;\n if (rd.y < 0.0 && p.y <= 0.0) break;\n float d = cloudDensity(p);\n // Distance-growing step (issue #37): far clouds are small on screen and\n // tolerate coarser sampling, so the step stretches with t. 32 growing\n // steps reach slightly past where 48 uniform steps did, spending the\n // samples up close where banding would show. growth also scales the\n // per-sample opacity so optical depth per unit distance stays consistent\n // with the uniform-step tuning the presets were dialed against.\n float growth = 1.0 + t * 0.15;\n if (d > 0.01) {\n float light = smoothstep(0.4, 2.8, p.y);\n vec3 sampleColor = mix(uCloudDarkColor, uCloudLightColor, light);\n float a = min(d * uDensity * growth, 1.0);\n accum += (1.0 - alpha) * sampleColor * a;\n alpha += (1.0 - alpha) * a;\n }\n t += uStepSize * growth;\n if (alpha > 0.95) break;\n }\n vec3 color = mix(skyColor, accum, alpha);\n color *= uExposure;\n color = pow(color, vec3(0.9));\n oColor = vec4(color, 1.0);\n}\n"; export declare const NEBULA_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uColor; // overall tint / color grade; [1,1,1] = untinted\nuniform float uBrightness; // final glow multiplier; 1.0 = stock\nuniform float uSpeed; // drift + rotation rate; 1.0 = stock, 0 freezes\nuniform float uTwinkleSpeed; // star color-cycle rate; 1.0 = stock\nuniform float uScale; // starfield zoom / density; >1 = more, smaller stars\nuniform float uStarGlow; // star-core size; 1.0 = stock\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nconst float PI = 3.14159265;\nconst float MIN_DIVIDE = 64.0;\nconst float MAX_DIVIDE = 0.01;\n// Number of stacked starfield layers. Compile-time constant so the layer\n// loop has a fixed integer bound (cross-compile-safe; no float loop counter).\n// 7 (was 8 #74, was 12 #39) for cost; the work is linear in the count and\n// dimByDensity rebalances per-star brightness automatically. 7 keeps the dense\n// look essentially intact (6 was visibly sparser at some animation phases);\n// paired with the empty-cell early-out below it lands ~34% under the old 8.\nconst int STARFIELD_LAYERS_COUNT = 7;\n\nmat2 Rotate(float angle) {\n float s = sin(angle);\n float c = cos(angle);\n return mat2(c, -s, s, c);\n}\n\nfloat Star(vec2 uv, float flaresize, float rotAngle, float randomN) {\n float d = length(uv);\n // The concentric fade at the bottom is exactly 0 for d >= 1.0; the star is\n // invisible there, so skip everything (issue #39: a large share of the 3x3\n // neighbor sweep lands outside this radius; the cull is output-identical).\n if (d >= 1.0) return 0.0;\n // Star core. Guard the division: length(uv) can be exactly 0 at a cell\n // center, which yields inf/NaN under Metal. max(d, 1e-4) caps the core\n // brightness without visibly changing the look (the concentric\n // smoothstep fade below already clamps it).\n float starcore = 0.05 * uStarGlow / max(d, 1e-4);\n // Flares exist only on the brightest stars: flaresize is exactly 0 below the\n // smoothstep(0.9, 1.0, size) knee (~90% of cells), and both Rotates feed\n // nothing but the flares. Skipping the block is output-identical, and\n // flaresize is constant per cell, so the branch is coherent (issue #39).\n if (flaresize > 0.0) {\n uv *= Rotate(-2.0 * PI * rotAngle);\n float flareMax = 1.0;\n\n // flares\n float starflares = max(0.0, flareMax - abs(uv.x * uv.y * 3000.0));\n starcore += starflares * flaresize;\n uv *= Rotate(PI * 0.25);\n starflares = max(0.0, flareMax - abs(uv.x * uv.y * 3000.0));\n starcore += starflares * 0.3 * flaresize;\n }\n // light can't go forever, fade it concentrically.\n starcore *= smoothstep(1.0, 0.05, d);\n return starcore;\n}\n\nfloat PseudoRandomizer(vec2 p) {\n // not really random, but it looks random.\n p = fract(p * vec2(123.45, 345.67));\n p += dot(p, p + 45.32);\n return fract(p.x * p.y);\n}\n\nvec3 StarFieldLayer(vec2 uv, float rotAngle) {\n vec3 col = vec3(0.0);\n\n vec2 gv = fract(uv) - 0.5;\n vec2 id = floor(uv);\n\n float deltaTimeTwinkle = uTime * 0.35 * uTwinkleSpeed;\n\n // sweep the 8 neighbors plus the home cell so stars are not clipped at\n // cell borders. Constant 3x3 bounds.\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 offset = vec2(float(x), float(y));\n\n float randomN = PseudoRandomizer(id + offset); // 0..1\n float randoX = randomN - 0.5;\n float randoY = fract(randomN * 45.0) - 0.5;\n vec2 randomPosition = gv - offset - vec2(randoX, randoY);\n // fract trick: random sizes\n float size = fract(randomN * 1356.33);\n float flareSwitch = smoothstep(0.9, 1.0, size);\n float star = Star(randomPosition, flareSwitch, rotAngle, randomN);\n // The per-cell color below is multiplied by `star` at the end, so for any\n // cell whose star is 0 (Star() returns exactly 0 for d >= 1.0, i.e. the\n // empty-sky majority of the 8x9 = 72 cells/pixel) the whole term is 0.\n // Skipping the sin(vec3) color work for those cells is output-identical and\n // is the bulk of the win (issue #74).\n if (star <= 0.0) continue;\n\n // fract trick: random colors\n float randomStarColorSeed = fract(randomN * 2150.0) * (3.0 * PI) * deltaTimeTwinkle;\n vec3 color = sin(vec3(0.7, 0.3, 0.9) * randomStarColorSeed);\n\n // compress\n color = color * (0.4 * sin(deltaTimeTwinkle)) + 0.6;\n // filter\n color = color * vec3(1.0, 0.1, 0.9 + size);\n float dimByDensity = 15.0 / float(STARFIELD_LAYERS_COUNT);\n col += star * size * color * dimByDensity;\n }\n }\n\n return col;\n}\n\nvoid main() {\n // ShaderToy fragCoord, reconstructed from vUv (see header).\n vec2 fragCoord = vUv * uResolution;\n\n // Normalized pixel coordinates centered at screen middle.\n vec2 uv = (fragCoord - 0.5 * uResolution.xy) / uResolution.y;\n\n float deltaTime = uTime * 0.01 * uSpeed;\n\n vec3 col = vec3(0.0);\n\n float rotAngle = deltaTime * 0.09;\n\n // Layer accumulation. Integer-counted loop replacing the original\n // `for (float i = 0.0; i < 1.0; i += 1.0/COUNT)`. With n in [0, COUNT),\n // i = n/COUNT reproduces the exact same {0, 1/N, 2/N, ...} sequence and\n // the same iteration count, so visual output is unchanged; only the loop\n // form is cross-compile-safe.\n for (int n = 0; n < STARFIELD_LAYERS_COUNT; n++) {\n float i = float(n) / float(STARFIELD_LAYERS_COUNT);\n float layerDepth = fract(i + deltaTime);\n float layerScale = mix(MIN_DIVIDE, MAX_DIVIDE, layerDepth);\n float layerFader = layerDepth * smoothstep(0.1, 1.1, layerDepth);\n float layerOffset = i * (3430.0 + fract(i));\n mat2 layerRot = Rotate(rotAngle * i * -10.0);\n uv *= layerRot;\n vec2 starfieldUv = uv * layerScale * uScale + layerOffset;\n col += StarFieldLayer(starfieldUv, rotAngle) * layerFader;\n }\n\n // Glow + color grade, then opaque procedural background.\n col *= uBrightness * uColor;\n oColor = vec4(col, 1.0);\n}\n"; export declare const GODRAYS_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing\nuniform vec2 uResolution; // framebuffer size in pixels\nuniform vec3 uLightColor; // ray tint (linear-ish RGB, 0..1)\nuniform float uRayCount; // number of ray bands\nuniform float uRaySpeed; // drift speed\nuniform float uRayIntensity; // overall brightness / additive strength\nuniform float uRaySoftness; // edge falloff exponent (higher = crisper shafts)\nuniform float uTopGlow; // extra glow concentrated near the top\nuniform float uFadeDistance; // vertical falloff from the top\nuniform float uWobbleAmount; // horizontal wobble magnitude\nuniform float uWobbleSpeed; // wobble animation speed\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nfloat hash(float n) {\n return fract(sin(n) * 43758.5453123);\n}\n\nfloat noise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n\n f = f * f * (3.0 - 2.0 * f);\n\n float a = hash(i.x + i.y * 57.0);\n float b = hash(i.x + 1.0 + i.y * 57.0);\n float c = hash(i.x + (i.y + 1.0) * 57.0);\n float d = hash(i.x + 1.0 + (i.y + 1.0) * 57.0);\n\n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n}\n\nvoid main() {\n // vUv is already 0..1 with bottom-left origin; this is the Shadertoy `uv`.\n vec2 uv = vUv;\n\n float aspect = uResolution.x / uResolution.y;\n vec2 p = uv;\n p.x = (p.x - 0.5) * aspect + 0.5;\n\n float t = uTime;\n float fromTop = 1.0 - uv.y;\n\n float verticalFade = exp(-fromTop * uFadeDistance);\n float topGlow = exp(-fromTop * 8.0) * uTopGlow;\n\n float wobble =\n (noise(vec2(uv.y * 3.0, t * uWobbleSpeed)) - 0.5) * uWobbleAmount;\n\n float rayCoord = (p.x + wobble) * uRayCount;\n\n float raysA = sin(rayCoord + t * uRaySpeed);\n float raysB = sin(rayCoord * 1.73 - t * uRaySpeed * 0.7);\n\n float rays = raysA * 0.65 + raysB * 0.35;\n rays = rays * 0.5 + 0.5;\n rays = pow(rays, uRaySoftness);\n\n float shimmer = noise(vec2(uv.x * 10.0, uv.y * 4.0 - t * 0.3));\n rays *= mix(0.75, 1.25, shimmer);\n\n float alpha = rays * verticalFade * uRayIntensity;\n alpha += topGlow * uRayIntensity;\n alpha = clamp(alpha, 0.0, 1.0);\n\n // Premultiplied additive output: rgb already scaled by alpha.\n vec3 rayColor = uLightColor * alpha;\n oColor = vec4(rayColor, alpha);\n}\n"; export declare const FIREFLIES_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform float uGlowSize;\nuniform float uDotSize;\nuniform float uSpeed;\nuniform float uTwinkle;\nuniform vec3 uColor;\n\nin highp vec2 vUv;\nout vec4 oColor;\n\n#define FIREFLY_COUNT 36\n\nfloat hash(float n) {\n return fract(sin(n) * 43758.5453123);\n}\n\nvec2 fireflyPos(float id, float t) {\n vec2 base = vec2(hash(id * 12.7), hash(id * 31.3));\n float a = hash(id * 5.1) * 6.28318;\n float b = hash(id * 9.7) * 6.28318;\n vec2 drift = vec2(sin(t * uSpeed + a), cos(t * uSpeed * 0.73 + b)) * 0.12;\n return fract(base + drift);\n}\n\nvoid main() {\n vec2 uv = vUv;\n vec2 p = uv;\n p.x *= uResolution.x / uResolution.y;\n vec3 color = vec3(0.0);\n float alpha = 0.0;\n for (int i = 0; i < FIREFLY_COUNT; i++) {\n float id = float(i);\n vec2 pos = fireflyPos(id, uTime);\n pos.x *= uResolution.x / uResolution.y;\n float d = length(p - pos);\n float phase = hash(id * 17.1) * 6.28318;\n float pulse = 0.5 + 0.5 * sin(uTime * uTwinkle + phase);\n pulse = pulse * pulse * sqrt(pulse); // pow(pulse, 2.5): a non-integer pow is ~2 transcendentals on mobile; this is 1 sqrt + 2 muls\n float glow = exp(-d * d / (uGlowSize * uGlowSize));\n float core = smoothstep(uDotSize, 0.0, d);\n float intensity = pulse * (glow * 0.55 + core * 1.4);\n color += uColor * intensity;\n alpha += intensity * 0.55;\n }\n alpha = clamp(alpha, 0.0, 1.0);\n color = clamp(color, 0.0, 1.0);\n oColor = vec4(color, alpha);\n}\n"; export declare const SIMIANLIGHTS_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uColor; // overall tint / color grade; [1,1,1] = untinted\nuniform float uBrightness; // final glow multiplier; 1.0 = stock\nuniform float uSpeed; // drift + rotation rate; 1.0 = stock, 0 freezes\nuniform float uTwinkleSpeed; // star color-cycle rate; 1.0 = stock\nuniform float uScale; // starfield zoom / density; >1 = more, smaller stars\nuniform float uStarGlow; // star-core size; 1.0 = stock\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nconst float PI = 3.14159265;\nconst float MIN_DIVIDE = 3.0;\nconst float MAX_DIVIDE = 0.01;\n// Number of stacked starfield layers. Compile-time constant so the layer\n// loop has a fixed integer bound (cross-compile-safe; no float loop counter).\nconst int STARFIELD_LAYERS_COUNT = 4;\n\nmat2 Rotate(float angle) {\n float s = sin(angle);\n float c = cos(angle);\n return mat2(c, -s, s, c);\n}\n\nfloat Star(vec2 uv, float flaresize, float rotAngle, float randomN) {\n float d = length(uv);\n // The concentric fade at the bottom is exactly 0 for d >= 1.0; the star is\n // invisible there, so skip everything (issue #39: a large share of the 3x3\n // neighbor sweep lands outside this radius; the cull is output-identical).\n if (d >= 1.0) return 0.0;\n // Star core. Guard the division: length(uv) can be exactly 0 at a cell\n // center, which yields inf/NaN under Metal. max(d, 1e-4) caps the core\n // brightness without visibly changing the look (the concentric\n // smoothstep fade below already clamps it).\n float starcore = 0.09 * uStarGlow / max(d, 1e-4);\n // Flares exist only on the brightest stars: flaresize is exactly 0 below the\n // smoothstep(0.9, 1.0, size) knee (~90% of cells), and both Rotates feed\n // nothing but the flares. Skipping the block is output-identical, and\n // flaresize is constant per cell, so the branch is coherent (issue #39).\n if (flaresize > 0.0) {\n uv *= Rotate(-2.0 * PI * rotAngle);\n float flareMax = 1.0;\n\n // flares\n float starflares = max(0.0, flareMax - abs(uv.x * uv.y * 3000.0));\n starcore += starflares * flaresize;\n uv *= Rotate(PI * 0.25);\n starflares = max(0.0, flareMax - abs(uv.x * uv.y * 3000.0));\n starcore += starflares * 0.3 * flaresize;\n }\n // light can't go forever, fade it concentrically.\n starcore *= smoothstep(1.0, 0.05, d);\n return starcore;\n}\n\nfloat PseudoRandomizer(vec2 p) {\n // not really random, but it looks random.\n p = fract(p * vec2(123.45, 345.67));\n p += dot(p, p + 45.32);\n return fract(p.x * p.y);\n}\n\nvec3 StarFieldLayer(vec2 uv, float rotAngle) {\n vec3 col = vec3(0.0);\n\n vec2 gv = fract(uv) - 0.5;\n vec2 id = floor(uv);\n\n float deltaTimeTwinkle = uTime * 0.35 * uTwinkleSpeed;\n\n // sweep the 8 neighbors plus the home cell so stars are not clipped at\n // cell borders. Constant 3x3 bounds.\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 offset = vec2(float(x), float(y));\n\n float randomN = PseudoRandomizer(id + offset); // 0..1\n float randoX = randomN - 0.5;\n float randoY = fract(randomN * 45.0) - 0.5;\n vec2 randomPosition = gv - offset - vec2(randoX, randoY);\n // fract trick: random sizes\n float size = fract(randomN * 1356.33);\n float flareSwitch = smoothstep(0.9, 1.0, size);\n float star = Star(randomPosition, flareSwitch, rotAngle, randomN);\n\n // fract trick: random colors\n float randomStarColorSeed = fract(randomN * 2150.0) * (3.0 * PI) * deltaTimeTwinkle;\n vec3 color = sin(vec3(0.7, 0.3, 0.9) * randomStarColorSeed);\n\n // compress\n color = color * (0.4 * sin(deltaTimeTwinkle)) + 0.6;\n // filter\n color = color * vec3(1.0, 0.1, 0.9 + size);\n float dimByDensity = 15.0 / float(STARFIELD_LAYERS_COUNT);\n col += star * size * color * dimByDensity;\n }\n }\n\n return col;\n}\n\nvoid main() {\n // ShaderToy fragCoord, reconstructed from vUv (see header).\n vec2 fragCoord = vUv * uResolution;\n\n // Normalized pixel coordinates centered at screen middle.\n vec2 uv = (fragCoord - 0.5 * uResolution.xy) / uResolution.y;\n\n float deltaTime = uTime * 0.01 * uSpeed;\n\n vec3 col = vec3(0.0);\n\n float rotAngle = deltaTime * 0.09;\n\n // Layer accumulation. Integer-counted loop replacing the original\n // `for (float i = 0.0; i < 1.0; i += 1.0/COUNT)`. With n in [0, COUNT),\n // i = n/COUNT reproduces the exact same {0, 1/N, 2/N, ...} sequence and\n // the same iteration count, so visual output is unchanged; only the loop\n // form is cross-compile-safe.\n for (int n = 0; n < STARFIELD_LAYERS_COUNT; n++) {\n float i = float(n) / float(STARFIELD_LAYERS_COUNT);\n float layerDepth = fract(i + deltaTime);\n float layerScale = mix(MIN_DIVIDE, MAX_DIVIDE, layerDepth);\n float layerFader = layerDepth * smoothstep(0.1, 1.1, layerDepth);\n float layerOffset = i * (3430.0 + fract(i));\n mat2 layerRot = Rotate(rotAngle * i * -10.0);\n uv *= layerRot;\n vec2 starfieldUv = uv * layerScale * uScale + layerOffset;\n col += StarFieldLayer(starfieldUv, rotAngle) * layerFader;\n }\n\n // Glow + color grade, then opaque procedural background.\n col *= uBrightness * uColor;\n oColor = vec4(col, 1.0);\n}\n"; export declare const ANAMORPHIC_LENSFLARE_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform float uFlareX; // flare X position, 0..1 (drifts slowly around this)\nuniform float uFlareY; // flare Y position, 0..1 (0 = bottom)\nuniform float uIntensity; // overall brightness multiplier\nuniform float uStreakLength; // horizontal streak reach; higher = longer\nuniform float uStreakWidth; // main streak vertical tightness; higher = thinner\nuniform float uGhostStrength; // optical-ghost strength along the flare axis\nuniform vec3 uWarmColor; // core / warm streak tint\nuniform vec3 uBlueColor; // halo / wide-streak tint\nuniform vec3 uPinkColor; // secondary streak / ghost tint\n\nin highp vec2 vUv;\nout vec4 oColor;\n\nfloat softOrb(vec2 uv, vec2 center, float radius) {\n float d = length(uv - center);\n float q = d / radius; // pow(q, 2.0) -> q*q; spirv-opt does not strength-reduce it\n return exp(-q * q);\n}\n\nfloat softStreak(vec2 uv, vec2 center, float width, float length) {\n float yFalloff = exp(-abs(uv.y - center.y) * width);\n float xFalloff = exp(-abs(uv.x - center.x) * length);\n return yFalloff * xFalloff;\n}\n\nvoid main() {\n // ShaderToy uv = fragCoord / iResolution; identical to vUv here.\n vec2 uv = vUv;\n\n // Slow horizontal drift.\n float horizontalDrift = sin(uTime * 0.18) * 0.10;\n vec2 flarePos = vec2(uFlareX + horizontalDrift, uFlareY);\n\n vec3 col = vec3(0.0);\n float alpha = 0.0;\n\n // Main source.\n float core = softOrb(uv, flarePos, 0.022);\n float bloom = softOrb(uv, flarePos, 0.095);\n float outerHalo = softOrb(uv, flarePos, 0.28);\n\n col += vec3(1.0) * core * 1.8;\n col += uWarmColor * bloom * 0.95;\n col += uBlueColor * outerHalo * 0.16;\n\n alpha += core * 0.45;\n alpha += bloom * 0.22;\n alpha += outerHalo * 0.045;\n\n // Moving streak intensity.\n float sweepGlow = 0.85 + 0.15 * sin(uTime * 0.7 + uv.x * 8.0);\n\n // Main + wide anamorphic streaks.\n float mainStreak = softStreak(uv, flarePos, uStreakWidth, uStreakLength);\n float wideStreak = softStreak(uv, flarePos, 70.0, uStreakLength * 0.65);\n\n col += uWarmColor * mainStreak * 1.15 * sweepGlow;\n col += uBlueColor * wideStreak * 0.26 * sweepGlow;\n\n alpha += mainStreak * 0.18;\n alpha += wideStreak * 0.055;\n\n // Secondary colored streaks.\n float upperLine = softStreak(uv, flarePos + vec2(0.0, 0.012), 260.0, uStreakLength * 0.7);\n float lowerLine = softStreak(uv, flarePos - vec2(0.0, 0.010), 240.0, uStreakLength * 0.8);\n\n col += uBlueColor * upperLine * 0.22;\n col += uPinkColor * lowerLine * 0.16;\n\n alpha += (upperLine + lowerLine) * 0.035;\n\n // Optical ghosts along the line from the flare through screen center.\n vec2 center = vec2(0.5);\n vec2 axis = center - flarePos;\n\n vec2 ghost1 = flarePos + axis * 0.45;\n vec2 ghost2 = flarePos + axis * 0.85;\n vec2 ghost3 = flarePos + axis * 1.28;\n vec2 ghost4 = flarePos - axis * 0.35;\n\n float g1 = softOrb(uv, ghost1, 0.070);\n float g2 = softOrb(uv, ghost2, 0.115);\n float g3 = softOrb(uv, ghost3, 0.055);\n float g4 = softOrb(uv, ghost4, 0.095);\n\n col += uPinkColor * g1 * 0.18 * uGhostStrength;\n col += uBlueColor * g2 * 0.15 * uGhostStrength;\n col += uWarmColor * g3 * 0.22 * uGhostStrength;\n col += uBlueColor * g4 * 0.10 * uGhostStrength;\n\n alpha += g1 * 0.040 * uGhostStrength;\n alpha += g2 * 0.035 * uGhostStrength;\n alpha += g3 * 0.050 * uGhostStrength;\n alpha += g4 * 0.030 * uGhostStrength;\n\n // Tiny shimmer to keep it alive.\n float shimmer = 0.97 + 0.03 * sin(uTime * 2.1);\n\n col *= uIntensity * shimmer;\n alpha *= uIntensity * shimmer;\n\n alpha = clamp(alpha, 0.0, 1.0);\n oColor = vec4(col, alpha);\n}\n"; export declare const LIGHT_BEAMS_AND_MOTES_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform float uSpeed; // animation rate; 1.0 = stock, 0 freezes the field\nuniform float uBeamSoftness; // beam polygon edge softness\nuniform float uOverlayAlpha; // overall overlay opacity, applied to final alpha\n\n// Per-beam: a row-major quad (TL, TR, BL, BR; y-up), a color, a fill strength\n// (absolute), and an on/off flag. A disabled beam's quadMask + sins do not execute\n// at all (the flag is uniform, so the branch is coherent across every fragment) --\n// that is how you stop paying for beams you are not using.\nuniform vec2 uBeam1Poly[4];\nuniform vec3 uBeam1Color;\nuniform float uBeam1Alpha;\nuniform float uBeam1On;\nuniform vec2 uBeam2Poly[4];\nuniform vec3 uBeam2Color;\nuniform float uBeam2Alpha;\nuniform float uBeam2On;\nuniform vec2 uBeam3Poly[4];\nuniform vec3 uBeam3Color;\nuniform float uBeam3Alpha;\nuniform float uBeam3On;\n\nuniform float uMoteAlpha; // mote brightness (absolute)\nuniform float uGlowSize; // mote glow radius, in mote-size multiples\nuniform float uMoteCount; // active motes (<= MOTE_COUNT); a coherent break trims the loop\n\nin highp vec2 vUv;\nout vec4 oColor;\n\n// ---------- Mote controls (internal constants) ----------\n#define MOTE_COUNT 128 // loop bound: compile-time constant, not a uniform\n#define DRIFT_SPEED 0.060\n#define FALL_SPEED 0.012\n#define SWIRL_AMOUNT 0.065\n#define TURBULENCE 0.030\n#define MOTE_SIZE_MIN 0.0013\n#define MOTE_SIZE_MAX 0.0048\n\nfloat hash1(float n) {\n return fract(sin(n) * 43758.5453123);\n}\n\nvec2 hash2(float n) {\n return vec2(hash1(n + 11.17), hash1(n + 47.83));\n}\n\nfloat softMote(vec2 uv, vec2 center, float radius) {\n float d = length(uv - center);\n float q = d / radius; // pow(q, 2.0) -> q*q; spirv-opt does not strength-reduce it\n return exp(-q * q);\n}\n\n// Soft convex quad mask, winding-AGNOSTIC: the corners are user-draggable, so the\n// perimeter can wind either way. A point is inside when it is on the same side of\n// all four edges, whichever side that is; product the positive-side smoothsteps and\n// the negative-side ones and keep the larger.\nfloat quadMask(vec2 p, vec2 a, vec2 b, vec2 c, vec2 d, float softness) {\n vec2 e0 = b - a;\n vec2 e1 = c - b;\n vec2 e2 = d - c;\n vec2 e3 = a - d;\n float s0 = e0.x * (p.y - a.y) - e0.y * (p.x - a.x);\n float s1 = e1.x * (p.y - b.y) - e1.y * (p.x - b.x);\n float s2 = e2.x * (p.y - c.y) - e2.y * (p.x - c.x);\n float s3 = e3.x * (p.y - d.y) - e3.y * (p.x - d.x);\n float inNeg =\n smoothstep(-softness, softness, -s0) *\n smoothstep(-softness, softness, -s1) *\n smoothstep(-softness, softness, -s2) *\n smoothstep(-softness, softness, -s3);\n float inPos =\n smoothstep(-softness, softness, s0) *\n smoothstep(-softness, softness, s1) *\n smoothstep(-softness, softness, s2) *\n smoothstep(-softness, softness, s3);\n return max(inNeg, inPos);\n}\n\n// Subtle animated variation inside each beam.\nfloat beamTexture(vec2 uv, float seed) {\n float t = uTime * uSpeed;\n float broadBands = 0.55 + 0.45 * sin(uv.x * 7.0 + uv.y * 4.0 + t * 0.06 + seed);\n float fineBands = 0.75 + 0.25 * sin(uv.x * 23.0 - uv.y * 11.0 + t * 0.11 + seed * 2.7);\n return mix(0.65, 1.0, broadBands * fineBands);\n}\n\n// Geometric coverage of one row-major beam quad at uv (mask * texture, 0..~1), with\n// the row-major -> perimeter reorder folded in. Independent of the beam's alpha.\nfloat beamShape(vec2 uv, vec2 poly[4], float seed) {\n return quadMask(uv, poly[0], poly[1], poly[3], poly[2], uBeamSoftness) * beamTexture(uv, seed);\n}\n\n// Evaluate the three beams once. Returns the GEOMETRIC coverage sum (used to gate +\n// brighten motes and to drive the haze, so per-beam alpha never dims the motes);\n// writes `color` (the geometry-weighted beam hue, for fill and motes) and `litSum`\n// (the alpha-weighted amount, the actual fill brightness/opacity).\nfloat evalBeams(vec2 uv, out vec3 color, out float litSum) {\n float a1 = 0.0;\n float a2 = 0.0;\n float a3 = 0.0;\n if (uBeam1On > 0.5) a1 = beamShape(uv, uBeam1Poly, 1.0);\n if (uBeam2On > 0.5) a2 = beamShape(uv, uBeam2Poly, 8.0);\n if (uBeam3On > 0.5) a3 = beamShape(uv, uBeam3Poly, 14.0);\n\n float geomSum = a1 + a2 + a3;\n color = (uBeam1Color * a1 + uBeam2Color * a2 + uBeam3Color * a3) / max(geomSum, 0.0001);\n litSum = a1 * uBeam1Alpha + a2 * uBeam2Alpha + a3 * uBeam3Alpha;\n return geomSum;\n}\n\n// Accumulate the dust motes for ALL on beams in ONE loop. Each mote is round-\n// robined to an on beam (mote n -> the (n mod nActive)-th on beam) and spawned in\n// THAT beam's (u,v) space: every mote lands in a beam, takes the beam's color, and\n// gets a cheap (u,v) edge falloff -- no screen-space scatter to cull, no per-mote\n// quadMask. n and nActive are uniform across fragments, so the beam pick is\n// COHERENT (same for every pixel), not a divergent per-pixel branch. Motes drift\n// ALONG the beam (fall in v, swirl in u) and wrap, fading at the boundaries so the\n// wrap is never a visible pop. Total mote count is uMoteCount regardless of how\n// many beams are on -- the on beams share the budget.\nvoid addMotes(vec2 uv, inout vec3 col, inout float alpha) {\n float nActive = uBeam1On + uBeam2On + uBeam3On; // on-flags are 0/1\n if (nActive < 0.5) return; // no beams -> no motes\n\n // Motes may spill past the polygon edge by ~softness so the soft fringe is\n // populated; the (u,v) falloff dims them there.\n float fuzz = clamp(uBeamSoftness * 2.0, 0.03, 0.35);\n float slot = 0.0; // round-robin cursor over the on beams (a wrapped counter, no per-mote mod)\n\n for (int n = 0; n < MOTE_COUNT; n++) {\n if (float(n) >= uMoteCount) break; // runtime-tunable mote count (coherent break)\n float seed = float(n) * 91.73;\n\n // Round-robin: this mote goes to the slot-th on beam. Walk the beams,\n // counting on ones; the slot-th match wins.\n float picked = 0.0;\n vec2 tl = vec2(0.0);\n vec2 tr = vec2(0.0);\n vec2 bl = vec2(0.0);\n vec2 br = vec2(0.0);\n vec3 color = vec3(0.0);\n if (uBeam1On > 0.5) {\n if (abs(picked - slot) < 0.5) {\n tl = uBeam1Poly[0]; tr = uBeam1Poly[1]; bl = uBeam1Poly[2]; br = uBeam1Poly[3];\n color = uBeam1Color;\n }\n picked += 1.0;\n }\n if (uBeam2On > 0.5) {\n if (abs(picked - slot) < 0.5) {\n tl = uBeam2Poly[0]; tr = uBeam2Poly[1]; bl = uBeam2Poly[2]; br = uBeam2Poly[3];\n color = uBeam2Color;\n }\n picked += 1.0;\n }\n if (uBeam3On > 0.5) {\n if (abs(picked - slot) < 0.5) {\n tl = uBeam3Poly[0]; tr = uBeam3Poly[1]; bl = uBeam3Poly[2]; br = uBeam3Poly[3];\n color = uBeam3Color;\n }\n picked += 1.0;\n }\n\n float depth = hash1(seed + 3.0);\n float size = mix(MOTE_SIZE_MIN, MOTE_SIZE_MAX, depth);\n float speed = mix(0.45, 1.35, hash1(seed + 5.0));\n float t = uTime * uSpeed * speed;\n\n // (u,v) in beam space; drift = swirl in u, fall in v. fract wraps within\n // the beam, so a mote that falls out the spread end reappears at the source.\n vec2 g = hash2(seed);\n g.x += sin(t * DRIFT_SPEED * 1.7 + seed) * SWIRL_AMOUNT;\n g.x += sin(t * DRIFT_SPEED * 3.9 + seed * 0.41) * TURBULENCE;\n g.y += uTime * uSpeed * FALL_SPEED * speed * 6.0;\n g.y += sin(t * DRIFT_SPEED * 2.4 + seed * 0.37) * SWIRL_AMOUNT * 0.55;\n g = fract(g);\n\n // Expand to [-fuzz, 1+fuzz] so motes populate the soft fringe, then map\n // bilinearly onto the quad.\n vec2 q = g * (1.0 + 2.0 * fuzz) - fuzz;\n vec2 pos = mix(mix(tl, tr, q.x), mix(bl, br, q.x), q.y);\n\n // Cheap soft-edge falloff in (u,v), replacing the per-mote quadMask.\n float edge =\n smoothstep(0.0, fuzz, q.x) * smoothstep(0.0, fuzz, 1.0 - q.x) *\n smoothstep(0.0, fuzz, q.y) * smoothstep(0.0, fuzz, 1.0 - q.y);\n\n float mote = softMote(uv, pos, size);\n float core = softMote(uv, pos, size * 0.42);\n float glow = softMote(uv, pos, size * uGlowSize);\n\n float shimmer =\n 0.72 + 0.28 * sin(uTime * uSpeed * mix(0.22, 0.95, hash1(seed + 9.0)) + seed);\n float strength = mix(0.15, 1.0, depth) * shimmer * edge * uMoteAlpha;\n\n col += color * glow * strength * 0.12;\n col += color * mote * strength * 0.36;\n col += vec3(1.0) * core * strength * 0.10;\n\n alpha += glow * strength * 0.030;\n alpha += mote * strength * 0.105;\n alpha += core * strength * 0.110;\n\n slot += 1.0;\n if (slot >= nActive) slot = 0.0; // wrap the round-robin cursor\n }\n}\n\nvoid main() {\n // vUv is already 0..1 with bottom-left origin; this is the Shadertoy uv.\n vec2 uv = vUv;\n\n vec3 col = vec3(0.0);\n float alpha = 0.0;\n\n vec3 beamColor;\n float litSum;\n float cover = evalBeams(uv, beamColor, litSum);\n\n col += beamColor * litSum; // litSum carries each beam's per-beam alpha\n alpha += litSum * 0.45;\n\n // One loop; each mote is round-robined into an on beam and spawned there.\n addMotes(uv, col, alpha);\n\n float haze =\n cover * cover * (0.6 + 0.4 * sin(uv.x * 8.0 + uv.y * 5.0 + uTime * uSpeed * 0.08));\n col += beamColor * haze * 0.018;\n alpha += haze * 0.010;\n\n alpha = clamp(alpha * uOverlayAlpha, 0.0, 1.0);\n oColor = vec4(col, alpha);\n}\n"; export declare const CORPORATE_BLOBS_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uColor; // overall tint / color grade; [1,1,1] = stock colors\nuniform float uGlobalAlpha; // overall blob opacity; stock 0.58\nuniform float uScale; // global blob size multiplier; stock 2.55\nuniform float uEdgePull; // pushes blobs outward from center; stock 0.32\nuniform float uCenterClear; // radius around center that repels blobs; stock 0.42\nuniform float uMotionAmount; // positional drift magnitude; 1.0 = stock, 0 = still\nuniform float uMotionSpeed; // drift + morph rate; 1.0 = stock, 0 freezes motion\nuniform float uEdgeSoftness; // blob edge falloff; stock 0.024\n// Per-blob base colors, multiplied by uColor at output. Defaults (the stock\n// brand palette) live in CORPORATE_BLOBS_CONTROLS.\nuniform vec3 uBlobColor1; // stock: light blue\nuniform vec3 uBlobColor2; // stock: dark green\nuniform vec3 uBlobColor3; // stock: yellow\nuniform vec3 uBlobColor4; // stock: orange\nuniform vec3 uBlobColor5; // stock: light green\nuniform vec3 uBlobColor6; // stock: magenta\nuniform vec3 uBlobColor7; // stock: brown\nuniform vec3 uBlobColor8; // stock: dark blue\n\nin highp vec2 vUv;\nout vec4 oColor;\n\n// BLOB_COUNT must stay a compile-time constant (GLSL ES loop bound).\n#define BLOB_COUNT 8\n\n// Internal animation constants (not tunable; keep the look coherent).\n#define CENTER_CLEAR_PUSH 0.34\n#define SCALE_PULSE_AMOUNT 0.10\n#define SCALE_PULSE_SPEED 0.42\n#define ROTATION_SWAY_AMOUNT 0.12\n#define ROTATION_SWAY_SPEED 0.11\n#define SHAPE_MORPH_SPEED 1.00\n\nstruct Blob {\n vec2 pos;\n float scale;\n float opacity;\n float speed;\n float drift;\n float rotation;\n float variant;\n vec3 color;\n};\n\nBlob getBlob(float i) {\n if (i < 0.5) return Blob(vec2(-1.18, -0.55), 0.62, 0.48, 0.22, 0.14, 0.10, 0.0, uBlobColor1);\n if (i < 1.5) return Blob(vec2( 1.12, -0.35), 0.66, 0.40, 0.18, 0.13, 1.00, 1.0, uBlobColor2);\n if (i < 2.5) return Blob(vec2( 0.95, 0.88), 0.58, 0.44, 0.20, 0.14, 2.20, 2.0, uBlobColor3);\n if (i < 3.5) return Blob(vec2(-0.98, 0.82), 0.56, 0.38, 0.16, 0.12, 0.70, 3.0, uBlobColor4);\n if (i < 4.5) return Blob(vec2( 1.28, 0.28), 0.50, 0.34, 0.24, 0.11, 1.80, 4.0, uBlobColor5);\n if (i < 5.5) return Blob(vec2(-0.25, -1.12), 0.54, 0.36, 0.19, 0.11, 2.60, 5.0, uBlobColor6);\n if (i < 6.5) return Blob(vec2(-1.30, 0.10), 0.48, 0.30, 0.17, 0.12, 0.40, 6.0, uBlobColor7);\n return Blob(vec2( 0.28, 1.18), 0.52, 0.30, 0.14, 0.10, 0.90, 7.0, uBlobColor8);\n}\n\nmat2 rotate2d(float a) {\n float s = sin(a);\n float c = cos(a);\n return mat2(c, -s, s, c);\n}\n\nfloat variantRadius(float angle, float variant, float phase) {\n float r = 1.0;\n\n if (variant < 0.5) {\n r += 0.115 * sin(angle * 2.0 + 0.20 + phase * 0.20);\n r += 0.075 * sin(angle * 3.0 - 1.10 - phase * 0.13);\n r += 0.035 * sin(angle * 5.0 + 2.00 + phase * 0.09);\n } else if (variant < 1.5) {\n r += 0.090 * sin(angle * 2.0 - 0.80 + phase * 0.18);\n r += 0.105 * sin(angle * 3.0 + 0.70 - phase * 0.10);\n r += 0.030 * sin(angle * 6.0 - 1.50 + phase * 0.08);\n } else if (variant < 2.5) {\n r += 0.130 * sin(angle * 2.0 + 1.10 + phase * 0.16);\n r += 0.060 * sin(angle * 4.0 - 0.30 - phase * 0.12);\n r += 0.045 * sin(angle * 5.0 + 2.80 + phase * 0.07);\n } else if (variant < 3.5) {\n r += 0.080 * sin(angle * 2.0 + 2.30 + phase * 0.14);\n r += 0.120 * sin(angle * 3.0 - 0.40 - phase * 0.11);\n r += 0.040 * sin(angle * 7.0 + 1.10 + phase * 0.06);\n } else if (variant < 4.5) {\n r += 0.035 * sin(angle * 2.0 + 0.10 + phase * 0.12);\n r += 0.030 * sin(angle * 3.0 + 1.80 - phase * 0.09);\n r += 0.020 * sin(angle * 5.0 - 0.90 + phase * 0.05);\n } else if (variant < 5.5) {\n r += 0.145 * sin(angle * 2.0 - 1.30 + phase * 0.17);\n r += 0.070 * sin(angle * 3.0 + 2.40 - phase * 0.11);\n r += 0.035 * sin(angle * 5.0 + 0.20 + phase * 0.08);\n } else if (variant < 6.5) {\n r += 0.045 * sin(angle * 2.0 + 1.70 + phase * 0.10);\n r += 0.035 * sin(angle * 4.0 - 2.10 - phase * 0.08);\n r += 0.025 * sin(angle * 6.0 + 0.50 + phase * 0.05);\n } else {\n r += 0.170 * sin(angle * 2.0 + 2.80 + phase * 0.20);\n r += 0.090 * sin(angle * 3.0 - 1.90 - phase * 0.15);\n r += 0.055 * sin(angle * 5.0 + 0.80 + phase * 0.09);\n }\n\n return r;\n}\n\nvec2 applyCenterRepulsor(vec2 center) {\n float d = length(center);\n vec2 dir = normalize(center + vec2(0.0001, 0.0001));\n\n center += dir * uEdgePull;\n\n float centerInfluence = 1.0 - smoothstep(uCenterClear, uCenterClear + 0.35, d);\n center += dir * centerInfluence * CENTER_CLEAR_PUSH;\n\n return center;\n}\n\nfloat animatedScale(float baseScale, float blobIndex, float blobSpeed) {\n float localPhase =\n uTime * SCALE_PULSE_SPEED * (0.65 + blobSpeed * 1.35) +\n blobIndex * 2.731;\n\n float pulseA = sin(localPhase);\n float pulseB = sin(localPhase * 0.47 + blobIndex * 5.13) * 0.45;\n\n float scaleMultiplier = 1.0 + (pulseA + pulseB) * SCALE_PULSE_AMOUNT;\n\n return baseScale * max(0.05, scaleMultiplier);\n}\n\nfloat blobMask(vec2 p, vec2 center, Blob b, float phase, float liveScale) {\n vec2 q = p - center;\n\n vec2 squash = vec2(\n 1.0 + 0.14 * sin(b.variant * 1.91),\n 1.0 + 0.14 * cos(b.variant * 2.37)\n );\n\n float rotationSway =\n sin(uTime * ROTATION_SWAY_SPEED * (0.6 + b.speed) + b.variant * 3.0) *\n ROTATION_SWAY_AMOUNT;\n\n q = rotate2d(b.rotation + rotationSway) * q;\n q /= squash;\n\n float angle = atan(q.y, q.x);\n float dist = length(q);\n\n float r = liveScale * uScale * 0.5 * variantRadius(angle, b.variant, phase);\n\n return 1.0 - smoothstep(r, r + uEdgeSoftness, dist);\n}\n\nvoid main() {\n vec2 uv = vUv;\n\n vec2 p = uv * 2.0 - 1.0;\n p.x *= uResolution.x / uResolution.y;\n\n vec3 blobCol = vec3(0.0);\n float blobAlpha = 0.0;\n\n // Integer-counted loop over a compile-time bound; i is reconstructed as\n // float(n), so the per-blob lookups and phases match the prototype.\n for (int n = 0; n < BLOB_COUNT; n++) {\n float i = float(n);\n Blob b = getBlob(i);\n\n float phase =\n uTime * b.speed * uMotionSpeed * SHAPE_MORPH_SPEED +\n i * 4.137;\n\n vec2 center = b.pos;\n\n center.x += sin(phase * 0.41 + i * 1.70) * b.drift * uMotionAmount;\n center.x += sin(phase * 0.19 + i * 3.10) * b.drift * uMotionAmount * 0.45;\n center.y += cos(phase * 0.33 + i * 2.30) * b.drift * uMotionAmount * 0.75;\n center.y += sin(phase * 0.17 + i * 4.40) * b.drift * uMotionAmount * 0.35;\n\n center = applyCenterRepulsor(center);\n\n float liveScale = animatedScale(b.scale, i, b.speed);\n float mask = blobMask(p, center, b, phase, liveScale);\n\n float inner = pow(mask, 1.35);\n float rim = mask * (1.0 - smoothstep(0.45, 1.0, mask));\n\n vec3 gelColor = b.color * inner + b.color * rim * 0.18;\n float a = mask * b.opacity * uGlobalAlpha;\n\n blobCol += gelColor * a * (1.0 - blobAlpha);\n blobAlpha += a * (1.0 - blobAlpha);\n }\n\n // Premultiplied output; tint grades the (premultiplied) color, not alpha.\n oColor = vec4(blobCol * uColor, blobAlpha);\n}\n"; export declare const DATA_MESH_FRAG_SRC = "#version 300 es\nprecision highp float;\n\nuniform float uTime; // seconds, monotonically increasing; range [0, inf)\nuniform vec2 uResolution; // framebuffer size in pixels; both components > 0\nuniform vec3 uBgTop; // background gradient color at the top of frame\nuniform vec3 uBgBottom; // background gradient color at the bottom of frame\nuniform vec3 uLineColor; // mid wireframe-line tint (the trough/body color)\nuniform vec3 uCrestColor; // crest highlight color (brightest along the peaks)\nuniform vec3 uHazeColor; // atmospheric haze tint on the far rows\nuniform vec3 uAccentColor; // the one restrained accent (e.g. enterprise red)\nuniform float uWaveScale; // wave-field spatial frequency; lower = looser, broader hills\nuniform float uWaveAmp; // vertical wave displacement amount (near rows)\nuniform float uWaveSpeed; // animation rate; 0 freezes the surface\nuniform float uGridX; // column-grid density across the surface; keep loose\nuniform float uHorizon; // horizon height in uv.y units (rows converge toward it)\nuniform float uFarScale; // perspective scale of the farthest row, 0.05..0.5 (>0)\nuniform float uSlant; // diagonal tilt; raises the right side for corner composition\nuniform float uLineWidth; // wireframe line half-width (smaller = finer, sharper)\nuniform float uNodeMix; // 0..1 emphasis of glowing intersection nodes (dot reading)\nuniform float uStrutMix; // 0..1 emphasis of vertical struts (wireframe reading)\nuniform float uGlow; // overall additive mesh-glow / bloom strength\nuniform float uHaze; // atmospheric far-haze strength\nuniform float uParticles; // floating-particle intensity; 0 disables the field\nuniform float uAccent; // lone accent-mote intensity; 0 disables it\nuniform float uCalm; // 0..1 eases the additive glow at frame center (face zone)\n\nin highp vec2 vUv;\nout vec4 oColor;\n\n// ROWS / PARTICLES must stay compile-time constants (GLSL ES loop bounds). ROWS is\n// kept modest on purpose (loose mesh); perspective bunching toward the horizon\n// makes it read as far more lines than it costs.\n#define ROWS 18\n#define PARTICLES 10\n#define WAVE_DEPTH_SPAN 4.5 // world-depth the eased row range maps across\n#define COL_SHARP 48.0 // column-stripe sharpness in cell-phase units\n#define Y_NEAR (-0.62) // nearest row baseline (just below the bottom edge)\n\n// Cheap stable hash for the particle field (highp; the 43758.5453 multiplier\n// bands under mediump, same note as clouds/nebula).\nfloat hash11(float n) {\n return fract(sin(n * 12.9898) * 43758.5453123);\n}\n\n// The shared surface. x is perspective world-x, z is eased world-depth, t is time.\n// A small sum of sines whose x/z cross terms produce the hills, valleys, and\n// saddles; bounded to roughly [-1.6, 1.6].\nfloat waveField(float x, float z, float t) {\n float h = 0.0;\n h += sin(x * 1.00 + z * 0.55 + t) * 0.60;\n h += sin(x * 0.55 - z * 0.95 - t * 0.70) * 0.45;\n h += sin((x + z) * 0.45 + t * 0.40 + 1.7) * 0.40; // diagonal ridges -> saddles\n h += sin(x * 1.70 - z * 0.30 + t * 1.20) * 0.16; // fine ripple\n return h;\n}\n\nvoid main() {\n vec2 fragCoord = vUv * uResolution;\n vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y; // centered, aspect-correct\n\n // Background: smooth vertical gradient, no texture. g = 0 bottom .. 1 top.\n float g = clamp(uv.y + 0.5, 0.0, 1.0);\n vec3 col = mix(uBgBottom, uBgTop, g);\n\n // Ease additive glow near the frame center (the subject's face sits there).\n float calm = 1.0 - uCalm * (1.0 - smoothstep(0.18, 0.62, length(uv)));\n\n float t = uTime * uWaveSpeed;\n float horizon = clamp(uHorizon, -0.2, 0.45);\n\n // Line-glow widths from the half-width. The core line keeps the one exp() (its\n // sharp gaussian is the wireframe signature); the bloom halo and the vertical\n // strut use rational falloffs (1/(1+k\u00B7dy^2)) instead of more exp() calls, which\n // are ~8x-weighted transcendentals on the hot per-row path. The node reuses the\n // core exp directly. Net: 2 exp/row (core + column), down from 5.\n float coreSharp = 1.0 / max(uLineWidth * uLineWidth, 1e-5);\n float haloK = coreSharp * 0.14; // rational-bloom width (matches the old halo half-width)\n float strutK = coreSharp * 0.14; // rational vertical-bridge width\n\n vec3 mesh = vec3(0.0);\n vec3 haze = vec3(0.0);\n\n for (int i = 0; i < ROWS; i++) {\n float rowT = float(i) / float(ROWS - 1); // 0 near .. 1 far\n float om = 1.0 - rowT;\n float f = 1.0 - om * om; // eased depth: rows bunch toward horizon\n float persp = mix(1.0, uFarScale, f);\n persp = max(persp, uFarScale); // guard the divide (uFarScale > 0)\n\n // Row baseline in screen-y, with a diagonal tilt for corner composition.\n float baseY = mix(Y_NEAR, horizon, f) + uv.x * uSlant * persp;\n\n // Early-out: skip the sines for any row that cannot reach this pixel. Margin\n // covers the max wave displacement plus the strut's vertical bridge.\n float reach = persp * uWaveAmp * 1.7 + uLineWidth * 3.0 + 0.06;\n if (abs(uv.y - baseY) > reach) continue;\n\n float worldX = uv.x / persp;\n float h = waveField(worldX * uWaveScale, f * WAVE_DEPTH_SPAN, t);\n float surfY = baseY + persp * uWaveAmp * h;\n float dy = uv.y - surfY;\n\n // Crest factor: peaks of the field glow white, troughs stay the line tint.\n float crest = smoothstep(0.2, 1.4, h);\n\n // Horizontal ribbon: sharp gaussian core (the line) + rational bloom halo.\n float dy2 = dy * dy;\n float core = exp(-dy2 * coreSharp);\n float ribbon = core + 0.22 / (1.0 + dy2 * haloK);\n\n // Column grid: one bright stripe per cell of worldX. cph = 0 at the stripe.\n float cph = fract(worldX * uGridX) - 0.5;\n float colLine = exp(-cph * cph * COL_SHARP);\n\n // Vertical strut (rational falloff in y so it bridges toward neighbors, gated\n // by the column) and the intersection node (core line x column -> a glowing\n // dot; reuses the core exp, no extra transcendental).\n float strut = colLine / (1.0 + dy2 * strutK);\n float node = core * colLine;\n\n // Atmospheric fade: far rows dim and tint toward the haze color.\n float fade = om * om; // 1 near .. 0 far\n float lit = ribbon + uStrutMix * strut + uNodeMix * node * 2.0;\n vec3 lineCol = mix(uLineColor, uCrestColor, crest);\n\n // Crest-dominant brightness: troughs stay dim, peaks carry the illumination.\n mesh += lineCol * lit * fade * (0.35 + 1.0 * crest);\n haze += uHazeColor * ribbon * (1.0 - fade) * crest;\n }\n\n col += mesh * uGlow * calm;\n col += haze * uHaze * calm;\n\n // Sparse floating particles; index 0 is the lone accent mote (independent of\n // uParticles so an accent can show with the particle field off).\n if (uParticles > 0.0 || uAccent > 0.0) {\n vec3 motes = vec3(0.0);\n for (int p = 0; p < PARTICLES; p++) {\n float fp = float(p);\n vec2 seed = vec2(hash11(fp * 1.7 + 0.3), hash11(fp * 3.1 + 1.9));\n vec2 ppos = (seed * 2.0 - 1.0) * vec2(0.92, 0.46);\n ppos.x += sin(uTime * 0.07 + fp * 2.3) * 0.03;\n ppos.y += cos(uTime * 0.05 + fp * 1.7) * 0.03;\n float twinkle = 0.5 + 0.5 * sin(uTime * (0.6 + hash11(fp * 5.0)) + fp * 4.0);\n float pd = length(uv - ppos);\n float glint = exp(-pd * pd * 2300.0) * twinkle;\n vec3 pcol = (p == 0) ? uAccentColor * uAccent : uCrestColor * uParticles;\n motes += pcol * glint;\n }\n col += motes * calm;\n }\n\n // Soft highlight rolloff: fold the additive foreground pile-up into clean white\n // crests instead of a clipped slab; leaves the dark gradient essentially intact.\n col = vec3(1.0) - exp(-col);\n\n oColor = vec4(col, 1.0);\n}\n"; export declare const SHADER_SOURCES: Readonly>; //# sourceMappingURL=shaders.generated.d.ts.map