@pixerate/flair 0.15.0 → 0.17.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 (43) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +33 -6
  3. package/dist/catalog/index.d.ts +3 -3
  4. package/dist/catalog/index.js +6 -2
  5. package/dist/{chunk-SHHAIWUR.js → chunk-LKQM3GSQ.js} +12 -12
  6. package/dist/{chunk-KWNFZ5NC.js → chunk-LURJMWYM.js} +237 -185
  7. package/dist/{chunk-KWNFZ5NC.js.map → chunk-LURJMWYM.js.map} +1 -1
  8. package/dist/{chunk-DVVQRZJ5.js → chunk-MILF5MRS.js} +11 -2
  9. package/dist/chunk-MILF5MRS.js.map +1 -0
  10. package/dist/{chunk-YLJWC4N2.js → chunk-PMVJP5I4.js} +2 -2
  11. package/dist/{chunk-4RGHZWQC.js → chunk-RM3I6WZH.js} +2 -2
  12. package/dist/{chunk-4RGHZWQC.js.map → chunk-RM3I6WZH.js.map} +1 -1
  13. package/dist/{chunk-FIJOMGPG.js → chunk-UP6QQVRS.js} +2 -2
  14. package/dist/{chunk-WC3VADZC.js → chunk-VYOMXE6I.js} +46 -4
  15. package/dist/chunk-VYOMXE6I.js.map +1 -0
  16. package/dist/cli.js +7 -7
  17. package/dist/{controls-Syr6drzO.d.ts → controls-Ec6P0Vpy.d.ts} +9 -2
  18. package/dist/editor/index.d.ts +3 -3
  19. package/dist/editor/index.js +7 -7
  20. package/dist/index.d.ts +4 -4
  21. package/dist/index.js +80 -76
  22. package/dist/index.js.map +1 -1
  23. package/dist/node.d.ts +1 -1
  24. package/dist/node.js +2 -2
  25. package/dist/react/index.d.ts +14 -3
  26. package/dist/react/index.js +18 -9
  27. package/dist/react/index.js.map +1 -1
  28. package/dist/recorder-HKFFHQES.js +10 -0
  29. package/dist/{renderer-SNYZu__R.d.ts → renderer-Bm0oQ7Bw.d.ts} +1 -1
  30. package/dist/svelte/index.d.ts +146 -0
  31. package/dist/svelte/index.js +195 -0
  32. package/dist/svelte/index.js.map +1 -0
  33. package/dist/{types-9J6NWaN3.d.ts → types-C7g8-lTX.d.ts} +9 -3
  34. package/dist/vector/index.d.ts +27 -1
  35. package/dist/vector/index.js +4 -2
  36. package/package.json +13 -3
  37. package/dist/chunk-DVVQRZJ5.js.map +0 -1
  38. package/dist/chunk-WC3VADZC.js.map +0 -1
  39. package/dist/recorder-KEX3U35D.js +0 -10
  40. /package/dist/{chunk-SHHAIWUR.js.map → chunk-LKQM3GSQ.js.map} +0 -0
  41. /package/dist/{chunk-YLJWC4N2.js.map → chunk-PMVJP5I4.js.map} +0 -0
  42. /package/dist/{chunk-FIJOMGPG.js.map → chunk-UP6QQVRS.js.map} +0 -0
  43. /package/dist/{recorder-KEX3U35D.js.map → recorder-HKFFHQES.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/catalog/glsl.ts","../src/catalog/shaders/gradients.ts","../src/catalog/images.ts","../src/catalog/shaders/image.ts","../src/catalog/shaders/light.ts","../src/catalog/shaders/organic.ts","../src/catalog/shaders/patterns.ts","../src/catalog/interaction.ts","../src/catalog/electric.ts","../src/catalog/melt.ts","../src/catalog/shaders/pixel.ts","../src/catalog/pixel.ts","../src/catalog/pyro.ts","../src/catalog/timewarp.ts","../src/catalog/morph.ts","../src/catalog/shaders/interaction.ts","../src/catalog/shaders/electric.ts","../src/catalog/shaders/melt.ts","../src/catalog/shaders/pyro.ts","../src/catalog/shaders/timewarp.ts","../src/catalog/shaders/morph.ts","../src/catalog/shaders/overlay.ts","../src/catalog/shaders/retro.ts","../src/catalog/shaders/text.ts","../src/catalog/shaders/treatments.ts","../src/catalog/text.ts","../src/catalog/types.ts","../src/catalog/vector.ts","../src/catalog/index.ts"],"sourcesContent":["/**\n * GLSL helpers the catalog's shaders are built from. Each effect's source\n * inlines the helpers it uses, so a source stays self-contained: copy it into\n * any Shadertoy-style host and it compiles.\n */\n\n/** Hashes: `hash12` (vec2 → float), `hash22` (vec2 → vec2), both 0–1. */\nexport const HASH = `\nfloat hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\nvec2 hash22(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.xx + p3.yz) * p3.zy);\n}`.trim();\n\n/** Smooth value noise, 0–1 (needs {@link HASH}). */\nexport const NOISE = `\nfloat vnoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n float a = hash12(i);\n float b = hash12(i + vec2(1.0, 0.0));\n float c = hash12(i + vec2(0.0, 1.0));\n float d = hash12(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}`.trim();\n\n/** Fractal noise: `fbm(p, octaves)`, about 0–1 (needs {@link NOISE}). */\nexport const FBM = `\nfloat fbm(vec2 p, int octaves) {\n float sum = 0.0;\n float amp = 0.5;\n mat2 turn = mat2(0.8, 0.6, -0.6, 0.8);\n for (int i = 0; i < 8; i++) {\n if (i >= octaves) break;\n sum += amp * vnoise(p);\n p = turn * p * 2.02 + 17.0;\n amp *= 0.5;\n }\n return sum;\n}`.trim();\n\n/** Inigo Quilez's cosine palette: `palette(t, a, b, c, d)`. */\nexport const PALETTE = `\nvec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {\n return a + b * cos(6.28318 * (c * t + d));\n}`.trim();\n\n/** Mixes colours in Oklab, so blends stay bright: `oklabMix(a, b, t)` on sRGB colours. */\nexport const OKLAB_MIX = `\nvec3 toOklab(vec3 c) {\n c = pow(max(c, 0.0), vec3(2.2));\n vec3 lms = mat3(0.4122, 0.2119, 0.0883, 0.5363, 0.6807, 0.2817, 0.0514, 0.1074, 0.6300) * c;\n lms = pow(lms, vec3(1.0 / 3.0));\n return mat3(0.2105, 1.9780, 0.0259, 0.7936, -2.4286, 0.7828, -0.0041, 0.4506, -0.8087) * lms;\n}\nvec3 fromOklab(vec3 c) {\n vec3 lms = mat3(1.0, 1.0, 1.0, 0.3963, -0.1056, -0.0895, 0.2158, -0.0639, -1.2915) * c;\n lms = lms * lms * lms;\n vec3 rgb = mat3(4.0767, -1.2684, -0.0042, -3.3077, 2.6098, -0.7034, 0.2310, -0.3413, 1.7076) * lms;\n return pow(max(rgb, 0.0), vec3(1.0 / 2.2));\n}\nvec3 oklabMix(vec3 a, vec3 b, float t) {\n return fromOklab(mix(toOklab(a), toOklab(b), t));\n}`.trim();\n\n/** 2D rotation matrix: `rot(angle)`. */\nexport const ROTATE = `\nmat2 rot(float a) {\n float c = cos(a);\n float s = sin(a);\n return mat2(c, s, -s, c);\n}`.trim();\n\n/** Joins helpers and a body into one source, a blank line apart. */\nexport function glsl(...parts: string[]): string {\n return parts.map((p) => p.trim()).join(\"\\n\\n\") + \"\\n\";\n}\n","import { FBM, glsl, HASH, NOISE, OKLAB_MIX, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const aurora: ShaderEffect = {\n kind: \"shader\",\n id: \"aurora\",\n name: \"Aurora\",\n description: \"Soft curtains of light drifting over a night sky.\",\n category: \"gradient\",\n tags: [\"background\", \"hero\", \"calm\", \"night\"],\n source: glsl(\n `// Aurora: curtains of light drifting over a night sky.\nuniform vec3 uSky; // @control color default=#050816 label=\"Sky\"\nuniform vec3 uGlowA; // @control color default=#22D3A6 label=\"Glow A\"\nuniform vec3 uGlowB; // @control color default=#7C3AED label=\"Glow B\"\nuniform float uSpeed; // @control min=0 max=2 default=0.35 label=\"Speed\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"\nuniform float uHeight; // @control min=0 max=1 default=0.55 label=\"Height\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n vec3 col = uSky * (0.6 + 0.4 * uv.y);\n for (int i = 0; i < 3; i++) {\n float fi = float(i);\n float x = uv.x * (1.4 + 0.3 * fi) + fi * 3.7;\n float wave = fbm(vec2(x * 1.5 + t * 0.4, t * 0.25 + fi), 4);\n float centre = uHeight + 0.18 * (wave - 0.5) + 0.06 * fi;\n float band = exp(-pow((uv.y - centre) * (7.0 + 2.0 * fi), 2.0));\n float rays = 0.55 + 0.45 * fbm(vec2(x * 12.0, t * 0.6 + fi * 9.0), 3);\n float above = smoothstep(centre - 0.05, centre + 0.35, uv.y) * 0.35;\n vec3 glow = mix(uGlowA, uGlowB, clamp(uv.y * 1.4 - 0.2 + 0.25 * fi, 0.0, 1.0));\n col += glow * (band * rays + above * band) * 0.6 * uIntensity;\n }\n float stars = step(0.997, hash12(floor(fragCoord * 0.5))) * smoothstep(0.3, 1.0, uv.y);\n col += stars * 0.6 * (0.5 + 0.5 * sin(iTime * 3.0 + hash12(floor(fragCoord)) * 40.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Arctic\", values: { uGlowA: [0.13, 0.83, 0.65], uGlowB: [0.49, 0.23, 0.93] } },\n { name: \"Ember\", values: { uSky: [0.06, 0.02, 0.03], uGlowA: [1, 0.45, 0.1], uGlowB: [0.9, 0.1, 0.4] } },\n { name: \"Ice\", values: { uSky: [0.01, 0.03, 0.06], uGlowA: [0.5, 0.9, 1], uGlowB: [0.2, 0.4, 1] } },\n ],\n};\n\nexport const meshGradient: ShaderEffect = {\n kind: \"shader\",\n id: \"mesh-gradient\",\n name: \"Mesh gradient\",\n description: \"Four colours blended across a slowly warping mesh, mixed in Oklab.\",\n category: \"gradient\",\n tags: [\"background\", \"hero\", \"brand\", \"soft\"],\n source: glsl(\n `// Mesh gradient: four colours on drifting points, blended in Oklab.\nuniform vec3 uColorA; // @control color default=#FF6B6B label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#FFD93D label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#6BCB77 label=\"Colour C\"\nuniform vec3 uColorD; // @control color default=#4D96FF label=\"Colour D\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Speed\"\nuniform float uWarp; // @control min=0 max=1 default=0.35 label=\"Warp\"\nuniform float uGrain; // @control min=0 max=0.2 default=0.04 label=\"Grain\"`,\n HASH,\n NOISE,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n vec2 w = uv + uWarp * 0.3 * vec2(vnoise(uv * 2.0 + t), vnoise(uv * 2.0 - t + 5.0)) - uWarp * 0.15;\n vec2 pa = vec2(0.2, 0.2) + 0.15 * vec2(sin(t * 1.1), cos(t * 0.9));\n vec2 pb = vec2(0.8, 0.25) + 0.15 * vec2(cos(t * 0.7), sin(t * 1.3));\n vec2 pc = vec2(0.25, 0.8) + 0.15 * vec2(sin(t * 0.8 + 2.0), cos(t * 1.2));\n vec2 pd = vec2(0.8, 0.8) + 0.15 * vec2(cos(t * 1.0 + 1.0), sin(t * 0.6));\n vec4 d = vec4(distance(w, pa), distance(w, pb), distance(w, pc), distance(w, pd));\n vec4 k = 1.0 / (d * d + 0.02);\n k /= dot(k, vec4(1.0));\n vec3 ab = oklabMix(uColorA, uColorB, k.y / max(k.x + k.y, 1e-4));\n vec3 cd = oklabMix(uColorC, uColorD, k.w / max(k.z + k.w, 1e-4));\n vec3 col = oklabMix(ab, cd, k.z + k.w);\n col += (hash12(fragCoord + fract(iTime) * 100.0) - 0.5) * uGrain;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Sunset\", values: { uColorA: [1, 0.42, 0.42], uColorB: [1, 0.85, 0.24], uColorC: [0.9, 0.3, 0.6], uColorD: [0.36, 0.2, 0.7] } },\n { name: \"Lagoon\", values: { uColorA: [0.0, 0.6, 0.7], uColorB: [0.5, 0.95, 0.85], uColorC: [0.1, 0.3, 0.6], uColorD: [0.85, 0.95, 1] } },\n { name: \"Mono\", values: { uColorA: [0.1, 0.1, 0.12], uColorB: [0.3, 0.3, 0.34], uColorC: [0.2, 0.2, 0.24], uColorD: [0.6, 0.6, 0.65] } },\n ],\n};\n\nexport const conicSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"conic-sweep\",\n name: \"Conic sweep\",\n description: \"A rotating conic gradient with a soft glowing core.\",\n category: \"gradient\",\n tags: [\"background\", \"spotlight\", \"brand\"],\n loop: 10,\n source: glsl(\n `// Conic sweep: a rotating conic gradient with a glowing core.\nuniform vec3 uColorA; // @control color default=#0EA5E9 label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#A855F7 label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#F43F5E label=\"Colour C\"\nuniform float uTurns; // @control min=-3 max=3 default=1 step=1 label=\"Turns per loop\"\nuniform float uCore; // @control min=0 max=1 default=0.4 label=\"Core glow\"\nuniform vec2 uCenter; // @control min=-0.5 max=0.5 default=0,0 label=\"Centre\"`,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y - uCenter;\n float a = atan(p.y, p.x) / 6.28318 + 0.5;\n a = fract(a + iTime * uTurns / 10.0);\n float s = a * 3.0;\n vec3 col = s < 1.0 ? oklabMix(uColorA, uColorB, s)\n : s < 2.0 ? oklabMix(uColorB, uColorC, s - 1.0)\n : oklabMix(uColorC, uColorA, s - 2.0);\n float r = length(p);\n col *= 0.75 + 0.25 * smoothstep(0.9, 0.0, r);\n col += uCore * exp(-r * 6.0);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const silk: ShaderEffect = {\n kind: \"shader\",\n id: \"silk\",\n name: \"Silk\",\n description: \"Folds of glossy fabric rippling in a slow breeze.\",\n category: \"gradient\",\n tags: [\"background\", \"luxury\", \"soft\"],\n source: glsl(\n `// Silk: glossy folds of fabric rippling slowly.\nuniform vec3 uBase; // @control color default=#3B0764 label=\"Base\"\nuniform vec3 uSheen; // @control color default=#F0ABFC label=\"Sheen\"\nuniform float uSpeed; // @control min=0 max=2 default=0.4 label=\"Speed\"\nuniform float uFolds; // @control min=1 max=10 default=5 label=\"Folds\"\nuniform float uGloss; // @control min=0 max=2 default=1 label=\"Gloss\"`,\n ROTATE,\n `float folds(vec2 p, float t) {\n float h = 0.0;\n for (int i = 1; i <= 4; i++) {\n float fi = float(i);\n h += sin(p.x * uFolds * fi * 0.7 + t * (1.0 + 0.3 * fi) + sin(p.y * 2.0 * fi + t)) / fi;\n }\n return h;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = rot(0.6) * (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float e = 0.002;\n float hx = (folds(p + vec2(e, 0.0), t) - folds(p - vec2(e, 0.0), t)) / (2.0 * e);\n float hy = (folds(p + vec2(0.0, e), t) - folds(p - vec2(0.0, e), t)) / (2.0 * e);\n vec3 n = normalize(vec3(-hx * 0.12, -hy * 0.12, 1.0));\n vec3 l = normalize(vec3(-0.4, 0.6, 0.7));\n float diff = clamp(dot(n, l), 0.0, 1.0);\n float spec = pow(clamp(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0, 1.0), 20.0) * uGloss;\n vec3 col = uBase * (0.35 + 0.9 * diff) + uSheen * (spec + 0.12 * pow(diff, 6.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Champagne\", values: { uBase: [0.55, 0.42, 0.25], uSheen: [1, 0.95, 0.8] } },\n { name: \"Midnight\", values: { uBase: [0.04, 0.08, 0.2], uSheen: [0.6, 0.75, 1] } },\n ],\n};\n\nexport const duotoneFlow: ShaderEffect = {\n kind: \"shader\",\n id: \"gradient-flow\",\n name: \"Gradient flow\",\n description: \"Two colours flowing through each other along a warped noise field.\",\n category: \"gradient\",\n tags: [\"background\", \"brand\", \"liquid\"],\n source: glsl(\n `// Gradient flow: two colours flowing through a warped noise field.\nuniform vec3 uColorA; // @control color default=#1E3A8A label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#F97316 label=\"Colour B\"\nuniform float uSpeed; // @control min=0 max=2 default=0.25 label=\"Speed\"\nuniform float uScale; // @control min=0.5 max=6 default=2 label=\"Scale\"\nuniform float uContrast; // @control min=0.5 max=4 default=1.5 label=\"Contrast\"`,\n HASH,\n NOISE,\n FBM,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n float t = iTime * uSpeed;\n vec2 q = vec2(fbm(p + t, 4), fbm(p + vec2(5.2, 1.3) - t, 4));\n float f = fbm(p + 3.0 * q + vec2(1.7, 9.2) + 0.5 * t, 5);\n f = clamp((f - 0.5) * uContrast + 0.5, 0.0, 1.0);\n fragColor = vec4(oklabMix(uColorA, uColorB, smoothstep(0.0, 1.0, f)), 1.0);\n}`,\n ),\n};\n","/**\n * Sample pictures for the catalog's image effects: small SVGs as `data:` URLs,\n * so image controls have something to show with nothing to download.\n */\n\n/** An ASCII SVG as a base64 `data:image/svg+xml` URL. */\nexport function svgDataUrl(svg: string): string {\n const base64 =\n typeof btoa === \"function\" ? btoa(svg) : (globalThis as { Buffer?: { from(s: string): { toString(e: string): string } } }).Buffer!.from(svg).toString(\"base64\");\n return `data:image/svg+xml;base64,${base64}`;\n}\n\nconst LANDSCAPE = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<defs><linearGradient id=\"s\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#3b4cb8\"/><stop offset=\"1\" stop-color=\"#ffa36b\"/></linearGradient></defs>\n<rect width=\"640\" height=\"360\" fill=\"url(#s)\"/>\n<circle cx=\"420\" cy=\"170\" r=\"62\" fill=\"#ffe9b0\"/>\n<path d=\"M0 250 Q120 190 240 240 T480 230 T640 220 V360 H0Z\" fill=\"#2c4a52\"/>\n<path d=\"M0 290 Q160 240 320 290 T640 280 V360 H0Z\" fill=\"#1b2f33\"/>\n<path d=\"M0 330 Q200 300 400 330 T640 325 V360 H0Z\" fill=\"#0f1c1f\"/>\n</svg>`;\n\nconst CITY = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<rect width=\"640\" height=\"360\" fill=\"#0d1028\"/>\n<circle cx=\"520\" cy=\"80\" r=\"34\" fill=\"#f5f3d7\"/>\n<g fill=\"#252a52\"><rect x=\"20\" y=\"170\" width=\"70\" height=\"190\"/><rect x=\"110\" y=\"120\" width=\"60\" height=\"240\"/><rect x=\"190\" y=\"200\" width=\"80\" height=\"160\"/><rect x=\"290\" y=\"90\" width=\"55\" height=\"270\"/><rect x=\"365\" y=\"160\" width=\"90\" height=\"200\"/><rect x=\"475\" y=\"130\" width=\"60\" height=\"230\"/><rect x=\"555\" y=\"190\" width=\"70\" height=\"170\"/></g>\n<g fill=\"#ffcf5a\"><rect x=\"125\" y=\"140\" width=\"8\" height=\"8\"/><rect x=\"150\" y=\"170\" width=\"8\" height=\"8\"/><rect x=\"305\" y=\"110\" width=\"8\" height=\"8\"/><rect x=\"320\" y=\"150\" width=\"8\" height=\"8\"/><rect x=\"380\" y=\"180\" width=\"8\" height=\"8\"/><rect x=\"420\" y=\"220\" width=\"8\" height=\"8\"/><rect x=\"490\" y=\"150\" width=\"8\" height=\"8\"/><rect x=\"40\" y=\"200\" width=\"8\" height=\"8\"/><rect x=\"215\" y=\"230\" width=\"8\" height=\"8\"/><rect x=\"575\" y=\"215\" width=\"8\" height=\"8\"/></g>\n</svg>`;\n\nconst PORTRAIT = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<rect width=\"640\" height=\"360\" fill=\"#f2e6d8\"/>\n<circle cx=\"320\" cy=\"150\" r=\"70\" fill=\"#c98b6b\"/>\n<path d=\"M190 360 Q200 240 320 240 Q440 240 450 360Z\" fill=\"#33415c\"/>\n<path d=\"M250 130 Q260 60 320 62 Q385 60 392 135 Q370 100 320 100 Q275 100 250 130Z\" fill=\"#2b1d16\"/>\n<circle cx=\"295\" cy=\"150\" r=\"6\" fill=\"#2b1d16\"/><circle cx=\"345\" cy=\"150\" r=\"6\" fill=\"#2b1d16\"/>\n<path d=\"M300 185 Q320 198 340 185\" stroke=\"#7a3e2c\" stroke-width=\"5\" fill=\"none\"/>\n</svg>`;\n\n// A second portrait, the face larger and right of centre, for morphing with PORTRAIT.\n// Features (viewBox units): eyes (396, 175) and (464, 175), mouth (430, 229), chin (430, 270), hairline (430, 80).\nconst PORTRAIT_2 = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\" width=\"640\" height=\"360\">\n<rect width=\"640\" height=\"360\" fill=\"#d3e4e6\"/>\n<path d=\"M255 360 Q268 300 430 297 Q592 300 605 360Z\" fill=\"#a4372f\"/>\n<rect x=\"408\" y=\"250\" width=\"44\" height=\"52\" fill=\"#d9a07c\"/>\n<circle cx=\"430\" cy=\"175\" r=\"95\" fill=\"#e8b48f\"/>\n<path d=\"M332 172 Q330 66 430 64 Q530 66 528 172 Q520 112 470 100 Q420 128 352 116 Q336 140 332 172Z\" fill=\"#8a3b1e\"/>\n<circle cx=\"396\" cy=\"175\" r=\"8\" fill=\"#3a2418\"/><circle cx=\"464\" cy=\"175\" r=\"8\" fill=\"#3a2418\"/>\n<path d=\"M424 186 Q430 206 436 186\" stroke=\"#c48262\" stroke-width=\"5\" fill=\"none\"/>\n<path d=\"M403 225 Q430 244 457 225\" stroke=\"#9c4a35\" stroke-width=\"7\" fill=\"none\" stroke-linecap=\"round\"/>\n</svg>`;\n\n// Flat shapes on transparent, for silhouette morphs and masks.\nconst LOGO = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" width=\"512\" height=\"512\">\n<path fill=\"#6366f1\" fill-rule=\"evenodd\" d=\"M256 56a200 200 0 1 1 0 400a200 200 0 1 1 0-400zm0 92a108 108 0 1 0 0 216a108 108 0 1 0 0-216z\"/>\n<circle cx=\"256\" cy=\"256\" r=\"52\" fill=\"#6366f1\"/>\n</svg>`;\n\nconst HEART = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" width=\"512\" height=\"512\">\n<path fill=\"#f43f5e\" d=\"M256 452C120 352 40 272 40 172C40 102 95 58 160 58C205 58 238 84 256 118C274 84 307 58 352 58C417 58 472 102 472 172C472 272 392 352 256 452Z\"/>\n</svg>`;\n\n/**\n * An icon drawn the way Lucide and similar sets draw them: 24 × 24, stroked\n * in `currentColor` (black in an image) on a transparent background.\n */\nconst ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 20C5 15.5 3 12 3 8.5a4.5 4.5 0 0 1 9 0a4.5 4.5 0 0 1 9 0c0 3.5-2 7-9 11.5Z\"/></svg>`;\n\n/** Built-in sample pictures, as image control values. */\nexport const SAMPLE_IMAGES = {\n landscape: svgDataUrl(LANDSCAPE),\n city: svgDataUrl(CITY),\n portrait: svgDataUrl(PORTRAIT),\n /** Another face, larger and to the right: morph it with `portrait`. */\n portrait2: svgDataUrl(PORTRAIT_2),\n /** A ring-and-dot mark, indigo on transparent. */\n logo: svgDataUrl(LOGO),\n /** A heart, rose on transparent. */\n heart: svgDataUrl(HEART),\n icon: svgDataUrl(ICON),\n} as const;\n\n/** Roughly how wide a character is in a bold sans-serif, in ems, for fitting text without measuring it. */\nfunction charWidth(c: string): number {\n if (/[iIjl.,:;'!|`]/.test(c)) return 0.3;\n if (/[\\sfrt()[\\]\\-]/.test(c)) return 0.4;\n if (/[MW@%]/.test(c)) return 0.94;\n if (/[mw]/.test(c)) return 0.88;\n if (/[A-Z&#]/.test(c)) return 0.74;\n if (/[0-9]/.test(c)) return 0.58;\n if (/[a-z]/.test(c)) return 0.6;\n // Wide scripts (CJK, kana, hangul) and emoji take about a full em.\n return /[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹏＀-⦆]|\\p{Extended_Pictographic}/u.test(c) ? 1 : 0.64;\n}\n\n/** About how wide `text` is in ems in a bold sans-serif (letters are code points). */\nexport function textWidthEm(text: string): number {\n return Array.from(text).reduce((sum, c) => sum + charWidth(c), 0);\n}\n\nconst escapeXml = (text: string) =>\n text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#39;\");\n\nexport interface TextImageOptions {\n /** CSS font family (default a heavy system sans-serif). */\n font?: string;\n /** Font weight (default 900). */\n weight?: number | string;\n /** Font size in the picture's units; by default as large as fits. */\n size?: number;\n /** The picture's size (default 1024 × 256). */\n width?: number;\n height?: number;\n}\n\n/**\n * A line of text, white on transparent, as an SVG `data:` URL for an image\n * control (the shader text effects use its alpha as a letter mask). The text\n * is centred and fitted to the picture (1024 × 256 by default): the font\n * size comes from its length, and `textLength` stretches it to the width\n * that size predicts, so any text fills about the same box in any font.\n * Takes any Unicode text.\n */\nexport function textImage(text: string, options: TextImageOptions = {}): string {\n const width = options.width ?? 1024;\n const height = options.height ?? 256;\n const ems = Math.max(0.5, textWidthEm(text));\n const size = options.size ?? Math.min(height * 0.78, (width * 0.9) / ems);\n const length = Math.min(width * 0.96, ems * size);\n const font = options.font ?? \"'Arial Black', 'Helvetica Neue', Helvetica, Arial, system-ui, sans-serif\";\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${width} ${height}\" width=\"${width}\" height=\"${height}\"><text x=\"${width / 2}\" y=\"${height / 2}\" dy=\"0.35em\" text-anchor=\"middle\" textLength=\"${+length.toFixed(1)}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${escapeXml(font)}\" font-weight=\"${escapeXml(String(options.weight ?? 900))}\" font-size=\"${+size.toFixed(1)}\" fill=\"#fff\">${escapeXml(text)}</text></svg>`;\n // UTF-8 percent-encoded rather than base64 (btoa only takes Latin-1); quotes and brackets are encoded too, so it is safe unquoted.\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg).replace(/['()*!]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)}`;\n}\n","import { getTransitionGLSL, type TransitionType } from \"../../shader/transition.js\";\nimport { glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/**\n * The controls {@link BACKDROP} reads: what shows through an image's\n * transparent parts. At opacity 1 an icon or cut-out (a Lucide icon, a logo)\n * sits on the backdrop colour; at 0 the effect keeps the image's alpha, for\n * overlays on a transparent canvas.\n */\nexport const BACKDROP_CONTROLS = `\nuniform vec3 uBackdrop; // @control color default=#FFFFFF label=\"Backdrop\"\nuniform float uBackdropAlpha; // @control min=0 max=1 default=1 label=\"Backdrop opacity\"`.trim();\n\n/**\n * `overBackdrop(sample)`: an image sample laid over the backdrop (see\n * {@link BACKDROP_CONTROLS}), as straight colour and alpha.\n */\nexport const BACKDROP = `\n// The sample is read as premultiplied: filtering a straight-alpha image whose clear pixels are\n// black (as browsers decode them) premultiplies it, and the clamp clears colour a clear pixel kept.\nvec4 overBackdrop(vec4 s) {\n vec3 colour = min(s.rgb, vec3(s.a)) + uBackdrop * uBackdropAlpha * (1.0 - s.a);\n float alpha = s.a + uBackdropAlpha * (1.0 - s.a);\n return vec4(colour / max(alpha, 1e-4), alpha);\n}`.trim();\n\n/**\n * `picture(tex, uv)`: the image over the backdrop (see {@link BACKDROP}), or a\n * test card while there is none (an empty image control is bound to a 1 × 1\n * placeholder), so effects show something before an image is chosen.\n * `pictureRGBA(tex, uv)` also gives its alpha, which effects pass on. Needs\n * the {@link BACKDROP_CONTROLS} uniforms.\n */\nexport const PICTURE = `\n${BACKDROP}\nvec3 testCard(vec2 uv) {\n vec3 sky = mix(vec3(0.98, 0.62, 0.42), vec3(0.24, 0.32, 0.72), uv.y);\n float sun = smoothstep(0.16, 0.15, length((uv - vec2(0.65, 0.58)) * vec2(1.6, 1.0)));\n float hills = step(uv.y, 0.32 + 0.06 * sin(uv.x * 9.0) + 0.04 * sin(uv.x * 23.0 + 1.0));\n vec3 col = mix(sky, vec3(1.0, 0.92, 0.7), sun);\n col = mix(col, vec3(0.12, 0.28, 0.24) + 0.08 * sin(uv.x * 40.0), hills);\n vec2 grid = abs(fract(uv * 8.0) - 0.5);\n col += 0.04 * step(0.48, max(grid.x, grid.y));\n return col;\n}\nvec4 pictureRGBA(sampler2D tex, vec2 uv) {\n return textureSize(tex, 0).x > 1 ? overBackdrop(texture(tex, uv)) : vec4(testCard(fract(uv)), 1.0);\n}\nvec3 picture(sampler2D tex, vec2 uv) {\n return pictureRGBA(tex, uv).rgb;\n}`.trim();\n\nexport const imageRipple: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ripple\",\n name: \"Ripple\",\n description: \"An image rippling as if seen through water, from the pointer or the centre.\",\n category: \"image\",\n tags: [\"image\", \"water\", \"interactive\", \"distortion\"],\n source: glsl(\n `// Ripple: an image rippling as if under water.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmplitude; // @control min=0 max=0.05 default=0.012 label=\"Amplitude\"\nuniform float uFrequency; // @control min=5 max=80 default=30 label=\"Frequency\"\nuniform float uSpeed; // @control min=0 max=6 default=2 label=\"Speed\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 centre = (iMouse.z > 0.0 ? iMouse.xy : 0.5 * iResolution.xy) / iResolution.xy;\n vec2 d = uv - centre;\n d.x *= iResolution.x / iResolution.y;\n float r = length(d);\n float wave = sin(r * uFrequency - iTime * uSpeed) * smoothstep(0.9, 0.0, r);\n vec2 offset = normalize(d + 1e-5) * wave * uAmplitude;\n vec4 pic = pictureRGBA(uImage, uv + offset);\n vec3 col = pic.rgb + 0.6 * max(wave, 0.0) * uAmplitude * 8.0;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n};\n\nexport const imageGlitch: ShaderEffect = {\n kind: \"shader\",\n id: \"image-glitch\",\n name: \"Glitch\",\n description: \"Digital glitch on an image: RGB split, slice displacement and blocky corruption in bursts.\",\n category: \"image\",\n tags: [\"image\", \"glitch\", \"cyber\", \"transition\"],\n source: glsl(\n `// Glitch: RGB split, slice displacement and blocky corruption in bursts.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmount; // @control min=0 max=1 default=0.5 label=\"Amount\"\nuniform float uSplit; // @control min=0 max=0.05 default=0.012 label=\"RGB split\"\nuniform float uRate; // @control min=0.5 max=12 default=4 label=\"Bursts per second\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float tick = floor(iTime * uRate);\n float burst = step(1.0 - uAmount * 0.6, hash12(vec2(tick, 1.0)));\n float slice = floor(uv.y * mix(8.0, 40.0, hash12(vec2(tick, 2.0))));\n float shift = (hash12(vec2(slice, tick)) - 0.5) * 0.15 * burst * step(0.6, hash12(vec2(slice, tick + 3.0)));\n vec2 block = floor(uv * vec2(16.0, 9.0));\n float corrupt = burst * step(0.97 - uAmount * 0.05, hash12(block + tick));\n vec2 st = uv + vec2(shift, 0.0);\n st = mix(st, floor(st * 24.0) / 24.0, corrupt);\n float split = uSplit * (0.3 + burst);\n vec4 r = pictureRGBA(uImage, st + vec2(split, 0.0));\n vec4 g = pictureRGBA(uImage, st);\n vec4 b = pictureRGBA(uImage, st - vec2(split, 0.0));\n vec3 col = vec3(r.r, g.g, b.b);\n col = mix(col, col.bgr, corrupt);\n col *= 0.92 + 0.08 * sin(fragCoord.y * 2.0);\n fragColor = vec4(col, max(max(r.a, g.a), b.a));\n}`,\n ),\n};\n\nexport const imageDuotone: ShaderEffect = {\n kind: \"shader\",\n id: \"image-duotone\",\n name: \"Duotone\",\n description: \"An image mapped onto two colours, with a slow light sweep.\",\n category: \"image\",\n tags: [\"image\", \"brand\", \"editorial\", \"colour\"],\n source: glsl(\n `// Duotone: an image mapped onto two colours, with a light sweep.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uShadow; // @control color default=#1E1B4B label=\"Shadows\"\nuniform vec3 uHighlight; // @control color default=#FB7185 label=\"Highlights\"\nuniform float uContrast; // @control min=0.5 max=3 default=1.2 label=\"Contrast\"\nuniform float uSweep; // @control min=0 max=1 default=0.3 label=\"Light sweep\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec4 src = pictureRGBA(uImage, uv);\n float l = dot(src.rgb, vec3(0.2126, 0.7152, 0.0722));\n l = clamp((l - 0.5) * uContrast + 0.5, 0.0, 1.0);\n float sweep = exp(-pow((uv.x + uv.y * 0.4 - fract(iTime * 0.15) * 2.0 + 0.4) * 6.0, 2.0));\n vec3 col = mix(uShadow, uHighlight, l) + sweep * uSweep;\n fragColor = vec4(col, src.a);\n}`,\n ),\n presets: [\n { name: \"Spotify\", values: { uShadow: [0.07, 0.1, 0.35], uHighlight: [0.12, 0.84, 0.38] } },\n { name: \"Newsprint\", values: { uShadow: [0.1, 0.1, 0.1], uHighlight: [0.96, 0.94, 0.88] } },\n ],\n};\n\nexport const imagePixelate: ShaderEffect = {\n kind: \"shader\",\n id: \"image-pixelate\",\n name: \"Pixel reveal\",\n description: \"An image resolving from big blocks to full detail, then back, in a loop.\",\n category: \"image\",\n tags: [\"image\", \"reveal\", \"transition\", \"8-bit\"],\n loop: 4,\n source: glsl(\n `// Pixel reveal: an image resolving from blocks to full detail and back.\nuniform sampler2D uImage; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uMaxBlock; // @control min=4 max=128 default=48 label=\"Largest block (px)\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=1 label=\"Detail (when still)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float k = uAnimate ? 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0) : uProgress;\n float block = max(1.0, floor(mix(uMaxBlock, 1.0, k)));\n vec2 cell = (floor(fragCoord / block) + 0.5) * block;\n fragColor = pictureRGBA(uImage, cell / iResolution.xy);\n}`,\n ),\n};\n\nexport const imageHalftone: ShaderEffect = {\n kind: \"shader\",\n id: \"image-halftone\",\n name: \"Halftone\",\n description: \"An image printed as rotated halftone dots, breathing slightly.\",\n category: \"image\",\n tags: [\"image\", \"print\", \"comic\", \"pop-art\"],\n source: glsl(\n `// Halftone: an image as rotated print dots.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uInk; // @control color default=#111827 label=\"Ink\"\nuniform vec3 uPaper; // @control color default=#FEF3C7 label=\"Paper\"\nuniform float uSpacing; // @control min=3 max=30 default=8 label=\"Dot spacing (px)\"\nuniform float uAngle; // @control min=0 max=90 default=45 label=\"Screen angle (°)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float a = radians(uAngle);\n mat2 r = mat2(cos(a), sin(a), -sin(a), cos(a));\n vec2 q = r * fragCoord / uSpacing;\n vec2 cell = floor(q) + 0.5;\n vec2 centre = transpose(r) * cell * uSpacing;\n vec4 pic = pictureRGBA(uImage, centre / iResolution.xy);\n float l = dot(pic.rgb, vec3(0.2126, 0.7152, 0.0722));\n float radius = sqrt(1.0 - l) * 0.62 * (0.95 + 0.05 * sin(iTime * 2.0));\n float d = length(q - cell);\n float ink = smoothstep(radius + 0.06, radius - 0.06, d);\n fragColor = vec4(mix(uPaper, uInk, ink), pic.a);\n}`,\n ),\n};\n\nexport const crt: ShaderEffect = {\n kind: \"shader\",\n id: \"crt\",\n name: \"CRT screen\",\n description: \"An image on a curved CRT: scanlines, shadow mask, bloom and flicker.\",\n category: \"image\",\n tags: [\"image\", \"retro\", \"screen\", \"arcade\"],\n source: glsl(\n `// CRT screen: an image on a curved tube with scanlines and a shadow mask.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uCurve; // @control min=0 max=0.5 default=0.15 label=\"Curvature\"\nuniform float uScanlines; // @control min=0 max=1 default=0.5 label=\"Scanlines\"\nuniform float uMask; // @control min=0 max=1 default=0.35 label=\"Shadow mask\"\nuniform float uFlicker; // @control min=0 max=0.2 default=0.03 label=\"Flicker\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy * 2.0 - 1.0;\n uv *= 1.0 + uCurve * dot(uv.yx, uv.yx) * 0.5;\n vec2 st = uv * 0.5 + 0.5;\n if (st.x < 0.0 || st.x > 1.0 || st.y < 0.0 || st.y > 1.0) {\n fragColor = vec4(0.0, 0.0, 0.0, uBackdropAlpha);\n return;\n }\n vec4 pic = pictureRGBA(uImage, st);\n vec3 col = pic.rgb;\n col += 0.25 * picture(uImage, st + vec2(0.003, 0.0)) * col;\n float scan = 1.0 - uScanlines * 0.5 * (1.0 - cos(st.y * iResolution.y * 3.14159));\n float m = mod(fragCoord.x, 3.0);\n vec3 mask = mix(vec3(1.0), vec3(m < 1.0 ? 1.2 : 0.8, m >= 1.0 && m < 2.0 ? 1.2 : 0.8, m >= 2.0 ? 1.2 : 0.8), uMask);\n col *= scan * mask;\n col *= 1.0 - uFlicker * hash12(vec2(floor(iTime * 24.0), 0.0));\n col *= smoothstep(1.0, 0.7, max(abs(uv.x), abs(uv.y)) * 0.98 + 0.02 * length(uv));\n fragColor = vec4(col, pic.a);\n}`,\n ),\n};\n\nexport const filmGrain: ShaderEffect = {\n kind: \"shader\",\n id: \"film-look\",\n name: \"Film look\",\n description: \"An image graded like film: grain, gate weave, halation and vignette.\",\n category: \"image\",\n tags: [\"image\", \"cinematic\", \"grain\", \"vintage\"],\n source: glsl(\n `// Film look: grain, gate weave, halation and vignette.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uGrain; // @control min=0 max=0.3 default=0.08 label=\"Grain\"\nuniform float uWeave; // @control min=0 max=0.01 default=0.0015 label=\"Gate weave\"\nuniform float uHalation; // @control min=0 max=1 default=0.3 label=\"Halation\"\nuniform float uVignette; // @control min=0 max=1 default=0.45 label=\"Vignette\"\nuniform vec3 uTint; // @control color default=#FFF1DC label=\"Print tint\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float frame = floor(iTime * 24.0);\n uv += uWeave * (vec2(vnoise(vec2(frame * 0.3, 0.0)), vnoise(vec2(0.0, frame * 0.3))) - 0.5);\n vec4 pic = pictureRGBA(uImage, uv);\n vec3 col = pic.rgb;\n vec3 blur = (picture(uImage, uv + vec2(0.006, 0.0)) + picture(uImage, uv - vec2(0.006, 0.0)) +\n picture(uImage, uv + vec2(0.0, 0.006)) + picture(uImage, uv - vec2(0.0, 0.006))) * 0.25;\n float bright = smoothstep(0.6, 1.0, dot(blur, vec3(0.333)));\n col += vec3(1.0, 0.3, 0.1) * bright * uHalation * 0.5;\n col *= uTint;\n col += (hash12(fragCoord + frame * 31.7) - 0.5) * uGrain;\n col *= 1.0 - uVignette * smoothstep(0.3, 0.9, length(uv - 0.5) * 1.3);\n fragColor = vec4(col, pic.a);\n}`,\n ),\n};\n\nconst TRANSITIONS: { type: TransitionType; id: string; name: string; description: string }[] = [\n { type: \"linearWipe\", id: \"wipe\", name: \"Wipe\", description: \"A soft-edged wipe from one image to the next.\" },\n { type: \"radialIris\", id: \"iris\", name: \"Iris\", description: \"A circle opening from the centre onto the next image.\" },\n { type: \"blockDissolve\", id: \"block-dissolve\", name: \"Block dissolve\", description: \"Random blocks switching to the next image.\" },\n { type: \"gridWipe\", id: \"grid-wipe\", name: \"Grid wipe\", description: \"A diagonal cascade of cells revealing the next image.\" },\n { type: \"glassWipe\", id: \"glass-wipe\", name: \"Glass wipe\", description: \"A refracting glass edge sweeping across.\" },\n { type: \"twister\", id: \"twister\", name: \"Twister\", description: \"A swirl that twists one image into the next.\" },\n { type: \"lightLeak\", id: \"light-leak\", name: \"Light leak\", description: \"A warm flare of light burning through to the next image.\" },\n { type: \"crossZoom\", id: \"cross-zoom\", name: \"Cross zoom\", description: \"A zoom blur punching through to the next image.\" },\n];\n\n/** The transitions (see `getTransitionGLSL`) as looping effects between two images. */\nexport const transitions: ShaderEffect[] = TRANSITIONS.map(({ type, id, name, description }) => ({\n kind: \"shader\",\n id: `transition-${id}`,\n name,\n description: `${description} Loops back and forth; or turn Animate off and set Progress.`,\n category: \"transition\",\n tags: [\"transition\", \"image\", \"slideshow\"],\n loop: 4,\n source: glsl(\n `// ${name} transition between two images. Progress runs 0 → 1 → 0 when animated.\nuniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"From image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"To image\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\n${BACKDROP_CONTROLS}`,\n BACKDROP,\n getTransitionGLSL(type),\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float p = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n fragColor = overBackdrop(flair_transition(uFrom, uTo, uv, p));\n}`,\n ),\n}));\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const bokeh: ShaderEffect = {\n kind: \"shader\",\n id: \"bokeh\",\n name: \"Bokeh\",\n description: \"Out-of-focus city lights drifting softly.\",\n category: \"light\",\n tags: [\"background\", \"festive\", \"dreamy\", \"night\"],\n source: glsl(\n `// Bokeh: soft out-of-focus lights drifting.\nuniform vec3 uBackground; // @control color default=#0B1026 label=\"Background\"\nuniform float uBackgroundAlpha; // @control min=0 max=1 default=1 label=\"Background opacity\"\nuniform vec3 uWarm; // @control color default=#FFC56E label=\"Warm light\"\nuniform vec3 uCool; // @control color default=#6EC8FF label=\"Cool light\"\nuniform int uCount; // @control min=4 max=60 default=30 label=\"Lights\"\nuniform float uSize; // @control min=0.02 max=0.25 default=0.08 label=\"Size\"\nuniform float uSpeed; // @control min=0 max=1 default=0.15 label=\"Drift\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec3 col = uBackground * (0.7 + 0.3 * fragCoord.y / iResolution.y) * uBackgroundAlpha;\n float lightAlpha = 0.0;\n for (int i = 0; i < 60; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 h = hash22(vec2(fi, 3.1));\n float depth = hash12(vec2(fi, 9.7));\n vec2 c = vec2(fract(h.x + iTime * uSpeed * (0.2 + depth) * 0.1) * (aspect + 0.4) - 0.2, h.y);\n c.y += 0.03 * sin(iTime * 0.5 + fi);\n float r = uSize * (0.5 + depth);\n float d = length(p - c);\n float disc = smoothstep(r, r * 0.85, d) * (0.6 + 0.4 * smoothstep(r * 0.4, r, d));\n vec3 light = mix(uWarm, uCool, step(0.5, hash12(vec2(fi, 1.3))));\n float weight = disc * (0.15 + 0.25 * (1.0 - depth));\n col += light * weight;\n lightAlpha += weight;\n }\n float a = clamp(uBackgroundAlpha + lightAlpha * (1.0 - uBackgroundAlpha), 0.0, 1.0);\n fragColor = vec4(col, a);\n}`,\n ),\n};\n\nexport const godRays: ShaderEffect = {\n kind: \"shader\",\n id: \"god-rays\",\n name: \"God rays\",\n description: \"Shafts of light fanning down through haze.\",\n category: \"light\",\n tags: [\"background\", \"hero\", \"heavenly\", \"spotlight\"],\n source: glsl(\n `// God rays: shafts of light fanning through haze.\nuniform vec3 uBackground; // @control color default=#0C0A09 label=\"Background\"\nuniform vec3 uLight; // @control color default=#FDE68A label=\"Light\"\nuniform vec2 uSource; // @control min=-1 max=1 default=0,0.6 label=\"Source\"\nuniform float uRays; // @control min=4 max=60 default=18 label=\"Rays\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Speed\"\nuniform float uStrength; // @control min=0 max=2 default=1 label=\"Strength\"`,\n HASH,\n NOISE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec2 d = p - uSource * vec2(iResolution.x / iResolution.y, 1.0) * 0.5;\n float a = atan(d.x, -d.y);\n float r = length(d);\n float t = iTime * uSpeed;\n float rays = vnoise(vec2(a * uRays, t)) * 0.6 + vnoise(vec2(a * uRays * 2.3, -t * 1.3)) * 0.4;\n rays = pow(rays, 2.0) * smoothstep(1.6, 0.0, r);\n float glow = exp(-r * 4.0);\n vec3 col = uBackground + uLight * (rays * 0.9 + glow * 0.8) * uStrength;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const sparkles: ShaderEffect = {\n kind: \"shader\",\n id: \"sparkles\",\n name: \"Sparkles\",\n description: \"Four-pointed glints twinkling on and off across the frame.\",\n category: \"light\",\n tags: [\"overlay\", \"magic\", \"celebration\", \"premium\"],\n source: glsl(\n `// Sparkles: four-pointed glints twinkling across the frame.\nuniform vec3 uBackground; // @control color default=#1E1B4B label=\"Background\"\nuniform float uBackgroundAlpha; // @control min=0 max=1 default=1 label=\"Background opacity\"\nuniform vec3 uSparkle; // @control color default=#FFFFFF label=\"Sparkle\"\nuniform float uDensity; // @control min=2 max=30 default=10 label=\"Density\"\nuniform float uChance; // @control min=0.02 max=1 default=1 label=\"Sparsity\"\nuniform float uSize; // @control min=0.05 max=0.5 default=0.35 label=\"Size\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Twinkle speed\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uDensity;\n float glint = 0.0;\n for (int layer = 0; layer < 2; layer++) {\n vec2 q = p * (1.0 + float(layer) * 0.6) + float(layer) * 7.3;\n vec2 id = floor(q);\n float keep = step(1.0 - uChance, hash12(id + 19.0 + float(layer) * 31.0));\n vec2 f = fract(q) - 0.5;\n vec2 o = hash22(id) - 0.5;\n vec2 d = f - o * 0.6;\n float phase = hash12(id + 4.0) * 6.28318;\n float tw = pow(max(0.0, sin(iTime * uSpeed * 2.0 + phase)), 4.0);\n float r = length(d);\n float rays = max(0.0, 1.0 - abs(d.x * d.y) * 3000.0);\n float core = 0.01 / (r + 0.01);\n float star = (rays * 0.8 + core) * smoothstep(uSize, 0.0, r) * tw * keep;\n glint += star;\n }\n vec3 col = uBackground * uBackgroundAlpha + uSparkle * glint;\n float a = clamp(uBackgroundAlpha + glint * (1.0 - uBackgroundAlpha), 0.0, 1.0);\n fragColor = vec4(col, a);\n}`,\n ),\n};\n\nexport const neonRipple: ShaderEffect = {\n kind: \"shader\",\n id: \"neon-ripple\",\n name: \"Neon ripple\",\n description: \"Glowing neon rings radiating out from the pointer or the centre.\",\n category: \"light\",\n tags: [\"interactive\", \"glow\", \"music\", \"pulse\"],\n loop: 2,\n source: glsl(\n `// Neon ripple: glowing rings radiating from the pointer (or the centre).\nuniform vec3 uBackground; // @control color default=#09090B label=\"Background\"\nuniform vec3 uNeon; // @control color default=#FF2BD6 label=\"Neon\"\nuniform float uRings; // @control min=1 max=10 default=4 label=\"Rings\"\nuniform float uWidth; // @control min=0.002 max=0.05 default=0.01 label=\"Width\"\nuniform float uGlow; // @control min=0 max=3 default=1 label=\"Glow\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 centre = iMouse.z > 0.0 ? iMouse.xy : 0.5 * iResolution.xy;\n float r = length(fragCoord - centre) / iResolution.y;\n float phase = fract(r * uRings - iTime * 0.5);\n float ringDist = min(phase, 1.0 - phase) / uRings;\n float fade = smoothstep(1.2, 0.0, r);\n float core = smoothstep(uWidth, 0.0, ringDist);\n float glow = uWidth * 2.0 / (ringDist + uWidth) * 0.25 * uGlow;\n vec3 col = uBackground + uNeon * (core + glow) * fade;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const starfield: ShaderEffect = {\n kind: \"shader\",\n id: \"starfield\",\n name: \"Warp starfield\",\n description: \"Flying through a field of stars, from cruising to warp speed.\",\n category: \"space\",\n tags: [\"background\", \"space\", \"speed\", \"sci-fi\"],\n source: glsl(\n `// Warp starfield: flying through layers of stars.\nuniform vec3 uBackground; // @control color default=#000005 label=\"Background\"\nuniform vec3 uStar; // @control color default=#E0E7FF label=\"Star\"\nuniform float uSpeed; // @control min=0 max=4 default=0.6 label=\"Speed\"\nuniform float uStreak; // @control min=0 max=1 default=0.3 label=\"Streak\"\nuniform int uLayers; // @control min=1 max=8 default=5 label=\"Layers\"`,\n HASH,\n ROTATE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec3 col = uBackground;\n float n = float(uLayers);\n for (int i = 0; i < 8; i++) {\n if (i >= uLayers) break;\n float depth = fract(float(i) / n + iTime * uSpeed * 0.1);\n float scale = mix(20.0, 0.5, depth);\n float fade = depth * smoothstep(1.0, 0.85, depth);\n vec2 q = rot(float(i) * 1.7) * p * scale + float(i) * 13.1;\n vec2 id = floor(q);\n vec2 f = fract(q) - 0.5;\n vec2 o = hash22(id) - 0.5;\n vec2 d = f - o * 0.8;\n vec2 dir = normalize(p + 1e-4);\n float along = dot(d, dir);\n float across = length(d - dir * along);\n float len = 0.02 + uStreak * depth * 0.4;\n float star = smoothstep(0.03, 0.0, across) * smoothstep(len, 0.0, abs(along));\n star *= step(0.6, hash12(id + 2.0));\n col += uStar * star * fade * 1.5;\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const nebula: ShaderEffect = {\n kind: \"shader\",\n id: \"nebula\",\n name: \"Nebula\",\n description: \"Glowing gas clouds and stars drifting in deep space.\",\n category: \"space\",\n tags: [\"background\", \"space\", \"cosmic\", \"hero\"],\n source: glsl(\n `// Nebula: glowing gas clouds over a field of stars.\nuniform vec3 uGasA; // @control color default=#7C3AED label=\"Gas A\"\nuniform vec3 uGasB; // @control color default=#EC4899 label=\"Gas B\"\nuniform vec3 uDeep; // @control color default=#020010 label=\"Deep space\"\nuniform float uSpeed; // @control min=0 max=1 default=0.05 label=\"Drift\"\nuniform float uDensity; // @control min=0 max=2 default=1 label=\"Density\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * 2.0;\n float t = iTime * uSpeed;\n vec2 q = vec2(fbm(p + t, 5), fbm(p - t + 3.3, 5));\n float gas = fbm(p * 1.3 + 2.5 * q, 6);\n float dust = smoothstep(0.45, 0.75, fbm(p * 3.0 - q, 5));\n vec3 col = uDeep;\n col += uGasA * smoothstep(0.35, 0.8, gas) * uDensity;\n col += uGasB * smoothstep(0.5, 0.9, gas * q.x * 1.6) * uDensity;\n col *= 1.0 - 0.6 * dust;\n float star = step(0.996, hash12(floor(fragCoord)));\n float bright = step(0.9993, hash12(floor(fragCoord * 0.5) + 7.0));\n col += vec3(star * 0.7 + bright * (0.8 + 0.2 * sin(iTime * 4.0 + fragCoord.x)));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const blackHole: ShaderEffect = {\n kind: \"shader\",\n id: \"event-horizon\",\n name: \"Event horizon\",\n description: \"A glowing accretion disc swirling into a black hole.\",\n category: \"space\",\n tags: [\"space\", \"dramatic\", \"vortex\", \"hero\"],\n source: glsl(\n `// Event horizon: an accretion disc swirling into a black hole.\nuniform vec3 uHot; // @control color default=#FFE4B5 label=\"Hot\"\nuniform vec3 uDisc; // @control color default=#FF6A00 label=\"Disc\"\nuniform float uRadius; // @control min=0.05 max=0.4 default=0.15 label=\"Horizon\"\nuniform float uSpin; // @control min=0 max=4 default=1 label=\"Spin\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n p.y *= 2.2;\n float r = length(p);\n float a = atan(p.y, p.x);\n float swirl = a + uSpin * iTime * 0.5 + 1.5 / (r + 0.05);\n float streaks = fbm(vec2(swirl * 3.0, r * 8.0), 5);\n float disc = smoothstep(uRadius, uRadius * 1.6, r) * smoothstep(1.0, uRadius * 1.6, r);\n vec3 col = mix(uDisc, uHot, smoothstep(0.5, 0.9, streaks) * smoothstep(0.6, 0.1, r));\n col *= disc * (0.4 + 1.2 * streaks);\n col += uHot * 0.6 * exp(-abs(r - uRadius * 1.05) * 60.0);\n col *= smoothstep(uRadius * 0.95, uRadius * 1.05, r);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const lightRibbons: ShaderEffect = {\n kind: \"shader\",\n id: \"light-ribbons\",\n name: \"Light ribbons\",\n description: \"A bundle of thin iridescent light strands weaving across a dark frame.\",\n category: \"light\",\n tags: [\"background\", \"hero\", \"tech\", \"iridescent\", \"flow\"],\n source: glsl(\n `// Light ribbons: thin glowing strands weaving across the frame, shading from one colour to the next.\nuniform vec3 uBackground; // @control color default=#05060D label=\"Background\"\nuniform vec3 uColorA; // @control color default=#4FD1FF label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#B06BFF label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#FF7AC6 label=\"Colour C\"\nuniform float uCount; // @control min=2 max=24 default=12 step=1 label=\"Strands\"\nuniform float uSpread; // @control min=0.02 max=0.6 default=0.18 label=\"Spread\"\nuniform float uWave; // @control min=0 max=0.5 default=0.22 label=\"Wave\"\nuniform float uTilt; // @control min=-1 max=1 default=0.3 label=\"Tilt\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Glow\"`,\n `// Three colours round a loop, so the shading drifts without a seam.\nvec3 shade(float g) {\n g = fract(g) * 3.0;\n return g < 1.0 ? mix(uColorA, uColorB, g) : g < 2.0 ? mix(uColorB, uColorC, g - 1.0) : mix(uColorC, uColorA, g - 2.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n float halfWidth = 0.5 * iResolution.x / iResolution.y;\n float x = p.x;\n float y = p.y - x * uTilt;\n // The bundle pinches and opens along its length, like ribbons twisting.\n float pinch = 0.35 + 0.65 * abs(sin(x * 1.3 - t * 0.7));\n vec3 light = vec3(0.0);\n for (int i = 0; i < 24; i++) {\n if (float(i) >= uCount) break;\n float f = float(i) / max(uCount - 1.0, 1.0) - 0.5;\n float centre = f * uSpread * pinch\n + uWave * (0.6 * sin(x * 1.7 + t + f * 2.0) + 0.3 * sin(x * 3.3 - t * 1.3 + f * 5.0));\n float d = abs(y - centre);\n float core = 1.0 - smoothstep(0.0, px * 1.5, d);\n float glow = uGlow * 0.006 / (d + 0.006);\n light += shade(f * 0.6 + x * 0.12 + t * 0.05) * (core * 0.9 + glow * 0.4);\n }\n light *= 1.0 - 0.75 * pow(min(abs(x) / halfWidth, 1.0), 2.0);\n fragColor = vec4(uBackground + (1.0 - exp(-light)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Gold\", values: { uBackground: [0.03, 0.03, 0.04], uColorA: [1, 0.78, 0.4], uColorB: [0.75, 0.5, 0.2], uColorC: [1, 0.93, 0.75], uCount: 8, uSpread: 0.4 } },\n { name: \"Aurora\", values: { uColorA: [0.2, 1, 0.7], uColorB: [0.2, 0.6, 1], uColorC: [0.6, 0.3, 1], uTilt: -0.2, uWave: 0.3 } },\n ],\n};\n","import { FBM, glsl, HASH, NOISE, PALETTE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const marble: ShaderEffect = {\n kind: \"shader\",\n id: \"marble\",\n name: \"Liquid marble\",\n description: \"Veined marble swirling like ink in water (domain-warped noise).\",\n category: \"organic\",\n tags: [\"background\", \"ink\", \"liquid\", \"luxury\"],\n source: glsl(\n `// Liquid marble: domain-warped noise swirling like ink in water.\nuniform vec3 uStone; // @control color default=#F5F1E8 label=\"Stone\"\nuniform vec3 uVein; // @control color default=#1F2937 label=\"Vein\"\nuniform vec3 uAccent; // @control color default=#B08D57 label=\"Accent\"\nuniform float uSpeed; // @control min=0 max=1 default=0.15 label=\"Speed\"\nuniform float uScale; // @control min=0.5 max=6 default=2.5 label=\"Scale\"\nuniform float uWarp; // @control min=0 max=8 default=4 label=\"Warp\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n float t = iTime * uSpeed;\n vec2 q = vec2(fbm(p + vec2(0.0, t), 5), fbm(p + vec2(5.2, 1.3 - t), 5));\n vec2 r = vec2(fbm(p + uWarp * q + vec2(1.7, 9.2) + 0.3 * t, 5), fbm(p + uWarp * q + vec2(8.3, 2.8), 5));\n float f = fbm(p + uWarp * r, 5);\n float vein = 1.0 - smoothstep(0.0, 0.06, abs(sin(f * 12.0 + r.x * 6.0)));\n vec3 col = mix(uStone, uStone * 0.85, length(q) * 0.6);\n col = mix(col, uAccent, smoothstep(0.55, 0.9, r.y) * 0.5);\n col = mix(col, uVein, vein * 0.85);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Nero\", values: { uStone: [0.08, 0.08, 0.09], uVein: [0.9, 0.88, 0.82], uAccent: [0.7, 0.55, 0.3] } },\n { name: \"Jade\", values: { uStone: [0.18, 0.45, 0.35], uVein: [0.85, 0.95, 0.88], uAccent: [0.05, 0.2, 0.15] } },\n ],\n};\n\nexport const smoke: ShaderEffect = {\n kind: \"shader\",\n id: \"smoke\",\n name: \"Smoke\",\n description: \"Billowing smoke or cloud drifting upwards.\",\n category: \"organic\",\n tags: [\"background\", \"atmosphere\", \"cloud\", \"mist\"],\n source: glsl(\n `// Smoke: billowing fractal noise drifting upwards.\nuniform vec3 uBackground; // @control color default=#0B0F19 label=\"Background\"\nuniform vec3 uSmoke; // @control color default=#CBD5E1 label=\"Smoke\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Speed\"\nuniform float uDensity; // @control min=0 max=2 default=1 label=\"Density\"\nuniform int uDetail; // @control min=1 max=8 default=6 label=\"Detail\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * 3.0;\n float t = iTime * uSpeed;\n p.y -= t;\n float n = fbm(p + fbm(p + vec2(t * 0.3, 0.0), uDetail), uDetail);\n float body = smoothstep(0.35, 0.85, n) * uDensity;\n float fade = smoothstep(0.0, 0.7, fragCoord.y / iResolution.y + 0.2);\n vec3 col = mix(uBackground, uSmoke, clamp(body * fade, 0.0, 1.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const lavaLamp: ShaderEffect = {\n kind: \"shader\",\n id: \"lava-lamp\",\n name: \"Lava lamp\",\n description: \"Soft metaballs merging and parting as they rise and fall.\",\n category: \"organic\",\n tags: [\"background\", \"playful\", \"blobs\", \"retro\"],\n source: glsl(\n `// Lava lamp: metaballs merging as they rise and fall.\nuniform vec3 uBackground; // @control color default=#1A0B2E label=\"Background\"\nuniform vec3 uBlobA; // @control color default=#FF5E8A label=\"Blob A\"\nuniform vec3 uBlobB; // @control color default=#FFB347 label=\"Blob B\"\nuniform int uCount; // @control min=2 max=12 default=7 label=\"Blobs\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform float uSize; // @control min=0.02 max=0.3 default=0.12 label=\"Size\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float t = iTime * uSpeed;\n float field = 0.0;\n float tint = 0.0;\n for (int i = 0; i < 12; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 seed = hash22(vec2(fi, 7.0));\n vec2 c = vec2(seed.x * aspect, 0.5 + 0.45 * sin(t * (0.4 + seed.y) + fi * 2.1));\n c.x += 0.1 * sin(t * 0.7 + fi);\n float r = uSize * (0.7 + 0.6 * seed.y);\n float k = r * r / dot(p - c, p - c);\n field += k;\n tint += k * seed.x;\n }\n float inside = smoothstep(0.9, 1.1, field);\n vec3 blob = mix(uBlobA, uBlobB, clamp(tint / max(field, 1e-3), 0.0, 1.0));\n blob *= 0.85 + 0.15 * smoothstep(1.0, 3.0, field);\n vec3 col = mix(uBackground, blob, inside);\n col += blob * 0.15 * smoothstep(0.3, 0.9, field) * (1.0 - inside);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const plasma: ShaderEffect = {\n kind: \"shader\",\n id: \"plasma\",\n name: \"Plasma\",\n description: \"The demoscene classic: interfering sine waves through a colour palette.\",\n category: \"organic\",\n tags: [\"background\", \"retro\", \"psychedelic\", \"loop\"],\n loop: 6.28318,\n source: glsl(\n `// Plasma: interfering sine waves through a cosine palette.\nuniform float uScale; // @control min=1 max=20 default=8 label=\"Scale\"\nuniform float uShift; // @control min=0 max=1 default=0 label=\"Hue shift\"\nuniform vec3 uPhase; // @control min=0 max=1 default=0,0.33,0.67 label=\"Palette phase\"`,\n PALETTE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uScale;\n float t = iTime;\n float v = sin(p.x + t);\n v += sin((p.y + t) * 0.5);\n v += sin((p.x + p.y + t) * 0.5);\n vec2 c = p + vec2(sin(t * 0.5), cos(t * 0.5)) * uScale * 0.3;\n v += sin(sqrt(dot(c, c) + 1.0) + t);\n vec3 col = palette(v * 0.25 + uShift, vec3(0.5), vec3(0.5), vec3(1.0), uPhase);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const caustics: ShaderEffect = {\n kind: \"shader\",\n id: \"caustics\",\n name: \"Caustics\",\n description: \"Light dancing on the floor of a swimming pool.\",\n category: \"organic\",\n tags: [\"background\", \"water\", \"summer\", \"calm\"],\n source: glsl(\n `// Caustics: light dancing on the floor of a pool.\nuniform vec3 uWater; // @control color default=#0369A1 label=\"Water\"\nuniform vec3 uLight; // @control color default=#E0F2FE label=\"Light\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform float uScale; // @control min=1 max=10 default=4 label=\"Scale\"\nuniform float uBright; // @control min=0 max=2 default=1 label=\"Brightness\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n // After Dave Hoskins' \"Tileable water caustic\".\n vec2 uv = fragCoord / iResolution.y * uScale * 0.25;\n float t = iTime * uSpeed * 0.5 + 23.0;\n vec2 p = mod(uv * 6.28318, 6.28318) - 250.0;\n vec2 i = p;\n float c = 1.0;\n float inten = 0.005;\n for (int n = 0; n < 5; n++) {\n float tn = t * (1.0 - 3.5 / float(n + 1));\n i = p + vec2(cos(tn - i.x) + sin(tn + i.y), sin(tn - i.y) + cos(tn + i.x));\n c += 1.0 / length(vec2(p.x / (sin(i.x + tn) / inten), p.y / (cos(i.y + tn) / inten)));\n }\n c /= 5.0;\n c = 1.17 - pow(c, 1.4);\n float light = pow(abs(c), 8.0) * uBright;\n vec3 col = uWater + uLight * clamp(light, 0.0, 1.5);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const flames: ShaderEffect = {\n kind: \"shader\",\n id: \"flames\",\n name: \"Flames\",\n description: \"A wall of fire licking upwards from the bottom edge.\",\n category: \"organic\",\n tags: [\"fire\", \"energy\", \"hot\", \"overlay\"],\n source: glsl(\n `// Flames: a wall of fire licking upwards.\nuniform vec3 uHot; // @control color default=#FFF3B0 label=\"Hot\"\nuniform vec3 uMid; // @control color default=#FF7A00 label=\"Mid\"\nuniform vec3 uCool; // @control color default=#7A0000 label=\"Cool\"\nuniform float uSpeed; // @control min=0 max=3 default=1.2 label=\"Speed\"\nuniform float uHeight; // @control min=0.1 max=1.5 default=0.7 label=\"Height\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = vec2(fragCoord.x / iResolution.y, uv.y);\n float t = iTime * uSpeed;\n float n = fbm(vec2(p.x * 4.0, p.y * 3.0 - t * 1.5), 5);\n float heat = (1.0 - uv.y / uHeight) + (n - 0.5) * 1.1;\n heat = clamp(heat, 0.0, 1.0);\n vec3 col = mix(vec3(0.0), uCool, smoothstep(0.05, 0.3, heat));\n col = mix(col, uMid, smoothstep(0.3, 0.6, heat));\n col = mix(col, uHot, smoothstep(0.6, 0.95, heat));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Spirit\", values: { uHot: [0.85, 1, 1], uMid: [0.2, 0.6, 1], uCool: [0.05, 0.05, 0.4] } },\n { name: \"Toxic\", values: { uHot: [0.95, 1, 0.7], uMid: [0.4, 0.95, 0.2], uCool: [0.05, 0.25, 0.05] } },\n ],\n};\n","import { glsl, HASH, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const dotWave: ShaderEffect = {\n kind: \"shader\",\n id: \"dot-wave\",\n name: \"Dot wave\",\n description: \"A halftone grid of dots swelling in a travelling wave.\",\n category: \"pattern\",\n tags: [\"background\", \"halftone\", \"tech\", \"minimal\"],\n loop: 4,\n source: glsl(\n `// Dot wave: a grid of dots swelling in a travelling wave.\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"\nuniform vec3 uDot; // @control color default=#38BDF8 label=\"Dot\"\nuniform float uSpacing; // @control min=8 max=64 default=22 label=\"Spacing (px)\"\nuniform float uWaves; // @control min=0.5 max=6 default=2 label=\"Waves\"\nuniform bool uRadial; // @control default=true label=\"Radial\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uSpacing);\n vec2 local = fract(fragCoord / uSpacing) - 0.5;\n vec2 centre = (cell + 0.5) * uSpacing;\n vec2 p = (centre - 0.5 * iResolution.xy) / iResolution.y;\n float d = uRadial ? length(p) : p.x + p.y * 0.3;\n float phase = d * uWaves * 6.28318 - iTime * 6.28318 / 4.0;\n float size = 0.1 + 0.32 * (0.5 + 0.5 * sin(phase));\n float aa = 1.5 / uSpacing;\n float disc = 1.0 - smoothstep(size - aa, size + aa, length(local));\n vec3 col = mix(uBackground, uDot * (0.6 + 0.4 * size / 0.42), disc);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const truchet: ShaderEffect = {\n kind: \"shader\",\n id: \"truchet\",\n name: \"Truchet flow\",\n description: \"Quarter-circle Truchet tiles forming endless winding paths, with light flowing along them.\",\n category: \"pattern\",\n tags: [\"background\", \"maze\", \"geometric\", \"tech\"],\n source: glsl(\n `// Truchet flow: winding quarter-circle tiles with light flowing along them.\nuniform vec3 uBackground; // @control color default=#111827 label=\"Background\"\nuniform vec3 uLine; // @control color default=#F472B6 label=\"Line\"\nuniform float uTiles; // @control min=3 max=30 default=10 label=\"Tiles\"\nuniform float uWidth; // @control min=0.02 max=0.3 default=0.1 label=\"Line width\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Flow speed\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uTiles;\n vec2 id = floor(p);\n vec2 f = fract(p) - 0.5;\n float flip = hash12(id) > 0.5 ? 1.0 : -1.0;\n f.x *= flip;\n vec2 c = f.x > -f.y ? vec2(0.5) : vec2(-0.5);\n vec2 q = f - c;\n float d = abs(length(q) - 0.5);\n float angle = atan(q.y, q.x);\n float checker = mod(id.x + id.y, 2.0) * 2.0 - 1.0;\n float flow = 0.5 + 0.5 * sin(angle * 4.0 * checker * flip + iTime * uSpeed * 4.0);\n float line = 1.0 - smoothstep(uWidth - 0.02, uWidth, d);\n vec3 col = mix(uBackground, uLine * (0.45 + 0.75 * flow), line);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const hexPulse: ShaderEffect = {\n kind: \"shader\",\n id: \"hex-pulse\",\n name: \"Hex pulse\",\n description: \"A honeycomb grid lighting up cell by cell in ripples.\",\n category: \"pattern\",\n tags: [\"background\", \"tech\", \"honeycomb\", \"sci-fi\"],\n source: glsl(\n `// Hex pulse: a honeycomb grid lighting up in ripples.\nuniform vec3 uBackground; // @control color default=#020617 label=\"Background\"\nuniform vec3 uEdge; // @control color default=#22D3EE label=\"Edge\"\nuniform vec3 uFill; // @control color default=#0E7490 label=\"Fill\"\nuniform float uCells; // @control min=3 max=40 default=12 label=\"Cells\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"`,\n HASH,\n `vec4 hexCoords(vec2 p) {\n vec2 r = vec2(1.0, 1.7320508);\n vec2 h = r * 0.5;\n vec2 a = mod(p, r) - h;\n vec2 b = mod(p - h, r) - h;\n vec2 gv = dot(a, a) < dot(b, b) ? a : b;\n return vec4(gv, p - gv);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uCells;\n vec4 h = hexCoords(p);\n vec2 gv = abs(h.xy);\n float edgeDist = 0.5 - max(dot(gv, normalize(vec2(1.0, 1.7320508))), gv.x);\n float ripple = 0.5 + 0.5 * sin(length(h.zw) * 0.6 - iTime * uSpeed * 3.0);\n float spark = step(0.92, hash12(h.zw + floor(iTime * uSpeed * 2.0)));\n float lit = clamp(pow(ripple, 6.0) + spark * 0.6, 0.0, 1.0);\n vec3 col = mix(uBackground, uFill, lit * smoothstep(0.0, 0.1, edgeDist));\n col = mix(col, uEdge, (1.0 - smoothstep(0.0, 0.04, edgeDist)) * (0.3 + 0.7 * ripple));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const moire: ShaderEffect = {\n kind: \"shader\",\n id: \"moire\",\n name: \"Moiré rings\",\n description: \"Two sets of concentric rings sliding over each other into shimmering interference.\",\n category: \"pattern\",\n tags: [\"background\", \"op-art\", \"hypnotic\", \"minimal\"],\n source: glsl(\n `// Moiré rings: two ring sets interfering as they slide.\nuniform vec3 uInk; // @control color default=#111111 label=\"Ink\"\nuniform vec3 uPaper; // @control color default=#F5F5F0 label=\"Paper\"\nuniform float uRings; // @control min=10 max=200 default=80 label=\"Rings\"\nuniform float uDrift; // @control min=0 max=0.5 default=0.15 label=\"Drift\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec2 o = uDrift * vec2(sin(iTime * 0.4), cos(iTime * 0.3));\n float a = sin(length(p - o) * uRings);\n float b = sin(length(p + o) * uRings);\n float v = smoothstep(-0.2, 0.2, a * b);\n fragColor = vec4(mix(uInk, uPaper, v), 1.0);\n}`,\n ),\n};\n\nexport const barberStripes: ShaderEffect = {\n kind: \"shader\",\n id: \"stripes\",\n name: \"Stripes\",\n description: \"Diagonal stripes marching across, for progress bars, banners and warnings.\",\n category: \"pattern\",\n tags: [\"progress\", \"banner\", \"warning\", \"loop\"],\n loop: 1,\n source: glsl(\n `// Stripes: diagonal stripes marching across.\nuniform vec3 uColorA; // @control color default=#FACC15 label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#18181B label=\"Colour B\"\nuniform float uWidth; // @control min=4 max=120 default=28 label=\"Stripe width (px)\"\nuniform float uAngle; // @control min=-90 max=90 default=45 label=\"Angle (°)\"\nuniform float uSoft; // @control min=0 max=1 default=0.05 label=\"Softness\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float a = radians(uAngle);\n float d = dot(fragCoord, vec2(cos(a), sin(a))) / (uWidth * 2.0);\n float s = fract(d - iTime);\n float edge = max(uSoft * 0.5, 0.5 / uWidth);\n float m = smoothstep(0.5 - edge, 0.5 + edge, s) - smoothstep(1.0 - edge, 1.0, s) + (1.0 - smoothstep(0.0, edge, s));\n fragColor = vec4(mix(uColorA, uColorB, clamp(m, 0.0, 1.0)), 1.0);\n}`,\n ),\n};\n\nexport const voronoi: ShaderEffect = {\n kind: \"shader\",\n id: \"voronoi\",\n name: \"Living cells\",\n description: \"Voronoi cells drifting and dividing, like a microscope slide.\",\n category: \"pattern\",\n tags: [\"background\", \"biology\", \"cells\", \"organic\"],\n source: glsl(\n `// Living cells: drifting Voronoi cells with glowing walls.\nuniform vec3 uBackground; // @control color default=#052E16 label=\"Background\"\nuniform vec3 uCell; // @control color default=#4ADE80 label=\"Cell\"\nuniform vec3 uWall; // @control color default=#DCFCE7 label=\"Wall\"\nuniform float uScale; // @control min=2 max=20 default=6 label=\"Scale\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n vec2 i = floor(p);\n vec2 f = fract(p);\n float d1 = 8.0;\n float d2 = 8.0;\n float shade = 0.0;\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 g = vec2(float(x), float(y));\n vec2 o = hash22(i + g);\n o = 0.5 + 0.4 * sin(iTime * uSpeed + 6.28318 * o);\n float d = length(g + o - f);\n if (d < d1) { d2 = d1; d1 = d; shade = hash12(i + g); }\n else if (d < d2) { d2 = d; }\n }\n }\n float wall = 1.0 - smoothstep(0.0, 0.08, d2 - d1);\n vec3 col = mix(uBackground, uCell * (0.4 + 0.6 * shade), smoothstep(0.9, 0.1, d1));\n col = mix(col, uWall, wall);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const kaleidoscope: ShaderEffect = {\n kind: \"shader\",\n id: \"kaleidoscope\",\n name: \"Kaleidoscope\",\n description: \"Mirrored wedges of shifting colour turning around the centre.\",\n category: \"pattern\",\n tags: [\"psychedelic\", \"music\", \"symmetry\"],\n source: glsl(\n `// Kaleidoscope: mirrored wedges of shifting colour.\nuniform int uSegments; // @control min=2 max=16 default=8 label=\"Segments\"\nuniform float uZoom; // @control min=0.5 max=8 default=3 label=\"Zoom\"\nuniform float uSpeed; // @control min=0 max=2 default=0.4 label=\"Speed\"\nuniform vec3 uTint; // @control color default=#FFFFFF label=\"Tint\"`,\n ROTATE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float n = float(uSegments);\n float a = atan(p.y, p.x) + t * 0.3;\n float r = length(p);\n float wedge = 6.28318 / n;\n a = mod(a, wedge);\n a = abs(a - wedge * 0.5);\n vec2 q = vec2(cos(a), sin(a)) * r * uZoom;\n q = rot(t * 0.2) * q + t;\n vec3 col = 0.5 + 0.5 * cos(vec3(0.0, 2.0, 4.0) + q.x * 2.0 + sin(q.y * 3.0) + t);\n col *= 0.6 + 0.4 * sin(q.x * 5.0) * sin(q.y * 5.0);\n col *= smoothstep(1.2, 0.2, r);\n fragColor = vec4(col * uTint, 1.0);\n}`,\n ),\n};\n\nexport const neonCircuit: ShaderEffect = {\n kind: \"shader\",\n id: \"neon-circuit\",\n name: \"Neon circuit\",\n description: \"Glowing neon traces routed up a circuit board, with pulses of light racing along them.\",\n category: \"pattern\",\n tags: [\"background\", \"neon\", \"circuit\", \"tech\", \"80s\", \"vaporwave\"],\n source: glsl(\n `// Neon circuit: glowing traces climbing a board in rounded jogs, with pulses running along them.\nuniform vec3 uBackground; // @control color default=#170A2E label=\"Background\"\nuniform vec3 uColorA; // @control color default=#FF5FA2 label=\"Trace A\"\nuniform vec3 uColorB; // @control color default=#43E5FF label=\"Trace B\"\nuniform vec3 uColorC; // @control color default=#FFD23F label=\"Trace C\"\nuniform vec3 uColorD; // @control color default=#9D7BFF label=\"Trace D\"\nuniform float uLanes; // @control min=4 max=40 default=14 label=\"Lanes\"\nuniform float uDensity; // @control min=0.1 max=1 default=0.7 label=\"Density\"\nuniform float uWidth; // @control min=0.04 max=0.4 default=0.16 label=\"Line width\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Glow\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Pulse speed\"\nuniform float uPulses; // @control min=0 max=1 default=0.5 label=\"Pulses\"\nuniform float uScroll; // @control min=-2 max=2 default=0.4 label=\"Scroll\"\nuniform float uGrid; // @control min=0 max=1 default=0.3 label=\"Grid\"`,\n HASH,\n `// Each trace k owns lanes 3k..3k+2 and climbs in runs of RUN lanes, jogging\n// sideways between them on rounded corners, so traces never cross.\nconst float RUN = 2.5;\nconst float RADIUS = 0.35;\n\nfloat laneOf(float k, float j) {\n return 3.0 * k + floor(hash12(vec2(k, j) + 0.37) * 3.0) + 0.5;\n}\n\nvec3 traceColor(float k) {\n float h = hash12(vec2(k, 7.3));\n return h < 0.25 ? uColorA : h < 0.5 ? uColorB : h < 0.75 ? uColorC : uColorD;\n}\n\n// Distance to a quarter circle of RADIUS round c, in the quadrant whose signs are q.\nfloat arcDist(vec2 p, vec2 c, vec2 q) {\n vec2 d = p - c;\n return d.x * q.x >= 0.0 && d.y * q.y >= 0.0 ? abs(length(d) - RADIUS) : 1e5;\n}\n\n// Trace k's run j: distance from p to its climb (x) and how far up it p is (y), then\n// the same for its jog into run j + 1 (z, w), measured along the run.\nvec4 run(vec2 p, float k, float j) {\n float x0 = laneOf(k, j - 1.0);\n float x1 = laneOf(k, j);\n float x2 = laneOf(k, j + 1.0);\n float y0 = j * RUN;\n float y1 = y0 + RUN;\n float lo = y0 + (x0 == x1 ? 0.0 : RADIUS);\n float hi = y1 - (x2 == x1 ? 0.0 : RADIUS);\n vec4 r = vec4(length(p - vec2(x1, clamp(p.y, lo, hi))), p.y - y0, 1e5, 0.0);\n if (x2 != x1) {\n float sx = sign(x2 - x1);\n float h = length(p - vec2(clamp(p.x, min(x1, x2) + RADIUS, max(x1, x2) - RADIUS), y1));\n h = min(h, arcDist(p, vec2(x1 + sx * RADIUS, y1 - RADIUS), vec2(-sx, 1.0)));\n h = min(h, arcDist(p, vec2(x2 - sx * RADIUS, y1 + RADIUS), vec2(sx, -1.0)));\n r.zw = vec2(h, RUN + abs(p.x - x1));\n }\n return r;\n}\n\n// How bright a pulse is at s along run j of trace k: a bright head with a fading tail.\n// A pulse crosses one run per cycle and carries on into the next with the next cycle.\nfloat pulseAt(float k, float j, float s) {\n float cycle = iTime * uSpeed * 1.5 + hash12(vec2(k, 8.8));\n float behind = fract(cycle) * (RUN + abs(laneOf(k, j + 1.0) - laneOf(k, j))) - s;\n float lit = step(hash12(vec2(k, floor(cycle) - j)), uPulses);\n return lit * (behind >= 0.0 ? exp(-behind * 0.8) : exp(behind * 30.0));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = uLanes / iResolution.y;\n vec2 p = fragCoord * px;\n p.y += iTime * uScroll;\n\n vec2 g = abs(fract(p / 1.5) - 0.5);\n float grid = 1.0 - smoothstep(0.0, px * 1.5, (0.5 - max(g.x, g.y)) * 1.5);\n vec3 light = uColorD * 0.12 * uGrid * grid;\n\n float home = floor(p.x / 3.0);\n for (int i = -1; i <= 1; i++) {\n float k = home + float(i);\n if (hash12(vec2(k, 1.9)) > uDensity) continue;\n vec2 q = vec2(p.x, p.y + hash12(vec2(k, 4.1)) * RUN);\n float jq = floor(q.y / RUN);\n float w = uWidth * 0.5;\n // The trace's nearest point lights it; each piece's pulse lights only round that piece.\n float d = 1e5;\n float pulse = 0.0;\n for (int b = -1; b <= 1; b++) {\n float j = jq + float(b);\n vec4 r = run(q, k, j);\n d = min(d, min(r.x, r.z));\n pulse = max(pulse, pulseAt(k, j, r.y) * exp(-r.x / uWidth));\n if (r.z < 1e4) pulse = max(pulse, pulseAt(k, j, r.w) * exp(-r.z / uWidth));\n }\n float core = 1.0 - smoothstep(w - px, w + px, d);\n float glow = uGlow * (0.5 * exp(-d / uWidth) + 0.2 * exp(-d / (uWidth * 5.0)));\n vec3 c = traceColor(k);\n light += c * (core * 0.8 + glow + uGlow * pulse) + mix(c, vec3(1.0), 0.7) * core * pulse * 3.0;\n }\n fragColor = vec4(uBackground + (1.0 - exp(-light * 1.4)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Mainframe\", values: { uBackground: [0.0, 0.04, 0.02], uColorA: [0.2, 1, 0.45], uColorB: [0.1, 0.75, 0.35], uColorC: [0.6, 1, 0.7], uColorD: [0.1, 0.5, 0.25] } },\n { name: \"Blueprint\", values: { uBackground: [0.02, 0.06, 0.16], uColorA: [0.35, 0.75, 1], uColorB: [0.6, 0.9, 1], uColorC: [1, 1, 1], uColorD: [0.25, 0.45, 0.9], uGlow: 0.6, uPulses: 0.3 } },\n { name: \"Dense\", values: { uLanes: 26, uDensity: 1, uWidth: 0.12, uPulses: 0.8 } },\n ],\n};\n","import { rgbToHex } from \"../shader/controls.js\";\nimport { morphPaths } from \"../vector/morph.js\";\nimport type { SvgAnimation, SvgMotion } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * UI micro-interactions play in answer to the pointer (`trigger`), not on a\n * loop. Hover and press pictures play to their end while hovered or held and\n * back after, so each is designed to look right backwards too. Click\n * pictures change on steps: a toggle turns on with step 1 and back off with\n * step 2, ending exactly as it started; a one-shot (copy, send, download)\n * has a single step that returns by itself, so every click replays it.\n * Elements a step only flashes (a ring, particles, a tick) snap back to their\n * starting values once hidden, so each round starts from the same look.\n */\n\nconst r1 = (v: number) => Math.round(v * 10) / 10;\nconst r2 = (v: number) => Math.round(v * 100) / 100;\n\n/** A derived number in an animation's numeric field (`count`, `ms`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/** `a` mixed `t` of the way to `b`, colours as written by vector controls ([r, g, b] 0–1). */\nconst mixHex = (a: unknown, b: unknown, t: number) => {\n const x = (Array.isArray(a) ? a : [1, 1, 1]) as number[];\n const y = (Array.isArray(b) ? b : [1, 1, 1]) as number[];\n return rgbToHex([0, 1, 2].map((i) => x[i]! + (y[i]! - x[i]!) * t));\n};\n\n/** Text fitted to `width` units, at most `max` high: its font size and width. */\nfunction fit(text: unknown, width: number, max: number) {\n const e = Math.max(0.6, textWidthEm(String(text)));\n const size = Math.min(max, width / e);\n return { size: r1(size), length: r1(e * size) };\n}\n\n/** A transform scaling by `s` about (`cx`, `cy`). */\nconst about = (cx: number, cy: number, s: number) => `translate(${cx} ${cy}) scale(${r2(s)}) translate(${-cx} ${-cy})`;\n\n/** Instant changes: the attribute snaps to `value` at `delay` (resets of hidden elements). */\nconst snap = (id: string, attr: string, value: string | number, delay: number, step = 1): SvgAnimation => ({\n id,\n step,\n attrs: { [attr]: [value, value] },\n delay,\n ms: 0,\n});\n\nconst SANS = `system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif`;\n\n/** A heart in a 24 box, curves and all. */\nconst HEART = \"M12 20.5 C12 20.5 3 14.8 3 8.8 C3 6 5.2 3.8 8 3.8 C9.7 3.8 11.2 4.7 12 6.1 C12.8 4.7 14.3 3.8 16 3.8 C18.8 3.8 21 6 21 8.8 C21 14.8 12 20.5 12 20.5 Z\";\n\n/** Like button's burst: particles round the heart, from and to these radii. */\nconst PARTICLES = 8;\nconst BURST_FROM = 22;\nconst BURST_TO = 46;\nconst HEART_X = 72;\nconst HEART_Y = 60;\n/** The heart's group: centred on the heart, scaled by `k` (1 at rest). */\nconst heartPose = (k: number) => `translate(${HEART_X} ${HEART_Y}) scale(${r2(2.2 * k)}) translate(-12 -12)`;\n\nexport const likeButton: VectorEffect = {\n kind: \"vector\",\n id: \"like-button\",\n name: \"Like button\",\n description: \"A heart that fills with a springy pop, a ring and a burst of particles as its like count ticks up, and empties again on the next click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"like\", \"heart\", \"toggle\", \"social\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], chip: [0.13, 0.14, 0.19], outline: [0.6, 0.63, 0.7], ink: [0.9, 0.91, 0.95] } },\n { name: \"Purple\", values: { heart: [0.6, 0.3, 1], accent: [1, 0.4, 0.75], count: 1204 } },\n ],\n derived: (v) => ({ liked: Number(v.count) + 1 }),\n motion: {\n svg: `<svg viewBox=\"0 0 240 120\"><!-- {{count: int min=0 max=99999 default=42 label='Start count'}} {{background: color default=#FFFFFF label='Background'}} {{chip: color default=#F3F4F6 label='Button'}} {{outline: color default=#6B7280 label='Outline'}} {{heart: color default=#F43F5E label='Heart'}} {{accent: color default=#FB923C label='Sparks'}} {{ink: color default=#111827 label='Count colour'}} --><rect width=\"240\" height=\"120\" fill=\"{{background}}\"/><rect x=\"20\" y=\"24\" width=\"200\" height=\"72\" rx=\"36\" fill=\"{{chip}}\"/><circle id=\"ring\" cx=\"${HEART_X}\" cy=\"${HEART_Y}\" r=\"14\" fill=\"none\" stroke=\"{{heart}}\" stroke-width=\"0\"/>${Array.from(\n { length: PARTICLES },\n (_, k) => {\n const a = ((k * 360) / PARTICLES - 90) * (Math.PI / 180);\n return `<circle id=\"p${k}\" cx=\"${r1(HEART_X + BURST_FROM * Math.cos(a))}\" cy=\"${r1(HEART_Y + BURST_FROM * Math.sin(a))}\" r=\"0\" fill=\"${k % 2 ? \"{{accent}}\" : \"{{heart}}\"}\"/>`;\n },\n ).join(\"\")}<g id=\"hg\" transform=\"${heartPose(1)}\"><path id=\"heartShape\" d=\"${HEART}\" fill=\"{{heart}}\" fill-opacity=\"0\" stroke=\"{{outline}}\" stroke-width=\"1.8\" stroke-linejoin=\"round\"/></g><text id=\"tally\" x=\"106\" y=\"70.5\" font-family=\"${SANS}\" font-size=\"30\" font-weight=\"700\" fill=\"{{ink}}\">{{count}}</text></svg>`,\n animate: [\n // Step 1, like: squash, pop past full size and settle while it fills.\n { id: \"hg\", step: 1, attrs: { transform: [heartPose(1), heartPose(0.78)] }, ms: 110, ease: \"out\" },\n { id: \"hg\", step: 1, attrs: { transform: [heartPose(0.78), heartPose(1.22)] }, delay: 110, ms: 170, ease: \"out\" },\n { id: \"hg\", step: 1, attrs: { transform: [heartPose(1.22), heartPose(1)] }, delay: 280, ms: 220, ease: \"in-out\" },\n { id: \"heartShape\", step: 1, attrs: { \"fill-opacity\": [0, 1], stroke: [\"{{outline}}\", \"{{heart}}\"] }, delay: 110, ms: 120 },\n // The ring and sparks burst out, then snap back once they are gone.\n snap(\"ring\", \"stroke-width\", 0, 0),\n { id: \"ring\", step: 1, attrs: { r: [14, 44], \"stroke-width\": [10, 0] }, delay: 130, ms: 480, ease: \"out\" },\n snap(\"ring\", \"r\", 14, 700),\n ...Array.from({ length: PARTICLES }, (_, k): SvgAnimation[] => {\n const a = ((k * 360) / PARTICLES - 90) * (Math.PI / 180);\n const [x0, y0] = [r1(HEART_X + BURST_FROM * Math.cos(a)), r1(HEART_Y + BURST_FROM * Math.sin(a))];\n const [x1, y1] = [r1(HEART_X + BURST_TO * Math.cos(a)), r1(HEART_Y + BURST_TO * Math.sin(a))];\n return [\n snap(`p${k}`, \"r\", 0, 0),\n { id: `p${k}`, step: 1, attrs: { cx: [x0, x1], cy: [y0, y1], r: [4.5, 0] }, delay: 150, ms: 520, ease: \"out\" },\n snap(`p${k}`, \"cx\", x0, 700),\n snap(`p${k}`, \"cy\", y0, 700),\n ];\n }).flat(),\n { id: \"tally\", step: 1, count: [n(\"count\"), n(\"liked\")], attrs: { fill: [\"{{ink}}\", \"{{heart}}\"] }, delay: 150, ms: 260, ease: \"out\" },\n // Step 2, unlike: a small dip as it empties and the count goes back.\n { id: \"hg\", step: 2, attrs: { transform: [heartPose(1), heartPose(0.86)] }, ms: 120, ease: \"out\" },\n { id: \"hg\", step: 2, attrs: { transform: [heartPose(0.86), heartPose(1)] }, delay: 120, ms: 200, ease: \"in-out\" },\n { id: \"heartShape\", step: 2, attrs: { \"fill-opacity\": [1, 0], stroke: [\"{{heart}}\", \"{{outline}}\"] }, ms: 180 },\n { id: \"tally\", step: 2, count: [n(\"liked\"), n(\"count\")], attrs: { fill: [\"{{heart}}\", \"{{ink}}\"] }, ms: 220, ease: \"out\" },\n ],\n },\n};\n\nexport const toggleSwitch: VectorEffect = {\n kind: \"vector\",\n id: \"toggle-switch\",\n name: \"Toggle switch\",\n description: \"A switch whose knob slides across, squashing a little mid-slide, as the track blends to its on colour; the next click slides it back.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"toggle\", \"switch\", \"settings\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"iOS\", values: { on: [0.2, 0.78, 0.35] } },\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], off: [0.22, 0.24, 0.3], on: [0.55, 0.45, 1], knob: [0.96, 0.96, 1] } },\n ],\n motion: ((): SvgMotion => {\n const slide = (from: number, to: number, step: number): SvgAnimation[] => [\n { id: \"slide\", step, attrs: { transform: [`translate(${from} 0)`, `translate(${to} 0)`] }, ms: 320, ease: \"in-out\" },\n // Stretched along the slide and flattened halfway, round again at the end.\n { id: \"knob\", step, attrs: { rx: [19, 24], ry: [19, 16.5] }, ms: 160, ease: \"out\" },\n { id: \"knob\", step, attrs: { rx: [24, 19], ry: [16.5, 19] }, delay: 160, ms: 160, ease: \"in-out\" },\n ];\n return {\n svg: `<svg viewBox=\"0 0 200 120\"><!-- {{background: color default=#FFFFFF label='Background'}} {{off: color default=#D1D5DB label='Track off'}} {{on: color default=#6366F1 label='Track on'}} {{knob: color default=#FFFFFF label='Knob'}} --><rect width=\"200\" height=\"120\" fill=\"{{background}}\"/><rect id=\"track\" x=\"40\" y=\"35\" width=\"120\" height=\"50\" rx=\"25\" fill=\"{{off}}\"/><g id=\"slide\" transform=\"translate(0 0)\"><ellipse cx=\"65\" cy=\"62.5\" rx=\"18\" ry=\"18\" fill=\"#000000\" opacity=\"0.16\"/><ellipse id=\"knob\" cx=\"65\" cy=\"60\" rx=\"19\" ry=\"19\" fill=\"{{knob}}\"/></g></svg>`,\n animate: [\n ...slide(0, 70, 1),\n { id: \"track\", step: 1, attrs: { fill: [\"{{off}}\", \"{{on}}\"] }, ms: 320, ease: \"in-out\" },\n ...slide(70, 0, 2),\n { id: \"track\", step: 2, attrs: { fill: [\"{{on}}\", \"{{off}}\"] }, ms: 320, ease: \"in-out\" },\n ],\n };\n })(),\n};\n\nexport const checkbox: VectorEffect = {\n kind: \"vector\",\n id: \"checkbox\",\n name: \"Checkbox\",\n description: \"A labelled checkbox that fills with a press and draws its tick on, then undraws it and empties on the next click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"checkbox\", \"form\", \"toggle\", \"todo\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Green\", values: { accent: [0.13, 0.7, 0.4] } },\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], border: [0.4, 0.43, 0.5], ink: [0.92, 0.93, 0.96], accent: [0.95, 0.6, 0.15], tick: [0.06, 0.07, 0.1] } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 216, 24);\n return { size, length, base: r1(60 + size * 0.35) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 120\"><!-- {{label: text default='Remember me' label='Label'}} {{background: color default=#FFFFFF label='Background'}} {{border: color default=#9CA3AF label='Border'}} {{accent: color default=#6366F1 label='Checked'}} {{tick: color default=#FFFFFF label='Tick'}} {{ink: color default=#111827 label='Label colour'}} --><rect width=\"320\" height=\"120\" fill=\"{{background}}\"/><g id=\"boxg\" transform=\"${about(48, 60, 1)}\"><rect id=\"box\" x=\"30\" y=\"42\" width=\"36\" height=\"36\" rx=\"9\" fill=\"{{accent}}\" fill-opacity=\"0\" stroke=\"{{border}}\" stroke-width=\"3\"/><path id=\"tick\" d=\"M39 60.5 L45.5 67 L58 53.5\" fill=\"none\" stroke=\"{{tick}}\" stroke-width=\"4.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g><text x=\"84\" y=\"{{base}}\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"500\" fill=\"{{ink}}\">{{label}}</text></svg>`,\n animate: [\n // Step 1, check: the box dips as it fills, then the tick draws on.\n { id: \"boxg\", step: 1, attrs: { transform: [about(48, 60, 1), about(48, 60, 0.86)] }, ms: 100, ease: \"out\" },\n { id: \"boxg\", step: 1, attrs: { transform: [about(48, 60, 0.86), about(48, 60, 1)] }, delay: 100, ms: 220, ease: \"in-out\" },\n { id: \"box\", step: 1, attrs: { \"fill-opacity\": [0, 1], stroke: [\"{{border}}\", \"{{accent}}\"] }, ms: 160 },\n // Shown only once it starts drawing: a round cap would leave a dot.\n { id: \"tick\", step: 1, attrs: { opacity: [0, 1] }, delay: 120, ms: 40 },\n { id: \"tick\", step: 1, draw: true, delay: 120, ms: 260, ease: \"out\" },\n // Step 2, uncheck: the tick undraws, then the box empties.\n { id: \"tick\", step: 2, draw: [1, 0], ms: 160, ease: \"in-out\" },\n { id: \"tick\", step: 2, attrs: { opacity: [1, 0] }, delay: 140, ms: 30 },\n { id: \"box\", step: 2, attrs: { \"fill-opacity\": [1, 0], stroke: [\"{{accent}}\", \"{{border}}\"] }, delay: 100, ms: 180 },\n { id: \"boxg\", step: 2, attrs: { transform: [about(48, 60, 1), about(48, 60, 0.92)] }, delay: 100, ms: 90, ease: \"out\" },\n { id: \"boxg\", step: 2, attrs: { transform: [about(48, 60, 0.92), about(48, 60, 1)] }, delay: 190, ms: 160, ease: \"in-out\" },\n ],\n },\n};\n\ntype Point = [number, number];\n\n/**\n * A stroke from `p` to `q`, `width` wide, as a filled outline: round ends,\n * or a flat one at `q` (where a cut stroke meets another without overlap,\n * which `evenodd` would punch a hole through).\n */\nfunction capsule(p: Point, q: Point, width: number, flatEnd = false): string {\n const h = width / 2;\n const a = Math.atan2(q[1] - p[1], q[0] - p[0]);\n const pts: Point[] = [];\n const cap = (c: Point, from: number) => {\n for (let k = 0; k <= 8; k++) {\n const t = from + (k * Math.PI) / 8;\n pts.push([c[0] + h * Math.cos(t), c[1] + h * Math.sin(t)]);\n }\n };\n if (flatEnd) pts.push([q[0] + h * Math.cos(a - Math.PI / 2), q[1] + h * Math.sin(a - Math.PI / 2)], [q[0] + h * Math.cos(a + Math.PI / 2), q[1] + h * Math.sin(a + Math.PI / 2)]);\n else cap(q, a - Math.PI / 2);\n cap(p, a + Math.PI / 2);\n return `M${pts.map((pt) => `${r2(pt[0])} ${r2(pt[1])}`).join(\" L\")} Z`;\n}\n\nconst menuMorphs = new Map<number, [string, string]>();\n\n/** Three bars and the close cross (one whole diagonal, the other cut where it meets it) at a line weight, in a 24 box, morphed once per weight. */\nfunction menuMorph(weight: number): [string, string] {\n if (!menuMorphs.has(weight)) {\n const bars = [7, 12, 17].map((y) => capsule([5, y], [19, y], weight)).join(\" \");\n // A cut stroke ends half a width from the centre, so its corners just touch the whole one.\n const meet = (weight / 2 + 0.05) / Math.SQRT2;\n const cross = [\n capsule([6.5, 6.5], [17.5, 17.5], weight),\n capsule([17.5, 6.5], [12 + meet, 12 - meet], weight, true),\n capsule([6.5, 17.5], [12 - meet, 12 + meet], weight, true),\n ].join(\" \");\n menuMorphs.set(weight, morphPaths(bars, cross, { points: 48 }));\n }\n return menuMorphs.get(weight)!;\n}\n\n/** The menu icon's group: centred in the button, turned `turn` degrees. */\nconst menuPose = (turn: number) => `translate(60 60) rotate(${turn}) scale(3) translate(-12 -12)`;\n\nexport const menuToggle: VectorEffect = {\n kind: \"vector\",\n id: \"menu-toggle\",\n name: \"Menu toggle\",\n description: \"A hamburger menu button whose three bars morph into a close cross as it spins half a turn, and back on the next click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"menu\", \"hamburger\", \"close\", \"morph\", \"navigation\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], button: [0.95, 0.96, 0.97], active: [0.07, 0.09, 0.15], ink: [0.07, 0.09, 0.15], activeInk: [1, 1, 1] } },\n { name: \"Bold\", values: { weight: 3, button: [0.98, 0.8, 0.1], active: [0.95, 0.3, 0.2], ink: [0.1, 0.1, 0.1], activeInk: [1, 1, 1] } },\n ],\n derived: (v) => {\n const [bars, cross] = menuMorph(Math.round(Number(v.weight) * 4) / 4);\n return { bars, cross };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{weight: float min=1 max=3.5 default=2 step=0.25 label='Line weight'}} {{background: color default=#0F172A label='Background'}} {{button: color default=#1E293B label='Button'}} {{active: color default=#6366F1 label='Button open'}} {{ink: color default=#F8FAFC label='Icon'}} {{activeInk: color default=#FFFFFF label='Icon open'}} --><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><rect id=\"bg\" x=\"16\" y=\"16\" width=\"88\" height=\"88\" rx=\"24\" fill=\"{{button}}\"/><g id=\"icon\" transform=\"${menuPose(0)}\"><path id=\"glyph\" d=\"{{bars}}\" fill=\"{{ink}}\" fill-rule=\"evenodd\"/></g></svg>`,\n animate: [\n // Step 1, open: bars to cross while turning half a turn.\n { id: \"glyph\", step: 1, attrs: { d: [\"{{bars}}\", \"{{cross}}\"], fill: [\"{{ink}}\", \"{{activeInk}}\"] }, ms: 450, ease: \"in-out\" },\n { id: \"icon\", step: 1, attrs: { transform: [menuPose(0), menuPose(180)] }, ms: 450, ease: \"in-out\" },\n { id: \"bg\", step: 1, attrs: { fill: [\"{{button}}\", \"{{active}}\"] }, ms: 300, ease: \"in-out\" },\n // Step 2, close: on round the same way (-180° looks like 180°), ending where it started.\n { id: \"glyph\", step: 2, attrs: { d: [\"{{cross}}\", \"{{bars}}\"], fill: [\"{{activeInk}}\", \"{{ink}}\"] }, ms: 450, ease: \"in-out\" },\n { id: \"icon\", step: 2, attrs: { transform: [menuPose(-180), menuPose(0)] }, ms: 450, ease: \"in-out\" },\n { id: \"bg\", step: 2, attrs: { fill: [\"{{active}}\", \"{{button}}\"] }, ms: 300, ease: \"in-out\" },\n ],\n },\n};\n\n/** A bookmark with rounded top corners and a notched foot. */\nconst BOOKMARK = \"M41 22 H79 Q84 22 84 27 V98 L60 81 L36 98 V27 Q36 22 41 22 Z\";\nconst bounce = (y: number) => `translate(0 ${y})`;\n\nexport const bookmark: VectorEffect = {\n kind: \"vector\",\n id: \"bookmark\",\n name: \"Bookmark\",\n description: \"A bookmark that hops and fills from top to bottom when saved, then drains and dips when unsaved.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"bookmark\", \"save\", \"toggle\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Gold\", values: { fill: [0.98, 0.72, 0.1] } },\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], outline: [0.6, 0.63, 0.7], fill: [0.4, 0.8, 1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{background: color default=#FFFFFF label='Background'}} {{outline: color default=#6B7280 label='Outline'}} {{fill: color default=#6366F1 label='Saved'}} --><defs><clipPath id=\"fillClip\"><rect id=\"level\" x=\"30\" y=\"18\" width=\"60\" height=\"0\"/></clipPath></defs><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><g id=\"mark\" transform=\"${bounce(0)}\"><path d=\"${BOOKMARK}\" fill=\"{{fill}}\" clip-path=\"url(#fillClip)\"/><path id=\"edge\" d=\"${BOOKMARK}\" fill=\"none\" stroke=\"{{outline}}\" stroke-width=\"4\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n // Step 1, save: a hop, a drop past rest and a settle, filling top down.\n { id: \"mark\", step: 1, attrs: { transform: [bounce(0), bounce(-7)] }, ms: 130, ease: \"out\" },\n { id: \"mark\", step: 1, attrs: { transform: [bounce(-7), bounce(4)] }, delay: 130, ms: 170, ease: \"in-out\" },\n { id: \"mark\", step: 1, attrs: { transform: [bounce(4), bounce(0)] }, delay: 300, ms: 200, ease: \"in-out\" },\n { id: \"level\", step: 1, attrs: { height: [0, 84] }, delay: 60, ms: 380, ease: \"in-out\" },\n { id: \"edge\", step: 1, attrs: { stroke: [\"{{outline}}\", \"{{fill}}\"] }, ms: 200 },\n // Step 2, unsave: drains top down (then the empty clip snaps back up) with a small dip.\n { id: \"level\", step: 2, attrs: { y: [18, 102], height: [84, 0] }, ms: 320, ease: \"in-out\" },\n snap(\"level\", \"y\", 18, 320, 2),\n { id: \"mark\", step: 2, attrs: { transform: [bounce(0), bounce(3)] }, ms: 120, ease: \"out\" },\n { id: \"mark\", step: 2, attrs: { transform: [bounce(3), bounce(0)] }, delay: 120, ms: 180, ease: \"in-out\" },\n { id: \"edge\", step: 2, attrs: { stroke: [\"{{fill}}\", \"{{outline}}\"] }, delay: 100, ms: 200 },\n ],\n },\n};\n\n/**\n * A pill button's two labels, swapped on a click: the first slides up and\n * out as the second slides up and in, `back` ms later the reverse (the\n * second then drops back below, hidden, ready for the next click).\n */\nconst swapLabels = (outAt: number, back: number): SvgAnimation[] => [\n { id: \"label\", step: 1, attrs: { opacity: [1, 0], transform: [\"translate(0 0)\", \"translate(0 -10)\"] }, delay: outAt, ms: 180, ease: \"out\" },\n { id: \"done\", step: 1, attrs: { opacity: [0, 1], transform: [\"translate(0 10)\", \"translate(0 0)\"] }, delay: outAt + 120, ms: 220, ease: \"out\" },\n { id: \"done\", step: 1, attrs: { opacity: [1, 0], transform: [\"translate(0 0)\", \"translate(0 -10)\"] }, delay: back, ms: 180, ease: \"out\" },\n { id: \"label\", step: 1, attrs: { opacity: [0, 1], transform: [\"translate(0 10)\", \"translate(0 0)\"] }, delay: back + 120, ms: 220, ease: \"out\" },\n snap(\"done\", \"transform\", \"translate(0 10)\", back + 200),\n];\n\n/** A check drawn on at `at` and hidden at `back`, then undrawn while hidden (so each round draws it afresh). */\nconst checkFlash = (at: number, back: number): SvgAnimation[] => [\n { id: \"check\", step: 1, attrs: { opacity: [0, 1] }, delay: at, ms: 40 },\n { id: \"check\", step: 1, draw: true, delay: at, ms: 280, ease: \"out\" },\n { id: \"check\", step: 1, attrs: { opacity: [1, 0] }, delay: back, ms: 160 },\n { id: \"check\", step: 1, draw: [0, 0], delay: back + 200, ms: 0 },\n];\n\n/** Two labels sharing a pill button's room left of an icon: one font size that fits both. */\nconst buttonLabels = (a: unknown, b: unknown, room: number, max: number) => {\n const ems = [a, b].map((t) => Math.max(0.6, textWidthEm(String(t))));\n const size = Math.min(max, room / Math.max(...ems));\n return { size: r1(size), base: r1(50 + size * 0.35), labelLen: r1(ems[0]! * size), doneLen: r1(ems[1]! * size) };\n};\n\nconst labelTexts = (x: number) =>\n `<text id=\"label\" x=\"${x}\" y=\"{{base}}\" textLength=\"{{labelLen}}\" lengthAdjust=\"spacingAndGlyphs\" transform=\"translate(0 0)\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"600\" fill=\"{{ink}}\">{{label}}</text><text id=\"done\" x=\"${x}\" y=\"{{base}}\" textLength=\"{{doneLen}}\" lengthAdjust=\"spacingAndGlyphs\" transform=\"translate(0 10)\" opacity=\"0\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"600\" fill=\"{{ink}}\">{{doneText}}</text>`;\n\n/** When the copy button turns back. */\nconst COPY_BACK = 1600;\nconst copyPose = (s: number) => `translate(54 50) scale(${r2(1.2 * s)}) translate(-12 -12)`;\n\nexport const copyButton: VectorEffect = {\n kind: \"vector\",\n id: \"copy-button\",\n name: \"Copy button\",\n description: \"A copy button whose icon shrinks away for a drawn check and a “Copied!” label, turning back by itself a moment later.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"copy\", \"clipboard\", \"feedback\", \"button\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], button: [0.95, 0.96, 0.97], success: [0.86, 0.97, 0.9], ink: [0.07, 0.09, 0.15] } },\n { name: \"Code\", values: { label: \"Copy code\", doneText: \"Copied to clipboard\", button: [0.2, 0.22, 0.28] } },\n ],\n derived: (v) => buttonLabels(v.label, v.doneText, 126, 19),\n motion: {\n svg: `<svg viewBox=\"0 0 240 100\"><!-- {{label: text default='Copy' label='Label'}} {{doneText: text default='Copied!' label='Copied label'}} {{background: color default=#0F172A label='Background'}} {{button: color default=#1E293B label='Button'}} {{success: color default=#166534 label='Copied'}} {{ink: color default=#F8FAFC label='Text and icon'}} --><rect width=\"240\" height=\"100\" fill=\"{{background}}\"/><rect id=\"btn\" x=\"20\" y=\"24\" width=\"200\" height=\"52\" rx=\"14\" fill=\"{{button}}\"/><g id=\"copy\" transform=\"${copyPose(1)}\" opacity=\"1\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"8.5\" y=\"8.5\" width=\"11.5\" height=\"11.5\" rx=\"2.5\"/><path d=\"M4.5 15.5 V6.5 C4.5 5.4 5.4 4.5 6.5 4.5 H15.5\"/></g><g transform=\"${copyPose(1)}\"><path id=\"check\" d=\"M5 12.5 L10 17.5 L19 7\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g>${labelTexts(80)}</svg>`,\n animate: [\n // One step that returns by itself: each click replays it.\n { id: \"copy\", step: 1, attrs: { transform: [copyPose(1), copyPose(0.3)], opacity: [1, 0] }, ms: 180, ease: \"out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{button}}\", \"{{success}}\"] }, ms: 200 },\n ...checkFlash(150, COPY_BACK),\n ...swapLabels(0, COPY_BACK),\n { id: \"copy\", step: 1, attrs: { transform: [copyPose(0.3), copyPose(1)], opacity: [0, 1] }, delay: COPY_BACK + 80, ms: 260, ease: \"out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{success}}\", \"{{button}}\"] }, delay: COPY_BACK, ms: 300 },\n ],\n },\n};\n\n/** When the send button resets. */\nconst SEND_BACK = 1800;\nconst planeScale = (s: number) => `scale(${r2(s)}) translate(-12 -12)`;\n\nexport const sendButton: VectorEffect = {\n kind: \"vector\",\n id: \"send-button\",\n name: \"Send button\",\n description: \"A send button whose paper plane winds up and flies off up and to the right as the label turns to “Sent” with a check, then it resets.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"send\", \"submit\", \"message\", \"button\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Sky\", values: { button: [0.05, 0.6, 0.9], success: [0.05, 0.45, 0.7] } },\n { name: \"Mail\", values: { label: \"Send email\", doneText: \"Delivered\", button: [0.9, 0.3, 0.25], success: [0.13, 0.6, 0.35] } },\n ],\n derived: (v) => buttonLabels(v.label, v.doneText, 120, 20),\n motion: {\n svg: `<svg viewBox=\"0 0 240 100\"><!-- {{label: text default='Send' label='Label'}} {{doneText: text default='Sent' label='Sent label'}} {{background: color default=#FFFFFF label='Background'}} {{button: color default=#4F46E5 label='Button'}} {{success: color default=#16A34A label='Sent'}} {{ink: color default=#FFFFFF label='Text and icon'}} --><rect width=\"240\" height=\"100\" fill=\"{{background}}\"/><rect id=\"btn\" x=\"20\" y=\"24\" width=\"200\" height=\"52\" rx=\"26\" fill=\"{{button}}\"/><path id=\"flight\" d=\"M56 50 C88 46 150 22 262 -36\" fill=\"none\"/><g transform=\"translate(56 50) scale(1.1) translate(-12 -12)\"><path id=\"check\" d=\"M5 12.5 L10 17.5 L19 7\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g>${labelTexts(82)}<g id=\"plane\" transform=\"translate(56 50)\"><g id=\"planeIcon\" transform=\"${planeScale(1.05)}\" opacity=\"1\"><path d=\"M22 2 L15 22 L11 13 L2 9 Z\" fill=\"{{ink}}\" stroke=\"{{ink}}\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/><path d=\"M22 2 L11 13\" stroke=\"{{button}}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></g></g></svg>`,\n animate: [\n // Wind up, then fly off along the curve, shrinking and fading.\n { id: \"planeIcon\", step: 1, attrs: { transform: [planeScale(1.05), planeScale(0.88)] }, ms: 120, ease: \"out\" },\n { id: \"plane\", step: 1, along: \"flight\", delay: 120, ms: 600, ease: \"in-out\" },\n { id: \"planeIcon\", step: 1, attrs: { transform: [planeScale(0.88), planeScale(0.5)] }, delay: 120, ms: 600, ease: \"in-out\" },\n { id: \"planeIcon\", step: 1, attrs: { opacity: [1, 0] }, delay: 520, ms: 200 },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{button}}\", \"{{success}}\"] }, delay: 450, ms: 250 },\n ...swapLabels(150, SEND_BACK),\n ...checkFlash(500, SEND_BACK),\n // Back home: the plane pops in where it started.\n { id: \"plane\", step: 1, along: \"flight\", at: [0, 0], delay: SEND_BACK, ms: 0 },\n { id: \"planeIcon\", step: 1, attrs: { transform: [planeScale(0), planeScale(1.05)], opacity: [0, 1] }, delay: SEND_BACK + 100, ms: 300, ease: \"out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{success}}\", \"{{button}}\"] }, delay: SEND_BACK, ms: 300 },\n ],\n },\n};\n\n/** The download arrow over its tray, and the progress ring they become, in a 24 box. */\nconst [ARROW, RING] = morphPaths(\n \"M10.6 4 H13.4 V11.6 H17.2 L12 17 L6.8 11.6 H10.6 Z M5 18.6 H19 V20.6 H5 Z\",\n (() => {\n const circle = (r: number) =>\n `M${Array.from({ length: 48 }, (_, k) => {\n const a = (k / 48) * Math.PI * 2 - Math.PI / 2;\n return `${r2(12 + r * Math.cos(a))} ${r2(12 + r * Math.sin(a))}`;\n }).join(\" L\")} Z`;\n return `${circle(9.6)} ${circle(8)}`;\n })(),\n { points: 56 },\n);\n/** The ring's middle radius and width in the picture (the icon is scaled 2.2 about the centre). */\nconst RING_R = r2(8.8 * 2.2);\nconst DOWNLOAD_BACK = 2300;\nconst iconAt = (y: number) => `translate(60 ${y}) scale(2.2) translate(-12 -12)`;\n\nexport const downloadButton: VectorEffect = {\n kind: \"vector\",\n id: \"download-button\",\n name: \"Download button\",\n description: \"A round download button whose arrow drops and morphs into a progress ring that fills, ends on a check, then resets.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"download\", \"progress\", \"morph\", \"button\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], button: [0.93, 0.95, 1], ink: [0.31, 0.27, 0.9], track: [0.78, 0.8, 0.95], progress: [0.31, 0.27, 0.9], success: [0.86, 0.97, 0.9] } },\n { name: \"Ocean\", values: { button: [0.03, 0.4, 0.6], progress: [0.4, 0.95, 0.85], success: [0.05, 0.55, 0.5] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{background: color default=#0F172A label='Background'}} {{button: color default=#4F46E5 label='Button'}} {{success: color default=#16A34A label='Done'}} {{ink: color default=#FFFFFF label='Icon'}} {{track: color default=#818CF8 label='Ring track'}} {{progress: color default=#FFFFFF label='Progress'}} --><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><circle id=\"btn\" cx=\"60\" cy=\"60\" r=\"42\" fill=\"{{button}}\"/><g id=\"icon\" transform=\"${iconAt(60)}\"><path id=\"glyph\" d=\"${ARROW}\" fill=\"{{ink}}\" fill-rule=\"evenodd\"/></g><circle id=\"bar\" cx=\"60\" cy=\"60\" r=\"${RING_R}\" fill=\"none\" stroke=\"{{progress}}\" stroke-width=\"3.6\" transform=\"rotate(-90 60 60)\"/><g transform=\"translate(60 60) scale(1.5) translate(-12 -12)\"><path id=\"check\" d=\"M6 12.5 L10.5 17 L18.5 8\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g></svg>`,\n animate: [\n // The arrow drops, then rises back as it morphs into the ring's track.\n { id: \"icon\", step: 1, attrs: { transform: [iconAt(60), iconAt(67)] }, ms: 180, ease: \"out\" },\n { id: \"icon\", step: 1, attrs: { transform: [iconAt(67), iconAt(60)] }, delay: 180, ms: 260, ease: \"in-out\" },\n { id: \"glyph\", step: 1, attrs: { d: [ARROW, RING], fill: [\"{{ink}}\", \"{{track}}\"] }, delay: 180, ms: 340, ease: \"in-out\" },\n // Progress round the ring (a flat-ended line, so nothing shows at 0), then a check.\n { id: \"bar\", step: 1, draw: true, delay: 520, ms: 900, ease: \"in-out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{button}}\", \"{{success}}\"] }, delay: 1400, ms: 250 },\n { id: \"check\", step: 1, attrs: { opacity: [0, 1] }, delay: 1450, ms: 40 },\n { id: \"check\", step: 1, draw: true, delay: 1450, ms: 300, ease: \"out\" },\n // Reset: check and ring fade, the track morphs back into the arrow.\n { id: \"check\", step: 1, attrs: { opacity: [1, 0] }, delay: DOWNLOAD_BACK, ms: 150 },\n { id: \"bar\", step: 1, attrs: { opacity: [1, 0] }, delay: DOWNLOAD_BACK, ms: 200 },\n { id: \"check\", step: 1, draw: [0, 0], delay: DOWNLOAD_BACK + 200, ms: 0 },\n { id: \"bar\", step: 1, draw: [0, 0], delay: DOWNLOAD_BACK + 200, ms: 0 },\n snap(\"bar\", \"opacity\", 1, DOWNLOAD_BACK + 200),\n { id: \"glyph\", step: 1, attrs: { d: [RING, ARROW], fill: [\"{{track}}\", \"{{ink}}\"] }, delay: DOWNLOAD_BACK + 100, ms: 420, ease: \"in-out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{success}}\", \"{{button}}\"] }, delay: DOWNLOAD_BACK, ms: 300 },\n ],\n },\n};\n\nexport const linkHover: VectorEffect = {\n kind: \"vector\",\n id: \"link-hover\",\n name: \"Link hover\",\n description: \"A text link whose underline grows from left to right on hover, its arrow nudging right as the text changes colour.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"hover\", \"link\", \"underline\", \"navigation\", \"micro-interaction\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], ink: [0.85, 0.87, 0.92], hover: [0.4, 0.85, 1] } },\n { name: \"Editorial\", values: { text: \"Continue reading\", ink: [0.1, 0.1, 0.1], hover: [0.85, 0.2, 0.15] } },\n ],\n // The text and its arrow centred together; the arrow is drawn round (0, 0) and placed.\n derived: (v) => {\n const { size, length } = fit(v.text, 230, 28);\n const total = length + size * 1.05;\n const left = 160 - total / 2;\n const base = 50 + size * 0.35;\n const ax = left + length + size * 0.35;\n const ay = base - size * 0.33;\n const s = size / 28;\n return {\n size,\n length,\n left: r1(left),\n base: r1(base),\n lineY: r1(base + size * 0.2),\n lineH: r1(Math.max(2, size * 0.08)),\n arrowAt: `translate(${r1(ax)} ${r1(ay)}) scale(${r2(s)})`,\n arrowTo: `translate(${r1(ax + size * 0.25)} ${r1(ay)}) scale(${r2(s)})`,\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 100\"><!-- {{text: text default='Read the docs' label='Link text'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#1F2937 label='Text colour'}} {{hover: color default=#4F46E5 label='Hover colour'}} --><rect width=\"320\" height=\"100\" fill=\"{{background}}\"/><text id=\"link\" x=\"{{left}}\" y=\"{{base}}\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"600\" fill=\"{{ink}}\">{{text}}</text><rect id=\"under\" x=\"{{left}}\" y=\"{{lineY}}\" width=\"0\" height=\"{{lineH}}\" rx=\"1\" fill=\"{{hover}}\"/><g id=\"arrow\" transform=\"{{arrowAt}}\"><path id=\"arrowPath\" d=\"M0 0 H18 M11 -7 L18 0 L11 7\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n { id: \"link\", attrs: { fill: [\"{{ink}}\", \"{{hover}}\"] }, ms: 220 },\n { id: \"under\", attrs: { width: [0, n(\"length\")] }, ms: 320, ease: \"out\" },\n { id: \"arrow\", attrs: { transform: [\"{{arrowAt}}\", \"{{arrowTo}}\"] }, ms: 300, ease: \"out\" },\n { id: \"arrowPath\", attrs: { stroke: [\"{{ink}}\", \"{{hover}}\"] }, ms: 220 },\n ],\n },\n};\n\nexport const buttonHoverFill: VectorEffect = {\n kind: \"vector\",\n id: \"button-hover-fill\",\n name: \"Button hover fill\",\n description: \"An outlined pill button that fills with a slanted sweep from the left on hover, its label inverting colour as the fill passes.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"hover\", \"button\", \"fill\", \"cta\", \"micro-interaction\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], surface: [0.06, 0.07, 0.1], accent: [0.98, 0.8, 0.2] } },\n { name: \"Coral\", values: { label: \"Book a demo\", accent: [0.96, 0.35, 0.3] } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 190, 22);\n return { size, length, base: r1(60 + size * 0.35) };\n },\n motion: ((): SvgMotion => {\n // The sweep's right edge leans back, so it is a slanted band starting outside the pill.\n const sweep = (x: number) => `M10 26 H${x} L${x - 24} 94 H10 Z`;\n const label = (fill: string, clip = \"\") =>\n `<text x=\"160\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" letter-spacing=\"0.5\" fill=\"${fill}\"${clip}>{{label}}</text>`;\n return {\n svg: `<svg viewBox=\"0 0 320 120\"><!-- {{label: text default='Get started' label='Label'}} {{background: color default=#FFFFFF label='Background'}} {{surface: color default=#FFFFFF label='Button'}} {{accent: color default=#4F46E5 label='Accent'}} --><defs><clipPath id=\"swept\"><path id=\"cover\" d=\"${sweep(40)}\"/></clipPath></defs><rect width=\"320\" height=\"120\" fill=\"{{background}}\"/><g id=\"btn\" transform=\"translate(0 0)\"><rect x=\"40\" y=\"30\" width=\"240\" height=\"60\" rx=\"30\" fill=\"{{surface}}\" stroke=\"{{accent}}\" stroke-width=\"2.5\"/><rect x=\"40\" y=\"30\" width=\"240\" height=\"60\" rx=\"30\" fill=\"{{accent}}\" stroke=\"{{accent}}\" stroke-width=\"2.5\" clip-path=\"url(#swept)\"/>${label(\"{{accent}}\")}${label(\"{{surface}}\", ` clip-path=\"url(#swept)\"`)}</g></svg>`,\n animate: [\n { id: \"cover\", attrs: { d: [sweep(40), sweep(310)] }, ms: 380, ease: \"in-out\" },\n { id: \"btn\", attrs: { transform: [\"translate(0 0)\", \"translate(0 -2)\"] }, ms: 240, ease: \"out\" },\n ],\n };\n })(),\n};\n\n/** The tooltip's group: grown from its pointer's tip (160, 104), raised by `dy`. */\nconst tipPose = (s: number, dy: number) => `translate(160 ${104 + dy}) scale(${r2(s)}) translate(-160 -104)`;\n\nexport const tooltipPop: VectorEffect = {\n kind: \"vector\",\n id: \"tooltip-pop\",\n name: \"Tooltip pop\",\n description: \"A small help badge that pops a tooltip bubble up above it on hover, rising and fading in with a slight overshoot.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"hover\", \"tooltip\", \"help\", \"popover\", \"micro-interaction\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Light\", values: { background: [0.97, 0.97, 0.98], bubble: [1, 1, 1], tipInk: [0.1, 0.1, 0.15], badge: [0.6, 0.63, 0.7] } },\n { name: \"Warning\", values: { tip: \"This can't be undone\", accent: [0.95, 0.4, 0.15], bubble: [0.95, 0.4, 0.15], tipInk: [1, 1, 1] } },\n ],\n // The bubble is as wide as its text, centred over the badge.\n derived: (v) => {\n const { size, length } = fit(v.tip, 250, 15);\n const w = length + 28;\n return { size, length, bx: r1(160 - w / 2), bw: r1(w), tipY: r1(79 + size * 0.35) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 180\"><!-- {{tip: text default='Saved to your library' label='Tooltip'}} {{background: color default=#0F172A label='Background'}} {{badge: color default=#475569 label='Badge'}} {{accent: color default=#6366F1 label='Badge hovered'}} {{bubble: color default=#F8FAFC label='Bubble'}} {{tipInk: color default=#0F172A label='Tooltip text'}} --><rect width=\"320\" height=\"180\" fill=\"{{background}}\"/><g id=\"tip\" transform=\"${tipPose(0.5, 8)}\" opacity=\"0\"><rect x=\"{{bx}}\" y=\"60\" width=\"{{bw}}\" height=\"38\" rx=\"10\" fill=\"{{bubble}}\"/><path d=\"M151 96 L160 105 L169 96 Z\" fill=\"{{bubble}}\"/><text x=\"160\" y=\"{{tipY}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"500\" fill=\"{{tipInk}}\">{{tip}}</text></g><g id=\"badgeG\" transform=\"${about(160, 134, 1)}\"><circle id=\"badge\" cx=\"160\" cy=\"134\" r=\"18\" fill=\"{{badge}}\"/><text x=\"160\" y=\"141\" text-anchor=\"middle\" font-family=\"${SANS}\" font-size=\"20\" font-weight=\"700\" fill=\"#FFFFFF\">?</text></g></svg>`,\n animate: [\n { id: \"tip\", attrs: { transform: [tipPose(0.5, 8), tipPose(1.07, -3)] }, ms: 190, ease: \"out\" },\n { id: \"tip\", attrs: { transform: [tipPose(1.07, -3), tipPose(1, 0)] }, delay: 190, ms: 150, ease: \"in-out\" },\n { id: \"tip\", attrs: { opacity: [0, 1] }, ms: 150 },\n { id: \"badge\", attrs: { fill: [\"{{badge}}\", \"{{accent}}\"] }, ms: 200 },\n { id: \"badgeG\", attrs: { transform: [about(160, 134, 1), about(160, 134, 1.08)] }, ms: 200, ease: \"out\" },\n ],\n },\n};\n\nexport const pressButton: VectorEffect = {\n kind: \"vector\",\n id: \"press-button\",\n name: \"Press button\",\n description: \"A chunky 3D button whose face pushes down onto its base while held, its shadow tightening, and springs back up on release.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"press\", \"button\", \"3d\", \"tactile\", \"micro-interaction\"],\n trigger: \"press\",\n hold: 800,\n presets: [\n { name: \"Arcade red\", values: { face: [0.94, 0.27, 0.27], background: [0.1, 0.09, 0.12] } },\n { name: \"Mint\", values: { face: [0.3, 0.85, 0.6], ink: [0.05, 0.25, 0.15], label: \"Let's go\" } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 170, 22);\n return { size, length, base: r1(67 + size * 0.35), side: mixHex(v.face, [0, 0, 0], 0.35), pressed: mixHex(v.face, [0, 0, 0], 0.08) };\n },\n // Played backwards on release, the brief lift at the start of the press becomes a spring past rest at the end.\n motion: {\n svg: `<svg viewBox=\"0 0 320 140\"><!-- {{label: text default='Press me' label='Label'}} {{background: color default=#F1F5F9 label='Background'}} {{face: color default=#6366F1 label='Button'}} {{ink: color default=#FFFFFF label='Label colour'}} {{shadow: color default=#0F172A label='Shadow'}} --><rect width=\"320\" height=\"140\" fill=\"{{background}}\"/><ellipse id=\"shadow\" cx=\"160\" cy=\"114\" rx=\"108\" ry=\"9\" fill=\"{{shadow}}\" opacity=\"0.3\"/><rect x=\"60\" y=\"50\" width=\"200\" height=\"58\" rx=\"16\" fill=\"{{side}}\"/><g id=\"faceG\" transform=\"translate(0 0)\"><rect id=\"faceRect\" x=\"60\" y=\"38\" width=\"200\" height=\"58\" rx=\"16\" fill=\"{{face}}\"/><text x=\"160\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"800\" fill=\"{{ink}}\">{{label}}</text></g></svg>`,\n animate: [\n { id: \"faceG\", attrs: { transform: [\"translate(0 0)\", \"translate(0 -1.5)\"] }, ms: 40, ease: \"out\" },\n { id: \"faceG\", attrs: { transform: [\"translate(0 -1.5)\", \"translate(0 9)\"] }, delay: 40, ms: 90, ease: \"out\" },\n { id: \"shadow\", attrs: { rx: [108, 96], ry: [9, 5], opacity: [0.3, 0.18] }, delay: 40, ms: 90, ease: \"out\" },\n { id: \"faceRect\", attrs: { fill: [\"{{face}}\", \"{{pressed}}\"] }, delay: 40, ms: 90 },\n ],\n },\n};\n\n/** UI micro-interactions as vector effects, each played by a hover, press or click (`trigger`). */\nexport const interactionEffects: VectorEffect[] = [\n likeButton,\n toggleSwitch,\n checkbox,\n menuToggle,\n bookmark,\n copyButton,\n sendButton,\n downloadButton,\n linkHover,\n buttonHoverFill,\n tooltipPop,\n pressButton,\n];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst r1 = (v: number) => Math.round(v * 10) / 10;\n\n/** A transform scaling by `s` about (`cx`, `cy`). */\nconst about = (cx: number, cy: number, s: number) => `translate(${cx} ${cy}) scale(${Math.round(s * 1000) / 1000}) translate(${-cx} ${-cy})`;\n\n/** Instant change: the attribute snaps to `value` at `delay` (resets of hidden elements). */\nconst snap = (id: string, attr: string, value: string | number, delay: number, step?: number): SvgAnimation => ({\n id,\n ...(step === undefined ? {} : { step }),\n attrs: { [attr]: [value, value] },\n delay,\n ms: 0,\n});\n\nconst SANS = `system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif`;\n\n/** A lightning bolt in a 120 box, centred on (60, 60). */\nconst BOLT = \"M68 8 L28 66 L56 66 L46 112 L92 48 L64 48 L76 8 Z\";\n\nexport const zapIcon: VectorEffect = {\n kind: \"vector\",\n id: \"zap-icon\",\n name: \"Zap icon\",\n description: \"A lightning bolt icon that draws itself on, flashes with a burst of glow and sparks, then settles.\",\n category: \"electric\",\n tags: [\"electric\", \"icon\", \"lightning\", \"bolt\", \"ui\", \"energy\"],\n hold: 1000,\n presets: [\n { name: \"Electric blue\", values: { bolt: [0.22, 0.74, 0.97], glow: [0.73, 0.9, 0.99] } },\n { name: \"Light\", values: { background: [1, 1, 1], bolt: [0.92, 0.7, 0.03], glow: [0.99, 0.83, 0.3] } },\n ],\n motion: (() => {\n // Sparks flying off the bolt: angle in degrees, from and to radii round the centre.\n const sparks = [-55, 25, 160, 215].map((deg, i) => {\n const a = (deg * Math.PI) / 180;\n const at = (r: number) => [r1(60 + r * Math.cos(a)), r1(60 + r * Math.sin(a))] as const;\n return { id: `s${i}`, from: at(30), mid: at(46), to: at(56) };\n });\n return {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{background: color default=#0B1020 label='Background'}} {{bolt: color default=#FACC15 label='Bolt'}} {{glow: color default=#FDE68A label='Glow'}} --><defs><filter id=\"zapGlow\" x=\"-60%\" y=\"-60%\" width=\"220%\" height=\"220%\"><feGaussianBlur stdDeviation=\"7\"/></filter></defs><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><circle id=\"burst\" cx=\"60\" cy=\"60\" r=\"20\" fill=\"none\" stroke=\"{{glow}}\" stroke-width=\"6\" opacity=\"0\"/><path id=\"halo\" d=\"${BOLT}\" fill=\"{{glow}}\" filter=\"url(#zapGlow)\" opacity=\"0\"/>${sparks\n .map(({ id, from }) => `<line id=\"${id}\" x1=\"${from[0]}\" y1=\"${from[1]}\" x2=\"${from[0]}\" y2=\"${from[1]}\" stroke=\"{{glow}}\" stroke-width=\"3\" stroke-linecap=\"round\" opacity=\"0\"/>`)\n .join(\"\")}<g id=\"zap\" transform=\"${about(60, 60, 1)}\"><path id=\"fill\" d=\"${BOLT}\" fill=\"{{bolt}}\" fill-opacity=\"0\"/><path id=\"outline\" d=\"${BOLT}\" fill=\"none\" stroke=\"{{bolt}}\" stroke-width=\"3.5\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n { id: \"outline\", draw: true, ms: 550, ease: \"in-out\" },\n { id: \"fill\", attrs: { \"fill-opacity\": [0, 1] }, delay: 500, ms: 100 },\n // The flash: a pop, a burst of glow and a ring, then a soft glow stays.\n { id: \"zap\", attrs: { transform: [about(60, 60, 1), about(60, 60, 1.16)] }, delay: 560, ms: 110, ease: \"out\" },\n { id: \"zap\", attrs: { transform: [about(60, 60, 1.16), about(60, 60, 1)] }, delay: 670, ms: 320, ease: \"in-out\" },\n { id: \"halo\", attrs: { opacity: [0, 1] }, delay: 560, ms: 70 },\n { id: \"halo\", attrs: { opacity: [1, 0.35] }, delay: 630, ms: 600, ease: \"out\" },\n snap(\"burst\", \"opacity\", 0, 0),\n { id: \"burst\", attrs: { r: [20, 58], \"stroke-width\": [6, 0], opacity: [0.9, 0] }, delay: 560, ms: 520, ease: \"out\" },\n ...sparks.flatMap(({ id, from, mid, to }, i): SvgAnimation[] => [\n { id, attrs: { opacity: [0, 1] }, delay: 570 + i * 25, ms: 30 },\n { id, attrs: { x2: [from[0], mid[0]], y2: [from[1], mid[1]] }, delay: 570 + i * 25, ms: 150, ease: \"out\" },\n { id, attrs: { x1: [from[0], to[0]], y1: [from[1], to[1]], x2: [mid[0], to[0]], y2: [mid[1], to[1]], opacity: [1, 0] }, delay: 720 + i * 25, ms: 220, ease: \"out\" },\n ]),\n ],\n };\n })(),\n};\n\n/** The power symbol: an arc open at the top round (80, 82), and a bar through the gap. */\nconst POWER_ARC = \"M63.3 62.1 A26 26 0 1 0 96.7 62.1\";\nconst POWER_BAR = \"M80 48 L80 78\";\n\nexport const powerButton: VectorEffect = {\n kind: \"vector\",\n id: \"power-button\",\n name: \"Power button\",\n description: \"A power button that lights up with a glow ring and its on colour when clicked, and dims again on the next click.\",\n category: \"electric\",\n tags: [\"electric\", \"interactive\", \"ui\", \"click\", \"power\", \"toggle\", \"button\", \"icon\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Green\", values: { on: [0.29, 0.87, 0.5] } },\n { name: \"Light\", values: { background: [0.96, 0.97, 0.98], button: [1, 1, 1], off: [0.6, 0.64, 0.7], on: [0.39, 0.4, 0.95] } },\n ],\n motion: (() => {\n const symbol = (id: string, stroke: string) =>\n `<path id=\"${id}Arc\" d=\"${POWER_ARC}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"7\" stroke-linecap=\"round\"/><path id=\"${id}Bar\" d=\"${POWER_BAR}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"7\" stroke-linecap=\"round\"/>`;\n const press = (step: number, depth: number): SvgAnimation[] => [\n { id: \"press\", step, attrs: { transform: [about(80, 80, 1), about(80, 80, depth)] }, ms: 90, ease: \"out\" },\n { id: \"press\", step, attrs: { transform: [about(80, 80, depth), about(80, 80, 1)] }, delay: 90, ms: 260, ease: \"in-out\" },\n ];\n const colours = (step: number, from: string, to: string, delay: number): SvgAnimation[] =>\n [\"symArc\", \"symBar\"].map((id) => ({ id, step, attrs: { stroke: [from, to] }, delay, ms: 220 }));\n return {\n svg: `<svg viewBox=\"0 0 160 160\"><!-- {{background: color default=#0B0F19 label='Background'}} {{button: color default=#1A2030 label='Button'}} {{off: color default=#5B6475 label='Off'}} {{on: color default=#22D3EE label='On'}} --><defs><filter id=\"pbGlow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\"><feGaussianBlur stdDeviation=\"5\"/></filter></defs><rect width=\"160\" height=\"160\" fill=\"{{background}}\"/><circle id=\"halo\" cx=\"80\" cy=\"80\" r=\"52\" fill=\"none\" stroke=\"{{on}}\" stroke-width=\"8\" opacity=\"0\" filter=\"url(#pbGlow)\"/><circle id=\"pulse\" cx=\"80\" cy=\"80\" r=\"50\" fill=\"none\" stroke=\"{{on}}\" stroke-width=\"3\" opacity=\"0\"/><g id=\"press\" transform=\"${about(80, 80, 1)}\"><circle id=\"disc\" cx=\"80\" cy=\"80\" r=\"48\" fill=\"{{button}}\" stroke=\"{{off}}\" stroke-width=\"2.5\"/><g id=\"symGlow\" opacity=\"0\" filter=\"url(#pbGlow)\">${symbol(\"glow\", \"{{on}}\")}</g>${symbol(\"sym\", \"{{off}}\")}</g></svg>`,\n animate: [\n // Step 1, on: a press, the symbol and rim light up, the glow ring comes on and a pulse rings out.\n ...press(1, 0.93),\n ...colours(1, \"{{off}}\", \"{{on}}\", 60),\n { id: \"disc\", step: 1, attrs: { stroke: [\"{{off}}\", \"{{on}}\"] }, delay: 60, ms: 220 },\n { id: \"symGlow\", step: 1, attrs: { opacity: [0, 1] }, delay: 60, ms: 260 },\n { id: \"halo\", step: 1, attrs: { opacity: [0, 0.75] }, delay: 80, ms: 360, ease: \"out\" },\n snap(\"pulse\", \"opacity\", 0, 0, 1),\n { id: \"pulse\", step: 1, attrs: { r: [50, 76], opacity: [0.9, 0] }, delay: 80, ms: 560, ease: \"out\" },\n snap(\"pulse\", \"r\", 50, 700, 1),\n // Step 2, off: a press and everything dims back to the start.\n ...press(2, 0.95),\n ...colours(2, \"{{on}}\", \"{{off}}\", 40),\n { id: \"disc\", step: 2, attrs: { stroke: [\"{{on}}\", \"{{off}}\"] }, delay: 40, ms: 220 },\n { id: \"symGlow\", step: 2, attrs: { opacity: [1, 0] }, delay: 40, ms: 220 },\n { id: \"halo\", step: 2, attrs: { opacity: [0.75, 0] }, delay: 40, ms: 300, ease: \"out\" },\n ],\n };\n })(),\n};\n\n/** Battery cells: five across the inside of the case. */\nconst CELLS = Array.from({ length: 5 }, (_, i) => ({ id: `cell${i}`, x: r1(36 + i * 24.8) }));\n/** The bolt over the battery's middle, scaled by `k` (1 at rest). */\nconst boltPose = (k: number) => `translate(96 58) scale(${Math.round(0.36 * k * 1000) / 1000}) translate(-60 -60)`;\n\nexport const batteryCharge: VectorEffect = {\n kind: \"vector\",\n id: \"battery-charge\",\n name: \"Battery charge\",\n description: \"A battery filling cell by cell as its percentage counts up and the bolt pulses, flashing when it is full.\",\n category: \"electric\",\n tags: [\"electric\", \"battery\", \"charging\", \"loader\", \"progress\", \"ui\", \"icon\"],\n hold: 900,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], shell: [0.2, 0.25, 0.33], ink: [0.06, 0.09, 0.16] } },\n { name: \"Low power\", values: { charge: [0.96, 0.62, 0.04] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 140\"><!-- {{background: color default=#0F172A label='Background'}} {{shell: color default=#CBD5E1 label='Case'}} {{charge: color default=#22C55E label='Charge'}} {{bolt: color default=#FDE047 label='Bolt'}} {{ink: color default=#F8FAFC label='Percent'}} --><rect width=\"200\" height=\"140\" fill=\"{{background}}\"/><rect id=\"case\" x=\"28\" y=\"26\" width=\"136\" height=\"64\" rx=\"12\" fill=\"none\" stroke=\"{{shell}}\" stroke-width=\"5\"/><rect id=\"nub\" x=\"167\" y=\"46\" width=\"9\" height=\"24\" rx=\"3\" fill=\"{{shell}}\"/>${CELLS.map(\n ({ id, x }) => `<rect id=\"${id}\" x=\"${x}\" y=\"34\" width=\"20.8\" height=\"48\" rx=\"4\" fill=\"{{charge}}\" opacity=\"0\"/>`,\n ).join(\"\")}<path id=\"bolt\" d=\"${BOLT}\" transform=\"${boltPose(1)}\" fill=\"{{bolt}}\" stroke=\"{{background}}\" stroke-width=\"10\" stroke-linejoin=\"round\" paint-order=\"stroke\"/><rect id=\"flash\" x=\"28\" y=\"26\" width=\"136\" height=\"64\" rx=\"12\" fill=\"#FFFFFF\" opacity=\"0\"/><text id=\"pct\" x=\"96\" y=\"124\" text-anchor=\"middle\" font-family=\"${SANS}\" font-size=\"22\" font-weight=\"700\" fill=\"{{ink}}\">0%</text></svg>`,\n animate: [\n { id: \"pct\", count: [0, 100], format: \"{n}%\", ms: 2000, ease: \"linear\" },\n // Each cell lights as the count passes its share.\n ...CELLS.map(({ id }, i): SvgAnimation => ({ id, attrs: { opacity: [0, 1] }, delay: (i + 1) * 400 - 80, ms: 120 })),\n // The bolt pulses as it charges.\n ...[0, 500, 1000, 1500].flatMap((t): SvgAnimation[] => [\n { id: \"bolt\", attrs: { transform: [boltPose(1), boltPose(1.2)] }, delay: t, ms: 150, ease: \"out\" },\n { id: \"bolt\", attrs: { transform: [boltPose(1.2), boltPose(1)] }, delay: t + 150, ms: 250, ease: \"in-out\" },\n ]),\n // Full: a flash and the case takes the charge colour.\n { id: \"flash\", attrs: { opacity: [0, 0.7] }, delay: 2050, ms: 70 },\n { id: \"flash\", attrs: { opacity: [0.7, 0] }, delay: 2120, ms: 420, ease: \"out\" },\n { id: \"case\", attrs: { stroke: [\"{{shell}}\", \"{{charge}}\"] }, delay: 2050, ms: 150 },\n { id: \"nub\", attrs: { fill: [\"{{shell}}\", \"{{charge}}\"] }, delay: 2050, ms: 150 },\n { id: \"pct\", attrs: { fill: [\"{{ink}}\", \"{{charge}}\"] }, delay: 2050, ms: 150 },\n { id: \"bolt\", attrs: { transform: [boltPose(1), boltPose(1.3)] }, delay: 2050, ms: 120, ease: \"out\" },\n { id: \"bolt\", attrs: { transform: [boltPose(1.3), boltPose(1)] }, delay: 2170, ms: 300, ease: \"in-out\" },\n ],\n },\n};\n\n/** Electricity as vector effects: zaps, power and charge. */\nexport const electricEffects: VectorEffect[] = [zapIcon, powerButton, batteryCharge];\n","import { morphSequence } from \"../vector/morph.js\";\nimport type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\ntype Point = [number, number];\n\nconst DEG = Math.PI / 180;\nconst r2 = (v: number) => {\n const r = Math.round(v * 100) / 100;\n return Object.is(r, -0) ? 0 : r;\n};\n\nconst polyline = (pts: readonly Point[]) => `M${pts.map((p) => `${r2(p[0])} ${r2(p[1])}`).join(\" L\")} Z`;\n\n/** Points round an ellipse between two angles in degrees (0 is right, 90 down), `wobble(a)` scaling the radius. */\nfunction arc(cx: number, cy: number, rx: number, ry: number, from: number, to: number, wobble: (a: number) => number = () => 1, every = 6): Point[] {\n const steps = Math.max(1, Math.ceil(Math.abs(to - from) / every));\n return Array.from({ length: steps + 1 }, (_, k) => {\n const deg = from + ((to - from) * k) / steps;\n const w = wobble(deg);\n return [cx + rx * w * Math.cos(deg * DEG), cy + ry * w * Math.sin(deg * DEG)];\n });\n}\n\n/** A polygon with its corners rounded off by `r`, as points. */\nfunction rounded(corners: readonly Point[], r: number): Point[] {\n return corners.flatMap((c, i) => {\n const a = corners[(i + corners.length - 1) % corners.length]!;\n const b = corners[(i + 1) % corners.length]!;\n const towards = (p: Point): Point => {\n const l = Math.hypot(p[0] - c[0], p[1] - c[1]);\n return [c[0] + ((p[0] - c[0]) * r) / l, c[1] + ((p[1] - c[1]) * r) / l];\n };\n const [s, e] = [towards(a), towards(b)];\n // A quadratic round the corner, in a few points.\n return [0, 0.25, 0.5, 0.75, 1].map((t): Point => [\n (1 - t) ** 2 * s[0] + 2 * t * (1 - t) * c[0] + t * t * e[0],\n (1 - t) ** 2 * s[1] + 2 * t * (1 - t) * c[1] + t * t * e[1],\n ]);\n });\n}\n\n// ── Ice cube melt ──────────────────────────────────────────────────────\n\n// An ice cube seen from above a corner: its outline, top face and shaded right face.\nconst CUBE: Point[] = [[100, 48], [152, 76], [152, 136], [100, 164], [48, 136], [48, 76]];\nconst lumpy = (a: number) => 1 + 0.035 * Math.sin(a * 5 * DEG) + 0.02 * Math.sin(a * 11 * DEG + 1);\n\nconst ICE_OUTLINE = morphSequence(\n [\n polyline(rounded(CUBE, 7)),\n // Slumped: a soft lump on a spreading foot.\n polyline([...arc(100, 158, 54, 62, 180, 360, lumpy), [154, 162], [130, 166], [100, 167], [70, 166], [46, 162]]),\n // A puddle.\n polyline(arc(100, 163, 84, 14, 0, 360, lumpy).slice(0, -1)),\n ],\n { points: 72 },\n);\n\nconst ICE_TOP = morphSequence(\n [\n polyline(rounded([[100, 48], [152, 76], [100, 104], [48, 76]], 5)),\n polyline(arc(86, 118, 24, 13, 0, 360).slice(0, -1)),\n polyline(arc(80, 159, 36, 3.5, 0, 360).slice(0, -1)),\n ],\n { points: 40 },\n);\n\nconst ICE_SIDE = morphSequence(\n [\n polyline([[100, 104], [152, 76], [152, 136], [100, 164]]),\n polyline([...arc(100, 158, 54, 62, 300, 360, lumpy), ...arc(100, 158, 30, 56, 360, 300)]),\n polyline([...arc(100, 163, 84, 14, -15, 100, lumpy), ...arc(100, 161, 72, 9, 100, -15)]),\n ],\n { points: 40 },\n);\n\nconst MELT = { delay: 400, ms: 1700 };\nconst SPREAD = { delay: 2100, ms: 1500 };\nconst REFORM = { delay: 4600, ms: 1100 };\n\n/** One shape through its three stages and back. */\nconst stages = (id: string, [cube, slump, puddle]: string[]): SvgAnimation[] => [\n { id, attrs: { d: [cube!, slump!] }, ...MELT, ease: \"in-out\" },\n { id, attrs: { d: [slump!, puddle!] }, ...SPREAD, ease: \"out\" },\n { id, attrs: { d: [puddle!, cube!] }, ...REFORM, ease: \"in-out\" },\n];\n\nexport const iceCubeMelt: VectorEffect = {\n kind: \"vector\",\n id: \"ice-cube-melt\",\n name: \"Ice cube melt\",\n description: \"An ice cube softening, slumping and spreading into a glossy puddle with a couple of drips, then freezing back into a cube.\",\n category: \"melt\",\n tags: [\"melt\", \"ice\", \"water\", \"puddle\", \"morph\", \"loop\"],\n hold: 700,\n presets: [\n { name: \"Night\", values: { background: [0.07, 0.09, 0.14], ice: [0.72, 0.88, 1], water: [0.25, 0.55, 0.85], edge: [0.55, 0.78, 0.95] } },\n { name: \"Popsicle\", values: { ice: [1, 0.55, 0.62], water: [0.95, 0.3, 0.42], edge: [0.85, 0.35, 0.45], background: [1, 0.96, 0.92] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{ice: color default=#CFEFFF label='Ice'}} {{water: color default=#7FC8F2 label='Water'}} {{edge: color default=#86C3E6 label='Edge'}} {{highlight: color default=#FFFFFF label='Highlight'}} {{background: color default=#F2F5FA label='Background'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><ellipse id=\"pool\" cx=\"100\" cy=\"164\" rx=\"36\" ry=\"5\" fill=\"{{water}}\" opacity=\"0.35\"/><path id=\"cube\" d=\"${ICE_OUTLINE[0]}\" fill=\"{{ice}}\" fill-rule=\"evenodd\" stroke=\"{{edge}}\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/><path id=\"side\" d=\"${ICE_SIDE[0]}\" fill=\"#0b2a44\" fill-rule=\"evenodd\" opacity=\"0.12\"/><path id=\"top\" d=\"${ICE_TOP[0]}\" fill=\"{{highlight}}\" fill-rule=\"evenodd\" opacity=\"0.55\"/><path id=\"streak\" d=\"M58 92 L58 128\" stroke=\"{{highlight}}\" stroke-width=\"4\" stroke-linecap=\"round\" opacity=\"0.85\"/><circle id=\"glint\" cx=\"118\" cy=\"66\" r=\"3\" fill=\"{{highlight}}\" opacity=\"0.9\"/><circle id=\"drop1\" cx=\"146\" cy=\"128\" r=\"0\" fill=\"{{water}}\" stroke=\"{{edge}}\" stroke-width=\"1\"/><circle id=\"drop2\" cx=\"62\" cy=\"134\" r=\"0\" fill=\"{{water}}\" stroke=\"{{edge}}\" stroke-width=\"1\"/></svg>`,\n animate: [\n ...stages(\"cube\", ICE_OUTLINE),\n ...stages(\"top\", ICE_TOP),\n ...stages(\"side\", ICE_SIDE),\n { id: \"cube\", attrs: { fill: [\"{{ice}}\", \"{{water}}\"] }, delay: 1800, ms: 1800, ease: \"in-out\" },\n { id: \"cube\", attrs: { fill: [\"{{water}}\", \"{{ice}}\"] }, ...REFORM, ease: \"in-out\" },\n { id: \"top\", attrs: { opacity: [0.55, 0.8] }, ...SPREAD, ease: \"in-out\" },\n { id: \"top\", attrs: { opacity: [0.8, 0.55] }, ...REFORM, ease: \"in-out\" },\n { id: \"streak\", attrs: { opacity: [0.85, 0] }, delay: 400, ms: 900, ease: \"in-out\" },\n { id: \"streak\", attrs: { opacity: [0, 0.85] }, delay: 5500, ms: 300, ease: \"in-out\" },\n { id: \"glint\", attrs: { opacity: [0.9, 0], r: [3, 1] }, delay: 300, ms: 700, ease: \"in-out\" },\n { id: \"glint\", attrs: { opacity: [0, 0.9], r: [1, 3] }, delay: 5500, ms: 300, ease: \"in-out\" },\n { id: \"pool\", attrs: { rx: [36, 92], ry: [5, 17], opacity: [0.35, 0.6] }, delay: 600, ms: 3000, ease: \"in-out\" },\n { id: \"pool\", attrs: { rx: [92, 36], ry: [17, 5], opacity: [0.6, 0.35] }, ...REFORM, ease: \"in-out\" },\n { id: \"drop1\", attrs: { cy: [128, 160], r: [0, 4.5] }, delay: 900, ms: 1000, ease: \"in-out\" },\n { id: \"drop1\", attrs: { r: [4.5, 0] }, delay: 1900, ms: 300, ease: \"in-out\" },\n { id: \"drop2\", attrs: { cy: [134, 160], r: [0, 3.5] }, delay: 1400, ms: 900, ease: \"in-out\" },\n { id: \"drop2\", attrs: { r: [3.5, 0] }, delay: 2300, ms: 300, ease: \"in-out\" },\n // Back up the sides, unseen, for the next melt.\n { id: \"drop1\", attrs: { cy: [160, 128] }, ...REFORM },\n { id: \"drop2\", attrs: { cy: [160, 134] }, ...REFORM },\n ],\n },\n};\n\n// ── Candle ─────────────────────────────────────────────────────────────\n\nconst BURN = 6000;\nconst TOP = 92;\nconst BURNT = 150;\nconst FLICKER = 150;\n\n/** The top of the candle at `ms` into the burn. */\nconst topAt = (ms: number) => TOP + ((BURNT - TOP) * Math.min(ms, BURN)) / BURN;\n\n/** A repeatable 0–1 number for a flicker. */\nconst rand = (i: number, k: number) => {\n const x = Math.sin(i * 127.1 + k * 311.7) * 43758.5453;\n return x - Math.floor(x);\n};\n\n/** The flame's transform at a flicker: following the top down, stretching, leaning and swelling at random. */\nconst flame = (i: number, ms: number) => {\n const sx = i < 0 ? 1 : 0.9 + 0.16 * rand(i, 1);\n const sy = i < 0 ? 1 : 0.82 + 0.34 * rand(i, 2);\n const lean = i < 0 ? 0 : (rand(i, 3) - 0.5) * 12;\n return `translate(100 ${r2(topAt(ms) - 12)}) skewX(${r2(lean)}) scale(${r2(sx)} ${r2(sy)})`;\n};\n\nconst FLICKERS = BURN / FLICKER;\n\nconst DRIPS = [\n { x: 66, delay: 700, ms: 2600, length: 70 },\n { x: 123, delay: 1600, ms: 3000, length: 96 },\n { x: 93, delay: 3000, ms: 2400, length: 52 },\n] as const;\n\nconst linear = { delay: 0, ms: BURN, ease: \"linear\" as const };\nconst relight = { delay: BURN, ms: 600, ease: \"in-out\" as const };\n\nexport const candle: VectorEffect = {\n kind: \"vector\",\n id: \"candle\",\n name: \"Candle\",\n description: \"A candle burning down with a flickering flame and halo while wax drips run down its sides, then it is lit anew.\",\n category: \"melt\",\n tags: [\"melt\", \"candle\", \"flame\", \"wax\", \"cosy\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Red taper\", values: { wax: [0.78, 0.15, 0.2], holder: [0.75, 0.62, 0.35] } },\n { name: \"Spirit flame\", values: { flame: [0.35, 0.7, 1], core: [0.88, 0.96, 1], background: [0.04, 0.05, 0.1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 260\"><!-- {{wax: color default=#F1E4CF label='Wax'}} {{flame: color default=#FFA733 label='Flame'}} {{core: color default=#FFF6CF label='Flame core'}} {{holder: color default=#6E5A48 label='Holder'}} {{background: color default=#17131F label='Background'}} --><defs><radialGradient id=\"halo\"><stop offset=\"0\" stop-color=\"{{flame}}\" stop-opacity=\"0.55\"/><stop offset=\"1\" stop-color=\"{{flame}}\" stop-opacity=\"0\"/></radialGradient><linearGradient id=\"waxshade\" x1=\"0\" x2=\"1\"><stop offset=\"0\" stop-color=\"#000\" stop-opacity=\"0.12\"/><stop offset=\"0.35\" stop-color=\"#fff\" stop-opacity=\"0.18\"/><stop offset=\"1\" stop-color=\"#000\" stop-opacity=\"0.3\"/></linearGradient></defs><rect width=\"200\" height=\"260\" fill=\"{{background}}\"/><circle id=\"glow\" cx=\"100\" cy=\"${TOP - 30}\" r=\"80\" fill=\"url(#halo)\" opacity=\"0.9\"/><ellipse cx=\"100\" cy=\"244\" rx=\"58\" ry=\"10\" fill=\"{{holder}}\"/><rect id=\"body\" x=\"70\" y=\"${TOP}\" width=\"60\" height=\"${244 - TOP}\" fill=\"{{wax}}\"/><rect id=\"shade\" x=\"70\" y=\"${TOP}\" width=\"60\" height=\"${244 - TOP}\" fill=\"url(#waxshade)\"/>${DRIPS.map(\n (d, i) => `<rect id=\"drip${i}\" x=\"${d.x}\" y=\"${TOP}\" width=\"11\" height=\"0\" rx=\"5.5\" fill=\"{{wax}}\" stroke=\"#000\" stroke-opacity=\"0.12\"/>`,\n ).join(\"\")}<ellipse id=\"rim\" cx=\"100\" cy=\"${TOP}\" rx=\"30\" ry=\"7\" fill=\"{{wax}}\" stroke=\"#000\" stroke-opacity=\"0.1\"/><ellipse id=\"pool\" cx=\"100\" cy=\"${TOP}\" rx=\"21\" ry=\"4\" fill=\"{{core}}\" opacity=\"0.35\"/><line id=\"wick\" x1=\"100\" y1=\"${TOP}\" x2=\"100\" y2=\"${TOP - 13}\" stroke=\"#2a211c\" stroke-width=\"2.5\" stroke-linecap=\"round\"/><g id=\"flame\" transform=\"${flame(-1, 0)}\"><path d=\"M0 0 C-13 -6 -12 -27 0 -50 C12 -27 13 -6 0 0 Z\" fill=\"{{flame}}\"/><path d=\"M0 -2 C-6 -5 -6 -15 0 -27 C6 -15 6 -5 0 -2 Z\" fill=\"{{core}}\"/></g></svg>`,\n animate: [\n // Burning down, then lit anew.\n { id: \"body\", attrs: { y: [TOP, BURNT], height: [244 - TOP, 244 - BURNT] }, ...linear },\n { id: \"body\", attrs: { y: [BURNT, TOP], height: [244 - BURNT, 244 - TOP] }, ...relight },\n { id: \"shade\", attrs: { y: [TOP, BURNT], height: [244 - TOP, 244 - BURNT] }, ...linear },\n { id: \"shade\", attrs: { y: [BURNT, TOP], height: [244 - BURNT, 244 - TOP] }, ...relight },\n ...([\"rim\", \"pool\"] as const).flatMap((id): SvgAnimation[] => [\n { id, attrs: { cy: [TOP, BURNT] }, ...linear },\n { id, attrs: { cy: [BURNT, TOP] }, ...relight },\n ]),\n { id: \"wick\", attrs: { y1: [TOP, BURNT], y2: [TOP - 13, BURNT - 13] }, ...linear },\n { id: \"wick\", attrs: { y1: [BURNT, TOP], y2: [BURNT - 13, TOP - 13] }, ...relight },\n { id: \"glow\", attrs: { cy: [TOP - 30, BURNT - 30] }, ...linear },\n { id: \"glow\", attrs: { cy: [BURNT - 30, TOP - 30] }, ...relight },\n // Wax runs down the sides, its drips riding down with the top as it burns.\n ...DRIPS.flatMap((d, i): SvgAnimation[] => [\n { id: `drip${i}`, attrs: { y: [TOP, BURNT] }, ...linear },\n { id: `drip${i}`, attrs: { height: [0, d.length] }, delay: d.delay, ms: d.ms, ease: \"out\" },\n { id: `drip${i}`, attrs: { y: [BURNT, TOP], height: [d.length, 0] }, ...relight },\n ]),\n // The flame flickers as it follows the top down, goes out, and is lit again.\n ...Array.from({ length: FLICKERS }, (_, i): SvgAnimation => ({\n id: \"flame\",\n attrs: { transform: [flame(i - 1, i * FLICKER), flame(i, (i + 1) * FLICKER)] },\n delay: i * FLICKER,\n ms: FLICKER,\n ease: \"in-out\",\n })),\n { id: \"flame\", attrs: { transform: [flame(FLICKERS - 1, BURN), flame(-1, 0)], opacity: [1, 0] }, delay: BURN, ms: 250, ease: \"in-out\" },\n { id: \"flame\", attrs: { opacity: [0, 1] }, delay: BURN + 500, ms: 300, ease: \"out\" },\n ...Array.from({ length: BURN / 300 }, (_, i): SvgAnimation => ({\n id: \"glow\",\n attrs: { opacity: [i ? r2(0.7 + 0.3 * rand(i - 1, 7)) : 0.9, r2(0.7 + 0.3 * rand(i, 7))] },\n delay: i * 300,\n ms: 300,\n ease: \"in-out\",\n })),\n { id: \"glow\", attrs: { opacity: [r2(0.7 + 0.3 * rand(BURN / 300 - 1, 7)), 0] }, delay: BURN, ms: 250, ease: \"in-out\" },\n { id: \"glow\", attrs: { opacity: [0, 0.9] }, delay: BURN + 500, ms: 300, ease: \"out\" },\n ],\n },\n};\n\n/** Melting: drips, heat haze, wax and liquefying shapes, as vector effects. */\nexport const meltEffects: VectorEffect[] = [iceCubeMelt, candle];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * Pixel looks stay crisp: every effect works on a virtual low-resolution grid\n * (`floor(fragCoord / uPixel)`), samples images at the centre of each virtual\n * pixel and quantises colours to a few levels, so no edge is ever blended.\n */\n\n/**\n * A 5 × 7 pixel font: each glyph seven rows of five, `#` inked, top row first.\n * Shared by the shaders (packed into ints, see {@link packGlyph}) and the\n * vector pixel effects (drawn as paths).\n */\nexport const PIXEL_FONT: Readonly<Record<string, readonly string[]>> = {\n \" \": [\".....\", \".....\", \".....\", \".....\", \".....\", \".....\", \".....\"],\n A: [\".###.\", \"#...#\", \"#...#\", \"#####\", \"#...#\", \"#...#\", \"#...#\"],\n B: [\"####.\", \"#...#\", \"#...#\", \"####.\", \"#...#\", \"#...#\", \"####.\"],\n C: [\".###.\", \"#...#\", \"#....\", \"#....\", \"#....\", \"#...#\", \".###.\"],\n D: [\"####.\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"####.\"],\n E: [\"#####\", \"#....\", \"#....\", \"####.\", \"#....\", \"#....\", \"#####\"],\n F: [\"#####\", \"#....\", \"#....\", \"####.\", \"#....\", \"#....\", \"#....\"],\n G: [\".###.\", \"#...#\", \"#....\", \"#.###\", \"#...#\", \"#...#\", \".####\"],\n H: [\"#...#\", \"#...#\", \"#...#\", \"#####\", \"#...#\", \"#...#\", \"#...#\"],\n I: [\".###.\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \".###.\"],\n J: [\"..###\", \"...#.\", \"...#.\", \"...#.\", \"...#.\", \"#..#.\", \".##..\"],\n K: [\"#...#\", \"#..#.\", \"#.#..\", \"##...\", \"#.#..\", \"#..#.\", \"#...#\"],\n L: [\"#....\", \"#....\", \"#....\", \"#....\", \"#....\", \"#....\", \"#####\"],\n M: [\"#...#\", \"##.##\", \"#.#.#\", \"#.#.#\", \"#...#\", \"#...#\", \"#...#\"],\n N: [\"#...#\", \"#...#\", \"##..#\", \"#.#.#\", \"#..##\", \"#...#\", \"#...#\"],\n O: [\".###.\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \".###.\"],\n P: [\"####.\", \"#...#\", \"#...#\", \"####.\", \"#....\", \"#....\", \"#....\"],\n Q: [\".###.\", \"#...#\", \"#...#\", \"#...#\", \"#.#.#\", \"#..#.\", \".##.#\"],\n R: [\"####.\", \"#...#\", \"#...#\", \"####.\", \"#.#..\", \"#..#.\", \"#...#\"],\n S: [\".####\", \"#....\", \"#....\", \".###.\", \"....#\", \"....#\", \"####.\"],\n T: [\"#####\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\"],\n U: [\"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \".###.\"],\n V: [\"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \".#.#.\", \"..#..\"],\n W: [\"#...#\", \"#...#\", \"#...#\", \"#.#.#\", \"#.#.#\", \"#.#.#\", \".#.#.\"],\n X: [\"#...#\", \"#...#\", \".#.#.\", \"..#..\", \".#.#.\", \"#...#\", \"#...#\"],\n Y: [\"#...#\", \"#...#\", \".#.#.\", \"..#..\", \"..#..\", \"..#..\", \"..#..\"],\n Z: [\"#####\", \"....#\", \"...#.\", \"..#..\", \".#...\", \"#....\", \"#####\"],\n \"0\": [\".###.\", \"#...#\", \"#..##\", \"#.#.#\", \"##..#\", \"#...#\", \".###.\"],\n \"1\": [\"..#..\", \".##..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \".###.\"],\n \"2\": [\".###.\", \"#...#\", \"....#\", \"...#.\", \"..#..\", \".#...\", \"#####\"],\n \"3\": [\"#####\", \"...#.\", \"..#..\", \"...#.\", \"....#\", \"#...#\", \".###.\"],\n \"4\": [\"...#.\", \"..##.\", \".#.#.\", \"#..#.\", \"#####\", \"...#.\", \"...#.\"],\n \"5\": [\"#####\", \"#....\", \"####.\", \"....#\", \"....#\", \"#...#\", \".###.\"],\n \"6\": [\"..##.\", \".#...\", \"#....\", \"####.\", \"#...#\", \"#...#\", \".###.\"],\n \"7\": [\"#####\", \"....#\", \"...#.\", \"..#..\", \".#...\", \".#...\", \".#...\"],\n \"8\": [\".###.\", \"#...#\", \"#...#\", \".###.\", \"#...#\", \"#...#\", \".###.\"],\n \"9\": [\".###.\", \"#...#\", \"#...#\", \".####\", \"....#\", \"...#.\", \".##..\"],\n \".\": [\".....\", \".....\", \".....\", \".....\", \".....\", \".##..\", \".##..\"],\n \",\": [\".....\", \".....\", \".....\", \".....\", \".##..\", \"..#..\", \".#...\"],\n \"!\": [\"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \".....\", \"..#..\"],\n \"?\": [\".###.\", \"#...#\", \"....#\", \"...#.\", \"..#..\", \".....\", \"..#..\"],\n \"-\": [\".....\", \".....\", \".....\", \"#####\", \".....\", \".....\", \".....\"],\n \"+\": [\".....\", \"..#..\", \"..#..\", \"#####\", \"..#..\", \"..#..\", \".....\"],\n \":\": [\".....\", \".##..\", \".##..\", \".....\", \".##..\", \".##..\", \".....\"],\n \";\": [\".....\", \".##..\", \".##..\", \".....\", \".##..\", \"..#..\", \".#...\"],\n \"'\": [\"..#..\", \"..#..\", \".#...\", \".....\", \".....\", \".....\", \".....\"],\n '\"': [\".#.#.\", \".#.#.\", \".....\", \".....\", \".....\", \".....\", \".....\"],\n \"/\": [\".....\", \"....#\", \"...#.\", \"..#..\", \".#...\", \"#....\", \".....\"],\n \"(\": [\"...#.\", \"..#..\", \".#...\", \".#...\", \".#...\", \"..#..\", \"...#.\"],\n \")\": [\".#...\", \"..#..\", \"...#.\", \"...#.\", \"...#.\", \"..#..\", \".#...\"],\n \"[\": [\".###.\", \".#...\", \".#...\", \".#...\", \".#...\", \".#...\", \".###.\"],\n \"]\": [\".###.\", \"...#.\", \"...#.\", \"...#.\", \"...#.\", \"...#.\", \".###.\"],\n \"#\": [\".#.#.\", \".#.#.\", \"#####\", \".#.#.\", \"#####\", \".#.#.\", \".#.#.\"],\n \"&\": [\".##..\", \"#..#.\", \"#.#..\", \".#...\", \"#.#.#\", \"#..#.\", \".##.#\"],\n \"*\": [\".....\", \"..#..\", \"#.#.#\", \".###.\", \"#.#.#\", \"..#..\", \".....\"],\n \"=\": [\".....\", \".....\", \"#####\", \".....\", \"#####\", \".....\", \".....\"],\n _: [\".....\", \".....\", \".....\", \".....\", \".....\", \".....\", \"#####\"],\n \"<\": [\"...#.\", \"..#..\", \".#...\", \"#....\", \".#...\", \"..#..\", \"...#.\"],\n \">\": [\".#...\", \"..#..\", \"...#.\", \"....#\", \"...#.\", \"..#..\", \".#...\"],\n \"%\": [\"##...\", \"##..#\", \"...#.\", \"..#..\", \".#...\", \"#..##\", \"...##\"],\n $: [\"..#..\", \".####\", \"#.#..\", \".###.\", \"..#.#\", \"####.\", \"..#..\"],\n \"@\": [\".###.\", \"#...#\", \"#.###\", \"#.#.#\", \"#.###\", \"#....\", \".####\"],\n};\n\n/** A glyph of {@link PIXEL_FONT}, upper-casing letters; unknown characters are `?`. */\nexport function pixelGlyph(char: string): readonly string[] {\n return PIXEL_FONT[char] ?? PIXEL_FONT[char.toUpperCase()] ?? PIXEL_FONT[\"?\"]!;\n}\n\n/** A glyph as GLSL `ivec2`: bit (x + 5y) of .x holds rows 0–3 (top first), of .y rows 4–6 (as image-ascii). */\nfunction packGlyph(rows: readonly string[]): string {\n let a = 0;\n let b = 0;\n rows.forEach((row, y) =>\n [...row].forEach((c, x) => {\n if (c !== \"#\") return;\n if (y < 4) a |= 1 << (x + 5 * y);\n else b |= 1 << (x + 5 * (y - 4));\n }),\n );\n return `ivec2(${a}, ${b})`;\n}\n\n/** `#rrggbb` as a GLSL `vec3`. */\nconst vec3Hex = (hex: string) => {\n const n = parseInt(hex.slice(1), 16);\n const c = [n >> 16, (n >> 8) & 255, n & 255].map((v) => +(v / 255).toFixed(3));\n return `vec3(${c.map((v) => (Number.isInteger(v) ? `${v}.0` : String(v))).join(\", \")})`;\n};\n\n/** A GLSL `const vec3 NAME[n]` palette. */\nconst paletteArray = (name: string, hexes: readonly string[]) =>\n `const vec3 ${name}[${hexes.length}] = vec3[${hexes.length}](\\n ${hexes.map(vec3Hex).join(\",\\n \")}\\n);`;\n\nconst GAMEBOY = [\"#0F380F\", \"#306230\", \"#8BAC0F\", \"#9BBC0F\"];\nconst PICO8 = [\"#000000\", \"#1D2B53\", \"#7E2553\", \"#008751\", \"#AB5236\", \"#5F574F\", \"#C2C3C7\", \"#FFF1E8\", \"#FF004D\", \"#FFA300\", \"#FFEC27\", \"#00E436\", \"#29ADFF\", \"#83769C\", \"#FF77A8\", \"#FFCCAA\"];\nconst NES = [\"#000000\", \"#FCFCFC\", \"#BCBCBC\", \"#7C7C7C\", \"#A81000\", \"#F83800\", \"#FCA044\", \"#F8D878\", \"#005800\", \"#00B800\", \"#B8F818\", \"#0058F8\", \"#3CBCFC\", \"#6844FC\", \"#D800CC\", \"#503000\"];\nconst CGA = [\"#000000\", \"#55FFFF\", \"#FF55FF\", \"#FFFFFF\"];\nconst C64 = [\"#000000\", \"#FFFFFF\", \"#880000\", \"#AAFFEE\", \"#CC44CC\", \"#00CC55\", \"#0000AA\", \"#EEEE77\", \"#DD8855\", \"#664400\", \"#FF7777\", \"#333333\", \"#777777\", \"#AAFF66\", \"#0088FF\", \"#BBBBBB\"];\n\n/** Ordered dithering thresholds, 0–1: `bayer4(cell)` (16 levels) and `bayer8(cell)` (64). */\nconst BAYER = `\nfloat bayer2(vec2 a) {\n a = floor(a);\n return fract(a.x / 2.0 + a.y * a.y * 0.75);\n}\nfloat bayer4(vec2 a) {\n return bayer2(0.5 * a) * 0.25 + bayer2(a);\n}\nfloat bayer8(vec2 a) {\n return bayer4(0.5 * a) * 0.25 + bayer2(a);\n}`.trim();\n\n/** 1D value noise along x, 0–1, for skylines (needs HASH). */\nconst NOISE1 = `\nfloat noise1(float x, float seed) {\n float i = floor(x);\n float f = fract(x);\n f = f * f * (3.0 - 2.0 * f);\n return mix(hash12(vec2(i, seed)), hash12(vec2(i + 1.0, seed)), f);\n}`.trim();\n\nexport const image8bit: ShaderEffect = {\n kind: \"shader\",\n id: \"image-8bit\",\n name: \"8-bit\",\n description: \"An image on a chunky pixel grid, reduced to a classic console or computer palette with ordered Bayer dithering.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"image\", \"8-bit\", \"dither\", \"palette\", \"game boy\", \"pico-8\"],\n source: glsl(\n `// 8-bit: an image on a chunky pixel grid in a classic palette, Bayer-dithered.\nuniform sampler2D uImage; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uPalette; // @control min=0 max=5 default=0 label=\"Palette (0 Game Boy, 1 PICO-8, 2 NES, 3 CGA, 4 C64, 5 1-bit)\"\nuniform float uPixel; // @control min=1 max=16 default=4 step=1 label=\"Pixel size\"\nuniform float uDither; // @control min=0 max=1 default=0.7 label=\"Dither\"\nuniform bool uBayer8; // @control default=true label=\"8 × 8 Bayer matrix\"\nuniform float uContrast; // @control min=0.5 max=2 default=1.1 label=\"Contrast\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n BAYER,\n paletteArray(\"GAMEBOY\", GAMEBOY),\n paletteArray(\"PICO8\", PICO8),\n paletteArray(\"NES\", NES),\n paletteArray(\"CGA\", CGA),\n paletteArray(\"C64\", C64),\n `// The palette colour closest to c (weighted for the eye).\nvec3 nearest(vec3 c, int pal) {\n vec3 best = vec3(0.0);\n float bestDist = 1e9;\n for (int i = 0; i < 16; i++) {\n vec3 p;\n if (pal == 1) p = PICO8[i];\n else if (pal == 2) p = NES[i];\n else if (pal == 4) p = C64[i];\n else {\n if (i >= 4) break;\n p = CGA[i];\n }\n vec3 d = c - p;\n float dist = dot(d * d, vec3(0.3, 0.59, 0.11));\n if (dist < bestDist) {\n bestDist = dist;\n best = p;\n }\n }\n return best;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec4 pic = pictureRGBA(uImage, (cell + 0.5) * uPixel / iResolution.xy);\n vec3 src = clamp((pic.rgb - 0.5) * uContrast + 0.5, 0.0, 1.0);\n float threshold = (uBayer8 ? bayer8(cell) + 0.5 / 64.0 : bayer4(cell) + 0.5 / 16.0) - 0.5;\n vec3 col;\n if (uPalette == 0 || uPalette == 5) {\n // Shades of one ramp: dither the brightness between its levels.\n float levels = uPalette == 0 ? 3.0 : 1.0;\n float l = dot(src, vec3(0.2126, 0.7152, 0.0722));\n int i = int(clamp(floor(l * levels + 0.5 + threshold * uDither), 0.0, levels));\n col = uPalette == 0 ? GAMEBOY[i] : vec3(float(i));\n } else {\n float spread = uPalette == 3 ? 0.55 : 0.22;\n col = nearest(src + threshold * uDither * spread, uPalette);\n }\n // Pixels are whole, so alpha is cut at a half rather than blended.\n fragColor = vec4(col, step(0.5, pic.a));\n}`,\n ),\n presets: [\n { name: \"Game Boy\", values: { uPalette: 0, uPixel: 4 } },\n { name: \"PICO-8\", values: { uPalette: 1, uPixel: 4 } },\n { name: \"NES\", values: { uPalette: 2, uPixel: 3 } },\n { name: \"CGA\", values: { uPalette: 3, uPixel: 3, uDither: 0.9 } },\n { name: \"C64\", values: { uPalette: 4, uPixel: 5, uBayer8: false } },\n { name: \"1-bit\", values: { uPalette: 5, uPixel: 2, uDither: 1 } },\n ],\n};\n\nexport const gameboyScreen: ShaderEffect = {\n kind: \"shader\",\n id: \"gameboy-screen\",\n name: \"Game Boy screen\",\n description: \"An image on a handheld's green dot-matrix LCD: four shades, a visible pixel grid and smeary ghosting, inset in an olive bezel.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"image\", \"game boy\", \"lcd\", \"handheld\", \"screen\"],\n source: glsl(\n `// Game Boy screen: an image on a 4-shade green LCD with a pixel grid, ghosting and a bezel.\nuniform sampler2D uImage; // @control filter=linear wrap=repeat default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uLines; // @control min=36 max=144 default=144 step=1 label=\"Screen lines\"\nuniform float uPan; // @control min=-0.3 max=0.3 default=0.04 label=\"Pan speed\"\nuniform float uGhost; // @control min=0 max=1 default=0.5 label=\"Ghosting\"\nuniform float uGrid; // @control min=0 max=1 default=0.6 label=\"Pixel grid\"\nuniform bool uDither; // @control default=true label=\"Dither\"\nuniform vec3 uDark; // @control color default=#0F380F label=\"Darkest shade\"\nuniform vec3 uLight; // @control color default=#9BBC0F label=\"Lightest shade\"\nuniform vec3 uBezel; // @control color default=#4E5236 label=\"Bezel\"\nuniform vec3 uCase; // @control color default=#C9C6BC label=\"Case\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n BAYER,\n `// The LCD shade (0 darkest – 3 lightest) of the picture at uv, for screen pixel cell.\nfloat shade(vec2 uv, vec2 cell) {\n float l = dot(picture(uImage, uv), vec3(0.2126, 0.7152, 0.0722));\n float d = uDither ? (bayer4(cell) - 0.47) * 0.7 : 0.0;\n return clamp(floor(l * 3.0 + 0.5 + d), 0.0, 3.0);\n}\n\nvec3 lcd(float s) {\n // The DMG's four greens sit at about these points between darkest and lightest.\n float w = s < 0.5 ? 0.0 : (s < 1.5 ? 0.28 : (s < 2.5 ? 0.88 : 1.0));\n return mix(uDark, uLight, w);\n}\n\nfloat roundBox(vec2 p, vec2 b, float r) {\n vec2 q = abs(p) - b + r;\n return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 res = iResolution.xy;\n float lines = floor(uLines);\n float cols = floor(lines * 160.0 / 144.0 + 0.5);\n // Whole device pixels per LCD pixel, so the grid is even.\n float px = max(1.0, floor(min(res.y * 0.64 / lines, res.x * 0.7 / cols)));\n vec2 size = vec2(cols, lines) * px;\n vec2 origin = floor((res - size) * 0.5);\n vec2 q = fragCoord - origin;\n float margin = floor(size.y * 0.12);\n\n vec3 col = uCase;\n // The bezel round the screen, with a rounded lower-right corner like the DMG's.\n vec2 bc = q - size * 0.5 - vec2(0.0, margin * 0.25);\n vec2 bh = size * 0.5 + vec2(margin * 1.6, margin * 1.25);\n float corner = (bc.x > 0.0 && bc.y < 0.0) ? margin * 2.0 : margin * 0.4;\n float bezel = roundBox(bc, bh, corner);\n col = mix(col, uBezel, clamp(0.5 - bezel, 0.0, 1.0));\n // Two stripes across the top of the bezel.\n float top = size.y + margin * 0.6;\n if (bezel < -1.0 && q.y > top && q.y < top + max(1.0, floor(margin * 0.08)))\n col = vec3(0.55, 0.15, 0.35);\n if (bezel < -1.0 && q.y > top + margin * 0.18 && q.y < top + margin * 0.18 + max(1.0, floor(margin * 0.08)))\n col = vec3(0.15, 0.18, 0.42);\n // Power LED.\n vec2 led = vec2(-margin * 0.85, size.y * 0.62);\n float ledR = max(2.0, margin * 0.18);\n float glow = 0.85 + 0.15 * sin(iTime * 3.0);\n col = mix(col, vec3(0.95, 0.15, 0.12) * glow, clamp(ledR - length(q - led) + 0.5, 0.0, 1.0));\n\n if (q.x >= 0.0 && q.y >= 0.0 && q.x < size.x && q.y < size.y) {\n vec2 cell = floor(q / px);\n vec2 f = q - cell * px;\n vec2 uv = (cell + 0.5) / vec2(cols, lines);\n vec2 now = uv + vec2(iTime * uPan, 0.0);\n // Ghosting: the LCD is slow, so where the picture was a moment ago still shows.\n vec2 before = now - vec2(uPan * 0.35, 0.0);\n float s = shade(now, cell);\n float g = shade(before, cell);\n vec3 lit = mix(lcd(s), lcd(g), uGhost * 0.45);\n // Each dot casts a faint shadow down and right onto the screen behind it.\n float behind = shade(now - vec2(1.0 / cols, -1.0 / lines), cell + vec2(-1.0, 1.0));\n lit = mix(lit, lcd(min(s, behind)), uGhost * 0.2);\n // The grid between dots shows the lighter screen behind.\n float edge = px >= 3.0 ? float(f.x < 1.0 || f.y >= px - 1.0) : 0.0;\n col = mix(lit, mix(uLight, vec3(1.0), 0.08), edge * uGrid * 0.6);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Chunky\", values: { uLines: 72 } },\n { name: \"Pocket\", values: { uDark: [0.16, 0.16, 0.14], uLight: [0.77, 0.79, 0.72], uBezel: [0.42, 0.42, 0.4], uCase: [0.78, 0.78, 0.76] } },\n ],\n};\n\nexport const pixelFire: ShaderEffect = {\n kind: \"shader\",\n id: \"pixel-fire\",\n name: \"Pixel fire\",\n description: \"Chunky Doom-style pixel fire licking up from the bottom through a stepped black, red, orange, yellow and white ramp.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"fire\", \"flame\", \"doom\", \"demoscene\", \"loop\"],\n source: glsl(\n `// Pixel fire: Doom-style chunky flames in a stepped palette ramp.\nuniform float uPixel; // @control min=2 max=16 default=6 step=1 label=\"Pixel size\"\nuniform float uHeight; // @control min=0.2 max=1.2 default=0.65 label=\"Flame height\"\nuniform float uWind; // @control min=-1 max=1 default=0.2 label=\"Wind\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uFlicker; // @control min=0 max=1 default=0.5 label=\"Flicker\"\nuniform int uLevels; // @control min=3 max=16 default=9 label=\"Palette steps\"\nuniform vec3 uEmber; // @control color default=#7A0E06 label=\"Embers\"\nuniform vec3 uFlame; // @control color default=#F2560E label=\"Flame\"\nuniform vec3 uCore; // @control color default=#FFE27A label=\"Core\"`,\n HASH,\n NOISE,\n FBM,\n `// Black → embers → flame → core → white.\nvec3 ramp(float t) {\n vec3 c = mix(vec3(0.02, 0.01, 0.01), uEmber, smoothstep(0.0, 0.3, t));\n c = mix(c, uFlame, smoothstep(0.3, 0.6, t));\n c = mix(c, uCore, smoothstep(0.6, 0.85, t));\n return mix(c, vec3(1.0, 1.0, 0.94), smoothstep(0.85, 1.0, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n float rows = max(floor(iResolution.y / uPixel), 1.0);\n float t = iTime * uSpeed;\n float y = cell.y / rows;\n // Columns lean with the wind the higher they get.\n float x = cell.x / rows - uWind * y * y * 0.8;\n float n = fbm(vec2(x * 7.0 + uWind * t * 1.5, y * 4.0 - t * 2.6), 4);\n float flick = hash12(cell + floor(t * 14.0) * 7.31) - 0.5;\n float heat = 1.05 - (y / uHeight) * (0.35 + 1.5 * n) + flick * 0.22 * uFlicker;\n float levels = float(uLevels);\n float lvl = clamp(floor(heat * levels), 0.0, levels - 1.0);\n fragColor = vec4(ramp(lvl / (levels - 1.0)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Doom\", values: { uPixel: 6, uLevels: 9 } },\n { name: \"Blue flame\", values: { uEmber: [0.04, 0.08, 0.42], uFlame: [0.16, 0.48, 1], uCore: [0.75, 0.96, 1] } },\n { name: \"Toxic\", values: { uEmber: [0.1, 0.3, 0.02], uFlame: [0.4, 0.85, 0.1], uCore: [0.85, 1, 0.5], uWind: -0.4 } },\n ],\n};\n\nexport const pixelLandscape: ShaderEffect = {\n kind: \"shader\",\n id: \"pixel-landscape\",\n name: \"Pixel landscape\",\n description: \"A parallax pixel-art landscape: clouds, snowy mountains, hills and pines scrolling at different speeds under a pixel sun or moon.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"landscape\", \"parallax\", \"game\", \"background\", \"16-bit\"],\n source: glsl(\n `// Pixel landscape: parallax layers of a limited-palette scene, each scrolling whole pixels.\nuniform float uPixel; // @control min=2 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Scroll speed\"\nuniform vec3 uSkyTop; // @control color default=#3E6FD8 label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#A8DCFF label=\"Sky bottom\"\nuniform vec3 uSun; // @control color default=#FFE066 label=\"Sun / moon\"\nuniform vec3 uCloud; // @control color default=#FFFFFF label=\"Clouds\"\nuniform vec3 uFar; // @control color default=#6E7EC0 label=\"Mountains\"\nuniform vec3 uMid; // @control color default=#3F9A4F label=\"Hills\"\nuniform vec3 uNear; // @control color default=#1E5B30 label=\"Foreground\"\nuniform float uStars; // @control min=0 max=1 default=0 label=\"Stars\"`,\n HASH,\n BAYER,\n NOISE1,\n `float mountain(float x) {\n float ridge = 1.0 - abs(2.0 * noise1(x * 0.03, 1.0) - 1.0);\n return ridge * 0.75 + noise1(x * 0.11, 2.0) * 0.25;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n float rows = max(floor(iResolution.y / uPixel), 1.0);\n float cols = max(floor(iResolution.x / uPixel), 1.0);\n float t = iTime * uSpeed;\n float y = cell.y;\n float sy = y / rows;\n\n // Sky in six bands, dithered where they meet.\n float band = clamp(floor(sy * 6.0 + (bayer4(cell) - 0.5) * 0.9), 0.0, 5.0) / 5.0;\n vec3 col = mix(uSkyBottom, uSkyTop, band);\n float star = hash12(cell);\n if (sy > 0.4 && star > 1.0 - 0.015 * uStars)\n col = mix(col, vec3(1.0), 0.5 + 0.5 * step(0.5, hash12(cell + floor(iTime * 2.0))));\n\n // Sun or moon: a pixel disc with a checkered halo.\n vec2 sun = floor(vec2(cols * 0.7, rows * 0.7));\n float r = max(3.0, floor(rows * 0.1));\n vec2 d = cell - sun;\n float dd = dot(d, d);\n if (dd <= (r + 2.0) * (r + 2.0) + r && mod(cell.x + cell.y, 2.0) < 1.0) col = mix(col, uSun, 0.45);\n if (dd <= r * r + r) col = uSun;\n\n // Clouds: flat-bottomed puffs drifting slowest.\n float cx = cell.x + floor(t * 2.0);\n float base = floor(rows * 0.76 + 3.0 * noise1(floor(cx / 40.0), 9.0));\n float puff = max(0.0, noise1(cx * 0.045, 4.0) - 0.42) * 2.4 * rows * 0.12 + max(0.0, noise1(cx * 0.16, 5.0) - 0.5) * rows * 0.05;\n if (y >= base && y < base + floor(puff)) col = y < base + 1.0 ? mix(uCloud, uSkyTop, 0.25) : uCloud;\n\n // Mountains, with snow on the high peaks and shaded far sides.\n float mx = cell.x + floor(t * 4.0);\n float mh = floor(rows * (0.3 + 0.32 * mountain(mx)));\n if (y <= mh) {\n // Faces sloping down to the right are in shade.\n float slope = mountain(mx + 2.0) - mountain(mx - 2.0);\n col = slope < 0.0 ? uFar * 0.82 : uFar;\n if (mh > rows * 0.52 && y > mh - 3.0 - mod(mx, 2.0)) col = mix(uFar, vec3(1.0), 0.75);\n }\n\n // Rolling hills, a lit rim along the top.\n float hx = cell.x + floor(t * 9.0);\n float hh = floor(rows * (0.24 + 0.06 * sin(hx * 0.045) + 0.04 * noise1(hx * 0.09, 6.0)));\n if (y <= hh) col = y > hh - 1.0 ? mix(uMid, vec3(1.0), 0.2) : uMid;\n\n // Foreground: a strip of ground with pine trees, fastest.\n float nx = cell.x + floor(t * 18.0);\n float nh = floor(rows * (0.1 + 0.02 * sin(nx * 0.08)));\n float slot = floor(nx / 14.0);\n float lx = abs(mod(nx, 14.0) - 7.0);\n float treeH = floor(rows * (0.08 + 0.08 * hash12(vec2(slot, 3.0))));\n bool tree = hash12(vec2(slot, 7.0)) > 0.35 && y > nh && y <= nh + treeH && lx <= floor((nh + treeH - y) / 2.5);\n if (y <= nh || tree) col = tree ? uNear * 0.8 : uNear;\n if (!tree && y <= nh && y > nh - 1.0) col = mix(uNear, uMid, 0.5);\n\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n {\n name: \"Dusk\",\n values: {\n uSkyTop: [0.17, 0.11, 0.31],\n uSkyBottom: [0.95, 0.53, 0.35],\n uSun: [1, 0.36, 0.24],\n uCloud: [0.96, 0.69, 0.57],\n uFar: [0.42, 0.24, 0.43],\n uMid: [0.23, 0.15, 0.31],\n uNear: [0.1, 0.07, 0.19],\n },\n },\n {\n name: \"Night\",\n values: {\n uSkyTop: [0.02, 0.03, 0.09],\n uSkyBottom: [0.11, 0.17, 0.35],\n uSun: [0.95, 0.94, 0.85],\n uCloud: [0.22, 0.27, 0.48],\n uFar: [0.15, 0.19, 0.37],\n uMid: [0.1, 0.14, 0.28],\n uNear: [0.05, 0.07, 0.16],\n uStars: 1,\n },\n },\n ],\n};\n\nexport const outrunRoad: ShaderEffect = {\n kind: \"shader\",\n id: \"outrun-road\",\n name: \"Outrun road\",\n description: \"A pseudo-3D arcade racer's road curving toward a striped sunset sun, with rumble strips, stripe bands and roadside poles rushing past.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"racing\", \"80s\", \"arcade\", \"road\", \"synthwave\", \"sunset\"],\n source: glsl(\n `// Outrun road: a pseudo-3D road racing toward a striped sun, all on a pixel grid.\nuniform float uPixel; // @control min=1 max=12 default=3 step=1 label=\"Pixel size\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Speed\"\nuniform float uCurve; // @control min=0 max=1 default=0.6 label=\"Curves\"\nuniform vec3 uSkyTop; // @control color default=#1B0B42 label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#FF6A5C label=\"Sky bottom\"\nuniform vec3 uSunTop; // @control color default=#FFE45E label=\"Sun top\"\nuniform vec3 uSunBottom; // @control color default=#FF2E88 label=\"Sun bottom\"\nuniform vec3 uGrass; // @control color default=#1F8F4E label=\"Verge\"\nuniform vec3 uRoad; // @control color default=#56566A label=\"Road\"\nuniform vec3 uKerb; // @control color default=#E8343F label=\"Rumble strip\"`,\n HASH,\n BAYER,\n NOISE1,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec2 grid = max(floor(iResolution.xy / uPixel), vec2(1.0));\n float horizon = floor(grid.y * 0.46);\n float t = iTime * uSpeed;\n float curve = uCurve * sin(iTime * 0.32);\n float cx = floor(grid.x * 0.5);\n vec3 col;\n\n if (cell.y >= horizon) {\n // Sky in banded steps, dithered between them.\n float h = (cell.y - horizon) / max(grid.y - horizon, 1.0);\n float band = clamp(floor(h * 7.0 + (bayer4(cell) - 0.5) * 0.8), 0.0, 6.0) / 6.0;\n col = mix(uSkyBottom, uSkyTop, band);\n // The sun, sliding against the curve, with gaps widening toward its foot.\n float r = floor(grid.y * 0.2);\n vec2 sc = vec2(floor(cx - curve * grid.x * 0.25), horizon + floor(r * 0.55));\n vec2 d = cell - sc;\n if (dot(d, d) <= r * r + r) {\n float below = -d.y;\n bool gap = below > 0.0 && mod(below, 5.0) < floor(below / r * 4.0 + 0.5);\n if (!gap) col = mix(uSunBottom, uSunTop, clamp(floor((d.y / r * 0.5 + 0.5) * 4.0) / 3.0, 0.0, 1.0));\n }\n // A pixel skyline of hills on the horizon.\n float hills = floor(2.0 + 5.0 * noise1((cell.x + floor(curve * grid.x * 0.4)) * 0.07, 3.0));\n if (cell.y < horizon + hills) col = mix(uSkyTop, uGrass, 0.25);\n } else {\n float dy = horizon - cell.y;\n float scale = dy / horizon;\n float z = 1.0 / scale;\n float roadX = cx + curve * grid.x * 0.6 * (1.0 - scale) * (1.0 - scale);\n float halfW = grid.x * 0.42 * scale;\n float dx = abs(cell.x - roadX);\n float alt = mod(floor((z + t * 10.0) * 0.5), 2.0);\n col = uGrass * (alt > 0.5 ? 1.0 : 0.8);\n if (dx < halfW) {\n col = uRoad * (alt > 0.5 ? 1.0 : 0.9);\n // Lane lines on every other band.\n float lane = abs(dx - halfW / 3.0);\n if (alt > 0.5 && (lane < max(0.5, halfW * 0.025) || dx < max(0.5, halfW * 0.025))) col = vec3(0.95);\n } else if (dx < halfW * 1.12) {\n col = alt > 0.5 ? uKerb : vec3(0.95);\n }\n // Haze near the horizon.\n float haze = clamp(1.0 - scale * 6.0, 0.0, 1.0);\n if (bayer4(cell) < haze * 0.8) col = uSkyBottom * 0.8;\n }\n\n // Roadside poles, the nearest drawn last.\n for (int k = 7; k >= 0; k--) {\n float period = 8.0;\n float zk = float(k) * period + period - mod(t * 10.0, period);\n if (zk < 1.0) continue;\n float sk = 1.0 / zk;\n float yb = horizon - sk * horizon;\n float roadX = cx + curve * grid.x * 0.6 * (1.0 - sk) * (1.0 - sk);\n float off = grid.x * 0.42 * sk * 1.35;\n float w = max(1.0, floor(grid.x * 0.012 * sk + 0.5));\n float ph = floor(grid.y * 0.42 * sk) + 2.0;\n float py = cell.y - floor(yb);\n if (py >= 0.0 && py < ph) {\n for (int side = 0; side < 2; side++) {\n float px = floor(roadX + (side == 0 ? -off : off));\n if (cell.x >= px && cell.x < px + w) {\n col = py > ph - max(1.0, floor(w * 1.5)) ? uSunTop : (mod(floor(py / max(1.0, w * 2.0)), 2.0) < 1.0 ? vec3(0.95) : uKerb);\n }\n }\n }\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Coastline\", values: { uSkyTop: [0.12, 0.35, 0.85], uSkyBottom: [0.65, 0.88, 1], uSunTop: [1, 1, 0.85], uSunBottom: [1, 0.85, 0.4], uGrass: [0.85, 0.78, 0.5] } },\n { name: \"Midnight\", values: { uSkyTop: [0.01, 0.0, 0.06], uSkyBottom: [0.3, 0.05, 0.45], uGrass: [0.05, 0.02, 0.15], uRoad: [0.12, 0.1, 0.2], uKerb: [0.0, 0.95, 1] } },\n ],\n};\n\nconst WATER_RAMP = [0, 0.1, 0.22, 0.4, 0.7, 1, 0.75, 0.45, 0.25, 0.12, 0.05, 0, 0.08, 0.18, 0.1, 0];\n\nexport const paletteCycle: ShaderEffect = {\n kind: \"shader\",\n id: \"palette-cycle\",\n name: \"Palette cycle\",\n description: \"Demoscene colour cycling: a still pixel-art waterfall (or plasma) brought to life purely by rotating its palette.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"palette\", \"colour cycling\", \"demoscene\", \"waterfall\", \"plasma\", \"loop\"],\n loop: 2,\n source: glsl(\n `// Palette cycle: a static indexed picture animated only by rotating its palette.\nuniform int uScene; // @control min=0 max=1 default=0 label=\"Scene (0 waterfall, 1 plasma)\"\nuniform float uPixel; // @control min=2 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uRate; // @control min=0 max=32 default=8 step=1 label=\"Cycle speed (steps per second)\"\nuniform vec3 uDeep; // @control color default=#163C8C label=\"Water\"\nuniform vec3 uFoam; // @control color default=#E8F7FF label=\"Foam\"\nuniform vec3 uRock; // @control color default=#5A4466 label=\"Rock\"\nuniform vec3 uSky; // @control color default=#1A1238 label=\"Sky\"`,\n HASH,\n BAYER,\n NOISE1,\n `const float WATER[16] = float[16](${WATER_RAMP.map((v) => v.toFixed(2)).join(\", \")});\n\nvec3 water(float i) {\n return mix(uDeep, uFoam, WATER[int(mod(i, 16.0))]);\n}\n\nvec3 rainbow(float i) {\n float t = mod(i, 16.0) / 16.0;\n return 0.5 + 0.5 * cos(6.28318 * (t + vec3(0.0, 0.33, 0.67)));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec2 grid = max(floor(iResolution.xy / uPixel), vec2(1.0));\n float shift = floor(iTime * uRate);\n vec3 col;\n\n if (uScene == 1) {\n // A plasma whose 16 palette indices rotate.\n vec2 p = cell / grid.y * 8.0;\n float v = sin(p.x) + sin(p.y * 1.3) + sin((p.x + p.y) * 0.7) + sin(length(p - 4.0) * 1.5);\n float index = floor((v * 0.125 + 0.5) * 32.0);\n fragColor = vec4(rainbow(index - shift), 1.0);\n return;\n }\n\n vec2 uv = cell / grid;\n float mid = floor(grid.x * 0.5);\n float fallHalf = floor(grid.x * 0.1 + 2.0 * noise1(cell.y * 0.2, 2.0));\n float cliffTop = floor(grid.y * (0.74 + 0.08 * noise1(cell.x * 0.08, 1.0)));\n float poolTop = floor(grid.y * 0.26);\n\n // Night sky with fixed stars (the sky never cycles).\n col = mix(uSky, uSky * 1.8 + 0.04, floor((1.0 - uv.y) * 4.0) / 4.0);\n if (hash12(cell) > 0.985) col = vec3(0.85, 0.85, 1.0);\n\n if (cell.y < cliffTop && cell.y >= poolTop) {\n // Rock in three tones with strata.\n float tone = floor(clamp(noise1(cell.x * 0.3 + floor(cell.y / 3.0) * 7.0, 5.0) * 2.2 + (bayer4(cell) - 0.5) * 0.6, 0.0, 2.0));\n col = uRock * (0.65 + 0.25 * tone);\n }\n if (abs(cell.x - mid) <= fallHalf && cell.y >= poolTop && cell.y < cliffTop + 1.0) {\n // The fall: streaks whose indices rise with height, so cycling moves them down.\n float streak = floor(hash12(vec2(cell.x, 7.0)) * 6.0);\n col = water(floor(cell.y / 2.0) + streak + shift);\n if (abs(cell.x - mid) == fallHalf) col = mix(col, uDeep, 0.5);\n }\n if (cell.y < poolTop) {\n // The pool: ripple rings whose indices fall outward from the splash.\n vec2 d = (cell - vec2(mid, poolTop)) * vec2(1.0, 2.6);\n float ring = floor(length(d) / 2.0);\n col = mix(uDeep * 0.7, water(ring - shift), 0.75 - 0.4 * uv.y / 0.26);\n // Churning foam where the fall lands.\n if (abs(cell.x - mid) <= fallHalf + 3.0 && cell.y > poolTop - 4.0)\n col = water(floor(hash12(cell) * 16.0) + shift);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Plasma\", values: { uScene: 1, uRate: 12 } },\n { name: \"Lava\", values: { uDeep: [0.45, 0.05, 0.02], uFoam: [1, 0.85, 0.3], uRock: [0.2, 0.17, 0.2], uSky: [0.12, 0.03, 0.05] } },\n ],\n};\n\nconst RASTER_COLOURS = [\"#E8343F\", \"#FF8A1F\", \"#FFE14D\", \"#3FD15C\", \"#2EE6E6\", \"#2E6BFF\", \"#9B4DFF\", \"#FF4DC4\"];\n\nexport const rasterBars: ShaderEffect = {\n kind: \"shader\",\n id: \"raster-bars\",\n name: \"Raster bars\",\n description: \"Demoscene copper bars bouncing on sine paths behind a sine-scrolling greeting, all in chunky pixels.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"demoscene\", \"amiga\", \"c64\", \"scroller\", \"text\", \"copper\"],\n source: glsl(\n `// Raster bars: copper bars on sine paths behind a sine scroller.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"GREETINGS FROM FLAIR\", { width: 2048, height: 256 })} label=\"Scroller text\"\nuniform float uPixel; // @control min=1 max=12 default=4 step=1 label=\"Pixel size\"\nuniform int uBars; // @control min=1 max=8 default=7 label=\"Bars\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uWave; // @control min=0 max=1 default=0.5 label=\"Text wave\"\nuniform vec3 uBackground; // @control color default=#0B0B24 label=\"Background\"\nuniform vec3 uTextTop; // @control color default=#FFFFFF label=\"Text top\"\nuniform vec3 uTextBottom; // @control color default=#3AA0FF label=\"Text bottom\"`,\n paletteArray(\"BARS\", RASTER_COLOURS),\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec2 grid = max(floor(iResolution.xy / uPixel), vec2(1.0));\n float t = iTime * uSpeed;\n vec3 col = uBackground;\n\n // Copper bars: each a stepped highlight, later bars over earlier ones.\n float thick = max(3.0, floor(grid.y * 0.06));\n for (int i = 0; i < 8; i++) {\n if (i >= uBars) break;\n float fi = float(i);\n float centre = floor(grid.y * (0.5 + 0.36 * sin(t * 1.7 + fi * 0.55)));\n float dy = abs(cell.y - centre);\n if (dy <= thick) {\n float level = ceil((1.0 - dy / (thick + 1.0)) * 4.0) / 4.0;\n col = BARS[i] * (0.25 + 0.75 * level) + vec3(pow(level, 4.0) * 0.35);\n }\n }\n\n // Scroller: text marching left, each column bobbing on a sine.\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float h = floor(grid.y * 0.3);\n float w = h * aspect;\n // Starting with the text already on screen, near the left.\n float scroll = mod(t * grid.y * 0.35 + grid.x * 0.9, w + grid.x);\n float tx = cell.x + scroll - grid.x;\n float bob = floor(sin(tx * 0.06 + t * 3.0) * grid.y * 0.14 * uWave);\n float ty = cell.y - (floor(grid.y * 0.5 - h * 0.5) + bob);\n vec2 uv = (vec2(tx, ty) + 0.5) / vec2(w, h);\n vec2 shadowUv = uv + vec2(-1.0 / w, 1.0 / h);\n float ink = (uv.x > 0.0 && uv.x < 1.0 && uv.y > 0.0 && uv.y < 1.0) ? step(0.5, texture(uText, uv).a) : 0.0;\n float shadow = (shadowUv.x > 0.0 && shadowUv.x < 1.0 && shadowUv.y > 0.0 && shadowUv.y < 1.0) ? step(0.5, texture(uText, shadowUv).a) : 0.0;\n if (shadow > 0.5) col = vec3(0.0);\n if (ink > 0.5) {\n // A stepped gradient down the letters.\n float g = clamp(floor((uv.y - 0.3) / 0.4 * 4.0) / 3.0, 0.0, 1.0);\n col = mix(uTextBottom, uTextTop, g);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Amiga\", values: { uBackground: [0, 0, 0], uTextTop: [1, 0.9, 0.3], uTextBottom: [1, 0.3, 0.1] } },\n { name: \"Gentle\", values: { uSpeed: 0.5, uWave: 0.25, uBars: 4 } },\n ],\n};\n\n/** The loading screen's lines, 20 columns each (a blank line between). */\nconst LOADING_LINES = [\"PRESS PLAY ON TAPE\", \"\", \"LOADING\", \"\", \"READY.\", \"\"];\nconst LOADING_COLS = 20;\nconst loadingChars = [...new Set([\" \", ...LOADING_LINES.join(\"\")])];\nconst loadingText = LOADING_LINES.flatMap((line) => [...line.padEnd(LOADING_COLS)].map((c) => loadingChars.indexOf(c)));\n\nexport const loadingStripes: ShaderEffect = {\n kind: \"shader\",\n id: \"loading-stripes\",\n name: \"Tape loading\",\n description: \"An 8-bit computer loading from tape: chaotic colour stripes racing through the border around a blue screen with a blinking cursor under READY.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"c64\", \"loading\", \"loader\", \"8-bit\", \"computer\", \"text\"],\n source: glsl(\n `// Tape loading: raster stripes in the border, a bitmap-font screen and a blinking cursor.\nuniform vec3 uScreen; // @control color default=#352879 label=\"Screen\"\nuniform vec3 uInk; // @control color default=#6C5EB5 label=\"Text\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Stripe speed\"\nuniform float uStripe; // @control min=1 max=12 default=3 step=1 label=\"Stripe thickness\"`,\n HASH,\n paletteArray(\"C64\", C64),\n `// 5 × 7 glyphs: bit (x + 5y) of .x holds rows 0–3 (top first), of .y rows 4–6.\nconst ivec2 GLYPHS[${loadingChars.length}] = ivec2[${loadingChars.length}](\n ${loadingChars.map((c) => packGlyph(PIXEL_FONT[c]!)).join(\",\\n \")}\n);\nconst int TEXT[${loadingText.length}] = int[${loadingText.length}](${loadingText.join(\", \")});\n\nfloat glyphBit(ivec2 g, int x, int y) {\n if (x < 0 || x > 4 || y < 0 || y > 6) return 0.0;\n int bits = y < 4 ? (g.x >> (x + 5 * y)) : (g.y >> (x + 5 * (y - 4)));\n return float(bits & 1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n // The screen is 128 × 80 virtual pixels: 20 columns of 6 and 8 rows of 8, a margin round them.\n vec2 screen = vec2(128.0, 80.0);\n float px = max(1.0, floor(min(iResolution.x * 0.78 / screen.x, iResolution.y * 0.72 / screen.y)));\n vec2 origin = floor((iResolution.xy - screen * px) * 0.5);\n vec2 q = floor((fragCoord - origin) / px);\n\n if (q.x < 0.0 || q.y < 0.0 || q.x >= screen.x || q.y >= screen.y) {\n // Border: stripes of two overlapping widths, reshuffled every tick.\n float row = floor(fragCoord.y / px);\n float tick = floor(iTime * uSpeed * 20.0);\n float offset = floor(hash12(vec2(tick, 3.0)) * 400.0);\n float a = floor((row + offset) / uStripe);\n float b = floor((row + offset * 1.7) / (uStripe * 2.3));\n int c = int(hash12(vec2(a + b * 31.0, tick)) * 16.0);\n fragColor = vec4(C64[c], 1.0);\n return;\n }\n\n vec3 col = uScreen;\n float x = q.x - 4.0;\n float y = screen.y - 5.0 - q.y;\n int tc = int(floor(x / 6.0));\n int tr = int(floor(y / 8.0));\n int gx = int(mod(x, 6.0));\n int gy = int(mod(y, 8.0));\n if (x >= 0.0 && y >= 0.0 && tc < ${LOADING_COLS} && tr < ${LOADING_LINES.length}) {\n float ink = glyphBit(GLYPHS[TEXT[tr * ${LOADING_COLS} + tc]], gx, gy);\n // The cursor: a block under READY., on and off.\n if (tr == ${LOADING_LINES.length - 1} && tc == 0 && gx < 6 && mod(floor(iTime * 2.5), 2.0) < 1.0) ink = 1.0;\n col = mix(col, uInk, ink);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Green screen\", values: { uScreen: [0.02, 0.1, 0.03], uInk: [0.3, 1, 0.4] } },\n { name: \"Turbo\", values: { uSpeed: 2.5, uStripe: 1 } },\n ],\n};\n\nexport const pixelWater: ShaderEffect = {\n kind: \"shader\",\n id: \"pixel-water\",\n name: \"Pixel water\",\n description: \"Tiling pixel-art water in three blues with wavy highlight lines and twinkling sparkles; it loops and tiles seamlessly.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"water\", \"tile\", \"game\", \"background\", \"loop\"],\n loop: 4,\n source: glsl(\n `// Pixel water: a seamless tile of banded blues, crest highlights and sparkles.\nuniform float uPixel; // @control min=1 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uTile; // @control min=8 max=64 default=32 step=1 label=\"Tile size (pixels)\"\nuniform vec3 uDeep; // @control color default=#1B3B8F label=\"Deep\"\nuniform vec3 uMid; // @control color default=#2F6FD6 label=\"Mid\"\nuniform vec3 uLight; // @control color default=#6FB8FF label=\"Light\"\nuniform vec3 uFoam; // @control color default=#FFFFFF label=\"Highlights\"\nuniform float uSparkle; // @control min=0 max=1 default=0.6 label=\"Sparkles\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n float tile = floor(uTile);\n vec2 p = mod(cell, tile);\n float k = 6.28318 / tile;\n float w = iTime * 6.28318 / 4.0;\n // Whole waves per tile and per loop, so it tiles and loops seamlessly.\n float a = sin(k * p.x + 1.4 * sin(k * 2.0 * p.y + w) + w);\n float b = sin(k * 2.0 * p.y - w + 0.9 * sin(k * p.x - w));\n float v = 0.5 + 0.28 * a + 0.22 * b;\n vec3 col = v < 0.4 ? uDeep : (v < 0.72 ? uMid : uLight);\n if (v > 0.86 && mod(p.y, 2.0) < 1.0) col = uFoam;\n\n // Sparkles: one per 8 × 8 block of the tile, a plus that blinks once a loop.\n vec2 block = floor(p / 8.0);\n vec2 at = floor(block * 8.0 + 1.0 + hash22(block + tile) * 6.0);\n float phase = fract(iTime / 4.0 + hash12(block * 1.7 + tile));\n float life = phase < 0.12 ? phase / 0.12 : 0.0;\n if (hash12(block + 9.1) < uSparkle && life > 0.0) {\n vec2 d = abs(p - at);\n float arm = life > 0.3 && life < 0.75 ? 1.0 : 0.0;\n if ((d.x + d.y < 0.5) || (arm > 0.5 && min(d.x, d.y) < 0.5 && d.x + d.y < 1.5)) col = uFoam;\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Lagoon\", values: { uDeep: [0.0, 0.42, 0.55], uMid: [0.1, 0.7, 0.75], uLight: [0.55, 0.95, 0.9] } },\n { name: \"Murky\", values: { uDeep: [0.1, 0.18, 0.15], uMid: [0.18, 0.3, 0.22], uLight: [0.35, 0.48, 0.32], uFoam: [0.7, 0.8, 0.6], uSparkle: 0.2 } },\n ],\n};\n\nexport const pixelDissolve: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-pixel-dissolve\",\n name: \"Pixel dissolve\",\n description: \"The picture pixelates up to big blocks, the blocks swap to the next image in a random order, then it resolves into the new picture. Loops back and forth; or turn Animate off and set Progress.\",\n category: \"transition\",\n tags: [\"transition\", \"pixel\", \"image\", \"retro\", \"8-bit\", \"slideshow\"],\n loop: 4,\n source: glsl(\n `// Pixel dissolve: pixelate up, swap blocks in a random order, resolve down. Progress runs 0 → 1 → 0 when animated.\nuniform sampler2D uFrom; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"From image\"\nuniform sampler2D uTo; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.city} label=\"To image\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uMaxBlock; // @control min=4 max=96 default=40 step=1 label=\"Largest block (px)\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float p = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n // 0–0.35 blocks grow; 0.35–0.65 blocks swap; 0.65–1 blocks shrink.\n float grow = clamp(p / 0.35, 0.0, 1.0);\n float shrink = clamp((1.0 - p) / 0.35, 0.0, 1.0);\n float k = min(grow, shrink);\n float block = max(1.0, floor(mix(1.0, uMaxBlock, k * k)));\n vec2 cell = floor(fragCoord / block);\n vec2 uv = (cell + 0.5) * block / iResolution.xy;\n // The order blocks swap in, picked on the largest grid so a block swaps whole.\n vec2 big = floor(fragCoord / uMaxBlock);\n float swap = clamp((p - 0.35) / 0.3, 0.0, 1.0);\n bool showTo = p >= 0.65 || (p > 0.35 && hash12(big + 0.5) < swap);\n fragColor = showTo ? pictureRGBA(uTo, uv) : pictureRGBA(uFrom, uv);\n}`,\n ),\n};\n\n/** Retro and pixel graphics: limited palettes, chunky pixels, demoscene and arcade looks. */\nexport const pixelShaders: ShaderEffect[] = [\n image8bit,\n gameboyScreen,\n pixelFire,\n pixelLandscape,\n outrunRoad,\n paletteCycle,\n rasterBars,\n loadingStripes,\n pixelWater,\n pixelDissolve,\n];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport { pixelGlyph } from \"./shaders/pixel.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Pixel art as SVG: each sprite is a bitmap (rows of characters, one per\n * colour) turned into one path per colour, a run of pixels per sub-path, and\n * drawn with `shape-rendering=\"crispEdges\"` so pixels stay hard-edged.\n * Sprite frames change by snapping a path's `d` (a change with no duration).\n */\n\nconst r2 = (v: number) => Math.round(v * 100) / 100;\n\n/** A derived number in an animation's numeric field (`delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/**\n * The pixels of `bitmap` that are `char`, as path data: a rectangle per run\n * of pixels in a row, each pixel `unit` wide, the top-left at (`x`, `y`).\n */\nexport function bitmapPath(bitmap: readonly string[], char: string, unit = 1, x = 0, y = 0): string {\n let d = \"\";\n bitmap.forEach((row, j) => {\n for (let i = 0; i < row.length; ) {\n if (row[i] !== char) {\n i++;\n continue;\n }\n let end = i;\n while (row[end] === char) end++;\n d += `M${r2(x + i * unit)} ${r2(y + j * unit)}h${r2((end - i) * unit)}v${r2(unit)}h${r2(-(end - i) * unit)}z`;\n i = end;\n }\n });\n return d || \"M0 0\";\n}\n\n/** A bitmap drawn as one path per colour: `colours` maps its characters to fills. */\nfunction sprite(bitmap: readonly string[], colours: Record<string, string>, unit = 1, x = 0, y = 0, id?: (char: string) => string | undefined): string {\n return Object.entries(colours)\n .map(([char, fill]) => {\n const pid = id?.(char);\n return `<path${pid ? ` id=\"${pid}\"` : \"\"} fill=\"${fill}\" d=\"${bitmapPath(bitmap, char, unit, x, y)}\"/>`;\n })\n .join(\"\");\n}\n\n/** Instant changes: the attribute snaps to `value` at `delay`. */\nconst snap = (id: string, attr: string, value: string | number, delay: number): SvgAnimation => ({ id, attrs: { [attr]: [value, value] }, delay, ms: 0 });\n\n// ── Pixel text ─────────────────────────────────────────────────────────\n\n/** Letters pixel text has room for; longer text is cut. */\nconst TEXT_SLOTS = 16;\nconst TEXT_W = 240;\nconst TEXT_H = 100;\n\n/** A letter's drop: from `lift` units above its place, a bounce, then at rest. */\nconst letterAt = (i: number, lift: number) => `translate(${i * 6} ${lift})`;\n\nexport const pixelText: VectorEffect = {\n kind: \"vector\",\n id: \"pixel-text\",\n name: \"Pixel text\",\n description: \"Any text set in a chunky 5 × 7 pixel font, its letters dropping in one after another with a little bounce.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"text\", \"title\", \"8-bit\", \"arcade\", \"font\"],\n hold: 1400,\n presets: [\n { name: \"Arcade\", values: { ink: [1, 0.85, 0.1], shadow: [0.85, 0.15, 0.1], background: [0, 0, 0] } },\n { name: \"Game Boy\", values: { ink: [0.06, 0.22, 0.06], shadow: [0.55, 0.67, 0.06], background: [0.61, 0.74, 0.06] } },\n ],\n // Each letter slot is one path; its `d` is worked out from the text here (attribute values, so no markup is injected).\n derived: (v) => {\n const letters = Array.from(String(v.text ?? \"\")).slice(0, TEXT_SLOTS);\n const count = Math.max(1, letters.length);\n const width = count * 6 - 1;\n const scale = Math.min(10, (TEXT_W - 20) / width);\n const out: Record<string, string | number> = {\n fit: `translate(${r2((TEXT_W - width * scale) / 2)} ${r2((TEXT_H - 7 * scale) / 2)}) scale(${r2(scale)})`,\n };\n const stagger = Number(v.stagger) || 0;\n for (let i = 0; i < TEXT_SLOTS; i++) {\n const c = letters[i];\n out[`d${i}`] = c === undefined || /\\s/.test(c) ? \"M0 0\" : bitmapPath(pixelGlyph(c), \"#\");\n // When it starts falling, lands and tops its bounce.\n out[`t${i}`] = Math.round(i * stagger);\n out[`u${i}`] = Math.round(i * stagger) + 260;\n out[`w${i}`] = Math.round(i * stagger) + 370;\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 ${TEXT_W} ${TEXT_H}\" shape-rendering=\"crispEdges\"><!-- {{text: text default=PIXEL label='Text'}} {{ink: color default=#FFFFFF label='Letters'}} {{shadow: color default=#E8343F label='Shadow'}} {{background: color default=#1A1C2C label='Background'}} {{stagger: float min=20 max=300 default=90 step=10 label='Stagger (ms)'}} --><rect width=\"${TEXT_W}\" height=\"${TEXT_H}\" fill=\"{{background}}\"/><g transform=\"{{fit}}\">${Array.from(\n { length: TEXT_SLOTS },\n (_, i) =>\n `<g id=\"g${i}\" transform=\"${letterAt(i, -14)}\" opacity=\"0\"><path transform=\"translate(0.6 0.6)\" fill=\"{{shadow}}\" d=\"{{d${i}}}\"/><path fill=\"{{ink}}\" d=\"{{d${i}}}\"/></g>`,\n ).join(\"\")}</g></svg>`,\n animate: Array.from({ length: TEXT_SLOTS }, (_, i): SvgAnimation[] => [\n { id: `g${i}`, attrs: { opacity: [0, 1] }, delay: n(`t${i}`), ms: 60, ease: \"linear\" },\n { id: `g${i}`, attrs: { transform: [letterAt(i, -14), letterAt(i, 0)] }, delay: n(`t${i}`), ms: 260, ease: \"in-out\" },\n { id: `g${i}`, attrs: { transform: [letterAt(i, 0), letterAt(i, -1.6)] }, delay: n(`u${i}`), ms: 110, ease: \"out\" },\n { id: `g${i}`, attrs: { transform: [letterAt(i, -1.6), letterAt(i, 0)] }, delay: n(`w${i}`), ms: 120, ease: \"in-out\" },\n ]).flat(),\n },\n};\n\n// ── Coin spin ──────────────────────────────────────────────────────────\n\nconst COIN = [\n \"...oooo...\",\n \"..oyyyyo..\",\n \".oylyyyyo.\",\n \".oylyddyo.\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \".oyyyddyo.\",\n \".oyyyyyyo.\",\n \"..oyyyyo..\",\n \"...oooo...\",\n];\nconst SPARKLE = [\"..w..\", \"..w..\", \"ww.ww\", \"..w..\", \"..w..\"];\n/** \"+1\" in the pixel font, a column apart. */\nconst PLUS_ONE = pixelGlyph(\"+\").map((row, j) => `${row}.${pixelGlyph(\"1\")[j]}`);\nconst coinPose = (sx: number) => `translate(60 60) scale(${sx} 1) translate(-25 -35)`;\nconst sparklePose = (s: number) => `translate(86 30) scale(${s}) translate(-6.25 -6.25)`;\n\nexport const coinSpin: VectorEffect = {\n kind: \"vector\",\n id: \"coin-spin\",\n name: \"Coin spin\",\n description: \"An 8-bit gold coin spinning on the spot, a pixel sparkle glinting and a +1 popping up each turn.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"coin\", \"game\", \"reward\", \"8-bit\", \"icon\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Silver\", values: { gold: [0.78, 0.8, 0.85], light: [1, 1, 1], dark: [0.45, 0.48, 0.55], outline: [0.2, 0.22, 0.28] } },\n { name: \"Ruby\", values: { gold: [0.9, 0.15, 0.3], light: [1, 0.6, 0.7], dark: [0.55, 0.05, 0.15], outline: [0.25, 0.02, 0.08] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#1A1C2C label='Background'}} {{gold: color default=#F7C531 label='Coin'}} {{light: color default=#FFF3A8 label='Shine'}} {{dark: color default=#C27C0E label='Shade'}} {{outline: color default=#5A2E05 label='Outline'}} {{plus: color default=#FFFFFF label='+1'}} --><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><g id=\"coin\" transform=\"${coinPose(1)}\">${sprite(COIN, { o: \"{{outline}}\", y: \"{{gold}}\", l: \"{{light}}\", d: \"{{dark}}\" }, 5)}</g><g id=\"sparkle\" transform=\"${sparklePose(0)}\">${sprite(SPARKLE, { w: \"{{light}}\" }, 2.5)}</g><g id=\"plus\" transform=\"translate(66 22)\" opacity=\"0\">${sprite(PLUS_ONE, { \"#\": \"{{plus}}\" }, 2)}</g></svg>`,\n animate: [\n // A full turn: face, edge, back (mirrored), edge, face.\n { id: \"coin\", attrs: { transform: [coinPose(1), coinPose(-1)] }, ms: 500, ease: \"in-out\" },\n { id: \"coin\", attrs: { transform: [coinPose(-1), coinPose(1)] }, delay: 500, ms: 500, ease: \"in-out\" },\n { id: \"sparkle\", attrs: { transform: [sparklePose(0), sparklePose(1)] }, delay: 150, ms: 150, ease: \"out\" },\n { id: \"sparkle\", attrs: { transform: [sparklePose(1), sparklePose(0)] }, delay: 300, ms: 200, ease: \"in-out\" },\n { id: \"plus\", attrs: { transform: [\"translate(66 22)\", \"translate(66 4)\"], opacity: [1, 0] }, delay: 450, ms: 650, ease: \"out\" },\n snap(\"plus\", \"opacity\", 0, 0),\n ],\n },\n};\n\n// ── Space invader ──────────────────────────────────────────────────────\n\nconst INVADER_A = [\"..#.....#..\", \"...#...#...\", \"..#######..\", \".##.###.##.\", \"###########\", \"#.#######.#\", \"#.#.....#.#\", \"...##.##...\"];\nconst INVADER_B = [\"..#.....#..\", \"#..#...#..#\", \"#.#######.#\", \"###.###.###\", \"###########\", \".#########.\", \"..#.....#..\", \".#.......#.\"];\nconst BOLT_A = [\".#\", \"#.\", \".#\", \"#.\"];\nconst BOLT_B = [\"#.\", \".#\", \"#.\", \".#\"];\nconst CANNON = [\"....#....\", \"...###...\", \".#######.\", \"#########\"];\nconst MARCH_MS = 320;\n/** The invader's positions: right in steps, down, left, down. */\nconst MARCH: [number, number][] = [\n ...[0, 1, 2, 3, 4, 5, 6].map((k): [number, number] => [24 + k * 16, 12]),\n ...[6, 5, 4, 3, 2, 1, 0].map((k): [number, number] => [24 + k * 16, 26]),\n [24, 40],\n];\n/** Shots fired: at which march step. */\nconst SHOTS = [3, 10];\n\nexport const spaceInvader: VectorEffect = {\n kind: \"vector\",\n id: \"space-invader\",\n name: \"Space invader\",\n description: \"The classic two-frame pixel invader marching across and down a step, dropping a blinking zigzag laser shot.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"arcade\", \"game\", \"sprite\", \"alien\", \"8-bit\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Green\", values: { invader: [0.3, 1, 0.35], shot: [1, 1, 1], ground: [0.3, 1, 0.35] } },\n { name: \"Overlay\", values: { invader: [1, 0.3, 0.6], shot: [1, 0.9, 0.2], ground: [0.2, 0.85, 1], background: [0.06, 0.02, 0.12] } },\n ],\n motion: (() => {\n const pose = ([x, y]: [number, number]) => `translate(${x} ${y})`;\n const frameA = bitmapPath(INVADER_A, \"#\", 4);\n const frameB = bitmapPath(INVADER_B, \"#\", 4);\n const boltA = bitmapPath(BOLT_A, \"#\", 2);\n const boltB = bitmapPath(BOLT_B, \"#\", 2);\n const animate: SvgAnimation[] = [snap(\"bolt\", \"opacity\", 0, 0)];\n MARCH.forEach((at, k) => {\n animate.push(snap(\"invader\", \"transform\", pose(at), k * MARCH_MS));\n animate.push(snap(\"body\", \"d\", k % 2 ? frameB : frameA, k * MARCH_MS));\n });\n SHOTS.forEach((k) => {\n const [x, y] = MARCH[k]!;\n const start = k * MARCH_MS + 60;\n const from = `translate(${x + 20} ${y + 34})`;\n animate.push(snap(\"bolt\", \"opacity\", 1, start));\n animate.push({ id: \"bolt\", attrs: { transform: [from, `translate(${x + 20} 118)`] }, delay: start, ms: 900, ease: \"linear\" });\n for (let f = 0; f < 9; f++) animate.push(snap(\"zig\", \"d\", f % 2 ? boltB : boltA, start + f * 100));\n animate.push(snap(\"bolt\", \"opacity\", 0, start + 900));\n });\n return {\n svg: `<svg viewBox=\"0 0 200 140\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#000000 label='Background'}} {{invader: color default=#FFFFFF label='Invader'}} {{shot: color default=#FF4D4D label='Laser'}} {{ground: color default=#3FD15C label='Ground'}} --><rect width=\"200\" height=\"140\" fill=\"{{background}}\"/><g id=\"invader\" transform=\"${pose(MARCH[0]!)}\"><path id=\"body\" fill=\"{{invader}}\" d=\"${frameA}\"/></g><g id=\"bolt\" transform=\"translate(0 0)\" opacity=\"0\"><path id=\"zig\" fill=\"{{shot}}\" d=\"${boltA}\"/></g><g fill=\"{{ground}}\"><path d=\"${bitmapPath(CANNON, \"#\", 3, 128, 114)}\"/><rect x=\"0\" y=\"128\" width=\"200\" height=\"2\"/></g></svg>`,\n animate,\n };\n })(),\n};\n\n// ── Pixel heart health ─────────────────────────────────────────────────\n\nconst HEART_INSIDE = [\".##.##.\", \"#######\", \"#######\", \"#######\", \".#####.\", \"..###..\", \"...#...\"];\n/** The heart on a 9 × 9 grid: `o` outline round the inside, `r` fill, `w` a highlight. */\nconst HEART = (() => {\n const grid = Array.from({ length: 9 }, () => Array<string>(9).fill(\".\"));\n HEART_INSIDE.forEach((row, j) => [...row].forEach((c, i) => c === \"#\" && (grid[j + 1]![i + 1] = \"r\")));\n const inside = (i: number, j: number) => grid[j]?.[i] === \"r\";\n for (let j = 0; j < 9; j++)\n for (let i = 0; i < 9; i++)\n if (!inside(i, j) && [[-1, 0], [1, 0], [0, -1], [0, 1]].some(([a, b]) => inside(i + a!, j + b!))) grid[j]![i] = \"o\";\n grid[2]![2] = \"w\";\n grid[3]![2] = \"w\";\n return grid.map((row) => row.join(\"\"));\n})();\nconst HEARTS = 5;\nconst HEART_UNIT = 4;\nconst heartPose = (i: number, s: number) => `translate(${30 + i * 45} 32) scale(${s}) translate(-18 -18)`;\n/** When hearts are lost (flash then empty) and refilled, in ms. */\nconst LOSSES: [number, number][] = [[4, 500], [3, 1500]];\nconst REFILLS: [number, number][] = [[3, 2700], [4, 3000]];\n\nexport const pixelHeartHealth: VectorEffect = {\n kind: \"vector\",\n id: \"pixel-heart-health\",\n name: \"Heart health bar\",\n description: \"A row of pixel hearts as a game health bar: two hearts flash and empty as damage lands, then pop back full.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"game\", \"health\", \"hud\", \"hearts\", \"8-bit\", \"loop\"],\n hold: 900,\n presets: [\n { name: \"Shield\", values: { heart: [0.2, 0.6, 1], highlight: [0.8, 0.95, 1] } },\n { name: \"Light\", values: { background: [0.96, 0.95, 0.9], empty: [0.82, 0.8, 0.76], outline: [0.15, 0.12, 0.12] } },\n ],\n motion: (() => {\n const animate: SvgAnimation[] = [];\n for (let i = 0; i < HEARTS; i++) {\n animate.push(snap(`f${i}`, \"opacity\", 1, 0), snap(`x${i}`, \"opacity\", 0, 0));\n }\n for (const [i, at] of LOSSES) {\n // Flash white and flicker, then empty, with a shake.\n [0, 1, 0, 1, 0].forEach((on, k) => {\n animate.push(snap(`x${i}`, \"opacity\", on ? 0 : 1, at + k * 90));\n animate.push(snap(`f${i}`, \"opacity\", on, at + k * 90));\n });\n animate.push(snap(`x${i}`, \"opacity\", 0, at + 450));\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 1), heartPose(i, 0.82)] }, delay: at, ms: 90, ease: \"out\" });\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 0.82), heartPose(i, 1)] }, delay: at + 90, ms: 220, ease: \"in-out\" });\n }\n for (const [i, at] of REFILLS) {\n animate.push(snap(`f${i}`, \"opacity\", 1, at));\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 1), heartPose(i, 1.3)] }, delay: at, ms: 120, ease: \"out\" });\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 1.3), heartPose(i, 1)] }, delay: at + 120, ms: 200, ease: \"in-out\" });\n }\n const hearts = Array.from(\n { length: HEARTS },\n (_, i) =>\n `<g id=\"h${i}\" transform=\"${heartPose(i, 1)}\">${sprite(HEART, { o: \"{{outline}}\", r: \"{{empty}}\", w: \"{{empty}}\" }, HEART_UNIT)}<g id=\"f${i}\">${sprite(HEART, { r: \"{{heart}}\", w: \"{{highlight}}\" }, HEART_UNIT)}</g><path id=\"x${i}\" opacity=\"0\" fill=\"{{flash}}\" d=\"${bitmapPath(HEART.map((row) => row.replace(/w/g, \"r\")), \"r\", HEART_UNIT)}\"/></g>`,\n ).join(\"\");\n return {\n svg: `<svg viewBox=\"0 0 240 64\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#14141F label='Background'}} {{heart: color default=#E83B3B label='Heart'}} {{highlight: color default=#FFB3B3 label='Highlight'}} {{empty: color default=#3A2E3E label='Empty'}} {{outline: color default=#000000 label='Outline'}} {{flash: color default=#FFFFFF label='Hit flash'}} --><rect width=\"240\" height=\"64\" fill=\"{{background}}\"/>${hearts}</svg>`,\n animate,\n };\n })(),\n};\n\n// ── Chomp loader ───────────────────────────────────────────────────────\n\n/** A 13 × 13 pixel mouth facing right, open by `angle` degrees each side of its axis. */\nfunction chomper(angle: number): string[] {\n return Array.from({ length: 13 }, (_, j) =>\n Array.from({ length: 13 }, (_, i) => {\n const [x, y] = [i - 6, j - 6];\n if (x * x + y * y > 6.6 * 6.6) return \".\";\n const a = (Math.atan2(-y, x) * 180) / Math.PI;\n return angle > 0 && x >= 0 && Math.abs(a) <= angle ? \".\" : \"#\";\n }).join(\"\"),\n );\n}\nconst CHOMP_UNIT = 3;\nconst CHOMP_FRAMES = [0, 25, 45, 25].map((a) => bitmapPath(chomper(a), \"#\", CHOMP_UNIT, -19.5, -19.5));\nconst CHOMP_MS = 2800;\nconst CHOMP_FROM = -30;\nconst CHOMP_TO = 270;\nconst DOTS = [50, 80, 110, 140, 170, 200];\n\nexport const chompLoader: VectorEffect = {\n kind: \"vector\",\n id: \"chomp-loader\",\n name: \"Chomp loader\",\n description: \"A chomping pixel mouth munching along a row of dots between maze walls, as a looping loader.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"loader\", \"arcade\", \"game\", \"8-bit\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Ghostly\", values: { mouth: [0.4, 0.9, 1], dots: [1, 1, 1], walls: [0.9, 0.2, 0.6] } },\n { name: \"Light\", values: { background: [1, 1, 1], mouth: [0.95, 0.65, 0], dots: [0.4, 0.4, 0.45], walls: [0.15, 0.3, 0.9] } },\n ],\n motion: (() => {\n const travel = CHOMP_TO - CHOMP_FROM;\n const animate: SvgAnimation[] = [\n { id: \"chomp\", attrs: { transform: [`translate(${CHOMP_FROM} 40)`, `translate(${CHOMP_TO} 40)`] }, ms: CHOMP_MS, ease: \"linear\" },\n ];\n for (let f = 0; f * 80 < CHOMP_MS; f++) animate.push(snap(\"mouth\", \"d\", CHOMP_FRAMES[f % CHOMP_FRAMES.length]!, f * 80));\n DOTS.forEach((x, k) => {\n animate.push(snap(`dot${k}`, \"opacity\", 1, 0));\n // Eaten as the mouth's centre reaches it.\n animate.push(snap(`dot${k}`, \"opacity\", 0, Math.round(((x - CHOMP_FROM) / travel) * CHOMP_MS)));\n });\n return {\n svg: `<svg viewBox=\"0 0 240 80\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#000000 label='Background'}} {{mouth: color default=#FFE600 label='Chomper'}} {{dots: color default=#FFB897 label='Dots'}} {{walls: color default=#2E3BFF label='Walls'}} --><rect width=\"240\" height=\"80\" fill=\"{{background}}\"/><g fill=\"none\" stroke=\"{{walls}}\" stroke-width=\"3\"><path d=\"M0 10.5 H240 M0 69.5 H240\"/></g>${DOTS.map((x, k) => `<rect id=\"dot${k}\" x=\"${x - 3}\" y=\"37\" width=\"6\" height=\"6\" fill=\"{{dots}}\"/>`).join(\"\")}<g id=\"chomp\" transform=\"translate(${CHOMP_FROM} 40)\"><path id=\"mouth\" fill=\"{{mouth}}\" d=\"${CHOMP_FRAMES[0]}\"/></g></svg>`,\n animate,\n };\n })(),\n};\n\n/** Pixel-art vector effects: sprites, pixel type and 8-bit UI. */\nexport const pixelEffects: VectorEffect[] = [pixelText, coinSpin, spaceInvader, pixelHeartHealth, chompLoader];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst round = (n: number) => Math.round(n * 10) / 10;\n\nexport const fireworkBurst: VectorEffect = {\n kind: \"vector\",\n id: \"firework-burst\",\n name: \"Firework burst\",\n description: \"A small firework for success moments: a flash, a ring of streaks and a staggered ring of dots bursting outwards and fading.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"celebration\", \"success\", \"reward\", \"ui\", \"fireworks\"],\n hold: 400,\n motion: (() => {\n // Ring one: streaks flying out; ring two: dots, half a step round and a beat later.\n const streaks = Array.from({ length: 12 }, (_, i) => {\n const a = (i / 12) * Math.PI * 2 - Math.PI / 2;\n const [c, s] = [Math.cos(a), Math.sin(a)];\n return { id: `l${i}`, c, s, stroke: [\"{{a}}\", \"{{b}}\", \"{{c}}\"][i % 3]! };\n });\n const dots = Array.from({ length: 10 }, (_, i) => {\n const a = ((i + 0.5) / 10) * Math.PI * 2 - Math.PI / 2;\n return { id: `d${i}`, c: Math.cos(a), s: Math.sin(a), fill: [\"{{b}}\", \"{{c}}\", \"{{a}}\"][i % 3]! };\n });\n const at = (c: number, s: number, r: number) => [round(c * r), round(s * r)] as const;\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{a: color default=#F43F5E label='Colour A'}} {{b: color default=#FACC15 label='Colour B'}} {{c: color default=#38BDF8 label='Colour C'}} {{width: float min=1 max=8 default=4 step=0.5 label='Line width'}} --><g transform=\"translate(100 100) scale({{size: float min=0.5 max=1.4 default=1 step=0.05 label='Size'}})\"><circle id=\"flash\" cx=\"0\" cy=\"0\" r=\"0\" fill=\"{{b}}\" opacity=\"0\"/>${streaks\n .map(({ id, c, s, stroke }) => {\n const [x, y] = at(c, s, 12);\n return `<line id=\"${id}\" x1=\"${x}\" y1=\"${y}\" x2=\"${x}\" y2=\"${y}\" stroke=\"${stroke}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" opacity=\"0\"/>`;\n })\n .join(\"\")}${dots.map(({ id, c, s, fill }) => `<circle id=\"${id}\" cx=\"${round(c * 14)}\" cy=\"${round(s * 14)}\" r=\"5\" fill=\"${fill}\" opacity=\"0\"/>`).join(\"\")}</g></svg>`,\n animate: [\n { id: \"flash\", attrs: { r: [0, 22], opacity: [0.9, 0] }, ms: 380, ease: \"out\" },\n ...streaks.flatMap(({ id, c, s }): SvgAnimation[] => {\n const [x0, y0] = at(c, s, 12);\n const [x1, y1] = at(c, s, 40);\n const [x2, y2] = at(c, s, 62);\n const [x3, y3] = at(c, s, 74);\n return [\n { id, attrs: { opacity: [0, 1] }, ms: 40 },\n { id, attrs: { x1: [x0, x1], y1: [y0, y1], x2: [x0, x2], y2: [y0, y2] }, ms: 420, ease: \"out\" },\n { id, attrs: { x1: [x1, x3], y1: [y1, y3], x2: [x2, x3], y2: [y2, y3], opacity: [1, 0] }, delay: 420, ms: 380, ease: \"in-out\" },\n ];\n }),\n ...dots.flatMap(({ id, c, s }): SvgAnimation[] => [\n { id, attrs: { opacity: [0, 1] }, delay: 150, ms: 40 },\n { id, attrs: { cx: [round(c * 14), round(c * 66)], cy: [round(s * 14), round(s * 66)] }, delay: 150, ms: 520, ease: \"out\" },\n { id, attrs: { cy: [round(s * 66), round(s * 66 + 10)], r: [5, 1], opacity: [1, 0] }, delay: 670, ms: 450, ease: \"in-out\" },\n ]),\n ],\n };\n })(),\n presets: [\n { name: \"Gold\", values: { a: [1, 0.78, 0.3], b: [1, 0.93, 0.6], c: [0.98, 0.6, 0.2] } },\n { name: \"Brand\", values: { a: [0.39, 0.4, 0.95], b: [0.93, 0.28, 0.6], c: [0.13, 0.83, 0.93] } },\n { name: \"Big\", values: { size: 1.4, width: 6 } },\n ],\n};\n\n/** Pyrotechnics: fireworks, sparks, explosions and smoke, as vector effects. */\nexport const pyroEffects: VectorEffect[] = [fireworkBurst];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst r1 = (n: number) => Math.round(n * 10) / 10;\n\n/** A point `radius` from the clock's centre (100, 100), `degrees` clockwise from 12. */\nconst at = (degrees: number, radius: number) => {\n const a = (degrees * Math.PI) / 180;\n return [r1(100 + radius * Math.sin(a)), r1(100 - radius * Math.cos(a))] as const;\n};\n\n/** A pie slice of the dial from `from` to `to` degrees clockwise from 12. */\nconst slice = (from: number, to: number, radius: number) => {\n const [x0, y0] = at(from, radius);\n const [x1, y1] = at(to, radius);\n return `M100 100 L${x0} ${y0} A${radius} ${radius} 0 0 1 ${x1} ${y1}Z`;\n};\n\n/** One clock cycle: day, dusk, night, dawn, 2 s each. */\nconst CYCLE = 8000;\nconst PHASE = CYCLE / 4;\n/** How long the sky takes to change at the end of each phase. */\nconst FADE = 1400;\n\nconst TICKS = Array.from({ length: 12 }, (_, i) => {\n const [x0, y0] = at(i * 30, i % 3 ? 80 : 74);\n const [x1, y1] = at(i * 30, 86);\n return `<line x1=\"${x0}\" y1=\"${y0}\" x2=\"${x1}\" y2=\"${y1}\" stroke=\"{{hands}}\" stroke-width=\"${i % 3 ? 2 : 4}\" stroke-linecap=\"round\" opacity=\"0.8\"/>`;\n}).join(\"\");\n\nconst STARS = [\n [62, 50, 1.6], [128, 44, 1.2], [150, 78, 1.8], [44, 92, 1.2], [70, 140, 1.4], [138, 132, 1.2], [104, 160, 1.6], [92, 34, 1], [160, 110, 1], [36, 124, 1.4],\n]\n .map(([x, y, r]) => `<circle cx=\"${x}\" cy=\"${y}\" r=\"${r}\" fill=\"#FFFFFF\"/>`)\n .join(\"\");\n\n// Fading wedges behind the minute hand: older (further back) is fainter.\nconst TRAIL = [0.07, 0.13, 0.22]\n .map((opacity, i) => `<path d=\"${slice(-36 + i * 12, -24 + i * 12, 72)}\" fill=\"{{trail}}\" opacity=\"${opacity}\"/>`)\n .join(\"\");\n\n/** The sky's colour from one phase to the next, at the end of each phase. */\nconst SKY: readonly (readonly [string, string])[] = [\n [\"{{day}}\", \"{{dusk}}\"],\n [\"{{dusk}}\", \"{{night}}\"],\n [\"{{night}}\", \"{{dawn}}\"],\n [\"{{dawn}}\", \"{{day}}\"],\n];\n\nexport const timeLapseClock: VectorEffect = {\n kind: \"vector\",\n id: \"time-lapse-clock\",\n name: \"Time-lapse clock\",\n description: \"A clock whose hands race round while the sky behind turns from day to dusk, night and dawn.\",\n category: \"timewarp\",\n tags: [\"time\", \"clock\", \"time-lapse\", \"day\", \"night\", \"loader\"],\n hold: 0,\n presets: [\n { name: \"Pastel\", values: { day: [0.75, 0.9, 1], dusk: [1, 0.72, 0.6], night: [0.36, 0.33, 0.6], dawn: [1, 0.85, 0.9] } },\n { name: \"Mono\", values: { day: [0.9, 0.9, 0.9], dusk: [0.55, 0.55, 0.55], night: [0.1, 0.1, 0.1], dawn: [0.7, 0.7, 0.7], sun: [1, 1, 1], trail: [1, 1, 1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{day: color default=#7DD3FC label='Day'}} {{dusk: color default=#F97316 label='Dusk'}} {{night: color default=#0F172A label='Night'}} {{dawn: color default=#F9A8D4 label='Dawn'}} {{sun: color default=#FDE68A label='Sun'}} {{hands: color default=#FFFFFF label='Hands'}} {{trail: color default=#FDE68A label='Trail'}} --><circle id=\"sky\" cx=\"100\" cy=\"100\" r=\"92\" fill=\"{{day}}\"/><g id=\"stars\" opacity=\"0\">${STARS}</g><g id=\"orbit\" transform=\"rotate(0 100 100)\"><circle id=\"sun\" cx=\"100\" cy=\"38\" r=\"11\" fill=\"{{sun}}\"/></g>${TICKS}<circle cx=\"100\" cy=\"100\" r=\"92\" fill=\"none\" stroke=\"{{hands}}\" stroke-width=\"4\" opacity=\"0.9\"/><g id=\"hour\" transform=\"rotate(0 100 100)\"><line x1=\"100\" y1=\"106\" x2=\"100\" y2=\"56\" stroke=\"#000000\" stroke-opacity=\"0.25\" stroke-width=\"9\" stroke-linecap=\"round\"/><line x1=\"100\" y1=\"106\" x2=\"100\" y2=\"56\" stroke=\"{{hands}}\" stroke-width=\"6\" stroke-linecap=\"round\"/></g><g id=\"minute\" transform=\"rotate(0 100 100)\">${TRAIL}<line x1=\"100\" y1=\"110\" x2=\"100\" y2=\"28\" stroke=\"#000000\" stroke-opacity=\"0.25\" stroke-width=\"6\" stroke-linecap=\"round\"/><line x1=\"100\" y1=\"110\" x2=\"100\" y2=\"28\" stroke=\"{{hands}}\" stroke-width=\"3.5\" stroke-linecap=\"round\"/></g><circle cx=\"100\" cy=\"100\" r=\"5\" fill=\"{{hands}}\"/></svg>`,\n animate: [\n // Twelve turns of the minute hand to one of the hour hand, and the sun once round the sky.\n { id: \"minute\", attrs: { transform: [\"rotate(0 100 100)\", \"rotate(4320 100 100)\"] }, ms: CYCLE, ease: \"linear\" },\n { id: \"hour\", attrs: { transform: [\"rotate(0 100 100)\", \"rotate(360 100 100)\"] }, ms: CYCLE, ease: \"linear\" },\n { id: \"orbit\", attrs: { transform: [\"rotate(0 100 100)\", \"rotate(360 100 100)\"] }, ms: CYCLE, ease: \"linear\" },\n ...SKY.map(([from, to], i): SvgAnimation => ({ id: \"sky\", attrs: { fill: [from, to] }, delay: (i + 1) * PHASE - FADE, ms: FADE, ease: \"in-out\" })),\n // Stars come out at night; the sun fades while it is below the horizon.\n { id: \"stars\", attrs: { opacity: [0, 1] }, delay: 2 * PHASE - FADE, ms: FADE, ease: \"in-out\" },\n { id: \"stars\", attrs: { opacity: [1, 0] }, delay: 3 * PHASE - FADE, ms: FADE, ease: \"in-out\" },\n { id: \"sun\", attrs: { opacity: [1, 0.25] }, delay: PHASE, ms: PHASE, ease: \"in-out\" },\n { id: \"sun\", attrs: { opacity: [0.25, 1] }, delay: 3 * PHASE - FADE, ms: FADE, ease: \"in-out\" },\n ],\n },\n};\n\n/** Time warps: echoes, rewinds, freezes and tunnels, as vector effects. */\nexport const timewarpEffects: VectorEffect[] = [timeLapseClock];\n","import { morphPaths, morphSequence } from \"../vector/morph.js\";\nimport type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Morph effects blend shapes point by point: `morphPaths` and\n * `morphSequence` give paths one structure, so `attrs: { d: [a, b] }`\n * blends them. Shapes are drawn with `fill-rule=\"evenodd\"`, since a piece's\n * direction can change, and pieces with no partner grow from or shrink to a\n * point.\n */\n\ntype Point = [number, number];\n\nconst NUMBER = /-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\nconst DEG = Math.PI / 180;\n\nconst r2 = (v: number) => {\n const r = Math.round(v * 100) / 100;\n return Object.is(r, -0) ? 0 : r;\n};\n\n/** A derived number in an animation's numeric field (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/** A path's numbers in pairs, in order (for paths of absolute M, L and C, like morph output). */\nconst pointsOf = (d: string): Point[] => {\n const nums = (d.match(NUMBER) ?? []).map(Number);\n return Array.from({ length: nums.length >> 1 }, (_, i) => [nums[2 * i]!, nums[2 * i + 1]!]);\n};\n\n/** A path (absolute M, L and C only) with every point moved by `f`. */\nfunction mapPath(d: string, f: (p: Point) => Point): string {\n const moved = pointsOf(d).map(f);\n let i = 0;\n return d.replace(NUMBER, () => {\n const k = i++;\n return String(r2(moved[k >> 1]![k % 2]!));\n });\n}\n\nconst polyline = (pts: readonly Point[], close = false) =>\n `M${pts.map((p) => `${r2(p[0])} ${r2(p[1])}`).join(\" L\")}${close ? \" Z\" : \"\"}`;\n\n/** Points round an ellipse between two angles in degrees (0 is right, 90 down), both ends included. */\nfunction arc(cx: number, cy: number, rx: number, ry: number, from: number, to: number, every = 8): Point[] {\n const steps = Math.max(1, Math.ceil(Math.abs(to - from) / every));\n return Array.from({ length: steps + 1 }, (_, k) => {\n const a = (from + ((to - from) * k) / steps) * DEG;\n return [cx + rx * Math.cos(a), cy + ry * Math.sin(a)];\n });\n}\n\nconst circle = (cx: number, cy: number, r: number) => polyline(arc(cx, cy, r, r, 0, 360).slice(0, -1), true);\n\n/** A regular star (or polygon, with `inner` equal to `outer`) of `tips` points, the first straight up. */\nconst star = (cx: number, cy: number, tips: number, outer: number, inner: number) =>\n polyline(\n Array.from({ length: tips * 2 }, (_, k): Point => {\n const r = k % 2 ? inner : outer;\n const a = (-90 + (k * 180) / tips) * DEG;\n return [cx + r * Math.cos(a), cy + r * Math.sin(a)];\n }),\n true,\n );\n\n/**\n * A stroke along `pts` written as a filled outline `width` wide, so it morphs\n * as a shape: mitred corners, and round ends unless `flat` names an end.\n */\nfunction stroke(pts: readonly Point[], width: number, flat: { start?: boolean; end?: boolean } = {}): string {\n const h = width / 2;\n const normals = pts.slice(1).map((p, i): Point => {\n const q = pts[i]!;\n const l = Math.hypot(p[0] - q[0], p[1] - q[1]);\n return [-(p[1] - q[1]) / l, (p[0] - q[0]) / l];\n });\n // Each corner's offset: along the two sides' mean normal, long enough to keep the width (a mitre).\n const offsets = pts.map((_, i): Point => {\n const a = normals[Math.max(0, i - 1)]!;\n const b = normals[Math.min(normals.length - 1, i)]!;\n const l = Math.hypot(a[0] + b[0], a[1] + b[1]);\n const m: Point = [(a[0] + b[0]) / l, (a[1] + b[1]) / l];\n const k = h / (m[0] * b[0] + m[1] * b[1]);\n return [m[0] * k, m[1] * k];\n });\n const left = pts.map((p, i): Point => [p[0] + offsets[i]![0], p[1] + offsets[i]![1]]);\n const right = pts.map((p, i): Point => [p[0] - offsets[i]![0], p[1] - offsets[i]![1]]).reverse();\n const angle = (v: Point) => Math.atan2(v[1], v[0]) / DEG;\n const [first, last] = [pts[0]!, pts[pts.length - 1]!];\n const endAt = angle(normals[normals.length - 1]!);\n const startAt = angle(normals[0]!) + 180;\n const endCap = flat.end ? [] : arc(last[0], last[1], h, h, endAt, endAt - 180, 15).slice(1, -1);\n const startCap = flat.start ? [] : arc(first[0], first[1], h, h, startAt, startAt - 180, 15).slice(1, -1);\n return polyline([...left, ...endCap, ...right, ...startCap], true);\n}\n\n/** Points round a circle from one angle to another, going the way that misses `avoid`. */\nfunction around(c: Point, r: number, from: number, to: number, avoid: number): Point[] {\n let delta = (((to - from) % 360) + 360) % 360;\n if ((((avoid - from) % 360) + 360) % 360 < delta) delta -= 360;\n return arc(c[0], c[1], r, r, from, from + delta);\n}\n\n/** The part of one circle outside another: a crescent moon. */\nfunction crescent(c1: Point, r1: number, c2: Point, r2_: number): string {\n const [dx, dy] = [c2[0] - c1[0], c2[1] - c1[1]];\n const d = Math.hypot(dx, dy);\n const a = (r1 * r1 - r2_ * r2_ + d * d) / (2 * d);\n const h = Math.sqrt(Math.max(0, r1 * r1 - a * a));\n const [px, py] = [c1[0] + (a * dx) / d, c1[1] + (a * dy) / d];\n const i1: Point = [px - (h * dy) / d, py + (h * dx) / d];\n const i2: Point = [px + (h * dy) / d, py - (h * dx) / d];\n const angle = (c: Point, p: Point) => Math.atan2(p[1] - c[1], p[0] - c[0]) / DEG;\n // The long way round the moon (away from the cut), then back round the cut, inside the moon.\n const outer = around(c1, r1, angle(c1, i1), angle(c1, i2), angle(c1, c2));\n const inner = around(c2, r2_, angle(c2, i2), angle(c2, i1), angle(c2, c1) + 180);\n return polyline([...outer, ...inner.slice(1, -1)], true);\n}\n\n/** A heart in a 24 box, curves and all. */\nconst HEART = \"M12 20.5 C12 20.5 3 14.8 3 8.8 C3 6 5.2 3.8 8 3.8 C9.7 3.8 11.2 4.7 12 6.1 C12.8 4.7 14.3 3.8 16 3.8 C18.8 3.8 21 6 21 8.8 C21 14.8 12 20.5 12 20.5 Z\";\n\n/** A path scaled by `s` about (12, 12) and moved to (`cx`, `cy`). */\nconst placed = (d: string, cx: number, cy: number, s: number) => mapPath(d, (p) => [cx + (p[0] - 12) * s, cy + (p[1] - 12) * s]);\n\n/**\n * Any path as one closed outline per piece (see `morphSequence`), scaled\n * and centred to fill `box` ([x, y, width, height]), so paths drawn in any\n * coordinates land in the picture. Throws a sentence on a path it cannot read.\n */\nfunction fitted(d: string, box: readonly [number, number, number, number], points: number): string {\n const outline = morphSequence([d], { points })[0]!;\n const pts = pointsOf(outline);\n const xs = pts.map((p) => p[0]);\n const ys = pts.map((p) => p[1]);\n const [x0, y0] = [Math.min(...xs), Math.min(...ys)];\n const [w, h] = [Math.max(...xs) - x0, Math.max(...ys) - y0];\n const s = Math.min(box[2] / Math.max(w, 1e-6), box[3] / Math.max(h, 1e-6));\n const [ox, oy] = [box[0] + (box[2] - w * s) / 2, box[1] + (box[3] - h * s) / 2];\n return mapPath(outline, (p) => [ox + (p[0] - x0) * s, oy + (p[1] - y0) * s]);\n}\n\n/** A user's path fitted to `box`, or `fallback` fitted when it cannot be read, so the effect still draws. */\nfunction fittedOr(d: unknown, fallback: string, box: readonly [number, number, number, number], points: number): string {\n try {\n return fitted(String(d), box, points);\n } catch {\n return fitted(fallback, box, points);\n }\n}\n\n// ── Shape morph ────────────────────────────────────────────────────────\n\nconst SHAPE_FROM = \"M30 12 H70 A18 18 0 0 1 88 30 V70 A18 18 0 0 1 70 88 H30 A18 18 0 0 1 12 70 V30 A18 18 0 0 1 30 12 Z\";\nconst SHAPE_TO = \"M50 6 L61 38 L95 38 L67 58 L78 92 L50 72 L22 92 L33 58 L5 38 L39 38 Z\";\n\nexport const shapeMorph: VectorEffect = {\n kind: \"vector\",\n id: \"shape-morph\",\n name: \"Shape morph\",\n description: \"Any two SVG paths morphing into each other and back, their fill and outline colours blending along.\",\n category: \"morph\",\n tags: [\"morph\", \"shape\", \"path\", \"icon\", \"logo\"],\n hold: 0,\n presets: [\n { name: \"Ink\", values: { background: [0.98, 0.97, 0.94], fillFrom: [0.1, 0.1, 0.12], fillTo: [0.1, 0.1, 0.12], strokeFrom: [0.1, 0.1, 0.12], strokeTo: [0.1, 0.1, 0.12], width: 0 } },\n {\n name: \"Heart to drop\",\n values: {\n from: \"M12 20.5 C12 20.5 3 14.8 3 8.8 C3 6 5.2 3.8 8 3.8 C9.7 3.8 11.2 4.7 12 6.1 C12.8 4.7 14.3 3.8 16 3.8 C18.8 3.8 21 6 21 8.8 C21 14.8 12 20.5 12 20.5 Z\",\n to: \"M12 2 C12 2 5 10 5 15 A7 7 0 0 0 19 15 C19 10 12 2 12 2 Z\",\n fillFrom: [0.96, 0.25, 0.37],\n fillTo: [0.22, 0.6, 0.97],\n },\n },\n { name: \"Outline\", values: { fillFrom: [0.06, 0.09, 0.16], fillTo: [0.06, 0.09, 0.16], strokeFrom: [0.2, 0.83, 0.6], strokeTo: [0.98, 0.8, 0.08], width: 2.5 } },\n ],\n // Each path is fitted to the picture on its own, so paths in any coordinates fill it.\n derived: (v) => {\n const [a, b] = morphPaths(fittedOr(v.from, SHAPE_FROM, [12, 12, 76, 76], 96), fittedOr(v.to, SHAPE_TO, [12, 12, 76, 76], 96), { points: 80 });\n return { a, b, back: Number(v.pause) * 2 + Number(v.morph) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{from: text default='${SHAPE_FROM}' label='From path'}} {{to: text default='${SHAPE_TO}' label='To path'}} {{fillFrom: color default=#6366F1 label='Fill (from)'}} {{fillTo: color default=#F59E0B label='Fill (to)'}} {{strokeFrom: color default=#C7D2FE label='Outline (from)'}} {{strokeTo: color default=#FEF3C7 label='Outline (to)'}} {{background: color default=#0F172A label='Background'}} {{width: float min=0 max=6 default=1.5 step=0.25 label='Outline width'}} {{morph: float min=200 max=3000 default=1000 step=50 label='Morph ms'}} {{pause: float min=0 max=3000 default=700 step=50 label='Pause ms'}} --><rect width=\"100\" height=\"100\" fill=\"{{background}}\"/><path id=\"shape\" d=\"{{a}}\" fill=\"{{fillFrom}}\" fill-rule=\"evenodd\" stroke=\"{{strokeFrom}}\" stroke-width=\"{{width}}\" stroke-linejoin=\"round\"/></svg>`,\n animate: [\n { id: \"shape\", attrs: { d: [\"{{a}}\", \"{{b}}\"], fill: [\"{{fillFrom}}\", \"{{fillTo}}\"], stroke: [\"{{strokeFrom}}\", \"{{strokeTo}}\"] }, delay: n(\"pause\"), ms: n(\"morph\"), ease: \"in-out\" },\n { id: \"shape\", attrs: { d: [\"{{b}}\", \"{{a}}\"], fill: [\"{{fillTo}}\", \"{{fillFrom}}\"], stroke: [\"{{strokeTo}}\", \"{{strokeFrom}}\"] }, delay: n(\"back\"), ms: n(\"morph\"), ease: \"in-out\" },\n ],\n },\n};\n\n// ── Icon toggle ────────────────────────────────────────────────────────\n\n/** Stroke width of the line icons, in their 24 box. */\nconst LINE = 2.4;\n\n/**\n * Icon pairs in a 24 box, every stroke written as a filled outline so it\n * morphs as a shape. Pieces are laid out to pair up: play's two halves\n * become pause's bars, menu's bars the three strokes of the close cross\n * (which is cut so its strokes do not overlap), the sun's rays shrink away.\n */\nconst ICON_PAIRS: readonly (readonly [string, string])[] = (() => {\n const c = 12;\n // The close cross: one whole diagonal, and the other cut in two where it meets it.\n const meet = LINE / 2 / Math.SQRT2;\n const sun = [circle(c, c, 4.6), ...Array.from({ length: 8 }, (_, k) => {\n const a = k * 45 * DEG;\n return stroke([[c + 7.6 * Math.cos(a), c + 7.6 * Math.sin(a)], [c + 10 * Math.cos(a), c + 10 * Math.sin(a)]], 2);\n })];\n return [\n [\n \"M7.5 4.5 L13.5 8.32 L13.5 15.68 L7.5 19.5 Z M13.5 8.32 L19.3 12 L13.5 15.68 Z\",\n [stroke([[8.5, 6.5], [8.5, 17.5]], 3.6), stroke([[15.5, 6.5], [15.5, 17.5]], 3.6)].join(\" \"),\n ],\n [\n [7, 12, 17].map((y) => stroke([[5, y], [19, y]], LINE)).join(\" \"),\n [\n stroke([[6.5, 6.5], [17.5, 17.5]], LINE),\n stroke([[17.5, 6.5], [c + meet, c - meet]], LINE, { end: true }),\n stroke([[6.5, 17.5], [c - meet, c + meet]], LINE, { end: true }),\n ].join(\" \"),\n ],\n [\"M10.7 5 H13.3 V10.7 H19 V13.3 H13.3 V19 H10.7 V13.3 H5 V10.7 H10.7 Z\", stroke([[5, 12.5], [10, 17.5], [19, 7]], 2.6)],\n [sun.join(\" \"), crescent([11.5, 12.5], 8.5, [16.5, 7.5], 7)],\n [`${HEART} ${placed(HEART, 12, 12, 0.7)}`, HEART],\n ];\n})();\n\nconst iconMorphs = new Map<number, [string, string]>();\n\n/** A pair's two icons morphed to one structure, worked out once. */\nfunction iconMorph(pair: number): [string, string] {\n if (!iconMorphs.has(pair)) iconMorphs.set(pair, morphPaths(...ICON_PAIRS[pair]!, { points: 64 }));\n return iconMorphs.get(pair)!;\n}\n\n/** The icon group's transform: centred in the button, turned and scaled. */\nconst pose = (turn: number, scale: number) => `translate(60 60) rotate(${turn}) scale(${scale}) translate(-12 -12)`;\n\n/** One toggle at `at` ms: the icon morphs while it dips, turns and pops back, and the button changes colour. */\nconst toggle = (at: number, d: [string, string], fill: [string, string], turn: number): SvgAnimation[] => [\n { id: \"glyph\", attrs: { d }, delay: at, ms: 420, ease: \"in-out\" },\n { id: \"icon\", attrs: { transform: [pose(0, 2.6), pose(turn, 2.15)] }, delay: at, ms: 170, ease: \"out\" },\n { id: \"icon\", attrs: { transform: [pose(turn, 2.15), pose(-turn * 0.3, 2.85)] }, delay: at + 170, ms: 190, ease: \"in-out\" },\n { id: \"icon\", attrs: { transform: [pose(-turn * 0.3, 2.85), pose(0, 2.6)] }, delay: at + 360, ms: 260, ease: \"in-out\" },\n { id: \"button\", attrs: { fill }, delay: at, ms: 320, ease: \"in-out\" },\n];\n\nexport const iconToggle: VectorEffect = {\n kind: \"vector\",\n id: \"icon-toggle\",\n name: \"Icon toggle\",\n description: \"A round button whose icon morphs between two states (play and pause, menu and close, sun and moon) with a little pop.\",\n category: \"morph\",\n tags: [\"morph\", \"icon\", \"ui\", \"button\", \"toggle\", \"micro-interaction\"],\n hold: 700,\n presets: [\n { name: \"Play / pause\", values: { pair: 0 } },\n { name: \"Menu / close\", values: { pair: 1, off: [0.98, 0.98, 0.98], on: [0.07, 0.07, 0.09], ink: [0.4, 0.4, 0.45], page: [0.9, 0.91, 0.93] } },\n { name: \"Plus / check\", values: { pair: 2, on: [0.13, 0.77, 0.37] } },\n { name: \"Day / night\", values: { pair: 3, off: [0.98, 0.75, 0.14], on: [0.19, 0.18, 0.5], page: [0.06, 0.07, 0.15] } },\n { name: \"Like\", values: { pair: 4, off: [0.12, 0.12, 0.14], on: [0.94, 0.27, 0.4] } },\n ],\n derived: (v) => {\n const [a, b] = iconMorph(Math.min(ICON_PAIRS.length - 1, Math.max(0, Math.round(Number(v.pair)) || 0)));\n return { a, b };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{pair: int min=0 max=4 default=0 label='Icons (play, menu, plus, sun, heart)'}} {{ink: color default=#FFFFFF label='Icon'}} {{off: color default=#334155 label='Button'}} {{on: color default=#6366F1 label='Button (on)'}} {{page: color default=#0B1020 label='Background'}} --><rect width=\"120\" height=\"120\" fill=\"{{page}}\"/><circle id=\"button\" cx=\"60\" cy=\"60\" r=\"44\" fill=\"{{off}}\"/><g id=\"icon\" transform=\"${pose(0, 2.6)}\"><path id=\"glyph\" d=\"{{a}}\" fill=\"{{ink}}\" fill-rule=\"evenodd\" stroke=\"{{ink}}\" stroke-width=\"0.3\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [...toggle(500, [\"{{a}}\", \"{{b}}\"], [\"{{off}}\", \"{{on}}\"], -16), ...toggle(2100, [\"{{b}}\", \"{{a}}\"], [\"{{on}}\", \"{{off}}\"], 16)],\n },\n};\n\n// ── Morph sequence ─────────────────────────────────────────────────────\n\n/** Circle, star, heart and hexagon, in a 200 box. */\nconst SEQUENCE = morphSequence(\n [circle(100, 100, 72), star(100, 104, 5, 82, 36), placed(HEART, 100, 98, 8.4), star(100, 100, 3, 78, 78)],\n { points: 96 },\n);\n\nexport const morphSequenceEffect: VectorEffect = {\n kind: \"vector\",\n id: \"morph-sequence\",\n name: \"Morph sequence\",\n description: \"One shape flowing from circle to star to heart to hexagon and round again, its colour changing with each.\",\n category: \"morph\",\n tags: [\"morph\", \"shape\", \"loop\", \"background\", \"playful\"],\n hold: 0,\n presets: [\n { name: \"Pastel\", values: { background: [0.99, 0.97, 0.94], c0: [0.65, 0.84, 0.98], c1: [0.99, 0.85, 0.55], c2: [0.98, 0.65, 0.7], c3: [0.75, 0.7, 0.98] } },\n { name: \"Mono\", values: { background: [0.04, 0.04, 0.05], c0: [0.95, 0.95, 0.95], c1: [0.95, 0.95, 0.95], c2: [0.95, 0.95, 0.95], c3: [0.95, 0.95, 0.95], morph: 600, pause: 300 } },\n ],\n derived: (v) => {\n const each = Number(v.morph) + Number(v.pause);\n return Object.fromEntries(SEQUENCE.map((_, i) => [`at${i}`, Number(v.pause) + i * each]));\n },\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{c0: color default=#38BDF8 label='Circle'}} {{c1: color default=#FACC15 label='Star'}} {{c2: color default=#F43F5E label='Heart'}} {{c3: color default=#A78BFA label='Hexagon'}} {{background: color default=#0F172A label='Background'}} {{morph: float min=200 max=3000 default=900 step=50 label='Morph ms'}} {{pause: float min=0 max=3000 default=500 step=50 label='Pause ms'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><path id=\"shape\" d=\"${SEQUENCE[0]}\" fill=\"{{c0}}\" fill-rule=\"evenodd\"/></svg>`,\n animate: SEQUENCE.map((d, i): SvgAnimation => {\n const next = (i + 1) % SEQUENCE.length;\n return { id: \"shape\", attrs: { d: [d, SEQUENCE[next]!], fill: [`{{c${i}}}`, `{{c${next}}}`] }, delay: n(`at${i}`), ms: n(\"morph\"), ease: \"in-out\" };\n }),\n },\n};\n\n// ── Gooey morph ────────────────────────────────────────────────────────\n\n/**\n * A cluster of drops, a star whose arms reach where the drops were, and two\n * blobs, in a 200 box. Each piece is its own path (overlapping pieces in one\n * evenodd path would cut holes), and the goo filter melts them together.\n */\nconst GOO = (() => {\n const cluster = [\n circle(100, 100, 25),\n ...Array.from({ length: 5 }, (_, k) => circle(100 + 56 * Math.cos((-90 + 72 * k) * DEG), 100 + 56 * Math.sin((-90 + 72 * k) * DEG), 15)),\n ].join(\" \");\n const blobStar = polyline(\n arc(100, 100, 1, 1, -90, 270, 4).slice(0, -1).map((p): Point => {\n const a = Math.atan2(p[1] - 100, p[0] - 100);\n const r = 50 + 20 * Math.cos(5 * (a + Math.PI / 2));\n return [100 + r * Math.cos(a), 100 + r * Math.sin(a)];\n }),\n true,\n );\n const pair = `${circle(63, 100, 35)} ${circle(137, 100, 35)}`;\n // Each stage's pieces, one path each.\n const stages = morphSequence([cluster, blobStar, pair], { points: 64 }).map((d) => d.split(/ (?=M)/));\n return stages[0]!.map((_, piece) => stages.map((stage) => stage[piece]!));\n})();\n\nexport const gooeyMorph: VectorEffect = {\n kind: \"vector\",\n id: \"gooey-morph\",\n name: \"Gooey morph\",\n description: \"A cluster of liquid drops melting into a star, splitting into two blobs and beading back into drops.\",\n category: \"morph\",\n tags: [\"morph\", \"gooey\", \"liquid\", \"metaball\", \"blob\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Lava\", values: { colorA: [1, 0.85, 0.2], colorB: [0.95, 0.2, 0.1], background: [0.1, 0.02, 0.02] } },\n { name: \"Slime\", values: { colorA: [0.75, 1, 0.3], colorB: [0.1, 0.7, 0.35], background: [0.03, 0.08, 0.05], goo: 9 } },\n { name: \"Ink\", values: { colorA: [0.1, 0.1, 0.12], colorB: [0.1, 0.1, 0.12], background: [0.97, 0.96, 0.93] } },\n ],\n derived: (v) => {\n const each = Number(v.morph) + Number(v.pause);\n return { ...Object.fromEntries(GOO[0]!.map((_, i) => [`at${i}`, Number(v.pause) + i * each])), threshold: -0.5 * Number(v.sharp) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{colorA: color default=#22D3EE label='Colour A'}} {{colorB: color default=#A855F7 label='Colour B'}} {{background: color default=#0B0B1A label='Background'}} {{goo: float min=1 max=14 default=7 step=0.5 label='Gooeyness'}} {{sharp: float min=8 max=40 default=20 step=1 label='Edge sharpness'}} {{morph: float min=300 max=3000 default=1200 step=50 label='Morph ms'}} {{pause: float min=0 max=3000 default=400 step=50 label='Pause ms'}} --><defs><linearGradient id=\"gooFill\" gradientUnits=\"userSpaceOnUse\" x1=\"30\" y1=\"30\" x2=\"170\" y2=\"170\"><stop offset=\"0\" stop-color=\"{{colorA}}\"/><stop offset=\"1\" stop-color=\"{{colorB}}\"/></linearGradient><filter id=\"goo\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{goo}}\" result=\"soft\"/><feColorMatrix in=\"soft\" type=\"matrix\" values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 {{sharp}} {{threshold}}\"/></filter></defs><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><g filter=\"url(#goo)\" fill=\"url(#gooFill)\">${GOO.map((stages, i) => `<path id=\"goo${i}\" d=\"${stages[0]}\" fill-rule=\"evenodd\"/>`).join(\"\")}</g></svg>`,\n animate: GOO.flatMap((stages, i) =>\n stages.map((d, s): SvgAnimation => ({ id: `goo${i}`, attrs: { d: [d, stages[(s + 1) % stages.length]!] }, delay: n(`at${s}`), ms: n(\"morph\"), ease: \"in-out\" })),\n ),\n },\n};\n\n// ── Particle morph ─────────────────────────────────────────────────────\n\n/** Particle morph's dots: one element each, whatever the shapes. */\nconst DOTS = 48;\n/** Ms between one dot setting off and the next. */\nconst DOT_STAGGER = 14;\nconst PARTICLE_FROM = HEART;\nconst PARTICLE_TO = star(12, 12, 5, 10, 4.2);\n\n/** A repeatable 0–1 number for dot `i`. */\nconst noise = (i: number) => {\n const x = Math.sin(i * 12.9898 + 4.1414) * 43758.5453;\n return x - Math.floor(x);\n};\n\nexport const particleMorph: VectorEffect = {\n kind: \"vector\",\n id: \"particle-morph\",\n name: \"Particle morph\",\n description: \"A shape bursting into dots along its outline that swirl across and settle into a second shape, then back.\",\n category: \"morph\",\n tags: [\"morph\", \"particles\", \"dots\", \"shape\", \"logo\", \"reveal\"],\n hold: 600,\n presets: [\n { name: \"Confetti\", values: { background: [1, 0.98, 0.95], fromColor: [0.93, 0.27, 0.6], toColor: [0.15, 0.55, 0.95], ghost: 0.1, size: 3.2 } },\n { name: \"Embers\", values: { background: [0.05, 0.02, 0.02], fromColor: [1, 0.85, 0.3], toColor: [1, 0.3, 0.1], scatter: 50, size: 2 } },\n { name: \"Circle to square\", values: { from: \"M12 2 A10 10 0 1 1 12 22 A10 10 0 1 1 12 2 Z\", to: \"M3 3 H21 V21 H3 Z\" } },\n ],\n // The dots sit on the morphed outlines: point k of one shape flies to point k of the other.\n derived: (v) => {\n const box = [40, 40, 120, 120] as const;\n const [a, b] = morphPaths(fittedOr(v.from, PARTICLE_FROM, box, 96), fittedOr(v.to, PARTICLE_TO, box, 96), { points: DOTS });\n const [pa, pb] = [pointsOf(a), pointsOf(b)];\n const out: Record<string, string | number> = { a, b };\n const scatter = Number(v.scatter);\n for (let i = 0; i < DOTS; i++) {\n // The same share of the outline in shapes of several pieces.\n const k = Math.floor((i * pa.length) / DOTS);\n const [p, q] = [pa[k]!, pb[k]!];\n out[`ax${i}`] = r2(p[0]);\n out[`ay${i}`] = r2(p[1]);\n out[`bx${i}`] = r2(q[0]);\n out[`by${i}`] = r2(q[1]);\n // Halfway, thrown off to one side: a different way out and back.\n for (const [name, seed] of [[\"s\", i], [\"t\", i + DOTS]] as const) {\n const angle = seed * 2.39996;\n const far = scatter * (0.45 + 0.55 * noise(seed));\n out[`${name}x${i}`] = r2((p[0] + q[0]) / 2 + far * Math.cos(angle));\n out[`${name}y${i}`] = r2((p[1] + q[1]) / 2 + far * Math.sin(angle));\n }\n }\n return out;\n },\n motion: (() => {\n const back = 3000;\n const spread = DOTS * DOT_STAGGER;\n const leg = (i: number, at: number, from: string, mid: string, to: string, colours: [string, string]): SvgAnimation[] => [\n { id: `p${i}`, attrs: { cx: [n(`${from}x${i}`), n(`${mid}x${i}`)], cy: [n(`${from}y${i}`), n(`${mid}y${i}`)] }, delay: at + i * DOT_STAGGER, ms: 450, ease: \"out\" },\n { id: `p${i}`, attrs: { cx: [n(`${mid}x${i}`), n(`${to}x${i}`)], cy: [n(`${mid}y${i}`), n(`${to}y${i}`)], fill: colours }, delay: at + 450 + i * DOT_STAGGER, ms: 650, ease: \"in-out\" },\n ];\n const fade = (id: string, at: number, show: boolean): SvgAnimation => ({ id, attrs: { opacity: show ? [0, n(\"ghost\")] : [n(\"ghost\"), 0] }, delay: at, ms: 450, ease: \"in-out\" });\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{from: text default='${PARTICLE_FROM}' label='From path'}} {{to: text default='${PARTICLE_TO}' label='To path'}} {{fromColor: color default=#F472B6 label='From colour'}} {{toColor: color default=#FBBF24 label='To colour'}} {{background: color default=#0C0A1D label='Background'}} {{size: float min=0.8 max=6 default=2.6 step=0.1 label='Dot size'}} {{scatter: float min=0 max=80 default=34 step=1 label='Scatter'}} {{ghost: float min=0 max=1 default=0.16 label='Shape fill'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><path id=\"ghostA\" d=\"{{a}}\" fill=\"{{fromColor}}\" fill-rule=\"evenodd\" opacity=\"{{ghost}}\"/><path id=\"ghostB\" d=\"{{b}}\" fill=\"{{toColor}}\" fill-rule=\"evenodd\" opacity=\"0\"/>${Array.from(\n { length: DOTS },\n (_, i) => `<circle id=\"p${i}\" cx=\"{{ax${i}}}\" cy=\"{{ay${i}}}\" r=\"{{size}}\" fill=\"{{fromColor}}\"/>`,\n ).join(\"\")}</svg>`,\n animate: [\n fade(\"ghostA\", 400, false),\n fade(\"ghostB\", 400 + spread + 900, true),\n fade(\"ghostB\", back, false),\n fade(\"ghostA\", back + spread + 900, true),\n ...Array.from({ length: DOTS }, (_, i) => [\n ...leg(i, 400, \"a\", \"s\", \"b\", [\"{{fromColor}}\", \"{{toColor}}\"]),\n ...leg(i, back, \"b\", \"t\", \"a\", [\"{{toColor}}\", \"{{fromColor}}\"]),\n ]).flat(),\n ],\n };\n })(),\n};\n\n// ── Digit morph ────────────────────────────────────────────────────────\n\n/**\n * The digits 0–9 as pen strokes in a 20 × 32 box, drawn with a round-capped\n * stroke rather than filled: an open stroke morphs as an outline going there\n * and back, which a stroke draws as the line itself.\n */\nconst DIGITS: readonly string[] = (() => {\n const six: Point[] = [...arc(17, 22, 14, 19, 245, 180), ...arc(10, 22, 7, 7, 180, 540).slice(1)];\n return [\n polyline(arc(10, 16, 7, 13, 0, 360).slice(0, -1), true),\n polyline([[5.5, 8], [11, 3], [11, 29]]),\n polyline([...arc(10, 9.5, 6.5, 6.5, 200, 380), [3.5, 29], [17, 29]]),\n polyline([...arc(10, 9, 6, 6, 215, 450), ...arc(10, 21.5, 7, 6.5, 270, 495).slice(1)]),\n polyline([[14, 29], [14, 3], [3, 20.5], [18, 20.5]]),\n polyline([[16.5, 3], [5.5, 3], [4.6, 14.6], ...arc(10.5, 21.2, 6.8, 7, 218, 500)]),\n polyline(six),\n polyline([[3, 3], [17, 3], [8, 29]]),\n polyline([...arc(10, 9.5, 5.5, 5.5, 90, 450), ...arc(10, 22, 7, 7, 270, 630).slice(1)]),\n polyline(six.map((p): Point => [20 - p[0], 32 - p[1]])),\n ];\n})();\n\n/** A slot with no digit: a point, hidden. */\nconst BLANK = \"M10 16 L10 16\";\n/** Digit slots: numbers up to 9999. */\nconst SLOTS = 4;\n/** At most this many morphs from one number to the other; bigger jumps skip numbers between. */\nconst MAX_STEPS = 8;\n/** Ms each number rests before the next morph. */\nconst DIGIT_REST = 260;\n\nexport const digitMorph: VectorEffect = {\n kind: \"vector\",\n id: \"digit-morph\",\n name: \"Digit morph\",\n description: \"A number counting from one value to another, each digit's stroke bending smoothly into the next.\",\n category: \"morph\",\n tags: [\"morph\", \"number\", \"counter\", \"countdown\", \"kpi\", \"digits\"],\n hold: 900,\n presets: [\n { name: \"Countdown\", values: { from: 10, to: 0, ink: [1, 0.36, 0.3] } },\n { name: \"New year\", values: { from: 2025, to: 2026, morph: 700, background: [0.04, 0.03, 0.1], ink: [1, 0.84, 0.4] } },\n { name: \"Thin\", values: { weight: 1.4, background: [0.98, 0.98, 0.97], ink: [0.1, 0.1, 0.12] } },\n ],\n derived: (v) => {\n const from = Math.round(Number(v.from)) || 0;\n const to = Math.round(Number(v.to)) || 0;\n const steps = Math.min(MAX_STEPS, Math.abs(to - from));\n const values = Array.from({ length: steps + 1 }, (_, k) => Math.round(from + ((to - from) * k) / Math.max(1, steps)));\n const used = Math.max(1, ...values.map((x) => String(x).length));\n // Slots centred in the picture, the last one the units.\n const scale = Math.min(4.2, 340 / (used * 22 - 2));\n const left = 200 - ((used * 22 - 2) * scale) / 2;\n const interval = Number(v.morph) + DIGIT_REST;\n const lastEnd = Math.max(0, steps - 1) * interval + Number(v.morph);\n const out: Record<string, string | number> = { scale: r2(scale), y: r2(100 - 16 * scale), back: lastEnd + DIGIT_REST * 3 };\n for (let k = 1; k <= MAX_STEPS; k++) out[`t${k}`] = k <= steps ? (k - 1) * interval : lastEnd;\n for (let j = 0; j < SLOTS; j++) {\n const place = j - (SLOTS - used);\n out[`x${j}`] = r2(left + Math.max(0, place) * 22 * scale);\n // The digit each number shows in this slot, right-aligned; none in a slot the number does not reach.\n const glyphs = values.map((x) => {\n const text = String(x);\n const at = text.length - (used - place);\n return place >= 0 && at >= 0 ? Number(text[at]) : -1;\n });\n const paths = morphSequence(glyphs.map((g) => (g < 0 ? BLANK : DIGITS[g]!)), { points: 64 });\n for (let k = 0; k <= MAX_STEPS; k++) {\n const s = Math.min(k, steps);\n out[`d${j}_${k}`] = paths[s]!;\n out[`o${j}_${k}`] = glyphs[s]! < 0 ? 0 : 1;\n }\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{from: int min=0 max=9999 default=12 label='From'}} {{to: int min=0 max=9999 default=20 label='To'}} {{ink: color default=#F8FAFC label='Digits'}} {{background: color default=#111827 label='Background'}} {{weight: float min=0.8 max=5 default=2.8 step=0.1 label='Weight'}} {{morph: float min=150 max=1500 default=420 step=10 label='Morph ms'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/>${Array.from(\n { length: SLOTS },\n (_, j) =>\n `<path id=\"s${j}\" d=\"{{d${j}_0}}\" opacity=\"{{o${j}_0}}\" transform=\"translate({{x${j}}} {{y}}) scale({{scale}})\" fill=\"none\" fill-rule=\"evenodd\" stroke=\"{{ink}}\" stroke-width=\"{{weight}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`,\n ).join(\"\")}</svg>`,\n animate: Array.from({ length: SLOTS }, (_, j): SvgAnimation[] => [\n ...Array.from({ length: MAX_STEPS }, (_, i): SvgAnimation => {\n const k = i + 1;\n return { id: `s${j}`, attrs: { d: [`{{d${j}_${k - 1}}}`, `{{d${j}_${k}}}`], opacity: [n(`o${j}_${k - 1}`), n(`o${j}_${k}`)] }, delay: n(`t${k}`), ms: n(\"morph\"), ease: \"in-out\" };\n }),\n // Back to the first number in one morph, so it loops.\n { id: `s${j}`, attrs: { d: [`{{d${j}_${MAX_STEPS}}}`, `{{d${j}_0}}`], opacity: [n(`o${j}_${MAX_STEPS}`), n(`o${j}_0`)] }, delay: n(\"back\"), ms: n(\"morph\"), ease: \"in-out\" },\n ]).flat(),\n },\n};\n\n/** Vector effects that turn one shape into another (see `morphPaths`). */\nexport const morphEffects: VectorEffect[] = [shapeMorph, iconToggle, morphSequenceEffect, gooeyMorph, particleMorph, digitMorph];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * These read the pointer built-ins the wrapper declares: `iPointer` (xy\n * pixels, z how hovered 0–1, w seconds held) and `iClicks[8]` (newest first:\n * xy pixels, z the `iTime` of the click, w 1 for a click). Thumbnails and\n * recordings have no pointer, so each one plays a gentle demo while idle,\n * which a `uDemo` control turns off.\n */\n\n/**\n * `clickAt(i, demo)`: click `i`, newest first, as (x, y, time, 1), or zeros\n * for none. With the demo on and no real clicks yet, a synthetic click lands\n * every 2 s at a pseudo-random spot (needs {@link HASH}).\n */\nconst CLICKS = `\nvec4 clickAt(int i, bool demo) {\n if (!demo || iClicks[0].w > 0.5) return iClicks[i];\n float k = floor(iTime / 2.0) - float(i);\n vec2 h = hash22(vec2(k * 1.37 + 0.5, 3.7));\n return vec4((0.15 + 0.7 * h) * iResolution.xy, k * 2.0, 1.0);\n}`.trim();\n\n/**\n * `hoverPoint(demo, idle)`: the point hover effects follow, in pixels, and\n * how strongly they answer it (z): the pointer while it is over the canvas,\n * else (with the demo on) a slow Lissajous drift at strength `idle`.\n */\nconst HOVER = `\nvec3 hoverPoint(bool demo, float idle) {\n vec2 drift = iResolution.xy * (0.5 + vec2(0.28 * sin(iTime * 0.63), 0.22 * sin(iTime * 0.91 + 1.3)));\n float h = clamp(iPointer.z, 0.0, 1.0);\n return vec3(mix(drift, iPointer.xy, h), mix(demo ? idle : 0.0, 1.0, h));\n}`.trim();\n\n/** `glow(c)`: light as a colour over whatever is behind it (alpha is its brightest channel). */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/** `over(acc, colour, alpha)` onto a premultiplied accumulator; `unpremultiply(acc)` for the output. */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\nexport const clickRipple: ShaderEffect = {\n kind: \"shader\",\n id: \"click-ripple\",\n name: \"Click ripple\",\n description: \"Rings of water spreading out from every click and fading as they go.\",\n category: \"interaction\",\n tags: [\"interactive\", \"click\", \"overlay\", \"water\", \"ripple\"],\n transparent: true,\n source: glsl(\n `// Click ripple: water rings spreading from each click (up to 8 at once).\nuniform vec3 uColor; // @control color default=#BFE6FF label=\"Colour\"\nuniform float uSpeed; // @control min=0.05 max=2 default=0.5 label=\"Speed\"\nuniform float uWidth; // @control min=0.002 max=0.05 default=0.012 label=\"Ring width\"\nuniform float uLife; // @control min=0.3 max=6 default=2 label=\"Lifetime\"\nuniform int uRings; // @control min=1 max=4 default=3 label=\"Rings per click\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n CLICKS,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec4 acc = vec4(0.0);\n for (int i = 7; i >= 0; i--) {\n vec4 c = clickAt(i, uDemo);\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > uLife) continue;\n float life = age / uLife;\n float fade = (1.0 - life) * (1.0 - life);\n float d = length(fragCoord - c.xy) * px;\n for (int j = 0; j < 4; j++) {\n if (j >= uRings) break;\n float r = (age - float(j) * 0.16) * uSpeed;\n if (r <= 0.0) continue;\n // Rings widen and soften as they spread.\n float w = max(uWidth * (1.0 + life * 1.5), 1.5 * px);\n float x = (d - r) / w;\n float k = fade * (1.0 - 0.28 * float(j)) * smoothstep(0.0, 0.05, r);\n // A bright crest with a darker trough just inside it.\n float crest = exp(-x * x * 2.0);\n float trough = exp(-(x + 1.6) * (x + 1.6) * 2.0);\n acc = over(acc, uColor * 0.15, trough * k * 0.35);\n acc = over(acc, mix(uColor, vec3(1.0), 0.5 * crest), crest * k);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Sonar\", values: { uColor: [0.3, 1, 0.6], uSpeed: 0.3, uWidth: 0.006, uLife: 4, uRings: 4 } },\n { name: \"Raindrop\", values: { uColor: [1, 1, 1], uSpeed: 0.8, uWidth: 0.02, uLife: 1.2, uRings: 2 } },\n ],\n};\n\nexport const clickBurst: ShaderEffect = {\n kind: \"shader\",\n id: \"click-burst\",\n name: \"Click burst\",\n description: \"Sparks or confetti bursting out of every click, falling under gravity as they fade.\",\n category: \"interaction\",\n tags: [\"interactive\", \"click\", \"overlay\", \"particles\", \"celebration\", \"confetti\"],\n transparent: true,\n source: glsl(\n `// Click burst: sparks (or confetti) thrown out of each click, slowed by drag and pulled down by gravity.\nuniform vec3 uColorA; // @control color default=#FFD166 label=\"Colour 1\"\nuniform vec3 uColorB; // @control color default=#EF476F label=\"Colour 2\"\nuniform vec3 uColorC; // @control color default=#06D6A0 label=\"Colour 3\"\nuniform int uCount; // @control min=4 max=48 default=24 label=\"Count\"\nuniform float uSpread; // @control min=0.1 max=2 default=0.8 label=\"Spread\"\nuniform float uGravity; // @control min=0 max=3 default=1 label=\"Gravity\"\nuniform float uLife; // @control min=0.4 max=4 default=1.6 label=\"Lifetime\"\nuniform bool uConfetti; // @control default=false label=\"Confetti\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n CLICKS,\n OVER,\n `float segment(vec2 p, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float t = clamp(dot(p - a, ab) / max(dot(ab, ab), 1e-8), 0.0, 1.0);\n return length(p - a - ab * t);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n const float drag = 2.5;\n vec4 acc = vec4(0.0);\n for (int i = 7; i >= 0; i--) {\n vec4 c = clickAt(i, uDemo);\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > uLife) continue;\n float life = age / uLife;\n vec2 origin = c.xy * px;\n // A quick flash where it landed.\n float flash = exp(-age * 18.0) * exp(-dot(p - origin, p - origin) / 0.002);\n acc = over(acc, vec3(1.0), clamp(flash, 0.0, 1.0));\n float slow = (1.0 - exp(-drag * age)) / drag;\n for (int j = 0; j < 48; j++) {\n if (j >= uCount) break;\n vec2 h = hash22(vec2(float(j) * 7.13 + 1.0, c.z * 3.1 + float(i)));\n float h3 = hash12(h * 91.7 + c.z);\n float angle = h.x * 6.28318;\n vec2 v0 = vec2(cos(angle), sin(angle)) * uSpread * (0.3 + 0.7 * h.y) + vec2(0.0, uSpread * 0.35);\n vec2 pos = origin + v0 * slow - vec2(0.0, 0.5 * uGravity * 0.6 * age * age);\n if (abs(p.x - pos.x) > 0.06 || abs(p.y - pos.y) > 0.06) continue;\n vec3 col = h3 < 0.333 ? uColorA : (h3 < 0.667 ? uColorB : uColorC);\n float a;\n if (uConfetti) {\n // A tumbling paper rectangle.\n float spin = (h3 - 0.5) * 20.0 * age + angle;\n float cs = cos(spin);\n float sn = sin(spin);\n vec2 q = mat2(cs, sn, -sn, cs) * (p - pos);\n vec2 size = vec2(0.011, 0.006 * abs(cos(age * (4.0 + 6.0 * h.y) + h.x * 9.0)) + px);\n vec2 e = abs(q) - size;\n float sd = length(max(e, 0.0)) + min(max(e.x, e.y), 0.0);\n a = (1.0 - smoothstep(-px, px, sd)) * (1.0 - smoothstep(0.7, 1.0, life));\n col *= 0.75 + 0.25 * cs;\n } else {\n // A streak along its velocity, with a white-hot core.\n vec2 v = v0 * exp(-drag * age) - vec2(0.0, uGravity * 0.6 * age);\n float r = 0.004 * (1.0 - 0.6 * life) + px;\n float sd = segment(p, pos, pos - v * 0.05) - r;\n a = (1.0 - smoothstep(-px, px, sd)) * (1.0 - life);\n a += exp(-max(sd, 0.0) / (r * 2.0)) * 0.35 * (1.0 - life);\n col = mix(col, vec3(1.0), exp(-max(sd + r, 0.0) / (r * 0.5)) * 0.6);\n }\n acc = over(acc, col, clamp(a, 0.0, 1.0));\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Confetti\", values: { uConfetti: true, uCount: 36, uSpread: 1, uGravity: 1.4, uLife: 2.5, uColorC: [0.3, 0.55, 1] } },\n { name: \"Embers\", values: { uColorA: [1, 0.6, 0.15], uColorB: [1, 0.3, 0.1], uColorC: [1, 0.85, 0.5], uCount: 16, uSpread: 0.5, uGravity: 0.2 } },\n ],\n};\n\nexport const cursorGlow: ShaderEffect = {\n kind: \"shader\",\n id: \"cursor-glow\",\n name: \"Cursor glow\",\n description: \"A soft light following the pointer, with a halo ring that tightens while it is pressed.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"press\", \"overlay\", \"glow\", \"cursor\"],\n transparent: true,\n source: glsl(\n `// Cursor glow: a soft light at the pointer, scaled by how hovered, with a halo that tightens while pressed.\nuniform vec3 uColor; // @control color default=#7DD3FC label=\"Colour\"\nuniform float uRadius; // @control min=0.03 max=0.6 default=0.18 label=\"Radius\"\nuniform float uIntensity; // @control min=0 max=3 default=1.2 label=\"Intensity\"\nuniform float uHalo; // @control min=0 max=1 default=0.7 label=\"Halo\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HOVER,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec3 hp = hoverPoint(uDemo, 0.7);\n float d = length(fragCoord - hp.xy) / iResolution.y;\n // How pressed: eases in while held; the idle demo pulses it.\n float press = 1.0 - exp(-max(iPointer.w, 0.0) * 4.0);\n if (uDemo) press = max(press, (1.0 - iPointer.z) * pow(max(sin(iTime * 1.3), 0.0), 3.0));\n float light = exp(-pow(d / uRadius, 2.0) * 2.0) * uIntensity * hp.z * (1.0 + 0.6 * press);\n float ringR = uRadius * mix(1.3, 0.55, press);\n float ringW = max(uRadius * 0.05, 1.5 / iResolution.y);\n float ring = exp(-pow((d - ringR) / ringW, 2.0)) * uHalo * hp.z * (0.6 + 0.8 * press);\n fragColor = glow(uColor * light + mix(uColor, vec3(1.0), 0.5) * ring * 1.5);\n}`,\n ),\n presets: [\n { name: \"Spotlight\", values: { uColor: [1, 0.95, 0.85], uRadius: 0.4, uIntensity: 0.8, uHalo: 0 } },\n { name: \"Neon\", values: { uColor: [1, 0.2, 0.75], uRadius: 0.1, uIntensity: 2, uHalo: 1 } },\n ],\n};\n\nexport const hoverLiquid: ShaderEffect = {\n kind: \"shader\",\n id: \"hover-liquid\",\n name: \"Liquid hover\",\n description: \"An image that swells and ripples like liquid around the pointer while it hovers.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"image\", \"liquid\", \"distortion\"],\n source: glsl(\n `// Liquid hover: an image bulging and rippling around the pointer, as strongly as it is hovered.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uStrength; // @control min=0 max=1 default=0.6 label=\"Strength\"\nuniform float uRadius; // @control min=0.05 max=0.8 default=0.3 label=\"Radius\"\nuniform float uWobble; // @control min=0 max=1 default=0.5 label=\"Wobble\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec3 hp = hoverPoint(uDemo, 0.5);\n vec2 d = (fragCoord - hp.xy) / iResolution.y;\n float r = length(d);\n float s = uStrength * hp.z;\n float fall = exp(-pow(r / uRadius, 2.0) * 1.5);\n // Swell: pull samples towards the pointer, so it magnifies like a drop.\n vec2 off = -d * fall * s * 0.6;\n // Wobble: rings running out from the pointer and a slow liquid churn.\n vec2 dir = d / max(r, 1e-5);\n float wave = sin(r / uRadius * 14.0 - iTime * 5.0) * fall;\n off += dir * wave * uWobble * s * 0.02;\n vec2 churn = vec2(vnoise(d * 6.0 + iTime * 0.7), vnoise(d * 6.0 - iTime * 0.6 + 5.0)) - 0.5;\n off += churn * fall * s * uWobble * 0.05;\n vec4 pic = pictureRGBA(uImage, uv + off * vec2(iResolution.y / iResolution.x, 1.0));\n // Light catching the swell's upper-left slope.\n float slope = dot(dir, normalize(vec2(-0.6, 0.8))) * r / uRadius;\n vec3 col = pic.rgb + 0.12 * s * fall * slope + 0.06 * s * wave * uWobble;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Syrup\", values: { uStrength: 0.9, uRadius: 0.45, uWobble: 0.15 } },\n { name: \"Splash\", values: { uStrength: 0.5, uRadius: 0.25, uWobble: 1 } },\n ],\n};\n\nexport const hoverReveal: ShaderEffect = {\n kind: \"shader\",\n id: \"hover-reveal\",\n name: \"X-ray reveal\",\n description: \"A second image showing through a soft lens around the pointer that grows as it hovers and pulses on click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"click\", \"image\", \"reveal\", \"x-ray\"],\n source: glsl(\n `// X-ray reveal: a second image seen through a soft lens at the pointer.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform sampler2D uReveal; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Revealed image\"\nuniform float uRadius; // @control min=0.05 max=0.6 default=0.22 label=\"Lens radius\"\nuniform float uSoftness; // @control min=0 max=1 default=0.35 label=\"Softness\"\nuniform vec3 uRim; // @control color default=#A5F3FC label=\"Rim\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n CLICKS,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float px = 1.0 / iResolution.y;\n vec3 hp = hoverPoint(uDemo, 0.85);\n // Each click swells the lens, which settles back.\n float pulse = 0.0;\n for (int i = 0; i < 8; i++) {\n vec4 c = clickAt(i, uDemo);\n float age = iTime - c.z;\n if (c.w < 0.5 || age < 0.0) continue;\n pulse += 0.6 * exp(-age * 4.0) * (1.0 - exp(-age * 30.0));\n }\n float R = uRadius * hp.z * (1.0 + pulse);\n float d = length(fragCoord - hp.xy) * px;\n // A wobbly edge, so the lens looks like it is melting through.\n d += (vnoise(fragCoord * px * 9.0 + iTime * 0.6) - 0.5) * 0.25 * R;\n float soft = max(uSoftness * R * 0.6, 1.5 * px);\n float m = 1.0 - smoothstep(R - soft, R, d);\n vec4 pic = mix(pictureRGBA(uImage, uv), pictureRGBA(uReveal, uv), m);\n float rim = exp(-pow((d - R + soft * 0.5) / max(soft * 0.5, 2.0 * px), 2.0)) * step(0.001, R);\n // The rim is light added over the picture, so it also shows where the picture is clear.\n float alpha = max(pic.a, clamp(rim * 0.6, 0.0, 1.0));\n fragColor = vec4((pic.rgb * pic.a + uRim * rim * 0.6) / max(alpha, 1e-4), alpha);\n}`,\n ),\n presets: [\n { name: \"Peephole\", values: { uRadius: 0.12, uSoftness: 0.05, uRim: [1, 1, 1] } },\n { name: \"Fog lamp\", values: { uRadius: 0.4, uSoftness: 1, uRim: [0, 0, 0] } },\n ],\n};\n\nexport const magnifier: ShaderEffect = {\n kind: \"shader\",\n id: \"magnifier\",\n name: \"Magnifier\",\n description: \"A round magnifying glass over an image at the pointer, with a bright rim and a fringe of colour at its edge.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"image\", \"lens\", \"zoom\"],\n source: glsl(\n `// Magnifier: a round lens over an image at the pointer, showing while hovered.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uZoom; // @control min=1 max=5 default=2 label=\"Zoom\"\nuniform float uRadius; // @control min=0.05 max=0.5 default=0.18 label=\"Radius\"\nuniform float uAberration; // @control min=0 max=1 default=0.35 label=\"Colour fringe\"\nuniform vec3 uRim; // @control color default=#FFFFFF label=\"Rim\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec3 hp = hoverPoint(uDemo, 1.0);\n float s = hp.z;\n vec4 col = pictureRGBA(uImage, uv);\n float R = uRadius * (0.75 + 0.25 * s) * iResolution.y;\n vec2 d = fragCoord - hp.xy;\n float r = length(d);\n float k = r / R;\n // A soft shadow under the glass.\n float shadow = 1.0 - smoothstep(R * 0.9, R * 1.3, length(d - vec2(R * 0.08, -R * 0.12)));\n col.rgb *= 1.0 - 0.35 * shadow * s;\n if (k < 1.05) {\n // More magnified at the centre, squeezed towards the rim like real glass.\n vec2 q = d / uZoom * (1.0 + 0.4 * k * k * k * k);\n float fr = uAberration * 0.08 * k * k * k;\n vec4 lr = pictureRGBA(uImage, (hp.xy + q * (1.0 + fr)) / iResolution.xy);\n vec4 lg = pictureRGBA(uImage, (hp.xy + q) / iResolution.xy);\n vec4 lb = pictureRGBA(uImage, (hp.xy + q * (1.0 - fr)) / iResolution.xy);\n vec4 lens = vec4(lr.r, lg.g, lb.b, max(max(lr.a, lg.a), lb.a));\n lens.rgb += 0.16 * exp(-pow(length(d / R - vec2(-0.35, 0.4)) * 2.6, 2.0));\n lens.rgb *= 1.0 - 0.25 * pow(k, 6.0);\n col = mix(col, lens, (1.0 - smoothstep(R - 1.5, R, r)) * s);\n }\n float rimW = max(R * 0.035, 2.0);\n float lit = 0.6 + 0.4 * dot(d / max(r, 1e-4), normalize(vec2(-1.0, 1.0)));\n float rim = exp(-pow((r - R) / rimW, 2.0));\n col = mix(col, vec4(uRim * lit, 1.0), rim * s * 0.9);\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Loupe\", values: { uZoom: 4, uRadius: 0.1, uAberration: 0.1 } },\n { name: \"Fishbowl\", values: { uZoom: 1.5, uRadius: 0.35, uAberration: 1 } },\n ],\n};\n\nexport const holoCard: ShaderEffect = {\n kind: \"shader\",\n id: \"holo-card\",\n name: \"Holo card\",\n description: \"A holographic foil trading card whose rainbow sheen and glare shift as the pointer tilts it.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"card\", \"holographic\", \"foil\", \"iridescent\"],\n transparent: true,\n source: glsl(\n `// Holo card: a rounded card with rainbow foil and glare that move as the pointer tilts it.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uFoil; // @control min=0 max=1 default=0.7 label=\"Foil\"\nuniform float uGlare; // @control min=0 max=1 default=0.6 label=\"Glare\"\nuniform float uTilt; // @control min=0 max=1 default=0.6 label=\"Tilt\"\nuniform float uCorner; // @control min=0 max=0.25 default=0.06 label=\"Corner radius\"\nuniform vec3 uBorder; // @control color default=#E2E8F0 label=\"Border\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n HOVER,\n OVER,\n PICTURE,\n `float roundedBox(vec2 p, vec2 hs, float r) {\n vec2 e = abs(p) - hs + r;\n return length(max(e, 0.0)) + min(max(e.x, e.y), 0.0) - r;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 res = iResolution.xy;\n const float aspect = 0.716;\n float h = min(res.y * 0.84, res.x * 0.84 / aspect);\n vec2 hs = vec2(h * aspect, h) * 0.5;\n vec3 hp = hoverPoint(uDemo, 0.7);\n vec2 tilt = clamp((hp.xy - 0.5 * res) / hs, -1.0, 1.0) * hp.z * uTilt;\n vec2 s = (fragCoord - 0.5 * res) / hs;\n // Fake perspective: the side the pointer is on leans away.\n vec2 q = s / max(1.0 - 0.15 * dot(s, tilt), 0.2);\n float radius = uCorner * hs.x * 2.0;\n float sd = roundedBox(q * hs, hs, radius);\n float mask = 1.0 - smoothstep(-1.0, 1.0, sd);\n // A soft shadow, falling away from the tilt.\n float shadowD = roundedBox(fragCoord - 0.5 * res + tilt * hs * 0.06 + vec2(0.0, h * 0.03), hs, radius);\n float shadow = (1.0 - smoothstep(-h * 0.04, h * 0.06, shadowD)) * 0.35;\n vec4 acc = over(vec4(0.0), vec3(0.0), shadow * (1.0 - mask));\n if (mask > 0.0) {\n vec2 cuv = q * 0.5 + 0.5;\n // The picture fills the card, cropped to fit.\n vec2 ts = vec2(textureSize(uImage, 0));\n float imageAspect = ts.x / max(ts.y, 1.0);\n vec2 fit = imageAspect > aspect ? vec2(aspect / imageAspect, 1.0) : vec2(1.0, imageAspect / aspect);\n vec3 base = picture(uImage, 0.5 + (cuv - 0.5) * fit);\n // Foil: rainbow bands that slide with the tilt, strongest in a broad band facing the light.\n float n = vnoise(cuv * 5.0);\n float phase = dot(cuv, vec2(0.7, 1.1)) * 1.6 + tilt.x * 0.9 - tilt.y * 0.6 + n * 0.5;\n vec3 rainbow = 0.5 + 0.5 * cos(6.28318 * (phase + vec3(0.0, 0.33, 0.67)));\n float lines = 0.75 + 0.25 * sin((cuv.x - cuv.y) * 90.0 + tilt.x * 8.0);\n float band = exp(-pow((cuv.x + cuv.y) * 0.7 - 0.7 - (tilt.x + tilt.y) * 0.6, 2.0) * 6.0);\n float foil = uFoil * (0.25 + 0.75 * band) * lines;\n // Overlay blend, so the picture keeps its darks under the foil.\n vec3 lit = mix(2.0 * base * rainbow, 1.0 - 2.0 * (1.0 - base) * (1.0 - rainbow), step(0.5, base));\n vec3 col = mix(base, lit + rainbow * 0.12, foil * 0.75);\n float sparkle = step(0.985, hash12(floor(cuv * vec2(90.0, 126.0))));\n col += sparkle * uFoil * band * (0.5 + 0.5 * sin(iTime * 3.0 + n * 20.0 + tilt.x * 10.0));\n // Glare: a highlight where the light hits, following the pointer.\n vec2 g = cuv - (0.5 + tilt * 0.55);\n col += uGlare * 0.6 * exp(-dot(g, g) * 7.0);\n // A thin foil border.\n float border = smoothstep(-0.03 * h - 1.0, -0.03 * h, sd);\n col = mix(col, uBorder * (0.8 + 0.4 * rainbow * uFoil), border);\n acc = over(acc, clamp(col, 0.0, 1.0), mask);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Subtle\", values: { uFoil: 0.3, uGlare: 0.35, uTilt: 0.4 } },\n { name: \"Full foil\", values: { uFoil: 1, uGlare: 0.8, uTilt: 1, uBorder: [0.98, 0.82, 0.35] } },\n ],\n};\n\nexport const pressCharge: ShaderEffect = {\n kind: \"shader\",\n id: \"press-charge\",\n name: \"Press to charge\",\n description: \"A ring that fills and glows while the pointer is held and drains when it is let go, bursting if it was fully charged.\",\n category: \"interaction\",\n tags: [\"interactive\", \"press\", \"overlay\", \"hold\", \"button\", \"ring\"],\n transparent: true,\n source: glsl(\n `// Press to charge: a ring that fills while held (iPointer.w > 0), drains when let go (iPointer.w < 0)\n// and bursts if it was let go fully charged.\nuniform vec3 uColor; // @control color default=#A78BFA label=\"Colour\"\nuniform float uHold; // @control min=0.3 max=5 default=1.2 label=\"Seconds to charge\"\nuniform float uSize; // @control min=0.08 max=0.45 default=0.22 label=\"Size\"\nuniform float uThickness; // @control min=0.005 max=0.08 default=0.025 label=\"Thickness\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n // iPointer.w: seconds held while pressed, minus the seconds since letting go after, 0 before any press.\n float w = iPointer.w;\n // The press is the newest click, so this is how long it was held when let go.\n float heldFor = iTime + min(w, 0.0) - iClicks[0].z;\n // Until someone presses, a synthetic press: hold, charge, let go, burst, rest.\n if (uDemo && iClicks[0].w < 0.5 && w == 0.0) {\n float t = mod(iTime, uHold + 2.0) - 0.4;\n float hold = uHold + 0.4;\n w = t <= 0.0 ? 0.0 : (t < hold ? t : -(t - hold));\n heldFor = hold;\n }\n float held = max(w, 0.0);\n float since = max(-w, 0.0);\n float reached = w < 0.0 ? clamp(heldFor / uHold, 0.0, 1.0) : 0.0;\n // While held it fills; once let go it drains from where it got to, over 0.4 s.\n float drain = 1.0 - smoothstep(0.0, 0.4, since);\n float charge = w > 0.0 ? clamp(held / uHold, 0.0, 1.0) : reached * drain;\n float full = step(uHold, held);\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float r = length(p);\n float turn = fract(atan(p.x, p.y) / 6.28318 + 1.0);\n float R = uSize * (1.0 - 0.06 * charge + 0.03 * iPointer.z);\n float ringD = abs(r - R) - uThickness * 0.5;\n float ring = 1.0 - smoothstep(-px, px, ringD);\n vec4 acc = vec4(0.0);\n // The core fills faintly, and the track shows where the charge goes.\n acc = over(acc, uColor, (1.0 - smoothstep(R - px, R + px, r)) * 0.1 * charge);\n acc = over(acc, uColor * 0.6, ring * (0.22 + 0.1 * iPointer.z));\n // The charge: an arc clockwise from the top, glowing brighter as it fills.\n float arcEnd = (charge - turn) * 6.28318 * R / px;\n float arc = ring * clamp(arcEnd + 0.5, 0.0, 1.0) * step(0.001, charge);\n float pulse = 1.0 + full * 0.25 * sin(iTime * 9.0);\n float halo = exp(-max(ringD, 0.0) / (uThickness * 1.5)) * charge * charge * 0.6 * clamp(arcEnd + 0.5, 0.0, 1.0);\n acc = over(acc, uColor, clamp(halo * pulse, 0.0, 1.0));\n acc = over(acc, mix(uColor, vec3(1.0), 0.35 * charge * pulse), arc);\n // A ping when it fills, and a flash with a ring bursting out when let go fully charged.\n float flashAge = -1.0;\n float flashSize = 0.0;\n if (w > 0.0 && held >= uHold) { flashAge = held - uHold; flashSize = 0.5; }\n if (w < 0.0 && reached >= 1.0) { flashAge = since; flashSize = 1.0; }\n if (flashAge >= 0.0 && flashAge < 0.8) {\n float k = 1.0 - flashAge / 0.8;\n float burstR = R + flashAge * 0.6 * flashSize;\n float burst = exp(-pow((r - burstR) / (uThickness * (1.0 + flashAge * 3.0)), 2.0)) * k * k * flashSize;\n acc = over(acc, mix(uColor, vec3(1.0), 0.5), clamp(burst, 0.0, 1.0));\n acc = over(acc, vec3(1.0), exp(-r * r / (R * R * 0.5)) * exp(-flashAge * 6.0) * 0.8 * flashSize);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Hold to confirm\", values: { uColor: [0.95, 0.3, 0.3], uHold: 2, uSize: 0.15, uThickness: 0.015 } },\n { name: \"Power up\", values: { uColor: [0.2, 0.9, 1], uHold: 0.8, uSize: 0.3, uThickness: 0.05 } },\n ],\n};\n\nexport const hoverSwap: ShaderEffect = {\n kind: \"shader\",\n id: \"hover-swap\",\n name: \"Hover swap\",\n description: \"One image burning away into another from the pointer as it hovers, along a glowing ragged edge.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"image\", \"dissolve\", \"transition\"],\n source: glsl(\n `// Hover swap: image A dissolves into image B as hover goes 0 → 1, spreading from the pointer.\nuniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Hover image\"\nuniform vec3 uEdge; // @control color default=#FFB86B label=\"Edge glow\"\nuniform float uEdgeWidth; // @control min=0 max=0.3 default=0.08 label=\"Edge width\"\nuniform float uGrain; // @control min=1 max=20 default=6 label=\"Noise scale\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec3 hp = hoverPoint(uDemo, 0.0);\n float h = clamp(iPointer.z, 0.0, 1.0);\n // Idle, hover swings slowly in and out.\n float demo = uDemo ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 0.9)) : 0.0;\n float progress = mix(demo, 1.0, h);\n // Distance from the pointer, as a share of the way to the farthest corner.\n vec2 o = hp.xy / iResolution.y;\n vec2 size = iResolution.xy / iResolution.y;\n float far = max(max(length(o), length(o - vec2(size.x, 0.0))), max(length(o - vec2(0.0, size.y)), length(o - size)));\n float dist = length(fragCoord / iResolution.y - o) / far;\n float f = 0.65 * dist + 0.35 * fbm(fragCoord / iResolution.y * uGrain, 5);\n float w = max(uEdgeWidth, 0.005);\n float t = progress * (1.0 + w);\n float m = 1.0 - smoothstep(t - w, t, f);\n vec4 col = mix(pictureRGBA(uFrom, uv), pictureRGBA(uTo, uv), m);\n float edge = m * (1.0 - m) * 4.0 * step(0.001, uEdgeWidth);\n fragColor = mix(col, vec4(uEdge, 1.0), edge * 0.85);\n}`,\n ),\n presets: [\n { name: \"Clean cut\", values: { uEdgeWidth: 0.01, uGrain: 2 } },\n { name: \"Embers\", values: { uEdge: [1, 0.35, 0.1], uEdgeWidth: 0.2, uGrain: 14 } },\n ],\n};\n\n/** Shaders that answer the pointer: hovers, presses and clicks (`iPointer`, `iClicks`). */\nexport const interactionShaders: ShaderEffect[] = [\n clickRipple,\n clickBurst,\n cursorGlow,\n hoverLiquid,\n hoverReveal,\n magnifier,\n holoCard,\n pressCharge,\n hoverSwap,\n];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * Electricity is drawn from jagged arcs: straight runs between hashed kinks,\n * octave on octave like midpoint displacement, re-seeded many times a second\n * (`floor(iTime * rate)`) so they snap from shape to shape rather than\n * wobble. Each arc is a thin white-hot core in a coloured glow. The\n * interactive ones read the pointer built-ins the wrapper declares\n * (`iPointer`, `iClicks`) and play on their own while nobody is pointing.\n */\n\n/** `zigzag(x, seed)`: fractal jagged noise, about -1 to 1 (needs {@link HASH}). */\nconst ZIGZAG = `\n// Jagged noise, -1 to 1: straight runs between hashed points, so arcs kink rather than wobble.\nfloat jag(float x, float seed) {\n float i = floor(x);\n return mix(hash12(vec2(i, seed)), hash12(vec2(i + 1.0, seed)), fract(x)) * 2.0 - 1.0;\n}\n// Each octave halves the run and the kick, like midpoint displacement.\nfloat zigzag(float x, float seed) {\n float s = 0.0;\n float amp = 0.6;\n for (int i = 0; i < 5; i++) {\n s += amp * jag(x, seed + float(i) * 17.3);\n x *= 2.1;\n amp *= 0.5;\n }\n return s;\n}`.trim();\n\n/**\n * Jagged arcs (needs {@link ZIGZAG}): `arcDist(p, a, b, seed, rough, open)`\n * is the distance from `p` to an arc from `a` to `b` and how far along it `p`\n * is (0–1); `rough` scales its kicks (a fraction of its length) and `open`\n * (1) lets the end at `b` swing free, for branches. `arcPoint` is the point\n * `t` of the way along one, and `arcLight(d, w, colour)` its light: a\n * white-hot core about `w` wide in a coloured glow.\n */\nconst ARC = `\nfloat arcKick(float t, float seed, float rough, float open) {\n float env = sqrt(max(sin(3.14159 * t * (1.0 - 0.5 * open)), 0.0));\n return zigzag(t * 5.0, seed) * rough * env;\n}\nvec2 arcPoint(vec2 a, vec2 b, float t, float seed, float rough, float open) {\n vec2 ab = b - a;\n return a + ab * t + vec2(-ab.y, ab.x) * arcKick(t, seed, rough, open);\n}\nfloat chordDist(vec2 p, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float t = clamp(dot(p - a, ab) / max(dot(ab, ab), 1e-10), 0.0, 1.0);\n return length(p - a - ab * t);\n}\nvec2 arcDist(vec2 p, vec2 a, vec2 b, float seed, float rough, float open) {\n vec2 ab = b - a;\n float len = max(length(ab), 1e-4);\n vec2 dir = ab / len;\n vec2 q = p - a;\n float along = dot(q, dir);\n float side = dot(q, vec2(-dir.y, dir.x));\n float t = clamp(along / len, 0.0, 1.0);\n // Well away from the arc's band, skip the noise.\n float band = rough * len * 1.3;\n if (abs(side) > band + 0.3) return vec2(length(vec2(along - t * len, abs(side) - band)), t);\n // The true distance to the arc's chords either side of t, so steep kicks stay thin and their glow even.\n const float STEP = 0.008;\n vec2 lp = vec2(along, side);\n vec2 c0 = vec2((t - STEP) * len, arcKick(t - STEP, seed, rough, open) * len);\n vec2 c1 = vec2(t * len, arcKick(t, seed, rough, open) * len);\n vec2 c2 = vec2((t + STEP) * len, arcKick(t + STEP, seed, rough, open) * len);\n return vec2(min(chordDist(lp, c0, c1), chordDist(lp, c1, c2)), t);\n}\nvec3 arcLight(float d, float w, vec3 col) {\n float core = exp(-d * d / (w * w));\n float halo = 0.55 * exp(-d / (w * 4.0)) + 0.18 * exp(-d / (w * 20.0));\n return mix(col, vec3(1.0), 0.75) * core * 2.0 + col * halo;\n}`.trim();\n\n/** `glow(c)`: light as a colour over whatever is behind it (alpha is its brightest channel). */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/** `over(acc, colour, alpha)` onto a premultiplied accumulator; `unpremultiply(acc)` for the output. */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\n/** `segment(p, a, b)`: distance from `p` to the segment `a`–`b`. */\nconst SEGMENT = `\nfloat segment(vec2 p, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float t = clamp(dot(p - a, ab) / max(dot(ab, ab), 1e-8), 0.0, 1.0);\n return length(p - a - ab * t);\n}`.trim();\n\n/** `crackle(p, seed)`: fractal jagged 2D noise, about -1 to 1, for crawling electricity (needs {@link HASH}). */\nconst CRACKLE = `\nfloat jag2(vec2 x, float seed) {\n vec2 i = floor(x) + seed;\n vec2 f = fract(x);\n float a = hash12(i);\n float b = hash12(i + vec2(1.0, 0.0));\n float c = hash12(i + vec2(0.0, 1.0));\n float d = hash12(i + vec2(1.0, 1.0));\n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y) * 2.0 - 1.0;\n}\nfloat crackle(vec2 x, float seed) {\n float s = 0.0;\n float amp = 0.6;\n for (int i = 0; i < 4; i++) {\n s += amp * jag2(x, seed + float(i) * 7.3);\n x = x * 2.1 + 3.1;\n amp *= 0.5;\n }\n return s;\n}`.trim();\n\nexport const lightning: ShaderEffect = {\n kind: \"shader\",\n id: \"lightning\",\n name: \"Lightning\",\n description: \"Branching lightning striking from the top on a random schedule and wherever you click, lighting up the sky and leaving an afterglow.\",\n category: \"electric\",\n tags: [\"electric\", \"lightning\", \"storm\", \"weather\", \"overlay\", \"interactive\", \"click\"],\n transparent: true,\n source: glsl(\n `// Lightning: branching bolts from the top, now and then and wherever you click.\nuniform vec3 uColor; // @control color default=#B4C6FF label=\"Colour\"\nuniform float uRate; // @control min=0 max=2 default=0.8 label=\"Strikes per second (0 clicks only)\"\nuniform int uBranches; // @control min=0 max=4 default=3 label=\"Branches\"\nuniform float uRough; // @control min=0.03 max=0.3 default=0.12 label=\"Jaggedness\"\nuniform float uWidth; // @control min=0.3 max=3 default=1 label=\"Width\"\nuniform float uFlash; // @control min=0 max=1 default=0.5 label=\"Sky flash\"\nuniform float uAfterglow; // @control min=0 max=1 default=0.5 label=\"Afterglow\"`,\n HASH,\n ROTATE,\n ZIGZAG,\n ARC,\n GLOW,\n `// How brightly a strike burns age seconds in: return strokes flickering for a moment.\nfloat strikeLevel(float age, float seed) {\n if (age < 0.0 || age > 0.35) return 0.0;\n if (age < 0.04) return 1.0;\n float flick = 0.3 + 0.7 * step(0.45, hash12(vec2(floor(age * 30.0), seed)));\n return flick * (1.0 - age * 1.7);\n}\n\n// One bolt from a down to b with its branches, age seconds after it struck; adds its flash.\nvec3 bolt(vec2 p, vec2 a, vec2 b, float seed, float age, float px, inout float flash) {\n if (age < 0.0 || age > 2.2) return vec3(0.0);\n float on = strikeLevel(age, seed);\n float level = max(on, uAfterglow * 0.45 * exp(-age * 1.6));\n if (level < 0.002) return vec3(0.0);\n flash += on;\n // The leader reaches down over the first 70 ms.\n float reach = clamp(age / 0.07, 0.0, 1.0) * 1.05;\n float w = max(0.0022 * uWidth * mix(0.6, 1.0, on), 0.7 * px);\n vec2 m = arcDist(p, a, b, seed, uRough, 0.0);\n vec3 col = arcLight(m.x, w, uColor) * level * smoothstep(reach, reach - 0.03, m.y);\n // A splash of light where it lands.\n col += uColor * exp(-length(p - b) / 0.03) * on * smoothstep(0.95, 1.0, reach);\n vec2 dir = normalize(b - a);\n float len = length(b - a);\n for (int j = 0; j < 4; j++) {\n if (j >= uBranches) break;\n float fj = float(j);\n vec3 h = vec3(hash12(vec2(seed, fj + 1.3)), hash12(vec2(fj + 3.1, seed)), hash12(vec2(seed + fj, 7.7)));\n float t0 = 0.12 + 0.6 * h.x;\n float prog = (reach - t0) / (1.0 - t0) * 1.2;\n if (prog <= 0.0) continue;\n vec2 s = arcPoint(a, b, t0, seed, uRough, 0.0);\n float turn = (h.y < 0.5 ? -1.0 : 1.0) * (0.35 + 0.55 * fract(h.y * 7.0));\n vec2 bdir = rot(turn) * dir;\n float blen = len * (1.0 - t0) * (0.25 + 0.35 * h.z);\n vec2 e = s + bdir * blen;\n float bseed = seed + fj * 5.3 + 1.0;\n vec2 d = arcDist(p, s, e, bseed, uRough * 1.3, 1.0);\n float shown = smoothstep(prog, prog - 0.05, d.y);\n col += arcLight(d.x, w * 0.6, uColor) * level * 0.6 * (1.0 - 0.8 * d.y) * shown;\n // A twig off each branch.\n float t1 = 0.3 + 0.4 * fract(h.z * 11.0);\n vec2 s2 = arcPoint(s, e, t1, bseed, uRough * 1.3, 1.0);\n vec2 e2 = s2 + rot(-turn * 0.9) * bdir * blen * (1.0 - t1) * 0.6;\n vec2 d2 = arcDist(p, s2, e2, bseed + 2.7, uRough * 1.5, 1.0);\n col += arcLight(d2.x, w * 0.4, uColor) * level * 0.35 * (1.0 - d2.y) * smoothstep(prog, prog - 0.05, t1 + d2.y * 0.3);\n }\n return col;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n float aspect = iResolution.x * px;\n vec3 col = vec3(0.0);\n float flash = 0.0;\n // Strikes on a random schedule: at most one in each slot, some slots quiet.\n if (uRate > 0.0) {\n float slot = 1.0 / uRate;\n float k0 = floor(iTime / slot);\n for (int i = 0; i < 5; i++) {\n float k = k0 - float(i);\n if (float(i - 1) * slot > 2.2) break;\n if (hash12(vec2(k, 9.1)) > 0.8) continue;\n vec2 h = hash22(vec2(k, 3.3));\n vec2 g = hash22(vec2(k, 5.9));\n vec2 a = vec2((0.1 + 0.8 * h.y) * aspect, 1.05);\n vec2 b = vec2(a.x + (g.x - 0.5) * 0.7, 0.35 * g.y - 0.05);\n col += bolt(p, a, b, k * 1.37 + 0.5, iTime - (k + 0.7 * h.x) * slot, px, flash);\n }\n }\n // And one aimed at each click.\n for (int i = 0; i < 4; i++) {\n vec4 c = iClicks[i];\n if (c.w < 0.5) continue;\n vec2 b = c.xy * px;\n vec2 a = vec2(b.x + (hash12(vec2(c.z, 1.9)) - 0.5) * 0.5, 1.05);\n col += bolt(p, a, b, fract(c.z * 0.731) * 97.0 + float(i), iTime - c.z, px, flash);\n }\n // The sky lights up with each stroke, most at the top.\n col += mix(uColor, vec3(1.0), 0.3) * uFlash * min(flash, 1.5) * (0.1 + 0.25 * p.y);\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Thunderstorm\", values: { uRate: 1.4, uBranches: 4, uFlash: 0.9, uAfterglow: 0.7 } },\n { name: \"Violet\", values: { uColor: [0.75, 0.55, 1], uRate: 0.4, uRough: 0.16, uWidth: 1.4 } },\n { name: \"Click to strike\", values: { uRate: 0, uFlash: 0.3 } },\n ],\n};\n\nexport const teslaArc: ShaderEffect = {\n kind: \"shader\",\n id: \"tesla-arc\",\n name: \"Tesla arc\",\n description: \"A jittering plasma arc between two electrodes with stray filaments and sparks at the ends; hover and one end follows the pointer.\",\n category: \"electric\",\n tags: [\"electric\", \"arc\", \"plasma\", \"tesla\", \"sci-fi\", \"overlay\", \"interactive\", \"hover\"],\n transparent: true,\n source: glsl(\n `// Tesla arc: a plasma arc between two electrodes, re-forming many times a second.\nuniform vec2 uStart; // @control min=-1 max=1 default=-0.6,0 label=\"Start\"\nuniform vec2 uEnd; // @control min=-1 max=1 default=0.6,0 label=\"End\"\nuniform vec3 uColor; // @control color default=#A98BFF label=\"Colour\"\nuniform float uRate; // @control min=2 max=40 default=16 label=\"Re-forms per second\"\nuniform int uFilaments; // @control min=0 max=3 default=2 label=\"Filaments\"\nuniform float uRough; // @control min=0.03 max=0.4 default=0.16 label=\"Jaggedness\"\nuniform float uWidth; // @control min=0.3 max=3 default=1 label=\"Width\"\nuniform float uSparks; // @control min=0 max=1 default=0.6 label=\"Sparks\"\nuniform bool uFollow; // @control default=true label=\"End follows pointer\"`,\n HASH,\n ZIGZAG,\n ARC,\n SEGMENT,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 span = vec2(iResolution.x * px, 1.0) * 0.5;\n vec2 a = uStart * span;\n vec2 b = uEnd * span;\n if (uFollow) b = mix(b, (iPointer.xy - 0.5 * iResolution.xy) * px, clamp(iPointer.z, 0.0, 1.0));\n float tick = floor(iTime * uRate);\n float w = max(0.003 * uWidth, 0.7 * px);\n // The main arc, a little brighter or dimmer each time it re-forms.\n float level = 0.75 + 0.5 * hash12(vec2(tick, 0.7));\n vec2 m = arcDist(p, a, b, tick, uRough, 0.0);\n vec3 col = arcLight(m.x, w, uColor) * level;\n // Fainter, wilder filaments, each flickering on and off on its own clock.\n for (int i = 0; i < 3; i++) {\n if (i >= uFilaments) break;\n float fi = float(i) + 1.0;\n float ft = floor(iTime * uRate * (0.5 + 0.2 * fi) + fi * 3.1);\n float on = step(0.3, hash12(vec2(ft, fi * 4.3)));\n vec2 f = arcDist(p, a, b, ft * 1.7 + fi * 31.0, uRough * (1.4 + 0.4 * fi), 0.0);\n col += arcLight(f.x, w * 0.5, uColor) * 0.45 * on;\n }\n // Hot spots and sparks at both ends.\n for (int e = 0; e < 2; e++) {\n vec2 c = e == 0 ? a : b;\n vec2 away = normalize((e == 0 ? a - b : b - a) + 1e-5);\n float r = length(p - c);\n col += mix(uColor, vec3(1.0), 0.6) * (exp(-r / (0.012 * uWidth)) * 1.2 + exp(-r / 0.05) * 0.25) * level;\n for (int k = 0; k < 6; k++) {\n float fk = float(k);\n float clock = iTime * 2.3 + hash12(vec2(fk, float(e) + 0.5));\n float life = fract(clock);\n vec3 h = vec3(hash22(vec2(floor(clock), fk + float(e) * 7.0)), hash12(vec2(fk, floor(clock) + 0.3)));\n if (h.z > uSparks) continue;\n float ang = atan(away.y, away.x) + (h.x - 0.5) * 2.6;\n vec2 v = vec2(cos(ang), sin(ang)) * (0.25 + 0.35 * h.y);\n float s = life * 0.45;\n vec2 pos = c + v * s - vec2(0.0, 0.5 * s * s);\n if (length(p - pos) > 0.08) continue;\n vec2 vel = v - vec2(0.0, s);\n float d = segment(p, pos, pos - vel * 0.04);\n col += mix(uColor, vec3(1.0, 0.95, 0.85), 0.7) * (exp(-d * d / (w * w * 0.5)) + 0.3 * exp(-d / (w * 3.0))) * (1.0 - life);\n }\n }\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Blue arc\", values: { uColor: [0.4, 0.7, 1], uRate: 24, uFilaments: 3 } },\n { name: \"Lazy\", values: { uRate: 5, uRough: 0.1, uFilaments: 1, uSparks: 0.2 } },\n { name: \"Vertical\", values: { uStart: [0, 0.75], uEnd: [0, -0.75], uColor: [0.55, 1, 0.75] } },\n ],\n};\n\nexport const plasmaBall: ShaderEffect = {\n kind: \"shader\",\n id: \"plasma-ball\",\n name: \"Plasma ball\",\n description: \"A plasma globe whose writhing filaments reach from a glowing electrode to the glass and gather where the pointer is.\",\n category: \"electric\",\n tags: [\"electric\", \"plasma\", \"globe\", \"retro\", \"sci-fi\", \"interactive\", \"hover\"],\n source: glsl(\n `// Plasma ball: filaments writhing from a glowing electrode to the glass, gathering at the pointer.\nuniform vec3 uColor; // @control color default=#D04CFF label=\"Filaments\"\nuniform vec3 uTip; // @control color default=#5BA8FF label=\"Tips\"\nuniform vec3 uBackground; // @control color default=#05030A label=\"Background\"\nuniform int uCount; // @control min=3 max=14 default=9 label=\"Filament count\"\nuniform float uPull; // @control min=0 max=1 default=0.85 label=\"Pull to pointer\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSize; // @control min=0.5 max=1 default=0.85 label=\"Size\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n ZIGZAG,\n ARC,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float R = 0.44 * uSize;\n vec2 o = vec2(0.0, 0.07 * uSize);\n vec2 q = p - o;\n float r = length(q);\n float t = iTime * uSpeed;\n float w = max(0.0035 * uSize, 0.7 * px);\n vec3 col = uBackground;\n vec3 light = vec3(0.0);\n\n // The stand, lit from above by the globe.\n vec2 sq = p - o + vec2(0.0, R * 0.92);\n float bw = (0.15 - sq.y * 0.7) * uSize;\n if (sq.y < 0.0 && sq.y > -0.13 * uSize && abs(sq.x) < bw) {\n float shade = 0.5 + 0.5 * cos(sq.x / bw * 1.4);\n col = vec3(0.07, 0.07, 0.09) * shade + uColor * 0.12 * exp(sq.y * 25.0 / uSize);\n }\n\n // Where the filaments reach: the pointer while it is over, else a wandering point.\n float hover = clamp(iPointer.z, 0.0, 1.0);\n vec2 drift = vec2(sin(t * 0.53), sin(t * 0.71 + 1.0)) * R;\n vec2 target = mix(drift, (iPointer.xy - 0.5 * iResolution.xy) * px - o, hover);\n float pull = uPull * mix(uDemo ? 0.5 : 0.0, 1.0, hover);\n float towards = atan(target.y, target.x);\n float tick = floor(iTime * 14.0);\n\n if (r < R) {\n light += uColor * 0.08 * (1.0 - r / R);\n for (int i = 0; i < 14; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n float home = fi / float(uCount) * 6.28318 + (vnoise(vec2(fi * 3.1, t * 0.4)) - 0.5) * 2.5;\n float spread = (hash12(vec2(fi, 2.0)) - 0.5) * 0.6;\n float diff = mod(towards + spread - home + 3.14159, 6.28318) - 3.14159;\n float ang = home + diff * pull;\n vec2 dir = vec2(cos(ang), sin(ang));\n vec2 root = dir * 0.05 * uSize;\n vec2 tip = dir * R * 0.985;\n // Bent in the middle, swaying slowly; kinked afresh each tick.\n vec2 mid = (root + tip) * 0.5 + vec2(-dir.y, dir.x) * (vnoise(vec2(fi * 5.7, t * 0.9)) - 0.5) * 0.5 * R;\n float seed = tick + fi * 13.0;\n vec2 d1 = arcDist(q, root, mid, seed, 0.1, 0.0);\n vec2 d2 = arcDist(q, mid, tip, seed + 7.0, 0.1, 0.0);\n float d = min(d1.x, d2.x);\n float along = d1.x < d2.x ? d1.y * 0.5 : 0.5 + d2.y * 0.5;\n vec3 fc = mix(uColor, uTip, smoothstep(0.45, 1.0, along));\n float flick = 0.7 + 0.3 * hash12(vec2(tick, fi));\n light += arcLight(d, w * mix(1.3, 0.7, along), fc) * flick * 0.75;\n // A bright spot where it touches the glass.\n light += uTip * exp(-length(q - tip) / (0.02 * uSize)) * 0.7;\n }\n } else {\n light += uColor * 0.25 * exp(-(r - R) / (0.06 * uSize));\n }\n // The electrode's glow.\n light += mix(uColor, vec3(1.0), 0.6) * exp(-r / (0.05 * uSize)) * 1.2;\n col += 1.0 - exp(-light);\n\n // The electrode, a frosted ball.\n float re = 0.05 * uSize;\n col = mix(col, mix(vec3(0.85, 0.8, 0.95), uColor, 0.3) * (1.1 - 0.4 * length(q / re - vec2(-0.3, 0.4))), smoothstep(re, re - px, r));\n // The glass: a thin rim, brighter toward the edge, and a highlight.\n col += vec3(0.75, 0.8, 1.0) * exp(-abs(r - R) / (0.003 + px)) * 0.4;\n col += mix(uColor, vec3(1.0), 0.5) * pow(clamp(r / R, 0.0, 1.0), 8.0) * 0.12 * step(r, R);\n float spec = length((q - vec2(-0.42, 0.5) * R) * vec2(1.0, 1.8));\n col += vec3(1.0) * (1.0 - smoothstep(0.0, 0.1 * R, spec)) * 0.35 * step(r, R);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Classic\", values: { uColor: [0.95, 0.35, 0.8], uTip: [0.6, 0.5, 1] } },\n { name: \"Ice\", values: { uColor: [0.3, 0.7, 1], uTip: [0.85, 0.95, 1], uBackground: [0.01, 0.03, 0.06] } },\n { name: \"Dense\", values: { uCount: 14, uSpeed: 1.6 } },\n ],\n};\n\nexport const electricBorder: ShaderEffect = {\n kind: \"shader\",\n id: \"electric-border\",\n name: \"Electric border\",\n description: \"Electricity crackling round a rounded frame and now and then arcing off it, for cards and buttons.\",\n category: \"electric\",\n tags: [\"electric\", \"border\", \"frame\", \"ui\", \"card\", \"overlay\", \"glow\"],\n transparent: true,\n source: glsl(\n `// Electric border: electricity crackling round a rounded frame, now and then arcing off it.\nuniform vec3 uColor; // @control color default=#5CE1FF label=\"Colour\"\nuniform float uInset; // @control min=0 max=0.3 default=0.08 label=\"Inset\"\nuniform float uRadius; // @control min=0 max=0.5 default=0.08 label=\"Corner radius\"\nuniform float uThickness; // @control min=0.002 max=0.06 default=0.016 label=\"Thickness\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uArcs; // @control min=0 max=1 default=0.5 label=\"Arcs\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"`,\n HASH,\n ZIGZAG,\n ARC,\n CRACKLE,\n GLOW,\n `float boxSdf(vec2 p, vec2 b, float r) {\n vec2 q = abs(p) - b + r;\n return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;\n}\n\n// The point on the frame in the direction ang from the centre, about.\nvec2 framePoint(float ang, vec2 box, float rad) {\n vec2 dir = vec2(cos(ang), sin(ang));\n float s = min(box.x / max(abs(dir.x), 1e-3), box.y / max(abs(dir.y), 1e-3));\n vec2 q = dir * s;\n return q - dir * boxSdf(q, box, rad);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 box = max(0.5 * iResolution.xy * px - uInset, vec2(0.05));\n float rad = min(uRadius, min(box.x, box.y));\n float sd = boxSdf(p, box, rad);\n float t = iTime * uSpeed;\n float w = max(0.0018, 0.7 * px);\n float around = atan(p.y, p.x);\n vec3 light = vec3(0.0);\n // Strands: the frame's outline pushed about by jagged noise, re-kinked many times a second.\n for (int i = 0; i < 3; i++) {\n float fi = float(i);\n float tick = floor(t * (12.0 + 5.0 * fi) + fi * 0.5);\n float v = sd - crackle(p * (9.0 + 3.0 * fi), fract(tick * 0.0731) * 300.0 + fi * 19.0) * uThickness;\n vec2 g = vec2(dFdx(v), dFdy(v)) / px;\n float d = abs(v) / max(length(g), 0.5);\n // Brighter stretches running round the frame.\n float flow = 0.5 + 0.5 * sin(around * (2.0 + fi) - t * (2.0 + fi) * (fi == 1.0 ? -1.0 : 1.0) + fi * 2.0);\n float level = mix(0.2, 1.0, smoothstep(0.2, 0.9, flow)) * (fi == 0.0 ? 1.0 : 0.55);\n light += arcLight(d, w * (fi == 0.0 ? 1.0 : 0.6), uColor) * level;\n }\n // A soft glow hugging the frame.\n light += uColor * exp(-abs(sd) / (uThickness * 2.0 + 0.01)) * 0.2;\n // Arcs leaping off the frame and back.\n for (int j = 0; j < 2; j++) {\n float fj = float(j);\n float clock = t * 1.3 + fj * 0.47;\n float slot = floor(clock);\n if (hash12(vec2(slot, fj + 0.3)) > uArcs || fract(clock) > 0.3) continue;\n float ang = hash12(vec2(slot, fj + 5.1)) * 6.28318;\n vec2 a = framePoint(ang, box, rad);\n vec2 b = framePoint(ang + 0.15 + 0.2 * hash12(vec2(slot, 9.0)), box, rad);\n vec2 mid = (a + b) * 0.5;\n mid += normalize(mid) * (0.04 + 0.05 * hash12(vec2(slot, 2.0)));\n float seed = floor(iTime * 30.0) + fj * 50.0;\n float d = min(arcDist(p, a, mid, seed, 0.25, 0.0).x, arcDist(p, mid, b, seed + 3.0, 0.25, 0.0).x);\n light += arcLight(d, w * 0.8, uColor) * (1.0 - fract(clock) / 0.3);\n }\n fragColor = glow(light * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Button\", values: { uInset: 0.04, uRadius: 0.5, uThickness: 0.01, uArcs: 0.3 } },\n { name: \"Toxic\", values: { uColor: [0.55, 1, 0.3], uThickness: 0.03, uSpeed: 1.5, uArcs: 0.8 } },\n { name: \"Hot pink\", values: { uColor: [1, 0.35, 0.75], uRadius: 0.02, uIntensity: 1.4 } },\n ],\n};\n\nexport const electricText: ShaderEffect = {\n kind: \"shader\",\n id: \"electric-text\",\n name: \"Electric text\",\n description: \"A word with electricity crawling over its outlines and arcs leaping between its letters, flickering on a dark background.\",\n category: \"electric\",\n tags: [\"electric\", \"text\", \"title\", \"glow\", \"sci-fi\"],\n source: glsl(\n `// Electric text: electricity crawling along the letters' outlines, arcs jumping between them.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"VOLT\")} label=\"Text\"\nuniform vec3 uColor; // @control color default=#6FD3FF label=\"Electricity\"\nuniform vec3 uFill; // @control color default=#0B1622 label=\"Letters\"\nuniform vec3 uBackground; // @control color default=#04060B label=\"Background\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Text size\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uArcs; // @control min=0 max=1 default=0.6 label=\"Arcs between letters\"\nuniform float uFlicker; // @control min=0 max=1 default=0.5 label=\"Flicker\"`,\n HASH,\n ZIGZAG,\n ARC,\n CRACKLE,\n `// The text image's half size in the frame (height 1, centred), contained in uSize of it.\nvec2 textHalf() {\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float h = min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n return vec2(h * aspect, h) * 0.5;\n}\n\nfloat letters(vec2 p) {\n vec2 uv = p / (2.0 * textHalf()) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uText, uv).a;\n}\n\n// The mask softened over a few taps, so its edge is a smooth slope to trace.\nfloat soft(vec2 p) {\n float s = letters(p);\n for (int i = 0; i < 6; i++) {\n float a = float(i) * 1.0472;\n s += letters(p + vec2(cos(a), sin(a)) * 0.005);\n }\n return s / 7.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float t = iTime * uSpeed;\n float w = max(0.0016, 0.6 * px);\n float mask = letters(p);\n float flick = mix(1.0, 0.35 + 0.65 * step(0.25, hash12(vec2(floor(t * 14.0), 4.0))), uFlicker);\n vec3 light = vec3(0.0);\n // Electricity crawling over the outlines: the edge traced through jagged jitter.\n for (int i = 0; i < 2; i++) {\n float fi = float(i);\n float seed = fract(floor(t * (16.0 + 7.0 * fi)) * 0.0371) * 300.0 + fi * 11.0;\n vec2 jitter = vec2(crackle(p * 14.0, seed), crackle(p * 14.0 + 5.2, seed + 3.0)) * 0.012;\n float v = soft(p + jitter) - 0.5;\n vec2 g = vec2(dFdx(v), dFdy(v)) / px;\n float d = abs(v) / max(length(g), 1.0);\n light += arcLight(d, w * (1.0 - 0.4 * fi), uColor) * (1.0 - 0.45 * fi);\n }\n // A halo round the letters.\n float halo = 0.0;\n for (int i = 0; i < 8; i++) {\n float a = float(i) * 0.7854;\n vec2 dir = vec2(cos(a), sin(a));\n halo += letters(p + dir * 0.025) + letters(p + dir * 0.06) * 0.5;\n }\n light += uColor * halo / 12.0 * 0.5 * (1.0 - mask);\n // Arcs between letters, hidden where they pass behind one.\n vec2 hb = textHalf();\n for (int j = 0; j < 2; j++) {\n float fj = float(j);\n float clock = t * 1.7 + fj * 0.5;\n float slot = floor(clock);\n if (hash12(vec2(slot, fj + 0.7)) > uArcs || fract(clock) > 0.35) continue;\n vec3 h = vec3(hash22(vec2(slot, fj + 2.3)), hash12(vec2(slot, fj + 8.1)));\n vec2 a = vec2((h.x * 2.0 - 1.0) * hb.x * 0.75, (h.y - 0.5) * hb.y * 0.8);\n vec2 b = vec2(a.x + (h.x > 0.5 ? -1.0 : 1.0) * (0.12 + 0.25 * h.z) * hb.x, (fract(h.z * 7.0) - 0.5) * hb.y * 0.8);\n vec2 d = arcDist(p, a, b, floor(iTime * 25.0) + fj * 40.0, 0.2, 0.0);\n light += arcLight(d.x, w * 0.8, uColor) * (1.0 - mask) * (1.0 - fract(clock) / 0.35) * 0.9;\n }\n vec3 col = mix(uBackground, uFill + uColor * 0.06 * flick, mask);\n col += 1.0 - exp(-light * flick);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Toxic\", values: { uColor: [0.5, 1, 0.3], uFill: [0.04, 0.1, 0.03] } },\n { name: \"Overload\", values: { uColor: [1, 0.85, 0.4], uArcs: 1, uFlicker: 0.9, uSpeed: 1.6 } },\n { name: \"Steady\", values: { uFlicker: 0, uArcs: 0.2, uSpeed: 0.6 } },\n ],\n};\n\nexport const jacobsLadder: ShaderEffect = {\n kind: \"shader\",\n id: \"jacobs-ladder\",\n name: \"Jacob's ladder\",\n description: \"An arc climbing between two diverging rods, stretching and breaking at the top, then striking again at the bottom.\",\n category: \"electric\",\n tags: [\"electric\", \"arc\", \"plasma\", \"lab\", \"retro\", \"loop\"],\n source: glsl(\n `// Jacob's ladder: an arc climbing between diverging rods, breaking at the top and re-forming below.\nuniform vec3 uColor; // @control color default=#B79BFF label=\"Arc\"\nuniform vec3 uRod; // @control color default=#8A8F9C label=\"Rods\"\nuniform vec3 uBackground; // @control color default=#06060B label=\"Background\"\nuniform float uPeriod; // @control min=0.8 max=6 default=2.6 label=\"Climb seconds\"\nuniform float uSpread; // @control min=0.05 max=0.5 default=0.24 label=\"Spread at top\"\nuniform float uRough; // @control min=0.03 max=0.4 default=0.14 label=\"Jaggedness\"\nuniform float uWidth; // @control min=0.3 max=3 default=1 label=\"Width\"`,\n HASH,\n ZIGZAG,\n ARC,\n SEGMENT,\n `const float BOTTOM = -0.4;\nconst float TOP = 0.3;\n\n// How far each rod is from the middle at height y.\nfloat rodX(float y) {\n return 0.035 + uSpread * clamp((y - BOTTOM) / (TOP - BOTTOM), 0.0, 1.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float w = max(0.003 * uWidth, 0.7 * px);\n vec3 col = uBackground;\n\n // The insulator block and the two rods, round and metallic.\n vec2 bq = abs(p - vec2(0.0, BOTTOM - 0.05)) - vec2(0.12 + uSpread * 0.3, 0.05);\n if (max(bq.x, bq.y) < 0.0) col = mix(uRod * 0.2, uRod * 0.35, smoothstep(-0.05, 0.05, p.y - BOTTOM + 0.05));\n for (int s = 0; s < 2; s++) {\n float side = s == 0 ? -1.0 : 1.0;\n vec2 a = vec2(side * rodX(BOTTOM), BOTTOM);\n vec2 b = vec2(side * rodX(TOP), TOP + 0.03);\n float d = segment(p, a, b);\n float r = 0.007;\n float across = clamp(d / r, 0.0, 1.0);\n vec3 metal = uRod * (0.45 + 0.55 * sqrt(1.0 - across * across)) + 0.25 * exp(-d / (r * 0.3));\n col = mix(col, metal, smoothstep(r, r - px, d));\n }\n\n // The climb: slow at the bottom, rising faster as the hot air carries it.\n float u = fract(iTime / uPeriod);\n float climb = clamp(u / 0.88, 0.0, 1.0);\n float y = BOTTOM + 0.02 + (TOP - BOTTOM - 0.02) * pow(climb, 1.5);\n float tick = floor(iTime * 20.0);\n vec3 light = vec3(0.0);\n if (u < 0.88) {\n vec2 l = vec2(-rodX(y) + 0.006, y);\n vec2 r = vec2(rodX(y) - 0.006, y);\n // It bows upward, more as it stretches before breaking.\n float bow = (r.x - l.x) * 0.15 + 0.12 * smoothstep(0.6, 0.88, u);\n vec2 mid = vec2((hash12(vec2(tick, 3.0)) - 0.5) * 0.04, y + bow);\n float d = min(arcDist(p, l, mid, tick * 2.1, uRough, 0.0).x, arcDist(p, mid, r, tick * 2.1 + 1.0, uRough, 0.0).x);\n float strike = 1.0 + 1.5 * exp(-u * uPeriod * 12.0);\n float flick = 0.75 + 0.35 * hash12(vec2(tick, 1.0)) - 0.4 * smoothstep(0.75, 0.88, u) * step(0.5, hash12(vec2(tick, 2.0)));\n light += arcLight(d, w, uColor) * strike * flick;\n // The rods glow where it touches them.\n light += uColor * (exp(-length(p - l) / 0.02) + exp(-length(p - r) / 0.02)) * 0.6 * flick;\n } else {\n // Broken: a puff of plasma rising off the top and fading.\n float age = (u - 0.88) * uPeriod;\n vec2 c = vec2(0.0, TOP + 0.12 + age * 0.25);\n light += uColor * exp(-length(p - c) / (0.03 + age * 0.1)) * exp(-age * 6.0) * 0.8;\n }\n col += 1.0 - exp(-light);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Fast\", values: { uPeriod: 1.2, uRough: 0.2 } },\n { name: \"Wide\", values: { uSpread: 0.45, uPeriod: 3.5, uWidth: 1.4 } },\n { name: \"Blue\", values: { uColor: [0.45, 0.7, 1], uRod: [0.75, 0.6, 0.4] } },\n ],\n};\n\nexport const shortCircuit: ShaderEffect = {\n kind: \"shader\",\n id: \"short-circuit\",\n name: \"Short circuit\",\n description: \"A sparking fault spitting irregular bursts of hot sparks that fall away, with bright flashes and a wisp of smoke.\",\n category: \"electric\",\n tags: [\"electric\", \"sparks\", \"fault\", \"overlay\", \"particles\", \"danger\"],\n transparent: true,\n source: glsl(\n `// Short circuit: a fault spitting bursts of hot sparks, flashes and a wisp of smoke.\nuniform vec2 uOrigin; // @control min=-1 max=1 default=0,0.2 label=\"Fault\"\nuniform vec3 uColor; // @control color default=#FFB54D label=\"Sparks\"\nuniform vec3 uFlashColor; // @control color default=#BFD9FF label=\"Flash\"\nuniform float uActivity; // @control min=0 max=1 default=0.6 label=\"Activity\"\nuniform int uSparks; // @control min=4 max=32 default=18 label=\"Sparks per burst\"\nuniform float uSpread; // @control min=0.2 max=2 default=1 label=\"Spread\"\nuniform float uGravity; // @control min=0 max=3 default=1 label=\"Gravity\"\nuniform float uSmoke; // @control min=0 max=1 default=0.4 label=\"Smoke\"`,\n HASH,\n NOISE,\n FBM,\n ZIGZAG,\n ARC,\n SEGMENT,\n GLOW,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 o = uOrigin * vec2(iResolution.x * px, 1.0) * 0.5;\n float w = max(0.0025, 0.7 * px);\n const float drag = 2.5;\n const float SLOT = 0.3;\n vec3 light = vec3(0.0);\n float ambient = 0.0;\n float k0 = floor(iTime / SLOT);\n for (int i = 0; i < 5; i++) {\n float k = k0 - float(i);\n if (hash12(vec2(k, 1.7)) > uActivity) continue;\n float age = iTime - (k + 0.6 * hash12(vec2(k, 2.9))) * SLOT;\n if (age < 0.0 || age > 1.2) continue;\n // A flash, flickering, with a little arc across the fault.\n float flash = exp(-age * 14.0) * (0.6 + 0.4 * step(0.5, hash12(vec2(floor(age * 40.0), k))));\n float r = length(p - o);\n light += uFlashColor * (exp(-r / 0.02) * 2.0 + exp(-r / 0.12) * 0.5) * flash;\n ambient += flash;\n if (age < 0.12) {\n vec2 s = vec2(0.035, 0.0) * (0.6 + hash12(vec2(k, 4.4)));\n light += arcLight(arcDist(p, o - s, o + s.yx * 0.3 + s, floor(iTime * 40.0), 0.35, 0.0).x, w, uFlashColor) * 0.8;\n }\n float slow = (1.0 - exp(-drag * age)) / drag;\n for (int j = 0; j < 32; j++) {\n if (j >= uSparks) break;\n vec3 h = vec3(hash22(vec2(float(j) * 7.13 + 1.0, k * 3.1)), hash12(vec2(k, float(j) + 0.5)));\n float span = 0.35 + 0.75 * h.z;\n if (age > span) continue;\n float ang = 1.5708 + (h.x - 0.5) * 2.8;\n vec2 v0 = vec2(cos(ang), sin(ang)) * uSpread * (0.4 + 0.9 * h.y);\n vec2 pos = o + v0 * slow - vec2(0.0, 0.5 * uGravity * 0.8 * age * age);\n if (length(p - pos) > 0.1) continue;\n vec2 vel = v0 * exp(-drag * age) - vec2(0.0, uGravity * 0.8 * age);\n float d = segment(p, pos, pos - vel * 0.035);\n float heat = 1.0 - age / span;\n vec3 c = mix(uColor * vec3(1.0, 0.55, 0.35), mix(uColor, vec3(1.0), 0.7), heat * heat);\n light += c * (exp(-d * d / (w * w)) * 1.5 + 0.25 * exp(-d / (w * 3.0))) * heat;\n }\n }\n light += uFlashColor * min(ambient, 1.0) * 0.08;\n // Smoke curling up from the fault.\n vec2 q = p - o;\n float spread = 0.03 + max(q.y, 0.0) * 0.35;\n float plume = fbm(vec2(q.x * 7.0, q.y * 4.0 - iTime * 0.6), 4);\n float smoke = smoothstep(0.4, 0.75, plume) * exp(-q.x * q.x / (spread * spread)) * smoothstep(-0.02, 0.04, q.y) * exp(-max(q.y, 0.0) * 2.5);\n vec4 acc = over(vec4(0.0), vec3(0.32, 0.31, 0.3), clamp(smoke * uSmoke, 0.0, 1.0));\n vec4 g = glow(light);\n acc = over(acc, g.rgb, g.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Welding\", values: { uColor: [0.75, 0.85, 1], uActivity: 1, uSparks: 32, uSmoke: 0.2 } },\n { name: \"Sputter\", values: { uActivity: 0.3, uSparks: 8, uSpread: 0.6 } },\n { name: \"Wall socket\", values: { uOrigin: [0, -0.3], uGravity: 1.6, uSmoke: 0.7 } },\n ],\n};\n\nexport const powerSurge: ShaderEffect = {\n kind: \"shader\",\n id: \"power-surge\",\n name: \"Power surge\",\n description: \"A picture jolted by a power surge: a flash, an arc tearing across, scanlines and colour split, then a brownout before it settles.\",\n category: \"electric\",\n tags: [\"electric\", \"image\", \"glitch\", \"surge\", \"flash\"],\n source: glsl(\n `// Power surge: an image jolted by a surge, then settling, on a schedule.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform vec3 uColor; // @control color default=#8FD8FF label=\"Arc colour\"\nuniform float uPeriod; // @control min=1.5 max=8 default=3.5 label=\"Seconds between surges\"\nuniform float uStrength; // @control min=0 max=1.5 default=1 label=\"Strength\"\nuniform float uGlitch; // @control min=0 max=1 default=0.6 label=\"Glitch\"\n${BACKDROP_CONTROLS}`,\n HASH,\n ZIGZAG,\n ARC,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n float aspect = iResolution.x * px;\n float cycle = floor(iTime / uPeriod);\n float since = iTime - cycle * uPeriod;\n float tick = floor(iTime * 24.0);\n float surge = uStrength * exp(-since * 4.0) * (0.55 + 0.45 * hash12(vec2(tick, 1.0)));\n // Rows torn sideways and the channels split while it surges.\n float rows = floor(uv.y * mix(12.0, 60.0, hash12(vec2(tick, 2.0))));\n float tear = (hash12(vec2(rows, tick)) - 0.5) * step(0.55, hash12(vec2(rows, tick + 5.0))) * 0.12 * surge * uGlitch;\n vec2 st = uv + vec2(tear, 0.0);\n float split = 0.012 * surge * uGlitch;\n vec4 r = pictureRGBA(uImage, st + vec2(split, 0.0));\n vec4 g = pictureRGBA(uImage, st);\n vec4 b2 = pictureRGBA(uImage, st - vec2(split, 0.0));\n vec3 col = vec3(r.r, g.g, b2.b);\n // Brightness spikes, dips in a brownout, then comes back.\n float brownout = 1.0 - 0.3 * min(uStrength, 1.0) * smoothstep(0.25, 0.5, since) * (1.0 - smoothstep(0.7, 1.5, since));\n col = col * brownout * (1.0 + surge * 1.4) + surge * 0.2 * mix(uColor, vec3(1.0), 0.5);\n col *= 1.0 - 0.35 * min(surge, 1.0) * uGlitch * (0.5 + 0.5 * sin(fragCoord.y * 1.5708));\n // The arc tearing across in the first moments, with a branch.\n vec3 light = vec3(0.0);\n float on = step(since, 0.35) * (0.5 + 0.5 * step(0.3, hash12(vec2(tick, 6.0)))) * uStrength;\n if (on > 0.0) {\n float w = max(0.003, 0.7 * px);\n vec2 a = vec2(-0.05, 0.2 + 0.6 * hash12(vec2(cycle, 3.0)));\n vec2 b = vec2(aspect + 0.05, 0.2 + 0.6 * hash12(vec2(cycle, 4.0)));\n light += arcLight(arcDist(p, a, b, tick, 0.07, 0.0).x, w, uColor);\n vec2 s = arcPoint(a, b, 0.3 + 0.4 * hash12(vec2(cycle, 5.0)), tick, 0.07, 0.0);\n vec2 e = s + vec2(0.15 + 0.2 * hash12(vec2(cycle, 6.0)), (hash12(vec2(cycle, 7.0)) - 0.5) * 0.6);\n light += arcLight(arcDist(p, s, e, tick + 9.0, 0.2, 1.0).x, w * 0.6, uColor) * 0.6;\n light *= on;\n }\n col = 1.0 - (1.0 - clamp(col, 0.0, 1.0)) * exp(-light);\n // The arc shows where the picture is clear too.\n float arc = 1.0 - exp(-max(light.r, max(light.g, light.b)));\n fragColor = vec4(col, max(max(max(r.a, g.a), b2.a), arc));\n}`,\n ),\n presets: [\n { name: \"Blackout\", values: { uStrength: 1.5, uGlitch: 1, uPeriod: 5 } },\n { name: \"Flicker\", values: { uStrength: 0.5, uGlitch: 0.3, uPeriod: 2 } },\n { name: \"Landscape\", values: { uImage: SAMPLE_IMAGES.landscape, uColor: [1, 0.85, 0.5] } },\n ],\n};\n\nexport const electricField: ShaderEffect = {\n kind: \"shader\",\n id: \"electric-field\",\n name: \"Electric field\",\n description: \"Field lines between glowing positive and negative charges with dashes flowing along them; hover and one charge follows the pointer.\",\n category: \"electric\",\n tags: [\"electric\", \"physics\", \"science\", \"field\", \"lines\", \"interactive\", \"hover\"],\n source: glsl(\n `// Electric field: the field lines of two or three charges, dashes flowing from + to -.\nuniform vec2 uCharge1; // @control min=-1 max=1 default=-0.5,0 label=\"Charge 1 (+)\"\nuniform vec2 uCharge2; // @control min=-1 max=1 default=0.5,0 label=\"Charge 2 (-)\"\nuniform vec2 uCharge3; // @control min=-1 max=1 default=0,0.7 label=\"Charge 3\"\nuniform int uThird; // @control min=-1 max=1 default=0 label=\"Charge 3 sign (0 off)\"\nuniform int uLines; // @control min=4 max=32 default=16 label=\"Field lines\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Flow speed\"\nuniform vec3 uLine; // @control color default=#8FB3FF label=\"Lines\"\nuniform vec3 uPositive; // @control color default=#FF5A5F label=\"Positive\"\nuniform vec3 uNegative; // @control color default=#3FA7FF label=\"Negative\"\nuniform vec3 uBackground; // @control color default=#060912 label=\"Background\"\nuniform float uDrift; // @control min=0 max=1 default=0.3 label=\"Drift\"\nuniform bool uFollow; // @control default=true label=\"Charge 1 follows pointer\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 span = vec2(iResolution.x * px, 1.0) * 0.5;\n float t = iTime;\n vec2 c[3];\n c[0] = uCharge1 * span + vec2(sin(t * 0.7), cos(t * 0.9)) * 0.06 * uDrift;\n c[1] = uCharge2 * span + vec2(cos(t * 0.6 + 1.0), sin(t * 0.8)) * 0.06 * uDrift;\n c[2] = uCharge3 * span + vec2(sin(t * 0.5 + 2.0), cos(t * 0.4)) * 0.06 * uDrift;\n if (uFollow) c[0] = mix(c[0], (iPointer.xy - 0.5 * iResolution.xy) * px, clamp(iPointer.z, 0.0, 1.0));\n float q[3];\n q[0] = 1.0;\n q[1] = -1.0;\n q[2] = float(uThird);\n // Field lines are contours of the stream function (the charges' angles summed);\n // the potential (their log distances) spaces the dashes along them.\n float psi = 0.0;\n vec2 gradPsi = vec2(0.0);\n float phi = 0.0;\n float nearest = 1e3;\n for (int i = 0; i < 3; i++) {\n if (q[i] == 0.0) continue;\n vec2 d = p - c[i];\n float r2 = max(dot(d, d), 1e-6);\n psi += q[i] * atan(d.y, d.x);\n gradPsi += q[i] * vec2(-d.y, d.x) / r2;\n phi += q[i] * 0.5 * log(r2);\n nearest = min(nearest, sqrt(r2));\n }\n float n = float(uLines) / 6.28318;\n float v = psi * n;\n float off = abs(fract(v + 0.5) - 0.5) / max(length(gradPsi) * n * px, 1e-5);\n float line = (1.0 - smoothstep(0.4, 1.4, off)) * smoothstep(0.03, 0.09, nearest);\n float dash = fract(phi * 2.5 - t * uSpeed);\n float lit = 0.25 + 0.9 * smoothstep(0.0, 0.08, dash) * (1.0 - smoothstep(0.35, 0.5, dash));\n vec3 tint = mix(uLine, mix(uPositive, uNegative, smoothstep(-1.0, 1.0, phi)), 0.3);\n vec3 col = uBackground + uLine * 0.05 * clamp(length(gradPsi) * 0.03, 0.0, 1.0);\n col += tint * line * lit;\n // The charges: glowing discs with their signs.\n for (int i = 0; i < 3; i++) {\n if (q[i] == 0.0) continue;\n vec2 d = p - c[i];\n float r = length(d);\n vec3 cc = q[i] > 0.0 ? uPositive : uNegative;\n col += cc * (exp(-r / 0.025) * 0.8 + exp(-r / 0.1) * 0.25);\n col = mix(col, cc, smoothstep(0.035, 0.035 - px, r));\n vec2 ad = abs(d);\n float bar = max(ad.x - 0.018, ad.y - 0.004);\n if (q[i] > 0.0) bar = min(bar, max(ad.x - 0.004, ad.y - 0.018));\n col = mix(col, vec3(1.0), smoothstep(px, 0.0, bar));\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Two positives\", values: { uThird: 1, uCharge3: [0, -0.7], uLines: 20 } },\n { name: \"Three body\", values: { uThird: -1, uCharge3: [0, 0.65], uDrift: 0.8 } },\n { name: \"Blueprint\", values: { uBackground: [0.04, 0.12, 0.3], uLine: [0.85, 0.92, 1], uSpeed: 0.5 } },\n ],\n};\n\n/** Electricity: lightning, arcs, plasma and sparks. */\nexport const electricShaders: ShaderEffect[] = [\n lightning,\n teslaArc,\n plasmaBall,\n electricBorder,\n electricText,\n jacobsLadder,\n shortCircuit,\n powerSurge,\n electricField,\n];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/**\n * `meltCycle(rate)`: how melted, 0–1, over an 8 s loop: it melts (faster\n * with a higher rate), holds, then reforms back to solid before the loop\n * starts again.\n */\nconst MELT_CYCLE = `\nfloat meltCycle(float rate) {\n float u = fract(iTime / 8.0);\n float m = clamp(min(u, 0.62) * 2.0 * rate, 0.0, 1.0);\n m = m * m * (3.0 - 2.0 * m);\n return m * (1.0 - smoothstep(0.74, 0.97, u));\n}`.trim();\n\n/** `smin(a, b, k)`: a smooth minimum of two distances, blending over `k`. */\nconst SMIN = `\nfloat smin(float a, float b, float k) {\n k = max(k, 1e-4);\n float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n return mix(b, a, h) - k * h * (1.0 - h);\n}`.trim();\n\n/**\n * `liquidShade(base, n, gloss)`: a glossy liquid surface of colour `base`\n * with normal `n`, lit from the upper left.\n */\nconst LIQUID_SHADE = `\nvec3 liquidShade(vec3 base, vec3 n, float gloss) {\n vec3 l = normalize(vec3(-0.5, 0.65, 0.85));\n float diff = clamp(dot(n, l), 0.0, 1.0);\n float spec = pow(max(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0), 36.0);\n float rim = pow(1.0 - n.z, 2.0);\n return base * (0.45 + 0.7 * diff) * (1.0 - 0.35 * rim) + vec3(spec) * gloss + rim * 0.12 * gloss;\n}`.trim();\n\nexport const dripMelt: ShaderEffect = {\n kind: \"shader\",\n id: \"drip-melt\",\n name: \"Drip melt\",\n description: \"An image melting from the top edge down: columns slump, thick glossy drips run down and pool in a puddle, then it all reforms.\",\n category: \"melt\",\n tags: [\"melt\", \"image\", \"drip\", \"liquid\", \"glossy\", \"loop\"],\n loop: 8,\n source: glsl(\n `// Drip melt: the top edge slumps, glossy drips run down the picture and pool at the bottom.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uDrips; // @control min=3 max=32 default=14 label=\"Drip count\"\nuniform float uSpeed; // @control min=0.25 max=3 default=1 label=\"Melt speed\"\nuniform float uViscosity; // @control min=0.004 max=0.04 default=0.02 label=\"Viscosity (drip width)\"\nuniform float uGloss; // @control min=0 max=1.5 default=0.8 label=\"Gloss\"\nuniform vec3 uBackground; // @control color default=#17121F label=\"Behind\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.7 label=\"Melt (when still)\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n MELT_CYCLE,\n SMIN,\n LIQUID_SHADE,\n `float aspect = 1.0;\n\n// Where the picture's top edge has slumped to at x.\nfloat edgeY(float x, float m) {\n return 1.0 - m * (0.04 + 0.3 * smoothstep(0.25, 0.7, fbm(vec2(x * 3.5, 1.7), 3)));\n}\n\n// The puddle's surface at x.\nfloat poolY(float x, float m) {\n return m * (0.1 + 0.012 * sin(x * 9.0 + iTime * 0.7854) + 0.025 * vnoise(vec2(x * 6.0, 2.0))) - 0.006;\n}\n\n// Distance to the liquid (negative inside): a lip along the slumped edge, drips hanging from it, the puddle.\nfloat liquid(vec2 uv, float m) {\n float n = float(uDrips);\n float grow = smoothstep(0.0, 0.2, m);\n float e = edgeY(uv.x, m) + 0.01 * (1.0 - grow);\n float lip = 0.022 * grow;\n float d = max(uv.y - e, e - lip - uv.y);\n float c = floor(uv.x * n);\n for (int k = -2; k <= 2; k++) {\n float ci = c + float(k);\n vec2 h = hash22(vec2(ci, 3.1));\n float xi = (ci + 0.2 + 0.6 * h.x) / n;\n float w = min(uViscosity * (0.7 + 0.6 * hash12(vec2(ci, 7.7))), 0.6 * aspect / n) * grow;\n float top = edgeY(xi, m) - lip * 0.5;\n float len = pow(m, 1.4) * min(0.2 + 0.95 * h.y, 1.0) * max(top - poolY(xi, m), 0.0);\n float head = top - len;\n float along = clamp(uv.y, head, top);\n // A stem thinning as it runs, then a round, heavier head.\n float r = w * mix(0.85, 0.6, smoothstep(top, top - 0.3, uv.y));\n r = mix(r, w * 1.3, smoothstep(head + 3.0 * w, head, uv.y));\n d = smin(d, length(vec2((uv.x - xi) * aspect, uv.y - along)) - r, 0.012 * grow);\n }\n return smin(d, uv.y - poolY(uv.x, m), 0.03 * grow);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n aspect = iResolution.x / iResolution.y;\n vec2 uv = fragCoord / iResolution.xy;\n float px = 1.0 / iResolution.y;\n float m = uAnimate ? meltCycle(uSpeed) : uProgress;\n\n // The picture slumped under its edge: squashed towards the bottom, stretched thin at the top.\n float e = edgeY(uv.x, m);\n float h = clamp(uv.y / e, 0.0, 1.0);\n float ys = 1.0 - pow(1.0 - h, 1.0 + m * 1.3);\n float xs = uv.x + m * 0.006 * sin(uv.y * 40.0 + uv.x * 13.0);\n vec4 col = pictureRGBA(uImage, vec2(xs, ys));\n vec4 behind = vec4(uBackground * (0.75 + 0.5 * uv.y), uBackdropAlpha);\n col = mix(col, behind, smoothstep(e - px, e + px, uv.y));\n\n // The liquid's shadow, down and to the right.\n float shadow = liquid(uv + vec2(-0.004, 0.009), m);\n col.rgb *= 1.0 - 0.4 * smoothstep(0.012, -0.004, shadow) * smoothstep(0.0, 0.1, m);\n\n float d = liquid(uv, m);\n if (d < 4.0 * px) {\n float eps = 0.0015;\n vec2 g = vec2(liquid(uv + vec2(eps / aspect, 0.0), m) - d, liquid(uv + vec2(0.0, eps), m) - d);\n g /= max(length(g), 1e-5);\n float thick = sqrt(clamp(-d / 0.018, 0.0, 1.0));\n vec3 nrm = normalize(vec3(g * (1.0 - thick) * 1.6, 0.4 + thick));\n // Drips carry the colour of the top edge down; the puddle is everything mixed.\n vec4 top = pictureRGBA(uImage, vec2(uv.x + 0.01 * sin(uv.y * 25.0), 0.965));\n float sx = uv.x + 0.04 * sin(uv.x * 11.0 + uv.y * 30.0);\n vec4 pool = (pictureRGBA(uImage, vec2(sx - 0.06, 0.25)) + pictureRGBA(uImage, vec2(sx + 0.06, 0.4)) + pictureRGBA(uImage, vec2(sx, 0.9))) / 3.0;\n float inPool = smoothstep(poolY(uv.x, m) + 0.04, poolY(uv.x, m) - 0.01, uv.y);\n vec4 base = mix(top, pool, inPool);\n base.rgb *= 0.9 + 0.12 * vnoise(vec2(uv.x * 90.0, uv.y * 3.0));\n vec3 wet = liquidShade(base.rgb * 1.05, nrm, uGloss);\n col = mix(col, vec4(wet, base.a), smoothstep(px, -px, d));\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Meltdown\", values: { uDrips: 22, uSpeed: 1.6, uViscosity: 0.012, uGloss: 1 } },\n { name: \"Syrup\", values: { uDrips: 7, uSpeed: 0.6, uViscosity: 0.032, uGloss: 1.3 } },\n { name: \"City at night\", values: { uImage: SAMPLE_IMAGES.city, uBackground: [0.02, 0.02, 0.05] } },\n ],\n};\n\nexport const heatHaze: ShaderEffect = {\n kind: \"shader\",\n id: \"heat-haze\",\n name: \"Heat haze\",\n description: \"A mirage shimmer rising off a hot image: wavering refraction strongest near the ground, with a warm tint and a faint reflection.\",\n category: \"melt\",\n tags: [\"melt\", \"image\", \"heat\", \"mirage\", \"shimmer\", \"desert\", \"distortion\"],\n source: glsl(\n `// Heat haze: rising, wavering refraction over a picture, strongest near the bottom.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uStrength; // @control min=0 max=1 default=0.5 label=\"Strength\"\nuniform float uScale; // @control min=1 max=20 default=7 label=\"Scale\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uHeight; // @control min=0.1 max=1 default=0.8 label=\"Height\"\nuniform vec3 uTint; // @control color default=#FFB070 label=\"Warm tint\"\nuniform float uWarmth; // @control min=0 max=1 default=0.3 label=\"Tint amount\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float aspect = iResolution.x / iResolution.y;\n float t = iTime * uSpeed;\n float heat = smoothstep(uHeight, 0.0, uv.y);\n // Rising turbulence, stretched upwards, and a fast horizontal waver through it.\n vec2 q = vec2(uv.x * aspect * uScale, uv.y * uScale * 1.6 - t * 1.4);\n float a = fbm(q, 4);\n float b = fbm(q + vec2(5.2, 1.3) + a, 4);\n vec2 off = vec2(a - 0.5, b - 0.5) * 0.05;\n off.x += sin(uv.y * uScale * 14.0 - t * 5.0 + a * 6.0) * 0.01;\n off *= uStrength * heat;\n vec2 st = uv + off;\n // A touch of colour fringing where the air bends light the most.\n float fringe = 0.25 * length(off);\n vec4 r = pictureRGBA(uImage, st + vec2(fringe, 0.0));\n vec4 g = pictureRGBA(uImage, st);\n vec4 b2 = pictureRGBA(uImage, st - vec2(fringe, 0.0));\n vec3 col = vec3(r.r, g.g, b2.b);\n float alpha = max(max(r.a, g.a), b2.a);\n // An inferior mirage: just above the ground, what sits above it shows again, flipped and shimmering.\n float y0 = 0.05 + 0.15 * uHeight;\n float below = smoothstep(y0, 0.0, uv.y) * (0.6 + 0.4 * b);\n vec4 mirage = pictureRGBA(uImage, vec2(st.x, y0 + (y0 - uv.y) * 1.4 + off.y * 2.0));\n col = mix(col, mirage.rgb, below * uStrength * 0.55);\n alpha = mix(alpha, mirage.a, below * uStrength * 0.55);\n // Warm, slightly hazy air.\n col = mix(col, col * mix(vec3(1.0), uTint * 1.35, uWarmth), heat);\n col = mix(col, uTint, heat * uWarmth * 0.12 * (0.7 + 0.6 * a));\n fragColor = vec4(col, alpha);\n}`,\n ),\n presets: [\n { name: \"Desert noon\", values: { uStrength: 0.85, uScale: 9, uHeight: 0.75, uWarmth: 0.55 } },\n { name: \"Asphalt\", values: { uStrength: 0.6, uScale: 14, uSpeed: 1.8, uHeight: 0.35, uWarmth: 0.15, uTint: [1, 0.85, 0.7] } },\n { name: \"City exhaust\", values: { uImage: SAMPLE_IMAGES.city, uStrength: 0.5, uHeight: 0.5, uTint: [0.75, 0.85, 1], uWarmth: 0.2 } },\n ],\n};\n\nexport const waxMelt: ShaderEffect = {\n kind: \"shader\",\n id: \"wax-melt\",\n name: \"Wax melt\",\n description: \"A silhouette softening like warm wax: its edges round off, its top sags and it slumps into a glossy puddle, then sets again.\",\n category: \"melt\",\n tags: [\"melt\", \"wax\", \"text\", \"silhouette\", \"glossy\", \"loop\"],\n loop: 8,\n source: glsl(\n `// Wax melt: an alpha mask softening, sagging and spreading into a puddle.\nuniform sampler2D uMask; // @control filter=linear wrap=clamp default=${textImage(\"WAX\")} label=\"Shape (alpha)\"\nuniform vec3 uColor; // @control color default=#E8452C label=\"Wax\"\nuniform vec3 uBackground; // @control color default=#1C1A22 label=\"Background\"\nuniform float uGloss; // @control min=0 max=1.5 default=0.8 label=\"Gloss\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Size\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.6 label=\"Melt (when still)\"`,\n HASH,\n NOISE,\n FBM,\n MELT_CYCLE,\n LIQUID_SHADE,\n `const float BASE = -0.14;\n\n// The mask's alpha at frame point s (height 1, centred), contained in uSize of the frame.\nfloat shape(vec2 s, out float halfWidth, out float bottom) {\n vec2 size = vec2(textureSize(uMask, 0));\n float aspect = size.x / max(size.y, 1.0);\n float frame = iResolution.x / iResolution.y;\n float h = min(uSize * 0.7, frame * uSize / aspect);\n halfWidth = 0.42 * h * aspect;\n // A text image's letters sit on a line about 0.27 of its height below the middle.\n bottom = -0.27 * h;\n vec2 uv = s / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uMask, uv).a;\n}\n\n// How much wax covers frame point p, 0–1, soft at the edges (softer still by soft): the sagging, spreading shape and its puddle.\nfloat wax(vec2 p, float m, float soft) {\n float halfWidth;\n float bottom;\n shape(vec2(0.0), halfWidth, bottom);\n float dy = p.y - BASE;\n // The top sags (more in some places than others), the base spreads, and it wobbles a little as it goes.\n float sag = 1.0 + (0.25 * m + 1.6 * m * m * m) * (0.6 + 0.8 * fbm(vec2(p.x * 3.0, 4.0), 3));\n float spread = 1.0 + m * 0.4 * exp(-max(dy, 0.0) * 7.0);\n vec2 s = vec2(p.x / spread + m * 0.012 * sin(dy * 30.0 + p.x * 8.0), bottom + dy * sag);\n // Softened: the mask averaged over a disc that widens as it melts, so corners round off.\n float r = 0.004 + 0.022 * m + soft;\n float sum = shape(s, halfWidth, bottom) * 2.0;\n for (int i = 0; i < 6; i++) {\n float a = float(i) * 1.0472;\n vec2 dir = vec2(cos(a), sin(a));\n sum += shape(s + dir * r * 0.5, halfWidth, bottom) + shape(s + dir.yx * vec2(-1.0, 1.0) * r, halfWidth, bottom);\n }\n float cover = dy < 0.0 ? 0.0 : sum / 14.0;\n // The puddle, growing out from under the shape, its rim lumpy.\n float rx = halfWidth * (0.25 + 0.8 * m);\n float ry = (0.008 + 0.05 * m) * (1.0 + 0.15 * sin(p.x * 17.0 + 1.0));\n vec2 e = vec2(p.x / rx, (p.y - BASE) / ry);\n float pool = smoothstep(0.012 + soft, -0.012 - soft, (length(e) - 1.0) * ry) * smoothstep(0.03, 0.25, m);\n return cover + pool - cover * pool;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float m = uAnimate ? meltCycle(1.0) : uProgress;\n // Background: a soft spot of light on a table top.\n vec3 col = uBackground * (1.0 + 0.6 * exp(-dot(p, p) * 3.0));\n col = mix(col, uBackground * 0.6, smoothstep(BASE + 0.02, BASE - 0.1, p.y));\n float shade = wax(p + vec2(-0.012, 0.02), m, 0.01);\n col *= 1.0 - 0.45 * smoothstep(0.2, 0.7, shade) * smoothstep(BASE + 0.25, BASE - 0.05, p.y);\n\n float c = wax(p, m, 0.0);\n float px = 1.5 / iResolution.y;\n float edge = smoothstep(0.5 - 0.06, 0.5 + 0.06, c);\n if (c > 0.3) {\n // The surface's slope from a softer copy, so the letters bulge like poured wax.\n float eps = 0.01;\n float soft = 0.014;\n vec2 g = vec2(wax(p + vec2(eps, 0.0), m, soft) - wax(p - vec2(eps, 0.0), m, soft), wax(p + vec2(0.0, eps), m, soft) - wax(p - vec2(0.0, eps), m, soft)) / (2.0 * eps);\n float thick = smoothstep(0.3, 1.0, c);\n vec3 nrm = normalize(vec3(-g * 0.03, 1.0));\n // Thin wax lets light through: warmer and brighter at the edges, deeper in the middle.\n vec3 deep = uColor * 0.7;\n vec3 glow = min(uColor * uColor * 1.6 + vec3(0.08, 0.03, 0.0), vec3(1.0));\n vec3 base = mix(glow, deep, thick);\n vec3 lit = liquidShade(base, nrm, uGloss * (0.35 + 0.65 * m));\n col = mix(col, lit, edge);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Beeswax\", values: { uColor: [0.95, 0.75, 0.32], uBackground: [0.12, 0.09, 0.06] } },\n { name: \"Candle white\", values: { uColor: [0.95, 0.92, 0.85], uBackground: [0.08, 0.09, 0.14], uGloss: 1.1 } },\n { name: \"Heart\", values: { uMask: SAMPLE_IMAGES.heart, uColor: [0.86, 0.12, 0.28], uSize: 0.6 } },\n ],\n};\n\nexport const meltingText: ShaderEffect = {\n kind: \"shader\",\n id: \"melting-text\",\n name: \"Melting text\",\n description: \"Letters sagging and stretching downwards as long glossy drips run from their bottoms and droplets break off and fall.\",\n category: \"melt\",\n tags: [\"melt\", \"text\", \"title\", \"drip\", \"liquid\", \"glossy\", \"loop\"],\n loop: 8,\n transparent: true,\n source: glsl(\n `// Melting text: letters sag, drips run from their bottoms, droplets fall.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"MELT\")} label=\"Text\"\nuniform vec3 uColor; // @control color default=#FF3D6E label=\"Liquid\"\nuniform vec3 uHighlight; // @control color default=#FFFFFF label=\"Highlight\"\nuniform float uGloss; // @control min=0 max=1.5 default=0.9 label=\"Gloss\"\nuniform float uDrip; // @control min=0.2 max=1.5 default=1 label=\"Drip length\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Text size\"\nuniform vec3 uBackground; // @control color default=#120E1A label=\"Background\"\nuniform float uBackgroundAlpha; // @control min=0 max=1 default=0 label=\"Background opacity\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.7 label=\"Melt (when still)\"`,\n HASH,\n NOISE,\n FBM,\n MELT_CYCLE,\n SMIN,\n `const float RAISE = 0.14;\nfloat textH = 0.3;\nfloat textW = 1.0;\n\n// The text image's alpha at frame point p (text raised by RAISE to leave room for drips).\nfloat letters(vec2 p) {\n vec2 uv = (p - vec2(0.0, RAISE)) / vec2(textW, textH) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uText, uv).a;\n}\n\n// Distance to the liquid (about; negative inside) at frame point p, m of the way melted.\nfloat liquid(vec2 p, float m) {\n float top = RAISE + 0.29 * textH;\n float baseline = RAISE - 0.24 * textH;\n // Letters stretch down from their tops, some columns further than others.\n float stretch = 1.0 + m * (0.25 + 0.35 * fbm(vec2(p.x * 4.0, 1.0), 3));\n vec2 s = vec2(p.x + m * 0.008 * sin(p.y * 30.0), top - (top - p.y) / stretch);\n float r = 0.003 + 0.006 * m;\n float cover = letters(s) * 2.0;\n for (int i = 0; i < 4; i++) {\n float a = float(i) * 1.5708 + 0.785;\n cover += letters(s + vec2(cos(a), sin(a)) * r);\n }\n cover /= 6.0;\n float d = (0.5 - cover) * 0.02;\n // Drips from the bottoms of the letters, each with a droplet that breaks off now and then.\n float grow = smoothstep(0.0, 0.25, m);\n float cell = 0.13 * textH;\n float c = floor(p.x / cell);\n for (int k = -1; k <= 1; k++) {\n float ci = c + float(k);\n vec2 h = hash22(vec2(ci, 11.3));\n float xi = (ci + 0.25 + 0.5 * h.x) * cell;\n float colStretch = 1.0 + m * (0.25 + 0.35 * fbm(vec2(xi * 4.0, 1.0), 3));\n float root = top - (top - baseline) * colStretch;\n // Only where a letter stands on the line, and not every one.\n float on = step(0.5, letters(vec2(xi, baseline + 0.04 * textH))) * step(0.25, hash12(vec2(ci, 2.7)));\n if (on < 0.5) continue;\n float w = textH * (0.03 + 0.025 * h.y) * grow;\n float len = uDrip * pow(m, 1.3) * (0.06 + 0.3 * hash12(vec2(ci, 5.9)));\n float head = root - len;\n float along = clamp(p.y, head, root + 0.06 * textH);\n float rr = w * mix(1.0, 0.6, smoothstep(root, root - 0.08, p.y));\n rr = mix(rr, w * 1.25, smoothstep(head + 2.5 * w, head, p.y));\n d = smin(d, length(vec2(p.x - xi, p.y - along)) - rr, 0.01 * grow);\n // The droplet: swells at the tip, lets go and falls, every 2 s once it is well melted.\n float phase = fract(iTime * 0.5 + h.y);\n float fall = phase * phase * 1.4;\n float drop = w * 1.1 * smoothstep(0.35, 0.65, m) * step(0.5, hash12(vec2(ci, 8.1)));\n d = min(d, length(vec2(p.x - xi, p.y - (head - w * 1.8 - fall))) - drop * (1.0 - 0.3 * phase));\n }\n return d;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float frame = iResolution.x / iResolution.y;\n textH = min(uSize * 0.6, frame * uSize / aspect);\n textW = textH * aspect;\n float m = uAnimate ? meltCycle(1.0) : uProgress;\n float px = 1.0 / iResolution.y;\n\n float d = liquid(p, m);\n float cover = smoothstep(px, -px, d);\n vec4 col = vec4(uBackground, uBackgroundAlpha);\n if (d < 2.0 * px) {\n float eps = 0.0015;\n vec2 g = vec2(liquid(p + vec2(eps, 0.0), m) - d, liquid(p + vec2(0.0, eps), m) - d);\n g /= max(length(g), 1e-5);\n float thick = sqrt(clamp(-d / 0.012, 0.0, 1.0));\n vec3 n = normalize(vec3(g * (1.0 - thick) * 1.8, 0.35 + thick));\n vec3 l = normalize(vec3(-0.5, 0.7, 0.8));\n float diff = clamp(dot(n, l), 0.0, 1.0);\n float spec = pow(max(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0), 40.0);\n // Darker and richer where it runs thin, like a coloured syrup.\n vec3 body = mix(uColor * uColor * 0.8, uColor, thick) * (0.5 + 0.65 * diff);\n body += uHighlight * (spec * uGloss + pow(1.0 - n.z, 3.0) * 0.15 * uGloss);\n col = mix(col, vec4(body, 1.0), cover);\n }\n fragColor = vec4(col.rgb, col.a);\n}`,\n ),\n presets: [\n { name: \"Slime\", values: { uColor: [0.45, 0.9, 0.2], uHighlight: [0.9, 1, 0.8], uDrip: 1.3 } },\n { name: \"Chocolate\", values: { uText: textImage(\"SWEET\"), uColor: [0.42, 0.22, 0.12], uHighlight: [1, 0.9, 0.8], uBackground: [0.98, 0.93, 0.85], uBackgroundAlpha: 1 } },\n { name: \"Gold\", values: { uColor: [1, 0.76, 0.25], uHighlight: [1, 0.98, 0.85], uGloss: 1.3, uBackgroundAlpha: 1 } },\n ],\n};\n\nexport const liquify: ShaderEffect = {\n kind: \"shader\",\n id: \"liquify\",\n name: \"Liquify\",\n description: \"An image pushed and smeared like wet paint by a moving brush (or the pointer), the smears slowly relaxing back.\",\n category: \"melt\",\n tags: [\"melt\", \"image\", \"liquify\", \"smear\", \"paint\", \"interactive\", \"hover\"],\n source: glsl(\n `// Liquify: a brush pushes the picture around; its recent path leaves smears that relax over time.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uBrush; // @control min=0.05 max=0.5 default=0.17 label=\"Brush size\"\nuniform float uStrength; // @control min=0 max=2 default=0.8 label=\"Strength\"\nuniform float uRelax; // @control min=0.2 max=5 default=1.2 label=\"Relax\"\nuniform float uSpeed; // @control min=0 max=2 default=1 label=\"Brush speed\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// The brush at time t (frame units, height 1): a Lissajous path, or stirring round the pointer while it hovers.\nvec2 brush(float t) {\n float aspect = iResolution.x / iResolution.y;\n vec2 path = vec2(0.36 * aspect * sin(t * 0.9), 0.3 * sin(t * 1.37 + 0.6));\n vec2 pointer = (iPointer.xy - 0.5 * iResolution.xy) / iResolution.y;\n vec2 stir = pointer + 0.05 * vec2(cos(t * 4.0), sin(t * 4.0));\n return mix(path, stir, iPointer.z);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed * 1.4;\n float dt = 0.14;\n vec2 disp = vec2(0.0);\n float wet = 0.0;\n // Each of the brush's recent places pushes paint the way it was going and twists it a little, fading as it relaxes.\n for (int k = 0; k < 10; k++) {\n float tk = t - float(k) * dt;\n vec2 b = brush(tk);\n vec2 v = b - brush(tk - dt);\n vec2 d = p - disp - b;\n float f = exp(-dot(d, d) / (uBrush * uBrush));\n float fade = exp(-float(k) * dt * uRelax / max(uSpeed * 1.4, 0.05));\n vec2 twist = vec2(-d.y, d.x) * length(v) * 4.0;\n disp += (v * 1.3 + twist) * f * fade * uStrength;\n wet += f * fade;\n }\n vec2 uv = (p - disp) * vec2(iResolution.y / iResolution.x, 1.0) + 0.5;\n vec4 pic = pictureRGBA(uImage, uv);\n // Wet paint catches a little light along the smears.\n float sheen = clamp(dot(disp, normalize(vec2(-0.6, 0.8))) * 12.0, -1.0, 1.0);\n vec3 col = pic.rgb * (1.0 + 0.05 * sheen * min(wet, 1.0) * min(uStrength, 1.0));\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Finger paint\", values: { uBrush: 0.25, uStrength: 1.6, uRelax: 0.5 } },\n { name: \"Quick flick\", values: { uBrush: 0.1, uStrength: 0.8, uRelax: 3, uSpeed: 1.8 } },\n { name: \"Landscape\", values: { uImage: SAMPLE_IMAGES.landscape, uStrength: 1.2 } },\n ],\n};\n\nexport const daliClock: ShaderEffect = {\n kind: \"shader\",\n id: \"dali-clock\",\n name: \"Melting clock\",\n description: \"A pocket-watch face draped over a ledge like Dalí's soft clocks, its lower half hanging and stretching as the hands keep turning.\",\n category: \"melt\",\n tags: [\"melt\", \"clock\", \"surreal\", \"dali\", \"time\", \"desert\"],\n source: glsl(\n `// Melting clock: a clock face drooping over a ledge in a desert.\nuniform vec3 uSkyTop; // @control color default=#24467E label=\"Sky\"\nuniform vec3 uHorizon; // @control color default=#F2C48D label=\"Horizon\"\nuniform vec3 uSand; // @control color default=#B98B57 label=\"Sand\"\nuniform vec3 uLedge; // @control color default=#5E4434 label=\"Ledge\"\nuniform vec3 uFace; // @control color default=#F1E6CC label=\"Clock face\"\nuniform vec3 uCase; // @control color default=#C9A048 label=\"Clock case\"\nuniform float uSag; // @control min=0 max=1.5 default=1 label=\"Droop\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Clock speed\"`,\n HASH,\n NOISE,\n FBM,\n `const float LEDGE_Y = 0.0;\nconst float LEDGE_X = 0.42;\nconst float R = 0.24;\nconst vec2 CENTRE = vec2(0.14, -0.02);\n\n// Clock-face point (relative to CENTRE, unmelted) shown at frame point w; .z is how far it hangs, 0 on the ledge.\nvec3 unmelt(vec2 w) {\n float sag = uSag;\n if (w.y >= LEDGE_Y) {\n // Lying back on the ledge top: foreshortened.\n return vec3(w.x - CENTRE.x, LEDGE_Y + (w.y - LEDGE_Y) / 0.5 - CENTRE.y, 0.0);\n }\n // Hanging: material further down is stretched more, narrows, sways and ripples.\n float d = LEDGE_Y - w.y;\n float k = 2.4 * sag + 1e-3;\n float u = (-1.0 + sqrt(1.0 + 4.0 * k * d)) / (2.0 * k);\n float sway = (0.05 * sin(iTime * 0.9) + 0.02 * sin(iTime * 2.1)) * sag * u * u * 8.0;\n float x = w.x - sway - 0.012 * sag * sin(u * 25.0 + iTime);\n float narrow = 1.0 + 0.75 * sag * smoothstep(0.0, R * 1.2, u) * u / R;\n return vec3((x - CENTRE.x) * narrow, LEDGE_Y - u - CENTRE.y, u);\n}\n\n// The clock at face point q: rgb, coverage in a.\nvec4 clockFace(vec2 q, float aa) {\n float r = length(q);\n float ang = atan(q.x, q.y);\n // Winding crown at twelve.\n float crown = max(abs(q.x) - 0.025, abs(q.y - R - 0.025) - 0.022);\n float body = min(r - R, crown);\n float cover = smoothstep(aa, -aa, body);\n if (cover <= 0.0) return vec4(0.0);\n vec3 col = uFace * (1.0 - 0.18 * smoothstep(0.4 * R, R, r));\n // Hour ticks (long at the quarters) and minute ticks.\n float hourA = ang / 0.5236;\n float hourD = abs(hourA - floor(hourA + 0.5)) * 0.5236 * r;\n float quarter = step(mod(floor(hourA + 0.5), 3.0), 0.5);\n float hourTick = smoothstep(0.012 + 0.006 * quarter + aa, 0.012 + 0.006 * quarter - aa, hourD) * step(R * (0.68 - 0.08 * quarter), r) * step(r, R * 0.86);\n float minA = ang / 0.10472;\n float minD = abs(minA - floor(minA + 0.5)) * 0.10472 * r;\n float minTick = smoothstep(0.003 + aa, 0.003 - aa, minD) * step(R * 0.8, r) * step(r, R * 0.86);\n col = mix(col, vec3(0.12, 0.1, 0.09), max(hourTick, minTick));\n // Hands: the minute hand goes round in 12 s, the hour hand in 144 s, the second hand in 4 s.\n float t = iTime * uSpeed;\n for (int i = 0; i < 3; i++) {\n float a = i == 0 ? t * 0.5236 / 12.0 : i == 1 ? t * 0.5236 : t * 1.5708;\n float len = i == 0 ? 0.5 * R : i == 1 ? 0.75 * R : 0.8 * R;\n float width = i == 0 ? 0.012 : i == 1 ? 0.008 : 0.003;\n vec2 dir = vec2(sin(a), cos(a));\n float along = clamp(dot(q, dir), -0.04, len);\n float hd = length(q - dir * along) - width;\n vec3 ink = i == 2 ? vec3(0.7, 0.15, 0.1) : vec3(0.1, 0.09, 0.08);\n col = mix(col, ink, smoothstep(aa, -aa, hd));\n }\n col = mix(col, uCase * 0.7, smoothstep(aa, -aa, r - 0.014));\n // The case: a bevelled ring and the crown.\n float ringD = max(body, -(r - R * 0.9));\n float bevel = 0.75 + 0.5 * dot(normalize(q + 1e-5), normalize(vec2(-0.6, 0.8)));\n col = mix(col, uCase * bevel, smoothstep(aa, -aa, min(ringD, crown)));\n return vec4(col, cover);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 w = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aa = 1.5 / iResolution.y;\n // Desert: sky, far cliffs and sand.\n float horizon = -0.18;\n vec3 col = mix(uHorizon, uSkyTop, smoothstep(horizon, 0.5, w.y));\n float cliffs = horizon + 0.05 + 0.12 * fbm(vec2(w.x * 2.5 + 3.0, 0.0), 4) * smoothstep(-0.2, 0.9, w.x);\n col = mix(col, mix(uSand, uSkyTop, 0.35) * 0.9, smoothstep(aa, -aa, w.y - cliffs));\n col = mix(col, uSand * (0.75 + 0.5 * smoothstep(-0.5, horizon, w.y)), smoothstep(aa, -aa, w.y - horizon));\n // The ledge: a block with a lit top and a front face in shade.\n float top = LEDGE_Y + 0.15;\n float inBlock = step(w.x, LEDGE_X);\n col = mix(col, uLedge * 1.35, inBlock * smoothstep(aa, -aa, w.y - top) * smoothstep(-aa, aa, w.y - LEDGE_Y));\n col = mix(col, uLedge * (0.8 - 0.3 * smoothstep(LEDGE_Y, -0.5, w.y)), inBlock * smoothstep(aa, -aa, w.y - LEDGE_Y));\n col = mix(col, uLedge * 0.5, smoothstep(aa, -aa, abs(w.x - LEDGE_X) - 0.002) * step(w.y, top));\n // The clock's shadow on the ledge, then the clock.\n vec3 sq = unmelt(w + vec2(-0.03, 0.025));\n float shadow = smoothstep(0.01, -0.01, length(sq.xy) - R) * inBlock;\n col *= 1.0 - 0.4 * shadow * step(w.y, top);\n vec3 q = unmelt(w);\n float stretch = 1.0 + q.z * 6.0 * uSag;\n vec4 clock = clockFace(q.xy, aa * stretch);\n // Shade the fold at the ledge's edge and the far side of the hanging part.\n float fold = exp(-pow((w.y - LEDGE_Y) / 0.02, 2.0));\n clock.rgb *= (q.z > 0.0 ? 0.88 - 0.2 * smoothstep(0.0, 0.3, q.z) : 1.0) * (1.0 - 0.3 * fold);\n clock.rgb += 0.15 * fold * smoothstep(LEDGE_Y - 0.01, LEDGE_Y + 0.02, w.y);\n col = mix(col, clock.rgb, clock.a);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Dusk\", values: { uSkyTop: [0.17, 0.12, 0.35], uHorizon: [0.98, 0.55, 0.4], uSand: [0.55, 0.36, 0.3] } },\n { name: \"Very soft\", values: { uSag: 1.5, uSpeed: 0.4 } },\n ],\n};\n\nexport const lavaFlow: ShaderEffect = {\n kind: \"shader\",\n id: \"lava-flow\",\n name: \"Lava flow\",\n description: \"Glowing molten rock oozing downhill, dark cooling crust plates cracking apart over bright flowing lava.\",\n category: \"melt\",\n tags: [\"melt\", \"lava\", \"fire\", \"volcano\", \"glow\", \"background\"],\n source: glsl(\n `// Lava flow: crust plates (Voronoi cells) drifting downhill over brighter, faster lava.\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Flow speed\"\nuniform float uCrust; // @control min=0 max=1 default=0.6 label=\"Crust\"\nuniform float uScale; // @control min=2 max=12 default=5 label=\"Scale\"\nuniform vec3 uHot; // @control color default=#FFE27A label=\"Hottest\"\nuniform vec3 uLava; // @control color default=#FF4A0A label=\"Lava\"\nuniform vec3 uCrustColor; // @control color default=#1C1310 label=\"Crust colour\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Heat glow\"`,\n HASH,\n NOISE,\n FBM,\n `// Voronoi of slowly shifting points: x = distance to the nearest edge (about), y = the cell's id hash.\nvec2 plates(vec2 q, float t) {\n vec2 cell = floor(q);\n vec2 f = fract(q);\n float d1 = 8.0;\n float d2 = 8.0;\n vec2 nearest = vec2(0.0);\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 g = vec2(float(x), float(y));\n vec2 h = hash22(cell + g);\n vec2 o = g + 0.5 + 0.38 * sin(t * 0.6 + 6.2831 * h) - f;\n float d = dot(o, o);\n if (d < d1) { d2 = d1; d1 = d; nearest = cell + g; }\n else if (d < d2) d2 = d;\n }\n }\n return vec2(sqrt(d2) - sqrt(d1), hash12(nearest));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float t = iTime * uSpeed;\n // Downhill is down the screen; the warp makes it flow sluggishly round obstacles.\n vec2 flow = vec2(0.0, t * 0.35);\n vec2 warp = vec2(fbm(p * 2.0 + flow * 0.6, 3), fbm(p * 2.0 + flow * 0.6 + 7.3, 3)) - 0.5;\n vec2 q = p * uScale + warp * 1.6 + flow * uScale * 0.3;\n vec2 v = plates(q, t);\n // The molten lava under the crust flows faster and churns.\n float churn = fbm(p * uScale * 0.9 + vec2(0.0, t * 0.9) + warp * 3.0, 5);\n vec3 lava = mix(uLava * 0.45, uLava, smoothstep(0.3, 0.5, churn));\n lava = mix(lava, uHot, smoothstep(0.55, 0.8, churn));\n // Cracks open wider where there is less crust; some plates melt through entirely.\n float crack = mix(0.3, 0.02, uCrust) * (0.6 + 0.8 * fbm(q * 0.7 + 3.0, 2));\n float molten = step(0.55 + 0.45 * uCrust, v.y);\n float crust = smoothstep(crack, crack + 0.06, v.x) * (1.0 - molten);\n // Crust: rough, dark, glowing dull red near the cracks and in its pores.\n float rough = fbm(q * 4.0, 3);\n float heat = exp(-max(v.x - crack, 0.0) * 6.0);\n vec3 rock = uCrustColor * (0.5 + 1.2 * rough) + uLava * heat * 0.6 * uGlow;\n rock += uLava * 0.3 * uGlow * smoothstep(0.62, 0.8, rough) * (1.0 - smoothstep(0.0, 0.4, v.x));\n vec3 col = mix(lava, rock, crust);\n // The glow of the cracks lighting the air.\n col += uHot * 0.2 * uGlow * (1.0 - crust) * smoothstep(0.5, 0.9, churn);\n col = min(col, vec3(1.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Fresh flow\", values: { uCrust: 0.3, uSpeed: 0.9, uGlow: 1.4 } },\n { name: \"Cooling field\", values: { uCrust: 0.9, uSpeed: 0.2, uScale: 7 } },\n { name: \"Blue lava\", values: { uHot: [0.85, 0.98, 1], uLava: [0.15, 0.45, 1], uCrustColor: [0.05, 0.06, 0.1] } },\n ],\n};\n\n/** Melting: drips, heat haze, wax and liquefying shapes. */\nexport const meltShaders: ShaderEffect[] = [dripMelt, heatHaze, waxMelt, meltingText, liquify, daliClock, lavaFlow];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/*\n * Pyrotechnics. Sparks are light: each overlay sums its sparks into an HDR\n * colour and writes it with `glow`, whose alpha is the brightest channel, so\n * they brighten whatever is under them. Particles fly ballistically with air\n * drag (`ballistic`), so bursts slow down and droop the way real ones do.\n * Fireworks and explosions also read `iClicks` (xy pixels, z the `iTime` of\n * the click, w 1 for a click), the built-in the wrapper declares.\n */\n\n/**\n * `glow(c)`: light as a colour over whatever is behind it. Its alpha is its\n * brightest channel, so it brightens what is under it like a screen blend.\n */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/**\n * `over(acc, colour, alpha)`: paints a colour over a premultiplied\n * accumulator; `unpremultiply(acc)` turns it into straight colour and coverage.\n */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\n/**\n * `ballistic(v, k, g, t)`: how far a particle launched at velocity `v` has\n * moved after `t` seconds, slowed by air drag `k` and pulled down by gravity\n * `g`. `streak(p, tail, head, w)`: a spark's streak of width `w`, brightest\n * at its head.\n */\nconst PARTICLE = `\nvec2 ballistic(vec2 v, float k, float g, float t) {\n float e = (1.0 - exp(-k * t)) / k;\n return v * e - vec2(0.0, g / k * (t - e));\n}\nvec2 segment(vec2 p, vec2 a, vec2 b) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-9), 0.0, 1.0);\n return vec2(length(pa - ba * h), h);\n}\nfloat streak(vec2 p, vec2 tail, vec2 head, float w) {\n vec2 s = segment(p, tail, head);\n float along = mix(0.08, 1.0, s.y * s.y);\n return (exp(-s.x * s.x / (w * w)) + 0.12 * exp(-s.x / (w * 3.0))) * along;\n}`.trim();\n\nexport const fireworks: ShaderEffect = {\n kind: \"shader\",\n id: \"fireworks\",\n name: \"Fireworks\",\n description: \"Shells rising on faint trails and bursting into peonies, chrysanthemums, gold willows and rings that droop and twinkle out; clicks fire more.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"fireworks\", \"celebration\", \"festive\", \"night\", \"click\"],\n transparent: true,\n source: glsl(\n `// Fireworks: staggered shells rising and bursting into peony, chrysanthemum, willow and ring patterns.\nuniform vec3 uColorA; // @control color default=#FF4D6D label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#4DD9FF label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#B98CFF label=\"Colour C\"\nuniform vec3 uGold; // @control color default=#FFB347 label=\"Willow gold\"\nuniform float uRate; // @control min=0.2 max=1.6 default=0.8 label=\"Shells per second\"\nuniform float uSize; // @control min=0.3 max=2 default=1 label=\"Burst size\"\nuniform float uGravity; // @control min=0 max=2 default=1 label=\"Gravity\"\nuniform float uTrail; // @control min=0 max=2 default=1 label=\"Trail length\"\nuniform float uBrightness; // @control min=0.2 max=3 default=1 label=\"Brightness\"`,\n HASH,\n GLOW,\n PARTICLE,\n `vec3 pick(float h) {\n return h < 0.333 ? uColorA : (h < 0.667 ? uColorB : uColorC);\n}\n\n// One burst at c, tb seconds after it bursts. Types: 0 peony, 1 chrysanthemum, 2 willow, 3 ring.\nvec3 burst(vec2 p, vec2 c, float tb, float seed, float px) {\n vec4 h = vec4(hash22(vec2(seed, 1.7)), hash22(vec2(seed, 8.3)));\n int type = int(floor(h.x * 4.0));\n bool willow = type == 2;\n float life = willow ? 3.4 : (type == 1 ? 2.4 : 1.9);\n if (tb < 0.0 || tb > life) return vec3(0.0);\n float speed = (willow ? 0.5 : 0.75) * (0.85 + 0.3 * h.y) * uSize;\n float k = willow ? 2.2 : 3.2;\n float g = 0.32 * uGravity;\n float trail = (type == 0 ? 0.05 : (type == 1 ? 0.28 : (willow ? 0.7 : 0.06))) * uTrail;\n // Skip pixels nowhere near the burst: everything lies within reach of its falling centre.\n float e = (1.0 - exp(-k * tb)) / k;\n float drop = g / k * (tb - e);\n if (length(p - c + vec2(0.0, drop * 0.5)) > speed * e + drop * 0.6 + 0.06) return vec3(0.0);\n vec3 primary = willow ? uGold : pick(h.z);\n vec3 second = pick(fract(h.z + 0.4));\n bool twoTone = h.w > 0.5 && !willow;\n float fade = 1.0 - smoothstep(life * 0.5, life, tb);\n float cool = smoothstep(0.0, 0.3, tb);\n float w = max(0.0028, 1.1 * px);\n float tilt = 0.25 + 0.6 * h.w;\n vec2 ringAxis = vec2(cos(h.y * 6.28), sin(h.y * 6.28));\n vec3 col = vec3(0.0);\n for (int j = 0; j < 44; j++) {\n float fj = float(j);\n vec2 r = hash22(vec2(fj * 1.31 + 0.7, seed));\n float a = r.x * 6.28318;\n vec2 dir;\n if (type == 3) {\n // A ring: a circle of stars in a tilted plane.\n a = (fj + 0.3 * r.y) / 44.0 * 6.28318;\n vec2 u = vec2(cos(a), sin(a) * tilt);\n dir = vec2(u.x * ringAxis.x - u.y * ringAxis.y, u.x * ringAxis.y + u.y * ringAxis.x) * (0.95 + 0.05 * r.y);\n } else {\n // A sphere of stars seen side on: denser towards the middle.\n float z = 2.0 * r.y - 1.0;\n dir = vec2(cos(a), sin(a)) * sqrt(1.0 - z * z) * (0.9 + 0.1 * hash12(vec2(fj, seed + 3.0)));\n }\n vec2 v = dir * speed;\n vec2 head = c + ballistic(v, k, g, tb);\n vec2 tail = c + ballistic(v, k, g, max(tb - trail, 0.0));\n float s = streak(p, tail, head, w * (willow ? 0.9 : 1.0));\n if (s < 1e-3) continue;\n float twinkle = type == 0 ? 1.0 : 0.45 + 0.55 * step(0.35, hash12(vec2(fj + seed, floor(iTime * 22.0))));\n vec3 tint = twoTone && fj > 21.5 ? second : primary;\n col += mix(vec3(1.0, 0.95, 0.85), tint, cool) * s * twinkle;\n }\n // The burst's flash.\n col += mix(vec3(1.0), primary, 0.5) * 0.5 * exp(-length(p - c) * 18.0 / uSize) * exp(-tb * 9.0);\n return col * fade * 1.6;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec3 col = vec3(0.0);\n float cycle = max(6.0 / uRate, 3.9);\n for (int i = 0; i < 6; i++) {\n float fi = float(i);\n float tt = iTime + fi * cycle / 6.0 + 0.6;\n float n = floor(tt / cycle);\n float local = tt - n * cycle;\n float seed = hash12(vec2(fi * 7.1, n)) * 100.0;\n vec4 h = vec4(hash22(vec2(seed, 4.4)), hash22(vec2(seed, 9.9)));\n vec2 target = vec2((h.x - 0.5) * 0.75 * aspect, mix(0.02, 0.3, h.y));\n vec2 launch = vec2(target.x + (h.z - 0.5) * 0.12, -0.56);\n float rise = 0.9 + 0.35 * h.w;\n if (local < rise) {\n // The rising shell: a sputtering head on a short, faint trail.\n float u = local / rise;\n float u0 = max(u - 0.18 * uTrail, 0.0);\n vec2 head = mix(launch, target, vec2(u, 1.0 - (1.0 - u) * (1.0 - u)));\n vec2 tail = mix(launch, target, vec2(u0, 1.0 - (1.0 - u0) * (1.0 - u0)));\n float flicker = 0.6 + 0.4 * hash12(vec2(fi, floor(iTime * 30.0)));\n col += vec3(1.0, 0.72, 0.42) * streak(p, tail, head, max(0.0022, px)) * 0.7 * flicker;\n } else {\n col += burst(p, target, local - rise, seed, px);\n }\n }\n // A burst at each click.\n for (int i = 0; i < 8; i++) {\n vec4 click = iClicks[i];\n if (click.w < 0.5) continue;\n float tb = iTime - click.z;\n if (tb < 0.0 || tb > 3.5) continue;\n vec2 c = (click.xy - 0.5 * iResolution.xy) / iResolution.y;\n col += burst(p, c, tb, fract(click.z * 0.6180339) * 100.0 + float(i) * 0.01, px);\n }\n fragColor = glow(col * uBrightness);\n}`,\n ),\n presets: [\n { name: \"Gold finale\", values: { uColorA: [1, 0.8, 0.4], uColorB: [1, 0.95, 0.85], uColorC: [1, 0.6, 0.25], uRate: 1.6, uSize: 1.2 } },\n { name: \"Patriotic\", values: { uColorA: [1, 0.2, 0.25], uColorB: [1, 1, 1], uColorC: [0.25, 0.45, 1] } },\n { name: \"Slow and big\", values: { uRate: 0.35, uSize: 1.8, uGravity: 0.6, uTrail: 1.6 } },\n ],\n};\n\nexport const sparkler: ShaderEffect = {\n kind: \"shader\",\n id: \"sparkler\",\n name: \"Sparkler\",\n description: \"A burning sparkler throwing crackling, forking spark streaks from its glowing tip, which follows the pointer when it hovers.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"sparks\", \"celebration\", \"festive\", \"interactive\", \"hover\"],\n transparent: true,\n source: glsl(\n `// Sparkler: short-lived spark streaks that fork as they burn, round a glowing tip.\nuniform vec2 uPosition; // @control min=-1 max=1 default=0,0.15 label=\"Tip\"\nuniform vec3 uColor; // @control color default=#FFC46B label=\"Sparks\"\nuniform float uDensity; // @control min=0 max=1 default=0.8 label=\"Density\"\nuniform float uLength; // @control min=0.3 max=2 default=1 label=\"Spark length\"\nuniform float uIntensity; // @control min=0.2 max=3 default=1 label=\"Intensity\"\nuniform bool uStick; // @control default=true label=\"Show stick\"`,\n HASH,\n GLOW,\n OVER,\n PARTICLE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 home = uPosition * vec2(aspect, 1.0) * 0.5;\n vec2 pointer = (iPointer.xy - 0.5 * iResolution.xy) / iResolution.y;\n vec2 tip = mix(home, pointer, clamp(iPointer.z, 0.0, 1.0));\n vec4 acc = vec4(0.0);\n\n if (uStick) {\n // The wire, and the grey coating that is still to burn.\n vec2 down = normalize(vec2(0.28, -1.0));\n vec2 wire = segment(p, tip, tip + down * 0.6);\n acc = over(acc, vec3(0.32, 0.31, 0.3), (1.0 - smoothstep(0.0015, 0.0015 + px, wire.x)));\n vec2 coat = segment(p, tip + down * 0.01, tip + down * 0.3);\n acc = over(acc, vec3(0.42, 0.4, 0.37), (1.0 - smoothstep(0.0045, 0.0045 + px, coat.x)) * 0.95);\n }\n\n vec3 col = vec3(0.0);\n float w = max(0.0018, 0.9 * px);\n if (length(p - tip) < 0.42 * uLength + 0.05) {\n for (int j = 0; j < 48; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, 7.13));\n float period = 0.28 + 0.3 * h.y;\n float tt = iTime / period + h.x;\n float n = floor(tt);\n float u = tt - n;\n vec2 s = hash22(vec2(fj * 3.1, n));\n if (s.x > uDensity) continue;\n float age = u * period;\n float angle = s.y * 6.28318;\n float speed = mix(0.6, 1.6, hash12(vec2(n, fj + 3.3))) * uLength;\n vec2 v = vec2(cos(angle), sin(angle)) * speed;\n float k = 6.0;\n float g = 0.6;\n // Each spark burns out in a fork: a few short branches flash from where it ends.\n float forkAt = mix(0.45, 0.8, hash12(vec2(fj, n + 0.5)));\n float ta = min(u, forkAt) * period;\n vec2 head = tip + ballistic(v, k, g, ta);\n vec2 tail = tip + ballistic(v, k, g, max(ta - 0.045, 0.0));\n float alive = u < forkAt ? 1.0 : 0.0;\n col += mix(vec3(1.0, 0.95, 0.8), uColor, u) * streak(p, tail, head, w) * alive * 1.6;\n if (u >= forkAt) {\n float since = (u - forkAt) * period;\n float flash = exp(-since * 22.0);\n if (flash < 0.02) continue;\n float grow = 1.0 - exp(-since * 40.0);\n vec2 heading = normalize(v + vec2(1e-5));\n for (int b = 0; b < 3; b++) {\n float fb = float(b);\n float turn = (fb - 1.0) * 0.9 + (hash12(vec2(fj + fb, n)) - 0.5) * 0.8;\n vec2 bd = vec2(heading.x * cos(turn) - heading.y * sin(turn), heading.x * sin(turn) + heading.y * cos(turn));\n float len = (0.025 + 0.03 * hash12(vec2(fb, fj + n))) * uLength * grow;\n col += uColor * streak(p, head, head + bd * len, w * 0.8) * flash * 1.6;\n }\n }\n }\n }\n // The tip: a white-hot core in a flickering orange halo.\n float r = length(p - tip);\n float flicker = 0.8 + 0.2 * hash12(vec2(floor(iTime * 25.0), 1.0));\n col += vec3(1.0, 0.97, 0.9) * exp(-r * r / 0.00006) * 3.0;\n col += uColor * (0.006 / (r + 0.006)) * 0.5 * flicker;\n vec4 light = glow(col * uIntensity);\n acc = over(acc, light.rgb, light.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Cool white\", values: { uColor: [0.85, 0.92, 1], uDensity: 1, uLength: 1.2 } },\n { name: \"Just sparks\", values: { uStick: false, uDensity: 0.6 } },\n ],\n};\n\nexport const explosion: ShaderEffect = {\n kind: \"shader\",\n id: \"explosion\",\n name: \"Explosion\",\n description: \"A fireball cooling from white-hot to orange to rolling dark smoke, with a shockwave ring and flying debris; it loops and also goes off at each click.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"explosion\", \"fire\", \"smoke\", \"action\", \"click\"],\n transparent: true,\n loop: 3,\n source: glsl(\n `// Explosion: fireball, shockwave, debris and smoke, every few seconds and at each click.\nuniform vec2 uPosition; // @control min=-1 max=1 default=0,-0.1 label=\"Position\"\nuniform float uSize; // @control min=0.3 max=2 default=1 label=\"Size\"\nuniform float uPeriod; // @control min=2 max=8 default=3 label=\"Every (seconds)\"\nuniform vec3 uFire; // @control color default=#FF7A1A label=\"Fire\"\nuniform vec3 uSmoke; // @control color default=#4A413A label=\"Smoke\"\nuniform float uSmokeAmount; // @control min=0 max=1 default=0.85 label=\"Smoke\"\nuniform bool uAuto; // @control default=true label=\"Loop on its own\"`,\n HASH,\n NOISE,\n FBM,\n GLOW,\n OVER,\n PARTICLE,\n `// Fire colour for a temperature 0–1: dark red, orange, yellow, white.\nvec3 fireRamp(float t) {\n t = clamp(t, 0.0, 1.0);\n vec3 c = mix(uFire * 0.25, uFire, smoothstep(0.0, 0.4, t));\n c = mix(c, vec3(1.0, 0.85, 0.4), smoothstep(0.4, 0.75, t));\n return mix(c, vec3(1.0, 0.98, 0.9), smoothstep(0.75, 1.0, t));\n}\n\n// An explosion at c, t seconds after it goes off, painted over acc.\nvec4 explode(vec4 acc, vec2 p, vec2 c, float t, float seed, float scale, float px) {\n float end = min(uPeriod, 3.6);\n if (t < 0.0 || t > end) return acc;\n vec2 q = p - c;\n if (length(q) > scale * 1.6) return acc;\n float out_ = 1.0 - smoothstep(end * 0.6, end, t);\n vec3 col = vec3(0.0);\n\n // Smoke: a billowing cloud growing, rising and thinning, lit from inside while the fire burns.\n vec2 sq = (q - vec2(0.0, 0.12 * t * scale)) / scale;\n float sr = 0.2 + 0.2 * sqrt(t);\n float sn = fbm(sq * 5.0 + vec2(seed, -t * 0.6), 5);\n float sd = length(sq * vec2(0.9, 1.1)) / sr - (sn - 0.5) * 1.2;\n float smoke = (1.0 - smoothstep(0.25, 1.1, sd)) * smoothstep(0.05, 0.35, t) * out_ * uSmokeAmount;\n vec3 smokeCol = mix(uSmoke, uSmoke * 0.6 + uFire * 0.35, exp(-t * 1.6) * (1.0 - smoothstep(0.2, 0.8, sd)));\n acc = over(acc, smokeCol * (0.8 + 0.4 * sn), smoke * 0.92);\n\n // Fireball: expanding fast, then rising and cooling into the smoke.\n float R = scale * 0.32 * (1.0 - exp(-t * 7.0)) + 1e-3;\n vec2 fq = q - vec2(0.0, 0.05 * t * scale);\n float fn = fbm(fq / scale * 7.0 + vec2(-seed, -t * 1.4), 5);\n float fd = length(fq) / R + (fn - 0.5) * 0.9;\n float heat = exp(-t * 1.5) * out_;\n float temp = (1.0 - smoothstep(0.0, 1.05, fd)) * heat * (0.6 + 1.4 * fn * fn * 2.0);\n col += fireRamp(temp) * smoothstep(0.02, 0.3, temp) * 1.5;\n\n // Shockwave: a thin bright ring racing out, with a haze of brightened air behind it.\n float rr = length(q);\n float ring = scale * 1.25 * (1.0 - exp(-t * 2.6));\n float rw = max(0.004, 1.5 * px) + 0.01 * t;\n float wave = exp(-pow((rr - ring) / rw, 2.0)) * exp(-t * 3.0);\n float haze = smoothstep(ring - 0.12 * scale, ring, rr) * step(rr, ring) * exp(-t * 4.0);\n col += vec3(1.0, 0.92, 0.8) * (wave * 1.2 + haze * 0.18);\n\n // The flash.\n col += mix(vec3(1.0), uFire, 0.4) * exp(-rr * 4.0 / scale) * exp(-t * 10.0) * 1.5;\n\n // Debris: sparks flung out on ballistic arcs.\n float w = max(0.0025, px);\n for (int j = 0; j < 36; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, seed + 2.0));\n float life = 0.6 + 1.0 * hash12(vec2(seed, fj));\n if (t > life) continue;\n float a = h.x * 6.28318;\n vec2 v = vec2(cos(a), sin(a) * 0.8 + 0.25) * (0.8 + 1.4 * h.y) * scale;\n vec2 head = c + ballistic(v, 2.2, 1.1, t);\n vec2 tail = c + ballistic(v, 2.2, 1.1, max(t - 0.06, 0.0));\n float f = 1.0 - smoothstep(life * 0.4, life, t);\n col += mix(vec3(1.0, 0.9, 0.6), uFire, t / life) * streak(p, tail, head, w) * f * 1.5;\n }\n vec4 light = glow(col);\n return over(acc, light.rgb, light.a);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec4 acc = vec4(0.0);\n if (uAuto) acc = explode(acc, p, uPosition * vec2(aspect, 1.0) * 0.5, mod(iTime, uPeriod), 3.7, 0.65 * uSize, px);\n for (int i = 7; i >= 0; i--) {\n vec4 click = iClicks[i];\n if (click.w < 0.5) continue;\n vec2 c = (click.xy - 0.5 * iResolution.xy) / iResolution.y;\n acc = explode(acc, p, c, iTime - click.z, fract(click.z * 0.618) * 50.0, 0.38 * uSize, px);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Clicks only\", values: { uAuto: false } },\n { name: \"Blue plasma\", values: { uFire: [0.25, 0.55, 1], uSmoke: [0.1, 0.12, 0.2], uSmokeAmount: 0.4 } },\n { name: \"Big and slow\", values: { uSize: 1.6, uPeriod: 5, uSmokeAmount: 1 } },\n ],\n};\n\nexport const sparkFountain: ShaderEffect = {\n kind: \"shader\",\n id: \"spark-fountain\",\n name: \"Spark fountain\",\n description: \"A gerb spraying sparks up from its base in a column that arcs over and falls back, lighting the ground.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"sparks\", \"fountain\", \"celebration\", \"stage\"],\n transparent: true,\n source: glsl(\n `// Spark fountain: sparks sprayed up from a base, arcing back down under gravity.\nuniform vec2 uBase; // @control min=-1 max=1 default=0,-0.85 label=\"Base\"\nuniform vec3 uColor; // @control color default=#FFB547 label=\"Sparks\"\nuniform float uHeight; // @control min=0.3 max=2 default=1 label=\"Height\"\nuniform float uSpread; // @control min=0 max=1 default=0.3 label=\"Spread\"\nuniform float uDensity; // @control min=0 max=1 default=0.85 label=\"Density\"\nuniform float uIntensity; // @control min=0.2 max=3 default=1 label=\"Intensity\"`,\n HASH,\n GLOW,\n PARTICLE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 base = uBase * vec2(aspect, 1.0) * 0.5;\n vec3 col = vec3(0.0);\n float w = max(0.0022, px);\n float k = 1.4;\n float g = 1.5;\n for (int j = 0; j < 112; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, 2.31));\n float life = 1.0 + 0.8 * h.y;\n float tt = iTime / life + h.x;\n float n = floor(tt);\n float age = (tt - n) * life;\n vec3 s = vec3(hash22(vec2(fj * 1.7, n)), hash12(vec2(n, fj + 0.37)));\n if (s.z > uDensity) continue;\n float a = (s.x - 0.5) * 2.0 * uSpread * 1.2;\n vec2 v = vec2(sin(a), cos(a)) * mix(0.9, 1.35, s.y) * uHeight * 1.25;\n vec2 head = base + ballistic(v, k, g, age);\n vec2 tail = base + ballistic(v, k, g, max(age - 0.07, 0.0));\n // Sparks that fall back past the base are gone.\n if (head.y < base.y - 0.01) continue;\n float fade = 1.0 - smoothstep(0.5, 1.0, age / life);\n float twinkle = 0.6 + 0.4 * hash12(vec2(fj, floor(iTime * 24.0)));\n vec3 tint = mix(vec3(1.0, 0.96, 0.85), uColor, smoothstep(0.0, 0.5, age));\n col += tint * streak(p, tail, head, w) * fade * twinkle * 1.2;\n }\n // The gerb's mouth: a white-hot plume, and the glow it throws on the ground.\n vec2 q = p - base;\n float flicker = 0.85 + 0.15 * hash12(vec2(floor(iTime * 30.0), 4.0));\n col += vec3(1.0, 0.95, 0.85) * exp(-pow(q.x / 0.012, 2.0) - pow((q.y - 0.02) / 0.04, 2.0)) * 2.0 * flicker;\n col += uColor * (0.012 / (length(q) + 0.012)) * 0.6 * flicker;\n col += uColor * exp(-abs(q.y) * 45.0) * exp(-abs(q.x) * 5.0) * 0.4 * uHeight;\n fragColor = glow(col * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Silver\", values: { uColor: [0.86, 0.9, 1] } },\n { name: \"Wide fan\", values: { uSpread: 0.8, uHeight: 0.8 } },\n ],\n};\n\nexport const romanCandle: ShaderEffect = {\n kind: \"shader\",\n id: \"roman-candle\",\n name: \"Roman candle\",\n description: \"Balls of coloured fire popping up from a tube one after another, trailing comet tails and sputtering sparks.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"fireworks\", \"celebration\", \"festive\"],\n transparent: true,\n source: glsl(\n `// Roman candle: coloured stars shot up at intervals with comet tails and sputter.\nuniform vec2 uBase; // @control min=-1 max=1 default=0,-0.95 label=\"Base\"\nuniform float uAngle; // @control min=-0.6 max=0.6 default=0.08 label=\"Tilt\"\nuniform float uInterval; // @control min=0.3 max=3 default=0.8 label=\"Seconds between shots\"\nuniform float uHeight; // @control min=0.5 max=2 default=1.2 label=\"Height\"\nuniform vec3 uColorA; // @control color default=#FF3D7F label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#3DFF9E label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#3DB2FF label=\"Colour C\"`,\n HASH,\n GLOW,\n OVER,\n PARTICLE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 base = uBase * vec2(aspect, 1.0) * 0.5;\n vec2 dir = vec2(sin(uAngle), cos(uAngle));\n vec4 acc = vec4(0.0);\n\n // The tube.\n vec2 tube = segment(p, base, base - dir * 0.14);\n acc = over(acc, vec3(0.45, 0.1, 0.12), 1.0 - smoothstep(0.011, 0.011 + px, tube.x));\n\n vec3 col = vec3(0.0);\n float w = max(0.0025, px);\n float k = 0.7;\n float g = 1.0;\n float shot = floor(iTime / uInterval);\n for (int i = 0; i < 5; i++) {\n float n = shot - float(i);\n float age = iTime - n * uInterval;\n float life = 1.9;\n if (age > life || n < 0.0) continue;\n vec2 h = hash22(vec2(n, 5.5));\n vec3 tint = mod(n, 3.0) < 0.5 ? uColorA : (mod(n, 3.0) < 1.5 ? uColorB : uColorC);\n vec2 v = (dir + vec2((h.x - 0.5) * 0.08, 0.0)) * (0.95 + 0.1 * h.y) * uHeight * 1.45;\n vec2 ball = base + ballistic(v, k, g, age);\n if (length(p - ball) > 0.45) continue;\n float burn = 1.0 - smoothstep(life * 0.65, life, age);\n // The star, and its comet tail.\n float r = length(p - ball);\n col += mix(vec3(1.0), tint, 0.35) * exp(-r * r / (0.0003 * burn + 1e-6)) * 2.5 * burn;\n col += tint * (0.012 / (r + 0.012)) * 0.4 * burn;\n vec2 tail = base + ballistic(v, k, g, max(age - 0.22, 0.0));\n col += tint * streak(p, tail, ball, w * 2.6) * burn * 1.1;\n // Sputter: sparks shed by the star, drifting off and dropping.\n for (int j = 0; j < 8; j++) {\n float fj = float(j);\n vec2 s = hash22(vec2(fj + n * 13.0, 2.2));\n float te = s.x * age;\n float sa = age - te;\n if (sa > 0.35) continue;\n vec2 from = base + ballistic(v, k, g, te);\n float a = s.y * 6.28318;\n vec2 sv = vec2(cos(a), sin(a)) * 0.45;\n vec2 head = from + ballistic(sv, 4.0, 0.8, sa);\n vec2 stail = from + ballistic(sv, 4.0, 0.8, max(sa - 0.04, 0.0));\n col += mix(vec3(1.0, 0.85, 0.6), tint, 0.5) * streak(p, stail, head, w) * (1.0 - sa / 0.35) * burn * 1.5;\n }\n }\n // The muzzle: a flash at each shot, and a little sputter between.\n float since = iTime - shot * uInterval;\n float m = length(p - base);\n float flicker = 0.7 + 0.3 * hash12(vec2(floor(iTime * 28.0), 3.0));\n col += vec3(1.0, 0.8, 0.5) * (exp(-since * 14.0) * 2.0 + 0.25 * flicker) * exp(-m * m / 0.0004);\n vec4 light = glow(col);\n acc = over(acc, light.rgb, light.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Rapid fire\", values: { uInterval: 0.35, uHeight: 1 } },\n { name: \"Gold\", values: { uColorA: [1, 0.75, 0.3], uColorB: [1, 0.9, 0.6], uColorC: [1, 0.6, 0.2] } },\n ],\n};\n\nexport const fuseBurn: ShaderEffect = {\n kind: \"shader\",\n id: \"fuse-burn\",\n name: \"Fuse burn\",\n description: \"A lit fuse burning along an S-curve, its bright spitting spark leaving a charred, smoking cord behind, then a pop.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"fuse\", \"sparks\", \"countdown\", \"suspense\"],\n transparent: true,\n source: glsl(\n `// Fuse burn: a spitting spark running along a curved cord, charring it as it goes.\nuniform float uCurve; // @control min=-1 max=1 default=0.6 label=\"Curve\"\nuniform float uWaves; // @control min=0.5 max=3 default=1 label=\"Waves\"\nuniform float uDuration; // @control min=1 max=15 default=5 label=\"Burn time\"\nuniform vec3 uCord; // @control color default=#C9A46A label=\"Cord\"\nuniform vec3 uSpark; // @control color default=#FFB040 label=\"Spark\"\nuniform float uThickness; // @control min=0.5 max=3 default=1 label=\"Thickness\"`,\n HASH,\n GLOW,\n OVER,\n PARTICLE,\n `// The fuse at s (0–1): an S-curve across the frame.\nvec2 fusePoint(float s, float aspect) {\n return vec2(mix(-0.42, 0.42, s) * aspect, uCurve * 0.22 * sin(s * 6.28318 * uWaves));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n // Burn for most of the cycle, then a pop at the end and a moment's rest.\n float cycle = uDuration + 1.0;\n float t = mod(iTime, cycle);\n float burnt = clamp(t / uDuration, 0.0, 1.0);\n float after = t - uDuration;\n\n // Nearest point of the cord (a polyline), and how far along it that is.\n float best = 1e9;\n float along = 0.0;\n float sAt = 0.0;\n float length_ = 0.0;\n vec2 prev = fusePoint(0.0, aspect);\n for (int i = 1; i <= 48; i++) {\n vec2 next = fusePoint(float(i) / 48.0, aspect);\n vec2 sg = segment(p, prev, next);\n float seg = length(next - prev);\n if (sg.x < best) {\n best = sg.x;\n sAt = (float(i) - 1.0 + sg.y) / 48.0;\n along = length_ + seg * sg.y;\n }\n length_ += seg;\n prev = next;\n }\n vec4 acc = vec4(0.0);\n float width = 0.0045 * uThickness;\n float ahead = step(burnt, sAt);\n float wv = ahead > 0.5 ? width : width * 0.75;\n float cover = 1.0 - smoothstep(wv - px, wv, best);\n // A twisted cord ahead of the spark; a charred one, still glowing near it, behind.\n float twist = 0.85 + 0.15 * sin(along * 420.0 / uThickness + best / width * 2.5);\n float shade = 1.0 - 0.4 * pow(best / max(wv, 1e-4), 2.0);\n vec3 cord = uCord * twist * shade;\n vec3 charred = vec3(0.1, 0.085, 0.075) * shade;\n acc = over(acc, mix(charred, cord, ahead), cover);\n\n vec2 head = fusePoint(burnt, aspect);\n vec3 col = vec3(0.0);\n if (ahead < 0.5) {\n float behind = (burnt - sAt) * length_;\n float ember = exp(-behind / 0.03) + 0.5 * exp(-behind / 0.12) * step(0.8, hash12(vec2(floor(along * 300.0), floor(iTime * 8.0))));\n col += uSpark * vec3(1.0, 0.55, 0.3) * ember * cover * 1.5;\n }\n\n // Smoke curling up from the spark.\n vec2 q = p - head;\n if (q.y > 0.0 && after < 0.0) {\n float sway = q.x - 0.02 * sin(q.y * 25.0 - iTime * 3.0) - q.y * 0.15;\n float plume = exp(-sway * sway / (0.00004 + q.y * 0.0012)) * exp(-q.y * 7.0) * smoothstep(0.0, 0.03, q.y);\n acc = over(acc, vec3(0.6, 0.58, 0.56), plume * 0.22);\n }\n\n if (after < 0.0) {\n // The spark: a white-hot head spitting short sparks every which way.\n float r = length(q);\n float flicker = 0.75 + 0.25 * hash12(vec2(floor(iTime * 30.0), 2.0));\n col += vec3(1.0, 0.95, 0.85) * exp(-r * r / 0.00005) * 3.0 * flicker;\n col += uSpark * (0.007 / (r + 0.007)) * 0.6 * flicker;\n if (r < 0.2) {\n float w = max(0.0018, 0.9 * px);\n for (int j = 0; j < 28; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, 6.6));\n float period = 0.22 + 0.25 * h.y;\n float tt = iTime / period + h.x;\n float n = floor(tt);\n float age = (tt - n) * period;\n vec2 s = hash22(vec2(fj * 2.3, n));\n float a = mix(-0.4, 3.54, s.x);\n vec2 v = vec2(cos(a), sin(a)) * mix(0.4, 1.1, s.y);\n vec2 sh = head + ballistic(v, 7.0, 0.8, age);\n vec2 st = head + ballistic(v, 7.0, 0.8, max(age - 0.035, 0.0));\n col += mix(vec3(1.0, 0.95, 0.8), uSpark, age / period) * streak(p, st, sh, w) * (1.0 - age / period) * 1.3;\n }\n }\n } else {\n // The pop: a flash at the end of the fuse.\n float r = length(q);\n col += mix(vec3(1.0), uSpark, 0.4) * exp(-r * 12.0) * exp(-after * 6.0) * 2.0;\n col += vec3(1.0, 0.9, 0.7) * exp(-pow((r - after * 0.6) / 0.006, 2.0)) * exp(-after * 5.0);\n }\n vec4 light = glow(col);\n acc = over(acc, light.rgb, light.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Straight\", values: { uCurve: 0 } },\n { name: \"Slow wiggle\", values: { uCurve: 0.9, uWaves: 2, uDuration: 10 } },\n ],\n};\n\nexport const smokeBomb: ShaderEffect = {\n kind: \"shader\",\n id: \"smoke-bomb\",\n name: \"Smoke bomb\",\n description: \"Billowing two-tone coloured smoke pouring from a point, rolling out along the ground and rising as it thins.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"smoke\", \"colour\", \"photo\", \"moody\"],\n transparent: true,\n source: glsl(\n `// Smoke bomb: domain-warped fbm smoke pouring from a source, spreading and rising.\nuniform vec2 uSource; // @control min=-1 max=1 default=0,-0.8 label=\"Source\"\nuniform vec3 uColorA; // @control color default=#FF4FA3 label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#7C5CFF label=\"Colour B\"\nuniform float uDensity; // @control min=0 max=1 default=0.85 label=\"Density\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSpread; // @control min=0.2 max=2 default=1 label=\"Spread\"\nuniform float uHeight; // @control min=0.2 max=2 default=1 label=\"Rise\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 src = uSource * vec2(aspect, 1.0) * 0.5;\n vec2 q = p - src;\n float t = iTime * uSpeed;\n float h = max(q.y, 0.0);\n // Where smoke is: a plume widening as it rises, and a cloud rolling out along the ground.\n float width = 0.04 + h * 0.75 * uSpread;\n float plume = exp(-pow(q.x / width, 2.0)) * exp(-h / (0.55 * uHeight));\n float ground = exp(-pow(q.y / 0.07, 2.0)) * exp(-abs(q.x) / (0.3 * uSpread));\n float env = max(plume, ground * 0.8) * smoothstep(-0.06, 0.0, q.y);\n if (env < 0.01) {\n fragColor = vec4(0.0);\n return;\n }\n // Billows: fbm advected up and outwards, warped by itself.\n vec2 flow = vec2(q.x * (1.0 - 0.4 * clamp(h * 2.0, 0.0, 1.0)), q.y - t * 0.22);\n vec2 warp = vec2(fbm(flow * 3.0 + vec2(0.0, t * 0.05), 4), fbm(flow * 3.0 + vec2(5.2, 1.3 - t * 0.07), 4));\n float n = fbm(flow * 4.5 + warp * 1.6, 5);\n float n2 = fbm(flow * 4.5 + warp * 1.6 + vec2(0.0, 0.03), 5);\n float d = smoothstep(0.25, 0.75, n * (0.6 + 0.8 * env)) * env;\n float a = clamp(d * 1.6 * uDensity, 0.0, 1.0);\n // Colour drifts between the two; billow tops catch the light.\n float mixer = smoothstep(0.3, 0.7, fbm(flow * 1.5 + warp + vec2(9.0, 0.0), 3) + q.x * 0.6);\n vec3 col = mix(uColorA, uColorB, mixer);\n float light = clamp(0.75 + (n2 - n) * 10.0 + 0.25 * n, 0.4, 1.25);\n col = col * light + 0.06;\n // The canister's flare at the source.\n float r = length(q);\n col = mix(col, mix(vec3(1.0, 0.95, 0.9), uColorA, 0.4), exp(-r * r / 0.0004) * 0.8);\n a = max(a, exp(-r * r / 0.0002));\n fragColor = vec4(clamp(col, 0.0, 1.0), a);\n}`,\n ),\n presets: [\n { name: \"Orange and teal\", values: { uColorA: [1, 0.55, 0.15], uColorB: [0.1, 0.75, 0.75] } },\n { name: \"Gender reveal\", values: { uColorA: [1, 0.55, 0.75], uColorB: [0.45, 0.7, 1], uDensity: 1, uSpread: 1.4 } },\n { name: \"Wisp\", values: { uDensity: 0.45, uSpread: 0.5, uHeight: 1.6, uSpeed: 0.6 } },\n ],\n};\n\nexport const lightShow: ShaderEffect = {\n kind: \"shader\",\n id: \"light-show\",\n name: \"Light show\",\n description: \"A stadium pyro finale: flame jets and spark gerbs firing from the stage edge in sequences under sweeping beams, for title cards.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"background\", \"concert\", \"stage\", \"title\", \"hero\", \"fire\"],\n source: glsl(\n `// Light show: flame jets and gerbs along the bottom firing in chases, with sweeping beams.\nuniform vec3 uBackground; // @control color default=#06040C label=\"Background\"\nuniform vec3 uFlame; // @control color default=#FF6A1A label=\"Flames\"\nuniform vec3 uSparks; // @control color default=#FFE2A0 label=\"Gerbs\"\nuniform vec3 uBeam; // @control color default=#5E8BFF label=\"Beams\"\nuniform int uJets; // @control min=3 max=12 default=7 label=\"Jets\"\nuniform float uSpeed; // @control min=0.2 max=3 default=1 label=\"Speed\"\nuniform float uBeams; // @control min=0 max=2 default=1 label=\"Beam strength\"`,\n HASH,\n NOISE,\n FBM,\n `// A firing: up fast, holding, and dying away.\nfloat fire(float x, float len) {\n return smoothstep(0.0, 0.08, x) * (1.0 - smoothstep(len * 0.7, len, x));\n}\n\nvec3 flameRamp(float t) {\n vec3 c = mix(uFlame * 0.3, uFlame, smoothstep(0.0, 0.45, t));\n c = mix(c, vec3(1.0, 0.85, 0.45), smoothstep(0.45, 0.8, t));\n return mix(c, vec3(1.0, 0.97, 0.88), smoothstep(0.8, 1.0, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float aspect = iResolution.x / iResolution.y;\n vec2 p = vec2((uv.x - 0.5) * aspect, uv.y);\n float t = iTime * uSpeed;\n vec3 col = uBackground * (0.6 + 0.6 * (1.0 - uv.y));\n\n // Beams: searchlights from below the stage, sweeping through a little haze.\n float haze = 0.6 + 0.6 * fbm(p * 3.0 + vec2(t * 0.1, 0.0), 3);\n for (int i = 0; i < 4; i++) {\n float fi = float(i);\n vec2 o = vec2((fi / 3.0 - 0.5) * aspect * 0.9, -0.05);\n float aim = 0.55 * sin(t * (0.35 + 0.1 * fi) + fi * 1.9) + (fi < 1.5 ? 0.2 : -0.2);\n vec2 d = p - o;\n float ang = atan(d.x, d.y) - aim;\n float cone = exp(-ang * ang / 0.0025) * smoothstep(1.4, 0.0, length(d));\n vec3 tint = mix(uBeam, vec3(1.0), 0.25 * mod(fi, 2.0));\n col += tint * cone * haze * 0.35 * uBeams;\n }\n\n // The firing sequence, in 4-beat phrases: all at once, a chase, centre out, alternate.\n float phrase = floor(t / 4.0);\n float pattern = mod(phrase, 4.0);\n float local = mod(t, 4.0);\n float jets = float(uJets);\n float stageGlow = 0.0;\n for (int j = 0; j < 12; j++) {\n if (j >= uJets) break;\n float fj = float(j);\n float x01 = (fj + 0.5) / jets;\n float x = (x01 - 0.5) * aspect * 0.9;\n float f;\n if (pattern < 0.5) f = fire(local, 1.4);\n else if (pattern < 1.5) f = fire(local - x01 * 1.8, 0.9);\n else if (pattern < 2.5) f = fire(local - abs(x01 - 0.5) * 2.6, 1.0);\n else f = fire(mod(local + (mod(fj, 2.0) < 0.5 ? 0.0 : 1.0), 2.0), 0.8);\n // Gerbs fire while the flames rest.\n float gerb = (1.0 - f) * (pattern < 0.5 ? smoothstep(1.4, 1.8, local) * (1.0 - smoothstep(3.6, 4.0, local)) : (pattern > 2.5 ? 1.0 : 0.0));\n stageGlow += f + gerb * 0.3;\n vec2 q = p - vec2(x, 0.0);\n if (abs(q.x) > 0.25) continue;\n\n if (f > 0.01) {\n // A flame jet: a turbulent column, hottest at the nozzle.\n float H = 0.75 * f;\n float y = q.y / max(H, 1e-3);\n if (y < 1.3) {\n float turb = fbm(vec2(q.x * 10.0 + fj * 7.0, q.y * 5.0 - t * 6.0), 4);\n float wdt = 0.012 + q.y * 0.13;\n float dx = q.x + (turb - 0.5) * 0.12 * q.y * 2.0;\n float core = exp(-dx * dx / (wdt * wdt));\n float heat = core * (1.0 - smoothstep(0.2, 1.2, y + (turb - 0.5) * 0.5)) * f * 1.4;\n col += flameRamp(heat) * smoothstep(0.03, 0.3, heat) * 1.6;\n }\n }\n if (gerb > 0.01) {\n // A gerb: streaks of sparks shooting straight up.\n float gx = q.x * 90.0;\n float top = 0.55 + 0.1 * sin(t * 3.0 + fj);\n if (abs(gx) < 4.0) {\n float lane = floor(gx);\n float speedY = 3.0 + hash12(vec2(lane, fj)) * 2.0;\n float cy = q.y * 6.0 - t * speedY + hash12(vec2(fj, lane)) * 10.0;\n float cell = floor(cy);\n vec2 r = hash22(vec2(lane + fj * 9.0, cell));\n float lit = step(0.45, r.x) * (1.0 - abs(gx) / 4.0);\n float tailF = fract(cy);\n float spark = lit * smoothstep(0.45, 0.95, tailF) * (1.0 - smoothstep(0.95, 1.0, tailF));\n float across = exp(-pow((fract(gx) - 0.5 - (r.y - 0.5) * 0.6) * 5.0, 2.0));\n col += mix(uSparks, vec3(1.0), 0.3) * spark * across * gerb * (1.0 - smoothstep(top * 0.4, top, q.y)) * 1.4;\n }\n col += uSparks * exp(-abs(q.x) * 60.0) * (1.0 - smoothstep(0.0, top, q.y)) * gerb * 0.12;\n col += uSparks * exp(-length(q * vec2(1.0, 2.0)) * 40.0) * gerb;\n }\n }\n // The stage edge, lit by the fire.\n col += uFlame * stageGlow / jets * 0.6 * exp(-p.y * 6.0);\n col = 1.0 - exp(-max(col, 0.0) * 1.2);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Ice\", values: { uFlame: [0.3, 0.6, 1], uSparks: [0.85, 0.95, 1], uBeam: [0.7, 0.4, 1] } },\n { name: \"Full stage\", values: { uJets: 12, uSpeed: 1.4, uBeams: 1.6 } },\n ],\n};\n\n/** Pyrotechnics: fireworks, sparks, explosions and smoke. */\nexport const pyroShaders: ShaderEffect[] = [fireworks, sparkler, explosion, sparkFountain, romanCandle, fuseBurn, smokeBomb, lightShow];\n","import { glsl, HASH } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * Shaders keep no previous frames, so these re-derive the past: the picture\n * moves on a known path, and an echo, a lagging channel or a frozen moment\n * is the same picture sampled where the path had it at an earlier time.\n */\n\n/** `coverOf(tex)`: the share of a cover-fitted image visible across and up (the test card fits the frame). */\nconst COVER = `\nvec2 coverOf(sampler2D tex) {\n vec2 size = vec2(textureSize(tex, 0));\n float frameAspect = iResolution.x / iResolution.y;\n float imageAspect = size.x > 1.0 ? size.x / size.y : frameAspect;\n return frameAspect > imageAspect ? vec2(1.0, imageAspect / frameAspect) : vec2(frameAspect / imageAspect, 1.0);\n}`.trim();\n\n/**\n * `swayUv(tex, uv, t, amount)`: where screen point `uv` sees the cover-fitted\n * image at time `t` while it sways, drifts and breathes (strength `amount`).\n * The motion repeats every 8 s, so effects built only on it loop in 8 s\n * (needs {@link COVER}).\n */\nconst SWAY = `\nvec2 swayUv(sampler2D tex, vec2 uv, float t, float amount) {\n vec2 cover = coverOf(tex);\n float aspect = iResolution.x / iResolution.y;\n float w = 0.785398;\n float zoom = 1.3 + 0.18 * amount * sin(w * t + 0.7);\n float angle = 0.07 * amount * sin(2.0 * w * t + 0.4);\n vec2 pan = amount * vec2(0.1 * sin(w * t) + 0.04 * sin(3.0 * w * t + 1.3), 0.07 * sin(2.0 * w * t + 2.1));\n vec2 p = (uv - 0.5) * vec2(aspect, 1.0);\n float c = cos(angle);\n float s = sin(angle);\n p = mat2(c, s, -s, c) * p / vec2(aspect, 1.0);\n return 0.5 + (p / zoom + pan) * cover;\n}`.trim();\n\nconst LUMA = \"vec3(0.2126, 0.7152, 0.0722)\";\n\nexport const timeEcho: ShaderEffect = {\n kind: \"shader\",\n id: \"time-echo\",\n name: \"Time echo\",\n description: \"A swaying picture trailed by fading, tinted ghost echoes of where it just was.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"echo\", \"trail\", \"ghost\"],\n loop: 8,\n source: glsl(\n `// Time echo: the picture now, blended with copies of where its motion had it a moment ago.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform int uEchoes; // @control min=1 max=8 default=5 label=\"Echoes\"\nuniform float uSpacing; // @control min=0.02 max=0.6 default=0.18 label=\"Spacing (s)\"\nuniform float uDecay; // @control min=0.1 max=0.95 default=0.65 label=\"Decay\"\nuniform float uMotion; // @control min=0 max=2 default=1.2 label=\"Motion\"\nuniform vec3 uTint; // @control color default=#38BDF8 label=\"Echo tint\"\nuniform float uTintAmount; // @control min=0 max=1 default=0.5 label=\"Tint strength\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // Summed premultiplied, so clear parts of the picture do not darken the echoes.\n vec4 now = pictureRGBA(uImage, swayUv(uImage, uv, iTime, uMotion));\n vec4 sum = vec4(now.rgb * now.a, now.a);\n float total = 1.0;\n float weight = 1.0;\n for (int k = 1; k <= 8; k++) {\n if (k > uEchoes) break;\n weight *= uDecay;\n float age = float(k) / float(uEchoes);\n vec4 echo = pictureRGBA(uImage, swayUv(uImage, uv, iTime - float(k) * uSpacing, uMotion));\n // Older echoes take on more of the tint.\n echo.rgb = mix(echo.rgb, uTint * dot(echo.rgb, ${LUMA}) * 1.8, uTintAmount * age);\n sum += vec4(echo.rgb * echo.a, echo.a) * weight;\n total += weight;\n }\n fragColor = vec4(sum.rgb / max(sum.a, 1e-4), sum.a / total);\n}`,\n ),\n presets: [\n { name: \"Trails\", values: { uEchoes: 8, uSpacing: 0.06, uDecay: 0.85 } },\n { name: \"Strobe\", values: { uEchoes: 3, uSpacing: 0.45, uDecay: 0.55, uTintAmount: 0 } },\n { name: \"Neon ghosts\", values: { uTint: [1, 0.2, 0.8], uTintAmount: 1, uMotion: 1.6 } },\n ],\n};\n\nexport const chronoSplit: ShaderEffect = {\n kind: \"shader\",\n id: \"chrono-split\",\n name: \"Chrono split\",\n description: \"Red, green and blue each lagging a little further behind in time, so movement leaves colour fringes.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"rgb\", \"chromatic\", \"echo\"],\n loop: 8,\n source: glsl(\n `// Chrono split: each colour channel shows the moving picture at a different moment.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uLag; // @control min=0 max=0.6 default=0.15 label=\"Lag per channel (s)\"\nuniform float uMotion; // @control min=0 max=2 default=1.4 label=\"Motion\"\nuniform int uOrder; // @control min=0 max=1 default=0 label=\"Leading channel (0 red, 1 blue)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float lagR = uOrder == 0 ? 0.0 : 2.0 * uLag;\n float lagB = uOrder == 0 ? 2.0 * uLag : 0.0;\n vec4 r = pictureRGBA(uImage, swayUv(uImage, uv, iTime - lagR, uMotion));\n vec4 g = pictureRGBA(uImage, swayUv(uImage, uv, iTime - uLag, uMotion));\n vec4 b = pictureRGBA(uImage, swayUv(uImage, uv, iTime - lagB, uMotion));\n fragColor = vec4(r.r, g.g, b.b, max(max(r.a, g.a), b.a));\n}`,\n ),\n presets: [\n { name: \"Subtle\", values: { uLag: 0.05, uMotion: 1 } },\n { name: \"Prism\", values: { uLag: 0.35, uMotion: 2 } },\n ],\n};\n\nexport const timeSlice: ShaderEffect = {\n kind: \"shader\",\n id: \"time-slice\",\n name: \"Time slice\",\n description: \"Bands of a moving picture each showing a different moment, staggered like a time-displacement.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"slices\", \"stagger\", \"displacement\"],\n loop: 8,\n source: glsl(\n `// Time slice: every band shows the picture's motion delayed by a different amount.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uBands; // @control min=2 max=48 default=10 label=\"Bands\"\nuniform float uDelay; // @control min=0 max=0.6 default=0.12 label=\"Delay per band (s)\"\nuniform int uDirection; // @control min=0 max=1 default=0 label=\"Bands (0 horizontal, 1 vertical)\"\nuniform int uPattern; // @control min=0 max=2 default=0 label=\"Order (0 stepped, 1 from centre, 2 random)\"\nuniform float uMotion; // @control min=0 max=2 default=1.5 label=\"Motion\"\nuniform float uSeams; // @control min=0 max=1 default=0.4 label=\"Seams\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float across = uDirection == 0 ? uv.y : uv.x;\n float bands = float(uBands);\n float band = floor(across * bands);\n float order = band;\n if (uPattern == 1) order = abs(band - (bands - 1.0) * 0.5);\n if (uPattern == 2) order = floor(hash12(vec2(band, 4.7)) * bands);\n vec4 pic = pictureRGBA(uImage, swayUv(uImage, uv, iTime - order * uDelay, uMotion));\n vec3 col = pic.rgb;\n // A thin dark seam between bands, a pixel or two wide.\n float px = (uDirection == 0 ? iResolution.y : iResolution.x) / bands;\n float f = fract(across * bands);\n float edge = min(f, 1.0 - f) * px;\n col *= 1.0 - uSeams * (1.0 - smoothstep(0.0, 1.5, edge));\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Venetian\", values: { uBands: 24, uDelay: 0.05, uPattern: 1 } },\n { name: \"Shuffle\", values: { uBands: 14, uDelay: 0.2, uPattern: 2, uDirection: 1 } },\n ],\n};\n\n/** `digit7(p, d)`: distance to digit `d` drawn as a seven-segment glyph in a 1 × 2 cell (bottom-left origin). */\nconst DIGIT7 = `\nfloat segDist(vec2 p, vec2 a, vec2 b) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n return length(pa - ba * clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0));\n}\nfloat digit7(vec2 p, int d) {\n const int MASKS[10] = int[10](63, 6, 91, 79, 102, 109, 125, 7, 127, 111);\n int m = MASKS[clamp(d, 0, 9)];\n float dist = 1e5;\n if ((m & 1) != 0) dist = min(dist, segDist(p, vec2(0.0, 2.0), vec2(1.0, 2.0)));\n if ((m & 2) != 0) dist = min(dist, segDist(p, vec2(1.0, 2.0), vec2(1.0, 1.0)));\n if ((m & 4) != 0) dist = min(dist, segDist(p, vec2(1.0, 1.0), vec2(1.0, 0.0)));\n if ((m & 8) != 0) dist = min(dist, segDist(p, vec2(0.0, 0.0), vec2(1.0, 0.0)));\n if ((m & 16) != 0) dist = min(dist, segDist(p, vec2(0.0, 0.0), vec2(0.0, 1.0)));\n if ((m & 32) != 0) dist = min(dist, segDist(p, vec2(0.0, 1.0), vec2(0.0, 2.0)));\n if ((m & 64) != 0) dist = min(dist, segDist(p, vec2(0.0, 1.0), vec2(1.0, 1.0)));\n return dist;\n}`.trim();\n\nexport const rewind: ShaderEffect = {\n kind: \"shader\",\n id: \"rewind\",\n name: \"VHS rewind\",\n description: \"A tape playing, then rewinding fast with tracking noise, jittering lines, colour bleed and a ◀◀ display.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"vhs\", \"retro\", \"rewind\", \"tape\"],\n loop: 6,\n source: glsl(\n `// VHS rewind: 4 s of play, then 2 s rewinding at double speed back to the start.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uNoise; // @control min=0 max=1 default=0.6 label=\"Tracking noise\"\nuniform float uJitter; // @control min=0 max=1 default=0.5 label=\"Line jitter\"\nuniform float uBleed; // @control min=0 max=0.03 default=0.008 label=\"Chroma bleed\"\nuniform bool uOsd; // @control default=true label=\"On-screen display\"\nuniform vec3 uOsdColor; // @control color default=#F8FAFC label=\"Display colour\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n COVER,\n SWAY,\n DIGIT7,\n `// Ink of the timecode \"M:SS:FF\" at q (units of half a digit's height).\nfloat timecode(vec2 q, float secs) {\n if (q.y < -0.3 || q.y > 2.3 || q.x < -0.3) return 0.0;\n int slot = int(floor(q.x / 1.6));\n vec2 c = vec2(q.x - float(slot) * 1.6, q.y);\n int s = int(floor(mod(secs, 60.0)));\n int f = int(floor(fract(secs) * 30.0));\n float dist = 1e5;\n if (slot == 0) dist = digit7(c, int(floor(secs / 60.0)));\n else if (slot == 1 || slot == 4) dist = min(length(c - vec2(0.5, 0.6)), length(c - vec2(0.5, 1.4)));\n else if (slot == 2) dist = digit7(c, s / 10);\n else if (slot == 3) dist = digit7(c, s - (s / 10) * 10);\n else if (slot == 5) dist = digit7(c, f / 10);\n else if (slot == 6) dist = digit7(c, f - (f / 10) * 10);\n return smoothstep(0.2, 0.12, dist);\n}\n\n// Ink of a right-pointing triangle 1 wide, 1 high, its back edge at q.x = 0.\nfloat playIcon(vec2 q) {\n float inside = min(q.x, 0.5 * (1.0 - q.x) - abs(q.y - 0.5));\n return smoothstep(0.0, 0.04, inside);\n}\n\n// The display's ink at fragCoord: a play arrow for a moment after play starts, rewind arrows while rewinding, and the timecode.\nfloat osd(vec2 fragCoord, float phase, float tau) {\n float unit = iResolution.y * 0.045;\n vec2 q = (fragCoord - vec2(iResolution.x - unit * 3.4, iResolution.y - unit * 2.4)) / unit;\n float ink = 0.0;\n if (phase >= 4.0) ink = max(playIcon(vec2(1.0 - q.x, q.y)), playIcon(vec2(2.0 - q.x, q.y)));\n else if (phase < 1.5) ink = playIcon(q);\n vec2 t = (fragCoord - vec2(iResolution.x - unit * 6.5, unit * 1.0)) / (unit * 0.5);\n return max(ink, timecode(t, tau));\n}`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float phase = mod(iTime, 6.0);\n // Tape time: forwards for 4 s, then back to the start in 2.\n float tau = phase < 4.0 ? phase : 4.0 - (phase - 4.0) * 2.0;\n float rw = smoothstep(3.9, 4.1, phase) * (1.0 - smoothstep(5.85, 6.0, phase));\n float shake = 0.15 + rw;\n float frame = mod(floor(iTime * 30.0), 180.0);\n // Line jitter: each scanline nudged sideways, stronger near the bottom head-switch band.\n float line = floor(uv.y * 240.0);\n float jitter = (hash12(vec2(line, frame)) - 0.5) * 0.012 * uJitter * shake;\n jitter += (1.0 - smoothstep(0.0, 0.05, uv.y)) * 0.03 * uJitter * (hash12(vec2(frame, 2.0)) - 0.2);\n // Tracking bars rolling down the picture while rewinding.\n float roll = fract(uv.y * 1.7 + iTime * 1.5);\n float bar = smoothstep(0.0, 0.02, roll) * smoothstep(0.1, 0.04, roll) * uNoise * rw;\n vec2 st = uv + vec2(jitter + bar * 0.06, 0.0);\n // While rewinding the picture jumps up and down a touch.\n st.y += rw * 0.01 * (hash12(vec2(frame, 5.0)) - 0.5);\n float bleed = uBleed * (1.0 + 2.0 * rw);\n float t = tau * 1.5;\n vec4 r = pictureRGBA(uImage, swayUv(uImage, st + vec2(bleed, 0.0), t, 1.4));\n vec4 g = pictureRGBA(uImage, swayUv(uImage, st, t, 1.4));\n vec4 b = pictureRGBA(uImage, swayUv(uImage, st - vec2(bleed, 0.0), t, 1.4));\n vec3 col = vec3(r.r, g.g, b.b);\n float alpha = max(max(r.a, g.a), b.a);\n // Static in the bars, a few white dropouts, and a washed-out tape look.\n float grain = hash12(fragCoord + frame * 17.0);\n col = mix(col, vec3(grain), bar * 0.75);\n col += step(0.9985 - 0.002 * rw * uNoise, hash12(vec2(floor(fragCoord.x / 6.0), line + frame * 31.0))) * uNoise;\n float grey = dot(col, ${LUMA});\n col = mix(vec3(grey), col, 0.85 - 0.25 * rw) * vec3(1.03, 1.0, 0.95);\n col = mix(col, vec3(0.08), (1.0 - smoothstep(0.0, 0.02, uv.y)) * rw);\n col *= 0.94 + 0.06 * sin(fragCoord.y * 3.14159);\n vec2 v = uv - 0.5;\n col *= 1.0 - 0.35 * dot(v, v);\n if (uOsd) {\n float shadow = osd(fragCoord + vec2(-2.0, 2.0), phase, tau);\n float text = osd(fragCoord, phase, tau);\n col = mix(col, vec3(0.0), shadow * 0.5);\n col = mix(col, uOsdColor, text);\n alpha = max(alpha, max(shadow * 0.5, text));\n }\n fragColor = vec4(clamp(col, 0.0, 1.0), alpha);\n}`,\n ),\n presets: [\n { name: \"Worn tape\", values: { uNoise: 1, uJitter: 0.9, uBleed: 0.018 } },\n { name: \"Clean deck\", values: { uNoise: 0.25, uJitter: 0.15, uBleed: 0.003 } },\n { name: \"Green OSD\", values: { uOsdColor: [0.4, 1, 0.5] } },\n ],\n};\n\nexport const bulletTime: ShaderEffect = {\n kind: \"shader\",\n id: \"bullet-time\",\n name: \"Bullet time\",\n description: \"A shockwave sweeping out from the centre or a click, freezing the picture grey and zoomed behind it while the rest moves on.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"freeze\", \"shockwave\", \"click\", \"cinematic\"],\n loop: 8,\n source: glsl(\n `// Bullet time: every 4 s (or on a click) a wave freezes the picture behind it, then lets go.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uSpeed; // @control min=0.2 max=3 default=1.2 label=\"Wave speed\"\nuniform float uHold; // @control min=0.5 max=3 default=2.2 label=\"Freeze (s)\"\nuniform float uDesaturate; // @control min=0 max=1 default=0.85 label=\"Desaturate\"\nuniform float uZoom; // @control min=0 max=0.25 default=0.08 label=\"Zoom\"\nuniform vec3 uRing; // @control color default=#A5F3FC label=\"Shockwave\"\nuniform float uMotion; // @control min=0 max=2 default=1.4 label=\"Motion\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // The demo freezes every 4 s from the centre; a click freezes from where it landed.\n vec2 centre = 0.5 * iResolution.xy;\n float since = mod(iTime, 4.0);\n if (iClicks[0].w > 0.5) {\n centre = iClicks[0].xy;\n since = iTime - iClicks[0].z;\n }\n float start = iTime - since;\n float radius = since * uSpeed * iResolution.y;\n vec2 d = fragCoord - centre;\n float dist = length(d);\n float release = smoothstep(uHold, uHold + 0.6, since);\n float inside = smoothstep(radius, radius - 0.02 * iResolution.y, dist) * (1.0 - release);\n // The wavefront bends the picture outwards as it passes.\n float front = (dist - radius) / (0.045 * iResolution.y);\n float ring = exp(-front * front) * (1.0 - release);\n vec2 warp = d / max(dist, 1.0) * ring * 0.018;\n vec4 live = pictureRGBA(uImage, swayUv(uImage, uv - warp, iTime, uMotion));\n // Behind the wave: the moment the freeze began, zooming in towards the centre the longer it is held.\n vec2 c = centre / iResolution.xy;\n float zoom = 1.0 + uZoom * smoothstep(0.0, 1.0, since / max(uHold, 0.1));\n vec4 frozen = pictureRGBA(uImage, swayUv(uImage, c + (uv - warp - c) / zoom, start, uMotion));\n float grey = dot(frozen.rgb, ${LUMA});\n frozen.rgb = mix(frozen.rgb, vec3(grey) * vec3(0.9, 0.98, 1.1), uDesaturate);\n frozen.rgb *= 1.0 + 0.025 * sin(dist / iResolution.y * 60.0 - since * 4.0) * inside;\n vec4 pic = mix(live, frozen, inside);\n // The ring is light added over the picture, so it also shows where the picture is clear.\n float alpha = max(pic.a, clamp(ring * 0.7, 0.0, 1.0));\n fragColor = vec4((pic.rgb * pic.a + uRing * ring * 0.7) / max(alpha, 1e-4), alpha);\n}`,\n ),\n presets: [\n { name: \"Slow wave\", values: { uSpeed: 0.5, uHold: 2.8 } },\n { name: \"Snap\", values: { uSpeed: 2.5, uHold: 1.2, uZoom: 0.15, uRing: [1, 1, 1] } },\n ],\n};\n\nexport const timeTunnel: ShaderEffect = {\n kind: \"shader\",\n id: \"time-tunnel\",\n name: \"Time tunnel\",\n description: \"A picture wrapped round a spiralling tunnel rushing at the viewer, with light streaks and a blazing core.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"tunnel\", \"vortex\", \"sci-fi\", \"warp\"],\n loop: 8,\n source: glsl(\n `// Time tunnel: the picture mapped onto a twisting tube by angle and depth.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uTwist; // @control min=0 max=4 default=1.2 label=\"Twist\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform vec3 uColor; // @control color default=#3B82F6 label=\"Tunnel colour\"\nuniform float uTint; // @control min=0 max=1 default=0.55 label=\"Colour strength\"\nuniform vec3 uCore; // @control color default=#F0F9FF label=\"Core\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n // The far end wanders a little.\n p += 0.05 * vec2(sin(iTime * 0.785398), cos(iTime * 1.570796));\n float r = max(length(p), 1e-3);\n float a = atan(p.y, p.x);\n float z = 0.3 / r;\n // Round the tube (seamless: twice round the mirrored image), twisting with depth; along it, rushing closer.\n float u = a / 6.28318 + uTwist * 0.15 * z + iTime * 0.125;\n float v = z * 0.5 + iTime * uSpeed;\n vec4 pic = pictureRGBA(uImage, vec2(u * 2.0, v));\n vec3 img = pic.rgb;\n float l = dot(img, vec3(0.2126, 0.7152, 0.0722));\n vec3 col = mix(img, uColor * l * 2.2, uTint);\n // Rings where the tube's sections meet.\n col *= 0.85 + 0.15 * smoothstep(0.0, 0.08, abs(fract(v * 2.0) - 0.5));\n // Light streaks flying past in some angular lanes.\n float lane = floor(fract(u) * 64.0);\n float h = hash12(vec2(lane, 3.0));\n float dash = smoothstep(0.85, 1.0, fract(z * 0.25 + iTime * uSpeed * 2.0 + h * 7.0));\n // Thin in screen space at any distance from the core.\n float across = abs(fract(u * 64.0) - 0.5) / 64.0 * 6.28318 * r;\n float thin = 1.0 - smoothstep(0.0015, 0.005, across);\n float streak = dash * step(0.75, h) * thin * smoothstep(0.05, 0.25, r);\n col += mix(uCore, uColor, 0.4) * streak;\n // Depth haze into the glowing core; the near rim darkens.\n float haze = 1.0 - smoothstep(0.0, 0.2, r);\n col = mix(col, uCore, haze);\n col += uCore * 0.002 / (r * r + 0.01);\n col *= 1.0 - 0.45 * smoothstep(0.5, 0.95, r);\n fragColor = vec4(clamp(col, 0.0, 1.0), clamp(max(pic.a, max(haze, streak)), 0.0, 1.0));\n}`,\n ),\n presets: [\n { name: \"Vortex\", values: { uTwist: 3, uSpeed: 1, uColor: [0.55, 0.3, 1] } },\n { name: \"Ember\", values: { uColor: [1, 0.45, 0.1], uCore: [1, 0.95, 0.8], uTint: 0.75 } },\n { name: \"True colour\", values: { uTint: 0, uTwist: 0.6 } },\n ],\n};\n\nexport const speedRamp: ShaderEffect = {\n kind: \"shader\",\n id: \"speed-ramp\",\n name: \"Speed ramp\",\n description: \"A panning picture lurching from a crawl to a blur and back, motion-blurred in proportion to its speed.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"speed\", \"motion blur\", \"cinematic\"],\n loop: 4,\n source: glsl(\n `// Speed ramp: a pan whose speed swings from almost still to nearly double, with matching blur.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uRamp; // @control min=0 max=0.95 default=0.9 label=\"Ramp strength\"\nuniform float uBlur; // @control min=0 max=0.25 default=0.1 label=\"Motion blur (shutter s)\"\nuniform float uPan; // @control min=0.1 max=1 default=0.5 label=\"Pan speed\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 cover = coverOf(uImage);\n // Speed 1 + ramp * cos(w t) over a 4 s cycle; tau is how far the pan has got.\n float w = 1.570796;\n float speed = 1.0 + uRamp * cos(w * iTime);\n float tau = iTime + uRamp * sin(w * iTime) / w;\n // A little push in as it speeds up.\n float zoom = 1.15 + 0.06 * (speed - 1.0);\n vec2 base = 0.5 + (uv - 0.5) * cover / zoom + vec2(uPan * tau, 0.02 * sin(w * 2.0 * tau));\n // Blur along the pan, as long as the picture moves while the shutter is open (16 taps at most).\n float len = min(uPan * speed * uBlur, 0.25);\n // Summed premultiplied, so clear parts of the picture do not darken the blur.\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 16; i++) {\n float k = float(i) / 15.0 - 0.5;\n vec4 c = pictureRGBA(uImage, base - vec2(len * k, 0.0));\n sum += vec4(c.rgb * c.a, c.a);\n }\n vec3 col = sum.rgb / max(sum.a, 1e-4);\n vec2 v = uv - 0.5;\n col *= 1.0 - (0.2 + 0.25 * max(speed - 1.0, 0.0)) * dot(v, v) * 2.0;\n fragColor = vec4(col, sum.a / 16.0);\n}`,\n ),\n presets: [\n { name: \"Gentle\", values: { uRamp: 0.5, uBlur: 0.05 } },\n { name: \"Whip\", values: { uRamp: 0.95, uBlur: 0.25, uPan: 1 } },\n ],\n};\n\nexport const stutterFreeze: ShaderEffect = {\n kind: \"shader\",\n id: \"stutter-freeze\",\n name: \"Stutter freeze\",\n description: \"A moving picture that catches in irregular bursts, holding or stuttering frames with a flash on each freeze.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"freeze\", \"stutter\", \"glitch\"],\n source: glsl(\n `// Stutter freeze: some moments end in a hold (or a skipping stutter) before cutting back to live.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uRate; // @control min=0.2 max=4 default=1 label=\"Bursts per second\"\nuniform float uHold; // @control min=0 max=1 default=0.55 label=\"Hold length\"\nuniform float uFlash; // @control min=0 max=1 default=0.6 label=\"Flash\"\nuniform float uMotion; // @control min=0 max=2 default=1.6 label=\"Motion\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float slot = floor(iTime * uRate);\n float f = fract(iTime * uRate);\n // Most moments end in a hold of random length.\n float len = uHold * mix(0.35, 1.0, hash12(vec2(slot, 3.3)));\n float startF = 1.0 - len;\n bool frozen = hash12(vec2(slot, 7.1)) > 0.25 && len > 0.001 && f >= startF;\n float freezeAt = (slot + startF) / uRate;\n float since = iTime - freezeAt;\n float t = iTime;\n float kick = 0.0;\n if (frozen) {\n // Some holds stutter, skipping back and forth between nearby frames.\n float stutter = step(0.55, hash12(vec2(slot, 9.7)));\n float k = floor(since * 12.0);\n t = freezeAt - stutter * mod(k, 3.0) * 0.06;\n kick = exp(-since * 10.0);\n }\n vec2 st = 0.5 + (uv - 0.5) / (1.0 + 0.04 * kick);\n vec4 pic = pictureRGBA(uImage, swayUv(uImage, st, t * 2.0, uMotion));\n vec3 col = pic.rgb;\n if (frozen) {\n col = mix(col, vec3(dot(col, ${LUMA})), 0.25);\n col = (col - 0.5) * 1.1 + 0.5;\n }\n col = mix(col, vec3(1.0), kick * uFlash * 0.85);\n fragColor = vec4(clamp(col, 0.0, 1.0), max(pic.a, kick * uFlash * 0.85));\n}`,\n ),\n presets: [\n { name: \"Nervous\", values: { uRate: 3, uHold: 0.4 } },\n { name: \"Long holds\", values: { uRate: 0.5, uHold: 0.8, uFlash: 0.3 } },\n ],\n};\n\n/** Time warps: echoes, rewinds, freezes and tunnels. */\nexport const timewarpShaders: ShaderEffect[] = [timeEcho, chronoSplit, timeSlice, rewind, bulletTime, timeTunnel, speedRamp, stutterFreeze];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/** The two-image controls every effect here starts with; progress runs 0 → 1 → 0 over 4 s when animated. */\nconst pair = (from: string, to: string) => `uniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${from} label=\"From image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${to} label=\"To image\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"`;\n\n/** `progress()`, and `cover(tex, uv)` / `coverRGBA(tex, uv)`: an image cover-fitted to the frame (needs {@link PICTURE}). */\nconst COMMON = `\nfloat progress() {\n return uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n}\n\n// The share of an image visible across and up when it covers the frame (the test card fits it).\nvec2 coverScale(sampler2D tex) {\n vec2 size = vec2(textureSize(tex, 0));\n float frameAspect = iResolution.x / iResolution.y;\n float imageAspect = size.x > 1.0 ? size.x / size.y : frameAspect;\n return frameAspect > imageAspect ? vec2(1.0, imageAspect / frameAspect) : vec2(frameAspect / imageAspect, 1.0);\n}\n\nvec4 coverRGBA(sampler2D tex, vec2 uv) {\n return pictureRGBA(tex, 0.5 + (uv - 0.5) * coverScale(tex));\n}\n\nvec3 cover(sampler2D tex, vec2 uv) {\n return coverRGBA(tex, uv).rgb;\n}\n\nfloat luma(vec3 c) {\n return dot(c, vec3(0.2126, 0.7152, 0.0722));\n}`.trim();\n\nexport const featureMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"feature-morph\",\n name: \"Feature morph\",\n description: \"The classic face morph: two pictures warp so five matching points (eyes, mouth, chin, hairline) meet while they cross-fade.\",\n category: \"morph\",\n tags: [\"morph\", \"face\", \"warp\", \"image\", \"transition\"],\n loop: 4,\n source: glsl(\n `// Feature morph: both images warp towards in-between positions of five matching points while they cross-fade.\n${pair(SAMPLE_IMAGES.portrait, SAMPLE_IMAGES.portrait2)}\nuniform vec2 uFromA; // @control min=0 max=1 default=0.461,0.583 label=\"From: left eye\"\nuniform vec2 uFromB; // @control min=0 max=1 default=0.539,0.583 label=\"From: right eye\"\nuniform vec2 uFromC; // @control min=0 max=1 default=0.5,0.472 label=\"From: mouth\"\nuniform vec2 uFromD; // @control min=0 max=1 default=0.5,0.389 label=\"From: chin\"\nuniform vec2 uFromE; // @control min=0 max=1 default=0.5,0.778 label=\"From: hairline\"\nuniform vec2 uToA; // @control min=0 max=1 default=0.619,0.514 label=\"To: left eye\"\nuniform vec2 uToB; // @control min=0 max=1 default=0.725,0.514 label=\"To: right eye\"\nuniform vec2 uToC; // @control min=0 max=1 default=0.672,0.364 label=\"To: mouth\"\nuniform vec2 uToD; // @control min=0 max=1 default=0.672,0.25 label=\"To: chin\"\nuniform vec2 uToE; // @control min=0 max=1 default=0.672,0.778 label=\"To: hairline\"\nuniform bool uShowPoints; // @control default=false label=\"Show points\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COMMON,\n `// Points are given in image uv; the warp works in frame space (height 1, x scaled by the aspect).\nvec2 toFrame(vec2 imageUv, vec2 scale) {\n return (0.5 + (imageUv - 0.5) / scale) * vec2(iResolution.x / iResolution.y, 1.0);\n}\n\nvec2 toImage(vec2 q, vec2 scale) {\n return 0.5 + (q / vec2(iResolution.x / iResolution.y, 1.0) - 0.5) * scale;\n}\n\nvec2 cmul(vec2 a, vec2 b) {\n return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);\n}\n\n// Where frame point x, among the in-between points m, comes from in a picture whose points are s:\n// a best-fit similarity (move, scale, turn) carries m onto s, then inverse-distance weighting of\n// what is left over bends each point exactly onto its partner.\nvec2 warp(vec2 x, vec2 m[5], vec2 s[5]) {\n vec2 cm = vec2(0.0);\n vec2 cs = vec2(0.0);\n for (int i = 0; i < 5; i++) {\n cm += m[i] * 0.2;\n cs += s[i] * 0.2;\n }\n vec2 num = vec2(0.0);\n float den = 0.0;\n for (int i = 0; i < 5; i++) {\n vec2 a = m[i] - cm;\n num += cmul(vec2(a.x, -a.y), s[i] - cs);\n den += dot(a, a);\n }\n vec2 k = num / max(den, 1e-6);\n vec2 bend = vec2(0.0);\n float total = 0.0;\n for (int i = 0; i < 5; i++) {\n vec2 left = s[i] - (cs + cmul(k, m[i] - cm));\n float d2 = dot(x - m[i], x - m[i]);\n float w = 1.0 / (d2 * d2 + 1e-6);\n bend += w * left;\n total += w;\n }\n return cs + cmul(k, x - cm) + bend / total;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = progress();\n vec2 scaleA = coverScale(uFrom);\n vec2 scaleB = coverScale(uTo);\n vec2 a[5] = vec2[5](toFrame(uFromA, scaleA), toFrame(uFromB, scaleA), toFrame(uFromC, scaleA), toFrame(uFromD, scaleA), toFrame(uFromE, scaleA));\n vec2 b[5] = vec2[5](toFrame(uToA, scaleB), toFrame(uToB, scaleB), toFrame(uToC, scaleB), toFrame(uToD, scaleB), toFrame(uToE, scaleB));\n vec2 m[5];\n for (int i = 0; i < 5; i++) m[i] = mix(a[i], b[i], t);\n vec2 x = fragCoord / iResolution.y;\n vec4 colA = pictureRGBA(uFrom, toImage(warp(x, m, a), scaleA));\n vec4 colB = pictureRGBA(uTo, toImage(warp(x, m, b), scaleB));\n vec4 pic = mix(colA, colB, smoothstep(0.2, 0.8, t));\n vec3 col = pic.rgb;\n float marks = 0.0;\n if (uShowPoints) {\n float px = 1.0 / iResolution.y;\n for (int i = 0; i < 5; i++) {\n float d = length(x - m[i]);\n float shadow = smoothstep(px * 1.5, 0.0, abs(d - 0.012)) * 0.6;\n float ring = smoothstep(px, 0.0, abs(d - 0.012));\n col = mix(col, vec3(0.0), shadow);\n col = mix(col, vec3(1.0, 0.85, 0.2), ring);\n marks = max(marks, max(shadow, ring));\n }\n }\n fragColor = vec4(col, max(pic.a, marks));\n}`,\n ),\n presets: [{ name: \"Show points\", values: { uShowPoints: true, uAnimate: false, uProgress: 0.5 } }],\n};\n\nexport const silhouetteMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"silhouette-morph\",\n name: \"Silhouette morph\",\n description: \"One silhouette or logo flowing into another as a gooey blob, its colour blending from the first shape's to the second's.\",\n category: \"morph\",\n tags: [\"morph\", \"shape\", \"logo\", \"goo\", \"blob\", \"text\"],\n loop: 4,\n source: glsl(\n `// Silhouette morph: blurred alpha masks of two shapes mixed by progress and thresholded, so one flows into the other.\nuniform sampler2D uFrom; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.logo} label=\"From shape\"\nuniform sampler2D uTo; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.heart} label=\"To shape\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uSize; // @control min=0.2 max=1 default=0.75 label=\"Shape size\"\nuniform float uGoo; // @control min=0 max=0.3 default=0.1 label=\"Gooeyness\"\nuniform float uEdge; // @control min=0 max=0.05 default=0.004 label=\"Edge softness\"\nuniform bool uImageColours; // @control default=true label=\"Use the shapes' own colours\"\nuniform vec3 uColourA; // @control color default=#6366F1 label=\"From colour\"\nuniform vec3 uColourB; // @control color default=#F43F5E label=\"To colour\"\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"`,\n `// A shape's colour (premultiplied) and alpha at frame point p (height 1, centred), the image contained in\n// uSize of the frame, read from a mip level about as coarse as the spacing (in frame units), so sparse blur\n// taps still sum smoothly. With no image, a disc (fallback 0) or a rounded square (1).\nvec4 shapeAt(sampler2D tex, vec2 p, float spacing, int fallback) {\n vec2 size = vec2(textureSize(tex, 0));\n if (size.x <= 1.0) {\n float d = fallback == 0 ? length(p) - 0.3 * uSize : length(max(abs(p) - 0.2 * uSize, 0.0)) - 0.08 * uSize;\n float a = step(d, 0.0);\n return vec4(vec3(a), a);\n }\n float aspect = size.x / size.y;\n float h = min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n vec2 uv = p / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return vec4(0.0);\n vec4 c = textureLod(tex, uv, log2(max(spacing * size.y / h, 1.0)));\n // Clear texels upload black, so filtered colour is already about colour × alpha: divide it out, then weight by alpha.\n return vec4(clamp(c.rgb / max(c.a, 1e-3), 0.0, 1.0) * c.a, c.a);\n}\n\n// A disc blur of the shape: 28 taps on a golden-angle spiral.\nvec4 blurred(sampler2D tex, vec2 p, float radius, int fallback) {\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 28; i++) {\n float r = radius * sqrt((float(i) + 0.5) / 28.0);\n float a = float(i) * 2.39996;\n sum += shapeAt(tex, p + r * vec2(cos(a), sin(a)), radius * 0.35, fallback);\n }\n return sum / 28.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n // Shapes are sharp at either end and softest half way, where the blobs merge.\n float radius = uGoo * sin(3.14159 * t) + 1.0 / iResolution.y;\n vec4 a = blurred(uFrom, p, radius, 0);\n vec4 b = blurred(uTo, p, radius, 1);\n float field = mix(a.a, b.a, t);\n float w = uEdge + fwidth(field) * 0.75;\n float inside = smoothstep(0.5 - w, 0.5 + w, field);\n // Each shape's colour here (or the other's, where only one shape reaches), blended by progress.\n vec3 ca = uImageColours ? a.rgb / max(a.a, 1e-4) : uColourA;\n vec3 cb = uImageColours ? b.rgb / max(b.a, 1e-4) : uColourB;\n ca = mix(cb, ca, smoothstep(0.0, 0.05, a.a));\n cb = mix(ca, cb, smoothstep(0.0, 0.05, b.a));\n vec3 tint = mix(ca, cb, smoothstep(0.2, 0.8, t));\n // A little roundness: the thick middle of a blob is lighter than its rim.\n tint *= 0.82 + 0.25 * smoothstep(0.5, 1.0, field);\n fragColor = vec4(mix(uBackground, tint, inside), 1.0);\n}`,\n ),\n presets: [\n {\n name: \"Hello → World\",\n values: { uFrom: textImage(\"HELLO\"), uTo: textImage(\"WORLD\"), uImageColours: false, uSize: 0.9, uGoo: 0.05, uColourA: [0.98, 0.75, 0.14], uColourB: [0.13, 0.83, 0.93] },\n },\n { name: \"Blobby\", values: { uGoo: 0.25, uBackground: [1, 0.97, 0.93] } },\n ],\n};\n\nexport const transitionLiquidMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-liquid-morph\",\n name: \"Liquid morph\",\n description: \"Both images swept along a flowing, swirling current that peaks half way, dissolving one into the other like ink in water.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"liquid\", \"image\", \"flow\"],\n loop: 4,\n source: glsl(\n `// Liquid morph: both images advected along a domain-warped fbm current, strongest at mid-progress, while cross-fading.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uStrength; // @control min=0 max=0.5 default=0.1 label=\"Strength\"\nuniform float uScale; // @control min=0.5 max=8 default=2.5 label=\"Scale\"\nuniform float uFlow; // @control min=0 max=2 default=0.4 label=\"Flow speed\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n float s = sin(3.14159 * t);\n float time = iTime * uFlow;\n vec2 q = fragCoord / iResolution.y * uScale;\n vec2 first = vec2(fbm(q + vec2(0.0, time), 4), fbm(q + vec2(5.2, 1.3) - vec2(time, 0.0), 4)) - 0.5;\n vec2 flow = vec2(fbm(q + 4.0 * first + vec2(1.7, 9.2) + time * 0.5, 4), fbm(q + 4.0 * first + vec2(8.3, 2.8) - time * 0.5, 4)) - 0.5;\n vec2 d = flow * uStrength * s * 2.0;\n // From is carried downstream, To arrives from upstream; neither moves at the ends.\n vec4 a = coverRGBA(uFrom, uv + d);\n vec4 b = coverRGBA(uTo, uv - d);\n float k = smoothstep(0.25, 0.75, t + (flow.x + flow.y) * 0.6 * s);\n fragColor = mix(a, b, k);\n}`,\n ),\n presets: [\n { name: \"Gentle\", values: { uStrength: 0.08, uScale: 1.5, uFlow: 0.2 } },\n { name: \"Turbulent\", values: { uStrength: 0.35, uScale: 4, uFlow: 1.2 } },\n ],\n};\n\nexport const transitionDisplacement: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-displacement\",\n name: \"Displacement\",\n description: \"Each image's brightness pushes it out in one direction as the next slides in, warped by its own light and dark.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"displacement\", \"image\", \"warp\"],\n loop: 4,\n source: glsl(\n `// Displacement: From's luminance drives a directional warp out, To's luminance the same warp in reverse.\n${pair(SAMPLE_IMAGES.city, SAMPLE_IMAGES.landscape)}\nuniform float uStrength; // @control min=0 max=1 default=0.4 label=\"Strength\"\nuniform float uAngle; // @control min=0 max=360 default=0 label=\"Direction (°)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n vec2 dir = vec2(cos(radians(uAngle)), sin(radians(uAngle))) * vec2(iResolution.y / iResolution.x, 1.0);\n float la = luma(cover(uFrom, uv));\n float lb = luma(cover(uTo, uv));\n vec4 a = coverRGBA(uFrom, uv + dir * t * uStrength * la);\n vec4 b = coverRGBA(uTo, uv - dir * (1.0 - t) * uStrength * lb);\n fragColor = mix(a, b, smoothstep(0.2, 0.8, t));\n}`,\n ),\n presets: [\n { name: \"Upward smear\", values: { uStrength: 0.6, uAngle: 90 } },\n { name: \"Subtle\", values: { uStrength: 0.12, uAngle: 30 } },\n ],\n};\n\nexport const transitionLuma: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-luma\",\n name: \"Luma fade\",\n description: \"Pixels switch to the next image in order of brightness, shadows first or highlights first, along a soft edge.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"luma\", \"image\", \"dissolve\"],\n loop: 4,\n source: glsl(\n `// Luma fade: each pixel switches when progress passes its brightness, with a soft edge.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uSoftness; // @control min=0.01 max=0.5 default=0.1 label=\"Softness\"\nuniform bool uLightFirst; // @control default=false label=\"Light first\"\nuniform int uSource; // @control min=0 max=1 default=0 label=\"Brightness of (0 From, 1 To)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n vec4 a = coverRGBA(uFrom, uv);\n vec4 b = coverRGBA(uTo, uv);\n float l = clamp(luma(uSource == 0 ? a.rgb : b.rgb), 0.0, 1.0);\n if (uLightFirst) l = 1.0 - l;\n // The front sweeps from below the darkest pixel to above the lightest, so both ends are clean.\n float front = mix(-uSoftness, 1.0 + uSoftness, t);\n fragColor = mix(a, b, smoothstep(l - uSoftness, l + uSoftness, front));\n}`,\n ),\n presets: [\n { name: \"Highlights first\", values: { uLightFirst: true, uSoftness: 0.06 } },\n { name: \"Hard threshold\", values: { uSoftness: 0.01, uSource: 1 } },\n ],\n};\n\nexport const transitionParticleSwap: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-particle-swap\",\n name: \"Particle swap\",\n description: \"The image breaks into square particles that tumble along curved, staggered paths and land as the next image.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"particles\", \"image\", \"mosaic\"],\n loop: 4,\n source: glsl(\n `// Particle swap: each cell of From flies to a neighbouring cell's place, shrinking and spinning on the way, and lands as To.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uParticle; // @control min=6 max=80 default=20 label=\"Particle size (px)\"\nuniform float uScatter; // @control min=0 max=0.8 default=0.45 label=\"Scatter\"\nuniform float uSpin; // @control min=0 max=2 default=0.6 label=\"Spin & curl\"\nuniform vec3 uBackground; // @control color default=#0B0B12 label=\"Background\"\n${BACKDROP_CONTROLS}`,\n HASH,\n ROTATE,\n PICTURE,\n COMMON,\n `const vec2 RING[4] = vec2[4](vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0));\n\n// Where cell c's particle lands: cells trade places around each 2 × 2 block, turned 1–3 steps.\nvec2 landing(vec2 c) {\n vec2 block = floor(c * 0.5);\n vec2 local = c - block * 2.0;\n int i = local.y < 0.5 ? int(local.x) : 3 - int(local.x);\n int turn = 1 + int(hash12(block + 7.3) * 2.999);\n return block * 2.0 + RING[(i + turn) % 4];\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = progress();\n vec2 p = fragCoord / uParticle;\n vec2 grid = iResolution.xy / uParticle;\n vec2 base = floor(p);\n vec4 col = vec4(uBackground, uBackdropAlpha);\n float top = -1.0;\n vec2 hitFrom = vec2(0.0);\n vec2 hitTo = vec2(0.0);\n float hitT = 0.0;\n float hitCover = 0.0;\n // Particles travel at most about 1.5 cells, so the 5 × 5 cells around are every candidate.\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 c = base + vec2(float(i), float(j));\n vec2 h = hash22(c);\n // Staggered: a sweep from the left plus some randomness.\n float delay = 0.5 * (0.55 * clamp(c.x / grid.x, 0.0, 1.0) + 0.45 * h.x);\n float k = smoothstep(0.0, 1.0, clamp((t - delay) / 0.5, 0.0, 1.0));\n float lift = sin(3.14159 * k);\n vec2 from = c + 0.5;\n vec2 to = landing(c) + 0.5;\n vec2 path = to - from;\n vec2 side = normalize(vec2(-path.y, path.x) + (h - 0.5) * 0.8);\n vec2 pos = mix(from, to, k) + side * lift * (uScatter + uSpin * 0.3) * (h.y > 0.5 ? 0.6 : -0.6);\n float size = 1.0 - 0.3 * lift;\n float angle = (h.y - 0.5) * 6.28318 * uSpin * lift;\n vec2 l = rot(-angle) * (p - pos) / size;\n float m = max(abs(l.x), abs(l.y));\n float z = h.y + lift;\n if (m <= 0.5 && z > top) {\n top = z;\n hitFrom = from + l;\n hitTo = to + l;\n hitT = k;\n hitCover = 1.0 - smoothstep(0.5 - 1.5 / uParticle, 0.5, m) * min(lift * 8.0, 1.0);\n }\n }\n }\n if (top > -1.0) {\n vec4 particle = mix(coverRGBA(uFrom, hitFrom / grid), coverRGBA(uTo, hitTo / grid), hitT);\n particle.rgb *= 1.0 + 0.15 * sin(3.14159 * hitT);\n col = mix(col, particle, hitCover);\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Confetti\", values: { uParticle: 10, uScatter: 0.8, uSpin: 1.6 } },\n { name: \"Tiles\", values: { uParticle: 48, uScatter: 0.2, uSpin: 0.15 } },\n ],\n};\n\nexport const transitionInkBleed: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-ink-bleed\",\n name: \"Ink bleed\",\n description: \"The next image bleeds through the first like wet ink on paper, spreading from a few seeds with dark, pooled edges.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"ink\", \"watercolour\", \"image\", \"organic\"],\n loop: 4,\n source: glsl(\n `// Ink bleed: To spreads through From along an fbm threshold grown from seeds, with a wet, darkened fringe.\n${pair(SAMPLE_IMAGES.city, SAMPLE_IMAGES.landscape)}\nuniform float uScale; // @control min=0.5 max=8 default=3 label=\"Scale\"\nuniform float uEdge; // @control min=0.005 max=0.2 default=0.05 label=\"Edge width\"\nuniform vec3 uInk; // @control color default=#1B1F3B label=\"Ink\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n vec2 q = fragCoord / iResolution.y;\n // Distance to the nearest of four seeds spread across the frame, measured through a noisy warp so the blots are ragged.\n vec2 warped = q + (vec2(fbm(q * uScale, 5), fbm(q * uScale + 31.7, 5)) - 0.5) * 0.35;\n float aspect = iResolution.x / iResolution.y;\n float near = 1e9;\n for (int i = 0; i < 4; i++) {\n vec2 h = hash22(vec2(float(i), 3.7));\n vec2 seed = vec2((float(i) + 0.2 + 0.6 * h.x) / 4.0 * aspect, 0.2 + 0.6 * h.y);\n near = min(near, length(warped - seed));\n }\n // Fine noise adds capillary fingers to the front.\n float v = clamp(near / 0.5 * 0.75 + 0.25 * fbm(q * uScale * 4.0, 4) + 0.06 * (vnoise(q * uScale * 18.0) - 0.5), 0.0, 1.0);\n float front = mix(-2.0 * uEdge - 0.02, 1.0 + 2.0 * uEdge + 0.02, t);\n float gap = front - v;\n float wet = smoothstep(-uEdge * 0.3, uEdge * 0.3, gap);\n // Paper just ahead of the front darkens as it soaks; pigment pools just behind it.\n float soak = smoothstep(-2.0 * uEdge, 0.0, gap) * (1.0 - wet);\n float pool = wet * smoothstep(uEdge, 0.0, gap);\n vec2 bleed = vec2(soak - pool) * 0.004;\n vec4 col = mix(coverRGBA(uFrom, uv + bleed), coverRGBA(uTo, uv - bleed), wet);\n col.rgb = mix(col.rgb, col.rgb * 0.82, soak * 0.6);\n col = mix(col, vec4(uInk, 1.0), pool * 0.85);\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Sepia wash\", values: { uInk: [0.36, 0.23, 0.12], uEdge: 0.08, uScale: 2 } },\n { name: \"Crisp\", values: { uEdge: 0.015, uScale: 5 } },\n ],\n};\n\n/** Shaders that turn one image into another: true morphs (category \"morph\") and morph-like transitions. */\nexport const morphShaders: ShaderEffect[] = [\n featureMorph,\n silhouetteMorph,\n transitionLiquidMorph,\n transitionDisplacement,\n transitionLuma,\n transitionParticleSwap,\n transitionInkBleed,\n];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/**\n * `glow(c)`: light as a colour over whatever is behind it. Its alpha is its\n * brightest channel, so it brightens what is under it like a screen blend.\n */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/**\n * `over(acc, colour, alpha)`: paints a colour over a premultiplied\n * accumulator; `unpremultiply(acc)` turns it into straight colour and coverage.\n */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\nexport const rainOnGlass: ShaderEffect = {\n kind: \"shader\",\n id: \"rain-on-glass\",\n name: \"Rain on glass\",\n description: \"Raindrops sliding down a window in fits and starts, leaving beaded trails behind them.\",\n category: \"overlay\",\n tags: [\"overlay\", \"rain\", \"weather\", \"moody\", \"window\"],\n transparent: true,\n source: glsl(\n `// Rain on glass: drops sliding down a pane, leaving trails of beads.\nuniform float uDensity; // @control min=0 max=1 default=0.7 label=\"Density\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSize; // @control min=0.5 max=2 default=1 label=\"Drop size\"\nuniform vec3 uTint; // @control color default=#CFE3F0 label=\"Tint\"`,\n HASH,\n OVER,\n `// One drop of radius r at offset d: a faint tinted body, a darker rim and a bright highlight.\nvec4 paintDrop(vec4 acc, vec2 d, float r, float px) {\n float dist = length(d);\n if (dist > r + px) return acc;\n float m = (1.0 - smoothstep(r - 1.5 * px, r, dist)) * smoothstep(0.0, 2.0 * px, r);\n vec2 n = d / max(r, 1e-5);\n float l = length(n);\n float rim = smoothstep(0.45, 1.0, l) * m;\n float spec = (1.0 - smoothstep(0.0, 0.3, length(n - vec2(-0.3, 0.38)))) * m;\n float caustic = (1.0 - smoothstep(0.0, 0.5, length(n - vec2(0.15, -0.5)))) * m;\n acc = over(acc, uTint, m * 0.2);\n acc = over(acc, vec3(0.0, 0.02, 0.05), rim * 0.5);\n acc = over(acc, mix(uTint, vec3(1.0), 0.6), caustic * 0.3);\n return over(acc, vec3(1.0), spec * 0.9);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n vec4 acc = vec4(0.0);\n\n // Condensation: still beads slowly forming and drying up.\n float beads = 30.0 / uSize;\n vec2 bq = p * beads;\n vec2 bid = floor(bq);\n vec2 bh = hash22(bid);\n float life = fract(iTime * 0.04 + bh.x * 7.0);\n float br = (0.12 + 0.18 * bh.y) / beads * sin(3.14159 * life);\n if (hash12(bid + 5.0) < uDensity) acc = paintDrop(acc, (fract(bq) - 0.5 - (bh - 0.5) * 0.4) / beads, br, px);\n\n // Running drops: one per cell at most, sliding down a wavy path with a trail above.\n for (int i = 0; i < 2; i++) {\n float fi = float(i);\n vec2 cell = vec2(0.12, 0.3) * uSize * (1.0 - 0.3 * fi);\n vec2 q = p / cell + vec2(fi * 3.7, 0.0);\n float column = floor(q.x);\n q.y += t * 0.15 + hash12(vec2(column, fi)) * 9.0;\n vec2 id = floor(q);\n vec2 f = fract(q) - 0.5;\n vec2 h = hash22(id + fi * 17.0);\n if (h.x > uDensity) continue;\n float tt = t * 1.2 + h.y * 6.28318;\n float y = -0.38 * sin(tt + sin(tt + sin(tt) * 0.5));\n float base = (h.y - 0.5) * 0.3;\n float wobble = h.x * 6.28318;\n float x = base + 0.03 * sin(y * 9.0 + wobble);\n float aspect = cell.x / cell.y;\n float r = cell.y * (0.05 + 0.04 * fract(h.x * 13.7));\n vec2 d = vec2((f.x - x) * aspect, f.y - y) * cell.y;\n d.y *= d.y > 0.0 ? 0.8 : 1.0;\n acc = paintDrop(acc, d, r, px);\n if (f.y > y) {\n float rows = 10.0;\n float row = floor(f.y * rows);\n float tx = base + 0.03 * sin((row + 0.5) / rows * 9.0 + wobble);\n vec2 bd = vec2((f.x - tx) * aspect, (fract(f.y * rows) - 0.5) / rows) * cell.y;\n float fade = 1.0 - clamp((f.y - y) / (0.5 - y), 0.0, 1.0);\n float keep = step(0.35, hash12(id * 3.1 + vec2(row, fi)));\n acc = paintDrop(acc, bd, r * 0.35 * fade * keep, px);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Storm\", values: { uDensity: 1, uSpeed: 1.8, uSize: 1.3 } },\n { name: \"Drizzle\", values: { uDensity: 0.4, uSpeed: 0.6, uSize: 0.7 } },\n ],\n};\n\nexport const snowfall: ShaderEffect = {\n kind: \"shader\",\n id: \"snowfall\",\n name: \"Snowfall\",\n description: \"Layers of snowflakes drifting down on the wind, the far ones smaller and softer.\",\n category: \"overlay\",\n tags: [\"overlay\", \"snow\", \"winter\", \"festive\", \"particles\"],\n transparent: true,\n source: glsl(\n `// Snowfall: layered flakes drifting with the wind, far layers smaller and blurrier.\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Colour\"\nuniform float uDensity; // @control min=0 max=1 default=0.6 label=\"Density\"\nuniform float uWind; // @control min=-2 max=2 default=0.3 label=\"Wind\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Fall speed\"\nuniform float uSize; // @control min=0.2 max=2 default=1 label=\"Size\"\nuniform int uLayers; // @control min=1 max=6 default=4 label=\"Layers\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float px = 1.0 / iResolution.y;\n float a = 0.0;\n for (int i = 0; i < 6; i++) {\n if (i >= uLayers) break;\n float fi = float(i);\n // Layer 0 is the farthest: smaller, slower, softer and fainter.\n float depth = (fi + 1.0) / float(uLayers);\n float scale = mix(22.0, 6.0, depth);\n vec2 vel = vec2(uWind * 0.12 * (0.4 + depth), -uSpeed * mix(0.06, 0.25, depth));\n vec2 q = (p - vel * iTime) * scale + fi * 11.3;\n vec2 id = floor(q);\n vec2 h = hash22(id);\n if (hash12(id + 3.7) > uDensity) continue;\n float phase = iTime * (0.4 + 0.6 * h.x) + h.y * 6.28318;\n vec2 centre = (h - 0.5) * 0.3 + vec2(sin(phase) * 0.12, cos(phase * 0.7) * 0.05);\n float d = length(fract(q) - 0.5 - centre);\n float r = 0.06 * uSize * (0.6 + 0.8 * hash12(id + 9.1));\n float soft = max(px * scale * 1.5, r * mix(0.9, 0.3, depth));\n float flake = 1.0 - smoothstep(r - soft, r, d);\n a = max(a, flake * mix(0.45, 1.0, depth));\n }\n fragColor = vec4(uColor, a);\n}`,\n ),\n presets: [\n { name: \"Dust motes\", values: { uColor: [1, 0.85, 0.63], uDensity: 0.25, uWind: 0.05, uSpeed: 0.08, uSize: 0.6, uLayers: 3 } },\n { name: \"Blizzard\", values: { uDensity: 0.9, uWind: 1.6, uSpeed: 2, uLayers: 6 } },\n ],\n};\n\nexport const lensFlare: ShaderEffect = {\n kind: \"shader\",\n id: \"lens-flare\",\n name: \"Lens flare\",\n description: \"An anamorphic lens flare: a long horizontal streak and a chain of ghosts through the centre, following the pointer.\",\n category: \"overlay\",\n tags: [\"overlay\", \"cinematic\", \"light\", \"interactive\", \"sci-fi\"],\n transparent: true,\n source: glsl(\n `// Lens flare: an anamorphic streak and ghosts along the line through the centre.\nuniform vec2 uSource; // @control min=-1 max=1 default=-0.45,0.4 label=\"Source\"\nuniform vec3 uColor; // @control color default=#FFC98A label=\"Colour\"\nuniform float uStreak; // @control min=0 max=2 default=1 label=\"Streak length\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"`,\n HASH,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 src = iMouse.z > 0.0\n ? (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y\n : uSource * vec2(aspect, 1.0) * 0.5;\n vec2 d = p - src;\n float r = length(d);\n vec3 col = uColor * (exp(-r * 20.0) * 1.5 + 0.015 / (r + 0.015) * 0.3);\n // The anamorphic streak: a bright thin line and a wider, fainter one, blue-shifted.\n vec3 streakColor = mix(uColor, vec3(0.45, 0.65, 1.0), 0.6);\n float len = uStreak + 1e-3;\n col += streakColor * exp(-abs(d.y) * 220.0) * exp(-abs(d.x) / (0.5 * len));\n col += streakColor * 0.4 * exp(-abs(d.y) * 60.0) * exp(-abs(d.x) / (0.25 * len));\n // Ghosts sit on the line from the source through the centre, mostly on the far side.\n for (int i = 0; i < 7; i++) {\n float fi = float(i);\n float along = mix(-1.6, 0.6, hash12(vec2(fi, 1.7)));\n float gr = mix(0.015, 0.11, hash12(vec2(fi, 4.1)));\n float gd = length(p - src * along);\n vec3 tint = mix(uColor, vec3(0.4, 0.85, 1.0), hash12(vec2(fi, 8.3)));\n float disc = (1.0 - smoothstep(gr * 0.6, gr, gd)) * 0.12;\n float ring = exp(-abs(gd - gr) * 90.0) * 0.18;\n col += tint * (hash12(vec2(fi, 2.9)) > 0.6 ? ring : disc);\n }\n fragColor = glow(col * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Sci-fi blue\", values: { uColor: [0.5, 0.7, 1], uStreak: 1.8 } },\n { name: \"Golden hour\", values: { uColor: [1, 0.7, 0.28], uStreak: 0.6, uIntensity: 1.3 } },\n ],\n};\n\nexport const vignetteGrain: ShaderEffect = {\n kind: \"shader\",\n id: \"vignette-grain\",\n name: \"Vignette & grain\",\n description: \"Darkened corners and fine animated film grain to lay over any picture.\",\n category: \"overlay\",\n tags: [\"overlay\", \"cinematic\", \"film\", \"grain\", \"vintage\"],\n transparent: true,\n source: glsl(\n `// Vignette & grain: darkened corners and fine grain, nothing else.\nuniform float uStrength; // @control min=0 max=1 default=0.6 label=\"Strength\"\nuniform float uRoundness; // @control min=0 max=1 default=0.5 label=\"Roundness\"\nuniform float uSoftness; // @control min=0.05 max=1 default=0.5 label=\"Softness\"\nuniform float uGrain; // @control min=0 max=0.3 default=0.08 label=\"Grain\"\nuniform float uGrainSize; // @control min=1 max=4 default=1.5 label=\"Grain size (px)\"`,\n HASH,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float aspect = iResolution.x / iResolution.y;\n // 0 at the centre, 1 at the edges; rounder shapes measure across the frame's aspect.\n vec2 q = abs(fragCoord / iResolution.xy - 0.5) * 2.0;\n q.x *= mix(1.0, aspect, uRoundness * 0.5);\n float n = mix(8.0, 2.0, uRoundness);\n float dist = pow(pow(q.x, n) + pow(q.y, n), 1.0 / n);\n float dark = smoothstep(1.25 - uSoftness * 1.2, 1.3, dist) * uStrength;\n vec4 acc = over(vec4(0.0), vec3(0.0), dark);\n float frame = mod(floor(iTime * 24.0), 64.0);\n float g = hash12(floor(fragCoord / uGrainSize) + frame * vec2(17.31, 31.73)) - 0.5;\n acc = over(acc, vec3(step(0.0, g)), abs(g) * uGrain * 2.0);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Subtle\", values: { uStrength: 0.35, uGrain: 0.04 } },\n { name: \"Gritty\", values: { uStrength: 0.8, uSoftness: 0.3, uGrain: 0.18, uGrainSize: 2 } },\n ],\n};\n\nexport const scanlineSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"scanline-sweep\",\n name: \"Scanline sweep\",\n description: \"A bright scanning line with a glow and fading trail passing across, like a scanner or hologram.\",\n category: \"overlay\",\n tags: [\"overlay\", \"scan\", \"hologram\", \"sci-fi\", \"tech\"],\n transparent: true,\n source: glsl(\n `// Scanline sweep: a glowing line with a faint trail crossing the frame at intervals.\nuniform float uAngle; // @control min=0 max=360 default=270 label=\"Direction (°)\"\nuniform float uSpeed; // @control min=0.1 max=3 default=1 label=\"Speed\"\nuniform float uWidth; // @control min=0.001 max=0.05 default=0.006 label=\"Width\"\nuniform vec3 uColor; // @control color default=#4FF0FF label=\"Colour\"\nuniform float uInterval; // @control min=0 max=5 default=1 label=\"Pause (s)\"\nuniform float uTrail; // @control min=0 max=1 default=0.5 label=\"Trail\"`,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float px = 1.0 / iResolution.y;\n float a = radians(uAngle);\n vec2 dir = vec2(cos(a), sin(a));\n float s = dot(p, dir);\n // Start and end far enough past the frame that the trail has gone before the next pass.\n float trailLength = 0.02 + 0.2 * uTrail;\n float reach = 0.5 * (abs(dir.x) * aspect + abs(dir.y)) + uWidth * 6.0 + trailLength * 4.0;\n float sweep = 1.5 / uSpeed;\n float k = mod(iTime, sweep + uInterval) / sweep;\n float d = s - mix(-reach, reach, k);\n float core = 1.0 - smoothstep(uWidth * 0.5, uWidth * 0.5 + px, abs(d));\n float halo = exp(-abs(d) / (uWidth * 3.0)) * 0.6;\n float trail = d < 0.0 ? exp(d / trailLength) * 0.35 * uTrail : 0.0;\n trail *= 0.75 + 0.25 * sin(fragCoord.y * 2.0);\n fragColor = glow(uColor * (core * 1.5 + halo + trail));\n}`,\n ),\n presets: [\n { name: \"Hologram\", values: { uAngle: 90, uColor: [0.3, 1, 0.6], uSpeed: 0.6, uInterval: 0, uTrail: 0.9 } },\n { name: \"Barcode scanner\", values: { uAngle: 0, uColor: [1, 0.15, 0.15], uSpeed: 2, uInterval: 0.2, uWidth: 0.003 } },\n ],\n};\n\nexport const spotlight: ShaderEffect = {\n kind: \"shader\",\n id: \"spotlight\",\n name: \"Spotlight\",\n description: \"Darkness everywhere but a soft circle of light that follows the pointer or wanders on its own.\",\n category: \"overlay\",\n tags: [\"overlay\", \"interactive\", \"reveal\", \"focus\", \"dramatic\"],\n transparent: true,\n source: glsl(\n `// Spotlight: dark everywhere but a soft circle, at the pointer or drifting.\nuniform float uRadius; // @control min=0.05 max=0.8 default=0.25 label=\"Radius\"\nuniform float uSoftness; // @control min=0 max=1 default=0.4 label=\"Softness\"\nuniform float uDarkness; // @control min=0 max=1 default=0.85 label=\"Darkness\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Drift speed\"\nuniform vec3 uShade; // @control color default=#05050A label=\"Shade\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n vec2 centre = iMouse.z > 0.0\n ? (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y\n : vec2(sin(t * 2.0) * 0.32 * aspect, sin(t * 3.0 + 0.5) * 0.28);\n float r = length(p - centre);\n float dark = smoothstep(uRadius * (1.0 - uSoftness) - px, uRadius + px, r);\n fragColor = vec4(uShade, dark * uDarkness);\n}`,\n ),\n presets: [\n { name: \"Stage\", values: { uRadius: 0.35, uSoftness: 0.15, uDarkness: 0.95, uSpeed: 0.15 } },\n { name: \"Torch\", values: { uRadius: 0.18, uSoftness: 0.7, uDarkness: 1, uShade: [0.02, 0.01, 0] } },\n ],\n};\n\nexport const embers: ShaderEffect = {\n kind: \"shader\",\n id: \"embers\",\n name: \"Embers\",\n description: \"Glowing sparks rising from below, swaying and flickering out as they cool.\",\n category: \"overlay\",\n tags: [\"overlay\", \"fire\", \"sparks\", \"particles\", \"warm\"],\n transparent: true,\n source: glsl(\n `// Embers: sparks rising, swaying and flickering out as they cool.\nuniform int uCount; // @control min=5 max=80 default=40 label=\"Sparks\"\nuniform vec3 uHeat; // @control color default=#FF7A1A label=\"Heat\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Rise speed\"\nuniform float uSize; // @control min=0.3 max=3 default=1 label=\"Size\"`,\n HASH,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec3 col = vec3(0.0);\n for (int i = 0; i < 80; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 h = hash22(vec2(fi, 1.3));\n float clock = iTime * uSpeed * 0.18 * (0.6 + 0.8 * h.y) + h.x;\n float life = fract(clock);\n // Each life starts somewhere new along the bottom.\n vec2 seed = vec2(fi, floor(clock));\n float x = hash12(seed) * aspect + 0.04 * sin(life * 8.0 + fi) + life * 0.15 * (hash12(seed + 2.0) - 0.5);\n float y = life * (0.5 + 0.7 * hash12(seed + 4.0)) - 0.02;\n float r = 0.005 * uSize * (0.5 + hash12(seed + 6.0));\n vec2 d = p - vec2(x, y);\n d.y *= 0.6;\n float dist = length(d);\n if (dist > r * 14.0) continue;\n float fade = smoothstep(0.0, 0.08, life) * (1.0 - smoothstep(0.45, 1.0, life));\n float flicker = 0.6 + 0.4 * sin(iTime * 17.0 + fi * 3.7) * sin(iTime * 7.3 + fi);\n vec3 heat = mix(vec3(1.0, 0.95, 0.75), uHeat, smoothstep(0.0, 0.5, life));\n heat = mix(heat, uHeat * vec3(0.8, 0.25, 0.1), smoothstep(0.5, 1.0, life));\n float core = 1.0 - smoothstep(r * 0.4, r, dist);\n float halo = exp(-dist / (r * 2.5)) * 0.35;\n col += heat * (core * 1.5 + halo) * fade * flicker;\n }\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Bonfire\", values: { uCount: 80, uSpeed: 1.6, uSize: 1.3 } },\n { name: \"Magic sparks\", values: { uHeat: [0.55, 0.4, 1], uCount: 30, uSpeed: 0.6 } },\n ],\n};\n\nexport const shineSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"shine-sweep\",\n name: \"Shine sweep\",\n description: \"A soft diagonal gloss band gliding across now and then, for cards and buttons.\",\n category: \"overlay\",\n tags: [\"overlay\", \"ui\", \"gloss\", \"premium\", \"button\"],\n transparent: true,\n source: glsl(\n `// Shine sweep: a soft gloss band crossing the frame at intervals.\nuniform float uAngle; // @control min=-60 max=60 default=25 label=\"Tilt (°)\"\nuniform float uWidth; // @control min=0.02 max=0.5 default=0.15 label=\"Width\"\nuniform float uIntensity; // @control min=0 max=1 default=0.6 label=\"Intensity\"\nuniform float uInterval; // @control min=1 max=8 default=3 label=\"Every (s)\"\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Colour\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float slope = tan(radians(uAngle));\n float s = p.x + p.y * slope;\n float reach = 0.5 * aspect + 0.5 * abs(slope) + uWidth;\n // Each sweep takes 0.9 s, then waits for the next.\n float k = clamp(mod(iTime, uInterval) / 0.9, 0.0, 1.0);\n k = k * k * (3.0 - 2.0 * k);\n float d = (s - mix(-reach, reach, k)) / uWidth;\n float band = exp(-d * d * 4.0) * 0.7 + exp(-d * d * 60.0) * 0.5;\n fragColor = vec4(uColor, clamp(band * uIntensity, 0.0, 1.0));\n}`,\n ),\n presets: [\n { name: \"Gold foil\", values: { uColor: [1, 0.9, 0.6], uWidth: 0.25, uIntensity: 0.5 } },\n { name: \"Quick glint\", values: { uWidth: 0.06, uIntensity: 0.9, uInterval: 1.5, uAngle: 35 } },\n ],\n};\n\nexport const frostCreep: ShaderEffect = {\n kind: \"shader\",\n id: \"frost-creep\",\n name: \"Frost creep\",\n description: \"Ice crystals creeping in from the edges of the frame and melting back.\",\n category: \"overlay\",\n tags: [\"overlay\", \"ice\", \"winter\", \"frozen\", \"reveal\"],\n transparent: true,\n loop: 8,\n source: glsl(\n `// Frost creep: crystalline frost growing in from the edges.\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uCoverage; // @control min=0 max=1 default=0.6 label=\"Coverage (when still)\"\nuniform float uScale; // @control min=1 max=10 default=4 label=\"Crystal size\"\nuniform vec3 uColor; // @control color default=#DDF2FF label=\"Frost\"`,\n HASH,\n NOISE,\n FBM,\n `// Voronoi: x = distance to the nearest point, y = to the second, zw = the nearest cell.\nvec4 voronoi(vec2 q) {\n vec2 id = floor(q);\n vec2 f = fract(q);\n float f1 = 8.0;\n float f2 = 8.0;\n vec2 nearest = id;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 o = vec2(float(i), float(j));\n float d = length(o + hash22(id + o) - f);\n if (d < f1) {\n f2 = f1;\n f1 = d;\n nearest = id + o;\n } else if (d < f2) {\n f2 = d;\n }\n }\n }\n return vec4(f1, f2, nearest);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float coverage = uAnimate ? 0.5 - 0.5 * cos(iTime * 6.28318 / 8.0) : uCoverage;\n // Distance in from the nearest edge, roughened by noise and stepped per crystal.\n float edge = min(min(fragCoord.x, iResolution.x - fragCoord.x), min(fragCoord.y, iResolution.y - fragCoord.y)) / iResolution.y;\n vec4 v = voronoi(p * uScale * 3.0);\n float n = fbm(p * uScale * 0.8, 5);\n float g = edge + (n - 0.5) * 0.3 + (hash12(v.zw) - 0.5) * 0.04;\n float front = mix(-0.25, 0.75, coverage);\n float frost = 1.0 - smoothstep(front - 0.06, front, g);\n if (frost <= 0.0) {\n fragColor = vec4(0.0);\n return;\n }\n // Facets catch the light differently; their edges and fine needles glint.\n float facet = hash12(v.zw + 3.1);\n float ridges = 1.0 - smoothstep(0.0, 0.06, v.y - v.x);\n float needles = smoothstep(0.55, 0.8, fbm(p * uScale * vec2(6.0, 1.5) + v.zw, 3));\n float fresh = 1.0 - smoothstep(0.0, 0.35, front - g);\n float rim = smoothstep(front - 0.06, front - 0.015, g);\n vec3 col = mix(uColor * vec3(0.8, 0.9, 1.0), vec3(1.0), facet * 0.4 + ridges * 0.6 + rim * 0.5 + needles * 0.4);\n float alpha = frost * clamp(0.35 + 0.25 * (1.0 - fresh) + 0.2 * facet + 0.35 * ridges + 0.25 * needles + 0.3 * rim, 0.0, 1.0);\n fragColor = vec4(min(col, 1.0), alpha);\n}`,\n ),\n presets: [\n { name: \"Hoarfrost\", values: { uAnimate: false, uCoverage: 0.85, uScale: 6 } },\n { name: \"Icy blue\", values: { uColor: [0.62, 0.83, 1], uScale: 2.5 } },\n ],\n};\n\n/** Effects drawn over other content: transparent where there is nothing to draw (see `ShaderEffect.transparent`). */\nexport const overlayEffects: ShaderEffect[] = [\n rainOnGlass,\n snowfall,\n lensFlare,\n vignetteGrain,\n scanlineSweep,\n spotlight,\n embers,\n shineSweep,\n frostCreep,\n];\n","import { glsl, HASH } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const synthwaveGrid: ShaderEffect = {\n kind: \"shader\",\n id: \"synthwave\",\n name: \"Synthwave\",\n description: \"A neon perspective grid racing towards a striped retro sun.\",\n category: \"retro\",\n tags: [\"background\", \"80s\", \"neon\", \"music\", \"loop\"],\n loop: 1,\n source: glsl(\n `// Synthwave: a neon grid racing towards a striped sun.\nuniform vec3 uSkyTop; // @control color default=#12002B label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#7A1A6B label=\"Sky bottom\"\nuniform vec3 uSunTop; // @control color default=#FFE45E label=\"Sun top\"\nuniform vec3 uSunBottom; // @control color default=#FF3D7F label=\"Sun bottom\"\nuniform vec3 uGrid; // @control color default=#00F0FF label=\"Grid\"\nuniform float uHorizon; // @control min=0.2 max=0.7 default=0.42 label=\"Horizon\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float horizon = uHorizon - 0.5;\n vec3 col;\n if (p.y > horizon) {\n float h = (p.y - horizon) / (0.5 - horizon);\n col = mix(uSkyBottom, uSkyTop, h);\n vec2 s = p - vec2(0.0, horizon + 0.18);\n float sun = smoothstep(0.2, 0.195, length(s));\n float bands = step(0.0, sin((s.y + 0.2) * 60.0 - 1.5)) + step(0.06, s.y);\n sun *= clamp(bands, 0.0, 1.0);\n col = mix(col, mix(uSunBottom, uSunTop, clamp(s.y / 0.2 * 0.5 + 0.5, 0.0, 1.0)), sun);\n col += uSunBottom * 0.25 * exp(-length(s) * 4.0);\n } else {\n float depth = (horizon - p.y);\n vec2 g = vec2(p.x / depth, 1.0 / depth);\n g.y += iTime * 2.0;\n vec2 grid = abs(fract(g * 0.5) - 0.5) / fwidth(g * 0.5);\n float line = 1.0 - clamp(min(grid.x, grid.y), 0.0, 1.0);\n float fade = smoothstep(0.0, 0.25, depth);\n col = mix(uSkyTop * 0.4, uSkyBottom * 0.3, uv.y);\n col += uGrid * line * fade + uGrid * 0.25 * exp(-depth * 20.0);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const tvStatic: ShaderEffect = {\n kind: \"shader\",\n id: \"tv-static\",\n name: \"TV static\",\n description: \"Analogue snow with rolling bars and scanlines.\",\n category: \"retro\",\n tags: [\"glitch\", \"analogue\", \"transition\", \"noise\"],\n source: glsl(\n `// TV static: analogue snow with a rolling bar and scanlines.\nuniform float uAmount; // @control min=0 max=1 default=0.9 label=\"Snow\"\nuniform float uScanlines; // @control min=0 max=1 default=0.35 label=\"Scanlines\"\nuniform float uRoll; // @control min=0 max=1 default=0.3 label=\"Rolling bar\"\nuniform vec3 uTint; // @control color default=#E6E6E6 label=\"Tint\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float n = hash12(floor(fragCoord * 0.5) + floor(iTime * 30.0) * 17.31);\n float scan = 1.0 - uScanlines * 0.5 * (1.0 + sin(fragCoord.y * 3.14159));\n float bar = 1.0 + uRoll * 0.6 * smoothstep(0.15, 0.0, abs(fract(uv.y - iTime * 0.2) - 0.5) - 0.3);\n vec3 col = uTint * mix(0.5, n, uAmount) * scan * bar;\n col *= smoothstep(1.2, 0.4, length(uv - 0.5) * 1.4);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const digitalRain: ShaderEffect = {\n kind: \"shader\",\n id: \"digital-rain\",\n name: \"Digital rain\",\n description: \"Columns of glyph-like characters raining down a terminal.\",\n category: \"retro\",\n tags: [\"hacker\", \"code\", \"tech\", \"cyber\"],\n source: glsl(\n `// Digital rain: glyph-like cells raining down in columns.\nuniform vec3 uBackground; // @control color default=#000000 label=\"Background\"\nuniform vec3 uGlyph; // @control color default=#22FF66 label=\"Glyph\"\nuniform float uCell; // @control min=6 max=40 default=14 label=\"Cell size (px)\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Speed\"`,\n HASH,\n `float glyph(vec2 cell, vec2 f) {\n vec2 g = floor(f * vec2(3.0, 5.0));\n float on = step(0.45, hash12(g + cell * 13.7 + floor(iTime * 4.0 * hash12(cell))));\n vec2 inset = abs(fract(f * vec2(3.0, 5.0)) - 0.5);\n return on * step(max(inset.x, inset.y), 0.38);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 q = fragCoord / uCell;\n vec2 cell = floor(q);\n vec2 f = fract(q);\n float col = cell.x;\n float speed = (0.5 + hash12(vec2(col, 1.0))) * uSpeed * 8.0;\n float offset = hash12(vec2(col, 2.0)) * 100.0;\n float head = fract((iTime * speed + offset) / 40.0) * (iResolution.y / uCell + 30.0);\n float y = iResolution.y / uCell - cell.y;\n float trail = head - y;\n float lit = trail >= 0.0 ? exp(-trail * 0.15) : 0.0;\n float isHead = step(abs(trail), 0.5);\n float g = glyph(cell, f);\n vec3 c = uBackground + uGlyph * g * lit + vec3(0.8) * g * isHead;\n fragColor = vec4(c, 1.0);\n}`,\n ),\n};\n\nexport const pixelSunset: ShaderEffect = {\n kind: \"shader\",\n id: \"dither-gradient\",\n name: \"Dithered gradient\",\n description: \"A 1-bit Bayer-dithered gradient wave, like an old Mac or Game Boy screen.\",\n category: \"retro\",\n tags: [\"pixel\", \"1-bit\", \"lo-fi\", \"background\"],\n source: glsl(\n `// Dithered gradient: a Bayer-dithered gradient wave in two colours.\nuniform vec3 uDark; // @control color default=#0F380F label=\"Dark\"\nuniform vec3 uLight; // @control color default=#9BBC0F label=\"Light\"\nuniform float uPixel; // @control min=1 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"`,\n `float bayer4(vec2 p) {\n vec2 q = mod(floor(p), 4.0);\n int i = int(q.x) + int(q.y) * 4;\n int m[16] = int[16](0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5);\n return (float(m[i]) + 0.5) / 16.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 px = floor(fragCoord / uPixel);\n vec2 uv = px * uPixel / iResolution.xy;\n float v = uv.y + 0.15 * sin(uv.x * 6.0 + iTime * uSpeed * 2.0) + 0.1 * sin(uv.x * 13.0 - iTime * uSpeed * 3.0);\n v = clamp(v, 0.0, 1.0);\n float on = step(bayer4(px), v);\n fragColor = vec4(mix(uDark, uLight, on), 1.0);\n}`,\n ),\n presets: [\n { name: \"Mac\", values: { uDark: [0.05, 0.05, 0.05], uLight: [0.93, 0.93, 0.9] } },\n { name: \"Amber\", values: { uDark: [0.1, 0.04, 0], uLight: [1, 0.69, 0] } },\n ],\n};\n","import { FBM, glsl, HASH, NOISE, PALETTE } from \"../glsl.js\";\nimport { textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const shaderText: ShaderEffect = {\n kind: \"shader\",\n id: \"shader-text\",\n name: \"Shader text\",\n description: \"A title filled with a living texture (plasma, fire, caustics or liquid chrome), with a soft glow and outline.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"plasma\", \"fire\", \"chrome\", \"glow\"],\n source: glsl(\n `// Shader text: the letters of a text image filled with an animated pattern.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"FLAIR\")} label=\"Text\"\nuniform int uFill; // @control min=0 max=3 default=0 label=\"Fill (0 plasma, 1 fire, 2 caustics, 3 chrome)\"\nuniform vec3 uBackground; // @control color default=#0A0A12 label=\"Background\"\nuniform vec3 uTint; // @control color default=#FFFFFF label=\"Tint\"\nuniform float uSize; // @control min=0.3 max=1 default=0.9 label=\"Text size\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uGlow; // @control min=0 max=2 default=0.6 label=\"Glow\"\nuniform float uOutline; // @control min=0 max=0.02 default=0.004 label=\"Outline width\"\nuniform vec3 uOutlineColor; // @control color default=#FFFFFF label=\"Outline\"`,\n HASH,\n NOISE,\n FBM,\n PALETTE,\n `// The text image's alpha at frame point p (height 1, centred), the image contained in uSize of the frame.\nfloat letters(vec2 p) {\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float frame = iResolution.x / iResolution.y;\n float h = min(uSize, frame * uSize / aspect);\n vec2 uv = p / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uText, uv).a;\n}\n\nvec3 plasmaFill(vec2 p, float t) {\n float v = sin(p.x * 6.0 + t) + sin(p.y * 7.0 - t * 1.3) + sin((p.x + p.y) * 5.0 + t * 0.7) + sin(length(p * 8.0) - t * 2.0);\n return palette(v * 0.125 + 0.5 + t * 0.05, vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.0, 0.33, 0.67));\n}\n\nvec3 fireFill(vec2 p, float t) {\n float n = fbm(vec2(p.x * 5.0, p.y * 3.0 - t * 1.8), 5);\n float heat = clamp(1.1 - (p.y + 0.3) * 1.6 + (n - 0.5) * 1.2, 0.0, 1.0);\n return vec3(1.0, 0.35, 0.05) * heat * 1.4 + vec3(1.0, 0.85, 0.3) * pow(heat, 3.0) + vec3(0.25, 0.0, 0.0);\n}\n\nvec3 causticsFill(vec2 p, float t) {\n vec2 q = p * 6.0;\n vec2 i = q;\n float c = 1.0;\n for (int n = 0; n < 5; n++) {\n float tn = t * 0.5 * (1.0 - 3.5 / float(n + 1));\n i = q + vec2(cos(tn - i.x) + sin(tn + i.y), sin(tn - i.y) + cos(tn + i.x));\n c += 1.0 / length(vec2(q.x / (sin(i.x + tn) / 0.005), q.y / (cos(i.y + tn) / 0.005)));\n }\n c = 1.17 - pow(c / 5.0, 1.4);\n float light = pow(abs(c), 8.0);\n return clamp(vec3(0.0, 0.3, 0.5) + light * vec3(0.7, 1.0, 1.0), 0.0, 1.0);\n}\n\n// Liquid chrome: a horizon reflection bent by the letters' bevel and a slow warp.\nvec3 chromeFill(vec2 p, float t, vec2 normal) {\n float warp = fbm(p * 3.0 + vec2(t * 0.3, -t * 0.2), 4) - 0.5;\n float y = p.y * 2.5 + normal.y * 1.5 + warp * 1.2 + 0.15 * sin(p.x * 4.0 + t);\n vec3 sky = mix(vec3(0.85, 0.9, 1.0), vec3(0.3, 0.4, 0.6), clamp(y, 0.0, 1.0));\n vec3 ground = mix(vec3(0.25, 0.2, 0.2), vec3(0.05), clamp(-y, 0.0, 1.0));\n vec3 col = y > 0.0 ? sky : ground;\n col += smoothstep(0.06, 0.0, abs(y)) * 0.9;\n return col + pow(max(0.0, normal.x * 0.7 + normal.y * 0.7), 6.0) * 0.8;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float mask = letters(p);\n // A soft bevel from the mask's slope, for chrome's reflections.\n float e = 0.004;\n vec2 normal = vec2(letters(p + vec2(e, 0.0)) - letters(p - vec2(e, 0.0)), letters(p + vec2(0.0, e)) - letters(p - vec2(0.0, e)));\n // Glow and outline: the mask's average and maximum on rings round the point.\n float glow = 0.0;\n float ring = 0.0;\n for (int i = 0; i < 12; i++) {\n float a = float(i) * 0.5236;\n vec2 dir = vec2(cos(a), sin(a));\n glow += letters(p + dir * 0.02) + letters(p + dir * 0.05) * 0.6;\n ring = max(ring, letters(p + dir * uOutline));\n }\n glow /= 19.2;\n vec3 fill = uFill == 0 ? plasmaFill(p, t) : uFill == 1 ? fireFill(p, t) : uFill == 2 ? causticsFill(p, t) : chromeFill(p, t, normal * 2.0);\n fill *= uTint;\n vec3 col = uBackground + fill * glow * uGlow;\n col = mix(col, uOutlineColor, clamp(ring - mask, 0.0, 1.0) * step(0.0001, uOutline));\n col = mix(col, fill, mask);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Inferno\", values: { uFill: 1, uBackground: [0.05, 0.01, 0.0], uGlow: 1.2, uOutline: 0 } },\n { name: \"Pool\", values: { uFill: 2, uBackground: [0.0, 0.08, 0.14], uOutlineColor: [0.7, 0.95, 1] } },\n { name: \"Chrome\", values: { uFill: 3, uBackground: [0.06, 0.06, 0.08], uGlow: 0.3, uOutline: 0.002 } },\n ],\n};\n\n/** Shader effects that fill or animate text, drawn from a text image (see `textImage`). */\nexport const textShaders: ShaderEffect[] = [shaderText];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\nexport const imageKenBurns: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ken-burns\",\n name: \"Ken Burns\",\n description: \"A slow documentary-style pan and zoom across an image, easing in and out and back again.\",\n category: \"image\",\n tags: [\"image\", \"camera\", \"documentary\", \"slideshow\"],\n loop: 12,\n source: glsl(\n `// Ken Burns: a slow, eased pan and zoom across a cover-fitted image, there and back.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uZoomStart; // @control min=1 max=3 default=1.05 label=\"Start zoom\"\nuniform float uZoomEnd; // @control min=1 max=3 default=1.4 label=\"End zoom\"\nuniform float uAngle; // @control min=0 max=360 default=20 label=\"Pan direction (°)\"\nuniform float uDuration; // @control min=2 max=30 default=6 label=\"Duration (s)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // Cover-fit: the share of the image visible across and up (the test card fits the frame).\n vec2 size = vec2(textureSize(uImage, 0));\n float frameAspect = iResolution.x / iResolution.y;\n float imageAspect = size.x > 1.0 ? size.x / size.y : frameAspect;\n vec2 cover = frameAspect > imageAspect ? vec2(1.0, imageAspect / frameAspect) : vec2(frameAspect / imageAspect, 1.0);\n // 0 → 1 over one duration, back over the next, eased at both ends.\n float k = 0.5 - 0.5 * cos(3.14159265 * iTime / max(uDuration, 0.1));\n float zoom = max(mix(uZoomStart, uZoomEnd, k), 1.0);\n vec2 window = cover / zoom;\n // Pan as far as the window allows in the chosen direction, from one side to the other.\n float a = radians(uAngle);\n vec2 pan = vec2(cos(a), sin(a)) * (1.0 - window) * 0.5 * (2.0 * k - 1.0);\n fragColor = pictureRGBA(uImage, 0.5 + (uv - 0.5) * window + pan);\n}`,\n ),\n presets: [\n { name: \"Push in\", values: { uZoomStart: 1.0, uZoomEnd: 1.5, uAngle: 0 } },\n { name: \"Pull out\", values: { uZoomStart: 1.6, uZoomEnd: 1.05, uAngle: 200 } },\n { name: \"Slow drift\", values: { uZoomStart: 1.2, uZoomEnd: 1.25, uAngle: 0, uDuration: 12 } },\n ],\n};\n\nexport const imageAscii: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ascii\",\n name: \"ASCII art\",\n description: \"An image drawn as text characters picked by brightness, in one ink or the picture's own colours.\",\n category: \"image\",\n tags: [\"image\", \"ascii\", \"text\", \"terminal\", \"retro\"],\n source: glsl(\n `// ASCII art: each cell of the image becomes a character, denser for brighter cells.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uCell; // @control min=4 max=32 default=9 label=\"Cell size (px)\"\nuniform int uColourMode; // @control min=0 max=1 default=0 label=\"Colour (0 ink, 1 original)\"\nuniform vec3 uInk; // @control color default=#A3E635 label=\"Ink\"\nuniform vec3 uBackground; // @control color default=#0A0F0A label=\"Background\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// 5 × 7 glyphs, lightest to densest: bit (x + 5y) of .x holds rows 0–3 (top first), of .y rows 4–6.\nconst ivec2 GLYPHS[10] = ivec2[10](\n ivec2(0, 0), // space\n ivec2(0, 6336), // .\n ivec2(1015808, 0), // -\n ivec2(6336, 198), // :\n ivec2(1020032, 132), // +\n ivec2(31744, 31), // =\n ivec2(1030816, 686), // *\n ivec2(139875, 25378), // %\n ivec2(359754, 10591), // #\n ivec2(718382, 30781) // @\n);\n\n// Whether glyph g has ink at column x (0–4), row y (0–6, top first).\nfloat glyphBit(ivec2 g, int x, int y) {\n if (x < 0 || x > 4 || y < 0 || y > 6) return 0.0;\n int bits = y < 4 ? (g.x >> (x + 5 * y)) : (g.y >> (x + 5 * (y - 4)));\n return float(bits & 1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n // Cells are 7 × 9 units: the 5 × 7 glyph and a unit of margin around it.\n vec2 cell = vec2(uCell, uCell * 9.0 / 7.0);\n vec2 id = floor(fragCoord / cell);\n vec2 local = fract(fragCoord / cell);\n vec4 pic = pictureRGBA(uImage, (id + 0.5) * cell / iResolution.xy);\n vec3 src = pic.rgb;\n float l = pow(clamp(dot(src, vec3(0.2126, 0.7152, 0.0722)), 0.0, 1.0), 0.8);\n int level = int(min(l * 10.0, 9.0));\n int gx = int(floor(local.x * 7.0)) - 1;\n int gy = int(floor((1.0 - local.y) * 9.0)) - 1;\n float ink = glyphBit(GLYPHS[level], gx, gy);\n vec3 tint = uColourMode == 1 ? src * 1.25 : uInk;\n fragColor = vec4(mix(uBackground, tint, ink), pic.a);\n}`,\n ),\n presets: [\n { name: \"Terminal\", values: { uColourMode: 0, uInk: [0.64, 0.9, 0.21], uBackground: [0.04, 0.06, 0.04] } },\n { name: \"Colour\", values: { uColourMode: 1, uBackground: [0.02, 0.02, 0.03] } },\n { name: \"Typewriter\", values: { uColourMode: 0, uInk: [0.1, 0.1, 0.12], uBackground: [0.96, 0.94, 0.88], uCell: 7 } },\n ],\n};\n\nexport const imageShatter: ShaderEffect = {\n kind: \"shader\",\n id: \"image-shatter\",\n name: \"Shatter\",\n description: \"An image breaking into glass-like shards that fly apart, spin and reassemble in a loop.\",\n category: \"image\",\n tags: [\"image\", \"shatter\", \"transition\", \"voronoi\", \"explode\"],\n loop: 5,\n source: glsl(\n `// Shatter: Voronoi shards of the image fly apart, spin and come back together.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform bool uAuto; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uCount; // @control min=3 max=30 default=8 label=\"Shards (across height)\"\nuniform float uSpread; // @control min=0 max=2 default=0.6 label=\"Spread\"\nuniform float uSpin; // @control min=0 max=6.28 default=1.5 label=\"Spin\"\nuniform vec3 uBackground; // @control color default=#0B0B12 label=\"Background\"\n${BACKDROP_CONTROLS}`,\n HASH,\n ROTATE,\n PICTURE,\n `vec2 shardSite(vec2 cell) {\n return cell + 0.15 + 0.7 * hash22(cell);\n}\n\n// The shard (cell) under grid point q, and how far q is from its edge (xy: cell, z: edge gap).\nvec3 shardAt(vec2 q) {\n vec2 base = floor(q);\n float d1 = 1e9;\n float d2 = 1e9;\n vec2 id = base;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 c = base + vec2(float(i), float(j));\n float d = distance(q, shardSite(c));\n if (d < d1) {\n d2 = d1;\n d1 = d;\n id = c;\n } else if (d < d2) {\n d2 = d;\n }\n }\n }\n return vec3(id, d2 - d1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float k = uAuto ? smoothstep(0.2, 0.8, 0.5 - 0.5 * cos(iTime * 6.28318 / 5.0)) : uProgress;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uCount;\n // Shard centres move out from the middle; shards keep their size, so gaps open between them.\n float grow = 1.0 + uSpread * k;\n vec2 base = floor(p / grow);\n vec4 col = vec4(uBackground, uBackdropAlpha);\n float top = -1.0;\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 c = base + vec2(float(i), float(j));\n vec2 site = shardSite(c);\n vec2 h = hash22(c + 41.7);\n vec2 centre = site * grow + (h - 0.5) * 1.2 * k;\n float a = (h.x - 0.5) * 2.0 * uSpin * k;\n // Back to where this pixel would sit in the unbroken image, if it is on this shard.\n vec2 q = rot(-a) * (p - centre) + site;\n vec3 s = shardAt(q);\n if (s.x == c.x && s.y == c.y && h.y > top) {\n top = h.y;\n vec2 uv = q / uCount * iResolution.y / iResolution.xy + 0.5;\n vec4 shard = pictureRGBA(uImage, uv);\n shard.rgb *= 1.0 - 0.35 * k * abs(sin(a));\n shard.rgb += k * 0.35 * smoothstep(0.06, 0.0, s.z);\n col = shard;\n }\n }\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Burst\", values: { uCount: 6, uSpread: 1.4, uSpin: 3 } },\n { name: \"Crackle\", values: { uCount: 18, uSpread: 0.15, uSpin: 0.4 } },\n ],\n};\n\nexport const imageMelt: ShaderEffect = {\n kind: \"shader\",\n id: \"image-melt\",\n name: \"Melt\",\n description: \"An image melting and dripping downwards in slow, noisy runs.\",\n category: \"image\",\n tags: [\"image\", \"melt\", \"drip\", \"psychedelic\", \"distortion\"],\n source: glsl(\n `// Melt: noise-driven runs drag the image downwards.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmount; // @control min=0 max=0.6 default=0.18 label=\"Amount\"\nuniform float uSpeed; // @control min=0 max=2 default=0.35 label=\"Flow speed\"\nuniform float uScale; // @control min=1 max=20 default=6 label=\"Scale\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n // Columns run at different lengths; thin drips ride on top; runs grow towards the bottom.\n float runs = fbm(vec2(uv.x * uScale, t * 0.5), 4);\n float drips = pow(vnoise(vec2(uv.x * uScale * 5.0, t * 0.3 + 7.0)), 3.0);\n float drop = uAmount * (0.7 * runs + 0.6 * drips) * (0.35 + 0.65 * (1.0 - uv.y));\n float wobble = (vnoise(vec2(uv.y * uScale * 2.0 - t, uv.x * uScale)) - 0.5) * uAmount * 0.12;\n vec2 st = clamp(uv + vec2(wobble, drop), 0.0, 1.0);\n vec4 pic = pictureRGBA(uImage, st);\n // A little sheen along the leading edges of the runs.\n vec3 col = pic.rgb + 0.12 * smoothstep(0.55, 0.9, drips) * uAmount * 4.0;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Slow ooze\", values: { uAmount: 0.12, uSpeed: 0.15, uScale: 4 } },\n { name: \"Meltdown\", values: { uAmount: 0.45, uSpeed: 0.8, uScale: 9 } },\n ],\n};\n\nexport const imageRisograph: ShaderEffect = {\n kind: \"shader\",\n id: \"image-risograph\",\n name: \"Risograph\",\n description: \"An image printed in two posterized, slightly misregistered inks on grainy paper.\",\n category: \"image\",\n tags: [\"image\", \"print\", \"riso\", \"editorial\", \"poster\"],\n source: glsl(\n `// Risograph: two posterized ink layers, out of register, on grainy paper.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uLevels; // @control min=2 max=8 default=4 label=\"Levels\"\nuniform vec3 uInkA; // @control color default=#FF48B0 label=\"Ink A\"\nuniform vec3 uInkB; // @control color default=#0078BF label=\"Ink B\"\nuniform float uOffset; // @control min=0 max=20 default=4 label=\"Misregistration (px)\"\nuniform float uGrain; // @control min=0 max=1 default=0.4 label=\"Grain\"\nuniform vec3 uPaper; // @control color default=#F5EFE0 label=\"Paper\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `// Ink density stepped to a few levels, with grain dithering the steps.\nfloat posterize(float d, float levels, float grain) {\n return clamp(floor(d * (levels - 1.0) + 0.5 + grain) / (levels - 1.0), 0.0, 1.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 shift = vec2(uOffset, uOffset * 0.6) / iResolution.xy;\n float levels = float(uLevels);\n float fibre = hash12(fragCoord);\n float mottle = vnoise(fragCoord / 6.0);\n // Two separations: ink A where the picture lacks green, ink B where it lacks red.\n vec4 a = pictureRGBA(uImage, uv + shift);\n vec4 b = pictureRGBA(uImage, uv - shift);\n float dA = posterize(1.0 - a.g, levels, (hash12(fragCoord + 17.0) - 0.5) * uGrain * 0.6);\n float dB = posterize(1.0 - b.r, levels, (hash12(fragCoord + 53.0) - 0.5) * uGrain * 0.6);\n // Ink never lays down evenly: mottled, with paper showing through.\n float cover = 0.9 * (1.0 - uGrain * 0.35 * mottle);\n vec3 col = uPaper * (1.0 - uGrain * 0.08 * fibre);\n col *= mix(vec3(1.0), uInkA, dA * cover);\n col *= mix(vec3(1.0), uInkB, dB * cover);\n fragColor = vec4(col, max(a.a, b.a));\n}`,\n ),\n presets: [\n { name: \"Pink & blue\", values: { uInkA: [1, 0.28, 0.69], uInkB: [0, 0.47, 0.75] } },\n { name: \"Sunflower & teal\", values: { uInkA: [1, 0.71, 0], uInkB: [0, 0.51, 0.54], uLevels: 3 } },\n { name: \"Red & black\", values: { uInkA: [1, 0.25, 0.25], uInkB: [0.15, 0.15, 0.17], uOffset: 2, uGrain: 0.6 } },\n ],\n};\n\nexport const imageThermal: ShaderEffect = {\n kind: \"shader\",\n id: \"image-thermal\",\n name: \"Thermal\",\n description: \"An image seen through a heat camera or night-vision goggles.\",\n category: \"image\",\n tags: [\"image\", \"thermal\", \"night-vision\", \"surveillance\", \"colour\"],\n source: glsl(\n `// Thermal: brightness mapped to a heat palette, or to green night-vision phosphor.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uMode; // @control min=0 max=1 default=0 label=\"Palette (0 thermal, 1 night vision)\"\nuniform float uNoise; // @control min=0 max=0.5 default=0.04 label=\"Noise\"\nuniform float uContrast; // @control min=0.5 max=3 default=1.3 label=\"Contrast\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `vec3 heat(float t) {\n vec3 c = mix(vec3(0.0, 0.0, 0.08), vec3(0.15, 0.0, 0.55), smoothstep(0.0, 0.2, t));\n c = mix(c, vec3(0.75, 0.0, 0.55), smoothstep(0.2, 0.4, t));\n c = mix(c, vec3(1.0, 0.25, 0.0), smoothstep(0.4, 0.6, t));\n c = mix(c, vec3(1.0, 0.8, 0.0), smoothstep(0.6, 0.8, t));\n return mix(c, vec3(1.0, 1.0, 0.9), smoothstep(0.8, 1.0, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // Heat spreads, so take a soft average around the pixel.\n vec2 px = 2.0 / iResolution.xy;\n vec4 src = 0.4 * pictureRGBA(uImage, uv) + 0.15 * (pictureRGBA(uImage, uv + vec2(px.x, 0.0)) + pictureRGBA(uImage, uv - vec2(px.x, 0.0)) +\n pictureRGBA(uImage, uv + vec2(0.0, px.y)) + pictureRGBA(uImage, uv - vec2(0.0, px.y)));\n float l = dot(src.rgb, vec3(0.2126, 0.7152, 0.0722));\n l = clamp((l - 0.5) * uContrast + 0.5, 0.0, 1.0);\n float frame = floor(iTime * 24.0);\n float grain = hash12(fragCoord + frame * 37.1) - 0.5;\n vec3 col;\n if (uMode == 0) {\n col = heat(clamp(l + grain * uNoise, 0.0, 1.0));\n } else {\n float g = clamp(l * 1.2 + grain * uNoise * 2.0, 0.0, 1.0);\n col = vec3(0.12, 1.0, 0.25) * g + vec3(0.02, 0.06, 0.02);\n col *= 0.94 + 0.06 * sin(fragCoord.y * 2.0);\n col *= 0.97 + 0.03 * hash12(vec2(frame, 3.0));\n vec2 d = (uv - 0.5) * vec2(iResolution.x / iResolution.y, 1.0);\n col *= smoothstep(0.75, 0.3, length(d));\n }\n fragColor = vec4(col, src.a);\n}`,\n ),\n presets: [\n { name: \"Thermal\", values: { uMode: 0, uNoise: 0.04, uContrast: 1.3 } },\n { name: \"Night vision\", values: { uMode: 1, uNoise: 0.2, uContrast: 1.8 } },\n ],\n};\n\nexport const imageEdgeGlow: ShaderEffect = {\n kind: \"shader\",\n id: \"image-edge-glow\",\n name: \"Edge glow\",\n description: \"An image's edges traced as glowing neon lines over a dimmed picture, with a travelling pulse.\",\n category: \"image\",\n tags: [\"image\", \"neon\", \"edges\", \"outline\", \"cyber\"],\n loop: 2,\n source: glsl(\n `// Edge glow: Sobel edges as neon lines and a soft halo over the dimmed image.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uThreshold; // @control min=0 max=1 default=0.15 label=\"Threshold\"\nuniform vec3 uGlow; // @control color default=#22D3EE label=\"Glow colour\"\nuniform float uWidth; // @control min=0.5 max=4 default=1.5 label=\"Glow width (px)\"\nuniform float uDim; // @control min=0 max=1 default=0.75 label=\"Dim image\"\nuniform float uPulse; // @control min=0 max=1 default=0.4 label=\"Pulse\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// Brightness and alpha: an edge is where either changes (an icon's outline is in its alpha).\nvec2 lumaAlpha(vec2 uv) {\n vec4 c = pictureRGBA(uImage, uv);\n return vec2(dot(c.rgb, vec3(0.2126, 0.7152, 0.0722)), c.a);\n}\n\n// Sobel edge strength, sampling d apart (in uv).\nfloat sobel(vec2 uv, vec2 d) {\n vec2 tl = lumaAlpha(uv + vec2(-d.x, d.y));\n vec2 t = lumaAlpha(uv + vec2(0.0, d.y));\n vec2 tr = lumaAlpha(uv + d);\n vec2 l = lumaAlpha(uv - vec2(d.x, 0.0));\n vec2 r = lumaAlpha(uv + vec2(d.x, 0.0));\n vec2 bl = lumaAlpha(uv - d);\n vec2 b = lumaAlpha(uv - vec2(0.0, d.y));\n vec2 br = lumaAlpha(uv + vec2(d.x, -d.y));\n vec2 gx = tr + 2.0 * r + br - tl - 2.0 * l - bl;\n vec2 gy = tl + 2.0 * t + tr - bl - 2.0 * b - br;\n return max(length(vec2(gx.x, gy.x)), length(vec2(gx.y, gy.y)));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 d = uWidth / iResolution.xy;\n float line = smoothstep(uThreshold, uThreshold + 0.15, sobel(uv, d));\n float halo = smoothstep(uThreshold, uThreshold + 0.5, sobel(uv, d * 3.0));\n vec2 c = (uv - 0.5) * vec2(iResolution.x / iResolution.y, 1.0);\n float pulse = 1.0 - uPulse * (0.5 + 0.5 * sin(iTime * 3.14159265 - length(c) * 12.0));\n vec4 pic = pictureRGBA(uImage, uv);\n float glow = (line + 0.45 * halo) * pulse;\n vec3 light = uGlow * glow + vec3(1.0) * line * line * 0.35 * pulse;\n // The glow is light added over the picture, so it also shows where the picture is clear.\n float alpha = max(pic.a, clamp(glow, 0.0, 1.0));\n vec3 col = (pic.rgb * (1.0 - uDim) * pic.a + light) / max(alpha, 1e-4);\n fragColor = vec4(col, alpha);\n}`,\n ),\n presets: [\n { name: \"Cyan\", values: { uGlow: [0.13, 0.83, 0.93] } },\n { name: \"Magenta blackout\", values: { uGlow: [0.93, 0.28, 0.6], uDim: 1, uThreshold: 0.1 } },\n ],\n};\n\nexport const imageTiltShift: ShaderEffect = {\n kind: \"shader\",\n id: \"image-tilt-shift\",\n name: \"Tilt-shift\",\n description: \"An image blurred outside a sharp horizontal band, with punchy colour, so it looks like a miniature.\",\n category: \"image\",\n tags: [\"image\", \"blur\", \"miniature\", \"photography\", \"depth\"],\n source: glsl(\n `// Tilt-shift: blur away from a focus band, plus saturation, for the miniature look.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uFocus; // @control min=0 max=1 default=0.45 label=\"Focus position\"\nuniform float uBand; // @control min=0 max=0.6 default=0.12 label=\"Focus band width\"\nuniform float uBlur; // @control min=0 max=30 default=12 label=\"Blur (px)\"\nuniform float uSaturation; // @control min=0 max=2 default=1.4 label=\"Saturation\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float away = smoothstep(uBand * 0.5, uBand * 0.5 + 0.3, abs(uv.y - uFocus));\n float radius = away * uBlur;\n // A 24-tap golden-angle disc.\n // Summed premultiplied, so clear parts of the picture do not darken the blur.\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 24; i++) {\n float fi = float(i);\n float r = sqrt((fi + 0.5) / 24.0) * radius;\n float a = fi * 2.39996;\n vec4 c = pictureRGBA(uImage, uv + r * vec2(cos(a), sin(a)) / iResolution.xy);\n sum += vec4(c.rgb * c.a, c.a);\n }\n vec3 col = sum.rgb / max(sum.a, 1e-4);\n float l = dot(col, vec3(0.2126, 0.7152, 0.0722));\n col = mix(vec3(l), col, uSaturation);\n col = clamp((col - 0.5) * 1.08 + 0.5, 0.0, 1.0);\n fragColor = vec4(col, sum.a / 24.0);\n}`,\n ),\n presets: [\n { name: \"Model village\", values: { uFocus: 0.4, uBand: 0.1, uBlur: 16, uSaturation: 1.6 } },\n { name: \"Subtle\", values: { uBand: 0.25, uBlur: 6, uSaturation: 1.15 } },\n ],\n};\n\nexport const imageSlitScan: ShaderEffect = {\n kind: \"shader\",\n id: \"image-slit-scan\",\n name: \"Slit-scan\",\n description: \"An image smeared into time-stretched streaks, like a slit-scan photograph.\",\n category: \"image\",\n tags: [\"image\", \"slit-scan\", \"smear\", \"experimental\", \"distortion\"],\n source: glsl(\n `// Slit-scan: rows (or columns) squeeze towards a moving slit and smear into streaks.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uDirection; // @control min=0 max=1 default=0 label=\"Direction (0 horizontal, 1 vertical)\"\nuniform float uStretch; // @control min=0 max=1 default=0.45 label=\"Stretch\"\nuniform float uSpeed; // @control min=0 max=3 default=0.6 label=\"Speed\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // along: the axis the streaks run along; across: the axis the delay varies over.\n vec2 a = uDirection == 0 ? uv : uv.yx;\n float t = iTime * uSpeed;\n float delay = vnoise(vec2(a.y * 7.0, t)) * 0.7 + vnoise(vec2(a.y * 31.0, t * 1.7)) * 0.3;\n float slit = 0.5 + 0.35 * sin(t * 0.7 + delay * 2.0);\n // Squeeze towards the slit (stretching what is there) and drift with the delay.\n float along = slit + (a.x - slit) * (1.0 - uStretch * delay);\n along += uStretch * 0.15 * (delay - 0.5);\n // Smear: average a few taps along the streak.\n // Summed premultiplied, so clear parts of the picture do not darken the smear.\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 8; i++) {\n float s = along - float(i) * uStretch * 0.006;\n vec2 st = uDirection == 0 ? vec2(s, a.y) : vec2(a.y, s);\n vec4 c = pictureRGBA(uImage, st);\n sum += vec4(c.rgb * c.a, c.a);\n }\n fragColor = vec4(sum.rgb / max(sum.a, 1e-4), sum.a / 8.0);\n}`,\n ),\n presets: [\n { name: \"Drift\", values: { uDirection: 0, uStretch: 0.3, uSpeed: 0.3 } },\n { name: \"Waterfall\", values: { uDirection: 1, uStretch: 0.7, uSpeed: 1.2 } },\n ],\n};\n\nexport const imageMosaic: ShaderEffect = {\n kind: \"shader\",\n id: \"image-mosaic\",\n name: \"Mosaic flip\",\n description: \"Hexagonal or triangular tiles flipping over from the left to reveal an image, then back.\",\n category: \"image\",\n tags: [\"image\", \"reveal\", \"transition\", \"tiles\", \"hexagon\"],\n loop: 6,\n source: glsl(\n `// Mosaic flip: tiles turn over in a wave from the left, background on one face, image on the other.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uShape; // @control min=0 max=1 default=0 label=\"Tile shape (0 hexagon, 1 triangle)\"\nuniform float uSize; // @control min=10 max=160 default=48 label=\"Tile size (px)\"\nuniform bool uAuto; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=1 label=\"Progress (when still)\"\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `// Hexagon tiles 1 unit across the flats: h is the offset from the tile's centre.\nvoid hexTile(vec2 p, out vec2 h, out vec2 centre) {\n vec2 s = vec2(1.0, 1.7320508);\n vec2 a = (floor(p / s) + 0.5) * s;\n vec2 b = (floor((p - 0.5 * s) / s) + 1.0) * s;\n centre = dot(p - a, p - a) < dot(p - b, p - b) ? a : b;\n h = p - centre;\n}\n\n// 0 at a hexagon's centre, 1 on its edge.\nfloat hexEdge(vec2 h) {\n h = abs(h);\n return max(h.x, dot(h, vec2(0.5, 0.8660254))) * 2.0;\n}\n\n// Triangle tiles with sides of 1 unit; up is 1 for upward-pointing tiles, -1 for downward.\nvoid triTile(vec2 p, out vec2 h, out vec2 centre, out float up) {\n vec2 q = vec2(p.x - p.y * 0.5773503, p.y * 1.1547005);\n vec2 cell = floor(q);\n vec2 f = q - cell;\n up = f.x + f.y < 1.0 ? 1.0 : -1.0;\n vec2 cq = cell + (up > 0.0 ? vec2(1.0 / 3.0) : vec2(2.0 / 3.0));\n centre = vec2(cq.x + cq.y * 0.5, cq.y * 0.8660254);\n h = p - centre;\n}\n\n// 0 at a triangle's centre, 1 on its edge.\nfloat triEdge(vec2 h, float up) {\n h *= up;\n float e = max(-h.y, max(dot(h, vec2(0.8660254, 0.5)), dot(h, vec2(-0.8660254, 0.5))));\n return e / 0.2886751;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float k = uAuto ? smoothstep(0.05, 0.95, 0.5 - 0.5 * cos(iTime * 6.28318 / 6.0)) : uProgress;\n vec2 p = fragCoord / uSize;\n vec2 h;\n vec2 centre;\n float up = 1.0;\n if (uShape == 0) {\n hexTile(p, h, centre);\n } else {\n triTile(p, h, centre, up);\n }\n // Each tile turns over in its own moment, sweeping left to right with a little jitter.\n float start = centre.x * uSize / iResolution.x * 0.75 + hash12(centre * 7.31) * 0.15;\n float flip = smoothstep(0.0, 1.0, clamp((k * 1.35 - start) / 0.35, 0.0, 1.0));\n float squash = abs(cos(flip * 3.14159265));\n vec2 hf = vec2(h.x / max(squash, 0.001), h.y);\n float e = uShape == 0 ? hexEdge(hf) : triEdge(hf, up);\n float gap = 0.1 * (1.0 - flip);\n vec4 col = vec4(uBackground * 0.6, uBackdropAlpha);\n if (e < 1.0 - gap + 0.001) {\n vec4 face = flip < 0.5\n ? vec4(uBackground * (0.9 + 0.2 * hash12(centre * 3.17)) + 0.04, uBackdropAlpha)\n : pictureRGBA(uImage, (centre + hf) * uSize / iResolution.xy);\n col = vec4(face.rgb * (0.5 + 0.5 * squash), face.a);\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Hexagons\", values: { uShape: 0, uSize: 48 } },\n { name: \"Triangles\", values: { uShape: 1, uSize: 64 } },\n ],\n};\n\nexport const imageChromaticLens: ShaderEffect = {\n kind: \"shader\",\n id: \"image-chromatic-lens\",\n name: \"Chromatic lens\",\n description: \"An image through a cheap wide lens: barrel distortion and colour fringes growing towards the edges.\",\n category: \"image\",\n tags: [\"image\", \"lens\", \"aberration\", \"distortion\", \"vintage\"],\n source: glsl(\n `// Chromatic lens: barrel distortion with red, green and blue bent by different amounts.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uDistortion; // @control min=-0.5 max=1 default=0.25 label=\"Distortion\"\nuniform float uAberration; // @control min=0 max=0.1 default=0.025 label=\"Aberration\"\nuniform float uVignette; // @control min=0 max=1 default=0.4 label=\"Vignette\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// Where a lens with barrel strength k shows the point c (centred, aspect-corrected) from.\nvec2 lens(vec2 c, float k, vec2 aspect) {\n float r2 = dot(c, c);\n // Zoom in to keep the corners filled when barrelling.\n float fill = 1.0 + max(k, 0.0) * 0.3;\n return 0.5 + c * (1.0 + k * r2) / fill / aspect;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 aspect = vec2(iResolution.x / iResolution.y, 1.0);\n vec2 c = (uv - 0.5) * aspect;\n vec4 r = pictureRGBA(uImage, lens(c, uDistortion + uAberration, aspect));\n vec4 g = pictureRGBA(uImage, lens(c, uDistortion, aspect));\n vec4 b = pictureRGBA(uImage, lens(c, uDistortion - uAberration, aspect));\n vec3 col = vec3(r.r, g.g, b.b);\n col *= 1.0 - uVignette * smoothstep(0.25, 0.95, length(c));\n fragColor = vec4(col, max(max(r.a, g.a), b.a));\n}`,\n ),\n presets: [\n { name: \"Fisheye\", values: { uDistortion: 0.7, uAberration: 0.04, uVignette: 0.6 } },\n { name: \"Fringe only\", values: { uDistortion: 0, uAberration: 0.05, uVignette: 0.2 } },\n ],\n};\n\nexport const imageOilPaint: ShaderEffect = {\n kind: \"shader\",\n id: \"image-oil-paint\",\n name: \"Oil paint\",\n description: \"An image repainted in flat, edge-keeping brush dabs, like an oil painting.\",\n category: \"image\",\n tags: [\"image\", \"painterly\", \"artistic\", \"kuwahara\", \"filter\"],\n source: glsl(\n `// Oil paint: a four-sector Kuwahara filter, each pixel takes the calmest neighbourhood's colour.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform int uRadius; // @control min=1 max=8 default=4 label=\"Brush radius (px)\"\nuniform float uSharpness; // @control min=0.5 max=8 default=4 label=\"Sharpness\"\nuniform float uSaturation; // @control min=0 max=2 default=1.15 label=\"Saturation\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 px = 1.0 / iResolution.xy;\n // Sums of colour and colour² over four overlapping squares: down-left, down-right, up-left, up-right.\n vec3 m0 = vec3(0.0), m1 = vec3(0.0), m2 = vec3(0.0), m3 = vec3(0.0);\n vec3 s0 = vec3(0.0), s1 = vec3(0.0), s2 = vec3(0.0), s3 = vec3(0.0);\n for (int j = 0; j <= 8; j++) {\n if (j > uRadius) break;\n for (int i = 0; i <= 8; i++) {\n if (i > uRadius) break;\n vec2 o = vec2(float(i), float(j)) * px;\n vec3 c = picture(uImage, uv + vec2(-o.x, -o.y));\n m0 += c;\n s0 += c * c;\n c = picture(uImage, uv + vec2(o.x, -o.y));\n m1 += c;\n s1 += c * c;\n c = picture(uImage, uv + vec2(-o.x, o.y));\n m2 += c;\n s2 += c * c;\n c = picture(uImage, uv + o);\n m3 += c;\n s3 += c * c;\n }\n }\n float n = float((uRadius + 1) * (uRadius + 1));\n m0 /= n; m1 /= n; m2 /= n; m3 /= n;\n // Weight each square by how calm (low-variance) it is; sharpness sets how strongly the calmest wins.\n vec4 v = vec4(\n dot(abs(s0 / n - m0 * m0), vec3(1.0)),\n dot(abs(s1 / n - m1 * m1), vec3(1.0)),\n dot(abs(s2 / n - m2 * m2), vec3(1.0)),\n dot(abs(s3 / n - m3 * m3), vec3(1.0))\n );\n vec4 w = pow(v * 100.0 + 1e-3, vec4(-uSharpness));\n vec3 col = (m0 * w.x + m1 * w.y + m2 * w.z + m3 * w.w) / (w.x + w.y + w.z + w.w);\n float l = dot(col, vec3(0.2126, 0.7152, 0.0722));\n col = mix(vec3(l), col, uSaturation);\n fragColor = vec4(col, pictureRGBA(uImage, uv).a);\n}`,\n ),\n presets: [\n { name: \"Broad strokes\", values: { uRadius: 7, uSharpness: 6, uSaturation: 1.3 } },\n { name: \"Watercolour\", values: { uRadius: 3, uSharpness: 1.5, uSaturation: 0.9 } },\n ],\n};\n\n/** More image treatments: each takes an image control and changes the picture. */\nexport const imageTreatments: ShaderEffect[] = [\n imageKenBurns,\n imageAscii,\n imageShatter,\n imageMelt,\n imageRisograph,\n imageThermal,\n imageEdgeGlow,\n imageTiltShift,\n imageSlitScan,\n imageMosaic,\n imageChromaticLens,\n imageOilPaint,\n];\n","import { rgbToHex } from \"../shader/controls.js\";\nimport type { SvgAnimation, SvgMotion } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Text effects take any word or phrase: `derived` works out a font size from\n * its length (see `textWidthEm`) and, where it can, `textLength` stretches it\n * to the width that size predicts, so it fills the same box in any font.\n */\n\nconst r1 = (n: number) => Math.round(n * 10) / 10;\n\n/** A line fitted to `width` units, at most `max` high: its font size, width and left edge (centred on 200). */\nfunction fit(text: string, width: number, max: number, ems = textWidthEm(text)) {\n const e = Math.max(0.6, ems);\n const size = Math.min(max, width / e);\n return { size: r1(size), length: r1(e * size), left: r1(200 - (e * size) / 2) };\n}\n\n/** Letters as code points, so emoji and accents count once. */\nconst lettersOf = (text: unknown) => Array.from(String(text));\n\n/** `a` mixed `t` of the way to `b`, colours as written by vector controls ([r, g, b] 0–1). */\nconst mixHex = (a: unknown, b: unknown, t: number) => {\n const x = (Array.isArray(a) ? a : [1, 1, 1]) as number[];\n const y = (Array.isArray(b) ? b : [1, 1, 1]) as number[];\n return rgbToHex([0, 1, 2].map((i) => x[i]! + (y[i]! - x[i]!) * t));\n};\n\n/** Instant changes: the attribute holds each value from its time on (flicker, jumps). */\nconst holds = (id: string, attr: string, keys: readonly (readonly [number, string | number])[]): SvgAnimation[] =>\n keys.map(([delay, value]) => ({ id, attrs: { [attr]: [value, value] }, delay, ms: 0 }));\n\n/** A derived number in an animation's numeric field (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\nconst MONO = `ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace`;\n/** A monospace letter's advance, in ems. */\nconst MONO_EM = 0.6;\nconst HEAVY = `'Arial Black', 'Helvetica Neue', Impact, system-ui, sans-serif`;\nconst SANS = `system-ui, 'Helvetica Neue', Arial, sans-serif`;\n\n/** The caret's blinks after typing: on and off every 500 ms. */\nconst BLINKS = 7;\n\nexport const typewriter: VectorEffect = {\n kind: \"vector\",\n id: \"typewriter\",\n name: \"Typewriter\",\n description: \"Letters typed out one at a time behind a block caret, which then blinks.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"typing\", \"terminal\", \"caption\"],\n hold: 300,\n presets: [\n { name: \"Terminal\", values: { paper: [0.03, 0.05, 0.04], ink: [0.3, 1, 0.45] } },\n { name: \"Paper\", values: { paper: [0.98, 0.95, 0.88], ink: [0.15, 0.13, 0.12], pace: 120 } },\n ],\n // Monospace, so the caret lands after the last letter however long the text is.\n derived: (v) => {\n const count = Math.max(1, lettersOf(v.text).length);\n const size = r1(Math.min(44, 340 / ((count + 1) * MONO_EM)));\n const left = r1(200 - ((count + 1) * MONO_EM * size) / 2);\n const typing = Math.round(count * Number(v.pace));\n return {\n size,\n left,\n base: r1(100 + size * 0.35),\n end: r1(left + count * MONO_EM * size),\n typing,\n ...Object.fromEntries(Array.from({ length: BLINKS }, (_, k) => [`blink${k}`, typing + k * 500])),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Hello, world.' label='Text'}} {{paper: color default=#111827 label='Background'}} {{ink: color default=#F9FAFB label='Text colour'}} {{pace: float min=30 max=300 default=90 step=5 label='Ms per letter'}} --><rect width=\"400\" height=\"200\" fill=\"{{paper}}\"/><text id=\"typed\" x=\"{{left}}\" y=\"{{base}}\" font-family=\"${MONO}\" font-size=\"{{size}}\" fill=\"{{ink}}\" xml:space=\"preserve\">{{text}}</text><text id=\"caret\" x=\"{{end}}\" y=\"{{base}}\" font-family=\"${MONO}\" font-size=\"{{size}}\" fill=\"{{ink}}\" opacity=\"0\">▌</text></svg>`,\n animate: [\n { id: \"typed\", write: \"{{text}}\", caret: \"▌\", ms: n(\"typing\"), ease: \"linear\" },\n // Hidden while the writer shows its own caret, then blinking where it stopped.\n ...holds(\"caret\", \"opacity\", [[0, 0], ...Array.from({ length: BLINKS }, (_, k) => [n(`blink${k}`), k % 2 ? 0 : 1] as const)]),\n ],\n },\n};\n\nexport const scrambleText: VectorEffect = {\n kind: \"vector\",\n id: \"scramble-text\",\n name: \"Scramble text\",\n description: \"Random glyphs flickering, then settling into the real word letter by letter, left to right.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"decode\", \"hacker\", \"cyber\", \"reveal\"],\n hold: 1200,\n presets: [\n { name: \"Matrix\", values: { background: [0, 0.03, 0.01], ink: [0.4, 1, 0.5], accent: [0.1, 0.7, 0.25], glyphs: \"01\" } },\n { name: \"Amber\", values: { background: [0.08, 0.04, 0], ink: [1, 0.72, 0.2], accent: [0.9, 0.4, 0.05] } },\n ],\n derived: (v) => {\n const count = Math.max(1, lettersOf(v.text).length);\n const size = r1(Math.min(60, 360 / (count * MONO_EM)));\n const width = r1(count * MONO_EM * size);\n const base = r1(100 + size * 0.35);\n return { size, base, barX: r1(200 - width / 2), barY: r1(base + size * 0.3), barW: width, decode: Math.round(count * Number(v.pace)), glowWide: Number(v.glow) * 2 };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='ACCESS GRANTED' label='Text'}} {{glyphs: text default='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&@$*+' label='Scramble glyphs'}} {{background: color default=#05070D label='Background'}} {{ink: color default=#E2E8F0 label='Text colour'}} {{accent: color default=#22D3EE label='Accent'}} {{pace: float min=20 max=250 default=70 step=5 label='Ms per letter'}} {{glow: float min=0 max=6 default=2 step=0.5 label='Glow'}} --><defs><filter id=\"glow\" x=\"-20%\" y=\"-50%\" width=\"140%\" height=\"200%\"><feGaussianBlur stdDeviation=\"{{glowWide}}\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text id=\"word\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" font-family=\"${MONO}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\" filter=\"url(#glow)\" xml:space=\"preserve\">{{text}}</text><rect id=\"bar\" x=\"{{barX}}\" y=\"{{barY}}\" width=\"0\" height=\"3\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n // Pure noise for a moment (the scramble runs before the change starts), then it decodes.\n { id: \"word\", write: \"{{text}}\", scramble: \"{{glyphs}}\", delay: 500, ms: n(\"decode\"), ease: \"linear\" },\n { id: \"bar\", attrs: { width: [0, n(\"barW\")] }, delay: 500, ms: n(\"decode\"), ease: \"linear\" },\n ],\n },\n};\n\n/** Kinetic stagger's letter slots: one element per letter, so each can move on its own. */\nconst SLOTS = 20;\n\nexport const kineticStagger: VectorEffect = {\n kind: \"vector\",\n id: \"kinetic-stagger\",\n name: \"Kinetic stagger\",\n description: \"Each letter springs up into place in turn, rising, turning and overshooting, then an underline sweeps beneath.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"kinetic\", \"typography\", \"headline\", \"intro\"],\n hold: 1200,\n presets: [\n { name: \"Poster\", values: { background: [0.98, 0.87, 0.2], ink: [0.07, 0.07, 0.07], accent: [0.9, 0.15, 0.2] } },\n { name: \"Midnight\", values: { background: [0.04, 0.05, 0.12], ink: [0.95, 0.96, 1], accent: [0.55, 0.45, 1], stagger: 80 } },\n ],\n // Up to SLOTS letters, each centred in its estimated advance; unused slots stay empty.\n derived: (v) => {\n const letters = lettersOf(v.text).slice(0, SLOTS);\n const widths = letters.map((c) => textWidthEm(c));\n const ems = Math.max(0.6, widths.reduce((a, b) => a + b, 0));\n const size = Math.min(92, 370 / ems);\n const base = 100 + size * 0.35;\n const stagger = Number(v.stagger);\n const out: Record<string, string | number> = {\n size: r1(size),\n base: r1(base),\n rise: r1(base - size * 0.1),\n drop: r1(base + size * 0.6),\n lineX: r1(200 - (ems * size) / 2),\n lineY: r1(base + size * 0.2),\n lineW: r1(ems * size),\n lineAt: Math.round(letters.length * stagger + 400),\n };\n let x = 200 - (ems * size) / 2;\n for (let i = 0; i < SLOTS; i++) {\n const w = (widths[i] ?? 0) * size;\n out[`c${i}`] = letters[i]?.trim() ?? \"\";\n out[`x${i}`] = r1(x + w / 2);\n out[`d${i}`] = Math.round(i * stagger);\n out[`e${i}`] = Math.round(i * stagger + 380);\n x += w;\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Kinetic' label='Text'}} {{background: color default=#F8FAFC label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#F43F5E label='Underline'}} {{stagger: float min=20 max=200 default=55 step=5 label='Ms between letters'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/>${Array.from(\n { length: SLOTS },\n (_, i) =>\n `<text id=\"l${i}\" text-anchor=\"middle\" transform=\"translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)\" opacity=\"0\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{ink}}\">{{c${i}}}</text>`,\n ).join(\"\")}<rect id=\"line\" x=\"{{lineX}}\" y=\"{{lineY}}\" width=\"0\" height=\"6\" rx=\"3\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n ...Array.from({ length: SLOTS }, (_, i): SvgAnimation[] => [\n {\n id: `l${i}`,\n attrs: { transform: [`translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)`, `translate({{x${i}}} {{rise}}) rotate(5) scale(1.12)`], opacity: [0, 1] },\n delay: n(`d${i}`),\n ms: 380,\n ease: \"out\",\n },\n { id: `l${i}`, attrs: { transform: [`translate({{x${i}}} {{rise}}) rotate(5) scale(1.12)`, `translate({{x${i}}} {{base}}) rotate(0) scale(1)`] }, delay: n(`e${i}`), ms: 260, ease: \"in-out\" },\n ]).flat(),\n { id: \"line\", attrs: { width: [0, n(\"lineW\")] }, delay: n(\"lineAt\"), ms: 500, ease: \"in-out\" },\n ],\n },\n};\n\nexport const neonSign: VectorEffect = {\n kind: \"vector\",\n id: \"neon-sign\",\n name: \"Neon sign\",\n description: \"Glowing neon tube lettering that stutters on, then keeps one faulty letter buzzing.\",\n category: \"text\",\n tags: [\"text\", \"neon\", \"glow\", \"sign\", \"night\", \"retro\"],\n hold: 400,\n presets: [\n { name: \"Hot pink\", values: { tube: [1, 0.2, 0.65], wall: [0.06, 0.02, 0.07] } },\n { name: \"Ice\", values: { tube: [0.35, 0.85, 1], wall: [0.02, 0.04, 0.08], glow: 5 } },\n { name: \"Lime\", values: { tube: [0.6, 1, 0.2], wall: [0.03, 0.05, 0.02] } },\n ],\n // The word in three runs, so the buzzing letter can flicker on its own.\n derived: (v) => {\n const letters = lettersOf(v.text);\n const k = Math.min(Math.max(0, Math.round(Number(v.faulty)) - 1), Math.max(0, letters.length - 1));\n const { size, length } = fit(String(v.text), 340, 84);\n return {\n head: letters.slice(0, k).join(\"\"),\n mid: letters[k] ?? \"\",\n tail: letters.slice(k + 1).join(\"\"),\n size,\n length,\n base: r1(100 + size * 0.3),\n far: Number(v.glow) * 3,\n core: mixHex(v.tube, [1, 1, 1], 0.6),\n };\n },\n motion: ((): SvgMotion => {\n const word = `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"'Pacifico', 'Brush Script MT', 'Segoe Script', 'Snell Roundhand', cursive\" font-size=\"{{size}}\"`;\n const runs = (id: string) => `<tspan>{{head}}</tspan><tspan id=\"${id}\">{{mid}}</tspan><tspan>{{tail}}</tspan>`;\n // Start-up: the tubes catch, drop out and catch again.\n const startUp = [[0, 0], [150, 0.85], [210, 0], [330, 1], [390, 0.15], [450, 1], [620, 0.35], [680, 1]] as const;\n const buzz = [[0, 1], [1300, 0.15], [1350, 1], [1420, 0.2], [1520, 1], [2100, 0.1], [2160, 1], [2230, 0.25], [2280, 1]] as const;\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Open late' label='Text'}} {{tube: color default=#FF3DA5 label='Tube'}} {{wall: color default=#120612 label='Wall'}} {{glow: float min=0.5 max=8 default=3.5 step=0.5 label='Glow'}} {{faulty: int min=1 max=24 default=6 label='Buzzing letter'}} --><defs><filter id=\"neon\" x=\"-30%\" y=\"-80%\" width=\"160%\" height=\"260%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{glow}}\" result=\"near\"/><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{far}}\" result=\"far\"/><feMerge><feMergeNode in=\"far\"/><feMergeNode in=\"far\"/><feMergeNode in=\"near\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter><filter id=\"haze\" x=\"-50%\" y=\"-100%\" width=\"200%\" height=\"300%\"><feGaussianBlur stdDeviation=\"30\"/></filter></defs><rect width=\"400\" height=\"200\" fill=\"{{wall}}\"/><g id=\"sign\" opacity=\"0\"><ellipse cx=\"200\" cy=\"100\" rx=\"170\" ry=\"55\" fill=\"{{tube}}\" opacity=\"0.18\" filter=\"url(#haze)\"/><text ${word} fill=\"{{tube}}\" stroke=\"{{tube}}\" stroke-width=\"1.5\" filter=\"url(#neon)\">${runs(\"buzzGlow\")}</text><text ${word} fill=\"{{core}}\">${runs(\"buzzCore\")}</text></g></svg>`,\n animate: [\n ...holds(\"sign\", \"opacity\", startUp),\n // fill-opacity rather than opacity: browsers ignore opacity on a <tspan>.\n ...[\"buzzGlow\", \"buzzCore\"].flatMap((id) => [...holds(id, \"fill-opacity\", buzz), ...holds(id, \"stroke-opacity\", buzz)]),\n ],\n };\n })(),\n};\n\nexport const strokeDrawText: VectorEffect = {\n kind: \"vector\",\n id: \"stroke-draw-text\",\n name: \"Stroke draw text\",\n description: \"A word's outline traced on along every letter, then its fill fading in.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"draw-on\", \"outline\", \"reveal\", \"handwriting\"],\n hold: 1200,\n presets: [\n { name: \"Blueprint\", values: { background: [0.05, 0.2, 0.45], outline: [0.85, 0.93, 1], fill: [0.85, 0.93, 1], fillOpacity: 0.15 } },\n { name: \"Gold\", values: { background: [0.07, 0.06, 0.05], outline: [1, 0.8, 0.35], fill: [0.85, 0.6, 0.15] } },\n ],\n // <text> takes no pathLength, so `draw` cannot measure it: the dash grows instead, longer than any letter's outline.\n derived: (v) => {\n const { size, length } = fit(String(v.text), 360, 100);\n return { size, length, base: r1(100 + size * 0.35), dash: Math.round(size * 6) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Draw' label='Text'}} {{background: color default=#FFFBF5 label='Background'}} {{outline: color default=#1E293B label='Outline'}} {{fill: color default=#F97316 label='Fill'}} {{width: float min=0.5 max=6 default=2 step=0.5 label='Outline width'}} {{fillOpacity: float min=0 max=1 default=1 label='Fill opacity'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text id=\"word\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{fill}}\" fill-opacity=\"0\" stroke=\"{{outline}}\" stroke-width=\"{{width}}\" stroke-linejoin=\"round\" stroke-dasharray=\"0 {{dash}}\">{{text}}</text></svg>`,\n animate: [\n { id: \"word\", attrs: { \"stroke-dasharray\": [\"0 {{dash}}\", \"{{dash}} 0\"] }, ms: 2000, ease: \"in-out\" },\n { id: \"word\", attrs: { \"fill-opacity\": [0, n(\"fillOpacity\")] }, delay: 1500, ms: 700, ease: \"out\" },\n ],\n },\n};\n\nexport const splitReveal: VectorEffect = {\n kind: \"vector\",\n id: \"split-reveal\",\n name: \"Split reveal\",\n description: \"A line draws across, then the title's top half rises out from behind it while the bottom half drops down.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"reveal\", \"mask\", \"editorial\", \"intro\"],\n hold: 1400,\n presets: [\n { name: \"Light\", values: { background: [0.97, 0.96, 0.94], ink: [0.08, 0.08, 0.1], line: [0.85, 0.2, 0.15] } },\n { name: \"Gold on black\", values: { background: [0.02, 0.02, 0.02], ink: [0.96, 0.84, 0.55], line: [0.96, 0.84, 0.55] } },\n ],\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), 360, 88);\n return {\n size,\n length,\n base: r1(100 + size * 0.36),\n shift: r1(size * 0.8),\n lineX1: r1(left - 10),\n lineX2: r1(400 - left + 10),\n captionY: r1(100 + size * 0.36 + 30),\n };\n },\n motion: ((): SvgMotion => {\n const word = `<text x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"800\" fill=\"{{ink}}\">{{text}}</text>`;\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Chapter One' label='Text'}} {{caption: text default='The beginning' label='Caption'}} {{background: color default=#0F172A label='Background'}} {{ink: color default=#F8FAFC label='Text colour'}} {{line: color default=#38BDF8 label='Line'}} --><defs><clipPath id=\"above\"><rect width=\"400\" height=\"100\"/></clipPath><clipPath id=\"below\"><rect y=\"100\" width=\"400\" height=\"100\"/></clipPath></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g clip-path=\"url(#above)\"><g id=\"top\" transform=\"translate(0 {{shift}})\">${word}</g></g><g clip-path=\"url(#below)\"><g id=\"bottom\" transform=\"translate(0 -{{shift}})\">${word}</g></g><path id=\"line\" d=\"M{{lineX1}} 100 H{{lineX2}}\" stroke=\"{{line}}\" stroke-width=\"2.5\" stroke-linecap=\"round\"/><text id=\"caption\" x=\"200\" y=\"{{captionY}}\" text-anchor=\"middle\" font-family=\"${SANS}\" font-size=\"13\" letter-spacing=\"3\" fill=\"{{ink}}\" opacity=\"0\">{{caption}}</text></svg>`,\n animate: [\n { id: \"line\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"top\", attrs: { transform: [\"translate(0 {{shift}})\", \"translate(0 0)\"] }, delay: 450, ms: 800, ease: \"out\" },\n { id: \"bottom\", attrs: { transform: [\"translate(0 -{{shift}})\", \"translate(0 0)\"] }, delay: 450, ms: 800, ease: \"out\" },\n { id: \"line\", attrs: { opacity: [1, 0] }, delay: 1100, ms: 400 },\n { id: \"caption\", attrs: { opacity: [0, 0.75] }, delay: 1100, ms: 500, ease: \"out\" },\n ],\n };\n })(),\n};\n\nexport const highlighter: VectorEffect = {\n kind: \"vector\",\n id: \"highlighter\",\n name: \"Highlighter\",\n description: \"A marker swipe drawn left to right behind a phrase, rough-edged like a real highlighter pen.\",\n category: \"text\",\n tags: [\"text\", \"highlight\", \"marker\", \"emphasis\", \"explainer\", \"callout\"],\n hold: 1400,\n presets: [\n { name: \"Pink\", values: { marker: [1, 0.55, 0.78] } },\n { name: \"Mint\", values: { marker: [0.55, 0.95, 0.7] } },\n { name: \"Dark\", values: { background: [0.07, 0.08, 0.1], ink: [0.97, 0.97, 0.98], marker: [0.55, 0.2, 0.95] } },\n ],\n // The swipe runs a little past the phrase at both ends, across its lower half, with a ragged second pass.\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), 330, 56);\n const base = 100 + size * 0.35;\n const x0 = left - size * 0.25;\n const x1 = 400 - left + size * 0.2;\n const y = base - size * 0.3;\n return {\n size,\n length,\n base: r1(base),\n swipe: `M${r1(x0)} ${r1(y + size * 0.05)} Q${r1((x0 + x1) / 2)} ${r1(y - size * 0.06)} ${r1(x1)} ${r1(y - size * 0.02)}`,\n ragged: `M${r1(x0 + size * 0.15)} ${r1(y + size * 0.3)} L${r1(x1 - size * 0.1)} ${r1(y + size * 0.26)}`,\n thick: r1(size * 0.72),\n thin: r1(size * 0.16),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Ship it faster' label='Phrase'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#111827 label='Text colour'}} {{marker: color default=#FDE047 label='Marker'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g transform=\"rotate(-1.2 200 100)\" opacity=\"0.9\"><path id=\"swipe\" d=\"{{swipe}}\" fill=\"none\" stroke=\"{{marker}}\" stroke-width=\"{{thick}}\"/><path id=\"ragged\" d=\"{{ragged}}\" fill=\"none\" stroke=\"{{marker}}\" stroke-width=\"{{thin}}\" stroke-linecap=\"round\"/></g><text id=\"phrase\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\" opacity=\"0\">{{text}}</text></svg>`,\n animate: [\n { id: \"phrase\", attrs: { opacity: [0, 1] }, ms: 300, ease: \"out\" },\n { id: \"swipe\", draw: true, delay: 350, ms: 650, ease: \"in-out\" },\n { id: \"ragged\", draw: true, delay: 420, ms: 620, ease: \"in-out\" },\n ],\n },\n};\n\n/** Word cycle's timing: how long each word rests, and how long a roll to the next takes. */\nconst SHOW_MS = 1000;\nconst ROLL_MS = 450;\nconst CYCLE_WORDS = 4;\n\nexport const wordCycle: VectorEffect = {\n kind: \"vector\",\n id: \"word-cycle\",\n name: \"Word cycle\",\n description: \"A fixed lead-in with the last word rolling through alternatives like a slot machine, an underline resizing to each.\",\n category: \"text\",\n tags: [\"text\", \"headline\", \"rotating\", \"hero\", \"marketing\", \"slot\"],\n hold: 0,\n presets: [\n { name: \"Dark\", values: { background: [0.05, 0.06, 0.1], ink: [0.95, 0.96, 1], accent: [0.4, 0.85, 0.65] } },\n { name: \"Warm\", values: { background: [1, 0.96, 0.9], ink: [0.2, 0.12, 0.08], accent: [0.93, 0.35, 0.15] } },\n ],\n // The lead-in and the longest word share the line; the reel ends with word 1 again, so the loop is seamless.\n derived: (v) => {\n const words = Array.from({ length: CYCLE_WORDS }, (_, i) => String(v[`word${i + 1}`]));\n const lead = textWidthEm(String(v.prefix));\n const ems = words.map((w) => Math.max(0.6, textWidthEm(w)));\n const total = lead + 0.3 + Math.max(...ems);\n const size = Math.min(52, 370 / total);\n const left = 200 - (total * size) / 2;\n const base = 100 + size * 0.35;\n const step = size * 1.3;\n const wx = left + (lead + 0.3) * size;\n return {\n size: r1(size),\n base: r1(base),\n px: r1(left),\n plen: r1(Math.max(0.6, lead) * size),\n wx: r1(wx),\n clipX: r1(wx - 4),\n clipY: r1(base - size * 1.0),\n clipW: r1(Math.max(...ems) * size + 8),\n clipH: r1(size * 1.32),\n underY: r1(base + size * 0.18),\n ...Object.fromEntries(\n [...words, words[0]!].flatMap((_, k) => [\n [`y${k}`, r1(base + k * step)],\n [`o${k}`, r1(k * step)],\n [`len${k}`, r1(ems[k % CYCLE_WORDS]! * size)],\n ]),\n ),\n ...Object.fromEntries(words.map((w, k) => [`w${k}`, w])),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{prefix: text default='We build' label='Lead-in'}} {{word1: text default=apps label='Word 1'}} {{word2: text default=brands label='Word 2'}} {{word3: text default=websites label='Word 3'}} {{word4: text default=games label='Word 4'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#6366F1 label='Accent'}} --><defs><clipPath id=\"window\"><rect x=\"{{clipX}}\" y=\"{{clipY}}\" width=\"{{clipW}}\" height=\"{{clipH}}\"/></clipPath></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text x=\"{{px}}\" y=\"{{base}}\" textLength=\"{{plen}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\">{{prefix}}</text><g clip-path=\"url(#window)\"><g id=\"reel\" transform=\"translate(0 -0)\">${Array.from(\n { length: CYCLE_WORDS + 1 },\n (_, k) =>\n `<text x=\"{{wx}}\" y=\"{{y${k}}}\" textLength=\"{{len${k}}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"800\" fill=\"{{accent}}\">{{w${k % CYCLE_WORDS}}}</text>`,\n ).join(\"\")}</g></g><rect id=\"under\" x=\"{{wx}}\" y=\"{{underY}}\" width=\"{{len0}}\" height=\"4\" rx=\"2\" fill=\"{{accent}}\"/></svg>`,\n animate: Array.from({ length: CYCLE_WORDS }, (_, i): SvgAnimation[] => {\n const at = { delay: (i + 1) * SHOW_MS + i * ROLL_MS, ms: ROLL_MS, ease: \"in-out\" as const };\n return [\n { id: \"reel\", attrs: { transform: [`translate(0 -{{o${i}}})`, `translate(0 -{{o${i + 1}}})`] }, ...at },\n { id: \"under\", attrs: { width: [n(`len${i}`), n(`len${i + 1}`)] }, ...at },\n ];\n }).flat(),\n },\n};\n\n/** Liquid fill's wave: crests along y = 0, two 100-unit periods either side of the picture, filled down below it. */\nconst WAVE = `M-200 0${\" q25 -8 50 0 t50 0\".repeat(8)} V320 H-200Z`;\n\nexport const liquidFill: VectorEffect = {\n kind: \"vector\",\n id: \"liquid-fill\",\n name: \"Liquid fill\",\n description: \"A title filling up with liquid, its wavy surface rising through the letters.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"liquid\", \"water\", \"progress\", \"fill\"],\n hold: 900,\n presets: [\n { name: \"Gradient sweep\", values: { liquid: [0.98, 0.25, 0.55], liquid2: [0.35, 0.4, 1], empty: [0.93, 0.93, 0.96] } },\n { name: \"Lava\", values: { liquid: [1, 0.35, 0.05], liquid2: [1, 0.8, 0.1], empty: [0.15, 0.08, 0.06], background: [0.06, 0.03, 0.02] } },\n { name: \"Juice\", values: { liquid: [1, 0.6, 0.1], liquid2: [1, 0.75, 0.25] } },\n ],\n // The surface starts under the letters and ends above their caps.\n derived: (v) => {\n const { size, length } = fit(String(v.text), 360, 110);\n const base = 100 + size * 0.36;\n return { size, length, base: r1(base), low: r1(base + 12), high: r1(base - size * 0.82 - 12) };\n },\n motion: ((): SvgMotion => {\n const word = `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\"`;\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='FILL' label='Text'}} {{background: color default=#FFFFFF label='Background'}} {{empty: color default=#E0F2FE label='Empty'}} {{liquid: color default=#0284C7 label='Liquid'}} {{liquid2: color default=#38BDF8 label='Liquid sweep'}} --><defs><clipPath id=\"letters\"><text ${word}>{{text}}</text></clipPath><linearGradient id=\"liq\" gradientUnits=\"userSpaceOnUse\" x1=\"0\" y1=\"0\" x2=\"400\" y2=\"0\" spreadMethod=\"repeat\"><stop offset=\"0\" stop-color=\"{{liquid}}\"/><stop offset=\"0.5\" stop-color=\"{{liquid2}}\"/><stop offset=\"1\" stop-color=\"{{liquid}}\"/></linearGradient></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text ${word} fill=\"{{empty}}\" stroke=\"{{liquid}}\" stroke-width=\"1.5\" stroke-opacity=\"0.5\">{{text}}</text><g clip-path=\"url(#letters)\"><g id=\"level\" transform=\"translate(0 {{low}})\"><path id=\"back\" d=\"${WAVE}\" fill=\"{{liquid}}\" opacity=\"0.45\" transform=\"translate(-50 -5)\"/><path id=\"wave\" d=\"${WAVE}\" fill=\"url(#liq)\" transform=\"translate(0 0)\"/></g></g></svg>`,\n animate: [\n { id: \"level\", attrs: { transform: [\"translate(0 {{low}})\", \"translate(0 {{high}})\"] }, ms: 2800, ease: \"out\" },\n { id: \"wave\", attrs: { transform: [\"translate(0 0)\", \"translate(-200 0)\"] }, ms: 3000, ease: \"linear\" },\n { id: \"back\", attrs: { transform: [\"translate(-50 -5)\", \"translate(150 -5)\"] }, ms: 3000, ease: \"linear\" },\n // The sweep: the repeating gradient slides along, visible when the two liquid colours differ.\n { id: \"liq\", attrs: { x1: [0, 400], x2: [400, 800] }, ms: 3000, ease: \"linear\" },\n ],\n };\n })(),\n};\n\n/** Glitch text's bands: where the word is cut into slices, as fractions from its cap line to its baseline. */\nconst BANDS = [0.3, 0.55, 0.8];\n/** Glitch text's jumps: [ms, red offset, cyan offset, each band's shift], in units of the word's size; rests between bursts. */\nconst GLITCH = (() => {\n let seed = 7;\n const rand = () => ((seed = (seed * 16807) % 2147483647) / 2147483647) * 2 - 1;\n const rest = { red: [-0.02, 0], cyan: [0.02, 0], bands: [0, 0, 0, 0] };\n const keys: { at: number; red: number[]; cyan: number[]; bands: number[] }[] = [{ at: 0, ...rest }];\n for (const [start, count] of [[250, 6], [1050, 3], [1650, 8]] as const) {\n for (let k = 0; k < count; k++)\n keys.push({\n at: start + k * 55,\n red: [rand() * 0.12, rand() * 0.04],\n cyan: [rand() * 0.12, rand() * 0.04],\n bands: [0, 1, 2, 3].map(() => (rand() > 0.1 ? rand() * 0.25 : 0)),\n });\n keys.push({ at: start + count * 55, ...rest });\n }\n return keys;\n})();\n\nexport const glitchText: VectorEffect = {\n kind: \"vector\",\n id: \"glitch-text\",\n name: \"Glitch text\",\n description: \"A title breaking up in bursts: red and cyan copies split apart and slices of the letters jump sideways.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"glitch\", \"cyber\", \"rgb-split\", \"error\"],\n hold: 400,\n presets: [\n { name: \"Classic\", values: { left: [1, 0, 0.2], right: [0, 1, 1] } },\n { name: \"Vapor\", values: { left: [1, 0.3, 0.85], right: [0.4, 0.6, 1], background: [0.08, 0.02, 0.12], amount: 1.4 } },\n ],\n derived: (v) => {\n const { size, length } = fit(String(v.text), 340, 100);\n const base = 100 + size * 0.36;\n const top = base - size * 0.78;\n const cuts = [0, ...BANDS.map((f) => r1(top + f * (base - top))), 200];\n const unit = size * Number(v.amount);\n const shift = ([x, y]: number[]) => `translate(${r1(x! * unit)} ${r1(y! * unit)})`;\n return {\n size,\n length,\n base: r1(base),\n ...Object.fromEntries([0, 1, 2, 3].flatMap((b) => [[`cut${b}`, cuts[b]!], [`band${b}`, r1(cuts[b + 1]! - cuts[b]!)]])),\n ...Object.fromEntries(\n GLITCH.flatMap((key, k) => [\n [`red${k}`, shift(key.red)],\n [`cyan${k}`, shift(key.cyan)],\n ...key.bands.map((x, b) => [`b${b}_${k}`, shift([x, 0])]),\n ]),\n ),\n };\n },\n motion: ((): SvgMotion => {\n const word = (paint: string) =>\n `<text x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" ${paint}>{{text}}</text>`;\n const jumps = (id: string, value: (k: number) => string) =>\n GLITCH.map((key, k): SvgAnimation => ({ id, attrs: { transform: [value(k), value(k)] }, delay: key.at, ms: 0 }));\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='GLITCH' label='Text'}} {{background: color default=#07070B label='Background'}} {{ink: color default=#F5F5F5 label='Text colour'}} {{left: color default=#FF0040 label='Red copy'}} {{right: color default=#00F0FF label='Cyan copy'}} {{amount: float min=0 max=3 default=1 step=0.1 label='Intensity'}} --><defs>${[0, 1, 2, 3]\n .map((b) => `<clipPath id=\"slice${b}\"><rect x=\"-100\" y=\"{{cut${b}}}\" width=\"600\" height=\"{{band${b}}}\"/></clipPath>`)\n .join(\"\")}</defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g id=\"red\" style=\"mix-blend-mode:screen\">${word(`fill=\"{{left}}\"`)}</g><g id=\"cyan\" style=\"mix-blend-mode:screen\">${word(`fill=\"{{right}}\"`)}</g>${[0, 1, 2, 3]\n .map((b) => `<g clip-path=\"url(#slice${b})\"><g id=\"s${b}\">${word(`fill=\"{{ink}}\"`)}</g></g>`)\n .join(\"\")}</svg>`,\n animate: [\n ...jumps(\"red\", (k) => `{{red${k}}}`),\n ...jumps(\"cyan\", (k) => `{{cyan${k}}}`),\n ...[0, 1, 2, 3].flatMap((b) => jumps(`s${b}`, (k) => `{{b${b}_${k}}}`)),\n ],\n };\n })(),\n};\n\n/** Extruded text's layers, back to front, and the directions the extrude swings between (degrees, 0 = right, 90 = down). */\nconst LAYERS = 12;\nconst EXTRUDE_FROM = 40;\nconst EXTRUDE_TO = 140;\n\nexport const extrudedText: VectorEffect = {\n kind: \"vector\",\n id: \"extruded-text\",\n name: \"Extruded text\",\n description: \"Retro 3D block lettering: stacked shaded layers extrude out of the title and swing as the light moves.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"3d\", \"retro\", \"extrude\", \"80s\"],\n hold: 600,\n presets: [\n { name: \"Arcade\", values: { face: [0.2, 0.95, 1], side: [0.85, 0.2, 0.75], shade: [0.2, 0.05, 0.3], background: [0.05, 0.02, 0.12] } },\n { name: \"Diner\", values: { face: [1, 1, 1], side: [0.9, 0.15, 0.2], shade: [0.35, 0.03, 0.06], background: [0.98, 0.9, 0.75], outline: [0.1, 0.1, 0.12] } },\n ],\n // Each layer sits a step further back along the extrude direction, shaded from the side colour to the shadow.\n derived: (v) => {\n const { size, length } = fit(String(v.text), 320, 96);\n const step = size * 0.03 * Number(v.depth);\n const at = (deg: number, i: number) => {\n const a = (deg * Math.PI) / 180;\n return `translate(${r1(Math.cos(a) * step * i)} ${r1(Math.sin(a) * step * i)})`;\n };\n return {\n size,\n length,\n base: r1(92 + size * 0.35),\n ...Object.fromEntries(\n Array.from({ length: LAYERS }, (_, k) => {\n const i = LAYERS - k;\n return [\n [`fill${i}`, mixHex(v.side, v.shade, i / LAYERS)],\n [`a${i}`, at(EXTRUDE_FROM, i)],\n [`b${i}`, at(EXTRUDE_TO, i)],\n ];\n }).flat(),\n ),\n };\n },\n motion: ((): SvgMotion => {\n const word = (paint: string) =>\n `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" stroke-linejoin=\"round\" ${paint}`;\n const layers = Array.from({ length: LAYERS }, (_, k) => LAYERS - k);\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='RETRO' label='Text'}} {{background: color default=#FFE8C2 label='Background'}} {{face: color default=#FFD23F label='Face'}} {{outline: color default=#1A1423 label='Outline'}} {{side: color default=#EE4266 label='Extrude'}} {{shade: color default=#3B1F2B label='Shadow'}} {{depth: float min=0.2 max=2 default=1 step=0.1 label='Depth'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/>${layers\n .map((i) => `<text id=\"e${i}\" transform=\"translate(0 0)\" ${word(`fill=\"{{fill${i}}}\" stroke=\"{{fill${i}}}\" stroke-width=\"2\"`)}>{{text}}</text>`)\n .join(\"\")}<text ${word(`fill=\"{{face}}\" stroke=\"{{outline}}\" stroke-width=\"2.5\" paint-order=\"stroke\"`)}>{{text}}</text></svg>`,\n animate: layers.flatMap((i): SvgAnimation[] => [\n { id: `e${i}`, attrs: { transform: [\"translate(0 0)\", `{{a${i}}}`] }, ms: 700, ease: \"out\" },\n { id: `e${i}`, attrs: { transform: [`{{a${i}}}`, `{{b${i}}}`] }, delay: 1200, ms: 1500, ease: \"in-out\" },\n { id: `e${i}`, attrs: { transform: [`{{b${i}}}`, `{{a${i}}}`] }, delay: 3200, ms: 1500, ease: \"in-out\" },\n ]),\n };\n })(),\n};\n\n/** Animated titles and type, as vector effects. */\nexport const textEffects: VectorEffect[] = [\n typewriter,\n scrambleText,\n kineticStagger,\n neonSign,\n strokeDrawText,\n splitReveal,\n highlighter,\n wordCycle,\n liquidFill,\n glitchText,\n extrudedText,\n];\n","import {\n checkControlValue,\n controlFromDeclaration,\n hexToRgb,\n rgbToHex,\n type ControlDef,\n type ControlType,\n type ControlValue,\n} from \"../shader/controls.js\";\nimport type { SvgMotion } from \"../vector/motion.js\";\nimport type { SvgTrigger } from \"../vector/svg.js\";\n\n/** What an effect is for, used to group the catalog. */\nexport type EffectCategory =\n | \"gradient\"\n | \"organic\"\n | \"pattern\"\n | \"light\"\n | \"space\"\n | \"retro\"\n | \"image\"\n | \"overlay\"\n | \"text\"\n | \"morph\"\n | \"interaction\"\n | \"pyrotechnics\"\n | \"timewarp\"\n | \"melt\"\n | \"electric\"\n | \"transition\"\n | \"loader\"\n | \"data\"\n | \"icon\";\n\n/** Every category, in the order the catalog lists them. */\nexport const EFFECT_CATEGORIES: readonly EffectCategory[] = [\n \"gradient\",\n \"organic\",\n \"pattern\",\n \"light\",\n \"space\",\n \"retro\",\n \"image\",\n \"overlay\",\n \"text\",\n \"morph\",\n \"interaction\",\n \"pyrotechnics\",\n \"timewarp\",\n \"melt\",\n \"electric\",\n \"transition\",\n \"loader\",\n \"data\",\n \"icon\",\n];\n\n/** Named control values: a look an effect can be switched to. */\nexport interface EffectPreset {\n name: string;\n values: Record<string, ControlValue>;\n}\n\ninterface EffectBase {\n /** Stable id, kebab-case: `aurora`, `image-glitch`. */\n id: string;\n name: string;\n /** One sentence: what it looks like. */\n description: string;\n category: EffectCategory;\n tags: readonly string[];\n presets?: readonly EffectPreset[];\n}\n\n/**\n * A WebGL2 fragment shader (Shadertoy-style `mainImage`). Its controls are the\n * `// @control` uniforms in `source`; run it with `ShaderRenderer`,\n * `ShaderFrames`, `ThumbnailPool`, `recordGif` or `standaloneHtml`.\n */\nexport interface ShaderEffect extends EffectBase {\n kind: \"shader\";\n source: string;\n /** Seconds after which it repeats exactly, when it loops seamlessly. */\n loop?: number;\n /**\n * Draws over other content: `fragColor.a` is coverage (0 where there is\n * nothing to draw), so render it on a transparent canvas\n * (`ShaderRenderer`'s `alpha` option) to layer it over a page or picture.\n */\n transparent?: boolean;\n}\n\n/**\n * A control of a vector effect, declared in a list rather than in the\n * picture (see {@link VectorEffect.controls}). The same shape as a shader's\n * controls (see `ControlDef`) less what only sources have; `vec3` colours\n * are written into the picture as `#rrggbb`.\n */\nexport type VectorControl = Pick<ControlDef, \"name\" | \"type\" | \"default\"> &\n Partial<Pick<ControlDef, \"label\" | \"color\" | \"min\" | \"max\" | \"step\">>;\n\n/**\n * An animated SVG picture (see `SvgMotion`) whose controls are declared in\n * the picture itself, the way a shader's are declared in its source. The\n * first `{{name: type …}}` declares a control and every `{{name}}` is\n * replaced by its value (see {@link vectorControls} and\n * {@link renderVectorEffect}); run the result with `SvgPlayer`.\n */\nexport interface VectorEffect extends EffectBase {\n kind: \"vector\";\n motion: SvgMotion;\n /**\n * Controls declared outside the picture, for effects written before\n * controls were declared inline. A control declared in the picture wins\n * over one of the same name here.\n */\n controls?: readonly VectorControl[];\n /**\n * More placeholders worked out from the control values (a bar's height\n * from its value, say), filled in after the controls.\n */\n derived?: (values: Record<string, ControlValue>) => Record<string, string | number>;\n /** Ms to rest on the last frame before it loops (default 600). */\n hold?: number;\n /**\n * Plays in answer to the pointer rather than on a loop: pass it to\n * `SvgPlayer` (`{ trigger: effect.trigger }`). Click-triggered pictures\n * change on steps, each click playing the next.\n */\n trigger?: SvgTrigger;\n}\n\nexport type EffectDefinition = ShaderEffect | VectorEffect;\n\n/** The types a vector effect's `{{name: type …}}` placeholder can declare. */\nexport const VECTOR_CONTROL_TYPES = [\"float\", \"int\", \"bool\", \"color\", \"text\"] as const;\n\n/**\n * A placeholder: `{{name}}`, or a declaration `{{name: type attributes}}`\n * whose attributes are a shader `@control`'s (`min`, `max`, `step`,\n * `default`, `label`). Quote values with spaces in single quotes inside an\n * SVG attribute: `fill=\"{{accent: color default=#6366F1 label='Accent'}}\"`.\n */\nconst PLACEHOLDER = /\\{\\{\\s*([A-Za-z_]\\w*)\\s*(?::\\s*([A-Za-z0-9]*)([^}]*))?\\}\\}/g;\n\n/** Every string in a motion, the markup first, then each animation's values in order. */\nfunction motionStrings(motion: SvgMotion): string[] {\n const out: string[] = [];\n const walk = (v: unknown) => {\n if (typeof v === \"string\") out.push(v);\n else if (Array.isArray(v)) v.forEach(walk);\n else if (v && typeof v === \"object\") Object.values(v).forEach(walk);\n };\n walk(motion);\n return out;\n}\n\n/**\n * The controls a vector effect's picture declares, in the order they are\n * first declared: `{{word: text default=SLOP label=Word}}`, `{{accent:\n * color default=#6366F1}}`, `{{width: float min=2 max=20 default=8 step=1}}`,\n * `{{shadow: bool default=true}}`. A name declared twice counts once (the\n * first wins), and declarations with an unknown type are left out (see\n * {@link vectorControlIssues}). A control only `derived` reads can be\n * declared in an XML comment: `<!-- {{drip: float default=1}} -->`.\n */\nexport function vectorControls(motion: SvgMotion): ControlDef[] {\n const controls: ControlDef[] = [];\n const seen = new Set<string>();\n for (const text of motionStrings(motion)) {\n for (const [, name, type, attributes] of text.matchAll(PLACEHOLDER)) {\n if (type === undefined || seen.has(name!) || !(VECTOR_CONTROL_TYPES as readonly string[]).includes(type)) continue;\n seen.add(name!);\n const colour = type === \"color\";\n controls.push(controlFromDeclaration(name!, colour ? \"vec3\" : (type as ControlType), `${attributes}${colour ? \" color\" : \"\"}`, controls.length + 1));\n }\n }\n return controls;\n}\n\n/** A vector effect's controls: those its picture declares, then any in its `controls` list it does not. */\nexport function vectorEffectControls(effect: Pick<VectorEffect, \"motion\" | \"controls\">): ControlDef[] {\n const declared = vectorControls(effect.motion);\n const names = new Set(declared.map((c) => c.name));\n const listed = (effect.controls ?? []).filter((c) => !names.has(c.name));\n return [...declared, ...listed.map((c, i) => vectorControlDef(c, declared.length + i + 1))];\n}\n\n/**\n * Problems with a picture's placeholders, as sentences: declarations of an\n * unknown type, and a name declared twice in different ways.\n */\nexport function vectorControlIssues(motion: SvgMotion): string[] {\n const issues: string[] = [];\n const declarations = new Map<string, string>();\n for (const text of motionStrings(motion)) {\n for (const [whole, name, type] of text.matchAll(PLACEHOLDER)) {\n if (type === undefined) continue;\n if (!(VECTOR_CONTROL_TYPES as readonly string[]).includes(type))\n issues.push(`${whole}: a control's type is one of ${VECTOR_CONTROL_TYPES.join(\", \")}`);\n else if (declarations.has(name!) && declarations.get(name!) !== whole)\n issues.push(`\"${name}\" is declared twice; declare it once and write {{${name}}} everywhere else`);\n else declarations.set(name!, whole);\n }\n }\n return issues;\n}\n\n/** A vector control's value written into the picture: colours as hex, vectors space-separated, the rest as they are. */\nfunction written(control: Pick<ControlDef, \"color\">, value: ControlValue): string | number | boolean {\n if (control.color && Array.isArray(value)) return rgbToHex(value);\n if (Array.isArray(value)) return value.join(\" \");\n return value;\n}\n\nconst escapeMarkup = (text: string) =>\n text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#39;\");\n\n/** A vector control as a full `ControlDef`, so editors treat both kinds of effect alike. */\nexport function vectorControlDef(control: VectorControl, line = 0): ControlDef {\n const min = control.min ?? 0;\n return {\n name: control.name,\n type: control.type,\n label: control.label ?? control.name,\n color: control.color ?? false,\n min,\n max: control.max ?? Math.max(min + 1, 1),\n step: control.step ?? (control.type === \"int\" ? 1 : 0.01),\n default: control.default,\n line,\n };\n}\n\n/**\n * A vector effect's motion with its controls filled in. A string that is\n * only a placeholder (an animation's `\"{{width}}\"`) becomes the value\n * itself, so numbers stay numbers; elsewhere a placeholder becomes its text,\n * escaped in the markup so any text is safe to show. Comments are dropped\n * from the markup. Colours also take \"#RRGGBB\"; missing values, and values a\n * control cannot take, use defaults. Placeholders no control or derived\n * value fills stay put.\n */\nexport function renderVectorEffect(\n effect: Pick<VectorEffect, \"motion\" | \"controls\" | \"derived\">,\n values: Record<string, ControlValue> = {},\n): SvgMotion {\n const filled: Record<string, ControlValue> = {};\n const placeholders = new Map<string, string | number | boolean>();\n for (const control of vectorEffectControls(effect)) {\n const given = values[control.name];\n const check = given === undefined ? undefined : checkControlValue(control, given);\n filled[control.name] = check?.ok ? check.value : control.default;\n placeholders.set(control.name, written(control, filled[control.name]!));\n }\n for (const [name, value] of Object.entries(effect.derived?.(filled) ?? {})) placeholders.set(name, value);\n const fill = (text: string, markup: boolean): string | number | boolean => {\n const whole = /^\\{\\{\\s*([A-Za-z_]\\w*)\\s*(?::[^}]*)?\\}\\}$/.exec(text);\n if (!markup && whole && placeholders.has(whole[1]!)) return placeholders.get(whole[1]!)!;\n return text.replace(PLACEHOLDER, (match, name: string) => {\n if (!placeholders.has(name)) return match;\n const value = String(placeholders.get(name));\n return markup ? escapeMarkup(value) : value;\n });\n };\n const walk = (v: unknown): unknown => {\n if (typeof v === \"string\") return fill(v, false);\n if (Array.isArray(v)) return v.map(walk);\n if (v && typeof v === \"object\") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));\n return v;\n };\n const { svg, ...rest } = effect.motion;\n // Comments hold declarations, not picture, and a value with \"--\" in one would break the markup.\n return { svg: fill(svg.replace(/<!--[\\s\\S]*?-->/g, \"\"), true) as string, ...(walk(rest) as Omit<SvgMotion, \"svg\">) };\n}\n\n/** A colour control for vector effects. */\nexport function colorControl(name: string, hex: string, label?: string): VectorControl {\n return { name, type: \"vec3\", color: true, default: hexToRgb(hex) ?? [1, 1, 1], label: label ?? name };\n}\n\n/** A number control for vector effects. */\nexport function numberControl(\n name: string,\n value: number,\n min: number,\n max: number,\n label?: string,\n step?: number,\n): VectorControl {\n return { name, type: \"float\", default: value, min, max, label: label ?? name, step };\n}\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nexport const spinner: VectorEffect = {\n kind: \"vector\",\n id: \"spinner\",\n name: \"Spinner\",\n description: \"An arc chasing its tail: the classic indeterminate loader.\",\n category: \"loader\",\n tags: [\"loader\", \"ui\", \"minimal\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#6366F1 label='Arc'}} {{track: color default=#E5E7EB label='Track'}} {{width: float min=2 max=20 default=8 step=1 label='Stroke width'}} --><circle cx=\"50\" cy=\"50\" r=\"38\" fill=\"none\" stroke=\"{{track}}\" stroke-width=\"{{width}}\"/><g id=\"spin\" transform=\"rotate(0 50 50)\"><circle id=\"arc\" cx=\"50\" cy=\"50\" r=\"38\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" pathLength=\"1\" stroke-dasharray=\"0.25 1\"/></g></svg>`,\n animate: [\n { id: \"spin\", attrs: { transform: [\"rotate(0 50 50)\", \"rotate(720 50 50)\"] }, ms: 1600, ease: \"linear\" },\n { id: \"arc\", attrs: { \"stroke-dasharray\": [\"0.08 1\", \"0.6 1\"] }, ms: 800, ease: \"in-out\" },\n { id: \"arc\", attrs: { \"stroke-dasharray\": [\"0.6 1\", \"0.08 1\"] }, delay: 800, ms: 800, ease: \"in-out\" },\n ],\n },\n};\n\nexport const bouncingDots: VectorEffect = {\n kind: \"vector\",\n id: \"bouncing-dots\",\n name: \"Bouncing dots\",\n description: \"Three dots hopping in turn, for typing indicators and loaders.\",\n category: \"loader\",\n tags: [\"loader\", \"chat\", \"typing\", \"ui\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 120 60\"><!-- {{accent: color default=#0EA5E9 label='Dots'}} {{height: float min=4 max=30 default=18 step=1 label='Bounce height'}} --><circle id=\"a\" cx=\"30\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/><circle id=\"b\" cx=\"60\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/><circle id=\"c\" cx=\"90\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/></svg>`,\n animate: [\"a\", \"b\", \"c\"].flatMap((id, i): SvgAnimation[] => [\n { id, attrs: { transform: [\"translate(0 0)\", \"translate(0 -{{height}})\"] }, delay: i * 150, ms: 250, ease: \"out\" as const },\n { id, attrs: { transform: [\"translate(0 -{{height}})\", \"translate(0 0)\"] }, delay: i * 150 + 250, ms: 250, ease: \"in-out\" as const },\n { id, attrs: { opacity: [0.5, 1] }, delay: i * 150, ms: 250 },\n { id, attrs: { opacity: [1, 0.5] }, delay: i * 150 + 250, ms: 250 },\n ]),\n },\n};\n\nexport const progressRing: VectorEffect = {\n kind: \"vector\",\n id: \"progress-ring\",\n name: \"Progress ring\",\n description: \"A ring filling up to a percentage while the number counts with it.\",\n category: \"data\",\n tags: [\"progress\", \"kpi\", \"dashboard\", \"loader\"],\n derived: (v) => ({ fraction: Math.min(1, Math.max(0, Number(v.value) / 100)) }),\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#22C55E label='Ring'}} {{track: color default=#E5E7EB label='Track'}} {{text: color default=#111827 label='Text'}} {{value: float min=0 max=100 default=72 step=1 label='Percent'}} --><circle cx=\"60\" cy=\"60\" r=\"48\" fill=\"none\" stroke=\"{{track}}\" stroke-width=\"10\"/><circle id=\"ring\" cx=\"60\" cy=\"60\" r=\"48\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"10\" stroke-linecap=\"round\" transform=\"rotate(-90 60 60)\"/><text id=\"label\" x=\"60\" y=\"68\" text-anchor=\"middle\" font-size=\"24\" font-weight=\"700\" fill=\"{{text}}\">0%</text></svg>`,\n animate: [\n { id: \"ring\", draw: [0, \"{{fraction}}\"] as unknown as [number, number], ms: 1600, ease: \"out\" },\n { id: \"label\", count: [0, \"{{value}}\"] as unknown as [number, number], format: \"{n}%\", ms: 1600, ease: \"out\" },\n ],\n },\n};\n\nexport const pulsePing: VectorEffect = {\n kind: \"vector\",\n id: \"pulse-ping\",\n name: \"Pulse ping\",\n description: \"Rings radiating from a dot, like a live indicator or radar ping.\",\n category: \"loader\",\n tags: [\"live\", \"notification\", \"location\", \"status\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#EF4444 label='Colour'}} --><circle id=\"r1\" cx=\"50\" cy=\"50\" r=\"8\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\"/><circle id=\"r2\" cx=\"50\" cy=\"50\" r=\"8\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\"/><circle cx=\"50\" cy=\"50\" r=\"9\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n { id: \"r1\", attrs: { r: [8, 44], opacity: [0.9, 0], \"stroke-width\": [4, 1] }, ms: 1400, ease: \"out\" },\n { id: \"r2\", attrs: { r: [8, 44], opacity: [0.9, 0], \"stroke-width\": [4, 1] }, delay: 700, ms: 1400, ease: \"out\" },\n ],\n },\n};\n\nexport const successCheck: VectorEffect = {\n kind: \"vector\",\n id: \"success-check\",\n name: \"Success check\",\n description: \"A circle drawing itself closed, then a tick, then a little pop.\",\n category: \"icon\",\n tags: [\"success\", \"confirmation\", \"ui\", \"feedback\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#16A34A label='Colour'}} {{width: float min=2 max=12 default=6 step=1 label='Stroke width'}} --><g id=\"badge\" transform=\"translate(50 50) scale(1) translate(-50 -50)\"><circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><path id=\"tick\" d=\"M31 52 L44 64 L70 37\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n { id: \"circle\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"tick\", draw: true, delay: 500, ms: 400, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(50 50) scale(1) translate(-50 -50)\", \"translate(50 50) scale(1.12) translate(-50 -50)\"] }, delay: 850, ms: 150, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(50 50) scale(1.12) translate(-50 -50)\", \"translate(50 50) scale(1) translate(-50 -50)\"] }, delay: 1000, ms: 250, ease: \"in-out\" },\n ],\n },\n};\n\nexport const errorCross: VectorEffect = {\n kind: \"vector\",\n id: \"error-cross\",\n name: \"Error cross\",\n description: \"A circle and a cross drawing on, with a short shake.\",\n category: \"icon\",\n tags: [\"error\", \"failure\", \"ui\", \"feedback\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#DC2626 label='Colour'}} {{width: float min=2 max=12 default=6 step=1 label='Stroke width'}} --><g id=\"badge\" transform=\"translate(0 0)\"><circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><path id=\"a\" d=\"M36 36 L64 64\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><path id=\"b\" d=\"M64 36 L36 64\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/></g></svg>`,\n animate: [\n { id: \"circle\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"a\", draw: true, delay: 500, ms: 250, ease: \"out\" },\n { id: \"b\", draw: true, delay: 700, ms: 250, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(0 0)\", \"translate(-6 0)\"] }, delay: 950, ms: 60, ease: \"linear\" },\n { id: \"badge\", attrs: { transform: [\"translate(-6 0)\", \"translate(6 0)\"] }, delay: 1010, ms: 100, ease: \"linear\" },\n { id: \"badge\", attrs: { transform: [\"translate(6 0)\", \"translate(0 0)\"] }, delay: 1110, ms: 80, ease: \"out\" },\n ],\n },\n};\n\nexport const heartbeat: VectorEffect = {\n kind: \"vector\",\n id: \"heartbeat\",\n name: \"Heartbeat\",\n description: \"A heart beating twice, with an ECG line tracing beneath it.\",\n category: \"icon\",\n tags: [\"health\", \"like\", \"love\", \"pulse\"],\n hold: 300,\n motion: {\n svg: `<svg viewBox=\"0 0 200 120\"><!-- {{accent: color default=#F43F5E label='Heart'}} {{line: color default=#94A3B8 label='Line'}} --><g id=\"heart\" transform=\"translate(100 46) scale(1)\"><path d=\"M0 22 C-30 0 -30 -26 -10 -26 C-3 -26 0 -20 0 -16 C0 -20 3 -26 10 -26 C30 -26 30 0 0 22Z\" fill=\"{{accent}}\"/></g><path id=\"ecg\" d=\"M10 100 H70 L80 86 L90 112 L100 76 L110 104 L118 100 H190\" fill=\"none\" stroke=\"{{line}}\" stroke-width=\"3\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></svg>`,\n animate: [\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1)\", \"translate(100 46) scale(1.18)\"] }, ms: 120, ease: \"out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1.18)\", \"translate(100 46) scale(1)\"] }, delay: 120, ms: 160, ease: \"in-out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1)\", \"translate(100 46) scale(1.12)\"] }, delay: 300, ms: 120, ease: \"out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1.12)\", \"translate(100 46) scale(1)\"] }, delay: 420, ms: 300, ease: \"in-out\" },\n { id: \"ecg\", draw: true, ms: 900, ease: \"linear\" },\n ],\n },\n};\n\nexport const barChart: VectorEffect = {\n kind: \"vector\",\n id: \"bar-chart\",\n name: \"Bar chart\",\n description: \"Bars growing into place one after another, values counting above them.\",\n category: \"data\",\n tags: [\"chart\", \"dashboard\", \"report\", \"explainer\"],\n hold: 1500,\n derived: (v) =>\n Object.fromEntries(\n [\"a\", \"b\", \"c\", \"d\"].flatMap((k) => {\n const h = Math.min(100, Math.max(0, Number(v[k]))) * 1.1;\n return [\n [`${k}_height`, +h.toFixed(2)],\n [`${k}_label_y`, +(134 - h).toFixed(2)],\n ];\n }),\n ),\n motion: {\n svg: `<svg viewBox=\"0 0 240 160\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#6366F1 label='Bars'}} {{text: color default=#334155 label='Text'}} {{a: float min=0 max=100 default=40 step=1 label='Bar 1'}} {{b: float min=0 max=100 default=65 step=1 label='Bar 2'}} {{c: float min=0 max=100 default=50 step=1 label='Bar 3'}} {{d: float min=0 max=100 default=90 step=1 label='Bar 4'}} --><line x1=\"20\" y1=\"140\" x2=\"220\" y2=\"140\" stroke=\"{{text}}\" stroke-opacity=\"0.3\" stroke-width=\"2\"/>${[\"a\", \"b\", \"c\", \"d\"]\n .map(\n (k, i) =>\n `<g id=\"bar-${k}\" transform=\"translate(${40 + i * 48} 140) scale(1 0)\"><rect x=\"0\" y=\"-1\" width=\"32\" height=\"1\" rx=\"0.02\" fill=\"{{accent}}\"/></g><text id=\"label-${k}\" x=\"${56 + i * 48}\" y=\"132\" text-anchor=\"middle\" font-size=\"12\" fill=\"{{text}}\" opacity=\"0\">0</text>`,\n )\n .join(\"\")}</svg>`,\n animate: [\"a\", \"b\", \"c\", \"d\"].flatMap((k, i): SvgAnimation[] => [\n { id: `bar-${k}`, attrs: { transform: [`translate(${40 + i * 48} 140) scale(1 0)`, `translate(${40 + i * 48} 140) scale(1 {{${k}_height}})`] }, delay: i * 180, ms: 700, ease: \"out\" as const },\n { id: `label-${k}`, attrs: { y: [132, `{{${k}_label_y}}`], opacity: [0, 1] }, delay: i * 180, ms: 700, ease: \"out\" as const },\n { id: `label-${k}`, count: [0, `{{${k}}}`] as unknown as [number, number], delay: i * 180, ms: 700, ease: \"out\" as const },\n ]),\n },\n};\n\nexport const lineChart: VectorEffect = {\n kind: \"vector\",\n id: \"line-chart\",\n name: \"Line chart\",\n description: \"A trend line drawing across with a marker riding its tip and the area fading in below.\",\n category: \"data\",\n tags: [\"chart\", \"trend\", \"growth\", \"dashboard\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 240 140\"><!-- {{accent: color default=#0EA5E9 label='Line'}} {{grid: color default=#CBD5E1 label='Grid'}} --><defs><linearGradient id=\"fill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"{{accent}}\" stop-opacity=\"0.35\"/><stop offset=\"1\" stop-color=\"{{accent}}\" stop-opacity=\"0\"/></linearGradient></defs><g stroke=\"{{grid}}\" stroke-width=\"1\"><line x1=\"20\" y1=\"30\" x2=\"220\" y2=\"30\"/><line x1=\"20\" y1=\"70\" x2=\"220\" y2=\"70\"/><line x1=\"20\" y1=\"110\" x2=\"220\" y2=\"110\"/></g><path id=\"area\" d=\"M20 110 L60 92 L100 98 L140 64 L180 70 L220 30 L220 120 L20 120Z\" fill=\"url(#fill)\" opacity=\"0\"/><path id=\"trend\" d=\"M20 110 L60 92 L100 98 L140 64 L180 70 L220 30\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><circle id=\"marker\" r=\"5\" fill=\"#fff\" stroke=\"{{accent}}\" stroke-width=\"3\"/></svg>`,\n animate: [\n { id: \"trend\", draw: true, ms: 1400, ease: \"in-out\" },\n { id: \"marker\", along: \"trend\", ms: 1400, ease: \"in-out\" },\n { id: \"area\", attrs: { opacity: [0, 1] }, delay: 900, ms: 600 },\n ],\n },\n};\n\nexport const statCounter: VectorEffect = {\n kind: \"vector\",\n id: \"stat-counter\",\n name: \"Stat counter\",\n description: \"A headline number counting up, with its caption and underline sweeping in.\",\n category: \"data\",\n tags: [\"kpi\", \"number\", \"headline\", \"explainer\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 240 120\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#F59E0B label='Accent'}} {{text: color default=#0F172A label='Text'}} {{value: float min=0 max=100000 default=1250 step=1 label='Value'}} {{caption: text default='happy customers' label='Caption'}} --><text id=\"number\" x=\"120\" y=\"62\" text-anchor=\"middle\" font-size=\"44\" font-weight=\"800\" fill=\"{{text}}\">0</text><path id=\"underline\" d=\"M60 78 H180\" stroke=\"{{accent}}\" stroke-width=\"6\" stroke-linecap=\"round\"/><text id=\"caption\" x=\"120\" y=\"104\" text-anchor=\"middle\" font-size=\"13\" fill=\"{{text}}\" opacity=\"0\">{{caption}}</text></svg>`,\n animate: [\n { id: \"number\", count: [0, \"{{value}}\"] as unknown as [number, number], ms: 1500, ease: \"out\" },\n { id: \"underline\", draw: true, delay: 300, ms: 900, ease: \"in-out\" },\n { id: \"caption\", attrs: { opacity: [0, 1], y: [112, 104] }, delay: 800, ms: 500, ease: \"out\" },\n ],\n },\n};\n\nexport const timelineTrack: VectorEffect = {\n kind: \"vector\",\n id: \"timeline-track\",\n name: \"Timeline track\",\n description: \"A vertical line drawing down with nodes popping along milestones.\",\n category: \"data\",\n tags: [\"timeline\", \"roadmap\", \"milestones\", \"history\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 400\"><!-- {{track: color default=#E5E7EB label='Track'}} {{accent: color default=#F97316 label='Accent'}} {{width: float min=1 max=8 default=3 step=0.5 label='Line width'}} --><line x1=\"50\" y1=\"20\" x2=\"50\" y2=\"380\" stroke=\"{{track}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><path id=\"line\" d=\"M50 20 L50 380\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><g id=\"n1\" transform=\"translate(50 60) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n2\" transform=\"translate(50 160) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n3\" transform=\"translate(50 260) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n4\" transform=\"translate(50 360) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g></svg>`,\n animate: [\n { id: \"line\", draw: true, ms: 1400, ease: \"in-out\" },\n { id: \"n1\", attrs: { transform: [\"translate(50 60) scale(0)\", \"translate(50 60) scale(1)\"] }, delay: 200, ms: 250, ease: \"out\" },\n { id: \"n2\", attrs: { transform: [\"translate(50 160) scale(0)\", \"translate(50 160) scale(1)\"] }, delay: 550, ms: 250, ease: \"out\" },\n { id: \"n3\", attrs: { transform: [\"translate(50 260) scale(0)\", \"translate(50 260) scale(1)\"] }, delay: 900, ms: 250, ease: \"out\" },\n { id: \"n4\", attrs: { transform: [\"translate(50 360) scale(0)\", \"translate(50 360) scale(1)\"] }, delay: 1300, ms: 250, ease: \"out\" },\n ],\n },\n};\n\nexport const route: VectorEffect = {\n kind: \"vector\",\n id: \"route\",\n name: \"Route\",\n description: \"A dashed journey drawing between two pins, with a traveller following it.\",\n category: \"data\",\n tags: [\"map\", \"travel\", \"delivery\", \"journey\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 240 150\"><!-- {{accent: color default=#8B5CF6 label='Route'}} {{pin: color default=#0F172A label='Pins'}} --><path id=\"path\" d=\"M30 120 C60 40 120 140 150 70 S210 30 210 30\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"4\" stroke-linecap=\"round\"/><circle cx=\"30\" cy=\"120\" r=\"7\" fill=\"{{pin}}\"/><g id=\"end\" opacity=\"0\"><circle cx=\"210\" cy=\"30\" r=\"9\" fill=\"{{pin}}\"/><circle cx=\"210\" cy=\"30\" r=\"3.5\" fill=\"#fff\"/></g><g id=\"traveller\"><circle r=\"7\" fill=\"{{accent}}\"/><circle r=\"3\" fill=\"#fff\"/></g></svg>`,\n animate: [\n { id: \"path\", draw: true, ms: 1800, ease: \"in-out\" },\n { id: \"traveller\", along: \"path\", ms: 1800, ease: \"in-out\" },\n { id: \"end\", attrs: { opacity: [0, 1] }, delay: 1600, ms: 300 },\n ],\n },\n};\n\nexport const blobMorph: VectorEffect = {\n kind: \"vector\",\n id: \"blob-morph\",\n name: \"Blob morph\",\n description: \"An organic blob shape-shifting through three forms.\",\n category: \"organic\",\n tags: [\"shape\", \"background\", \"playful\", \"brand\"],\n hold: 0,\n motion: (() => {\n const shapes = [\n \"M100 30 C140 30 170 60 170 100 C170 140 140 170 100 170 C60 170 30 140 30 100 C30 60 60 30 100 30Z\",\n \"M100 20 C150 40 180 70 160 110 C140 160 120 175 85 165 C45 155 25 120 40 80 C55 40 70 15 100 20Z\",\n \"M110 35 C155 25 175 85 165 120 C155 160 105 180 70 160 C35 140 20 100 45 70 C65 45 80 40 110 35Z\",\n ];\n const step = 1200;\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{colorA: color default=#F472B6 label='Colour A'}} {{colorB: color default=#818CF8 label='Colour B'}} --><defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"{{colorA}}\"/><stop offset=\"1\" stop-color=\"{{colorB}}\"/></linearGradient></defs><path id=\"blob\" d=\"${shapes[0]}\" fill=\"url(#g)\"/></svg>`,\n animate: shapes.map((d, i) => ({\n id: \"blob\",\n attrs: { d: [d, shapes[(i + 1) % shapes.length]!] as [string, string] },\n delay: i * step,\n ms: step,\n ease: \"in-out\" as const,\n })),\n };\n })(),\n};\n\nexport const signature: VectorEffect = {\n kind: \"vector\",\n id: \"signature\",\n name: \"Signature\",\n description: \"A handwritten flourish drawing itself as if by pen.\",\n category: \"icon\",\n tags: [\"handwriting\", \"draw-on\", \"personal\", \"reveal\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 260 120\"><!-- {{ink: color default=#1E293B label='Ink'}} {{width: float min=1 max=8 default=3 step=0.5 label='Pen width'}} --><path id=\"sig\" d=\"M20 80 C40 20 60 20 55 70 C52 95 70 95 85 60 C95 40 100 75 110 70 C120 65 125 40 135 55 C145 70 150 75 165 50 C175 35 185 60 190 65 C200 75 215 40 240 45\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"dash\" d=\"M70 100 Q140 92 220 98\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/></svg>`,\n animate: [\n { id: \"sig\", draw: true, ms: 1800, ease: \"in-out\" },\n { id: \"dash\", draw: true, delay: 1700, ms: 400, ease: \"out\" },\n ],\n },\n};\n\nexport const equalizer: VectorEffect = {\n kind: \"vector\",\n id: \"equalizer\",\n name: \"Equalizer\",\n description: \"Audio level bars dancing, for now-playing badges and voice states.\",\n category: \"loader\",\n tags: [\"music\", \"audio\", \"voice\", \"now-playing\"],\n hold: 0,\n motion: (() => {\n const heights = [\n [0.3, 0.9, 0.5, 0.3],\n [0.7, 0.4, 1.0, 0.7],\n [0.5, 1.0, 0.3, 0.5],\n [0.9, 0.5, 0.7, 0.9],\n [0.4, 0.8, 0.6, 0.4],\n ];\n const beat = 250;\n return {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#10B981 label='Bars'}} -->${heights\n .map((_, i) => `<g id=\"bar${i}\" transform=\"translate(${14 + i * 16} 85) scale(1 ${heights[i]![0]})\"><rect x=\"0\" y=\"-70\" width=\"10\" height=\"70\" rx=\"5\" fill=\"{{accent}}\"/></g>`)\n .join(\"\")}</svg>`,\n animate: heights.flatMap((h, i) =>\n [0, 1, 2].map((k) => ({\n id: `bar${i}`,\n attrs: { transform: [`translate(${14 + i * 16} 85) scale(1 ${h[k]})`, `translate(${14 + i * 16} 85) scale(1 ${h[k + 1]})`] as [string, string] },\n delay: k * beat,\n ms: beat,\n ease: \"in-out\" as const,\n })),\n ),\n };\n })(),\n};\n\nexport const confetti: VectorEffect = {\n kind: \"vector\",\n id: \"confetti\",\n name: \"Confetti burst\",\n description: \"A burst of confetti flying out and fluttering down.\",\n category: \"icon\",\n tags: [\"celebration\", \"success\", \"party\", \"reward\"],\n hold: 400,\n motion: (() => {\n const pieces = Array.from({ length: 18 }, (_, i) => {\n const angle = (i / 18) * Math.PI * 2 + (i % 3) * 0.2;\n const dist = 55 + (i % 4) * 12;\n const x = Math.round(Math.cos(angle) * dist);\n const y = Math.round(Math.sin(angle) * dist * 0.8 - 20);\n const spin = (i % 2 ? 1 : -1) * (180 + (i % 5) * 60);\n return { i, x, y, spin, fill: [\"{{a}}\", \"{{b}}\", \"{{c}}\"][i % 3]! };\n });\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{a: color default=#F43F5E label='Colour A'}} {{b: color default=#FACC15 label='Colour B'}} {{c: color default=#22D3EE label='Colour C'}} -->${pieces\n .map((p) => `<rect id=\"p${p.i}\" x=\"-4\" y=\"-2\" width=\"8\" height=\"4\" rx=\"1\" fill=\"${p.fill}\" transform=\"translate(100 110) rotate(0)\" opacity=\"0\"/>`)\n .join(\"\")}</svg>`,\n animate: pieces.flatMap((p): SvgAnimation[] => [\n { id: `p${p.i}`, attrs: { opacity: [0, 1] }, ms: 50 },\n {\n id: `p${p.i}`,\n attrs: { transform: [\"translate(100 110) rotate(0)\", `translate(${100 + p.x} ${110 + p.y}) rotate(${p.spin})`] as [string, string] },\n ms: 600,\n ease: \"out\" as const,\n },\n {\n id: `p${p.i}`,\n attrs: {\n transform: [`translate(${100 + p.x} ${110 + p.y}) rotate(${p.spin})`, `translate(${100 + p.x * 1.2} ${180 + p.y * 0.2}) rotate(${p.spin * 2})`] as [string, string],\n },\n delay: 600,\n ms: 1000,\n ease: \"in-out\" as const,\n },\n { id: `p${p.i}`, attrs: { opacity: [1, 0] }, delay: 1300, ms: 300 },\n ]),\n };\n })(),\n};\n\n\n/** Flow network's nodes and links, left to right, with the critical path through them. */\nconst NODES: Record<string, [number, number]> = {\n s: [40, 120], a: [120, 60], b: [120, 180], c: [280, 50], d: [290, 130], e: [280, 200], t: [360, 120],\n};\nconst HUB: [number, number] = [200, 120];\nconst link = ([x1, y1]: [number, number], [x2, y2]: [number, number]) => {\n const mid = (x1 + x2) / 2;\n return `M${x1} ${y1} C${mid} ${y1} ${mid} ${y2} ${x2} ${y2}`;\n};\nconst LINKS: { from: [number, number]; to: [number, number]; column: number }[] = [\n { from: NODES.s!, to: NODES.a!, column: 0 },\n { from: NODES.s!, to: NODES.b!, column: 0 },\n { from: NODES.a!, to: HUB, column: 1 },\n { from: NODES.b!, to: HUB, column: 1 },\n { from: HUB, to: NODES.c!, column: 2 },\n { from: HUB, to: NODES.d!, column: 2 },\n { from: HUB, to: NODES.e!, column: 2 },\n { from: NODES.c!, to: NODES.t!, column: 3 },\n { from: NODES.d!, to: NODES.t!, column: 3 },\n { from: NODES.e!, to: NODES.t!, column: 3 },\n];\nconst CRITICAL = [NODES.s!, NODES.b!, HUB, NODES.c!, NODES.t!]\n .map((p, i, all) => (i === 0 ? \"\" : link(all[i - 1]!, p).replace(/^M[\\d.]+ [\\d.]+ /, i === 1 ? `M${all[0]![0]} ${all[0]![1]} ` : \"\")))\n .filter(Boolean)\n .join(\" \");\n/** The column a node is reached in, so it appears as the links arrive. */\nconst NODE_COLUMN: Record<string, number> = { s: 0, a: 1, b: 1, c: 3, d: 3, e: 3, t: 4 };\nconst COLUMN_MS = 280;\nconst PATH_START = 1500;\nconst PATH_MS = 1800;\n\nexport const flowNetwork: VectorEffect = {\n kind: \"vector\",\n id: \"flow-network\",\n name: \"Flow network\",\n description: \"A node graph linking up, then a glowing critical path racing through it to a pulsing hub.\",\n category: \"data\",\n tags: [\"network\", \"graph\", \"dag\", \"workflow\", \"tech\", \"explainer\"],\n hold: 1200,\n presets: [\n { name: \"Light\", values: { background: [0.93, 0.95, 0.96], link: [0.37, 0.72, 0.69], path: [0.96, 0.62, 0.04], ink: [0.2, 0.25, 0.33] } },\n { name: \"Neon\", values: { background: [0.04, 0.02, 0.1], link: [0.13, 0.83, 0.93], path: [0.96, 0.45, 0.71], ink: [0.85, 0.85, 1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 400 240\" font-family=\"system-ui, sans-serif\"><!-- {{label: text default='Critical path' label='Hub label'}} {{background: color default=#0B1220 label='Background'}} {{link: color default=#4FD1C5 label='Links'}} {{path: color default=#F5A524 label='Critical path'}} {{ink: color default=#CBD5E1 label='Label'}} {{glow: float min=0 max=6 default=2.5 step=0.5 label='Glow'}} --><defs><filter id=\"glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\"><feGaussianBlur stdDeviation=\"{{glow}}\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs><rect width=\"400\" height=\"240\" fill=\"{{background}}\"/>${LINKS.map(\n (l, i) => `<path id=\"l${i}\" d=\"${link(l.from, l.to)}\" fill=\"none\" stroke=\"{{link}}\" stroke-width=\"1.6\" stroke-opacity=\"0.75\" filter=\"url(#glow)\"/>`,\n ).join(\"\")}<path id=\"crit\" d=\"${CRITICAL}\" fill=\"none\" stroke=\"{{path}}\" stroke-width=\"3\" stroke-linecap=\"round\" filter=\"url(#glow)\"/>${[0, 1]\n .map((i) => `<circle id=\"ring${i}\" cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"10\" fill=\"none\" stroke=\"{{link}}\" stroke-width=\"2\" opacity=\"0\"/>`)\n .join(\"\")}${Object.entries(NODES)\n .map(([id, [x, y]]) => `<circle id=\"n${id}\" cx=\"${x}\" cy=\"${y}\" r=\"6\" fill=\"{{background}}\" stroke=\"{{link}}\" stroke-width=\"2.5\" filter=\"url(#glow)\" opacity=\"0\"/>`)\n .join(\"\")}<g id=\"hub\" opacity=\"0\"><circle cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"13\" fill=\"{{link}}\" fill-opacity=\"0.25\" stroke=\"{{link}}\" stroke-width=\"2\" filter=\"url(#glow)\"/><circle cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"6\" fill=\"{{link}}\"/></g><text id=\"caption\" x=\"${HUB[0]}\" y=\"${HUB[1] + 34}\" text-anchor=\"middle\" font-size=\"12\" font-weight=\"600\" fill=\"{{ink}}\" opacity=\"0\">{{label}}</text>${[0, 1, 2]\n .map((i) => `<circle id=\"pkt${i}\" r=\"2.5\" fill=\"{{link}}\" filter=\"url(#glow)\" opacity=\"0\"/>`)\n .join(\"\")}<circle id=\"comet\" r=\"5\" fill=\"#FFFFFF\" stroke=\"{{path}}\" stroke-width=\"2\" filter=\"url(#glow)\" opacity=\"0\"/></svg>`,\n animate: [\n ...LINKS.map((l, i): SvgAnimation => ({ id: `l${i}`, draw: true, delay: l.column * COLUMN_MS, ms: 500, ease: \"out\" })),\n ...Object.keys(NODES).map((id): SvgAnimation => ({ id: `n${id}`, attrs: { opacity: [0, 1] }, delay: Math.max(0, NODE_COLUMN[id]! * COLUMN_MS - 120), ms: 250 })),\n { id: \"hub\", attrs: { opacity: [0, 1] }, delay: 2 * COLUMN_MS - 120, ms: 300 },\n { id: \"caption\", attrs: { opacity: [0, 1], y: [HUB[1] + 40, HUB[1] + 34] }, delay: 2 * COLUMN_MS, ms: 400, ease: \"out\" },\n // Data packets drift along a few links while the path waits.\n ...[3, 5, 8].map((link, i): SvgAnimation[] => [\n { id: `pkt${i}`, attrs: { opacity: [0, 1] }, delay: 1000 + i * 150, ms: 150 },\n { id: `pkt${i}`, along: `l${link}`, delay: 1000 + i * 150, ms: 1100, ease: \"in-out\" },\n { id: `pkt${i}`, attrs: { opacity: [1, 0] }, delay: 2000 + i * 150, ms: 200 },\n ]).flat(),\n { id: \"crit\", draw: true, delay: PATH_START, ms: PATH_MS, ease: \"in-out\" },\n { id: \"comet\", attrs: { opacity: [0, 1] }, delay: PATH_START, ms: 150 },\n { id: \"comet\", along: \"crit\", delay: PATH_START, ms: PATH_MS, ease: \"in-out\" },\n { id: \"comet\", attrs: { opacity: [1, 0] }, delay: PATH_START + PATH_MS, ms: 300 },\n // Rings pulse out from the hub as the comet passes it, halfway along.\n ...[0, 1].map((i): SvgAnimation => ({\n id: `ring${i}`,\n attrs: { r: [10, 52], opacity: [0.9, 0], \"stroke-width\": [3, 0.5] },\n delay: PATH_START + PATH_MS / 2 + i * 350,\n ms: 1200,\n ease: \"out\",\n })),\n ],\n },\n};\n\n/** Drip text's word: its baseline, and its cap height (a heavy sans's, about 0.72 of its 104 size). */\nconst DRIP_BASELINE = 120;\nconst DRIP_CAP = 75;\n/** Drip text's drips: where each leaves the word, as a fraction of its width, and how it runs. */\nconst DRIP_TOP = 106;\nconst DRIPS = [\n { at: 0.067, width: 11, length: 34, delay: 0, ms: 1500 },\n { at: 0.18, width: 8, length: 18, delay: 260, ms: 1100 },\n { at: 0.3, width: 13, length: 50, delay: 120, ms: 1800 },\n { at: 0.453, width: 9, length: 22, delay: 380, ms: 1200 },\n { at: 0.587, width: 10, length: 28, delay: 200, ms: 1400 },\n { at: 0.693, width: 12, length: 42, delay: 60, ms: 1700 },\n { at: 0.793, width: 11, length: 32, delay: 300, ms: 1500 },\n];\n\n/**\n * Drip text. With `inline` on, the picture frames the word from cap height to\n * baseline and lets the rest spill out, so in a heading it sits on the\n * baseline without adding leading: give its container `display: inline-block;\n * height: 0.72em` and the viewBox's aspect ratio (its width over 75). A\n * `font` of `inherit` takes the surrounding text's.\n */\nexport const dripText: VectorEffect = {\n kind: \"vector\",\n id: \"drip-text\",\n name: \"Drip text\",\n description: \"A chunky outlined title popping in, then oozing slime drips from its letters; Inline sets it in a line of text.\",\n category: \"text\",\n tags: [\"title\", \"text\", \"drip\", \"slime\", \"y2k\", \"headline\"],\n hold: 1200,\n presets: [\n { name: \"Slime\", values: { fill: [0.55, 0.93, 0.25], outline: [0.06, 0.2, 0.04], shine: [0.85, 1, 0.7] } },\n { name: \"Molten gold\", values: { fill: [1, 0.78, 0.2], outline: [0.35, 0.16, 0], shine: [1, 0.96, 0.75], drip: 1.5 } },\n ],\n // The word is stretched to a width set by its length (textLength), so the drips land under its letters in any font.\n derived: (v) => {\n const letters = Math.max(1, Array.from(String(v.word).trim()).length);\n const width = Math.min(380, letters * 75);\n const left = 200 - width / 2;\n return {\n width,\n // Inline, the picture frames just the word's capitals, from cap height to baseline, so it sits on\n // the line like a letter would; the pop, outline and drips spill out over the text around it.\n viewBox: v.inline ? `${left} ${DRIP_BASELINE - DRIP_CAP} ${width} ${DRIP_CAP}` : \"0 0 400 200\",\n overflow: v.inline ? \"visible\" : \"hidden\",\n ...Object.fromEntries(\n DRIPS.flatMap((d, i) => {\n const x = Math.round((left + d.at * width) * 10) / 10;\n const length = Math.round(d.length * Number(v.drip) * 10) / 10;\n return [\n [`x${i}`, x],\n [`left${i}`, x - d.width / 2],\n [`shine${i}`, x - d.width * 0.25],\n [`len${i}`, length],\n [`tip${i}`, DRIP_TOP + length],\n ];\n }),\n ),\n };\n },\n motion: (() => {\n const word = `<text x=\"200\" y=\"${DRIP_BASELINE}\" text-anchor=\"middle\" textLength=\"{{width}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"104\" font-weight=\"{{weight}}\" stroke-linejoin=\"round\"`;\n const drips = (layer: \"o\" | \"f\", paint: string) =>\n DRIPS.map(\n (d, i) =>\n `<rect id=\"${layer}r${i}\" x=\"{{left${i}}}\" y=\"${DRIP_TOP}\" width=\"${d.width}\" height=\"0\" rx=\"${d.width / 2}\" ${paint}/><circle id=\"${layer}c${i}\" cx=\"{{x${i}}}\" cy=\"${DRIP_TOP}\" r=\"${d.width * 0.72}\" ${paint}/>`,\n ).join(\"\");\n const outline = `fill=\"{{outline}}\" stroke=\"{{outline}}\" stroke-width=\"{{stroke}}\"`;\n const pop = (from: number, to: number) =>\n [`translate(200 100) scale(${from}) translate(-200 -100)`, `translate(200 100) scale(${to}) translate(-200 -100)`] as [string, string];\n return {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\"><!-- {{word: text default=SLOP label='Word'}} {{font: text default='Arial Black, Impact, system-ui, sans-serif' label='Font'}} {{weight: int min=100 max=900 default=900 step=100 label='Weight'}} {{fill: color default=#FF7EB6 label='Fill'}} {{outline: color default=#3A0A2C label='Outline'}} {{shine: color default=#FFD1E6 label='Shine'}} {{drip: float min=0.2 max=2 default=1 label='Drip length'}} {{stroke: float min=0 max=14 default=7 step=0.5 label='Outline width'}} {{inline: bool default=false label='Inline'}} --><g id=\"word\" transform=\"${pop(0.6, 1)[0]}\" opacity=\"0\">${drips(\"o\", outline)}${word} fill=\"none\" stroke=\"{{outline}}\" stroke-width=\"{{stroke}}\">{{word}}</text>${drips(\"f\", `fill=\"{{fill}}\"`)}${word} fill=\"{{fill}}\">{{word}}</text>${DRIPS.map(\n (d, i) => `<circle id=\"s${i}\" cx=\"{{shine${i}}}\" cy=\"${DRIP_TOP}\" r=\"${d.width * 0.2}\" fill=\"{{shine}}\" opacity=\"0\"/>`,\n ).join(\"\")}</g></svg>`,\n animate: [\n { id: \"word\", attrs: { transform: pop(0.6, 1.08), opacity: [0, 1] }, ms: 260, ease: \"out\" },\n { id: \"word\", attrs: { transform: pop(1.08, 1) }, delay: 260, ms: 200, ease: \"in-out\" },\n ...DRIPS.flatMap((d, i): SvgAnimation[] => {\n const at = { delay: 400 + d.delay, ms: d.ms, ease: \"in-out\" as const };\n const tip = `{{tip${i}}}` as unknown as number;\n return [\n ...([\"o\", \"f\"] as const).flatMap((layer): SvgAnimation[] => [\n { id: `${layer}r${i}`, attrs: { height: [0, `{{len${i}}}` as unknown as number] }, ...at },\n { id: `${layer}c${i}`, attrs: { cy: [DRIP_TOP, tip] }, ...at },\n ]),\n { id: `s${i}`, attrs: { cy: [DRIP_TOP, tip], opacity: [0, 0.9] }, ...at },\n ];\n }),\n ],\n };\n })(),\n};\n\n/** Viewfinder's timecode runs this many seconds (at 25 fps) before it loops back to zero. */\nconst VIEWFINDER_SECONDS = 10;\n\nexport const viewfinder: VectorEffect = {\n kind: \"vector\",\n id: \"viewfinder\",\n name: \"Viewfinder\",\n description: \"A camera viewfinder over the picture: corner brackets, a blinking REC light and a running timecode.\",\n category: \"overlay\",\n tags: [\"overlay\", \"camera\", \"recording\", \"vlog\", \"frame\"],\n hold: 0,\n presets: [\n { name: \"Night vision\", values: { color: [0.45, 1, 0.45], rec: [0.45, 1, 0.45] } },\n { name: \"Live\", values: { label: \"LIVE\", timecode: false } },\n ],\n derived: (v) => ({ timecodeOpacity: v.timecode ? 1 : 0 }),\n motion: {\n svg: `<svg viewBox=\"0 0 320 180\" font-family=\"ui-monospace, Menlo, Consolas, monospace\"><!-- {{color: color default=#FFFFFF label='Frame'}} {{rec: color default=#EF4444 label='Record light'}} {{timecode: bool default=true label='Timecode'}} --><g fill=\"none\" stroke=\"{{color}}\" stroke-width=\"2.5\" stroke-linecap=\"square\"><path d=\"M16 42 V16 H42\"/><path d=\"M278 16 H304 V42\"/><path d=\"M304 138 V164 H278\"/><path d=\"M42 164 H16 V138\"/><path d=\"M154 90 H166 M160 84 V96\" stroke-width=\"1.5\" opacity=\"0.8\"/></g><circle id=\"dot\" cx=\"34\" cy=\"33\" r=\"4.5\" fill=\"{{rec}}\"/><text x=\"44\" y=\"37.5\" font-size=\"12\" font-weight=\"700\" fill=\"{{color}}\">{{label: text default=REC label='Label'}}</text><text x=\"296\" y=\"37.5\" text-anchor=\"end\" font-size=\"12\" fill=\"{{color}}\" opacity=\"{{timecodeOpacity}}\">00:00:<tspan id=\"sec\">00</tspan>:<tspan id=\"ff\">00</tspan></text></svg>`,\n animate: Array.from({ length: VIEWFINDER_SECONDS }, (_, s): SvgAnimation[] => [\n { id: \"sec\", count: [s, s], format: s < 10 ? \"0{n}\" : \"{n}\", delay: s * 1000, ms: 1 },\n // Frames 00–24: the single digits padded with a zero, then the rest.\n { id: \"ff\", count: [0, 9.49], format: \"0{n}\", delay: s * 1000, ms: 400, ease: \"linear\" },\n { id: \"ff\", count: [10, 24.49], format: \"{n}\", delay: s * 1000 + 400, ms: 600, ease: \"linear\" },\n { id: \"dot\", attrs: { opacity: [0, 1] }, delay: s * 1000, ms: 1 },\n { id: \"dot\", attrs: { opacity: [1, 0] }, delay: s * 1000 + 600, ms: 1 },\n ]).flat(),\n },\n};\n\nexport const vectorEffects: VectorEffect[] = [\n spinner,\n bouncingDots,\n pulsePing,\n equalizer,\n progressRing,\n barChart,\n lineChart,\n statCounter,\n route,\n timelineTrack,\n successCheck,\n errorCross,\n heartbeat,\n signature,\n confetti,\n blobMorph,\n dripText,\n flowNetwork,\n viewfinder,\n];\n","/**\n * The effect catalog: ready-made shader and vector effects, each with\n * controls and presets, to drop into a product or start an edit from.\n *\n * - Browsing: `EFFECTS`, `getEffect`, `findEffects`, `EFFECT_CATEGORIES`.\n * - Controls: `effectControls`, `effectDefaults`.\n * - Vector effects: their pictures declare their controls (`vectorControls`),\n * and `renderVectorEffect` fills them in.\n *\n * @packageDocumentation\n */\n\nimport { controlValue, parseControls, type ControlDef, type ControlValue } from \"../shader/controls.js\";\nimport { aurora, conicSweep, duotoneFlow, meshGradient, silk } from \"./shaders/gradients.js\";\nimport {\n crt,\n filmGrain,\n imageDuotone,\n imageGlitch,\n imageHalftone,\n imagePixelate,\n imageRipple,\n transitions,\n} from \"./shaders/image.js\";\nimport { blackHole, bokeh, godRays, lightRibbons, nebula, neonRipple, sparkles, starfield } from \"./shaders/light.js\";\nimport { caustics, flames, lavaLamp, marble, plasma, smoke } from \"./shaders/organic.js\";\nimport { barberStripes, dotWave, hexPulse, kaleidoscope, moire, neonCircuit, truchet, voronoi } from \"./shaders/patterns.js\";\nimport { interactionEffects } from \"./interaction.js\";\nimport { electricEffects } from \"./electric.js\";\nimport { meltEffects } from \"./melt.js\";\nimport { pixelEffects } from \"./pixel.js\";\nimport { pyroEffects } from \"./pyro.js\";\nimport { timewarpEffects } from \"./timewarp.js\";\nimport { morphEffects } from \"./morph.js\";\nimport { interactionShaders } from \"./shaders/interaction.js\";\nimport { electricShaders } from \"./shaders/electric.js\";\nimport { meltShaders } from \"./shaders/melt.js\";\nimport { pixelShaders } from \"./shaders/pixel.js\";\nimport { pyroShaders } from \"./shaders/pyro.js\";\nimport { timewarpShaders } from \"./shaders/timewarp.js\";\nimport { morphShaders } from \"./shaders/morph.js\";\nimport { overlayEffects } from \"./shaders/overlay.js\";\nimport { digitalRain, pixelSunset, synthwaveGrid, tvStatic } from \"./shaders/retro.js\";\nimport { textShaders } from \"./shaders/text.js\";\nimport { imageTreatments } from \"./shaders/treatments.js\";\nimport { textEffects } from \"./text.js\";\nimport { EFFECT_CATEGORIES, vectorEffectControls, type EffectCategory, type EffectDefinition, type ShaderEffect } from \"./types.js\";\nimport { vectorEffects } from \"./vector.js\";\n\nexport {\n colorControl,\n EFFECT_CATEGORIES,\n numberControl,\n renderVectorEffect,\n VECTOR_CONTROL_TYPES,\n vectorControlDef,\n vectorControlIssues,\n vectorControls,\n vectorEffectControls,\n type EffectCategory,\n type EffectDefinition,\n type EffectPreset,\n type ShaderEffect,\n type VectorControl,\n type VectorEffect,\n} from \"./types.js\";\nexport { SAMPLE_IMAGES, svgDataUrl, textImage } from \"./images.js\";\nexport { FBM, glsl, HASH, NOISE, OKLAB_MIX, PALETTE, ROTATE } from \"./glsl.js\";\n\n/** The catalog's shader effects. */\nexport const SHADER_EFFECTS: readonly ShaderEffect[] = [\n meshGradient,\n aurora,\n duotoneFlow,\n conicSweep,\n silk,\n marble,\n smoke,\n lavaLamp,\n plasma,\n caustics,\n flames,\n dotWave,\n truchet,\n hexPulse,\n voronoi,\n moire,\n kaleidoscope,\n barberStripes,\n neonCircuit,\n bokeh,\n godRays,\n sparkles,\n neonRipple,\n lightRibbons,\n starfield,\n nebula,\n blackHole,\n synthwaveGrid,\n digitalRain,\n pixelSunset,\n tvStatic,\n imageRipple,\n imageGlitch,\n imageDuotone,\n imageHalftone,\n imagePixelate,\n ...imageTreatments,\n crt,\n filmGrain,\n ...overlayEffects,\n ...textShaders,\n ...morphShaders,\n ...interactionShaders,\n ...pyroShaders,\n ...timewarpShaders,\n ...meltShaders,\n ...electricShaders,\n ...pixelShaders,\n ...transitions,\n];\n\n/** Every effect in the catalog, shaders first, grouped by category. */\nexport const EFFECTS: readonly EffectDefinition[] = [...SHADER_EFFECTS, ...vectorEffects, ...textEffects, ...morphEffects, ...interactionEffects, ...pyroEffects, ...timewarpEffects, ...meltEffects, ...electricEffects, ...pixelEffects].sort(\n (a, b) => EFFECT_CATEGORIES.indexOf(a.category) - EFFECT_CATEGORIES.indexOf(b.category),\n);\n\nconst byId = new Map(EFFECTS.map((e) => [e.id, e]));\n\n/** The effect with this id, or undefined. */\nexport function getEffect(id: string): EffectDefinition | undefined {\n return byId.get(id);\n}\n\nexport interface EffectQuery {\n /** Words to look for in the name, description, tags and id (all must match). */\n text?: string;\n category?: EffectCategory;\n kind?: EffectDefinition[\"kind\"];\n /** Effects with every one of these tags. */\n tags?: readonly string[];\n}\n\n/** Effects matching a query, in catalog order. */\nexport function findEffects(query: EffectQuery = {}): EffectDefinition[] {\n const words = (query.text ?? \"\").toLowerCase().split(/\\s+/).filter(Boolean);\n return EFFECTS.filter((e) => {\n if (query.category && e.category !== query.category) return false;\n if (query.kind && e.kind !== query.kind) return false;\n if (query.tags && !query.tags.every((t) => e.tags.includes(t))) return false;\n const haystack = [e.id, e.name, e.description, e.category, ...e.tags].join(\" \").toLowerCase();\n return words.every((w) => haystack.includes(w));\n });\n}\n\n/** An effect's controls: a shader's `@control` uniforms, or a vector effect's declared controls. */\nexport function effectControls(effect: EffectDefinition): ControlDef[] {\n return effect.kind === \"shader\" ? parseControls(effect.source) : vectorEffectControls(effect);\n}\n\n/** An effect's values: each control's default, overridden by `values` (and a preset by name, when given). */\nexport function effectDefaults(\n effect: EffectDefinition,\n options: { preset?: string; values?: Record<string, ControlValue> } = {},\n): Record<string, ControlValue> {\n const preset = options.preset ? effect.presets?.find((p) => p.name === options.preset)?.values : undefined;\n const merged = { ...preset, ...options.values };\n return Object.fromEntries(effectControls(effect).map((c) => [c.name, controlValue(c, merged)]));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAOO,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAUjB,KAAK;AAGD,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAUlB,KAAK;AAGD,IAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAYhB,KAAK;AAGD,IAAM,UAAU;AAAA;AAAA;AAAA,GAGpB,KAAK;AAGD,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAetB,KAAK;AAGD,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,GAKnB,KAAK;AAGD,SAAS,QAAQ,OAAyB;AAC/C,SAAO,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI;AACnD;;;AC/EO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,QAAQ,OAAO;AAAA,EAC5C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACrF,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,KAAK,GAAG,EAAE,EAAE;AAAA,IACvG,EAAE,MAAM,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,KAAK,CAAC,GAAG,QAAQ,CAAC,KAAK,KAAK,CAAC,EAAE,EAAE;AAAA,EACpG;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,SAAS,MAAM;AAAA,EAC5C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IACtI,EAAE,MAAM,UAAU,QAAQ,EAAE,SAAS,CAAC,GAAK,KAAK,GAAG,GAAG,SAAS,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE;AAAA,IACvI,EAAE,MAAM,QAAQ,QAAQ,EAAE,SAAS,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,EAAE,EAAE;AAAA,EACzI;AACF;AAEO,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,aAAa,OAAO;AAAA,EACzC,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF;AACF;AAEO,IAAM,OAAqB;AAAA,EAChC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,UAAU,MAAM;AAAA,EACrC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE;AAAA,IACnF,EAAE,MAAM,YAAY,QAAQ,EAAE,OAAO,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,MAAM,CAAC,EAAE,EAAE;AAAA,EACnF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,QAAQ;AAAA,EACtC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF;AACF;;;AC9LO,SAAS,WAAW,KAAqB;AAC9C,QAAM,SACJ,OAAO,SAAS,aAAa,KAAK,GAAG,IAAK,WAAiF,OAAQ,KAAK,GAAG,EAAE,SAAS,QAAQ;AAChK,SAAO,6BAA6B,MAAM;AAC5C;AAEA,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASlB,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAOb,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWjB,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYnB,IAAM,OAAO;AAAA;AAAA;AAAA;AAKb,IAAM,QAAQ;AAAA;AAAA;AAQd,IAAM,OAAO;AAGN,IAAM,gBAAgB;AAAA,EAC3B,WAAW,WAAW,SAAS;AAAA,EAC/B,MAAM,WAAW,IAAI;AAAA,EACrB,UAAU,WAAW,QAAQ;AAAA;AAAA,EAE7B,WAAW,WAAW,UAAU;AAAA;AAAA,EAEhC,MAAM,WAAW,IAAI;AAAA;AAAA,EAErB,OAAO,WAAW,KAAK;AAAA,EACvB,MAAM,WAAW,IAAI;AACvB;AAGA,SAAS,UAAU,GAAmB;AACpC,MAAI,iBAAiB,KAAK,CAAC,EAAG,QAAO;AACrC,MAAI,iBAAiB,KAAK,CAAC,EAAG,QAAO;AACrC,MAAI,SAAS,KAAK,CAAC,EAAG,QAAO;AAC7B,MAAI,OAAO,KAAK,CAAC,EAAG,QAAO;AAC3B,MAAI,UAAU,KAAK,CAAC,EAAG,QAAO;AAC9B,MAAI,QAAQ,KAAK,CAAC,EAAG,QAAO;AAC5B,MAAI,QAAQ,KAAK,CAAC,EAAG,QAAO;AAE5B,SAAO,kDAAkD,KAAK,CAAC,IAAI,IAAI;AACzE;AAGO,SAAS,YAAY,MAAsB;AAChD,SAAO,MAAM,KAAK,IAAI,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,UAAU,CAAC,GAAG,CAAC;AAClE;AAEA,IAAM,YAAY,CAAC,SACjB,KAAK,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,QAAQ,EAAE,QAAQ,MAAM,OAAO;AAsBhH,SAAS,UAAU,MAAc,UAA4B,CAAC,GAAW;AAC9E,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,MAAM,KAAK,IAAI,KAAK,YAAY,IAAI,CAAC;AAC3C,QAAM,OAAO,QAAQ,QAAQ,KAAK,IAAI,SAAS,MAAO,QAAQ,MAAO,GAAG;AACxE,QAAM,SAAS,KAAK,IAAI,QAAQ,MAAM,MAAM,IAAI;AAChD,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,MAAM,wDAAwD,KAAK,IAAI,MAAM,YAAY,KAAK,aAAa,MAAM,cAAc,QAAQ,CAAC,QAAQ,SAAS,CAAC,kDAAkD,CAAC,OAAO,QAAQ,CAAC,CAAC,kDAAkD,UAAU,IAAI,CAAC,kBAAkB,UAAU,OAAO,QAAQ,UAAU,GAAG,CAAC,CAAC,gBAAgB,CAAC,KAAK,QAAQ,CAAC,CAAC,iBAAiB,UAAU,IAAI,CAAC;AAE/Z,SAAO,oCAAoC,mBAAmB,GAAG,EAAE,QAAQ,YAAY,CAAC,MAAM,IAAI,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC;AACjJ;;;ACxHO,IAAM,oBAAoB;AAAA;AAAA,6FAE4D,KAAK;AAM3F,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAOrB,KAAK;AASD,IAAM,UAAU;AAAA,EACrB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAgBP,KAAK;AAED,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,eAAe,YAAY;AAAA,EACpD,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA,EAIhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,UAAU,SAAS,YAAY;AAAA,EAC/C,QAAQ;AAAA,IACN;AAAA,0EACsE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA,EAI/F,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,aAAa,QAAQ;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA,0EACsE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/F,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,WAAW,QAAQ,EAAE,SAAS,CAAC,MAAM,KAAK,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IAC1F,EAAE,MAAM,aAAa,QAAQ,EAAE,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EAC5F;AACF;AAEO,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,UAAU,cAAc,OAAO;AAAA,EAC/C,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA,EAIhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF;AACF;AAEO,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,SAAS,SAAS;AAAA,EAC3C,QAAQ;AAAA,IACN;AAAA,0EACsE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/F,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF;AACF;AAEO,IAAM,MAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,UAAU,QAAQ;AAAA,EAC3C,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,aAAa,SAAS,SAAS;AAAA,EAC/C,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeF;AACF;AAEA,IAAM,cAAyF;AAAA,EAC7F,EAAE,MAAM,cAAc,IAAI,QAAQ,MAAM,QAAQ,aAAa,gDAAgD;AAAA,EAC7G,EAAE,MAAM,cAAc,IAAI,QAAQ,MAAM,QAAQ,aAAa,wDAAwD;AAAA,EACrH,EAAE,MAAM,iBAAiB,IAAI,kBAAkB,MAAM,kBAAkB,aAAa,6CAA6C;AAAA,EACjI,EAAE,MAAM,YAAY,IAAI,aAAa,MAAM,aAAa,aAAa,wDAAwD;AAAA,EAC7H,EAAE,MAAM,aAAa,IAAI,cAAc,MAAM,cAAc,aAAa,2CAA2C;AAAA,EACnH,EAAE,MAAM,WAAW,IAAI,WAAW,MAAM,WAAW,aAAa,+CAA+C;AAAA,EAC/G,EAAE,MAAM,aAAa,IAAI,cAAc,MAAM,cAAc,aAAa,2DAA2D;AAAA,EACnI,EAAE,MAAM,aAAa,IAAI,cAAc,MAAM,cAAc,aAAa,kDAAkD;AAC5H;AAGO,IAAM,cAA8B,YAAY,IAAI,CAAC,EAAE,MAAM,IAAI,MAAM,YAAY,OAAO;AAAA,EAC/F,MAAM;AAAA,EACN,IAAI,cAAc,EAAE;AAAA,EACpB;AAAA,EACA,aAAa,GAAG,WAAW;AAAA,EAC3B,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,WAAW;AAAA,EACzC,MAAM;AAAA,EACN,QAAQ;AAAA,IACN,MAAM,IAAI;AAAA,0EAC4D,cAAc,SAAS;AAAA,0EACvB,cAAc,IAAI;AAAA;AAAA;AAAA,EAG1F,iBAAiB;AAAA,IACf;AAAA,IACA,kBAAkB,IAAI;AAAA,IACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKF;AACF,EAAE;;;AC/TK,IAAM,QAAsB;AAAA,EACjC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,WAAW,UAAU,OAAO;AAAA,EACjD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBF;AACF;AAEO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,YAAY,WAAW;AAAA,EACpD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,eAAe,SAAS;AAAA,EACnD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBF;AACF;AAEO,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,QAAQ,SAAS,OAAO;AAAA,EAC9C,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,SAAS,QAAQ;AAAA,EAC/C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBF;AACF;AAEO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,UAAU,MAAM;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,YAAY,UAAU,MAAM;AAAA,EAC5C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,QAAQ,cAAc,MAAM;AAAA,EACzD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,aAAa,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,KAAK,GAAG,GAAG,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,QAAQ,GAAG,SAAS,IAAI,EAAE;AAAA,IACnK,EAAE,MAAM,UAAU,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,OAAO,MAAM,OAAO,IAAI,EAAE;AAAA,EAChI;AACF;;;ACtTO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,OAAO,UAAU,QAAQ;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,GAAG,EAAE,EAAE;AAAA,IAC5G,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAChH;AACF;AAEO,IAAM,QAAsB;AAAA,EACjC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,cAAc,SAAS,MAAM;AAAA,EAClD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,WAAW,SAAS,OAAO;AAAA,EAChD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBF;AACF;AAEO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,eAAe,MAAM;AAAA,EACnD,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,UAAU,MAAM;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AACF;AAEO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,UAAU,OAAO,SAAS;AAAA,EACzC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IAChG,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EACvG;AACF;;;AChNO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,YAAY,QAAQ,SAAS;AAAA,EAClD,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF;AACF;AAEO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,aAAa,MAAM;AAAA,EAChD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,aAAa,QAAQ;AAAA,EAClD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBF;AACF;AAEO,IAAM,QAAsB;AAAA,EACjC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,UAAU,YAAY,SAAS;AAAA,EACpD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF;AACF;AAEO,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,UAAU,WAAW,MAAM;AAAA,EAC9C,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF;AACF;AAEO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,WAAW,SAAS,SAAS;AAAA,EAClD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,SAAS,UAAU;AAAA,EACzC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,WAAW,QAAQ,OAAO,WAAW;AAAA,EAClE,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAcA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmFF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,aAAa,CAAC,GAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,EAAE,EAAE;AAAA,IACxK,EAAE,MAAM,aAAa,QAAQ,EAAE,aAAa,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,GAAG,OAAO,KAAK,SAAS,IAAI,EAAE;AAAA,IAC7L,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,IAAI,UAAU,GAAG,QAAQ,MAAM,SAAS,IAAI,EAAE;AAAA,EACnF;AACF;;;ACrUA,IAAM,KAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAC/C,IAAM,KAAK,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAGhD,IAAM,IAAI,CAAC,SAAiB,KAAK,IAAI;AAGrC,IAAM,SAAS,CAAC,GAAY,GAAY,MAAc;AACpD,QAAM,IAAK,MAAM,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC;AAC1C,QAAM,IAAK,MAAM,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC;AAC1C,SAAO,SAAS,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,KAAM,EAAE,CAAC,IAAK,EAAE,CAAC,KAAM,CAAC,CAAC;AACnE;AAGA,SAAS,IAAI,MAAe,OAAe,KAAa;AACtD,QAAM,IAAI,KAAK,IAAI,KAAK,YAAY,OAAO,IAAI,CAAC,CAAC;AACjD,QAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,CAAC;AACpC,SAAO,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,IAAI,EAAE;AAChD;AAGA,IAAM,QAAQ,CAAC,IAAY,IAAY,MAAc,aAAa,EAAE,IAAI,EAAE,WAAW,GAAG,CAAC,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,EAAE;AAGnH,IAAM,OAAO,CAAC,IAAY,MAAc,OAAwB,OAAe,OAAO,OAAqB;AAAA,EACzG;AAAA,EACA;AAAA,EACA,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,EAAE;AAAA,EAChC;AAAA,EACA,IAAI;AACN;AAEA,IAAM,OAAO;AAGb,IAAMA,SAAQ;AAGd,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,WAAW;AACjB,IAAM,UAAU;AAChB,IAAM,UAAU;AAEhB,IAAM,YAAY,CAAC,MAAc,aAAa,OAAO,IAAI,OAAO,WAAW,GAAG,MAAM,CAAC,CAAC;AAE/E,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,SAAS,UAAU,UAAU,mBAAmB;AAAA,EAC7F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,IACvI,EAAE,MAAM,UAAU,QAAQ,EAAE,OAAO,CAAC,KAAK,KAAK,CAAC,GAAG,QAAQ,CAAC,GAAG,KAAK,IAAI,GAAG,OAAO,KAAK,EAAE;AAAA,EAC1F;AAAA,EACA,SAAS,CAAC,OAAO,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,EAAE;AAAA,EAC9C,QAAQ;AAAA,IACN,KAAK,oiBAAoiB,OAAO,SAAS,OAAO,6DAA6D,MAAM;AAAA,MACjoB,EAAE,QAAQ,UAAU;AAAA,MACpB,CAAC,GAAG,MAAM;AACR,cAAM,KAAM,IAAI,MAAO,YAAY,OAAO,KAAK,KAAK;AACpD,eAAO,gBAAgB,CAAC,SAAS,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,iBAAiB,IAAI,IAAI,eAAe,WAAW;AAAA,MAC3K;AAAA,IACF,EAAE,KAAK,EAAE,CAAC,yBAAyB,UAAU,CAAC,CAAC,8BAA8BA,MAAK,2JAA2J,IAAI;AAAA,IACjP,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,GAAG,UAAU,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,IAAI,GAAG,UAAU,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MAChH,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAChH,EAAE,IAAI,cAAc,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,eAAe,WAAW,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA;AAAA,MAE1H,KAAK,QAAQ,gBAAgB,GAAG,CAAC;AAAA,MACjC,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACzG,KAAK,QAAQ,KAAK,IAAI,GAAG;AAAA,MACzB,GAAG,MAAM,KAAK,EAAE,QAAQ,UAAU,GAAG,CAAC,GAAG,MAAsB;AAC7D,cAAM,KAAM,IAAI,MAAO,YAAY,OAAO,KAAK,KAAK;AACpD,cAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC;AAChG,cAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU,WAAW,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,UAAU,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC;AAC5F,eAAO;AAAA,UACL,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC;AAAA,UACvB,EAAE,IAAI,IAAI,CAAC,IAAI,MAAM,GAAG,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,UAC7G,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,GAAG;AAAA,UAC3B,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,GAAG;AAAA,QAC7B;AAAA,MACF,CAAC,EAAE,KAAK;AAAA,MACR,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAErI,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,GAAG,UAAU,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAChH,EAAE,IAAI,cAAc,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,aAAa,aAAa,EAAE,GAAG,IAAI,IAAI;AAAA,MAC9G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC,aAAa,SAAS,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,IAC3H;AAAA,EACF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,UAAU,UAAU,YAAY,mBAAmB;AAAA,EACxF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,OAAO,QAAQ,EAAE,IAAI,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,IACjD,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE;AAAA,EAChI;AAAA,EACA,SAAS,MAAiB;AACxB,UAAM,QAAQ,CAAC,MAAc,IAAY,SAAiC;AAAA,MACxE,EAAE,IAAI,SAAS,MAAM,OAAO,EAAE,WAAW,CAAC,aAAa,IAAI,OAAO,aAAa,EAAE,KAAK,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAEnH,EAAE,IAAI,QAAQ,MAAM,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAClF,EAAE,IAAI,QAAQ,MAAM,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,IACnG;AACA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,SAAS;AAAA,QACP,GAAG,MAAM,GAAG,IAAI,CAAC;AAAA,QACjB,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,WAAW,QAAQ,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,QACxF,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,QACjB,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,UAAU,SAAS,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1F;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,YAAY,QAAQ,UAAU,QAAQ,mBAAmB;AAAA,EAC9F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IACtD,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACnK;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAM,GAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACpD;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,qaAAqa,MAAM,IAAI,IAAI,CAAC,CAAC,wYAAwY,IAAI;AAAA,IACt0B,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3G,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1H,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,cAAc,YAAY,EAAE,GAAG,IAAI,IAAI;AAAA;AAAA,MAEvG,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG;AAAA,MACtE,EAAE,IAAI,QAAQ,MAAM,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAEpE,EAAE,IAAI,QAAQ,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7D,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG;AAAA,MACtE,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,cAAc,YAAY,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MACnH,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI,MAAM,MAAM;AAAA,MACtH,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,IAC5H;AAAA,EACF;AACF;AASA,SAAS,QAAQ,GAAU,GAAU,OAAe,UAAU,OAAe;AAC3E,QAAM,IAAI,QAAQ;AAClB,QAAM,IAAI,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7C,QAAM,MAAe,CAAC;AACtB,QAAM,MAAM,CAAC,GAAU,SAAiB;AACtC,aAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,YAAM,IAAI,OAAQ,IAAI,KAAK,KAAM;AACjC,UAAI,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AAAA,IAC3D;AAAA,EACF;AACA,MAAI,QAAS,KAAI,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC;AAAA,MAC3K,KAAI,GAAG,IAAI,KAAK,KAAK,CAAC;AAC3B,MAAI,GAAG,IAAI,KAAK,KAAK,CAAC;AACtB,SAAO,IAAI,IAAI,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AACpE;AAEA,IAAM,aAAa,oBAAI,IAA8B;AAGrD,SAAS,UAAU,QAAkC;AACnD,MAAI,CAAC,WAAW,IAAI,MAAM,GAAG;AAC3B,UAAM,OAAO,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,GAAG;AAE9E,UAAM,QAAQ,SAAS,IAAI,QAAQ,KAAK;AACxC,UAAM,QAAQ;AAAA,MACZ,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,MAAM;AAAA,MACxC,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,MACzD,QAAQ,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,IAC3D,EAAE,KAAK,GAAG;AACV,eAAW,IAAI,QAAQ,WAAW,MAAM,OAAO,EAAE,QAAQ,GAAG,CAAC,CAAC;AAAA,EAChE;AACA,SAAO,WAAW,IAAI,MAAM;AAC9B;AAGA,IAAM,WAAW,CAAC,SAAiB,2BAA2B,IAAI;AAE3D,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,aAAa,SAAS,SAAS,cAAc,mBAAmB;AAAA,EAC7G,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,IAC1J,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,KAAK,KAAK,GAAG,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,EACxI;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,CAAC,MAAM,KAAK,IAAI,UAAU,KAAK,MAAM,OAAO,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC;AACpE,WAAO,EAAE,MAAM,MAAM;AAAA,EACvB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,6gBAA6gB,SAAS,CAAC,CAAC;AAAA,IAC7hB,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,YAAY,WAAW,GAAG,MAAM,CAAC,WAAW,eAAe,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7H,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MACnG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,YAAY,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAE5F,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,aAAa,UAAU,GAAG,MAAM,CAAC,iBAAiB,SAAS,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7H,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MACpG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,YAAY,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,IAC9F;AAAA,EACF;AACF;AAGA,IAAM,WAAW;AACjB,IAAM,SAAS,CAAC,MAAc,eAAe,CAAC;AAEvC,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,YAAY,QAAQ,UAAU,mBAAmB;AAAA,EACtF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IACpD,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,EAAE;AAAA,EAC5G;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,oXAAoX,OAAO,CAAC,CAAC,cAAc,QAAQ,oEAAoE,QAAQ;AAAA,IACpe,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3F,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1G,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACzG,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,SAAS;AAAA,MACvF,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,eAAe,UAAU,EAAE,GAAG,IAAI,IAAI;AAAA;AAAA,MAE/E,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1F,KAAK,SAAS,KAAK,IAAI,KAAK,CAAC;AAAA,MAC7B,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC1F,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACzG,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,YAAY,aAAa,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,IAC7F;AAAA,EACF;AACF;AAOA,IAAM,aAAa,CAAC,OAAe,SAAiC;AAAA,EAClE,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,kBAAkB,kBAAkB,EAAE,GAAG,OAAO,OAAO,IAAI,KAAK,MAAM,MAAM;AAAA,EAC1I,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,mBAAmB,gBAAgB,EAAE,GAAG,OAAO,QAAQ,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,EAC9I,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,kBAAkB,kBAAkB,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,EACxI,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,mBAAmB,gBAAgB,EAAE,GAAG,OAAO,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,EAC9I,KAAK,QAAQ,aAAa,mBAAmB,OAAO,GAAG;AACzD;AAGA,IAAM,aAAa,CAACC,KAAY,SAAiC;AAAA,EAC/D,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAOA,KAAI,IAAI,GAAG;AAAA,EACtE,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,MAAM,OAAOA,KAAI,IAAI,KAAK,MAAM,MAAM;AAAA,EACpE,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,EACzE,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,OAAO,KAAK,IAAI,EAAE;AACjE;AAGA,IAAM,eAAe,CAAC,GAAY,GAAY,MAAc,QAAgB;AAC1E,QAAM,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,KAAK,IAAI,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC;AACnE,QAAM,OAAO,KAAK,IAAI,KAAK,OAAO,KAAK,IAAI,GAAG,GAAG,CAAC;AAClD,SAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,OAAO,IAAI,GAAG,UAAU,GAAG,IAAI,CAAC,IAAK,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC,IAAK,IAAI,EAAE;AACjH;AAEA,IAAM,aAAa,CAAC,MAClB,uBAAuB,CAAC,oHAAoH,IAAI,8FAA8F,CAAC,gIAAgI,IAAI;AAGrX,IAAM,YAAY;AAClB,IAAM,WAAW,CAAC,MAAc,0BAA0B,GAAG,MAAM,CAAC,CAAC;AAE9D,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,aAAa,YAAY,UAAU,mBAAmB;AAAA,EACnG,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACpI,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,aAAa,UAAU,uBAAuB,QAAQ,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,EAC7G;AAAA,EACA,SAAS,CAAC,MAAM,aAAa,EAAE,OAAO,EAAE,UAAU,KAAK,EAAE;AAAA,EACzD,QAAQ;AAAA,IACN,KAAK,4fAA4f,SAAS,CAAC,CAAC,oPAAoP,SAAS,CAAC,CAAC,iKAAiK,WAAW,EAAE,CAAC;AAAA,IAC17B,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjH,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,aAAa,EAAE,GAAG,IAAI,IAAI;AAAA,MAC9E,GAAG,WAAW,KAAK,SAAS;AAAA,MAC5B,GAAG,WAAW,GAAG,SAAS;AAAA,MAC1B,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,GAAG,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,YAAY,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,MACxI,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,eAAe,YAAY,EAAE,GAAG,OAAO,WAAW,IAAI,IAAI;AAAA,IAClG;AAAA,EACF;AACF;AAGA,IAAM,YAAY;AAClB,IAAM,aAAa,CAAC,MAAc,SAAS,GAAG,CAAC,CAAC;AAEzC,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,UAAU,WAAW,UAAU,mBAAmB;AAAA,EAC/F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,OAAO,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IAChF,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,cAAc,UAAU,aAAa,QAAQ,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAC/H;AAAA,EACA,SAAS,CAAC,MAAM,aAAa,EAAE,OAAO,EAAE,UAAU,KAAK,EAAE;AAAA,EACzD,QAAQ;AAAA,IACN,KAAK,uvBAAuvB,WAAW,EAAE,CAAC,2EAA2E,WAAW,IAAI,CAAC;AAAA,IACr2B,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,WAAW,IAAI,GAAG,WAAW,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC7G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,UAAU,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7E,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,WAAW,IAAI,GAAG,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC3H,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MAC5E,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,aAAa,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MAC1F,GAAG,WAAW,KAAK,SAAS;AAAA,MAC5B,GAAG,WAAW,KAAK,SAAS;AAAA;AAAA,MAE5B,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,WAAW,IAAI,EAAE;AAAA,MAC7E,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,WAAW,CAAC,GAAG,WAAW,IAAI,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,YAAY,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACnJ,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,eAAe,YAAY,EAAE,GAAG,OAAO,WAAW,IAAI,IAAI;AAAA,IAClG;AAAA,EACF;AACF;AAGA,IAAM,CAAC,OAAO,IAAI,IAAI;AAAA,EACpB;AAAA,GACC,MAAM;AACL,UAAMC,UAAS,CAAC,MACd,IAAI,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,MAAM;AACvC,YAAM,IAAK,IAAI,KAAM,KAAK,KAAK,IAAI,KAAK,KAAK;AAC7C,aAAO,GAAG,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AAAA,IAChE,CAAC,EAAE,KAAK,IAAI,CAAC;AACf,WAAO,GAAGA,QAAO,GAAG,CAAC,IAAIA,QAAO,CAAC,CAAC;AAAA,EACpC,GAAG;AAAA,EACH,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,SAAS,GAAG,MAAM,GAAG;AAC3B,IAAM,gBAAgB;AACtB,IAAM,SAAS,CAAC,MAAc,gBAAgB,CAAC;AAExC,IAAM,iBAA+B;AAAA,EAC1C,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,YAAY,YAAY,SAAS,UAAU,mBAAmB;AAAA,EACnG,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,GAAG,UAAU,CAAC,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IACvL,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,UAAU,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACjH;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,8dAA8d,OAAO,EAAE,CAAC,yBAAyB,KAAK,iFAAiF,MAAM;AAAA,IAClmB,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC5F,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC3G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAEzH,EAAE,IAAI,OAAO,MAAM,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACtE,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,aAAa,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MAC3F,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,GAAG;AAAA,MACxE,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,MAAM,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAEtE,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,eAAe,IAAI,IAAI;AAAA,MAClF,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,eAAe,IAAI,IAAI;AAAA,MAChF,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,gBAAgB,KAAK,IAAI,EAAE;AAAA,MACxE,EAAE,IAAI,OAAO,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,gBAAgB,KAAK,IAAI,EAAE;AAAA,MACtE,KAAK,OAAO,WAAW,GAAG,gBAAgB,GAAG;AAAA,MAC7C,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,SAAS,EAAE,GAAG,OAAO,gBAAgB,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACzI,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,eAAe,YAAY,EAAE,GAAG,OAAO,eAAe,IAAI,IAAI;AAAA,IACtG;AAAA,EACF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,aAAa,cAAc,mBAAmB;AAAA,EAC3F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,MAAM,CAAC,EAAE,EAAE;AAAA,IAC1G,EAAE,MAAM,aAAa,QAAQ,EAAE,MAAM,oBAAoB,KAAK,CAAC,KAAK,KAAK,GAAG,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAC5G;AAAA;AAAA,EAEA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,MAAM,KAAK,EAAE;AAC5C,UAAM,QAAQ,SAAS,OAAO;AAC9B,UAAM,OAAO,MAAM,QAAQ;AAC3B,UAAM,OAAO,KAAK,OAAO;AACzB,UAAM,KAAK,OAAO,SAAS,OAAO;AAClC,UAAM,KAAK,OAAO,OAAO;AACzB,UAAM,IAAI,OAAO;AACjB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,MAAM,GAAG,IAAI;AAAA,MACb,MAAM,GAAG,IAAI;AAAA,MACb,OAAO,GAAG,OAAO,OAAO,GAAG;AAAA,MAC3B,OAAO,GAAG,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC;AAAA,MAClC,SAAS,aAAa,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,WAAW,GAAG,CAAC,CAAC;AAAA,MACtD,SAAS,aAAa,GAAG,KAAK,OAAO,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,WAAW,GAAG,CAAC,CAAC;AAAA,IACtE;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,saAAsa,IAAI;AAAA,IAC/a,SAAS;AAAA,MACP,EAAE,IAAI,QAAQ,OAAO,EAAE,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,IAAI,IAAI;AAAA,MACjE,EAAE,IAAI,SAAS,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACxE,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,eAAe,aAAa,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC1F,EAAE,IAAI,aAAa,OAAO,EAAE,QAAQ,CAAC,WAAW,WAAW,EAAE,GAAG,IAAI,IAAI;AAAA,IAC1E;AAAA,EACF;AACF;AAEO,IAAM,kBAAgC;AAAA,EAC3C,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,UAAU,QAAQ,OAAO,mBAAmB;AAAA,EACjF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IAChH,EAAE,MAAM,SAAS,QAAQ,EAAE,OAAO,eAAe,QAAQ,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EAC/E;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAM,GAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACpD;AAAA,EACA,SAAS,MAAiB;AAExB,UAAM,QAAQ,CAAC,MAAc,WAAW,CAAC,KAAK,IAAI,EAAE;AACpD,UAAM,QAAQ,CAAC,MAAc,OAAO,OAClC,wHAAwH,IAAI,uEAAuE,IAAI,IAAI,IAAI;AACjN,WAAO;AAAA,MACL,KAAK,qSAAqS,MAAM,EAAE,CAAC,0WAA0W,MAAM,YAAY,CAAC,GAAG,MAAM,eAAe,0BAA0B,CAAC;AAAA,MACnuB,SAAS;AAAA,QACP,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,QAC9E,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAAC,kBAAkB,iBAAiB,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjG;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAGA,IAAM,UAAU,CAAC,GAAW,OAAe,iBAAiB,MAAM,EAAE,WAAW,GAAG,CAAC,CAAC;AAE7E,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,WAAW,QAAQ,WAAW,mBAAmB;AAAA,EACtF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,KAAK,MAAM,GAAG,EAAE,EAAE;AAAA,IAClI,EAAE,MAAM,WAAW,QAAQ,EAAE,KAAK,wBAAwB,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,EACtI;AAAA;AAAA,EAEA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,KAAK,KAAK,EAAE;AAC3C,UAAM,IAAI,SAAS;AACnB,WAAO,EAAE,MAAM,QAAQ,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,MAAM,GAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACpF;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,ybAAyb,QAAQ,KAAK,CAAC,CAAC,4QAA4Q,IAAI,0GAA0G,MAAM,KAAK,KAAK,CAAC,CAAC,2HAA2H,IAAI;AAAA,IACx9B,SAAS;AAAA,MACP,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAAC,QAAQ,KAAK,CAAC,GAAG,QAAQ,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC9F,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAAC,QAAQ,MAAM,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC3G,EAAE,IAAI,OAAO,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,IAAI;AAAA,MACjD,EAAE,IAAI,SAAS,OAAO,EAAE,MAAM,CAAC,aAAa,YAAY,EAAE,GAAG,IAAI,IAAI;AAAA,MACrE,EAAE,IAAI,UAAU,OAAO,EAAE,WAAW,CAAC,MAAM,KAAK,KAAK,CAAC,GAAG,MAAM,KAAK,KAAK,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,IAC1G;AAAA,EACF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,UAAU,MAAM,WAAW,mBAAmB;AAAA,EACnF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,cAAc,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,IAC1F,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,WAAW,EAAE;AAAA,EACjG;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAM,GAAG,KAAK,OAAO,IAAI,GAAG,MAAM,OAAO,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,OAAO,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE;AAAA,EACrI;AAAA;AAAA,EAEA,QAAQ;AAAA,IACN,KAAK,wuBAAwuB,IAAI;AAAA,IACjvB,SAAS;AAAA,MACP,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,kBAAkB,mBAAmB,EAAE,GAAG,IAAI,IAAI,MAAM,MAAM;AAAA,MAClG,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,qBAAqB,gBAAgB,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,MAAM,MAAM;AAAA,MAC7G,EAAE,IAAI,UAAU,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,MAAM,MAAM;AAAA,MAC3G,EAAE,IAAI,YAAY,OAAO,EAAE,MAAM,CAAC,YAAY,aAAa,EAAE,GAAG,OAAO,IAAI,IAAI,GAAG;AAAA,IACpF;AAAA,EACF;AACF;AAGO,IAAM,qBAAqC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AC1lBA,IAAMC,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAG/C,IAAMC,SAAQ,CAAC,IAAY,IAAY,MAAc,aAAa,EAAE,IAAI,EAAE,WAAW,KAAK,MAAM,IAAI,GAAI,IAAI,GAAI,eAAe,CAAC,EAAE,IAAI,CAAC,EAAE;AAGzI,IAAMC,QAAO,CAAC,IAAY,MAAc,OAAwB,OAAe,UAAiC;AAAA,EAC9G;AAAA,EACA,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,KAAK;AAAA,EACrC,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,EAAE;AAAA,EAChC;AAAA,EACA,IAAI;AACN;AAEA,IAAMC,QAAO;AAGb,IAAM,OAAO;AAEN,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,QAAQ,aAAa,QAAQ,MAAM,QAAQ;AAAA,EAC9D,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,iBAAiB,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,IACvF,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACvG;AAAA,EACA,SAAS,MAAM;AAEb,UAAM,SAAS,CAAC,KAAK,IAAI,KAAK,GAAG,EAAE,IAAI,CAAC,KAAK,MAAM;AACjD,YAAM,IAAK,MAAM,KAAK,KAAM;AAC5B,YAAMC,MAAK,CAAC,MAAc,CAACJ,IAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,GAAGA,IAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AAC7E,aAAO,EAAE,IAAI,IAAI,CAAC,IAAI,MAAMI,IAAG,EAAE,GAAG,KAAKA,IAAG,EAAE,GAAG,IAAIA,IAAG,EAAE,EAAE;AAAA,IAC9D,CAAC;AACD,WAAO;AAAA,MACL,KAAK,keAAke,IAAI,yDAAyD,OACjiB,IAAI,CAAC,EAAE,IAAI,KAAK,MAAM,aAAa,EAAE,SAAS,KAAK,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,2EAA2E,EAChL,KAAK,EAAE,CAAC,0BAA0BH,OAAM,IAAI,IAAI,CAAC,CAAC,wBAAwB,IAAI,6DAA6D,IAAI;AAAA,MAClJ,SAAS;AAAA,QACP,EAAE,IAAI,WAAW,MAAM,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,QACrD,EAAE,IAAI,QAAQ,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA;AAAA,QAErE,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAACA,OAAM,IAAI,IAAI,CAAC,GAAGA,OAAM,IAAI,IAAI,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,QAC7G,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAACA,OAAM,IAAI,IAAI,IAAI,GAAGA,OAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,QAChH,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG;AAAA,QAC7D,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,QAC9EC,MAAK,SAAS,WAAW,GAAG,CAAC;AAAA,QAC7B,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,QACnH,GAAG,OAAO,QAAQ,CAAC,EAAE,IAAI,MAAM,KAAK,GAAG,GAAG,MAAsB;AAAA,UAC9D,EAAE,IAAI,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI,IAAI,GAAG;AAAA,UAC9D,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,UACzG,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,QACpK,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAGA,IAAM,YAAY;AAClB,IAAM,YAAY;AAEX,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,eAAe,MAAM,SAAS,SAAS,UAAU,UAAU,MAAM;AAAA,EACpF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,IAAI,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IACnD,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAC/H;AAAA,EACA,SAAS,MAAM;AACb,UAAM,SAAS,CAAC,IAAYG,YAC1B,aAAa,EAAE,WAAW,SAAS,yBAAyBA,OAAM,wDAAwD,EAAE,WAAW,SAAS,yBAAyBA,OAAM;AACjL,UAAM,QAAQ,CAAC,MAAc,UAAkC;AAAA,MAC7D,EAAE,IAAI,SAAS,MAAM,OAAO,EAAE,WAAW,CAACJ,OAAM,IAAI,IAAI,CAAC,GAAGA,OAAM,IAAI,IAAI,KAAK,CAAC,EAAE,GAAG,IAAI,IAAI,MAAM,MAAM;AAAA,MACzG,EAAE,IAAI,SAAS,MAAM,OAAO,EAAE,WAAW,CAACA,OAAM,IAAI,IAAI,KAAK,GAAGA,OAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,SAAS;AAAA,IAC1H;AACA,UAAM,UAAU,CAAC,MAAc,MAAc,IAAY,UACvD,CAAC,UAAU,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,IAAI,IAAI,EAAE;AAChG,WAAO;AAAA,MACL,KAAK,yoBAAyoBA,OAAM,IAAI,IAAI,CAAC,CAAC,uJAAuJ,OAAO,QAAQ,QAAQ,CAAC,OAAO,OAAO,OAAO,SAAS,CAAC;AAAA,MAC52B,SAAS;AAAA;AAAA,QAEP,GAAG,MAAM,GAAG,IAAI;AAAA,QAChB,GAAG,QAAQ,GAAG,WAAW,UAAU,EAAE;AAAA,QACrC,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,WAAW,QAAQ,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACpF,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACzE,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,QACtFC,MAAK,SAAS,WAAW,GAAG,GAAG,CAAC;AAAA,QAChC,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,QACnGA,MAAK,SAAS,KAAK,IAAI,KAAK,CAAC;AAAA;AAAA,QAE7B,GAAG,MAAM,GAAG,IAAI;AAAA,QAChB,GAAG,QAAQ,GAAG,UAAU,WAAW,EAAE;AAAA,QACrC,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,UAAU,SAAS,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACpF,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACzE,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,MACxF;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAGA,IAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,OAAO,EAAE,IAAI,OAAO,CAAC,IAAI,GAAGF,IAAG,KAAK,IAAI,IAAI,EAAE,EAAE;AAE5F,IAAM,WAAW,CAAC,MAAc,0BAA0B,KAAK,MAAM,OAAO,IAAI,GAAI,IAAI,GAAI;AAErF,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,WAAW,YAAY,UAAU,YAAY,MAAM,MAAM;AAAA,EAC5E,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACtG,EAAE,MAAM,aAAa,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EAC9D;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,4gBAA4gB,MAAM;AAAA,MACrhB,CAAC,EAAE,IAAI,EAAE,MAAM,aAAa,EAAE,QAAQ,CAAC;AAAA,IACzC,EAAE,KAAK,EAAE,CAAC,sBAAsB,IAAI,gBAAgB,SAAS,CAAC,CAAC,wQAAwQG,KAAI;AAAA,IAC3U,SAAS;AAAA,MACP,EAAE,IAAI,OAAO,OAAO,CAAC,GAAG,GAAG,GAAG,QAAQ,QAAQ,IAAI,KAAM,MAAM,SAAS;AAAA;AAAA,MAEvE,GAAG,MAAM,IAAI,CAAC,EAAE,GAAG,GAAG,OAAqB,EAAE,IAAI,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,QAAQ,IAAI,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE;AAAA;AAAA,MAElH,GAAG,CAAC,GAAG,KAAK,KAAM,IAAI,EAAE,QAAQ,CAAC,MAAsB;AAAA,QACrD,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,GAAG,OAAO,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,QACjG,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,GAAG,OAAO,IAAI,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5G,CAAC;AAAA;AAAA,MAED,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,MAAM,IAAI,GAAG;AAAA,MACjE,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,MAC/E,EAAE,IAAI,QAAQ,OAAO,EAAE,QAAQ,CAAC,aAAa,YAAY,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MACnF,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,CAAC,aAAa,YAAY,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MAChF,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,CAAC,WAAW,YAAY,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MAC9E,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,MACpG,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,IACzG;AAAA,EACF;AACF;AAGO,IAAM,kBAAkC,CAAC,SAAS,aAAa,aAAa;;;ACvJnF,IAAM,MAAM,KAAK,KAAK;AACtB,IAAMG,MAAK,CAAC,MAAc;AACxB,QAAM,IAAI,KAAK,MAAM,IAAI,GAAG,IAAI;AAChC,SAAO,OAAO,GAAG,GAAG,EAAE,IAAI,IAAI;AAChC;AAEA,IAAM,WAAW,CAAC,QAA0B,IAAI,IAAI,IAAI,CAAC,MAAM,GAAGA,IAAG,EAAE,CAAC,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAGpG,SAAS,IAAI,IAAY,IAAY,IAAY,IAAY,MAAc,IAAY,SAAgC,MAAM,GAAG,QAAQ,GAAY;AAClJ,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC;AAChE,SAAO,MAAM,KAAK,EAAE,QAAQ,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM;AACjD,UAAM,MAAM,QAAS,KAAK,QAAQ,IAAK;AACvC,UAAM,IAAI,OAAO,GAAG;AACpB,WAAO,CAAC,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,GAAG,GAAG,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,GAAG,CAAC;AAAA,EAC9E,CAAC;AACH;AAGA,SAAS,QAAQ,SAA2B,GAAoB;AAC9D,SAAO,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAC/B,UAAM,IAAI,SAAS,IAAI,QAAQ,SAAS,KAAK,QAAQ,MAAM;AAC3D,UAAM,IAAI,SAAS,IAAI,KAAK,QAAQ,MAAM;AAC1C,UAAM,UAAU,CAAC,MAAoB;AACnC,YAAM,IAAI,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7C,aAAO,CAAC,EAAE,CAAC,KAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAK,GAAG,EAAE,CAAC,KAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAK,CAAC;AAAA,IACxE;AACA,UAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;AAEtC,WAAO,CAAC,GAAG,MAAM,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,MAAa;AAAA,OAC9C,IAAI,MAAM,IAAI,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,OACzD,IAAI,MAAM,IAAI,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IAC5D,CAAC;AAAA,EACH,CAAC;AACH;AAKA,IAAM,OAAgB,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;AACxF,IAAM,QAAQ,CAAC,MAAc,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,MAAM,CAAC;AAEjG,IAAM,cAAc;AAAA,EAClB;AAAA,IACE,SAAS,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA,IAEzB,SAAS,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;AAAA;AAAA,IAE9G,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EAC5D;AAAA,EACA,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,UAAU;AAAA,EACd;AAAA,IACE,SAAS,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;AAAA,IACjE,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IAClD,SAAS,IAAI,IAAI,KAAK,IAAI,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EACrD;AAAA,EACA,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,WAAW;AAAA,EACf;AAAA,IACE,SAAS,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;AAAA,IACxD,SAAS,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;AAAA,IACxF,SAAS,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC;AAAA,EACzF;AAAA,EACA,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK;AACpC,IAAM,SAAS,EAAE,OAAO,MAAM,IAAI,KAAK;AACvC,IAAM,SAAS,EAAE,OAAO,MAAM,IAAI,KAAK;AAGvC,IAAM,SAAS,CAAC,IAAY,CAAC,MAAM,OAAO,MAAM,MAAgC;AAAA,EAC9E,EAAE,IAAI,OAAO,EAAE,GAAG,CAAC,MAAO,KAAM,EAAE,GAAG,GAAG,MAAM,MAAM,SAAS;AAAA,EAC7D,EAAE,IAAI,OAAO,EAAE,GAAG,CAAC,OAAQ,MAAO,EAAE,GAAG,GAAG,QAAQ,MAAM,MAAM;AAAA,EAC9D,EAAE,IAAI,OAAO,EAAE,GAAG,CAAC,QAAS,IAAK,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAClE;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,OAAO,SAAS,UAAU,SAAS,MAAM;AAAA,EACxD,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACvI,EAAE,MAAM,YAAY,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,MAAM,IAAI,EAAE,EAAE;AAAA,EACxI;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,2bAA2b,YAAY,CAAC,CAAC,yHAAyH,SAAS,CAAC,CAAC,0EAA0E,QAAQ,CAAC,CAAC;AAAA,IACtqB,SAAS;AAAA,MACP,GAAG,OAAO,QAAQ,WAAW;AAAA,MAC7B,GAAG,OAAO,OAAO,OAAO;AAAA,MACxB,GAAG,OAAO,QAAQ,QAAQ;AAAA,MAC1B,EAAE,IAAI,QAAQ,OAAO,EAAE,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,OAAO,MAAM,IAAI,MAAM,MAAM,SAAS;AAAA,MAC/F,EAAE,IAAI,QAAQ,OAAO,EAAE,MAAM,CAAC,aAAa,SAAS,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACnF,EAAE,IAAI,OAAO,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACxE,EAAE,IAAI,OAAO,OAAO,EAAE,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACxE,EAAE,IAAI,UAAU,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACnF,EAAE,IAAI,UAAU,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MACpF,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5F,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7F,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,MAAM,GAAG,EAAE,GAAG,OAAO,KAAK,IAAI,KAAM,MAAM,SAAS;AAAA,MAC/G,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACpG,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,IAAI,KAAM,MAAM,SAAS;AAAA,MAC5F,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5E,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5F,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAE5E,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,GAAG,OAAO;AAAA,MACpD,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,GAAG,OAAO;AAAA,IACtD;AAAA,EACF;AACF;AAIA,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,QAAQ;AACd,IAAM,UAAU;AAGhB,IAAM,QAAQ,CAAC,OAAe,OAAQ,QAAQ,OAAO,KAAK,IAAI,IAAI,IAAI,IAAK;AAG3E,IAAM,OAAO,CAAC,GAAW,MAAc;AACrC,QAAM,IAAI,KAAK,IAAI,IAAI,QAAQ,IAAI,KAAK,IAAI;AAC5C,SAAO,IAAI,KAAK,MAAM,CAAC;AACzB;AAGA,IAAM,QAAQ,CAAC,GAAW,OAAe;AACvC,QAAM,KAAK,IAAI,IAAI,IAAI,MAAM,OAAO,KAAK,GAAG,CAAC;AAC7C,QAAM,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,GAAG,CAAC;AAC9C,QAAM,OAAO,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC,IAAI,OAAO;AAC9C,SAAO,iBAAiBA,IAAG,MAAM,EAAE,IAAI,EAAE,CAAC,WAAWA,IAAG,IAAI,CAAC,WAAWA,IAAG,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC;AAC1F;AAEA,IAAM,WAAW,OAAO;AAExB,IAAM,QAAQ;AAAA,EACZ,EAAE,GAAG,IAAI,OAAO,KAAK,IAAI,MAAM,QAAQ,GAAG;AAAA,EAC1C,EAAE,GAAG,KAAK,OAAO,MAAM,IAAI,KAAM,QAAQ,GAAG;AAAA,EAC5C,EAAE,GAAG,IAAI,OAAO,KAAM,IAAI,MAAM,QAAQ,GAAG;AAC7C;AAEA,IAAM,SAAS,EAAE,OAAO,GAAG,IAAI,MAAM,MAAM,SAAkB;AAC7D,IAAM,UAAU,EAAE,OAAO,MAAM,IAAI,KAAK,MAAM,SAAkB;AAEzD,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,UAAU,SAAS,OAAO,QAAQ,MAAM;AAAA,EACvD,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACpF,EAAE,MAAM,gBAAgB,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EAClH;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,wwBAAwwB,MAAM,EAAE,qIAAqI,GAAG,wBAAwB,MAAM,GAAG,gDAAgD,GAAG,wBAAwB,MAAM,GAAG,4BAA4B,MAAM;AAAA,MACljC,CAAC,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE,CAAC,QAAQ,GAAG;AAAA,IACpD,EAAE,KAAK,EAAE,CAAC,kCAAkC,GAAG,uGAAuG,GAAG,iFAAiF,GAAG,kBAAkB,MAAM,EAAE,0FAA0F,MAAM,IAAI,CAAC,CAAC;AAAA,IAC7W,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,MAAM,KAAK,MAAM,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,MACtF,EAAE,IAAI,QAAQ,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,QAAQ,CAAC,MAAM,OAAO,MAAM,GAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MACvF,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,MAAM,KAAK,MAAM,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,MACvF,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,QAAQ,CAAC,MAAM,OAAO,MAAM,GAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MACxF,GAAI,CAAC,OAAO,MAAM,EAAY,QAAQ,CAAC,OAAuB;AAAA,QAC5D,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,QAC7C,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MAChD,CAAC;AAAA,MACD,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,EAAE,GAAG,GAAG,OAAO;AAAA,MACjF,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,GAAG,GAAG,QAAQ;AAAA,MAClF,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,EAAE,GAAG,GAAG,OAAO;AAAA,MAC/D,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,GAAG,GAAG,QAAQ;AAAA;AAAA,MAEhE,GAAG,MAAM,QAAQ,CAAC,GAAG,MAAsB;AAAA,QACzC,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,QACxD,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,OAAO,IAAI,EAAE,IAAI,MAAM,MAAM;AAAA,QAC1F,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,QAAQ;AAAA,MAClF,CAAC;AAAA;AAAA,MAED,GAAG,MAAM,KAAK,EAAE,QAAQ,SAAS,GAAG,CAAC,GAAG,OAAqB;AAAA,QAC3D,IAAI;AAAA,QACJ,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,IAAI,OAAO,GAAG,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC,EAAE;AAAA,QAC7E,OAAO,IAAI;AAAA,QACX,IAAI;AAAA,QACJ,MAAM;AAAA,MACR,EAAE;AAAA,MACF,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MACtI,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACnF,GAAG,MAAM,KAAK,EAAE,QAAQ,OAAO,IAAI,GAAG,CAAC,GAAG,OAAqB;AAAA,QAC7D,IAAI;AAAA,QACJ,OAAO,EAAE,SAAS,CAAC,IAAIA,IAAG,MAAM,MAAM,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,KAAKA,IAAG,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE;AAAA,QACzF,OAAO,IAAI;AAAA,QACX,IAAI;AAAA,QACJ,MAAM;AAAA,MACR,EAAE;AAAA,MACF,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAACA,IAAG,MAAM,MAAM,KAAK,OAAO,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MACrH,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,IACtF;AAAA,EACF;AACF;AAGO,IAAM,cAA8B,CAAC,aAAa,MAAM;;;AC9MxD,IAAM,aAA0D;AAAA,EACrE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,GAAG,CAAC,SAAS,SAAS,SAAS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","names":["HEART","at","circle","r1","about","snap","SANS","at","stroke","r2","n","r2","n","snap","pose","at","HEART","heartPose","_","n","at","stroke","r1","n","DEG","r2","n","polyline","arc","r1","HEART","pair","at","stages","DOTS","_","GLOW","OVER","GLOW","OVER","GLOW","OVER","r1","n","fit","mixHex","SANS","SLOTS","at","rand","link","DRIPS","at"]}
1
+ {"version":3,"sources":["../src/catalog/glsl.ts","../src/catalog/shaders/gradients.ts","../src/catalog/images.ts","../src/catalog/shaders/image.ts","../src/catalog/shaders/light.ts","../src/catalog/shaders/organic.ts","../src/catalog/shaders/patterns.ts","../src/catalog/interaction.ts","../src/catalog/electric.ts","../src/catalog/melt.ts","../src/catalog/shaders/pixel.ts","../src/catalog/pixel.ts","../src/catalog/pyro.ts","../src/catalog/timewarp.ts","../src/catalog/morph.ts","../src/catalog/shaders/interaction.ts","../src/catalog/shaders/electric.ts","../src/catalog/shaders/melt.ts","../src/catalog/shaders/pyro.ts","../src/catalog/shaders/timewarp.ts","../src/catalog/shaders/morph.ts","../src/catalog/shaders/overlay.ts","../src/catalog/shaders/retro.ts","../src/catalog/shaders/text.ts","../src/catalog/shaders/treatments.ts","../src/catalog/types.ts","../src/catalog/text.ts","../src/catalog/vector.ts","../src/catalog/index.ts"],"sourcesContent":["/**\n * GLSL helpers the catalog's shaders are built from. Each effect's source\n * inlines the helpers it uses, so a source stays self-contained: copy it into\n * any Shadertoy-style host and it compiles.\n */\n\n/** Hashes: `hash12` (vec2 → float), `hash22` (vec2 → vec2), both 0–1. */\nexport const HASH = `\nfloat hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\nvec2 hash22(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.xx + p3.yz) * p3.zy);\n}`.trim();\n\n/** Smooth value noise, 0–1 (needs {@link HASH}). */\nexport const NOISE = `\nfloat vnoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n float a = hash12(i);\n float b = hash12(i + vec2(1.0, 0.0));\n float c = hash12(i + vec2(0.0, 1.0));\n float d = hash12(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}`.trim();\n\n/** Fractal noise: `fbm(p, octaves)`, about 0–1 (needs {@link NOISE}). */\nexport const FBM = `\nfloat fbm(vec2 p, int octaves) {\n float sum = 0.0;\n float amp = 0.5;\n mat2 turn = mat2(0.8, 0.6, -0.6, 0.8);\n for (int i = 0; i < 8; i++) {\n if (i >= octaves) break;\n sum += amp * vnoise(p);\n p = turn * p * 2.02 + 17.0;\n amp *= 0.5;\n }\n return sum;\n}`.trim();\n\n/** Inigo Quilez's cosine palette: `palette(t, a, b, c, d)`. */\nexport const PALETTE = `\nvec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {\n return a + b * cos(6.28318 * (c * t + d));\n}`.trim();\n\n/** Mixes colours in Oklab, so blends stay bright: `oklabMix(a, b, t)` on sRGB colours. */\nexport const OKLAB_MIX = `\nvec3 toOklab(vec3 c) {\n c = pow(max(c, 0.0), vec3(2.2));\n vec3 lms = mat3(0.4122, 0.2119, 0.0883, 0.5363, 0.6807, 0.2817, 0.0514, 0.1074, 0.6300) * c;\n lms = pow(lms, vec3(1.0 / 3.0));\n return mat3(0.2105, 1.9780, 0.0259, 0.7936, -2.4286, 0.7828, -0.0041, 0.4506, -0.8087) * lms;\n}\nvec3 fromOklab(vec3 c) {\n vec3 lms = mat3(1.0, 1.0, 1.0, 0.3963, -0.1056, -0.0895, 0.2158, -0.0639, -1.2915) * c;\n lms = lms * lms * lms;\n vec3 rgb = mat3(4.0767, -1.2684, -0.0042, -3.3077, 2.6098, -0.7034, 0.2310, -0.3413, 1.7076) * lms;\n return pow(max(rgb, 0.0), vec3(1.0 / 2.2));\n}\nvec3 oklabMix(vec3 a, vec3 b, float t) {\n return fromOklab(mix(toOklab(a), toOklab(b), t));\n}`.trim();\n\n/** 2D rotation matrix: `rot(angle)`. */\nexport const ROTATE = `\nmat2 rot(float a) {\n float c = cos(a);\n float s = sin(a);\n return mat2(c, s, -s, c);\n}`.trim();\n\n/** Joins helpers and a body into one source, a blank line apart. */\nexport function glsl(...parts: string[]): string {\n return parts.map((p) => p.trim()).join(\"\\n\\n\") + \"\\n\";\n}\n","import { FBM, glsl, HASH, NOISE, OKLAB_MIX, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const aurora: ShaderEffect = {\n kind: \"shader\",\n id: \"aurora\",\n name: \"Aurora\",\n description: \"Soft curtains of light drifting over a night sky.\",\n category: \"gradient\",\n tags: [\"background\", \"hero\", \"calm\", \"night\"],\n source: glsl(\n `// Aurora: curtains of light drifting over a night sky.\nuniform vec3 uSky; // @control color default=#050816 label=\"Sky\"\nuniform vec3 uGlowA; // @control color default=#22D3A6 label=\"Glow A\"\nuniform vec3 uGlowB; // @control color default=#7C3AED label=\"Glow B\"\nuniform float uSpeed; // @control min=0 max=2 default=0.35 label=\"Speed\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"\nuniform float uHeight; // @control min=0 max=1 default=0.55 label=\"Height\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n vec3 col = uSky * (0.6 + 0.4 * uv.y);\n for (int i = 0; i < 3; i++) {\n float fi = float(i);\n float x = uv.x * (1.4 + 0.3 * fi) + fi * 3.7;\n float wave = fbm(vec2(x * 1.5 + t * 0.4, t * 0.25 + fi), 4);\n float centre = uHeight + 0.18 * (wave - 0.5) + 0.06 * fi;\n float band = exp(-pow((uv.y - centre) * (7.0 + 2.0 * fi), 2.0));\n float rays = 0.55 + 0.45 * fbm(vec2(x * 12.0, t * 0.6 + fi * 9.0), 3);\n float above = smoothstep(centre - 0.05, centre + 0.35, uv.y) * 0.35;\n vec3 glow = mix(uGlowA, uGlowB, clamp(uv.y * 1.4 - 0.2 + 0.25 * fi, 0.0, 1.0));\n col += glow * (band * rays + above * band) * 0.6 * uIntensity;\n }\n float stars = step(0.997, hash12(floor(fragCoord * 0.5))) * smoothstep(0.3, 1.0, uv.y);\n col += stars * 0.6 * (0.5 + 0.5 * sin(iTime * 3.0 + hash12(floor(fragCoord)) * 40.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Arctic\", values: { uGlowA: [0.13, 0.83, 0.65], uGlowB: [0.49, 0.23, 0.93] } },\n { name: \"Ember\", values: { uSky: [0.06, 0.02, 0.03], uGlowA: [1, 0.45, 0.1], uGlowB: [0.9, 0.1, 0.4] } },\n { name: \"Ice\", values: { uSky: [0.01, 0.03, 0.06], uGlowA: [0.5, 0.9, 1], uGlowB: [0.2, 0.4, 1] } },\n ],\n};\n\nexport const meshGradient: ShaderEffect = {\n kind: \"shader\",\n id: \"mesh-gradient\",\n name: \"Mesh gradient\",\n description: \"Four colours blended across a slowly warping mesh, mixed in Oklab.\",\n category: \"gradient\",\n tags: [\"background\", \"hero\", \"brand\", \"soft\"],\n source: glsl(\n `// Mesh gradient: four colours on drifting points, blended in Oklab.\nuniform vec3 uColorA; // @control color default=#FF6B6B label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#FFD93D label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#6BCB77 label=\"Colour C\"\nuniform vec3 uColorD; // @control color default=#4D96FF label=\"Colour D\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Speed\"\nuniform float uWarp; // @control min=0 max=1 default=0.35 label=\"Warp\"\nuniform float uGrain; // @control min=0 max=0.2 default=0.04 label=\"Grain\"`,\n HASH,\n NOISE,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n vec2 w = uv + uWarp * 0.3 * vec2(vnoise(uv * 2.0 + t), vnoise(uv * 2.0 - t + 5.0)) - uWarp * 0.15;\n vec2 pa = vec2(0.2, 0.2) + 0.15 * vec2(sin(t * 1.1), cos(t * 0.9));\n vec2 pb = vec2(0.8, 0.25) + 0.15 * vec2(cos(t * 0.7), sin(t * 1.3));\n vec2 pc = vec2(0.25, 0.8) + 0.15 * vec2(sin(t * 0.8 + 2.0), cos(t * 1.2));\n vec2 pd = vec2(0.8, 0.8) + 0.15 * vec2(cos(t * 1.0 + 1.0), sin(t * 0.6));\n vec4 d = vec4(distance(w, pa), distance(w, pb), distance(w, pc), distance(w, pd));\n vec4 k = 1.0 / (d * d + 0.02);\n k /= dot(k, vec4(1.0));\n vec3 ab = oklabMix(uColorA, uColorB, k.y / max(k.x + k.y, 1e-4));\n vec3 cd = oklabMix(uColorC, uColorD, k.w / max(k.z + k.w, 1e-4));\n vec3 col = oklabMix(ab, cd, k.z + k.w);\n col += (hash12(fragCoord + fract(iTime) * 100.0) - 0.5) * uGrain;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Sunset\", values: { uColorA: [1, 0.42, 0.42], uColorB: [1, 0.85, 0.24], uColorC: [0.9, 0.3, 0.6], uColorD: [0.36, 0.2, 0.7] } },\n { name: \"Lagoon\", values: { uColorA: [0.0, 0.6, 0.7], uColorB: [0.5, 0.95, 0.85], uColorC: [0.1, 0.3, 0.6], uColorD: [0.85, 0.95, 1] } },\n { name: \"Mono\", values: { uColorA: [0.1, 0.1, 0.12], uColorB: [0.3, 0.3, 0.34], uColorC: [0.2, 0.2, 0.24], uColorD: [0.6, 0.6, 0.65] } },\n ],\n};\n\nexport const conicSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"conic-sweep\",\n name: \"Conic sweep\",\n description: \"A rotating conic gradient with a soft glowing core.\",\n category: \"gradient\",\n tags: [\"background\", \"spotlight\", \"brand\"],\n loop: 10,\n source: glsl(\n `// Conic sweep: a rotating conic gradient with a glowing core.\nuniform vec3 uColorA; // @control color default=#0EA5E9 label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#A855F7 label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#F43F5E label=\"Colour C\"\nuniform float uTurns; // @control min=-3 max=3 default=1 step=1 label=\"Turns per loop\"\nuniform float uCore; // @control min=0 max=1 default=0.4 label=\"Core glow\"\nuniform vec2 uCenter; // @control min=-0.5 max=0.5 default=0,0 label=\"Centre\"`,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y - uCenter;\n float a = atan(p.y, p.x) / 6.28318 + 0.5;\n a = fract(a + iTime * uTurns / 10.0);\n float s = a * 3.0;\n vec3 col = s < 1.0 ? oklabMix(uColorA, uColorB, s)\n : s < 2.0 ? oklabMix(uColorB, uColorC, s - 1.0)\n : oklabMix(uColorC, uColorA, s - 2.0);\n float r = length(p);\n col *= 0.75 + 0.25 * smoothstep(0.9, 0.0, r);\n col += uCore * exp(-r * 6.0);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const silk: ShaderEffect = {\n kind: \"shader\",\n id: \"silk\",\n name: \"Silk\",\n description: \"Folds of glossy fabric rippling in a slow breeze.\",\n category: \"gradient\",\n tags: [\"background\", \"luxury\", \"soft\"],\n source: glsl(\n `// Silk: glossy folds of fabric rippling slowly.\nuniform vec3 uBase; // @control color default=#3B0764 label=\"Base\"\nuniform vec3 uSheen; // @control color default=#F0ABFC label=\"Sheen\"\nuniform float uSpeed; // @control min=0 max=2 default=0.4 label=\"Speed\"\nuniform float uFolds; // @control min=1 max=10 default=5 label=\"Folds\"\nuniform float uGloss; // @control min=0 max=2 default=1 label=\"Gloss\"`,\n ROTATE,\n `float folds(vec2 p, float t) {\n float h = 0.0;\n for (int i = 1; i <= 4; i++) {\n float fi = float(i);\n h += sin(p.x * uFolds * fi * 0.7 + t * (1.0 + 0.3 * fi) + sin(p.y * 2.0 * fi + t)) / fi;\n }\n return h;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = rot(0.6) * (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float e = 0.002;\n float hx = (folds(p + vec2(e, 0.0), t) - folds(p - vec2(e, 0.0), t)) / (2.0 * e);\n float hy = (folds(p + vec2(0.0, e), t) - folds(p - vec2(0.0, e), t)) / (2.0 * e);\n vec3 n = normalize(vec3(-hx * 0.12, -hy * 0.12, 1.0));\n vec3 l = normalize(vec3(-0.4, 0.6, 0.7));\n float diff = clamp(dot(n, l), 0.0, 1.0);\n float spec = pow(clamp(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0, 1.0), 20.0) * uGloss;\n vec3 col = uBase * (0.35 + 0.9 * diff) + uSheen * (spec + 0.12 * pow(diff, 6.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Champagne\", values: { uBase: [0.55, 0.42, 0.25], uSheen: [1, 0.95, 0.8] } },\n { name: \"Midnight\", values: { uBase: [0.04, 0.08, 0.2], uSheen: [0.6, 0.75, 1] } },\n ],\n};\n\nexport const duotoneFlow: ShaderEffect = {\n kind: \"shader\",\n id: \"gradient-flow\",\n name: \"Gradient flow\",\n description: \"Two colours flowing through each other along a warped noise field.\",\n category: \"gradient\",\n tags: [\"background\", \"brand\", \"liquid\"],\n source: glsl(\n `// Gradient flow: two colours flowing through a warped noise field.\nuniform vec3 uColorA; // @control color default=#1E3A8A label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#F97316 label=\"Colour B\"\nuniform float uSpeed; // @control min=0 max=2 default=0.25 label=\"Speed\"\nuniform float uScale; // @control min=0.5 max=6 default=2 label=\"Scale\"\nuniform float uContrast; // @control min=0.5 max=4 default=1.5 label=\"Contrast\"`,\n HASH,\n NOISE,\n FBM,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n float t = iTime * uSpeed;\n vec2 q = vec2(fbm(p + t, 4), fbm(p + vec2(5.2, 1.3) - t, 4));\n float f = fbm(p + 3.0 * q + vec2(1.7, 9.2) + 0.5 * t, 5);\n f = clamp((f - 0.5) * uContrast + 0.5, 0.0, 1.0);\n fragColor = vec4(oklabMix(uColorA, uColorB, smoothstep(0.0, 1.0, f)), 1.0);\n}`,\n ),\n};\n","/**\n * Sample pictures for the catalog's image effects: small SVGs as `data:` URLs,\n * so image controls have something to show with nothing to download.\n */\n\n/** An ASCII SVG as a base64 `data:image/svg+xml` URL. */\nexport function svgDataUrl(svg: string): string {\n const base64 =\n typeof btoa === \"function\" ? btoa(svg) : (globalThis as { Buffer?: { from(s: string): { toString(e: string): string } } }).Buffer!.from(svg).toString(\"base64\");\n return `data:image/svg+xml;base64,${base64}`;\n}\n\nconst LANDSCAPE = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<defs><linearGradient id=\"s\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#3b4cb8\"/><stop offset=\"1\" stop-color=\"#ffa36b\"/></linearGradient></defs>\n<rect width=\"640\" height=\"360\" fill=\"url(#s)\"/>\n<circle cx=\"420\" cy=\"170\" r=\"62\" fill=\"#ffe9b0\"/>\n<path d=\"M0 250 Q120 190 240 240 T480 230 T640 220 V360 H0Z\" fill=\"#2c4a52\"/>\n<path d=\"M0 290 Q160 240 320 290 T640 280 V360 H0Z\" fill=\"#1b2f33\"/>\n<path d=\"M0 330 Q200 300 400 330 T640 325 V360 H0Z\" fill=\"#0f1c1f\"/>\n</svg>`;\n\nconst CITY = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<rect width=\"640\" height=\"360\" fill=\"#0d1028\"/>\n<circle cx=\"520\" cy=\"80\" r=\"34\" fill=\"#f5f3d7\"/>\n<g fill=\"#252a52\"><rect x=\"20\" y=\"170\" width=\"70\" height=\"190\"/><rect x=\"110\" y=\"120\" width=\"60\" height=\"240\"/><rect x=\"190\" y=\"200\" width=\"80\" height=\"160\"/><rect x=\"290\" y=\"90\" width=\"55\" height=\"270\"/><rect x=\"365\" y=\"160\" width=\"90\" height=\"200\"/><rect x=\"475\" y=\"130\" width=\"60\" height=\"230\"/><rect x=\"555\" y=\"190\" width=\"70\" height=\"170\"/></g>\n<g fill=\"#ffcf5a\"><rect x=\"125\" y=\"140\" width=\"8\" height=\"8\"/><rect x=\"150\" y=\"170\" width=\"8\" height=\"8\"/><rect x=\"305\" y=\"110\" width=\"8\" height=\"8\"/><rect x=\"320\" y=\"150\" width=\"8\" height=\"8\"/><rect x=\"380\" y=\"180\" width=\"8\" height=\"8\"/><rect x=\"420\" y=\"220\" width=\"8\" height=\"8\"/><rect x=\"490\" y=\"150\" width=\"8\" height=\"8\"/><rect x=\"40\" y=\"200\" width=\"8\" height=\"8\"/><rect x=\"215\" y=\"230\" width=\"8\" height=\"8\"/><rect x=\"575\" y=\"215\" width=\"8\" height=\"8\"/></g>\n</svg>`;\n\nconst PORTRAIT = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<rect width=\"640\" height=\"360\" fill=\"#f2e6d8\"/>\n<circle cx=\"320\" cy=\"150\" r=\"70\" fill=\"#c98b6b\"/>\n<path d=\"M190 360 Q200 240 320 240 Q440 240 450 360Z\" fill=\"#33415c\"/>\n<path d=\"M250 130 Q260 60 320 62 Q385 60 392 135 Q370 100 320 100 Q275 100 250 130Z\" fill=\"#2b1d16\"/>\n<circle cx=\"295\" cy=\"150\" r=\"6\" fill=\"#2b1d16\"/><circle cx=\"345\" cy=\"150\" r=\"6\" fill=\"#2b1d16\"/>\n<path d=\"M300 185 Q320 198 340 185\" stroke=\"#7a3e2c\" stroke-width=\"5\" fill=\"none\"/>\n</svg>`;\n\n// A second portrait, the face larger and right of centre, for morphing with PORTRAIT.\n// Features (viewBox units): eyes (396, 175) and (464, 175), mouth (430, 229), chin (430, 270), hairline (430, 80).\nconst PORTRAIT_2 = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\" width=\"640\" height=\"360\">\n<rect width=\"640\" height=\"360\" fill=\"#d3e4e6\"/>\n<path d=\"M255 360 Q268 300 430 297 Q592 300 605 360Z\" fill=\"#a4372f\"/>\n<rect x=\"408\" y=\"250\" width=\"44\" height=\"52\" fill=\"#d9a07c\"/>\n<circle cx=\"430\" cy=\"175\" r=\"95\" fill=\"#e8b48f\"/>\n<path d=\"M332 172 Q330 66 430 64 Q530 66 528 172 Q520 112 470 100 Q420 128 352 116 Q336 140 332 172Z\" fill=\"#8a3b1e\"/>\n<circle cx=\"396\" cy=\"175\" r=\"8\" fill=\"#3a2418\"/><circle cx=\"464\" cy=\"175\" r=\"8\" fill=\"#3a2418\"/>\n<path d=\"M424 186 Q430 206 436 186\" stroke=\"#c48262\" stroke-width=\"5\" fill=\"none\"/>\n<path d=\"M403 225 Q430 244 457 225\" stroke=\"#9c4a35\" stroke-width=\"7\" fill=\"none\" stroke-linecap=\"round\"/>\n</svg>`;\n\n// Flat shapes on transparent, for silhouette morphs and masks.\nconst LOGO = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" width=\"512\" height=\"512\">\n<path fill=\"#6366f1\" fill-rule=\"evenodd\" d=\"M256 56a200 200 0 1 1 0 400a200 200 0 1 1 0-400zm0 92a108 108 0 1 0 0 216a108 108 0 1 0 0-216z\"/>\n<circle cx=\"256\" cy=\"256\" r=\"52\" fill=\"#6366f1\"/>\n</svg>`;\n\nconst HEART = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" width=\"512\" height=\"512\">\n<path fill=\"#f43f5e\" d=\"M256 452C120 352 40 272 40 172C40 102 95 58 160 58C205 58 238 84 256 118C274 84 307 58 352 58C417 58 472 102 472 172C472 272 392 352 256 452Z\"/>\n</svg>`;\n\n/**\n * An icon drawn the way Lucide and similar sets draw them: 24 × 24, stroked\n * in `currentColor` (black in an image) on a transparent background.\n */\nconst ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 20C5 15.5 3 12 3 8.5a4.5 4.5 0 0 1 9 0a4.5 4.5 0 0 1 9 0c0 3.5-2 7-9 11.5Z\"/></svg>`;\n\n/** Built-in sample pictures, as image control values. */\nexport const SAMPLE_IMAGES = {\n landscape: svgDataUrl(LANDSCAPE),\n city: svgDataUrl(CITY),\n portrait: svgDataUrl(PORTRAIT),\n /** Another face, larger and to the right: morph it with `portrait`. */\n portrait2: svgDataUrl(PORTRAIT_2),\n /** A ring-and-dot mark, indigo on transparent. */\n logo: svgDataUrl(LOGO),\n /** A heart, rose on transparent. */\n heart: svgDataUrl(HEART),\n icon: svgDataUrl(ICON),\n} as const;\n\n/** Roughly how wide a character is in a bold sans-serif, in ems, for fitting text without measuring it. */\nfunction charWidth(c: string): number {\n if (/[iIjl.,:;'!|`]/.test(c)) return 0.3;\n if (/[\\sfrt()[\\]\\-]/.test(c)) return 0.4;\n if (/[MW@%]/.test(c)) return 0.94;\n if (/[mw]/.test(c)) return 0.88;\n if (/[A-Z&#]/.test(c)) return 0.74;\n if (/[0-9]/.test(c)) return 0.58;\n if (/[a-z]/.test(c)) return 0.6;\n // Wide scripts (CJK, kana, hangul) and emoji take about a full em.\n return /[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹏＀-⦆]|\\p{Extended_Pictographic}/u.test(c) ? 1 : 0.64;\n}\n\n/** About how wide `text` is in ems in a bold sans-serif (letters are code points). */\nexport function textWidthEm(text: string): number {\n return Array.from(text).reduce((sum, c) => sum + charWidth(c), 0);\n}\n\nconst escapeXml = (text: string) =>\n text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#39;\");\n\nexport interface TextImageOptions {\n /** CSS font family (default a heavy system sans-serif). */\n font?: string;\n /** Font weight (default 900). */\n weight?: number | string;\n /** Font size in the picture's units; by default as large as fits. */\n size?: number;\n /** The picture's size (default 1024 × 256). */\n width?: number;\n height?: number;\n}\n\n/**\n * A line of text, white on transparent, as an SVG `data:` URL for an image\n * control (the shader text effects use its alpha as a letter mask). The text\n * is centred and fitted to the picture (1024 × 256 by default): the font\n * size comes from its length, and `textLength` stretches it to the width\n * that size predicts, so any text fills about the same box in any font.\n * Takes any Unicode text.\n */\nexport function textImage(text: string, options: TextImageOptions = {}): string {\n const width = options.width ?? 1024;\n const height = options.height ?? 256;\n const ems = Math.max(0.5, textWidthEm(text));\n const size = options.size ?? Math.min(height * 0.78, (width * 0.9) / ems);\n const length = Math.min(width * 0.96, ems * size);\n const font = options.font ?? \"'Arial Black', 'Helvetica Neue', Helvetica, Arial, system-ui, sans-serif\";\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${width} ${height}\" width=\"${width}\" height=\"${height}\"><text x=\"${width / 2}\" y=\"${height / 2}\" dy=\"0.35em\" text-anchor=\"middle\" textLength=\"${+length.toFixed(1)}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${escapeXml(font)}\" font-weight=\"${escapeXml(String(options.weight ?? 900))}\" font-size=\"${+size.toFixed(1)}\" fill=\"#fff\">${escapeXml(text)}</text></svg>`;\n // UTF-8 percent-encoded rather than base64 (btoa only takes Latin-1); quotes and brackets are encoded too, so it is safe unquoted.\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg).replace(/['()*!]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)}`;\n}\n","import { getTransitionGLSL, type TransitionType } from \"../../shader/transition.js\";\nimport { glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/**\n * The controls {@link BACKDROP} reads: what shows through an image's\n * transparent parts. At opacity 1 an icon or cut-out (a Lucide icon, a logo)\n * sits on the backdrop colour; at 0 the effect keeps the image's alpha, for\n * overlays on a transparent canvas.\n */\nexport const BACKDROP_CONTROLS = `\nuniform vec3 uBackdrop; // @control color default=#FFFFFF label=\"Backdrop\"\nuniform float uBackdropAlpha; // @control min=0 max=1 default=1 label=\"Backdrop opacity\"`.trim();\n\n/**\n * `overBackdrop(sample)`: an image sample laid over the backdrop (see\n * {@link BACKDROP_CONTROLS}), as straight colour and alpha.\n */\nexport const BACKDROP = `\n// The sample is read as premultiplied: filtering a straight-alpha image whose clear pixels are\n// black (as browsers decode them) premultiplies it, and the clamp clears colour a clear pixel kept.\nvec4 overBackdrop(vec4 s) {\n vec3 colour = min(s.rgb, vec3(s.a)) + uBackdrop * uBackdropAlpha * (1.0 - s.a);\n float alpha = s.a + uBackdropAlpha * (1.0 - s.a);\n return vec4(colour / max(alpha, 1e-4), alpha);\n}`.trim();\n\n/**\n * `picture(tex, uv)`: the image over the backdrop (see {@link BACKDROP}), or a\n * test card while there is none (an empty image control is bound to a 1 × 1\n * placeholder), so effects show something before an image is chosen.\n * `pictureRGBA(tex, uv)` also gives its alpha, which effects pass on. Needs\n * the {@link BACKDROP_CONTROLS} uniforms.\n */\nexport const PICTURE = `\n${BACKDROP}\nvec3 testCard(vec2 uv) {\n vec3 sky = mix(vec3(0.98, 0.62, 0.42), vec3(0.24, 0.32, 0.72), uv.y);\n float sun = smoothstep(0.16, 0.15, length((uv - vec2(0.65, 0.58)) * vec2(1.6, 1.0)));\n float hills = step(uv.y, 0.32 + 0.06 * sin(uv.x * 9.0) + 0.04 * sin(uv.x * 23.0 + 1.0));\n vec3 col = mix(sky, vec3(1.0, 0.92, 0.7), sun);\n col = mix(col, vec3(0.12, 0.28, 0.24) + 0.08 * sin(uv.x * 40.0), hills);\n vec2 grid = abs(fract(uv * 8.0) - 0.5);\n col += 0.04 * step(0.48, max(grid.x, grid.y));\n return col;\n}\nvec4 pictureRGBA(sampler2D tex, vec2 uv) {\n return textureSize(tex, 0).x > 1 ? overBackdrop(texture(tex, uv)) : vec4(testCard(fract(uv)), 1.0);\n}\nvec3 picture(sampler2D tex, vec2 uv) {\n return pictureRGBA(tex, uv).rgb;\n}`.trim();\n\nexport const imageRipple: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ripple\",\n name: \"Ripple\",\n description: \"An image rippling as if seen through water, from the pointer or the centre.\",\n category: \"image\",\n tags: [\"image\", \"water\", \"interactive\", \"distortion\"],\n source: glsl(\n `// Ripple: an image rippling as if under water.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmplitude; // @control min=0 max=0.05 default=0.012 label=\"Amplitude\"\nuniform float uFrequency; // @control min=5 max=80 default=30 label=\"Frequency\"\nuniform float uSpeed; // @control min=0 max=6 default=2 label=\"Speed\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 centre = (iMouse.z > 0.0 ? iMouse.xy : 0.5 * iResolution.xy) / iResolution.xy;\n vec2 d = uv - centre;\n d.x *= iResolution.x / iResolution.y;\n float r = length(d);\n float wave = sin(r * uFrequency - iTime * uSpeed) * smoothstep(0.9, 0.0, r);\n vec2 offset = normalize(d + 1e-5) * wave * uAmplitude;\n vec4 pic = pictureRGBA(uImage, uv + offset);\n vec3 col = pic.rgb + 0.6 * max(wave, 0.0) * uAmplitude * 8.0;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n};\n\nexport const imageGlitch: ShaderEffect = {\n kind: \"shader\",\n id: \"image-glitch\",\n name: \"Glitch\",\n description: \"Digital glitch on an image: RGB split, slice displacement and blocky corruption in bursts.\",\n category: \"image\",\n tags: [\"image\", \"glitch\", \"cyber\", \"transition\"],\n source: glsl(\n `// Glitch: RGB split, slice displacement and blocky corruption in bursts.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmount; // @control min=0 max=1 default=0.5 label=\"Amount\"\nuniform float uSplit; // @control min=0 max=0.05 default=0.012 label=\"RGB split\"\nuniform float uRate; // @control min=0.5 max=12 default=4 label=\"Bursts per second\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float tick = floor(iTime * uRate);\n float burst = step(1.0 - uAmount * 0.6, hash12(vec2(tick, 1.0)));\n float slice = floor(uv.y * mix(8.0, 40.0, hash12(vec2(tick, 2.0))));\n float shift = (hash12(vec2(slice, tick)) - 0.5) * 0.15 * burst * step(0.6, hash12(vec2(slice, tick + 3.0)));\n vec2 block = floor(uv * vec2(16.0, 9.0));\n float corrupt = burst * step(0.97 - uAmount * 0.05, hash12(block + tick));\n vec2 st = uv + vec2(shift, 0.0);\n st = mix(st, floor(st * 24.0) / 24.0, corrupt);\n float split = uSplit * (0.3 + burst);\n vec4 r = pictureRGBA(uImage, st + vec2(split, 0.0));\n vec4 g = pictureRGBA(uImage, st);\n vec4 b = pictureRGBA(uImage, st - vec2(split, 0.0));\n vec3 col = vec3(r.r, g.g, b.b);\n col = mix(col, col.bgr, corrupt);\n col *= 0.92 + 0.08 * sin(fragCoord.y * 2.0);\n fragColor = vec4(col, max(max(r.a, g.a), b.a));\n}`,\n ),\n};\n\nexport const imageDuotone: ShaderEffect = {\n kind: \"shader\",\n id: \"image-duotone\",\n name: \"Duotone\",\n description: \"An image mapped onto two colours, with a slow light sweep.\",\n category: \"image\",\n tags: [\"image\", \"brand\", \"editorial\", \"colour\"],\n source: glsl(\n `// Duotone: an image mapped onto two colours, with a light sweep.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uShadow; // @control color default=#1E1B4B label=\"Shadows\"\nuniform vec3 uHighlight; // @control color default=#FB7185 label=\"Highlights\"\nuniform float uContrast; // @control min=0.5 max=3 default=1.2 label=\"Contrast\"\nuniform float uSweep; // @control min=0 max=1 default=0.3 label=\"Light sweep\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec4 src = pictureRGBA(uImage, uv);\n float l = dot(src.rgb, vec3(0.2126, 0.7152, 0.0722));\n l = clamp((l - 0.5) * uContrast + 0.5, 0.0, 1.0);\n float sweep = exp(-pow((uv.x + uv.y * 0.4 - fract(iTime * 0.15) * 2.0 + 0.4) * 6.0, 2.0));\n vec3 col = mix(uShadow, uHighlight, l) + sweep * uSweep;\n fragColor = vec4(col, src.a);\n}`,\n ),\n presets: [\n { name: \"Spotify\", values: { uShadow: [0.07, 0.1, 0.35], uHighlight: [0.12, 0.84, 0.38] } },\n { name: \"Newsprint\", values: { uShadow: [0.1, 0.1, 0.1], uHighlight: [0.96, 0.94, 0.88] } },\n ],\n};\n\nexport const imagePixelate: ShaderEffect = {\n kind: \"shader\",\n id: \"image-pixelate\",\n name: \"Pixel reveal\",\n description: \"An image resolving from big blocks to full detail, then back, in a loop.\",\n category: \"image\",\n tags: [\"image\", \"reveal\", \"transition\", \"8-bit\"],\n loop: 4,\n source: glsl(\n `// Pixel reveal: an image resolving from blocks to full detail and back.\nuniform sampler2D uImage; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uMaxBlock; // @control min=4 max=128 default=48 label=\"Largest block (px)\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=1 label=\"Detail (when still)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float k = uAnimate ? 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0) : uProgress;\n float block = max(1.0, floor(mix(uMaxBlock, 1.0, k)));\n vec2 cell = (floor(fragCoord / block) + 0.5) * block;\n fragColor = pictureRGBA(uImage, cell / iResolution.xy);\n}`,\n ),\n};\n\nexport const imageHalftone: ShaderEffect = {\n kind: \"shader\",\n id: \"image-halftone\",\n name: \"Halftone\",\n description: \"An image printed as rotated halftone dots, breathing slightly.\",\n category: \"image\",\n tags: [\"image\", \"print\", \"comic\", \"pop-art\"],\n source: glsl(\n `// Halftone: an image as rotated print dots.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uInk; // @control color default=#111827 label=\"Ink\"\nuniform vec3 uPaper; // @control color default=#FEF3C7 label=\"Paper\"\nuniform float uSpacing; // @control min=3 max=30 default=8 label=\"Dot spacing (px)\"\nuniform float uAngle; // @control min=0 max=90 default=45 label=\"Screen angle (°)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float a = radians(uAngle);\n mat2 r = mat2(cos(a), sin(a), -sin(a), cos(a));\n vec2 q = r * fragCoord / uSpacing;\n vec2 cell = floor(q) + 0.5;\n vec2 centre = transpose(r) * cell * uSpacing;\n vec4 pic = pictureRGBA(uImage, centre / iResolution.xy);\n float l = dot(pic.rgb, vec3(0.2126, 0.7152, 0.0722));\n float radius = sqrt(1.0 - l) * 0.62 * (0.95 + 0.05 * sin(iTime * 2.0));\n float d = length(q - cell);\n float ink = smoothstep(radius + 0.06, radius - 0.06, d);\n fragColor = vec4(mix(uPaper, uInk, ink), pic.a);\n}`,\n ),\n};\n\nexport const crt: ShaderEffect = {\n kind: \"shader\",\n id: \"crt\",\n name: \"CRT screen\",\n description: \"An image on a curved CRT: scanlines, shadow mask, bloom and flicker.\",\n category: \"image\",\n tags: [\"image\", \"retro\", \"screen\", \"arcade\"],\n source: glsl(\n `// CRT screen: an image on a curved tube with scanlines and a shadow mask.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uCurve; // @control min=0 max=0.5 default=0.15 label=\"Curvature\"\nuniform float uScanlines; // @control min=0 max=1 default=0.5 label=\"Scanlines\"\nuniform float uMask; // @control min=0 max=1 default=0.35 label=\"Shadow mask\"\nuniform float uFlicker; // @control min=0 max=0.2 default=0.03 label=\"Flicker\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy * 2.0 - 1.0;\n uv *= 1.0 + uCurve * dot(uv.yx, uv.yx) * 0.5;\n vec2 st = uv * 0.5 + 0.5;\n if (st.x < 0.0 || st.x > 1.0 || st.y < 0.0 || st.y > 1.0) {\n fragColor = vec4(0.0, 0.0, 0.0, uBackdropAlpha);\n return;\n }\n vec4 pic = pictureRGBA(uImage, st);\n vec3 col = pic.rgb;\n col += 0.25 * picture(uImage, st + vec2(0.003, 0.0)) * col;\n float scan = 1.0 - uScanlines * 0.5 * (1.0 - cos(st.y * iResolution.y * 3.14159));\n float m = mod(fragCoord.x, 3.0);\n vec3 mask = mix(vec3(1.0), vec3(m < 1.0 ? 1.2 : 0.8, m >= 1.0 && m < 2.0 ? 1.2 : 0.8, m >= 2.0 ? 1.2 : 0.8), uMask);\n col *= scan * mask;\n col *= 1.0 - uFlicker * hash12(vec2(floor(iTime * 24.0), 0.0));\n col *= smoothstep(1.0, 0.7, max(abs(uv.x), abs(uv.y)) * 0.98 + 0.02 * length(uv));\n fragColor = vec4(col, pic.a);\n}`,\n ),\n};\n\nexport const filmGrain: ShaderEffect = {\n kind: \"shader\",\n id: \"film-look\",\n name: \"Film look\",\n description: \"An image graded like film: grain, gate weave, halation and vignette.\",\n category: \"image\",\n tags: [\"image\", \"cinematic\", \"grain\", \"vintage\"],\n source: glsl(\n `// Film look: grain, gate weave, halation and vignette.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uGrain; // @control min=0 max=0.3 default=0.08 label=\"Grain\"\nuniform float uWeave; // @control min=0 max=0.01 default=0.0015 label=\"Gate weave\"\nuniform float uHalation; // @control min=0 max=1 default=0.3 label=\"Halation\"\nuniform float uVignette; // @control min=0 max=1 default=0.45 label=\"Vignette\"\nuniform vec3 uTint; // @control color default=#FFF1DC label=\"Print tint\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float frame = floor(iTime * 24.0);\n uv += uWeave * (vec2(vnoise(vec2(frame * 0.3, 0.0)), vnoise(vec2(0.0, frame * 0.3))) - 0.5);\n vec4 pic = pictureRGBA(uImage, uv);\n vec3 col = pic.rgb;\n vec3 blur = (picture(uImage, uv + vec2(0.006, 0.0)) + picture(uImage, uv - vec2(0.006, 0.0)) +\n picture(uImage, uv + vec2(0.0, 0.006)) + picture(uImage, uv - vec2(0.0, 0.006))) * 0.25;\n float bright = smoothstep(0.6, 1.0, dot(blur, vec3(0.333)));\n col += vec3(1.0, 0.3, 0.1) * bright * uHalation * 0.5;\n col *= uTint;\n col += (hash12(fragCoord + frame * 31.7) - 0.5) * uGrain;\n col *= 1.0 - uVignette * smoothstep(0.3, 0.9, length(uv - 0.5) * 1.3);\n fragColor = vec4(col, pic.a);\n}`,\n ),\n};\n\nconst TRANSITIONS: { type: TransitionType; id: string; name: string; description: string }[] = [\n { type: \"linearWipe\", id: \"wipe\", name: \"Wipe\", description: \"A soft-edged wipe from one image to the next.\" },\n { type: \"radialIris\", id: \"iris\", name: \"Iris\", description: \"A circle opening from the centre onto the next image.\" },\n { type: \"blockDissolve\", id: \"block-dissolve\", name: \"Block dissolve\", description: \"Random blocks switching to the next image.\" },\n { type: \"gridWipe\", id: \"grid-wipe\", name: \"Grid wipe\", description: \"A diagonal cascade of cells revealing the next image.\" },\n { type: \"glassWipe\", id: \"glass-wipe\", name: \"Glass wipe\", description: \"A refracting glass edge sweeping across.\" },\n { type: \"twister\", id: \"twister\", name: \"Twister\", description: \"A swirl that twists one image into the next.\" },\n { type: \"lightLeak\", id: \"light-leak\", name: \"Light leak\", description: \"A warm flare of light burning through to the next image.\" },\n { type: \"crossZoom\", id: \"cross-zoom\", name: \"Cross zoom\", description: \"A zoom blur punching through to the next image.\" },\n];\n\n/** The transitions (see `getTransitionGLSL`) as looping effects between two images. */\nexport const transitions: ShaderEffect[] = TRANSITIONS.map(({ type, id, name, description }) => ({\n kind: \"shader\",\n id: `transition-${id}`,\n name,\n description: `${description} Loops back and forth; or turn Animate off and set Progress.`,\n category: \"transition\",\n tags: [\"transition\", \"image\", \"slideshow\"],\n loop: 4,\n source: glsl(\n `// ${name} transition between two images. Progress runs 0 → 1 → 0 when animated.\nuniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"From image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"To image\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\n${BACKDROP_CONTROLS}`,\n BACKDROP,\n getTransitionGLSL(type),\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float p = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n fragColor = overBackdrop(flair_transition(uFrom, uTo, uv, p));\n}`,\n ),\n}));\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const bokeh: ShaderEffect = {\n kind: \"shader\",\n id: \"bokeh\",\n name: \"Bokeh\",\n description: \"Out-of-focus city lights drifting softly.\",\n category: \"light\",\n tags: [\"background\", \"festive\", \"dreamy\", \"night\"],\n source: glsl(\n `// Bokeh: soft out-of-focus lights drifting.\nuniform vec3 uBackground; // @control color default=#0B1026 label=\"Background\"\nuniform float uBackgroundAlpha; // @control min=0 max=1 default=1 label=\"Background opacity\"\nuniform vec3 uWarm; // @control color default=#FFC56E label=\"Warm light\"\nuniform vec3 uCool; // @control color default=#6EC8FF label=\"Cool light\"\nuniform int uCount; // @control min=4 max=60 default=30 label=\"Lights\"\nuniform float uSize; // @control min=0.02 max=0.25 default=0.08 label=\"Size\"\nuniform float uSpeed; // @control min=0 max=1 default=0.15 label=\"Drift\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec3 col = uBackground * (0.7 + 0.3 * fragCoord.y / iResolution.y) * uBackgroundAlpha;\n float lightAlpha = 0.0;\n for (int i = 0; i < 60; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 h = hash22(vec2(fi, 3.1));\n float depth = hash12(vec2(fi, 9.7));\n vec2 c = vec2(fract(h.x + iTime * uSpeed * (0.2 + depth) * 0.1) * (aspect + 0.4) - 0.2, h.y);\n c.y += 0.03 * sin(iTime * 0.5 + fi);\n float r = uSize * (0.5 + depth);\n float d = length(p - c);\n float disc = smoothstep(r, r * 0.85, d) * (0.6 + 0.4 * smoothstep(r * 0.4, r, d));\n vec3 light = mix(uWarm, uCool, step(0.5, hash12(vec2(fi, 1.3))));\n float weight = disc * (0.15 + 0.25 * (1.0 - depth));\n col += light * weight;\n lightAlpha += weight;\n }\n float a = clamp(uBackgroundAlpha + lightAlpha * (1.0 - uBackgroundAlpha), 0.0, 1.0);\n fragColor = vec4(col, a);\n}`,\n ),\n};\n\nexport const godRays: ShaderEffect = {\n kind: \"shader\",\n id: \"god-rays\",\n name: \"God rays\",\n description: \"Shafts of light fanning down through haze.\",\n category: \"light\",\n tags: [\"background\", \"hero\", \"heavenly\", \"spotlight\"],\n source: glsl(\n `// God rays: shafts of light fanning through haze.\nuniform vec3 uBackground; // @control color default=#0C0A09 label=\"Background\"\nuniform vec3 uLight; // @control color default=#FDE68A label=\"Light\"\nuniform vec2 uSource; // @control min=-1 max=1 default=0,0.6 label=\"Source\"\nuniform float uRays; // @control min=4 max=60 default=18 label=\"Rays\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Speed\"\nuniform float uStrength; // @control min=0 max=2 default=1 label=\"Strength\"`,\n HASH,\n NOISE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec2 d = p - uSource * vec2(iResolution.x / iResolution.y, 1.0) * 0.5;\n float a = atan(d.x, -d.y);\n float r = length(d);\n float t = iTime * uSpeed;\n float rays = vnoise(vec2(a * uRays, t)) * 0.6 + vnoise(vec2(a * uRays * 2.3, -t * 1.3)) * 0.4;\n rays = pow(rays, 2.0) * smoothstep(1.6, 0.0, r);\n float glow = exp(-r * 4.0);\n vec3 col = uBackground + uLight * (rays * 0.9 + glow * 0.8) * uStrength;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const sparkles: ShaderEffect = {\n kind: \"shader\",\n id: \"sparkles\",\n name: \"Sparkles\",\n description: \"Four-pointed glints twinkling on and off across the frame.\",\n category: \"light\",\n tags: [\"overlay\", \"magic\", \"celebration\", \"premium\"],\n source: glsl(\n `// Sparkles: four-pointed glints twinkling across the frame.\nuniform vec3 uBackground; // @control color default=#1E1B4B label=\"Background\"\nuniform float uBackgroundAlpha; // @control min=0 max=1 default=1 label=\"Background opacity\"\nuniform vec3 uSparkle; // @control color default=#FFFFFF label=\"Sparkle\"\nuniform float uDensity; // @control min=2 max=30 default=10 label=\"Density\"\nuniform float uChance; // @control min=0.02 max=1 default=1 label=\"Sparsity\"\nuniform float uSize; // @control min=0.05 max=0.5 default=0.35 label=\"Size\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Twinkle speed\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uDensity;\n float glint = 0.0;\n for (int layer = 0; layer < 2; layer++) {\n vec2 q = p * (1.0 + float(layer) * 0.6) + float(layer) * 7.3;\n vec2 id = floor(q);\n float keep = step(1.0 - uChance, hash12(id + 19.0 + float(layer) * 31.0));\n vec2 f = fract(q) - 0.5;\n vec2 o = hash22(id) - 0.5;\n vec2 d = f - o * 0.6;\n float phase = hash12(id + 4.0) * 6.28318;\n float tw = pow(max(0.0, sin(iTime * uSpeed * 2.0 + phase)), 4.0);\n float r = length(d);\n float rays = max(0.0, 1.0 - abs(d.x * d.y) * 3000.0);\n float core = 0.01 / (r + 0.01);\n float star = (rays * 0.8 + core) * smoothstep(uSize, 0.0, r) * tw * keep;\n glint += star;\n }\n vec3 col = uBackground * uBackgroundAlpha + uSparkle * glint;\n float a = clamp(uBackgroundAlpha + glint * (1.0 - uBackgroundAlpha), 0.0, 1.0);\n fragColor = vec4(col, a);\n}`,\n ),\n};\n\nexport const neonRipple: ShaderEffect = {\n kind: \"shader\",\n id: \"neon-ripple\",\n name: \"Neon ripple\",\n description: \"Glowing neon rings radiating out from the pointer or the centre.\",\n category: \"light\",\n tags: [\"interactive\", \"glow\", \"music\", \"pulse\"],\n loop: 2,\n source: glsl(\n `// Neon ripple: glowing rings radiating from the pointer (or the centre).\nuniform vec3 uBackground; // @control color default=#09090B label=\"Background\"\nuniform vec3 uNeon; // @control color default=#FF2BD6 label=\"Neon\"\nuniform float uRings; // @control min=1 max=10 default=4 label=\"Rings\"\nuniform float uWidth; // @control min=0.002 max=0.05 default=0.01 label=\"Width\"\nuniform float uGlow; // @control min=0 max=3 default=1 label=\"Glow\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 centre = iMouse.z > 0.0 ? iMouse.xy : 0.5 * iResolution.xy;\n float r = length(fragCoord - centre) / iResolution.y;\n float phase = fract(r * uRings - iTime * 0.5);\n float ringDist = min(phase, 1.0 - phase) / uRings;\n float fade = smoothstep(1.2, 0.0, r);\n float core = smoothstep(uWidth, 0.0, ringDist);\n float glow = uWidth * 2.0 / (ringDist + uWidth) * 0.25 * uGlow;\n vec3 col = uBackground + uNeon * (core + glow) * fade;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const starfield: ShaderEffect = {\n kind: \"shader\",\n id: \"starfield\",\n name: \"Warp starfield\",\n description: \"Flying through a field of stars, from cruising to warp speed.\",\n category: \"space\",\n tags: [\"background\", \"space\", \"speed\", \"sci-fi\"],\n source: glsl(\n `// Warp starfield: flying through layers of stars.\nuniform vec3 uBackground; // @control color default=#000005 label=\"Background\"\nuniform vec3 uStar; // @control color default=#E0E7FF label=\"Star\"\nuniform float uSpeed; // @control min=0 max=4 default=0.6 label=\"Speed\"\nuniform float uStreak; // @control min=0 max=1 default=0.3 label=\"Streak\"\nuniform int uLayers; // @control min=1 max=8 default=5 label=\"Layers\"`,\n HASH,\n ROTATE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec3 col = uBackground;\n float n = float(uLayers);\n for (int i = 0; i < 8; i++) {\n if (i >= uLayers) break;\n float depth = fract(float(i) / n + iTime * uSpeed * 0.1);\n float scale = mix(20.0, 0.5, depth);\n float fade = depth * smoothstep(1.0, 0.85, depth);\n vec2 q = rot(float(i) * 1.7) * p * scale + float(i) * 13.1;\n vec2 id = floor(q);\n vec2 f = fract(q) - 0.5;\n vec2 o = hash22(id) - 0.5;\n vec2 d = f - o * 0.8;\n vec2 dir = normalize(p + 1e-4);\n float along = dot(d, dir);\n float across = length(d - dir * along);\n float len = 0.02 + uStreak * depth * 0.4;\n float star = smoothstep(0.03, 0.0, across) * smoothstep(len, 0.0, abs(along));\n star *= step(0.6, hash12(id + 2.0));\n col += uStar * star * fade * 1.5;\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const nebula: ShaderEffect = {\n kind: \"shader\",\n id: \"nebula\",\n name: \"Nebula\",\n description: \"Glowing gas clouds and stars drifting in deep space.\",\n category: \"space\",\n tags: [\"background\", \"space\", \"cosmic\", \"hero\"],\n source: glsl(\n `// Nebula: glowing gas clouds over a field of stars.\nuniform vec3 uGasA; // @control color default=#7C3AED label=\"Gas A\"\nuniform vec3 uGasB; // @control color default=#EC4899 label=\"Gas B\"\nuniform vec3 uDeep; // @control color default=#020010 label=\"Deep space\"\nuniform float uSpeed; // @control min=0 max=1 default=0.05 label=\"Drift\"\nuniform float uDensity; // @control min=0 max=2 default=1 label=\"Density\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * 2.0;\n float t = iTime * uSpeed;\n vec2 q = vec2(fbm(p + t, 5), fbm(p - t + 3.3, 5));\n float gas = fbm(p * 1.3 + 2.5 * q, 6);\n float dust = smoothstep(0.45, 0.75, fbm(p * 3.0 - q, 5));\n vec3 col = uDeep;\n col += uGasA * smoothstep(0.35, 0.8, gas) * uDensity;\n col += uGasB * smoothstep(0.5, 0.9, gas * q.x * 1.6) * uDensity;\n col *= 1.0 - 0.6 * dust;\n float star = step(0.996, hash12(floor(fragCoord)));\n float bright = step(0.9993, hash12(floor(fragCoord * 0.5) + 7.0));\n col += vec3(star * 0.7 + bright * (0.8 + 0.2 * sin(iTime * 4.0 + fragCoord.x)));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const blackHole: ShaderEffect = {\n kind: \"shader\",\n id: \"event-horizon\",\n name: \"Event horizon\",\n description: \"A glowing accretion disc swirling into a black hole.\",\n category: \"space\",\n tags: [\"space\", \"dramatic\", \"vortex\", \"hero\"],\n source: glsl(\n `// Event horizon: an accretion disc swirling into a black hole.\nuniform vec3 uHot; // @control color default=#FFE4B5 label=\"Hot\"\nuniform vec3 uDisc; // @control color default=#FF6A00 label=\"Disc\"\nuniform float uRadius; // @control min=0.05 max=0.4 default=0.15 label=\"Horizon\"\nuniform float uSpin; // @control min=0 max=4 default=1 label=\"Spin\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n p.y *= 2.2;\n float r = length(p);\n float a = atan(p.y, p.x);\n float swirl = a + uSpin * iTime * 0.5 + 1.5 / (r + 0.05);\n float streaks = fbm(vec2(swirl * 3.0, r * 8.0), 5);\n float disc = smoothstep(uRadius, uRadius * 1.6, r) * smoothstep(1.0, uRadius * 1.6, r);\n vec3 col = mix(uDisc, uHot, smoothstep(0.5, 0.9, streaks) * smoothstep(0.6, 0.1, r));\n col *= disc * (0.4 + 1.2 * streaks);\n col += uHot * 0.6 * exp(-abs(r - uRadius * 1.05) * 60.0);\n col *= smoothstep(uRadius * 0.95, uRadius * 1.05, r);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const lightRibbons: ShaderEffect = {\n kind: \"shader\",\n id: \"light-ribbons\",\n name: \"Light ribbons\",\n description: \"A bundle of thin iridescent light strands weaving across a dark frame.\",\n category: \"light\",\n tags: [\"background\", \"hero\", \"tech\", \"iridescent\", \"flow\"],\n source: glsl(\n `// Light ribbons: thin glowing strands weaving across the frame, shading from one colour to the next.\nuniform vec3 uBackground; // @control color default=#05060D label=\"Background\"\nuniform vec3 uColorA; // @control color default=#4FD1FF label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#B06BFF label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#FF7AC6 label=\"Colour C\"\nuniform float uCount; // @control min=2 max=24 default=12 step=1 label=\"Strands\"\nuniform float uSpread; // @control min=0.02 max=0.6 default=0.18 label=\"Spread\"\nuniform float uWave; // @control min=0 max=0.5 default=0.22 label=\"Wave\"\nuniform float uTilt; // @control min=-1 max=1 default=0.3 label=\"Tilt\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Glow\"`,\n `// Three colours round a loop, so the shading drifts without a seam.\nvec3 shade(float g) {\n g = fract(g) * 3.0;\n return g < 1.0 ? mix(uColorA, uColorB, g) : g < 2.0 ? mix(uColorB, uColorC, g - 1.0) : mix(uColorC, uColorA, g - 2.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n float halfWidth = 0.5 * iResolution.x / iResolution.y;\n float x = p.x;\n float y = p.y - x * uTilt;\n // The bundle pinches and opens along its length, like ribbons twisting.\n float pinch = 0.35 + 0.65 * abs(sin(x * 1.3 - t * 0.7));\n vec3 light = vec3(0.0);\n for (int i = 0; i < 24; i++) {\n if (float(i) >= uCount) break;\n float f = float(i) / max(uCount - 1.0, 1.0) - 0.5;\n float centre = f * uSpread * pinch\n + uWave * (0.6 * sin(x * 1.7 + t + f * 2.0) + 0.3 * sin(x * 3.3 - t * 1.3 + f * 5.0));\n float d = abs(y - centre);\n float core = 1.0 - smoothstep(0.0, px * 1.5, d);\n float glow = uGlow * 0.006 / (d + 0.006);\n light += shade(f * 0.6 + x * 0.12 + t * 0.05) * (core * 0.9 + glow * 0.4);\n }\n light *= 1.0 - 0.75 * pow(min(abs(x) / halfWidth, 1.0), 2.0);\n fragColor = vec4(uBackground + (1.0 - exp(-light)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Gold\", values: { uBackground: [0.03, 0.03, 0.04], uColorA: [1, 0.78, 0.4], uColorB: [0.75, 0.5, 0.2], uColorC: [1, 0.93, 0.75], uCount: 8, uSpread: 0.4 } },\n { name: \"Aurora\", values: { uColorA: [0.2, 1, 0.7], uColorB: [0.2, 0.6, 1], uColorC: [0.6, 0.3, 1], uTilt: -0.2, uWave: 0.3 } },\n ],\n};\n","import { FBM, glsl, HASH, NOISE, PALETTE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const marble: ShaderEffect = {\n kind: \"shader\",\n id: \"marble\",\n name: \"Liquid marble\",\n description: \"Veined marble swirling like ink in water (domain-warped noise).\",\n category: \"organic\",\n tags: [\"background\", \"ink\", \"liquid\", \"luxury\"],\n source: glsl(\n `// Liquid marble: domain-warped noise swirling like ink in water.\nuniform vec3 uStone; // @control color default=#F5F1E8 label=\"Stone\"\nuniform vec3 uVein; // @control color default=#1F2937 label=\"Vein\"\nuniform vec3 uAccent; // @control color default=#B08D57 label=\"Accent\"\nuniform float uSpeed; // @control min=0 max=1 default=0.15 label=\"Speed\"\nuniform float uScale; // @control min=0.5 max=6 default=2.5 label=\"Scale\"\nuniform float uWarp; // @control min=0 max=8 default=4 label=\"Warp\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n float t = iTime * uSpeed;\n vec2 q = vec2(fbm(p + vec2(0.0, t), 5), fbm(p + vec2(5.2, 1.3 - t), 5));\n vec2 r = vec2(fbm(p + uWarp * q + vec2(1.7, 9.2) + 0.3 * t, 5), fbm(p + uWarp * q + vec2(8.3, 2.8), 5));\n float f = fbm(p + uWarp * r, 5);\n float vein = 1.0 - smoothstep(0.0, 0.06, abs(sin(f * 12.0 + r.x * 6.0)));\n vec3 col = mix(uStone, uStone * 0.85, length(q) * 0.6);\n col = mix(col, uAccent, smoothstep(0.55, 0.9, r.y) * 0.5);\n col = mix(col, uVein, vein * 0.85);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Nero\", values: { uStone: [0.08, 0.08, 0.09], uVein: [0.9, 0.88, 0.82], uAccent: [0.7, 0.55, 0.3] } },\n { name: \"Jade\", values: { uStone: [0.18, 0.45, 0.35], uVein: [0.85, 0.95, 0.88], uAccent: [0.05, 0.2, 0.15] } },\n ],\n};\n\nexport const smoke: ShaderEffect = {\n kind: \"shader\",\n id: \"smoke\",\n name: \"Smoke\",\n description: \"Billowing smoke or cloud drifting upwards.\",\n category: \"organic\",\n tags: [\"background\", \"atmosphere\", \"cloud\", \"mist\"],\n source: glsl(\n `// Smoke: billowing fractal noise drifting upwards.\nuniform vec3 uBackground; // @control color default=#0B0F19 label=\"Background\"\nuniform vec3 uSmoke; // @control color default=#CBD5E1 label=\"Smoke\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Speed\"\nuniform float uDensity; // @control min=0 max=2 default=1 label=\"Density\"\nuniform int uDetail; // @control min=1 max=8 default=6 label=\"Detail\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * 3.0;\n float t = iTime * uSpeed;\n p.y -= t;\n float n = fbm(p + fbm(p + vec2(t * 0.3, 0.0), uDetail), uDetail);\n float body = smoothstep(0.35, 0.85, n) * uDensity;\n float fade = smoothstep(0.0, 0.7, fragCoord.y / iResolution.y + 0.2);\n vec3 col = mix(uBackground, uSmoke, clamp(body * fade, 0.0, 1.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const lavaLamp: ShaderEffect = {\n kind: \"shader\",\n id: \"lava-lamp\",\n name: \"Lava lamp\",\n description: \"Soft metaballs merging and parting as they rise and fall.\",\n category: \"organic\",\n tags: [\"background\", \"playful\", \"blobs\", \"retro\"],\n source: glsl(\n `// Lava lamp: metaballs merging as they rise and fall.\nuniform vec3 uBackground; // @control color default=#1A0B2E label=\"Background\"\nuniform vec3 uBlobA; // @control color default=#FF5E8A label=\"Blob A\"\nuniform vec3 uBlobB; // @control color default=#FFB347 label=\"Blob B\"\nuniform int uCount; // @control min=2 max=12 default=7 label=\"Blobs\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform float uSize; // @control min=0.02 max=0.3 default=0.12 label=\"Size\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float t = iTime * uSpeed;\n float field = 0.0;\n float tint = 0.0;\n for (int i = 0; i < 12; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 seed = hash22(vec2(fi, 7.0));\n vec2 c = vec2(seed.x * aspect, 0.5 + 0.45 * sin(t * (0.4 + seed.y) + fi * 2.1));\n c.x += 0.1 * sin(t * 0.7 + fi);\n float r = uSize * (0.7 + 0.6 * seed.y);\n float k = r * r / dot(p - c, p - c);\n field += k;\n tint += k * seed.x;\n }\n float inside = smoothstep(0.9, 1.1, field);\n vec3 blob = mix(uBlobA, uBlobB, clamp(tint / max(field, 1e-3), 0.0, 1.0));\n blob *= 0.85 + 0.15 * smoothstep(1.0, 3.0, field);\n vec3 col = mix(uBackground, blob, inside);\n col += blob * 0.15 * smoothstep(0.3, 0.9, field) * (1.0 - inside);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const plasma: ShaderEffect = {\n kind: \"shader\",\n id: \"plasma\",\n name: \"Plasma\",\n description: \"The demoscene classic: interfering sine waves through a colour palette.\",\n category: \"organic\",\n tags: [\"background\", \"retro\", \"psychedelic\", \"loop\"],\n loop: 6.28318,\n source: glsl(\n `// Plasma: interfering sine waves through a cosine palette.\nuniform float uScale; // @control min=1 max=20 default=8 label=\"Scale\"\nuniform float uShift; // @control min=0 max=1 default=0 label=\"Hue shift\"\nuniform vec3 uPhase; // @control min=0 max=1 default=0,0.33,0.67 label=\"Palette phase\"`,\n PALETTE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uScale;\n float t = iTime;\n float v = sin(p.x + t);\n v += sin((p.y + t) * 0.5);\n v += sin((p.x + p.y + t) * 0.5);\n vec2 c = p + vec2(sin(t * 0.5), cos(t * 0.5)) * uScale * 0.3;\n v += sin(sqrt(dot(c, c) + 1.0) + t);\n vec3 col = palette(v * 0.25 + uShift, vec3(0.5), vec3(0.5), vec3(1.0), uPhase);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const caustics: ShaderEffect = {\n kind: \"shader\",\n id: \"caustics\",\n name: \"Caustics\",\n description: \"Light dancing on the floor of a swimming pool.\",\n category: \"organic\",\n tags: [\"background\", \"water\", \"summer\", \"calm\"],\n source: glsl(\n `// Caustics: light dancing on the floor of a pool.\nuniform vec3 uWater; // @control color default=#0369A1 label=\"Water\"\nuniform vec3 uLight; // @control color default=#E0F2FE label=\"Light\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform float uScale; // @control min=1 max=10 default=4 label=\"Scale\"\nuniform float uBright; // @control min=0 max=2 default=1 label=\"Brightness\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n // After Dave Hoskins' \"Tileable water caustic\".\n vec2 uv = fragCoord / iResolution.y * uScale * 0.25;\n float t = iTime * uSpeed * 0.5 + 23.0;\n vec2 p = mod(uv * 6.28318, 6.28318) - 250.0;\n vec2 i = p;\n float c = 1.0;\n float inten = 0.005;\n for (int n = 0; n < 5; n++) {\n float tn = t * (1.0 - 3.5 / float(n + 1));\n i = p + vec2(cos(tn - i.x) + sin(tn + i.y), sin(tn - i.y) + cos(tn + i.x));\n c += 1.0 / length(vec2(p.x / (sin(i.x + tn) / inten), p.y / (cos(i.y + tn) / inten)));\n }\n c /= 5.0;\n c = 1.17 - pow(c, 1.4);\n float light = pow(abs(c), 8.0) * uBright;\n vec3 col = uWater + uLight * clamp(light, 0.0, 1.5);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const flames: ShaderEffect = {\n kind: \"shader\",\n id: \"flames\",\n name: \"Flames\",\n description: \"A wall of fire licking upwards from the bottom edge.\",\n category: \"organic\",\n tags: [\"fire\", \"energy\", \"hot\", \"overlay\"],\n source: glsl(\n `// Flames: a wall of fire licking upwards.\nuniform vec3 uHot; // @control color default=#FFF3B0 label=\"Hot\"\nuniform vec3 uMid; // @control color default=#FF7A00 label=\"Mid\"\nuniform vec3 uCool; // @control color default=#7A0000 label=\"Cool\"\nuniform float uSpeed; // @control min=0 max=3 default=1.2 label=\"Speed\"\nuniform float uHeight; // @control min=0.1 max=1.5 default=0.7 label=\"Height\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = vec2(fragCoord.x / iResolution.y, uv.y);\n float t = iTime * uSpeed;\n float n = fbm(vec2(p.x * 4.0, p.y * 3.0 - t * 1.5), 5);\n float heat = (1.0 - uv.y / uHeight) + (n - 0.5) * 1.1;\n heat = clamp(heat, 0.0, 1.0);\n vec3 col = mix(vec3(0.0), uCool, smoothstep(0.05, 0.3, heat));\n col = mix(col, uMid, smoothstep(0.3, 0.6, heat));\n col = mix(col, uHot, smoothstep(0.6, 0.95, heat));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Spirit\", values: { uHot: [0.85, 1, 1], uMid: [0.2, 0.6, 1], uCool: [0.05, 0.05, 0.4] } },\n { name: \"Toxic\", values: { uHot: [0.95, 1, 0.7], uMid: [0.4, 0.95, 0.2], uCool: [0.05, 0.25, 0.05] } },\n ],\n};\n","import { glsl, HASH, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const dotWave: ShaderEffect = {\n kind: \"shader\",\n id: \"dot-wave\",\n name: \"Dot wave\",\n description: \"A halftone grid of dots swelling in a travelling wave.\",\n category: \"pattern\",\n tags: [\"background\", \"halftone\", \"tech\", \"minimal\"],\n loop: 4,\n source: glsl(\n `// Dot wave: a grid of dots swelling in a travelling wave.\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"\nuniform vec3 uDot; // @control color default=#38BDF8 label=\"Dot\"\nuniform float uSpacing; // @control min=8 max=64 default=22 label=\"Spacing (px)\"\nuniform float uWaves; // @control min=0.5 max=6 default=2 label=\"Waves\"\nuniform bool uRadial; // @control default=true label=\"Radial\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uSpacing);\n vec2 local = fract(fragCoord / uSpacing) - 0.5;\n vec2 centre = (cell + 0.5) * uSpacing;\n vec2 p = (centre - 0.5 * iResolution.xy) / iResolution.y;\n float d = uRadial ? length(p) : p.x + p.y * 0.3;\n float phase = d * uWaves * 6.28318 - iTime * 6.28318 / 4.0;\n float size = 0.1 + 0.32 * (0.5 + 0.5 * sin(phase));\n float aa = 1.5 / uSpacing;\n float disc = 1.0 - smoothstep(size - aa, size + aa, length(local));\n vec3 col = mix(uBackground, uDot * (0.6 + 0.4 * size / 0.42), disc);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const truchet: ShaderEffect = {\n kind: \"shader\",\n id: \"truchet\",\n name: \"Truchet flow\",\n description: \"Quarter-circle Truchet tiles forming endless winding paths, with light flowing along them.\",\n category: \"pattern\",\n tags: [\"background\", \"maze\", \"geometric\", \"tech\"],\n source: glsl(\n `// Truchet flow: winding quarter-circle tiles with light flowing along them.\nuniform vec3 uBackground; // @control color default=#111827 label=\"Background\"\nuniform vec3 uLine; // @control color default=#F472B6 label=\"Line\"\nuniform float uTiles; // @control min=3 max=30 default=10 label=\"Tiles\"\nuniform float uWidth; // @control min=0.02 max=0.3 default=0.1 label=\"Line width\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Flow speed\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uTiles;\n vec2 id = floor(p);\n vec2 f = fract(p) - 0.5;\n float flip = hash12(id) > 0.5 ? 1.0 : -1.0;\n f.x *= flip;\n vec2 c = f.x > -f.y ? vec2(0.5) : vec2(-0.5);\n vec2 q = f - c;\n float d = abs(length(q) - 0.5);\n float angle = atan(q.y, q.x);\n float checker = mod(id.x + id.y, 2.0) * 2.0 - 1.0;\n float flow = 0.5 + 0.5 * sin(angle * 4.0 * checker * flip + iTime * uSpeed * 4.0);\n float line = 1.0 - smoothstep(uWidth - 0.02, uWidth, d);\n vec3 col = mix(uBackground, uLine * (0.45 + 0.75 * flow), line);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const hexPulse: ShaderEffect = {\n kind: \"shader\",\n id: \"hex-pulse\",\n name: \"Hex pulse\",\n description: \"A honeycomb grid lighting up cell by cell in ripples.\",\n category: \"pattern\",\n tags: [\"background\", \"tech\", \"honeycomb\", \"sci-fi\"],\n source: glsl(\n `// Hex pulse: a honeycomb grid lighting up in ripples.\nuniform vec3 uBackground; // @control color default=#020617 label=\"Background\"\nuniform vec3 uEdge; // @control color default=#22D3EE label=\"Edge\"\nuniform vec3 uFill; // @control color default=#0E7490 label=\"Fill\"\nuniform float uCells; // @control min=3 max=40 default=12 label=\"Cells\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"`,\n HASH,\n `vec4 hexCoords(vec2 p) {\n vec2 r = vec2(1.0, 1.7320508);\n vec2 h = r * 0.5;\n vec2 a = mod(p, r) - h;\n vec2 b = mod(p - h, r) - h;\n vec2 gv = dot(a, a) < dot(b, b) ? a : b;\n return vec4(gv, p - gv);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uCells;\n vec4 h = hexCoords(p);\n vec2 gv = abs(h.xy);\n float edgeDist = 0.5 - max(dot(gv, normalize(vec2(1.0, 1.7320508))), gv.x);\n float ripple = 0.5 + 0.5 * sin(length(h.zw) * 0.6 - iTime * uSpeed * 3.0);\n float spark = step(0.92, hash12(h.zw + floor(iTime * uSpeed * 2.0)));\n float lit = clamp(pow(ripple, 6.0) + spark * 0.6, 0.0, 1.0);\n vec3 col = mix(uBackground, uFill, lit * smoothstep(0.0, 0.1, edgeDist));\n col = mix(col, uEdge, (1.0 - smoothstep(0.0, 0.04, edgeDist)) * (0.3 + 0.7 * ripple));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const moire: ShaderEffect = {\n kind: \"shader\",\n id: \"moire\",\n name: \"Moiré rings\",\n description: \"Two sets of concentric rings sliding over each other into shimmering interference.\",\n category: \"pattern\",\n tags: [\"background\", \"op-art\", \"hypnotic\", \"minimal\"],\n source: glsl(\n `// Moiré rings: two ring sets interfering as they slide.\nuniform vec3 uInk; // @control color default=#111111 label=\"Ink\"\nuniform vec3 uPaper; // @control color default=#F5F5F0 label=\"Paper\"\nuniform float uRings; // @control min=10 max=200 default=80 label=\"Rings\"\nuniform float uDrift; // @control min=0 max=0.5 default=0.15 label=\"Drift\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec2 o = uDrift * vec2(sin(iTime * 0.4), cos(iTime * 0.3));\n float a = sin(length(p - o) * uRings);\n float b = sin(length(p + o) * uRings);\n float v = smoothstep(-0.2, 0.2, a * b);\n fragColor = vec4(mix(uInk, uPaper, v), 1.0);\n}`,\n ),\n};\n\nexport const barberStripes: ShaderEffect = {\n kind: \"shader\",\n id: \"stripes\",\n name: \"Stripes\",\n description: \"Diagonal stripes marching across, for progress bars, banners and warnings.\",\n category: \"pattern\",\n tags: [\"progress\", \"banner\", \"warning\", \"loop\"],\n loop: 1,\n source: glsl(\n `// Stripes: diagonal stripes marching across.\nuniform vec3 uColorA; // @control color default=#FACC15 label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#18181B label=\"Colour B\"\nuniform float uWidth; // @control min=4 max=120 default=28 label=\"Stripe width (px)\"\nuniform float uAngle; // @control min=-90 max=90 default=45 label=\"Angle (°)\"\nuniform float uSoft; // @control min=0 max=1 default=0.05 label=\"Softness\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float a = radians(uAngle);\n float d = dot(fragCoord, vec2(cos(a), sin(a))) / (uWidth * 2.0);\n float s = fract(d - iTime);\n float edge = max(uSoft * 0.5, 0.5 / uWidth);\n float m = smoothstep(0.5 - edge, 0.5 + edge, s) - smoothstep(1.0 - edge, 1.0, s) + (1.0 - smoothstep(0.0, edge, s));\n fragColor = vec4(mix(uColorA, uColorB, clamp(m, 0.0, 1.0)), 1.0);\n}`,\n ),\n};\n\nexport const voronoi: ShaderEffect = {\n kind: \"shader\",\n id: \"voronoi\",\n name: \"Living cells\",\n description: \"Voronoi cells drifting and dividing, like a microscope slide.\",\n category: \"pattern\",\n tags: [\"background\", \"biology\", \"cells\", \"organic\"],\n source: glsl(\n `// Living cells: drifting Voronoi cells with glowing walls.\nuniform vec3 uBackground; // @control color default=#052E16 label=\"Background\"\nuniform vec3 uCell; // @control color default=#4ADE80 label=\"Cell\"\nuniform vec3 uWall; // @control color default=#DCFCE7 label=\"Wall\"\nuniform float uScale; // @control min=2 max=20 default=6 label=\"Scale\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n vec2 i = floor(p);\n vec2 f = fract(p);\n float d1 = 8.0;\n float d2 = 8.0;\n float shade = 0.0;\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 g = vec2(float(x), float(y));\n vec2 o = hash22(i + g);\n o = 0.5 + 0.4 * sin(iTime * uSpeed + 6.28318 * o);\n float d = length(g + o - f);\n if (d < d1) { d2 = d1; d1 = d; shade = hash12(i + g); }\n else if (d < d2) { d2 = d; }\n }\n }\n float wall = 1.0 - smoothstep(0.0, 0.08, d2 - d1);\n vec3 col = mix(uBackground, uCell * (0.4 + 0.6 * shade), smoothstep(0.9, 0.1, d1));\n col = mix(col, uWall, wall);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const kaleidoscope: ShaderEffect = {\n kind: \"shader\",\n id: \"kaleidoscope\",\n name: \"Kaleidoscope\",\n description: \"Mirrored wedges of shifting colour turning around the centre.\",\n category: \"pattern\",\n tags: [\"psychedelic\", \"music\", \"symmetry\"],\n source: glsl(\n `// Kaleidoscope: mirrored wedges of shifting colour.\nuniform int uSegments; // @control min=2 max=16 default=8 label=\"Segments\"\nuniform float uZoom; // @control min=0.5 max=8 default=3 label=\"Zoom\"\nuniform float uSpeed; // @control min=0 max=2 default=0.4 label=\"Speed\"\nuniform vec3 uTint; // @control color default=#FFFFFF label=\"Tint\"`,\n ROTATE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float n = float(uSegments);\n float a = atan(p.y, p.x) + t * 0.3;\n float r = length(p);\n float wedge = 6.28318 / n;\n a = mod(a, wedge);\n a = abs(a - wedge * 0.5);\n vec2 q = vec2(cos(a), sin(a)) * r * uZoom;\n q = rot(t * 0.2) * q + t;\n vec3 col = 0.5 + 0.5 * cos(vec3(0.0, 2.0, 4.0) + q.x * 2.0 + sin(q.y * 3.0) + t);\n col *= 0.6 + 0.4 * sin(q.x * 5.0) * sin(q.y * 5.0);\n col *= smoothstep(1.2, 0.2, r);\n fragColor = vec4(col * uTint, 1.0);\n}`,\n ),\n};\n\nexport const neonCircuit: ShaderEffect = {\n kind: \"shader\",\n id: \"neon-circuit\",\n name: \"Neon circuit\",\n description: \"Glowing neon traces routed up a circuit board, with pulses of light racing along them.\",\n category: \"pattern\",\n tags: [\"background\", \"neon\", \"circuit\", \"tech\", \"80s\", \"vaporwave\"],\n source: glsl(\n `// Neon circuit: glowing traces climbing a board in rounded jogs, with pulses running along them.\nuniform vec3 uBackground; // @control color default=#170A2E label=\"Background\"\nuniform vec3 uColorA; // @control color default=#FF5FA2 label=\"Trace A\"\nuniform vec3 uColorB; // @control color default=#43E5FF label=\"Trace B\"\nuniform vec3 uColorC; // @control color default=#FFD23F label=\"Trace C\"\nuniform vec3 uColorD; // @control color default=#9D7BFF label=\"Trace D\"\nuniform float uLanes; // @control min=4 max=40 default=14 label=\"Lanes\"\nuniform float uDensity; // @control min=0.1 max=1 default=0.7 label=\"Density\"\nuniform float uWidth; // @control min=0.04 max=0.4 default=0.16 label=\"Line width\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Glow\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Pulse speed\"\nuniform float uPulses; // @control min=0 max=1 default=0.5 label=\"Pulses\"\nuniform float uScroll; // @control min=-2 max=2 default=0.4 label=\"Scroll\"\nuniform float uGrid; // @control min=0 max=1 default=0.3 label=\"Grid\"`,\n HASH,\n `// Each trace k owns lanes 3k..3k+2 and climbs in runs of RUN lanes, jogging\n// sideways between them on rounded corners, so traces never cross.\nconst float RUN = 2.5;\nconst float RADIUS = 0.35;\n\nfloat laneOf(float k, float j) {\n return 3.0 * k + floor(hash12(vec2(k, j) + 0.37) * 3.0) + 0.5;\n}\n\nvec3 traceColor(float k) {\n float h = hash12(vec2(k, 7.3));\n return h < 0.25 ? uColorA : h < 0.5 ? uColorB : h < 0.75 ? uColorC : uColorD;\n}\n\n// Distance to a quarter circle of RADIUS round c, in the quadrant whose signs are q.\nfloat arcDist(vec2 p, vec2 c, vec2 q) {\n vec2 d = p - c;\n return d.x * q.x >= 0.0 && d.y * q.y >= 0.0 ? abs(length(d) - RADIUS) : 1e5;\n}\n\n// Trace k's run j: distance from p to its climb (x) and how far up it p is (y), then\n// the same for its jog into run j + 1 (z, w), measured along the run.\nvec4 run(vec2 p, float k, float j) {\n float x0 = laneOf(k, j - 1.0);\n float x1 = laneOf(k, j);\n float x2 = laneOf(k, j + 1.0);\n float y0 = j * RUN;\n float y1 = y0 + RUN;\n float lo = y0 + (x0 == x1 ? 0.0 : RADIUS);\n float hi = y1 - (x2 == x1 ? 0.0 : RADIUS);\n vec4 r = vec4(length(p - vec2(x1, clamp(p.y, lo, hi))), p.y - y0, 1e5, 0.0);\n if (x2 != x1) {\n float sx = sign(x2 - x1);\n float h = length(p - vec2(clamp(p.x, min(x1, x2) + RADIUS, max(x1, x2) - RADIUS), y1));\n h = min(h, arcDist(p, vec2(x1 + sx * RADIUS, y1 - RADIUS), vec2(-sx, 1.0)));\n h = min(h, arcDist(p, vec2(x2 - sx * RADIUS, y1 + RADIUS), vec2(sx, -1.0)));\n r.zw = vec2(h, RUN + abs(p.x - x1));\n }\n return r;\n}\n\n// How bright a pulse is at s along run j of trace k: a bright head with a fading tail.\n// A pulse crosses one run per cycle and carries on into the next with the next cycle.\nfloat pulseAt(float k, float j, float s) {\n float cycle = iTime * uSpeed * 1.5 + hash12(vec2(k, 8.8));\n float behind = fract(cycle) * (RUN + abs(laneOf(k, j + 1.0) - laneOf(k, j))) - s;\n float lit = step(hash12(vec2(k, floor(cycle) - j)), uPulses);\n return lit * (behind >= 0.0 ? exp(-behind * 0.8) : exp(behind * 30.0));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = uLanes / iResolution.y;\n vec2 p = fragCoord * px;\n p.y += iTime * uScroll;\n\n vec2 g = abs(fract(p / 1.5) - 0.5);\n float grid = 1.0 - smoothstep(0.0, px * 1.5, (0.5 - max(g.x, g.y)) * 1.5);\n vec3 light = uColorD * 0.12 * uGrid * grid;\n\n float home = floor(p.x / 3.0);\n for (int i = -1; i <= 1; i++) {\n float k = home + float(i);\n if (hash12(vec2(k, 1.9)) > uDensity) continue;\n vec2 q = vec2(p.x, p.y + hash12(vec2(k, 4.1)) * RUN);\n float jq = floor(q.y / RUN);\n float w = uWidth * 0.5;\n // The trace's nearest point lights it; each piece's pulse lights only round that piece.\n float d = 1e5;\n float pulse = 0.0;\n for (int b = -1; b <= 1; b++) {\n float j = jq + float(b);\n vec4 r = run(q, k, j);\n d = min(d, min(r.x, r.z));\n pulse = max(pulse, pulseAt(k, j, r.y) * exp(-r.x / uWidth));\n if (r.z < 1e4) pulse = max(pulse, pulseAt(k, j, r.w) * exp(-r.z / uWidth));\n }\n float core = 1.0 - smoothstep(w - px, w + px, d);\n float glow = uGlow * (0.5 * exp(-d / uWidth) + 0.2 * exp(-d / (uWidth * 5.0)));\n vec3 c = traceColor(k);\n light += c * (core * 0.8 + glow + uGlow * pulse) + mix(c, vec3(1.0), 0.7) * core * pulse * 3.0;\n }\n fragColor = vec4(uBackground + (1.0 - exp(-light * 1.4)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Mainframe\", values: { uBackground: [0.0, 0.04, 0.02], uColorA: [0.2, 1, 0.45], uColorB: [0.1, 0.75, 0.35], uColorC: [0.6, 1, 0.7], uColorD: [0.1, 0.5, 0.25] } },\n { name: \"Blueprint\", values: { uBackground: [0.02, 0.06, 0.16], uColorA: [0.35, 0.75, 1], uColorB: [0.6, 0.9, 1], uColorC: [1, 1, 1], uColorD: [0.25, 0.45, 0.9], uGlow: 0.6, uPulses: 0.3 } },\n { name: \"Dense\", values: { uLanes: 26, uDensity: 1, uWidth: 0.12, uPulses: 0.8 } },\n ],\n};\n","import { rgbToHex } from \"../shader/controls.js\";\nimport { morphPaths } from \"../vector/morph.js\";\nimport type { SvgAnimation, SvgMotion } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * UI micro-interactions play in answer to the pointer (`trigger`), not on a\n * loop. Hover and press pictures play to their end while hovered or held and\n * back after, so each is designed to look right backwards too. Click\n * pictures change on steps: a toggle turns on with step 1 and back off with\n * step 2, ending exactly as it started; a one-shot (copy, send, download)\n * has a single step that returns by itself, so every click replays it.\n * Elements a step only flashes (a ring, particles, a tick) snap back to their\n * starting values once hidden, so each round starts from the same look.\n */\n\nconst r1 = (v: number) => Math.round(v * 10) / 10;\nconst r2 = (v: number) => Math.round(v * 100) / 100;\n\n/** A derived number in an animation's numeric field (`count`, `ms`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/** `a` mixed `t` of the way to `b`, colours as written by vector controls ([r, g, b] 0–1). */\nconst mixHex = (a: unknown, b: unknown, t: number) => {\n const x = (Array.isArray(a) ? a : [1, 1, 1]) as number[];\n const y = (Array.isArray(b) ? b : [1, 1, 1]) as number[];\n return rgbToHex([0, 1, 2].map((i) => x[i]! + (y[i]! - x[i]!) * t));\n};\n\n/** Text fitted to `width` units, at most `max` high: its font size and width. */\nfunction fit(text: unknown, width: number, max: number) {\n const e = Math.max(0.6, textWidthEm(String(text)));\n const size = Math.min(max, width / e);\n return { size: r1(size), length: r1(e * size) };\n}\n\n/** A transform scaling by `s` about (`cx`, `cy`). */\nconst about = (cx: number, cy: number, s: number) => `translate(${cx} ${cy}) scale(${r2(s)}) translate(${-cx} ${-cy})`;\n\n/** Instant changes: the attribute snaps to `value` at `delay` (resets of hidden elements). */\nconst snap = (id: string, attr: string, value: string | number, delay: number, step = 1): SvgAnimation => ({\n id,\n step,\n attrs: { [attr]: [value, value] },\n delay,\n ms: 0,\n});\n\nconst SANS = `system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif`;\n\n/** A heart in a 24 box, curves and all. */\nconst HEART = \"M12 20.5 C12 20.5 3 14.8 3 8.8 C3 6 5.2 3.8 8 3.8 C9.7 3.8 11.2 4.7 12 6.1 C12.8 4.7 14.3 3.8 16 3.8 C18.8 3.8 21 6 21 8.8 C21 14.8 12 20.5 12 20.5 Z\";\n\n/** Like button's burst: particles round the heart, from and to these radii. */\nconst PARTICLES = 8;\nconst BURST_FROM = 22;\nconst BURST_TO = 46;\nconst HEART_X = 72;\nconst HEART_Y = 60;\n/** The heart's group: centred on the heart, scaled by `k` (1 at rest). */\nconst heartPose = (k: number) => `translate(${HEART_X} ${HEART_Y}) scale(${r2(2.2 * k)}) translate(-12 -12)`;\n\nexport const likeButton: VectorEffect = {\n kind: \"vector\",\n id: \"like-button\",\n name: \"Like button\",\n description: \"A heart that fills with a springy pop, a ring and a burst of particles as its like count ticks up, and empties again on the next click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"like\", \"heart\", \"toggle\", \"social\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], chip: [0.13, 0.14, 0.19], outline: [0.6, 0.63, 0.7], ink: [0.9, 0.91, 0.95] } },\n { name: \"Purple\", values: { heart: [0.6, 0.3, 1], accent: [1, 0.4, 0.75], count: 1204 } },\n ],\n derived: (v) => ({ liked: Number(v.count) + 1 }),\n motion: {\n svg: `<svg viewBox=\"0 0 240 120\"><!-- {{count: int min=0 max=99999 default=42 label='Start count'}} {{background: color default=#FFFFFF label='Background'}} {{chip: color default=#F3F4F6 label='Button'}} {{outline: color default=#6B7280 label='Outline'}} {{heart: color default=#F43F5E label='Heart'}} {{accent: color default=#FB923C label='Sparks'}} {{ink: color default=#111827 label='Count colour'}} --><rect width=\"240\" height=\"120\" fill=\"{{background}}\"/><rect x=\"20\" y=\"24\" width=\"200\" height=\"72\" rx=\"36\" fill=\"{{chip}}\"/><circle id=\"ring\" cx=\"${HEART_X}\" cy=\"${HEART_Y}\" r=\"14\" fill=\"none\" stroke=\"{{heart}}\" stroke-width=\"0\"/>${Array.from(\n { length: PARTICLES },\n (_, k) => {\n const a = ((k * 360) / PARTICLES - 90) * (Math.PI / 180);\n return `<circle id=\"p${k}\" cx=\"${r1(HEART_X + BURST_FROM * Math.cos(a))}\" cy=\"${r1(HEART_Y + BURST_FROM * Math.sin(a))}\" r=\"0\" fill=\"${k % 2 ? \"{{accent}}\" : \"{{heart}}\"}\"/>`;\n },\n ).join(\"\")}<g id=\"hg\" transform=\"${heartPose(1)}\"><path id=\"heartShape\" d=\"${HEART}\" fill=\"{{heart}}\" fill-opacity=\"0\" stroke=\"{{outline}}\" stroke-width=\"1.8\" stroke-linejoin=\"round\"/></g><text id=\"tally\" x=\"106\" y=\"70.5\" font-family=\"${SANS}\" font-size=\"30\" font-weight=\"700\" fill=\"{{ink}}\">{{count}}</text></svg>`,\n animate: [\n // Step 1, like: squash, pop past full size and settle while it fills.\n { id: \"hg\", step: 1, attrs: { transform: [heartPose(1), heartPose(0.78)] }, ms: 110, ease: \"out\" },\n { id: \"hg\", step: 1, attrs: { transform: [heartPose(0.78), heartPose(1.22)] }, delay: 110, ms: 170, ease: \"out\" },\n { id: \"hg\", step: 1, attrs: { transform: [heartPose(1.22), heartPose(1)] }, delay: 280, ms: 220, ease: \"in-out\" },\n { id: \"heartShape\", step: 1, attrs: { \"fill-opacity\": [0, 1], stroke: [\"{{outline}}\", \"{{heart}}\"] }, delay: 110, ms: 120 },\n // The ring and sparks burst out, then snap back once they are gone.\n snap(\"ring\", \"stroke-width\", 0, 0),\n { id: \"ring\", step: 1, attrs: { r: [14, 44], \"stroke-width\": [10, 0] }, delay: 130, ms: 480, ease: \"out\" },\n snap(\"ring\", \"r\", 14, 700),\n ...Array.from({ length: PARTICLES }, (_, k): SvgAnimation[] => {\n const a = ((k * 360) / PARTICLES - 90) * (Math.PI / 180);\n const [x0, y0] = [r1(HEART_X + BURST_FROM * Math.cos(a)), r1(HEART_Y + BURST_FROM * Math.sin(a))];\n const [x1, y1] = [r1(HEART_X + BURST_TO * Math.cos(a)), r1(HEART_Y + BURST_TO * Math.sin(a))];\n return [\n snap(`p${k}`, \"r\", 0, 0),\n { id: `p${k}`, step: 1, attrs: { cx: [x0, x1], cy: [y0, y1], r: [4.5, 0] }, delay: 150, ms: 520, ease: \"out\" },\n snap(`p${k}`, \"cx\", x0, 700),\n snap(`p${k}`, \"cy\", y0, 700),\n ];\n }).flat(),\n { id: \"tally\", step: 1, count: [n(\"count\"), n(\"liked\")], attrs: { fill: [\"{{ink}}\", \"{{heart}}\"] }, delay: 150, ms: 260, ease: \"out\" },\n // Step 2, unlike: a small dip as it empties and the count goes back.\n { id: \"hg\", step: 2, attrs: { transform: [heartPose(1), heartPose(0.86)] }, ms: 120, ease: \"out\" },\n { id: \"hg\", step: 2, attrs: { transform: [heartPose(0.86), heartPose(1)] }, delay: 120, ms: 200, ease: \"in-out\" },\n { id: \"heartShape\", step: 2, attrs: { \"fill-opacity\": [1, 0], stroke: [\"{{heart}}\", \"{{outline}}\"] }, ms: 180 },\n { id: \"tally\", step: 2, count: [n(\"liked\"), n(\"count\")], attrs: { fill: [\"{{heart}}\", \"{{ink}}\"] }, ms: 220, ease: \"out\" },\n ],\n },\n};\n\nexport const toggleSwitch: VectorEffect = {\n kind: \"vector\",\n id: \"toggle-switch\",\n name: \"Toggle switch\",\n description: \"A switch whose knob slides across, squashing a little mid-slide, as the track blends to its on colour; the next click slides it back.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"toggle\", \"switch\", \"settings\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"iOS\", values: { on: [0.2, 0.78, 0.35] } },\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], off: [0.22, 0.24, 0.3], on: [0.55, 0.45, 1], knob: [0.96, 0.96, 1] } },\n ],\n motion: ((): SvgMotion => {\n const slide = (from: number, to: number, step: number): SvgAnimation[] => [\n { id: \"slide\", step, attrs: { transform: [`translate(${from} 0)`, `translate(${to} 0)`] }, ms: 320, ease: \"in-out\" },\n // Stretched along the slide and flattened halfway, round again at the end.\n { id: \"knob\", step, attrs: { rx: [19, 24], ry: [19, 16.5] }, ms: 160, ease: \"out\" },\n { id: \"knob\", step, attrs: { rx: [24, 19], ry: [16.5, 19] }, delay: 160, ms: 160, ease: \"in-out\" },\n ];\n return {\n svg: `<svg viewBox=\"0 0 200 120\"><!-- {{background: color default=#FFFFFF label='Background'}} {{off: color default=#D1D5DB label='Track off'}} {{on: color default=#6366F1 label='Track on'}} {{knob: color default=#FFFFFF label='Knob'}} --><rect width=\"200\" height=\"120\" fill=\"{{background}}\"/><rect id=\"track\" x=\"40\" y=\"35\" width=\"120\" height=\"50\" rx=\"25\" fill=\"{{off}}\"/><g id=\"slide\" transform=\"translate(0 0)\"><ellipse cx=\"65\" cy=\"62.5\" rx=\"18\" ry=\"18\" fill=\"#000000\" opacity=\"0.16\"/><ellipse id=\"knob\" cx=\"65\" cy=\"60\" rx=\"19\" ry=\"19\" fill=\"{{knob}}\"/></g></svg>`,\n animate: [\n ...slide(0, 70, 1),\n { id: \"track\", step: 1, attrs: { fill: [\"{{off}}\", \"{{on}}\"] }, ms: 320, ease: \"in-out\" },\n ...slide(70, 0, 2),\n { id: \"track\", step: 2, attrs: { fill: [\"{{on}}\", \"{{off}}\"] }, ms: 320, ease: \"in-out\" },\n ],\n };\n })(),\n};\n\nexport const checkbox: VectorEffect = {\n kind: \"vector\",\n id: \"checkbox\",\n name: \"Checkbox\",\n description: \"A labelled checkbox that fills with a press and draws its tick on, then undraws it and empties on the next click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"checkbox\", \"form\", \"toggle\", \"todo\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Green\", values: { accent: [0.13, 0.7, 0.4] } },\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], border: [0.4, 0.43, 0.5], ink: [0.92, 0.93, 0.96], accent: [0.95, 0.6, 0.15], tick: [0.06, 0.07, 0.1] } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 216, 24);\n return { size, length, base: r1(60 + size * 0.35) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 120\"><!-- {{label: text default='Remember me' label='Label'}} {{background: color default=#FFFFFF label='Background'}} {{border: color default=#9CA3AF label='Border'}} {{accent: color default=#6366F1 label='Checked'}} {{tick: color default=#FFFFFF label='Tick'}} {{ink: color default=#111827 label='Label colour'}} --><rect width=\"320\" height=\"120\" fill=\"{{background}}\"/><g id=\"boxg\" transform=\"${about(48, 60, 1)}\"><rect id=\"box\" x=\"30\" y=\"42\" width=\"36\" height=\"36\" rx=\"9\" fill=\"{{accent}}\" fill-opacity=\"0\" stroke=\"{{border}}\" stroke-width=\"3\"/><path id=\"tick\" d=\"M39 60.5 L45.5 67 L58 53.5\" fill=\"none\" stroke=\"{{tick}}\" stroke-width=\"4.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g><text x=\"84\" y=\"{{base}}\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"500\" fill=\"{{ink}}\">{{label}}</text></svg>`,\n animate: [\n // Step 1, check: the box dips as it fills, then the tick draws on.\n { id: \"boxg\", step: 1, attrs: { transform: [about(48, 60, 1), about(48, 60, 0.86)] }, ms: 100, ease: \"out\" },\n { id: \"boxg\", step: 1, attrs: { transform: [about(48, 60, 0.86), about(48, 60, 1)] }, delay: 100, ms: 220, ease: \"in-out\" },\n { id: \"box\", step: 1, attrs: { \"fill-opacity\": [0, 1], stroke: [\"{{border}}\", \"{{accent}}\"] }, ms: 160 },\n // Shown only once it starts drawing: a round cap would leave a dot.\n { id: \"tick\", step: 1, attrs: { opacity: [0, 1] }, delay: 120, ms: 40 },\n { id: \"tick\", step: 1, draw: true, delay: 120, ms: 260, ease: \"out\" },\n // Step 2, uncheck: the tick undraws, then the box empties.\n { id: \"tick\", step: 2, draw: [1, 0], ms: 160, ease: \"in-out\" },\n { id: \"tick\", step: 2, attrs: { opacity: [1, 0] }, delay: 140, ms: 30 },\n { id: \"box\", step: 2, attrs: { \"fill-opacity\": [1, 0], stroke: [\"{{accent}}\", \"{{border}}\"] }, delay: 100, ms: 180 },\n { id: \"boxg\", step: 2, attrs: { transform: [about(48, 60, 1), about(48, 60, 0.92)] }, delay: 100, ms: 90, ease: \"out\" },\n { id: \"boxg\", step: 2, attrs: { transform: [about(48, 60, 0.92), about(48, 60, 1)] }, delay: 190, ms: 160, ease: \"in-out\" },\n ],\n },\n};\n\ntype Point = [number, number];\n\n/**\n * A stroke from `p` to `q`, `width` wide, as a filled outline: round ends,\n * or a flat one at `q` (where a cut stroke meets another without overlap,\n * which `evenodd` would punch a hole through).\n */\nfunction capsule(p: Point, q: Point, width: number, flatEnd = false): string {\n const h = width / 2;\n const a = Math.atan2(q[1] - p[1], q[0] - p[0]);\n const pts: Point[] = [];\n const cap = (c: Point, from: number) => {\n for (let k = 0; k <= 8; k++) {\n const t = from + (k * Math.PI) / 8;\n pts.push([c[0] + h * Math.cos(t), c[1] + h * Math.sin(t)]);\n }\n };\n if (flatEnd) pts.push([q[0] + h * Math.cos(a - Math.PI / 2), q[1] + h * Math.sin(a - Math.PI / 2)], [q[0] + h * Math.cos(a + Math.PI / 2), q[1] + h * Math.sin(a + Math.PI / 2)]);\n else cap(q, a - Math.PI / 2);\n cap(p, a + Math.PI / 2);\n return `M${pts.map((pt) => `${r2(pt[0])} ${r2(pt[1])}`).join(\" L\")} Z`;\n}\n\nconst menuMorphs = new Map<number, [string, string]>();\n\n/** Three bars and the close cross (one whole diagonal, the other cut where it meets it) at a line weight, in a 24 box, morphed once per weight. */\nfunction menuMorph(weight: number): [string, string] {\n if (!menuMorphs.has(weight)) {\n const bars = [7, 12, 17].map((y) => capsule([5, y], [19, y], weight)).join(\" \");\n // A cut stroke ends half a width from the centre, so its corners just touch the whole one.\n const meet = (weight / 2 + 0.05) / Math.SQRT2;\n const cross = [\n capsule([6.5, 6.5], [17.5, 17.5], weight),\n capsule([17.5, 6.5], [12 + meet, 12 - meet], weight, true),\n capsule([6.5, 17.5], [12 - meet, 12 + meet], weight, true),\n ].join(\" \");\n menuMorphs.set(weight, morphPaths(bars, cross, { points: 48 }));\n }\n return menuMorphs.get(weight)!;\n}\n\n/** The menu icon's group: centred in the button, turned `turn` degrees. */\nconst menuPose = (turn: number) => `translate(60 60) rotate(${turn}) scale(3) translate(-12 -12)`;\n\nexport const menuToggle: VectorEffect = {\n kind: \"vector\",\n id: \"menu-toggle\",\n name: \"Menu toggle\",\n description: \"A hamburger menu button whose three bars morph into a close cross as it spins half a turn, and back on the next click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"menu\", \"hamburger\", \"close\", \"morph\", \"navigation\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], button: [0.95, 0.96, 0.97], active: [0.07, 0.09, 0.15], ink: [0.07, 0.09, 0.15], activeInk: [1, 1, 1] } },\n { name: \"Bold\", values: { weight: 3, button: [0.98, 0.8, 0.1], active: [0.95, 0.3, 0.2], ink: [0.1, 0.1, 0.1], activeInk: [1, 1, 1] } },\n ],\n derived: (v) => {\n const [bars, cross] = menuMorph(Math.round(Number(v.weight) * 4) / 4);\n return { bars, cross };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{weight: float min=1 max=3.5 default=2 step=0.25 label='Line weight'}} {{background: color default=#0F172A label='Background'}} {{button: color default=#1E293B label='Button'}} {{active: color default=#6366F1 label='Button open'}} {{ink: color default=#F8FAFC label='Icon'}} {{activeInk: color default=#FFFFFF label='Icon open'}} --><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><rect id=\"bg\" x=\"16\" y=\"16\" width=\"88\" height=\"88\" rx=\"24\" fill=\"{{button}}\"/><g id=\"icon\" transform=\"${menuPose(0)}\"><path id=\"glyph\" d=\"{{bars}}\" fill=\"{{ink}}\" fill-rule=\"evenodd\"/></g></svg>`,\n animate: [\n // Step 1, open: bars to cross while turning half a turn.\n { id: \"glyph\", step: 1, attrs: { d: [\"{{bars}}\", \"{{cross}}\"], fill: [\"{{ink}}\", \"{{activeInk}}\"] }, ms: 450, ease: \"in-out\" },\n { id: \"icon\", step: 1, attrs: { transform: [menuPose(0), menuPose(180)] }, ms: 450, ease: \"in-out\" },\n { id: \"bg\", step: 1, attrs: { fill: [\"{{button}}\", \"{{active}}\"] }, ms: 300, ease: \"in-out\" },\n // Step 2, close: on round the same way (-180° looks like 180°), ending where it started.\n { id: \"glyph\", step: 2, attrs: { d: [\"{{cross}}\", \"{{bars}}\"], fill: [\"{{activeInk}}\", \"{{ink}}\"] }, ms: 450, ease: \"in-out\" },\n { id: \"icon\", step: 2, attrs: { transform: [menuPose(-180), menuPose(0)] }, ms: 450, ease: \"in-out\" },\n { id: \"bg\", step: 2, attrs: { fill: [\"{{active}}\", \"{{button}}\"] }, ms: 300, ease: \"in-out\" },\n ],\n },\n};\n\n/** A bookmark with rounded top corners and a notched foot. */\nconst BOOKMARK = \"M41 22 H79 Q84 22 84 27 V98 L60 81 L36 98 V27 Q36 22 41 22 Z\";\nconst bounce = (y: number) => `translate(0 ${y})`;\n\nexport const bookmark: VectorEffect = {\n kind: \"vector\",\n id: \"bookmark\",\n name: \"Bookmark\",\n description: \"A bookmark that hops and fills from top to bottom when saved, then drains and dips when unsaved.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"bookmark\", \"save\", \"toggle\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Gold\", values: { fill: [0.98, 0.72, 0.1] } },\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], outline: [0.6, 0.63, 0.7], fill: [0.4, 0.8, 1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{background: color default=#FFFFFF label='Background'}} {{outline: color default=#6B7280 label='Outline'}} {{fill: color default=#6366F1 label='Saved'}} --><defs><clipPath id=\"fillClip\"><rect id=\"level\" x=\"30\" y=\"18\" width=\"60\" height=\"0\"/></clipPath></defs><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><g id=\"mark\" transform=\"${bounce(0)}\"><path d=\"${BOOKMARK}\" fill=\"{{fill}}\" clip-path=\"url(#fillClip)\"/><path id=\"edge\" d=\"${BOOKMARK}\" fill=\"none\" stroke=\"{{outline}}\" stroke-width=\"4\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n // Step 1, save: a hop, a drop past rest and a settle, filling top down.\n { id: \"mark\", step: 1, attrs: { transform: [bounce(0), bounce(-7)] }, ms: 130, ease: \"out\" },\n { id: \"mark\", step: 1, attrs: { transform: [bounce(-7), bounce(4)] }, delay: 130, ms: 170, ease: \"in-out\" },\n { id: \"mark\", step: 1, attrs: { transform: [bounce(4), bounce(0)] }, delay: 300, ms: 200, ease: \"in-out\" },\n { id: \"level\", step: 1, attrs: { height: [0, 84] }, delay: 60, ms: 380, ease: \"in-out\" },\n { id: \"edge\", step: 1, attrs: { stroke: [\"{{outline}}\", \"{{fill}}\"] }, ms: 200 },\n // Step 2, unsave: drains top down (then the empty clip snaps back up) with a small dip.\n { id: \"level\", step: 2, attrs: { y: [18, 102], height: [84, 0] }, ms: 320, ease: \"in-out\" },\n snap(\"level\", \"y\", 18, 320, 2),\n { id: \"mark\", step: 2, attrs: { transform: [bounce(0), bounce(3)] }, ms: 120, ease: \"out\" },\n { id: \"mark\", step: 2, attrs: { transform: [bounce(3), bounce(0)] }, delay: 120, ms: 180, ease: \"in-out\" },\n { id: \"edge\", step: 2, attrs: { stroke: [\"{{fill}}\", \"{{outline}}\"] }, delay: 100, ms: 200 },\n ],\n },\n};\n\n/**\n * A pill button's two labels, swapped on a click: the first slides up and\n * out as the second slides up and in, `back` ms later the reverse (the\n * second then drops back below, hidden, ready for the next click).\n */\nconst swapLabels = (outAt: number, back: number): SvgAnimation[] => [\n { id: \"label\", step: 1, attrs: { opacity: [1, 0], transform: [\"translate(0 0)\", \"translate(0 -10)\"] }, delay: outAt, ms: 180, ease: \"out\" },\n { id: \"done\", step: 1, attrs: { opacity: [0, 1], transform: [\"translate(0 10)\", \"translate(0 0)\"] }, delay: outAt + 120, ms: 220, ease: \"out\" },\n { id: \"done\", step: 1, attrs: { opacity: [1, 0], transform: [\"translate(0 0)\", \"translate(0 -10)\"] }, delay: back, ms: 180, ease: \"out\" },\n { id: \"label\", step: 1, attrs: { opacity: [0, 1], transform: [\"translate(0 10)\", \"translate(0 0)\"] }, delay: back + 120, ms: 220, ease: \"out\" },\n snap(\"done\", \"transform\", \"translate(0 10)\", back + 200),\n];\n\n/** A check drawn on at `at` and hidden at `back`, then undrawn while hidden (so each round draws it afresh). */\nconst checkFlash = (at: number, back: number): SvgAnimation[] => [\n { id: \"check\", step: 1, attrs: { opacity: [0, 1] }, delay: at, ms: 40 },\n { id: \"check\", step: 1, draw: true, delay: at, ms: 280, ease: \"out\" },\n { id: \"check\", step: 1, attrs: { opacity: [1, 0] }, delay: back, ms: 160 },\n { id: \"check\", step: 1, draw: [0, 0], delay: back + 200, ms: 0 },\n];\n\n/** Two labels sharing a pill button's room left of an icon: one font size that fits both. */\nconst buttonLabels = (a: unknown, b: unknown, room: number, max: number) => {\n const ems = [a, b].map((t) => Math.max(0.6, textWidthEm(String(t))));\n const size = Math.min(max, room / Math.max(...ems));\n return { size: r1(size), base: r1(50 + size * 0.35), labelLen: r1(ems[0]! * size), doneLen: r1(ems[1]! * size) };\n};\n\nconst labelTexts = (x: number) =>\n `<text id=\"label\" x=\"${x}\" y=\"{{base}}\" textLength=\"{{labelLen}}\" lengthAdjust=\"spacingAndGlyphs\" transform=\"translate(0 0)\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"600\" fill=\"{{ink}}\">{{label}}</text><text id=\"done\" x=\"${x}\" y=\"{{base}}\" textLength=\"{{doneLen}}\" lengthAdjust=\"spacingAndGlyphs\" transform=\"translate(0 10)\" opacity=\"0\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"600\" fill=\"{{ink}}\">{{doneText}}</text>`;\n\n/** When the copy button turns back. */\nconst COPY_BACK = 1600;\nconst copyPose = (s: number) => `translate(54 50) scale(${r2(1.2 * s)}) translate(-12 -12)`;\n\nexport const copyButton: VectorEffect = {\n kind: \"vector\",\n id: \"copy-button\",\n name: \"Copy button\",\n description: \"A copy button whose icon shrinks away for a drawn check and a “Copied!” label, turning back by itself a moment later.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"copy\", \"clipboard\", \"feedback\", \"button\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], button: [0.95, 0.96, 0.97], success: [0.86, 0.97, 0.9], ink: [0.07, 0.09, 0.15] } },\n { name: \"Code\", values: { label: \"Copy code\", doneText: \"Copied to clipboard\", button: [0.2, 0.22, 0.28] } },\n ],\n derived: (v) => buttonLabels(v.label, v.doneText, 126, 19),\n motion: {\n svg: `<svg viewBox=\"0 0 240 100\"><!-- {{label: text default='Copy' label='Label'}} {{doneText: text default='Copied!' label='Copied label'}} {{background: color default=#0F172A label='Background'}} {{button: color default=#1E293B label='Button'}} {{success: color default=#166534 label='Copied'}} {{ink: color default=#F8FAFC label='Text and icon'}} --><rect width=\"240\" height=\"100\" fill=\"{{background}}\"/><rect id=\"btn\" x=\"20\" y=\"24\" width=\"200\" height=\"52\" rx=\"14\" fill=\"{{button}}\"/><g id=\"copy\" transform=\"${copyPose(1)}\" opacity=\"1\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"8.5\" y=\"8.5\" width=\"11.5\" height=\"11.5\" rx=\"2.5\"/><path d=\"M4.5 15.5 V6.5 C4.5 5.4 5.4 4.5 6.5 4.5 H15.5\"/></g><g transform=\"${copyPose(1)}\"><path id=\"check\" d=\"M5 12.5 L10 17.5 L19 7\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g>${labelTexts(80)}</svg>`,\n animate: [\n // One step that returns by itself: each click replays it.\n { id: \"copy\", step: 1, attrs: { transform: [copyPose(1), copyPose(0.3)], opacity: [1, 0] }, ms: 180, ease: \"out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{button}}\", \"{{success}}\"] }, ms: 200 },\n ...checkFlash(150, COPY_BACK),\n ...swapLabels(0, COPY_BACK),\n { id: \"copy\", step: 1, attrs: { transform: [copyPose(0.3), copyPose(1)], opacity: [0, 1] }, delay: COPY_BACK + 80, ms: 260, ease: \"out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{success}}\", \"{{button}}\"] }, delay: COPY_BACK, ms: 300 },\n ],\n },\n};\n\n/** When the send button resets. */\nconst SEND_BACK = 1800;\nconst planeScale = (s: number) => `scale(${r2(s)}) translate(-12 -12)`;\n\nexport const sendButton: VectorEffect = {\n kind: \"vector\",\n id: \"send-button\",\n name: \"Send button\",\n description: \"A send button whose paper plane winds up and flies off up and to the right as the label turns to “Sent” with a check, then it resets.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"send\", \"submit\", \"message\", \"button\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Sky\", values: { button: [0.05, 0.6, 0.9], success: [0.05, 0.45, 0.7] } },\n { name: \"Mail\", values: { label: \"Send email\", doneText: \"Delivered\", button: [0.9, 0.3, 0.25], success: [0.13, 0.6, 0.35] } },\n ],\n derived: (v) => buttonLabels(v.label, v.doneText, 120, 20),\n motion: {\n svg: `<svg viewBox=\"0 0 240 100\"><!-- {{label: text default='Send' label='Label'}} {{doneText: text default='Sent' label='Sent label'}} {{background: color default=#FFFFFF label='Background'}} {{button: color default=#4F46E5 label='Button'}} {{success: color default=#16A34A label='Sent'}} {{ink: color default=#FFFFFF label='Text and icon'}} --><rect width=\"240\" height=\"100\" fill=\"{{background}}\"/><rect id=\"btn\" x=\"20\" y=\"24\" width=\"200\" height=\"52\" rx=\"26\" fill=\"{{button}}\"/><path id=\"flight\" d=\"M56 50 C88 46 150 22 262 -36\" fill=\"none\"/><g transform=\"translate(56 50) scale(1.1) translate(-12 -12)\"><path id=\"check\" d=\"M5 12.5 L10 17.5 L19 7\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g>${labelTexts(82)}<g id=\"plane\" transform=\"translate(56 50)\"><g id=\"planeIcon\" transform=\"${planeScale(1.05)}\" opacity=\"1\"><path d=\"M22 2 L15 22 L11 13 L2 9 Z\" fill=\"{{ink}}\" stroke=\"{{ink}}\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/><path d=\"M22 2 L11 13\" stroke=\"{{button}}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></g></g></svg>`,\n animate: [\n // Wind up, then fly off along the curve, shrinking and fading.\n { id: \"planeIcon\", step: 1, attrs: { transform: [planeScale(1.05), planeScale(0.88)] }, ms: 120, ease: \"out\" },\n { id: \"plane\", step: 1, along: \"flight\", delay: 120, ms: 600, ease: \"in-out\" },\n { id: \"planeIcon\", step: 1, attrs: { transform: [planeScale(0.88), planeScale(0.5)] }, delay: 120, ms: 600, ease: \"in-out\" },\n { id: \"planeIcon\", step: 1, attrs: { opacity: [1, 0] }, delay: 520, ms: 200 },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{button}}\", \"{{success}}\"] }, delay: 450, ms: 250 },\n ...swapLabels(150, SEND_BACK),\n ...checkFlash(500, SEND_BACK),\n // Back home: the plane pops in where it started.\n { id: \"plane\", step: 1, along: \"flight\", at: [0, 0], delay: SEND_BACK, ms: 0 },\n { id: \"planeIcon\", step: 1, attrs: { transform: [planeScale(0), planeScale(1.05)], opacity: [0, 1] }, delay: SEND_BACK + 100, ms: 300, ease: \"out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{success}}\", \"{{button}}\"] }, delay: SEND_BACK, ms: 300 },\n ],\n },\n};\n\n/** The download arrow over its tray, and the progress ring they become, in a 24 box. */\nconst [ARROW, RING] = morphPaths(\n \"M10.6 4 H13.4 V11.6 H17.2 L12 17 L6.8 11.6 H10.6 Z M5 18.6 H19 V20.6 H5 Z\",\n (() => {\n const circle = (r: number) =>\n `M${Array.from({ length: 48 }, (_, k) => {\n const a = (k / 48) * Math.PI * 2 - Math.PI / 2;\n return `${r2(12 + r * Math.cos(a))} ${r2(12 + r * Math.sin(a))}`;\n }).join(\" L\")} Z`;\n return `${circle(9.6)} ${circle(8)}`;\n })(),\n { points: 56 },\n);\n/** The ring's middle radius and width in the picture (the icon is scaled 2.2 about the centre). */\nconst RING_R = r2(8.8 * 2.2);\nconst DOWNLOAD_BACK = 2300;\nconst iconAt = (y: number) => `translate(60 ${y}) scale(2.2) translate(-12 -12)`;\n\nexport const downloadButton: VectorEffect = {\n kind: \"vector\",\n id: \"download-button\",\n name: \"Download button\",\n description: \"A round download button whose arrow drops and morphs into a progress ring that fills, ends on a check, then resets.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"click\", \"download\", \"progress\", \"morph\", \"button\", \"micro-interaction\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], button: [0.93, 0.95, 1], ink: [0.31, 0.27, 0.9], track: [0.78, 0.8, 0.95], progress: [0.31, 0.27, 0.9], success: [0.86, 0.97, 0.9] } },\n { name: \"Ocean\", values: { button: [0.03, 0.4, 0.6], progress: [0.4, 0.95, 0.85], success: [0.05, 0.55, 0.5] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{background: color default=#0F172A label='Background'}} {{button: color default=#4F46E5 label='Button'}} {{success: color default=#16A34A label='Done'}} {{ink: color default=#FFFFFF label='Icon'}} {{track: color default=#818CF8 label='Ring track'}} {{progress: color default=#FFFFFF label='Progress'}} --><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><circle id=\"btn\" cx=\"60\" cy=\"60\" r=\"42\" fill=\"{{button}}\"/><g id=\"icon\" transform=\"${iconAt(60)}\"><path id=\"glyph\" d=\"${ARROW}\" fill=\"{{ink}}\" fill-rule=\"evenodd\"/></g><circle id=\"bar\" cx=\"60\" cy=\"60\" r=\"${RING_R}\" fill=\"none\" stroke=\"{{progress}}\" stroke-width=\"3.6\" transform=\"rotate(-90 60 60)\"/><g transform=\"translate(60 60) scale(1.5) translate(-12 -12)\"><path id=\"check\" d=\"M6 12.5 L10.5 17 L18.5 8\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0\"/></g></svg>`,\n animate: [\n // The arrow drops, then rises back as it morphs into the ring's track.\n { id: \"icon\", step: 1, attrs: { transform: [iconAt(60), iconAt(67)] }, ms: 180, ease: \"out\" },\n { id: \"icon\", step: 1, attrs: { transform: [iconAt(67), iconAt(60)] }, delay: 180, ms: 260, ease: \"in-out\" },\n { id: \"glyph\", step: 1, attrs: { d: [ARROW, RING], fill: [\"{{ink}}\", \"{{track}}\"] }, delay: 180, ms: 340, ease: \"in-out\" },\n // Progress round the ring (a flat-ended line, so nothing shows at 0), then a check.\n { id: \"bar\", step: 1, draw: true, delay: 520, ms: 900, ease: \"in-out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{button}}\", \"{{success}}\"] }, delay: 1400, ms: 250 },\n { id: \"check\", step: 1, attrs: { opacity: [0, 1] }, delay: 1450, ms: 40 },\n { id: \"check\", step: 1, draw: true, delay: 1450, ms: 300, ease: \"out\" },\n // Reset: check and ring fade, the track morphs back into the arrow.\n { id: \"check\", step: 1, attrs: { opacity: [1, 0] }, delay: DOWNLOAD_BACK, ms: 150 },\n { id: \"bar\", step: 1, attrs: { opacity: [1, 0] }, delay: DOWNLOAD_BACK, ms: 200 },\n { id: \"check\", step: 1, draw: [0, 0], delay: DOWNLOAD_BACK + 200, ms: 0 },\n { id: \"bar\", step: 1, draw: [0, 0], delay: DOWNLOAD_BACK + 200, ms: 0 },\n snap(\"bar\", \"opacity\", 1, DOWNLOAD_BACK + 200),\n { id: \"glyph\", step: 1, attrs: { d: [RING, ARROW], fill: [\"{{track}}\", \"{{ink}}\"] }, delay: DOWNLOAD_BACK + 100, ms: 420, ease: \"in-out\" },\n { id: \"btn\", step: 1, attrs: { fill: [\"{{success}}\", \"{{button}}\"] }, delay: DOWNLOAD_BACK, ms: 300 },\n ],\n },\n};\n\nexport const linkHover: VectorEffect = {\n kind: \"vector\",\n id: \"link-hover\",\n name: \"Link hover\",\n description: \"A text link whose underline grows from left to right on hover, its arrow nudging right as the text changes colour.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"hover\", \"link\", \"underline\", \"navigation\", \"micro-interaction\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], ink: [0.85, 0.87, 0.92], hover: [0.4, 0.85, 1] } },\n { name: \"Editorial\", values: { text: \"Continue reading\", ink: [0.1, 0.1, 0.1], hover: [0.85, 0.2, 0.15] } },\n ],\n // The text and its arrow centred together; the arrow is drawn round (0, 0) and placed.\n derived: (v) => {\n const { size, length } = fit(v.text, 230, 28);\n const total = length + size * 1.05;\n const left = 160 - total / 2;\n const base = 50 + size * 0.35;\n const ax = left + length + size * 0.35;\n const ay = base - size * 0.33;\n const s = size / 28;\n return {\n size,\n length,\n left: r1(left),\n base: r1(base),\n lineY: r1(base + size * 0.2),\n lineH: r1(Math.max(2, size * 0.08)),\n arrowAt: `translate(${r1(ax)} ${r1(ay)}) scale(${r2(s)})`,\n arrowTo: `translate(${r1(ax + size * 0.25)} ${r1(ay)}) scale(${r2(s)})`,\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 100\"><!-- {{text: text default='Read the docs' label='Link text'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#1F2937 label='Text colour'}} {{hover: color default=#4F46E5 label='Hover colour'}} --><rect width=\"320\" height=\"100\" fill=\"{{background}}\"/><text id=\"link\" x=\"{{left}}\" y=\"{{base}}\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"600\" fill=\"{{ink}}\">{{text}}</text><rect id=\"under\" x=\"{{left}}\" y=\"{{lineY}}\" width=\"0\" height=\"{{lineH}}\" rx=\"1\" fill=\"{{hover}}\"/><g id=\"arrow\" transform=\"{{arrowAt}}\"><path id=\"arrowPath\" d=\"M0 0 H18 M11 -7 L18 0 L11 7\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n { id: \"link\", attrs: { fill: [\"{{ink}}\", \"{{hover}}\"] }, ms: 220 },\n { id: \"under\", attrs: { width: [0, n(\"length\")] }, ms: 320, ease: \"out\" },\n { id: \"arrow\", attrs: { transform: [\"{{arrowAt}}\", \"{{arrowTo}}\"] }, ms: 300, ease: \"out\" },\n { id: \"arrowPath\", attrs: { stroke: [\"{{ink}}\", \"{{hover}}\"] }, ms: 220 },\n ],\n },\n};\n\nexport const buttonHoverFill: VectorEffect = {\n kind: \"vector\",\n id: \"button-hover-fill\",\n name: \"Button hover fill\",\n description: \"An outlined pill button that fills with a slanted sweep from the left on hover, its label inverting colour as the fill passes.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"hover\", \"button\", \"fill\", \"cta\", \"micro-interaction\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Dark\", values: { background: [0.06, 0.07, 0.1], surface: [0.06, 0.07, 0.1], accent: [0.98, 0.8, 0.2] } },\n { name: \"Coral\", values: { label: \"Book a demo\", accent: [0.96, 0.35, 0.3] } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 190, 22);\n return { size, length, base: r1(60 + size * 0.35) };\n },\n motion: ((): SvgMotion => {\n // The sweep's right edge leans back, so it is a slanted band starting outside the pill.\n const sweep = (x: number) => `M10 26 H${x} L${x - 24} 94 H10 Z`;\n const label = (fill: string, clip = \"\") =>\n `<text x=\"160\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" letter-spacing=\"0.5\" fill=\"${fill}\"${clip}>{{label}}</text>`;\n return {\n svg: `<svg viewBox=\"0 0 320 120\"><!-- {{label: text default='Get started' label='Label'}} {{background: color default=#FFFFFF label='Background'}} {{surface: color default=#FFFFFF label='Button'}} {{accent: color default=#4F46E5 label='Accent'}} --><defs><clipPath id=\"swept\"><path id=\"cover\" d=\"${sweep(40)}\"/></clipPath></defs><rect width=\"320\" height=\"120\" fill=\"{{background}}\"/><g id=\"btn\" transform=\"translate(0 0)\"><rect x=\"40\" y=\"30\" width=\"240\" height=\"60\" rx=\"30\" fill=\"{{surface}}\" stroke=\"{{accent}}\" stroke-width=\"2.5\"/><rect x=\"40\" y=\"30\" width=\"240\" height=\"60\" rx=\"30\" fill=\"{{accent}}\" stroke=\"{{accent}}\" stroke-width=\"2.5\" clip-path=\"url(#swept)\"/>${label(\"{{accent}}\")}${label(\"{{surface}}\", ` clip-path=\"url(#swept)\"`)}</g></svg>`,\n animate: [\n { id: \"cover\", attrs: { d: [sweep(40), sweep(310)] }, ms: 380, ease: \"in-out\" },\n { id: \"btn\", attrs: { transform: [\"translate(0 0)\", \"translate(0 -2)\"] }, ms: 240, ease: \"out\" },\n ],\n };\n })(),\n};\n\n/** The tooltip's group: grown from its pointer's tip (160, 104), raised by `dy`. */\nconst tipPose = (s: number, dy: number) => `translate(160 ${104 + dy}) scale(${r2(s)}) translate(-160 -104)`;\n\nexport const tooltipPop: VectorEffect = {\n kind: \"vector\",\n id: \"tooltip-pop\",\n name: \"Tooltip pop\",\n description: \"A small help badge that pops a tooltip bubble up above it on hover, rising and fading in with a slight overshoot.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"hover\", \"tooltip\", \"help\", \"popover\", \"micro-interaction\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Light\", values: { background: [0.97, 0.97, 0.98], bubble: [1, 1, 1], tipInk: [0.1, 0.1, 0.15], badge: [0.6, 0.63, 0.7] } },\n { name: \"Warning\", values: { tip: \"This can't be undone\", accent: [0.95, 0.4, 0.15], bubble: [0.95, 0.4, 0.15], tipInk: [1, 1, 1] } },\n ],\n // The bubble is as wide as its text, centred over the badge.\n derived: (v) => {\n const { size, length } = fit(v.tip, 250, 15);\n const w = length + 28;\n return { size, length, bx: r1(160 - w / 2), bw: r1(w), tipY: r1(79 + size * 0.35) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 180\"><!-- {{tip: text default='Saved to your library' label='Tooltip'}} {{background: color default=#0F172A label='Background'}} {{badge: color default=#475569 label='Badge'}} {{accent: color default=#6366F1 label='Badge hovered'}} {{bubble: color default=#F8FAFC label='Bubble'}} {{tipInk: color default=#0F172A label='Tooltip text'}} --><rect width=\"320\" height=\"180\" fill=\"{{background}}\"/><g id=\"tip\" transform=\"${tipPose(0.5, 8)}\" opacity=\"0\"><rect x=\"{{bx}}\" y=\"60\" width=\"{{bw}}\" height=\"38\" rx=\"10\" fill=\"{{bubble}}\"/><path d=\"M151 96 L160 105 L169 96 Z\" fill=\"{{bubble}}\"/><text x=\"160\" y=\"{{tipY}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"500\" fill=\"{{tipInk}}\">{{tip}}</text></g><g id=\"badgeG\" transform=\"${about(160, 134, 1)}\"><circle id=\"badge\" cx=\"160\" cy=\"134\" r=\"18\" fill=\"{{badge}}\"/><text x=\"160\" y=\"141\" text-anchor=\"middle\" font-family=\"${SANS}\" font-size=\"20\" font-weight=\"700\" fill=\"#FFFFFF\">?</text></g></svg>`,\n animate: [\n { id: \"tip\", attrs: { transform: [tipPose(0.5, 8), tipPose(1.07, -3)] }, ms: 190, ease: \"out\" },\n { id: \"tip\", attrs: { transform: [tipPose(1.07, -3), tipPose(1, 0)] }, delay: 190, ms: 150, ease: \"in-out\" },\n { id: \"tip\", attrs: { opacity: [0, 1] }, ms: 150 },\n { id: \"badge\", attrs: { fill: [\"{{badge}}\", \"{{accent}}\"] }, ms: 200 },\n { id: \"badgeG\", attrs: { transform: [about(160, 134, 1), about(160, 134, 1.08)] }, ms: 200, ease: \"out\" },\n ],\n },\n};\n\nexport const pressButton: VectorEffect = {\n kind: \"vector\",\n id: \"press-button\",\n name: \"Press button\",\n description: \"A chunky 3D button whose face pushes down onto its base while held, its shadow tightening, and springs back up on release.\",\n category: \"interaction\",\n tags: [\"interactive\", \"ui\", \"press\", \"button\", \"3d\", \"tactile\", \"micro-interaction\"],\n trigger: \"press\",\n hold: 800,\n presets: [\n { name: \"Arcade red\", values: { face: [0.94, 0.27, 0.27], background: [0.1, 0.09, 0.12] } },\n { name: \"Mint\", values: { face: [0.3, 0.85, 0.6], ink: [0.05, 0.25, 0.15], label: \"Let's go\" } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 170, 22);\n return { size, length, base: r1(67 + size * 0.35), side: mixHex(v.face, [0, 0, 0], 0.35), pressed: mixHex(v.face, [0, 0, 0], 0.08) };\n },\n // Played backwards on release, the brief lift at the start of the press becomes a spring past rest at the end.\n motion: {\n svg: `<svg viewBox=\"0 0 320 140\"><!-- {{label: text default='Press me' label='Label'}} {{background: color default=#F1F5F9 label='Background'}} {{face: color default=#6366F1 label='Button'}} {{ink: color default=#FFFFFF label='Label colour'}} {{shadow: color default=#0F172A label='Shadow'}} --><rect width=\"320\" height=\"140\" fill=\"{{background}}\"/><ellipse id=\"shadow\" cx=\"160\" cy=\"114\" rx=\"108\" ry=\"9\" fill=\"{{shadow}}\" opacity=\"0.3\"/><rect x=\"60\" y=\"50\" width=\"200\" height=\"58\" rx=\"16\" fill=\"{{side}}\"/><g id=\"faceG\" transform=\"translate(0 0)\"><rect id=\"faceRect\" x=\"60\" y=\"38\" width=\"200\" height=\"58\" rx=\"16\" fill=\"{{face}}\"/><text x=\"160\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"800\" fill=\"{{ink}}\">{{label}}</text></g></svg>`,\n animate: [\n { id: \"faceG\", attrs: { transform: [\"translate(0 0)\", \"translate(0 -1.5)\"] }, ms: 40, ease: \"out\" },\n { id: \"faceG\", attrs: { transform: [\"translate(0 -1.5)\", \"translate(0 9)\"] }, delay: 40, ms: 90, ease: \"out\" },\n { id: \"shadow\", attrs: { rx: [108, 96], ry: [9, 5], opacity: [0.3, 0.18] }, delay: 40, ms: 90, ease: \"out\" },\n { id: \"faceRect\", attrs: { fill: [\"{{face}}\", \"{{pressed}}\"] }, delay: 40, ms: 90 },\n ],\n },\n};\n\n/** UI micro-interactions as vector effects, each played by a hover, press or click (`trigger`). */\nexport const interactionEffects: VectorEffect[] = [\n likeButton,\n toggleSwitch,\n checkbox,\n menuToggle,\n bookmark,\n copyButton,\n sendButton,\n downloadButton,\n linkHover,\n buttonHoverFill,\n tooltipPop,\n pressButton,\n];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst r1 = (v: number) => Math.round(v * 10) / 10;\n\n/** A transform scaling by `s` about (`cx`, `cy`). */\nconst about = (cx: number, cy: number, s: number) => `translate(${cx} ${cy}) scale(${Math.round(s * 1000) / 1000}) translate(${-cx} ${-cy})`;\n\n/** Instant change: the attribute snaps to `value` at `delay` (resets of hidden elements). */\nconst snap = (id: string, attr: string, value: string | number, delay: number, step?: number): SvgAnimation => ({\n id,\n ...(step === undefined ? {} : { step }),\n attrs: { [attr]: [value, value] },\n delay,\n ms: 0,\n});\n\nconst SANS = `system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif`;\n\n/** A lightning bolt in a 120 box, centred on (60, 60). */\nconst BOLT = \"M68 8 L28 66 L56 66 L46 112 L92 48 L64 48 L76 8 Z\";\n\nexport const zapIcon: VectorEffect = {\n kind: \"vector\",\n id: \"zap-icon\",\n name: \"Zap icon\",\n description: \"A lightning bolt icon that draws itself on, flashes with a burst of glow and sparks, then settles.\",\n category: \"electric\",\n tags: [\"electric\", \"icon\", \"lightning\", \"bolt\", \"ui\", \"energy\"],\n hold: 1000,\n presets: [\n { name: \"Electric blue\", values: { bolt: [0.22, 0.74, 0.97], glow: [0.73, 0.9, 0.99] } },\n { name: \"Light\", values: { background: [1, 1, 1], bolt: [0.92, 0.7, 0.03], glow: [0.99, 0.83, 0.3] } },\n ],\n motion: (() => {\n // Sparks flying off the bolt: angle in degrees, from and to radii round the centre.\n const sparks = [-55, 25, 160, 215].map((deg, i) => {\n const a = (deg * Math.PI) / 180;\n const at = (r: number) => [r1(60 + r * Math.cos(a)), r1(60 + r * Math.sin(a))] as const;\n return { id: `s${i}`, from: at(30), mid: at(46), to: at(56) };\n });\n return {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{background: color default=#0B1020 label='Background'}} {{bolt: color default=#FACC15 label='Bolt'}} {{glow: color default=#FDE68A label='Glow'}} --><defs><filter id=\"zapGlow\" x=\"-60%\" y=\"-60%\" width=\"220%\" height=\"220%\"><feGaussianBlur stdDeviation=\"7\"/></filter></defs><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><circle id=\"burst\" cx=\"60\" cy=\"60\" r=\"20\" fill=\"none\" stroke=\"{{glow}}\" stroke-width=\"6\" opacity=\"0\"/><path id=\"halo\" d=\"${BOLT}\" fill=\"{{glow}}\" filter=\"url(#zapGlow)\" opacity=\"0\"/>${sparks\n .map(({ id, from }) => `<line id=\"${id}\" x1=\"${from[0]}\" y1=\"${from[1]}\" x2=\"${from[0]}\" y2=\"${from[1]}\" stroke=\"{{glow}}\" stroke-width=\"3\" stroke-linecap=\"round\" opacity=\"0\"/>`)\n .join(\"\")}<g id=\"zap\" transform=\"${about(60, 60, 1)}\"><path id=\"fill\" d=\"${BOLT}\" fill=\"{{bolt}}\" fill-opacity=\"0\"/><path id=\"outline\" d=\"${BOLT}\" fill=\"none\" stroke=\"{{bolt}}\" stroke-width=\"3.5\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n { id: \"outline\", draw: true, ms: 550, ease: \"in-out\" },\n { id: \"fill\", attrs: { \"fill-opacity\": [0, 1] }, delay: 500, ms: 100 },\n // The flash: a pop, a burst of glow and a ring, then a soft glow stays.\n { id: \"zap\", attrs: { transform: [about(60, 60, 1), about(60, 60, 1.16)] }, delay: 560, ms: 110, ease: \"out\" },\n { id: \"zap\", attrs: { transform: [about(60, 60, 1.16), about(60, 60, 1)] }, delay: 670, ms: 320, ease: \"in-out\" },\n { id: \"halo\", attrs: { opacity: [0, 1] }, delay: 560, ms: 70 },\n { id: \"halo\", attrs: { opacity: [1, 0.35] }, delay: 630, ms: 600, ease: \"out\" },\n snap(\"burst\", \"opacity\", 0, 0),\n { id: \"burst\", attrs: { r: [20, 58], \"stroke-width\": [6, 0], opacity: [0.9, 0] }, delay: 560, ms: 520, ease: \"out\" },\n ...sparks.flatMap(({ id, from, mid, to }, i): SvgAnimation[] => [\n { id, attrs: { opacity: [0, 1] }, delay: 570 + i * 25, ms: 30 },\n { id, attrs: { x2: [from[0], mid[0]], y2: [from[1], mid[1]] }, delay: 570 + i * 25, ms: 150, ease: \"out\" },\n { id, attrs: { x1: [from[0], to[0]], y1: [from[1], to[1]], x2: [mid[0], to[0]], y2: [mid[1], to[1]], opacity: [1, 0] }, delay: 720 + i * 25, ms: 220, ease: \"out\" },\n ]),\n ],\n };\n })(),\n};\n\n/** The power symbol: an arc open at the top round (80, 82), and a bar through the gap. */\nconst POWER_ARC = \"M63.3 62.1 A26 26 0 1 0 96.7 62.1\";\nconst POWER_BAR = \"M80 48 L80 78\";\n\nexport const powerButton: VectorEffect = {\n kind: \"vector\",\n id: \"power-button\",\n name: \"Power button\",\n description: \"A power button that lights up with a glow ring and its on colour when clicked, and dims again on the next click.\",\n category: \"electric\",\n tags: [\"electric\", \"interactive\", \"ui\", \"click\", \"power\", \"toggle\", \"button\", \"icon\"],\n trigger: \"click\",\n hold: 900,\n presets: [\n { name: \"Green\", values: { on: [0.29, 0.87, 0.5] } },\n { name: \"Light\", values: { background: [0.96, 0.97, 0.98], button: [1, 1, 1], off: [0.6, 0.64, 0.7], on: [0.39, 0.4, 0.95] } },\n ],\n motion: (() => {\n const symbol = (id: string, stroke: string) =>\n `<path id=\"${id}Arc\" d=\"${POWER_ARC}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"7\" stroke-linecap=\"round\"/><path id=\"${id}Bar\" d=\"${POWER_BAR}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"7\" stroke-linecap=\"round\"/>`;\n const press = (step: number, depth: number): SvgAnimation[] => [\n { id: \"press\", step, attrs: { transform: [about(80, 80, 1), about(80, 80, depth)] }, ms: 90, ease: \"out\" },\n { id: \"press\", step, attrs: { transform: [about(80, 80, depth), about(80, 80, 1)] }, delay: 90, ms: 260, ease: \"in-out\" },\n ];\n const colours = (step: number, from: string, to: string, delay: number): SvgAnimation[] =>\n [\"symArc\", \"symBar\"].map((id) => ({ id, step, attrs: { stroke: [from, to] }, delay, ms: 220 }));\n return {\n svg: `<svg viewBox=\"0 0 160 160\"><!-- {{background: color default=#0B0F19 label='Background'}} {{button: color default=#1A2030 label='Button'}} {{off: color default=#5B6475 label='Off'}} {{on: color default=#22D3EE label='On'}} --><defs><filter id=\"pbGlow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\"><feGaussianBlur stdDeviation=\"5\"/></filter></defs><rect width=\"160\" height=\"160\" fill=\"{{background}}\"/><circle id=\"halo\" cx=\"80\" cy=\"80\" r=\"52\" fill=\"none\" stroke=\"{{on}}\" stroke-width=\"8\" opacity=\"0\" filter=\"url(#pbGlow)\"/><circle id=\"pulse\" cx=\"80\" cy=\"80\" r=\"50\" fill=\"none\" stroke=\"{{on}}\" stroke-width=\"3\" opacity=\"0\"/><g id=\"press\" transform=\"${about(80, 80, 1)}\"><circle id=\"disc\" cx=\"80\" cy=\"80\" r=\"48\" fill=\"{{button}}\" stroke=\"{{off}}\" stroke-width=\"2.5\"/><g id=\"symGlow\" opacity=\"0\" filter=\"url(#pbGlow)\">${symbol(\"glow\", \"{{on}}\")}</g>${symbol(\"sym\", \"{{off}}\")}</g></svg>`,\n animate: [\n // Step 1, on: a press, the symbol and rim light up, the glow ring comes on and a pulse rings out.\n ...press(1, 0.93),\n ...colours(1, \"{{off}}\", \"{{on}}\", 60),\n { id: \"disc\", step: 1, attrs: { stroke: [\"{{off}}\", \"{{on}}\"] }, delay: 60, ms: 220 },\n { id: \"symGlow\", step: 1, attrs: { opacity: [0, 1] }, delay: 60, ms: 260 },\n { id: \"halo\", step: 1, attrs: { opacity: [0, 0.75] }, delay: 80, ms: 360, ease: \"out\" },\n snap(\"pulse\", \"opacity\", 0, 0, 1),\n { id: \"pulse\", step: 1, attrs: { r: [50, 76], opacity: [0.9, 0] }, delay: 80, ms: 560, ease: \"out\" },\n snap(\"pulse\", \"r\", 50, 700, 1),\n // Step 2, off: a press and everything dims back to the start.\n ...press(2, 0.95),\n ...colours(2, \"{{on}}\", \"{{off}}\", 40),\n { id: \"disc\", step: 2, attrs: { stroke: [\"{{on}}\", \"{{off}}\"] }, delay: 40, ms: 220 },\n { id: \"symGlow\", step: 2, attrs: { opacity: [1, 0] }, delay: 40, ms: 220 },\n { id: \"halo\", step: 2, attrs: { opacity: [0.75, 0] }, delay: 40, ms: 300, ease: \"out\" },\n ],\n };\n })(),\n};\n\n/** Battery cells: five across the inside of the case. */\nconst CELLS = Array.from({ length: 5 }, (_, i) => ({ id: `cell${i}`, x: r1(36 + i * 24.8) }));\n/** The bolt over the battery's middle, scaled by `k` (1 at rest). */\nconst boltPose = (k: number) => `translate(96 58) scale(${Math.round(0.36 * k * 1000) / 1000}) translate(-60 -60)`;\n\nexport const batteryCharge: VectorEffect = {\n kind: \"vector\",\n id: \"battery-charge\",\n name: \"Battery charge\",\n description: \"A battery filling cell by cell as its percentage counts up and the bolt pulses, flashing when it is full.\",\n category: \"electric\",\n tags: [\"electric\", \"battery\", \"charging\", \"loader\", \"progress\", \"ui\", \"icon\"],\n hold: 900,\n presets: [\n { name: \"Light\", values: { background: [1, 1, 1], shell: [0.2, 0.25, 0.33], ink: [0.06, 0.09, 0.16] } },\n { name: \"Low power\", values: { charge: [0.96, 0.62, 0.04] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 140\"><!-- {{background: color default=#0F172A label='Background'}} {{shell: color default=#CBD5E1 label='Case'}} {{charge: color default=#22C55E label='Charge'}} {{bolt: color default=#FDE047 label='Bolt'}} {{ink: color default=#F8FAFC label='Percent'}} --><rect width=\"200\" height=\"140\" fill=\"{{background}}\"/><rect id=\"case\" x=\"28\" y=\"26\" width=\"136\" height=\"64\" rx=\"12\" fill=\"none\" stroke=\"{{shell}}\" stroke-width=\"5\"/><rect id=\"nub\" x=\"167\" y=\"46\" width=\"9\" height=\"24\" rx=\"3\" fill=\"{{shell}}\"/>${CELLS.map(\n ({ id, x }) => `<rect id=\"${id}\" x=\"${x}\" y=\"34\" width=\"20.8\" height=\"48\" rx=\"4\" fill=\"{{charge}}\" opacity=\"0\"/>`,\n ).join(\"\")}<path id=\"bolt\" d=\"${BOLT}\" transform=\"${boltPose(1)}\" fill=\"{{bolt}}\" stroke=\"{{background}}\" stroke-width=\"10\" stroke-linejoin=\"round\" paint-order=\"stroke\"/><rect id=\"flash\" x=\"28\" y=\"26\" width=\"136\" height=\"64\" rx=\"12\" fill=\"#FFFFFF\" opacity=\"0\"/><text id=\"pct\" x=\"96\" y=\"124\" text-anchor=\"middle\" font-family=\"${SANS}\" font-size=\"22\" font-weight=\"700\" fill=\"{{ink}}\">0%</text></svg>`,\n animate: [\n { id: \"pct\", count: [0, 100], format: \"{n}%\", ms: 2000, ease: \"linear\" },\n // Each cell lights as the count passes its share.\n ...CELLS.map(({ id }, i): SvgAnimation => ({ id, attrs: { opacity: [0, 1] }, delay: (i + 1) * 400 - 80, ms: 120 })),\n // The bolt pulses as it charges.\n ...[0, 500, 1000, 1500].flatMap((t): SvgAnimation[] => [\n { id: \"bolt\", attrs: { transform: [boltPose(1), boltPose(1.2)] }, delay: t, ms: 150, ease: \"out\" },\n { id: \"bolt\", attrs: { transform: [boltPose(1.2), boltPose(1)] }, delay: t + 150, ms: 250, ease: \"in-out\" },\n ]),\n // Full: a flash and the case takes the charge colour.\n { id: \"flash\", attrs: { opacity: [0, 0.7] }, delay: 2050, ms: 70 },\n { id: \"flash\", attrs: { opacity: [0.7, 0] }, delay: 2120, ms: 420, ease: \"out\" },\n { id: \"case\", attrs: { stroke: [\"{{shell}}\", \"{{charge}}\"] }, delay: 2050, ms: 150 },\n { id: \"nub\", attrs: { fill: [\"{{shell}}\", \"{{charge}}\"] }, delay: 2050, ms: 150 },\n { id: \"pct\", attrs: { fill: [\"{{ink}}\", \"{{charge}}\"] }, delay: 2050, ms: 150 },\n { id: \"bolt\", attrs: { transform: [boltPose(1), boltPose(1.3)] }, delay: 2050, ms: 120, ease: \"out\" },\n { id: \"bolt\", attrs: { transform: [boltPose(1.3), boltPose(1)] }, delay: 2170, ms: 300, ease: \"in-out\" },\n ],\n },\n};\n\n/** Electricity as vector effects: zaps, power and charge. */\nexport const electricEffects: VectorEffect[] = [zapIcon, powerButton, batteryCharge];\n","import { morphSequence } from \"../vector/morph.js\";\nimport type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\ntype Point = [number, number];\n\nconst DEG = Math.PI / 180;\nconst r2 = (v: number) => {\n const r = Math.round(v * 100) / 100;\n return Object.is(r, -0) ? 0 : r;\n};\n\nconst polyline = (pts: readonly Point[]) => `M${pts.map((p) => `${r2(p[0])} ${r2(p[1])}`).join(\" L\")} Z`;\n\n/** Points round an ellipse between two angles in degrees (0 is right, 90 down), `wobble(a)` scaling the radius. */\nfunction arc(cx: number, cy: number, rx: number, ry: number, from: number, to: number, wobble: (a: number) => number = () => 1, every = 6): Point[] {\n const steps = Math.max(1, Math.ceil(Math.abs(to - from) / every));\n return Array.from({ length: steps + 1 }, (_, k) => {\n const deg = from + ((to - from) * k) / steps;\n const w = wobble(deg);\n return [cx + rx * w * Math.cos(deg * DEG), cy + ry * w * Math.sin(deg * DEG)];\n });\n}\n\n/** A polygon with its corners rounded off by `r`, as points. */\nfunction rounded(corners: readonly Point[], r: number): Point[] {\n return corners.flatMap((c, i) => {\n const a = corners[(i + corners.length - 1) % corners.length]!;\n const b = corners[(i + 1) % corners.length]!;\n const towards = (p: Point): Point => {\n const l = Math.hypot(p[0] - c[0], p[1] - c[1]);\n return [c[0] + ((p[0] - c[0]) * r) / l, c[1] + ((p[1] - c[1]) * r) / l];\n };\n const [s, e] = [towards(a), towards(b)];\n // A quadratic round the corner, in a few points.\n return [0, 0.25, 0.5, 0.75, 1].map((t): Point => [\n (1 - t) ** 2 * s[0] + 2 * t * (1 - t) * c[0] + t * t * e[0],\n (1 - t) ** 2 * s[1] + 2 * t * (1 - t) * c[1] + t * t * e[1],\n ]);\n });\n}\n\n// ── Ice cube melt ──────────────────────────────────────────────────────\n\n// An ice cube seen from above a corner: its outline, top face and shaded right face.\nconst CUBE: Point[] = [[100, 48], [152, 76], [152, 136], [100, 164], [48, 136], [48, 76]];\nconst lumpy = (a: number) => 1 + 0.035 * Math.sin(a * 5 * DEG) + 0.02 * Math.sin(a * 11 * DEG + 1);\n\nconst ICE_OUTLINE = morphSequence(\n [\n polyline(rounded(CUBE, 7)),\n // Slumped: a soft lump on a spreading foot.\n polyline([...arc(100, 158, 54, 62, 180, 360, lumpy), [154, 162], [130, 166], [100, 167], [70, 166], [46, 162]]),\n // A puddle.\n polyline(arc(100, 163, 84, 14, 0, 360, lumpy).slice(0, -1)),\n ],\n { points: 72 },\n);\n\nconst ICE_TOP = morphSequence(\n [\n polyline(rounded([[100, 48], [152, 76], [100, 104], [48, 76]], 5)),\n polyline(arc(86, 118, 24, 13, 0, 360).slice(0, -1)),\n polyline(arc(80, 159, 36, 3.5, 0, 360).slice(0, -1)),\n ],\n { points: 40 },\n);\n\nconst ICE_SIDE = morphSequence(\n [\n polyline([[100, 104], [152, 76], [152, 136], [100, 164]]),\n polyline([...arc(100, 158, 54, 62, 300, 360, lumpy), ...arc(100, 158, 30, 56, 360, 300)]),\n polyline([...arc(100, 163, 84, 14, -15, 100, lumpy), ...arc(100, 161, 72, 9, 100, -15)]),\n ],\n { points: 40 },\n);\n\nconst MELT = { delay: 400, ms: 1700 };\nconst SPREAD = { delay: 2100, ms: 1500 };\nconst REFORM = { delay: 4600, ms: 1100 };\n\n/** One shape through its three stages and back. */\nconst stages = (id: string, [cube, slump, puddle]: string[]): SvgAnimation[] => [\n { id, attrs: { d: [cube!, slump!] }, ...MELT, ease: \"in-out\" },\n { id, attrs: { d: [slump!, puddle!] }, ...SPREAD, ease: \"out\" },\n { id, attrs: { d: [puddle!, cube!] }, ...REFORM, ease: \"in-out\" },\n];\n\nexport const iceCubeMelt: VectorEffect = {\n kind: \"vector\",\n id: \"ice-cube-melt\",\n name: \"Ice cube melt\",\n description: \"An ice cube softening, slumping and spreading into a glossy puddle with a couple of drips, then freezing back into a cube.\",\n category: \"melt\",\n tags: [\"melt\", \"ice\", \"water\", \"puddle\", \"morph\", \"loop\"],\n hold: 700,\n presets: [\n { name: \"Night\", values: { background: [0.07, 0.09, 0.14], ice: [0.72, 0.88, 1], water: [0.25, 0.55, 0.85], edge: [0.55, 0.78, 0.95] } },\n { name: \"Popsicle\", values: { ice: [1, 0.55, 0.62], water: [0.95, 0.3, 0.42], edge: [0.85, 0.35, 0.45], background: [1, 0.96, 0.92] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{ice: color default=#CFEFFF label='Ice'}} {{water: color default=#7FC8F2 label='Water'}} {{edge: color default=#86C3E6 label='Edge'}} {{highlight: color default=#FFFFFF label='Highlight'}} {{background: color default=#F2F5FA label='Background'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><ellipse id=\"pool\" cx=\"100\" cy=\"164\" rx=\"36\" ry=\"5\" fill=\"{{water}}\" opacity=\"0.35\"/><path id=\"cube\" d=\"${ICE_OUTLINE[0]}\" fill=\"{{ice}}\" fill-rule=\"evenodd\" stroke=\"{{edge}}\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/><path id=\"side\" d=\"${ICE_SIDE[0]}\" fill=\"#0b2a44\" fill-rule=\"evenodd\" opacity=\"0.12\"/><path id=\"top\" d=\"${ICE_TOP[0]}\" fill=\"{{highlight}}\" fill-rule=\"evenodd\" opacity=\"0.55\"/><path id=\"streak\" d=\"M58 92 L58 128\" stroke=\"{{highlight}}\" stroke-width=\"4\" stroke-linecap=\"round\" opacity=\"0.85\"/><circle id=\"glint\" cx=\"118\" cy=\"66\" r=\"3\" fill=\"{{highlight}}\" opacity=\"0.9\"/><circle id=\"drop1\" cx=\"146\" cy=\"128\" r=\"0\" fill=\"{{water}}\" stroke=\"{{edge}}\" stroke-width=\"1\"/><circle id=\"drop2\" cx=\"62\" cy=\"134\" r=\"0\" fill=\"{{water}}\" stroke=\"{{edge}}\" stroke-width=\"1\"/></svg>`,\n animate: [\n ...stages(\"cube\", ICE_OUTLINE),\n ...stages(\"top\", ICE_TOP),\n ...stages(\"side\", ICE_SIDE),\n { id: \"cube\", attrs: { fill: [\"{{ice}}\", \"{{water}}\"] }, delay: 1800, ms: 1800, ease: \"in-out\" },\n { id: \"cube\", attrs: { fill: [\"{{water}}\", \"{{ice}}\"] }, ...REFORM, ease: \"in-out\" },\n { id: \"top\", attrs: { opacity: [0.55, 0.8] }, ...SPREAD, ease: \"in-out\" },\n { id: \"top\", attrs: { opacity: [0.8, 0.55] }, ...REFORM, ease: \"in-out\" },\n { id: \"streak\", attrs: { opacity: [0.85, 0] }, delay: 400, ms: 900, ease: \"in-out\" },\n { id: \"streak\", attrs: { opacity: [0, 0.85] }, delay: 5500, ms: 300, ease: \"in-out\" },\n { id: \"glint\", attrs: { opacity: [0.9, 0], r: [3, 1] }, delay: 300, ms: 700, ease: \"in-out\" },\n { id: \"glint\", attrs: { opacity: [0, 0.9], r: [1, 3] }, delay: 5500, ms: 300, ease: \"in-out\" },\n { id: \"pool\", attrs: { rx: [36, 92], ry: [5, 17], opacity: [0.35, 0.6] }, delay: 600, ms: 3000, ease: \"in-out\" },\n { id: \"pool\", attrs: { rx: [92, 36], ry: [17, 5], opacity: [0.6, 0.35] }, ...REFORM, ease: \"in-out\" },\n { id: \"drop1\", attrs: { cy: [128, 160], r: [0, 4.5] }, delay: 900, ms: 1000, ease: \"in-out\" },\n { id: \"drop1\", attrs: { r: [4.5, 0] }, delay: 1900, ms: 300, ease: \"in-out\" },\n { id: \"drop2\", attrs: { cy: [134, 160], r: [0, 3.5] }, delay: 1400, ms: 900, ease: \"in-out\" },\n { id: \"drop2\", attrs: { r: [3.5, 0] }, delay: 2300, ms: 300, ease: \"in-out\" },\n // Back up the sides, unseen, for the next melt.\n { id: \"drop1\", attrs: { cy: [160, 128] }, ...REFORM },\n { id: \"drop2\", attrs: { cy: [160, 134] }, ...REFORM },\n ],\n },\n};\n\n// ── Candle ─────────────────────────────────────────────────────────────\n\nconst BURN = 6000;\nconst TOP = 92;\nconst BURNT = 150;\nconst FLICKER = 150;\n\n/** The top of the candle at `ms` into the burn. */\nconst topAt = (ms: number) => TOP + ((BURNT - TOP) * Math.min(ms, BURN)) / BURN;\n\n/** A repeatable 0–1 number for a flicker. */\nconst rand = (i: number, k: number) => {\n const x = Math.sin(i * 127.1 + k * 311.7) * 43758.5453;\n return x - Math.floor(x);\n};\n\n/** The flame's transform at a flicker: following the top down, stretching, leaning and swelling at random. */\nconst flame = (i: number, ms: number) => {\n const sx = i < 0 ? 1 : 0.9 + 0.16 * rand(i, 1);\n const sy = i < 0 ? 1 : 0.82 + 0.34 * rand(i, 2);\n const lean = i < 0 ? 0 : (rand(i, 3) - 0.5) * 12;\n return `translate(100 ${r2(topAt(ms) - 12)}) skewX(${r2(lean)}) scale(${r2(sx)} ${r2(sy)})`;\n};\n\nconst FLICKERS = BURN / FLICKER;\n\nconst DRIPS = [\n { x: 66, delay: 700, ms: 2600, length: 70 },\n { x: 123, delay: 1600, ms: 3000, length: 96 },\n { x: 93, delay: 3000, ms: 2400, length: 52 },\n] as const;\n\nconst linear = { delay: 0, ms: BURN, ease: \"linear\" as const };\nconst relight = { delay: BURN, ms: 600, ease: \"in-out\" as const };\n\nexport const candle: VectorEffect = {\n kind: \"vector\",\n id: \"candle\",\n name: \"Candle\",\n description: \"A candle burning down with a flickering flame and halo while wax drips run down its sides, then it is lit anew.\",\n category: \"melt\",\n tags: [\"melt\", \"candle\", \"flame\", \"wax\", \"cosy\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Red taper\", values: { wax: [0.78, 0.15, 0.2], holder: [0.75, 0.62, 0.35] } },\n { name: \"Spirit flame\", values: { flame: [0.35, 0.7, 1], core: [0.88, 0.96, 1], background: [0.04, 0.05, 0.1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 260\"><!-- {{wax: color default=#F1E4CF label='Wax'}} {{flame: color default=#FFA733 label='Flame'}} {{core: color default=#FFF6CF label='Flame core'}} {{holder: color default=#6E5A48 label='Holder'}} {{background: color default=#17131F label='Background'}} --><defs><radialGradient id=\"halo\"><stop offset=\"0\" stop-color=\"{{flame}}\" stop-opacity=\"0.55\"/><stop offset=\"1\" stop-color=\"{{flame}}\" stop-opacity=\"0\"/></radialGradient><linearGradient id=\"waxshade\" x1=\"0\" x2=\"1\"><stop offset=\"0\" stop-color=\"#000\" stop-opacity=\"0.12\"/><stop offset=\"0.35\" stop-color=\"#fff\" stop-opacity=\"0.18\"/><stop offset=\"1\" stop-color=\"#000\" stop-opacity=\"0.3\"/></linearGradient></defs><rect width=\"200\" height=\"260\" fill=\"{{background}}\"/><circle id=\"glow\" cx=\"100\" cy=\"${TOP - 30}\" r=\"80\" fill=\"url(#halo)\" opacity=\"0.9\"/><ellipse cx=\"100\" cy=\"244\" rx=\"58\" ry=\"10\" fill=\"{{holder}}\"/><rect id=\"body\" x=\"70\" y=\"${TOP}\" width=\"60\" height=\"${244 - TOP}\" fill=\"{{wax}}\"/><rect id=\"shade\" x=\"70\" y=\"${TOP}\" width=\"60\" height=\"${244 - TOP}\" fill=\"url(#waxshade)\"/>${DRIPS.map(\n (d, i) => `<rect id=\"drip${i}\" x=\"${d.x}\" y=\"${TOP}\" width=\"11\" height=\"0\" rx=\"5.5\" fill=\"{{wax}}\" stroke=\"#000\" stroke-opacity=\"0.12\"/>`,\n ).join(\"\")}<ellipse id=\"rim\" cx=\"100\" cy=\"${TOP}\" rx=\"30\" ry=\"7\" fill=\"{{wax}}\" stroke=\"#000\" stroke-opacity=\"0.1\"/><ellipse id=\"pool\" cx=\"100\" cy=\"${TOP}\" rx=\"21\" ry=\"4\" fill=\"{{core}}\" opacity=\"0.35\"/><line id=\"wick\" x1=\"100\" y1=\"${TOP}\" x2=\"100\" y2=\"${TOP - 13}\" stroke=\"#2a211c\" stroke-width=\"2.5\" stroke-linecap=\"round\"/><g id=\"flame\" transform=\"${flame(-1, 0)}\"><path d=\"M0 0 C-13 -6 -12 -27 0 -50 C12 -27 13 -6 0 0 Z\" fill=\"{{flame}}\"/><path d=\"M0 -2 C-6 -5 -6 -15 0 -27 C6 -15 6 -5 0 -2 Z\" fill=\"{{core}}\"/></g></svg>`,\n animate: [\n // Burning down, then lit anew.\n { id: \"body\", attrs: { y: [TOP, BURNT], height: [244 - TOP, 244 - BURNT] }, ...linear },\n { id: \"body\", attrs: { y: [BURNT, TOP], height: [244 - BURNT, 244 - TOP] }, ...relight },\n { id: \"shade\", attrs: { y: [TOP, BURNT], height: [244 - TOP, 244 - BURNT] }, ...linear },\n { id: \"shade\", attrs: { y: [BURNT, TOP], height: [244 - BURNT, 244 - TOP] }, ...relight },\n ...([\"rim\", \"pool\"] as const).flatMap((id): SvgAnimation[] => [\n { id, attrs: { cy: [TOP, BURNT] }, ...linear },\n { id, attrs: { cy: [BURNT, TOP] }, ...relight },\n ]),\n { id: \"wick\", attrs: { y1: [TOP, BURNT], y2: [TOP - 13, BURNT - 13] }, ...linear },\n { id: \"wick\", attrs: { y1: [BURNT, TOP], y2: [BURNT - 13, TOP - 13] }, ...relight },\n { id: \"glow\", attrs: { cy: [TOP - 30, BURNT - 30] }, ...linear },\n { id: \"glow\", attrs: { cy: [BURNT - 30, TOP - 30] }, ...relight },\n // Wax runs down the sides, its drips riding down with the top as it burns.\n ...DRIPS.flatMap((d, i): SvgAnimation[] => [\n { id: `drip${i}`, attrs: { y: [TOP, BURNT] }, ...linear },\n { id: `drip${i}`, attrs: { height: [0, d.length] }, delay: d.delay, ms: d.ms, ease: \"out\" },\n { id: `drip${i}`, attrs: { y: [BURNT, TOP], height: [d.length, 0] }, ...relight },\n ]),\n // The flame flickers as it follows the top down, goes out, and is lit again.\n ...Array.from({ length: FLICKERS }, (_, i): SvgAnimation => ({\n id: \"flame\",\n attrs: { transform: [flame(i - 1, i * FLICKER), flame(i, (i + 1) * FLICKER)] },\n delay: i * FLICKER,\n ms: FLICKER,\n ease: \"in-out\",\n })),\n { id: \"flame\", attrs: { transform: [flame(FLICKERS - 1, BURN), flame(-1, 0)], opacity: [1, 0] }, delay: BURN, ms: 250, ease: \"in-out\" },\n { id: \"flame\", attrs: { opacity: [0, 1] }, delay: BURN + 500, ms: 300, ease: \"out\" },\n ...Array.from({ length: BURN / 300 }, (_, i): SvgAnimation => ({\n id: \"glow\",\n attrs: { opacity: [i ? r2(0.7 + 0.3 * rand(i - 1, 7)) : 0.9, r2(0.7 + 0.3 * rand(i, 7))] },\n delay: i * 300,\n ms: 300,\n ease: \"in-out\",\n })),\n { id: \"glow\", attrs: { opacity: [r2(0.7 + 0.3 * rand(BURN / 300 - 1, 7)), 0] }, delay: BURN, ms: 250, ease: \"in-out\" },\n { id: \"glow\", attrs: { opacity: [0, 0.9] }, delay: BURN + 500, ms: 300, ease: \"out\" },\n ],\n },\n};\n\n/** Melting: drips, heat haze, wax and liquefying shapes, as vector effects. */\nexport const meltEffects: VectorEffect[] = [iceCubeMelt, candle];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * Pixel looks stay crisp: every effect works on a virtual low-resolution grid\n * (`floor(fragCoord / uPixel)`), samples images at the centre of each virtual\n * pixel and quantises colours to a few levels, so no edge is ever blended.\n */\n\n/**\n * A 5 × 7 pixel font: each glyph seven rows of five, `#` inked, top row first.\n * Shared by the shaders (packed into ints, see {@link packGlyph}) and the\n * vector pixel effects (drawn as paths).\n */\nexport const PIXEL_FONT: Readonly<Record<string, readonly string[]>> = {\n \" \": [\".....\", \".....\", \".....\", \".....\", \".....\", \".....\", \".....\"],\n A: [\".###.\", \"#...#\", \"#...#\", \"#####\", \"#...#\", \"#...#\", \"#...#\"],\n B: [\"####.\", \"#...#\", \"#...#\", \"####.\", \"#...#\", \"#...#\", \"####.\"],\n C: [\".###.\", \"#...#\", \"#....\", \"#....\", \"#....\", \"#...#\", \".###.\"],\n D: [\"####.\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"####.\"],\n E: [\"#####\", \"#....\", \"#....\", \"####.\", \"#....\", \"#....\", \"#####\"],\n F: [\"#####\", \"#....\", \"#....\", \"####.\", \"#....\", \"#....\", \"#....\"],\n G: [\".###.\", \"#...#\", \"#....\", \"#.###\", \"#...#\", \"#...#\", \".####\"],\n H: [\"#...#\", \"#...#\", \"#...#\", \"#####\", \"#...#\", \"#...#\", \"#...#\"],\n I: [\".###.\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \".###.\"],\n J: [\"..###\", \"...#.\", \"...#.\", \"...#.\", \"...#.\", \"#..#.\", \".##..\"],\n K: [\"#...#\", \"#..#.\", \"#.#..\", \"##...\", \"#.#..\", \"#..#.\", \"#...#\"],\n L: [\"#....\", \"#....\", \"#....\", \"#....\", \"#....\", \"#....\", \"#####\"],\n M: [\"#...#\", \"##.##\", \"#.#.#\", \"#.#.#\", \"#...#\", \"#...#\", \"#...#\"],\n N: [\"#...#\", \"#...#\", \"##..#\", \"#.#.#\", \"#..##\", \"#...#\", \"#...#\"],\n O: [\".###.\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \".###.\"],\n P: [\"####.\", \"#...#\", \"#...#\", \"####.\", \"#....\", \"#....\", \"#....\"],\n Q: [\".###.\", \"#...#\", \"#...#\", \"#...#\", \"#.#.#\", \"#..#.\", \".##.#\"],\n R: [\"####.\", \"#...#\", \"#...#\", \"####.\", \"#.#..\", \"#..#.\", \"#...#\"],\n S: [\".####\", \"#....\", \"#....\", \".###.\", \"....#\", \"....#\", \"####.\"],\n T: [\"#####\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\"],\n U: [\"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \".###.\"],\n V: [\"#...#\", \"#...#\", \"#...#\", \"#...#\", \"#...#\", \".#.#.\", \"..#..\"],\n W: [\"#...#\", \"#...#\", \"#...#\", \"#.#.#\", \"#.#.#\", \"#.#.#\", \".#.#.\"],\n X: [\"#...#\", \"#...#\", \".#.#.\", \"..#..\", \".#.#.\", \"#...#\", \"#...#\"],\n Y: [\"#...#\", \"#...#\", \".#.#.\", \"..#..\", \"..#..\", \"..#..\", \"..#..\"],\n Z: [\"#####\", \"....#\", \"...#.\", \"..#..\", \".#...\", \"#....\", \"#####\"],\n \"0\": [\".###.\", \"#...#\", \"#..##\", \"#.#.#\", \"##..#\", \"#...#\", \".###.\"],\n \"1\": [\"..#..\", \".##..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \".###.\"],\n \"2\": [\".###.\", \"#...#\", \"....#\", \"...#.\", \"..#..\", \".#...\", \"#####\"],\n \"3\": [\"#####\", \"...#.\", \"..#..\", \"...#.\", \"....#\", \"#...#\", \".###.\"],\n \"4\": [\"...#.\", \"..##.\", \".#.#.\", \"#..#.\", \"#####\", \"...#.\", \"...#.\"],\n \"5\": [\"#####\", \"#....\", \"####.\", \"....#\", \"....#\", \"#...#\", \".###.\"],\n \"6\": [\"..##.\", \".#...\", \"#....\", \"####.\", \"#...#\", \"#...#\", \".###.\"],\n \"7\": [\"#####\", \"....#\", \"...#.\", \"..#..\", \".#...\", \".#...\", \".#...\"],\n \"8\": [\".###.\", \"#...#\", \"#...#\", \".###.\", \"#...#\", \"#...#\", \".###.\"],\n \"9\": [\".###.\", \"#...#\", \"#...#\", \".####\", \"....#\", \"...#.\", \".##..\"],\n \".\": [\".....\", \".....\", \".....\", \".....\", \".....\", \".##..\", \".##..\"],\n \",\": [\".....\", \".....\", \".....\", \".....\", \".##..\", \"..#..\", \".#...\"],\n \"!\": [\"..#..\", \"..#..\", \"..#..\", \"..#..\", \"..#..\", \".....\", \"..#..\"],\n \"?\": [\".###.\", \"#...#\", \"....#\", \"...#.\", \"..#..\", \".....\", \"..#..\"],\n \"-\": [\".....\", \".....\", \".....\", \"#####\", \".....\", \".....\", \".....\"],\n \"+\": [\".....\", \"..#..\", \"..#..\", \"#####\", \"..#..\", \"..#..\", \".....\"],\n \":\": [\".....\", \".##..\", \".##..\", \".....\", \".##..\", \".##..\", \".....\"],\n \";\": [\".....\", \".##..\", \".##..\", \".....\", \".##..\", \"..#..\", \".#...\"],\n \"'\": [\"..#..\", \"..#..\", \".#...\", \".....\", \".....\", \".....\", \".....\"],\n '\"': [\".#.#.\", \".#.#.\", \".....\", \".....\", \".....\", \".....\", \".....\"],\n \"/\": [\".....\", \"....#\", \"...#.\", \"..#..\", \".#...\", \"#....\", \".....\"],\n \"(\": [\"...#.\", \"..#..\", \".#...\", \".#...\", \".#...\", \"..#..\", \"...#.\"],\n \")\": [\".#...\", \"..#..\", \"...#.\", \"...#.\", \"...#.\", \"..#..\", \".#...\"],\n \"[\": [\".###.\", \".#...\", \".#...\", \".#...\", \".#...\", \".#...\", \".###.\"],\n \"]\": [\".###.\", \"...#.\", \"...#.\", \"...#.\", \"...#.\", \"...#.\", \".###.\"],\n \"#\": [\".#.#.\", \".#.#.\", \"#####\", \".#.#.\", \"#####\", \".#.#.\", \".#.#.\"],\n \"&\": [\".##..\", \"#..#.\", \"#.#..\", \".#...\", \"#.#.#\", \"#..#.\", \".##.#\"],\n \"*\": [\".....\", \"..#..\", \"#.#.#\", \".###.\", \"#.#.#\", \"..#..\", \".....\"],\n \"=\": [\".....\", \".....\", \"#####\", \".....\", \"#####\", \".....\", \".....\"],\n _: [\".....\", \".....\", \".....\", \".....\", \".....\", \".....\", \"#####\"],\n \"<\": [\"...#.\", \"..#..\", \".#...\", \"#....\", \".#...\", \"..#..\", \"...#.\"],\n \">\": [\".#...\", \"..#..\", \"...#.\", \"....#\", \"...#.\", \"..#..\", \".#...\"],\n \"%\": [\"##...\", \"##..#\", \"...#.\", \"..#..\", \".#...\", \"#..##\", \"...##\"],\n $: [\"..#..\", \".####\", \"#.#..\", \".###.\", \"..#.#\", \"####.\", \"..#..\"],\n \"@\": [\".###.\", \"#...#\", \"#.###\", \"#.#.#\", \"#.###\", \"#....\", \".####\"],\n};\n\n/** A glyph of {@link PIXEL_FONT}, upper-casing letters; unknown characters are `?`. */\nexport function pixelGlyph(char: string): readonly string[] {\n return PIXEL_FONT[char] ?? PIXEL_FONT[char.toUpperCase()] ?? PIXEL_FONT[\"?\"]!;\n}\n\n/** A glyph as GLSL `ivec2`: bit (x + 5y) of .x holds rows 0–3 (top first), of .y rows 4–6 (as image-ascii). */\nfunction packGlyph(rows: readonly string[]): string {\n let a = 0;\n let b = 0;\n rows.forEach((row, y) =>\n [...row].forEach((c, x) => {\n if (c !== \"#\") return;\n if (y < 4) a |= 1 << (x + 5 * y);\n else b |= 1 << (x + 5 * (y - 4));\n }),\n );\n return `ivec2(${a}, ${b})`;\n}\n\n/** `#rrggbb` as a GLSL `vec3`. */\nconst vec3Hex = (hex: string) => {\n const n = parseInt(hex.slice(1), 16);\n const c = [n >> 16, (n >> 8) & 255, n & 255].map((v) => +(v / 255).toFixed(3));\n return `vec3(${c.map((v) => (Number.isInteger(v) ? `${v}.0` : String(v))).join(\", \")})`;\n};\n\n/** A GLSL `const vec3 NAME[n]` palette. */\nconst paletteArray = (name: string, hexes: readonly string[]) =>\n `const vec3 ${name}[${hexes.length}] = vec3[${hexes.length}](\\n ${hexes.map(vec3Hex).join(\",\\n \")}\\n);`;\n\nconst GAMEBOY = [\"#0F380F\", \"#306230\", \"#8BAC0F\", \"#9BBC0F\"];\nconst PICO8 = [\"#000000\", \"#1D2B53\", \"#7E2553\", \"#008751\", \"#AB5236\", \"#5F574F\", \"#C2C3C7\", \"#FFF1E8\", \"#FF004D\", \"#FFA300\", \"#FFEC27\", \"#00E436\", \"#29ADFF\", \"#83769C\", \"#FF77A8\", \"#FFCCAA\"];\nconst NES = [\"#000000\", \"#FCFCFC\", \"#BCBCBC\", \"#7C7C7C\", \"#A81000\", \"#F83800\", \"#FCA044\", \"#F8D878\", \"#005800\", \"#00B800\", \"#B8F818\", \"#0058F8\", \"#3CBCFC\", \"#6844FC\", \"#D800CC\", \"#503000\"];\nconst CGA = [\"#000000\", \"#55FFFF\", \"#FF55FF\", \"#FFFFFF\"];\nconst C64 = [\"#000000\", \"#FFFFFF\", \"#880000\", \"#AAFFEE\", \"#CC44CC\", \"#00CC55\", \"#0000AA\", \"#EEEE77\", \"#DD8855\", \"#664400\", \"#FF7777\", \"#333333\", \"#777777\", \"#AAFF66\", \"#0088FF\", \"#BBBBBB\"];\n\n/** Ordered dithering thresholds, 0–1: `bayer4(cell)` (16 levels) and `bayer8(cell)` (64). */\nconst BAYER = `\nfloat bayer2(vec2 a) {\n a = floor(a);\n return fract(a.x / 2.0 + a.y * a.y * 0.75);\n}\nfloat bayer4(vec2 a) {\n return bayer2(0.5 * a) * 0.25 + bayer2(a);\n}\nfloat bayer8(vec2 a) {\n return bayer4(0.5 * a) * 0.25 + bayer2(a);\n}`.trim();\n\n/** 1D value noise along x, 0–1, for skylines (needs HASH). */\nconst NOISE1 = `\nfloat noise1(float x, float seed) {\n float i = floor(x);\n float f = fract(x);\n f = f * f * (3.0 - 2.0 * f);\n return mix(hash12(vec2(i, seed)), hash12(vec2(i + 1.0, seed)), f);\n}`.trim();\n\nexport const image8bit: ShaderEffect = {\n kind: \"shader\",\n id: \"image-8bit\",\n name: \"8-bit\",\n description: \"An image on a chunky pixel grid, reduced to a classic console or computer palette with ordered Bayer dithering.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"image\", \"8-bit\", \"dither\", \"palette\", \"game boy\", \"pico-8\"],\n source: glsl(\n `// 8-bit: an image on a chunky pixel grid in a classic palette, Bayer-dithered.\nuniform sampler2D uImage; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uPalette; // @control min=0 max=5 default=0 label=\"Palette (0 Game Boy, 1 PICO-8, 2 NES, 3 CGA, 4 C64, 5 1-bit)\"\nuniform float uPixel; // @control min=1 max=16 default=4 step=1 label=\"Pixel size\"\nuniform float uDither; // @control min=0 max=1 default=0.7 label=\"Dither\"\nuniform bool uBayer8; // @control default=true label=\"8 × 8 Bayer matrix\"\nuniform float uContrast; // @control min=0.5 max=2 default=1.1 label=\"Contrast\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n BAYER,\n paletteArray(\"GAMEBOY\", GAMEBOY),\n paletteArray(\"PICO8\", PICO8),\n paletteArray(\"NES\", NES),\n paletteArray(\"CGA\", CGA),\n paletteArray(\"C64\", C64),\n `// The palette colour closest to c (weighted for the eye).\nvec3 nearest(vec3 c, int pal) {\n vec3 best = vec3(0.0);\n float bestDist = 1e9;\n for (int i = 0; i < 16; i++) {\n vec3 p;\n if (pal == 1) p = PICO8[i];\n else if (pal == 2) p = NES[i];\n else if (pal == 4) p = C64[i];\n else {\n if (i >= 4) break;\n p = CGA[i];\n }\n vec3 d = c - p;\n float dist = dot(d * d, vec3(0.3, 0.59, 0.11));\n if (dist < bestDist) {\n bestDist = dist;\n best = p;\n }\n }\n return best;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec4 pic = pictureRGBA(uImage, (cell + 0.5) * uPixel / iResolution.xy);\n vec3 src = clamp((pic.rgb - 0.5) * uContrast + 0.5, 0.0, 1.0);\n float threshold = (uBayer8 ? bayer8(cell) + 0.5 / 64.0 : bayer4(cell) + 0.5 / 16.0) - 0.5;\n vec3 col;\n if (uPalette == 0 || uPalette == 5) {\n // Shades of one ramp: dither the brightness between its levels.\n float levels = uPalette == 0 ? 3.0 : 1.0;\n float l = dot(src, vec3(0.2126, 0.7152, 0.0722));\n int i = int(clamp(floor(l * levels + 0.5 + threshold * uDither), 0.0, levels));\n col = uPalette == 0 ? GAMEBOY[i] : vec3(float(i));\n } else {\n float spread = uPalette == 3 ? 0.55 : 0.22;\n col = nearest(src + threshold * uDither * spread, uPalette);\n }\n // Pixels are whole, so alpha is cut at a half rather than blended.\n fragColor = vec4(col, step(0.5, pic.a));\n}`,\n ),\n presets: [\n { name: \"Game Boy\", values: { uPalette: 0, uPixel: 4 } },\n { name: \"PICO-8\", values: { uPalette: 1, uPixel: 4 } },\n { name: \"NES\", values: { uPalette: 2, uPixel: 3 } },\n { name: \"CGA\", values: { uPalette: 3, uPixel: 3, uDither: 0.9 } },\n { name: \"C64\", values: { uPalette: 4, uPixel: 5, uBayer8: false } },\n { name: \"1-bit\", values: { uPalette: 5, uPixel: 2, uDither: 1 } },\n ],\n};\n\nexport const gameboyScreen: ShaderEffect = {\n kind: \"shader\",\n id: \"gameboy-screen\",\n name: \"Game Boy screen\",\n description: \"An image on a handheld's green dot-matrix LCD: four shades, a visible pixel grid and smeary ghosting, inset in an olive bezel.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"image\", \"game boy\", \"lcd\", \"handheld\", \"screen\"],\n source: glsl(\n `// Game Boy screen: an image on a 4-shade green LCD with a pixel grid, ghosting and a bezel.\nuniform sampler2D uImage; // @control filter=linear wrap=repeat default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uLines; // @control min=36 max=144 default=144 step=1 label=\"Screen lines\"\nuniform float uPan; // @control min=-0.3 max=0.3 default=0.04 label=\"Pan speed\"\nuniform float uGhost; // @control min=0 max=1 default=0.5 label=\"Ghosting\"\nuniform float uGrid; // @control min=0 max=1 default=0.6 label=\"Pixel grid\"\nuniform bool uDither; // @control default=true label=\"Dither\"\nuniform vec3 uDark; // @control color default=#0F380F label=\"Darkest shade\"\nuniform vec3 uLight; // @control color default=#9BBC0F label=\"Lightest shade\"\nuniform vec3 uBezel; // @control color default=#4E5236 label=\"Bezel\"\nuniform vec3 uCase; // @control color default=#C9C6BC label=\"Case\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n BAYER,\n `// The LCD shade (0 darkest – 3 lightest) of the picture at uv, for screen pixel cell.\nfloat shade(vec2 uv, vec2 cell) {\n float l = dot(picture(uImage, uv), vec3(0.2126, 0.7152, 0.0722));\n float d = uDither ? (bayer4(cell) - 0.47) * 0.7 : 0.0;\n return clamp(floor(l * 3.0 + 0.5 + d), 0.0, 3.0);\n}\n\nvec3 lcd(float s) {\n // The DMG's four greens sit at about these points between darkest and lightest.\n float w = s < 0.5 ? 0.0 : (s < 1.5 ? 0.28 : (s < 2.5 ? 0.88 : 1.0));\n return mix(uDark, uLight, w);\n}\n\nfloat roundBox(vec2 p, vec2 b, float r) {\n vec2 q = abs(p) - b + r;\n return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 res = iResolution.xy;\n float lines = floor(uLines);\n float cols = floor(lines * 160.0 / 144.0 + 0.5);\n // Whole device pixels per LCD pixel, so the grid is even.\n float px = max(1.0, floor(min(res.y * 0.64 / lines, res.x * 0.7 / cols)));\n vec2 size = vec2(cols, lines) * px;\n vec2 origin = floor((res - size) * 0.5);\n vec2 q = fragCoord - origin;\n float margin = floor(size.y * 0.12);\n\n vec3 col = uCase;\n // The bezel round the screen, with a rounded lower-right corner like the DMG's.\n vec2 bc = q - size * 0.5 - vec2(0.0, margin * 0.25);\n vec2 bh = size * 0.5 + vec2(margin * 1.6, margin * 1.25);\n float corner = (bc.x > 0.0 && bc.y < 0.0) ? margin * 2.0 : margin * 0.4;\n float bezel = roundBox(bc, bh, corner);\n col = mix(col, uBezel, clamp(0.5 - bezel, 0.0, 1.0));\n // Two stripes across the top of the bezel.\n float top = size.y + margin * 0.6;\n if (bezel < -1.0 && q.y > top && q.y < top + max(1.0, floor(margin * 0.08)))\n col = vec3(0.55, 0.15, 0.35);\n if (bezel < -1.0 && q.y > top + margin * 0.18 && q.y < top + margin * 0.18 + max(1.0, floor(margin * 0.08)))\n col = vec3(0.15, 0.18, 0.42);\n // Power LED.\n vec2 led = vec2(-margin * 0.85, size.y * 0.62);\n float ledR = max(2.0, margin * 0.18);\n float glow = 0.85 + 0.15 * sin(iTime * 3.0);\n col = mix(col, vec3(0.95, 0.15, 0.12) * glow, clamp(ledR - length(q - led) + 0.5, 0.0, 1.0));\n\n if (q.x >= 0.0 && q.y >= 0.0 && q.x < size.x && q.y < size.y) {\n vec2 cell = floor(q / px);\n vec2 f = q - cell * px;\n vec2 uv = (cell + 0.5) / vec2(cols, lines);\n vec2 now = uv + vec2(iTime * uPan, 0.0);\n // Ghosting: the LCD is slow, so where the picture was a moment ago still shows.\n vec2 before = now - vec2(uPan * 0.35, 0.0);\n float s = shade(now, cell);\n float g = shade(before, cell);\n vec3 lit = mix(lcd(s), lcd(g), uGhost * 0.45);\n // Each dot casts a faint shadow down and right onto the screen behind it.\n float behind = shade(now - vec2(1.0 / cols, -1.0 / lines), cell + vec2(-1.0, 1.0));\n lit = mix(lit, lcd(min(s, behind)), uGhost * 0.2);\n // The grid between dots shows the lighter screen behind.\n float edge = px >= 3.0 ? float(f.x < 1.0 || f.y >= px - 1.0) : 0.0;\n col = mix(lit, mix(uLight, vec3(1.0), 0.08), edge * uGrid * 0.6);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Chunky\", values: { uLines: 72 } },\n { name: \"Pocket\", values: { uDark: [0.16, 0.16, 0.14], uLight: [0.77, 0.79, 0.72], uBezel: [0.42, 0.42, 0.4], uCase: [0.78, 0.78, 0.76] } },\n ],\n};\n\nexport const pixelFire: ShaderEffect = {\n kind: \"shader\",\n id: \"pixel-fire\",\n name: \"Pixel fire\",\n description: \"Chunky Doom-style pixel fire licking up from the bottom through a stepped black, red, orange, yellow and white ramp.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"fire\", \"flame\", \"doom\", \"demoscene\", \"loop\"],\n source: glsl(\n `// Pixel fire: Doom-style chunky flames in a stepped palette ramp.\nuniform float uPixel; // @control min=2 max=16 default=6 step=1 label=\"Pixel size\"\nuniform float uHeight; // @control min=0.2 max=1.2 default=0.65 label=\"Flame height\"\nuniform float uWind; // @control min=-1 max=1 default=0.2 label=\"Wind\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uFlicker; // @control min=0 max=1 default=0.5 label=\"Flicker\"\nuniform int uLevels; // @control min=3 max=16 default=9 label=\"Palette steps\"\nuniform vec3 uEmber; // @control color default=#7A0E06 label=\"Embers\"\nuniform vec3 uFlame; // @control color default=#F2560E label=\"Flame\"\nuniform vec3 uCore; // @control color default=#FFE27A label=\"Core\"`,\n HASH,\n NOISE,\n FBM,\n `// Black → embers → flame → core → white.\nvec3 ramp(float t) {\n vec3 c = mix(vec3(0.02, 0.01, 0.01), uEmber, smoothstep(0.0, 0.3, t));\n c = mix(c, uFlame, smoothstep(0.3, 0.6, t));\n c = mix(c, uCore, smoothstep(0.6, 0.85, t));\n return mix(c, vec3(1.0, 1.0, 0.94), smoothstep(0.85, 1.0, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n float rows = max(floor(iResolution.y / uPixel), 1.0);\n float t = iTime * uSpeed;\n float y = cell.y / rows;\n // Columns lean with the wind the higher they get.\n float x = cell.x / rows - uWind * y * y * 0.8;\n float n = fbm(vec2(x * 7.0 + uWind * t * 1.5, y * 4.0 - t * 2.6), 4);\n float flick = hash12(cell + floor(t * 14.0) * 7.31) - 0.5;\n float heat = 1.05 - (y / uHeight) * (0.35 + 1.5 * n) + flick * 0.22 * uFlicker;\n float levels = float(uLevels);\n float lvl = clamp(floor(heat * levels), 0.0, levels - 1.0);\n fragColor = vec4(ramp(lvl / (levels - 1.0)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Doom\", values: { uPixel: 6, uLevels: 9 } },\n { name: \"Blue flame\", values: { uEmber: [0.04, 0.08, 0.42], uFlame: [0.16, 0.48, 1], uCore: [0.75, 0.96, 1] } },\n { name: \"Toxic\", values: { uEmber: [0.1, 0.3, 0.02], uFlame: [0.4, 0.85, 0.1], uCore: [0.85, 1, 0.5], uWind: -0.4 } },\n ],\n};\n\nexport const pixelLandscape: ShaderEffect = {\n kind: \"shader\",\n id: \"pixel-landscape\",\n name: \"Pixel landscape\",\n description: \"A parallax pixel-art landscape: clouds, snowy mountains, hills and pines scrolling at different speeds under a pixel sun or moon.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"landscape\", \"parallax\", \"game\", \"background\", \"16-bit\"],\n source: glsl(\n `// Pixel landscape: parallax layers of a limited-palette scene, each scrolling whole pixels.\nuniform float uPixel; // @control min=2 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Scroll speed\"\nuniform vec3 uSkyTop; // @control color default=#3E6FD8 label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#A8DCFF label=\"Sky bottom\"\nuniform vec3 uSun; // @control color default=#FFE066 label=\"Sun / moon\"\nuniform vec3 uCloud; // @control color default=#FFFFFF label=\"Clouds\"\nuniform vec3 uFar; // @control color default=#6E7EC0 label=\"Mountains\"\nuniform vec3 uMid; // @control color default=#3F9A4F label=\"Hills\"\nuniform vec3 uNear; // @control color default=#1E5B30 label=\"Foreground\"\nuniform float uStars; // @control min=0 max=1 default=0 label=\"Stars\"`,\n HASH,\n BAYER,\n NOISE1,\n `float mountain(float x) {\n float ridge = 1.0 - abs(2.0 * noise1(x * 0.03, 1.0) - 1.0);\n return ridge * 0.75 + noise1(x * 0.11, 2.0) * 0.25;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n float rows = max(floor(iResolution.y / uPixel), 1.0);\n float cols = max(floor(iResolution.x / uPixel), 1.0);\n float t = iTime * uSpeed;\n float y = cell.y;\n float sy = y / rows;\n\n // Sky in six bands, dithered where they meet.\n float band = clamp(floor(sy * 6.0 + (bayer4(cell) - 0.5) * 0.9), 0.0, 5.0) / 5.0;\n vec3 col = mix(uSkyBottom, uSkyTop, band);\n float star = hash12(cell);\n if (sy > 0.4 && star > 1.0 - 0.015 * uStars)\n col = mix(col, vec3(1.0), 0.5 + 0.5 * step(0.5, hash12(cell + floor(iTime * 2.0))));\n\n // Sun or moon: a pixel disc with a checkered halo.\n vec2 sun = floor(vec2(cols * 0.7, rows * 0.7));\n float r = max(3.0, floor(rows * 0.1));\n vec2 d = cell - sun;\n float dd = dot(d, d);\n if (dd <= (r + 2.0) * (r + 2.0) + r && mod(cell.x + cell.y, 2.0) < 1.0) col = mix(col, uSun, 0.45);\n if (dd <= r * r + r) col = uSun;\n\n // Clouds: flat-bottomed puffs drifting slowest.\n float cx = cell.x + floor(t * 2.0);\n float base = floor(rows * 0.76 + 3.0 * noise1(floor(cx / 40.0), 9.0));\n float puff = max(0.0, noise1(cx * 0.045, 4.0) - 0.42) * 2.4 * rows * 0.12 + max(0.0, noise1(cx * 0.16, 5.0) - 0.5) * rows * 0.05;\n if (y >= base && y < base + floor(puff)) col = y < base + 1.0 ? mix(uCloud, uSkyTop, 0.25) : uCloud;\n\n // Mountains, with snow on the high peaks and shaded far sides.\n float mx = cell.x + floor(t * 4.0);\n float mh = floor(rows * (0.3 + 0.32 * mountain(mx)));\n if (y <= mh) {\n // Faces sloping down to the right are in shade.\n float slope = mountain(mx + 2.0) - mountain(mx - 2.0);\n col = slope < 0.0 ? uFar * 0.82 : uFar;\n if (mh > rows * 0.52 && y > mh - 3.0 - mod(mx, 2.0)) col = mix(uFar, vec3(1.0), 0.75);\n }\n\n // Rolling hills, a lit rim along the top.\n float hx = cell.x + floor(t * 9.0);\n float hh = floor(rows * (0.24 + 0.06 * sin(hx * 0.045) + 0.04 * noise1(hx * 0.09, 6.0)));\n if (y <= hh) col = y > hh - 1.0 ? mix(uMid, vec3(1.0), 0.2) : uMid;\n\n // Foreground: a strip of ground with pine trees, fastest.\n float nx = cell.x + floor(t * 18.0);\n float nh = floor(rows * (0.1 + 0.02 * sin(nx * 0.08)));\n float slot = floor(nx / 14.0);\n float lx = abs(mod(nx, 14.0) - 7.0);\n float treeH = floor(rows * (0.08 + 0.08 * hash12(vec2(slot, 3.0))));\n bool tree = hash12(vec2(slot, 7.0)) > 0.35 && y > nh && y <= nh + treeH && lx <= floor((nh + treeH - y) / 2.5);\n if (y <= nh || tree) col = tree ? uNear * 0.8 : uNear;\n if (!tree && y <= nh && y > nh - 1.0) col = mix(uNear, uMid, 0.5);\n\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n {\n name: \"Dusk\",\n values: {\n uSkyTop: [0.17, 0.11, 0.31],\n uSkyBottom: [0.95, 0.53, 0.35],\n uSun: [1, 0.36, 0.24],\n uCloud: [0.96, 0.69, 0.57],\n uFar: [0.42, 0.24, 0.43],\n uMid: [0.23, 0.15, 0.31],\n uNear: [0.1, 0.07, 0.19],\n },\n },\n {\n name: \"Night\",\n values: {\n uSkyTop: [0.02, 0.03, 0.09],\n uSkyBottom: [0.11, 0.17, 0.35],\n uSun: [0.95, 0.94, 0.85],\n uCloud: [0.22, 0.27, 0.48],\n uFar: [0.15, 0.19, 0.37],\n uMid: [0.1, 0.14, 0.28],\n uNear: [0.05, 0.07, 0.16],\n uStars: 1,\n },\n },\n ],\n};\n\nexport const outrunRoad: ShaderEffect = {\n kind: \"shader\",\n id: \"outrun-road\",\n name: \"Outrun road\",\n description: \"A pseudo-3D arcade racer's road curving toward a striped sunset sun, with rumble strips, stripe bands and roadside poles rushing past.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"racing\", \"80s\", \"arcade\", \"road\", \"synthwave\", \"sunset\"],\n source: glsl(\n `// Outrun road: a pseudo-3D road racing toward a striped sun, all on a pixel grid.\nuniform float uPixel; // @control min=1 max=12 default=3 step=1 label=\"Pixel size\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Speed\"\nuniform float uCurve; // @control min=0 max=1 default=0.6 label=\"Curves\"\nuniform vec3 uSkyTop; // @control color default=#1B0B42 label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#FF6A5C label=\"Sky bottom\"\nuniform vec3 uSunTop; // @control color default=#FFE45E label=\"Sun top\"\nuniform vec3 uSunBottom; // @control color default=#FF2E88 label=\"Sun bottom\"\nuniform vec3 uGrass; // @control color default=#1F8F4E label=\"Verge\"\nuniform vec3 uRoad; // @control color default=#56566A label=\"Road\"\nuniform vec3 uKerb; // @control color default=#E8343F label=\"Rumble strip\"`,\n HASH,\n BAYER,\n NOISE1,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec2 grid = max(floor(iResolution.xy / uPixel), vec2(1.0));\n float horizon = floor(grid.y * 0.46);\n float t = iTime * uSpeed;\n float curve = uCurve * sin(iTime * 0.32);\n float cx = floor(grid.x * 0.5);\n vec3 col;\n\n if (cell.y >= horizon) {\n // Sky in banded steps, dithered between them.\n float h = (cell.y - horizon) / max(grid.y - horizon, 1.0);\n float band = clamp(floor(h * 7.0 + (bayer4(cell) - 0.5) * 0.8), 0.0, 6.0) / 6.0;\n col = mix(uSkyBottom, uSkyTop, band);\n // The sun, sliding against the curve, with gaps widening toward its foot.\n float r = floor(grid.y * 0.2);\n vec2 sc = vec2(floor(cx - curve * grid.x * 0.25), horizon + floor(r * 0.55));\n vec2 d = cell - sc;\n if (dot(d, d) <= r * r + r) {\n float below = -d.y;\n bool gap = below > 0.0 && mod(below, 5.0) < floor(below / r * 4.0 + 0.5);\n if (!gap) col = mix(uSunBottom, uSunTop, clamp(floor((d.y / r * 0.5 + 0.5) * 4.0) / 3.0, 0.0, 1.0));\n }\n // A pixel skyline of hills on the horizon.\n float hills = floor(2.0 + 5.0 * noise1((cell.x + floor(curve * grid.x * 0.4)) * 0.07, 3.0));\n if (cell.y < horizon + hills) col = mix(uSkyTop, uGrass, 0.25);\n } else {\n float dy = horizon - cell.y;\n float scale = dy / horizon;\n float z = 1.0 / scale;\n float roadX = cx + curve * grid.x * 0.6 * (1.0 - scale) * (1.0 - scale);\n float halfW = grid.x * 0.42 * scale;\n float dx = abs(cell.x - roadX);\n float alt = mod(floor((z + t * 10.0) * 0.5), 2.0);\n col = uGrass * (alt > 0.5 ? 1.0 : 0.8);\n if (dx < halfW) {\n col = uRoad * (alt > 0.5 ? 1.0 : 0.9);\n // Lane lines on every other band.\n float lane = abs(dx - halfW / 3.0);\n if (alt > 0.5 && (lane < max(0.5, halfW * 0.025) || dx < max(0.5, halfW * 0.025))) col = vec3(0.95);\n } else if (dx < halfW * 1.12) {\n col = alt > 0.5 ? uKerb : vec3(0.95);\n }\n // Haze near the horizon.\n float haze = clamp(1.0 - scale * 6.0, 0.0, 1.0);\n if (bayer4(cell) < haze * 0.8) col = uSkyBottom * 0.8;\n }\n\n // Roadside poles, the nearest drawn last.\n for (int k = 7; k >= 0; k--) {\n float period = 8.0;\n float zk = float(k) * period + period - mod(t * 10.0, period);\n if (zk < 1.0) continue;\n float sk = 1.0 / zk;\n float yb = horizon - sk * horizon;\n float roadX = cx + curve * grid.x * 0.6 * (1.0 - sk) * (1.0 - sk);\n float off = grid.x * 0.42 * sk * 1.35;\n float w = max(1.0, floor(grid.x * 0.012 * sk + 0.5));\n float ph = floor(grid.y * 0.42 * sk) + 2.0;\n float py = cell.y - floor(yb);\n if (py >= 0.0 && py < ph) {\n for (int side = 0; side < 2; side++) {\n float px = floor(roadX + (side == 0 ? -off : off));\n if (cell.x >= px && cell.x < px + w) {\n col = py > ph - max(1.0, floor(w * 1.5)) ? uSunTop : (mod(floor(py / max(1.0, w * 2.0)), 2.0) < 1.0 ? vec3(0.95) : uKerb);\n }\n }\n }\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Coastline\", values: { uSkyTop: [0.12, 0.35, 0.85], uSkyBottom: [0.65, 0.88, 1], uSunTop: [1, 1, 0.85], uSunBottom: [1, 0.85, 0.4], uGrass: [0.85, 0.78, 0.5] } },\n { name: \"Midnight\", values: { uSkyTop: [0.01, 0.0, 0.06], uSkyBottom: [0.3, 0.05, 0.45], uGrass: [0.05, 0.02, 0.15], uRoad: [0.12, 0.1, 0.2], uKerb: [0.0, 0.95, 1] } },\n ],\n};\n\nconst WATER_RAMP = [0, 0.1, 0.22, 0.4, 0.7, 1, 0.75, 0.45, 0.25, 0.12, 0.05, 0, 0.08, 0.18, 0.1, 0];\n\nexport const paletteCycle: ShaderEffect = {\n kind: \"shader\",\n id: \"palette-cycle\",\n name: \"Palette cycle\",\n description: \"Demoscene colour cycling: a still pixel-art waterfall (or plasma) brought to life purely by rotating its palette.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"palette\", \"colour cycling\", \"demoscene\", \"waterfall\", \"plasma\", \"loop\"],\n loop: 2,\n source: glsl(\n `// Palette cycle: a static indexed picture animated only by rotating its palette.\nuniform int uScene; // @control min=0 max=1 default=0 label=\"Scene (0 waterfall, 1 plasma)\"\nuniform float uPixel; // @control min=2 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uRate; // @control min=0 max=32 default=8 step=1 label=\"Cycle speed (steps per second)\"\nuniform vec3 uDeep; // @control color default=#163C8C label=\"Water\"\nuniform vec3 uFoam; // @control color default=#E8F7FF label=\"Foam\"\nuniform vec3 uRock; // @control color default=#5A4466 label=\"Rock\"\nuniform vec3 uSky; // @control color default=#1A1238 label=\"Sky\"`,\n HASH,\n BAYER,\n NOISE1,\n `const float WATER[16] = float[16](${WATER_RAMP.map((v) => v.toFixed(2)).join(\", \")});\n\nvec3 water(float i) {\n return mix(uDeep, uFoam, WATER[int(mod(i, 16.0))]);\n}\n\nvec3 rainbow(float i) {\n float t = mod(i, 16.0) / 16.0;\n return 0.5 + 0.5 * cos(6.28318 * (t + vec3(0.0, 0.33, 0.67)));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec2 grid = max(floor(iResolution.xy / uPixel), vec2(1.0));\n float shift = floor(iTime * uRate);\n vec3 col;\n\n if (uScene == 1) {\n // A plasma whose 16 palette indices rotate.\n vec2 p = cell / grid.y * 8.0;\n float v = sin(p.x) + sin(p.y * 1.3) + sin((p.x + p.y) * 0.7) + sin(length(p - 4.0) * 1.5);\n float index = floor((v * 0.125 + 0.5) * 32.0);\n fragColor = vec4(rainbow(index - shift), 1.0);\n return;\n }\n\n vec2 uv = cell / grid;\n float mid = floor(grid.x * 0.5);\n float fallHalf = floor(grid.x * 0.1 + 2.0 * noise1(cell.y * 0.2, 2.0));\n float cliffTop = floor(grid.y * (0.74 + 0.08 * noise1(cell.x * 0.08, 1.0)));\n float poolTop = floor(grid.y * 0.26);\n\n // Night sky with fixed stars (the sky never cycles).\n col = mix(uSky, uSky * 1.8 + 0.04, floor((1.0 - uv.y) * 4.0) / 4.0);\n if (hash12(cell) > 0.985) col = vec3(0.85, 0.85, 1.0);\n\n if (cell.y < cliffTop && cell.y >= poolTop) {\n // Rock in three tones with strata.\n float tone = floor(clamp(noise1(cell.x * 0.3 + floor(cell.y / 3.0) * 7.0, 5.0) * 2.2 + (bayer4(cell) - 0.5) * 0.6, 0.0, 2.0));\n col = uRock * (0.65 + 0.25 * tone);\n }\n if (abs(cell.x - mid) <= fallHalf && cell.y >= poolTop && cell.y < cliffTop + 1.0) {\n // The fall: streaks whose indices rise with height, so cycling moves them down.\n float streak = floor(hash12(vec2(cell.x, 7.0)) * 6.0);\n col = water(floor(cell.y / 2.0) + streak + shift);\n if (abs(cell.x - mid) == fallHalf) col = mix(col, uDeep, 0.5);\n }\n if (cell.y < poolTop) {\n // The pool: ripple rings whose indices fall outward from the splash.\n vec2 d = (cell - vec2(mid, poolTop)) * vec2(1.0, 2.6);\n float ring = floor(length(d) / 2.0);\n col = mix(uDeep * 0.7, water(ring - shift), 0.75 - 0.4 * uv.y / 0.26);\n // Churning foam where the fall lands.\n if (abs(cell.x - mid) <= fallHalf + 3.0 && cell.y > poolTop - 4.0)\n col = water(floor(hash12(cell) * 16.0) + shift);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Plasma\", values: { uScene: 1, uRate: 12 } },\n { name: \"Lava\", values: { uDeep: [0.45, 0.05, 0.02], uFoam: [1, 0.85, 0.3], uRock: [0.2, 0.17, 0.2], uSky: [0.12, 0.03, 0.05] } },\n ],\n};\n\nconst RASTER_COLOURS = [\"#E8343F\", \"#FF8A1F\", \"#FFE14D\", \"#3FD15C\", \"#2EE6E6\", \"#2E6BFF\", \"#9B4DFF\", \"#FF4DC4\"];\n\nexport const rasterBars: ShaderEffect = {\n kind: \"shader\",\n id: \"raster-bars\",\n name: \"Raster bars\",\n description: \"Demoscene copper bars bouncing on sine paths behind a sine-scrolling greeting, all in chunky pixels.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"demoscene\", \"amiga\", \"c64\", \"scroller\", \"text\", \"copper\"],\n source: glsl(\n `// Raster bars: copper bars on sine paths behind a sine scroller.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"GREETINGS FROM FLAIR\", { width: 2048, height: 256 })} label=\"Scroller text\"\nuniform float uPixel; // @control min=1 max=12 default=4 step=1 label=\"Pixel size\"\nuniform int uBars; // @control min=1 max=8 default=7 label=\"Bars\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uWave; // @control min=0 max=1 default=0.5 label=\"Text wave\"\nuniform vec3 uBackground; // @control color default=#0B0B24 label=\"Background\"\nuniform vec3 uTextTop; // @control color default=#FFFFFF label=\"Text top\"\nuniform vec3 uTextBottom; // @control color default=#3AA0FF label=\"Text bottom\"`,\n paletteArray(\"BARS\", RASTER_COLOURS),\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n vec2 grid = max(floor(iResolution.xy / uPixel), vec2(1.0));\n float t = iTime * uSpeed;\n vec3 col = uBackground;\n\n // Copper bars: each a stepped highlight, later bars over earlier ones.\n float thick = max(3.0, floor(grid.y * 0.06));\n for (int i = 0; i < 8; i++) {\n if (i >= uBars) break;\n float fi = float(i);\n float centre = floor(grid.y * (0.5 + 0.36 * sin(t * 1.7 + fi * 0.55)));\n float dy = abs(cell.y - centre);\n if (dy <= thick) {\n float level = ceil((1.0 - dy / (thick + 1.0)) * 4.0) / 4.0;\n col = BARS[i] * (0.25 + 0.75 * level) + vec3(pow(level, 4.0) * 0.35);\n }\n }\n\n // Scroller: text marching left, each column bobbing on a sine.\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float h = floor(grid.y * 0.3);\n float w = h * aspect;\n // Starting with the text already on screen, near the left.\n float scroll = mod(t * grid.y * 0.35 + grid.x * 0.9, w + grid.x);\n float tx = cell.x + scroll - grid.x;\n float bob = floor(sin(tx * 0.06 + t * 3.0) * grid.y * 0.14 * uWave);\n float ty = cell.y - (floor(grid.y * 0.5 - h * 0.5) + bob);\n vec2 uv = (vec2(tx, ty) + 0.5) / vec2(w, h);\n vec2 shadowUv = uv + vec2(-1.0 / w, 1.0 / h);\n float ink = (uv.x > 0.0 && uv.x < 1.0 && uv.y > 0.0 && uv.y < 1.0) ? step(0.5, texture(uText, uv).a) : 0.0;\n float shadow = (shadowUv.x > 0.0 && shadowUv.x < 1.0 && shadowUv.y > 0.0 && shadowUv.y < 1.0) ? step(0.5, texture(uText, shadowUv).a) : 0.0;\n if (shadow > 0.5) col = vec3(0.0);\n if (ink > 0.5) {\n // A stepped gradient down the letters.\n float g = clamp(floor((uv.y - 0.3) / 0.4 * 4.0) / 3.0, 0.0, 1.0);\n col = mix(uTextBottom, uTextTop, g);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Amiga\", values: { uBackground: [0, 0, 0], uTextTop: [1, 0.9, 0.3], uTextBottom: [1, 0.3, 0.1] } },\n { name: \"Gentle\", values: { uSpeed: 0.5, uWave: 0.25, uBars: 4 } },\n ],\n};\n\n/** The loading screen's lines, 20 columns each (a blank line between). */\nconst LOADING_LINES = [\"PRESS PLAY ON TAPE\", \"\", \"LOADING\", \"\", \"READY.\", \"\"];\nconst LOADING_COLS = 20;\nconst loadingChars = [...new Set([\" \", ...LOADING_LINES.join(\"\")])];\nconst loadingText = LOADING_LINES.flatMap((line) => [...line.padEnd(LOADING_COLS)].map((c) => loadingChars.indexOf(c)));\n\nexport const loadingStripes: ShaderEffect = {\n kind: \"shader\",\n id: \"loading-stripes\",\n name: \"Tape loading\",\n description: \"An 8-bit computer loading from tape: chaotic colour stripes racing through the border around a blue screen with a blinking cursor under READY.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"c64\", \"loading\", \"loader\", \"8-bit\", \"computer\", \"text\"],\n source: glsl(\n `// Tape loading: raster stripes in the border, a bitmap-font screen and a blinking cursor.\nuniform vec3 uScreen; // @control color default=#352879 label=\"Screen\"\nuniform vec3 uInk; // @control color default=#6C5EB5 label=\"Text\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Stripe speed\"\nuniform float uStripe; // @control min=1 max=12 default=3 step=1 label=\"Stripe thickness\"`,\n HASH,\n paletteArray(\"C64\", C64),\n `// 5 × 7 glyphs: bit (x + 5y) of .x holds rows 0–3 (top first), of .y rows 4–6.\nconst ivec2 GLYPHS[${loadingChars.length}] = ivec2[${loadingChars.length}](\n ${loadingChars.map((c) => packGlyph(PIXEL_FONT[c]!)).join(\",\\n \")}\n);\nconst int TEXT[${loadingText.length}] = int[${loadingText.length}](${loadingText.join(\", \")});\n\nfloat glyphBit(ivec2 g, int x, int y) {\n if (x < 0 || x > 4 || y < 0 || y > 6) return 0.0;\n int bits = y < 4 ? (g.x >> (x + 5 * y)) : (g.y >> (x + 5 * (y - 4)));\n return float(bits & 1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n // The screen is 128 × 80 virtual pixels: 20 columns of 6 and 8 rows of 8, a margin round them.\n vec2 screen = vec2(128.0, 80.0);\n float px = max(1.0, floor(min(iResolution.x * 0.78 / screen.x, iResolution.y * 0.72 / screen.y)));\n vec2 origin = floor((iResolution.xy - screen * px) * 0.5);\n vec2 q = floor((fragCoord - origin) / px);\n\n if (q.x < 0.0 || q.y < 0.0 || q.x >= screen.x || q.y >= screen.y) {\n // Border: stripes of two overlapping widths, reshuffled every tick.\n float row = floor(fragCoord.y / px);\n float tick = floor(iTime * uSpeed * 20.0);\n float offset = floor(hash12(vec2(tick, 3.0)) * 400.0);\n float a = floor((row + offset) / uStripe);\n float b = floor((row + offset * 1.7) / (uStripe * 2.3));\n int c = int(hash12(vec2(a + b * 31.0, tick)) * 16.0);\n fragColor = vec4(C64[c], 1.0);\n return;\n }\n\n vec3 col = uScreen;\n float x = q.x - 4.0;\n float y = screen.y - 5.0 - q.y;\n int tc = int(floor(x / 6.0));\n int tr = int(floor(y / 8.0));\n int gx = int(mod(x, 6.0));\n int gy = int(mod(y, 8.0));\n if (x >= 0.0 && y >= 0.0 && tc < ${LOADING_COLS} && tr < ${LOADING_LINES.length}) {\n float ink = glyphBit(GLYPHS[TEXT[tr * ${LOADING_COLS} + tc]], gx, gy);\n // The cursor: a block under READY., on and off.\n if (tr == ${LOADING_LINES.length - 1} && tc == 0 && gx < 6 && mod(floor(iTime * 2.5), 2.0) < 1.0) ink = 1.0;\n col = mix(col, uInk, ink);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Green screen\", values: { uScreen: [0.02, 0.1, 0.03], uInk: [0.3, 1, 0.4] } },\n { name: \"Turbo\", values: { uSpeed: 2.5, uStripe: 1 } },\n ],\n};\n\nexport const pixelWater: ShaderEffect = {\n kind: \"shader\",\n id: \"pixel-water\",\n name: \"Pixel water\",\n description: \"Tiling pixel-art water in three blues with wavy highlight lines and twinkling sparkles; it loops and tiles seamlessly.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"water\", \"tile\", \"game\", \"background\", \"loop\"],\n loop: 4,\n source: glsl(\n `// Pixel water: a seamless tile of banded blues, crest highlights and sparkles.\nuniform float uPixel; // @control min=1 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uTile; // @control min=8 max=64 default=32 step=1 label=\"Tile size (pixels)\"\nuniform vec3 uDeep; // @control color default=#1B3B8F label=\"Deep\"\nuniform vec3 uMid; // @control color default=#2F6FD6 label=\"Mid\"\nuniform vec3 uLight; // @control color default=#6FB8FF label=\"Light\"\nuniform vec3 uFoam; // @control color default=#FFFFFF label=\"Highlights\"\nuniform float uSparkle; // @control min=0 max=1 default=0.6 label=\"Sparkles\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 cell = floor(fragCoord / uPixel);\n float tile = floor(uTile);\n vec2 p = mod(cell, tile);\n float k = 6.28318 / tile;\n float w = iTime * 6.28318 / 4.0;\n // Whole waves per tile and per loop, so it tiles and loops seamlessly.\n float a = sin(k * p.x + 1.4 * sin(k * 2.0 * p.y + w) + w);\n float b = sin(k * 2.0 * p.y - w + 0.9 * sin(k * p.x - w));\n float v = 0.5 + 0.28 * a + 0.22 * b;\n vec3 col = v < 0.4 ? uDeep : (v < 0.72 ? uMid : uLight);\n if (v > 0.86 && mod(p.y, 2.0) < 1.0) col = uFoam;\n\n // Sparkles: one per 8 × 8 block of the tile, a plus that blinks once a loop.\n vec2 block = floor(p / 8.0);\n vec2 at = floor(block * 8.0 + 1.0 + hash22(block + tile) * 6.0);\n float phase = fract(iTime / 4.0 + hash12(block * 1.7 + tile));\n float life = phase < 0.12 ? phase / 0.12 : 0.0;\n if (hash12(block + 9.1) < uSparkle && life > 0.0) {\n vec2 d = abs(p - at);\n float arm = life > 0.3 && life < 0.75 ? 1.0 : 0.0;\n if ((d.x + d.y < 0.5) || (arm > 0.5 && min(d.x, d.y) < 0.5 && d.x + d.y < 1.5)) col = uFoam;\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Lagoon\", values: { uDeep: [0.0, 0.42, 0.55], uMid: [0.1, 0.7, 0.75], uLight: [0.55, 0.95, 0.9] } },\n { name: \"Murky\", values: { uDeep: [0.1, 0.18, 0.15], uMid: [0.18, 0.3, 0.22], uLight: [0.35, 0.48, 0.32], uFoam: [0.7, 0.8, 0.6], uSparkle: 0.2 } },\n ],\n};\n\nexport const pixelDissolve: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-pixel-dissolve\",\n name: \"Pixel dissolve\",\n description: \"The picture pixelates up to big blocks, the blocks swap to the next image in a random order, then it resolves into the new picture. Loops back and forth; or turn Animate off and set Progress.\",\n category: \"transition\",\n tags: [\"transition\", \"pixel\", \"image\", \"retro\", \"8-bit\", \"slideshow\"],\n loop: 4,\n source: glsl(\n `// Pixel dissolve: pixelate up, swap blocks in a random order, resolve down. Progress runs 0 → 1 → 0 when animated.\nuniform sampler2D uFrom; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"From image\"\nuniform sampler2D uTo; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.city} label=\"To image\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uMaxBlock; // @control min=4 max=96 default=40 step=1 label=\"Largest block (px)\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float p = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n // 0–0.35 blocks grow; 0.35–0.65 blocks swap; 0.65–1 blocks shrink.\n float grow = clamp(p / 0.35, 0.0, 1.0);\n float shrink = clamp((1.0 - p) / 0.35, 0.0, 1.0);\n float k = min(grow, shrink);\n float block = max(1.0, floor(mix(1.0, uMaxBlock, k * k)));\n vec2 cell = floor(fragCoord / block);\n vec2 uv = (cell + 0.5) * block / iResolution.xy;\n // The order blocks swap in, picked on the largest grid so a block swaps whole.\n vec2 big = floor(fragCoord / uMaxBlock);\n float swap = clamp((p - 0.35) / 0.3, 0.0, 1.0);\n bool showTo = p >= 0.65 || (p > 0.35 && hash12(big + 0.5) < swap);\n fragColor = showTo ? pictureRGBA(uTo, uv) : pictureRGBA(uFrom, uv);\n}`,\n ),\n};\n\n/** Retro and pixel graphics: limited palettes, chunky pixels, demoscene and arcade looks. */\nexport const pixelShaders: ShaderEffect[] = [\n image8bit,\n gameboyScreen,\n pixelFire,\n pixelLandscape,\n outrunRoad,\n paletteCycle,\n rasterBars,\n loadingStripes,\n pixelWater,\n pixelDissolve,\n];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport { pixelGlyph } from \"./shaders/pixel.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Pixel art as SVG: each sprite is a bitmap (rows of characters, one per\n * colour) turned into one path per colour, a run of pixels per sub-path, and\n * drawn with `shape-rendering=\"crispEdges\"` so pixels stay hard-edged.\n * Sprite frames change by snapping a path's `d` (a change with no duration).\n */\n\nconst r2 = (v: number) => Math.round(v * 100) / 100;\n\n/** A derived number in an animation's numeric field (`delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/**\n * The pixels of `bitmap` that are `char`, as path data: a rectangle per run\n * of pixels in a row, each pixel `unit` wide, the top-left at (`x`, `y`).\n */\nexport function bitmapPath(bitmap: readonly string[], char: string, unit = 1, x = 0, y = 0): string {\n let d = \"\";\n bitmap.forEach((row, j) => {\n for (let i = 0; i < row.length; ) {\n if (row[i] !== char) {\n i++;\n continue;\n }\n let end = i;\n while (row[end] === char) end++;\n d += `M${r2(x + i * unit)} ${r2(y + j * unit)}h${r2((end - i) * unit)}v${r2(unit)}h${r2(-(end - i) * unit)}z`;\n i = end;\n }\n });\n return d || \"M0 0\";\n}\n\n/** A bitmap drawn as one path per colour: `colours` maps its characters to fills. */\nfunction sprite(bitmap: readonly string[], colours: Record<string, string>, unit = 1, x = 0, y = 0, id?: (char: string) => string | undefined): string {\n return Object.entries(colours)\n .map(([char, fill]) => {\n const pid = id?.(char);\n return `<path${pid ? ` id=\"${pid}\"` : \"\"} fill=\"${fill}\" d=\"${bitmapPath(bitmap, char, unit, x, y)}\"/>`;\n })\n .join(\"\");\n}\n\n/** Instant changes: the attribute snaps to `value` at `delay`. */\nconst snap = (id: string, attr: string, value: string | number, delay: number): SvgAnimation => ({ id, attrs: { [attr]: [value, value] }, delay, ms: 0 });\n\n// ── Pixel text ─────────────────────────────────────────────────────────\n\n/** Letters pixel text has room for; longer text is cut. */\nconst TEXT_SLOTS = 16;\nconst TEXT_W = 240;\nconst TEXT_H = 100;\n\n/** A letter's drop: from `lift` units above its place, a bounce, then at rest. */\nconst letterAt = (i: number, lift: number) => `translate(${i * 6} ${lift})`;\n\nexport const pixelText: VectorEffect = {\n kind: \"vector\",\n id: \"pixel-text\",\n name: \"Pixel text\",\n description: \"Any text set in a chunky 5 × 7 pixel font, its letters dropping in one after another with a little bounce.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"text\", \"title\", \"8-bit\", \"arcade\", \"font\"],\n hold: 1400,\n presets: [\n { name: \"Arcade\", values: { ink: [1, 0.85, 0.1], shadow: [0.85, 0.15, 0.1], background: [0, 0, 0] } },\n { name: \"Game Boy\", values: { ink: [0.06, 0.22, 0.06], shadow: [0.55, 0.67, 0.06], background: [0.61, 0.74, 0.06] } },\n ],\n // Each letter slot is one path; its `d` is worked out from the text here (attribute values, so no markup is injected).\n derived: (v) => {\n const letters = Array.from(String(v.text ?? \"\")).slice(0, TEXT_SLOTS);\n const count = Math.max(1, letters.length);\n const width = count * 6 - 1;\n const scale = Math.min(10, (TEXT_W - 20) / width);\n const out: Record<string, string | number> = {\n fit: `translate(${r2((TEXT_W - width * scale) / 2)} ${r2((TEXT_H - 7 * scale) / 2)}) scale(${r2(scale)})`,\n };\n const stagger = Number(v.stagger) || 0;\n for (let i = 0; i < TEXT_SLOTS; i++) {\n const c = letters[i];\n out[`d${i}`] = c === undefined || /\\s/.test(c) ? \"M0 0\" : bitmapPath(pixelGlyph(c), \"#\");\n // When it starts falling, lands and tops its bounce.\n out[`t${i}`] = Math.round(i * stagger);\n out[`u${i}`] = Math.round(i * stagger) + 260;\n out[`w${i}`] = Math.round(i * stagger) + 370;\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 ${TEXT_W} ${TEXT_H}\" shape-rendering=\"crispEdges\"><!-- {{text: text default=PIXEL label='Text'}} {{ink: color default=#FFFFFF label='Letters'}} {{shadow: color default=#E8343F label='Shadow'}} {{background: color default=#1A1C2C label='Background'}} {{stagger: float min=20 max=300 default=90 step=10 label='Stagger (ms)'}} --><rect width=\"${TEXT_W}\" height=\"${TEXT_H}\" fill=\"{{background}}\"/><g transform=\"{{fit}}\">${Array.from(\n { length: TEXT_SLOTS },\n (_, i) =>\n `<g id=\"g${i}\" transform=\"${letterAt(i, -14)}\" opacity=\"0\"><path transform=\"translate(0.6 0.6)\" fill=\"{{shadow}}\" d=\"{{d${i}}}\"/><path fill=\"{{ink}}\" d=\"{{d${i}}}\"/></g>`,\n ).join(\"\")}</g></svg>`,\n animate: Array.from({ length: TEXT_SLOTS }, (_, i): SvgAnimation[] => [\n { id: `g${i}`, attrs: { opacity: [0, 1] }, delay: n(`t${i}`), ms: 60, ease: \"linear\" },\n { id: `g${i}`, attrs: { transform: [letterAt(i, -14), letterAt(i, 0)] }, delay: n(`t${i}`), ms: 260, ease: \"in-out\" },\n { id: `g${i}`, attrs: { transform: [letterAt(i, 0), letterAt(i, -1.6)] }, delay: n(`u${i}`), ms: 110, ease: \"out\" },\n { id: `g${i}`, attrs: { transform: [letterAt(i, -1.6), letterAt(i, 0)] }, delay: n(`w${i}`), ms: 120, ease: \"in-out\" },\n ]).flat(),\n },\n};\n\n// ── Coin spin ──────────────────────────────────────────────────────────\n\nconst COIN = [\n \"...oooo...\",\n \"..oyyyyo..\",\n \".oylyyyyo.\",\n \".oylyddyo.\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \"oylyyddyyo\",\n \".oyyyddyo.\",\n \".oyyyyyyo.\",\n \"..oyyyyo..\",\n \"...oooo...\",\n];\nconst SPARKLE = [\"..w..\", \"..w..\", \"ww.ww\", \"..w..\", \"..w..\"];\n/** \"+1\" in the pixel font, a column apart. */\nconst PLUS_ONE = pixelGlyph(\"+\").map((row, j) => `${row}.${pixelGlyph(\"1\")[j]}`);\nconst coinPose = (sx: number) => `translate(60 60) scale(${sx} 1) translate(-25 -35)`;\nconst sparklePose = (s: number) => `translate(86 30) scale(${s}) translate(-6.25 -6.25)`;\n\nexport const coinSpin: VectorEffect = {\n kind: \"vector\",\n id: \"coin-spin\",\n name: \"Coin spin\",\n description: \"An 8-bit gold coin spinning on the spot, a pixel sparkle glinting and a +1 popping up each turn.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"coin\", \"game\", \"reward\", \"8-bit\", \"icon\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Silver\", values: { gold: [0.78, 0.8, 0.85], light: [1, 1, 1], dark: [0.45, 0.48, 0.55], outline: [0.2, 0.22, 0.28] } },\n { name: \"Ruby\", values: { gold: [0.9, 0.15, 0.3], light: [1, 0.6, 0.7], dark: [0.55, 0.05, 0.15], outline: [0.25, 0.02, 0.08] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#1A1C2C label='Background'}} {{gold: color default=#F7C531 label='Coin'}} {{light: color default=#FFF3A8 label='Shine'}} {{dark: color default=#C27C0E label='Shade'}} {{outline: color default=#5A2E05 label='Outline'}} {{plus: color default=#FFFFFF label='+1'}} --><rect width=\"120\" height=\"120\" fill=\"{{background}}\"/><g id=\"coin\" transform=\"${coinPose(1)}\">${sprite(COIN, { o: \"{{outline}}\", y: \"{{gold}}\", l: \"{{light}}\", d: \"{{dark}}\" }, 5)}</g><g id=\"sparkle\" transform=\"${sparklePose(0)}\">${sprite(SPARKLE, { w: \"{{light}}\" }, 2.5)}</g><g id=\"plus\" transform=\"translate(66 22)\" opacity=\"0\">${sprite(PLUS_ONE, { \"#\": \"{{plus}}\" }, 2)}</g></svg>`,\n animate: [\n // A full turn: face, edge, back (mirrored), edge, face.\n { id: \"coin\", attrs: { transform: [coinPose(1), coinPose(-1)] }, ms: 500, ease: \"in-out\" },\n { id: \"coin\", attrs: { transform: [coinPose(-1), coinPose(1)] }, delay: 500, ms: 500, ease: \"in-out\" },\n { id: \"sparkle\", attrs: { transform: [sparklePose(0), sparklePose(1)] }, delay: 150, ms: 150, ease: \"out\" },\n { id: \"sparkle\", attrs: { transform: [sparklePose(1), sparklePose(0)] }, delay: 300, ms: 200, ease: \"in-out\" },\n { id: \"plus\", attrs: { transform: [\"translate(66 22)\", \"translate(66 4)\"], opacity: [1, 0] }, delay: 450, ms: 650, ease: \"out\" },\n snap(\"plus\", \"opacity\", 0, 0),\n ],\n },\n};\n\n// ── Space invader ──────────────────────────────────────────────────────\n\nconst INVADER_A = [\"..#.....#..\", \"...#...#...\", \"..#######..\", \".##.###.##.\", \"###########\", \"#.#######.#\", \"#.#.....#.#\", \"...##.##...\"];\nconst INVADER_B = [\"..#.....#..\", \"#..#...#..#\", \"#.#######.#\", \"###.###.###\", \"###########\", \".#########.\", \"..#.....#..\", \".#.......#.\"];\nconst BOLT_A = [\".#\", \"#.\", \".#\", \"#.\"];\nconst BOLT_B = [\"#.\", \".#\", \"#.\", \".#\"];\nconst CANNON = [\"....#....\", \"...###...\", \".#######.\", \"#########\"];\nconst MARCH_MS = 320;\n/** The invader's positions: right in steps, down, left, down. */\nconst MARCH: [number, number][] = [\n ...[0, 1, 2, 3, 4, 5, 6].map((k): [number, number] => [24 + k * 16, 12]),\n ...[6, 5, 4, 3, 2, 1, 0].map((k): [number, number] => [24 + k * 16, 26]),\n [24, 40],\n];\n/** Shots fired: at which march step. */\nconst SHOTS = [3, 10];\n\nexport const spaceInvader: VectorEffect = {\n kind: \"vector\",\n id: \"space-invader\",\n name: \"Space invader\",\n description: \"The classic two-frame pixel invader marching across and down a step, dropping a blinking zigzag laser shot.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"arcade\", \"game\", \"sprite\", \"alien\", \"8-bit\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Green\", values: { invader: [0.3, 1, 0.35], shot: [1, 1, 1], ground: [0.3, 1, 0.35] } },\n { name: \"Overlay\", values: { invader: [1, 0.3, 0.6], shot: [1, 0.9, 0.2], ground: [0.2, 0.85, 1], background: [0.06, 0.02, 0.12] } },\n ],\n motion: (() => {\n const pose = ([x, y]: [number, number]) => `translate(${x} ${y})`;\n const frameA = bitmapPath(INVADER_A, \"#\", 4);\n const frameB = bitmapPath(INVADER_B, \"#\", 4);\n const boltA = bitmapPath(BOLT_A, \"#\", 2);\n const boltB = bitmapPath(BOLT_B, \"#\", 2);\n const animate: SvgAnimation[] = [snap(\"bolt\", \"opacity\", 0, 0)];\n MARCH.forEach((at, k) => {\n animate.push(snap(\"invader\", \"transform\", pose(at), k * MARCH_MS));\n animate.push(snap(\"body\", \"d\", k % 2 ? frameB : frameA, k * MARCH_MS));\n });\n SHOTS.forEach((k) => {\n const [x, y] = MARCH[k]!;\n const start = k * MARCH_MS + 60;\n const from = `translate(${x + 20} ${y + 34})`;\n animate.push(snap(\"bolt\", \"opacity\", 1, start));\n animate.push({ id: \"bolt\", attrs: { transform: [from, `translate(${x + 20} 118)`] }, delay: start, ms: 900, ease: \"linear\" });\n for (let f = 0; f < 9; f++) animate.push(snap(\"zig\", \"d\", f % 2 ? boltB : boltA, start + f * 100));\n animate.push(snap(\"bolt\", \"opacity\", 0, start + 900));\n });\n return {\n svg: `<svg viewBox=\"0 0 200 140\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#000000 label='Background'}} {{invader: color default=#FFFFFF label='Invader'}} {{shot: color default=#FF4D4D label='Laser'}} {{ground: color default=#3FD15C label='Ground'}} --><rect width=\"200\" height=\"140\" fill=\"{{background}}\"/><g id=\"invader\" transform=\"${pose(MARCH[0]!)}\"><path id=\"body\" fill=\"{{invader}}\" d=\"${frameA}\"/></g><g id=\"bolt\" transform=\"translate(0 0)\" opacity=\"0\"><path id=\"zig\" fill=\"{{shot}}\" d=\"${boltA}\"/></g><g fill=\"{{ground}}\"><path d=\"${bitmapPath(CANNON, \"#\", 3, 128, 114)}\"/><rect x=\"0\" y=\"128\" width=\"200\" height=\"2\"/></g></svg>`,\n animate,\n };\n })(),\n};\n\n// ── Pixel heart health ─────────────────────────────────────────────────\n\nconst HEART_INSIDE = [\".##.##.\", \"#######\", \"#######\", \"#######\", \".#####.\", \"..###..\", \"...#...\"];\n/** The heart on a 9 × 9 grid: `o` outline round the inside, `r` fill, `w` a highlight. */\nconst HEART = (() => {\n const grid = Array.from({ length: 9 }, () => Array<string>(9).fill(\".\"));\n HEART_INSIDE.forEach((row, j) => [...row].forEach((c, i) => c === \"#\" && (grid[j + 1]![i + 1] = \"r\")));\n const inside = (i: number, j: number) => grid[j]?.[i] === \"r\";\n for (let j = 0; j < 9; j++)\n for (let i = 0; i < 9; i++)\n if (!inside(i, j) && [[-1, 0], [1, 0], [0, -1], [0, 1]].some(([a, b]) => inside(i + a!, j + b!))) grid[j]![i] = \"o\";\n grid[2]![2] = \"w\";\n grid[3]![2] = \"w\";\n return grid.map((row) => row.join(\"\"));\n})();\nconst HEARTS = 5;\nconst HEART_UNIT = 4;\nconst heartPose = (i: number, s: number) => `translate(${30 + i * 45} 32) scale(${s}) translate(-18 -18)`;\n/** When hearts are lost (flash then empty) and refilled, in ms. */\nconst LOSSES: [number, number][] = [[4, 500], [3, 1500]];\nconst REFILLS: [number, number][] = [[3, 2700], [4, 3000]];\n\nexport const pixelHeartHealth: VectorEffect = {\n kind: \"vector\",\n id: \"pixel-heart-health\",\n name: \"Heart health bar\",\n description: \"A row of pixel hearts as a game health bar: two hearts flash and empty as damage lands, then pop back full.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"game\", \"health\", \"hud\", \"hearts\", \"8-bit\", \"loop\"],\n hold: 900,\n presets: [\n { name: \"Shield\", values: { heart: [0.2, 0.6, 1], highlight: [0.8, 0.95, 1] } },\n { name: \"Light\", values: { background: [0.96, 0.95, 0.9], empty: [0.82, 0.8, 0.76], outline: [0.15, 0.12, 0.12] } },\n ],\n motion: (() => {\n const animate: SvgAnimation[] = [];\n for (let i = 0; i < HEARTS; i++) {\n animate.push(snap(`f${i}`, \"opacity\", 1, 0), snap(`x${i}`, \"opacity\", 0, 0));\n }\n for (const [i, at] of LOSSES) {\n // Flash white and flicker, then empty, with a shake.\n [0, 1, 0, 1, 0].forEach((on, k) => {\n animate.push(snap(`x${i}`, \"opacity\", on ? 0 : 1, at + k * 90));\n animate.push(snap(`f${i}`, \"opacity\", on, at + k * 90));\n });\n animate.push(snap(`x${i}`, \"opacity\", 0, at + 450));\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 1), heartPose(i, 0.82)] }, delay: at, ms: 90, ease: \"out\" });\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 0.82), heartPose(i, 1)] }, delay: at + 90, ms: 220, ease: \"in-out\" });\n }\n for (const [i, at] of REFILLS) {\n animate.push(snap(`f${i}`, \"opacity\", 1, at));\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 1), heartPose(i, 1.3)] }, delay: at, ms: 120, ease: \"out\" });\n animate.push({ id: `h${i}`, attrs: { transform: [heartPose(i, 1.3), heartPose(i, 1)] }, delay: at + 120, ms: 200, ease: \"in-out\" });\n }\n const hearts = Array.from(\n { length: HEARTS },\n (_, i) =>\n `<g id=\"h${i}\" transform=\"${heartPose(i, 1)}\">${sprite(HEART, { o: \"{{outline}}\", r: \"{{empty}}\", w: \"{{empty}}\" }, HEART_UNIT)}<g id=\"f${i}\">${sprite(HEART, { r: \"{{heart}}\", w: \"{{highlight}}\" }, HEART_UNIT)}</g><path id=\"x${i}\" opacity=\"0\" fill=\"{{flash}}\" d=\"${bitmapPath(HEART.map((row) => row.replace(/w/g, \"r\")), \"r\", HEART_UNIT)}\"/></g>`,\n ).join(\"\");\n return {\n svg: `<svg viewBox=\"0 0 240 64\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#14141F label='Background'}} {{heart: color default=#E83B3B label='Heart'}} {{highlight: color default=#FFB3B3 label='Highlight'}} {{empty: color default=#3A2E3E label='Empty'}} {{outline: color default=#000000 label='Outline'}} {{flash: color default=#FFFFFF label='Hit flash'}} --><rect width=\"240\" height=\"64\" fill=\"{{background}}\"/>${hearts}</svg>`,\n animate,\n };\n })(),\n};\n\n// ── Chomp loader ───────────────────────────────────────────────────────\n\n/** A 13 × 13 pixel mouth facing right, open by `angle` degrees each side of its axis. */\nfunction chomper(angle: number): string[] {\n return Array.from({ length: 13 }, (_, j) =>\n Array.from({ length: 13 }, (_, i) => {\n const [x, y] = [i - 6, j - 6];\n if (x * x + y * y > 6.6 * 6.6) return \".\";\n const a = (Math.atan2(-y, x) * 180) / Math.PI;\n return angle > 0 && x >= 0 && Math.abs(a) <= angle ? \".\" : \"#\";\n }).join(\"\"),\n );\n}\nconst CHOMP_UNIT = 3;\nconst CHOMP_FRAMES = [0, 25, 45, 25].map((a) => bitmapPath(chomper(a), \"#\", CHOMP_UNIT, -19.5, -19.5));\nconst CHOMP_MS = 2800;\nconst CHOMP_FROM = -30;\nconst CHOMP_TO = 270;\nconst DOTS = [50, 80, 110, 140, 170, 200];\n\nexport const chompLoader: VectorEffect = {\n kind: \"vector\",\n id: \"chomp-loader\",\n name: \"Chomp loader\",\n description: \"A chomping pixel mouth munching along a row of dots between maze walls, as a looping loader.\",\n category: \"retro\",\n tags: [\"pixel\", \"retro\", \"loader\", \"arcade\", \"game\", \"8-bit\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Ghostly\", values: { mouth: [0.4, 0.9, 1], dots: [1, 1, 1], walls: [0.9, 0.2, 0.6] } },\n { name: \"Light\", values: { background: [1, 1, 1], mouth: [0.95, 0.65, 0], dots: [0.4, 0.4, 0.45], walls: [0.15, 0.3, 0.9] } },\n ],\n motion: (() => {\n const travel = CHOMP_TO - CHOMP_FROM;\n const animate: SvgAnimation[] = [\n { id: \"chomp\", attrs: { transform: [`translate(${CHOMP_FROM} 40)`, `translate(${CHOMP_TO} 40)`] }, ms: CHOMP_MS, ease: \"linear\" },\n ];\n for (let f = 0; f * 80 < CHOMP_MS; f++) animate.push(snap(\"mouth\", \"d\", CHOMP_FRAMES[f % CHOMP_FRAMES.length]!, f * 80));\n DOTS.forEach((x, k) => {\n animate.push(snap(`dot${k}`, \"opacity\", 1, 0));\n // Eaten as the mouth's centre reaches it.\n animate.push(snap(`dot${k}`, \"opacity\", 0, Math.round(((x - CHOMP_FROM) / travel) * CHOMP_MS)));\n });\n return {\n svg: `<svg viewBox=\"0 0 240 80\" shape-rendering=\"crispEdges\"><!-- {{background: color default=#000000 label='Background'}} {{mouth: color default=#FFE600 label='Chomper'}} {{dots: color default=#FFB897 label='Dots'}} {{walls: color default=#2E3BFF label='Walls'}} --><rect width=\"240\" height=\"80\" fill=\"{{background}}\"/><g fill=\"none\" stroke=\"{{walls}}\" stroke-width=\"3\"><path d=\"M0 10.5 H240 M0 69.5 H240\"/></g>${DOTS.map((x, k) => `<rect id=\"dot${k}\" x=\"${x - 3}\" y=\"37\" width=\"6\" height=\"6\" fill=\"{{dots}}\"/>`).join(\"\")}<g id=\"chomp\" transform=\"translate(${CHOMP_FROM} 40)\"><path id=\"mouth\" fill=\"{{mouth}}\" d=\"${CHOMP_FRAMES[0]}\"/></g></svg>`,\n animate,\n };\n })(),\n};\n\n/** Pixel-art vector effects: sprites, pixel type and 8-bit UI. */\nexport const pixelEffects: VectorEffect[] = [pixelText, coinSpin, spaceInvader, pixelHeartHealth, chompLoader];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst round = (n: number) => Math.round(n * 10) / 10;\n\nexport const fireworkBurst: VectorEffect = {\n kind: \"vector\",\n id: \"firework-burst\",\n name: \"Firework burst\",\n description: \"A small firework for success moments: a flash, a ring of streaks and a staggered ring of dots bursting outwards and fading.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"celebration\", \"success\", \"reward\", \"ui\", \"fireworks\"],\n hold: 400,\n motion: (() => {\n // Ring one: streaks flying out; ring two: dots, half a step round and a beat later.\n const streaks = Array.from({ length: 12 }, (_, i) => {\n const a = (i / 12) * Math.PI * 2 - Math.PI / 2;\n const [c, s] = [Math.cos(a), Math.sin(a)];\n return { id: `l${i}`, c, s, stroke: [\"{{a}}\", \"{{b}}\", \"{{c}}\"][i % 3]! };\n });\n const dots = Array.from({ length: 10 }, (_, i) => {\n const a = ((i + 0.5) / 10) * Math.PI * 2 - Math.PI / 2;\n return { id: `d${i}`, c: Math.cos(a), s: Math.sin(a), fill: [\"{{b}}\", \"{{c}}\", \"{{a}}\"][i % 3]! };\n });\n const at = (c: number, s: number, r: number) => [round(c * r), round(s * r)] as const;\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{a: color default=#F43F5E label='Colour A'}} {{b: color default=#FACC15 label='Colour B'}} {{c: color default=#38BDF8 label='Colour C'}} {{width: float min=1 max=8 default=4 step=0.5 label='Line width'}} --><g transform=\"translate(100 100) scale({{size: float min=0.5 max=1.4 default=1 step=0.05 label='Size'}})\"><circle id=\"flash\" cx=\"0\" cy=\"0\" r=\"0\" fill=\"{{b}}\" opacity=\"0\"/>${streaks\n .map(({ id, c, s, stroke }) => {\n const [x, y] = at(c, s, 12);\n return `<line id=\"${id}\" x1=\"${x}\" y1=\"${y}\" x2=\"${x}\" y2=\"${y}\" stroke=\"${stroke}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" opacity=\"0\"/>`;\n })\n .join(\"\")}${dots.map(({ id, c, s, fill }) => `<circle id=\"${id}\" cx=\"${round(c * 14)}\" cy=\"${round(s * 14)}\" r=\"5\" fill=\"${fill}\" opacity=\"0\"/>`).join(\"\")}</g></svg>`,\n animate: [\n { id: \"flash\", attrs: { r: [0, 22], opacity: [0.9, 0] }, ms: 380, ease: \"out\" },\n ...streaks.flatMap(({ id, c, s }): SvgAnimation[] => {\n const [x0, y0] = at(c, s, 12);\n const [x1, y1] = at(c, s, 40);\n const [x2, y2] = at(c, s, 62);\n const [x3, y3] = at(c, s, 74);\n return [\n { id, attrs: { opacity: [0, 1] }, ms: 40 },\n { id, attrs: { x1: [x0, x1], y1: [y0, y1], x2: [x0, x2], y2: [y0, y2] }, ms: 420, ease: \"out\" },\n { id, attrs: { x1: [x1, x3], y1: [y1, y3], x2: [x2, x3], y2: [y2, y3], opacity: [1, 0] }, delay: 420, ms: 380, ease: \"in-out\" },\n ];\n }),\n ...dots.flatMap(({ id, c, s }): SvgAnimation[] => [\n { id, attrs: { opacity: [0, 1] }, delay: 150, ms: 40 },\n { id, attrs: { cx: [round(c * 14), round(c * 66)], cy: [round(s * 14), round(s * 66)] }, delay: 150, ms: 520, ease: \"out\" },\n { id, attrs: { cy: [round(s * 66), round(s * 66 + 10)], r: [5, 1], opacity: [1, 0] }, delay: 670, ms: 450, ease: \"in-out\" },\n ]),\n ],\n };\n })(),\n presets: [\n { name: \"Gold\", values: { a: [1, 0.78, 0.3], b: [1, 0.93, 0.6], c: [0.98, 0.6, 0.2] } },\n { name: \"Brand\", values: { a: [0.39, 0.4, 0.95], b: [0.93, 0.28, 0.6], c: [0.13, 0.83, 0.93] } },\n { name: \"Big\", values: { size: 1.4, width: 6 } },\n ],\n};\n\n/** Pyrotechnics: fireworks, sparks, explosions and smoke, as vector effects. */\nexport const pyroEffects: VectorEffect[] = [fireworkBurst];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst r1 = (n: number) => Math.round(n * 10) / 10;\n\n/** A point `radius` from the clock's centre (100, 100), `degrees` clockwise from 12. */\nconst at = (degrees: number, radius: number) => {\n const a = (degrees * Math.PI) / 180;\n return [r1(100 + radius * Math.sin(a)), r1(100 - radius * Math.cos(a))] as const;\n};\n\n/** A pie slice of the dial from `from` to `to` degrees clockwise from 12. */\nconst slice = (from: number, to: number, radius: number) => {\n const [x0, y0] = at(from, radius);\n const [x1, y1] = at(to, radius);\n return `M100 100 L${x0} ${y0} A${radius} ${radius} 0 0 1 ${x1} ${y1}Z`;\n};\n\n/** One clock cycle: day, dusk, night, dawn, 2 s each. */\nconst CYCLE = 8000;\nconst PHASE = CYCLE / 4;\n/** How long the sky takes to change at the end of each phase. */\nconst FADE = 1400;\n\nconst TICKS = Array.from({ length: 12 }, (_, i) => {\n const [x0, y0] = at(i * 30, i % 3 ? 80 : 74);\n const [x1, y1] = at(i * 30, 86);\n return `<line x1=\"${x0}\" y1=\"${y0}\" x2=\"${x1}\" y2=\"${y1}\" stroke=\"{{hands}}\" stroke-width=\"${i % 3 ? 2 : 4}\" stroke-linecap=\"round\" opacity=\"0.8\"/>`;\n}).join(\"\");\n\nconst STARS = [\n [62, 50, 1.6], [128, 44, 1.2], [150, 78, 1.8], [44, 92, 1.2], [70, 140, 1.4], [138, 132, 1.2], [104, 160, 1.6], [92, 34, 1], [160, 110, 1], [36, 124, 1.4],\n]\n .map(([x, y, r]) => `<circle cx=\"${x}\" cy=\"${y}\" r=\"${r}\" fill=\"#FFFFFF\"/>`)\n .join(\"\");\n\n// Fading wedges behind the minute hand: older (further back) is fainter.\nconst TRAIL = [0.07, 0.13, 0.22]\n .map((opacity, i) => `<path d=\"${slice(-36 + i * 12, -24 + i * 12, 72)}\" fill=\"{{trail}}\" opacity=\"${opacity}\"/>`)\n .join(\"\");\n\n/** The sky's colour from one phase to the next, at the end of each phase. */\nconst SKY: readonly (readonly [string, string])[] = [\n [\"{{day}}\", \"{{dusk}}\"],\n [\"{{dusk}}\", \"{{night}}\"],\n [\"{{night}}\", \"{{dawn}}\"],\n [\"{{dawn}}\", \"{{day}}\"],\n];\n\nexport const timeLapseClock: VectorEffect = {\n kind: \"vector\",\n id: \"time-lapse-clock\",\n name: \"Time-lapse clock\",\n description: \"A clock whose hands race round while the sky behind turns from day to dusk, night and dawn.\",\n category: \"timewarp\",\n tags: [\"time\", \"clock\", \"time-lapse\", \"day\", \"night\", \"loader\"],\n hold: 0,\n presets: [\n { name: \"Pastel\", values: { day: [0.75, 0.9, 1], dusk: [1, 0.72, 0.6], night: [0.36, 0.33, 0.6], dawn: [1, 0.85, 0.9] } },\n { name: \"Mono\", values: { day: [0.9, 0.9, 0.9], dusk: [0.55, 0.55, 0.55], night: [0.1, 0.1, 0.1], dawn: [0.7, 0.7, 0.7], sun: [1, 1, 1], trail: [1, 1, 1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{day: color default=#7DD3FC label='Day'}} {{dusk: color default=#F97316 label='Dusk'}} {{night: color default=#0F172A label='Night'}} {{dawn: color default=#F9A8D4 label='Dawn'}} {{sun: color default=#FDE68A label='Sun'}} {{hands: color default=#FFFFFF label='Hands'}} {{trail: color default=#FDE68A label='Trail'}} --><circle id=\"sky\" cx=\"100\" cy=\"100\" r=\"92\" fill=\"{{day}}\"/><g id=\"stars\" opacity=\"0\">${STARS}</g><g id=\"orbit\" transform=\"rotate(0 100 100)\"><circle id=\"sun\" cx=\"100\" cy=\"38\" r=\"11\" fill=\"{{sun}}\"/></g>${TICKS}<circle cx=\"100\" cy=\"100\" r=\"92\" fill=\"none\" stroke=\"{{hands}}\" stroke-width=\"4\" opacity=\"0.9\"/><g id=\"hour\" transform=\"rotate(0 100 100)\"><line x1=\"100\" y1=\"106\" x2=\"100\" y2=\"56\" stroke=\"#000000\" stroke-opacity=\"0.25\" stroke-width=\"9\" stroke-linecap=\"round\"/><line x1=\"100\" y1=\"106\" x2=\"100\" y2=\"56\" stroke=\"{{hands}}\" stroke-width=\"6\" stroke-linecap=\"round\"/></g><g id=\"minute\" transform=\"rotate(0 100 100)\">${TRAIL}<line x1=\"100\" y1=\"110\" x2=\"100\" y2=\"28\" stroke=\"#000000\" stroke-opacity=\"0.25\" stroke-width=\"6\" stroke-linecap=\"round\"/><line x1=\"100\" y1=\"110\" x2=\"100\" y2=\"28\" stroke=\"{{hands}}\" stroke-width=\"3.5\" stroke-linecap=\"round\"/></g><circle cx=\"100\" cy=\"100\" r=\"5\" fill=\"{{hands}}\"/></svg>`,\n animate: [\n // Twelve turns of the minute hand to one of the hour hand, and the sun once round the sky.\n { id: \"minute\", attrs: { transform: [\"rotate(0 100 100)\", \"rotate(4320 100 100)\"] }, ms: CYCLE, ease: \"linear\" },\n { id: \"hour\", attrs: { transform: [\"rotate(0 100 100)\", \"rotate(360 100 100)\"] }, ms: CYCLE, ease: \"linear\" },\n { id: \"orbit\", attrs: { transform: [\"rotate(0 100 100)\", \"rotate(360 100 100)\"] }, ms: CYCLE, ease: \"linear\" },\n ...SKY.map(([from, to], i): SvgAnimation => ({ id: \"sky\", attrs: { fill: [from, to] }, delay: (i + 1) * PHASE - FADE, ms: FADE, ease: \"in-out\" })),\n // Stars come out at night; the sun fades while it is below the horizon.\n { id: \"stars\", attrs: { opacity: [0, 1] }, delay: 2 * PHASE - FADE, ms: FADE, ease: \"in-out\" },\n { id: \"stars\", attrs: { opacity: [1, 0] }, delay: 3 * PHASE - FADE, ms: FADE, ease: \"in-out\" },\n { id: \"sun\", attrs: { opacity: [1, 0.25] }, delay: PHASE, ms: PHASE, ease: \"in-out\" },\n { id: \"sun\", attrs: { opacity: [0.25, 1] }, delay: 3 * PHASE - FADE, ms: FADE, ease: \"in-out\" },\n ],\n },\n};\n\n/** Time warps: echoes, rewinds, freezes and tunnels, as vector effects. */\nexport const timewarpEffects: VectorEffect[] = [timeLapseClock];\n","import { morphPaths, morphSequence } from \"../vector/morph.js\";\nimport type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Morph effects blend shapes point by point: `morphPaths` and\n * `morphSequence` give paths one structure, so `attrs: { d: [a, b] }`\n * blends them. Shapes are drawn with `fill-rule=\"evenodd\"`, since a piece's\n * direction can change, and pieces with no partner grow from or shrink to a\n * point.\n */\n\ntype Point = [number, number];\n\nconst NUMBER = /-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\nconst DEG = Math.PI / 180;\n\nconst r2 = (v: number) => {\n const r = Math.round(v * 100) / 100;\n return Object.is(r, -0) ? 0 : r;\n};\n\n/** A derived number in an animation's numeric field (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/** A path's numbers in pairs, in order (for paths of absolute M, L and C, like morph output). */\nconst pointsOf = (d: string): Point[] => {\n const nums = (d.match(NUMBER) ?? []).map(Number);\n return Array.from({ length: nums.length >> 1 }, (_, i) => [nums[2 * i]!, nums[2 * i + 1]!]);\n};\n\n/** A path (absolute M, L and C only) with every point moved by `f`. */\nfunction mapPath(d: string, f: (p: Point) => Point): string {\n const moved = pointsOf(d).map(f);\n let i = 0;\n return d.replace(NUMBER, () => {\n const k = i++;\n return String(r2(moved[k >> 1]![k % 2]!));\n });\n}\n\nconst polyline = (pts: readonly Point[], close = false) =>\n `M${pts.map((p) => `${r2(p[0])} ${r2(p[1])}`).join(\" L\")}${close ? \" Z\" : \"\"}`;\n\n/** Points round an ellipse between two angles in degrees (0 is right, 90 down), both ends included. */\nfunction arc(cx: number, cy: number, rx: number, ry: number, from: number, to: number, every = 8): Point[] {\n const steps = Math.max(1, Math.ceil(Math.abs(to - from) / every));\n return Array.from({ length: steps + 1 }, (_, k) => {\n const a = (from + ((to - from) * k) / steps) * DEG;\n return [cx + rx * Math.cos(a), cy + ry * Math.sin(a)];\n });\n}\n\nconst circle = (cx: number, cy: number, r: number) => polyline(arc(cx, cy, r, r, 0, 360).slice(0, -1), true);\n\n/** A regular star (or polygon, with `inner` equal to `outer`) of `tips` points, the first straight up. */\nconst star = (cx: number, cy: number, tips: number, outer: number, inner: number) =>\n polyline(\n Array.from({ length: tips * 2 }, (_, k): Point => {\n const r = k % 2 ? inner : outer;\n const a = (-90 + (k * 180) / tips) * DEG;\n return [cx + r * Math.cos(a), cy + r * Math.sin(a)];\n }),\n true,\n );\n\n/**\n * A stroke along `pts` written as a filled outline `width` wide, so it morphs\n * as a shape: mitred corners, and round ends unless `flat` names an end.\n */\nfunction stroke(pts: readonly Point[], width: number, flat: { start?: boolean; end?: boolean } = {}): string {\n const h = width / 2;\n const normals = pts.slice(1).map((p, i): Point => {\n const q = pts[i]!;\n const l = Math.hypot(p[0] - q[0], p[1] - q[1]);\n return [-(p[1] - q[1]) / l, (p[0] - q[0]) / l];\n });\n // Each corner's offset: along the two sides' mean normal, long enough to keep the width (a mitre).\n const offsets = pts.map((_, i): Point => {\n const a = normals[Math.max(0, i - 1)]!;\n const b = normals[Math.min(normals.length - 1, i)]!;\n const l = Math.hypot(a[0] + b[0], a[1] + b[1]);\n const m: Point = [(a[0] + b[0]) / l, (a[1] + b[1]) / l];\n const k = h / (m[0] * b[0] + m[1] * b[1]);\n return [m[0] * k, m[1] * k];\n });\n const left = pts.map((p, i): Point => [p[0] + offsets[i]![0], p[1] + offsets[i]![1]]);\n const right = pts.map((p, i): Point => [p[0] - offsets[i]![0], p[1] - offsets[i]![1]]).reverse();\n const angle = (v: Point) => Math.atan2(v[1], v[0]) / DEG;\n const [first, last] = [pts[0]!, pts[pts.length - 1]!];\n const endAt = angle(normals[normals.length - 1]!);\n const startAt = angle(normals[0]!) + 180;\n const endCap = flat.end ? [] : arc(last[0], last[1], h, h, endAt, endAt - 180, 15).slice(1, -1);\n const startCap = flat.start ? [] : arc(first[0], first[1], h, h, startAt, startAt - 180, 15).slice(1, -1);\n return polyline([...left, ...endCap, ...right, ...startCap], true);\n}\n\n/** Points round a circle from one angle to another, going the way that misses `avoid`. */\nfunction around(c: Point, r: number, from: number, to: number, avoid: number): Point[] {\n let delta = (((to - from) % 360) + 360) % 360;\n if ((((avoid - from) % 360) + 360) % 360 < delta) delta -= 360;\n return arc(c[0], c[1], r, r, from, from + delta);\n}\n\n/** The part of one circle outside another: a crescent moon. */\nfunction crescent(c1: Point, r1: number, c2: Point, r2_: number): string {\n const [dx, dy] = [c2[0] - c1[0], c2[1] - c1[1]];\n const d = Math.hypot(dx, dy);\n const a = (r1 * r1 - r2_ * r2_ + d * d) / (2 * d);\n const h = Math.sqrt(Math.max(0, r1 * r1 - a * a));\n const [px, py] = [c1[0] + (a * dx) / d, c1[1] + (a * dy) / d];\n const i1: Point = [px - (h * dy) / d, py + (h * dx) / d];\n const i2: Point = [px + (h * dy) / d, py - (h * dx) / d];\n const angle = (c: Point, p: Point) => Math.atan2(p[1] - c[1], p[0] - c[0]) / DEG;\n // The long way round the moon (away from the cut), then back round the cut, inside the moon.\n const outer = around(c1, r1, angle(c1, i1), angle(c1, i2), angle(c1, c2));\n const inner = around(c2, r2_, angle(c2, i2), angle(c2, i1), angle(c2, c1) + 180);\n return polyline([...outer, ...inner.slice(1, -1)], true);\n}\n\n/** A heart in a 24 box, curves and all. */\nconst HEART = \"M12 20.5 C12 20.5 3 14.8 3 8.8 C3 6 5.2 3.8 8 3.8 C9.7 3.8 11.2 4.7 12 6.1 C12.8 4.7 14.3 3.8 16 3.8 C18.8 3.8 21 6 21 8.8 C21 14.8 12 20.5 12 20.5 Z\";\n\n/** A path scaled by `s` about (12, 12) and moved to (`cx`, `cy`). */\nconst placed = (d: string, cx: number, cy: number, s: number) => mapPath(d, (p) => [cx + (p[0] - 12) * s, cy + (p[1] - 12) * s]);\n\n/**\n * Any path as one closed outline per piece (see `morphSequence`), scaled\n * and centred to fill `box` ([x, y, width, height]), so paths drawn in any\n * coordinates land in the picture. Throws a sentence on a path it cannot read.\n */\nfunction fitted(d: string, box: readonly [number, number, number, number], points: number): string {\n const outline = morphSequence([d], { points })[0]!;\n const pts = pointsOf(outline);\n const xs = pts.map((p) => p[0]);\n const ys = pts.map((p) => p[1]);\n const [x0, y0] = [Math.min(...xs), Math.min(...ys)];\n const [w, h] = [Math.max(...xs) - x0, Math.max(...ys) - y0];\n const s = Math.min(box[2] / Math.max(w, 1e-6), box[3] / Math.max(h, 1e-6));\n const [ox, oy] = [box[0] + (box[2] - w * s) / 2, box[1] + (box[3] - h * s) / 2];\n return mapPath(outline, (p) => [ox + (p[0] - x0) * s, oy + (p[1] - y0) * s]);\n}\n\n/** A user's path fitted to `box`, or `fallback` fitted when it cannot be read, so the effect still draws. */\nfunction fittedOr(d: unknown, fallback: string, box: readonly [number, number, number, number], points: number): string {\n try {\n return fitted(String(d), box, points);\n } catch {\n return fitted(fallback, box, points);\n }\n}\n\n// ── Shape morph ────────────────────────────────────────────────────────\n\nconst SHAPE_FROM = \"M30 12 H70 A18 18 0 0 1 88 30 V70 A18 18 0 0 1 70 88 H30 A18 18 0 0 1 12 70 V30 A18 18 0 0 1 30 12 Z\";\nconst SHAPE_TO = \"M50 6 L61 38 L95 38 L67 58 L78 92 L50 72 L22 92 L33 58 L5 38 L39 38 Z\";\n\nexport const shapeMorph: VectorEffect = {\n kind: \"vector\",\n id: \"shape-morph\",\n name: \"Shape morph\",\n description: \"Any two SVG paths morphing into each other and back, their fill and outline colours blending along.\",\n category: \"morph\",\n tags: [\"morph\", \"shape\", \"path\", \"icon\", \"logo\"],\n hold: 0,\n presets: [\n { name: \"Ink\", values: { background: [0.98, 0.97, 0.94], fillFrom: [0.1, 0.1, 0.12], fillTo: [0.1, 0.1, 0.12], strokeFrom: [0.1, 0.1, 0.12], strokeTo: [0.1, 0.1, 0.12], width: 0 } },\n {\n name: \"Heart to drop\",\n values: {\n from: \"M12 20.5 C12 20.5 3 14.8 3 8.8 C3 6 5.2 3.8 8 3.8 C9.7 3.8 11.2 4.7 12 6.1 C12.8 4.7 14.3 3.8 16 3.8 C18.8 3.8 21 6 21 8.8 C21 14.8 12 20.5 12 20.5 Z\",\n to: \"M12 2 C12 2 5 10 5 15 A7 7 0 0 0 19 15 C19 10 12 2 12 2 Z\",\n fillFrom: [0.96, 0.25, 0.37],\n fillTo: [0.22, 0.6, 0.97],\n },\n },\n { name: \"Outline\", values: { fillFrom: [0.06, 0.09, 0.16], fillTo: [0.06, 0.09, 0.16], strokeFrom: [0.2, 0.83, 0.6], strokeTo: [0.98, 0.8, 0.08], width: 2.5 } },\n ],\n // Each path is fitted to the picture on its own, so paths in any coordinates fill it.\n derived: (v) => {\n const [a, b] = morphPaths(fittedOr(v.from, SHAPE_FROM, [12, 12, 76, 76], 96), fittedOr(v.to, SHAPE_TO, [12, 12, 76, 76], 96), { points: 80 });\n return { a, b, back: Number(v.pause) * 2 + Number(v.morph) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{from: text default='${SHAPE_FROM}' label='From path'}} {{to: text default='${SHAPE_TO}' label='To path'}} {{fillFrom: color default=#6366F1 label='Fill (from)'}} {{fillTo: color default=#F59E0B label='Fill (to)'}} {{strokeFrom: color default=#C7D2FE label='Outline (from)'}} {{strokeTo: color default=#FEF3C7 label='Outline (to)'}} {{background: color default=#0F172A label='Background'}} {{width: float min=0 max=6 default=1.5 step=0.25 label='Outline width'}} {{morph: float min=200 max=3000 default=1000 step=50 label='Morph ms'}} {{pause: float min=0 max=3000 default=700 step=50 label='Pause ms'}} --><rect width=\"100\" height=\"100\" fill=\"{{background}}\"/><path id=\"shape\" d=\"{{a}}\" fill=\"{{fillFrom}}\" fill-rule=\"evenodd\" stroke=\"{{strokeFrom}}\" stroke-width=\"{{width}}\" stroke-linejoin=\"round\"/></svg>`,\n animate: [\n { id: \"shape\", attrs: { d: [\"{{a}}\", \"{{b}}\"], fill: [\"{{fillFrom}}\", \"{{fillTo}}\"], stroke: [\"{{strokeFrom}}\", \"{{strokeTo}}\"] }, delay: n(\"pause\"), ms: n(\"morph\"), ease: \"in-out\" },\n { id: \"shape\", attrs: { d: [\"{{b}}\", \"{{a}}\"], fill: [\"{{fillTo}}\", \"{{fillFrom}}\"], stroke: [\"{{strokeTo}}\", \"{{strokeFrom}}\"] }, delay: n(\"back\"), ms: n(\"morph\"), ease: \"in-out\" },\n ],\n },\n};\n\n// ── Icon toggle ────────────────────────────────────────────────────────\n\n/** Stroke width of the line icons, in their 24 box. */\nconst LINE = 2.4;\n\n/**\n * Icon pairs in a 24 box, every stroke written as a filled outline so it\n * morphs as a shape. Pieces are laid out to pair up: play's two halves\n * become pause's bars, menu's bars the three strokes of the close cross\n * (which is cut so its strokes do not overlap), the sun's rays shrink away.\n */\nconst ICON_PAIRS: readonly (readonly [string, string])[] = (() => {\n const c = 12;\n // The close cross: one whole diagonal, and the other cut in two where it meets it.\n const meet = LINE / 2 / Math.SQRT2;\n const sun = [circle(c, c, 4.6), ...Array.from({ length: 8 }, (_, k) => {\n const a = k * 45 * DEG;\n return stroke([[c + 7.6 * Math.cos(a), c + 7.6 * Math.sin(a)], [c + 10 * Math.cos(a), c + 10 * Math.sin(a)]], 2);\n })];\n return [\n [\n \"M7.5 4.5 L13.5 8.32 L13.5 15.68 L7.5 19.5 Z M13.5 8.32 L19.3 12 L13.5 15.68 Z\",\n [stroke([[8.5, 6.5], [8.5, 17.5]], 3.6), stroke([[15.5, 6.5], [15.5, 17.5]], 3.6)].join(\" \"),\n ],\n [\n [7, 12, 17].map((y) => stroke([[5, y], [19, y]], LINE)).join(\" \"),\n [\n stroke([[6.5, 6.5], [17.5, 17.5]], LINE),\n stroke([[17.5, 6.5], [c + meet, c - meet]], LINE, { end: true }),\n stroke([[6.5, 17.5], [c - meet, c + meet]], LINE, { end: true }),\n ].join(\" \"),\n ],\n [\"M10.7 5 H13.3 V10.7 H19 V13.3 H13.3 V19 H10.7 V13.3 H5 V10.7 H10.7 Z\", stroke([[5, 12.5], [10, 17.5], [19, 7]], 2.6)],\n [sun.join(\" \"), crescent([11.5, 12.5], 8.5, [16.5, 7.5], 7)],\n [`${HEART} ${placed(HEART, 12, 12, 0.7)}`, HEART],\n ];\n})();\n\nconst iconMorphs = new Map<number, [string, string]>();\n\n/** A pair's two icons morphed to one structure, worked out once. */\nfunction iconMorph(pair: number): [string, string] {\n if (!iconMorphs.has(pair)) iconMorphs.set(pair, morphPaths(...ICON_PAIRS[pair]!, { points: 64 }));\n return iconMorphs.get(pair)!;\n}\n\n/** The icon group's transform: centred in the button, turned and scaled. */\nconst pose = (turn: number, scale: number) => `translate(60 60) rotate(${turn}) scale(${scale}) translate(-12 -12)`;\n\n/** One toggle at `at` ms: the icon morphs while it dips, turns and pops back, and the button changes colour. */\nconst toggle = (at: number, d: [string, string], fill: [string, string], turn: number): SvgAnimation[] => [\n { id: \"glyph\", attrs: { d }, delay: at, ms: 420, ease: \"in-out\" },\n { id: \"icon\", attrs: { transform: [pose(0, 2.6), pose(turn, 2.15)] }, delay: at, ms: 170, ease: \"out\" },\n { id: \"icon\", attrs: { transform: [pose(turn, 2.15), pose(-turn * 0.3, 2.85)] }, delay: at + 170, ms: 190, ease: \"in-out\" },\n { id: \"icon\", attrs: { transform: [pose(-turn * 0.3, 2.85), pose(0, 2.6)] }, delay: at + 360, ms: 260, ease: \"in-out\" },\n { id: \"button\", attrs: { fill }, delay: at, ms: 320, ease: \"in-out\" },\n];\n\nexport const iconToggle: VectorEffect = {\n kind: \"vector\",\n id: \"icon-toggle\",\n name: \"Icon toggle\",\n description: \"A round button whose icon morphs between two states (play and pause, menu and close, sun and moon) with a little pop.\",\n category: \"morph\",\n tags: [\"morph\", \"icon\", \"ui\", \"button\", \"toggle\", \"micro-interaction\"],\n hold: 700,\n presets: [\n { name: \"Play / pause\", values: { pair: 0 } },\n { name: \"Menu / close\", values: { pair: 1, off: [0.98, 0.98, 0.98], on: [0.07, 0.07, 0.09], ink: [0.4, 0.4, 0.45], page: [0.9, 0.91, 0.93] } },\n { name: \"Plus / check\", values: { pair: 2, on: [0.13, 0.77, 0.37] } },\n { name: \"Day / night\", values: { pair: 3, off: [0.98, 0.75, 0.14], on: [0.19, 0.18, 0.5], page: [0.06, 0.07, 0.15] } },\n { name: \"Like\", values: { pair: 4, off: [0.12, 0.12, 0.14], on: [0.94, 0.27, 0.4] } },\n ],\n derived: (v) => {\n const [a, b] = iconMorph(Math.min(ICON_PAIRS.length - 1, Math.max(0, Math.round(Number(v.pair)) || 0)));\n return { a, b };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\"><!-- {{pair: int min=0 max=4 default=0 label='Icons (play, menu, plus, sun, heart)'}} {{ink: color default=#FFFFFF label='Icon'}} {{off: color default=#334155 label='Button'}} {{on: color default=#6366F1 label='Button (on)'}} {{page: color default=#0B1020 label='Background'}} --><rect width=\"120\" height=\"120\" fill=\"{{page}}\"/><circle id=\"button\" cx=\"60\" cy=\"60\" r=\"44\" fill=\"{{off}}\"/><g id=\"icon\" transform=\"${pose(0, 2.6)}\"><path id=\"glyph\" d=\"{{a}}\" fill=\"{{ink}}\" fill-rule=\"evenodd\" stroke=\"{{ink}}\" stroke-width=\"0.3\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [...toggle(500, [\"{{a}}\", \"{{b}}\"], [\"{{off}}\", \"{{on}}\"], -16), ...toggle(2100, [\"{{b}}\", \"{{a}}\"], [\"{{on}}\", \"{{off}}\"], 16)],\n },\n};\n\n// ── Morph sequence ─────────────────────────────────────────────────────\n\n/** Circle, star, heart and hexagon, in a 200 box. */\nconst SEQUENCE = morphSequence(\n [circle(100, 100, 72), star(100, 104, 5, 82, 36), placed(HEART, 100, 98, 8.4), star(100, 100, 3, 78, 78)],\n { points: 96 },\n);\n\nexport const morphSequenceEffect: VectorEffect = {\n kind: \"vector\",\n id: \"morph-sequence\",\n name: \"Morph sequence\",\n description: \"One shape flowing from circle to star to heart to hexagon and round again, its colour changing with each.\",\n category: \"morph\",\n tags: [\"morph\", \"shape\", \"loop\", \"background\", \"playful\"],\n hold: 0,\n presets: [\n { name: \"Pastel\", values: { background: [0.99, 0.97, 0.94], c0: [0.65, 0.84, 0.98], c1: [0.99, 0.85, 0.55], c2: [0.98, 0.65, 0.7], c3: [0.75, 0.7, 0.98] } },\n { name: \"Mono\", values: { background: [0.04, 0.04, 0.05], c0: [0.95, 0.95, 0.95], c1: [0.95, 0.95, 0.95], c2: [0.95, 0.95, 0.95], c3: [0.95, 0.95, 0.95], morph: 600, pause: 300 } },\n ],\n derived: (v) => {\n const each = Number(v.morph) + Number(v.pause);\n return Object.fromEntries(SEQUENCE.map((_, i) => [`at${i}`, Number(v.pause) + i * each]));\n },\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{c0: color default=#38BDF8 label='Circle'}} {{c1: color default=#FACC15 label='Star'}} {{c2: color default=#F43F5E label='Heart'}} {{c3: color default=#A78BFA label='Hexagon'}} {{background: color default=#0F172A label='Background'}} {{morph: float min=200 max=3000 default=900 step=50 label='Morph ms'}} {{pause: float min=0 max=3000 default=500 step=50 label='Pause ms'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><path id=\"shape\" d=\"${SEQUENCE[0]}\" fill=\"{{c0}}\" fill-rule=\"evenodd\"/></svg>`,\n animate: SEQUENCE.map((d, i): SvgAnimation => {\n const next = (i + 1) % SEQUENCE.length;\n return { id: \"shape\", attrs: { d: [d, SEQUENCE[next]!], fill: [`{{c${i}}}`, `{{c${next}}}`] }, delay: n(`at${i}`), ms: n(\"morph\"), ease: \"in-out\" };\n }),\n },\n};\n\n// ── Gooey morph ────────────────────────────────────────────────────────\n\n/**\n * A cluster of drops, a star whose arms reach where the drops were, and two\n * blobs, in a 200 box. Each piece is its own path (overlapping pieces in one\n * evenodd path would cut holes), and the goo filter melts them together.\n */\nconst GOO = (() => {\n const cluster = [\n circle(100, 100, 25),\n ...Array.from({ length: 5 }, (_, k) => circle(100 + 56 * Math.cos((-90 + 72 * k) * DEG), 100 + 56 * Math.sin((-90 + 72 * k) * DEG), 15)),\n ].join(\" \");\n const blobStar = polyline(\n arc(100, 100, 1, 1, -90, 270, 4).slice(0, -1).map((p): Point => {\n const a = Math.atan2(p[1] - 100, p[0] - 100);\n const r = 50 + 20 * Math.cos(5 * (a + Math.PI / 2));\n return [100 + r * Math.cos(a), 100 + r * Math.sin(a)];\n }),\n true,\n );\n const pair = `${circle(63, 100, 35)} ${circle(137, 100, 35)}`;\n // Each stage's pieces, one path each.\n const stages = morphSequence([cluster, blobStar, pair], { points: 64 }).map((d) => d.split(/ (?=M)/));\n return stages[0]!.map((_, piece) => stages.map((stage) => stage[piece]!));\n})();\n\nexport const gooeyMorph: VectorEffect = {\n kind: \"vector\",\n id: \"gooey-morph\",\n name: \"Gooey morph\",\n description: \"A cluster of liquid drops melting into a star, splitting into two blobs and beading back into drops.\",\n category: \"morph\",\n tags: [\"morph\", \"gooey\", \"liquid\", \"metaball\", \"blob\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Lava\", values: { colorA: [1, 0.85, 0.2], colorB: [0.95, 0.2, 0.1], background: [0.1, 0.02, 0.02] } },\n { name: \"Slime\", values: { colorA: [0.75, 1, 0.3], colorB: [0.1, 0.7, 0.35], background: [0.03, 0.08, 0.05], goo: 9 } },\n { name: \"Ink\", values: { colorA: [0.1, 0.1, 0.12], colorB: [0.1, 0.1, 0.12], background: [0.97, 0.96, 0.93] } },\n ],\n derived: (v) => {\n const each = Number(v.morph) + Number(v.pause);\n return { ...Object.fromEntries(GOO[0]!.map((_, i) => [`at${i}`, Number(v.pause) + i * each])), threshold: -0.5 * Number(v.sharp) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{colorA: color default=#22D3EE label='Colour A'}} {{colorB: color default=#A855F7 label='Colour B'}} {{background: color default=#0B0B1A label='Background'}} {{goo: float min=1 max=14 default=7 step=0.5 label='Gooeyness'}} {{sharp: float min=8 max=40 default=20 step=1 label='Edge sharpness'}} {{morph: float min=300 max=3000 default=1200 step=50 label='Morph ms'}} {{pause: float min=0 max=3000 default=400 step=50 label='Pause ms'}} --><defs><linearGradient id=\"gooFill\" gradientUnits=\"userSpaceOnUse\" x1=\"30\" y1=\"30\" x2=\"170\" y2=\"170\"><stop offset=\"0\" stop-color=\"{{colorA}}\"/><stop offset=\"1\" stop-color=\"{{colorB}}\"/></linearGradient><filter id=\"goo\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{goo}}\" result=\"soft\"/><feColorMatrix in=\"soft\" type=\"matrix\" values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 {{sharp}} {{threshold}}\"/></filter></defs><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><g filter=\"url(#goo)\" fill=\"url(#gooFill)\">${GOO.map((stages, i) => `<path id=\"goo${i}\" d=\"${stages[0]}\" fill-rule=\"evenodd\"/>`).join(\"\")}</g></svg>`,\n animate: GOO.flatMap((stages, i) =>\n stages.map((d, s): SvgAnimation => ({ id: `goo${i}`, attrs: { d: [d, stages[(s + 1) % stages.length]!] }, delay: n(`at${s}`), ms: n(\"morph\"), ease: \"in-out\" })),\n ),\n },\n};\n\n// ── Particle morph ─────────────────────────────────────────────────────\n\n/** Particle morph's dots: one element each, whatever the shapes. */\nconst DOTS = 48;\n/** Ms between one dot setting off and the next. */\nconst DOT_STAGGER = 14;\nconst PARTICLE_FROM = HEART;\nconst PARTICLE_TO = star(12, 12, 5, 10, 4.2);\n\n/** A repeatable 0–1 number for dot `i`. */\nconst noise = (i: number) => {\n const x = Math.sin(i * 12.9898 + 4.1414) * 43758.5453;\n return x - Math.floor(x);\n};\n\nexport const particleMorph: VectorEffect = {\n kind: \"vector\",\n id: \"particle-morph\",\n name: \"Particle morph\",\n description: \"A shape bursting into dots along its outline that swirl across and settle into a second shape, then back.\",\n category: \"morph\",\n tags: [\"morph\", \"particles\", \"dots\", \"shape\", \"logo\", \"reveal\"],\n hold: 600,\n presets: [\n { name: \"Confetti\", values: { background: [1, 0.98, 0.95], fromColor: [0.93, 0.27, 0.6], toColor: [0.15, 0.55, 0.95], ghost: 0.1, size: 3.2 } },\n { name: \"Embers\", values: { background: [0.05, 0.02, 0.02], fromColor: [1, 0.85, 0.3], toColor: [1, 0.3, 0.1], scatter: 50, size: 2 } },\n { name: \"Circle to square\", values: { from: \"M12 2 A10 10 0 1 1 12 22 A10 10 0 1 1 12 2 Z\", to: \"M3 3 H21 V21 H3 Z\" } },\n ],\n // The dots sit on the morphed outlines: point k of one shape flies to point k of the other.\n derived: (v) => {\n const box = [40, 40, 120, 120] as const;\n const [a, b] = morphPaths(fittedOr(v.from, PARTICLE_FROM, box, 96), fittedOr(v.to, PARTICLE_TO, box, 96), { points: DOTS });\n const [pa, pb] = [pointsOf(a), pointsOf(b)];\n const out: Record<string, string | number> = { a, b };\n const scatter = Number(v.scatter);\n for (let i = 0; i < DOTS; i++) {\n // The same share of the outline in shapes of several pieces.\n const k = Math.floor((i * pa.length) / DOTS);\n const [p, q] = [pa[k]!, pb[k]!];\n out[`ax${i}`] = r2(p[0]);\n out[`ay${i}`] = r2(p[1]);\n out[`bx${i}`] = r2(q[0]);\n out[`by${i}`] = r2(q[1]);\n // Halfway, thrown off to one side: a different way out and back.\n for (const [name, seed] of [[\"s\", i], [\"t\", i + DOTS]] as const) {\n const angle = seed * 2.39996;\n const far = scatter * (0.45 + 0.55 * noise(seed));\n out[`${name}x${i}`] = r2((p[0] + q[0]) / 2 + far * Math.cos(angle));\n out[`${name}y${i}`] = r2((p[1] + q[1]) / 2 + far * Math.sin(angle));\n }\n }\n return out;\n },\n motion: (() => {\n const back = 3000;\n const spread = DOTS * DOT_STAGGER;\n const leg = (i: number, at: number, from: string, mid: string, to: string, colours: [string, string]): SvgAnimation[] => [\n { id: `p${i}`, attrs: { cx: [n(`${from}x${i}`), n(`${mid}x${i}`)], cy: [n(`${from}y${i}`), n(`${mid}y${i}`)] }, delay: at + i * DOT_STAGGER, ms: 450, ease: \"out\" },\n { id: `p${i}`, attrs: { cx: [n(`${mid}x${i}`), n(`${to}x${i}`)], cy: [n(`${mid}y${i}`), n(`${to}y${i}`)], fill: colours }, delay: at + 450 + i * DOT_STAGGER, ms: 650, ease: \"in-out\" },\n ];\n const fade = (id: string, at: number, show: boolean): SvgAnimation => ({ id, attrs: { opacity: show ? [0, n(\"ghost\")] : [n(\"ghost\"), 0] }, delay: at, ms: 450, ease: \"in-out\" });\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{from: text default='${PARTICLE_FROM}' label='From path'}} {{to: text default='${PARTICLE_TO}' label='To path'}} {{fromColor: color default=#F472B6 label='From colour'}} {{toColor: color default=#FBBF24 label='To colour'}} {{background: color default=#0C0A1D label='Background'}} {{size: float min=0.8 max=6 default=2.6 step=0.1 label='Dot size'}} {{scatter: float min=0 max=80 default=34 step=1 label='Scatter'}} {{ghost: float min=0 max=1 default=0.16 label='Shape fill'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><path id=\"ghostA\" d=\"{{a}}\" fill=\"{{fromColor}}\" fill-rule=\"evenodd\" opacity=\"{{ghost}}\"/><path id=\"ghostB\" d=\"{{b}}\" fill=\"{{toColor}}\" fill-rule=\"evenodd\" opacity=\"0\"/>${Array.from(\n { length: DOTS },\n (_, i) => `<circle id=\"p${i}\" cx=\"{{ax${i}}}\" cy=\"{{ay${i}}}\" r=\"{{size}}\" fill=\"{{fromColor}}\"/>`,\n ).join(\"\")}</svg>`,\n animate: [\n fade(\"ghostA\", 400, false),\n fade(\"ghostB\", 400 + spread + 900, true),\n fade(\"ghostB\", back, false),\n fade(\"ghostA\", back + spread + 900, true),\n ...Array.from({ length: DOTS }, (_, i) => [\n ...leg(i, 400, \"a\", \"s\", \"b\", [\"{{fromColor}}\", \"{{toColor}}\"]),\n ...leg(i, back, \"b\", \"t\", \"a\", [\"{{toColor}}\", \"{{fromColor}}\"]),\n ]).flat(),\n ],\n };\n })(),\n};\n\n// ── Digit morph ────────────────────────────────────────────────────────\n\n/**\n * The digits 0–9 as pen strokes in a 20 × 32 box, drawn with a round-capped\n * stroke rather than filled: an open stroke morphs as an outline going there\n * and back, which a stroke draws as the line itself.\n */\nconst DIGITS: readonly string[] = (() => {\n const six: Point[] = [...arc(17, 22, 14, 19, 245, 180), ...arc(10, 22, 7, 7, 180, 540).slice(1)];\n return [\n polyline(arc(10, 16, 7, 13, 0, 360).slice(0, -1), true),\n polyline([[5.5, 8], [11, 3], [11, 29]]),\n polyline([...arc(10, 9.5, 6.5, 6.5, 200, 380), [3.5, 29], [17, 29]]),\n polyline([...arc(10, 9, 6, 6, 215, 450), ...arc(10, 21.5, 7, 6.5, 270, 495).slice(1)]),\n polyline([[14, 29], [14, 3], [3, 20.5], [18, 20.5]]),\n polyline([[16.5, 3], [5.5, 3], [4.6, 14.6], ...arc(10.5, 21.2, 6.8, 7, 218, 500)]),\n polyline(six),\n polyline([[3, 3], [17, 3], [8, 29]]),\n polyline([...arc(10, 9.5, 5.5, 5.5, 90, 450), ...arc(10, 22, 7, 7, 270, 630).slice(1)]),\n polyline(six.map((p): Point => [20 - p[0], 32 - p[1]])),\n ];\n})();\n\n/** A slot with no digit: a point, hidden. */\nconst BLANK = \"M10 16 L10 16\";\n/** Digit slots: numbers up to 9999. */\nconst SLOTS = 4;\n/** At most this many morphs from one number to the other; bigger jumps skip numbers between. */\nconst MAX_STEPS = 8;\n/** Ms each number rests before the next morph. */\nconst DIGIT_REST = 260;\n\nexport const digitMorph: VectorEffect = {\n kind: \"vector\",\n id: \"digit-morph\",\n name: \"Digit morph\",\n description: \"A number counting from one value to another, each digit's stroke bending smoothly into the next.\",\n category: \"morph\",\n tags: [\"morph\", \"number\", \"counter\", \"countdown\", \"kpi\", \"digits\"],\n hold: 900,\n presets: [\n { name: \"Countdown\", values: { from: 10, to: 0, ink: [1, 0.36, 0.3] } },\n { name: \"New year\", values: { from: 2025, to: 2026, morph: 700, background: [0.04, 0.03, 0.1], ink: [1, 0.84, 0.4] } },\n { name: \"Thin\", values: { weight: 1.4, background: [0.98, 0.98, 0.97], ink: [0.1, 0.1, 0.12] } },\n ],\n derived: (v) => {\n const from = Math.round(Number(v.from)) || 0;\n const to = Math.round(Number(v.to)) || 0;\n const steps = Math.min(MAX_STEPS, Math.abs(to - from));\n const values = Array.from({ length: steps + 1 }, (_, k) => Math.round(from + ((to - from) * k) / Math.max(1, steps)));\n const used = Math.max(1, ...values.map((x) => String(x).length));\n // Slots centred in the picture, the last one the units.\n const scale = Math.min(4.2, 340 / (used * 22 - 2));\n const left = 200 - ((used * 22 - 2) * scale) / 2;\n const interval = Number(v.morph) + DIGIT_REST;\n const lastEnd = Math.max(0, steps - 1) * interval + Number(v.morph);\n const out: Record<string, string | number> = { scale: r2(scale), y: r2(100 - 16 * scale), back: lastEnd + DIGIT_REST * 3 };\n for (let k = 1; k <= MAX_STEPS; k++) out[`t${k}`] = k <= steps ? (k - 1) * interval : lastEnd;\n for (let j = 0; j < SLOTS; j++) {\n const place = j - (SLOTS - used);\n out[`x${j}`] = r2(left + Math.max(0, place) * 22 * scale);\n // The digit each number shows in this slot, right-aligned; none in a slot the number does not reach.\n const glyphs = values.map((x) => {\n const text = String(x);\n const at = text.length - (used - place);\n return place >= 0 && at >= 0 ? Number(text[at]) : -1;\n });\n const paths = morphSequence(glyphs.map((g) => (g < 0 ? BLANK : DIGITS[g]!)), { points: 64 });\n for (let k = 0; k <= MAX_STEPS; k++) {\n const s = Math.min(k, steps);\n out[`d${j}_${k}`] = paths[s]!;\n out[`o${j}_${k}`] = glyphs[s]! < 0 ? 0 : 1;\n }\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{from: int min=0 max=9999 default=12 label='From'}} {{to: int min=0 max=9999 default=20 label='To'}} {{ink: color default=#F8FAFC label='Digits'}} {{background: color default=#111827 label='Background'}} {{weight: float min=0.8 max=5 default=2.8 step=0.1 label='Weight'}} {{morph: float min=150 max=1500 default=420 step=10 label='Morph ms'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/>${Array.from(\n { length: SLOTS },\n (_, j) =>\n `<path id=\"s${j}\" d=\"{{d${j}_0}}\" opacity=\"{{o${j}_0}}\" transform=\"translate({{x${j}}} {{y}}) scale({{scale}})\" fill=\"none\" fill-rule=\"evenodd\" stroke=\"{{ink}}\" stroke-width=\"{{weight}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`,\n ).join(\"\")}</svg>`,\n animate: Array.from({ length: SLOTS }, (_, j): SvgAnimation[] => [\n ...Array.from({ length: MAX_STEPS }, (_, i): SvgAnimation => {\n const k = i + 1;\n return { id: `s${j}`, attrs: { d: [`{{d${j}_${k - 1}}}`, `{{d${j}_${k}}}`], opacity: [n(`o${j}_${k - 1}`), n(`o${j}_${k}`)] }, delay: n(`t${k}`), ms: n(\"morph\"), ease: \"in-out\" };\n }),\n // Back to the first number in one morph, so it loops.\n { id: `s${j}`, attrs: { d: [`{{d${j}_${MAX_STEPS}}}`, `{{d${j}_0}}`], opacity: [n(`o${j}_${MAX_STEPS}`), n(`o${j}_0`)] }, delay: n(\"back\"), ms: n(\"morph\"), ease: \"in-out\" },\n ]).flat(),\n },\n};\n\n/** Vector effects that turn one shape into another (see `morphPaths`). */\nexport const morphEffects: VectorEffect[] = [shapeMorph, iconToggle, morphSequenceEffect, gooeyMorph, particleMorph, digitMorph];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * These read the pointer built-ins the wrapper declares: `iPointer` (xy\n * pixels, z how hovered 0–1, w seconds held) and `iClicks[8]` (newest first:\n * xy pixels, z the `iTime` of the click, w 1 for a click). Thumbnails and\n * recordings have no pointer, so each one plays a gentle demo while idle,\n * which a `uDemo` control turns off.\n */\n\n/**\n * `clickAt(i, demo)`: click `i`, newest first, as (x, y, time, 1), or zeros\n * for none. With the demo on and no real clicks yet, a synthetic click lands\n * every 2 s at a pseudo-random spot (needs {@link HASH}).\n */\nconst CLICKS = `\nvec4 clickAt(int i, bool demo) {\n if (!demo || iClicks[0].w > 0.5) return iClicks[i];\n float k = floor(iTime / 2.0) - float(i);\n vec2 h = hash22(vec2(k * 1.37 + 0.5, 3.7));\n return vec4((0.15 + 0.7 * h) * iResolution.xy, k * 2.0, 1.0);\n}`.trim();\n\n/**\n * `hoverPoint(demo, idle)`: the point hover effects follow, in pixels, and\n * how strongly they answer it (z): the pointer while it is over the canvas,\n * else (with the demo on) a slow Lissajous drift at strength `idle`.\n */\nconst HOVER = `\nvec3 hoverPoint(bool demo, float idle) {\n vec2 drift = iResolution.xy * (0.5 + vec2(0.28 * sin(iTime * 0.63), 0.22 * sin(iTime * 0.91 + 1.3)));\n float h = clamp(iPointer.z, 0.0, 1.0);\n return vec3(mix(drift, iPointer.xy, h), mix(demo ? idle : 0.0, 1.0, h));\n}`.trim();\n\n/** `glow(c)`: light as a colour over whatever is behind it (alpha is its brightest channel). */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/** `over(acc, colour, alpha)` onto a premultiplied accumulator; `unpremultiply(acc)` for the output. */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\nexport const clickRipple: ShaderEffect = {\n kind: \"shader\",\n id: \"click-ripple\",\n name: \"Click ripple\",\n description: \"Rings of water spreading out from every click and fading as they go.\",\n category: \"interaction\",\n tags: [\"interactive\", \"click\", \"overlay\", \"water\", \"ripple\"],\n transparent: true,\n source: glsl(\n `// Click ripple: water rings spreading from each click (up to 8 at once).\nuniform vec3 uColor; // @control color default=#BFE6FF label=\"Colour\"\nuniform float uSpeed; // @control min=0.05 max=2 default=0.5 label=\"Speed\"\nuniform float uWidth; // @control min=0.002 max=0.05 default=0.012 label=\"Ring width\"\nuniform float uLife; // @control min=0.3 max=6 default=2 label=\"Lifetime\"\nuniform int uRings; // @control min=1 max=4 default=3 label=\"Rings per click\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n CLICKS,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec4 acc = vec4(0.0);\n for (int i = 7; i >= 0; i--) {\n vec4 c = clickAt(i, uDemo);\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > uLife) continue;\n float life = age / uLife;\n float fade = (1.0 - life) * (1.0 - life);\n float d = length(fragCoord - c.xy) * px;\n for (int j = 0; j < 4; j++) {\n if (j >= uRings) break;\n float r = (age - float(j) * 0.16) * uSpeed;\n if (r <= 0.0) continue;\n // Rings widen and soften as they spread.\n float w = max(uWidth * (1.0 + life * 1.5), 1.5 * px);\n float x = (d - r) / w;\n float k = fade * (1.0 - 0.28 * float(j)) * smoothstep(0.0, 0.05, r);\n // A bright crest with a darker trough just inside it.\n float crest = exp(-x * x * 2.0);\n float trough = exp(-(x + 1.6) * (x + 1.6) * 2.0);\n acc = over(acc, uColor * 0.15, trough * k * 0.35);\n acc = over(acc, mix(uColor, vec3(1.0), 0.5 * crest), crest * k);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Sonar\", values: { uColor: [0.3, 1, 0.6], uSpeed: 0.3, uWidth: 0.006, uLife: 4, uRings: 4 } },\n { name: \"Raindrop\", values: { uColor: [1, 1, 1], uSpeed: 0.8, uWidth: 0.02, uLife: 1.2, uRings: 2 } },\n ],\n};\n\nexport const clickBurst: ShaderEffect = {\n kind: \"shader\",\n id: \"click-burst\",\n name: \"Click burst\",\n description: \"Sparks or confetti bursting out of every click, falling under gravity as they fade.\",\n category: \"interaction\",\n tags: [\"interactive\", \"click\", \"overlay\", \"particles\", \"celebration\", \"confetti\"],\n transparent: true,\n source: glsl(\n `// Click burst: sparks (or confetti) thrown out of each click, slowed by drag and pulled down by gravity.\nuniform vec3 uColorA; // @control color default=#FFD166 label=\"Colour 1\"\nuniform vec3 uColorB; // @control color default=#EF476F label=\"Colour 2\"\nuniform vec3 uColorC; // @control color default=#06D6A0 label=\"Colour 3\"\nuniform int uCount; // @control min=4 max=48 default=24 label=\"Count\"\nuniform float uSpread; // @control min=0.1 max=2 default=0.8 label=\"Spread\"\nuniform float uGravity; // @control min=0 max=3 default=1 label=\"Gravity\"\nuniform float uLife; // @control min=0.4 max=4 default=1.6 label=\"Lifetime\"\nuniform bool uConfetti; // @control default=false label=\"Confetti\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n CLICKS,\n OVER,\n `float segment(vec2 p, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float t = clamp(dot(p - a, ab) / max(dot(ab, ab), 1e-8), 0.0, 1.0);\n return length(p - a - ab * t);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n const float drag = 2.5;\n vec4 acc = vec4(0.0);\n for (int i = 7; i >= 0; i--) {\n vec4 c = clickAt(i, uDemo);\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > uLife) continue;\n float life = age / uLife;\n vec2 origin = c.xy * px;\n // A quick flash where it landed.\n float flash = exp(-age * 18.0) * exp(-dot(p - origin, p - origin) / 0.002);\n acc = over(acc, vec3(1.0), clamp(flash, 0.0, 1.0));\n float slow = (1.0 - exp(-drag * age)) / drag;\n for (int j = 0; j < 48; j++) {\n if (j >= uCount) break;\n vec2 h = hash22(vec2(float(j) * 7.13 + 1.0, c.z * 3.1 + float(i)));\n float h3 = hash12(h * 91.7 + c.z);\n float angle = h.x * 6.28318;\n vec2 v0 = vec2(cos(angle), sin(angle)) * uSpread * (0.3 + 0.7 * h.y) + vec2(0.0, uSpread * 0.35);\n vec2 pos = origin + v0 * slow - vec2(0.0, 0.5 * uGravity * 0.6 * age * age);\n if (abs(p.x - pos.x) > 0.06 || abs(p.y - pos.y) > 0.06) continue;\n vec3 col = h3 < 0.333 ? uColorA : (h3 < 0.667 ? uColorB : uColorC);\n float a;\n if (uConfetti) {\n // A tumbling paper rectangle.\n float spin = (h3 - 0.5) * 20.0 * age + angle;\n float cs = cos(spin);\n float sn = sin(spin);\n vec2 q = mat2(cs, sn, -sn, cs) * (p - pos);\n vec2 size = vec2(0.011, 0.006 * abs(cos(age * (4.0 + 6.0 * h.y) + h.x * 9.0)) + px);\n vec2 e = abs(q) - size;\n float sd = length(max(e, 0.0)) + min(max(e.x, e.y), 0.0);\n a = (1.0 - smoothstep(-px, px, sd)) * (1.0 - smoothstep(0.7, 1.0, life));\n col *= 0.75 + 0.25 * cs;\n } else {\n // A streak along its velocity, with a white-hot core.\n vec2 v = v0 * exp(-drag * age) - vec2(0.0, uGravity * 0.6 * age);\n float r = 0.004 * (1.0 - 0.6 * life) + px;\n float sd = segment(p, pos, pos - v * 0.05) - r;\n a = (1.0 - smoothstep(-px, px, sd)) * (1.0 - life);\n a += exp(-max(sd, 0.0) / (r * 2.0)) * 0.35 * (1.0 - life);\n col = mix(col, vec3(1.0), exp(-max(sd + r, 0.0) / (r * 0.5)) * 0.6);\n }\n acc = over(acc, col, clamp(a, 0.0, 1.0));\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Confetti\", values: { uConfetti: true, uCount: 36, uSpread: 1, uGravity: 1.4, uLife: 2.5, uColorC: [0.3, 0.55, 1] } },\n { name: \"Embers\", values: { uColorA: [1, 0.6, 0.15], uColorB: [1, 0.3, 0.1], uColorC: [1, 0.85, 0.5], uCount: 16, uSpread: 0.5, uGravity: 0.2 } },\n ],\n};\n\nexport const cursorGlow: ShaderEffect = {\n kind: \"shader\",\n id: \"cursor-glow\",\n name: \"Cursor glow\",\n description: \"A soft light following the pointer, with a halo ring that tightens while it is pressed.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"press\", \"overlay\", \"glow\", \"cursor\"],\n transparent: true,\n source: glsl(\n `// Cursor glow: a soft light at the pointer, scaled by how hovered, with a halo that tightens while pressed.\nuniform vec3 uColor; // @control color default=#7DD3FC label=\"Colour\"\nuniform float uRadius; // @control min=0.03 max=0.6 default=0.18 label=\"Radius\"\nuniform float uIntensity; // @control min=0 max=3 default=1.2 label=\"Intensity\"\nuniform float uHalo; // @control min=0 max=1 default=0.7 label=\"Halo\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HOVER,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec3 hp = hoverPoint(uDemo, 0.7);\n float d = length(fragCoord - hp.xy) / iResolution.y;\n // How pressed: eases in while held; the idle demo pulses it.\n float press = 1.0 - exp(-max(iPointer.w, 0.0) * 4.0);\n if (uDemo) press = max(press, (1.0 - iPointer.z) * pow(max(sin(iTime * 1.3), 0.0), 3.0));\n float light = exp(-pow(d / uRadius, 2.0) * 2.0) * uIntensity * hp.z * (1.0 + 0.6 * press);\n float ringR = uRadius * mix(1.3, 0.55, press);\n float ringW = max(uRadius * 0.05, 1.5 / iResolution.y);\n float ring = exp(-pow((d - ringR) / ringW, 2.0)) * uHalo * hp.z * (0.6 + 0.8 * press);\n fragColor = glow(uColor * light + mix(uColor, vec3(1.0), 0.5) * ring * 1.5);\n}`,\n ),\n presets: [\n { name: \"Spotlight\", values: { uColor: [1, 0.95, 0.85], uRadius: 0.4, uIntensity: 0.8, uHalo: 0 } },\n { name: \"Neon\", values: { uColor: [1, 0.2, 0.75], uRadius: 0.1, uIntensity: 2, uHalo: 1 } },\n ],\n};\n\nexport const hoverLiquid: ShaderEffect = {\n kind: \"shader\",\n id: \"hover-liquid\",\n name: \"Liquid hover\",\n description: \"An image that swells and ripples like liquid around the pointer while it hovers.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"image\", \"liquid\", \"distortion\"],\n source: glsl(\n `// Liquid hover: an image bulging and rippling around the pointer, as strongly as it is hovered.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uStrength; // @control min=0 max=1 default=0.6 label=\"Strength\"\nuniform float uRadius; // @control min=0.05 max=0.8 default=0.3 label=\"Radius\"\nuniform float uWobble; // @control min=0 max=1 default=0.5 label=\"Wobble\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec3 hp = hoverPoint(uDemo, 0.5);\n vec2 d = (fragCoord - hp.xy) / iResolution.y;\n float r = length(d);\n float s = uStrength * hp.z;\n float fall = exp(-pow(r / uRadius, 2.0) * 1.5);\n // Swell: pull samples towards the pointer, so it magnifies like a drop.\n vec2 off = -d * fall * s * 0.6;\n // Wobble: rings running out from the pointer and a slow liquid churn.\n vec2 dir = d / max(r, 1e-5);\n float wave = sin(r / uRadius * 14.0 - iTime * 5.0) * fall;\n off += dir * wave * uWobble * s * 0.02;\n vec2 churn = vec2(vnoise(d * 6.0 + iTime * 0.7), vnoise(d * 6.0 - iTime * 0.6 + 5.0)) - 0.5;\n off += churn * fall * s * uWobble * 0.05;\n vec4 pic = pictureRGBA(uImage, uv + off * vec2(iResolution.y / iResolution.x, 1.0));\n // Light catching the swell's upper-left slope.\n float slope = dot(dir, normalize(vec2(-0.6, 0.8))) * r / uRadius;\n vec3 col = pic.rgb + 0.12 * s * fall * slope + 0.06 * s * wave * uWobble;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Syrup\", values: { uStrength: 0.9, uRadius: 0.45, uWobble: 0.15 } },\n { name: \"Splash\", values: { uStrength: 0.5, uRadius: 0.25, uWobble: 1 } },\n ],\n};\n\nexport const hoverReveal: ShaderEffect = {\n kind: \"shader\",\n id: \"hover-reveal\",\n name: \"X-ray reveal\",\n description: \"A second image showing through a soft lens around the pointer that grows as it hovers and pulses on click.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"click\", \"image\", \"reveal\", \"x-ray\"],\n source: glsl(\n `// X-ray reveal: a second image seen through a soft lens at the pointer.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform sampler2D uReveal; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Revealed image\"\nuniform float uRadius; // @control min=0.05 max=0.6 default=0.22 label=\"Lens radius\"\nuniform float uSoftness; // @control min=0 max=1 default=0.35 label=\"Softness\"\nuniform vec3 uRim; // @control color default=#A5F3FC label=\"Rim\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n CLICKS,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float px = 1.0 / iResolution.y;\n vec3 hp = hoverPoint(uDemo, 0.85);\n // Each click swells the lens, which settles back.\n float pulse = 0.0;\n for (int i = 0; i < 8; i++) {\n vec4 c = clickAt(i, uDemo);\n float age = iTime - c.z;\n if (c.w < 0.5 || age < 0.0) continue;\n pulse += 0.6 * exp(-age * 4.0) * (1.0 - exp(-age * 30.0));\n }\n float R = uRadius * hp.z * (1.0 + pulse);\n float d = length(fragCoord - hp.xy) * px;\n // A wobbly edge, so the lens looks like it is melting through.\n d += (vnoise(fragCoord * px * 9.0 + iTime * 0.6) - 0.5) * 0.25 * R;\n float soft = max(uSoftness * R * 0.6, 1.5 * px);\n float m = 1.0 - smoothstep(R - soft, R, d);\n vec4 pic = mix(pictureRGBA(uImage, uv), pictureRGBA(uReveal, uv), m);\n float rim = exp(-pow((d - R + soft * 0.5) / max(soft * 0.5, 2.0 * px), 2.0)) * step(0.001, R);\n // The rim is light added over the picture, so it also shows where the picture is clear.\n float alpha = max(pic.a, clamp(rim * 0.6, 0.0, 1.0));\n fragColor = vec4((pic.rgb * pic.a + uRim * rim * 0.6) / max(alpha, 1e-4), alpha);\n}`,\n ),\n presets: [\n { name: \"Peephole\", values: { uRadius: 0.12, uSoftness: 0.05, uRim: [1, 1, 1] } },\n { name: \"Fog lamp\", values: { uRadius: 0.4, uSoftness: 1, uRim: [0, 0, 0] } },\n ],\n};\n\nexport const magnifier: ShaderEffect = {\n kind: \"shader\",\n id: \"magnifier\",\n name: \"Magnifier\",\n description: \"A round magnifying glass over an image at the pointer, with a bright rim and a fringe of colour at its edge.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"image\", \"lens\", \"zoom\"],\n source: glsl(\n `// Magnifier: a round lens over an image at the pointer, showing while hovered.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uZoom; // @control min=1 max=5 default=2 label=\"Zoom\"\nuniform float uRadius; // @control min=0.05 max=0.5 default=0.18 label=\"Radius\"\nuniform float uAberration; // @control min=0 max=1 default=0.35 label=\"Colour fringe\"\nuniform vec3 uRim; // @control color default=#FFFFFF label=\"Rim\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec3 hp = hoverPoint(uDemo, 1.0);\n float s = hp.z;\n vec4 col = pictureRGBA(uImage, uv);\n float R = uRadius * (0.75 + 0.25 * s) * iResolution.y;\n vec2 d = fragCoord - hp.xy;\n float r = length(d);\n float k = r / R;\n // A soft shadow under the glass.\n float shadow = 1.0 - smoothstep(R * 0.9, R * 1.3, length(d - vec2(R * 0.08, -R * 0.12)));\n col.rgb *= 1.0 - 0.35 * shadow * s;\n if (k < 1.05) {\n // More magnified at the centre, squeezed towards the rim like real glass.\n vec2 q = d / uZoom * (1.0 + 0.4 * k * k * k * k);\n float fr = uAberration * 0.08 * k * k * k;\n vec4 lr = pictureRGBA(uImage, (hp.xy + q * (1.0 + fr)) / iResolution.xy);\n vec4 lg = pictureRGBA(uImage, (hp.xy + q) / iResolution.xy);\n vec4 lb = pictureRGBA(uImage, (hp.xy + q * (1.0 - fr)) / iResolution.xy);\n vec4 lens = vec4(lr.r, lg.g, lb.b, max(max(lr.a, lg.a), lb.a));\n lens.rgb += 0.16 * exp(-pow(length(d / R - vec2(-0.35, 0.4)) * 2.6, 2.0));\n lens.rgb *= 1.0 - 0.25 * pow(k, 6.0);\n col = mix(col, lens, (1.0 - smoothstep(R - 1.5, R, r)) * s);\n }\n float rimW = max(R * 0.035, 2.0);\n float lit = 0.6 + 0.4 * dot(d / max(r, 1e-4), normalize(vec2(-1.0, 1.0)));\n float rim = exp(-pow((r - R) / rimW, 2.0));\n col = mix(col, vec4(uRim * lit, 1.0), rim * s * 0.9);\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Loupe\", values: { uZoom: 4, uRadius: 0.1, uAberration: 0.1 } },\n { name: \"Fishbowl\", values: { uZoom: 1.5, uRadius: 0.35, uAberration: 1 } },\n ],\n};\n\nexport const holoCard: ShaderEffect = {\n kind: \"shader\",\n id: \"holo-card\",\n name: \"Holo card\",\n description: \"A holographic foil trading card whose rainbow sheen and glare shift as the pointer tilts it.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"card\", \"holographic\", \"foil\", \"iridescent\"],\n transparent: true,\n source: glsl(\n `// Holo card: a rounded card with rainbow foil and glare that move as the pointer tilts it.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uFoil; // @control min=0 max=1 default=0.7 label=\"Foil\"\nuniform float uGlare; // @control min=0 max=1 default=0.6 label=\"Glare\"\nuniform float uTilt; // @control min=0 max=1 default=0.6 label=\"Tilt\"\nuniform float uCorner; // @control min=0 max=0.25 default=0.06 label=\"Corner radius\"\nuniform vec3 uBorder; // @control color default=#E2E8F0 label=\"Border\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n HOVER,\n OVER,\n PICTURE,\n `float roundedBox(vec2 p, vec2 hs, float r) {\n vec2 e = abs(p) - hs + r;\n return length(max(e, 0.0)) + min(max(e.x, e.y), 0.0) - r;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 res = iResolution.xy;\n const float aspect = 0.716;\n float h = min(res.y * 0.84, res.x * 0.84 / aspect);\n vec2 hs = vec2(h * aspect, h) * 0.5;\n vec3 hp = hoverPoint(uDemo, 0.7);\n vec2 tilt = clamp((hp.xy - 0.5 * res) / hs, -1.0, 1.0) * hp.z * uTilt;\n vec2 s = (fragCoord - 0.5 * res) / hs;\n // Fake perspective: the side the pointer is on leans away.\n vec2 q = s / max(1.0 - 0.15 * dot(s, tilt), 0.2);\n float radius = uCorner * hs.x * 2.0;\n float sd = roundedBox(q * hs, hs, radius);\n float mask = 1.0 - smoothstep(-1.0, 1.0, sd);\n // A soft shadow, falling away from the tilt.\n float shadowD = roundedBox(fragCoord - 0.5 * res + tilt * hs * 0.06 + vec2(0.0, h * 0.03), hs, radius);\n float shadow = (1.0 - smoothstep(-h * 0.04, h * 0.06, shadowD)) * 0.35;\n vec4 acc = over(vec4(0.0), vec3(0.0), shadow * (1.0 - mask));\n if (mask > 0.0) {\n vec2 cuv = q * 0.5 + 0.5;\n // The picture fills the card, cropped to fit.\n vec2 ts = vec2(textureSize(uImage, 0));\n float imageAspect = ts.x / max(ts.y, 1.0);\n vec2 fit = imageAspect > aspect ? vec2(aspect / imageAspect, 1.0) : vec2(1.0, imageAspect / aspect);\n vec3 base = picture(uImage, 0.5 + (cuv - 0.5) * fit);\n // Foil: rainbow bands that slide with the tilt, strongest in a broad band facing the light.\n float n = vnoise(cuv * 5.0);\n float phase = dot(cuv, vec2(0.7, 1.1)) * 1.6 + tilt.x * 0.9 - tilt.y * 0.6 + n * 0.5;\n vec3 rainbow = 0.5 + 0.5 * cos(6.28318 * (phase + vec3(0.0, 0.33, 0.67)));\n float lines = 0.75 + 0.25 * sin((cuv.x - cuv.y) * 90.0 + tilt.x * 8.0);\n float band = exp(-pow((cuv.x + cuv.y) * 0.7 - 0.7 - (tilt.x + tilt.y) * 0.6, 2.0) * 6.0);\n float foil = uFoil * (0.25 + 0.75 * band) * lines;\n // Overlay blend, so the picture keeps its darks under the foil.\n vec3 lit = mix(2.0 * base * rainbow, 1.0 - 2.0 * (1.0 - base) * (1.0 - rainbow), step(0.5, base));\n vec3 col = mix(base, lit + rainbow * 0.12, foil * 0.75);\n float sparkle = step(0.985, hash12(floor(cuv * vec2(90.0, 126.0))));\n col += sparkle * uFoil * band * (0.5 + 0.5 * sin(iTime * 3.0 + n * 20.0 + tilt.x * 10.0));\n // Glare: a highlight where the light hits, following the pointer.\n vec2 g = cuv - (0.5 + tilt * 0.55);\n col += uGlare * 0.6 * exp(-dot(g, g) * 7.0);\n // A thin foil border.\n float border = smoothstep(-0.03 * h - 1.0, -0.03 * h, sd);\n col = mix(col, uBorder * (0.8 + 0.4 * rainbow * uFoil), border);\n acc = over(acc, clamp(col, 0.0, 1.0), mask);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Subtle\", values: { uFoil: 0.3, uGlare: 0.35, uTilt: 0.4 } },\n { name: \"Full foil\", values: { uFoil: 1, uGlare: 0.8, uTilt: 1, uBorder: [0.98, 0.82, 0.35] } },\n ],\n};\n\nexport const pressCharge: ShaderEffect = {\n kind: \"shader\",\n id: \"press-charge\",\n name: \"Press to charge\",\n description: \"A ring that fills and glows while the pointer is held and drains when it is let go, bursting if it was fully charged.\",\n category: \"interaction\",\n tags: [\"interactive\", \"press\", \"overlay\", \"hold\", \"button\", \"ring\"],\n transparent: true,\n source: glsl(\n `// Press to charge: a ring that fills while held (iPointer.w > 0), drains when let go (iPointer.w < 0)\n// and bursts if it was let go fully charged.\nuniform vec3 uColor; // @control color default=#A78BFA label=\"Colour\"\nuniform float uHold; // @control min=0.3 max=5 default=1.2 label=\"Seconds to charge\"\nuniform float uSize; // @control min=0.08 max=0.45 default=0.22 label=\"Size\"\nuniform float uThickness; // @control min=0.005 max=0.08 default=0.025 label=\"Thickness\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n // iPointer.w: seconds held while pressed, minus the seconds since letting go after, 0 before any press.\n float w = iPointer.w;\n // The press is the newest click, so this is how long it was held when let go.\n float heldFor = iTime + min(w, 0.0) - iClicks[0].z;\n // Until someone presses, a synthetic press: hold, charge, let go, burst, rest.\n if (uDemo && iClicks[0].w < 0.5 && w == 0.0) {\n float t = mod(iTime, uHold + 2.0) - 0.4;\n float hold = uHold + 0.4;\n w = t <= 0.0 ? 0.0 : (t < hold ? t : -(t - hold));\n heldFor = hold;\n }\n float held = max(w, 0.0);\n float since = max(-w, 0.0);\n float reached = w < 0.0 ? clamp(heldFor / uHold, 0.0, 1.0) : 0.0;\n // While held it fills; once let go it drains from where it got to, over 0.4 s.\n float drain = 1.0 - smoothstep(0.0, 0.4, since);\n float charge = w > 0.0 ? clamp(held / uHold, 0.0, 1.0) : reached * drain;\n float full = step(uHold, held);\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float r = length(p);\n float turn = fract(atan(p.x, p.y) / 6.28318 + 1.0);\n float R = uSize * (1.0 - 0.06 * charge + 0.03 * iPointer.z);\n float ringD = abs(r - R) - uThickness * 0.5;\n float ring = 1.0 - smoothstep(-px, px, ringD);\n vec4 acc = vec4(0.0);\n // The core fills faintly, and the track shows where the charge goes.\n acc = over(acc, uColor, (1.0 - smoothstep(R - px, R + px, r)) * 0.1 * charge);\n acc = over(acc, uColor * 0.6, ring * (0.22 + 0.1 * iPointer.z));\n // The charge: an arc clockwise from the top, glowing brighter as it fills.\n float arcEnd = (charge - turn) * 6.28318 * R / px;\n float arc = ring * clamp(arcEnd + 0.5, 0.0, 1.0) * step(0.001, charge);\n float pulse = 1.0 + full * 0.25 * sin(iTime * 9.0);\n float halo = exp(-max(ringD, 0.0) / (uThickness * 1.5)) * charge * charge * 0.6 * clamp(arcEnd + 0.5, 0.0, 1.0);\n acc = over(acc, uColor, clamp(halo * pulse, 0.0, 1.0));\n acc = over(acc, mix(uColor, vec3(1.0), 0.35 * charge * pulse), arc);\n // A ping when it fills, and a flash with a ring bursting out when let go fully charged.\n float flashAge = -1.0;\n float flashSize = 0.0;\n if (w > 0.0 && held >= uHold) { flashAge = held - uHold; flashSize = 0.5; }\n if (w < 0.0 && reached >= 1.0) { flashAge = since; flashSize = 1.0; }\n if (flashAge >= 0.0 && flashAge < 0.8) {\n float k = 1.0 - flashAge / 0.8;\n float burstR = R + flashAge * 0.6 * flashSize;\n float burst = exp(-pow((r - burstR) / (uThickness * (1.0 + flashAge * 3.0)), 2.0)) * k * k * flashSize;\n acc = over(acc, mix(uColor, vec3(1.0), 0.5), clamp(burst, 0.0, 1.0));\n acc = over(acc, vec3(1.0), exp(-r * r / (R * R * 0.5)) * exp(-flashAge * 6.0) * 0.8 * flashSize);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Hold to confirm\", values: { uColor: [0.95, 0.3, 0.3], uHold: 2, uSize: 0.15, uThickness: 0.015 } },\n { name: \"Power up\", values: { uColor: [0.2, 0.9, 1], uHold: 0.8, uSize: 0.3, uThickness: 0.05 } },\n ],\n};\n\nexport const hoverSwap: ShaderEffect = {\n kind: \"shader\",\n id: \"hover-swap\",\n name: \"Hover swap\",\n description: \"One image burning away into another from the pointer as it hovers, along a glowing ragged edge.\",\n category: \"interaction\",\n tags: [\"interactive\", \"hover\", \"image\", \"dissolve\", \"transition\"],\n source: glsl(\n `// Hover swap: image A dissolves into image B as hover goes 0 → 1, spreading from the pointer.\nuniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Hover image\"\nuniform vec3 uEdge; // @control color default=#FFB86B label=\"Edge glow\"\nuniform float uEdgeWidth; // @control min=0 max=0.3 default=0.08 label=\"Edge width\"\nuniform float uGrain; // @control min=1 max=20 default=6 label=\"Noise scale\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n HOVER,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec3 hp = hoverPoint(uDemo, 0.0);\n float h = clamp(iPointer.z, 0.0, 1.0);\n // Idle, hover swings slowly in and out.\n float demo = uDemo ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 0.9)) : 0.0;\n float progress = mix(demo, 1.0, h);\n // Distance from the pointer, as a share of the way to the farthest corner.\n vec2 o = hp.xy / iResolution.y;\n vec2 size = iResolution.xy / iResolution.y;\n float far = max(max(length(o), length(o - vec2(size.x, 0.0))), max(length(o - vec2(0.0, size.y)), length(o - size)));\n float dist = length(fragCoord / iResolution.y - o) / far;\n float f = 0.65 * dist + 0.35 * fbm(fragCoord / iResolution.y * uGrain, 5);\n float w = max(uEdgeWidth, 0.005);\n float t = progress * (1.0 + w);\n float m = 1.0 - smoothstep(t - w, t, f);\n vec4 col = mix(pictureRGBA(uFrom, uv), pictureRGBA(uTo, uv), m);\n float edge = m * (1.0 - m) * 4.0 * step(0.001, uEdgeWidth);\n fragColor = mix(col, vec4(uEdge, 1.0), edge * 0.85);\n}`,\n ),\n presets: [\n { name: \"Clean cut\", values: { uEdgeWidth: 0.01, uGrain: 2 } },\n { name: \"Embers\", values: { uEdge: [1, 0.35, 0.1], uEdgeWidth: 0.2, uGrain: 14 } },\n ],\n};\n\n/** Shaders that answer the pointer: hovers, presses and clicks (`iPointer`, `iClicks`). */\nexport const interactionShaders: ShaderEffect[] = [\n clickRipple,\n clickBurst,\n cursorGlow,\n hoverLiquid,\n hoverReveal,\n magnifier,\n holoCard,\n pressCharge,\n hoverSwap,\n];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * Electricity is drawn from jagged arcs: straight runs between hashed kinks,\n * octave on octave like midpoint displacement, re-seeded many times a second\n * (`floor(iTime * rate)`) so they snap from shape to shape rather than\n * wobble. Each arc is a thin white-hot core in a coloured glow. The\n * interactive ones read the pointer built-ins the wrapper declares\n * (`iPointer`, `iClicks`) and play on their own while nobody is pointing.\n */\n\n/** `zigzag(x, seed)`: fractal jagged noise, about -1 to 1 (needs {@link HASH}). */\nconst ZIGZAG = `\n// Jagged noise, -1 to 1: straight runs between hashed points, so arcs kink rather than wobble.\nfloat jag(float x, float seed) {\n float i = floor(x);\n return mix(hash12(vec2(i, seed)), hash12(vec2(i + 1.0, seed)), fract(x)) * 2.0 - 1.0;\n}\n// Each octave halves the run and the kick, like midpoint displacement.\nfloat zigzag(float x, float seed) {\n float s = 0.0;\n float amp = 0.6;\n for (int i = 0; i < 5; i++) {\n s += amp * jag(x, seed + float(i) * 17.3);\n x *= 2.1;\n amp *= 0.5;\n }\n return s;\n}`.trim();\n\n/**\n * Jagged arcs (needs {@link ZIGZAG}): `arcDist(p, a, b, seed, rough, open)`\n * is the distance from `p` to an arc from `a` to `b` and how far along it `p`\n * is (0–1); `rough` scales its kicks (a fraction of its length) and `open`\n * (1) lets the end at `b` swing free, for branches. `arcPoint` is the point\n * `t` of the way along one, and `arcLight(d, w, colour)` its light: a\n * white-hot core about `w` wide in a coloured glow.\n */\nconst ARC = `\nfloat arcKick(float t, float seed, float rough, float open) {\n float env = sqrt(max(sin(3.14159 * t * (1.0 - 0.5 * open)), 0.0));\n return zigzag(t * 5.0, seed) * rough * env;\n}\nvec2 arcPoint(vec2 a, vec2 b, float t, float seed, float rough, float open) {\n vec2 ab = b - a;\n return a + ab * t + vec2(-ab.y, ab.x) * arcKick(t, seed, rough, open);\n}\nfloat chordDist(vec2 p, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float t = clamp(dot(p - a, ab) / max(dot(ab, ab), 1e-10), 0.0, 1.0);\n return length(p - a - ab * t);\n}\nvec2 arcDist(vec2 p, vec2 a, vec2 b, float seed, float rough, float open) {\n vec2 ab = b - a;\n float len = max(length(ab), 1e-4);\n vec2 dir = ab / len;\n vec2 q = p - a;\n float along = dot(q, dir);\n float side = dot(q, vec2(-dir.y, dir.x));\n float t = clamp(along / len, 0.0, 1.0);\n // Well away from the arc's band, skip the noise.\n float band = rough * len * 1.3;\n if (abs(side) > band + 0.3) return vec2(length(vec2(along - t * len, abs(side) - band)), t);\n // The true distance to the arc's chords either side of t, so steep kicks stay thin and their glow even.\n const float STEP = 0.008;\n vec2 lp = vec2(along, side);\n vec2 c0 = vec2((t - STEP) * len, arcKick(t - STEP, seed, rough, open) * len);\n vec2 c1 = vec2(t * len, arcKick(t, seed, rough, open) * len);\n vec2 c2 = vec2((t + STEP) * len, arcKick(t + STEP, seed, rough, open) * len);\n return vec2(min(chordDist(lp, c0, c1), chordDist(lp, c1, c2)), t);\n}\nvec3 arcLight(float d, float w, vec3 col) {\n float core = exp(-d * d / (w * w));\n float halo = 0.55 * exp(-d / (w * 4.0)) + 0.18 * exp(-d / (w * 20.0));\n return mix(col, vec3(1.0), 0.75) * core * 2.0 + col * halo;\n}`.trim();\n\n/** `glow(c)`: light as a colour over whatever is behind it (alpha is its brightest channel). */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/** `over(acc, colour, alpha)` onto a premultiplied accumulator; `unpremultiply(acc)` for the output. */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\n/** `segment(p, a, b)`: distance from `p` to the segment `a`–`b`. */\nconst SEGMENT = `\nfloat segment(vec2 p, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float t = clamp(dot(p - a, ab) / max(dot(ab, ab), 1e-8), 0.0, 1.0);\n return length(p - a - ab * t);\n}`.trim();\n\n/** `crackle(p, seed)`: fractal jagged 2D noise, about -1 to 1, for crawling electricity (needs {@link HASH}). */\nconst CRACKLE = `\nfloat jag2(vec2 x, float seed) {\n vec2 i = floor(x) + seed;\n vec2 f = fract(x);\n float a = hash12(i);\n float b = hash12(i + vec2(1.0, 0.0));\n float c = hash12(i + vec2(0.0, 1.0));\n float d = hash12(i + vec2(1.0, 1.0));\n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y) * 2.0 - 1.0;\n}\nfloat crackle(vec2 x, float seed) {\n float s = 0.0;\n float amp = 0.6;\n for (int i = 0; i < 4; i++) {\n s += amp * jag2(x, seed + float(i) * 7.3);\n x = x * 2.1 + 3.1;\n amp *= 0.5;\n }\n return s;\n}`.trim();\n\nexport const lightning: ShaderEffect = {\n kind: \"shader\",\n id: \"lightning\",\n name: \"Lightning\",\n description: \"Branching lightning striking from the top on a random schedule and wherever you click, lighting up the sky and leaving an afterglow.\",\n category: \"electric\",\n tags: [\"electric\", \"lightning\", \"storm\", \"weather\", \"overlay\", \"interactive\", \"click\"],\n transparent: true,\n source: glsl(\n `// Lightning: branching bolts from the top, now and then and wherever you click.\nuniform vec3 uColor; // @control color default=#B4C6FF label=\"Colour\"\nuniform float uRate; // @control min=0 max=2 default=0.8 label=\"Strikes per second (0 clicks only)\"\nuniform int uBranches; // @control min=0 max=4 default=3 label=\"Branches\"\nuniform float uRough; // @control min=0.03 max=0.3 default=0.12 label=\"Jaggedness\"\nuniform float uWidth; // @control min=0.3 max=3 default=1 label=\"Width\"\nuniform float uFlash; // @control min=0 max=1 default=0.5 label=\"Sky flash\"\nuniform float uAfterglow; // @control min=0 max=1 default=0.5 label=\"Afterglow\"`,\n HASH,\n ROTATE,\n ZIGZAG,\n ARC,\n GLOW,\n `// How brightly a strike burns age seconds in: return strokes flickering for a moment.\nfloat strikeLevel(float age, float seed) {\n if (age < 0.0 || age > 0.35) return 0.0;\n if (age < 0.04) return 1.0;\n float flick = 0.3 + 0.7 * step(0.45, hash12(vec2(floor(age * 30.0), seed)));\n return flick * (1.0 - age * 1.7);\n}\n\n// One bolt from a down to b with its branches, age seconds after it struck; adds its flash.\nvec3 bolt(vec2 p, vec2 a, vec2 b, float seed, float age, float px, inout float flash) {\n if (age < 0.0 || age > 2.2) return vec3(0.0);\n float on = strikeLevel(age, seed);\n float level = max(on, uAfterglow * 0.45 * exp(-age * 1.6));\n if (level < 0.002) return vec3(0.0);\n flash += on;\n // The leader reaches down over the first 70 ms.\n float reach = clamp(age / 0.07, 0.0, 1.0) * 1.05;\n float w = max(0.0022 * uWidth * mix(0.6, 1.0, on), 0.7 * px);\n vec2 m = arcDist(p, a, b, seed, uRough, 0.0);\n vec3 col = arcLight(m.x, w, uColor) * level * smoothstep(reach, reach - 0.03, m.y);\n // A splash of light where it lands.\n col += uColor * exp(-length(p - b) / 0.03) * on * smoothstep(0.95, 1.0, reach);\n vec2 dir = normalize(b - a);\n float len = length(b - a);\n for (int j = 0; j < 4; j++) {\n if (j >= uBranches) break;\n float fj = float(j);\n vec3 h = vec3(hash12(vec2(seed, fj + 1.3)), hash12(vec2(fj + 3.1, seed)), hash12(vec2(seed + fj, 7.7)));\n float t0 = 0.12 + 0.6 * h.x;\n float prog = (reach - t0) / (1.0 - t0) * 1.2;\n if (prog <= 0.0) continue;\n vec2 s = arcPoint(a, b, t0, seed, uRough, 0.0);\n float turn = (h.y < 0.5 ? -1.0 : 1.0) * (0.35 + 0.55 * fract(h.y * 7.0));\n vec2 bdir = rot(turn) * dir;\n float blen = len * (1.0 - t0) * (0.25 + 0.35 * h.z);\n vec2 e = s + bdir * blen;\n float bseed = seed + fj * 5.3 + 1.0;\n vec2 d = arcDist(p, s, e, bseed, uRough * 1.3, 1.0);\n float shown = smoothstep(prog, prog - 0.05, d.y);\n col += arcLight(d.x, w * 0.6, uColor) * level * 0.6 * (1.0 - 0.8 * d.y) * shown;\n // A twig off each branch.\n float t1 = 0.3 + 0.4 * fract(h.z * 11.0);\n vec2 s2 = arcPoint(s, e, t1, bseed, uRough * 1.3, 1.0);\n vec2 e2 = s2 + rot(-turn * 0.9) * bdir * blen * (1.0 - t1) * 0.6;\n vec2 d2 = arcDist(p, s2, e2, bseed + 2.7, uRough * 1.5, 1.0);\n col += arcLight(d2.x, w * 0.4, uColor) * level * 0.35 * (1.0 - d2.y) * smoothstep(prog, prog - 0.05, t1 + d2.y * 0.3);\n }\n return col;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n float aspect = iResolution.x * px;\n vec3 col = vec3(0.0);\n float flash = 0.0;\n // Strikes on a random schedule: at most one in each slot, some slots quiet.\n if (uRate > 0.0) {\n float slot = 1.0 / uRate;\n float k0 = floor(iTime / slot);\n for (int i = 0; i < 5; i++) {\n float k = k0 - float(i);\n if (float(i - 1) * slot > 2.2) break;\n if (hash12(vec2(k, 9.1)) > 0.8) continue;\n vec2 h = hash22(vec2(k, 3.3));\n vec2 g = hash22(vec2(k, 5.9));\n vec2 a = vec2((0.1 + 0.8 * h.y) * aspect, 1.05);\n vec2 b = vec2(a.x + (g.x - 0.5) * 0.7, 0.35 * g.y - 0.05);\n col += bolt(p, a, b, k * 1.37 + 0.5, iTime - (k + 0.7 * h.x) * slot, px, flash);\n }\n }\n // And one aimed at each click.\n for (int i = 0; i < 4; i++) {\n vec4 c = iClicks[i];\n if (c.w < 0.5) continue;\n vec2 b = c.xy * px;\n vec2 a = vec2(b.x + (hash12(vec2(c.z, 1.9)) - 0.5) * 0.5, 1.05);\n col += bolt(p, a, b, fract(c.z * 0.731) * 97.0 + float(i), iTime - c.z, px, flash);\n }\n // The sky lights up with each stroke, most at the top.\n col += mix(uColor, vec3(1.0), 0.3) * uFlash * min(flash, 1.5) * (0.1 + 0.25 * p.y);\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Thunderstorm\", values: { uRate: 1.4, uBranches: 4, uFlash: 0.9, uAfterglow: 0.7 } },\n { name: \"Violet\", values: { uColor: [0.75, 0.55, 1], uRate: 0.4, uRough: 0.16, uWidth: 1.4 } },\n { name: \"Click to strike\", values: { uRate: 0, uFlash: 0.3 } },\n ],\n};\n\nexport const teslaArc: ShaderEffect = {\n kind: \"shader\",\n id: \"tesla-arc\",\n name: \"Tesla arc\",\n description: \"A jittering plasma arc between two electrodes with stray filaments and sparks at the ends; hover and one end follows the pointer.\",\n category: \"electric\",\n tags: [\"electric\", \"arc\", \"plasma\", \"tesla\", \"sci-fi\", \"overlay\", \"interactive\", \"hover\"],\n transparent: true,\n source: glsl(\n `// Tesla arc: a plasma arc between two electrodes, re-forming many times a second.\nuniform vec2 uStart; // @control min=-1 max=1 default=-0.6,0 label=\"Start\"\nuniform vec2 uEnd; // @control min=-1 max=1 default=0.6,0 label=\"End\"\nuniform vec3 uColor; // @control color default=#A98BFF label=\"Colour\"\nuniform float uRate; // @control min=2 max=40 default=16 label=\"Re-forms per second\"\nuniform int uFilaments; // @control min=0 max=3 default=2 label=\"Filaments\"\nuniform float uRough; // @control min=0.03 max=0.4 default=0.16 label=\"Jaggedness\"\nuniform float uWidth; // @control min=0.3 max=3 default=1 label=\"Width\"\nuniform float uSparks; // @control min=0 max=1 default=0.6 label=\"Sparks\"\nuniform bool uFollow; // @control default=true label=\"End follows pointer\"`,\n HASH,\n ZIGZAG,\n ARC,\n SEGMENT,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 span = vec2(iResolution.x * px, 1.0) * 0.5;\n vec2 a = uStart * span;\n vec2 b = uEnd * span;\n if (uFollow) b = mix(b, (iPointer.xy - 0.5 * iResolution.xy) * px, clamp(iPointer.z, 0.0, 1.0));\n float tick = floor(iTime * uRate);\n float w = max(0.003 * uWidth, 0.7 * px);\n // The main arc, a little brighter or dimmer each time it re-forms.\n float level = 0.75 + 0.5 * hash12(vec2(tick, 0.7));\n vec2 m = arcDist(p, a, b, tick, uRough, 0.0);\n vec3 col = arcLight(m.x, w, uColor) * level;\n // Fainter, wilder filaments, each flickering on and off on its own clock.\n for (int i = 0; i < 3; i++) {\n if (i >= uFilaments) break;\n float fi = float(i) + 1.0;\n float ft = floor(iTime * uRate * (0.5 + 0.2 * fi) + fi * 3.1);\n float on = step(0.3, hash12(vec2(ft, fi * 4.3)));\n vec2 f = arcDist(p, a, b, ft * 1.7 + fi * 31.0, uRough * (1.4 + 0.4 * fi), 0.0);\n col += arcLight(f.x, w * 0.5, uColor) * 0.45 * on;\n }\n // Hot spots and sparks at both ends.\n for (int e = 0; e < 2; e++) {\n vec2 c = e == 0 ? a : b;\n vec2 away = normalize((e == 0 ? a - b : b - a) + 1e-5);\n float r = length(p - c);\n col += mix(uColor, vec3(1.0), 0.6) * (exp(-r / (0.012 * uWidth)) * 1.2 + exp(-r / 0.05) * 0.25) * level;\n for (int k = 0; k < 6; k++) {\n float fk = float(k);\n float clock = iTime * 2.3 + hash12(vec2(fk, float(e) + 0.5));\n float life = fract(clock);\n vec3 h = vec3(hash22(vec2(floor(clock), fk + float(e) * 7.0)), hash12(vec2(fk, floor(clock) + 0.3)));\n if (h.z > uSparks) continue;\n float ang = atan(away.y, away.x) + (h.x - 0.5) * 2.6;\n vec2 v = vec2(cos(ang), sin(ang)) * (0.25 + 0.35 * h.y);\n float s = life * 0.45;\n vec2 pos = c + v * s - vec2(0.0, 0.5 * s * s);\n if (length(p - pos) > 0.08) continue;\n vec2 vel = v - vec2(0.0, s);\n float d = segment(p, pos, pos - vel * 0.04);\n col += mix(uColor, vec3(1.0, 0.95, 0.85), 0.7) * (exp(-d * d / (w * w * 0.5)) + 0.3 * exp(-d / (w * 3.0))) * (1.0 - life);\n }\n }\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Blue arc\", values: { uColor: [0.4, 0.7, 1], uRate: 24, uFilaments: 3 } },\n { name: \"Lazy\", values: { uRate: 5, uRough: 0.1, uFilaments: 1, uSparks: 0.2 } },\n { name: \"Vertical\", values: { uStart: [0, 0.75], uEnd: [0, -0.75], uColor: [0.55, 1, 0.75] } },\n ],\n};\n\nexport const plasmaBall: ShaderEffect = {\n kind: \"shader\",\n id: \"plasma-ball\",\n name: \"Plasma ball\",\n description: \"A plasma globe whose writhing filaments reach from a glowing electrode to the glass and gather where the pointer is.\",\n category: \"electric\",\n tags: [\"electric\", \"plasma\", \"globe\", \"retro\", \"sci-fi\", \"interactive\", \"hover\"],\n source: glsl(\n `// Plasma ball: filaments writhing from a glowing electrode to the glass, gathering at the pointer.\nuniform vec3 uColor; // @control color default=#D04CFF label=\"Filaments\"\nuniform vec3 uTip; // @control color default=#5BA8FF label=\"Tips\"\nuniform vec3 uBackground; // @control color default=#05030A label=\"Background\"\nuniform int uCount; // @control min=3 max=14 default=9 label=\"Filament count\"\nuniform float uPull; // @control min=0 max=1 default=0.85 label=\"Pull to pointer\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSize; // @control min=0.5 max=1 default=0.85 label=\"Size\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n ZIGZAG,\n ARC,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float R = 0.44 * uSize;\n vec2 o = vec2(0.0, 0.07 * uSize);\n vec2 q = p - o;\n float r = length(q);\n float t = iTime * uSpeed;\n float w = max(0.0035 * uSize, 0.7 * px);\n vec3 col = uBackground;\n vec3 light = vec3(0.0);\n\n // The stand, lit from above by the globe.\n vec2 sq = p - o + vec2(0.0, R * 0.92);\n float bw = (0.15 - sq.y * 0.7) * uSize;\n if (sq.y < 0.0 && sq.y > -0.13 * uSize && abs(sq.x) < bw) {\n float shade = 0.5 + 0.5 * cos(sq.x / bw * 1.4);\n col = vec3(0.07, 0.07, 0.09) * shade + uColor * 0.12 * exp(sq.y * 25.0 / uSize);\n }\n\n // Where the filaments reach: the pointer while it is over, else a wandering point.\n float hover = clamp(iPointer.z, 0.0, 1.0);\n vec2 drift = vec2(sin(t * 0.53), sin(t * 0.71 + 1.0)) * R;\n vec2 target = mix(drift, (iPointer.xy - 0.5 * iResolution.xy) * px - o, hover);\n float pull = uPull * mix(uDemo ? 0.5 : 0.0, 1.0, hover);\n float towards = atan(target.y, target.x);\n float tick = floor(iTime * 14.0);\n\n if (r < R) {\n light += uColor * 0.08 * (1.0 - r / R);\n for (int i = 0; i < 14; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n float home = fi / float(uCount) * 6.28318 + (vnoise(vec2(fi * 3.1, t * 0.4)) - 0.5) * 2.5;\n float spread = (hash12(vec2(fi, 2.0)) - 0.5) * 0.6;\n float diff = mod(towards + spread - home + 3.14159, 6.28318) - 3.14159;\n float ang = home + diff * pull;\n vec2 dir = vec2(cos(ang), sin(ang));\n vec2 root = dir * 0.05 * uSize;\n vec2 tip = dir * R * 0.985;\n // Bent in the middle, swaying slowly; kinked afresh each tick.\n vec2 mid = (root + tip) * 0.5 + vec2(-dir.y, dir.x) * (vnoise(vec2(fi * 5.7, t * 0.9)) - 0.5) * 0.5 * R;\n float seed = tick + fi * 13.0;\n vec2 d1 = arcDist(q, root, mid, seed, 0.1, 0.0);\n vec2 d2 = arcDist(q, mid, tip, seed + 7.0, 0.1, 0.0);\n float d = min(d1.x, d2.x);\n float along = d1.x < d2.x ? d1.y * 0.5 : 0.5 + d2.y * 0.5;\n vec3 fc = mix(uColor, uTip, smoothstep(0.45, 1.0, along));\n float flick = 0.7 + 0.3 * hash12(vec2(tick, fi));\n light += arcLight(d, w * mix(1.3, 0.7, along), fc) * flick * 0.75;\n // A bright spot where it touches the glass.\n light += uTip * exp(-length(q - tip) / (0.02 * uSize)) * 0.7;\n }\n } else {\n light += uColor * 0.25 * exp(-(r - R) / (0.06 * uSize));\n }\n // The electrode's glow.\n light += mix(uColor, vec3(1.0), 0.6) * exp(-r / (0.05 * uSize)) * 1.2;\n col += 1.0 - exp(-light);\n\n // The electrode, a frosted ball.\n float re = 0.05 * uSize;\n col = mix(col, mix(vec3(0.85, 0.8, 0.95), uColor, 0.3) * (1.1 - 0.4 * length(q / re - vec2(-0.3, 0.4))), smoothstep(re, re - px, r));\n // The glass: a thin rim, brighter toward the edge, and a highlight.\n col += vec3(0.75, 0.8, 1.0) * exp(-abs(r - R) / (0.003 + px)) * 0.4;\n col += mix(uColor, vec3(1.0), 0.5) * pow(clamp(r / R, 0.0, 1.0), 8.0) * 0.12 * step(r, R);\n float spec = length((q - vec2(-0.42, 0.5) * R) * vec2(1.0, 1.8));\n col += vec3(1.0) * (1.0 - smoothstep(0.0, 0.1 * R, spec)) * 0.35 * step(r, R);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Classic\", values: { uColor: [0.95, 0.35, 0.8], uTip: [0.6, 0.5, 1] } },\n { name: \"Ice\", values: { uColor: [0.3, 0.7, 1], uTip: [0.85, 0.95, 1], uBackground: [0.01, 0.03, 0.06] } },\n { name: \"Dense\", values: { uCount: 14, uSpeed: 1.6 } },\n ],\n};\n\nexport const electricBorder: ShaderEffect = {\n kind: \"shader\",\n id: \"electric-border\",\n name: \"Electric border\",\n description: \"Electricity crackling round a rounded frame and now and then arcing off it, for cards and buttons.\",\n category: \"electric\",\n tags: [\"electric\", \"border\", \"frame\", \"ui\", \"card\", \"overlay\", \"glow\"],\n transparent: true,\n source: glsl(\n `// Electric border: electricity crackling round a rounded frame, now and then arcing off it.\nuniform vec3 uColor; // @control color default=#5CE1FF label=\"Colour\"\nuniform float uInset; // @control min=0 max=0.3 default=0.08 label=\"Inset\"\nuniform float uRadius; // @control min=0 max=0.5 default=0.08 label=\"Corner radius\"\nuniform float uThickness; // @control min=0.002 max=0.06 default=0.016 label=\"Thickness\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uArcs; // @control min=0 max=1 default=0.5 label=\"Arcs\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"`,\n HASH,\n ZIGZAG,\n ARC,\n CRACKLE,\n GLOW,\n `float boxSdf(vec2 p, vec2 b, float r) {\n vec2 q = abs(p) - b + r;\n return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;\n}\n\n// The point on the frame in the direction ang from the centre, about.\nvec2 framePoint(float ang, vec2 box, float rad) {\n vec2 dir = vec2(cos(ang), sin(ang));\n float s = min(box.x / max(abs(dir.x), 1e-3), box.y / max(abs(dir.y), 1e-3));\n vec2 q = dir * s;\n return q - dir * boxSdf(q, box, rad);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 box = max(0.5 * iResolution.xy * px - uInset, vec2(0.05));\n float rad = min(uRadius, min(box.x, box.y));\n float sd = boxSdf(p, box, rad);\n float t = iTime * uSpeed;\n float w = max(0.0018, 0.7 * px);\n float around = atan(p.y, p.x);\n vec3 light = vec3(0.0);\n // Strands: the frame's outline pushed about by jagged noise, re-kinked many times a second.\n for (int i = 0; i < 3; i++) {\n float fi = float(i);\n float tick = floor(t * (12.0 + 5.0 * fi) + fi * 0.5);\n float v = sd - crackle(p * (9.0 + 3.0 * fi), fract(tick * 0.0731) * 300.0 + fi * 19.0) * uThickness;\n vec2 g = vec2(dFdx(v), dFdy(v)) / px;\n float d = abs(v) / max(length(g), 0.5);\n // Brighter stretches running round the frame.\n float flow = 0.5 + 0.5 * sin(around * (2.0 + fi) - t * (2.0 + fi) * (fi == 1.0 ? -1.0 : 1.0) + fi * 2.0);\n float level = mix(0.2, 1.0, smoothstep(0.2, 0.9, flow)) * (fi == 0.0 ? 1.0 : 0.55);\n light += arcLight(d, w * (fi == 0.0 ? 1.0 : 0.6), uColor) * level;\n }\n // A soft glow hugging the frame.\n light += uColor * exp(-abs(sd) / (uThickness * 2.0 + 0.01)) * 0.2;\n // Arcs leaping off the frame and back.\n for (int j = 0; j < 2; j++) {\n float fj = float(j);\n float clock = t * 1.3 + fj * 0.47;\n float slot = floor(clock);\n if (hash12(vec2(slot, fj + 0.3)) > uArcs || fract(clock) > 0.3) continue;\n float ang = hash12(vec2(slot, fj + 5.1)) * 6.28318;\n vec2 a = framePoint(ang, box, rad);\n vec2 b = framePoint(ang + 0.15 + 0.2 * hash12(vec2(slot, 9.0)), box, rad);\n vec2 mid = (a + b) * 0.5;\n mid += normalize(mid) * (0.04 + 0.05 * hash12(vec2(slot, 2.0)));\n float seed = floor(iTime * 30.0) + fj * 50.0;\n float d = min(arcDist(p, a, mid, seed, 0.25, 0.0).x, arcDist(p, mid, b, seed + 3.0, 0.25, 0.0).x);\n light += arcLight(d, w * 0.8, uColor) * (1.0 - fract(clock) / 0.3);\n }\n fragColor = glow(light * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Button\", values: { uInset: 0.04, uRadius: 0.5, uThickness: 0.01, uArcs: 0.3 } },\n { name: \"Toxic\", values: { uColor: [0.55, 1, 0.3], uThickness: 0.03, uSpeed: 1.5, uArcs: 0.8 } },\n { name: \"Hot pink\", values: { uColor: [1, 0.35, 0.75], uRadius: 0.02, uIntensity: 1.4 } },\n ],\n};\n\nexport const electricText: ShaderEffect = {\n kind: \"shader\",\n id: \"electric-text\",\n name: \"Electric text\",\n description: \"A word with electricity crawling over its outlines and arcs leaping between its letters, flickering on a dark background.\",\n category: \"electric\",\n tags: [\"electric\", \"text\", \"title\", \"glow\", \"sci-fi\"],\n source: glsl(\n `// Electric text: electricity crawling along the letters' outlines, arcs jumping between them.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"VOLT\")} label=\"Text\"\nuniform vec3 uColor; // @control color default=#6FD3FF label=\"Electricity\"\nuniform vec3 uFill; // @control color default=#0B1622 label=\"Letters\"\nuniform vec3 uBackground; // @control color default=#04060B label=\"Background\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Text size\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uArcs; // @control min=0 max=1 default=0.6 label=\"Arcs between letters\"\nuniform float uFlicker; // @control min=0 max=1 default=0.5 label=\"Flicker\"`,\n HASH,\n ZIGZAG,\n ARC,\n CRACKLE,\n `// The text image's half size in the frame (height 1, centred), contained in uSize of it.\nvec2 textHalf() {\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float h = min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n return vec2(h * aspect, h) * 0.5;\n}\n\nfloat letters(vec2 p) {\n vec2 uv = p / (2.0 * textHalf()) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uText, uv).a;\n}\n\n// The mask softened over a few taps, so its edge is a smooth slope to trace.\nfloat soft(vec2 p) {\n float s = letters(p);\n for (int i = 0; i < 6; i++) {\n float a = float(i) * 1.0472;\n s += letters(p + vec2(cos(a), sin(a)) * 0.005);\n }\n return s / 7.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float t = iTime * uSpeed;\n float w = max(0.0016, 0.6 * px);\n float mask = letters(p);\n float flick = mix(1.0, 0.35 + 0.65 * step(0.25, hash12(vec2(floor(t * 14.0), 4.0))), uFlicker);\n vec3 light = vec3(0.0);\n // Electricity crawling over the outlines: the edge traced through jagged jitter.\n for (int i = 0; i < 2; i++) {\n float fi = float(i);\n float seed = fract(floor(t * (16.0 + 7.0 * fi)) * 0.0371) * 300.0 + fi * 11.0;\n vec2 jitter = vec2(crackle(p * 14.0, seed), crackle(p * 14.0 + 5.2, seed + 3.0)) * 0.012;\n float v = soft(p + jitter) - 0.5;\n vec2 g = vec2(dFdx(v), dFdy(v)) / px;\n float d = abs(v) / max(length(g), 1.0);\n light += arcLight(d, w * (1.0 - 0.4 * fi), uColor) * (1.0 - 0.45 * fi);\n }\n // A halo round the letters.\n float halo = 0.0;\n for (int i = 0; i < 8; i++) {\n float a = float(i) * 0.7854;\n vec2 dir = vec2(cos(a), sin(a));\n halo += letters(p + dir * 0.025) + letters(p + dir * 0.06) * 0.5;\n }\n light += uColor * halo / 12.0 * 0.5 * (1.0 - mask);\n // Arcs between letters, hidden where they pass behind one.\n vec2 hb = textHalf();\n for (int j = 0; j < 2; j++) {\n float fj = float(j);\n float clock = t * 1.7 + fj * 0.5;\n float slot = floor(clock);\n if (hash12(vec2(slot, fj + 0.7)) > uArcs || fract(clock) > 0.35) continue;\n vec3 h = vec3(hash22(vec2(slot, fj + 2.3)), hash12(vec2(slot, fj + 8.1)));\n vec2 a = vec2((h.x * 2.0 - 1.0) * hb.x * 0.75, (h.y - 0.5) * hb.y * 0.8);\n vec2 b = vec2(a.x + (h.x > 0.5 ? -1.0 : 1.0) * (0.12 + 0.25 * h.z) * hb.x, (fract(h.z * 7.0) - 0.5) * hb.y * 0.8);\n vec2 d = arcDist(p, a, b, floor(iTime * 25.0) + fj * 40.0, 0.2, 0.0);\n light += arcLight(d.x, w * 0.8, uColor) * (1.0 - mask) * (1.0 - fract(clock) / 0.35) * 0.9;\n }\n vec3 col = mix(uBackground, uFill + uColor * 0.06 * flick, mask);\n col += 1.0 - exp(-light * flick);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Toxic\", values: { uColor: [0.5, 1, 0.3], uFill: [0.04, 0.1, 0.03] } },\n { name: \"Overload\", values: { uColor: [1, 0.85, 0.4], uArcs: 1, uFlicker: 0.9, uSpeed: 1.6 } },\n { name: \"Steady\", values: { uFlicker: 0, uArcs: 0.2, uSpeed: 0.6 } },\n ],\n};\n\nexport const jacobsLadder: ShaderEffect = {\n kind: \"shader\",\n id: \"jacobs-ladder\",\n name: \"Jacob's ladder\",\n description: \"An arc climbing between two diverging rods, stretching and breaking at the top, then striking again at the bottom.\",\n category: \"electric\",\n tags: [\"electric\", \"arc\", \"plasma\", \"lab\", \"retro\", \"loop\"],\n source: glsl(\n `// Jacob's ladder: an arc climbing between diverging rods, breaking at the top and re-forming below.\nuniform vec3 uColor; // @control color default=#B79BFF label=\"Arc\"\nuniform vec3 uRod; // @control color default=#8A8F9C label=\"Rods\"\nuniform vec3 uBackground; // @control color default=#06060B label=\"Background\"\nuniform float uPeriod; // @control min=0.8 max=6 default=2.6 label=\"Climb seconds\"\nuniform float uSpread; // @control min=0.05 max=0.5 default=0.24 label=\"Spread at top\"\nuniform float uRough; // @control min=0.03 max=0.4 default=0.14 label=\"Jaggedness\"\nuniform float uWidth; // @control min=0.3 max=3 default=1 label=\"Width\"`,\n HASH,\n ZIGZAG,\n ARC,\n SEGMENT,\n `const float BOTTOM = -0.4;\nconst float TOP = 0.3;\n\n// How far each rod is from the middle at height y.\nfloat rodX(float y) {\n return 0.035 + uSpread * clamp((y - BOTTOM) / (TOP - BOTTOM), 0.0, 1.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n float w = max(0.003 * uWidth, 0.7 * px);\n vec3 col = uBackground;\n\n // The insulator block and the two rods, round and metallic.\n vec2 bq = abs(p - vec2(0.0, BOTTOM - 0.05)) - vec2(0.12 + uSpread * 0.3, 0.05);\n if (max(bq.x, bq.y) < 0.0) col = mix(uRod * 0.2, uRod * 0.35, smoothstep(-0.05, 0.05, p.y - BOTTOM + 0.05));\n for (int s = 0; s < 2; s++) {\n float side = s == 0 ? -1.0 : 1.0;\n vec2 a = vec2(side * rodX(BOTTOM), BOTTOM);\n vec2 b = vec2(side * rodX(TOP), TOP + 0.03);\n float d = segment(p, a, b);\n float r = 0.007;\n float across = clamp(d / r, 0.0, 1.0);\n vec3 metal = uRod * (0.45 + 0.55 * sqrt(1.0 - across * across)) + 0.25 * exp(-d / (r * 0.3));\n col = mix(col, metal, smoothstep(r, r - px, d));\n }\n\n // The climb: slow at the bottom, rising faster as the hot air carries it.\n float u = fract(iTime / uPeriod);\n float climb = clamp(u / 0.88, 0.0, 1.0);\n float y = BOTTOM + 0.02 + (TOP - BOTTOM - 0.02) * pow(climb, 1.5);\n float tick = floor(iTime * 20.0);\n vec3 light = vec3(0.0);\n if (u < 0.88) {\n vec2 l = vec2(-rodX(y) + 0.006, y);\n vec2 r = vec2(rodX(y) - 0.006, y);\n // It bows upward, more as it stretches before breaking.\n float bow = (r.x - l.x) * 0.15 + 0.12 * smoothstep(0.6, 0.88, u);\n vec2 mid = vec2((hash12(vec2(tick, 3.0)) - 0.5) * 0.04, y + bow);\n float d = min(arcDist(p, l, mid, tick * 2.1, uRough, 0.0).x, arcDist(p, mid, r, tick * 2.1 + 1.0, uRough, 0.0).x);\n float strike = 1.0 + 1.5 * exp(-u * uPeriod * 12.0);\n float flick = 0.75 + 0.35 * hash12(vec2(tick, 1.0)) - 0.4 * smoothstep(0.75, 0.88, u) * step(0.5, hash12(vec2(tick, 2.0)));\n light += arcLight(d, w, uColor) * strike * flick;\n // The rods glow where it touches them.\n light += uColor * (exp(-length(p - l) / 0.02) + exp(-length(p - r) / 0.02)) * 0.6 * flick;\n } else {\n // Broken: a puff of plasma rising off the top and fading.\n float age = (u - 0.88) * uPeriod;\n vec2 c = vec2(0.0, TOP + 0.12 + age * 0.25);\n light += uColor * exp(-length(p - c) / (0.03 + age * 0.1)) * exp(-age * 6.0) * 0.8;\n }\n col += 1.0 - exp(-light);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Fast\", values: { uPeriod: 1.2, uRough: 0.2 } },\n { name: \"Wide\", values: { uSpread: 0.45, uPeriod: 3.5, uWidth: 1.4 } },\n { name: \"Blue\", values: { uColor: [0.45, 0.7, 1], uRod: [0.75, 0.6, 0.4] } },\n ],\n};\n\nexport const shortCircuit: ShaderEffect = {\n kind: \"shader\",\n id: \"short-circuit\",\n name: \"Short circuit\",\n description: \"A sparking fault spitting irregular bursts of hot sparks that fall away, with bright flashes and a wisp of smoke.\",\n category: \"electric\",\n tags: [\"electric\", \"sparks\", \"fault\", \"overlay\", \"particles\", \"danger\"],\n transparent: true,\n source: glsl(\n `// Short circuit: a fault spitting bursts of hot sparks, flashes and a wisp of smoke.\nuniform vec2 uOrigin; // @control min=-1 max=1 default=0,0.2 label=\"Fault\"\nuniform vec3 uColor; // @control color default=#FFB54D label=\"Sparks\"\nuniform vec3 uFlashColor; // @control color default=#BFD9FF label=\"Flash\"\nuniform float uActivity; // @control min=0 max=1 default=0.6 label=\"Activity\"\nuniform int uSparks; // @control min=4 max=32 default=18 label=\"Sparks per burst\"\nuniform float uSpread; // @control min=0.2 max=2 default=1 label=\"Spread\"\nuniform float uGravity; // @control min=0 max=3 default=1 label=\"Gravity\"\nuniform float uSmoke; // @control min=0 max=1 default=0.4 label=\"Smoke\"`,\n HASH,\n NOISE,\n FBM,\n ZIGZAG,\n ARC,\n SEGMENT,\n GLOW,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 o = uOrigin * vec2(iResolution.x * px, 1.0) * 0.5;\n float w = max(0.0025, 0.7 * px);\n const float drag = 2.5;\n const float SLOT = 0.3;\n vec3 light = vec3(0.0);\n float ambient = 0.0;\n float k0 = floor(iTime / SLOT);\n for (int i = 0; i < 5; i++) {\n float k = k0 - float(i);\n if (hash12(vec2(k, 1.7)) > uActivity) continue;\n float age = iTime - (k + 0.6 * hash12(vec2(k, 2.9))) * SLOT;\n if (age < 0.0 || age > 1.2) continue;\n // A flash, flickering, with a little arc across the fault.\n float flash = exp(-age * 14.0) * (0.6 + 0.4 * step(0.5, hash12(vec2(floor(age * 40.0), k))));\n float r = length(p - o);\n light += uFlashColor * (exp(-r / 0.02) * 2.0 + exp(-r / 0.12) * 0.5) * flash;\n ambient += flash;\n if (age < 0.12) {\n vec2 s = vec2(0.035, 0.0) * (0.6 + hash12(vec2(k, 4.4)));\n light += arcLight(arcDist(p, o - s, o + s.yx * 0.3 + s, floor(iTime * 40.0), 0.35, 0.0).x, w, uFlashColor) * 0.8;\n }\n float slow = (1.0 - exp(-drag * age)) / drag;\n for (int j = 0; j < 32; j++) {\n if (j >= uSparks) break;\n vec3 h = vec3(hash22(vec2(float(j) * 7.13 + 1.0, k * 3.1)), hash12(vec2(k, float(j) + 0.5)));\n float span = 0.35 + 0.75 * h.z;\n if (age > span) continue;\n float ang = 1.5708 + (h.x - 0.5) * 2.8;\n vec2 v0 = vec2(cos(ang), sin(ang)) * uSpread * (0.4 + 0.9 * h.y);\n vec2 pos = o + v0 * slow - vec2(0.0, 0.5 * uGravity * 0.8 * age * age);\n if (length(p - pos) > 0.1) continue;\n vec2 vel = v0 * exp(-drag * age) - vec2(0.0, uGravity * 0.8 * age);\n float d = segment(p, pos, pos - vel * 0.035);\n float heat = 1.0 - age / span;\n vec3 c = mix(uColor * vec3(1.0, 0.55, 0.35), mix(uColor, vec3(1.0), 0.7), heat * heat);\n light += c * (exp(-d * d / (w * w)) * 1.5 + 0.25 * exp(-d / (w * 3.0))) * heat;\n }\n }\n light += uFlashColor * min(ambient, 1.0) * 0.08;\n // Smoke curling up from the fault.\n vec2 q = p - o;\n float spread = 0.03 + max(q.y, 0.0) * 0.35;\n float plume = fbm(vec2(q.x * 7.0, q.y * 4.0 - iTime * 0.6), 4);\n float smoke = smoothstep(0.4, 0.75, plume) * exp(-q.x * q.x / (spread * spread)) * smoothstep(-0.02, 0.04, q.y) * exp(-max(q.y, 0.0) * 2.5);\n vec4 acc = over(vec4(0.0), vec3(0.32, 0.31, 0.3), clamp(smoke * uSmoke, 0.0, 1.0));\n vec4 g = glow(light);\n acc = over(acc, g.rgb, g.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Welding\", values: { uColor: [0.75, 0.85, 1], uActivity: 1, uSparks: 32, uSmoke: 0.2 } },\n { name: \"Sputter\", values: { uActivity: 0.3, uSparks: 8, uSpread: 0.6 } },\n { name: \"Wall socket\", values: { uOrigin: [0, -0.3], uGravity: 1.6, uSmoke: 0.7 } },\n ],\n};\n\nexport const powerSurge: ShaderEffect = {\n kind: \"shader\",\n id: \"power-surge\",\n name: \"Power surge\",\n description: \"A picture jolted by a power surge: a flash, an arc tearing across, scanlines and colour split, then a brownout before it settles.\",\n category: \"electric\",\n tags: [\"electric\", \"image\", \"glitch\", \"surge\", \"flash\"],\n source: glsl(\n `// Power surge: an image jolted by a surge, then settling, on a schedule.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform vec3 uColor; // @control color default=#8FD8FF label=\"Arc colour\"\nuniform float uPeriod; // @control min=1.5 max=8 default=3.5 label=\"Seconds between surges\"\nuniform float uStrength; // @control min=0 max=1.5 default=1 label=\"Strength\"\nuniform float uGlitch; // @control min=0 max=1 default=0.6 label=\"Glitch\"\n${BACKDROP_CONTROLS}`,\n HASH,\n ZIGZAG,\n ARC,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n float aspect = iResolution.x * px;\n float cycle = floor(iTime / uPeriod);\n float since = iTime - cycle * uPeriod;\n float tick = floor(iTime * 24.0);\n float surge = uStrength * exp(-since * 4.0) * (0.55 + 0.45 * hash12(vec2(tick, 1.0)));\n // Rows torn sideways and the channels split while it surges.\n float rows = floor(uv.y * mix(12.0, 60.0, hash12(vec2(tick, 2.0))));\n float tear = (hash12(vec2(rows, tick)) - 0.5) * step(0.55, hash12(vec2(rows, tick + 5.0))) * 0.12 * surge * uGlitch;\n vec2 st = uv + vec2(tear, 0.0);\n float split = 0.012 * surge * uGlitch;\n vec4 r = pictureRGBA(uImage, st + vec2(split, 0.0));\n vec4 g = pictureRGBA(uImage, st);\n vec4 b2 = pictureRGBA(uImage, st - vec2(split, 0.0));\n vec3 col = vec3(r.r, g.g, b2.b);\n // Brightness spikes, dips in a brownout, then comes back.\n float brownout = 1.0 - 0.3 * min(uStrength, 1.0) * smoothstep(0.25, 0.5, since) * (1.0 - smoothstep(0.7, 1.5, since));\n col = col * brownout * (1.0 + surge * 1.4) + surge * 0.2 * mix(uColor, vec3(1.0), 0.5);\n col *= 1.0 - 0.35 * min(surge, 1.0) * uGlitch * (0.5 + 0.5 * sin(fragCoord.y * 1.5708));\n // The arc tearing across in the first moments, with a branch.\n vec3 light = vec3(0.0);\n float on = step(since, 0.35) * (0.5 + 0.5 * step(0.3, hash12(vec2(tick, 6.0)))) * uStrength;\n if (on > 0.0) {\n float w = max(0.003, 0.7 * px);\n vec2 a = vec2(-0.05, 0.2 + 0.6 * hash12(vec2(cycle, 3.0)));\n vec2 b = vec2(aspect + 0.05, 0.2 + 0.6 * hash12(vec2(cycle, 4.0)));\n light += arcLight(arcDist(p, a, b, tick, 0.07, 0.0).x, w, uColor);\n vec2 s = arcPoint(a, b, 0.3 + 0.4 * hash12(vec2(cycle, 5.0)), tick, 0.07, 0.0);\n vec2 e = s + vec2(0.15 + 0.2 * hash12(vec2(cycle, 6.0)), (hash12(vec2(cycle, 7.0)) - 0.5) * 0.6);\n light += arcLight(arcDist(p, s, e, tick + 9.0, 0.2, 1.0).x, w * 0.6, uColor) * 0.6;\n light *= on;\n }\n col = 1.0 - (1.0 - clamp(col, 0.0, 1.0)) * exp(-light);\n // The arc shows where the picture is clear too.\n float arc = 1.0 - exp(-max(light.r, max(light.g, light.b)));\n fragColor = vec4(col, max(max(max(r.a, g.a), b2.a), arc));\n}`,\n ),\n presets: [\n { name: \"Blackout\", values: { uStrength: 1.5, uGlitch: 1, uPeriod: 5 } },\n { name: \"Flicker\", values: { uStrength: 0.5, uGlitch: 0.3, uPeriod: 2 } },\n { name: \"Landscape\", values: { uImage: SAMPLE_IMAGES.landscape, uColor: [1, 0.85, 0.5] } },\n ],\n};\n\nexport const electricField: ShaderEffect = {\n kind: \"shader\",\n id: \"electric-field\",\n name: \"Electric field\",\n description: \"Field lines between glowing positive and negative charges with dashes flowing along them; hover and one charge follows the pointer.\",\n category: \"electric\",\n tags: [\"electric\", \"physics\", \"science\", \"field\", \"lines\", \"interactive\", \"hover\"],\n source: glsl(\n `// Electric field: the field lines of two or three charges, dashes flowing from + to -.\nuniform vec2 uCharge1; // @control min=-1 max=1 default=-0.5,0 label=\"Charge 1 (+)\"\nuniform vec2 uCharge2; // @control min=-1 max=1 default=0.5,0 label=\"Charge 2 (-)\"\nuniform vec2 uCharge3; // @control min=-1 max=1 default=0,0.7 label=\"Charge 3\"\nuniform int uThird; // @control min=-1 max=1 default=0 label=\"Charge 3 sign (0 off)\"\nuniform int uLines; // @control min=4 max=32 default=16 label=\"Field lines\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Flow speed\"\nuniform vec3 uLine; // @control color default=#8FB3FF label=\"Lines\"\nuniform vec3 uPositive; // @control color default=#FF5A5F label=\"Positive\"\nuniform vec3 uNegative; // @control color default=#3FA7FF label=\"Negative\"\nuniform vec3 uBackground; // @control color default=#060912 label=\"Background\"\nuniform float uDrift; // @control min=0 max=1 default=0.3 label=\"Drift\"\nuniform bool uFollow; // @control default=true label=\"Charge 1 follows pointer\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 span = vec2(iResolution.x * px, 1.0) * 0.5;\n float t = iTime;\n vec2 c[3];\n c[0] = uCharge1 * span + vec2(sin(t * 0.7), cos(t * 0.9)) * 0.06 * uDrift;\n c[1] = uCharge2 * span + vec2(cos(t * 0.6 + 1.0), sin(t * 0.8)) * 0.06 * uDrift;\n c[2] = uCharge3 * span + vec2(sin(t * 0.5 + 2.0), cos(t * 0.4)) * 0.06 * uDrift;\n if (uFollow) c[0] = mix(c[0], (iPointer.xy - 0.5 * iResolution.xy) * px, clamp(iPointer.z, 0.0, 1.0));\n float q[3];\n q[0] = 1.0;\n q[1] = -1.0;\n q[2] = float(uThird);\n // Field lines are contours of the stream function (the charges' angles summed);\n // the potential (their log distances) spaces the dashes along them.\n float psi = 0.0;\n vec2 gradPsi = vec2(0.0);\n float phi = 0.0;\n float nearest = 1e3;\n for (int i = 0; i < 3; i++) {\n if (q[i] == 0.0) continue;\n vec2 d = p - c[i];\n float r2 = max(dot(d, d), 1e-6);\n psi += q[i] * atan(d.y, d.x);\n gradPsi += q[i] * vec2(-d.y, d.x) / r2;\n phi += q[i] * 0.5 * log(r2);\n nearest = min(nearest, sqrt(r2));\n }\n float n = float(uLines) / 6.28318;\n float v = psi * n;\n float off = abs(fract(v + 0.5) - 0.5) / max(length(gradPsi) * n * px, 1e-5);\n float line = (1.0 - smoothstep(0.4, 1.4, off)) * smoothstep(0.03, 0.09, nearest);\n float dash = fract(phi * 2.5 - t * uSpeed);\n float lit = 0.25 + 0.9 * smoothstep(0.0, 0.08, dash) * (1.0 - smoothstep(0.35, 0.5, dash));\n vec3 tint = mix(uLine, mix(uPositive, uNegative, smoothstep(-1.0, 1.0, phi)), 0.3);\n vec3 col = uBackground + uLine * 0.05 * clamp(length(gradPsi) * 0.03, 0.0, 1.0);\n col += tint * line * lit;\n // The charges: glowing discs with their signs.\n for (int i = 0; i < 3; i++) {\n if (q[i] == 0.0) continue;\n vec2 d = p - c[i];\n float r = length(d);\n vec3 cc = q[i] > 0.0 ? uPositive : uNegative;\n col += cc * (exp(-r / 0.025) * 0.8 + exp(-r / 0.1) * 0.25);\n col = mix(col, cc, smoothstep(0.035, 0.035 - px, r));\n vec2 ad = abs(d);\n float bar = max(ad.x - 0.018, ad.y - 0.004);\n if (q[i] > 0.0) bar = min(bar, max(ad.x - 0.004, ad.y - 0.018));\n col = mix(col, vec3(1.0), smoothstep(px, 0.0, bar));\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Two positives\", values: { uThird: 1, uCharge3: [0, -0.7], uLines: 20 } },\n { name: \"Three body\", values: { uThird: -1, uCharge3: [0, 0.65], uDrift: 0.8 } },\n { name: \"Blueprint\", values: { uBackground: [0.04, 0.12, 0.3], uLine: [0.85, 0.92, 1], uSpeed: 0.5 } },\n ],\n};\n\n/** Electricity: lightning, arcs, plasma and sparks. */\nexport const electricShaders: ShaderEffect[] = [\n lightning,\n teslaArc,\n plasmaBall,\n electricBorder,\n electricText,\n jacobsLadder,\n shortCircuit,\n powerSurge,\n electricField,\n];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/**\n * `meltCycle(rate)`: how melted, 0–1, over an 8 s loop: it melts (faster\n * with a higher rate), holds, then reforms back to solid before the loop\n * starts again.\n */\nconst MELT_CYCLE = `\nfloat meltCycle(float rate) {\n float u = fract(iTime / 8.0);\n float m = clamp(min(u, 0.62) * 2.0 * rate, 0.0, 1.0);\n m = m * m * (3.0 - 2.0 * m);\n return m * (1.0 - smoothstep(0.74, 0.97, u));\n}`.trim();\n\n/** `smin(a, b, k)`: a smooth minimum of two distances, blending over `k`. */\nconst SMIN = `\nfloat smin(float a, float b, float k) {\n k = max(k, 1e-4);\n float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n return mix(b, a, h) - k * h * (1.0 - h);\n}`.trim();\n\n/**\n * `liquidShade(base, n, gloss)`: a glossy liquid surface of colour `base`\n * with normal `n`, lit from the upper left.\n */\nconst LIQUID_SHADE = `\nvec3 liquidShade(vec3 base, vec3 n, float gloss) {\n vec3 l = normalize(vec3(-0.5, 0.65, 0.85));\n float diff = clamp(dot(n, l), 0.0, 1.0);\n float spec = pow(max(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0), 36.0);\n float rim = pow(1.0 - n.z, 2.0);\n return base * (0.45 + 0.7 * diff) * (1.0 - 0.35 * rim) + vec3(spec) * gloss + rim * 0.12 * gloss;\n}`.trim();\n\nexport const dripMelt: ShaderEffect = {\n kind: \"shader\",\n id: \"drip-melt\",\n name: \"Drip melt\",\n description: \"An image melting from the top edge down: columns slump, thick glossy drips run down and pool in a puddle, then it all reforms.\",\n category: \"melt\",\n tags: [\"melt\", \"image\", \"drip\", \"liquid\", \"glossy\", \"loop\"],\n loop: 8,\n source: glsl(\n `// Drip melt: the top edge slumps, glossy drips run down the picture and pool at the bottom.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uDrips; // @control min=3 max=32 default=14 label=\"Drip count\"\nuniform float uSpeed; // @control min=0.25 max=3 default=1 label=\"Melt speed\"\nuniform float uViscosity; // @control min=0.004 max=0.04 default=0.02 label=\"Viscosity (drip width)\"\nuniform float uGloss; // @control min=0 max=1.5 default=0.8 label=\"Gloss\"\nuniform vec3 uBackground; // @control color default=#17121F label=\"Behind\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.7 label=\"Melt (when still)\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n MELT_CYCLE,\n SMIN,\n LIQUID_SHADE,\n `float aspect = 1.0;\n\n// Where the picture's top edge has slumped to at x.\nfloat edgeY(float x, float m) {\n return 1.0 - m * (0.04 + 0.3 * smoothstep(0.25, 0.7, fbm(vec2(x * 3.5, 1.7), 3)));\n}\n\n// The puddle's surface at x.\nfloat poolY(float x, float m) {\n return m * (0.1 + 0.012 * sin(x * 9.0 + iTime * 0.7854) + 0.025 * vnoise(vec2(x * 6.0, 2.0))) - 0.006;\n}\n\n// Distance to the liquid (negative inside): a lip along the slumped edge, drips hanging from it, the puddle.\nfloat liquid(vec2 uv, float m) {\n float n = float(uDrips);\n float grow = smoothstep(0.0, 0.2, m);\n float e = edgeY(uv.x, m) + 0.01 * (1.0 - grow);\n float lip = 0.022 * grow;\n float d = max(uv.y - e, e - lip - uv.y);\n float c = floor(uv.x * n);\n for (int k = -2; k <= 2; k++) {\n float ci = c + float(k);\n vec2 h = hash22(vec2(ci, 3.1));\n float xi = (ci + 0.2 + 0.6 * h.x) / n;\n float w = min(uViscosity * (0.7 + 0.6 * hash12(vec2(ci, 7.7))), 0.6 * aspect / n) * grow;\n float top = edgeY(xi, m) - lip * 0.5;\n float len = pow(m, 1.4) * min(0.2 + 0.95 * h.y, 1.0) * max(top - poolY(xi, m), 0.0);\n float head = top - len;\n float along = clamp(uv.y, head, top);\n // A stem thinning as it runs, then a round, heavier head.\n float r = w * mix(0.85, 0.6, smoothstep(top, top - 0.3, uv.y));\n r = mix(r, w * 1.3, smoothstep(head + 3.0 * w, head, uv.y));\n d = smin(d, length(vec2((uv.x - xi) * aspect, uv.y - along)) - r, 0.012 * grow);\n }\n return smin(d, uv.y - poolY(uv.x, m), 0.03 * grow);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n aspect = iResolution.x / iResolution.y;\n vec2 uv = fragCoord / iResolution.xy;\n float px = 1.0 / iResolution.y;\n float m = uAnimate ? meltCycle(uSpeed) : uProgress;\n\n // The picture slumped under its edge: squashed towards the bottom, stretched thin at the top.\n float e = edgeY(uv.x, m);\n float h = clamp(uv.y / e, 0.0, 1.0);\n float ys = 1.0 - pow(1.0 - h, 1.0 + m * 1.3);\n float xs = uv.x + m * 0.006 * sin(uv.y * 40.0 + uv.x * 13.0);\n vec4 col = pictureRGBA(uImage, vec2(xs, ys));\n vec4 behind = vec4(uBackground * (0.75 + 0.5 * uv.y), uBackdropAlpha);\n col = mix(col, behind, smoothstep(e - px, e + px, uv.y));\n\n // The liquid's shadow, down and to the right.\n float shadow = liquid(uv + vec2(-0.004, 0.009), m);\n col.rgb *= 1.0 - 0.4 * smoothstep(0.012, -0.004, shadow) * smoothstep(0.0, 0.1, m);\n\n float d = liquid(uv, m);\n if (d < 4.0 * px) {\n float eps = 0.0015;\n vec2 g = vec2(liquid(uv + vec2(eps / aspect, 0.0), m) - d, liquid(uv + vec2(0.0, eps), m) - d);\n g /= max(length(g), 1e-5);\n float thick = sqrt(clamp(-d / 0.018, 0.0, 1.0));\n vec3 nrm = normalize(vec3(g * (1.0 - thick) * 1.6, 0.4 + thick));\n // Drips carry the colour of the top edge down; the puddle is everything mixed.\n vec4 top = pictureRGBA(uImage, vec2(uv.x + 0.01 * sin(uv.y * 25.0), 0.965));\n float sx = uv.x + 0.04 * sin(uv.x * 11.0 + uv.y * 30.0);\n vec4 pool = (pictureRGBA(uImage, vec2(sx - 0.06, 0.25)) + pictureRGBA(uImage, vec2(sx + 0.06, 0.4)) + pictureRGBA(uImage, vec2(sx, 0.9))) / 3.0;\n float inPool = smoothstep(poolY(uv.x, m) + 0.04, poolY(uv.x, m) - 0.01, uv.y);\n vec4 base = mix(top, pool, inPool);\n base.rgb *= 0.9 + 0.12 * vnoise(vec2(uv.x * 90.0, uv.y * 3.0));\n vec3 wet = liquidShade(base.rgb * 1.05, nrm, uGloss);\n col = mix(col, vec4(wet, base.a), smoothstep(px, -px, d));\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Meltdown\", values: { uDrips: 22, uSpeed: 1.6, uViscosity: 0.012, uGloss: 1 } },\n { name: \"Syrup\", values: { uDrips: 7, uSpeed: 0.6, uViscosity: 0.032, uGloss: 1.3 } },\n { name: \"City at night\", values: { uImage: SAMPLE_IMAGES.city, uBackground: [0.02, 0.02, 0.05] } },\n ],\n};\n\nexport const heatHaze: ShaderEffect = {\n kind: \"shader\",\n id: \"heat-haze\",\n name: \"Heat haze\",\n description: \"A mirage shimmer rising off a hot image: wavering refraction strongest near the ground, with a warm tint and a faint reflection.\",\n category: \"melt\",\n tags: [\"melt\", \"image\", \"heat\", \"mirage\", \"shimmer\", \"desert\", \"distortion\"],\n source: glsl(\n `// Heat haze: rising, wavering refraction over a picture, strongest near the bottom.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uStrength; // @control min=0 max=1 default=0.5 label=\"Strength\"\nuniform float uScale; // @control min=1 max=20 default=7 label=\"Scale\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uHeight; // @control min=0.1 max=1 default=0.8 label=\"Height\"\nuniform vec3 uTint; // @control color default=#FFB070 label=\"Warm tint\"\nuniform float uWarmth; // @control min=0 max=1 default=0.3 label=\"Tint amount\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float aspect = iResolution.x / iResolution.y;\n float t = iTime * uSpeed;\n float heat = smoothstep(uHeight, 0.0, uv.y);\n // Rising turbulence, stretched upwards, and a fast horizontal waver through it.\n vec2 q = vec2(uv.x * aspect * uScale, uv.y * uScale * 1.6 - t * 1.4);\n float a = fbm(q, 4);\n float b = fbm(q + vec2(5.2, 1.3) + a, 4);\n vec2 off = vec2(a - 0.5, b - 0.5) * 0.05;\n off.x += sin(uv.y * uScale * 14.0 - t * 5.0 + a * 6.0) * 0.01;\n off *= uStrength * heat;\n vec2 st = uv + off;\n // A touch of colour fringing where the air bends light the most.\n float fringe = 0.25 * length(off);\n vec4 r = pictureRGBA(uImage, st + vec2(fringe, 0.0));\n vec4 g = pictureRGBA(uImage, st);\n vec4 b2 = pictureRGBA(uImage, st - vec2(fringe, 0.0));\n vec3 col = vec3(r.r, g.g, b2.b);\n float alpha = max(max(r.a, g.a), b2.a);\n // An inferior mirage: just above the ground, what sits above it shows again, flipped and shimmering.\n float y0 = 0.05 + 0.15 * uHeight;\n float below = smoothstep(y0, 0.0, uv.y) * (0.6 + 0.4 * b);\n vec4 mirage = pictureRGBA(uImage, vec2(st.x, y0 + (y0 - uv.y) * 1.4 + off.y * 2.0));\n col = mix(col, mirage.rgb, below * uStrength * 0.55);\n alpha = mix(alpha, mirage.a, below * uStrength * 0.55);\n // Warm, slightly hazy air.\n col = mix(col, col * mix(vec3(1.0), uTint * 1.35, uWarmth), heat);\n col = mix(col, uTint, heat * uWarmth * 0.12 * (0.7 + 0.6 * a));\n fragColor = vec4(col, alpha);\n}`,\n ),\n presets: [\n { name: \"Desert noon\", values: { uStrength: 0.85, uScale: 9, uHeight: 0.75, uWarmth: 0.55 } },\n { name: \"Asphalt\", values: { uStrength: 0.6, uScale: 14, uSpeed: 1.8, uHeight: 0.35, uWarmth: 0.15, uTint: [1, 0.85, 0.7] } },\n { name: \"City exhaust\", values: { uImage: SAMPLE_IMAGES.city, uStrength: 0.5, uHeight: 0.5, uTint: [0.75, 0.85, 1], uWarmth: 0.2 } },\n ],\n};\n\nexport const waxMelt: ShaderEffect = {\n kind: \"shader\",\n id: \"wax-melt\",\n name: \"Wax melt\",\n description: \"A silhouette softening like warm wax: its edges round off, its top sags and it slumps into a glossy puddle, then sets again.\",\n category: \"melt\",\n tags: [\"melt\", \"wax\", \"text\", \"silhouette\", \"glossy\", \"loop\"],\n loop: 8,\n source: glsl(\n `// Wax melt: an alpha mask softening, sagging and spreading into a puddle.\nuniform sampler2D uMask; // @control filter=linear wrap=clamp default=${textImage(\"WAX\")} label=\"Shape (alpha)\"\nuniform vec3 uColor; // @control color default=#E8452C label=\"Wax\"\nuniform vec3 uBackground; // @control color default=#1C1A22 label=\"Background\"\nuniform float uGloss; // @control min=0 max=1.5 default=0.8 label=\"Gloss\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Size\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.6 label=\"Melt (when still)\"`,\n HASH,\n NOISE,\n FBM,\n MELT_CYCLE,\n LIQUID_SHADE,\n `const float BASE = -0.14;\n\n// The mask's alpha at frame point s (height 1, centred), contained in uSize of the frame.\nfloat shape(vec2 s, out float halfWidth, out float bottom) {\n vec2 size = vec2(textureSize(uMask, 0));\n float aspect = size.x / max(size.y, 1.0);\n float frame = iResolution.x / iResolution.y;\n float h = min(uSize * 0.7, frame * uSize / aspect);\n halfWidth = 0.42 * h * aspect;\n // A text image's letters sit on a line about 0.27 of its height below the middle.\n bottom = -0.27 * h;\n vec2 uv = s / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uMask, uv).a;\n}\n\n// How much wax covers frame point p, 0–1, soft at the edges (softer still by soft): the sagging, spreading shape and its puddle.\nfloat wax(vec2 p, float m, float soft) {\n float halfWidth;\n float bottom;\n shape(vec2(0.0), halfWidth, bottom);\n float dy = p.y - BASE;\n // The top sags (more in some places than others), the base spreads, and it wobbles a little as it goes.\n float sag = 1.0 + (0.25 * m + 1.6 * m * m * m) * (0.6 + 0.8 * fbm(vec2(p.x * 3.0, 4.0), 3));\n float spread = 1.0 + m * 0.4 * exp(-max(dy, 0.0) * 7.0);\n vec2 s = vec2(p.x / spread + m * 0.012 * sin(dy * 30.0 + p.x * 8.0), bottom + dy * sag);\n // Softened: the mask averaged over a disc that widens as it melts, so corners round off.\n float r = 0.004 + 0.022 * m + soft;\n float sum = shape(s, halfWidth, bottom) * 2.0;\n for (int i = 0; i < 6; i++) {\n float a = float(i) * 1.0472;\n vec2 dir = vec2(cos(a), sin(a));\n sum += shape(s + dir * r * 0.5, halfWidth, bottom) + shape(s + dir.yx * vec2(-1.0, 1.0) * r, halfWidth, bottom);\n }\n float cover = dy < 0.0 ? 0.0 : sum / 14.0;\n // The puddle, growing out from under the shape, its rim lumpy.\n float rx = halfWidth * (0.25 + 0.8 * m);\n float ry = (0.008 + 0.05 * m) * (1.0 + 0.15 * sin(p.x * 17.0 + 1.0));\n vec2 e = vec2(p.x / rx, (p.y - BASE) / ry);\n float pool = smoothstep(0.012 + soft, -0.012 - soft, (length(e) - 1.0) * ry) * smoothstep(0.03, 0.25, m);\n return cover + pool - cover * pool;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float m = uAnimate ? meltCycle(1.0) : uProgress;\n // Background: a soft spot of light on a table top.\n vec3 col = uBackground * (1.0 + 0.6 * exp(-dot(p, p) * 3.0));\n col = mix(col, uBackground * 0.6, smoothstep(BASE + 0.02, BASE - 0.1, p.y));\n float shade = wax(p + vec2(-0.012, 0.02), m, 0.01);\n col *= 1.0 - 0.45 * smoothstep(0.2, 0.7, shade) * smoothstep(BASE + 0.25, BASE - 0.05, p.y);\n\n float c = wax(p, m, 0.0);\n float px = 1.5 / iResolution.y;\n float edge = smoothstep(0.5 - 0.06, 0.5 + 0.06, c);\n if (c > 0.3) {\n // The surface's slope from a softer copy, so the letters bulge like poured wax.\n float eps = 0.01;\n float soft = 0.014;\n vec2 g = vec2(wax(p + vec2(eps, 0.0), m, soft) - wax(p - vec2(eps, 0.0), m, soft), wax(p + vec2(0.0, eps), m, soft) - wax(p - vec2(0.0, eps), m, soft)) / (2.0 * eps);\n float thick = smoothstep(0.3, 1.0, c);\n vec3 nrm = normalize(vec3(-g * 0.03, 1.0));\n // Thin wax lets light through: warmer and brighter at the edges, deeper in the middle.\n vec3 deep = uColor * 0.7;\n vec3 glow = min(uColor * uColor * 1.6 + vec3(0.08, 0.03, 0.0), vec3(1.0));\n vec3 base = mix(glow, deep, thick);\n vec3 lit = liquidShade(base, nrm, uGloss * (0.35 + 0.65 * m));\n col = mix(col, lit, edge);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Beeswax\", values: { uColor: [0.95, 0.75, 0.32], uBackground: [0.12, 0.09, 0.06] } },\n { name: \"Candle white\", values: { uColor: [0.95, 0.92, 0.85], uBackground: [0.08, 0.09, 0.14], uGloss: 1.1 } },\n { name: \"Heart\", values: { uMask: SAMPLE_IMAGES.heart, uColor: [0.86, 0.12, 0.28], uSize: 0.6 } },\n ],\n};\n\nexport const meltingText: ShaderEffect = {\n kind: \"shader\",\n id: \"melting-text\",\n name: \"Melting text\",\n description: \"Letters sagging and stretching downwards as long glossy drips run from their bottoms and droplets break off and fall.\",\n category: \"melt\",\n tags: [\"melt\", \"text\", \"title\", \"drip\", \"liquid\", \"glossy\", \"loop\"],\n loop: 8,\n transparent: true,\n source: glsl(\n `// Melting text: letters sag, drips run from their bottoms, droplets fall.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"MELT\")} label=\"Text\"\nuniform vec3 uColor; // @control color default=#FF3D6E label=\"Liquid\"\nuniform vec3 uHighlight; // @control color default=#FFFFFF label=\"Highlight\"\nuniform float uGloss; // @control min=0 max=1.5 default=0.9 label=\"Gloss\"\nuniform float uDrip; // @control min=0.2 max=1.5 default=1 label=\"Drip length\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Text size\"\nuniform vec3 uBackground; // @control color default=#120E1A label=\"Background\"\nuniform float uBackgroundAlpha; // @control min=0 max=1 default=0 label=\"Background opacity\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.7 label=\"Melt (when still)\"`,\n HASH,\n NOISE,\n FBM,\n MELT_CYCLE,\n SMIN,\n `const float RAISE = 0.14;\nfloat textH = 0.3;\nfloat textW = 1.0;\n\n// The text image's alpha at frame point p (text raised by RAISE to leave room for drips).\nfloat letters(vec2 p) {\n vec2 uv = (p - vec2(0.0, RAISE)) / vec2(textW, textH) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uText, uv).a;\n}\n\n// Distance to the liquid (about; negative inside) at frame point p, m of the way melted.\nfloat liquid(vec2 p, float m) {\n float top = RAISE + 0.29 * textH;\n float baseline = RAISE - 0.24 * textH;\n // Letters stretch down from their tops, some columns further than others.\n float stretch = 1.0 + m * (0.25 + 0.35 * fbm(vec2(p.x * 4.0, 1.0), 3));\n vec2 s = vec2(p.x + m * 0.008 * sin(p.y * 30.0), top - (top - p.y) / stretch);\n float r = 0.003 + 0.006 * m;\n float cover = letters(s) * 2.0;\n for (int i = 0; i < 4; i++) {\n float a = float(i) * 1.5708 + 0.785;\n cover += letters(s + vec2(cos(a), sin(a)) * r);\n }\n cover /= 6.0;\n float d = (0.5 - cover) * 0.02;\n // Drips from the bottoms of the letters, each with a droplet that breaks off now and then.\n float grow = smoothstep(0.0, 0.25, m);\n float cell = 0.13 * textH;\n float c = floor(p.x / cell);\n for (int k = -1; k <= 1; k++) {\n float ci = c + float(k);\n vec2 h = hash22(vec2(ci, 11.3));\n float xi = (ci + 0.25 + 0.5 * h.x) * cell;\n float colStretch = 1.0 + m * (0.25 + 0.35 * fbm(vec2(xi * 4.0, 1.0), 3));\n float root = top - (top - baseline) * colStretch;\n // Only where a letter stands on the line, and not every one.\n float on = step(0.5, letters(vec2(xi, baseline + 0.04 * textH))) * step(0.25, hash12(vec2(ci, 2.7)));\n if (on < 0.5) continue;\n float w = textH * (0.03 + 0.025 * h.y) * grow;\n float len = uDrip * pow(m, 1.3) * (0.06 + 0.3 * hash12(vec2(ci, 5.9)));\n float head = root - len;\n float along = clamp(p.y, head, root + 0.06 * textH);\n float rr = w * mix(1.0, 0.6, smoothstep(root, root - 0.08, p.y));\n rr = mix(rr, w * 1.25, smoothstep(head + 2.5 * w, head, p.y));\n d = smin(d, length(vec2(p.x - xi, p.y - along)) - rr, 0.01 * grow);\n // The droplet: swells at the tip, lets go and falls, every 2 s once it is well melted.\n float phase = fract(iTime * 0.5 + h.y);\n float fall = phase * phase * 1.4;\n float drop = w * 1.1 * smoothstep(0.35, 0.65, m) * step(0.5, hash12(vec2(ci, 8.1)));\n d = min(d, length(vec2(p.x - xi, p.y - (head - w * 1.8 - fall))) - drop * (1.0 - 0.3 * phase));\n }\n return d;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float frame = iResolution.x / iResolution.y;\n textH = min(uSize * 0.6, frame * uSize / aspect);\n textW = textH * aspect;\n float m = uAnimate ? meltCycle(1.0) : uProgress;\n float px = 1.0 / iResolution.y;\n\n float d = liquid(p, m);\n float cover = smoothstep(px, -px, d);\n vec4 col = vec4(uBackground, uBackgroundAlpha);\n if (d < 2.0 * px) {\n float eps = 0.0015;\n vec2 g = vec2(liquid(p + vec2(eps, 0.0), m) - d, liquid(p + vec2(0.0, eps), m) - d);\n g /= max(length(g), 1e-5);\n float thick = sqrt(clamp(-d / 0.012, 0.0, 1.0));\n vec3 n = normalize(vec3(g * (1.0 - thick) * 1.8, 0.35 + thick));\n vec3 l = normalize(vec3(-0.5, 0.7, 0.8));\n float diff = clamp(dot(n, l), 0.0, 1.0);\n float spec = pow(max(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0), 40.0);\n // Darker and richer where it runs thin, like a coloured syrup.\n vec3 body = mix(uColor * uColor * 0.8, uColor, thick) * (0.5 + 0.65 * diff);\n body += uHighlight * (spec * uGloss + pow(1.0 - n.z, 3.0) * 0.15 * uGloss);\n col = mix(col, vec4(body, 1.0), cover);\n }\n fragColor = vec4(col.rgb, col.a);\n}`,\n ),\n presets: [\n { name: \"Slime\", values: { uColor: [0.45, 0.9, 0.2], uHighlight: [0.9, 1, 0.8], uDrip: 1.3 } },\n { name: \"Chocolate\", values: { uText: textImage(\"SWEET\"), uColor: [0.42, 0.22, 0.12], uHighlight: [1, 0.9, 0.8], uBackground: [0.98, 0.93, 0.85], uBackgroundAlpha: 1 } },\n { name: \"Gold\", values: { uColor: [1, 0.76, 0.25], uHighlight: [1, 0.98, 0.85], uGloss: 1.3, uBackgroundAlpha: 1 } },\n ],\n};\n\nexport const liquify: ShaderEffect = {\n kind: \"shader\",\n id: \"liquify\",\n name: \"Liquify\",\n description: \"An image pushed and smeared like wet paint by a moving brush (or the pointer), the smears slowly relaxing back.\",\n category: \"melt\",\n tags: [\"melt\", \"image\", \"liquify\", \"smear\", \"paint\", \"interactive\", \"hover\"],\n source: glsl(\n `// Liquify: a brush pushes the picture around; its recent path leaves smears that relax over time.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uBrush; // @control min=0.05 max=0.5 default=0.17 label=\"Brush size\"\nuniform float uStrength; // @control min=0 max=2 default=0.8 label=\"Strength\"\nuniform float uRelax; // @control min=0.2 max=5 default=1.2 label=\"Relax\"\nuniform float uSpeed; // @control min=0 max=2 default=1 label=\"Brush speed\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// The brush at time t (frame units, height 1): a Lissajous path, or stirring round the pointer while it hovers.\nvec2 brush(float t) {\n float aspect = iResolution.x / iResolution.y;\n vec2 path = vec2(0.36 * aspect * sin(t * 0.9), 0.3 * sin(t * 1.37 + 0.6));\n vec2 pointer = (iPointer.xy - 0.5 * iResolution.xy) / iResolution.y;\n vec2 stir = pointer + 0.05 * vec2(cos(t * 4.0), sin(t * 4.0));\n return mix(path, stir, iPointer.z);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed * 1.4;\n float dt = 0.14;\n vec2 disp = vec2(0.0);\n float wet = 0.0;\n // Each of the brush's recent places pushes paint the way it was going and twists it a little, fading as it relaxes.\n for (int k = 0; k < 10; k++) {\n float tk = t - float(k) * dt;\n vec2 b = brush(tk);\n vec2 v = b - brush(tk - dt);\n vec2 d = p - disp - b;\n float f = exp(-dot(d, d) / (uBrush * uBrush));\n float fade = exp(-float(k) * dt * uRelax / max(uSpeed * 1.4, 0.05));\n vec2 twist = vec2(-d.y, d.x) * length(v) * 4.0;\n disp += (v * 1.3 + twist) * f * fade * uStrength;\n wet += f * fade;\n }\n vec2 uv = (p - disp) * vec2(iResolution.y / iResolution.x, 1.0) + 0.5;\n vec4 pic = pictureRGBA(uImage, uv);\n // Wet paint catches a little light along the smears.\n float sheen = clamp(dot(disp, normalize(vec2(-0.6, 0.8))) * 12.0, -1.0, 1.0);\n vec3 col = pic.rgb * (1.0 + 0.05 * sheen * min(wet, 1.0) * min(uStrength, 1.0));\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Finger paint\", values: { uBrush: 0.25, uStrength: 1.6, uRelax: 0.5 } },\n { name: \"Quick flick\", values: { uBrush: 0.1, uStrength: 0.8, uRelax: 3, uSpeed: 1.8 } },\n { name: \"Landscape\", values: { uImage: SAMPLE_IMAGES.landscape, uStrength: 1.2 } },\n ],\n};\n\nexport const daliClock: ShaderEffect = {\n kind: \"shader\",\n id: \"dali-clock\",\n name: \"Melting clock\",\n description: \"A pocket-watch face draped over a ledge like Dalí's soft clocks, its lower half hanging and stretching as the hands keep turning.\",\n category: \"melt\",\n tags: [\"melt\", \"clock\", \"surreal\", \"dali\", \"time\", \"desert\"],\n source: glsl(\n `// Melting clock: a clock face drooping over a ledge in a desert.\nuniform vec3 uSkyTop; // @control color default=#24467E label=\"Sky\"\nuniform vec3 uHorizon; // @control color default=#F2C48D label=\"Horizon\"\nuniform vec3 uSand; // @control color default=#B98B57 label=\"Sand\"\nuniform vec3 uLedge; // @control color default=#5E4434 label=\"Ledge\"\nuniform vec3 uFace; // @control color default=#F1E6CC label=\"Clock face\"\nuniform vec3 uCase; // @control color default=#C9A048 label=\"Clock case\"\nuniform float uSag; // @control min=0 max=1.5 default=1 label=\"Droop\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Clock speed\"`,\n HASH,\n NOISE,\n FBM,\n `const float LEDGE_Y = 0.0;\nconst float LEDGE_X = 0.42;\nconst float R = 0.24;\nconst vec2 CENTRE = vec2(0.14, -0.02);\n\n// Clock-face point (relative to CENTRE, unmelted) shown at frame point w; .z is how far it hangs, 0 on the ledge.\nvec3 unmelt(vec2 w) {\n float sag = uSag;\n if (w.y >= LEDGE_Y) {\n // Lying back on the ledge top: foreshortened.\n return vec3(w.x - CENTRE.x, LEDGE_Y + (w.y - LEDGE_Y) / 0.5 - CENTRE.y, 0.0);\n }\n // Hanging: material further down is stretched more, narrows, sways and ripples.\n float d = LEDGE_Y - w.y;\n float k = 2.4 * sag + 1e-3;\n float u = (-1.0 + sqrt(1.0 + 4.0 * k * d)) / (2.0 * k);\n float sway = (0.05 * sin(iTime * 0.9) + 0.02 * sin(iTime * 2.1)) * sag * u * u * 8.0;\n float x = w.x - sway - 0.012 * sag * sin(u * 25.0 + iTime);\n float narrow = 1.0 + 0.75 * sag * smoothstep(0.0, R * 1.2, u) * u / R;\n return vec3((x - CENTRE.x) * narrow, LEDGE_Y - u - CENTRE.y, u);\n}\n\n// The clock at face point q: rgb, coverage in a.\nvec4 clockFace(vec2 q, float aa) {\n float r = length(q);\n float ang = atan(q.x, q.y);\n // Winding crown at twelve.\n float crown = max(abs(q.x) - 0.025, abs(q.y - R - 0.025) - 0.022);\n float body = min(r - R, crown);\n float cover = smoothstep(aa, -aa, body);\n if (cover <= 0.0) return vec4(0.0);\n vec3 col = uFace * (1.0 - 0.18 * smoothstep(0.4 * R, R, r));\n // Hour ticks (long at the quarters) and minute ticks.\n float hourA = ang / 0.5236;\n float hourD = abs(hourA - floor(hourA + 0.5)) * 0.5236 * r;\n float quarter = step(mod(floor(hourA + 0.5), 3.0), 0.5);\n float hourTick = smoothstep(0.012 + 0.006 * quarter + aa, 0.012 + 0.006 * quarter - aa, hourD) * step(R * (0.68 - 0.08 * quarter), r) * step(r, R * 0.86);\n float minA = ang / 0.10472;\n float minD = abs(minA - floor(minA + 0.5)) * 0.10472 * r;\n float minTick = smoothstep(0.003 + aa, 0.003 - aa, minD) * step(R * 0.8, r) * step(r, R * 0.86);\n col = mix(col, vec3(0.12, 0.1, 0.09), max(hourTick, minTick));\n // Hands: the minute hand goes round in 12 s, the hour hand in 144 s, the second hand in 4 s.\n float t = iTime * uSpeed;\n for (int i = 0; i < 3; i++) {\n float a = i == 0 ? t * 0.5236 / 12.0 : i == 1 ? t * 0.5236 : t * 1.5708;\n float len = i == 0 ? 0.5 * R : i == 1 ? 0.75 * R : 0.8 * R;\n float width = i == 0 ? 0.012 : i == 1 ? 0.008 : 0.003;\n vec2 dir = vec2(sin(a), cos(a));\n float along = clamp(dot(q, dir), -0.04, len);\n float hd = length(q - dir * along) - width;\n vec3 ink = i == 2 ? vec3(0.7, 0.15, 0.1) : vec3(0.1, 0.09, 0.08);\n col = mix(col, ink, smoothstep(aa, -aa, hd));\n }\n col = mix(col, uCase * 0.7, smoothstep(aa, -aa, r - 0.014));\n // The case: a bevelled ring and the crown.\n float ringD = max(body, -(r - R * 0.9));\n float bevel = 0.75 + 0.5 * dot(normalize(q + 1e-5), normalize(vec2(-0.6, 0.8)));\n col = mix(col, uCase * bevel, smoothstep(aa, -aa, min(ringD, crown)));\n return vec4(col, cover);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 w = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aa = 1.5 / iResolution.y;\n // Desert: sky, far cliffs and sand.\n float horizon = -0.18;\n vec3 col = mix(uHorizon, uSkyTop, smoothstep(horizon, 0.5, w.y));\n float cliffs = horizon + 0.05 + 0.12 * fbm(vec2(w.x * 2.5 + 3.0, 0.0), 4) * smoothstep(-0.2, 0.9, w.x);\n col = mix(col, mix(uSand, uSkyTop, 0.35) * 0.9, smoothstep(aa, -aa, w.y - cliffs));\n col = mix(col, uSand * (0.75 + 0.5 * smoothstep(-0.5, horizon, w.y)), smoothstep(aa, -aa, w.y - horizon));\n // The ledge: a block with a lit top and a front face in shade.\n float top = LEDGE_Y + 0.15;\n float inBlock = step(w.x, LEDGE_X);\n col = mix(col, uLedge * 1.35, inBlock * smoothstep(aa, -aa, w.y - top) * smoothstep(-aa, aa, w.y - LEDGE_Y));\n col = mix(col, uLedge * (0.8 - 0.3 * smoothstep(LEDGE_Y, -0.5, w.y)), inBlock * smoothstep(aa, -aa, w.y - LEDGE_Y));\n col = mix(col, uLedge * 0.5, smoothstep(aa, -aa, abs(w.x - LEDGE_X) - 0.002) * step(w.y, top));\n // The clock's shadow on the ledge, then the clock.\n vec3 sq = unmelt(w + vec2(-0.03, 0.025));\n float shadow = smoothstep(0.01, -0.01, length(sq.xy) - R) * inBlock;\n col *= 1.0 - 0.4 * shadow * step(w.y, top);\n vec3 q = unmelt(w);\n float stretch = 1.0 + q.z * 6.0 * uSag;\n vec4 clock = clockFace(q.xy, aa * stretch);\n // Shade the fold at the ledge's edge and the far side of the hanging part.\n float fold = exp(-pow((w.y - LEDGE_Y) / 0.02, 2.0));\n clock.rgb *= (q.z > 0.0 ? 0.88 - 0.2 * smoothstep(0.0, 0.3, q.z) : 1.0) * (1.0 - 0.3 * fold);\n clock.rgb += 0.15 * fold * smoothstep(LEDGE_Y - 0.01, LEDGE_Y + 0.02, w.y);\n col = mix(col, clock.rgb, clock.a);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Dusk\", values: { uSkyTop: [0.17, 0.12, 0.35], uHorizon: [0.98, 0.55, 0.4], uSand: [0.55, 0.36, 0.3] } },\n { name: \"Very soft\", values: { uSag: 1.5, uSpeed: 0.4 } },\n ],\n};\n\nexport const lavaFlow: ShaderEffect = {\n kind: \"shader\",\n id: \"lava-flow\",\n name: \"Lava flow\",\n description: \"Glowing molten rock oozing downhill, dark cooling crust plates cracking apart over bright flowing lava.\",\n category: \"melt\",\n tags: [\"melt\", \"lava\", \"fire\", \"volcano\", \"glow\", \"background\"],\n source: glsl(\n `// Lava flow: crust plates (Voronoi cells) drifting downhill over brighter, faster lava.\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Flow speed\"\nuniform float uCrust; // @control min=0 max=1 default=0.6 label=\"Crust\"\nuniform float uScale; // @control min=2 max=12 default=5 label=\"Scale\"\nuniform vec3 uHot; // @control color default=#FFE27A label=\"Hottest\"\nuniform vec3 uLava; // @control color default=#FF4A0A label=\"Lava\"\nuniform vec3 uCrustColor; // @control color default=#1C1310 label=\"Crust colour\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Heat glow\"`,\n HASH,\n NOISE,\n FBM,\n `// Voronoi of slowly shifting points: x = distance to the nearest edge (about), y = the cell's id hash.\nvec2 plates(vec2 q, float t) {\n vec2 cell = floor(q);\n vec2 f = fract(q);\n float d1 = 8.0;\n float d2 = 8.0;\n vec2 nearest = vec2(0.0);\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 g = vec2(float(x), float(y));\n vec2 h = hash22(cell + g);\n vec2 o = g + 0.5 + 0.38 * sin(t * 0.6 + 6.2831 * h) - f;\n float d = dot(o, o);\n if (d < d1) { d2 = d1; d1 = d; nearest = cell + g; }\n else if (d < d2) d2 = d;\n }\n }\n return vec2(sqrt(d2) - sqrt(d1), hash12(nearest));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float t = iTime * uSpeed;\n // Downhill is down the screen; the warp makes it flow sluggishly round obstacles.\n vec2 flow = vec2(0.0, t * 0.35);\n vec2 warp = vec2(fbm(p * 2.0 + flow * 0.6, 3), fbm(p * 2.0 + flow * 0.6 + 7.3, 3)) - 0.5;\n vec2 q = p * uScale + warp * 1.6 + flow * uScale * 0.3;\n vec2 v = plates(q, t);\n // The molten lava under the crust flows faster and churns.\n float churn = fbm(p * uScale * 0.9 + vec2(0.0, t * 0.9) + warp * 3.0, 5);\n vec3 lava = mix(uLava * 0.45, uLava, smoothstep(0.3, 0.5, churn));\n lava = mix(lava, uHot, smoothstep(0.55, 0.8, churn));\n // Cracks open wider where there is less crust; some plates melt through entirely.\n float crack = mix(0.3, 0.02, uCrust) * (0.6 + 0.8 * fbm(q * 0.7 + 3.0, 2));\n float molten = step(0.55 + 0.45 * uCrust, v.y);\n float crust = smoothstep(crack, crack + 0.06, v.x) * (1.0 - molten);\n // Crust: rough, dark, glowing dull red near the cracks and in its pores.\n float rough = fbm(q * 4.0, 3);\n float heat = exp(-max(v.x - crack, 0.0) * 6.0);\n vec3 rock = uCrustColor * (0.5 + 1.2 * rough) + uLava * heat * 0.6 * uGlow;\n rock += uLava * 0.3 * uGlow * smoothstep(0.62, 0.8, rough) * (1.0 - smoothstep(0.0, 0.4, v.x));\n vec3 col = mix(lava, rock, crust);\n // The glow of the cracks lighting the air.\n col += uHot * 0.2 * uGlow * (1.0 - crust) * smoothstep(0.5, 0.9, churn);\n col = min(col, vec3(1.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Fresh flow\", values: { uCrust: 0.3, uSpeed: 0.9, uGlow: 1.4 } },\n { name: \"Cooling field\", values: { uCrust: 0.9, uSpeed: 0.2, uScale: 7 } },\n { name: \"Blue lava\", values: { uHot: [0.85, 0.98, 1], uLava: [0.15, 0.45, 1], uCrustColor: [0.05, 0.06, 0.1] } },\n ],\n};\n\n/** Melting: drips, heat haze, wax and liquefying shapes. */\nexport const meltShaders: ShaderEffect[] = [dripMelt, heatHaze, waxMelt, meltingText, liquify, daliClock, lavaFlow];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/*\n * Pyrotechnics. Sparks are light: each overlay sums its sparks into an HDR\n * colour and writes it with `glow`, whose alpha is the brightest channel, so\n * they brighten whatever is under them. Particles fly ballistically with air\n * drag (`ballistic`), so bursts slow down and droop the way real ones do.\n * Fireworks and explosions also read `iClicks` (xy pixels, z the `iTime` of\n * the click, w 1 for a click), the built-in the wrapper declares.\n */\n\n/**\n * `glow(c)`: light as a colour over whatever is behind it. Its alpha is its\n * brightest channel, so it brightens what is under it like a screen blend.\n */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/**\n * `over(acc, colour, alpha)`: paints a colour over a premultiplied\n * accumulator; `unpremultiply(acc)` turns it into straight colour and coverage.\n */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\n/**\n * `ballistic(v, k, g, t)`: how far a particle launched at velocity `v` has\n * moved after `t` seconds, slowed by air drag `k` and pulled down by gravity\n * `g`. `streak(p, tail, head, w)`: a spark's streak of width `w`, brightest\n * at its head.\n */\nconst PARTICLE = `\nvec2 ballistic(vec2 v, float k, float g, float t) {\n float e = (1.0 - exp(-k * t)) / k;\n return v * e - vec2(0.0, g / k * (t - e));\n}\nvec2 segment(vec2 p, vec2 a, vec2 b) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-9), 0.0, 1.0);\n return vec2(length(pa - ba * h), h);\n}\nfloat streak(vec2 p, vec2 tail, vec2 head, float w) {\n vec2 s = segment(p, tail, head);\n float along = mix(0.08, 1.0, s.y * s.y);\n return (exp(-s.x * s.x / (w * w)) + 0.12 * exp(-s.x / (w * 3.0))) * along;\n}`.trim();\n\nexport const fireworks: ShaderEffect = {\n kind: \"shader\",\n id: \"fireworks\",\n name: \"Fireworks\",\n description: \"Shells rising on faint trails and bursting into peonies, chrysanthemums, gold willows and rings that droop and twinkle out; clicks fire more.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"fireworks\", \"celebration\", \"festive\", \"night\", \"click\"],\n transparent: true,\n source: glsl(\n `// Fireworks: staggered shells rising and bursting into peony, chrysanthemum, willow and ring patterns.\nuniform vec3 uColorA; // @control color default=#FF4D6D label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#4DD9FF label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#B98CFF label=\"Colour C\"\nuniform vec3 uGold; // @control color default=#FFB347 label=\"Willow gold\"\nuniform float uRate; // @control min=0.2 max=1.6 default=0.8 label=\"Shells per second\"\nuniform float uSize; // @control min=0.3 max=2 default=1 label=\"Burst size\"\nuniform float uGravity; // @control min=0 max=2 default=1 label=\"Gravity\"\nuniform float uTrail; // @control min=0 max=2 default=1 label=\"Trail length\"\nuniform float uBrightness; // @control min=0.2 max=3 default=1 label=\"Brightness\"`,\n HASH,\n GLOW,\n PARTICLE,\n `vec3 pick(float h) {\n return h < 0.333 ? uColorA : (h < 0.667 ? uColorB : uColorC);\n}\n\n// One burst at c, tb seconds after it bursts. Types: 0 peony, 1 chrysanthemum, 2 willow, 3 ring.\nvec3 burst(vec2 p, vec2 c, float tb, float seed, float px) {\n vec4 h = vec4(hash22(vec2(seed, 1.7)), hash22(vec2(seed, 8.3)));\n int type = int(floor(h.x * 4.0));\n bool willow = type == 2;\n float life = willow ? 3.4 : (type == 1 ? 2.4 : 1.9);\n if (tb < 0.0 || tb > life) return vec3(0.0);\n float speed = (willow ? 0.5 : 0.75) * (0.85 + 0.3 * h.y) * uSize;\n float k = willow ? 2.2 : 3.2;\n float g = 0.32 * uGravity;\n float trail = (type == 0 ? 0.05 : (type == 1 ? 0.28 : (willow ? 0.7 : 0.06))) * uTrail;\n // Skip pixels nowhere near the burst: everything lies within reach of its falling centre.\n float e = (1.0 - exp(-k * tb)) / k;\n float drop = g / k * (tb - e);\n if (length(p - c + vec2(0.0, drop * 0.5)) > speed * e + drop * 0.6 + 0.06) return vec3(0.0);\n vec3 primary = willow ? uGold : pick(h.z);\n vec3 second = pick(fract(h.z + 0.4));\n bool twoTone = h.w > 0.5 && !willow;\n float fade = 1.0 - smoothstep(life * 0.5, life, tb);\n float cool = smoothstep(0.0, 0.3, tb);\n float w = max(0.0028, 1.1 * px);\n float tilt = 0.25 + 0.6 * h.w;\n vec2 ringAxis = vec2(cos(h.y * 6.28), sin(h.y * 6.28));\n vec3 col = vec3(0.0);\n for (int j = 0; j < 44; j++) {\n float fj = float(j);\n vec2 r = hash22(vec2(fj * 1.31 + 0.7, seed));\n float a = r.x * 6.28318;\n vec2 dir;\n if (type == 3) {\n // A ring: a circle of stars in a tilted plane.\n a = (fj + 0.3 * r.y) / 44.0 * 6.28318;\n vec2 u = vec2(cos(a), sin(a) * tilt);\n dir = vec2(u.x * ringAxis.x - u.y * ringAxis.y, u.x * ringAxis.y + u.y * ringAxis.x) * (0.95 + 0.05 * r.y);\n } else {\n // A sphere of stars seen side on: denser towards the middle.\n float z = 2.0 * r.y - 1.0;\n dir = vec2(cos(a), sin(a)) * sqrt(1.0 - z * z) * (0.9 + 0.1 * hash12(vec2(fj, seed + 3.0)));\n }\n vec2 v = dir * speed;\n vec2 head = c + ballistic(v, k, g, tb);\n vec2 tail = c + ballistic(v, k, g, max(tb - trail, 0.0));\n float s = streak(p, tail, head, w * (willow ? 0.9 : 1.0));\n if (s < 1e-3) continue;\n float twinkle = type == 0 ? 1.0 : 0.45 + 0.55 * step(0.35, hash12(vec2(fj + seed, floor(iTime * 22.0))));\n vec3 tint = twoTone && fj > 21.5 ? second : primary;\n col += mix(vec3(1.0, 0.95, 0.85), tint, cool) * s * twinkle;\n }\n // The burst's flash.\n col += mix(vec3(1.0), primary, 0.5) * 0.5 * exp(-length(p - c) * 18.0 / uSize) * exp(-tb * 9.0);\n return col * fade * 1.6;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec3 col = vec3(0.0);\n float cycle = max(6.0 / uRate, 3.9);\n for (int i = 0; i < 6; i++) {\n float fi = float(i);\n float tt = iTime + fi * cycle / 6.0 + 0.6;\n float n = floor(tt / cycle);\n float local = tt - n * cycle;\n float seed = hash12(vec2(fi * 7.1, n)) * 100.0;\n vec4 h = vec4(hash22(vec2(seed, 4.4)), hash22(vec2(seed, 9.9)));\n vec2 target = vec2((h.x - 0.5) * 0.75 * aspect, mix(0.02, 0.3, h.y));\n vec2 launch = vec2(target.x + (h.z - 0.5) * 0.12, -0.56);\n float rise = 0.9 + 0.35 * h.w;\n if (local < rise) {\n // The rising shell: a sputtering head on a short, faint trail.\n float u = local / rise;\n float u0 = max(u - 0.18 * uTrail, 0.0);\n vec2 head = mix(launch, target, vec2(u, 1.0 - (1.0 - u) * (1.0 - u)));\n vec2 tail = mix(launch, target, vec2(u0, 1.0 - (1.0 - u0) * (1.0 - u0)));\n float flicker = 0.6 + 0.4 * hash12(vec2(fi, floor(iTime * 30.0)));\n col += vec3(1.0, 0.72, 0.42) * streak(p, tail, head, max(0.0022, px)) * 0.7 * flicker;\n } else {\n col += burst(p, target, local - rise, seed, px);\n }\n }\n // A burst at each click.\n for (int i = 0; i < 8; i++) {\n vec4 click = iClicks[i];\n if (click.w < 0.5) continue;\n float tb = iTime - click.z;\n if (tb < 0.0 || tb > 3.5) continue;\n vec2 c = (click.xy - 0.5 * iResolution.xy) / iResolution.y;\n col += burst(p, c, tb, fract(click.z * 0.6180339) * 100.0 + float(i) * 0.01, px);\n }\n fragColor = glow(col * uBrightness);\n}`,\n ),\n presets: [\n { name: \"Gold finale\", values: { uColorA: [1, 0.8, 0.4], uColorB: [1, 0.95, 0.85], uColorC: [1, 0.6, 0.25], uRate: 1.6, uSize: 1.2 } },\n { name: \"Patriotic\", values: { uColorA: [1, 0.2, 0.25], uColorB: [1, 1, 1], uColorC: [0.25, 0.45, 1] } },\n { name: \"Slow and big\", values: { uRate: 0.35, uSize: 1.8, uGravity: 0.6, uTrail: 1.6 } },\n ],\n};\n\nexport const sparkler: ShaderEffect = {\n kind: \"shader\",\n id: \"sparkler\",\n name: \"Sparkler\",\n description: \"A burning sparkler throwing crackling, forking spark streaks from its glowing tip, which follows the pointer when it hovers.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"sparks\", \"celebration\", \"festive\", \"interactive\", \"hover\"],\n transparent: true,\n source: glsl(\n `// Sparkler: short-lived spark streaks that fork as they burn, round a glowing tip.\nuniform vec2 uPosition; // @control min=-1 max=1 default=0,0.15 label=\"Tip\"\nuniform vec3 uColor; // @control color default=#FFC46B label=\"Sparks\"\nuniform float uDensity; // @control min=0 max=1 default=0.8 label=\"Density\"\nuniform float uLength; // @control min=0.3 max=2 default=1 label=\"Spark length\"\nuniform float uIntensity; // @control min=0.2 max=3 default=1 label=\"Intensity\"\nuniform bool uStick; // @control default=true label=\"Show stick\"`,\n HASH,\n GLOW,\n OVER,\n PARTICLE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 home = uPosition * vec2(aspect, 1.0) * 0.5;\n vec2 pointer = (iPointer.xy - 0.5 * iResolution.xy) / iResolution.y;\n vec2 tip = mix(home, pointer, clamp(iPointer.z, 0.0, 1.0));\n vec4 acc = vec4(0.0);\n\n if (uStick) {\n // The wire, and the grey coating that is still to burn.\n vec2 down = normalize(vec2(0.28, -1.0));\n vec2 wire = segment(p, tip, tip + down * 0.6);\n acc = over(acc, vec3(0.32, 0.31, 0.3), (1.0 - smoothstep(0.0015, 0.0015 + px, wire.x)));\n vec2 coat = segment(p, tip + down * 0.01, tip + down * 0.3);\n acc = over(acc, vec3(0.42, 0.4, 0.37), (1.0 - smoothstep(0.0045, 0.0045 + px, coat.x)) * 0.95);\n }\n\n vec3 col = vec3(0.0);\n float w = max(0.0018, 0.9 * px);\n if (length(p - tip) < 0.42 * uLength + 0.05) {\n for (int j = 0; j < 48; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, 7.13));\n float period = 0.28 + 0.3 * h.y;\n float tt = iTime / period + h.x;\n float n = floor(tt);\n float u = tt - n;\n vec2 s = hash22(vec2(fj * 3.1, n));\n if (s.x > uDensity) continue;\n float age = u * period;\n float angle = s.y * 6.28318;\n float speed = mix(0.6, 1.6, hash12(vec2(n, fj + 3.3))) * uLength;\n vec2 v = vec2(cos(angle), sin(angle)) * speed;\n float k = 6.0;\n float g = 0.6;\n // Each spark burns out in a fork: a few short branches flash from where it ends.\n float forkAt = mix(0.45, 0.8, hash12(vec2(fj, n + 0.5)));\n float ta = min(u, forkAt) * period;\n vec2 head = tip + ballistic(v, k, g, ta);\n vec2 tail = tip + ballistic(v, k, g, max(ta - 0.045, 0.0));\n float alive = u < forkAt ? 1.0 : 0.0;\n col += mix(vec3(1.0, 0.95, 0.8), uColor, u) * streak(p, tail, head, w) * alive * 1.6;\n if (u >= forkAt) {\n float since = (u - forkAt) * period;\n float flash = exp(-since * 22.0);\n if (flash < 0.02) continue;\n float grow = 1.0 - exp(-since * 40.0);\n vec2 heading = normalize(v + vec2(1e-5));\n for (int b = 0; b < 3; b++) {\n float fb = float(b);\n float turn = (fb - 1.0) * 0.9 + (hash12(vec2(fj + fb, n)) - 0.5) * 0.8;\n vec2 bd = vec2(heading.x * cos(turn) - heading.y * sin(turn), heading.x * sin(turn) + heading.y * cos(turn));\n float len = (0.025 + 0.03 * hash12(vec2(fb, fj + n))) * uLength * grow;\n col += uColor * streak(p, head, head + bd * len, w * 0.8) * flash * 1.6;\n }\n }\n }\n }\n // The tip: a white-hot core in a flickering orange halo.\n float r = length(p - tip);\n float flicker = 0.8 + 0.2 * hash12(vec2(floor(iTime * 25.0), 1.0));\n col += vec3(1.0, 0.97, 0.9) * exp(-r * r / 0.00006) * 3.0;\n col += uColor * (0.006 / (r + 0.006)) * 0.5 * flicker;\n vec4 light = glow(col * uIntensity);\n acc = over(acc, light.rgb, light.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Cool white\", values: { uColor: [0.85, 0.92, 1], uDensity: 1, uLength: 1.2 } },\n { name: \"Just sparks\", values: { uStick: false, uDensity: 0.6 } },\n ],\n};\n\nexport const explosion: ShaderEffect = {\n kind: \"shader\",\n id: \"explosion\",\n name: \"Explosion\",\n description: \"A fireball cooling from white-hot to orange to rolling dark smoke, with a shockwave ring and flying debris; it loops and also goes off at each click.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"explosion\", \"fire\", \"smoke\", \"action\", \"click\"],\n transparent: true,\n loop: 3,\n source: glsl(\n `// Explosion: fireball, shockwave, debris and smoke, every few seconds and at each click.\nuniform vec2 uPosition; // @control min=-1 max=1 default=0,-0.1 label=\"Position\"\nuniform float uSize; // @control min=0.3 max=2 default=1 label=\"Size\"\nuniform float uPeriod; // @control min=2 max=8 default=3 label=\"Every (seconds)\"\nuniform vec3 uFire; // @control color default=#FF7A1A label=\"Fire\"\nuniform vec3 uSmoke; // @control color default=#4A413A label=\"Smoke\"\nuniform float uSmokeAmount; // @control min=0 max=1 default=0.85 label=\"Smoke\"\nuniform bool uAuto; // @control default=true label=\"Loop on its own\"`,\n HASH,\n NOISE,\n FBM,\n GLOW,\n OVER,\n PARTICLE,\n `// Fire colour for a temperature 0–1: dark red, orange, yellow, white.\nvec3 fireRamp(float t) {\n t = clamp(t, 0.0, 1.0);\n vec3 c = mix(uFire * 0.25, uFire, smoothstep(0.0, 0.4, t));\n c = mix(c, vec3(1.0, 0.85, 0.4), smoothstep(0.4, 0.75, t));\n return mix(c, vec3(1.0, 0.98, 0.9), smoothstep(0.75, 1.0, t));\n}\n\n// An explosion at c, t seconds after it goes off, painted over acc.\nvec4 explode(vec4 acc, vec2 p, vec2 c, float t, float seed, float scale, float px) {\n float end = min(uPeriod, 3.6);\n if (t < 0.0 || t > end) return acc;\n vec2 q = p - c;\n if (length(q) > scale * 1.6) return acc;\n float out_ = 1.0 - smoothstep(end * 0.6, end, t);\n vec3 col = vec3(0.0);\n\n // Smoke: a billowing cloud growing, rising and thinning, lit from inside while the fire burns.\n vec2 sq = (q - vec2(0.0, 0.12 * t * scale)) / scale;\n float sr = 0.2 + 0.2 * sqrt(t);\n float sn = fbm(sq * 5.0 + vec2(seed, -t * 0.6), 5);\n float sd = length(sq * vec2(0.9, 1.1)) / sr - (sn - 0.5) * 1.2;\n float smoke = (1.0 - smoothstep(0.25, 1.1, sd)) * smoothstep(0.05, 0.35, t) * out_ * uSmokeAmount;\n vec3 smokeCol = mix(uSmoke, uSmoke * 0.6 + uFire * 0.35, exp(-t * 1.6) * (1.0 - smoothstep(0.2, 0.8, sd)));\n acc = over(acc, smokeCol * (0.8 + 0.4 * sn), smoke * 0.92);\n\n // Fireball: expanding fast, then rising and cooling into the smoke.\n float R = scale * 0.32 * (1.0 - exp(-t * 7.0)) + 1e-3;\n vec2 fq = q - vec2(0.0, 0.05 * t * scale);\n float fn = fbm(fq / scale * 7.0 + vec2(-seed, -t * 1.4), 5);\n float fd = length(fq) / R + (fn - 0.5) * 0.9;\n float heat = exp(-t * 1.5) * out_;\n float temp = (1.0 - smoothstep(0.0, 1.05, fd)) * heat * (0.6 + 1.4 * fn * fn * 2.0);\n col += fireRamp(temp) * smoothstep(0.02, 0.3, temp) * 1.5;\n\n // Shockwave: a thin bright ring racing out, with a haze of brightened air behind it.\n float rr = length(q);\n float ring = scale * 1.25 * (1.0 - exp(-t * 2.6));\n float rw = max(0.004, 1.5 * px) + 0.01 * t;\n float wave = exp(-pow((rr - ring) / rw, 2.0)) * exp(-t * 3.0);\n float haze = smoothstep(ring - 0.12 * scale, ring, rr) * step(rr, ring) * exp(-t * 4.0);\n col += vec3(1.0, 0.92, 0.8) * (wave * 1.2 + haze * 0.18);\n\n // The flash.\n col += mix(vec3(1.0), uFire, 0.4) * exp(-rr * 4.0 / scale) * exp(-t * 10.0) * 1.5;\n\n // Debris: sparks flung out on ballistic arcs.\n float w = max(0.0025, px);\n for (int j = 0; j < 36; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, seed + 2.0));\n float life = 0.6 + 1.0 * hash12(vec2(seed, fj));\n if (t > life) continue;\n float a = h.x * 6.28318;\n vec2 v = vec2(cos(a), sin(a) * 0.8 + 0.25) * (0.8 + 1.4 * h.y) * scale;\n vec2 head = c + ballistic(v, 2.2, 1.1, t);\n vec2 tail = c + ballistic(v, 2.2, 1.1, max(t - 0.06, 0.0));\n float f = 1.0 - smoothstep(life * 0.4, life, t);\n col += mix(vec3(1.0, 0.9, 0.6), uFire, t / life) * streak(p, tail, head, w) * f * 1.5;\n }\n vec4 light = glow(col);\n return over(acc, light.rgb, light.a);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec4 acc = vec4(0.0);\n if (uAuto) acc = explode(acc, p, uPosition * vec2(aspect, 1.0) * 0.5, mod(iTime, uPeriod), 3.7, 0.65 * uSize, px);\n for (int i = 7; i >= 0; i--) {\n vec4 click = iClicks[i];\n if (click.w < 0.5) continue;\n vec2 c = (click.xy - 0.5 * iResolution.xy) / iResolution.y;\n acc = explode(acc, p, c, iTime - click.z, fract(click.z * 0.618) * 50.0, 0.38 * uSize, px);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Clicks only\", values: { uAuto: false } },\n { name: \"Blue plasma\", values: { uFire: [0.25, 0.55, 1], uSmoke: [0.1, 0.12, 0.2], uSmokeAmount: 0.4 } },\n { name: \"Big and slow\", values: { uSize: 1.6, uPeriod: 5, uSmokeAmount: 1 } },\n ],\n};\n\nexport const sparkFountain: ShaderEffect = {\n kind: \"shader\",\n id: \"spark-fountain\",\n name: \"Spark fountain\",\n description: \"A gerb spraying sparks up from its base in a column that arcs over and falls back, lighting the ground.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"sparks\", \"fountain\", \"celebration\", \"stage\"],\n transparent: true,\n source: glsl(\n `// Spark fountain: sparks sprayed up from a base, arcing back down under gravity.\nuniform vec2 uBase; // @control min=-1 max=1 default=0,-0.85 label=\"Base\"\nuniform vec3 uColor; // @control color default=#FFB547 label=\"Sparks\"\nuniform float uHeight; // @control min=0.3 max=2 default=1 label=\"Height\"\nuniform float uSpread; // @control min=0 max=1 default=0.3 label=\"Spread\"\nuniform float uDensity; // @control min=0 max=1 default=0.85 label=\"Density\"\nuniform float uIntensity; // @control min=0.2 max=3 default=1 label=\"Intensity\"`,\n HASH,\n GLOW,\n PARTICLE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 base = uBase * vec2(aspect, 1.0) * 0.5;\n vec3 col = vec3(0.0);\n float w = max(0.0022, px);\n float k = 1.4;\n float g = 1.5;\n for (int j = 0; j < 112; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, 2.31));\n float life = 1.0 + 0.8 * h.y;\n float tt = iTime / life + h.x;\n float n = floor(tt);\n float age = (tt - n) * life;\n vec3 s = vec3(hash22(vec2(fj * 1.7, n)), hash12(vec2(n, fj + 0.37)));\n if (s.z > uDensity) continue;\n float a = (s.x - 0.5) * 2.0 * uSpread * 1.2;\n vec2 v = vec2(sin(a), cos(a)) * mix(0.9, 1.35, s.y) * uHeight * 1.25;\n vec2 head = base + ballistic(v, k, g, age);\n vec2 tail = base + ballistic(v, k, g, max(age - 0.07, 0.0));\n // Sparks that fall back past the base are gone.\n if (head.y < base.y - 0.01) continue;\n float fade = 1.0 - smoothstep(0.5, 1.0, age / life);\n float twinkle = 0.6 + 0.4 * hash12(vec2(fj, floor(iTime * 24.0)));\n vec3 tint = mix(vec3(1.0, 0.96, 0.85), uColor, smoothstep(0.0, 0.5, age));\n col += tint * streak(p, tail, head, w) * fade * twinkle * 1.2;\n }\n // The gerb's mouth: a white-hot plume, and the glow it throws on the ground.\n vec2 q = p - base;\n float flicker = 0.85 + 0.15 * hash12(vec2(floor(iTime * 30.0), 4.0));\n col += vec3(1.0, 0.95, 0.85) * exp(-pow(q.x / 0.012, 2.0) - pow((q.y - 0.02) / 0.04, 2.0)) * 2.0 * flicker;\n col += uColor * (0.012 / (length(q) + 0.012)) * 0.6 * flicker;\n col += uColor * exp(-abs(q.y) * 45.0) * exp(-abs(q.x) * 5.0) * 0.4 * uHeight;\n fragColor = glow(col * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Silver\", values: { uColor: [0.86, 0.9, 1] } },\n { name: \"Wide fan\", values: { uSpread: 0.8, uHeight: 0.8 } },\n ],\n};\n\nexport const romanCandle: ShaderEffect = {\n kind: \"shader\",\n id: \"roman-candle\",\n name: \"Roman candle\",\n description: \"Balls of coloured fire popping up from a tube one after another, trailing comet tails and sputtering sparks.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"fireworks\", \"celebration\", \"festive\"],\n transparent: true,\n source: glsl(\n `// Roman candle: coloured stars shot up at intervals with comet tails and sputter.\nuniform vec2 uBase; // @control min=-1 max=1 default=0,-0.95 label=\"Base\"\nuniform float uAngle; // @control min=-0.6 max=0.6 default=0.08 label=\"Tilt\"\nuniform float uInterval; // @control min=0.3 max=3 default=0.8 label=\"Seconds between shots\"\nuniform float uHeight; // @control min=0.5 max=2 default=1.2 label=\"Height\"\nuniform vec3 uColorA; // @control color default=#FF3D7F label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#3DFF9E label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#3DB2FF label=\"Colour C\"`,\n HASH,\n GLOW,\n OVER,\n PARTICLE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 base = uBase * vec2(aspect, 1.0) * 0.5;\n vec2 dir = vec2(sin(uAngle), cos(uAngle));\n vec4 acc = vec4(0.0);\n\n // The tube.\n vec2 tube = segment(p, base, base - dir * 0.14);\n acc = over(acc, vec3(0.45, 0.1, 0.12), 1.0 - smoothstep(0.011, 0.011 + px, tube.x));\n\n vec3 col = vec3(0.0);\n float w = max(0.0025, px);\n float k = 0.7;\n float g = 1.0;\n float shot = floor(iTime / uInterval);\n for (int i = 0; i < 5; i++) {\n float n = shot - float(i);\n float age = iTime - n * uInterval;\n float life = 1.9;\n if (age > life || n < 0.0) continue;\n vec2 h = hash22(vec2(n, 5.5));\n vec3 tint = mod(n, 3.0) < 0.5 ? uColorA : (mod(n, 3.0) < 1.5 ? uColorB : uColorC);\n vec2 v = (dir + vec2((h.x - 0.5) * 0.08, 0.0)) * (0.95 + 0.1 * h.y) * uHeight * 1.45;\n vec2 ball = base + ballistic(v, k, g, age);\n if (length(p - ball) > 0.45) continue;\n float burn = 1.0 - smoothstep(life * 0.65, life, age);\n // The star, and its comet tail.\n float r = length(p - ball);\n col += mix(vec3(1.0), tint, 0.35) * exp(-r * r / (0.0003 * burn + 1e-6)) * 2.5 * burn;\n col += tint * (0.012 / (r + 0.012)) * 0.4 * burn;\n vec2 tail = base + ballistic(v, k, g, max(age - 0.22, 0.0));\n col += tint * streak(p, tail, ball, w * 2.6) * burn * 1.1;\n // Sputter: sparks shed by the star, drifting off and dropping.\n for (int j = 0; j < 8; j++) {\n float fj = float(j);\n vec2 s = hash22(vec2(fj + n * 13.0, 2.2));\n float te = s.x * age;\n float sa = age - te;\n if (sa > 0.35) continue;\n vec2 from = base + ballistic(v, k, g, te);\n float a = s.y * 6.28318;\n vec2 sv = vec2(cos(a), sin(a)) * 0.45;\n vec2 head = from + ballistic(sv, 4.0, 0.8, sa);\n vec2 stail = from + ballistic(sv, 4.0, 0.8, max(sa - 0.04, 0.0));\n col += mix(vec3(1.0, 0.85, 0.6), tint, 0.5) * streak(p, stail, head, w) * (1.0 - sa / 0.35) * burn * 1.5;\n }\n }\n // The muzzle: a flash at each shot, and a little sputter between.\n float since = iTime - shot * uInterval;\n float m = length(p - base);\n float flicker = 0.7 + 0.3 * hash12(vec2(floor(iTime * 28.0), 3.0));\n col += vec3(1.0, 0.8, 0.5) * (exp(-since * 14.0) * 2.0 + 0.25 * flicker) * exp(-m * m / 0.0004);\n vec4 light = glow(col);\n acc = over(acc, light.rgb, light.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Rapid fire\", values: { uInterval: 0.35, uHeight: 1 } },\n { name: \"Gold\", values: { uColorA: [1, 0.75, 0.3], uColorB: [1, 0.9, 0.6], uColorC: [1, 0.6, 0.2] } },\n ],\n};\n\nexport const fuseBurn: ShaderEffect = {\n kind: \"shader\",\n id: \"fuse-burn\",\n name: \"Fuse burn\",\n description: \"A lit fuse burning along an S-curve, its bright spitting spark leaving a charred, smoking cord behind, then a pop.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"fuse\", \"sparks\", \"countdown\", \"suspense\"],\n transparent: true,\n source: glsl(\n `// Fuse burn: a spitting spark running along a curved cord, charring it as it goes.\nuniform float uCurve; // @control min=-1 max=1 default=0.6 label=\"Curve\"\nuniform float uWaves; // @control min=0.5 max=3 default=1 label=\"Waves\"\nuniform float uDuration; // @control min=1 max=15 default=5 label=\"Burn time\"\nuniform vec3 uCord; // @control color default=#C9A46A label=\"Cord\"\nuniform vec3 uSpark; // @control color default=#FFB040 label=\"Spark\"\nuniform float uThickness; // @control min=0.5 max=3 default=1 label=\"Thickness\"`,\n HASH,\n GLOW,\n OVER,\n PARTICLE,\n `// The fuse at s (0–1): an S-curve across the frame.\nvec2 fusePoint(float s, float aspect) {\n return vec2(mix(-0.42, 0.42, s) * aspect, uCurve * 0.22 * sin(s * 6.28318 * uWaves));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n // Burn for most of the cycle, then a pop at the end and a moment's rest.\n float cycle = uDuration + 1.0;\n float t = mod(iTime, cycle);\n float burnt = clamp(t / uDuration, 0.0, 1.0);\n float after = t - uDuration;\n\n // Nearest point of the cord (a polyline), and how far along it that is.\n float best = 1e9;\n float along = 0.0;\n float sAt = 0.0;\n float length_ = 0.0;\n vec2 prev = fusePoint(0.0, aspect);\n for (int i = 1; i <= 48; i++) {\n vec2 next = fusePoint(float(i) / 48.0, aspect);\n vec2 sg = segment(p, prev, next);\n float seg = length(next - prev);\n if (sg.x < best) {\n best = sg.x;\n sAt = (float(i) - 1.0 + sg.y) / 48.0;\n along = length_ + seg * sg.y;\n }\n length_ += seg;\n prev = next;\n }\n vec4 acc = vec4(0.0);\n float width = 0.0045 * uThickness;\n float ahead = step(burnt, sAt);\n float wv = ahead > 0.5 ? width : width * 0.75;\n float cover = 1.0 - smoothstep(wv - px, wv, best);\n // A twisted cord ahead of the spark; a charred one, still glowing near it, behind.\n float twist = 0.85 + 0.15 * sin(along * 420.0 / uThickness + best / width * 2.5);\n float shade = 1.0 - 0.4 * pow(best / max(wv, 1e-4), 2.0);\n vec3 cord = uCord * twist * shade;\n vec3 charred = vec3(0.1, 0.085, 0.075) * shade;\n acc = over(acc, mix(charred, cord, ahead), cover);\n\n vec2 head = fusePoint(burnt, aspect);\n vec3 col = vec3(0.0);\n if (ahead < 0.5) {\n float behind = (burnt - sAt) * length_;\n float ember = exp(-behind / 0.03) + 0.5 * exp(-behind / 0.12) * step(0.8, hash12(vec2(floor(along * 300.0), floor(iTime * 8.0))));\n col += uSpark * vec3(1.0, 0.55, 0.3) * ember * cover * 1.5;\n }\n\n // Smoke curling up from the spark.\n vec2 q = p - head;\n if (q.y > 0.0 && after < 0.0) {\n float sway = q.x - 0.02 * sin(q.y * 25.0 - iTime * 3.0) - q.y * 0.15;\n float plume = exp(-sway * sway / (0.00004 + q.y * 0.0012)) * exp(-q.y * 7.0) * smoothstep(0.0, 0.03, q.y);\n acc = over(acc, vec3(0.6, 0.58, 0.56), plume * 0.22);\n }\n\n if (after < 0.0) {\n // The spark: a white-hot head spitting short sparks every which way.\n float r = length(q);\n float flicker = 0.75 + 0.25 * hash12(vec2(floor(iTime * 30.0), 2.0));\n col += vec3(1.0, 0.95, 0.85) * exp(-r * r / 0.00005) * 3.0 * flicker;\n col += uSpark * (0.007 / (r + 0.007)) * 0.6 * flicker;\n if (r < 0.2) {\n float w = max(0.0018, 0.9 * px);\n for (int j = 0; j < 28; j++) {\n float fj = float(j);\n vec2 h = hash22(vec2(fj, 6.6));\n float period = 0.22 + 0.25 * h.y;\n float tt = iTime / period + h.x;\n float n = floor(tt);\n float age = (tt - n) * period;\n vec2 s = hash22(vec2(fj * 2.3, n));\n float a = mix(-0.4, 3.54, s.x);\n vec2 v = vec2(cos(a), sin(a)) * mix(0.4, 1.1, s.y);\n vec2 sh = head + ballistic(v, 7.0, 0.8, age);\n vec2 st = head + ballistic(v, 7.0, 0.8, max(age - 0.035, 0.0));\n col += mix(vec3(1.0, 0.95, 0.8), uSpark, age / period) * streak(p, st, sh, w) * (1.0 - age / period) * 1.3;\n }\n }\n } else {\n // The pop: a flash at the end of the fuse.\n float r = length(q);\n col += mix(vec3(1.0), uSpark, 0.4) * exp(-r * 12.0) * exp(-after * 6.0) * 2.0;\n col += vec3(1.0, 0.9, 0.7) * exp(-pow((r - after * 0.6) / 0.006, 2.0)) * exp(-after * 5.0);\n }\n vec4 light = glow(col);\n acc = over(acc, light.rgb, light.a);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Straight\", values: { uCurve: 0 } },\n { name: \"Slow wiggle\", values: { uCurve: 0.9, uWaves: 2, uDuration: 10 } },\n ],\n};\n\nexport const smokeBomb: ShaderEffect = {\n kind: \"shader\",\n id: \"smoke-bomb\",\n name: \"Smoke bomb\",\n description: \"Billowing two-tone coloured smoke pouring from a point, rolling out along the ground and rising as it thins.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"overlay\", \"smoke\", \"colour\", \"photo\", \"moody\"],\n transparent: true,\n source: glsl(\n `// Smoke bomb: domain-warped fbm smoke pouring from a source, spreading and rising.\nuniform vec2 uSource; // @control min=-1 max=1 default=0,-0.8 label=\"Source\"\nuniform vec3 uColorA; // @control color default=#FF4FA3 label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#7C5CFF label=\"Colour B\"\nuniform float uDensity; // @control min=0 max=1 default=0.85 label=\"Density\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSpread; // @control min=0.2 max=2 default=1 label=\"Spread\"\nuniform float uHeight; // @control min=0.2 max=2 default=1 label=\"Rise\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 src = uSource * vec2(aspect, 1.0) * 0.5;\n vec2 q = p - src;\n float t = iTime * uSpeed;\n float h = max(q.y, 0.0);\n // Where smoke is: a plume widening as it rises, and a cloud rolling out along the ground.\n float width = 0.04 + h * 0.75 * uSpread;\n float plume = exp(-pow(q.x / width, 2.0)) * exp(-h / (0.55 * uHeight));\n float ground = exp(-pow(q.y / 0.07, 2.0)) * exp(-abs(q.x) / (0.3 * uSpread));\n float env = max(plume, ground * 0.8) * smoothstep(-0.06, 0.0, q.y);\n if (env < 0.01) {\n fragColor = vec4(0.0);\n return;\n }\n // Billows: fbm advected up and outwards, warped by itself.\n vec2 flow = vec2(q.x * (1.0 - 0.4 * clamp(h * 2.0, 0.0, 1.0)), q.y - t * 0.22);\n vec2 warp = vec2(fbm(flow * 3.0 + vec2(0.0, t * 0.05), 4), fbm(flow * 3.0 + vec2(5.2, 1.3 - t * 0.07), 4));\n float n = fbm(flow * 4.5 + warp * 1.6, 5);\n float n2 = fbm(flow * 4.5 + warp * 1.6 + vec2(0.0, 0.03), 5);\n float d = smoothstep(0.25, 0.75, n * (0.6 + 0.8 * env)) * env;\n float a = clamp(d * 1.6 * uDensity, 0.0, 1.0);\n // Colour drifts between the two; billow tops catch the light.\n float mixer = smoothstep(0.3, 0.7, fbm(flow * 1.5 + warp + vec2(9.0, 0.0), 3) + q.x * 0.6);\n vec3 col = mix(uColorA, uColorB, mixer);\n float light = clamp(0.75 + (n2 - n) * 10.0 + 0.25 * n, 0.4, 1.25);\n col = col * light + 0.06;\n // The canister's flare at the source.\n float r = length(q);\n col = mix(col, mix(vec3(1.0, 0.95, 0.9), uColorA, 0.4), exp(-r * r / 0.0004) * 0.8);\n a = max(a, exp(-r * r / 0.0002));\n fragColor = vec4(clamp(col, 0.0, 1.0), a);\n}`,\n ),\n presets: [\n { name: \"Orange and teal\", values: { uColorA: [1, 0.55, 0.15], uColorB: [0.1, 0.75, 0.75] } },\n { name: \"Gender reveal\", values: { uColorA: [1, 0.55, 0.75], uColorB: [0.45, 0.7, 1], uDensity: 1, uSpread: 1.4 } },\n { name: \"Wisp\", values: { uDensity: 0.45, uSpread: 0.5, uHeight: 1.6, uSpeed: 0.6 } },\n ],\n};\n\nexport const lightShow: ShaderEffect = {\n kind: \"shader\",\n id: \"light-show\",\n name: \"Light show\",\n description: \"A stadium pyro finale: flame jets and spark gerbs firing from the stage edge in sequences under sweeping beams, for title cards.\",\n category: \"pyrotechnics\",\n tags: [\"pyro\", \"background\", \"concert\", \"stage\", \"title\", \"hero\", \"fire\"],\n source: glsl(\n `// Light show: flame jets and gerbs along the bottom firing in chases, with sweeping beams.\nuniform vec3 uBackground; // @control color default=#06040C label=\"Background\"\nuniform vec3 uFlame; // @control color default=#FF6A1A label=\"Flames\"\nuniform vec3 uSparks; // @control color default=#FFE2A0 label=\"Gerbs\"\nuniform vec3 uBeam; // @control color default=#5E8BFF label=\"Beams\"\nuniform int uJets; // @control min=3 max=12 default=7 label=\"Jets\"\nuniform float uSpeed; // @control min=0.2 max=3 default=1 label=\"Speed\"\nuniform float uBeams; // @control min=0 max=2 default=1 label=\"Beam strength\"`,\n HASH,\n NOISE,\n FBM,\n `// A firing: up fast, holding, and dying away.\nfloat fire(float x, float len) {\n return smoothstep(0.0, 0.08, x) * (1.0 - smoothstep(len * 0.7, len, x));\n}\n\nvec3 flameRamp(float t) {\n vec3 c = mix(uFlame * 0.3, uFlame, smoothstep(0.0, 0.45, t));\n c = mix(c, vec3(1.0, 0.85, 0.45), smoothstep(0.45, 0.8, t));\n return mix(c, vec3(1.0, 0.97, 0.88), smoothstep(0.8, 1.0, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float aspect = iResolution.x / iResolution.y;\n vec2 p = vec2((uv.x - 0.5) * aspect, uv.y);\n float t = iTime * uSpeed;\n vec3 col = uBackground * (0.6 + 0.6 * (1.0 - uv.y));\n\n // Beams: searchlights from below the stage, sweeping through a little haze.\n float haze = 0.6 + 0.6 * fbm(p * 3.0 + vec2(t * 0.1, 0.0), 3);\n for (int i = 0; i < 4; i++) {\n float fi = float(i);\n vec2 o = vec2((fi / 3.0 - 0.5) * aspect * 0.9, -0.05);\n float aim = 0.55 * sin(t * (0.35 + 0.1 * fi) + fi * 1.9) + (fi < 1.5 ? 0.2 : -0.2);\n vec2 d = p - o;\n float ang = atan(d.x, d.y) - aim;\n float cone = exp(-ang * ang / 0.0025) * smoothstep(1.4, 0.0, length(d));\n vec3 tint = mix(uBeam, vec3(1.0), 0.25 * mod(fi, 2.0));\n col += tint * cone * haze * 0.35 * uBeams;\n }\n\n // The firing sequence, in 4-beat phrases: all at once, a chase, centre out, alternate.\n float phrase = floor(t / 4.0);\n float pattern = mod(phrase, 4.0);\n float local = mod(t, 4.0);\n float jets = float(uJets);\n float stageGlow = 0.0;\n for (int j = 0; j < 12; j++) {\n if (j >= uJets) break;\n float fj = float(j);\n float x01 = (fj + 0.5) / jets;\n float x = (x01 - 0.5) * aspect * 0.9;\n float f;\n if (pattern < 0.5) f = fire(local, 1.4);\n else if (pattern < 1.5) f = fire(local - x01 * 1.8, 0.9);\n else if (pattern < 2.5) f = fire(local - abs(x01 - 0.5) * 2.6, 1.0);\n else f = fire(mod(local + (mod(fj, 2.0) < 0.5 ? 0.0 : 1.0), 2.0), 0.8);\n // Gerbs fire while the flames rest.\n float gerb = (1.0 - f) * (pattern < 0.5 ? smoothstep(1.4, 1.8, local) * (1.0 - smoothstep(3.6, 4.0, local)) : (pattern > 2.5 ? 1.0 : 0.0));\n stageGlow += f + gerb * 0.3;\n vec2 q = p - vec2(x, 0.0);\n if (abs(q.x) > 0.25) continue;\n\n if (f > 0.01) {\n // A flame jet: a turbulent column, hottest at the nozzle.\n float H = 0.75 * f;\n float y = q.y / max(H, 1e-3);\n if (y < 1.3) {\n float turb = fbm(vec2(q.x * 10.0 + fj * 7.0, q.y * 5.0 - t * 6.0), 4);\n float wdt = 0.012 + q.y * 0.13;\n float dx = q.x + (turb - 0.5) * 0.12 * q.y * 2.0;\n float core = exp(-dx * dx / (wdt * wdt));\n float heat = core * (1.0 - smoothstep(0.2, 1.2, y + (turb - 0.5) * 0.5)) * f * 1.4;\n col += flameRamp(heat) * smoothstep(0.03, 0.3, heat) * 1.6;\n }\n }\n if (gerb > 0.01) {\n // A gerb: streaks of sparks shooting straight up.\n float gx = q.x * 90.0;\n float top = 0.55 + 0.1 * sin(t * 3.0 + fj);\n if (abs(gx) < 4.0) {\n float lane = floor(gx);\n float speedY = 3.0 + hash12(vec2(lane, fj)) * 2.0;\n float cy = q.y * 6.0 - t * speedY + hash12(vec2(fj, lane)) * 10.0;\n float cell = floor(cy);\n vec2 r = hash22(vec2(lane + fj * 9.0, cell));\n float lit = step(0.45, r.x) * (1.0 - abs(gx) / 4.0);\n float tailF = fract(cy);\n float spark = lit * smoothstep(0.45, 0.95, tailF) * (1.0 - smoothstep(0.95, 1.0, tailF));\n float across = exp(-pow((fract(gx) - 0.5 - (r.y - 0.5) * 0.6) * 5.0, 2.0));\n col += mix(uSparks, vec3(1.0), 0.3) * spark * across * gerb * (1.0 - smoothstep(top * 0.4, top, q.y)) * 1.4;\n }\n col += uSparks * exp(-abs(q.x) * 60.0) * (1.0 - smoothstep(0.0, top, q.y)) * gerb * 0.12;\n col += uSparks * exp(-length(q * vec2(1.0, 2.0)) * 40.0) * gerb;\n }\n }\n // The stage edge, lit by the fire.\n col += uFlame * stageGlow / jets * 0.6 * exp(-p.y * 6.0);\n col = 1.0 - exp(-max(col, 0.0) * 1.2);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Ice\", values: { uFlame: [0.3, 0.6, 1], uSparks: [0.85, 0.95, 1], uBeam: [0.7, 0.4, 1] } },\n { name: \"Full stage\", values: { uJets: 12, uSpeed: 1.4, uBeams: 1.6 } },\n ],\n};\n\n/** Pyrotechnics: fireworks, sparks, explosions and smoke. */\nexport const pyroShaders: ShaderEffect[] = [fireworks, sparkler, explosion, sparkFountain, romanCandle, fuseBurn, smokeBomb, lightShow];\n","import { glsl, HASH } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * Shaders keep no previous frames, so these re-derive the past: the picture\n * moves on a known path, and an echo, a lagging channel or a frozen moment\n * is the same picture sampled where the path had it at an earlier time.\n */\n\n/** `coverOf(tex)`: the share of a cover-fitted image visible across and up (the test card fits the frame). */\nconst COVER = `\nvec2 coverOf(sampler2D tex) {\n vec2 size = vec2(textureSize(tex, 0));\n float frameAspect = iResolution.x / iResolution.y;\n float imageAspect = size.x > 1.0 ? size.x / size.y : frameAspect;\n return frameAspect > imageAspect ? vec2(1.0, imageAspect / frameAspect) : vec2(frameAspect / imageAspect, 1.0);\n}`.trim();\n\n/**\n * `swayUv(tex, uv, t, amount)`: where screen point `uv` sees the cover-fitted\n * image at time `t` while it sways, drifts and breathes (strength `amount`).\n * The motion repeats every 8 s, so effects built only on it loop in 8 s\n * (needs {@link COVER}).\n */\nconst SWAY = `\nvec2 swayUv(sampler2D tex, vec2 uv, float t, float amount) {\n vec2 cover = coverOf(tex);\n float aspect = iResolution.x / iResolution.y;\n float w = 0.785398;\n float zoom = 1.3 + 0.18 * amount * sin(w * t + 0.7);\n float angle = 0.07 * amount * sin(2.0 * w * t + 0.4);\n vec2 pan = amount * vec2(0.1 * sin(w * t) + 0.04 * sin(3.0 * w * t + 1.3), 0.07 * sin(2.0 * w * t + 2.1));\n vec2 p = (uv - 0.5) * vec2(aspect, 1.0);\n float c = cos(angle);\n float s = sin(angle);\n p = mat2(c, s, -s, c) * p / vec2(aspect, 1.0);\n return 0.5 + (p / zoom + pan) * cover;\n}`.trim();\n\nconst LUMA = \"vec3(0.2126, 0.7152, 0.0722)\";\n\nexport const timeEcho: ShaderEffect = {\n kind: \"shader\",\n id: \"time-echo\",\n name: \"Time echo\",\n description: \"A swaying picture trailed by fading, tinted ghost echoes of where it just was.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"echo\", \"trail\", \"ghost\"],\n loop: 8,\n source: glsl(\n `// Time echo: the picture now, blended with copies of where its motion had it a moment ago.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform int uEchoes; // @control min=1 max=8 default=5 label=\"Echoes\"\nuniform float uSpacing; // @control min=0.02 max=0.6 default=0.18 label=\"Spacing (s)\"\nuniform float uDecay; // @control min=0.1 max=0.95 default=0.65 label=\"Decay\"\nuniform float uMotion; // @control min=0 max=2 default=1.2 label=\"Motion\"\nuniform vec3 uTint; // @control color default=#38BDF8 label=\"Echo tint\"\nuniform float uTintAmount; // @control min=0 max=1 default=0.5 label=\"Tint strength\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // Summed premultiplied, so clear parts of the picture do not darken the echoes.\n vec4 now = pictureRGBA(uImage, swayUv(uImage, uv, iTime, uMotion));\n vec4 sum = vec4(now.rgb * now.a, now.a);\n float total = 1.0;\n float weight = 1.0;\n for (int k = 1; k <= 8; k++) {\n if (k > uEchoes) break;\n weight *= uDecay;\n float age = float(k) / float(uEchoes);\n vec4 echo = pictureRGBA(uImage, swayUv(uImage, uv, iTime - float(k) * uSpacing, uMotion));\n // Older echoes take on more of the tint.\n echo.rgb = mix(echo.rgb, uTint * dot(echo.rgb, ${LUMA}) * 1.8, uTintAmount * age);\n sum += vec4(echo.rgb * echo.a, echo.a) * weight;\n total += weight;\n }\n fragColor = vec4(sum.rgb / max(sum.a, 1e-4), sum.a / total);\n}`,\n ),\n presets: [\n { name: \"Trails\", values: { uEchoes: 8, uSpacing: 0.06, uDecay: 0.85 } },\n { name: \"Strobe\", values: { uEchoes: 3, uSpacing: 0.45, uDecay: 0.55, uTintAmount: 0 } },\n { name: \"Neon ghosts\", values: { uTint: [1, 0.2, 0.8], uTintAmount: 1, uMotion: 1.6 } },\n ],\n};\n\nexport const chronoSplit: ShaderEffect = {\n kind: \"shader\",\n id: \"chrono-split\",\n name: \"Chrono split\",\n description: \"Red, green and blue each lagging a little further behind in time, so movement leaves colour fringes.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"rgb\", \"chromatic\", \"echo\"],\n loop: 8,\n source: glsl(\n `// Chrono split: each colour channel shows the moving picture at a different moment.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uLag; // @control min=0 max=0.6 default=0.15 label=\"Lag per channel (s)\"\nuniform float uMotion; // @control min=0 max=2 default=1.4 label=\"Motion\"\nuniform int uOrder; // @control min=0 max=1 default=0 label=\"Leading channel (0 red, 1 blue)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float lagR = uOrder == 0 ? 0.0 : 2.0 * uLag;\n float lagB = uOrder == 0 ? 2.0 * uLag : 0.0;\n vec4 r = pictureRGBA(uImage, swayUv(uImage, uv, iTime - lagR, uMotion));\n vec4 g = pictureRGBA(uImage, swayUv(uImage, uv, iTime - uLag, uMotion));\n vec4 b = pictureRGBA(uImage, swayUv(uImage, uv, iTime - lagB, uMotion));\n fragColor = vec4(r.r, g.g, b.b, max(max(r.a, g.a), b.a));\n}`,\n ),\n presets: [\n { name: \"Subtle\", values: { uLag: 0.05, uMotion: 1 } },\n { name: \"Prism\", values: { uLag: 0.35, uMotion: 2 } },\n ],\n};\n\nexport const timeSlice: ShaderEffect = {\n kind: \"shader\",\n id: \"time-slice\",\n name: \"Time slice\",\n description: \"Bands of a moving picture each showing a different moment, staggered like a time-displacement.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"slices\", \"stagger\", \"displacement\"],\n loop: 8,\n source: glsl(\n `// Time slice: every band shows the picture's motion delayed by a different amount.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uBands; // @control min=2 max=48 default=10 label=\"Bands\"\nuniform float uDelay; // @control min=0 max=0.6 default=0.12 label=\"Delay per band (s)\"\nuniform int uDirection; // @control min=0 max=1 default=0 label=\"Bands (0 horizontal, 1 vertical)\"\nuniform int uPattern; // @control min=0 max=2 default=0 label=\"Order (0 stepped, 1 from centre, 2 random)\"\nuniform float uMotion; // @control min=0 max=2 default=1.5 label=\"Motion\"\nuniform float uSeams; // @control min=0 max=1 default=0.4 label=\"Seams\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float across = uDirection == 0 ? uv.y : uv.x;\n float bands = float(uBands);\n float band = floor(across * bands);\n float order = band;\n if (uPattern == 1) order = abs(band - (bands - 1.0) * 0.5);\n if (uPattern == 2) order = floor(hash12(vec2(band, 4.7)) * bands);\n vec4 pic = pictureRGBA(uImage, swayUv(uImage, uv, iTime - order * uDelay, uMotion));\n vec3 col = pic.rgb;\n // A thin dark seam between bands, a pixel or two wide.\n float px = (uDirection == 0 ? iResolution.y : iResolution.x) / bands;\n float f = fract(across * bands);\n float edge = min(f, 1.0 - f) * px;\n col *= 1.0 - uSeams * (1.0 - smoothstep(0.0, 1.5, edge));\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Venetian\", values: { uBands: 24, uDelay: 0.05, uPattern: 1 } },\n { name: \"Shuffle\", values: { uBands: 14, uDelay: 0.2, uPattern: 2, uDirection: 1 } },\n ],\n};\n\n/** `digit7(p, d)`: distance to digit `d` drawn as a seven-segment glyph in a 1 × 2 cell (bottom-left origin). */\nconst DIGIT7 = `\nfloat segDist(vec2 p, vec2 a, vec2 b) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n return length(pa - ba * clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0));\n}\nfloat digit7(vec2 p, int d) {\n const int MASKS[10] = int[10](63, 6, 91, 79, 102, 109, 125, 7, 127, 111);\n int m = MASKS[clamp(d, 0, 9)];\n float dist = 1e5;\n if ((m & 1) != 0) dist = min(dist, segDist(p, vec2(0.0, 2.0), vec2(1.0, 2.0)));\n if ((m & 2) != 0) dist = min(dist, segDist(p, vec2(1.0, 2.0), vec2(1.0, 1.0)));\n if ((m & 4) != 0) dist = min(dist, segDist(p, vec2(1.0, 1.0), vec2(1.0, 0.0)));\n if ((m & 8) != 0) dist = min(dist, segDist(p, vec2(0.0, 0.0), vec2(1.0, 0.0)));\n if ((m & 16) != 0) dist = min(dist, segDist(p, vec2(0.0, 0.0), vec2(0.0, 1.0)));\n if ((m & 32) != 0) dist = min(dist, segDist(p, vec2(0.0, 1.0), vec2(0.0, 2.0)));\n if ((m & 64) != 0) dist = min(dist, segDist(p, vec2(0.0, 1.0), vec2(1.0, 1.0)));\n return dist;\n}`.trim();\n\nexport const rewind: ShaderEffect = {\n kind: \"shader\",\n id: \"rewind\",\n name: \"VHS rewind\",\n description: \"A tape playing, then rewinding fast with tracking noise, jittering lines, colour bleed and a ◀◀ display.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"vhs\", \"retro\", \"rewind\", \"tape\"],\n loop: 6,\n source: glsl(\n `// VHS rewind: 4 s of play, then 2 s rewinding at double speed back to the start.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uNoise; // @control min=0 max=1 default=0.6 label=\"Tracking noise\"\nuniform float uJitter; // @control min=0 max=1 default=0.5 label=\"Line jitter\"\nuniform float uBleed; // @control min=0 max=0.03 default=0.008 label=\"Chroma bleed\"\nuniform bool uOsd; // @control default=true label=\"On-screen display\"\nuniform vec3 uOsdColor; // @control color default=#F8FAFC label=\"Display colour\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n COVER,\n SWAY,\n DIGIT7,\n `// Ink of the timecode \"M:SS:FF\" at q (units of half a digit's height).\nfloat timecode(vec2 q, float secs) {\n if (q.y < -0.3 || q.y > 2.3 || q.x < -0.3) return 0.0;\n int slot = int(floor(q.x / 1.6));\n vec2 c = vec2(q.x - float(slot) * 1.6, q.y);\n int s = int(floor(mod(secs, 60.0)));\n int f = int(floor(fract(secs) * 30.0));\n float dist = 1e5;\n if (slot == 0) dist = digit7(c, int(floor(secs / 60.0)));\n else if (slot == 1 || slot == 4) dist = min(length(c - vec2(0.5, 0.6)), length(c - vec2(0.5, 1.4)));\n else if (slot == 2) dist = digit7(c, s / 10);\n else if (slot == 3) dist = digit7(c, s - (s / 10) * 10);\n else if (slot == 5) dist = digit7(c, f / 10);\n else if (slot == 6) dist = digit7(c, f - (f / 10) * 10);\n return smoothstep(0.2, 0.12, dist);\n}\n\n// Ink of a right-pointing triangle 1 wide, 1 high, its back edge at q.x = 0.\nfloat playIcon(vec2 q) {\n float inside = min(q.x, 0.5 * (1.0 - q.x) - abs(q.y - 0.5));\n return smoothstep(0.0, 0.04, inside);\n}\n\n// The display's ink at fragCoord: a play arrow for a moment after play starts, rewind arrows while rewinding, and the timecode.\nfloat osd(vec2 fragCoord, float phase, float tau) {\n float unit = iResolution.y * 0.045;\n vec2 q = (fragCoord - vec2(iResolution.x - unit * 3.4, iResolution.y - unit * 2.4)) / unit;\n float ink = 0.0;\n if (phase >= 4.0) ink = max(playIcon(vec2(1.0 - q.x, q.y)), playIcon(vec2(2.0 - q.x, q.y)));\n else if (phase < 1.5) ink = playIcon(q);\n vec2 t = (fragCoord - vec2(iResolution.x - unit * 6.5, unit * 1.0)) / (unit * 0.5);\n return max(ink, timecode(t, tau));\n}`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float phase = mod(iTime, 6.0);\n // Tape time: forwards for 4 s, then back to the start in 2.\n float tau = phase < 4.0 ? phase : 4.0 - (phase - 4.0) * 2.0;\n float rw = smoothstep(3.9, 4.1, phase) * (1.0 - smoothstep(5.85, 6.0, phase));\n float shake = 0.15 + rw;\n float frame = mod(floor(iTime * 30.0), 180.0);\n // Line jitter: each scanline nudged sideways, stronger near the bottom head-switch band.\n float line = floor(uv.y * 240.0);\n float jitter = (hash12(vec2(line, frame)) - 0.5) * 0.012 * uJitter * shake;\n jitter += (1.0 - smoothstep(0.0, 0.05, uv.y)) * 0.03 * uJitter * (hash12(vec2(frame, 2.0)) - 0.2);\n // Tracking bars rolling down the picture while rewinding.\n float roll = fract(uv.y * 1.7 + iTime * 1.5);\n float bar = smoothstep(0.0, 0.02, roll) * smoothstep(0.1, 0.04, roll) * uNoise * rw;\n vec2 st = uv + vec2(jitter + bar * 0.06, 0.0);\n // While rewinding the picture jumps up and down a touch.\n st.y += rw * 0.01 * (hash12(vec2(frame, 5.0)) - 0.5);\n float bleed = uBleed * (1.0 + 2.0 * rw);\n float t = tau * 1.5;\n vec4 r = pictureRGBA(uImage, swayUv(uImage, st + vec2(bleed, 0.0), t, 1.4));\n vec4 g = pictureRGBA(uImage, swayUv(uImage, st, t, 1.4));\n vec4 b = pictureRGBA(uImage, swayUv(uImage, st - vec2(bleed, 0.0), t, 1.4));\n vec3 col = vec3(r.r, g.g, b.b);\n float alpha = max(max(r.a, g.a), b.a);\n // Static in the bars, a few white dropouts, and a washed-out tape look.\n float grain = hash12(fragCoord + frame * 17.0);\n col = mix(col, vec3(grain), bar * 0.75);\n col += step(0.9985 - 0.002 * rw * uNoise, hash12(vec2(floor(fragCoord.x / 6.0), line + frame * 31.0))) * uNoise;\n float grey = dot(col, ${LUMA});\n col = mix(vec3(grey), col, 0.85 - 0.25 * rw) * vec3(1.03, 1.0, 0.95);\n col = mix(col, vec3(0.08), (1.0 - smoothstep(0.0, 0.02, uv.y)) * rw);\n col *= 0.94 + 0.06 * sin(fragCoord.y * 3.14159);\n vec2 v = uv - 0.5;\n col *= 1.0 - 0.35 * dot(v, v);\n if (uOsd) {\n float shadow = osd(fragCoord + vec2(-2.0, 2.0), phase, tau);\n float text = osd(fragCoord, phase, tau);\n col = mix(col, vec3(0.0), shadow * 0.5);\n col = mix(col, uOsdColor, text);\n alpha = max(alpha, max(shadow * 0.5, text));\n }\n fragColor = vec4(clamp(col, 0.0, 1.0), alpha);\n}`,\n ),\n presets: [\n { name: \"Worn tape\", values: { uNoise: 1, uJitter: 0.9, uBleed: 0.018 } },\n { name: \"Clean deck\", values: { uNoise: 0.25, uJitter: 0.15, uBleed: 0.003 } },\n { name: \"Green OSD\", values: { uOsdColor: [0.4, 1, 0.5] } },\n ],\n};\n\nexport const bulletTime: ShaderEffect = {\n kind: \"shader\",\n id: \"bullet-time\",\n name: \"Bullet time\",\n description: \"A shockwave sweeping out from the centre or a click, freezing the picture grey and zoomed behind it while the rest moves on.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"freeze\", \"shockwave\", \"click\", \"cinematic\"],\n loop: 8,\n source: glsl(\n `// Bullet time: every 4 s (or on a click) a wave freezes the picture behind it, then lets go.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uSpeed; // @control min=0.2 max=3 default=1.2 label=\"Wave speed\"\nuniform float uHold; // @control min=0.5 max=3 default=2.2 label=\"Freeze (s)\"\nuniform float uDesaturate; // @control min=0 max=1 default=0.85 label=\"Desaturate\"\nuniform float uZoom; // @control min=0 max=0.25 default=0.08 label=\"Zoom\"\nuniform vec3 uRing; // @control color default=#A5F3FC label=\"Shockwave\"\nuniform float uMotion; // @control min=0 max=2 default=1.4 label=\"Motion\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // The demo freezes every 4 s from the centre; a click freezes from where it landed.\n vec2 centre = 0.5 * iResolution.xy;\n float since = mod(iTime, 4.0);\n if (iClicks[0].w > 0.5) {\n centre = iClicks[0].xy;\n since = iTime - iClicks[0].z;\n }\n float start = iTime - since;\n float radius = since * uSpeed * iResolution.y;\n vec2 d = fragCoord - centre;\n float dist = length(d);\n float release = smoothstep(uHold, uHold + 0.6, since);\n float inside = smoothstep(radius, radius - 0.02 * iResolution.y, dist) * (1.0 - release);\n // The wavefront bends the picture outwards as it passes.\n float front = (dist - radius) / (0.045 * iResolution.y);\n float ring = exp(-front * front) * (1.0 - release);\n vec2 warp = d / max(dist, 1.0) * ring * 0.018;\n vec4 live = pictureRGBA(uImage, swayUv(uImage, uv - warp, iTime, uMotion));\n // Behind the wave: the moment the freeze began, zooming in towards the centre the longer it is held.\n vec2 c = centre / iResolution.xy;\n float zoom = 1.0 + uZoom * smoothstep(0.0, 1.0, since / max(uHold, 0.1));\n vec4 frozen = pictureRGBA(uImage, swayUv(uImage, c + (uv - warp - c) / zoom, start, uMotion));\n float grey = dot(frozen.rgb, ${LUMA});\n frozen.rgb = mix(frozen.rgb, vec3(grey) * vec3(0.9, 0.98, 1.1), uDesaturate);\n frozen.rgb *= 1.0 + 0.025 * sin(dist / iResolution.y * 60.0 - since * 4.0) * inside;\n vec4 pic = mix(live, frozen, inside);\n // The ring is light added over the picture, so it also shows where the picture is clear.\n float alpha = max(pic.a, clamp(ring * 0.7, 0.0, 1.0));\n fragColor = vec4((pic.rgb * pic.a + uRing * ring * 0.7) / max(alpha, 1e-4), alpha);\n}`,\n ),\n presets: [\n { name: \"Slow wave\", values: { uSpeed: 0.5, uHold: 2.8 } },\n { name: \"Snap\", values: { uSpeed: 2.5, uHold: 1.2, uZoom: 0.15, uRing: [1, 1, 1] } },\n ],\n};\n\nexport const timeTunnel: ShaderEffect = {\n kind: \"shader\",\n id: \"time-tunnel\",\n name: \"Time tunnel\",\n description: \"A picture wrapped round a spiralling tunnel rushing at the viewer, with light streaks and a blazing core.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"tunnel\", \"vortex\", \"sci-fi\", \"warp\"],\n loop: 8,\n source: glsl(\n `// Time tunnel: the picture mapped onto a twisting tube by angle and depth.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uTwist; // @control min=0 max=4 default=1.2 label=\"Twist\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform vec3 uColor; // @control color default=#3B82F6 label=\"Tunnel colour\"\nuniform float uTint; // @control min=0 max=1 default=0.55 label=\"Colour strength\"\nuniform vec3 uCore; // @control color default=#F0F9FF label=\"Core\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n // The far end wanders a little.\n p += 0.05 * vec2(sin(iTime * 0.785398), cos(iTime * 1.570796));\n float r = max(length(p), 1e-3);\n float a = atan(p.y, p.x);\n float z = 0.3 / r;\n // Round the tube (seamless: twice round the mirrored image), twisting with depth; along it, rushing closer.\n float u = a / 6.28318 + uTwist * 0.15 * z + iTime * 0.125;\n float v = z * 0.5 + iTime * uSpeed;\n vec4 pic = pictureRGBA(uImage, vec2(u * 2.0, v));\n vec3 img = pic.rgb;\n float l = dot(img, vec3(0.2126, 0.7152, 0.0722));\n vec3 col = mix(img, uColor * l * 2.2, uTint);\n // Rings where the tube's sections meet.\n col *= 0.85 + 0.15 * smoothstep(0.0, 0.08, abs(fract(v * 2.0) - 0.5));\n // Light streaks flying past in some angular lanes.\n float lane = floor(fract(u) * 64.0);\n float h = hash12(vec2(lane, 3.0));\n float dash = smoothstep(0.85, 1.0, fract(z * 0.25 + iTime * uSpeed * 2.0 + h * 7.0));\n // Thin in screen space at any distance from the core.\n float across = abs(fract(u * 64.0) - 0.5) / 64.0 * 6.28318 * r;\n float thin = 1.0 - smoothstep(0.0015, 0.005, across);\n float streak = dash * step(0.75, h) * thin * smoothstep(0.05, 0.25, r);\n col += mix(uCore, uColor, 0.4) * streak;\n // Depth haze into the glowing core; the near rim darkens.\n float haze = 1.0 - smoothstep(0.0, 0.2, r);\n col = mix(col, uCore, haze);\n col += uCore * 0.002 / (r * r + 0.01);\n col *= 1.0 - 0.45 * smoothstep(0.5, 0.95, r);\n fragColor = vec4(clamp(col, 0.0, 1.0), clamp(max(pic.a, max(haze, streak)), 0.0, 1.0));\n}`,\n ),\n presets: [\n { name: \"Vortex\", values: { uTwist: 3, uSpeed: 1, uColor: [0.55, 0.3, 1] } },\n { name: \"Ember\", values: { uColor: [1, 0.45, 0.1], uCore: [1, 0.95, 0.8], uTint: 0.75 } },\n { name: \"True colour\", values: { uTint: 0, uTwist: 0.6 } },\n ],\n};\n\nexport const speedRamp: ShaderEffect = {\n kind: \"shader\",\n id: \"speed-ramp\",\n name: \"Speed ramp\",\n description: \"A panning picture lurching from a crawl to a blur and back, motion-blurred in proportion to its speed.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"speed\", \"motion blur\", \"cinematic\"],\n loop: 4,\n source: glsl(\n `// Speed ramp: a pan whose speed swings from almost still to nearly double, with matching blur.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uRamp; // @control min=0 max=0.95 default=0.9 label=\"Ramp strength\"\nuniform float uBlur; // @control min=0 max=0.25 default=0.1 label=\"Motion blur (shutter s)\"\nuniform float uPan; // @control min=0.1 max=1 default=0.5 label=\"Pan speed\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 cover = coverOf(uImage);\n // Speed 1 + ramp * cos(w t) over a 4 s cycle; tau is how far the pan has got.\n float w = 1.570796;\n float speed = 1.0 + uRamp * cos(w * iTime);\n float tau = iTime + uRamp * sin(w * iTime) / w;\n // A little push in as it speeds up.\n float zoom = 1.15 + 0.06 * (speed - 1.0);\n vec2 base = 0.5 + (uv - 0.5) * cover / zoom + vec2(uPan * tau, 0.02 * sin(w * 2.0 * tau));\n // Blur along the pan, as long as the picture moves while the shutter is open (16 taps at most).\n float len = min(uPan * speed * uBlur, 0.25);\n // Summed premultiplied, so clear parts of the picture do not darken the blur.\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 16; i++) {\n float k = float(i) / 15.0 - 0.5;\n vec4 c = pictureRGBA(uImage, base - vec2(len * k, 0.0));\n sum += vec4(c.rgb * c.a, c.a);\n }\n vec3 col = sum.rgb / max(sum.a, 1e-4);\n vec2 v = uv - 0.5;\n col *= 1.0 - (0.2 + 0.25 * max(speed - 1.0, 0.0)) * dot(v, v) * 2.0;\n fragColor = vec4(col, sum.a / 16.0);\n}`,\n ),\n presets: [\n { name: \"Gentle\", values: { uRamp: 0.5, uBlur: 0.05 } },\n { name: \"Whip\", values: { uRamp: 0.95, uBlur: 0.25, uPan: 1 } },\n ],\n};\n\nexport const stutterFreeze: ShaderEffect = {\n kind: \"shader\",\n id: \"stutter-freeze\",\n name: \"Stutter freeze\",\n description: \"A moving picture that catches in irregular bursts, holding or stuttering frames with a flash on each freeze.\",\n category: \"timewarp\",\n tags: [\"time\", \"image\", \"freeze\", \"stutter\", \"glitch\"],\n source: glsl(\n `// Stutter freeze: some moments end in a hold (or a skipping stutter) before cutting back to live.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uRate; // @control min=0.2 max=4 default=1 label=\"Bursts per second\"\nuniform float uHold; // @control min=0 max=1 default=0.55 label=\"Hold length\"\nuniform float uFlash; // @control min=0 max=1 default=0.6 label=\"Flash\"\nuniform float uMotion; // @control min=0 max=2 default=1.6 label=\"Motion\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n COVER,\n SWAY,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float slot = floor(iTime * uRate);\n float f = fract(iTime * uRate);\n // Most moments end in a hold of random length.\n float len = uHold * mix(0.35, 1.0, hash12(vec2(slot, 3.3)));\n float startF = 1.0 - len;\n bool frozen = hash12(vec2(slot, 7.1)) > 0.25 && len > 0.001 && f >= startF;\n float freezeAt = (slot + startF) / uRate;\n float since = iTime - freezeAt;\n float t = iTime;\n float kick = 0.0;\n if (frozen) {\n // Some holds stutter, skipping back and forth between nearby frames.\n float stutter = step(0.55, hash12(vec2(slot, 9.7)));\n float k = floor(since * 12.0);\n t = freezeAt - stutter * mod(k, 3.0) * 0.06;\n kick = exp(-since * 10.0);\n }\n vec2 st = 0.5 + (uv - 0.5) / (1.0 + 0.04 * kick);\n vec4 pic = pictureRGBA(uImage, swayUv(uImage, st, t * 2.0, uMotion));\n vec3 col = pic.rgb;\n if (frozen) {\n col = mix(col, vec3(dot(col, ${LUMA})), 0.25);\n col = (col - 0.5) * 1.1 + 0.5;\n }\n col = mix(col, vec3(1.0), kick * uFlash * 0.85);\n fragColor = vec4(clamp(col, 0.0, 1.0), max(pic.a, kick * uFlash * 0.85));\n}`,\n ),\n presets: [\n { name: \"Nervous\", values: { uRate: 3, uHold: 0.4 } },\n { name: \"Long holds\", values: { uRate: 0.5, uHold: 0.8, uFlash: 0.3 } },\n ],\n};\n\n/** Time warps: echoes, rewinds, freezes and tunnels. */\nexport const timewarpShaders: ShaderEffect[] = [timeEcho, chronoSplit, timeSlice, rewind, bulletTime, timeTunnel, speedRamp, stutterFreeze];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/** The two-image controls every effect here starts with; progress runs 0 → 1 → 0 over 4 s when animated. */\nconst pair = (from: string, to: string) => `uniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${from} label=\"From image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${to} label=\"To image\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"`;\n\n/** `progress()`, and `cover(tex, uv)` / `coverRGBA(tex, uv)`: an image cover-fitted to the frame (needs {@link PICTURE}). */\nconst COMMON = `\nfloat progress() {\n return uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n}\n\n// The share of an image visible across and up when it covers the frame (the test card fits it).\nvec2 coverScale(sampler2D tex) {\n vec2 size = vec2(textureSize(tex, 0));\n float frameAspect = iResolution.x / iResolution.y;\n float imageAspect = size.x > 1.0 ? size.x / size.y : frameAspect;\n return frameAspect > imageAspect ? vec2(1.0, imageAspect / frameAspect) : vec2(frameAspect / imageAspect, 1.0);\n}\n\nvec4 coverRGBA(sampler2D tex, vec2 uv) {\n return pictureRGBA(tex, 0.5 + (uv - 0.5) * coverScale(tex));\n}\n\nvec3 cover(sampler2D tex, vec2 uv) {\n return coverRGBA(tex, uv).rgb;\n}\n\nfloat luma(vec3 c) {\n return dot(c, vec3(0.2126, 0.7152, 0.0722));\n}`.trim();\n\nexport const featureMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"feature-morph\",\n name: \"Feature morph\",\n description: \"The classic face morph: two pictures warp so five matching points (eyes, mouth, chin, hairline) meet while they cross-fade.\",\n category: \"morph\",\n tags: [\"morph\", \"face\", \"warp\", \"image\", \"transition\"],\n loop: 4,\n source: glsl(\n `// Feature morph: both images warp towards in-between positions of five matching points while they cross-fade.\n${pair(SAMPLE_IMAGES.portrait, SAMPLE_IMAGES.portrait2)}\nuniform vec2 uFromA; // @control min=0 max=1 default=0.461,0.583 label=\"From: left eye\"\nuniform vec2 uFromB; // @control min=0 max=1 default=0.539,0.583 label=\"From: right eye\"\nuniform vec2 uFromC; // @control min=0 max=1 default=0.5,0.472 label=\"From: mouth\"\nuniform vec2 uFromD; // @control min=0 max=1 default=0.5,0.389 label=\"From: chin\"\nuniform vec2 uFromE; // @control min=0 max=1 default=0.5,0.778 label=\"From: hairline\"\nuniform vec2 uToA; // @control min=0 max=1 default=0.619,0.514 label=\"To: left eye\"\nuniform vec2 uToB; // @control min=0 max=1 default=0.725,0.514 label=\"To: right eye\"\nuniform vec2 uToC; // @control min=0 max=1 default=0.672,0.364 label=\"To: mouth\"\nuniform vec2 uToD; // @control min=0 max=1 default=0.672,0.25 label=\"To: chin\"\nuniform vec2 uToE; // @control min=0 max=1 default=0.672,0.778 label=\"To: hairline\"\nuniform bool uShowPoints; // @control default=false label=\"Show points\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COMMON,\n `// Points are given in image uv; the warp works in frame space (height 1, x scaled by the aspect).\nvec2 toFrame(vec2 imageUv, vec2 scale) {\n return (0.5 + (imageUv - 0.5) / scale) * vec2(iResolution.x / iResolution.y, 1.0);\n}\n\nvec2 toImage(vec2 q, vec2 scale) {\n return 0.5 + (q / vec2(iResolution.x / iResolution.y, 1.0) - 0.5) * scale;\n}\n\nvec2 cmul(vec2 a, vec2 b) {\n return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);\n}\n\n// Where frame point x, among the in-between points m, comes from in a picture whose points are s:\n// a best-fit similarity (move, scale, turn) carries m onto s, then inverse-distance weighting of\n// what is left over bends each point exactly onto its partner.\nvec2 warp(vec2 x, vec2 m[5], vec2 s[5]) {\n vec2 cm = vec2(0.0);\n vec2 cs = vec2(0.0);\n for (int i = 0; i < 5; i++) {\n cm += m[i] * 0.2;\n cs += s[i] * 0.2;\n }\n vec2 num = vec2(0.0);\n float den = 0.0;\n for (int i = 0; i < 5; i++) {\n vec2 a = m[i] - cm;\n num += cmul(vec2(a.x, -a.y), s[i] - cs);\n den += dot(a, a);\n }\n vec2 k = num / max(den, 1e-6);\n vec2 bend = vec2(0.0);\n float total = 0.0;\n for (int i = 0; i < 5; i++) {\n vec2 left = s[i] - (cs + cmul(k, m[i] - cm));\n float d2 = dot(x - m[i], x - m[i]);\n float w = 1.0 / (d2 * d2 + 1e-6);\n bend += w * left;\n total += w;\n }\n return cs + cmul(k, x - cm) + bend / total;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = progress();\n vec2 scaleA = coverScale(uFrom);\n vec2 scaleB = coverScale(uTo);\n vec2 a[5] = vec2[5](toFrame(uFromA, scaleA), toFrame(uFromB, scaleA), toFrame(uFromC, scaleA), toFrame(uFromD, scaleA), toFrame(uFromE, scaleA));\n vec2 b[5] = vec2[5](toFrame(uToA, scaleB), toFrame(uToB, scaleB), toFrame(uToC, scaleB), toFrame(uToD, scaleB), toFrame(uToE, scaleB));\n vec2 m[5];\n for (int i = 0; i < 5; i++) m[i] = mix(a[i], b[i], t);\n vec2 x = fragCoord / iResolution.y;\n vec4 colA = pictureRGBA(uFrom, toImage(warp(x, m, a), scaleA));\n vec4 colB = pictureRGBA(uTo, toImage(warp(x, m, b), scaleB));\n vec4 pic = mix(colA, colB, smoothstep(0.2, 0.8, t));\n vec3 col = pic.rgb;\n float marks = 0.0;\n if (uShowPoints) {\n float px = 1.0 / iResolution.y;\n for (int i = 0; i < 5; i++) {\n float d = length(x - m[i]);\n float shadow = smoothstep(px * 1.5, 0.0, abs(d - 0.012)) * 0.6;\n float ring = smoothstep(px, 0.0, abs(d - 0.012));\n col = mix(col, vec3(0.0), shadow);\n col = mix(col, vec3(1.0, 0.85, 0.2), ring);\n marks = max(marks, max(shadow, ring));\n }\n }\n fragColor = vec4(col, max(pic.a, marks));\n}`,\n ),\n presets: [{ name: \"Show points\", values: { uShowPoints: true, uAnimate: false, uProgress: 0.5 } }],\n};\n\nexport const silhouetteMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"silhouette-morph\",\n name: \"Silhouette morph\",\n description: \"One silhouette or logo flowing into another as a gooey blob, its colour blending from the first shape's to the second's.\",\n category: \"morph\",\n tags: [\"morph\", \"shape\", \"logo\", \"goo\", \"blob\", \"text\"],\n loop: 4,\n source: glsl(\n `// Silhouette morph: blurred alpha masks of two shapes mixed by progress and thresholded, so one flows into the other.\nuniform sampler2D uFrom; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.logo} label=\"From shape\"\nuniform sampler2D uTo; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.heart} label=\"To shape\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uSize; // @control min=0.2 max=1 default=0.75 label=\"Shape size\"\nuniform float uGoo; // @control min=0 max=0.3 default=0.1 label=\"Gooeyness\"\nuniform float uEdge; // @control min=0 max=0.05 default=0.004 label=\"Edge softness\"\nuniform bool uImageColours; // @control default=true label=\"Use the shapes' own colours\"\nuniform vec3 uColourA; // @control color default=#6366F1 label=\"From colour\"\nuniform vec3 uColourB; // @control color default=#F43F5E label=\"To colour\"\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"`,\n `// A shape's colour (premultiplied) and alpha at frame point p (height 1, centred), the image contained in\n// uSize of the frame, read from a mip level about as coarse as the spacing (in frame units), so sparse blur\n// taps still sum smoothly. With no image, a disc (fallback 0) or a rounded square (1).\nvec4 shapeAt(sampler2D tex, vec2 p, float spacing, int fallback) {\n vec2 size = vec2(textureSize(tex, 0));\n if (size.x <= 1.0) {\n float d = fallback == 0 ? length(p) - 0.3 * uSize : length(max(abs(p) - 0.2 * uSize, 0.0)) - 0.08 * uSize;\n float a = step(d, 0.0);\n return vec4(vec3(a), a);\n }\n float aspect = size.x / size.y;\n float h = min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n vec2 uv = p / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return vec4(0.0);\n vec4 c = textureLod(tex, uv, log2(max(spacing * size.y / h, 1.0)));\n // Clear texels upload black, so filtered colour is already about colour × alpha: divide it out, then weight by alpha.\n return vec4(clamp(c.rgb / max(c.a, 1e-3), 0.0, 1.0) * c.a, c.a);\n}\n\n// A disc blur of the shape: 28 taps on a golden-angle spiral.\nvec4 blurred(sampler2D tex, vec2 p, float radius, int fallback) {\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 28; i++) {\n float r = radius * sqrt((float(i) + 0.5) / 28.0);\n float a = float(i) * 2.39996;\n sum += shapeAt(tex, p + r * vec2(cos(a), sin(a)), radius * 0.35, fallback);\n }\n return sum / 28.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n // Shapes are sharp at either end and softest half way, where the blobs merge.\n float radius = uGoo * sin(3.14159 * t) + 1.0 / iResolution.y;\n vec4 a = blurred(uFrom, p, radius, 0);\n vec4 b = blurred(uTo, p, radius, 1);\n float field = mix(a.a, b.a, t);\n float w = uEdge + fwidth(field) * 0.75;\n float inside = smoothstep(0.5 - w, 0.5 + w, field);\n // Each shape's colour here (or the other's, where only one shape reaches), blended by progress.\n vec3 ca = uImageColours ? a.rgb / max(a.a, 1e-4) : uColourA;\n vec3 cb = uImageColours ? b.rgb / max(b.a, 1e-4) : uColourB;\n ca = mix(cb, ca, smoothstep(0.0, 0.05, a.a));\n cb = mix(ca, cb, smoothstep(0.0, 0.05, b.a));\n vec3 tint = mix(ca, cb, smoothstep(0.2, 0.8, t));\n // A little roundness: the thick middle of a blob is lighter than its rim.\n tint *= 0.82 + 0.25 * smoothstep(0.5, 1.0, field);\n fragColor = vec4(mix(uBackground, tint, inside), 1.0);\n}`,\n ),\n presets: [\n {\n name: \"Hello → World\",\n values: { uFrom: textImage(\"HELLO\"), uTo: textImage(\"WORLD\"), uImageColours: false, uSize: 0.9, uGoo: 0.05, uColourA: [0.98, 0.75, 0.14], uColourB: [0.13, 0.83, 0.93] },\n },\n { name: \"Blobby\", values: { uGoo: 0.25, uBackground: [1, 0.97, 0.93] } },\n ],\n};\n\nexport const transitionLiquidMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-liquid-morph\",\n name: \"Liquid morph\",\n description: \"Both images swept along a flowing, swirling current that peaks half way, dissolving one into the other like ink in water.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"liquid\", \"image\", \"flow\"],\n loop: 4,\n source: glsl(\n `// Liquid morph: both images advected along a domain-warped fbm current, strongest at mid-progress, while cross-fading.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uStrength; // @control min=0 max=0.5 default=0.1 label=\"Strength\"\nuniform float uScale; // @control min=0.5 max=8 default=2.5 label=\"Scale\"\nuniform float uFlow; // @control min=0 max=2 default=0.4 label=\"Flow speed\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n float s = sin(3.14159 * t);\n float time = iTime * uFlow;\n vec2 q = fragCoord / iResolution.y * uScale;\n vec2 first = vec2(fbm(q + vec2(0.0, time), 4), fbm(q + vec2(5.2, 1.3) - vec2(time, 0.0), 4)) - 0.5;\n vec2 flow = vec2(fbm(q + 4.0 * first + vec2(1.7, 9.2) + time * 0.5, 4), fbm(q + 4.0 * first + vec2(8.3, 2.8) - time * 0.5, 4)) - 0.5;\n vec2 d = flow * uStrength * s * 2.0;\n // From is carried downstream, To arrives from upstream; neither moves at the ends.\n vec4 a = coverRGBA(uFrom, uv + d);\n vec4 b = coverRGBA(uTo, uv - d);\n float k = smoothstep(0.25, 0.75, t + (flow.x + flow.y) * 0.6 * s);\n fragColor = mix(a, b, k);\n}`,\n ),\n presets: [\n { name: \"Gentle\", values: { uStrength: 0.08, uScale: 1.5, uFlow: 0.2 } },\n { name: \"Turbulent\", values: { uStrength: 0.35, uScale: 4, uFlow: 1.2 } },\n ],\n};\n\nexport const transitionDisplacement: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-displacement\",\n name: \"Displacement\",\n description: \"Each image's brightness pushes it out in one direction as the next slides in, warped by its own light and dark.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"displacement\", \"image\", \"warp\"],\n loop: 4,\n source: glsl(\n `// Displacement: From's luminance drives a directional warp out, To's luminance the same warp in reverse.\n${pair(SAMPLE_IMAGES.city, SAMPLE_IMAGES.landscape)}\nuniform float uStrength; // @control min=0 max=1 default=0.4 label=\"Strength\"\nuniform float uAngle; // @control min=0 max=360 default=0 label=\"Direction (°)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n vec2 dir = vec2(cos(radians(uAngle)), sin(radians(uAngle))) * vec2(iResolution.y / iResolution.x, 1.0);\n float la = luma(cover(uFrom, uv));\n float lb = luma(cover(uTo, uv));\n vec4 a = coverRGBA(uFrom, uv + dir * t * uStrength * la);\n vec4 b = coverRGBA(uTo, uv - dir * (1.0 - t) * uStrength * lb);\n fragColor = mix(a, b, smoothstep(0.2, 0.8, t));\n}`,\n ),\n presets: [\n { name: \"Upward smear\", values: { uStrength: 0.6, uAngle: 90 } },\n { name: \"Subtle\", values: { uStrength: 0.12, uAngle: 30 } },\n ],\n};\n\nexport const transitionLuma: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-luma\",\n name: \"Luma fade\",\n description: \"Pixels switch to the next image in order of brightness, shadows first or highlights first, along a soft edge.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"luma\", \"image\", \"dissolve\"],\n loop: 4,\n source: glsl(\n `// Luma fade: each pixel switches when progress passes its brightness, with a soft edge.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uSoftness; // @control min=0.01 max=0.5 default=0.1 label=\"Softness\"\nuniform bool uLightFirst; // @control default=false label=\"Light first\"\nuniform int uSource; // @control min=0 max=1 default=0 label=\"Brightness of (0 From, 1 To)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n vec4 a = coverRGBA(uFrom, uv);\n vec4 b = coverRGBA(uTo, uv);\n float l = clamp(luma(uSource == 0 ? a.rgb : b.rgb), 0.0, 1.0);\n if (uLightFirst) l = 1.0 - l;\n // The front sweeps from below the darkest pixel to above the lightest, so both ends are clean.\n float front = mix(-uSoftness, 1.0 + uSoftness, t);\n fragColor = mix(a, b, smoothstep(l - uSoftness, l + uSoftness, front));\n}`,\n ),\n presets: [\n { name: \"Highlights first\", values: { uLightFirst: true, uSoftness: 0.06 } },\n { name: \"Hard threshold\", values: { uSoftness: 0.01, uSource: 1 } },\n ],\n};\n\nexport const transitionParticleSwap: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-particle-swap\",\n name: \"Particle swap\",\n description: \"The image breaks into square particles that tumble along curved, staggered paths and land as the next image.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"particles\", \"image\", \"mosaic\"],\n loop: 4,\n source: glsl(\n `// Particle swap: each cell of From flies to a neighbouring cell's place, shrinking and spinning on the way, and lands as To.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uParticle; // @control min=6 max=80 default=20 label=\"Particle size (px)\"\nuniform float uScatter; // @control min=0 max=0.8 default=0.45 label=\"Scatter\"\nuniform float uSpin; // @control min=0 max=2 default=0.6 label=\"Spin & curl\"\nuniform vec3 uBackground; // @control color default=#0B0B12 label=\"Background\"\n${BACKDROP_CONTROLS}`,\n HASH,\n ROTATE,\n PICTURE,\n COMMON,\n `const vec2 RING[4] = vec2[4](vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0));\n\n// Where cell c's particle lands: cells trade places around each 2 × 2 block, turned 1–3 steps.\nvec2 landing(vec2 c) {\n vec2 block = floor(c * 0.5);\n vec2 local = c - block * 2.0;\n int i = local.y < 0.5 ? int(local.x) : 3 - int(local.x);\n int turn = 1 + int(hash12(block + 7.3) * 2.999);\n return block * 2.0 + RING[(i + turn) % 4];\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = progress();\n vec2 p = fragCoord / uParticle;\n vec2 grid = iResolution.xy / uParticle;\n vec2 base = floor(p);\n vec4 col = vec4(uBackground, uBackdropAlpha);\n float top = -1.0;\n vec2 hitFrom = vec2(0.0);\n vec2 hitTo = vec2(0.0);\n float hitT = 0.0;\n float hitCover = 0.0;\n // Particles travel at most about 1.5 cells, so the 5 × 5 cells around are every candidate.\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 c = base + vec2(float(i), float(j));\n vec2 h = hash22(c);\n // Staggered: a sweep from the left plus some randomness.\n float delay = 0.5 * (0.55 * clamp(c.x / grid.x, 0.0, 1.0) + 0.45 * h.x);\n float k = smoothstep(0.0, 1.0, clamp((t - delay) / 0.5, 0.0, 1.0));\n float lift = sin(3.14159 * k);\n vec2 from = c + 0.5;\n vec2 to = landing(c) + 0.5;\n vec2 path = to - from;\n vec2 side = normalize(vec2(-path.y, path.x) + (h - 0.5) * 0.8);\n vec2 pos = mix(from, to, k) + side * lift * (uScatter + uSpin * 0.3) * (h.y > 0.5 ? 0.6 : -0.6);\n float size = 1.0 - 0.3 * lift;\n float angle = (h.y - 0.5) * 6.28318 * uSpin * lift;\n vec2 l = rot(-angle) * (p - pos) / size;\n float m = max(abs(l.x), abs(l.y));\n float z = h.y + lift;\n if (m <= 0.5 && z > top) {\n top = z;\n hitFrom = from + l;\n hitTo = to + l;\n hitT = k;\n hitCover = 1.0 - smoothstep(0.5 - 1.5 / uParticle, 0.5, m) * min(lift * 8.0, 1.0);\n }\n }\n }\n if (top > -1.0) {\n vec4 particle = mix(coverRGBA(uFrom, hitFrom / grid), coverRGBA(uTo, hitTo / grid), hitT);\n particle.rgb *= 1.0 + 0.15 * sin(3.14159 * hitT);\n col = mix(col, particle, hitCover);\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Confetti\", values: { uParticle: 10, uScatter: 0.8, uSpin: 1.6 } },\n { name: \"Tiles\", values: { uParticle: 48, uScatter: 0.2, uSpin: 0.15 } },\n ],\n};\n\nexport const transitionInkBleed: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-ink-bleed\",\n name: \"Ink bleed\",\n description: \"The next image bleeds through the first like wet ink on paper, spreading from a few seeds with dark, pooled edges.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"ink\", \"watercolour\", \"image\", \"organic\"],\n loop: 4,\n source: glsl(\n `// Ink bleed: To spreads through From along an fbm threshold grown from seeds, with a wet, darkened fringe.\n${pair(SAMPLE_IMAGES.city, SAMPLE_IMAGES.landscape)}\nuniform float uScale; // @control min=0.5 max=8 default=3 label=\"Scale\"\nuniform float uEdge; // @control min=0.005 max=0.2 default=0.05 label=\"Edge width\"\nuniform vec3 uInk; // @control color default=#1B1F3B label=\"Ink\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n vec2 q = fragCoord / iResolution.y;\n // Distance to the nearest of four seeds spread across the frame, measured through a noisy warp so the blots are ragged.\n vec2 warped = q + (vec2(fbm(q * uScale, 5), fbm(q * uScale + 31.7, 5)) - 0.5) * 0.35;\n float aspect = iResolution.x / iResolution.y;\n float near = 1e9;\n for (int i = 0; i < 4; i++) {\n vec2 h = hash22(vec2(float(i), 3.7));\n vec2 seed = vec2((float(i) + 0.2 + 0.6 * h.x) / 4.0 * aspect, 0.2 + 0.6 * h.y);\n near = min(near, length(warped - seed));\n }\n // Fine noise adds capillary fingers to the front.\n float v = clamp(near / 0.5 * 0.75 + 0.25 * fbm(q * uScale * 4.0, 4) + 0.06 * (vnoise(q * uScale * 18.0) - 0.5), 0.0, 1.0);\n float front = mix(-2.0 * uEdge - 0.02, 1.0 + 2.0 * uEdge + 0.02, t);\n float gap = front - v;\n float wet = smoothstep(-uEdge * 0.3, uEdge * 0.3, gap);\n // Paper just ahead of the front darkens as it soaks; pigment pools just behind it.\n float soak = smoothstep(-2.0 * uEdge, 0.0, gap) * (1.0 - wet);\n float pool = wet * smoothstep(uEdge, 0.0, gap);\n vec2 bleed = vec2(soak - pool) * 0.004;\n vec4 col = mix(coverRGBA(uFrom, uv + bleed), coverRGBA(uTo, uv - bleed), wet);\n col.rgb = mix(col.rgb, col.rgb * 0.82, soak * 0.6);\n col = mix(col, vec4(uInk, 1.0), pool * 0.85);\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Sepia wash\", values: { uInk: [0.36, 0.23, 0.12], uEdge: 0.08, uScale: 2 } },\n { name: \"Crisp\", values: { uEdge: 0.015, uScale: 5 } },\n ],\n};\n\n/** Shaders that turn one image into another: true morphs (category \"morph\") and morph-like transitions. */\nexport const morphShaders: ShaderEffect[] = [\n featureMorph,\n silhouetteMorph,\n transitionLiquidMorph,\n transitionDisplacement,\n transitionLuma,\n transitionParticleSwap,\n transitionInkBleed,\n];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/**\n * `glow(c)`: light as a colour over whatever is behind it. Its alpha is its\n * brightest channel, so it brightens what is under it like a screen blend.\n */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/**\n * `over(acc, colour, alpha)`: paints a colour over a premultiplied\n * accumulator; `unpremultiply(acc)` turns it into straight colour and coverage.\n */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\nexport const rainOnGlass: ShaderEffect = {\n kind: \"shader\",\n id: \"rain-on-glass\",\n name: \"Rain on glass\",\n description: \"Raindrops sliding down a window in fits and starts, leaving beaded trails behind them.\",\n category: \"overlay\",\n tags: [\"overlay\", \"rain\", \"weather\", \"moody\", \"window\"],\n transparent: true,\n source: glsl(\n `// Rain on glass: drops sliding down a pane, leaving trails of beads.\nuniform float uDensity; // @control min=0 max=1 default=0.7 label=\"Density\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSize; // @control min=0.5 max=2 default=1 label=\"Drop size\"\nuniform vec3 uTint; // @control color default=#CFE3F0 label=\"Tint\"`,\n HASH,\n OVER,\n `// One drop of radius r at offset d: a faint tinted body, a darker rim and a bright highlight.\nvec4 paintDrop(vec4 acc, vec2 d, float r, float px) {\n float dist = length(d);\n if (dist > r + px) return acc;\n float m = (1.0 - smoothstep(r - 1.5 * px, r, dist)) * smoothstep(0.0, 2.0 * px, r);\n vec2 n = d / max(r, 1e-5);\n float l = length(n);\n float rim = smoothstep(0.45, 1.0, l) * m;\n float spec = (1.0 - smoothstep(0.0, 0.3, length(n - vec2(-0.3, 0.38)))) * m;\n float caustic = (1.0 - smoothstep(0.0, 0.5, length(n - vec2(0.15, -0.5)))) * m;\n acc = over(acc, uTint, m * 0.2);\n acc = over(acc, vec3(0.0, 0.02, 0.05), rim * 0.5);\n acc = over(acc, mix(uTint, vec3(1.0), 0.6), caustic * 0.3);\n return over(acc, vec3(1.0), spec * 0.9);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n vec4 acc = vec4(0.0);\n\n // Condensation: still beads slowly forming and drying up.\n float beads = 30.0 / uSize;\n vec2 bq = p * beads;\n vec2 bid = floor(bq);\n vec2 bh = hash22(bid);\n float life = fract(iTime * 0.04 + bh.x * 7.0);\n float br = (0.12 + 0.18 * bh.y) / beads * sin(3.14159 * life);\n if (hash12(bid + 5.0) < uDensity) acc = paintDrop(acc, (fract(bq) - 0.5 - (bh - 0.5) * 0.4) / beads, br, px);\n\n // Running drops: one per cell at most, sliding down a wavy path with a trail above.\n for (int i = 0; i < 2; i++) {\n float fi = float(i);\n vec2 cell = vec2(0.12, 0.3) * uSize * (1.0 - 0.3 * fi);\n vec2 q = p / cell + vec2(fi * 3.7, 0.0);\n float column = floor(q.x);\n q.y += t * 0.15 + hash12(vec2(column, fi)) * 9.0;\n vec2 id = floor(q);\n vec2 f = fract(q) - 0.5;\n vec2 h = hash22(id + fi * 17.0);\n if (h.x > uDensity) continue;\n float tt = t * 1.2 + h.y * 6.28318;\n float y = -0.38 * sin(tt + sin(tt + sin(tt) * 0.5));\n float base = (h.y - 0.5) * 0.3;\n float wobble = h.x * 6.28318;\n float x = base + 0.03 * sin(y * 9.0 + wobble);\n float aspect = cell.x / cell.y;\n float r = cell.y * (0.05 + 0.04 * fract(h.x * 13.7));\n vec2 d = vec2((f.x - x) * aspect, f.y - y) * cell.y;\n d.y *= d.y > 0.0 ? 0.8 : 1.0;\n acc = paintDrop(acc, d, r, px);\n if (f.y > y) {\n float rows = 10.0;\n float row = floor(f.y * rows);\n float tx = base + 0.03 * sin((row + 0.5) / rows * 9.0 + wobble);\n vec2 bd = vec2((f.x - tx) * aspect, (fract(f.y * rows) - 0.5) / rows) * cell.y;\n float fade = 1.0 - clamp((f.y - y) / (0.5 - y), 0.0, 1.0);\n float keep = step(0.35, hash12(id * 3.1 + vec2(row, fi)));\n acc = paintDrop(acc, bd, r * 0.35 * fade * keep, px);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Storm\", values: { uDensity: 1, uSpeed: 1.8, uSize: 1.3 } },\n { name: \"Drizzle\", values: { uDensity: 0.4, uSpeed: 0.6, uSize: 0.7 } },\n ],\n};\n\nexport const snowfall: ShaderEffect = {\n kind: \"shader\",\n id: \"snowfall\",\n name: \"Snowfall\",\n description: \"Layers of snowflakes drifting down on the wind, the far ones smaller and softer.\",\n category: \"overlay\",\n tags: [\"overlay\", \"snow\", \"winter\", \"festive\", \"particles\"],\n transparent: true,\n source: glsl(\n `// Snowfall: layered flakes drifting with the wind, far layers smaller and blurrier.\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Colour\"\nuniform float uDensity; // @control min=0 max=1 default=0.6 label=\"Density\"\nuniform float uWind; // @control min=-2 max=2 default=0.3 label=\"Wind\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Fall speed\"\nuniform float uSize; // @control min=0.2 max=2 default=1 label=\"Size\"\nuniform int uLayers; // @control min=1 max=6 default=4 label=\"Layers\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float px = 1.0 / iResolution.y;\n float a = 0.0;\n for (int i = 0; i < 6; i++) {\n if (i >= uLayers) break;\n float fi = float(i);\n // Layer 0 is the farthest: smaller, slower, softer and fainter.\n float depth = (fi + 1.0) / float(uLayers);\n float scale = mix(22.0, 6.0, depth);\n vec2 vel = vec2(uWind * 0.12 * (0.4 + depth), -uSpeed * mix(0.06, 0.25, depth));\n vec2 q = (p - vel * iTime) * scale + fi * 11.3;\n vec2 id = floor(q);\n vec2 h = hash22(id);\n if (hash12(id + 3.7) > uDensity) continue;\n float phase = iTime * (0.4 + 0.6 * h.x) + h.y * 6.28318;\n vec2 centre = (h - 0.5) * 0.3 + vec2(sin(phase) * 0.12, cos(phase * 0.7) * 0.05);\n float d = length(fract(q) - 0.5 - centre);\n float r = 0.06 * uSize * (0.6 + 0.8 * hash12(id + 9.1));\n float soft = max(px * scale * 1.5, r * mix(0.9, 0.3, depth));\n float flake = 1.0 - smoothstep(r - soft, r, d);\n a = max(a, flake * mix(0.45, 1.0, depth));\n }\n fragColor = vec4(uColor, a);\n}`,\n ),\n presets: [\n { name: \"Dust motes\", values: { uColor: [1, 0.85, 0.63], uDensity: 0.25, uWind: 0.05, uSpeed: 0.08, uSize: 0.6, uLayers: 3 } },\n { name: \"Blizzard\", values: { uDensity: 0.9, uWind: 1.6, uSpeed: 2, uLayers: 6 } },\n ],\n};\n\nexport const lensFlare: ShaderEffect = {\n kind: \"shader\",\n id: \"lens-flare\",\n name: \"Lens flare\",\n description: \"An anamorphic lens flare: a long horizontal streak and a chain of ghosts through the centre, following the pointer.\",\n category: \"overlay\",\n tags: [\"overlay\", \"cinematic\", \"light\", \"interactive\", \"sci-fi\"],\n transparent: true,\n source: glsl(\n `// Lens flare: an anamorphic streak and ghosts along the line through the centre.\nuniform vec2 uSource; // @control min=-1 max=1 default=-0.45,0.4 label=\"Source\"\nuniform vec3 uColor; // @control color default=#FFC98A label=\"Colour\"\nuniform float uStreak; // @control min=0 max=2 default=1 label=\"Streak length\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"`,\n HASH,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 src = iMouse.z > 0.0\n ? (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y\n : uSource * vec2(aspect, 1.0) * 0.5;\n vec2 d = p - src;\n float r = length(d);\n vec3 col = uColor * (exp(-r * 20.0) * 1.5 + 0.015 / (r + 0.015) * 0.3);\n // The anamorphic streak: a bright thin line and a wider, fainter one, blue-shifted.\n vec3 streakColor = mix(uColor, vec3(0.45, 0.65, 1.0), 0.6);\n float len = uStreak + 1e-3;\n col += streakColor * exp(-abs(d.y) * 220.0) * exp(-abs(d.x) / (0.5 * len));\n col += streakColor * 0.4 * exp(-abs(d.y) * 60.0) * exp(-abs(d.x) / (0.25 * len));\n // Ghosts sit on the line from the source through the centre, mostly on the far side.\n for (int i = 0; i < 7; i++) {\n float fi = float(i);\n float along = mix(-1.6, 0.6, hash12(vec2(fi, 1.7)));\n float gr = mix(0.015, 0.11, hash12(vec2(fi, 4.1)));\n float gd = length(p - src * along);\n vec3 tint = mix(uColor, vec3(0.4, 0.85, 1.0), hash12(vec2(fi, 8.3)));\n float disc = (1.0 - smoothstep(gr * 0.6, gr, gd)) * 0.12;\n float ring = exp(-abs(gd - gr) * 90.0) * 0.18;\n col += tint * (hash12(vec2(fi, 2.9)) > 0.6 ? ring : disc);\n }\n fragColor = glow(col * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Sci-fi blue\", values: { uColor: [0.5, 0.7, 1], uStreak: 1.8 } },\n { name: \"Golden hour\", values: { uColor: [1, 0.7, 0.28], uStreak: 0.6, uIntensity: 1.3 } },\n ],\n};\n\nexport const vignetteGrain: ShaderEffect = {\n kind: \"shader\",\n id: \"vignette-grain\",\n name: \"Vignette & grain\",\n description: \"Darkened corners and fine animated film grain to lay over any picture.\",\n category: \"overlay\",\n tags: [\"overlay\", \"cinematic\", \"film\", \"grain\", \"vintage\"],\n transparent: true,\n source: glsl(\n `// Vignette & grain: darkened corners and fine grain, nothing else.\nuniform float uStrength; // @control min=0 max=1 default=0.6 label=\"Strength\"\nuniform float uRoundness; // @control min=0 max=1 default=0.5 label=\"Roundness\"\nuniform float uSoftness; // @control min=0.05 max=1 default=0.5 label=\"Softness\"\nuniform float uGrain; // @control min=0 max=0.3 default=0.08 label=\"Grain\"\nuniform float uGrainSize; // @control min=1 max=4 default=1.5 label=\"Grain size (px)\"`,\n HASH,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float aspect = iResolution.x / iResolution.y;\n // 0 at the centre, 1 at the edges; rounder shapes measure across the frame's aspect.\n vec2 q = abs(fragCoord / iResolution.xy - 0.5) * 2.0;\n q.x *= mix(1.0, aspect, uRoundness * 0.5);\n float n = mix(8.0, 2.0, uRoundness);\n float dist = pow(pow(q.x, n) + pow(q.y, n), 1.0 / n);\n float dark = smoothstep(1.25 - uSoftness * 1.2, 1.3, dist) * uStrength;\n vec4 acc = over(vec4(0.0), vec3(0.0), dark);\n float frame = mod(floor(iTime * 24.0), 64.0);\n float g = hash12(floor(fragCoord / uGrainSize) + frame * vec2(17.31, 31.73)) - 0.5;\n acc = over(acc, vec3(step(0.0, g)), abs(g) * uGrain * 2.0);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Subtle\", values: { uStrength: 0.35, uGrain: 0.04 } },\n { name: \"Gritty\", values: { uStrength: 0.8, uSoftness: 0.3, uGrain: 0.18, uGrainSize: 2 } },\n ],\n};\n\nexport const scanlineSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"scanline-sweep\",\n name: \"Scanline sweep\",\n description: \"A bright scanning line with a glow and fading trail passing across, like a scanner or hologram.\",\n category: \"overlay\",\n tags: [\"overlay\", \"scan\", \"hologram\", \"sci-fi\", \"tech\"],\n transparent: true,\n source: glsl(\n `// Scanline sweep: a glowing line with a faint trail crossing the frame at intervals.\nuniform float uAngle; // @control min=0 max=360 default=270 label=\"Direction (°)\"\nuniform float uSpeed; // @control min=0.1 max=3 default=1 label=\"Speed\"\nuniform float uWidth; // @control min=0.001 max=0.05 default=0.006 label=\"Width\"\nuniform vec3 uColor; // @control color default=#4FF0FF label=\"Colour\"\nuniform float uInterval; // @control min=0 max=5 default=1 label=\"Pause (s)\"\nuniform float uTrail; // @control min=0 max=1 default=0.5 label=\"Trail\"`,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float px = 1.0 / iResolution.y;\n float a = radians(uAngle);\n vec2 dir = vec2(cos(a), sin(a));\n float s = dot(p, dir);\n // Start and end far enough past the frame that the trail has gone before the next pass.\n float trailLength = 0.02 + 0.2 * uTrail;\n float reach = 0.5 * (abs(dir.x) * aspect + abs(dir.y)) + uWidth * 6.0 + trailLength * 4.0;\n float sweep = 1.5 / uSpeed;\n float k = mod(iTime, sweep + uInterval) / sweep;\n float d = s - mix(-reach, reach, k);\n float core = 1.0 - smoothstep(uWidth * 0.5, uWidth * 0.5 + px, abs(d));\n float halo = exp(-abs(d) / (uWidth * 3.0)) * 0.6;\n float trail = d < 0.0 ? exp(d / trailLength) * 0.35 * uTrail : 0.0;\n trail *= 0.75 + 0.25 * sin(fragCoord.y * 2.0);\n fragColor = glow(uColor * (core * 1.5 + halo + trail));\n}`,\n ),\n presets: [\n { name: \"Hologram\", values: { uAngle: 90, uColor: [0.3, 1, 0.6], uSpeed: 0.6, uInterval: 0, uTrail: 0.9 } },\n { name: \"Barcode scanner\", values: { uAngle: 0, uColor: [1, 0.15, 0.15], uSpeed: 2, uInterval: 0.2, uWidth: 0.003 } },\n ],\n};\n\nexport const spotlight: ShaderEffect = {\n kind: \"shader\",\n id: \"spotlight\",\n name: \"Spotlight\",\n description: \"Darkness everywhere but a soft circle of light that follows the pointer or wanders on its own.\",\n category: \"overlay\",\n tags: [\"overlay\", \"interactive\", \"reveal\", \"focus\", \"dramatic\"],\n transparent: true,\n source: glsl(\n `// Spotlight: dark everywhere but a soft circle, at the pointer or drifting.\nuniform float uRadius; // @control min=0.05 max=0.8 default=0.25 label=\"Radius\"\nuniform float uSoftness; // @control min=0 max=1 default=0.4 label=\"Softness\"\nuniform float uDarkness; // @control min=0 max=1 default=0.85 label=\"Darkness\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Drift speed\"\nuniform vec3 uShade; // @control color default=#05050A label=\"Shade\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n vec2 centre = iMouse.z > 0.0\n ? (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y\n : vec2(sin(t * 2.0) * 0.32 * aspect, sin(t * 3.0 + 0.5) * 0.28);\n float r = length(p - centre);\n float dark = smoothstep(uRadius * (1.0 - uSoftness) - px, uRadius + px, r);\n fragColor = vec4(uShade, dark * uDarkness);\n}`,\n ),\n presets: [\n { name: \"Stage\", values: { uRadius: 0.35, uSoftness: 0.15, uDarkness: 0.95, uSpeed: 0.15 } },\n { name: \"Torch\", values: { uRadius: 0.18, uSoftness: 0.7, uDarkness: 1, uShade: [0.02, 0.01, 0] } },\n ],\n};\n\nexport const embers: ShaderEffect = {\n kind: \"shader\",\n id: \"embers\",\n name: \"Embers\",\n description: \"Glowing sparks rising from below, swaying and flickering out as they cool.\",\n category: \"overlay\",\n tags: [\"overlay\", \"fire\", \"sparks\", \"particles\", \"warm\"],\n transparent: true,\n source: glsl(\n `// Embers: sparks rising, swaying and flickering out as they cool.\nuniform int uCount; // @control min=5 max=80 default=40 label=\"Sparks\"\nuniform vec3 uHeat; // @control color default=#FF7A1A label=\"Heat\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Rise speed\"\nuniform float uSize; // @control min=0.3 max=3 default=1 label=\"Size\"`,\n HASH,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec3 col = vec3(0.0);\n for (int i = 0; i < 80; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 h = hash22(vec2(fi, 1.3));\n float clock = iTime * uSpeed * 0.18 * (0.6 + 0.8 * h.y) + h.x;\n float life = fract(clock);\n // Each life starts somewhere new along the bottom.\n vec2 seed = vec2(fi, floor(clock));\n float x = hash12(seed) * aspect + 0.04 * sin(life * 8.0 + fi) + life * 0.15 * (hash12(seed + 2.0) - 0.5);\n float y = life * (0.5 + 0.7 * hash12(seed + 4.0)) - 0.02;\n float r = 0.005 * uSize * (0.5 + hash12(seed + 6.0));\n vec2 d = p - vec2(x, y);\n d.y *= 0.6;\n float dist = length(d);\n if (dist > r * 14.0) continue;\n float fade = smoothstep(0.0, 0.08, life) * (1.0 - smoothstep(0.45, 1.0, life));\n float flicker = 0.6 + 0.4 * sin(iTime * 17.0 + fi * 3.7) * sin(iTime * 7.3 + fi);\n vec3 heat = mix(vec3(1.0, 0.95, 0.75), uHeat, smoothstep(0.0, 0.5, life));\n heat = mix(heat, uHeat * vec3(0.8, 0.25, 0.1), smoothstep(0.5, 1.0, life));\n float core = 1.0 - smoothstep(r * 0.4, r, dist);\n float halo = exp(-dist / (r * 2.5)) * 0.35;\n col += heat * (core * 1.5 + halo) * fade * flicker;\n }\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Bonfire\", values: { uCount: 80, uSpeed: 1.6, uSize: 1.3 } },\n { name: \"Magic sparks\", values: { uHeat: [0.55, 0.4, 1], uCount: 30, uSpeed: 0.6 } },\n ],\n};\n\nexport const shineSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"shine-sweep\",\n name: \"Shine sweep\",\n description: \"A soft diagonal gloss band gliding across now and then, for cards and buttons.\",\n category: \"overlay\",\n tags: [\"overlay\", \"ui\", \"gloss\", \"premium\", \"button\"],\n transparent: true,\n source: glsl(\n `// Shine sweep: a soft gloss band crossing the frame at intervals.\nuniform float uAngle; // @control min=-60 max=60 default=25 label=\"Tilt (°)\"\nuniform float uWidth; // @control min=0.02 max=0.5 default=0.15 label=\"Width\"\nuniform float uIntensity; // @control min=0 max=1 default=0.6 label=\"Intensity\"\nuniform float uInterval; // @control min=1 max=8 default=3 label=\"Every (s)\"\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Colour\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float slope = tan(radians(uAngle));\n float s = p.x + p.y * slope;\n float reach = 0.5 * aspect + 0.5 * abs(slope) + uWidth;\n // Each sweep takes 0.9 s, then waits for the next.\n float k = clamp(mod(iTime, uInterval) / 0.9, 0.0, 1.0);\n k = k * k * (3.0 - 2.0 * k);\n float d = (s - mix(-reach, reach, k)) / uWidth;\n float band = exp(-d * d * 4.0) * 0.7 + exp(-d * d * 60.0) * 0.5;\n fragColor = vec4(uColor, clamp(band * uIntensity, 0.0, 1.0));\n}`,\n ),\n presets: [\n { name: \"Gold foil\", values: { uColor: [1, 0.9, 0.6], uWidth: 0.25, uIntensity: 0.5 } },\n { name: \"Quick glint\", values: { uWidth: 0.06, uIntensity: 0.9, uInterval: 1.5, uAngle: 35 } },\n ],\n};\n\nexport const frostCreep: ShaderEffect = {\n kind: \"shader\",\n id: \"frost-creep\",\n name: \"Frost creep\",\n description: \"Ice crystals creeping in from the edges of the frame and melting back.\",\n category: \"overlay\",\n tags: [\"overlay\", \"ice\", \"winter\", \"frozen\", \"reveal\"],\n transparent: true,\n loop: 8,\n source: glsl(\n `// Frost creep: crystalline frost growing in from the edges.\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uCoverage; // @control min=0 max=1 default=0.6 label=\"Coverage (when still)\"\nuniform float uScale; // @control min=1 max=10 default=4 label=\"Crystal size\"\nuniform vec3 uColor; // @control color default=#DDF2FF label=\"Frost\"`,\n HASH,\n NOISE,\n FBM,\n `// Voronoi: x = distance to the nearest point, y = to the second, zw = the nearest cell.\nvec4 voronoi(vec2 q) {\n vec2 id = floor(q);\n vec2 f = fract(q);\n float f1 = 8.0;\n float f2 = 8.0;\n vec2 nearest = id;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 o = vec2(float(i), float(j));\n float d = length(o + hash22(id + o) - f);\n if (d < f1) {\n f2 = f1;\n f1 = d;\n nearest = id + o;\n } else if (d < f2) {\n f2 = d;\n }\n }\n }\n return vec4(f1, f2, nearest);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float coverage = uAnimate ? 0.5 - 0.5 * cos(iTime * 6.28318 / 8.0) : uCoverage;\n // Distance in from the nearest edge, roughened by noise and stepped per crystal.\n float edge = min(min(fragCoord.x, iResolution.x - fragCoord.x), min(fragCoord.y, iResolution.y - fragCoord.y)) / iResolution.y;\n vec4 v = voronoi(p * uScale * 3.0);\n float n = fbm(p * uScale * 0.8, 5);\n float g = edge + (n - 0.5) * 0.3 + (hash12(v.zw) - 0.5) * 0.04;\n float front = mix(-0.25, 0.75, coverage);\n float frost = 1.0 - smoothstep(front - 0.06, front, g);\n if (frost <= 0.0) {\n fragColor = vec4(0.0);\n return;\n }\n // Facets catch the light differently; their edges and fine needles glint.\n float facet = hash12(v.zw + 3.1);\n float ridges = 1.0 - smoothstep(0.0, 0.06, v.y - v.x);\n float needles = smoothstep(0.55, 0.8, fbm(p * uScale * vec2(6.0, 1.5) + v.zw, 3));\n float fresh = 1.0 - smoothstep(0.0, 0.35, front - g);\n float rim = smoothstep(front - 0.06, front - 0.015, g);\n vec3 col = mix(uColor * vec3(0.8, 0.9, 1.0), vec3(1.0), facet * 0.4 + ridges * 0.6 + rim * 0.5 + needles * 0.4);\n float alpha = frost * clamp(0.35 + 0.25 * (1.0 - fresh) + 0.2 * facet + 0.35 * ridges + 0.25 * needles + 0.3 * rim, 0.0, 1.0);\n fragColor = vec4(min(col, 1.0), alpha);\n}`,\n ),\n presets: [\n { name: \"Hoarfrost\", values: { uAnimate: false, uCoverage: 0.85, uScale: 6 } },\n { name: \"Icy blue\", values: { uColor: [0.62, 0.83, 1], uScale: 2.5 } },\n ],\n};\n\n/** Effects drawn over other content: transparent where there is nothing to draw (see `ShaderEffect.transparent`). */\nexport const overlayEffects: ShaderEffect[] = [\n rainOnGlass,\n snowfall,\n lensFlare,\n vignetteGrain,\n scanlineSweep,\n spotlight,\n embers,\n shineSweep,\n frostCreep,\n];\n","import { glsl, HASH } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const synthwaveGrid: ShaderEffect = {\n kind: \"shader\",\n id: \"synthwave\",\n name: \"Synthwave\",\n description: \"A neon perspective grid racing towards a striped retro sun.\",\n category: \"retro\",\n tags: [\"background\", \"80s\", \"neon\", \"music\", \"loop\"],\n loop: 1,\n source: glsl(\n `// Synthwave: a neon grid racing towards a striped sun.\nuniform vec3 uSkyTop; // @control color default=#12002B label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#7A1A6B label=\"Sky bottom\"\nuniform vec3 uSunTop; // @control color default=#FFE45E label=\"Sun top\"\nuniform vec3 uSunBottom; // @control color default=#FF3D7F label=\"Sun bottom\"\nuniform vec3 uGrid; // @control color default=#00F0FF label=\"Grid\"\nuniform float uHorizon; // @control min=0.2 max=0.7 default=0.42 label=\"Horizon\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float horizon = uHorizon - 0.5;\n vec3 col;\n if (p.y > horizon) {\n float h = (p.y - horizon) / (0.5 - horizon);\n col = mix(uSkyBottom, uSkyTop, h);\n vec2 s = p - vec2(0.0, horizon + 0.18);\n float sun = smoothstep(0.2, 0.195, length(s));\n float bands = step(0.0, sin((s.y + 0.2) * 60.0 - 1.5)) + step(0.06, s.y);\n sun *= clamp(bands, 0.0, 1.0);\n col = mix(col, mix(uSunBottom, uSunTop, clamp(s.y / 0.2 * 0.5 + 0.5, 0.0, 1.0)), sun);\n col += uSunBottom * 0.25 * exp(-length(s) * 4.0);\n } else {\n float depth = (horizon - p.y);\n vec2 g = vec2(p.x / depth, 1.0 / depth);\n g.y += iTime * 2.0;\n vec2 grid = abs(fract(g * 0.5) - 0.5) / fwidth(g * 0.5);\n float line = 1.0 - clamp(min(grid.x, grid.y), 0.0, 1.0);\n float fade = smoothstep(0.0, 0.25, depth);\n col = mix(uSkyTop * 0.4, uSkyBottom * 0.3, uv.y);\n col += uGrid * line * fade + uGrid * 0.25 * exp(-depth * 20.0);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const tvStatic: ShaderEffect = {\n kind: \"shader\",\n id: \"tv-static\",\n name: \"TV static\",\n description: \"Analogue snow with rolling bars and scanlines.\",\n category: \"retro\",\n tags: [\"glitch\", \"analogue\", \"transition\", \"noise\"],\n source: glsl(\n `// TV static: analogue snow with a rolling bar and scanlines.\nuniform float uAmount; // @control min=0 max=1 default=0.9 label=\"Snow\"\nuniform float uScanlines; // @control min=0 max=1 default=0.35 label=\"Scanlines\"\nuniform float uRoll; // @control min=0 max=1 default=0.3 label=\"Rolling bar\"\nuniform vec3 uTint; // @control color default=#E6E6E6 label=\"Tint\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float n = hash12(floor(fragCoord * 0.5) + floor(iTime * 30.0) * 17.31);\n float scan = 1.0 - uScanlines * 0.5 * (1.0 + sin(fragCoord.y * 3.14159));\n float bar = 1.0 + uRoll * 0.6 * smoothstep(0.15, 0.0, abs(fract(uv.y - iTime * 0.2) - 0.5) - 0.3);\n vec3 col = uTint * mix(0.5, n, uAmount) * scan * bar;\n col *= smoothstep(1.2, 0.4, length(uv - 0.5) * 1.4);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const digitalRain: ShaderEffect = {\n kind: \"shader\",\n id: \"digital-rain\",\n name: \"Digital rain\",\n description: \"Columns of glyph-like characters raining down a terminal.\",\n category: \"retro\",\n tags: [\"hacker\", \"code\", \"tech\", \"cyber\"],\n source: glsl(\n `// Digital rain: glyph-like cells raining down in columns.\nuniform vec3 uBackground; // @control color default=#000000 label=\"Background\"\nuniform vec3 uGlyph; // @control color default=#22FF66 label=\"Glyph\"\nuniform float uCell; // @control min=6 max=40 default=14 label=\"Cell size (px)\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Speed\"`,\n HASH,\n `float glyph(vec2 cell, vec2 f) {\n vec2 g = floor(f * vec2(3.0, 5.0));\n float on = step(0.45, hash12(g + cell * 13.7 + floor(iTime * 4.0 * hash12(cell))));\n vec2 inset = abs(fract(f * vec2(3.0, 5.0)) - 0.5);\n return on * step(max(inset.x, inset.y), 0.38);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 q = fragCoord / uCell;\n vec2 cell = floor(q);\n vec2 f = fract(q);\n float col = cell.x;\n float speed = (0.5 + hash12(vec2(col, 1.0))) * uSpeed * 8.0;\n float offset = hash12(vec2(col, 2.0)) * 100.0;\n float head = fract((iTime * speed + offset) / 40.0) * (iResolution.y / uCell + 30.0);\n float y = iResolution.y / uCell - cell.y;\n float trail = head - y;\n float lit = trail >= 0.0 ? exp(-trail * 0.15) : 0.0;\n float isHead = step(abs(trail), 0.5);\n float g = glyph(cell, f);\n vec3 c = uBackground + uGlyph * g * lit + vec3(0.8) * g * isHead;\n fragColor = vec4(c, 1.0);\n}`,\n ),\n};\n\nexport const pixelSunset: ShaderEffect = {\n kind: \"shader\",\n id: \"dither-gradient\",\n name: \"Dithered gradient\",\n description: \"A 1-bit Bayer-dithered gradient wave, like an old Mac or Game Boy screen.\",\n category: \"retro\",\n tags: [\"pixel\", \"1-bit\", \"lo-fi\", \"background\"],\n source: glsl(\n `// Dithered gradient: a Bayer-dithered gradient wave in two colours.\nuniform vec3 uDark; // @control color default=#0F380F label=\"Dark\"\nuniform vec3 uLight; // @control color default=#9BBC0F label=\"Light\"\nuniform float uPixel; // @control min=1 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"`,\n `float bayer4(vec2 p) {\n vec2 q = mod(floor(p), 4.0);\n int i = int(q.x) + int(q.y) * 4;\n int m[16] = int[16](0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5);\n return (float(m[i]) + 0.5) / 16.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 px = floor(fragCoord / uPixel);\n vec2 uv = px * uPixel / iResolution.xy;\n float v = uv.y + 0.15 * sin(uv.x * 6.0 + iTime * uSpeed * 2.0) + 0.1 * sin(uv.x * 13.0 - iTime * uSpeed * 3.0);\n v = clamp(v, 0.0, 1.0);\n float on = step(bayer4(px), v);\n fragColor = vec4(mix(uDark, uLight, on), 1.0);\n}`,\n ),\n presets: [\n { name: \"Mac\", values: { uDark: [0.05, 0.05, 0.05], uLight: [0.93, 0.93, 0.9] } },\n { name: \"Amber\", values: { uDark: [0.1, 0.04, 0], uLight: [1, 0.69, 0] } },\n ],\n};\n","import { FBM, glsl, HASH, NOISE, PALETTE } from \"../glsl.js\";\nimport { textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const shaderText: ShaderEffect = {\n kind: \"shader\",\n id: \"shader-text\",\n name: \"Shader text\",\n description: \"A title filled with a living texture (plasma, fire, caustics or liquid chrome), with a soft glow and outline.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"plasma\", \"fire\", \"chrome\", \"glow\"],\n source: glsl(\n `// Shader text: the letters of a text image filled with an animated pattern.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"FLAIR\")} label=\"Text\"\nuniform int uFill; // @control min=0 max=3 default=0 label=\"Fill (0 plasma, 1 fire, 2 caustics, 3 chrome)\"\nuniform vec3 uBackground; // @control color default=#0A0A12 label=\"Background\"\nuniform vec3 uTint; // @control color default=#FFFFFF label=\"Tint\"\nuniform float uSize; // @control min=0.3 max=1 default=0.9 label=\"Text size\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uGlow; // @control min=0 max=2 default=0.6 label=\"Glow\"\nuniform float uOutline; // @control min=0 max=0.02 default=0.004 label=\"Outline width\"\nuniform vec3 uOutlineColor; // @control color default=#FFFFFF label=\"Outline\"`,\n HASH,\n NOISE,\n FBM,\n PALETTE,\n `// The text image's alpha at frame point p (height 1, centred), the image contained in uSize of the frame.\nfloat letters(vec2 p) {\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float frame = iResolution.x / iResolution.y;\n float h = min(uSize, frame * uSize / aspect);\n vec2 uv = p / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uText, uv).a;\n}\n\nvec3 plasmaFill(vec2 p, float t) {\n float v = sin(p.x * 6.0 + t) + sin(p.y * 7.0 - t * 1.3) + sin((p.x + p.y) * 5.0 + t * 0.7) + sin(length(p * 8.0) - t * 2.0);\n return palette(v * 0.125 + 0.5 + t * 0.05, vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.0, 0.33, 0.67));\n}\n\nvec3 fireFill(vec2 p, float t) {\n float n = fbm(vec2(p.x * 5.0, p.y * 3.0 - t * 1.8), 5);\n float heat = clamp(1.1 - (p.y + 0.3) * 1.6 + (n - 0.5) * 1.2, 0.0, 1.0);\n return vec3(1.0, 0.35, 0.05) * heat * 1.4 + vec3(1.0, 0.85, 0.3) * pow(heat, 3.0) + vec3(0.25, 0.0, 0.0);\n}\n\nvec3 causticsFill(vec2 p, float t) {\n vec2 q = p * 6.0;\n vec2 i = q;\n float c = 1.0;\n for (int n = 0; n < 5; n++) {\n float tn = t * 0.5 * (1.0 - 3.5 / float(n + 1));\n i = q + vec2(cos(tn - i.x) + sin(tn + i.y), sin(tn - i.y) + cos(tn + i.x));\n c += 1.0 / length(vec2(q.x / (sin(i.x + tn) / 0.005), q.y / (cos(i.y + tn) / 0.005)));\n }\n c = 1.17 - pow(c / 5.0, 1.4);\n float light = pow(abs(c), 8.0);\n return clamp(vec3(0.0, 0.3, 0.5) + light * vec3(0.7, 1.0, 1.0), 0.0, 1.0);\n}\n\n// Liquid chrome: a horizon reflection bent by the letters' bevel and a slow warp.\nvec3 chromeFill(vec2 p, float t, vec2 normal) {\n float warp = fbm(p * 3.0 + vec2(t * 0.3, -t * 0.2), 4) - 0.5;\n float y = p.y * 2.5 + normal.y * 1.5 + warp * 1.2 + 0.15 * sin(p.x * 4.0 + t);\n vec3 sky = mix(vec3(0.85, 0.9, 1.0), vec3(0.3, 0.4, 0.6), clamp(y, 0.0, 1.0));\n vec3 ground = mix(vec3(0.25, 0.2, 0.2), vec3(0.05), clamp(-y, 0.0, 1.0));\n vec3 col = y > 0.0 ? sky : ground;\n col += smoothstep(0.06, 0.0, abs(y)) * 0.9;\n return col + pow(max(0.0, normal.x * 0.7 + normal.y * 0.7), 6.0) * 0.8;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float mask = letters(p);\n // A soft bevel from the mask's slope, for chrome's reflections.\n float e = 0.004;\n vec2 normal = vec2(letters(p + vec2(e, 0.0)) - letters(p - vec2(e, 0.0)), letters(p + vec2(0.0, e)) - letters(p - vec2(0.0, e)));\n // Glow and outline: the mask's average and maximum on rings round the point.\n float glow = 0.0;\n float ring = 0.0;\n for (int i = 0; i < 12; i++) {\n float a = float(i) * 0.5236;\n vec2 dir = vec2(cos(a), sin(a));\n glow += letters(p + dir * 0.02) + letters(p + dir * 0.05) * 0.6;\n ring = max(ring, letters(p + dir * uOutline));\n }\n glow /= 19.2;\n vec3 fill = uFill == 0 ? plasmaFill(p, t) : uFill == 1 ? fireFill(p, t) : uFill == 2 ? causticsFill(p, t) : chromeFill(p, t, normal * 2.0);\n fill *= uTint;\n vec3 col = uBackground + fill * glow * uGlow;\n col = mix(col, uOutlineColor, clamp(ring - mask, 0.0, 1.0) * step(0.0001, uOutline));\n col = mix(col, fill, mask);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Inferno\", values: { uFill: 1, uBackground: [0.05, 0.01, 0.0], uGlow: 1.2, uOutline: 0 } },\n { name: \"Pool\", values: { uFill: 2, uBackground: [0.0, 0.08, 0.14], uOutlineColor: [0.7, 0.95, 1] } },\n { name: \"Chrome\", values: { uFill: 3, uBackground: [0.06, 0.06, 0.08], uGlow: 0.3, uOutline: 0.002 } },\n ],\n};\n\n/** Shader effects that fill or animate text, drawn from a text image (see `textImage`). */\nexport const textShaders: ShaderEffect[] = [shaderText];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\nexport const imageKenBurns: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ken-burns\",\n name: \"Ken Burns\",\n description: \"A slow documentary-style pan and zoom across an image, easing in and out and back again.\",\n category: \"image\",\n tags: [\"image\", \"camera\", \"documentary\", \"slideshow\"],\n loop: 12,\n source: glsl(\n `// Ken Burns: a slow, eased pan and zoom across a cover-fitted image, there and back.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uZoomStart; // @control min=1 max=3 default=1.05 label=\"Start zoom\"\nuniform float uZoomEnd; // @control min=1 max=3 default=1.4 label=\"End zoom\"\nuniform float uAngle; // @control min=0 max=360 default=20 label=\"Pan direction (°)\"\nuniform float uDuration; // @control min=2 max=30 default=6 label=\"Duration (s)\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // Cover-fit: the share of the image visible across and up (the test card fits the frame).\n vec2 size = vec2(textureSize(uImage, 0));\n float frameAspect = iResolution.x / iResolution.y;\n float imageAspect = size.x > 1.0 ? size.x / size.y : frameAspect;\n vec2 cover = frameAspect > imageAspect ? vec2(1.0, imageAspect / frameAspect) : vec2(frameAspect / imageAspect, 1.0);\n // 0 → 1 over one duration, back over the next, eased at both ends.\n float k = 0.5 - 0.5 * cos(3.14159265 * iTime / max(uDuration, 0.1));\n float zoom = max(mix(uZoomStart, uZoomEnd, k), 1.0);\n vec2 window = cover / zoom;\n // Pan as far as the window allows in the chosen direction, from one side to the other.\n float a = radians(uAngle);\n vec2 pan = vec2(cos(a), sin(a)) * (1.0 - window) * 0.5 * (2.0 * k - 1.0);\n fragColor = pictureRGBA(uImage, 0.5 + (uv - 0.5) * window + pan);\n}`,\n ),\n presets: [\n { name: \"Push in\", values: { uZoomStart: 1.0, uZoomEnd: 1.5, uAngle: 0 } },\n { name: \"Pull out\", values: { uZoomStart: 1.6, uZoomEnd: 1.05, uAngle: 200 } },\n { name: \"Slow drift\", values: { uZoomStart: 1.2, uZoomEnd: 1.25, uAngle: 0, uDuration: 12 } },\n ],\n};\n\nexport const imageAscii: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ascii\",\n name: \"ASCII art\",\n description: \"An image drawn as text characters picked by brightness, in one ink or the picture's own colours.\",\n category: \"image\",\n tags: [\"image\", \"ascii\", \"text\", \"terminal\", \"retro\"],\n source: glsl(\n `// ASCII art: each cell of the image becomes a character, denser for brighter cells.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uCell; // @control min=4 max=32 default=9 label=\"Cell size (px)\"\nuniform int uColourMode; // @control min=0 max=1 default=0 label=\"Colour (0 ink, 1 original)\"\nuniform vec3 uInk; // @control color default=#A3E635 label=\"Ink\"\nuniform vec3 uBackground; // @control color default=#0A0F0A label=\"Background\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// 5 × 7 glyphs, lightest to densest: bit (x + 5y) of .x holds rows 0–3 (top first), of .y rows 4–6.\nconst ivec2 GLYPHS[10] = ivec2[10](\n ivec2(0, 0), // space\n ivec2(0, 6336), // .\n ivec2(1015808, 0), // -\n ivec2(6336, 198), // :\n ivec2(1020032, 132), // +\n ivec2(31744, 31), // =\n ivec2(1030816, 686), // *\n ivec2(139875, 25378), // %\n ivec2(359754, 10591), // #\n ivec2(718382, 30781) // @\n);\n\n// Whether glyph g has ink at column x (0–4), row y (0–6, top first).\nfloat glyphBit(ivec2 g, int x, int y) {\n if (x < 0 || x > 4 || y < 0 || y > 6) return 0.0;\n int bits = y < 4 ? (g.x >> (x + 5 * y)) : (g.y >> (x + 5 * (y - 4)));\n return float(bits & 1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n // Cells are 7 × 9 units: the 5 × 7 glyph and a unit of margin around it.\n vec2 cell = vec2(uCell, uCell * 9.0 / 7.0);\n vec2 id = floor(fragCoord / cell);\n vec2 local = fract(fragCoord / cell);\n vec4 pic = pictureRGBA(uImage, (id + 0.5) * cell / iResolution.xy);\n vec3 src = pic.rgb;\n float l = pow(clamp(dot(src, vec3(0.2126, 0.7152, 0.0722)), 0.0, 1.0), 0.8);\n int level = int(min(l * 10.0, 9.0));\n int gx = int(floor(local.x * 7.0)) - 1;\n int gy = int(floor((1.0 - local.y) * 9.0)) - 1;\n float ink = glyphBit(GLYPHS[level], gx, gy);\n vec3 tint = uColourMode == 1 ? src * 1.25 : uInk;\n fragColor = vec4(mix(uBackground, tint, ink), pic.a);\n}`,\n ),\n presets: [\n { name: \"Terminal\", values: { uColourMode: 0, uInk: [0.64, 0.9, 0.21], uBackground: [0.04, 0.06, 0.04] } },\n { name: \"Colour\", values: { uColourMode: 1, uBackground: [0.02, 0.02, 0.03] } },\n { name: \"Typewriter\", values: { uColourMode: 0, uInk: [0.1, 0.1, 0.12], uBackground: [0.96, 0.94, 0.88], uCell: 7 } },\n ],\n};\n\nexport const imageShatter: ShaderEffect = {\n kind: \"shader\",\n id: \"image-shatter\",\n name: \"Shatter\",\n description: \"An image breaking into glass-like shards that fly apart, spin and reassemble in a loop.\",\n category: \"image\",\n tags: [\"image\", \"shatter\", \"transition\", \"voronoi\", \"explode\"],\n loop: 5,\n source: glsl(\n `// Shatter: Voronoi shards of the image fly apart, spin and come back together.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform bool uAuto; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uCount; // @control min=3 max=30 default=8 label=\"Shards (across height)\"\nuniform float uSpread; // @control min=0 max=2 default=0.6 label=\"Spread\"\nuniform float uSpin; // @control min=0 max=6.28 default=1.5 label=\"Spin\"\nuniform vec3 uBackground; // @control color default=#0B0B12 label=\"Background\"\n${BACKDROP_CONTROLS}`,\n HASH,\n ROTATE,\n PICTURE,\n `vec2 shardSite(vec2 cell) {\n return cell + 0.15 + 0.7 * hash22(cell);\n}\n\n// The shard (cell) under grid point q, and how far q is from its edge (xy: cell, z: edge gap).\nvec3 shardAt(vec2 q) {\n vec2 base = floor(q);\n float d1 = 1e9;\n float d2 = 1e9;\n vec2 id = base;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 c = base + vec2(float(i), float(j));\n float d = distance(q, shardSite(c));\n if (d < d1) {\n d2 = d1;\n d1 = d;\n id = c;\n } else if (d < d2) {\n d2 = d;\n }\n }\n }\n return vec3(id, d2 - d1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float k = uAuto ? smoothstep(0.2, 0.8, 0.5 - 0.5 * cos(iTime * 6.28318 / 5.0)) : uProgress;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uCount;\n // Shard centres move out from the middle; shards keep their size, so gaps open between them.\n float grow = 1.0 + uSpread * k;\n vec2 base = floor(p / grow);\n vec4 col = vec4(uBackground, uBackdropAlpha);\n float top = -1.0;\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 c = base + vec2(float(i), float(j));\n vec2 site = shardSite(c);\n vec2 h = hash22(c + 41.7);\n vec2 centre = site * grow + (h - 0.5) * 1.2 * k;\n float a = (h.x - 0.5) * 2.0 * uSpin * k;\n // Back to where this pixel would sit in the unbroken image, if it is on this shard.\n vec2 q = rot(-a) * (p - centre) + site;\n vec3 s = shardAt(q);\n if (s.x == c.x && s.y == c.y && h.y > top) {\n top = h.y;\n vec2 uv = q / uCount * iResolution.y / iResolution.xy + 0.5;\n vec4 shard = pictureRGBA(uImage, uv);\n shard.rgb *= 1.0 - 0.35 * k * abs(sin(a));\n shard.rgb += k * 0.35 * smoothstep(0.06, 0.0, s.z);\n col = shard;\n }\n }\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Burst\", values: { uCount: 6, uSpread: 1.4, uSpin: 3 } },\n { name: \"Crackle\", values: { uCount: 18, uSpread: 0.15, uSpin: 0.4 } },\n ],\n};\n\nexport const imageMelt: ShaderEffect = {\n kind: \"shader\",\n id: \"image-melt\",\n name: \"Melt\",\n description: \"An image melting and dripping downwards in slow, noisy runs.\",\n category: \"image\",\n tags: [\"image\", \"melt\", \"drip\", \"psychedelic\", \"distortion\"],\n source: glsl(\n `// Melt: noise-driven runs drag the image downwards.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmount; // @control min=0 max=0.6 default=0.18 label=\"Amount\"\nuniform float uSpeed; // @control min=0 max=2 default=0.35 label=\"Flow speed\"\nuniform float uScale; // @control min=1 max=20 default=6 label=\"Scale\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n FBM,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n // Columns run at different lengths; thin drips ride on top; runs grow towards the bottom.\n float runs = fbm(vec2(uv.x * uScale, t * 0.5), 4);\n float drips = pow(vnoise(vec2(uv.x * uScale * 5.0, t * 0.3 + 7.0)), 3.0);\n float drop = uAmount * (0.7 * runs + 0.6 * drips) * (0.35 + 0.65 * (1.0 - uv.y));\n float wobble = (vnoise(vec2(uv.y * uScale * 2.0 - t, uv.x * uScale)) - 0.5) * uAmount * 0.12;\n vec2 st = clamp(uv + vec2(wobble, drop), 0.0, 1.0);\n vec4 pic = pictureRGBA(uImage, st);\n // A little sheen along the leading edges of the runs.\n vec3 col = pic.rgb + 0.12 * smoothstep(0.55, 0.9, drips) * uAmount * 4.0;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Slow ooze\", values: { uAmount: 0.12, uSpeed: 0.15, uScale: 4 } },\n { name: \"Meltdown\", values: { uAmount: 0.45, uSpeed: 0.8, uScale: 9 } },\n ],\n};\n\nexport const imageRisograph: ShaderEffect = {\n kind: \"shader\",\n id: \"image-risograph\",\n name: \"Risograph\",\n description: \"An image printed in two posterized, slightly misregistered inks on grainy paper.\",\n category: \"image\",\n tags: [\"image\", \"print\", \"riso\", \"editorial\", \"poster\"],\n source: glsl(\n `// Risograph: two posterized ink layers, out of register, on grainy paper.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uLevels; // @control min=2 max=8 default=4 label=\"Levels\"\nuniform vec3 uInkA; // @control color default=#FF48B0 label=\"Ink A\"\nuniform vec3 uInkB; // @control color default=#0078BF label=\"Ink B\"\nuniform float uOffset; // @control min=0 max=20 default=4 label=\"Misregistration (px)\"\nuniform float uGrain; // @control min=0 max=1 default=0.4 label=\"Grain\"\nuniform vec3 uPaper; // @control color default=#F5EFE0 label=\"Paper\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `// Ink density stepped to a few levels, with grain dithering the steps.\nfloat posterize(float d, float levels, float grain) {\n return clamp(floor(d * (levels - 1.0) + 0.5 + grain) / (levels - 1.0), 0.0, 1.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 shift = vec2(uOffset, uOffset * 0.6) / iResolution.xy;\n float levels = float(uLevels);\n float fibre = hash12(fragCoord);\n float mottle = vnoise(fragCoord / 6.0);\n // Two separations: ink A where the picture lacks green, ink B where it lacks red.\n vec4 a = pictureRGBA(uImage, uv + shift);\n vec4 b = pictureRGBA(uImage, uv - shift);\n float dA = posterize(1.0 - a.g, levels, (hash12(fragCoord + 17.0) - 0.5) * uGrain * 0.6);\n float dB = posterize(1.0 - b.r, levels, (hash12(fragCoord + 53.0) - 0.5) * uGrain * 0.6);\n // Ink never lays down evenly: mottled, with paper showing through.\n float cover = 0.9 * (1.0 - uGrain * 0.35 * mottle);\n vec3 col = uPaper * (1.0 - uGrain * 0.08 * fibre);\n col *= mix(vec3(1.0), uInkA, dA * cover);\n col *= mix(vec3(1.0), uInkB, dB * cover);\n fragColor = vec4(col, max(a.a, b.a));\n}`,\n ),\n presets: [\n { name: \"Pink & blue\", values: { uInkA: [1, 0.28, 0.69], uInkB: [0, 0.47, 0.75] } },\n { name: \"Sunflower & teal\", values: { uInkA: [1, 0.71, 0], uInkB: [0, 0.51, 0.54], uLevels: 3 } },\n { name: \"Red & black\", values: { uInkA: [1, 0.25, 0.25], uInkB: [0.15, 0.15, 0.17], uOffset: 2, uGrain: 0.6 } },\n ],\n};\n\nexport const imageThermal: ShaderEffect = {\n kind: \"shader\",\n id: \"image-thermal\",\n name: \"Thermal\",\n description: \"An image seen through a heat camera or night-vision goggles.\",\n category: \"image\",\n tags: [\"image\", \"thermal\", \"night-vision\", \"surveillance\", \"colour\"],\n source: glsl(\n `// Thermal: brightness mapped to a heat palette, or to green night-vision phosphor.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uMode; // @control min=0 max=1 default=0 label=\"Palette (0 thermal, 1 night vision)\"\nuniform float uNoise; // @control min=0 max=0.5 default=0.04 label=\"Noise\"\nuniform float uContrast; // @control min=0.5 max=3 default=1.3 label=\"Contrast\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `vec3 heat(float t) {\n vec3 c = mix(vec3(0.0, 0.0, 0.08), vec3(0.15, 0.0, 0.55), smoothstep(0.0, 0.2, t));\n c = mix(c, vec3(0.75, 0.0, 0.55), smoothstep(0.2, 0.4, t));\n c = mix(c, vec3(1.0, 0.25, 0.0), smoothstep(0.4, 0.6, t));\n c = mix(c, vec3(1.0, 0.8, 0.0), smoothstep(0.6, 0.8, t));\n return mix(c, vec3(1.0, 1.0, 0.9), smoothstep(0.8, 1.0, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // Heat spreads, so take a soft average around the pixel.\n vec2 px = 2.0 / iResolution.xy;\n vec4 src = 0.4 * pictureRGBA(uImage, uv) + 0.15 * (pictureRGBA(uImage, uv + vec2(px.x, 0.0)) + pictureRGBA(uImage, uv - vec2(px.x, 0.0)) +\n pictureRGBA(uImage, uv + vec2(0.0, px.y)) + pictureRGBA(uImage, uv - vec2(0.0, px.y)));\n float l = dot(src.rgb, vec3(0.2126, 0.7152, 0.0722));\n l = clamp((l - 0.5) * uContrast + 0.5, 0.0, 1.0);\n float frame = floor(iTime * 24.0);\n float grain = hash12(fragCoord + frame * 37.1) - 0.5;\n vec3 col;\n if (uMode == 0) {\n col = heat(clamp(l + grain * uNoise, 0.0, 1.0));\n } else {\n float g = clamp(l * 1.2 + grain * uNoise * 2.0, 0.0, 1.0);\n col = vec3(0.12, 1.0, 0.25) * g + vec3(0.02, 0.06, 0.02);\n col *= 0.94 + 0.06 * sin(fragCoord.y * 2.0);\n col *= 0.97 + 0.03 * hash12(vec2(frame, 3.0));\n vec2 d = (uv - 0.5) * vec2(iResolution.x / iResolution.y, 1.0);\n col *= smoothstep(0.75, 0.3, length(d));\n }\n fragColor = vec4(col, src.a);\n}`,\n ),\n presets: [\n { name: \"Thermal\", values: { uMode: 0, uNoise: 0.04, uContrast: 1.3 } },\n { name: \"Night vision\", values: { uMode: 1, uNoise: 0.2, uContrast: 1.8 } },\n ],\n};\n\nexport const imageEdgeGlow: ShaderEffect = {\n kind: \"shader\",\n id: \"image-edge-glow\",\n name: \"Edge glow\",\n description: \"An image's edges traced as glowing neon lines over a dimmed picture, with a travelling pulse.\",\n category: \"image\",\n tags: [\"image\", \"neon\", \"edges\", \"outline\", \"cyber\"],\n loop: 2,\n source: glsl(\n `// Edge glow: Sobel edges as neon lines and a soft halo over the dimmed image.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uThreshold; // @control min=0 max=1 default=0.15 label=\"Threshold\"\nuniform vec3 uGlow; // @control color default=#22D3EE label=\"Glow colour\"\nuniform float uWidth; // @control min=0.5 max=4 default=1.5 label=\"Glow width (px)\"\nuniform float uDim; // @control min=0 max=1 default=0.75 label=\"Dim image\"\nuniform float uPulse; // @control min=0 max=1 default=0.4 label=\"Pulse\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// Brightness and alpha: an edge is where either changes (an icon's outline is in its alpha).\nvec2 lumaAlpha(vec2 uv) {\n vec4 c = pictureRGBA(uImage, uv);\n return vec2(dot(c.rgb, vec3(0.2126, 0.7152, 0.0722)), c.a);\n}\n\n// Sobel edge strength, sampling d apart (in uv).\nfloat sobel(vec2 uv, vec2 d) {\n vec2 tl = lumaAlpha(uv + vec2(-d.x, d.y));\n vec2 t = lumaAlpha(uv + vec2(0.0, d.y));\n vec2 tr = lumaAlpha(uv + d);\n vec2 l = lumaAlpha(uv - vec2(d.x, 0.0));\n vec2 r = lumaAlpha(uv + vec2(d.x, 0.0));\n vec2 bl = lumaAlpha(uv - d);\n vec2 b = lumaAlpha(uv - vec2(0.0, d.y));\n vec2 br = lumaAlpha(uv + vec2(d.x, -d.y));\n vec2 gx = tr + 2.0 * r + br - tl - 2.0 * l - bl;\n vec2 gy = tl + 2.0 * t + tr - bl - 2.0 * b - br;\n return max(length(vec2(gx.x, gy.x)), length(vec2(gx.y, gy.y)));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 d = uWidth / iResolution.xy;\n float line = smoothstep(uThreshold, uThreshold + 0.15, sobel(uv, d));\n float halo = smoothstep(uThreshold, uThreshold + 0.5, sobel(uv, d * 3.0));\n vec2 c = (uv - 0.5) * vec2(iResolution.x / iResolution.y, 1.0);\n float pulse = 1.0 - uPulse * (0.5 + 0.5 * sin(iTime * 3.14159265 - length(c) * 12.0));\n vec4 pic = pictureRGBA(uImage, uv);\n float glow = (line + 0.45 * halo) * pulse;\n vec3 light = uGlow * glow + vec3(1.0) * line * line * 0.35 * pulse;\n // The glow is light added over the picture, so it also shows where the picture is clear.\n float alpha = max(pic.a, clamp(glow, 0.0, 1.0));\n vec3 col = (pic.rgb * (1.0 - uDim) * pic.a + light) / max(alpha, 1e-4);\n fragColor = vec4(col, alpha);\n}`,\n ),\n presets: [\n { name: \"Cyan\", values: { uGlow: [0.13, 0.83, 0.93] } },\n { name: \"Magenta blackout\", values: { uGlow: [0.93, 0.28, 0.6], uDim: 1, uThreshold: 0.1 } },\n ],\n};\n\nexport const imageTiltShift: ShaderEffect = {\n kind: \"shader\",\n id: \"image-tilt-shift\",\n name: \"Tilt-shift\",\n description: \"An image blurred outside a sharp horizontal band, with punchy colour, so it looks like a miniature.\",\n category: \"image\",\n tags: [\"image\", \"blur\", \"miniature\", \"photography\", \"depth\"],\n source: glsl(\n `// Tilt-shift: blur away from a focus band, plus saturation, for the miniature look.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uFocus; // @control min=0 max=1 default=0.45 label=\"Focus position\"\nuniform float uBand; // @control min=0 max=0.6 default=0.12 label=\"Focus band width\"\nuniform float uBlur; // @control min=0 max=30 default=12 label=\"Blur (px)\"\nuniform float uSaturation; // @control min=0 max=2 default=1.4 label=\"Saturation\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float away = smoothstep(uBand * 0.5, uBand * 0.5 + 0.3, abs(uv.y - uFocus));\n float radius = away * uBlur;\n // A 24-tap golden-angle disc.\n // Summed premultiplied, so clear parts of the picture do not darken the blur.\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 24; i++) {\n float fi = float(i);\n float r = sqrt((fi + 0.5) / 24.0) * radius;\n float a = fi * 2.39996;\n vec4 c = pictureRGBA(uImage, uv + r * vec2(cos(a), sin(a)) / iResolution.xy);\n sum += vec4(c.rgb * c.a, c.a);\n }\n vec3 col = sum.rgb / max(sum.a, 1e-4);\n float l = dot(col, vec3(0.2126, 0.7152, 0.0722));\n col = mix(vec3(l), col, uSaturation);\n col = clamp((col - 0.5) * 1.08 + 0.5, 0.0, 1.0);\n fragColor = vec4(col, sum.a / 24.0);\n}`,\n ),\n presets: [\n { name: \"Model village\", values: { uFocus: 0.4, uBand: 0.1, uBlur: 16, uSaturation: 1.6 } },\n { name: \"Subtle\", values: { uBand: 0.25, uBlur: 6, uSaturation: 1.15 } },\n ],\n};\n\nexport const imageSlitScan: ShaderEffect = {\n kind: \"shader\",\n id: \"image-slit-scan\",\n name: \"Slit-scan\",\n description: \"An image smeared into time-stretched streaks, like a slit-scan photograph.\",\n category: \"image\",\n tags: [\"image\", \"slit-scan\", \"smear\", \"experimental\", \"distortion\"],\n source: glsl(\n `// Slit-scan: rows (or columns) squeeze towards a moving slit and smear into streaks.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uDirection; // @control min=0 max=1 default=0 label=\"Direction (0 horizontal, 1 vertical)\"\nuniform float uStretch; // @control min=0 max=1 default=0.45 label=\"Stretch\"\nuniform float uSpeed; // @control min=0 max=3 default=0.6 label=\"Speed\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n // along: the axis the streaks run along; across: the axis the delay varies over.\n vec2 a = uDirection == 0 ? uv : uv.yx;\n float t = iTime * uSpeed;\n float delay = vnoise(vec2(a.y * 7.0, t)) * 0.7 + vnoise(vec2(a.y * 31.0, t * 1.7)) * 0.3;\n float slit = 0.5 + 0.35 * sin(t * 0.7 + delay * 2.0);\n // Squeeze towards the slit (stretching what is there) and drift with the delay.\n float along = slit + (a.x - slit) * (1.0 - uStretch * delay);\n along += uStretch * 0.15 * (delay - 0.5);\n // Smear: average a few taps along the streak.\n // Summed premultiplied, so clear parts of the picture do not darken the smear.\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 8; i++) {\n float s = along - float(i) * uStretch * 0.006;\n vec2 st = uDirection == 0 ? vec2(s, a.y) : vec2(a.y, s);\n vec4 c = pictureRGBA(uImage, st);\n sum += vec4(c.rgb * c.a, c.a);\n }\n fragColor = vec4(sum.rgb / max(sum.a, 1e-4), sum.a / 8.0);\n}`,\n ),\n presets: [\n { name: \"Drift\", values: { uDirection: 0, uStretch: 0.3, uSpeed: 0.3 } },\n { name: \"Waterfall\", values: { uDirection: 1, uStretch: 0.7, uSpeed: 1.2 } },\n ],\n};\n\nexport const imageMosaic: ShaderEffect = {\n kind: \"shader\",\n id: \"image-mosaic\",\n name: \"Mosaic flip\",\n description: \"Hexagonal or triangular tiles flipping over from the left to reveal an image, then back.\",\n category: \"image\",\n tags: [\"image\", \"reveal\", \"transition\", \"tiles\", \"hexagon\"],\n loop: 6,\n source: glsl(\n `// Mosaic flip: tiles turn over in a wave from the left, background on one face, image on the other.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uShape; // @control min=0 max=1 default=0 label=\"Tile shape (0 hexagon, 1 triangle)\"\nuniform float uSize; // @control min=10 max=160 default=48 label=\"Tile size (px)\"\nuniform bool uAuto; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=1 label=\"Progress (when still)\"\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `// Hexagon tiles 1 unit across the flats: h is the offset from the tile's centre.\nvoid hexTile(vec2 p, out vec2 h, out vec2 centre) {\n vec2 s = vec2(1.0, 1.7320508);\n vec2 a = (floor(p / s) + 0.5) * s;\n vec2 b = (floor((p - 0.5 * s) / s) + 1.0) * s;\n centre = dot(p - a, p - a) < dot(p - b, p - b) ? a : b;\n h = p - centre;\n}\n\n// 0 at a hexagon's centre, 1 on its edge.\nfloat hexEdge(vec2 h) {\n h = abs(h);\n return max(h.x, dot(h, vec2(0.5, 0.8660254))) * 2.0;\n}\n\n// Triangle tiles with sides of 1 unit; up is 1 for upward-pointing tiles, -1 for downward.\nvoid triTile(vec2 p, out vec2 h, out vec2 centre, out float up) {\n vec2 q = vec2(p.x - p.y * 0.5773503, p.y * 1.1547005);\n vec2 cell = floor(q);\n vec2 f = q - cell;\n up = f.x + f.y < 1.0 ? 1.0 : -1.0;\n vec2 cq = cell + (up > 0.0 ? vec2(1.0 / 3.0) : vec2(2.0 / 3.0));\n centre = vec2(cq.x + cq.y * 0.5, cq.y * 0.8660254);\n h = p - centre;\n}\n\n// 0 at a triangle's centre, 1 on its edge.\nfloat triEdge(vec2 h, float up) {\n h *= up;\n float e = max(-h.y, max(dot(h, vec2(0.8660254, 0.5)), dot(h, vec2(-0.8660254, 0.5))));\n return e / 0.2886751;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float k = uAuto ? smoothstep(0.05, 0.95, 0.5 - 0.5 * cos(iTime * 6.28318 / 6.0)) : uProgress;\n vec2 p = fragCoord / uSize;\n vec2 h;\n vec2 centre;\n float up = 1.0;\n if (uShape == 0) {\n hexTile(p, h, centre);\n } else {\n triTile(p, h, centre, up);\n }\n // Each tile turns over in its own moment, sweeping left to right with a little jitter.\n float start = centre.x * uSize / iResolution.x * 0.75 + hash12(centre * 7.31) * 0.15;\n float flip = smoothstep(0.0, 1.0, clamp((k * 1.35 - start) / 0.35, 0.0, 1.0));\n float squash = abs(cos(flip * 3.14159265));\n vec2 hf = vec2(h.x / max(squash, 0.001), h.y);\n float e = uShape == 0 ? hexEdge(hf) : triEdge(hf, up);\n float gap = 0.1 * (1.0 - flip);\n vec4 col = vec4(uBackground * 0.6, uBackdropAlpha);\n if (e < 1.0 - gap + 0.001) {\n vec4 face = flip < 0.5\n ? vec4(uBackground * (0.9 + 0.2 * hash12(centre * 3.17)) + 0.04, uBackdropAlpha)\n : pictureRGBA(uImage, (centre + hf) * uSize / iResolution.xy);\n col = vec4(face.rgb * (0.5 + 0.5 * squash), face.a);\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Hexagons\", values: { uShape: 0, uSize: 48 } },\n { name: \"Triangles\", values: { uShape: 1, uSize: 64 } },\n ],\n};\n\nexport const imageChromaticLens: ShaderEffect = {\n kind: \"shader\",\n id: \"image-chromatic-lens\",\n name: \"Chromatic lens\",\n description: \"An image through a cheap wide lens: barrel distortion and colour fringes growing towards the edges.\",\n category: \"image\",\n tags: [\"image\", \"lens\", \"aberration\", \"distortion\", \"vintage\"],\n source: glsl(\n `// Chromatic lens: barrel distortion with red, green and blue bent by different amounts.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uDistortion; // @control min=-0.5 max=1 default=0.25 label=\"Distortion\"\nuniform float uAberration; // @control min=0 max=0.1 default=0.025 label=\"Aberration\"\nuniform float uVignette; // @control min=0 max=1 default=0.4 label=\"Vignette\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// Where a lens with barrel strength k shows the point c (centred, aspect-corrected) from.\nvec2 lens(vec2 c, float k, vec2 aspect) {\n float r2 = dot(c, c);\n // Zoom in to keep the corners filled when barrelling.\n float fill = 1.0 + max(k, 0.0) * 0.3;\n return 0.5 + c * (1.0 + k * r2) / fill / aspect;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 aspect = vec2(iResolution.x / iResolution.y, 1.0);\n vec2 c = (uv - 0.5) * aspect;\n vec4 r = pictureRGBA(uImage, lens(c, uDistortion + uAberration, aspect));\n vec4 g = pictureRGBA(uImage, lens(c, uDistortion, aspect));\n vec4 b = pictureRGBA(uImage, lens(c, uDistortion - uAberration, aspect));\n vec3 col = vec3(r.r, g.g, b.b);\n col *= 1.0 - uVignette * smoothstep(0.25, 0.95, length(c));\n fragColor = vec4(col, max(max(r.a, g.a), b.a));\n}`,\n ),\n presets: [\n { name: \"Fisheye\", values: { uDistortion: 0.7, uAberration: 0.04, uVignette: 0.6 } },\n { name: \"Fringe only\", values: { uDistortion: 0, uAberration: 0.05, uVignette: 0.2 } },\n ],\n};\n\nexport const imageOilPaint: ShaderEffect = {\n kind: \"shader\",\n id: \"image-oil-paint\",\n name: \"Oil paint\",\n description: \"An image repainted in flat, edge-keeping brush dabs, like an oil painting.\",\n category: \"image\",\n tags: [\"image\", \"painterly\", \"artistic\", \"kuwahara\", \"filter\"],\n source: glsl(\n `// Oil paint: a four-sector Kuwahara filter, each pixel takes the calmest neighbourhood's colour.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform int uRadius; // @control min=1 max=8 default=4 label=\"Brush radius (px)\"\nuniform float uSharpness; // @control min=0.5 max=8 default=4 label=\"Sharpness\"\nuniform float uSaturation; // @control min=0 max=2 default=1.15 label=\"Saturation\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 px = 1.0 / iResolution.xy;\n // Sums of colour and colour² over four overlapping squares: down-left, down-right, up-left, up-right.\n vec3 m0 = vec3(0.0), m1 = vec3(0.0), m2 = vec3(0.0), m3 = vec3(0.0);\n vec3 s0 = vec3(0.0), s1 = vec3(0.0), s2 = vec3(0.0), s3 = vec3(0.0);\n for (int j = 0; j <= 8; j++) {\n if (j > uRadius) break;\n for (int i = 0; i <= 8; i++) {\n if (i > uRadius) break;\n vec2 o = vec2(float(i), float(j)) * px;\n vec3 c = picture(uImage, uv + vec2(-o.x, -o.y));\n m0 += c;\n s0 += c * c;\n c = picture(uImage, uv + vec2(o.x, -o.y));\n m1 += c;\n s1 += c * c;\n c = picture(uImage, uv + vec2(-o.x, o.y));\n m2 += c;\n s2 += c * c;\n c = picture(uImage, uv + o);\n m3 += c;\n s3 += c * c;\n }\n }\n float n = float((uRadius + 1) * (uRadius + 1));\n m0 /= n; m1 /= n; m2 /= n; m3 /= n;\n // Weight each square by how calm (low-variance) it is; sharpness sets how strongly the calmest wins.\n vec4 v = vec4(\n dot(abs(s0 / n - m0 * m0), vec3(1.0)),\n dot(abs(s1 / n - m1 * m1), vec3(1.0)),\n dot(abs(s2 / n - m2 * m2), vec3(1.0)),\n dot(abs(s3 / n - m3 * m3), vec3(1.0))\n );\n vec4 w = pow(v * 100.0 + 1e-3, vec4(-uSharpness));\n vec3 col = (m0 * w.x + m1 * w.y + m2 * w.z + m3 * w.w) / (w.x + w.y + w.z + w.w);\n float l = dot(col, vec3(0.2126, 0.7152, 0.0722));\n col = mix(vec3(l), col, uSaturation);\n fragColor = vec4(col, pictureRGBA(uImage, uv).a);\n}`,\n ),\n presets: [\n { name: \"Broad strokes\", values: { uRadius: 7, uSharpness: 6, uSaturation: 1.3 } },\n { name: \"Watercolour\", values: { uRadius: 3, uSharpness: 1.5, uSaturation: 0.9 } },\n ],\n};\n\n/** More image treatments: each takes an image control and changes the picture. */\nexport const imageTreatments: ShaderEffect[] = [\n imageKenBurns,\n imageAscii,\n imageShatter,\n imageMelt,\n imageRisograph,\n imageThermal,\n imageEdgeGlow,\n imageTiltShift,\n imageSlitScan,\n imageMosaic,\n imageChromaticLens,\n imageOilPaint,\n];\n","import {\n checkControlValue,\n controlFromDeclaration,\n hexToRgb,\n rgbToHex,\n type ControlDef,\n type ControlType,\n type ControlValue,\n} from \"../shader/controls.js\";\nimport type { SvgMotion } from \"../vector/motion.js\";\nimport type { SvgTrigger } from \"../vector/svg.js\";\n\n/** What an effect is for, used to group the catalog. */\nexport type EffectCategory =\n | \"gradient\"\n | \"organic\"\n | \"pattern\"\n | \"light\"\n | \"space\"\n | \"retro\"\n | \"image\"\n | \"overlay\"\n | \"text\"\n | \"morph\"\n | \"interaction\"\n | \"pyrotechnics\"\n | \"timewarp\"\n | \"melt\"\n | \"electric\"\n | \"transition\"\n | \"loader\"\n | \"data\"\n | \"icon\";\n\n/** Every category, in the order the catalog lists them. */\nexport const EFFECT_CATEGORIES: readonly EffectCategory[] = [\n \"gradient\",\n \"organic\",\n \"pattern\",\n \"light\",\n \"space\",\n \"retro\",\n \"image\",\n \"overlay\",\n \"text\",\n \"morph\",\n \"interaction\",\n \"pyrotechnics\",\n \"timewarp\",\n \"melt\",\n \"electric\",\n \"transition\",\n \"loader\",\n \"data\",\n \"icon\",\n];\n\n/** Named control values: a look an effect can be switched to. */\nexport interface EffectPreset {\n name: string;\n values: Record<string, ControlValue>;\n}\n\ninterface EffectBase {\n /** Stable id, kebab-case: `aurora`, `image-glitch`. */\n id: string;\n name: string;\n /** One sentence: what it looks like. */\n description: string;\n category: EffectCategory;\n tags: readonly string[];\n presets?: readonly EffectPreset[];\n}\n\n/**\n * A WebGL2 fragment shader (Shadertoy-style `mainImage`). Its controls are the\n * `// @control` uniforms in `source`; run it with `ShaderRenderer`,\n * `ShaderFrames`, `ThumbnailPool`, `recordGif` or `standaloneHtml`.\n */\nexport interface ShaderEffect extends EffectBase {\n kind: \"shader\";\n source: string;\n /** Seconds after which it repeats exactly, when it loops seamlessly. */\n loop?: number;\n /**\n * Draws over other content: `fragColor.a` is coverage (0 where there is\n * nothing to draw), so render it on a transparent canvas\n * (`ShaderRenderer`'s `alpha` option) to layer it over a page or picture.\n */\n transparent?: boolean;\n}\n\n/**\n * A control of a vector effect, declared in a list rather than in the\n * picture (see {@link VectorEffect.controls}). The same shape as a shader's\n * controls (see `ControlDef`) less what only sources have; `vec3` colours\n * are written into the picture as `#rrggbb`.\n */\nexport type VectorControl = Pick<ControlDef, \"name\" | \"type\" | \"default\"> &\n Partial<Pick<ControlDef, \"label\" | \"color\" | \"min\" | \"max\" | \"step\">>;\n\n/**\n * An animated SVG picture (see `SvgMotion`) whose controls are declared in\n * the picture itself, the way a shader's are declared in its source. The\n * first `{{name: type …}}` declares a control and every `{{name}}` is\n * replaced by its value (see {@link vectorControls} and\n * {@link renderVectorEffect}); run the result with `SvgPlayer`.\n */\nexport interface VectorEffect extends EffectBase {\n kind: \"vector\";\n motion: SvgMotion;\n /**\n * Controls declared outside the picture, for effects written before\n * controls were declared inline. A control declared in the picture wins\n * over one of the same name here.\n */\n controls?: readonly VectorControl[];\n /**\n * More placeholders worked out from the control values (a bar's height\n * from its value, say), filled in after the controls.\n */\n derived?: (values: Record<string, ControlValue>) => Record<string, string | number>;\n /** Ms to rest on the last frame before it loops (default 600). */\n hold?: number;\n /**\n * Plays in answer to the pointer rather than on a loop: pass it to\n * `SvgPlayer` (`{ trigger: effect.trigger }`). Click-triggered pictures\n * change on steps, each click playing the next.\n */\n trigger?: SvgTrigger;\n}\n\nexport type EffectDefinition = ShaderEffect | VectorEffect;\n\n/** The types a vector effect's `{{name: type …}}` placeholder can declare. */\nexport const VECTOR_CONTROL_TYPES = [\"float\", \"int\", \"bool\", \"color\", \"text\"] as const;\n\n/**\n * A placeholder: `{{name}}`, or a declaration `{{name: type attributes}}`\n * whose attributes are a shader `@control`'s (`min`, `max`, `step`,\n * `default`, `label`). Quote values with spaces in single quotes inside an\n * SVG attribute: `fill=\"{{accent: color default=#6366F1 label='Accent'}}\"`.\n */\nconst PLACEHOLDER = /\\{\\{\\s*([A-Za-z_]\\w*)\\s*(?::\\s*([A-Za-z0-9]*)([^}]*))?\\}\\}/g;\n\n/** Every string in a motion, the markup first, then each animation's values in order. */\nfunction motionStrings(motion: SvgMotion): string[] {\n const out: string[] = [];\n const walk = (v: unknown) => {\n if (typeof v === \"string\") out.push(v);\n else if (Array.isArray(v)) v.forEach(walk);\n else if (v && typeof v === \"object\") Object.values(v).forEach(walk);\n };\n walk(motion);\n return out;\n}\n\n/**\n * The controls a vector effect's picture declares, in the order they are\n * first declared: `{{word: text default=SLOP label=Word}}`, `{{accent:\n * color default=#6366F1}}`, `{{width: float min=2 max=20 default=8 step=1}}`,\n * `{{shadow: bool default=true}}`. A name declared twice counts once (the\n * first wins), and declarations with an unknown type are left out (see\n * {@link vectorControlIssues}). A control only `derived` reads can be\n * declared in an XML comment: `<!-- {{drip: float default=1}} -->`.\n */\nexport function vectorControls(motion: SvgMotion): ControlDef[] {\n const controls: ControlDef[] = [];\n const seen = new Set<string>();\n for (const text of motionStrings(motion)) {\n for (const [, name, type, attributes] of text.matchAll(PLACEHOLDER)) {\n if (type === undefined || seen.has(name!) || !(VECTOR_CONTROL_TYPES as readonly string[]).includes(type)) continue;\n seen.add(name!);\n const colour = type === \"color\";\n controls.push(controlFromDeclaration(name!, colour ? \"vec3\" : (type as ControlType), `${attributes}${colour ? \" color\" : \"\"}`, controls.length + 1));\n }\n }\n return controls;\n}\n\n/** A vector effect's controls: those its picture declares, then any in its `controls` list it does not. */\nexport function vectorEffectControls(effect: Pick<VectorEffect, \"motion\" | \"controls\">): ControlDef[] {\n const declared = vectorControls(effect.motion);\n const names = new Set(declared.map((c) => c.name));\n const listed = (effect.controls ?? []).filter((c) => !names.has(c.name));\n return [...declared, ...listed.map((c, i) => vectorControlDef(c, declared.length + i + 1))];\n}\n\n/**\n * Problems with a picture's placeholders, as sentences: declarations of an\n * unknown type, and a name declared twice in different ways.\n */\nexport function vectorControlIssues(motion: SvgMotion): string[] {\n const issues: string[] = [];\n const declarations = new Map<string, string>();\n for (const text of motionStrings(motion)) {\n for (const [whole, name, type] of text.matchAll(PLACEHOLDER)) {\n if (type === undefined) continue;\n if (!(VECTOR_CONTROL_TYPES as readonly string[]).includes(type))\n issues.push(`${whole}: a control's type is one of ${VECTOR_CONTROL_TYPES.join(\", \")}`);\n else if (declarations.has(name!) && declarations.get(name!) !== whole)\n issues.push(`\"${name}\" is declared twice; declare it once and write {{${name}}} everywhere else`);\n else declarations.set(name!, whole);\n }\n }\n return issues;\n}\n\n/** A vector control's value written into the picture: colours as hex, vectors space-separated, the rest as they are. */\nfunction written(control: Pick<ControlDef, \"color\">, value: ControlValue): string | number | boolean {\n if (control.color && Array.isArray(value)) return rgbToHex(value);\n if (Array.isArray(value)) return value.join(\" \");\n return value;\n}\n\nconst escapeMarkup = (text: string) =>\n text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#39;\");\n\n/** A vector control as a full `ControlDef`, so editors treat both kinds of effect alike. */\nexport function vectorControlDef(control: VectorControl, line = 0): ControlDef {\n const min = control.min ?? 0;\n return {\n name: control.name,\n type: control.type,\n label: control.label ?? control.name,\n color: control.color ?? false,\n min,\n max: control.max ?? Math.max(min + 1, 1),\n step: control.step ?? (control.type === \"int\" ? 1 : 0.01),\n default: control.default,\n line,\n };\n}\n\n/** What a vector effect's colour control takes to paint in the surrounding text's colour (CSS `color`). */\nexport const CURRENT_COLOR = \"currentColor\";\n\n/** Whether a colour value is `currentColor` (in any case), which vector effects keep as it is. */\nexport function isCurrentColor(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().toLowerCase() === \"currentcolor\";\n}\n\n/**\n * A vector effect's motion with its controls filled in. A string that is\n * only a placeholder (an animation's `\"{{width}}\"`) becomes the value\n * itself, so numbers stay numbers; elsewhere a placeholder becomes its text,\n * escaped in the markup so any text is safe to show. Comments are dropped\n * from the markup. Colours also take CSS colours (see `parseColor`) and\n * `currentColor`, which paints in the surrounding text's colour (`derived`\n * then sees the string \"currentColor\"); missing values, and values a\n * control cannot take, use defaults. Placeholders no control or derived\n * value fills stay put.\n */\nexport function renderVectorEffect(\n effect: Pick<VectorEffect, \"motion\" | \"controls\" | \"derived\">,\n values: Record<string, ControlValue> = {},\n): SvgMotion {\n const filled: Record<string, ControlValue> = {};\n const placeholders = new Map<string, string | number | boolean>();\n for (const control of vectorEffectControls(effect)) {\n const given = values[control.name];\n if (control.color && isCurrentColor(given)) {\n filled[control.name] = CURRENT_COLOR;\n placeholders.set(control.name, CURRENT_COLOR);\n continue;\n }\n const check = given === undefined ? undefined : checkControlValue(control, given);\n filled[control.name] = check?.ok ? check.value : control.default;\n placeholders.set(control.name, written(control, filled[control.name]!));\n }\n for (const [name, value] of Object.entries(effect.derived?.(filled) ?? {})) placeholders.set(name, value);\n const fill = (text: string, markup: boolean): string | number | boolean => {\n const whole = /^\\{\\{\\s*([A-Za-z_]\\w*)\\s*(?::[^}]*)?\\}\\}$/.exec(text);\n if (!markup && whole && placeholders.has(whole[1]!)) return placeholders.get(whole[1]!)!;\n return text.replace(PLACEHOLDER, (match, name: string) => {\n if (!placeholders.has(name)) return match;\n const value = String(placeholders.get(name));\n return markup ? escapeMarkup(value) : value;\n });\n };\n const walk = (v: unknown): unknown => {\n if (typeof v === \"string\") return fill(v, false);\n if (Array.isArray(v)) return v.map(walk);\n if (v && typeof v === \"object\") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));\n return v;\n };\n const { svg, ...rest } = effect.motion;\n // Comments hold declarations, not picture, and a value with \"--\" in one would break the markup.\n return { svg: fill(svg.replace(/<!--[\\s\\S]*?-->/g, \"\"), true) as string, ...(walk(rest) as Omit<SvgMotion, \"svg\">) };\n}\n\n/** A colour control for vector effects. */\nexport function colorControl(name: string, hex: string, label?: string): VectorControl {\n return { name, type: \"vec3\", color: true, default: hexToRgb(hex) ?? [1, 1, 1], label: label ?? name };\n}\n\n/** A number control for vector effects. */\nexport function numberControl(\n name: string,\n value: number,\n min: number,\n max: number,\n label?: string,\n step?: number,\n): VectorControl {\n return { name, type: \"float\", default: value, min, max, label: label ?? name, step };\n}\n","import { rgbToHex } from \"../shader/controls.js\";\nimport type { SvgAnimation, SvgMotion } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport { CURRENT_COLOR, isCurrentColor, type VectorEffect } from \"./types.js\";\n\n/*\n * Text effects take any word or phrase: `derived` works out a font size from\n * its length (see `textWidthEm`) and, where it can, `textLength` stretches it\n * to the width that size predicts, so it fills the same box in any font.\n */\n\nconst r1 = (n: number) => Math.round(n * 10) / 10;\n\n/** A line fitted to `width` units, at most `max` high: its font size, width and left edge (centred on 200). */\nfunction fit(text: string, width: number, max: number, ems = textWidthEm(text)) {\n const e = Math.max(0.6, ems);\n const size = Math.min(max, width / e);\n return { size: r1(size), length: r1(e * size), left: r1(200 - (e * size) / 2) };\n}\n\n/** Letters as code points, so emoji and accents count once. */\nconst lettersOf = (text: unknown) => Array.from(String(text));\n\n/**\n * `a` mixed `t` of the way to `b`, colours as written by vector controls\n * ([r, g, b] 0–1). Mixed with `currentColor`, the browser mixes them (CSS `color-mix`).\n */\nconst mixHex = (a: unknown, b: unknown, t: number) => {\n if (isCurrentColor(a) || isCurrentColor(b)) {\n const css = (c: unknown) => (isCurrentColor(c) ? CURRENT_COLOR : rgbToHex((Array.isArray(c) ? c : [1, 1, 1]) as number[]));\n return `color-mix(in srgb, ${css(a)}, ${css(b)} ${Math.round(t * 100)}%)`;\n }\n const x = (Array.isArray(a) ? a : [1, 1, 1]) as number[];\n const y = (Array.isArray(b) ? b : [1, 1, 1]) as number[];\n return rgbToHex([0, 1, 2].map((i) => x[i]! + (y[i]! - x[i]!) * t));\n};\n\n/** Instant changes: the attribute holds each value from its time on (flicker, jumps). */\nconst holds = (id: string, attr: string, keys: readonly (readonly [number, string | number])[]): SvgAnimation[] =>\n keys.map(([delay, value]) => ({ id, attrs: { [attr]: [value, value] }, delay, ms: 0 }));\n\n/** A derived number in an animation's numeric field (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\nconst MONO = `ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace`;\n/** A monospace letter's advance, in ems. */\nconst MONO_EM = 0.6;\nconst HEAVY = `'Arial Black', 'Helvetica Neue', Impact, system-ui, sans-serif`;\nconst SANS = `system-ui, 'Helvetica Neue', Arial, sans-serif`;\nconst SCRIPT = `'Pacifico', 'Brush Script MT', 'Segoe Script', 'Snell Roundhand', cursive`;\n\n/** Text effects' cap height, in ems: near enough for the heavy, plain, monospace and script faces they use. */\nconst CAP = 0.72;\n\n/**\n * The controls every text effect shares, declared after its own: its\n * typeface (`font` takes any CSS font-family, `inherit` the surrounding\n * text's), and `inline`, which sets it in a line of text (see {@link frame}).\n */\nconst typeface = (font: string, weight: number) =>\n `{{font: text default=\"${font}\" label='Font'}} {{weight: int min=100 max=900 default=${weight} step=100 label='Weight'}} {{inline: bool default=false label='Inline'}}`;\n\n/**\n * What a text effect's picture frames: its whole 400 × 200 stage, or with\n * `inline` just its text, from cap height down to the baseline, so it sits\n * on the line like a word would. Inline, the backdrop goes and everything\n * else (glows, underlines, drops) spills over the text around it.\n */\nfunction frame(\n v: Record<string, unknown>,\n left: number,\n width: number,\n base: number,\n size: number,\n overhang: Overhang = [0.05, 0, DESCENT, 0],\n) {\n const spill = overhang.map((e) => Math.round(Math.max(0, e) * 100) / 100).join(\" \");\n return v.inline\n ? { viewBox: `${r1(left)} ${r1(base - size * CAP)} ${r1(width)} ${r1(size * CAP)}`, overflow: \"visible\", backdrop: 0, overhang: spill }\n : { viewBox: \"0 0 400 200\", overflow: \"hidden\", backdrop: 1, overhang: spill };\n}\n\n/**\n * How far a text effect spills past its inline box at rest (top, right,\n * bottom, left), in ems of its font size: descenders, outlines, glows,\n * underlines. Written on the picture as `data-overhang` (see `svgInlineLayout`).\n */\ntype Overhang = [number, number, number, number];\n\n/** How far descenders reach below the baseline, in ems. */\nconst DESCENT = 0.25;\n\n/** `overhang` grown by `by` ems on every side (a glow's or an outline's reach). */\nconst glowing = (overhang: Overhang, by: number): Overhang => overhang.map((e) => e + by) as Overhang;\n\n/** The width a line fits in: inline, any (the picture widens with the text instead of the text shrinking). */\nconst room = (v: Record<string, unknown>, width: number) => (v.inline ? Infinity : width);\n\n/** The caret's blinks after typing: on and off every 500 ms. */\nconst BLINKS = 7;\n\nexport const typewriter: VectorEffect = {\n kind: \"vector\",\n id: \"typewriter\",\n name: \"Typewriter\",\n description: \"Letters typed out one at a time behind a block caret, which then blinks.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"typing\", \"terminal\", \"caption\"],\n hold: 300,\n presets: [\n { name: \"Terminal\", values: { paper: [0.03, 0.05, 0.04], ink: [0.3, 1, 0.45] } },\n { name: \"Paper\", values: { paper: [0.98, 0.95, 0.88], ink: [0.15, 0.13, 0.12], pace: 120 } },\n ],\n // Monospace, so the caret lands after the last letter however long the text is.\n derived: (v) => {\n const count = Math.max(1, lettersOf(v.text).length);\n const size = r1(Math.min(44, room(v, 340) / ((count + 1) * MONO_EM)));\n const left = r1(200 - ((count + 1) * MONO_EM * size) / 2);\n const typing = Math.round(count * Number(v.pace));\n const base = r1(100 + size * 0.35);\n return {\n ...frame(v, left, (count + 1) * MONO_EM * size, base, size, [0.08, 0, DESCENT, 0]),\n size,\n left,\n base,\n end: r1(left + count * MONO_EM * size),\n typing,\n ...Object.fromEntries(Array.from({ length: BLINKS }, (_, k) => [`blink${k}`, typing + k * 500])),\n };\n },\n motion: {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='Hello, world.' label='Text'}} {{paper: color default=#111827 label='Background'}} {{ink: color default=#F9FAFB label='Text colour'}} {{pace: float min=30 max=300 default=90 step=5 label='Ms per letter'}} ${typeface(MONO, 400)} --><rect width=\"400\" height=\"200\" fill=\"{{paper}}\" opacity=\"{{backdrop}}\"/><text id=\"typed\" x=\"{{left}}\" y=\"{{base}}\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{ink}}\" xml:space=\"preserve\">{{text}}</text><text id=\"caret\" x=\"{{end}}\" y=\"{{base}}\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{ink}}\" opacity=\"0\">▌</text></svg>`,\n animate: [\n { id: \"typed\", write: \"{{text}}\", caret: \"▌\", ms: n(\"typing\"), ease: \"linear\" },\n // Hidden while the writer shows its own caret, then blinking where it stopped.\n ...holds(\"caret\", \"opacity\", [[0, 0], ...Array.from({ length: BLINKS }, (_, k) => [n(`blink${k}`), k % 2 ? 0 : 1] as const)]),\n ],\n },\n};\n\nexport const scrambleText: VectorEffect = {\n kind: \"vector\",\n id: \"scramble-text\",\n name: \"Scramble text\",\n description: \"Random glyphs flickering, then settling into the real word letter by letter, left to right.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"decode\", \"hacker\", \"cyber\", \"reveal\"],\n hold: 1200,\n presets: [\n { name: \"Matrix\", values: { background: [0, 0.03, 0.01], ink: [0.4, 1, 0.5], accent: [0.1, 0.7, 0.25], glyphs: \"01\" } },\n { name: \"Amber\", values: { background: [0.08, 0.04, 0], ink: [1, 0.72, 0.2], accent: [0.9, 0.4, 0.05] } },\n ],\n derived: (v) => {\n const count = Math.max(1, lettersOf(v.text).length);\n const size = r1(Math.min(60, room(v, 360) / (count * MONO_EM)));\n const width = r1(count * MONO_EM * size);\n const base = r1(100 + size * 0.35);\n return { size, base, barX: r1(200 - width / 2), barY: r1(base + size * 0.3), barW: width, decode: Math.round(count * Number(v.pace)), glowWide: Number(v.glow) * 2, ...frame(v, 200 - width / 2, width, base, size, glowing([0.08, 0, Math.max(DESCENT, 0.3 + 3 / size), 0], (Number(v.glow) * 4) / size)) };\n },\n motion: {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='ACCESS GRANTED' label='Text'}} {{glyphs: text default='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&@$*+' label='Scramble glyphs'}} {{background: color default=#05070D label='Background'}} {{ink: color default=#E2E8F0 label='Text colour'}} {{accent: color default=#22D3EE label='Accent'}} {{pace: float min=20 max=250 default=70 step=5 label='Ms per letter'}} {{glow: float min=0 max=6 default=2 step=0.5 label='Glow'}} ${typeface(MONO, 700)} --><defs><filter id=\"glow\" x=\"-20%\" y=\"-50%\" width=\"140%\" height=\"200%\"><feGaussianBlur stdDeviation=\"{{glowWide}}\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/><text id=\"word\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{ink}}\" filter=\"url(#glow)\" xml:space=\"preserve\">{{text}}</text><rect id=\"bar\" x=\"{{barX}}\" y=\"{{barY}}\" width=\"0\" height=\"3\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n // Pure noise for a moment (the scramble runs before the change starts), then it decodes.\n { id: \"word\", write: \"{{text}}\", scramble: \"{{glyphs}}\", delay: 500, ms: n(\"decode\"), ease: \"linear\" },\n { id: \"bar\", attrs: { width: [0, n(\"barW\")] }, delay: 500, ms: n(\"decode\"), ease: \"linear\" },\n ],\n },\n};\n\n/** Kinetic stagger's letter slots: one element per letter, so each can move on its own. */\nconst SLOTS = 20;\n\nexport const kineticStagger: VectorEffect = {\n kind: \"vector\",\n id: \"kinetic-stagger\",\n name: \"Kinetic stagger\",\n description: \"Each letter springs up into place in turn, rising, turning and overshooting, then an underline sweeps beneath.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"kinetic\", \"typography\", \"headline\", \"intro\"],\n hold: 1200,\n presets: [\n { name: \"Poster\", values: { background: [0.98, 0.87, 0.2], ink: [0.07, 0.07, 0.07], accent: [0.9, 0.15, 0.2] } },\n { name: \"Midnight\", values: { background: [0.04, 0.05, 0.12], ink: [0.95, 0.96, 1], accent: [0.55, 0.45, 1], stagger: 80 } },\n ],\n // Up to SLOTS letters, each centred in its estimated advance; unused slots stay empty.\n derived: (v) => {\n const letters = lettersOf(v.text).slice(0, SLOTS);\n const widths = letters.map((c) => textWidthEm(c));\n const ems = Math.max(0.6, widths.reduce((a, b) => a + b, 0));\n const size = Math.min(92, room(v, 370) / ems);\n const base = 100 + size * 0.35;\n const stagger = Number(v.stagger);\n const out: Record<string, string | number> = {\n ...frame(v, 200 - (ems * size) / 2, ems * size, base, size, [0.15, 0, Math.max(DESCENT, 0.2 + 6 / size), 0]),\n size: r1(size),\n base: r1(base),\n rise: r1(base - size * 0.1),\n drop: r1(base + size * 0.6),\n lineX: r1(200 - (ems * size) / 2),\n lineY: r1(base + size * 0.2),\n lineW: r1(ems * size),\n lineAt: Math.round(letters.length * stagger + 400),\n };\n let x = 200 - (ems * size) / 2;\n for (let i = 0; i < SLOTS; i++) {\n const w = (widths[i] ?? 0) * size;\n out[`c${i}`] = letters[i]?.trim() ?? \"\";\n out[`x${i}`] = r1(x + w / 2);\n out[`d${i}`] = Math.round(i * stagger);\n out[`e${i}`] = Math.round(i * stagger + 380);\n x += w;\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='Kinetic' label='Text'}} {{background: color default=#F8FAFC label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#F43F5E label='Underline'}} {{stagger: float min=20 max=200 default=55 step=5 label='Ms between letters'}} ${typeface(HEAVY, 900)} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/>${Array.from(\n { length: SLOTS },\n (_, i) =>\n `<text id=\"l${i}\" text-anchor=\"middle\" transform=\"translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)\" opacity=\"0\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{ink}}\">{{c${i}}}</text>`,\n ).join(\"\")}<rect id=\"line\" x=\"{{lineX}}\" y=\"{{lineY}}\" width=\"0\" height=\"6\" rx=\"3\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n ...Array.from({ length: SLOTS }, (_, i): SvgAnimation[] => [\n {\n id: `l${i}`,\n attrs: { transform: [`translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)`, `translate({{x${i}}} {{rise}}) rotate(5) scale(1.12)`], opacity: [0, 1] },\n delay: n(`d${i}`),\n ms: 380,\n ease: \"out\",\n },\n { id: `l${i}`, attrs: { transform: [`translate({{x${i}}} {{rise}}) rotate(5) scale(1.12)`, `translate({{x${i}}} {{base}}) rotate(0) scale(1)`] }, delay: n(`e${i}`), ms: 260, ease: \"in-out\" },\n ]).flat(),\n { id: \"line\", attrs: { width: [0, n(\"lineW\")] }, delay: n(\"lineAt\"), ms: 500, ease: \"in-out\" },\n ],\n },\n};\n\nexport const neonSign: VectorEffect = {\n kind: \"vector\",\n id: \"neon-sign\",\n name: \"Neon sign\",\n description: \"Glowing neon tube lettering that stutters on, then keeps one faulty letter buzzing.\",\n category: \"text\",\n tags: [\"text\", \"neon\", \"glow\", \"sign\", \"night\", \"retro\"],\n hold: 400,\n presets: [\n { name: \"Hot pink\", values: { tube: [1, 0.2, 0.65], wall: [0.06, 0.02, 0.07] } },\n { name: \"Ice\", values: { tube: [0.35, 0.85, 1], wall: [0.02, 0.04, 0.08], glow: 5 } },\n { name: \"Lime\", values: { tube: [0.6, 1, 0.2], wall: [0.03, 0.05, 0.02] } },\n ],\n // The word in three runs, so the buzzing letter can flicker on its own.\n derived: (v) => {\n const letters = lettersOf(v.text);\n const k = Math.min(Math.max(0, Math.round(Number(v.faulty)) - 1), Math.max(0, letters.length - 1));\n const { size, length, left } = fit(String(v.text), room(v, 340), 84);\n return {\n ...frame(v, left, length, 100 + size * 0.3, size, glowing([0.1, 0, DESCENT, 0], (Number(v.glow) * 6) / size)),\n hazeX: r1(Math.max(170, length / 2 + 30)),\n head: letters.slice(0, k).join(\"\"),\n mid: letters[k] ?? \"\",\n tail: letters.slice(k + 1).join(\"\"),\n size,\n length,\n base: r1(100 + size * 0.3),\n far: Number(v.glow) * 3,\n core: mixHex(v.tube, [1, 1, 1], 0.6),\n };\n },\n motion: ((): SvgMotion => {\n const word = `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\"`;\n const runs = (id: string) => `<tspan>{{head}}</tspan><tspan id=\"${id}\">{{mid}}</tspan><tspan>{{tail}}</tspan>`;\n // Start-up: the tubes catch, drop out and catch again.\n const startUp = [[0, 0], [150, 0.85], [210, 0], [330, 1], [390, 0.15], [450, 1], [620, 0.35], [680, 1]] as const;\n const buzz = [[0, 1], [1300, 0.15], [1350, 1], [1420, 0.2], [1520, 1], [2100, 0.1], [2160, 1], [2230, 0.25], [2280, 1]] as const;\n return {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='Open late' label='Text'}} {{tube: color default=#FF3DA5 label='Tube'}} {{wall: color default=#120612 label='Wall'}} {{glow: float min=0.5 max=8 default=3.5 step=0.5 label='Glow'}} {{faulty: int min=1 max=24 default=6 label='Buzzing letter'}} ${typeface(SCRIPT, 400)} --><defs><filter id=\"neon\" x=\"-30%\" y=\"-80%\" width=\"160%\" height=\"260%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{glow}}\" result=\"near\"/><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{far}}\" result=\"far\"/><feMerge><feMergeNode in=\"far\"/><feMergeNode in=\"far\"/><feMergeNode in=\"near\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter><filter id=\"haze\" x=\"-50%\" y=\"-100%\" width=\"200%\" height=\"300%\"><feGaussianBlur stdDeviation=\"30\"/></filter></defs><rect width=\"400\" height=\"200\" fill=\"{{wall}}\" opacity=\"{{backdrop}}\"/><g id=\"sign\" opacity=\"0\"><ellipse cx=\"200\" cy=\"100\" rx=\"{{hazeX}}\" ry=\"55\" fill=\"{{tube}}\" opacity=\"0.18\" filter=\"url(#haze)\"/><text ${word} fill=\"{{tube}}\" stroke=\"{{tube}}\" stroke-width=\"1.5\" filter=\"url(#neon)\">${runs(\"buzzGlow\")}</text><text ${word} fill=\"{{core}}\">${runs(\"buzzCore\")}</text></g></svg>`,\n animate: [\n ...holds(\"sign\", \"opacity\", startUp),\n // fill-opacity rather than opacity: browsers ignore opacity on a <tspan>.\n ...[\"buzzGlow\", \"buzzCore\"].flatMap((id) => [...holds(id, \"fill-opacity\", buzz), ...holds(id, \"stroke-opacity\", buzz)]),\n ],\n };\n })(),\n};\n\nexport const strokeDrawText: VectorEffect = {\n kind: \"vector\",\n id: \"stroke-draw-text\",\n name: \"Stroke draw text\",\n description: \"A word's outline traced on along every letter, then its fill fading in.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"draw-on\", \"outline\", \"reveal\", \"handwriting\"],\n hold: 1200,\n presets: [\n { name: \"Blueprint\", values: { background: [0.05, 0.2, 0.45], outline: [0.85, 0.93, 1], fill: [0.85, 0.93, 1], fillOpacity: 0.15 } },\n { name: \"Gold\", values: { background: [0.07, 0.06, 0.05], outline: [1, 0.8, 0.35], fill: [0.85, 0.6, 0.15] } },\n ],\n // <text> takes no pathLength, so `draw` cannot measure it: the dash grows instead, longer than any letter's outline.\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), room(v, 360), 100);\n const edge = Number(v.width) / 2 / size;\n return { size, length, base: r1(100 + size * 0.35), dash: Math.round(size * 6), ...frame(v, left, length, 100 + size * 0.35, size, glowing([0.05, 0, DESCENT, 0], edge)) };\n },\n motion: {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='Draw' label='Text'}} {{background: color default=#FFFBF5 label='Background'}} {{outline: color default=#1E293B label='Outline'}} {{fill: color default=#F97316 label='Fill'}} {{width: float min=0.5 max=6 default=2 step=0.5 label='Outline width'}} {{fillOpacity: float min=0 max=1 default=1 label='Fill opacity'}} ${typeface(HEAVY, 900)} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/><text id=\"word\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{fill}}\" fill-opacity=\"0\" stroke=\"{{outline}}\" stroke-width=\"{{width}}\" stroke-linejoin=\"round\" stroke-dasharray=\"0 {{dash}}\">{{text}}</text></svg>`,\n animate: [\n { id: \"word\", attrs: { \"stroke-dasharray\": [\"0 {{dash}}\", \"{{dash}} 0\"] }, ms: 2000, ease: \"in-out\" },\n { id: \"word\", attrs: { \"fill-opacity\": [0, n(\"fillOpacity\")] }, delay: 1500, ms: 700, ease: \"out\" },\n ],\n },\n};\n\nexport const splitReveal: VectorEffect = {\n kind: \"vector\",\n id: \"split-reveal\",\n name: \"Split reveal\",\n description: \"A line draws across, then the title's top half rises out from behind it while the bottom half drops down.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"reveal\", \"mask\", \"editorial\", \"intro\"],\n hold: 1400,\n presets: [\n { name: \"Light\", values: { background: [0.97, 0.96, 0.94], ink: [0.08, 0.08, 0.1], line: [0.85, 0.2, 0.15] } },\n { name: \"Gold on black\", values: { background: [0.02, 0.02, 0.02], ink: [0.96, 0.84, 0.55], line: [0.96, 0.84, 0.55] } },\n ],\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), room(v, 360), 88);\n return {\n ...frame(v, left, length, 100 + size * 0.36, size, [0.05, 10 / size, Math.max(DESCENT, 34 / size), 10 / size]),\n size,\n length,\n base: r1(100 + size * 0.36),\n shift: r1(size * 0.8),\n lineX1: r1(left - 10),\n lineX2: r1(400 - left + 10),\n captionY: r1(100 + size * 0.36 + 30),\n };\n },\n motion: ((): SvgMotion => {\n const word = `<text x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{ink}}\">{{text}}</text>`;\n return {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='Chapter One' label='Text'}} {{caption: text default='The beginning' label='Caption'}} {{background: color default=#0F172A label='Background'}} {{ink: color default=#F8FAFC label='Text colour'}} {{line: color default=#38BDF8 label='Line'}} ${typeface(SANS, 800)} --><defs><clipPath id=\"above\"><rect x=\"-5000\" y=\"-5000\" width=\"10400\" height=\"5100\"/></clipPath><clipPath id=\"below\"><rect x=\"-5000\" y=\"100\" width=\"10400\" height=\"5100\"/></clipPath></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/><g clip-path=\"url(#above)\"><g id=\"top\" transform=\"translate(0 {{shift}})\">${word}</g></g><g clip-path=\"url(#below)\"><g id=\"bottom\" transform=\"translate(0 -{{shift}})\">${word}</g></g><path id=\"line\" d=\"M{{lineX1}} 100 H{{lineX2}}\" stroke=\"{{line}}\" stroke-width=\"2.5\" stroke-linecap=\"round\"/><text id=\"caption\" x=\"200\" y=\"{{captionY}}\" text-anchor=\"middle\" font-family=\"{{font}}\" font-size=\"13\" letter-spacing=\"3\" fill=\"{{ink}}\" opacity=\"0\">{{caption}}</text></svg>`,\n animate: [\n { id: \"line\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"top\", attrs: { transform: [\"translate(0 {{shift}})\", \"translate(0 0)\"] }, delay: 450, ms: 800, ease: \"out\" },\n { id: \"bottom\", attrs: { transform: [\"translate(0 -{{shift}})\", \"translate(0 0)\"] }, delay: 450, ms: 800, ease: \"out\" },\n { id: \"line\", attrs: { opacity: [1, 0] }, delay: 1100, ms: 400 },\n { id: \"caption\", attrs: { opacity: [0, 0.75] }, delay: 1100, ms: 500, ease: \"out\" },\n ],\n };\n })(),\n};\n\nexport const highlighter: VectorEffect = {\n kind: \"vector\",\n id: \"highlighter\",\n name: \"Highlighter\",\n description: \"A marker swipe drawn left to right behind a phrase, rough-edged like a real highlighter pen.\",\n category: \"text\",\n tags: [\"text\", \"highlight\", \"marker\", \"emphasis\", \"explainer\", \"callout\"],\n hold: 1400,\n presets: [\n { name: \"Pink\", values: { marker: [1, 0.55, 0.78] } },\n { name: \"Mint\", values: { marker: [0.55, 0.95, 0.7] } },\n { name: \"Dark\", values: { background: [0.07, 0.08, 0.1], ink: [0.97, 0.97, 0.98], marker: [0.55, 0.2, 0.95] } },\n ],\n // The swipe runs a little past the phrase at both ends, across its lower half, with a ragged second pass.\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), room(v, 330), 56);\n const base = 100 + size * 0.35;\n const x0 = left - size * 0.25;\n const x1 = 400 - left + size * 0.2;\n const y = base - size * 0.3;\n return {\n ...frame(v, left, length, base, size, [0.05, 0.2, DESCENT, 0.25]),\n size,\n length,\n base: r1(base),\n swipe: `M${r1(x0)} ${r1(y + size * 0.05)} Q${r1((x0 + x1) / 2)} ${r1(y - size * 0.06)} ${r1(x1)} ${r1(y - size * 0.02)}`,\n ragged: `M${r1(x0 + size * 0.15)} ${r1(y + size * 0.3)} L${r1(x1 - size * 0.1)} ${r1(y + size * 0.26)}`,\n thick: r1(size * 0.72),\n thin: r1(size * 0.16),\n };\n },\n motion: {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='Ship it faster' label='Phrase'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#111827 label='Text colour'}} {{marker: color default=#FDE047 label='Marker'}} ${typeface(SANS, 700)} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/><g transform=\"rotate(-1.2 200 100)\" opacity=\"0.9\"><path id=\"swipe\" d=\"{{swipe}}\" fill=\"none\" stroke=\"{{marker}}\" stroke-width=\"{{thick}}\"/><path id=\"ragged\" d=\"{{ragged}}\" fill=\"none\" stroke=\"{{marker}}\" stroke-width=\"{{thin}}\" stroke-linecap=\"round\"/></g><text id=\"phrase\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{ink}}\" opacity=\"0\">{{text}}</text></svg>`,\n animate: [\n { id: \"phrase\", attrs: { opacity: [0, 1] }, ms: 300, ease: \"out\" },\n { id: \"swipe\", draw: true, delay: 350, ms: 650, ease: \"in-out\" },\n { id: \"ragged\", draw: true, delay: 420, ms: 620, ease: \"in-out\" },\n ],\n },\n};\n\n/** Word cycle's timing: how long each word rests, and how long a roll to the next takes. */\nconst SHOW_MS = 1000;\nconst ROLL_MS = 450;\nconst CYCLE_WORDS = 4;\n\nexport const wordCycle: VectorEffect = {\n kind: \"vector\",\n id: \"word-cycle\",\n name: \"Word cycle\",\n description: \"A fixed lead-in with the last word rolling through alternatives like a slot machine, an underline resizing to each.\",\n category: \"text\",\n tags: [\"text\", \"headline\", \"rotating\", \"hero\", \"marketing\", \"slot\"],\n hold: 0,\n presets: [\n { name: \"Dark\", values: { background: [0.05, 0.06, 0.1], ink: [0.95, 0.96, 1], accent: [0.4, 0.85, 0.65] } },\n { name: \"Warm\", values: { background: [1, 0.96, 0.9], ink: [0.2, 0.12, 0.08], accent: [0.93, 0.35, 0.15] } },\n ],\n // The lead-in and the longest word share the line; the reel ends with word 1 again, so the loop is seamless.\n derived: (v) => {\n const words = Array.from({ length: CYCLE_WORDS }, (_, i) => String(v[`word${i + 1}`]));\n const lead = textWidthEm(String(v.prefix));\n const ems = words.map((w) => Math.max(0.6, textWidthEm(w)));\n const total = lead + 0.3 + Math.max(...ems);\n const size = Math.min(52, room(v, 370) / total);\n const left = 200 - (total * size) / 2;\n const base = 100 + size * 0.35;\n const step = size * 1.3;\n const wx = left + (lead + 0.3) * size;\n return {\n ...frame(v, left, total * size, base, size, [0.08, 0, Math.max(DESCENT, 0.18 + 4 / size), 0]),\n bold: Math.min(900, Number(v.weight) + 100),\n size: r1(size),\n base: r1(base),\n px: r1(left),\n plen: r1(Math.max(0.6, lead) * size),\n wx: r1(wx),\n clipX: r1(wx - 4),\n clipY: r1(base - size * 1.0),\n clipW: r1(Math.max(...ems) * size + 8),\n clipH: r1(size * 1.32),\n underY: r1(base + size * 0.18),\n ...Object.fromEntries(\n [...words, words[0]!].flatMap((_, k) => [\n [`y${k}`, r1(base + k * step)],\n [`o${k}`, r1(k * step)],\n [`len${k}`, r1(ems[k % CYCLE_WORDS]! * size)],\n ]),\n ),\n ...Object.fromEntries(words.map((w, k) => [`w${k}`, w])),\n };\n },\n motion: {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{prefix: text default='We build' label='Lead-in'}} {{word1: text default=apps label='Word 1'}} {{word2: text default=brands label='Word 2'}} {{word3: text default=websites label='Word 3'}} {{word4: text default=games label='Word 4'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#6366F1 label='Accent'}} ${typeface(SANS, 700)} --><defs><clipPath id=\"window\"><rect x=\"{{clipX}}\" y=\"{{clipY}}\" width=\"{{clipW}}\" height=\"{{clipH}}\"/></clipPath></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/><text x=\"{{px}}\" y=\"{{base}}\" textLength=\"{{plen}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" fill=\"{{ink}}\">{{prefix}}</text><g clip-path=\"url(#window)\"><g id=\"reel\" transform=\"translate(0 -0)\">${Array.from(\n { length: CYCLE_WORDS + 1 },\n (_, k) =>\n `<text x=\"{{wx}}\" y=\"{{y${k}}}\" textLength=\"{{len${k}}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{bold}}\" fill=\"{{accent}}\">{{w${k % CYCLE_WORDS}}}</text>`,\n ).join(\"\")}</g></g><rect id=\"under\" x=\"{{wx}}\" y=\"{{underY}}\" width=\"{{len0}}\" height=\"4\" rx=\"2\" fill=\"{{accent}}\"/></svg>`,\n animate: Array.from({ length: CYCLE_WORDS }, (_, i): SvgAnimation[] => {\n const at = { delay: (i + 1) * SHOW_MS + i * ROLL_MS, ms: ROLL_MS, ease: \"in-out\" as const };\n return [\n { id: \"reel\", attrs: { transform: [`translate(0 -{{o${i}}})`, `translate(0 -{{o${i + 1}}})`] }, ...at },\n { id: \"under\", attrs: { width: [n(`len${i}`), n(`len${i + 1}`)] }, ...at },\n ];\n }).flat(),\n },\n};\n\n/** Liquid fill's wave: crests along y = 0 in 100-unit periods, far either side of the picture (inline text runs wide), filled down below it. */\nconst WAVE = `M-2000 0${\" q25 -8 50 0 t50 0\".repeat(46)} V320 H-2000Z`;\n\nexport const liquidFill: VectorEffect = {\n kind: \"vector\",\n id: \"liquid-fill\",\n name: \"Liquid fill\",\n description: \"A title filling up with liquid, its wavy surface rising through the letters.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"liquid\", \"water\", \"progress\", \"fill\"],\n hold: 900,\n presets: [\n { name: \"Gradient sweep\", values: { liquid: [0.98, 0.25, 0.55], liquid2: [0.35, 0.4, 1], empty: [0.93, 0.93, 0.96] } },\n { name: \"Lava\", values: { liquid: [1, 0.35, 0.05], liquid2: [1, 0.8, 0.1], empty: [0.15, 0.08, 0.06], background: [0.06, 0.03, 0.02] } },\n { name: \"Juice\", values: { liquid: [1, 0.6, 0.1], liquid2: [1, 0.75, 0.25] } },\n ],\n // The surface starts under the letters and ends above their caps.\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), room(v, 360), 110);\n const base = 100 + size * 0.36;\n return { ...frame(v, left, length, base, size), size, length, base: r1(base), low: r1(base + 12), high: r1(base - size * 0.82 - 12) };\n },\n motion: ((): SvgMotion => {\n const word = `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\"`;\n return {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='FILL' label='Text'}} {{background: color default=#FFFFFF label='Background'}} {{empty: color default=#E0F2FE label='Empty'}} {{liquid: color default=#0284C7 label='Liquid'}} {{liquid2: color default=#38BDF8 label='Liquid sweep'}} ${typeface(HEAVY, 900)} --><defs><clipPath id=\"letters\"><text ${word}>{{text}}</text></clipPath><linearGradient id=\"liq\" gradientUnits=\"userSpaceOnUse\" x1=\"0\" y1=\"0\" x2=\"400\" y2=\"0\" spreadMethod=\"repeat\"><stop offset=\"0\" stop-color=\"{{liquid}}\"/><stop offset=\"0.5\" stop-color=\"{{liquid2}}\"/><stop offset=\"1\" stop-color=\"{{liquid}}\"/></linearGradient></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/><text ${word} fill=\"{{empty}}\" stroke=\"{{liquid}}\" stroke-width=\"1.5\" stroke-opacity=\"0.5\">{{text}}</text><g clip-path=\"url(#letters)\"><g id=\"level\" transform=\"translate(0 {{low}})\"><path id=\"back\" d=\"${WAVE}\" fill=\"{{liquid}}\" opacity=\"0.45\" transform=\"translate(-50 -5)\"/><path id=\"wave\" d=\"${WAVE}\" fill=\"url(#liq)\" transform=\"translate(0 0)\"/></g></g></svg>`,\n animate: [\n { id: \"level\", attrs: { transform: [\"translate(0 {{low}})\", \"translate(0 {{high}})\"] }, ms: 2800, ease: \"out\" },\n { id: \"wave\", attrs: { transform: [\"translate(0 0)\", \"translate(-200 0)\"] }, ms: 3000, ease: \"linear\" },\n { id: \"back\", attrs: { transform: [\"translate(-50 -5)\", \"translate(150 -5)\"] }, ms: 3000, ease: \"linear\" },\n // The sweep: the repeating gradient slides along, visible when the two liquid colours differ.\n { id: \"liq\", attrs: { x1: [0, 400], x2: [400, 800] }, ms: 3000, ease: \"linear\" },\n ],\n };\n })(),\n};\n\n/** Glitch text's bands: where the word is cut into slices, as fractions from its cap line to its baseline. */\nconst BANDS = [0.3, 0.55, 0.8];\n/** Glitch text's jumps: [ms, red offset, cyan offset, each band's shift], in units of the word's size; rests between bursts. */\nconst GLITCH = (() => {\n let seed = 7;\n const rand = () => ((seed = (seed * 16807) % 2147483647) / 2147483647) * 2 - 1;\n const rest = { red: [-0.02, 0], cyan: [0.02, 0], bands: [0, 0, 0, 0] };\n const keys: { at: number; red: number[]; cyan: number[]; bands: number[] }[] = [{ at: 0, ...rest }];\n for (const [start, count] of [[250, 6], [1050, 3], [1650, 8]] as const) {\n for (let k = 0; k < count; k++)\n keys.push({\n at: start + k * 55,\n red: [rand() * 0.12, rand() * 0.04],\n cyan: [rand() * 0.12, rand() * 0.04],\n bands: [0, 1, 2, 3].map(() => (rand() > 0.1 ? rand() * 0.25 : 0)),\n });\n keys.push({ at: start + count * 55, ...rest });\n }\n return keys;\n})();\n\nexport const glitchText: VectorEffect = {\n kind: \"vector\",\n id: \"glitch-text\",\n name: \"Glitch text\",\n description: \"A title breaking up in bursts: red and cyan copies split apart and slices of the letters jump sideways.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"glitch\", \"cyber\", \"rgb-split\", \"error\"],\n hold: 400,\n presets: [\n { name: \"Classic\", values: { left: [1, 0, 0.2], right: [0, 1, 1] } },\n { name: \"Vapor\", values: { left: [1, 0.3, 0.85], right: [0.4, 0.6, 1], background: [0.08, 0.02, 0.12], amount: 1.4 } },\n ],\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), room(v, 340), 100);\n const a = Number(v.amount);\n const base = 100 + size * 0.36;\n const top = base - size * 0.78;\n const cuts = [-1000, ...BANDS.map((f) => r1(top + f * (base - top))), 1200];\n const unit = size * Number(v.amount);\n const shift = ([x, y]: number[]) => `translate(${r1(x! * unit)} ${r1(y! * unit)})`;\n return {\n ...frame(v, left, length, base, size, [0.05 + 0.04 * a, 0.25 * a, DESCENT + 0.04 * a, 0.25 * a]),\n size,\n length,\n base: r1(base),\n ...Object.fromEntries([0, 1, 2, 3].flatMap((b) => [[`cut${b}`, cuts[b]!], [`band${b}`, r1(cuts[b + 1]! - cuts[b]!)]])),\n ...Object.fromEntries(\n GLITCH.flatMap((key, k) => [\n [`red${k}`, shift(key.red)],\n [`cyan${k}`, shift(key.cyan)],\n ...key.bands.map((x, b) => [`b${b}_${k}`, shift([x, 0])]),\n ]),\n ),\n };\n },\n motion: ((): SvgMotion => {\n const word = (paint: string) =>\n `<text x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" ${paint}>{{text}}</text>`;\n const jumps = (id: string, value: (k: number) => string) =>\n GLITCH.map((key, k): SvgAnimation => ({ id, attrs: { transform: [value(k), value(k)] }, delay: key.at, ms: 0 }));\n return {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='GLITCH' label='Text'}} {{background: color default=#07070B label='Background'}} {{ink: color default=#F5F5F5 label='Text colour'}} {{left: color default=#FF0040 label='Red copy'}} {{right: color default=#00F0FF label='Cyan copy'}} {{amount: float min=0 max=3 default=1 step=0.1 label='Intensity'}} ${typeface(HEAVY, 900)} --><defs>${[0, 1, 2, 3]\n .map((b) => `<clipPath id=\"slice${b}\"><rect x=\"-5000\" y=\"{{cut${b}}}\" width=\"10400\" height=\"{{band${b}}}\"/></clipPath>`)\n .join(\"\")}</defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/><g id=\"red\" style=\"mix-blend-mode:screen\">${word(`fill=\"{{left}}\"`)}</g><g id=\"cyan\" style=\"mix-blend-mode:screen\">${word(`fill=\"{{right}}\"`)}</g>${[0, 1, 2, 3]\n .map((b) => `<g clip-path=\"url(#slice${b})\"><g id=\"s${b}\">${word(`fill=\"{{ink}}\"`)}</g></g>`)\n .join(\"\")}</svg>`,\n animate: [\n ...jumps(\"red\", (k) => `{{red${k}}}`),\n ...jumps(\"cyan\", (k) => `{{cyan${k}}}`),\n ...[0, 1, 2, 3].flatMap((b) => jumps(`s${b}`, (k) => `{{b${b}_${k}}}`)),\n ],\n };\n })(),\n};\n\n/** Extruded text's layers, back to front, and the directions the extrude swings between (degrees, 0 = right, 90 = down). */\nconst LAYERS = 12;\nconst EXTRUDE_FROM = 40;\nconst EXTRUDE_TO = 140;\n\nexport const extrudedText: VectorEffect = {\n kind: \"vector\",\n id: \"extruded-text\",\n name: \"Extruded text\",\n description: \"Retro 3D block lettering: stacked shaded layers extrude out of the title and swing as the light moves.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"3d\", \"retro\", \"extrude\", \"80s\"],\n hold: 600,\n presets: [\n { name: \"Arcade\", values: { face: [0.2, 0.95, 1], side: [0.85, 0.2, 0.75], shade: [0.2, 0.05, 0.3], background: [0.05, 0.02, 0.12] } },\n { name: \"Diner\", values: { face: [1, 1, 1], side: [0.9, 0.15, 0.2], shade: [0.35, 0.03, 0.06], background: [0.98, 0.9, 0.75], outline: [0.1, 0.1, 0.12] } },\n ],\n // Each layer sits a step further back along the extrude direction, shaded from the side colour to the shadow.\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), room(v, 320), 96);\n const d = 0.36 * Number(v.depth);\n const step = size * 0.03 * Number(v.depth);\n const at = (deg: number, i: number) => {\n const a = (deg * Math.PI) / 180;\n return `translate(${r1(Math.cos(a) * step * i)} ${r1(Math.sin(a) * step * i)})`;\n };\n return {\n ...frame(v, left, length, 92 + size * 0.35, size, [0.05, 0.77 * d, DESCENT + d, 0.77 * d]),\n size,\n length,\n base: r1(92 + size * 0.35),\n ...Object.fromEntries(\n Array.from({ length: LAYERS }, (_, k) => {\n const i = LAYERS - k;\n return [\n [`fill${i}`, mixHex(v.side, v.shade, i / LAYERS)],\n [`a${i}`, at(EXTRUDE_FROM, i)],\n [`b${i}`, at(EXTRUDE_TO, i)],\n ];\n }).flat(),\n ),\n };\n },\n motion: ((): SvgMotion => {\n const word = (paint: string) =>\n `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"{{weight}}\" stroke-linejoin=\"round\" ${paint}`;\n const layers = Array.from({ length: LAYERS }, (_, k) => LAYERS - k);\n return {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{text: text default='RETRO' label='Text'}} {{background: color default=#FFE8C2 label='Background'}} {{face: color default=#FFD23F label='Face'}} {{outline: color default=#1A1423 label='Outline'}} {{side: color default=#EE4266 label='Extrude'}} {{shade: color default=#3B1F2B label='Shadow'}} {{depth: float min=0.2 max=2 default=1 step=0.1 label='Depth'}} ${typeface(HEAVY, 900)} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\" opacity=\"{{backdrop}}\"/>${layers\n .map((i) => `<text id=\"e${i}\" transform=\"translate(0 0)\" ${word(`fill=\"{{fill${i}}}\" stroke=\"{{fill${i}}}\" stroke-width=\"2\"`)}>{{text}}</text>`)\n .join(\"\")}<text ${word(`fill=\"{{face}}\" stroke=\"{{outline}}\" stroke-width=\"2.5\" paint-order=\"stroke\"`)}>{{text}}</text></svg>`,\n animate: layers.flatMap((i): SvgAnimation[] => [\n { id: `e${i}`, attrs: { transform: [\"translate(0 0)\", `{{a${i}}}`] }, ms: 700, ease: \"out\" },\n { id: `e${i}`, attrs: { transform: [`{{a${i}}}`, `{{b${i}}}`] }, delay: 1200, ms: 1500, ease: \"in-out\" },\n { id: `e${i}`, attrs: { transform: [`{{b${i}}}`, `{{a${i}}}`] }, delay: 3200, ms: 1500, ease: \"in-out\" },\n ]),\n };\n })(),\n};\n\n/** Animated titles and type, as vector effects. */\nexport const textEffects: VectorEffect[] = [\n typewriter,\n scrambleText,\n kineticStagger,\n neonSign,\n strokeDrawText,\n splitReveal,\n highlighter,\n wordCycle,\n liquidFill,\n glitchText,\n extrudedText,\n];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nexport const spinner: VectorEffect = {\n kind: \"vector\",\n id: \"spinner\",\n name: \"Spinner\",\n description: \"An arc chasing its tail: the classic indeterminate loader.\",\n category: \"loader\",\n tags: [\"loader\", \"ui\", \"minimal\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#6366F1 label='Arc'}} {{track: color default=#E5E7EB label='Track'}} {{width: float min=2 max=20 default=8 step=1 label='Stroke width'}} --><circle cx=\"50\" cy=\"50\" r=\"38\" fill=\"none\" stroke=\"{{track}}\" stroke-width=\"{{width}}\"/><g id=\"spin\" transform=\"rotate(0 50 50)\"><circle id=\"arc\" cx=\"50\" cy=\"50\" r=\"38\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" pathLength=\"1\" stroke-dasharray=\"0.25 1\"/></g></svg>`,\n animate: [\n { id: \"spin\", attrs: { transform: [\"rotate(0 50 50)\", \"rotate(720 50 50)\"] }, ms: 1600, ease: \"linear\" },\n { id: \"arc\", attrs: { \"stroke-dasharray\": [\"0.08 1\", \"0.6 1\"] }, ms: 800, ease: \"in-out\" },\n { id: \"arc\", attrs: { \"stroke-dasharray\": [\"0.6 1\", \"0.08 1\"] }, delay: 800, ms: 800, ease: \"in-out\" },\n ],\n },\n};\n\nexport const bouncingDots: VectorEffect = {\n kind: \"vector\",\n id: \"bouncing-dots\",\n name: \"Bouncing dots\",\n description: \"Three dots hopping in turn, for typing indicators and loaders.\",\n category: \"loader\",\n tags: [\"loader\", \"chat\", \"typing\", \"ui\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 120 60\"><!-- {{accent: color default=#0EA5E9 label='Dots'}} {{height: float min=4 max=30 default=18 step=1 label='Bounce height'}} --><circle id=\"a\" cx=\"30\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/><circle id=\"b\" cx=\"60\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/><circle id=\"c\" cx=\"90\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/></svg>`,\n animate: [\"a\", \"b\", \"c\"].flatMap((id, i): SvgAnimation[] => [\n { id, attrs: { transform: [\"translate(0 0)\", \"translate(0 -{{height}})\"] }, delay: i * 150, ms: 250, ease: \"out\" as const },\n { id, attrs: { transform: [\"translate(0 -{{height}})\", \"translate(0 0)\"] }, delay: i * 150 + 250, ms: 250, ease: \"in-out\" as const },\n { id, attrs: { opacity: [0.5, 1] }, delay: i * 150, ms: 250 },\n { id, attrs: { opacity: [1, 0.5] }, delay: i * 150 + 250, ms: 250 },\n ]),\n },\n};\n\nexport const progressRing: VectorEffect = {\n kind: \"vector\",\n id: \"progress-ring\",\n name: \"Progress ring\",\n description: \"A ring filling up to a percentage while the number counts with it.\",\n category: \"data\",\n tags: [\"progress\", \"kpi\", \"dashboard\", \"loader\"],\n derived: (v) => ({ fraction: Math.min(1, Math.max(0, Number(v.value) / 100)) }),\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#22C55E label='Ring'}} {{track: color default=#E5E7EB label='Track'}} {{text: color default=#111827 label='Text'}} {{value: float min=0 max=100 default=72 step=1 label='Percent'}} --><circle cx=\"60\" cy=\"60\" r=\"48\" fill=\"none\" stroke=\"{{track}}\" stroke-width=\"10\"/><circle id=\"ring\" cx=\"60\" cy=\"60\" r=\"48\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"10\" stroke-linecap=\"round\" transform=\"rotate(-90 60 60)\"/><text id=\"label\" x=\"60\" y=\"68\" text-anchor=\"middle\" font-size=\"24\" font-weight=\"700\" fill=\"{{text}}\">0%</text></svg>`,\n animate: [\n { id: \"ring\", draw: [0, \"{{fraction}}\"] as unknown as [number, number], ms: 1600, ease: \"out\" },\n { id: \"label\", count: [0, \"{{value}}\"] as unknown as [number, number], format: \"{n}%\", ms: 1600, ease: \"out\" },\n ],\n },\n};\n\nexport const pulsePing: VectorEffect = {\n kind: \"vector\",\n id: \"pulse-ping\",\n name: \"Pulse ping\",\n description: \"Rings radiating from a dot, like a live indicator or radar ping.\",\n category: \"loader\",\n tags: [\"live\", \"notification\", \"location\", \"status\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#EF4444 label='Colour'}} --><circle id=\"r1\" cx=\"50\" cy=\"50\" r=\"8\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\"/><circle id=\"r2\" cx=\"50\" cy=\"50\" r=\"8\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\"/><circle cx=\"50\" cy=\"50\" r=\"9\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n { id: \"r1\", attrs: { r: [8, 44], opacity: [0.9, 0], \"stroke-width\": [4, 1] }, ms: 1400, ease: \"out\" },\n { id: \"r2\", attrs: { r: [8, 44], opacity: [0.9, 0], \"stroke-width\": [4, 1] }, delay: 700, ms: 1400, ease: \"out\" },\n ],\n },\n};\n\nexport const successCheck: VectorEffect = {\n kind: \"vector\",\n id: \"success-check\",\n name: \"Success check\",\n description: \"A circle drawing itself closed, then a tick, then a little pop.\",\n category: \"icon\",\n tags: [\"success\", \"confirmation\", \"ui\", \"feedback\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#16A34A label='Colour'}} {{width: float min=2 max=12 default=6 step=1 label='Stroke width'}} --><g id=\"badge\" transform=\"translate(50 50) scale(1) translate(-50 -50)\"><circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><path id=\"tick\" d=\"M31 52 L44 64 L70 37\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n { id: \"circle\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"tick\", draw: true, delay: 500, ms: 400, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(50 50) scale(1) translate(-50 -50)\", \"translate(50 50) scale(1.12) translate(-50 -50)\"] }, delay: 850, ms: 150, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(50 50) scale(1.12) translate(-50 -50)\", \"translate(50 50) scale(1) translate(-50 -50)\"] }, delay: 1000, ms: 250, ease: \"in-out\" },\n ],\n },\n};\n\nexport const errorCross: VectorEffect = {\n kind: \"vector\",\n id: \"error-cross\",\n name: \"Error cross\",\n description: \"A circle and a cross drawing on, with a short shake.\",\n category: \"icon\",\n tags: [\"error\", \"failure\", \"ui\", \"feedback\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#DC2626 label='Colour'}} {{width: float min=2 max=12 default=6 step=1 label='Stroke width'}} --><g id=\"badge\" transform=\"translate(0 0)\"><circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><path id=\"a\" d=\"M36 36 L64 64\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><path id=\"b\" d=\"M64 36 L36 64\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/></g></svg>`,\n animate: [\n { id: \"circle\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"a\", draw: true, delay: 500, ms: 250, ease: \"out\" },\n { id: \"b\", draw: true, delay: 700, ms: 250, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(0 0)\", \"translate(-6 0)\"] }, delay: 950, ms: 60, ease: \"linear\" },\n { id: \"badge\", attrs: { transform: [\"translate(-6 0)\", \"translate(6 0)\"] }, delay: 1010, ms: 100, ease: \"linear\" },\n { id: \"badge\", attrs: { transform: [\"translate(6 0)\", \"translate(0 0)\"] }, delay: 1110, ms: 80, ease: \"out\" },\n ],\n },\n};\n\nexport const heartbeat: VectorEffect = {\n kind: \"vector\",\n id: \"heartbeat\",\n name: \"Heartbeat\",\n description: \"A heart beating twice, with an ECG line tracing beneath it.\",\n category: \"icon\",\n tags: [\"health\", \"like\", \"love\", \"pulse\"],\n hold: 300,\n motion: {\n svg: `<svg viewBox=\"0 0 200 120\"><!-- {{accent: color default=#F43F5E label='Heart'}} {{line: color default=#94A3B8 label='Line'}} --><g id=\"heart\" transform=\"translate(100 46) scale(1)\"><path d=\"M0 22 C-30 0 -30 -26 -10 -26 C-3 -26 0 -20 0 -16 C0 -20 3 -26 10 -26 C30 -26 30 0 0 22Z\" fill=\"{{accent}}\"/></g><path id=\"ecg\" d=\"M10 100 H70 L80 86 L90 112 L100 76 L110 104 L118 100 H190\" fill=\"none\" stroke=\"{{line}}\" stroke-width=\"3\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></svg>`,\n animate: [\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1)\", \"translate(100 46) scale(1.18)\"] }, ms: 120, ease: \"out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1.18)\", \"translate(100 46) scale(1)\"] }, delay: 120, ms: 160, ease: \"in-out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1)\", \"translate(100 46) scale(1.12)\"] }, delay: 300, ms: 120, ease: \"out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1.12)\", \"translate(100 46) scale(1)\"] }, delay: 420, ms: 300, ease: \"in-out\" },\n { id: \"ecg\", draw: true, ms: 900, ease: \"linear\" },\n ],\n },\n};\n\nexport const barChart: VectorEffect = {\n kind: \"vector\",\n id: \"bar-chart\",\n name: \"Bar chart\",\n description: \"Bars growing into place one after another, values counting above them.\",\n category: \"data\",\n tags: [\"chart\", \"dashboard\", \"report\", \"explainer\"],\n hold: 1500,\n derived: (v) =>\n Object.fromEntries(\n [\"a\", \"b\", \"c\", \"d\"].flatMap((k) => {\n const h = Math.min(100, Math.max(0, Number(v[k]))) * 1.1;\n return [\n [`${k}_height`, +h.toFixed(2)],\n [`${k}_label_y`, +(134 - h).toFixed(2)],\n ];\n }),\n ),\n motion: {\n svg: `<svg viewBox=\"0 0 240 160\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#6366F1 label='Bars'}} {{text: color default=#334155 label='Text'}} {{a: float min=0 max=100 default=40 step=1 label='Bar 1'}} {{b: float min=0 max=100 default=65 step=1 label='Bar 2'}} {{c: float min=0 max=100 default=50 step=1 label='Bar 3'}} {{d: float min=0 max=100 default=90 step=1 label='Bar 4'}} --><line x1=\"20\" y1=\"140\" x2=\"220\" y2=\"140\" stroke=\"{{text}}\" stroke-opacity=\"0.3\" stroke-width=\"2\"/>${[\"a\", \"b\", \"c\", \"d\"]\n .map(\n (k, i) =>\n `<g id=\"bar-${k}\" transform=\"translate(${40 + i * 48} 140) scale(1 0)\"><rect x=\"0\" y=\"-1\" width=\"32\" height=\"1\" rx=\"0.02\" fill=\"{{accent}}\"/></g><text id=\"label-${k}\" x=\"${56 + i * 48}\" y=\"132\" text-anchor=\"middle\" font-size=\"12\" fill=\"{{text}}\" opacity=\"0\">0</text>`,\n )\n .join(\"\")}</svg>`,\n animate: [\"a\", \"b\", \"c\", \"d\"].flatMap((k, i): SvgAnimation[] => [\n { id: `bar-${k}`, attrs: { transform: [`translate(${40 + i * 48} 140) scale(1 0)`, `translate(${40 + i * 48} 140) scale(1 {{${k}_height}})`] }, delay: i * 180, ms: 700, ease: \"out\" as const },\n { id: `label-${k}`, attrs: { y: [132, `{{${k}_label_y}}`], opacity: [0, 1] }, delay: i * 180, ms: 700, ease: \"out\" as const },\n { id: `label-${k}`, count: [0, `{{${k}}}`] as unknown as [number, number], delay: i * 180, ms: 700, ease: \"out\" as const },\n ]),\n },\n};\n\nexport const lineChart: VectorEffect = {\n kind: \"vector\",\n id: \"line-chart\",\n name: \"Line chart\",\n description: \"A trend line drawing across with a marker riding its tip and the area fading in below.\",\n category: \"data\",\n tags: [\"chart\", \"trend\", \"growth\", \"dashboard\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 240 140\"><!-- {{accent: color default=#0EA5E9 label='Line'}} {{grid: color default=#CBD5E1 label='Grid'}} --><defs><linearGradient id=\"fill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"{{accent}}\" stop-opacity=\"0.35\"/><stop offset=\"1\" stop-color=\"{{accent}}\" stop-opacity=\"0\"/></linearGradient></defs><g stroke=\"{{grid}}\" stroke-width=\"1\"><line x1=\"20\" y1=\"30\" x2=\"220\" y2=\"30\"/><line x1=\"20\" y1=\"70\" x2=\"220\" y2=\"70\"/><line x1=\"20\" y1=\"110\" x2=\"220\" y2=\"110\"/></g><path id=\"area\" d=\"M20 110 L60 92 L100 98 L140 64 L180 70 L220 30 L220 120 L20 120Z\" fill=\"url(#fill)\" opacity=\"0\"/><path id=\"trend\" d=\"M20 110 L60 92 L100 98 L140 64 L180 70 L220 30\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><circle id=\"marker\" r=\"5\" fill=\"#fff\" stroke=\"{{accent}}\" stroke-width=\"3\"/></svg>`,\n animate: [\n { id: \"trend\", draw: true, ms: 1400, ease: \"in-out\" },\n { id: \"marker\", along: \"trend\", ms: 1400, ease: \"in-out\" },\n { id: \"area\", attrs: { opacity: [0, 1] }, delay: 900, ms: 600 },\n ],\n },\n};\n\nexport const statCounter: VectorEffect = {\n kind: \"vector\",\n id: \"stat-counter\",\n name: \"Stat counter\",\n description: \"A headline number counting up, with its caption and underline sweeping in.\",\n category: \"data\",\n tags: [\"kpi\", \"number\", \"headline\", \"explainer\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 240 120\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#F59E0B label='Accent'}} {{text: color default=#0F172A label='Text'}} {{value: float min=0 max=100000 default=1250 step=1 label='Value'}} {{caption: text default='happy customers' label='Caption'}} --><text id=\"number\" x=\"120\" y=\"62\" text-anchor=\"middle\" font-size=\"44\" font-weight=\"800\" fill=\"{{text}}\">0</text><path id=\"underline\" d=\"M60 78 H180\" stroke=\"{{accent}}\" stroke-width=\"6\" stroke-linecap=\"round\"/><text id=\"caption\" x=\"120\" y=\"104\" text-anchor=\"middle\" font-size=\"13\" fill=\"{{text}}\" opacity=\"0\">{{caption}}</text></svg>`,\n animate: [\n { id: \"number\", count: [0, \"{{value}}\"] as unknown as [number, number], ms: 1500, ease: \"out\" },\n { id: \"underline\", draw: true, delay: 300, ms: 900, ease: \"in-out\" },\n { id: \"caption\", attrs: { opacity: [0, 1], y: [112, 104] }, delay: 800, ms: 500, ease: \"out\" },\n ],\n },\n};\n\nexport const timelineTrack: VectorEffect = {\n kind: \"vector\",\n id: \"timeline-track\",\n name: \"Timeline track\",\n description: \"A vertical line drawing down with nodes popping along milestones.\",\n category: \"data\",\n tags: [\"timeline\", \"roadmap\", \"milestones\", \"history\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 400\"><!-- {{track: color default=#E5E7EB label='Track'}} {{accent: color default=#F97316 label='Accent'}} {{width: float min=1 max=8 default=3 step=0.5 label='Line width'}} --><line x1=\"50\" y1=\"20\" x2=\"50\" y2=\"380\" stroke=\"{{track}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><path id=\"line\" d=\"M50 20 L50 380\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><g id=\"n1\" transform=\"translate(50 60) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n2\" transform=\"translate(50 160) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n3\" transform=\"translate(50 260) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n4\" transform=\"translate(50 360) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g></svg>`,\n animate: [\n { id: \"line\", draw: true, ms: 1400, ease: \"in-out\" },\n { id: \"n1\", attrs: { transform: [\"translate(50 60) scale(0)\", \"translate(50 60) scale(1)\"] }, delay: 200, ms: 250, ease: \"out\" },\n { id: \"n2\", attrs: { transform: [\"translate(50 160) scale(0)\", \"translate(50 160) scale(1)\"] }, delay: 550, ms: 250, ease: \"out\" },\n { id: \"n3\", attrs: { transform: [\"translate(50 260) scale(0)\", \"translate(50 260) scale(1)\"] }, delay: 900, ms: 250, ease: \"out\" },\n { id: \"n4\", attrs: { transform: [\"translate(50 360) scale(0)\", \"translate(50 360) scale(1)\"] }, delay: 1300, ms: 250, ease: \"out\" },\n ],\n },\n};\n\nexport const route: VectorEffect = {\n kind: \"vector\",\n id: \"route\",\n name: \"Route\",\n description: \"A dashed journey drawing between two pins, with a traveller following it.\",\n category: \"data\",\n tags: [\"map\", \"travel\", \"delivery\", \"journey\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 240 150\"><!-- {{accent: color default=#8B5CF6 label='Route'}} {{pin: color default=#0F172A label='Pins'}} --><path id=\"path\" d=\"M30 120 C60 40 120 140 150 70 S210 30 210 30\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"4\" stroke-linecap=\"round\"/><circle cx=\"30\" cy=\"120\" r=\"7\" fill=\"{{pin}}\"/><g id=\"end\" opacity=\"0\"><circle cx=\"210\" cy=\"30\" r=\"9\" fill=\"{{pin}}\"/><circle cx=\"210\" cy=\"30\" r=\"3.5\" fill=\"#fff\"/></g><g id=\"traveller\"><circle r=\"7\" fill=\"{{accent}}\"/><circle r=\"3\" fill=\"#fff\"/></g></svg>`,\n animate: [\n { id: \"path\", draw: true, ms: 1800, ease: \"in-out\" },\n { id: \"traveller\", along: \"path\", ms: 1800, ease: \"in-out\" },\n { id: \"end\", attrs: { opacity: [0, 1] }, delay: 1600, ms: 300 },\n ],\n },\n};\n\nexport const blobMorph: VectorEffect = {\n kind: \"vector\",\n id: \"blob-morph\",\n name: \"Blob morph\",\n description: \"An organic blob shape-shifting through three forms.\",\n category: \"organic\",\n tags: [\"shape\", \"background\", \"playful\", \"brand\"],\n hold: 0,\n motion: (() => {\n const shapes = [\n \"M100 30 C140 30 170 60 170 100 C170 140 140 170 100 170 C60 170 30 140 30 100 C30 60 60 30 100 30Z\",\n \"M100 20 C150 40 180 70 160 110 C140 160 120 175 85 165 C45 155 25 120 40 80 C55 40 70 15 100 20Z\",\n \"M110 35 C155 25 175 85 165 120 C155 160 105 180 70 160 C35 140 20 100 45 70 C65 45 80 40 110 35Z\",\n ];\n const step = 1200;\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{colorA: color default=#F472B6 label='Colour A'}} {{colorB: color default=#818CF8 label='Colour B'}} --><defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"{{colorA}}\"/><stop offset=\"1\" stop-color=\"{{colorB}}\"/></linearGradient></defs><path id=\"blob\" d=\"${shapes[0]}\" fill=\"url(#g)\"/></svg>`,\n animate: shapes.map((d, i) => ({\n id: \"blob\",\n attrs: { d: [d, shapes[(i + 1) % shapes.length]!] as [string, string] },\n delay: i * step,\n ms: step,\n ease: \"in-out\" as const,\n })),\n };\n })(),\n};\n\nexport const signature: VectorEffect = {\n kind: \"vector\",\n id: \"signature\",\n name: \"Signature\",\n description: \"A handwritten flourish drawing itself as if by pen.\",\n category: \"icon\",\n tags: [\"handwriting\", \"draw-on\", \"personal\", \"reveal\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 260 120\"><!-- {{ink: color default=#1E293B label='Ink'}} {{width: float min=1 max=8 default=3 step=0.5 label='Pen width'}} --><path id=\"sig\" d=\"M20 80 C40 20 60 20 55 70 C52 95 70 95 85 60 C95 40 100 75 110 70 C120 65 125 40 135 55 C145 70 150 75 165 50 C175 35 185 60 190 65 C200 75 215 40 240 45\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"dash\" d=\"M70 100 Q140 92 220 98\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/></svg>`,\n animate: [\n { id: \"sig\", draw: true, ms: 1800, ease: \"in-out\" },\n { id: \"dash\", draw: true, delay: 1700, ms: 400, ease: \"out\" },\n ],\n },\n};\n\nexport const equalizer: VectorEffect = {\n kind: \"vector\",\n id: \"equalizer\",\n name: \"Equalizer\",\n description: \"Audio level bars dancing, for now-playing badges and voice states.\",\n category: \"loader\",\n tags: [\"music\", \"audio\", \"voice\", \"now-playing\"],\n hold: 0,\n motion: (() => {\n const heights = [\n [0.3, 0.9, 0.5, 0.3],\n [0.7, 0.4, 1.0, 0.7],\n [0.5, 1.0, 0.3, 0.5],\n [0.9, 0.5, 0.7, 0.9],\n [0.4, 0.8, 0.6, 0.4],\n ];\n const beat = 250;\n return {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#10B981 label='Bars'}} -->${heights\n .map((_, i) => `<g id=\"bar${i}\" transform=\"translate(${14 + i * 16} 85) scale(1 ${heights[i]![0]})\"><rect x=\"0\" y=\"-70\" width=\"10\" height=\"70\" rx=\"5\" fill=\"{{accent}}\"/></g>`)\n .join(\"\")}</svg>`,\n animate: heights.flatMap((h, i) =>\n [0, 1, 2].map((k) => ({\n id: `bar${i}`,\n attrs: { transform: [`translate(${14 + i * 16} 85) scale(1 ${h[k]})`, `translate(${14 + i * 16} 85) scale(1 ${h[k + 1]})`] as [string, string] },\n delay: k * beat,\n ms: beat,\n ease: \"in-out\" as const,\n })),\n ),\n };\n })(),\n};\n\nexport const confetti: VectorEffect = {\n kind: \"vector\",\n id: \"confetti\",\n name: \"Confetti burst\",\n description: \"A burst of confetti flying out and fluttering down.\",\n category: \"icon\",\n tags: [\"celebration\", \"success\", \"party\", \"reward\"],\n hold: 400,\n motion: (() => {\n const pieces = Array.from({ length: 18 }, (_, i) => {\n const angle = (i / 18) * Math.PI * 2 + (i % 3) * 0.2;\n const dist = 55 + (i % 4) * 12;\n const x = Math.round(Math.cos(angle) * dist);\n const y = Math.round(Math.sin(angle) * dist * 0.8 - 20);\n const spin = (i % 2 ? 1 : -1) * (180 + (i % 5) * 60);\n return { i, x, y, spin, fill: [\"{{a}}\", \"{{b}}\", \"{{c}}\"][i % 3]! };\n });\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{a: color default=#F43F5E label='Colour A'}} {{b: color default=#FACC15 label='Colour B'}} {{c: color default=#22D3EE label='Colour C'}} -->${pieces\n .map((p) => `<rect id=\"p${p.i}\" x=\"-4\" y=\"-2\" width=\"8\" height=\"4\" rx=\"1\" fill=\"${p.fill}\" transform=\"translate(100 110) rotate(0)\" opacity=\"0\"/>`)\n .join(\"\")}</svg>`,\n animate: pieces.flatMap((p): SvgAnimation[] => [\n { id: `p${p.i}`, attrs: { opacity: [0, 1] }, ms: 50 },\n {\n id: `p${p.i}`,\n attrs: { transform: [\"translate(100 110) rotate(0)\", `translate(${100 + p.x} ${110 + p.y}) rotate(${p.spin})`] as [string, string] },\n ms: 600,\n ease: \"out\" as const,\n },\n {\n id: `p${p.i}`,\n attrs: {\n transform: [`translate(${100 + p.x} ${110 + p.y}) rotate(${p.spin})`, `translate(${100 + p.x * 1.2} ${180 + p.y * 0.2}) rotate(${p.spin * 2})`] as [string, string],\n },\n delay: 600,\n ms: 1000,\n ease: \"in-out\" as const,\n },\n { id: `p${p.i}`, attrs: { opacity: [1, 0] }, delay: 1300, ms: 300 },\n ]),\n };\n })(),\n};\n\n\n/** Flow network's nodes and links, left to right, with the critical path through them. */\nconst NODES: Record<string, [number, number]> = {\n s: [40, 120], a: [120, 60], b: [120, 180], c: [280, 50], d: [290, 130], e: [280, 200], t: [360, 120],\n};\nconst HUB: [number, number] = [200, 120];\nconst link = ([x1, y1]: [number, number], [x2, y2]: [number, number]) => {\n const mid = (x1 + x2) / 2;\n return `M${x1} ${y1} C${mid} ${y1} ${mid} ${y2} ${x2} ${y2}`;\n};\nconst LINKS: { from: [number, number]; to: [number, number]; column: number }[] = [\n { from: NODES.s!, to: NODES.a!, column: 0 },\n { from: NODES.s!, to: NODES.b!, column: 0 },\n { from: NODES.a!, to: HUB, column: 1 },\n { from: NODES.b!, to: HUB, column: 1 },\n { from: HUB, to: NODES.c!, column: 2 },\n { from: HUB, to: NODES.d!, column: 2 },\n { from: HUB, to: NODES.e!, column: 2 },\n { from: NODES.c!, to: NODES.t!, column: 3 },\n { from: NODES.d!, to: NODES.t!, column: 3 },\n { from: NODES.e!, to: NODES.t!, column: 3 },\n];\nconst CRITICAL = [NODES.s!, NODES.b!, HUB, NODES.c!, NODES.t!]\n .map((p, i, all) => (i === 0 ? \"\" : link(all[i - 1]!, p).replace(/^M[\\d.]+ [\\d.]+ /, i === 1 ? `M${all[0]![0]} ${all[0]![1]} ` : \"\")))\n .filter(Boolean)\n .join(\" \");\n/** The column a node is reached in, so it appears as the links arrive. */\nconst NODE_COLUMN: Record<string, number> = { s: 0, a: 1, b: 1, c: 3, d: 3, e: 3, t: 4 };\nconst COLUMN_MS = 280;\nconst PATH_START = 1500;\nconst PATH_MS = 1800;\n\nexport const flowNetwork: VectorEffect = {\n kind: \"vector\",\n id: \"flow-network\",\n name: \"Flow network\",\n description: \"A node graph linking up, then a glowing critical path racing through it to a pulsing hub.\",\n category: \"data\",\n tags: [\"network\", \"graph\", \"dag\", \"workflow\", \"tech\", \"explainer\"],\n hold: 1200,\n presets: [\n { name: \"Light\", values: { background: [0.93, 0.95, 0.96], link: [0.37, 0.72, 0.69], path: [0.96, 0.62, 0.04], ink: [0.2, 0.25, 0.33] } },\n { name: \"Neon\", values: { background: [0.04, 0.02, 0.1], link: [0.13, 0.83, 0.93], path: [0.96, 0.45, 0.71], ink: [0.85, 0.85, 1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 400 240\" font-family=\"system-ui, sans-serif\"><!-- {{label: text default='Critical path' label='Hub label'}} {{background: color default=#0B1220 label='Background'}} {{link: color default=#4FD1C5 label='Links'}} {{path: color default=#F5A524 label='Critical path'}} {{ink: color default=#CBD5E1 label='Label'}} {{glow: float min=0 max=6 default=2.5 step=0.5 label='Glow'}} --><defs><filter id=\"glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\"><feGaussianBlur stdDeviation=\"{{glow}}\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs><rect width=\"400\" height=\"240\" fill=\"{{background}}\"/>${LINKS.map(\n (l, i) => `<path id=\"l${i}\" d=\"${link(l.from, l.to)}\" fill=\"none\" stroke=\"{{link}}\" stroke-width=\"1.6\" stroke-opacity=\"0.75\" filter=\"url(#glow)\"/>`,\n ).join(\"\")}<path id=\"crit\" d=\"${CRITICAL}\" fill=\"none\" stroke=\"{{path}}\" stroke-width=\"3\" stroke-linecap=\"round\" filter=\"url(#glow)\"/>${[0, 1]\n .map((i) => `<circle id=\"ring${i}\" cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"10\" fill=\"none\" stroke=\"{{link}}\" stroke-width=\"2\" opacity=\"0\"/>`)\n .join(\"\")}${Object.entries(NODES)\n .map(([id, [x, y]]) => `<circle id=\"n${id}\" cx=\"${x}\" cy=\"${y}\" r=\"6\" fill=\"{{background}}\" stroke=\"{{link}}\" stroke-width=\"2.5\" filter=\"url(#glow)\" opacity=\"0\"/>`)\n .join(\"\")}<g id=\"hub\" opacity=\"0\"><circle cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"13\" fill=\"{{link}}\" fill-opacity=\"0.25\" stroke=\"{{link}}\" stroke-width=\"2\" filter=\"url(#glow)\"/><circle cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"6\" fill=\"{{link}}\"/></g><text id=\"caption\" x=\"${HUB[0]}\" y=\"${HUB[1] + 34}\" text-anchor=\"middle\" font-size=\"12\" font-weight=\"600\" fill=\"{{ink}}\" opacity=\"0\">{{label}}</text>${[0, 1, 2]\n .map((i) => `<circle id=\"pkt${i}\" r=\"2.5\" fill=\"{{link}}\" filter=\"url(#glow)\" opacity=\"0\"/>`)\n .join(\"\")}<circle id=\"comet\" r=\"5\" fill=\"#FFFFFF\" stroke=\"{{path}}\" stroke-width=\"2\" filter=\"url(#glow)\" opacity=\"0\"/></svg>`,\n animate: [\n ...LINKS.map((l, i): SvgAnimation => ({ id: `l${i}`, draw: true, delay: l.column * COLUMN_MS, ms: 500, ease: \"out\" })),\n ...Object.keys(NODES).map((id): SvgAnimation => ({ id: `n${id}`, attrs: { opacity: [0, 1] }, delay: Math.max(0, NODE_COLUMN[id]! * COLUMN_MS - 120), ms: 250 })),\n { id: \"hub\", attrs: { opacity: [0, 1] }, delay: 2 * COLUMN_MS - 120, ms: 300 },\n { id: \"caption\", attrs: { opacity: [0, 1], y: [HUB[1] + 40, HUB[1] + 34] }, delay: 2 * COLUMN_MS, ms: 400, ease: \"out\" },\n // Data packets drift along a few links while the path waits.\n ...[3, 5, 8].map((link, i): SvgAnimation[] => [\n { id: `pkt${i}`, attrs: { opacity: [0, 1] }, delay: 1000 + i * 150, ms: 150 },\n { id: `pkt${i}`, along: `l${link}`, delay: 1000 + i * 150, ms: 1100, ease: \"in-out\" },\n { id: `pkt${i}`, attrs: { opacity: [1, 0] }, delay: 2000 + i * 150, ms: 200 },\n ]).flat(),\n { id: \"crit\", draw: true, delay: PATH_START, ms: PATH_MS, ease: \"in-out\" },\n { id: \"comet\", attrs: { opacity: [0, 1] }, delay: PATH_START, ms: 150 },\n { id: \"comet\", along: \"crit\", delay: PATH_START, ms: PATH_MS, ease: \"in-out\" },\n { id: \"comet\", attrs: { opacity: [1, 0] }, delay: PATH_START + PATH_MS, ms: 300 },\n // Rings pulse out from the hub as the comet passes it, halfway along.\n ...[0, 1].map((i): SvgAnimation => ({\n id: `ring${i}`,\n attrs: { r: [10, 52], opacity: [0.9, 0], \"stroke-width\": [3, 0.5] },\n delay: PATH_START + PATH_MS / 2 + i * 350,\n ms: 1200,\n ease: \"out\",\n })),\n ],\n },\n};\n\n/** Drip text's word: its baseline, size, and cap height (a heavy sans's, about 0.72 of its size). */\nconst DRIP_BASELINE = 120;\nconst DRIP_SIZE = 104;\nconst DRIP_CAP = 75;\n/** Drip text's drips: where each leaves the word, as a fraction of its run of the word, and how it runs. */\nconst DRIP_TOP = 106;\nconst DRIPS = [\n { at: 0.067, width: 11, length: 34, delay: 0, ms: 1500 },\n { at: 0.18, width: 8, length: 18, delay: 260, ms: 1100 },\n { at: 0.3, width: 13, length: 50, delay: 120, ms: 1800 },\n { at: 0.453, width: 9, length: 22, delay: 380, ms: 1200 },\n { at: 0.587, width: 10, length: 28, delay: 200, ms: 1400 },\n { at: 0.693, width: 12, length: 42, delay: 60, ms: 1700 },\n { at: 0.793, width: 11, length: 32, delay: 300, ms: 1500 },\n];\n/**\n * The drips repeat along a long word, one run of them every `DRIP_RUN`\n * units (about four letters), up to `DRIP_RUNS` runs; past that the runs\n * spread out.\n */\nconst DRIP_RUN = 300;\nconst DRIP_RUNS = 8;\nconst DRIP_SLOTS = Array.from({ length: DRIP_RUNS }, (_, run) => DRIPS.map((d, k) => ({ ...d, i: run * DRIPS.length + k, run, delay: d.delay + run * 90 }))).flat();\n\n/**\n * Drip text. The word keeps its letters' shapes at any length: on its own\n * stage a long word is scaled down to fit, and with `inline` on the picture\n * widens with it instead. Inline, it frames the word from cap height to\n * baseline and lets the rest spill out (by its `data-overhang`, see\n * `svgInlineLayout`), so in a heading it sits on the baseline without adding\n * leading: give its container `display: inline-block; height: 0.72em` and\n * the viewBox's aspect ratio. A `font` of `inherit` takes the surrounding\n * text's, and colours take `currentColor`.\n */\nexport const dripText: VectorEffect = {\n kind: \"vector\",\n id: \"drip-text\",\n name: \"Drip text\",\n description: \"A chunky outlined title popping in, then oozing slime drips from its letters; Inline sets it in a line of text.\",\n category: \"text\",\n tags: [\"title\", \"text\", \"drip\", \"slime\", \"y2k\", \"headline\"],\n hold: 1200,\n presets: [\n { name: \"Slime\", values: { fill: [0.55, 0.93, 0.25], outline: [0.06, 0.2, 0.04], shine: [0.85, 1, 0.7] } },\n { name: \"Molten gold\", values: { fill: [1, 0.78, 0.2], outline: [0.35, 0.16, 0], shine: [1, 0.96, 0.75], drip: 1.5 } },\n ],\n // The word is drawn at its own width (textLength from its estimated width), so the drips land under its letters in any font.\n derived: (v) => {\n const width = Math.round(Math.max(0.6, textWidthEm(String(v.word).trim())) * DRIP_SIZE);\n const left = 200 - width / 2;\n const runs = Math.min(DRIP_RUNS, Math.max(1, Math.round(width / DRIP_RUN)));\n const run = width / runs;\n const r1 = (n: number) => Math.round(n * 10) / 10;\n // At rest: the longest drip's tip below the baseline, and the outline's half width all round, in ems.\n const edge = Number(v.stroke) / 2 / DRIP_SIZE;\n const tip = (DRIP_TOP + Math.max(...DRIPS.map((d) => d.length)) * Number(v.drip) + 13 * 0.72 - DRIP_BASELINE) / DRIP_SIZE;\n const overhang = [edge, edge, Math.max(0.05, tip) + edge, edge].map((e) => Math.round(e * 100) / 100).join(\" \");\n return {\n width,\n fit: v.inline ? 1 : Math.round(Math.min(1, 380 / width) * 1000) / 1000,\n // Inline, the picture frames just the word's capitals, from cap height to baseline, so it sits on\n // the line like a letter would; the pop, outline and drips spill out over the text around it.\n viewBox: v.inline ? `${left} ${DRIP_BASELINE - DRIP_CAP} ${width} ${DRIP_CAP}` : \"0 0 400 200\",\n overflow: v.inline ? \"visible\" : \"hidden\",\n overhang,\n ...Object.fromEntries(\n DRIP_SLOTS.flatMap((d) => {\n const x = r1(left + (d.run + d.at) * run);\n const length = r1(d.length * Number(v.drip));\n return [\n [`show${d.i}`, d.run < runs ? \"inline\" : \"none\"],\n [`x${d.i}`, x],\n [`left${d.i}`, r1(x - d.width / 2)],\n [`shine${d.i}`, r1(x - d.width * 0.25)],\n [`len${d.i}`, length],\n [`tip${d.i}`, r1(DRIP_TOP + length)],\n ];\n }),\n ),\n };\n },\n motion: (() => {\n const word = `<text x=\"200\" y=\"${DRIP_BASELINE}\" text-anchor=\"middle\" textLength=\"{{width}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"${DRIP_SIZE}\" font-weight=\"{{weight}}\" stroke-linejoin=\"round\"`;\n const drips = (layer: \"o\" | \"f\", paint: string) =>\n DRIP_SLOTS.map(\n (d) =>\n `<g display=\"{{show${d.i}}}\"><rect id=\"${layer}r${d.i}\" x=\"{{left${d.i}}}\" y=\"${DRIP_TOP}\" width=\"${d.width}\" height=\"0\" rx=\"${d.width / 2}\" ${paint}/><circle id=\"${layer}c${d.i}\" cx=\"{{x${d.i}}}\" cy=\"${DRIP_TOP}\" r=\"${d.width * 0.72}\" ${paint}/></g>`,\n ).join(\"\");\n const outline = `fill=\"{{outline}}\" stroke=\"{{outline}}\" stroke-width=\"{{stroke}}\"`;\n const pop = (from: number, to: number) =>\n [`translate(200 100) scale(${from}) translate(-200 -100)`, `translate(200 100) scale(${to}) translate(-200 -100)`] as [string, string];\n return {\n svg: `<svg viewBox=\"{{viewBox}}\" overflow=\"{{overflow}}\" data-overhang=\"{{overhang}}\"><!-- {{word: text default=SLOP label='Word'}} {{font: text default='Arial Black, Impact, system-ui, sans-serif' label='Font'}} {{weight: int min=100 max=900 default=900 step=100 label='Weight'}} {{fill: color default=#FF7EB6 label='Fill'}} {{outline: color default=#3A0A2C label='Outline'}} {{shine: color default=#FFD1E6 label='Shine'}} {{drip: float min=0.2 max=2 default=1 label='Drip length'}} {{stroke: float min=0 max=14 default=7 step=0.5 label='Outline width'}} {{inline: bool default=false label='Inline'}} --><g transform=\"translate(200 100) scale({{fit}}) translate(-200 -100)\"><g id=\"word\" transform=\"${pop(0.6, 1)[0]}\" opacity=\"0\">${drips(\"o\", outline)}${word} fill=\"none\" stroke=\"{{outline}}\" stroke-width=\"{{stroke}}\">{{word}}</text>${drips(\"f\", `fill=\"{{fill}}\"`)}${word} fill=\"{{fill}}\">{{word}}</text>${DRIP_SLOTS.map(\n (d) => `<circle id=\"s${d.i}\" display=\"{{show${d.i}}}\" cx=\"{{shine${d.i}}}\" cy=\"${DRIP_TOP}\" r=\"${d.width * 0.2}\" fill=\"{{shine}}\" opacity=\"0\"/>`,\n ).join(\"\")}</g></g></svg>`,\n animate: [\n { id: \"word\", attrs: { transform: pop(0.6, 1.08), opacity: [0, 1] }, ms: 260, ease: \"out\" },\n { id: \"word\", attrs: { transform: pop(1.08, 1) }, delay: 260, ms: 200, ease: \"in-out\" },\n ...DRIP_SLOTS.flatMap((d): SvgAnimation[] => {\n const at = { delay: 400 + d.delay, ms: d.ms, ease: \"in-out\" as const };\n const tip = `{{tip${d.i}}}` as unknown as number;\n return [\n ...([\"o\", \"f\"] as const).flatMap((layer): SvgAnimation[] => [\n { id: `${layer}r${d.i}`, attrs: { height: [0, `{{len${d.i}}}` as unknown as number] }, ...at },\n { id: `${layer}c${d.i}`, attrs: { cy: [DRIP_TOP, tip] }, ...at },\n ]),\n { id: `s${d.i}`, attrs: { cy: [DRIP_TOP, tip], opacity: [0, 0.9] }, ...at },\n ];\n }),\n ],\n };\n })(),\n};\n\n/** Viewfinder's timecode runs this many seconds (at 25 fps) before it loops back to zero. */\nconst VIEWFINDER_SECONDS = 10;\n\nexport const viewfinder: VectorEffect = {\n kind: \"vector\",\n id: \"viewfinder\",\n name: \"Viewfinder\",\n description: \"A camera viewfinder over the picture: corner brackets, a blinking REC light and a running timecode.\",\n category: \"overlay\",\n tags: [\"overlay\", \"camera\", \"recording\", \"vlog\", \"frame\"],\n hold: 0,\n presets: [\n { name: \"Night vision\", values: { color: [0.45, 1, 0.45], rec: [0.45, 1, 0.45] } },\n { name: \"Live\", values: { label: \"LIVE\", timecode: false } },\n ],\n derived: (v) => ({ timecodeOpacity: v.timecode ? 1 : 0 }),\n motion: {\n svg: `<svg viewBox=\"0 0 320 180\" font-family=\"ui-monospace, Menlo, Consolas, monospace\"><!-- {{color: color default=#FFFFFF label='Frame'}} {{rec: color default=#EF4444 label='Record light'}} {{timecode: bool default=true label='Timecode'}} --><g fill=\"none\" stroke=\"{{color}}\" stroke-width=\"2.5\" stroke-linecap=\"square\"><path d=\"M16 42 V16 H42\"/><path d=\"M278 16 H304 V42\"/><path d=\"M304 138 V164 H278\"/><path d=\"M42 164 H16 V138\"/><path d=\"M154 90 H166 M160 84 V96\" stroke-width=\"1.5\" opacity=\"0.8\"/></g><circle id=\"dot\" cx=\"34\" cy=\"33\" r=\"4.5\" fill=\"{{rec}}\"/><text x=\"44\" y=\"37.5\" font-size=\"12\" font-weight=\"700\" fill=\"{{color}}\">{{label: text default=REC label='Label'}}</text><text x=\"296\" y=\"37.5\" text-anchor=\"end\" font-size=\"12\" fill=\"{{color}}\" opacity=\"{{timecodeOpacity}}\">00:00:<tspan id=\"sec\">00</tspan>:<tspan id=\"ff\">00</tspan></text></svg>`,\n animate: Array.from({ length: VIEWFINDER_SECONDS }, (_, s): SvgAnimation[] => [\n { id: \"sec\", count: [s, s], format: s < 10 ? \"0{n}\" : \"{n}\", delay: s * 1000, ms: 1 },\n // Frames 00–24: the single digits padded with a zero, then the rest.\n { id: \"ff\", count: [0, 9.49], format: \"0{n}\", delay: s * 1000, ms: 400, ease: \"linear\" },\n { id: \"ff\", count: [10, 24.49], format: \"{n}\", delay: s * 1000 + 400, ms: 600, ease: \"linear\" },\n { id: \"dot\", attrs: { opacity: [0, 1] }, delay: s * 1000, ms: 1 },\n { id: \"dot\", attrs: { opacity: [1, 0] }, delay: s * 1000 + 600, ms: 1 },\n ]).flat(),\n },\n};\n\nexport const vectorEffects: VectorEffect[] = [\n spinner,\n bouncingDots,\n pulsePing,\n equalizer,\n progressRing,\n barChart,\n lineChart,\n statCounter,\n route,\n timelineTrack,\n successCheck,\n errorCross,\n heartbeat,\n signature,\n confetti,\n blobMorph,\n dripText,\n flowNetwork,\n viewfinder,\n];\n","/**\n * The effect catalog: ready-made shader and vector effects, each with\n * controls and presets, to drop into a product or start an edit from.\n *\n * - Browsing: `EFFECTS`, `getEffect`, `findEffects`, `EFFECT_CATEGORIES`.\n * - Controls: `effectControls`, `effectDefaults`.\n * - Vector effects: their pictures declare their controls (`vectorControls`),\n * and `renderVectorEffect` fills them in.\n *\n * @packageDocumentation\n */\n\nimport { controlValue, parseControls, type ControlDef, type ControlValue } from \"../shader/controls.js\";\nimport { aurora, conicSweep, duotoneFlow, meshGradient, silk } from \"./shaders/gradients.js\";\nimport {\n crt,\n filmGrain,\n imageDuotone,\n imageGlitch,\n imageHalftone,\n imagePixelate,\n imageRipple,\n transitions,\n} from \"./shaders/image.js\";\nimport { blackHole, bokeh, godRays, lightRibbons, nebula, neonRipple, sparkles, starfield } from \"./shaders/light.js\";\nimport { caustics, flames, lavaLamp, marble, plasma, smoke } from \"./shaders/organic.js\";\nimport { barberStripes, dotWave, hexPulse, kaleidoscope, moire, neonCircuit, truchet, voronoi } from \"./shaders/patterns.js\";\nimport { interactionEffects } from \"./interaction.js\";\nimport { electricEffects } from \"./electric.js\";\nimport { meltEffects } from \"./melt.js\";\nimport { pixelEffects } from \"./pixel.js\";\nimport { pyroEffects } from \"./pyro.js\";\nimport { timewarpEffects } from \"./timewarp.js\";\nimport { morphEffects } from \"./morph.js\";\nimport { interactionShaders } from \"./shaders/interaction.js\";\nimport { electricShaders } from \"./shaders/electric.js\";\nimport { meltShaders } from \"./shaders/melt.js\";\nimport { pixelShaders } from \"./shaders/pixel.js\";\nimport { pyroShaders } from \"./shaders/pyro.js\";\nimport { timewarpShaders } from \"./shaders/timewarp.js\";\nimport { morphShaders } from \"./shaders/morph.js\";\nimport { overlayEffects } from \"./shaders/overlay.js\";\nimport { digitalRain, pixelSunset, synthwaveGrid, tvStatic } from \"./shaders/retro.js\";\nimport { textShaders } from \"./shaders/text.js\";\nimport { imageTreatments } from \"./shaders/treatments.js\";\nimport { textEffects } from \"./text.js\";\nimport { CURRENT_COLOR, EFFECT_CATEGORIES, isCurrentColor, vectorEffectControls, type EffectCategory, type EffectDefinition, type ShaderEffect } from \"./types.js\";\nimport { vectorEffects } from \"./vector.js\";\n\nexport {\n colorControl,\n CURRENT_COLOR,\n EFFECT_CATEGORIES,\n isCurrentColor,\n numberControl,\n renderVectorEffect,\n VECTOR_CONTROL_TYPES,\n vectorControlDef,\n vectorControlIssues,\n vectorControls,\n vectorEffectControls,\n type EffectCategory,\n type EffectDefinition,\n type EffectPreset,\n type ShaderEffect,\n type VectorControl,\n type VectorEffect,\n} from \"./types.js\";\nexport { SAMPLE_IMAGES, svgDataUrl, textImage } from \"./images.js\";\nexport { FBM, glsl, HASH, NOISE, OKLAB_MIX, PALETTE, ROTATE } from \"./glsl.js\";\n\n/** The catalog's shader effects. */\nexport const SHADER_EFFECTS: readonly ShaderEffect[] = [\n meshGradient,\n aurora,\n duotoneFlow,\n conicSweep,\n silk,\n marble,\n smoke,\n lavaLamp,\n plasma,\n caustics,\n flames,\n dotWave,\n truchet,\n hexPulse,\n voronoi,\n moire,\n kaleidoscope,\n barberStripes,\n neonCircuit,\n bokeh,\n godRays,\n sparkles,\n neonRipple,\n lightRibbons,\n starfield,\n nebula,\n blackHole,\n synthwaveGrid,\n digitalRain,\n pixelSunset,\n tvStatic,\n imageRipple,\n imageGlitch,\n imageDuotone,\n imageHalftone,\n imagePixelate,\n ...imageTreatments,\n crt,\n filmGrain,\n ...overlayEffects,\n ...textShaders,\n ...morphShaders,\n ...interactionShaders,\n ...pyroShaders,\n ...timewarpShaders,\n ...meltShaders,\n ...electricShaders,\n ...pixelShaders,\n ...transitions,\n];\n\n/** Every effect in the catalog, shaders first, grouped by category. */\nexport const EFFECTS: readonly EffectDefinition[] = [...SHADER_EFFECTS, ...vectorEffects, ...textEffects, ...morphEffects, ...interactionEffects, ...pyroEffects, ...timewarpEffects, ...meltEffects, ...electricEffects, ...pixelEffects].sort(\n (a, b) => EFFECT_CATEGORIES.indexOf(a.category) - EFFECT_CATEGORIES.indexOf(b.category),\n);\n\nconst byId = new Map(EFFECTS.map((e) => [e.id, e]));\n\n/** The effect with this id, or undefined. */\nexport function getEffect(id: string): EffectDefinition | undefined {\n return byId.get(id);\n}\n\nexport interface EffectQuery {\n /** Words to look for in the name, description, tags and id (all must match). */\n text?: string;\n category?: EffectCategory;\n kind?: EffectDefinition[\"kind\"];\n /** Effects with every one of these tags. */\n tags?: readonly string[];\n}\n\n/** Effects matching a query, in catalog order. */\nexport function findEffects(query: EffectQuery = {}): EffectDefinition[] {\n const words = (query.text ?? \"\").toLowerCase().split(/\\s+/).filter(Boolean);\n return EFFECTS.filter((e) => {\n if (query.category && e.category !== query.category) return false;\n if (query.kind && e.kind !== query.kind) return false;\n if (query.tags && !query.tags.every((t) => e.tags.includes(t))) return false;\n const haystack = [e.id, e.name, e.description, e.category, ...e.tags].join(\" \").toLowerCase();\n return words.every((w) => haystack.includes(w));\n });\n}\n\n/** An effect's controls: a shader's `@control` uniforms, or a vector effect's declared controls. */\nexport function effectControls(effect: EffectDefinition): ControlDef[] {\n return effect.kind === \"shader\" ? parseControls(effect.source) : vectorEffectControls(effect);\n}\n\n/** An effect's values: each control's default, overridden by `values` (and a preset by name, when given). */\nexport function effectDefaults(\n effect: EffectDefinition,\n options: { preset?: string; values?: Record<string, ControlValue> } = {},\n): Record<string, ControlValue> {\n const preset = options.preset ? effect.presets?.find((p) => p.name === options.preset)?.values : undefined;\n const merged = { ...preset, ...options.values };\n // A vector effect's colours may also follow the text around it.\n const keep = (c: ControlDef) => effect.kind === \"vector\" && c.color && isCurrentColor(merged[c.name]);\n return Object.fromEntries(effectControls(effect).map((c) => [c.name, keep(c) ? CURRENT_COLOR : controlValue(c, merged)]));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAOO,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAUjB,KAAK;AAGD,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAUlB,KAAK;AAGD,IAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAYhB,KAAK;AAGD,IAAM,UAAU;AAAA;AAAA;AAAA,GAGpB,KAAK;AAGD,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAetB,KAAK;AAGD,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,GAKnB,KAAK;AAGD,SAAS,QAAQ,OAAyB;AAC/C,SAAO,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI;AACnD;;;AC/EO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,QAAQ,OAAO;AAAA,EAC5C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACrF,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,KAAK,GAAG,EAAE,EAAE;AAAA,IACvG,EAAE,MAAM,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,KAAK,CAAC,GAAG,QAAQ,CAAC,KAAK,KAAK,CAAC,EAAE,EAAE;AAAA,EACpG;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,SAAS,MAAM;AAAA,EAC5C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IACtI,EAAE,MAAM,UAAU,QAAQ,EAAE,SAAS,CAAC,GAAK,KAAK,GAAG,GAAG,SAAS,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE;AAAA,IACvI,EAAE,MAAM,QAAQ,QAAQ,EAAE,SAAS,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,EAAE,EAAE;AAAA,EACzI;AACF;AAEO,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,aAAa,OAAO;AAAA,EACzC,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF;AACF;AAEO,IAAM,OAAqB;AAAA,EAChC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,UAAU,MAAM;AAAA,EACrC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE;AAAA,IACnF,EAAE,MAAM,YAAY,QAAQ,EAAE,OAAO,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,MAAM,CAAC,EAAE,EAAE;AAAA,EACnF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,QAAQ;AAAA,EACtC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF;AACF;;;AC9LO,SAAS,WAAW,KAAqB;AAC9C,QAAM,SACJ,OAAO,SAAS,aAAa,KAAK,GAAG,IAAK,WAAiF,OAAQ,KAAK,GAAG,EAAE,SAAS,QAAQ;AAChK,SAAO,6BAA6B,MAAM;AAC5C;AAEA,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASlB,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAOb,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWjB,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYnB,IAAM,OAAO;AAAA;AAAA;AAAA;AAKb,IAAM,QAAQ;AAAA;AAAA;AAQd,IAAM,OAAO;AAGN,IAAM,gBAAgB;AAAA,EAC3B,WAAW,WAAW,SAAS;AAAA,EAC/B,MAAM,WAAW,IAAI;AAAA,EACrB,UAAU,WAAW,QAAQ;AAAA;AAAA,EAE7B,WAAW,WAAW,UAAU;AAAA;AAAA,EAEhC,MAAM,WAAW,IAAI;AAAA;AAAA,EAErB,OAAO,WAAW,KAAK;AAAA,EACvB,MAAM,WAAW,IAAI;AACvB;AAGA,SAAS,UAAU,GAAmB;AACpC,MAAI,iBAAiB,KAAK,CAAC,EAAG,QAAO;AACrC,MAAI,iBAAiB,KAAK,CAAC,EAAG,QAAO;AACrC,MAAI,SAAS,KAAK,CAAC,EAAG,QAAO;AAC7B,MAAI,OAAO,KAAK,CAAC,EAAG,QAAO;AAC3B,MAAI,UAAU,KAAK,CAAC,EAAG,QAAO;AAC9B,MAAI,QAAQ,KAAK,CAAC,EAAG,QAAO;AAC5B,MAAI,QAAQ,KAAK,CAAC,EAAG,QAAO;AAE5B,SAAO,kDAAkD,KAAK,CAAC,IAAI,IAAI;AACzE;AAGO,SAAS,YAAY,MAAsB;AAChD,SAAO,MAAM,KAAK,IAAI,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,UAAU,CAAC,GAAG,CAAC;AAClE;AAEA,IAAM,YAAY,CAAC,SACjB,KAAK,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,QAAQ,EAAE,QAAQ,MAAM,OAAO;AAsBhH,SAAS,UAAU,MAAc,UAA4B,CAAC,GAAW;AAC9E,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,MAAM,KAAK,IAAI,KAAK,YAAY,IAAI,CAAC;AAC3C,QAAM,OAAO,QAAQ,QAAQ,KAAK,IAAI,SAAS,MAAO,QAAQ,MAAO,GAAG;AACxE,QAAM,SAAS,KAAK,IAAI,QAAQ,MAAM,MAAM,IAAI;AAChD,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,MAAM,wDAAwD,KAAK,IAAI,MAAM,YAAY,KAAK,aAAa,MAAM,cAAc,QAAQ,CAAC,QAAQ,SAAS,CAAC,kDAAkD,CAAC,OAAO,QAAQ,CAAC,CAAC,kDAAkD,UAAU,IAAI,CAAC,kBAAkB,UAAU,OAAO,QAAQ,UAAU,GAAG,CAAC,CAAC,gBAAgB,CAAC,KAAK,QAAQ,CAAC,CAAC,iBAAiB,UAAU,IAAI,CAAC;AAE/Z,SAAO,oCAAoC,mBAAmB,GAAG,EAAE,QAAQ,YAAY,CAAC,MAAM,IAAI,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC;AACjJ;;;ACxHO,IAAM,oBAAoB;AAAA;AAAA,6FAE4D,KAAK;AAM3F,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAOrB,KAAK;AASD,IAAM,UAAU;AAAA,EACrB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAgBP,KAAK;AAED,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,eAAe,YAAY;AAAA,EACpD,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA,EAIhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,UAAU,SAAS,YAAY;AAAA,EAC/C,QAAQ;AAAA,IACN;AAAA,0EACsE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA,EAI/F,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,aAAa,QAAQ;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA,0EACsE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/F,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,WAAW,QAAQ,EAAE,SAAS,CAAC,MAAM,KAAK,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IAC1F,EAAE,MAAM,aAAa,QAAQ,EAAE,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EAC5F;AACF;AAEO,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,UAAU,cAAc,OAAO;AAAA,EAC/C,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA,EAIhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF;AACF;AAEO,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,SAAS,SAAS;AAAA,EAC3C,QAAQ;AAAA,IACN;AAAA,0EACsE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/F,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF;AACF;AAEO,IAAM,MAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,SAAS,UAAU,QAAQ;AAAA,EAC3C,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,aAAa,SAAS,SAAS;AAAA,EAC/C,QAAQ;AAAA,IACN;AAAA,2EACuE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhG,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeF;AACF;AAEA,IAAM,cAAyF;AAAA,EAC7F,EAAE,MAAM,cAAc,IAAI,QAAQ,MAAM,QAAQ,aAAa,gDAAgD;AAAA,EAC7G,EAAE,MAAM,cAAc,IAAI,QAAQ,MAAM,QAAQ,aAAa,wDAAwD;AAAA,EACrH,EAAE,MAAM,iBAAiB,IAAI,kBAAkB,MAAM,kBAAkB,aAAa,6CAA6C;AAAA,EACjI,EAAE,MAAM,YAAY,IAAI,aAAa,MAAM,aAAa,aAAa,wDAAwD;AAAA,EAC7H,EAAE,MAAM,aAAa,IAAI,cAAc,MAAM,cAAc,aAAa,2CAA2C;AAAA,EACnH,EAAE,MAAM,WAAW,IAAI,WAAW,MAAM,WAAW,aAAa,+CAA+C;AAAA,EAC/G,EAAE,MAAM,aAAa,IAAI,cAAc,MAAM,cAAc,aAAa,2DAA2D;AAAA,EACnI,EAAE,MAAM,aAAa,IAAI,cAAc,MAAM,cAAc,aAAa,kDAAkD;AAC5H;AAGO,IAAM,cAA8B,YAAY,IAAI,CAAC,EAAE,MAAM,IAAI,MAAM,YAAY,OAAO;AAAA,EAC/F,MAAM;AAAA,EACN,IAAI,cAAc,EAAE;AAAA,EACpB;AAAA,EACA,aAAa,GAAG,WAAW;AAAA,EAC3B,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,WAAW;AAAA,EACzC,MAAM;AAAA,EACN,QAAQ;AAAA,IACN,MAAM,IAAI;AAAA,0EAC4D,cAAc,SAAS;AAAA,0EACvB,cAAc,IAAI;AAAA;AAAA;AAAA,EAG1F,iBAAiB;AAAA,IACf;AAAA,IACA,kBAAkB,IAAI;AAAA,IACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKF;AACF,EAAE;;;AC/TK,IAAM,QAAsB;AAAA,EACjC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,WAAW,UAAU,OAAO;AAAA,EACjD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBF;AACF;AAEO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,YAAY,WAAW;AAAA,EACpD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,eAAe,SAAS;AAAA,EACnD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBF;AACF;AAEO,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,QAAQ,SAAS,OAAO;AAAA,EAC9C,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,SAAS,QAAQ;AAAA,EAC/C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBF;AACF;AAEO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,UAAU,MAAM;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,YAAY,UAAU,MAAM;AAAA,EAC5C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,QAAQ,cAAc,MAAM;AAAA,EACzD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,aAAa,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,KAAK,GAAG,GAAG,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,QAAQ,GAAG,SAAS,IAAI,EAAE;AAAA,IACnK,EAAE,MAAM,UAAU,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,OAAO,MAAM,OAAO,IAAI,EAAE;AAAA,EAChI;AACF;;;ACtTO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,OAAO,UAAU,QAAQ;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,GAAG,EAAE,EAAE;AAAA,IAC5G,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAChH;AACF;AAEO,IAAM,QAAsB;AAAA,EACjC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,cAAc,SAAS,MAAM;AAAA,EAClD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,WAAW,SAAS,OAAO;AAAA,EAChD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBF;AACF;AAEO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,eAAe,MAAM;AAAA,EACnD,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,SAAS,UAAU,MAAM;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AACF;AAEO,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,UAAU,OAAO,SAAS;AAAA,EACzC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IAChG,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EACvG;AACF;;;AChNO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,YAAY,QAAQ,SAAS;AAAA,EAClD,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF;AACF;AAEO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,aAAa,MAAM;AAAA,EAChD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBF;AACF;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,aAAa,QAAQ;AAAA,EAClD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBF;AACF;AAEO,IAAM,QAAsB;AAAA,EACjC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,UAAU,YAAY,SAAS;AAAA,EACpD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF;AACF;AAEO,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,UAAU,WAAW,MAAM;AAAA,EAC9C,MAAM;AAAA,EACN,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF;AACF;AAEO,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,WAAW,SAAS,SAAS;AAAA,EAClD,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,SAAS,UAAU;AAAA,EACzC,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,cAAc,QAAQ,WAAW,QAAQ,OAAO,WAAW;AAAA,EAClE,QAAQ;AAAA,IACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAcA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmFF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,aAAa,CAAC,GAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,EAAE,EAAE;AAAA,IACxK,EAAE,MAAM,aAAa,QAAQ,EAAE,aAAa,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,GAAG,OAAO,KAAK,SAAS,IAAI,EAAE;AAAA,IAC7L,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,IAAI,UAAU,GAAG,QAAQ,MAAM,SAAS,IAAI,EAAE;AAAA,EACnF;AACF;;;ACrUA,IAAM,KAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAC/C,IAAM,KAAK,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAGhD,IAAM,IAAI,CAAC,SAAiB,KAAK,IAAI;AAGrC,IAAM,SAAS,CAAC,GAAY,GAAY,MAAc;AACpD,QAAM,IAAK,MAAM,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC;AAC1C,QAAM,IAAK,MAAM,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC;AAC1C,SAAO,SAAS,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,KAAM,EAAE,CAAC,IAAK,EAAE,CAAC,KAAM,CAAC,CAAC;AACnE;AAGA,SAAS,IAAI,MAAe,OAAe,KAAa;AACtD,QAAM,IAAI,KAAK,IAAI,KAAK,YAAY,OAAO,IAAI,CAAC,CAAC;AACjD,QAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,CAAC;AACpC,SAAO,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,IAAI,EAAE;AAChD;AAGA,IAAM,QAAQ,CAAC,IAAY,IAAY,MAAc,aAAa,EAAE,IAAI,EAAE,WAAW,GAAG,CAAC,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,EAAE;AAGnH,IAAM,OAAO,CAAC,IAAY,MAAc,OAAwB,OAAe,OAAO,OAAqB;AAAA,EACzG;AAAA,EACA;AAAA,EACA,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,EAAE;AAAA,EAChC;AAAA,EACA,IAAI;AACN;AAEA,IAAM,OAAO;AAGb,IAAMA,SAAQ;AAGd,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,WAAW;AACjB,IAAM,UAAU;AAChB,IAAM,UAAU;AAEhB,IAAM,YAAY,CAAC,MAAc,aAAa,OAAO,IAAI,OAAO,WAAW,GAAG,MAAM,CAAC,CAAC;AAE/E,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,SAAS,UAAU,UAAU,mBAAmB;AAAA,EAC7F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,IACvI,EAAE,MAAM,UAAU,QAAQ,EAAE,OAAO,CAAC,KAAK,KAAK,CAAC,GAAG,QAAQ,CAAC,GAAG,KAAK,IAAI,GAAG,OAAO,KAAK,EAAE;AAAA,EAC1F;AAAA,EACA,SAAS,CAAC,OAAO,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,EAAE;AAAA,EAC9C,QAAQ;AAAA,IACN,KAAK,oiBAAoiB,OAAO,SAAS,OAAO,6DAA6D,MAAM;AAAA,MACjoB,EAAE,QAAQ,UAAU;AAAA,MACpB,CAAC,GAAG,MAAM;AACR,cAAM,KAAM,IAAI,MAAO,YAAY,OAAO,KAAK,KAAK;AACpD,eAAO,gBAAgB,CAAC,SAAS,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,iBAAiB,IAAI,IAAI,eAAe,WAAW;AAAA,MAC3K;AAAA,IACF,EAAE,KAAK,EAAE,CAAC,yBAAyB,UAAU,CAAC,CAAC,8BAA8BA,MAAK,2JAA2J,IAAI;AAAA,IACjP,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,GAAG,UAAU,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,IAAI,GAAG,UAAU,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MAChH,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAChH,EAAE,IAAI,cAAc,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,eAAe,WAAW,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA;AAAA,MAE1H,KAAK,QAAQ,gBAAgB,GAAG,CAAC;AAAA,MACjC,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACzG,KAAK,QAAQ,KAAK,IAAI,GAAG;AAAA,MACzB,GAAG,MAAM,KAAK,EAAE,QAAQ,UAAU,GAAG,CAAC,GAAG,MAAsB;AAC7D,cAAM,KAAM,IAAI,MAAO,YAAY,OAAO,KAAK,KAAK;AACpD,cAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,UAAU,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC;AAChG,cAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU,WAAW,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,UAAU,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC;AAC5F,eAAO;AAAA,UACL,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC;AAAA,UACvB,EAAE,IAAI,IAAI,CAAC,IAAI,MAAM,GAAG,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,UAC7G,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,GAAG;AAAA,UAC3B,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,GAAG;AAAA,QAC7B;AAAA,MACF,CAAC,EAAE,KAAK;AAAA,MACR,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAErI,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,GAAG,UAAU,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAChH,EAAE,IAAI,cAAc,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,aAAa,aAAa,EAAE,GAAG,IAAI,IAAI;AAAA,MAC9G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC,aAAa,SAAS,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,IAC3H;AAAA,EACF;AACF;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,UAAU,UAAU,YAAY,mBAAmB;AAAA,EACxF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,OAAO,QAAQ,EAAE,IAAI,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,IACjD,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE;AAAA,EAChI;AAAA,EACA,SAAS,MAAiB;AACxB,UAAM,QAAQ,CAAC,MAAc,IAAY,SAAiC;AAAA,MACxE,EAAE,IAAI,SAAS,MAAM,OAAO,EAAE,WAAW,CAAC,aAAa,IAAI,OAAO,aAAa,EAAE,KAAK,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAEnH,EAAE,IAAI,QAAQ,MAAM,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAClF,EAAE,IAAI,QAAQ,MAAM,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,IACnG;AACA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,SAAS;AAAA,QACP,GAAG,MAAM,GAAG,IAAI,CAAC;AAAA,QACjB,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,WAAW,QAAQ,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,QACxF,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,QACjB,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,UAAU,SAAS,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1F;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAEO,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,YAAY,QAAQ,UAAU,QAAQ,mBAAmB;AAAA,EAC9F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IACtD,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACnK;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAM,GAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACpD;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,qaAAqa,MAAM,IAAI,IAAI,CAAC,CAAC,wYAAwY,IAAI;AAAA,IACt0B,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3G,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1H,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,cAAc,YAAY,EAAE,GAAG,IAAI,IAAI;AAAA;AAAA,MAEvG,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG;AAAA,MACtE,EAAE,IAAI,QAAQ,MAAM,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAEpE,EAAE,IAAI,QAAQ,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7D,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG;AAAA,MACtE,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,cAAc,YAAY,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MACnH,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI,MAAM,MAAM;AAAA,MACtH,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,IAC5H;AAAA,EACF;AACF;AASA,SAAS,QAAQ,GAAU,GAAU,OAAe,UAAU,OAAe;AAC3E,QAAM,IAAI,QAAQ;AAClB,QAAM,IAAI,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7C,QAAM,MAAe,CAAC;AACtB,QAAM,MAAM,CAAC,GAAU,SAAiB;AACtC,aAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,YAAM,IAAI,OAAQ,IAAI,KAAK,KAAM;AACjC,UAAI,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AAAA,IAC3D;AAAA,EACF;AACA,MAAI,QAAS,KAAI,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC;AAAA,MAC3K,KAAI,GAAG,IAAI,KAAK,KAAK,CAAC;AAC3B,MAAI,GAAG,IAAI,KAAK,KAAK,CAAC;AACtB,SAAO,IAAI,IAAI,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AACpE;AAEA,IAAM,aAAa,oBAAI,IAA8B;AAGrD,SAAS,UAAU,QAAkC;AACnD,MAAI,CAAC,WAAW,IAAI,MAAM,GAAG;AAC3B,UAAM,OAAO,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,GAAG;AAE9E,UAAM,QAAQ,SAAS,IAAI,QAAQ,KAAK;AACxC,UAAM,QAAQ;AAAA,MACZ,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,MAAM;AAAA,MACxC,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,MACzD,QAAQ,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,IAC3D,EAAE,KAAK,GAAG;AACV,eAAW,IAAI,QAAQ,WAAW,MAAM,OAAO,EAAE,QAAQ,GAAG,CAAC,CAAC;AAAA,EAChE;AACA,SAAO,WAAW,IAAI,MAAM;AAC9B;AAGA,IAAM,WAAW,CAAC,SAAiB,2BAA2B,IAAI;AAE3D,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,aAAa,SAAS,SAAS,cAAc,mBAAmB;AAAA,EAC7G,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,IAC1J,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,KAAK,KAAK,GAAG,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,EACxI;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,CAAC,MAAM,KAAK,IAAI,UAAU,KAAK,MAAM,OAAO,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC;AACpE,WAAO,EAAE,MAAM,MAAM;AAAA,EACvB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,6gBAA6gB,SAAS,CAAC,CAAC;AAAA,IAC7hB,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,YAAY,WAAW,GAAG,MAAM,CAAC,WAAW,eAAe,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7H,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MACnG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,YAAY,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAE5F,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,aAAa,UAAU,GAAG,MAAM,CAAC,iBAAiB,SAAS,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7H,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MACpG,EAAE,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,YAAY,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,IAC9F;AAAA,EACF;AACF;AAGA,IAAM,WAAW;AACjB,IAAM,SAAS,CAAC,MAAc,eAAe,CAAC;AAEvC,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,YAAY,QAAQ,UAAU,mBAAmB;AAAA,EACtF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IACpD,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,EAAE;AAAA,EAC5G;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,oXAAoX,OAAO,CAAC,CAAC,cAAc,QAAQ,oEAAoE,QAAQ;AAAA,IACpe,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3F,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1G,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACzG,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,SAAS;AAAA,MACvF,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,eAAe,UAAU,EAAE,GAAG,IAAI,IAAI;AAAA;AAAA,MAE/E,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1F,KAAK,SAAS,KAAK,IAAI,KAAK,CAAC;AAAA,MAC7B,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC1F,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACzG,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,YAAY,aAAa,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,IAC7F;AAAA,EACF;AACF;AAOA,IAAM,aAAa,CAAC,OAAe,SAAiC;AAAA,EAClE,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,kBAAkB,kBAAkB,EAAE,GAAG,OAAO,OAAO,IAAI,KAAK,MAAM,MAAM;AAAA,EAC1I,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,mBAAmB,gBAAgB,EAAE,GAAG,OAAO,QAAQ,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,EAC9I,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,kBAAkB,kBAAkB,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,EACxI,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,mBAAmB,gBAAgB,EAAE,GAAG,OAAO,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,EAC9I,KAAK,QAAQ,aAAa,mBAAmB,OAAO,GAAG;AACzD;AAGA,IAAM,aAAa,CAACC,KAAY,SAAiC;AAAA,EAC/D,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAOA,KAAI,IAAI,GAAG;AAAA,EACtE,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,MAAM,OAAOA,KAAI,IAAI,KAAK,MAAM,MAAM;AAAA,EACpE,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,EACzE,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,OAAO,KAAK,IAAI,EAAE;AACjE;AAGA,IAAM,eAAe,CAAC,GAAY,GAAYC,OAAc,QAAgB;AAC1E,QAAM,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,KAAK,IAAI,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC;AACnE,QAAM,OAAO,KAAK,IAAI,KAAKA,QAAO,KAAK,IAAI,GAAG,GAAG,CAAC;AAClD,SAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,OAAO,IAAI,GAAG,UAAU,GAAG,IAAI,CAAC,IAAK,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC,IAAK,IAAI,EAAE;AACjH;AAEA,IAAM,aAAa,CAAC,MAClB,uBAAuB,CAAC,oHAAoH,IAAI,8FAA8F,CAAC,gIAAgI,IAAI;AAGrX,IAAM,YAAY;AAClB,IAAM,WAAW,CAAC,MAAc,0BAA0B,GAAG,MAAM,CAAC,CAAC;AAE9D,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,aAAa,YAAY,UAAU,mBAAmB;AAAA,EACnG,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACpI,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,aAAa,UAAU,uBAAuB,QAAQ,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,EAC7G;AAAA,EACA,SAAS,CAAC,MAAM,aAAa,EAAE,OAAO,EAAE,UAAU,KAAK,EAAE;AAAA,EACzD,QAAQ;AAAA,IACN,KAAK,4fAA4f,SAAS,CAAC,CAAC,oPAAoP,SAAS,CAAC,CAAC,iKAAiK,WAAW,EAAE,CAAC;AAAA,IAC17B,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjH,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,aAAa,EAAE,GAAG,IAAI,IAAI;AAAA,MAC9E,GAAG,WAAW,KAAK,SAAS;AAAA,MAC5B,GAAG,WAAW,GAAG,SAAS;AAAA,MAC1B,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,SAAS,GAAG,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,YAAY,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,MACxI,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,eAAe,YAAY,EAAE,GAAG,OAAO,WAAW,IAAI,IAAI;AAAA,IAClG;AAAA,EACF;AACF;AAGA,IAAM,YAAY;AAClB,IAAM,aAAa,CAAC,MAAc,SAAS,GAAG,CAAC,CAAC;AAEzC,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,UAAU,WAAW,UAAU,mBAAmB;AAAA,EAC/F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,OAAO,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IAChF,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,cAAc,UAAU,aAAa,QAAQ,CAAC,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAC/H;AAAA,EACA,SAAS,CAAC,MAAM,aAAa,EAAE,OAAO,EAAE,UAAU,KAAK,EAAE;AAAA,EACzD,QAAQ;AAAA,IACN,KAAK,uvBAAuvB,WAAW,EAAE,CAAC,2EAA2E,WAAW,IAAI,CAAC;AAAA,IACr2B,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,WAAW,IAAI,GAAG,WAAW,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC7G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,UAAU,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7E,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,WAAW,IAAI,GAAG,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC3H,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MAC5E,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,aAAa,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MAC1F,GAAG,WAAW,KAAK,SAAS;AAAA,MAC5B,GAAG,WAAW,KAAK,SAAS;AAAA;AAAA,MAE5B,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,WAAW,IAAI,EAAE;AAAA,MAC7E,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,WAAW,CAAC,GAAG,WAAW,IAAI,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,YAAY,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACnJ,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,eAAe,YAAY,EAAE,GAAG,OAAO,WAAW,IAAI,IAAI;AAAA,IAClG;AAAA,EACF;AACF;AAGA,IAAM,CAAC,OAAO,IAAI,IAAI;AAAA,EACpB;AAAA,GACC,MAAM;AACL,UAAMC,UAAS,CAAC,MACd,IAAI,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,MAAM;AACvC,YAAM,IAAK,IAAI,KAAM,KAAK,KAAK,IAAI,KAAK,KAAK;AAC7C,aAAO,GAAG,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AAAA,IAChE,CAAC,EAAE,KAAK,IAAI,CAAC;AACf,WAAO,GAAGA,QAAO,GAAG,CAAC,IAAIA,QAAO,CAAC,CAAC;AAAA,EACpC,GAAG;AAAA,EACH,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,SAAS,GAAG,MAAM,GAAG;AAC3B,IAAM,gBAAgB;AACtB,IAAM,SAAS,CAAC,MAAc,gBAAgB,CAAC;AAExC,IAAM,iBAA+B;AAAA,EAC1C,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,YAAY,YAAY,SAAS,UAAU,mBAAmB;AAAA,EACnG,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,GAAG,UAAU,CAAC,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IACvL,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,UAAU,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACjH;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,8dAA8d,OAAO,EAAE,CAAC,yBAAyB,KAAK,iFAAiF,MAAM;AAAA,IAClmB,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC5F,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC3G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAEzH,EAAE,IAAI,OAAO,MAAM,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACtE,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,cAAc,aAAa,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MAC3F,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,GAAG;AAAA,MACxE,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,MAAM,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAEtE,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,eAAe,IAAI,IAAI;AAAA,MAClF,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,eAAe,IAAI,IAAI;AAAA,MAChF,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,gBAAgB,KAAK,IAAI,EAAE;AAAA,MACxE,EAAE,IAAI,OAAO,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,gBAAgB,KAAK,IAAI,EAAE;AAAA,MACtE,KAAK,OAAO,WAAW,GAAG,gBAAgB,GAAG;AAAA,MAC7C,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,SAAS,EAAE,GAAG,OAAO,gBAAgB,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACzI,EAAE,IAAI,OAAO,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,eAAe,YAAY,EAAE,GAAG,OAAO,eAAe,IAAI,IAAI;AAAA,IACtG;AAAA,EACF;AACF;AAEO,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,QAAQ,aAAa,cAAc,mBAAmB;AAAA,EAC3F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,MAAM,CAAC,EAAE,EAAE;AAAA,IAC1G,EAAE,MAAM,aAAa,QAAQ,EAAE,MAAM,oBAAoB,KAAK,CAAC,KAAK,KAAK,GAAG,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAC5G;AAAA;AAAA,EAEA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,MAAM,KAAK,EAAE;AAC5C,UAAM,QAAQ,SAAS,OAAO;AAC9B,UAAM,OAAO,MAAM,QAAQ;AAC3B,UAAM,OAAO,KAAK,OAAO;AACzB,UAAM,KAAK,OAAO,SAAS,OAAO;AAClC,UAAM,KAAK,OAAO,OAAO;AACzB,UAAM,IAAI,OAAO;AACjB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,MAAM,GAAG,IAAI;AAAA,MACb,MAAM,GAAG,IAAI;AAAA,MACb,OAAO,GAAG,OAAO,OAAO,GAAG;AAAA,MAC3B,OAAO,GAAG,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC;AAAA,MAClC,SAAS,aAAa,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,WAAW,GAAG,CAAC,CAAC;AAAA,MACtD,SAAS,aAAa,GAAG,KAAK,OAAO,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,WAAW,GAAG,CAAC,CAAC;AAAA,IACtE;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,saAAsa,IAAI;AAAA,IAC/a,SAAS;AAAA,MACP,EAAE,IAAI,QAAQ,OAAO,EAAE,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,IAAI,IAAI;AAAA,MACjE,EAAE,IAAI,SAAS,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACxE,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,eAAe,aAAa,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC1F,EAAE,IAAI,aAAa,OAAO,EAAE,QAAQ,CAAC,WAAW,WAAW,EAAE,GAAG,IAAI,IAAI;AAAA,IAC1E;AAAA,EACF;AACF;AAEO,IAAM,kBAAgC;AAAA,EAC3C,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,UAAU,QAAQ,OAAO,mBAAmB;AAAA,EACjF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IAChH,EAAE,MAAM,SAAS,QAAQ,EAAE,OAAO,eAAe,QAAQ,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EAC/E;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAM,GAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACpD;AAAA,EACA,SAAS,MAAiB;AAExB,UAAM,QAAQ,CAAC,MAAc,WAAW,CAAC,KAAK,IAAI,EAAE;AACpD,UAAM,QAAQ,CAAC,MAAc,OAAO,OAClC,wHAAwH,IAAI,uEAAuE,IAAI,IAAI,IAAI;AACjN,WAAO;AAAA,MACL,KAAK,qSAAqS,MAAM,EAAE,CAAC,0WAA0W,MAAM,YAAY,CAAC,GAAG,MAAM,eAAe,0BAA0B,CAAC;AAAA,MACnuB,SAAS;AAAA,QACP,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,QAC9E,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAAC,kBAAkB,iBAAiB,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjG;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAGA,IAAM,UAAU,CAAC,GAAW,OAAe,iBAAiB,MAAM,EAAE,WAAW,GAAG,CAAC,CAAC;AAE7E,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,WAAW,QAAQ,WAAW,mBAAmB;AAAA,EACtF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,KAAK,MAAM,GAAG,EAAE,EAAE;AAAA,IAClI,EAAE,MAAM,WAAW,QAAQ,EAAE,KAAK,wBAAwB,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,EACtI;AAAA;AAAA,EAEA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,KAAK,KAAK,EAAE;AAC3C,UAAM,IAAI,SAAS;AACnB,WAAO,EAAE,MAAM,QAAQ,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,MAAM,GAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACpF;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,ybAAyb,QAAQ,KAAK,CAAC,CAAC,4QAA4Q,IAAI,0GAA0G,MAAM,KAAK,KAAK,CAAC,CAAC,2HAA2H,IAAI;AAAA,IACx9B,SAAS;AAAA,MACP,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAAC,QAAQ,KAAK,CAAC,GAAG,QAAQ,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC9F,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAAC,QAAQ,MAAM,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC3G,EAAE,IAAI,OAAO,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,IAAI;AAAA,MACjD,EAAE,IAAI,SAAS,OAAO,EAAE,MAAM,CAAC,aAAa,YAAY,EAAE,GAAG,IAAI,IAAI;AAAA,MACrE,EAAE,IAAI,UAAU,OAAO,EAAE,WAAW,CAAC,MAAM,KAAK,KAAK,CAAC,GAAG,MAAM,KAAK,KAAK,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,IAC1G;AAAA,EACF;AACF;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,eAAe,MAAM,SAAS,UAAU,MAAM,WAAW,mBAAmB;AAAA,EACnF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,cAAc,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,IAC1F,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,WAAW,EAAE;AAAA,EACjG;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAM,GAAG,KAAK,OAAO,IAAI,GAAG,MAAM,OAAO,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,OAAO,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE;AAAA,EACrI;AAAA;AAAA,EAEA,QAAQ;AAAA,IACN,KAAK,wuBAAwuB,IAAI;AAAA,IACjvB,SAAS;AAAA,MACP,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,kBAAkB,mBAAmB,EAAE,GAAG,IAAI,IAAI,MAAM,MAAM;AAAA,MAClG,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,qBAAqB,gBAAgB,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,MAAM,MAAM;AAAA,MAC7G,EAAE,IAAI,UAAU,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,MAAM,MAAM;AAAA,MAC3G,EAAE,IAAI,YAAY,OAAO,EAAE,MAAM,CAAC,YAAY,aAAa,EAAE,GAAG,OAAO,IAAI,IAAI,GAAG;AAAA,IACpF;AAAA,EACF;AACF;AAGO,IAAM,qBAAqC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AC1lBA,IAAMC,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAG/C,IAAMC,SAAQ,CAAC,IAAY,IAAY,MAAc,aAAa,EAAE,IAAI,EAAE,WAAW,KAAK,MAAM,IAAI,GAAI,IAAI,GAAI,eAAe,CAAC,EAAE,IAAI,CAAC,EAAE;AAGzI,IAAMC,QAAO,CAAC,IAAY,MAAc,OAAwB,OAAe,UAAiC;AAAA,EAC9G;AAAA,EACA,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,KAAK;AAAA,EACrC,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,EAAE;AAAA,EAChC;AAAA,EACA,IAAI;AACN;AAEA,IAAMC,QAAO;AAGb,IAAM,OAAO;AAEN,IAAM,UAAwB;AAAA,EACnC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,QAAQ,aAAa,QAAQ,MAAM,QAAQ;AAAA,EAC9D,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,iBAAiB,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,IACvF,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACvG;AAAA,EACA,SAAS,MAAM;AAEb,UAAM,SAAS,CAAC,KAAK,IAAI,KAAK,GAAG,EAAE,IAAI,CAAC,KAAK,MAAM;AACjD,YAAM,IAAK,MAAM,KAAK,KAAM;AAC5B,YAAMC,MAAK,CAAC,MAAc,CAACJ,IAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,GAAGA,IAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AAC7E,aAAO,EAAE,IAAI,IAAI,CAAC,IAAI,MAAMI,IAAG,EAAE,GAAG,KAAKA,IAAG,EAAE,GAAG,IAAIA,IAAG,EAAE,EAAE;AAAA,IAC9D,CAAC;AACD,WAAO;AAAA,MACL,KAAK,keAAke,IAAI,yDAAyD,OACjiB,IAAI,CAAC,EAAE,IAAI,KAAK,MAAM,aAAa,EAAE,SAAS,KAAK,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,2EAA2E,EAChL,KAAK,EAAE,CAAC,0BAA0BH,OAAM,IAAI,IAAI,CAAC,CAAC,wBAAwB,IAAI,6DAA6D,IAAI;AAAA,MAClJ,SAAS;AAAA,QACP,EAAE,IAAI,WAAW,MAAM,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,QACrD,EAAE,IAAI,QAAQ,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA;AAAA,QAErE,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAACA,OAAM,IAAI,IAAI,CAAC,GAAGA,OAAM,IAAI,IAAI,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,QAC7G,EAAE,IAAI,OAAO,OAAO,EAAE,WAAW,CAACA,OAAM,IAAI,IAAI,IAAI,GAAGA,OAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,QAChH,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG;AAAA,QAC7D,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,QAC9EC,MAAK,SAAS,WAAW,GAAG,CAAC;AAAA,QAC7B,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,QACnH,GAAG,OAAO,QAAQ,CAAC,EAAE,IAAI,MAAM,KAAK,GAAG,GAAG,MAAsB;AAAA,UAC9D,EAAE,IAAI,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI,IAAI,GAAG;AAAA,UAC9D,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,UACzG,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,QACpK,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAGA,IAAM,YAAY;AAClB,IAAM,YAAY;AAEX,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,eAAe,MAAM,SAAS,SAAS,UAAU,UAAU,MAAM;AAAA,EACpF,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,IAAI,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,IACnD,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,EAC/H;AAAA,EACA,SAAS,MAAM;AACb,UAAM,SAAS,CAAC,IAAYG,YAC1B,aAAa,EAAE,WAAW,SAAS,yBAAyBA,OAAM,wDAAwD,EAAE,WAAW,SAAS,yBAAyBA,OAAM;AACjL,UAAM,QAAQ,CAAC,MAAc,UAAkC;AAAA,MAC7D,EAAE,IAAI,SAAS,MAAM,OAAO,EAAE,WAAW,CAACJ,OAAM,IAAI,IAAI,CAAC,GAAGA,OAAM,IAAI,IAAI,KAAK,CAAC,EAAE,GAAG,IAAI,IAAI,MAAM,MAAM;AAAA,MACzG,EAAE,IAAI,SAAS,MAAM,OAAO,EAAE,WAAW,CAACA,OAAM,IAAI,IAAI,KAAK,GAAGA,OAAM,IAAI,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,SAAS;AAAA,IAC1H;AACA,UAAM,UAAU,CAAC,MAAc,MAAc,IAAY,UACvD,CAAC,UAAU,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,IAAI,IAAI,EAAE;AAChG,WAAO;AAAA,MACL,KAAK,yoBAAyoBA,OAAM,IAAI,IAAI,CAAC,CAAC,uJAAuJ,OAAO,QAAQ,QAAQ,CAAC,OAAO,OAAO,OAAO,SAAS,CAAC;AAAA,MAC52B,SAAS;AAAA;AAAA,QAEP,GAAG,MAAM,GAAG,IAAI;AAAA,QAChB,GAAG,QAAQ,GAAG,WAAW,UAAU,EAAE;AAAA,QACrC,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,WAAW,QAAQ,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACpF,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACzE,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,QACtFC,MAAK,SAAS,WAAW,GAAG,GAAG,CAAC;AAAA,QAChC,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,QACnGA,MAAK,SAAS,KAAK,IAAI,KAAK,CAAC;AAAA;AAAA,QAE7B,GAAG,MAAM,GAAG,IAAI;AAAA,QAChB,GAAG,QAAQ,GAAG,UAAU,WAAW,EAAE;AAAA,QACrC,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,UAAU,SAAS,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACpF,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;AAAA,QACzE,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,MACxF;AAAA,IACF;AAAA,EACF,GAAG;AACL;AAGA,IAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,OAAO,EAAE,IAAI,OAAO,CAAC,IAAI,GAAGF,IAAG,KAAK,IAAI,IAAI,EAAE,EAAE;AAE5F,IAAM,WAAW,CAAC,MAAc,0BAA0B,KAAK,MAAM,OAAO,IAAI,GAAI,IAAI,GAAI;AAErF,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,WAAW,YAAY,UAAU,YAAY,MAAM,MAAM;AAAA,EAC5E,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACtG,EAAE,MAAM,aAAa,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EAC9D;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,4gBAA4gB,MAAM;AAAA,MACrhB,CAAC,EAAE,IAAI,EAAE,MAAM,aAAa,EAAE,QAAQ,CAAC;AAAA,IACzC,EAAE,KAAK,EAAE,CAAC,sBAAsB,IAAI,gBAAgB,SAAS,CAAC,CAAC,wQAAwQG,KAAI;AAAA,IAC3U,SAAS;AAAA,MACP,EAAE,IAAI,OAAO,OAAO,CAAC,GAAG,GAAG,GAAG,QAAQ,QAAQ,IAAI,KAAM,MAAM,SAAS;AAAA;AAAA,MAEvE,GAAG,MAAM,IAAI,CAAC,EAAE,GAAG,GAAG,OAAqB,EAAE,IAAI,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,QAAQ,IAAI,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE;AAAA;AAAA,MAElH,GAAG,CAAC,GAAG,KAAK,KAAM,IAAI,EAAE,QAAQ,CAAC,MAAsB;AAAA,QACrD,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,GAAG,OAAO,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,QACjG,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,GAAG,OAAO,IAAI,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5G,CAAC;AAAA;AAAA,MAED,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,MAAM,IAAI,GAAG;AAAA,MACjE,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,MAC/E,EAAE,IAAI,QAAQ,OAAO,EAAE,QAAQ,CAAC,aAAa,YAAY,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MACnF,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,CAAC,aAAa,YAAY,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MAChF,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,CAAC,WAAW,YAAY,EAAE,GAAG,OAAO,MAAM,IAAI,IAAI;AAAA,MAC9E,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,MACpG,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,SAAS,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,IACzG;AAAA,EACF;AACF;AAGO,IAAM,kBAAkC,CAAC,SAAS,aAAa,aAAa;;;ACvJnF,IAAM,MAAM,KAAK,KAAK;AACtB,IAAMG,MAAK,CAAC,MAAc;AACxB,QAAM,IAAI,KAAK,MAAM,IAAI,GAAG,IAAI;AAChC,SAAO,OAAO,GAAG,GAAG,EAAE,IAAI,IAAI;AAChC;AAEA,IAAM,WAAW,CAAC,QAA0B,IAAI,IAAI,IAAI,CAAC,MAAM,GAAGA,IAAG,EAAE,CAAC,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAGpG,SAAS,IAAI,IAAY,IAAY,IAAY,IAAY,MAAc,IAAY,SAAgC,MAAM,GAAG,QAAQ,GAAY;AAClJ,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC;AAChE,SAAO,MAAM,KAAK,EAAE,QAAQ,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM;AACjD,UAAM,MAAM,QAAS,KAAK,QAAQ,IAAK;AACvC,UAAM,IAAI,OAAO,GAAG;AACpB,WAAO,CAAC,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,GAAG,GAAG,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,GAAG,CAAC;AAAA,EAC9E,CAAC;AACH;AAGA,SAAS,QAAQ,SAA2B,GAAoB;AAC9D,SAAO,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAC/B,UAAM,IAAI,SAAS,IAAI,QAAQ,SAAS,KAAK,QAAQ,MAAM;AAC3D,UAAM,IAAI,SAAS,IAAI,KAAK,QAAQ,MAAM;AAC1C,UAAM,UAAU,CAAC,MAAoB;AACnC,YAAM,IAAI,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7C,aAAO,CAAC,EAAE,CAAC,KAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAK,GAAG,EAAE,CAAC,KAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAK,CAAC;AAAA,IACxE;AACA,UAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;AAEtC,WAAO,CAAC,GAAG,MAAM,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,MAAa;AAAA,OAC9C,IAAI,MAAM,IAAI,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,OACzD,IAAI,MAAM,IAAI,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IAC5D,CAAC;AAAA,EACH,CAAC;AACH;AAKA,IAAM,OAAgB,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;AACxF,IAAM,QAAQ,CAAC,MAAc,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,MAAM,CAAC;AAEjG,IAAM,cAAc;AAAA,EAClB;AAAA,IACE,SAAS,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA,IAEzB,SAAS,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;AAAA;AAAA,IAE9G,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EAC5D;AAAA,EACA,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,UAAU;AAAA,EACd;AAAA,IACE,SAAS,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;AAAA,IACjE,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IAClD,SAAS,IAAI,IAAI,KAAK,IAAI,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EACrD;AAAA,EACA,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,WAAW;AAAA,EACf;AAAA,IACE,SAAS,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;AAAA,IACxD,SAAS,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;AAAA,IACxF,SAAS,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC;AAAA,EACzF;AAAA,EACA,EAAE,QAAQ,GAAG;AACf;AAEA,IAAM,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK;AACpC,IAAM,SAAS,EAAE,OAAO,MAAM,IAAI,KAAK;AACvC,IAAM,SAAS,EAAE,OAAO,MAAM,IAAI,KAAK;AAGvC,IAAM,SAAS,CAAC,IAAY,CAAC,MAAM,OAAO,MAAM,MAAgC;AAAA,EAC9E,EAAE,IAAI,OAAO,EAAE,GAAG,CAAC,MAAO,KAAM,EAAE,GAAG,GAAG,MAAM,MAAM,SAAS;AAAA,EAC7D,EAAE,IAAI,OAAO,EAAE,GAAG,CAAC,OAAQ,MAAO,EAAE,GAAG,GAAG,QAAQ,MAAM,MAAM;AAAA,EAC9D,EAAE,IAAI,OAAO,EAAE,GAAG,CAAC,QAAS,IAAK,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAClE;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,OAAO,SAAS,UAAU,SAAS,MAAM;AAAA,EACxD,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACvI,EAAE,MAAM,YAAY,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,MAAM,IAAI,EAAE,EAAE;AAAA,EACxI;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,2bAA2b,YAAY,CAAC,CAAC,yHAAyH,SAAS,CAAC,CAAC,0EAA0E,QAAQ,CAAC,CAAC;AAAA,IACtqB,SAAS;AAAA,MACP,GAAG,OAAO,QAAQ,WAAW;AAAA,MAC7B,GAAG,OAAO,OAAO,OAAO;AAAA,MACxB,GAAG,OAAO,QAAQ,QAAQ;AAAA,MAC1B,EAAE,IAAI,QAAQ,OAAO,EAAE,MAAM,CAAC,WAAW,WAAW,EAAE,GAAG,OAAO,MAAM,IAAI,MAAM,MAAM,SAAS;AAAA,MAC/F,EAAE,IAAI,QAAQ,OAAO,EAAE,MAAM,CAAC,aAAa,SAAS,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACnF,EAAE,IAAI,OAAO,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACxE,EAAE,IAAI,OAAO,OAAO,EAAE,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACxE,EAAE,IAAI,UAAU,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACnF,EAAE,IAAI,UAAU,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MACpF,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5F,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7F,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,MAAM,GAAG,EAAE,GAAG,OAAO,KAAK,IAAI,KAAM,MAAM,SAAS;AAAA,MAC/G,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,QAAQ,MAAM,SAAS;AAAA,MACpG,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,IAAI,KAAM,MAAM,SAAS;AAAA,MAC5F,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5E,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5F,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAE5E,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,GAAG,OAAO;AAAA,MACpD,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,GAAG,OAAO;AAAA,IACtD;AAAA,EACF;AACF;AAIA,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,QAAQ;AACd,IAAM,UAAU;AAGhB,IAAM,QAAQ,CAAC,OAAe,OAAQ,QAAQ,OAAO,KAAK,IAAI,IAAI,IAAI,IAAK;AAG3E,IAAM,OAAO,CAAC,GAAW,MAAc;AACrC,QAAM,IAAI,KAAK,IAAI,IAAI,QAAQ,IAAI,KAAK,IAAI;AAC5C,SAAO,IAAI,KAAK,MAAM,CAAC;AACzB;AAGA,IAAM,QAAQ,CAAC,GAAW,OAAe;AACvC,QAAM,KAAK,IAAI,IAAI,IAAI,MAAM,OAAO,KAAK,GAAG,CAAC;AAC7C,QAAM,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,GAAG,CAAC;AAC9C,QAAM,OAAO,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC,IAAI,OAAO;AAC9C,SAAO,iBAAiBA,IAAG,MAAM,EAAE,IAAI,EAAE,CAAC,WAAWA,IAAG,IAAI,CAAC,WAAWA,IAAG,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC;AAC1F;AAEA,IAAM,WAAW,OAAO;AAExB,IAAM,QAAQ;AAAA,EACZ,EAAE,GAAG,IAAI,OAAO,KAAK,IAAI,MAAM,QAAQ,GAAG;AAAA,EAC1C,EAAE,GAAG,KAAK,OAAO,MAAM,IAAI,KAAM,QAAQ,GAAG;AAAA,EAC5C,EAAE,GAAG,IAAI,OAAO,KAAM,IAAI,MAAM,QAAQ,GAAG;AAC7C;AAEA,IAAM,SAAS,EAAE,OAAO,GAAG,IAAI,MAAM,MAAM,SAAkB;AAC7D,IAAM,UAAU,EAAE,OAAO,MAAM,IAAI,KAAK,MAAM,SAAkB;AAEzD,IAAM,SAAuB;AAAA,EAClC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,UAAU,SAAS,OAAO,QAAQ,MAAM;AAAA,EACvD,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACpF,EAAE,MAAM,gBAAgB,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EAClH;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,wwBAAwwB,MAAM,EAAE,qIAAqI,GAAG,wBAAwB,MAAM,GAAG,gDAAgD,GAAG,wBAAwB,MAAM,GAAG,4BAA4B,MAAM;AAAA,MACljC,CAAC,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE,CAAC,QAAQ,GAAG;AAAA,IACpD,EAAE,KAAK,EAAE,CAAC,kCAAkC,GAAG,uGAAuG,GAAG,iFAAiF,GAAG,kBAAkB,MAAM,EAAE,0FAA0F,MAAM,IAAI,CAAC,CAAC;AAAA,IAC7W,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,MAAM,KAAK,MAAM,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,MACtF,EAAE,IAAI,QAAQ,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,QAAQ,CAAC,MAAM,OAAO,MAAM,GAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MACvF,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,MAAM,KAAK,MAAM,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,MACvF,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,QAAQ,CAAC,MAAM,OAAO,MAAM,GAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MACxF,GAAI,CAAC,OAAO,MAAM,EAAY,QAAQ,CAAC,OAAuB;AAAA,QAC5D,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,QAC7C,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MAChD,CAAC;AAAA,MACD,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,EAAE,GAAG,GAAG,OAAO;AAAA,MACjF,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,GAAG,GAAG,QAAQ;AAAA,MAClF,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,EAAE,GAAG,GAAG,OAAO;AAAA,MAC/D,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,GAAG,GAAG,QAAQ;AAAA;AAAA,MAEhE,GAAG,MAAM,QAAQ,CAAC,GAAG,MAAsB;AAAA,QACzC,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,QACxD,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,OAAO,IAAI,EAAE,IAAI,MAAM,MAAM;AAAA,QAC1F,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,QAAQ;AAAA,MAClF,CAAC;AAAA;AAAA,MAED,GAAG,MAAM,KAAK,EAAE,QAAQ,SAAS,GAAG,CAAC,GAAG,OAAqB;AAAA,QAC3D,IAAI;AAAA,QACJ,OAAO,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,IAAI,OAAO,GAAG,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC,EAAE;AAAA,QAC7E,OAAO,IAAI;AAAA,QACX,IAAI;AAAA,QACJ,MAAM;AAAA,MACR,EAAE;AAAA,MACF,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MACtI,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACnF,GAAG,MAAM,KAAK,EAAE,QAAQ,OAAO,IAAI,GAAG,CAAC,GAAG,OAAqB;AAAA,QAC7D,IAAI;AAAA,QACJ,OAAO,EAAE,SAAS,CAAC,IAAIA,IAAG,MAAM,MAAM,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,KAAKA,IAAG,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE;AAAA,QACzF,OAAO,IAAI;AAAA,QACX,IAAI;AAAA,QACJ,MAAM;AAAA,MACR,EAAE;AAAA,MACF,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAACA,IAAG,MAAM,MAAM,KAAK,OAAO,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MACrH,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,IACtF;AAAA,EACF;AACF;AAGO,IAAM,cAA8B,CAAC,aAAa,MAAM;;;AC9MxD,IAAM,aAA0D;AAAA,EACrE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,GAAG,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACjE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,KAAK,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO;AAAA,EACnE,GAAG,CAAC,SAAS,SAAS,SA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","names":["HEART","at","room","circle","r1","about","snap","SANS","at","stroke","r2","n","r2","n","snap","pose","at","HEART","heartPose","_","n","at","stroke","r1","n","DEG","r2","n","polyline","arc","r1","HEART","pair","at","stages","DOTS","_","GLOW","OVER","GLOW","OVER","GLOW","OVER","r1","n","fit","mixHex","SANS","SLOTS","at","rand","link","DRIPS","r1","n","at"]}