react-native-webrtc-kaleidoscope 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/android/src/main/java/com/simiancraft/kaleidoscope/gpu/ShadersGenerated.kt +173 -3
  2. package/catalog/composites/clouds/clouds.ts +5 -5
  3. package/catalog/composites/nebula/nebula.thumb.webp +0 -0
  4. package/catalog/shaders/data-mesh/data-mesh.form.tsx +53 -0
  5. package/catalog/shaders/data-mesh/data-mesh.frag +205 -0
  6. package/catalog/shaders/data-mesh/data-mesh.ts +225 -0
  7. package/catalog/shaders/index.ts +4 -0
  8. package/catalog/shaders/nebula/nebula.frag +11 -3
  9. package/dist/catalog/composites/clouds/clouds.d.ts +5 -5
  10. package/dist/catalog/composites/clouds/clouds.js +5 -5
  11. package/dist/catalog/composites/clouds/clouds.js.map +1 -1
  12. package/dist/catalog/composites/nebula/nebula.thumb.webp +0 -0
  13. package/dist/catalog/shaders/data-mesh/data-mesh.d.ts +50 -0
  14. package/dist/catalog/shaders/data-mesh/data-mesh.d.ts.map +1 -0
  15. package/dist/catalog/shaders/data-mesh/data-mesh.form.d.ts +3 -0
  16. package/dist/catalog/shaders/data-mesh/data-mesh.form.d.ts.map +1 -0
  17. package/dist/catalog/shaders/data-mesh/data-mesh.form.js +15 -0
  18. package/dist/catalog/shaders/data-mesh/data-mesh.form.js.map +1 -0
  19. package/dist/catalog/shaders/data-mesh/data-mesh.js +179 -0
  20. package/dist/catalog/shaders/data-mesh/data-mesh.js.map +1 -0
  21. package/dist/catalog/shaders/index.d.ts +4 -0
  22. package/dist/catalog/shaders/index.d.ts.map +1 -1
  23. package/dist/catalog/shaders/index.js +3 -1
  24. package/dist/catalog/shaders/index.js.map +1 -1
  25. package/dist/web-driver/shaders.generated.d.ts +2 -1
  26. package/dist/web-driver/shaders.generated.d.ts.map +1 -1
  27. package/dist/web-driver/shaders.generated.js +173 -4
  28. package/dist/web-driver/shaders.generated.js.map +1 -1
  29. package/ios/KaleidoscopeModule/shaders/GENERATIVE.txt +1 -0
  30. package/ios/KaleidoscopeModule/shaders/SHADERS.txt +1 -0
  31. package/ios/KaleidoscopeModule/shaders/data-mesh.metalsrc +99 -0
  32. package/ios/KaleidoscopeModule/shaders/nebula.metalsrc +56 -51
  33. package/package.json +8 -1
@@ -1 +1 @@
1
- {"version":3,"file":"shaders.generated.js","sourceRoot":"","sources":["../../web-driver/shaders.generated.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,6CAA6C;;;AAEhC,QAAA,oBAAoB,GAAG;;;;;;;;CAQnC,CAAC;AAEW,QAAA,yBAAyB,GAAG;;;;;;;;CAQxC,CAAC;AAEW,QAAA,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBtC,CAAC;AAEW,QAAA,wBAAwB,GAAG;;;;;;;;;;;CAWvC,CAAC;AAEW,QAAA,0BAA0B,GAAG;;;;;;;;;;;;;;;;;CAiBzC,CAAC;AAEW,QAAA,yBAAyB,GAAG;;;;;;;;;;;;;;;;;CAiBxC,CAAC;AAEW,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkC9B,CAAC;AAEW,QAAA,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqEpC,CAAC;AAEW,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+HnC,CAAC;AAEW,QAAA,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DtC,CAAC;AAEW,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFnC,CAAC;AAEW,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkGnC,CAAC;AAEW,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmH9B,CAAC;AAEW,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6I9B,CAAC;AAEW,QAAA,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyE/B,CAAC;AAEW,QAAA,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDjC,CAAC;AAEW,QAAA,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IpC,CAAC;AAEW,QAAA,6BAA6B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4G5C,CAAC;AAEW,QAAA,8BAA8B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2O7C,CAAC;AAEW,QAAA,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsMvC,CAAC;AAEF,+EAA+E;AAC/E,uEAAuE;AAC1D,QAAA,cAAc,GAAqC;IAC9D,QAAQ,EAAE,QAAA,eAAe;IACzB,cAAc,EAAE,QAAA,qBAAqB;IACrC,aAAa,EAAE,QAAA,oBAAoB;IACnC,gBAAgB,EAAE,QAAA,uBAAuB;IACzC,aAAa,EAAE,QAAA,oBAAoB;IACnC,aAAa,EAAE,QAAA,oBAAoB;IACnC,QAAQ,EAAE,QAAA,eAAe;IACzB,QAAQ,EAAE,QAAA,eAAe;IACzB,SAAS,EAAE,QAAA,gBAAgB;IAC3B,WAAW,EAAE,QAAA,kBAAkB;IAC/B,cAAc,EAAE,QAAA,qBAAqB;IACrC,sBAAsB,EAAE,QAAA,6BAA6B;IACrD,uBAAuB,EAAE,QAAA,8BAA8B;IACvD,iBAAiB,EAAE,QAAA,wBAAwB;CACnC,CAAC","sourcesContent":["// @generated by scripts/build-shaders.ts from shaders/. DO NOT EDIT.\n// Run `bun run build:shaders` to regenerate.\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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. Guard the divide; shade only below horizon.\n float depth = 1.0 / max(h - fy, 1.5e-3); // large near the horizon\n float depthMin = 1.0 / h; // depth at the very front (fy = 0)\n\n // Grid coordinates: x widens with depth (perspective); uGridDensity sets the\n // cell count; the scroll is in cell units so its rate is density-independent.\n vec2 g = vec2(fx * depth, depth) * uGridDensity;\n g.y += uTime * uSpeed * 2.0;\n vec2 cell = abs(fract(g) - 0.5); // 0 on a line .. 0.5 mid-cell, per axis\n\n // Per-axis, depth-scaled line half-width: the rungs (g.y) compress toward the\n // horizon as depth^2 and the verticals (g.x) ~linearly, so widening each axis'\n // line band at its own compression rate holds the on-screen line width roughly\n // constant. Far lines fuse into a band instead of a sub-pixel sheet that\n // shimmers as it scrolls; near lines stay crisp. Written 1 - smoothstep(0, w, .)\n // (NOT the reversed-edge smoothstep(w, 0, .), which is undefined on GLSL ES /\n // Metal) and derivative-free, so it is portable and mobile-precision safe.\n vec2 w = max(vec2(depth, depth * depth * 0.2) * uGridDensity * 0.0013, vec2(1e-4));\n vec2 core = 1.0 - smoothstep(vec2(0.0), w, cell);\n vec2 halo = (1.0 - smoothstep(vec2(0.0), w * 6.0, cell)) * (0.5 * uGridGlow);\n float gridVal = clamp(core.x + core.y + halo.x + halo.y, 0.0, 1.5);\n\n // Distance fog: fade the grid out toward the horizon for the converging look.\n float fog = clamp(1.0 - (depth - depthMin) / (depthMin * 10.0), 0.0, 1.0);\n fog *= fog;\n\n vec3 floorBase = mix(vec3(0.0), uSkyHorizon * 0.16, fog * 0.6);\n col = floorBase + uGridColor * gridVal * fog * 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`;\n\nexport 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`;\n\nexport 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// 8 (was 12) for low-end-mobile cost (issue #39); the work is linear in the\n// count and dimByDensity rebalances per-star brightness automatically.\nconst int STARFIELD_LAYERS_COUNT = 8;\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\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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\n// Generative background shaders, by name. The generic shader processor and the\n// dispatch iterate this; adding a generative .frag adds an entry here.\nexport const SHADER_SOURCES: Readonly<Record<string, string>> = {\n 'plasma': PLASMA_FRAG_SRC,\n 'kaleidoscope': KALEIDOSCOPE_FRAG_SRC,\n 'neo-memphis': NEO_MEMPHIS_FRAG_SRC,\n 'halftone-waves': HALFTONE_WAVES_FRAG_SRC,\n 'aurora-silk': AURORA_SILK_FRAG_SRC,\n 'outrun-grid': OUTRUN_GRID_FRAG_SRC,\n 'clouds': CLOUDS_FRAG_SRC,\n 'nebula': NEBULA_FRAG_SRC,\n 'godrays': GODRAYS_FRAG_SRC,\n 'fireflies': FIREFLIES_FRAG_SRC,\n 'simianlights': SIMIANLIGHTS_FRAG_SRC,\n 'anamorphic-lensflare': ANAMORPHIC_LENSFLARE_FRAG_SRC,\n 'light-beams-and-motes': LIGHT_BEAMS_AND_MOTES_FRAG_SRC,\n 'corporate-blobs': CORPORATE_BLOBS_FRAG_SRC,\n} as const;\n"]}
1
+ {"version":3,"file":"shaders.generated.js","sourceRoot":"","sources":["../../web-driver/shaders.generated.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,6CAA6C;;;AAEhC,QAAA,oBAAoB,GAAG;;;;;;;;CAQnC,CAAC;AAEW,QAAA,yBAAyB,GAAG;;;;;;;;CAQxC,CAAC;AAEW,QAAA,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBtC,CAAC;AAEW,QAAA,wBAAwB,GAAG;;;;;;;;;;;CAWvC,CAAC;AAEW,QAAA,0BAA0B,GAAG;;;;;;;;;;;;;;;;;CAiBzC,CAAC;AAEW,QAAA,yBAAyB,GAAG;;;;;;;;;;;;;;;;;CAiBxC,CAAC;AAEW,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkC9B,CAAC;AAEW,QAAA,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqEpC,CAAC;AAEW,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+HnC,CAAC;AAEW,QAAA,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DtC,CAAC;AAEW,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFnC,CAAC;AAEW,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkGnC,CAAC;AAEW,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmH9B,CAAC;AAEW,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqJ9B,CAAC;AAEW,QAAA,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyE/B,CAAC;AAEW,QAAA,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDjC,CAAC;AAEW,QAAA,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IpC,CAAC;AAEW,QAAA,6BAA6B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4G5C,CAAC;AAEW,QAAA,8BAA8B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2O7C,CAAC;AAEW,QAAA,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsMvC,CAAC;AAEW,QAAA,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+JjC,CAAC;AAEF,+EAA+E;AAC/E,uEAAuE;AAC1D,QAAA,cAAc,GAAqC;IAC9D,QAAQ,EAAE,QAAA,eAAe;IACzB,cAAc,EAAE,QAAA,qBAAqB;IACrC,aAAa,EAAE,QAAA,oBAAoB;IACnC,gBAAgB,EAAE,QAAA,uBAAuB;IACzC,aAAa,EAAE,QAAA,oBAAoB;IACnC,aAAa,EAAE,QAAA,oBAAoB;IACnC,QAAQ,EAAE,QAAA,eAAe;IACzB,QAAQ,EAAE,QAAA,eAAe;IACzB,SAAS,EAAE,QAAA,gBAAgB;IAC3B,WAAW,EAAE,QAAA,kBAAkB;IAC/B,cAAc,EAAE,QAAA,qBAAqB;IACrC,sBAAsB,EAAE,QAAA,6BAA6B;IACrD,uBAAuB,EAAE,QAAA,8BAA8B;IACvD,iBAAiB,EAAE,QAAA,wBAAwB;IAC3C,WAAW,EAAE,QAAA,kBAAkB;CACvB,CAAC","sourcesContent":["// @generated by scripts/build-shaders.ts from shaders/. DO NOT EDIT.\n// Run `bun run build:shaders` to regenerate.\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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. Guard the divide; shade only below horizon.\n float depth = 1.0 / max(h - fy, 1.5e-3); // large near the horizon\n float depthMin = 1.0 / h; // depth at the very front (fy = 0)\n\n // Grid coordinates: x widens with depth (perspective); uGridDensity sets the\n // cell count; the scroll is in cell units so its rate is density-independent.\n vec2 g = vec2(fx * depth, depth) * uGridDensity;\n g.y += uTime * uSpeed * 2.0;\n vec2 cell = abs(fract(g) - 0.5); // 0 on a line .. 0.5 mid-cell, per axis\n\n // Per-axis, depth-scaled line half-width: the rungs (g.y) compress toward the\n // horizon as depth^2 and the verticals (g.x) ~linearly, so widening each axis'\n // line band at its own compression rate holds the on-screen line width roughly\n // constant. Far lines fuse into a band instead of a sub-pixel sheet that\n // shimmers as it scrolls; near lines stay crisp. Written 1 - smoothstep(0, w, .)\n // (NOT the reversed-edge smoothstep(w, 0, .), which is undefined on GLSL ES /\n // Metal) and derivative-free, so it is portable and mobile-precision safe.\n vec2 w = max(vec2(depth, depth * depth * 0.2) * uGridDensity * 0.0013, vec2(1e-4));\n vec2 core = 1.0 - smoothstep(vec2(0.0), w, cell);\n vec2 halo = (1.0 - smoothstep(vec2(0.0), w * 6.0, cell)) * (0.5 * uGridGlow);\n float gridVal = clamp(core.x + core.y + halo.x + halo.y, 0.0, 1.5);\n\n // Distance fog: fade the grid out toward the horizon for the converging look.\n float fog = clamp(1.0 - (depth - depthMin) / (depthMin * 10.0), 0.0, 1.0);\n fog *= fog;\n\n vec3 floorBase = mix(vec3(0.0), uSkyHorizon * 0.16, fog * 0.6);\n col = floorBase + uGridColor * gridVal * fog * 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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`;\n\nexport 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·dy^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`;\n\n// Generative background shaders, by name. The generic shader processor and the\n// dispatch iterate this; adding a generative .frag adds an entry here.\nexport const SHADER_SOURCES: Readonly<Record<string, string>> = {\n 'plasma': PLASMA_FRAG_SRC,\n 'kaleidoscope': KALEIDOSCOPE_FRAG_SRC,\n 'neo-memphis': NEO_MEMPHIS_FRAG_SRC,\n 'halftone-waves': HALFTONE_WAVES_FRAG_SRC,\n 'aurora-silk': AURORA_SILK_FRAG_SRC,\n 'outrun-grid': OUTRUN_GRID_FRAG_SRC,\n 'clouds': CLOUDS_FRAG_SRC,\n 'nebula': NEBULA_FRAG_SRC,\n 'godrays': GODRAYS_FRAG_SRC,\n 'fireflies': FIREFLIES_FRAG_SRC,\n 'simianlights': SIMIANLIGHTS_FRAG_SRC,\n 'anamorphic-lensflare': ANAMORPHIC_LENSFLARE_FRAG_SRC,\n 'light-beams-and-motes': LIGHT_BEAMS_AND_MOTES_FRAG_SRC,\n 'corporate-blobs': CORPORATE_BLOBS_FRAG_SRC,\n 'data-mesh': DATA_MESH_FRAG_SRC,\n} as const;\n"]}
@@ -2,6 +2,7 @@ anamorphic-lensflare
2
2
  aurora-silk
3
3
  clouds
4
4
  corporate-blobs
5
+ data-mesh
5
6
  fireflies
6
7
  godrays
7
8
  halftone-waves
@@ -8,6 +8,7 @@ composite-image.frag
8
8
  composite-masked.frag
9
9
  composite-subject.frag
10
10
  corporate-blobs.frag
11
+ data-mesh.frag
11
12
  fireflies.frag
12
13
  godrays.frag
13
14
  halftone-waves.frag
@@ -0,0 +1,99 @@
1
+ #include <metal_stdlib>
2
+ #include <simd/simd.h>
3
+
4
+ using namespace metal;
5
+
6
+ struct main0_out
7
+ {
8
+ float4 oColor [[color(0)]];
9
+ };
10
+
11
+ struct main0_in
12
+ {
13
+ float2 vUv [[user(locn0)]];
14
+ };
15
+
16
+ fragment main0_out main0(main0_in in [[stage_in]], constant float2& uResolution [[buffer(0)]], constant float3& uBgBottom [[buffer(1)]], constant float3& uBgTop [[buffer(2)]], constant float& uCalm [[buffer(3)]], constant float& uTime [[buffer(4)]], constant float& uWaveSpeed [[buffer(5)]], constant float& uHorizon [[buffer(6)]], constant float& uLineWidth [[buffer(7)]], constant float& uFarScale [[buffer(8)]], constant float& uSlant [[buffer(9)]], constant float& uWaveAmp [[buffer(10)]], constant float& uWaveScale [[buffer(11)]], constant float& uGridX [[buffer(12)]], constant float& uStrutMix [[buffer(13)]], constant float& uNodeMix [[buffer(14)]], constant float3& uLineColor [[buffer(15)]], constant float3& uCrestColor [[buffer(16)]], constant float3& uHazeColor [[buffer(17)]], constant float& uGlow [[buffer(18)]], constant float& uHaze [[buffer(19)]], constant float& uParticles [[buffer(20)]], constant float& uAccent [[buffer(21)]], constant float3& uAccentColor [[buffer(22)]])
17
+ {
18
+ main0_out out = {};
19
+ float2 _112 = ((in.vUv * uResolution) - (uResolution * 0.5)) / float2(uResolution.y);
20
+ float _115 = _112.y;
21
+ float _139 = 1.0 - (uCalm * (1.0 - smoothstep(0.180000007152557373046875, 0.62000000476837158203125, length(_112))));
22
+ float _145 = uTime * uWaveSpeed;
23
+ float _150 = fast::clamp(uHorizon, -0.20000000298023223876953125, 0.449999988079071044921875);
24
+ float _157 = fast::max(uLineWidth * uLineWidth, 9.9999997473787516355514526367188e-06);
25
+ float _158 = 1.0 / _157;
26
+ float _162 = 0.14000000059604644775390625 / _157;
27
+ float3 _614;
28
+ float3 _616;
29
+ _616 = float3(0.0);
30
+ _614 = float3(0.0);
31
+ float3 _625;
32
+ float3 _627;
33
+ for (int _613 = 0; _613 < 18; _616 = _627, _614 = _625, _613++)
34
+ {
35
+ float _189 = 1.0 - (float(_613) * 0.0588235296308994293212890625);
36
+ float _193 = _189 * _189;
37
+ float _194 = 1.0 - _193;
38
+ float _202 = fast::max(mix(1.0, uFarScale, _194), uFarScale);
39
+ float _210 = _112.x;
40
+ float _216 = mix(-0.62000000476837158203125, _150, _194) + ((_210 * uSlant) * _202);
41
+ float _221 = _202 * uWaveAmp;
42
+ if (abs(_115 - _216) > (((_221 * 1.7000000476837158203125) + (uLineWidth * 3.0)) + 0.0599999986588954925537109375))
43
+ {
44
+ _627 = _616;
45
+ _625 = _614;
46
+ continue;
47
+ }
48
+ float _243 = _210 / _202;
49
+ float _248 = _243 * uWaveScale;
50
+ float _579 = (((sin((_248 + (_194 * 2.4750001430511474609375)) + _145) * 0.60000002384185791015625) + (sin(((_248 * 0.550000011920928955078125) - (_194 * 4.275000095367431640625)) - (_145 * 0.699999988079071044921875)) * 0.449999988079071044921875)) + (sin((((_248 + (_194 * 4.5)) * 0.449999988079071044921875) + (_145 * 0.4000000059604644775390625)) + 1.7000000476837158203125) * 0.4000000059604644775390625)) + (sin(((_248 * 1.7000000476837158203125) - (_194 * 1.35000002384185791015625)) + (_145 * 1.2000000476837158203125)) * 0.1599999964237213134765625);
51
+ float _269 = _115 - (_216 + (_221 * _579));
52
+ float _274 = smoothstep(0.20000000298023223876953125, 1.39999997615814208984375, _579);
53
+ float _278 = _269 * _269;
54
+ float _284 = exp((-_278) * _158);
55
+ float _291 = 1.0 + (_278 * _162);
56
+ float _293 = _284 + (0.2199999988079071044921875 / _291);
57
+ float _299 = fract(_243 * uGridX);
58
+ float _308 = exp(((0.5 - _299) * (_299 - 0.5)) * 48.0);
59
+ _627 = _616 + (((uHazeColor * _293) * _194) * _274);
60
+ _625 = _614 + (((mix(uLineColor, uCrestColor, float3(_274)) * ((_293 + (uStrutMix * (_308 / _291))) + ((uNodeMix * (_284 * _308)) * 2.0))) * _193) * (0.3499999940395355224609375 + _274));
61
+ }
62
+ float3 _387 = (mix(uBgBottom, uBgTop, float3(fast::clamp(_115 + 0.5, 0.0, 1.0))) + ((_614 * uGlow) * _139)) + ((_616 * uHaze) * _139);
63
+ float3 _620;
64
+ if ((uParticles > 0.0) || (uAccent > 0.0))
65
+ {
66
+ float3 _618;
67
+ _618 = float3(0.0);
68
+ float3 _509;
69
+ for (int _617 = 0; _617 < 10; _618 = _509, _617++)
70
+ {
71
+ float _409 = float(_617);
72
+ float _412 = _409 * 1.7000000476837158203125;
73
+ float2 _432 = ((float2(fract(sin((_412 + 0.300000011920928955078125) * 12.98980045318603515625) * 43758.546875), fract(sin(((_409 * 3.099999904632568359375) + 1.89999997615814208984375) * 12.98980045318603515625) * 43758.546875)) * 2.0) - float2(1.0)) * float2(0.920000016689300537109375, 0.4600000083446502685546875);
74
+ float2 _609 = _432;
75
+ _609.x = _432.x + (sin((uTime * 0.070000000298023223876953125) + (_409 * 2.2999999523162841796875)) * 0.02999999932944774627685546875);
76
+ float2 _612 = _609;
77
+ _612.y = _432.y + (cos((uTime * 0.0500000007450580596923828125) + _412) * 0.02999999932944774627685546875);
78
+ float _479 = length(_112 - _612);
79
+ float3 _621;
80
+ if (_617 == 0)
81
+ {
82
+ _621 = uAccentColor * uAccent;
83
+ }
84
+ else
85
+ {
86
+ _621 = uCrestColor * uParticles;
87
+ }
88
+ _509 = _618 + (_621 * (exp(((-_479) * _479) * 2300.0) * (0.5 + (0.5 * sin((uTime * (0.60000002384185791015625 + fract(sin(_409 * 64.949005126953125) * 43758.546875))) + (_409 * 4.0))))));
89
+ }
90
+ _620 = _387 + (_618 * _139);
91
+ }
92
+ else
93
+ {
94
+ _620 = _387;
95
+ }
96
+ out.oColor = float4(float3(1.0) - exp(-_620), 1.0);
97
+ return out;
98
+ }
99
+
@@ -16,75 +16,80 @@ struct main0_in
16
16
  fragment main0_out main0(main0_in in [[stage_in]], constant float& uStarGlow [[buffer(0)]], constant float& uTime [[buffer(1)]], constant float& uTwinkleSpeed [[buffer(2)]], constant float2& uResolution [[buffer(3)]], constant float& uSpeed [[buffer(4)]], constant float& uScale [[buffer(5)]], constant float& uBrightness [[buffer(6)]], constant float3& uColor [[buffer(7)]])
17
17
  {
18
18
  main0_out out = {};
19
- float _312 = (uTime * 0.00999999977648258209228515625) * uSpeed;
20
- float _317 = _312 * 0.0900000035762786865234375;
21
- float3 _674;
22
- float2 _675;
23
- _675 = ((in.vUv * uResolution) - (uResolution * 0.5)) / float2(uResolution.y);
24
- _674 = float3(0.0);
25
- float2 _366;
26
- float3 _385;
27
- for (int _673 = 0; _673 < 8; _675 = _366, _674 = _385, _673++)
19
+ float _317 = (uTime * 0.00999999977648258209228515625) * uSpeed;
20
+ float _322 = _317 * 0.0900000035762786865234375;
21
+ float3 _683;
22
+ float2 _684;
23
+ _684 = ((in.vUv * uResolution) - (uResolution * 0.5)) / float2(uResolution.y);
24
+ _683 = float3(0.0);
25
+ float2 _371;
26
+ float3 _390;
27
+ for (int _682 = 0; _682 < 7; _684 = _371, _683 = _390, _682++)
28
28
  {
29
- float _332 = float(_673) * 0.125;
30
- float _337 = fract(_332 + _312);
31
- float _361 = (_317 * _332) * (-10.0);
32
- float _418 = sin(_361);
33
- float _420 = cos(_361);
34
- _366 = _675 * float2x2(float2(_420, -_418), float2(_418, _420));
35
- float2 _376 = ((_366 * mix(64.0, 0.00999999977648258209228515625, _337)) * uScale) + float2(_332 * (3430.0 + fract(_332)));
36
- float2 _456 = fract(_376) - float2(0.5);
37
- float2 _458 = floor(_376);
38
- float _462 = (uTime * 0.3499999940395355224609375) * uTwinkleSpeed;
39
- float3 _677;
40
- _677 = float3(0.0);
41
- float3 _685;
42
- for (int _676 = -1; _676 <= 1; _677 = _685, _676++)
29
+ float _337 = float(_682) * 0.14285714924335479736328125;
30
+ float _342 = fract(_337 + _317);
31
+ float _366 = (_322 * _337) * (-10.0);
32
+ float _423 = sin(_366);
33
+ float _425 = cos(_366);
34
+ _371 = _684 * float2x2(float2(_425, -_423), float2(_423, _425));
35
+ float2 _381 = ((_371 * mix(64.0, 0.00999999977648258209228515625, _342)) * uScale) + float2(_337 * (3430.0 + fract(_337)));
36
+ float2 _461 = fract(_381) - float2(0.5);
37
+ float2 _463 = floor(_381);
38
+ float _467 = (uTime * 0.3499999940395355224609375) * uTwinkleSpeed;
39
+ float3 _686;
40
+ _686 = float3(0.0);
41
+ float3 _694;
42
+ for (int _685 = -1; _685 <= 1; _686 = _694, _685++)
43
43
  {
44
- _685 = _677;
45
- float3 _534;
46
- for (int _680 = -1; _680 <= 1; _685 = _534, _680++)
44
+ _694 = _686;
45
+ float3 _715;
46
+ for (int _689 = -1; _689 <= 1; _694 = _715, _689++)
47
47
  {
48
- float2 _477 = float2(float(_680), float(_676));
49
- float2 _548 = fract((_458 + _477) * float2(123.4499969482421875, 345.670013427734375));
50
- float2 _556 = _548 + float2(dot(_548, _548 + float2(45.31999969482421875)));
51
- float _562 = fract(_556.x * _556.y);
52
- float2 _494 = (_456 - _477) - float2(_562 - 0.5, fract(_562 * 45.0) - 0.5);
53
- float _497 = fract(_562 * 1356.3299560546875);
54
- float _499 = smoothstep(0.89999997615814208984375, 1.0, _497);
55
- float _683;
48
+ float2 _482 = float2(float(_689), float(_685));
49
+ float2 _557 = fract((_463 + _482) * float2(123.4499969482421875, 345.670013427734375));
50
+ float2 _565 = _557 + float2(dot(_557, _557 + float2(45.31999969482421875)));
51
+ float _571 = fract(_565.x * _565.y);
52
+ float2 _499 = (_461 - _482) - float2(_571 - 0.5, fract(_571 * 45.0) - 0.5);
53
+ float _502 = fract(_571 * 1356.3299560546875);
54
+ float _504 = smoothstep(0.89999997615814208984375, 1.0, _502);
55
+ float _692;
56
56
  do
57
57
  {
58
- float _575 = length(_494);
59
- if (_575 >= 1.0)
58
+ float _584 = length(_499);
59
+ if (_584 >= 1.0)
60
60
  {
61
- _683 = 0.0;
61
+ _692 = 0.0;
62
62
  break;
63
63
  }
64
- float _584 = (0.0500000007450580596923828125 * uStarGlow) / fast::max(_575, 9.9999997473787516355514526367188e-05);
65
- float _682;
66
- if (_499 > 0.0)
64
+ float _593 = (0.0500000007450580596923828125 * uStarGlow) / fast::max(_584, 9.9999997473787516355514526367188e-05);
65
+ float _691;
66
+ if (_504 > 0.0)
67
67
  {
68
- float _589 = _312 * (-0.565486729145050048828125);
69
- float _640 = sin(_589);
70
- float _642 = cos(_589);
71
- float2 _592 = _494 * float2x2(float2(_642, -_640), float2(_640, _642));
72
- float2 _610 = _592 * float2x2(float2(0.707106769084930419921875, -0.707106769084930419921875), float2(0.707106769084930419921875));
73
- _682 = (_584 + (fast::max(0.0, 1.0 - abs((_592.x * _592.y) * 3000.0)) * _499)) + ((fast::max(0.0, 1.0 - abs((_610.x * _610.y) * 3000.0)) * 0.300000011920928955078125) * _499);
68
+ float _598 = _317 * (-0.565486729145050048828125);
69
+ float _649 = sin(_598);
70
+ float _651 = cos(_598);
71
+ float2 _601 = _499 * float2x2(float2(_651, -_649), float2(_649, _651));
72
+ float2 _619 = _601 * float2x2(float2(0.707106769084930419921875, -0.707106769084930419921875), float2(0.707106769084930419921875));
73
+ _691 = (_593 + (fast::max(0.0, 1.0 - abs((_601.x * _601.y) * 3000.0)) * _504)) + ((fast::max(0.0, 1.0 - abs((_619.x * _619.y) * 3000.0)) * 0.300000011920928955078125) * _504);
74
74
  }
75
75
  else
76
76
  {
77
- _682 = _584;
77
+ _691 = _593;
78
78
  }
79
- _683 = _682 * smoothstep(1.0, 0.0500000007450580596923828125, _575);
79
+ _692 = _691 * smoothstep(1.0, 0.0500000007450580596923828125, _584);
80
80
  break;
81
81
  } while(false);
82
- _534 = _685 + (((((sin(float3(0.699999988079071044921875, 0.300000011920928955078125, 0.89999997615814208984375) * ((fract(_562 * 2150.0) * 9.424777984619140625) * _462)) * (0.4000000059604644775390625 * sin(_462))) + float3(0.60000002384185791015625)) * float3(1.0, 0.100000001490116119384765625, 0.89999997615814208984375 + _497)) * (_683 * _497)) * 1.875);
82
+ if (_692 <= 0.0)
83
+ {
84
+ _715 = _694;
85
+ continue;
86
+ }
87
+ _715 = _694 + (((((sin(float3(0.699999988079071044921875, 0.300000011920928955078125, 0.89999997615814208984375) * ((fract(_571 * 2150.0) * 9.424777984619140625) * _467)) * (0.4000000059604644775390625 * sin(_467))) + float3(0.60000002384185791015625)) * float3(1.0, 0.100000001490116119384765625, 0.89999997615814208984375 + _502)) * (_692 * _502)) * 2.142857074737548828125);
83
88
  }
84
89
  }
85
- _385 = _674 + (_677 * (_337 * smoothstep(0.100000001490116119384765625, 1.10000002384185791015625, _337)));
90
+ _390 = _683 + (_686 * (_342 * smoothstep(0.100000001490116119384765625, 1.10000002384185791015625, _342)));
86
91
  }
87
- out.oColor = float4(_674 * (uColor * uBrightness), 1.0);
92
+ out.oColor = float4(_683 * (uColor * uBrightness), 1.0);
88
93
  return out;
89
94
  }
90
95