@pixerate/flair 0.21.0 → 0.22.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.
@@ -0,0 +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/splatter.ts","../src/catalog/bubble.ts","../src/catalog/sticker.ts","../src/catalog/trail.ts","../src/catalog/impact.ts","../src/catalog/comic.ts","../src/catalog/glow.ts","../src/catalog/shadow.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/splatter.ts","../src/catalog/shaders/bubble.ts","../src/catalog/shaders/growth.ts","../src/catalog/shaders/sticker.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/shaders/trail.ts","../src/catalog/shaders/particles.ts","../src/catalog/shaders/debris.ts","../src/catalog/shaders/impact.ts","../src/catalog/shaders/comic.ts","../src/catalog/shaders/atmosphere.ts","../src/catalog/shaders/glow.ts","../src/catalog/shaders/shadow.ts","../src/catalog/shaders/distortion.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 video: \"filter\",\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 video: \"filter\",\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, from its shadows to its highlights. For a passing glare, lay `shine-sweep` over it.\",\n category: \"image\",\n video: \"filter\",\n tags: [\"image\", \"brand\", \"editorial\", \"colour\"],\n source: glsl(\n `// Duotone: an image mapped onto two colours by its brightness.\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\"\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 fragColor = vec4(mix(uShadow, uHighlight, l), 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 video: \"filter\",\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 video: \"filter\",\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 video: \"filter\",\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 video: \"filter\",\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 video: \"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 { ControlValue } from \"../shader/controls.js\";\nimport { morphSequence } from \"../vector/morph.js\";\nimport type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Splats as vector effects. Shapes are worked out from a seed, so a `shape`\n * control picks among irregular splats, and `morphSequence` gives the dot,\n * the overshoot and the settled splat one structure so their `d`s blend.\n */\n\ntype Point = [number, number];\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. */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/** A small seeded random generator (mulberry32), 0–1. */\nfunction random(seed: number): () => number {\n let a = (seed * 2654435761) >>> 0;\n return () => {\n a = (a + 0x6d2b79f5) >>> 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\nconst polyline = (pts: readonly Point[]) => `M${pts.map((p) => `${r2(p[0])} ${r2(p[1])}`).join(\" L\")} Z`;\n\nconst CX = 100;\nconst CY = 100;\nconst DROPS = 8;\nconst POINTS = 144;\n\ninterface Splat {\n dot: string;\n over: string;\n settled: string;\n drops: { x: number; y: number; r: number }[];\n}\n\n/**\n * A splat of radius `size` from a seed: a lumpy body with spikes of varied\n * length, as a polygon round the centre (at `scale`), and droplets round it.\n */\nfunction makeSplat(seed: number, size: number): Splat {\n const rnd = random(seed + 1);\n const lumps = Array.from({ length: 4 }, () => ({ k: 2 + Math.floor(rnd() * 4), a: rnd() * 0.12, p: rnd() * Math.PI * 2 }));\n const spikes = Array.from({ length: 9 + Math.floor(rnd() * 4) }, () => ({ at: rnd() * Math.PI * 2, len: 0.15 + rnd() * 0.45, w: 0.06 + rnd() * 0.08 }));\n const radius = (a: number) => {\n let r = 1;\n for (const l of lumps) r += l.a * Math.sin(l.k * a + l.p);\n for (const s of spikes) {\n const d = Math.atan2(Math.sin(a - s.at), Math.cos(a - s.at));\n r += s.len * Math.exp(-(d * d) / (s.w * s.w));\n }\n return r;\n };\n const shape = (scale: number) =>\n polyline(\n Array.from({ length: POINTS }, (_, k): Point => {\n const a = (k / POINTS) * Math.PI * 2;\n const r = radius(a) * size * scale;\n return [CX + r * Math.cos(a), CY + r * Math.sin(a)];\n }),\n );\n const dotR = size * 0.42;\n const dot = polyline(Array.from({ length: POINTS }, (_, k): Point => [CX + dotR * Math.cos((k / POINTS) * Math.PI * 2), CY + dotR * Math.sin((k / POINTS) * Math.PI * 2)]));\n const drops = Array.from({ length: DROPS }, (_, k) => {\n const a = ((k + 0.2 + rnd() * 0.6) / DROPS) * Math.PI * 2;\n const d = size * (1.55 + rnd() * 0.75);\n return { x: r2(CX + d * Math.cos(a)), y: r2(CY + d * Math.sin(a)), r: r2(size * (0.06 + rnd() * 0.1)) };\n });\n const [d, o, s] = morphSequence([dot, shape(1.14), shape(1)], { points: POINTS });\n return { dot: d!, over: o!, settled: s!, drops };\n}\n\nconst splats = new Map<string, Splat>();\n\n/** A splat for these control values, worked out once. */\nfunction splatFor(values: Record<string, ControlValue>): Splat {\n const seed = Math.max(0, Math.round(Number(values.shape)) || 0);\n const size = Math.min(60, Math.max(15, Number(values.size) || 36));\n const key = `${seed}/${size}`;\n if (!splats.has(key)) splats.set(key, makeSplat(seed, size));\n return splats.get(key)!;\n}\n\n/** When each droplet pops out after the splat lands, in ms. */\nconst POP = 380;\nconst SETTLE = 1700;\n\nexport const splatStamp: VectorEffect = {\n kind: \"vector\",\n id: \"splat-stamp\",\n name: \"Splat stamp\",\n description: \"A dot that bursts into an irregular paint splat, droplets popping out round it before it settles and shrinks back.\",\n category: \"splatter\",\n tags: [\"splatter\", \"paint\", \"morph\", \"stamp\", \"playful\", \"micro-interaction\"],\n hold: 300,\n presets: [\n { name: \"Ink\", values: { ink: [0.07, 0.07, 0.09], background: [0.97, 0.96, 0.93], shine: false } },\n { name: \"Lime\", values: { ink: [0.52, 0.85, 0.16], background: [0.1, 0.1, 0.14], shape: 4 } },\n { name: \"Big pink\", values: { ink: [0.96, 0.3, 0.55], background: [1, 0.95, 0.96], size: 50, shape: 7 } },\n ],\n derived: (v) => {\n const s = splatFor(v);\n const out: Record<string, string | number> = { a: s.dot, b: s.over, c: s.settled, gloss: v.shine === false ? 0 : 0.35 };\n const size = Math.min(60, Math.max(15, Number(v.size) || 36));\n Object.assign(out, { gx: r2(CX - size * 0.36), grx: r2(size * 0.24), gry: r2(size * 0.13) });\n s.drops.forEach((d, i) => {\n out[`x${i}`] = d.x;\n out[`y${i}`] = d.y;\n out[`r${i}`] = d.r;\n out[`ro${i}`] = r2(d.r * 1.35);\n out[`xm${i}`] = r2(CX + (d.x - CX) * 0.55);\n out[`ym${i}`] = r2(CY + (d.y - CY) * 0.55);\n });\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{ink: color default=#E11D48 label='Paint'}} {{background: color default=#FFF7ED label='Background'}} {{shape: int min=0 max=9 default=0 label='Shape'}} {{size: float min=15 max=60 default=36 step=1 label='Size'}} {{shine: bool default=true label='Shine'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><path id=\"splat\" d=\"{{a}}\" fill=\"{{ink}}\" fill-rule=\"evenodd\"/><ellipse id=\"gloss\" cx=\"{{gx}}\" cy=\"{{gx}}\" rx=\"{{grx}}\" ry=\"{{gry}}\" transform=\"rotate(-35 {{gx}} {{gx}})\" fill=\"#FFFFFF\" opacity=\"0\"/>${Array.from(\n { length: DROPS },\n (_, i) => `<circle id=\"drop${i}\" cx=\"${CX}\" cy=\"${CY}\" r=\"0\" fill=\"{{ink}}\"/>`,\n ).join(\"\")}</svg>`,\n animate: [\n { id: \"splat\", attrs: { d: [\"{{a}}\", \"{{b}}\"] }, delay: 300, ms: 220, ease: \"out\" },\n { id: \"splat\", attrs: { d: [\"{{b}}\", \"{{c}}\"] }, delay: 520, ms: 380, ease: \"in-out\" },\n { id: \"gloss\", attrs: { opacity: [0, n(\"gloss\")] }, delay: 600, ms: 400, ease: \"out\" },\n ...Array.from({ length: DROPS }, (_, i): SvgAnimation[] => {\n const at = POP + i * 35;\n return [\n { id: `drop${i}`, attrs: { cx: [CX, n(`xm${i}`)], cy: [CY, n(`ym${i}`)], r: [0, n(`ro${i}`)] }, delay: at, ms: 150, ease: \"out\" },\n { id: `drop${i}`, attrs: { cx: [n(`xm${i}`), n(`x${i}`)], cy: [n(`ym${i}`), n(`y${i}`)], r: [n(`ro${i}`), n(`r${i}`)] }, delay: at + 150, ms: 260, ease: \"out\" },\n { id: `drop${i}`, attrs: { cx: [n(`x${i}`), CX], cy: [n(`y${i}`), CY], r: [n(`r${i}`), 0] }, delay: SETTLE + 2000, ms: 360, ease: \"in-out\" },\n ];\n }).flat(),\n { id: \"gloss\", attrs: { opacity: [n(\"gloss\"), 0] }, delay: SETTLE + 2000, ms: 300, ease: \"in-out\" },\n { id: \"splat\", attrs: { d: [\"{{c}}\", \"{{a}}\"] }, delay: SETTLE + 2050, ms: 420, ease: \"in-out\" },\n ],\n },\n};\n\n/** Splats as vector effects. */\nexport const splatterEffects: VectorEffect[] = [splatStamp];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\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 (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/** A transform scaling by `s` about (`cx`, `cy`). */\nconst about = (cx: number, cy: number, s: number) => `translate(${r1(cx)} ${r1(cy)}) scale(${r2(s)}) translate(${r1(-cx)} ${r1(-cy)})`;\n\n/** Instant change: the attribute snaps to `value` at `delay` (resets of hidden elements, so a loop starts clean). */\nconst snap = (id: string, attr: string, value: string | number, delay: number): SvgAnimation => ({ id, attrs: { [attr]: [value, value] }, delay, ms: 0 });\n\nconst SANS = `system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif`;\n\n/** Chat bubble: the sent bubble's right edge, top, and the reply's left edge (viewBox units). */\nconst RIGHT = 372;\nconst TOP = 34;\nconst REPLY_X = 28;\n/** Typing dots: bounces and the time between them. */\nconst BOUNCES = 4;\nconst BOUNCE_MS = 900;\nconst DOTS = 3;\n\nexport const chatBubble: VectorEffect = {\n kind: \"vector\",\n id: \"chat-bubble\",\n name: \"Chat bubble\",\n description: \"A chat message bubble popping in with an overshoot and its text typing in, then a reply bubble with bouncing typing dots.\",\n category: \"bubble\",\n tags: [\"bubble\", \"chat\", \"message\", \"ui\", \"typing\", \"speech\", \"text\"],\n hold: 700,\n presets: [\n { name: \"Green\", values: { bubble: [0.15, 0.75, 0.4], ink: [1, 1, 1] } },\n { name: \"Dark\", values: { background: [0.07, 0.08, 0.11], bubble: [0.45, 0.4, 1], reply: [0.17, 0.18, 0.23], dots: [0.65, 0.67, 0.75] } },\n { name: \"Short\", values: { text: \"On my way! 🚀\", pace: 70 } },\n ],\n derived: (v) => {\n const text = String(v.text);\n const e = Math.max(0.6, textWidthEm(text));\n const size = r1(Math.min(22, 290 / e));\n const width = r1(Math.max(58, e * size + 38));\n const height = r1(size + 30);\n const left = r1(RIGHT - width);\n const bottom = r1(TOP + height);\n const typing = Math.max(1, Math.round(Array.from(text).length * Number(v.pace)));\n const reply = 350 + typing + 450;\n const replyTop = r1(bottom + 22);\n const replyBottom = r1(replyTop + 44);\n const dotY = r1(replyTop + 22);\n const sent = (s: number) => about(RIGHT, bottom, s);\n const back = (s: number) => about(REPLY_X, replyBottom, s);\n return {\n size,\n left,\n width,\n height,\n bottom,\n textX: r1(left + 19),\n textY: r1(TOP + height / 2 + size * 0.35),\n rx: r1(Math.min(height / 2, 20)),\n tail: `M${r1(RIGHT - 20)} ${r1(bottom - 12)} C${r1(RIGHT - 16)} ${r1(bottom - 2)} ${r1(RIGHT - 8)} ${r1(bottom + 4)} ${r1(RIGHT + 6)} ${r1(bottom + 4)} C${r1(RIGHT - 2)} ${r1(bottom - 1)} ${r1(RIGHT - 3)} ${r1(bottom - 8)} ${r1(RIGHT - 3)} ${r1(bottom - 16)}Z`,\n replyTop,\n replyTail: `M${REPLY_X + 20} ${r1(replyBottom - 12)} C${REPLY_X + 16} ${r1(replyBottom - 2)} ${REPLY_X + 8} ${r1(replyBottom + 4)} ${REPLY_X - 6} ${r1(replyBottom + 4)} C${REPLY_X + 2} ${r1(replyBottom - 1)} ${REPLY_X + 3} ${r1(replyBottom - 8)} ${REPLY_X + 3} ${r1(replyBottom - 16)}Z`,\n dotY,\n dotUp: r1(dotY - 6),\n typing,\n sent0: sent(0),\n sent1: sent(1),\n sentOver: sent(1.12),\n sentUnder: sent(0.95),\n reply0: back(0),\n reply1: back(1),\n replyOver: back(1.12),\n replyUnder: back(0.95),\n ...Object.fromEntries([0, 220, 340].map((k) => [`replyAt${k}`, reply + k])),\n ...Object.fromEntries(\n Array.from({ length: BOUNCES * DOTS }, (_, i) => {\n const [k, j] = [Math.floor(i / DOTS), i % DOTS];\n const at = reply + 450 + k * BOUNCE_MS + j * 150;\n return [\n [`rise${k}_${j}`, at],\n [`fall${k}_${j}`, at + 180],\n ];\n }).flat(),\n ),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Hey! Are we still on for tonight?' label='Message'}} {{pace: float min=15 max=200 default=45 step=5 label='Ms per letter'}} {{background: color default=#FFFFFF label='Background'}} {{bubble: color default=#3B82F6 label='Bubble'}} {{ink: color default=#FFFFFF label='Text colour'}} {{reply: color default=#E5E7EB label='Reply bubble'}} {{dots: color default=#6B7280 label='Typing dots'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g id=\"sent\" transform=\"{{sent0}}\"><path d=\"{{tail}}\" fill=\"{{bubble}}\"/><rect x=\"{{left}}\" y=\"${TOP}\" width=\"{{width}}\" height=\"{{height}}\" rx=\"{{rx}}\" fill=\"{{bubble}}\"/><text id=\"msg\" x=\"{{textX}}\" y=\"{{textY}}\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"500\" fill=\"{{ink}}\" xml:space=\"preserve\">{{text}}</text></g><g id=\"reply\" transform=\"{{reply0}}\"><path d=\"{{replyTail}}\" fill=\"{{reply}}\"/><rect x=\"${REPLY_X}\" y=\"{{replyTop}}\" width=\"86\" height=\"44\" rx=\"22\" fill=\"{{reply}}\"/>${Array.from(\n { length: DOTS },\n (_, j) => `<circle id=\"dot${j}\" cx=\"${REPLY_X + 22 + j * 21}\" cy=\"{{dotY}}\" r=\"5\" fill=\"{{dots}}\" opacity=\"0.45\"/>`,\n ).join(\"\")}</g></svg>`,\n animate: [\n { id: \"sent\", attrs: { transform: [\"{{sent0}}\", \"{{sentOver}}\"] }, ms: 220, ease: \"out\" },\n { id: \"sent\", attrs: { transform: [\"{{sentOver}}\", \"{{sentUnder}}\"] }, delay: 220, ms: 120, ease: \"in-out\" },\n { id: \"sent\", attrs: { transform: [\"{{sentUnder}}\", \"{{sent1}}\"] }, delay: 340, ms: 140, ease: \"in-out\" },\n { id: \"msg\", write: \"{{text}}\", delay: 350, ms: n(\"typing\"), ease: \"linear\" },\n { id: \"reply\", attrs: { transform: [\"{{reply0}}\", \"{{replyOver}}\"] }, delay: n(\"replyAt0\"), ms: 220, ease: \"out\" },\n { id: \"reply\", attrs: { transform: [\"{{replyOver}}\", \"{{replyUnder}}\"] }, delay: n(\"replyAt220\"), ms: 120, ease: \"in-out\" },\n { id: \"reply\", attrs: { transform: [\"{{replyUnder}}\", \"{{reply1}}\"] }, delay: n(\"replyAt340\"), ms: 140, ease: \"in-out\" },\n // The typing dots bounce one after another, brightening as they rise.\n ...Array.from({ length: BOUNCES * DOTS }, (_, i): SvgAnimation[] => {\n const [k, j] = [Math.floor(i / DOTS), i % DOTS];\n const id = `dot${j}`;\n return [\n { id, attrs: { cy: [\"{{dotY}}\", \"{{dotUp}}\"], opacity: [0.45, 1] }, delay: n(`rise${k}_${j}`), ms: 180, ease: \"out\" },\n { id, attrs: { cy: [\"{{dotUp}}\", \"{{dotY}}\"], opacity: [1, 0.45] }, delay: n(`fall${k}_${j}`), ms: 260, ease: \"in-out\" },\n ];\n }).flat(),\n ],\n },\n};\n\n/** Bubble pop loader: the bubbles' centres, radius and droplets per bubble. */\nconst LOADER_X = [45, 95, 145, 195];\nconst LOADER_Y = 40;\nconst LOADER_R = 14;\nconst DROPS = 6;\nconst LOADER_STAGGER = 300;\nconst POP_AT = 800;\nconst LOADER_END = (LOADER_X.length - 1) * LOADER_STAGGER + POP_AT + 600;\n\nexport const bubblePopLoader: VectorEffect = {\n kind: \"vector\",\n id: \"bubble-pop-loader\",\n name: \"Bubble pop loader\",\n description: \"A loader of four bubbles inflating in turn and popping into droplets, over and over.\",\n category: \"bubble\",\n tags: [\"bubble\", \"loader\", \"loading\", \"spinner\", \"ui\", \"playful\"],\n hold: 120,\n presets: [\n { name: \"Mint\", values: { color: [0.2, 0.8, 0.65], accent: [0.55, 0.95, 0.85] } },\n { name: \"Dark\", values: { background: [0.07, 0.08, 0.11], color: [0.55, 0.6, 1], accent: [1, 0.55, 0.85] } },\n { name: \"Candy\", values: { color: [1, 0.4, 0.65], accent: [1, 0.8, 0.3], width: 3 } },\n ],\n motion: (() => {\n const drop = (i: number, k: number, r: number) => {\n const a = ((k + 0.5) / DROPS) * Math.PI * 2;\n return [r1(LOADER_X[i]! + r * Math.cos(a)), r1(LOADER_Y + r * Math.sin(a))] as const;\n };\n const pose = (i: number) => (s: number) => about(LOADER_X[i]!, LOADER_Y, s);\n const bubbles = LOADER_X.map(\n (x, i) =>\n `<circle id=\"ring${i}\" cx=\"${x}\" cy=\"${LOADER_Y}\" r=\"${LOADER_R}\" fill=\"none\" stroke=\"{{color}}\" stroke-width=\"0\"/>${Array.from({ length: DROPS }, (_, k) => {\n const [dx, dy] = drop(i, k, LOADER_R);\n return `<circle id=\"d${i}_${k}\" cx=\"${dx}\" cy=\"${dy}\" r=\"0\" fill=\"${k % 2 ? \"{{accent}}\" : \"{{color}}\"}\"/>`;\n }).join(\n \"\",\n )}<g id=\"b${i}\" transform=\"${pose(i)(0)}\"><circle cx=\"${x}\" cy=\"${LOADER_Y}\" r=\"${LOADER_R}\" fill=\"{{color}}\" fill-opacity=\"0.22\" stroke=\"{{color}}\" stroke-width=\"{{width}}\"/><ellipse cx=\"${x - 5}\" cy=\"${LOADER_Y - 5}\" rx=\"4\" ry=\"2.6\" fill=\"#FFFFFF\" opacity=\"0.85\" transform=\"rotate(-35 ${x - 5} ${LOADER_Y - 5})\"/></g>`,\n ).join(\"\");\n return {\n svg: `<svg viewBox=\"0 0 240 80\"><!-- {{color: color default=#6366F1 label='Bubbles'}} {{accent: color default=#38BDF8 label='Droplets'}} {{background: color default=#FFFFFF label='Background'}} {{width: float min=1 max=4 default=2 step=0.5 label='Outline'}} --><rect width=\"240\" height=\"80\" fill=\"{{background}}\"/>${bubbles}</svg>`,\n animate: LOADER_X.flatMap((_, i): SvgAnimation[] => {\n const t0 = i * LOADER_STAGGER;\n const pop = t0 + POP_AT;\n const p = pose(i);\n return [\n // Inflating with a wobble, then bursting.\n { id: `b${i}`, attrs: { transform: [p(0), p(1.1)] }, delay: t0, ms: 450, ease: \"out\" },\n { id: `b${i}`, attrs: { transform: [p(1.1), p(0.95)] }, delay: t0 + 450, ms: 150, ease: \"in-out\" },\n { id: `b${i}`, attrs: { transform: [p(0.95), p(1)] }, delay: t0 + 600, ms: 200, ease: \"in-out\" },\n { id: `b${i}`, attrs: { transform: [p(1), p(1.35)], opacity: [1, 0] }, delay: pop, ms: 90, ease: \"out\" },\n snap(`ring${i}`, \"stroke-width\", 0, 0),\n { id: `ring${i}`, attrs: { r: [LOADER_R, LOADER_R * 2], \"stroke-width\": [3, 0] }, delay: pop, ms: 320, ease: \"out\" },\n ...Array.from({ length: DROPS }, (_, k): SvgAnimation[] => {\n const [x0, y0] = drop(i, k, LOADER_R);\n const [x1, y1] = drop(i, k, LOADER_R * 2.1);\n return [\n snap(`d${i}_${k}`, \"r\", 0, 0),\n { id: `d${i}_${k}`, attrs: { cx: [x0, x1], cy: [y0, r1(y1 + 4)], r: [3, 0] }, delay: pop, ms: 420, ease: \"out\" },\n snap(`d${i}_${k}`, \"cx\", x0, LOADER_END),\n snap(`d${i}_${k}`, \"cy\", y0, LOADER_END),\n ];\n }).flat(),\n // Hidden again, ready for the next round.\n snap(`ring${i}`, \"r\", LOADER_R, LOADER_END),\n snap(`b${i}`, \"transform\", p(0), LOADER_END),\n snap(`b${i}`, \"opacity\", 1, LOADER_END),\n ];\n }),\n };\n })(),\n};\n\n/** Bubbles as vector effects: chat bubbles and pops. */\nexport const bubbleEffects: VectorEffect[] = [chatBubble, bubblePopLoader];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Stickers read as stickers by three things they all share: a thick white\n * die-cut border (the shape stroked wide in the border colour, round joins),\n * a soft drop shadow under it, and a glossy sheen (a white gradient across\n * the face that stops short, like light on vinyl). Shapes are worked out in\n * code and handed to the picture by `derived`, so one control can switch them.\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 (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\nconst HEAVY = `'Arial Black', 'Helvetica Neue', Impact, system-ui, sans-serif`;\n\n/** The font control the labelled stickers share. */\nconst FONT = `{{font: text default=\"${HEAVY}\" label='Font'}}`;\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\ntype Point = readonly [number, number];\n\n/** A closed outline through `points`. */\nconst outline = (points: readonly Point[]) => `M${points.map(([x, y]) => `${r1(x)} ${r1(y)}`).join(\" L\")} Z`;\n\n/** A scalloped badge: a circle of radius `r` with `bumps` round bumps `depth` deep. */\nfunction burst(cx: number, cy: number, r: number, bumps = 14, depth = 0.08): string {\n return outline(\n Array.from({ length: 112 }, (_, k) => {\n const a = (k / 112) * Math.PI * 2;\n const rr = r * (1 - depth + depth * Math.cos(a * bumps));\n return [cx + rr * Math.cos(a), cy + rr * Math.sin(a)] as const;\n }),\n );\n}\n\n/** A star of `points` points, outer radius `r`, inner `inner`, point up. */\nfunction star(cx: number, cy: number, r: number, inner: number, points = 5): string {\n return outline(\n Array.from({ length: points * 2 }, (_, k) => {\n const a = -Math.PI / 2 + (k * Math.PI) / points;\n const rr = k % 2 ? inner : r;\n return [cx + rr * Math.cos(a), cy + rr * Math.sin(a)] as const;\n }),\n );\n}\n\n/** A heart in a 24 box, curves and all. */\nconst HEART = \"M12 21 C12 21 2.5 15 2.5 8.6 C2.5 5.6 4.9 3.3 7.9 3.3 C9.7 3.3 11.2 4.3 12 5.8 C12.8 4.3 14.3 3.3 16.1 3.3 C19.1 3.3 21.5 5.6 21.5 8.6 C21.5 15 12 21 12 21 Z\";\n\n/** The heart scaled to `size` wide and centred on (`cx`, `cy`). */\nfunction heart(cx: number, cy: number, size: number): string {\n const k = size / 19;\n let i = 0;\n return HEART.replace(/-?\\d+(?:\\.\\d+)?/g, (m) => String(r1(i++ % 2 === 0 ? cx + (Number(m) - 12) * k : cy + (Number(m) - 12.2) * k)));\n}\n\n/** A circle as a path. */\nconst circle = (cx: number, cy: number, r: number) => `M${cx - r} ${cy} A${r} ${r} 0 1 0 ${cx + r} ${cy} A${r} ${r} 0 1 0 ${cx - r} ${cy} Z`;\n\n/** A lightning bolt about `size` high, centred on (`cx`, `cy`). */\nfunction bolt(cx: number, cy: number, size: number): string {\n const k = size / 68;\n const pts: Point[] = [[4, -34], [-22, 6], [-3, 6], [-10, 34], [22, -8], [3, -8], [12, -34]];\n return outline(pts.map(([x, y]) => [cx + x * k, cy + y * k] as const));\n}\n\n/**\n * The shapes a sticker control picks between (0 burst, 1 heart, 2 star, 3\n * circle), centred on (`cx`, `cy`) about `r` in radius, with where and how\n * wide its label goes.\n */\nfunction stickerShape(shape: unknown, cx: number, cy: number, r: number) {\n switch (Math.round(Number(shape))) {\n case 1:\n return { d: heart(cx, cy, r * 2.15), labelY: cy - r * 0.08, labelW: r * 1.25 };\n case 2:\n return { d: star(cx, cy, r * 1.12, r * 0.56), labelY: cy + r * 0.12, labelW: r * 0.95 };\n case 3:\n return { d: circle(cx, cy, r * 0.95), labelY: cy, labelW: r * 1.5 };\n default:\n return { d: burst(cx, cy, r), labelY: cy, labelW: r * 1.45 };\n }\n}\n\nconst SHAPE_CONTROL = `{{shape: int min=0 max=3 default=0 label='Shape (0 burst, 1 heart, 2 star, 3 circle)'}}`;\n\n/** The gloss every sticker's face wears: light from the top left that stops short, as on vinyl. */\nconst gloss = (id: string) => `<linearGradient id=\"${id}\" x1=\"0\" y1=\"0\" x2=\"0.55\" y2=\"1\"><stop offset=\"0\" stop-color=\"#FFFFFF\" stop-opacity=\"0.6\"/><stop offset=\"0.36\" stop-color=\"#FFFFFF\" stop-opacity=\"0.12\"/><stop offset=\"0.4\" stop-color=\"#FFFFFF\" stop-opacity=\"0\"/><stop offset=\"1\" stop-color=\"#FFFFFF\" stop-opacity=\"0\"/></linearGradient>`;\n\n/** A transform posing a sticker round (`cx`, `cy`): turned `r` degrees, scaled `s` (and `sy` if squashed), dropped `dy`. */\nconst pose = (cx: number, cy: number, s: number, r: number, dy = 0, sy = s) =>\n `translate(${cx} ${r1(cy + dy)}) rotate(${r1(r)}) scale(${r2(s)} ${r2(sy)}) translate(${-cx} ${-cy})`;\n\n/** Instant changes: the attribute snaps to `value` at `delay`. */\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\n// ── Sticker slap ───────────────────────────────────────────────────────\n\n/** Slap keyframes: [ms, scale, turn, shadow drop, shadow opacity, shadow blur]. */\nconst SLAP: readonly (readonly [number, number, number, number, number, number])[] = [\n [0, 1, -6, 7, 0.32, 3],\n [150, 1.45, 6, 26, 0, 12],\n // A jump to big and clear, then the slap down past its size and back.\n [150, 2.5, 18, 34, 0.06, 15],\n [430, 0.9, -10, 3, 0.42, 2],\n [550, 1.06, -4, 8, 0.36, 3.5],\n [740, 1, -6, 7, 0.32, 3],\n];\n\nexport const stickerSlap: VectorEffect = {\n kind: \"vector\",\n id: \"sticker-slap\",\n name: \"Sticker slap\",\n description: \"A die-cut sticker with a label that flicks up and slaps back down from big with a twist, overshooting and settling as its shadow tightens; every click slaps it again.\",\n category: \"sticker\",\n tags: [\"sticker\", \"click\", \"interactive\", \"die-cut\", \"badge\", \"label\", \"slap\"],\n trigger: \"click\",\n hold: 400,\n presets: [\n { name: \"Hello heart\", values: { shape: 1, label: \"HI!\", sticker: [0.98, 0.33, 0.52], ink: [1, 1, 1] } },\n { name: \"Gold star\", values: { shape: 2, label: \"TOP\", sticker: [1, 0.78, 0.18], ink: [0.36, 0.2, 0.02], background: [0.13, 0.14, 0.18] } },\n { name: \"Laptop lid\", values: { shape: 3, label: \"SHIP IT\", sticker: [0.2, 0.83, 0.6], ink: [0.04, 0.2, 0.15], background: [0.75, 0.77, 0.8] } },\n ],\n derived: (v) => {\n const { d, labelY, labelW } = stickerShape(v.shape, 120, 120, 78);\n const { size, length } = fit(v.label, labelW, 40);\n return { d, size, length, base: r1(labelY + size * 0.36) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 240 240\"><!-- {{label: text default='NEW!' label='Label'}} ${SHAPE_CONTROL} {{background: color default=#EDE8DF label='Background'}} {{sticker: color default=#FF5A36 label='Sticker'}} {{ink: color default=#FFFFFF label='Label colour'}} {{border: color default=#FFFFFF label='Border'}} ${FONT} --><defs><filter id=\"slapSoft\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\"><feGaussianBlur id=\"shadeBlur\" stdDeviation=\"3\"/></filter>${gloss(\"slapGloss\")}</defs><rect width=\"240\" height=\"240\" fill=\"{{background}}\"/><g id=\"shade\" transform=\"${pose(120, 120, 1, -6, 7)}\" opacity=\"0.32\"><path d=\"{{d}}\" fill=\"#000000\" stroke=\"#000000\" stroke-width=\"16\" stroke-linejoin=\"round\" filter=\"url(#slapSoft)\"/></g><g id=\"sticker\" transform=\"${pose(120, 120, 1, -6)}\"><path d=\"{{d}}\" fill=\"{{border}}\" stroke=\"{{border}}\" stroke-width=\"16\" stroke-linejoin=\"round\"/><path d=\"{{d}}\" fill=\"{{sticker}}\"/><text x=\"120\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{ink}}\">{{label}}</text><path d=\"{{d}}\" fill=\"url(#slapGloss)\" stroke=\"#FFFFFF\" stroke-opacity=\"0.35\" stroke-width=\"16\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: SLAP.slice(1).flatMap(([at, s, r, dy, o, blur], i): SvgAnimation[] => {\n const [from, fs, fr, fdy, fo, fblur] = SLAP[i]!;\n const ms = at - from;\n if (ms === 0)\n return [\n snap(\"sticker\", \"transform\", pose(120, 120, s, r), at),\n snap(\"shade\", \"transform\", pose(120, 120, s, r, dy), at),\n snap(\"shade\", \"opacity\", o, at),\n snap(\"shadeBlur\", \"stdDeviation\", blur, at),\n ];\n const ease = i === 0 || i === 3 ? \"out\" : \"in-out\";\n return [\n { id: \"sticker\", step: 1, attrs: { transform: [pose(120, 120, fs, fr), pose(120, 120, s, r)] }, delay: from, ms, ease },\n { id: \"shade\", step: 1, attrs: { transform: [pose(120, 120, fs, fr, fdy), pose(120, 120, s, r, dy)], opacity: [fo, o] }, delay: from, ms, ease },\n { id: \"shadeBlur\", step: 1, attrs: { stdDeviation: [fblur, blur] }, delay: from, ms, ease },\n ];\n }).concat([\n // Gone as it flicks up, back in as it comes down.\n { id: \"sticker\", step: 1, attrs: { opacity: [1, 0] }, ms: 150, ease: \"out\" },\n { id: \"sticker\", step: 1, attrs: { opacity: [0, 1] }, delay: 150, ms: 110 },\n ]),\n },\n};\n\n// ── Sticker peel ───────────────────────────────────────────────────────\n\n/*\n * The peel folds the bottom-right corner back along the line x + y = k: the\n * sticker is clipped to the side of the line it still covers, and its back\n * is the sticker's outline reflected across the line, clipped to the\n * triangle the fold lifted, so the flap has the sticker's rounded corner.\n */\nconst PEEL_LO = 50;\nconst PEEL_HI = 190;\n/** The clip's edge, just past the sticker. */\nconst PEEL_EDGE = PEEL_HI + 5;\nconst PEEL_REST = 2 * PEEL_HI + 4;\nconst PEEL_UP = 310;\n\nconst peelRemain = (k: number) =>\n [[40, 40], [PEEL_EDGE, 40], [PEEL_EDGE, k - PEEL_EDGE], [k - PEEL_EDGE, PEEL_EDGE], [40, PEEL_EDGE]].map((p) => p.join(\",\")).join(\" \");\nconst peelFlap = (k: number) => [[PEEL_EDGE, k - PEEL_EDGE], [k - PEEL_EDGE, PEEL_EDGE], [k - PEEL_EDGE, k - PEEL_EDGE]].map((p) => p.join(\",\")).join(\" \");\n/** Reflection across x + y = k. */\nconst peelMirror = (k: number) => `matrix(0 -1 -1 0 ${k} ${k})`;\n\nexport const stickerPeel: VectorEffect = {\n kind: \"vector\",\n id: \"sticker-peel\",\n name: \"Sticker peel\",\n description: \"A square die-cut sticker whose corner curls up on hover, showing its paper-white backing and the shadow under the lifted flap, and lies back down after.\",\n category: \"sticker\",\n tags: [\"sticker\", \"hover\", \"interactive\", \"peel\", \"curl\", \"die-cut\", \"label\"],\n trigger: \"hover\",\n presets: [\n { name: \"Mint\", values: { sticker: [0.3, 0.85, 0.66], ink: [0.04, 0.24, 0.18], label: \"FRESH\" } },\n { name: \"Midnight\", values: { background: [0.1, 0.11, 0.15], sticker: [0.42, 0.36, 1], ink: [1, 1, 1], label: \"PEEL ME\" } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 104, 36);\n return { size, length, base: r1(132 + size * 0.36), icon: r1(96 - size * 0.25) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 240 240\"><!-- {{label: text default='HELLO' label='Label'}} {{background: color default=#E7E2D8 label='Background'}} {{sticker: color default=#FFB627 label='Sticker'}} {{ink: color default=#3B1F00 label='Label colour'}} {{border: color default=#FFFFFF label='Border'}} {{back: color default=#F4F1EA label='Backing'}} ${FONT} --><defs><filter id=\"peelDrop\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\"><feDropShadow dx=\"0\" dy=\"4\" stdDeviation=\"4\" flood-color=\"#000000\" flood-opacity=\"0.28\"/></filter><filter id=\"peelLift\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\"><feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"5\"/><feOffset dx=\"6\" dy=\"8\"/><feComponentTransfer><feFuncA type=\"linear\" slope=\"0.4\"/></feComponentTransfer></filter><clipPath id=\"peelRemain\"><polygon id=\"remainEdge\" points=\"${peelRemain(PEEL_REST)}\"/></clipPath><clipPath id=\"peelLifted\"><polygon id=\"flapEdge\" points=\"${peelFlap(PEEL_REST)}\"/></clipPath><linearGradient id=\"peelBacking\" gradientUnits=\"userSpaceOnUse\" x1=\"${PEEL_REST / 2}\" y1=\"${PEEL_REST / 2}\" x2=\"${PEEL_HI}\" y2=\"${PEEL_HI}\"><stop offset=\"0\" stop-color=\"#B9BDC6\"/><stop offset=\"0.22\" stop-color=\"{{back}}\"/><stop offset=\"0.7\" stop-color=\"#FFFFFF\"/><stop offset=\"1\" stop-color=\"{{back}}\"/></linearGradient>${gloss(\"peelGloss\")}</defs><rect width=\"240\" height=\"240\" fill=\"{{background}}\"/><g filter=\"url(#peelDrop)\"><g clip-path=\"url(#peelRemain)\"><rect x=\"${PEEL_LO}\" y=\"${PEEL_LO}\" width=\"${PEEL_HI - PEEL_LO}\" height=\"${PEEL_HI - PEEL_LO}\" rx=\"24\" fill=\"{{border}}\"/><rect x=\"${PEEL_LO + 9}\" y=\"${PEEL_LO + 9}\" width=\"${PEEL_HI - PEEL_LO - 18}\" height=\"${PEEL_HI - PEEL_LO - 18}\" rx=\"16\" fill=\"{{sticker}}\"/><path d=\"${star(120, 96, 20, 9)}\" fill=\"{{ink}}\" transform=\"translate(0 {{icon}}) translate(0 -96)\"/><text x=\"120\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{ink}}\">{{label}}</text><rect x=\"${PEEL_LO}\" y=\"${PEEL_LO}\" width=\"${PEEL_HI - PEEL_LO}\" height=\"${PEEL_HI - PEEL_LO}\" rx=\"24\" fill=\"url(#peelGloss)\"/></g></g><use href=\"#peelFlap\" filter=\"url(#peelLift)\"/><g id=\"peelFlap\" clip-path=\"url(#peelLifted)\"><g id=\"mirror\" transform=\"${peelMirror(PEEL_REST)}\"><rect x=\"${PEEL_LO}\" y=\"${PEEL_LO}\" width=\"${PEEL_HI - PEEL_LO}\" height=\"${PEEL_HI - PEEL_LO}\" rx=\"24\" fill=\"url(#peelBacking)\"/></g></g></svg>`,\n animate: [\n { id: \"remainEdge\", attrs: { points: [peelRemain(PEEL_REST), peelRemain(PEEL_UP)] }, ms: 650, ease: \"in-out\" },\n { id: \"flapEdge\", attrs: { points: [peelFlap(PEEL_REST), peelFlap(PEEL_UP)] }, ms: 650, ease: \"in-out\" },\n { id: \"mirror\", attrs: { transform: [peelMirror(PEEL_REST), peelMirror(PEEL_UP)] }, ms: 650, ease: \"in-out\" },\n { id: \"peelBacking\", attrs: { x1: [PEEL_REST / 2, PEEL_UP / 2], y1: [PEEL_REST / 2, PEEL_UP / 2] }, ms: 650, ease: \"in-out\" },\n ],\n },\n};\n\n// ── Holo sticker ───────────────────────────────────────────────────────\n\n/** The holo gradient's period along its direction, in picture units. */\nconst HOLO_PERIOD = 150;\n/** Sparkles: [x, y, size, start as a share of the loop]. */\nconst GLINTS: readonly (readonly [number, number, number, number])[] = [\n [86, 84, 14, 0.12],\n [158, 150, 11, 0.42],\n [150, 78, 9, 0.66],\n [92, 160, 8, 0.8],\n];\n/** A four-point sparkle round (0, 0), radius 1. */\nconst SPARKLE = \"M0 -1 C0.12 -0.12 0.12 -0.12 1 0 C0.12 0.12 0.12 0.12 0 1 C-0.12 0.12 -0.12 0.12 -1 0 C-0.12 -0.12 -0.12 -0.12 0 -1 Z\";\n\nexport const holoSticker: VectorEffect = {\n kind: \"vector\",\n id: \"holo-sticker\",\n name: \"Holo sticker\",\n description: \"A holographic die-cut sticker whose rainbow foil sweeps round and round under a white border, with a sheen passing over and sparkles glinting.\",\n category: \"sticker\",\n tags: [\"sticker\", \"holographic\", \"foil\", \"rainbow\", \"iridescent\", \"sparkle\", \"badge\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Gold foil\", values: { holo1: [1, 0.84, 0.4], holo2: [1, 0.62, 0.3], holo3: [1, 0.95, 0.7], ink: [0.4, 0.22, 0.02] } },\n { name: \"Heart on black\", values: { shape: 1, background: [0.07, 0.07, 0.1], label: \"LOVE\" } },\n { name: \"Badge\", values: { shape: 0, label: \"PRO\", speed: 2 } },\n ],\n derived: (v) => {\n const { d, labelY, labelW } = stickerShape(v.shape, 120, 120, 80);\n const { size, length } = fit(v.label, labelW, 40);\n const period = Math.round(Number(v.speed) * 1000);\n const glints = Object.fromEntries(GLINTS.flatMap(([, , , at], k) => [[`g${k}`, Math.round(at * period)], [`h${k}`, Math.round(at * period) + Math.round(period * 0.08)]]));\n // Each glint grows for 8% of the loop and fades for 11%, all inside it, so the loop stays seamless.\n return { d, size, length, base: r1(labelY + size * 0.36), period, sheen: Math.round(period * 0.35), grow: Math.round(period * 0.08), fade: Math.round(period * 0.11), ...glints };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 240 240\"><!-- {{label: text default='WOW' label='Label'}} {{shape: int min=0 max=3 default=2 label='Shape (0 burst, 1 heart, 2 star, 3 circle)'}} {{background: color default=#E9E6F5 label='Background'}} {{holo1: color default=#FF9DE2 label='Foil 1'}} {{holo2: color default=#8FE3FF label='Foil 2'}} {{holo3: color default=#FFF3A0 label='Foil 3'}} {{ink: color default=#2E1065 label='Label colour'}} {{border: color default=#FFFFFF label='Border'}} {{speed: float min=1 max=8 default=3 step=0.5 label='Seconds per sweep'}} ${FONT} --><defs><filter id=\"holoDrop\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\"><feDropShadow dx=\"0\" dy=\"5\" stdDeviation=\"5\" flood-color=\"#000000\" flood-opacity=\"0.3\"/></filter><linearGradient id=\"holoFoil\" gradientUnits=\"userSpaceOnUse\" x1=\"0\" y1=\"0\" x2=\"${HOLO_PERIOD}\" y2=\"0\" spreadMethod=\"repeat\" gradientTransform=\"rotate(35 120 120) translate(0 0)\"><stop offset=\"0\" stop-color=\"{{holo1}}\"/><stop offset=\"0.2\" stop-color=\"#C4B5FD\"/><stop offset=\"0.36\" stop-color=\"{{holo2}}\"/><stop offset=\"0.52\" stop-color=\"#B9FBC0\"/><stop offset=\"0.68\" stop-color=\"{{holo3}}\"/><stop offset=\"0.84\" stop-color=\"#FFC4A3\"/><stop offset=\"1\" stop-color=\"{{holo1}}\"/></linearGradient><linearGradient id=\"holoGrain\" gradientUnits=\"userSpaceOnUse\" x1=\"0\" y1=\"0\" x2=\"${HOLO_PERIOD / 5}\" y2=\"0\" spreadMethod=\"reflect\" gradientTransform=\"rotate(-50 120 120) translate(0 0)\"><stop offset=\"0\" stop-color=\"#FFFFFF\" stop-opacity=\"0.45\"/><stop offset=\"1\" stop-color=\"#6D28D9\" stop-opacity=\"0.12\"/></linearGradient><linearGradient id=\"holoSheenFill\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\"><stop offset=\"0\" stop-color=\"#FFFFFF\" stop-opacity=\"0\"/><stop offset=\"0.5\" stop-color=\"#FFFFFF\" stop-opacity=\"0.75\"/><stop offset=\"1\" stop-color=\"#FFFFFF\" stop-opacity=\"0\"/></linearGradient><clipPath id=\"holoFace\"><path d=\"{{d}}\"/></clipPath>${gloss(\"holoGloss\")}</defs><rect width=\"240\" height=\"240\" fill=\"{{background}}\"/><path d=\"{{d}}\" fill=\"{{border}}\" stroke=\"{{border}}\" stroke-width=\"18\" stroke-linejoin=\"round\" filter=\"url(#holoDrop)\"/><path d=\"{{d}}\" fill=\"url(#holoFoil)\"/><path d=\"{{d}}\" fill=\"url(#holoGrain)\"/><g clip-path=\"url(#holoFace)\"><rect id=\"sheen\" x=\"-60\" y=\"-40\" width=\"60\" height=\"320\" fill=\"url(#holoSheenFill)\" transform=\"translate(-80 0) rotate(20 120 120)\"/></g><text x=\"120\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{ink}}\" stroke=\"#FFFFFF\" stroke-opacity=\"0.6\" stroke-width=\"1.5\" paint-order=\"stroke\">{{label}}</text><path d=\"{{d}}\" fill=\"url(#holoGloss)\"/>${GLINTS.map(\n ([x, y], k) => `<path id=\"glint${k}\" d=\"${SPARKLE}\" fill=\"#FFFFFF\" transform=\"translate(${x} ${y}) scale(0) rotate(0)\"/>`,\n ).join(\"\")}</svg>`,\n animate: [\n // One period along each gradient per loop, so it wraps seamlessly.\n { id: \"holoFoil\", attrs: { gradientTransform: [\"rotate(35 120 120) translate(0 0)\", `rotate(35 120 120) translate(${HOLO_PERIOD} 0)`] }, ms: n(\"period\"), ease: \"linear\" },\n { id: \"holoGrain\", attrs: { gradientTransform: [\"rotate(-50 120 120) translate(0 0)\", `rotate(-50 120 120) translate(${-HOLO_PERIOD * 0.4} 0)`] }, ms: n(\"period\"), ease: \"linear\" },\n { id: \"sheen\", attrs: { transform: [\"translate(-80 0) rotate(20 120 120)\", \"translate(320 0) rotate(20 120 120)\"] }, ms: n(\"sheen\"), ease: \"in-out\" },\n ...GLINTS.flatMap(([x, y, size], k): SvgAnimation[] => [\n { id: `glint${k}`, attrs: { transform: [`translate(${x} ${y}) scale(0) rotate(0)`, `translate(${x} ${y}) scale(${size}) rotate(45)`] }, delay: n(`g${k}`), ms: n(\"grow\"), ease: \"out\" },\n { id: `glint${k}`, attrs: { transform: [`translate(${x} ${y}) scale(${size}) rotate(45)`, `translate(${x} ${y}) scale(0) rotate(90)`] }, delay: n(`h${k}`), ms: n(\"fade\"), ease: \"in-out\" },\n ]),\n ],\n },\n};\n\n// ── Sticker sheet ──────────────────────────────────────────────────────\n\n/** The sheet's stickers: [kind, x, y, turn]. */\nconst SHEET: readonly (readonly [\"heart\" | \"star\" | \"smile\" | \"bolt\" | \"pill\" | \"burst\", number, number, number])[] = [\n [\"heart\", 86, 80, -10],\n [\"star\", 178, 76, 8],\n [\"smile\", 272, 82, -5],\n [\"bolt\", 84, 168, 12],\n [\"pill\", 190, 166, -6],\n [\"burst\", 290, 170, 9],\n];\nconst SHEET_COLOURS = [\"{{c1}}\", \"{{c2}}\", \"{{c3}}\", \"{{c4}}\", \"{{c1}}\", \"{{c2}}\"];\n\n/** A sticker of the sheet, drawn round its own centre. */\nfunction sheetSticker(kind: (typeof SHEET)[number][0], x: number, y: number, colour: string): string {\n const cut = (d: string) => `<path d=\"${d}\" fill=\"{{border}}\" stroke=\"{{border}}\" stroke-width=\"10\" stroke-linejoin=\"round\" filter=\"url(#sheetDrop)\"/><path d=\"${d}\" fill=\"${colour}\"/>`;\n const shine = (d: string) => `<path d=\"${d}\" fill=\"url(#sheetGloss)\"/>`;\n switch (kind) {\n case \"heart\":\n return cut(heart(x, y, 64)) + shine(heart(x, y, 64));\n case \"star\":\n return cut(star(x, y, 36, 17)) + shine(star(x, y, 36, 17));\n case \"bolt\":\n return cut(bolt(x, y, 66)) + shine(bolt(x, y, 66));\n case \"burst\":\n return cut(burst(x, y, 32, 10, 0.1)) + `<text x=\"${x}\" y=\"${y + 6}\" text-anchor=\"middle\" font-family=\"${HEAVY}\" font-size=\"16\" font-weight=\"900\" fill=\"{{ink}}\">★</text>` + shine(burst(x, y, 32, 10, 0.1));\n case \"smile\":\n return (\n cut(circle(x, y, 30)) +\n `<circle cx=\"${x - 10}\" cy=\"${y - 7}\" r=\"4\" fill=\"{{ink}}\"/><circle cx=\"${x + 10}\" cy=\"${y - 7}\" r=\"4\" fill=\"{{ink}}\"/><path d=\"M${x - 15} ${y + 6} Q${x} ${y + 21} ${x + 15} ${y + 6}\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linecap=\"round\"/>` +\n shine(circle(x, y, 30))\n );\n case \"pill\":\n return `<rect x=\"{{pillX}}\" y=\"${y - 21}\" width=\"{{pillW}}\" height=\"42\" rx=\"21\" fill=\"{{border}}\" stroke=\"{{border}}\" stroke-width=\"10\" filter=\"url(#sheetDrop)\"/><rect x=\"{{pillX}}\" y=\"${y - 21}\" width=\"{{pillW}}\" height=\"42\" rx=\"21\" fill=\"${colour}\"/><text x=\"${x}\" y=\"{{pillBase}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{ink}}\">{{label}}</text><rect x=\"{{pillX}}\" y=\"${y - 21}\" width=\"{{pillW}}\" height=\"42\" rx=\"21\" fill=\"url(#sheetGloss)\"/>`;\n }\n}\n\n/** When the sheet's stickers pop, and when they all go. */\nconst POP_GAP = 230;\nconst SHEET_EXIT = 3300;\n\nexport const stickerSheet: VectorEffect = {\n kind: \"vector\",\n id: \"sticker-sheet\",\n name: \"Sticker sheet\",\n description: \"A sheet of six little die-cut stickers popping onto the backing one after another, each with its own tilt, like a sticker pack being opened.\",\n category: \"sticker\",\n tags: [\"sticker\", \"pack\", \"reveal\", \"stagger\", \"pop\", \"die-cut\", \"collection\", \"loop\"],\n hold: 200,\n presets: [\n { name: \"Pastel\", values: { c1: [1, 0.7, 0.8], c2: [0.7, 0.85, 1], c3: [1, 0.93, 0.6], c4: [0.75, 0.95, 0.78], ink: [0.25, 0.2, 0.35] } },\n { name: \"Night pack\", values: { background: [0.08, 0.09, 0.13], sheet: [0.16, 0.17, 0.23], label: \"RAD\" } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 84, 22);\n const pillW = r1(Math.max(56, length + 30));\n return { size, length, pillW, pillX: r1(190 - pillW / 2), pillBase: r1(166 + size * 0.36) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 360 240\"><!-- {{label: text default='COOL' label='Label'}} {{background: color default=#DCD6CC label='Background'}} {{sheet: color default=#FBFAF7 label='Sheet'}} {{c1: color default=#FF5D8F label='Colour 1'}} {{c2: color default=#4CC9F0 label='Colour 2'}} {{c3: color default=#FFD23F label='Colour 3'}} {{c4: color default=#7BE495 label='Colour 4'}} {{ink: color default=#1F1A2E label='Ink'}} {{border: color default=#FFFFFF label='Border'}} ${FONT} --><defs><filter id=\"sheetDrop\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\"><feDropShadow dx=\"0\" dy=\"3\" stdDeviation=\"2.5\" flood-color=\"#000000\" flood-opacity=\"0.25\"/></filter><filter id=\"sheetPaper\" x=\"-10%\" y=\"-10%\" width=\"120%\" height=\"120%\"><feDropShadow dx=\"0\" dy=\"4\" stdDeviation=\"6\" flood-color=\"#000000\" flood-opacity=\"0.18\"/></filter>${gloss(\"sheetGloss\")}</defs><rect width=\"360\" height=\"240\" fill=\"{{background}}\"/><rect x=\"16\" y=\"14\" width=\"328\" height=\"212\" rx=\"14\" fill=\"{{sheet}}\" filter=\"url(#sheetPaper)\"/><rect x=\"26\" y=\"24\" width=\"308\" height=\"192\" rx=\"9\" fill=\"none\" stroke=\"{{ink}}\" stroke-opacity=\"0.08\" stroke-width=\"1.5\" stroke-dasharray=\"4 5\"/>${SHEET.map(\n ([kind, x, y, r], i) => `<g id=\"s${i}\" transform=\"${pose(x, y, 0, r - 30)}\" opacity=\"0\">${sheetSticker(kind, x, y, SHEET_COLOURS[i]!)}</g>`,\n ).join(\"\")}</svg>`,\n animate: SHEET.flatMap(([, x, y, r], i): SvgAnimation[] => {\n const at = 150 + i * POP_GAP;\n const out = SHEET_EXIT + i * 40;\n return [\n { id: `s${i}`, attrs: { opacity: [0, 1] }, delay: at, ms: 60 },\n { id: `s${i}`, attrs: { transform: [pose(x, y, 0, r - 30), pose(x, y, 1.18, r + 4)] }, delay: at, ms: 220, ease: \"out\" },\n { id: `s${i}`, attrs: { transform: [pose(x, y, 1.18, r + 4), pose(x, y, 1, r)] }, delay: at + 220, ms: 180, ease: \"in-out\" },\n { id: `s${i}`, attrs: { transform: [pose(x, y, 1, r), pose(x, y, 0, r - 30)] }, delay: out, ms: 240, ease: \"in-out\" },\n { id: `s${i}`, attrs: { opacity: [1, 0] }, delay: out + 160, ms: 80 },\n ];\n }),\n },\n};\n\n// ── Stamp badge ────────────────────────────────────────────────────────\n\n/** The stamp's pose round the middle of the page: scaled `sx` by `sy`, turned `r`. */\nconst stampPose = (sx: number, sy: number, r: number) => pose(160, 100, sx, r, 0, sy);\nconst STAMP_UP = stampPose(1.8, 1.8, -16);\nconst FLECKS: readonly Point[] = [[38, 62], [284, 142], [276, 50], [52, 150], [230, 160]];\n\nexport const stampBadge: VectorEffect = {\n kind: \"vector\",\n id: \"stamp-badge\",\n name: \"Stamp badge\",\n description: \"A rubber stamp that thumps down onto the page with a squash, leaving a tilted badge in grungy, patchy ink; the next click lifts it off again.\",\n category: \"sticker\",\n tags: [\"sticker\", \"stamp\", \"click\", \"interactive\", \"toggle\", \"approved\", \"ink\", \"badge\", \"grunge\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Rejected\", values: { label: \"REJECTED\", sub: \"★ NOT TODAY ★\", ink: [0.12, 0.2, 0.62] } },\n { name: \"Paid\", values: { label: \"PAID\", sub: \"★ THANK YOU ★\", ink: [0.1, 0.5, 0.25], roughness: 3, wear: 0.85 } },\n ],\n derived: (v) => {\n const main = fit(v.label, 184, 46);\n const sub = fit(v.sub, 140, 12);\n // Worn ink: the blotchy noise's alpha cut-off, from clean (8.8) to patchy (6.4).\n return { size: main.size, length: main.length, base: r1(112 + main.size * 0.34), subSize: sub.size, subLength: sub.length, worn: r2(8.8 - Number(v.wear) * 2.4) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 200\"><!-- {{label: text default='APPROVED' label='Label'}} {{sub: text default='★ OFFICIAL ★' label='Small print'}} {{paper: color default=#FBF8F1 label='Paper'}} {{ink: color default=#C81E1E label='Ink'}} {{roughness: float min=0 max=6 default=1.6 step=0.2 label='Rough edges'}} {{wear: float min=0 max=1 default=0.4 label='Worn ink'}} ${FONT} --><defs><filter id=\"stampInk\" x=\"-15%\" y=\"-25%\" width=\"130%\" height=\"150%\"><feTurbulence type=\"fractalNoise\" baseFrequency=\"0.8\" numOctaves=\"2\" seed=\"3\" result=\"grain\"/><feDisplacementMap in=\"SourceGraphic\" in2=\"grain\" scale=\"{{roughness}}\" xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"rough\"/><feTurbulence type=\"fractalNoise\" baseFrequency=\"0.035 0.06\" numOctaves=\"3\" seed=\"11\" result=\"blots\"/><feColorMatrix in=\"blots\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -10 0 0 0 {{worn}}\" result=\"worn\"/><feComposite in=\"rough\" in2=\"worn\" operator=\"in\"/></filter><filter id=\"stampBlur\" x=\"-30%\" y=\"-50%\" width=\"160%\" height=\"200%\"><feGaussianBlur stdDeviation=\"10\"/></filter></defs><g id=\"page\" transform=\"translate(0 0)\"><rect x=\"-10\" y=\"-10\" width=\"340\" height=\"220\" fill=\"{{paper}}\"/><g fill=\"#000000\" opacity=\"0.07\"><rect x=\"28\" y=\"24\" width=\"150\" height=\"6\" rx=\"3\"/><rect x=\"28\" y=\"38\" width=\"210\" height=\"4\" rx=\"2\"/><rect x=\"28\" y=\"168\" width=\"230\" height=\"4\" rx=\"2\"/><rect x=\"28\" y=\"178\" width=\"180\" height=\"4\" rx=\"2\"/></g></g><ellipse id=\"hover\" cx=\"160\" cy=\"106\" rx=\"150\" ry=\"70\" fill=\"#000000\" opacity=\"0\" filter=\"url(#stampBlur)\"/><g id=\"stamp\" transform=\"${STAMP_UP}\" opacity=\"0\"><g filter=\"url(#stampInk)\" fill=\"{{ink}}\" stroke=\"{{ink}}\"><rect x=\"46\" y=\"46\" width=\"228\" height=\"108\" rx=\"14\" fill=\"none\" stroke-width=\"7\"/><rect x=\"57\" y=\"57\" width=\"206\" height=\"86\" rx=\"8\" fill=\"none\" stroke-width=\"2.5\"/><text x=\"160\" y=\"82\" text-anchor=\"middle\" textLength=\"{{subLength}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{subSize}}\" font-weight=\"700\" stroke=\"none\">{{sub}}</text><text x=\"160\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"900\" stroke=\"none\">{{label}}</text>${FLECKS.map(\n ([x, y], k) => `<circle id=\"fleck${k}\" cx=\"${x}\" cy=\"${y}\" r=\"${2 + (k % 3)}\" stroke=\"none\" opacity=\"0\"/>`,\n ).join(\"\")}</g></g></svg>`,\n animate: [\n // Step 1, stamp: down from above, a hard squash on impact, a little rebound, settled.\n { id: \"stamp\", step: 1, attrs: { opacity: [0, 0.92] }, ms: 120 },\n { id: \"stamp\", step: 1, attrs: { transform: [STAMP_UP, stampPose(1.08, 0.86, -8)] }, ms: 170, ease: \"linear\" },\n { id: \"stamp\", step: 1, attrs: { transform: [stampPose(1.08, 0.86, -8), stampPose(0.97, 1.04, -8)] }, delay: 170, ms: 120, ease: \"out\" },\n { id: \"stamp\", step: 1, attrs: { transform: [stampPose(0.97, 1.04, -8), stampPose(1, 1, -8)] }, delay: 290, ms: 140, ease: \"in-out\" },\n // The stamp's shadow closing in as it comes down, gone once it lands.\n { id: \"hover\", step: 1, attrs: { rx: [150, 118], ry: [70, 56], opacity: [0, 0.22] }, ms: 170, ease: \"linear\" },\n { id: \"hover\", step: 1, attrs: { opacity: [0.22, 0] }, delay: 170, ms: 60 },\n snap(\"hover\", \"rx\", 150, 400),\n snap(\"hover\", \"ry\", 70, 400),\n // The page jolts and ink flecks off.\n { id: \"page\", step: 1, attrs: { transform: [\"translate(0 0)\", \"translate(0 2.5)\"] }, delay: 170, ms: 60, ease: \"out\" },\n { id: \"page\", step: 1, attrs: { transform: [\"translate(0 2.5)\", \"translate(0 0)\"] }, delay: 230, ms: 140, ease: \"in-out\" },\n ...FLECKS.map((_, k): SvgAnimation => ({ id: `fleck${k}`, step: 1, attrs: { opacity: [0, 1] }, delay: 170, ms: 40 })),\n // Step 2, lift off: up and away, then back where it started.\n { id: \"stamp\", step: 2, attrs: { transform: [stampPose(1, 1, -8), stampPose(1.18, 1.18, -4)] }, ms: 280, ease: \"out\" },\n { id: \"stamp\", step: 2, attrs: { opacity: [0.92, 0] }, ms: 260 },\n snap(\"stamp\", \"transform\", STAMP_UP, 300, 2),\n ...FLECKS.map((_, k): SvgAnimation => ({ id: `fleck${k}`, step: 2, attrs: { opacity: [1, 0] }, ms: 200 })),\n ],\n },\n};\n\n// ── Washi tape ─────────────────────────────────────────────────────────\n\nconst TAPE_L = 344;\nconst TAPE_W = 46;\n/** How far each torn end's points reach in, top to bottom. */\nconst TORN_LEFT = [3, 0, 5, 1, 4, 0, 6, 2, 3, 0, 4];\nconst TORN_RIGHT = [1, 5, 0, 4, 2, 6, 1, 3, 0, 5, 2];\n\n/** The tape's outline, along x from 0 to its length, y round 0, with torn ends. */\nconst TAPE = (() => {\n const h = TAPE_W / 2;\n const at = (k: number) => -h + (k * TAPE_W) / (TORN_LEFT.length - 1);\n const right = TORN_RIGHT.map((dx, k) => [TAPE_L - dx, at(k)] as const);\n const left = TORN_LEFT.map((dx, k) => [dx, at(k)] as const).reverse();\n return outline([...right, ...left]);\n})();\nconst UNROLL_MS = 1500;\nconst TAPE_OFF = 3000;\n\nexport const washiTape: VectorEffect = {\n kind: \"vector\",\n id: \"washi-tape\",\n name: \"Washi tape\",\n description: \"A strip of translucent patterned washi tape unrolling across the page from its roll, with torn ends and the paper showing through.\",\n category: \"sticker\",\n tags: [\"sticker\", \"tape\", \"washi\", \"scrapbook\", \"pattern\", \"craft\", \"unroll\", \"loop\"],\n hold: 300,\n presets: [\n { name: \"Mint dots\", values: { tape: [0.66, 0.9, 0.82], stripe: [0.45, 0.78, 0.7], dot: [1, 1, 1], stripes: false, dots: true } },\n { name: \"Kraft\", values: { tape: [0.8, 0.65, 0.45], stripe: [0.55, 0.38, 0.22], dot: [0.98, 0.95, 0.88], alpha: 0.95, stripes: true, dots: false } },\n { name: \"Candy stripe\", values: { tape: [1, 1, 1], stripe: [0.95, 0.3, 0.4], dot: [0.95, 0.3, 0.4], alpha: 0.75 } },\n ],\n derived: (v) => ({ stripesOn: v.stripes ? 1 : 0, dotsOn: v.dots ? 1 : 0 }),\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{background: color default=#F6F1E7 label='Paper'}} {{tape: color default=#F9C6D3 label='Tape'}} {{stripe: color default=#F48FB1 label='Stripes'}} {{dot: color default=#FFFFFF label='Dots'}} {{alpha: float min=0.3 max=1 default=0.82 label='Opacity'}} {{stripes: bool default=true label='Stripes'}} {{dots: bool default=true label='Dots'}} --><defs><pattern id=\"washiStripeFill\" patternUnits=\"userSpaceOnUse\" width=\"14\" height=\"14\" patternTransform=\"rotate(45)\"><rect width=\"6\" height=\"14\" fill=\"{{stripe}}\"/></pattern><pattern id=\"washiDotFill\" patternUnits=\"userSpaceOnUse\" width=\"16\" height=\"16\"><circle cx=\"4\" cy=\"4\" r=\"2.4\" fill=\"{{dot}}\"/><circle cx=\"12\" cy=\"12\" r=\"2.4\" fill=\"{{dot}}\"/></pattern><filter id=\"washiFiber\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\"><feTurbulence type=\"fractalNoise\" baseFrequency=\"0.9 0.05\" numOctaves=\"2\" seed=\"4\"/><feColorMatrix type=\"matrix\" values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.7 0 0 0 -0.25\"/><feComposite in2=\"SourceGraphic\" operator=\"in\"/></filter><filter id=\"washiFlat\" x=\"-5%\" y=\"-30%\" width=\"110%\" height=\"160%\"><feDropShadow dx=\"0\" dy=\"1.5\" stdDeviation=\"1.5\" flood-color=\"#000000\" flood-opacity=\"0.18\"/></filter><filter id=\"washiRollShadow\" x=\"-100%\" y=\"-30%\" width=\"300%\" height=\"160%\"><feDropShadow dx=\"2\" dy=\"4\" stdDeviation=\"3\" flood-color=\"#000000\" flood-opacity=\"0.3\"/></filter><linearGradient id=\"washiCurve\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\"><stop offset=\"0\" stop-color=\"#000000\" stop-opacity=\"0.28\"/><stop offset=\"0.45\" stop-color=\"#FFFFFF\" stop-opacity=\"0.35\"/><stop offset=\"1\" stop-color=\"#000000\" stop-opacity=\"0.35\"/></linearGradient><clipPath id=\"washiUnrolled\"><rect id=\"reveal\" x=\"-4\" y=\"-40\" width=\"0\" height=\"80\"/></clipPath></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g fill=\"#000000\" opacity=\"0.1\"><rect x=\"36\" y=\"38\" width=\"210\" height=\"5\" rx=\"2.5\"/><rect x=\"36\" y=\"52\" width=\"160\" height=\"5\" rx=\"2.5\"/><rect x=\"150\" y=\"146\" width=\"214\" height=\"5\" rx=\"2.5\"/><rect x=\"150\" y=\"160\" width=\"170\" height=\"5\" rx=\"2.5\"/></g><g transform=\"translate(28 106) rotate(-5)\"><g id=\"tape\"><g clip-path=\"url(#washiUnrolled)\" filter=\"url(#washiFlat)\"><g opacity=\"{{alpha}}\"><path d=\"${TAPE}\" fill=\"{{tape}}\"/><path d=\"${TAPE}\" fill=\"url(#washiStripeFill)\" opacity=\"{{stripesOn}}\"/><path d=\"${TAPE}\" fill=\"url(#washiDotFill)\" opacity=\"{{dotsOn}}\"/><path d=\"${TAPE}\" fill=\"#FFFFFF\" filter=\"url(#washiFiber)\"/></g><path d=\"M0 ${-TAPE_W / 2 + 1} H${TAPE_L}\" stroke=\"#FFFFFF\" stroke-opacity=\"0.45\" stroke-width=\"1.2\"/></g><g id=\"roll\" transform=\"translate(0 0)\" opacity=\"1\"><g filter=\"url(#washiRollShadow)\"><rect x=\"-6\" y=\"${-TAPE_W / 2 - 4}\" width=\"14\" height=\"${TAPE_W + 8}\" rx=\"6\" fill=\"{{tape}}\"/><rect x=\"-6\" y=\"${-TAPE_W / 2 - 4}\" width=\"14\" height=\"${TAPE_W + 8}\" rx=\"6\" fill=\"url(#washiStripeFill)\" opacity=\"{{stripesOn}}\"/><rect x=\"-6\" y=\"${-TAPE_W / 2 - 4}\" width=\"14\" height=\"${TAPE_W + 8}\" rx=\"6\" fill=\"url(#washiCurve)\"/></g></g></g></g></svg>`,\n animate: [\n { id: \"reveal\", attrs: { width: [0, TAPE_L + 8] }, ms: UNROLL_MS, ease: \"in-out\" },\n { id: \"roll\", attrs: { transform: [\"translate(0 0)\", `translate(${TAPE_L} 0)`] }, ms: UNROLL_MS, ease: \"in-out\" },\n // The roll lifts away once it reaches the end, which tears clean.\n { id: \"roll\", attrs: { opacity: [1, 0] }, delay: UNROLL_MS, ms: 250 },\n { id: \"tape\", attrs: { opacity: [1, 0] }, delay: TAPE_OFF, ms: 400 },\n ],\n },\n};\n\n/** Stickers: slapped on, peeled, holographic and stamped. */\nexport const stickerEffects: VectorEffect[] = [stickerSlap, stickerPeel, holoSticker, stickerSheet, stampBadge, washiTape];\n","import type { ControlValue } from \"../shader/controls.js\";\nimport type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Trails as vector effects: shapes are worked out in code from the control\n * values and handed to the picture by `derived`, so one control can reshape\n * a streak or move a line of dots.\n */\n\nconst r1 = (v: number) => {\n const r = Math.round(v * 10) / 10;\n return Object.is(r, -0) ? 0 : r;\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 number control's value, clamped, or its default. */\nconst num = (v: ControlValue | undefined, fallback: number, min: number, max: number) => {\n const x = Number(v);\n return Number.isFinite(x) ? Math.min(max, Math.max(min, x)) : fallback;\n};\n\ntype Point = readonly [number, number];\n\n/** A closed outline through `points`. */\nconst outline = (points: readonly Point[]) => `M${points.map(([x, y]) => `${r1(x)} ${r1(y)}`).join(\" L\")} Z`;\n\n// ── Motion streak ──────────────────────────────────────────────────────\n\n/** A circle of radius `r` round the origin, as a path. */\nconst circlePath = (r: number) => `M${r1(-r)} 0 A${r1(r)} ${r1(r)} 0 1 0 ${r1(r)} 0 A${r1(r)} ${r1(r)} 0 1 0 ${r1(-r)} 0 Z`;\n\n/** A five-point star of radius `r` round the origin, point up. */\nconst starPath = (r: number) =>\n outline(\n Array.from({ length: 10 }, (_, k) => {\n const a = -Math.PI / 2 + (k * Math.PI) / 5;\n const rr = k % 2 ? r * 0.48 : r * 1.15;\n return [rr * Math.cos(a), rr * Math.sin(a)] as const;\n }),\n );\n\n/** Where the object rests, and where it comes from and goes to. */\nconst STREAK_Y = 80;\nconst STREAK_IN = -60;\nconst STREAK_REST = 160;\nconst STREAK_OUT = 400;\nconst at = (x: number) => `translate(${x} ${STREAK_Y})`;\nconst squash = (sx: number, sy: number) => `scale(${sx} ${sy})`;\n\nexport const motionStreak: VectorEffect = {\n kind: \"vector\",\n id: \"motion-streak\",\n name: \"Motion streak\",\n description: \"A ball or star whizzing in, easing to a stop with a squash, then easing off again, a motion-blur streak and speed lines stretching behind it while it is fast.\",\n category: \"trail\",\n tags: [\"trail\", \"motion\", \"speed\", \"streak\", \"motion-blur\", \"cartoon\", \"loop\"],\n hold: 500,\n presets: [\n { name: \"Shooting star\", values: { shape: 1, object: [1, 0.84, 0.25], streak: [1, 0.6, 0.2], background: [0.06, 0.07, 0.16], length: 170 } },\n { name: \"Tennis ball\", values: { object: [0.8, 0.95, 0.2], streak: [0.55, 0.7, 0.15], background: [0.2, 0.45, 0.3], size: 14 } },\n ],\n derived: (v) => {\n const size = num(v.size, 18, 8, 32);\n const len = num(v.length, 130, 40, 220);\n const star = Math.round(Number(v.shape)) === 1;\n const line = (y: number, from: number, to: number) => `M${r1(from)} ${r1(y)} L${r1(to)} ${r1(y)}`;\n return {\n body: star ? starPath(size) : circlePath(size),\n shine: star ? 0 : 0.55,\n hx: r1(-size * 0.35),\n hy: r1(-size * 0.4),\n hr: r1(size * 0.32),\n tail: `M0 ${r1(-size)} L${r1(-len)} ${r1(-size * 0.2)} L${r1(-len)} ${r1(size * 0.2)} L0 ${r1(size)} Z`,\n lines: [line(-size * 1.15, -size * 1.3, -len * 0.75), line(size * 0.1, -size * 1.6, -len * 1.05), line(size * 1.15, -size * 1.4, -len * 0.6)].join(\" \"),\n lineWidth: r1(Math.max(1.5, size * 0.14)),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 160\"><!-- {{shape: int min=0 max=1 default=0 label='Shape (0 ball, 1 star)'}} {{size: float min=8 max=32 default=18 step=1 label='Size'}} {{length: float min=40 max=220 default=130 step=5 label='Streak length'}} --><defs><linearGradient id=\"motionStreakFade\" x1=\"1\" y1=\"0\" x2=\"0\" y2=\"0\"><stop offset=\"0\" stop-color=\"{{streak: color default=#FF7A59 label='Streak'}}\" stop-opacity=\"0.8\"/><stop offset=\"1\" stop-color=\"{{streak}}\" stop-opacity=\"0\"/></linearGradient></defs><rect width=\"320\" height=\"160\" fill=\"{{background: color default=#FFF8EE label='Background'}}\"/><g id=\"motionStreakMover\" transform=\"${at(STREAK_IN)}\"><g id=\"motionStreakTail\" transform=\"scale(1 1)\" opacity=\"1\"><path d=\"{{tail}}\" fill=\"url(#motionStreakFade)\"/><path d=\"{{lines}}\" fill=\"none\" stroke=\"{{streak}}\" stroke-width=\"{{lineWidth}}\" stroke-linecap=\"round\" opacity=\"0.6\"/></g><g id=\"motionStreakBody\" transform=\"${squash(1.3, 0.8)}\"><path d=\"{{body}}\" fill=\"{{object: color default=#FF4D4D label='Object'}}\" stroke-linejoin=\"round\"/><circle cx=\"{{hx}}\" cy=\"{{hy}}\" r=\"{{hr}}\" fill=\"#FFFFFF\" opacity=\"{{shine}}\"/></g></g></svg>`,\n animate: [\n // In fast, easing to a stop: the streak shrinks as it slows.\n { id: \"motionStreakMover\", attrs: { transform: [at(STREAK_IN), at(STREAK_REST)] }, ms: 700, ease: \"out\" },\n { id: \"motionStreakTail\", attrs: { transform: [\"scale(1 1)\", \"scale(0 1)\"], opacity: [1, 0] }, ms: 650, ease: \"out\" },\n { id: \"motionStreakBody\", attrs: { transform: [squash(1.3, 0.8), squash(1, 1)] }, ms: 600, ease: \"out\" },\n // A squash as it stops, and back.\n { id: \"motionStreakBody\", attrs: { transform: [squash(1, 1), squash(0.84, 1.14)] }, delay: 600, ms: 140, ease: \"out\" },\n { id: \"motionStreakBody\", attrs: { transform: [squash(0.84, 1.14), squash(1, 1)] }, delay: 740, ms: 260, ease: \"out\" },\n // A wind-up back, then off, easing in and out as the streak grows behind it.\n { id: \"motionStreakMover\", attrs: { transform: [at(STREAK_REST), at(STREAK_REST - 12)] }, delay: 1300, ms: 220, ease: \"out\" },\n { id: \"motionStreakMover\", attrs: { transform: [at(STREAK_REST - 12), at(STREAK_OUT)] }, delay: 1520, ms: 700, ease: \"in-out\" },\n { id: \"motionStreakTail\", attrs: { transform: [\"scale(0 1)\", \"scale(1 1)\"], opacity: [0, 1] }, delay: 1560, ms: 420, ease: \"in-out\" },\n { id: \"motionStreakBody\", attrs: { transform: [squash(1, 1), squash(1.3, 0.8)] }, delay: 1520, ms: 400, ease: \"in-out\" },\n ],\n },\n};\n\n// ── Dotted trail ───────────────────────────────────────────────────────\n\n/** How many dots the trail has. */\nconst DOTS = 12;\n\n/** The curve the dots follow, sampled: an S from the bottom left to the top right. */\nconst CURVE: Point[] = Array.from({ length: 49 }, (_, k) => {\n const t = k / 48;\n const p0 = [26, 124];\n const p1 = [120, 150];\n const p2 = [170, 6];\n const p3 = [294, 40];\n const b = (i: number) => (1 - t) ** 3 * p0[i]! + 3 * (1 - t) ** 2 * t * p1[i]! + 3 * (1 - t) * t * t * p2[i]! + t ** 3 * p3[i]!;\n return [b(0), b(1)] as const;\n});\n\n/** The curve moved `offset` to its left (negative: right), and the direction it heads in at each sample, in degrees. */\nfunction offsetCurve(offset: number): { points: Point[]; angles: number[] } {\n const points: Point[] = [];\n const angles: number[] = [];\n CURVE.forEach((p, k) => {\n const a = CURVE[Math.max(0, k - 1)]!;\n const b = CURVE[Math.min(CURVE.length - 1, k + 1)]!;\n const dx = b[0] - a[0];\n const dy = b[1] - a[1];\n const l = Math.hypot(dx, dy) || 1;\n points.push([p[0] + (dy / l) * offset, p[1] - (dx / l) * offset]);\n angles.push((Math.atan2(dy, dx) * 180) / Math.PI);\n });\n return { points, angles };\n}\n\n/** The point `f` (0–1) of the way along a polyline by length, and the sample index nearest it. */\nfunction pointAlong(points: readonly Point[], f: number): { p: Point; i: number } {\n const lengths = [0];\n for (let k = 1; k < points.length; k++) lengths.push(lengths[k - 1]! + Math.hypot(points[k]![0] - points[k - 1]![0], points[k]![1] - points[k - 1]![1]));\n const target = f * lengths[lengths.length - 1]!;\n let k = 1;\n while (k < points.length - 1 && lengths[k]! < target) k++;\n const span = lengths[k]! - lengths[k - 1]! || 1;\n const u = Math.min(1, Math.max(0, (target - lengths[k - 1]!) / span));\n const a = points[k - 1]!;\n const b = points[k]!;\n return { p: [a[0] + (b[0] - a[0]) * u, a[1] + (b[1] - a[1]) * u], i: u < 0.5 ? k - 1 : k };\n}\n\n/** How far along its side's path dot `k` sits. */\nconst dotAt = (k: number) => r2(0.02 + (0.96 * k) / (DOTS - 1));\n\nconst DOT_IDS = Array.from({ length: DOTS }, (_, k) => k);\n\nexport const dottedTrail: VectorEffect = {\n kind: \"vector\",\n id: \"dotted-trail\",\n name: \"Dotted trail\",\n description: \"A staggered line of dots, like footsteps or breadcrumbs, stepping one by one along a curvy path and fading out behind, on a loop.\",\n category: \"trail\",\n tags: [\"trail\", \"path\", \"dots\", \"footsteps\", \"breadcrumb\", \"loop\", \"loader\"],\n hold: 300,\n presets: [\n { name: \"Footprints in snow\", values: { footprints: true, dot: [0.45, 0.55, 0.7], background: [0.95, 0.97, 1], stagger: 14, size: 5 } },\n { name: \"Breadcrumbs\", values: { dot: [0.75, 0.5, 0.25], background: [0.99, 0.95, 0.88], stagger: 0, keep: 12, guide: false } },\n { name: \"Night trail\", values: { dot: [0.4, 1, 0.75], background: [0.05, 0.07, 0.1], keep: 4, gap: 110 } },\n ],\n derived: (v) => {\n const stagger = num(v.stagger, 10, 0, 24);\n const size = num(v.size, 5, 2, 10);\n const gap = num(v.gap, 170, 60, 400);\n const keep = Math.round(num(v.keep, 6, 2, 12));\n const left = offsetCurve(stagger / 2);\n const right = offsetCurve(-stagger / 2);\n const path = (pts: readonly Point[]) => `M${pts.map(([x, y]) => `${r1(x)} ${r1(y)}`).join(\" L\")}`;\n const out: Record<string, string | number> = {\n left: path(left.points),\n right: path(right.points),\n middle: path(CURVE),\n guideOpacity: v.guide === false ? 0 : 0.18,\n rx: r1(v.footprints === true ? size * 1.5 : size),\n ry: r1(size),\n shrinkRx: r1((v.footprints === true ? size * 1.5 : size) * 0.6),\n shrinkRy: r1(size * 0.6),\n inMs: Math.round(gap * 1.6),\n outMs: Math.round(gap * 2.5),\n };\n for (const k of DOT_IDS) {\n const side = k % 2 ? right : left;\n const { p, i } = pointAlong(side.points, dotAt(k));\n out[`x${k}`] = r1(p[0]);\n out[`y${k}`] = r1(p[1]);\n out[`a${k}`] = r1(side.angles[i]!);\n out[`in${k}`] = Math.round(k * gap);\n out[`out${k}`] = Math.round((k + keep) * gap);\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 160\"><!-- {{stagger: float min=0 max=24 default=10 step=1 label='Stagger'}} {{size: float min=2 max=10 default=5 step=0.5 label='Dot size'}} {{gap: float min=60 max=400 default=170 step=10 label='Ms between dots'}} {{keep: int min=2 max=12 default=6 label='Dots shown at once'}} {{footprints: bool default=false label='Footprints'}} {{guide: bool default=true label='Show path'}} --><rect width=\"320\" height=\"160\" fill=\"{{background: color default=#14121F label='Background'}}\"/><path d=\"{{middle}}\" fill=\"none\" stroke=\"{{dot: color default=#FFB547 label='Dots'}}\" stroke-width=\"1.5\" stroke-dasharray=\"2 6\" stroke-linecap=\"round\" opacity=\"{{guideOpacity}}\"/><path id=\"dottedTrailLeft\" d=\"{{left}}\" fill=\"none\"/><path id=\"dottedTrailRight\" d=\"{{right}}\" fill=\"none\"/>${DOT_IDS.map(\n (k) =>\n `<g id=\"dottedTrailDot${k}\" transform=\"translate({{x${k}}} {{y${k}}})\"><ellipse id=\"dottedTrailMark${k}\" rx=\"0\" ry=\"0\" transform=\"rotate({{a${k}}})\" fill=\"{{dot}}\" opacity=\"0\"/></g>`,\n ).join(\"\")}</svg>`,\n animate: DOT_IDS.flatMap((k): SvgAnimation[] => [\n // Each dot steps in along its side of the path, then fades away a few dots later.\n { id: `dottedTrailDot${k}`, along: k % 2 ? \"dottedTrailRight\" : \"dottedTrailLeft\", at: [Math.max(0, r2(dotAt(k) - 0.025)), dotAt(k)], delay: n(`in${k}`), ms: n(\"inMs\"), ease: \"out\" },\n { id: `dottedTrailMark${k}`, attrs: { rx: [0, \"{{rx}}\"], ry: [0, \"{{ry}}\"], opacity: [0, 1] }, delay: n(`in${k}`), ms: n(\"inMs\"), ease: \"out\" },\n { id: `dottedTrailMark${k}`, attrs: { rx: [\"{{rx}}\", \"{{shrinkRx}}\"], ry: [\"{{ry}}\", \"{{shrinkRy}}\"], opacity: [1, 0] }, delay: n(`out${k}`), ms: n(\"outMs\"), ease: \"in-out\" },\n ]),\n },\n};\n\n/** Trails as vector effects. */\nexport const trailEffects: VectorEffect[] = [motionStreak, dottedTrail];\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Impact vector effects play on a click (`trigger: \"click\"`) with a single\n * step that returns by itself, so every click replays the hit. Elements the\n * step only flashes snap back to their starting values once hidden.\n */\n\nconst r2 = (v: number) => Math.round(v * 100) / 100;\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): SvgAnimation => ({\n id,\n step: 1,\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/** The marker's centre and its four diagonal ticks, from `inner` to `outer` out. */\nconst CX = 120;\nconst CY = 84;\nconst ticks = (inner: number, outer: number) =>\n [45, 135, 225, 315]\n .map((deg) => {\n const a = (deg * Math.PI) / 180;\n const [c, s] = [Math.cos(a), Math.sin(a)];\n return `M${r2(CX + inner * c)} ${r2(CY + inner * s)} L${r2(CX + outer * c)} ${r2(CY + outer * s)}`;\n })\n .join(\" \");\n\n/** When the marker fades and the number is gone. */\nconst MARK_OUT = 420;\nconst NUMBER_OUT = 700;\n\nexport const hitMarker: VectorEffect = {\n kind: \"vector\",\n id: \"hit-marker\",\n name: \"Hit marker\",\n description: \"An FPS hit marker whose four diagonal ticks pop in at the crosshair and fade, with a damage number floating up beside it on every click.\",\n category: \"impact\",\n tags: [\"impact\", \"interactive\", \"ui\", \"click\", \"game\", \"fps\", \"hit\", \"damage\", \"crosshair\"],\n trigger: \"click\",\n hold: 600,\n presets: [\n { name: \"Kill\", values: { marker: [1, 0.2, 0.2], number: [1, 0.2, 0.2], damage: 150 } },\n { name: \"Headshot\", values: { marker: [1, 0.82, 0.2], number: [1, 0.82, 0.2], damage: 200, weight: 6 } },\n { name: \"No number\", values: { showNumber: false } },\n ],\n derived: (v) => ({ numberOn: v.showNumber ? 1 : 0 }),\n motion: {\n svg: `<svg viewBox=\"0 0 240 160\"><!-- {{damage: int min=0 max=99999 default=42 label='Damage'}} {{showNumber: bool default=true label='Damage number'}} {{background: color default=#1B2430 label='Background'}} {{crosshair: color default=#9FB3C8 label='Crosshair'}} {{marker: color default=#FFFFFF label='Marker'}} {{number: color default=#FFFFFF label='Number colour'}} {{weight: float min=2 max=9 default=4.5 step=0.5 label='Tick weight'}} --><defs><filter id=\"hitMarkerShadow\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\"><feDropShadow dx=\"0\" dy=\"1.5\" stdDeviation=\"1.5\" flood-color=\"#000000\" flood-opacity=\"0.6\"/></filter></defs><rect width=\"240\" height=\"160\" fill=\"{{background}}\"/><g stroke=\"{{crosshair}}\" stroke-width=\"2\" stroke-linecap=\"round\" opacity=\"0.7\"><path d=\"M${CX} ${CY - 6} V${CY - 2} M${CX} ${CY + 2} V${CY + 6} M${CX - 6} ${CY} H${CX - 2} M${CX + 2} ${CY} H${CX + 6}\"/></g><g id=\"hitMarkerTicks\" transform=\"${about(CX, CY, 1.7)}\" opacity=\"0\" filter=\"url(#hitMarkerShadow)\"><path d=\"${ticks(9, 24)}\" fill=\"none\" stroke=\"{{marker}}\" stroke-width=\"{{weight}}\" stroke-linecap=\"square\"/></g><g id=\"hitMarkerRise\" transform=\"translate(0 6)\"><text id=\"hitMarkerNumber\" x=\"${CX + 22}\" y=\"${CY - 26}\" font-family=\"${SANS}\" font-size=\"22\" font-weight=\"800\" fill=\"{{number}}\" stroke=\"#000000\" stroke-opacity=\"0.55\" stroke-width=\"3\" paint-order=\"stroke\" opacity=\"0\">{{damage}}</text></g></svg>`,\n animate: [\n // The ticks snap in from large, overshoot small and settle, then fade.\n { id: \"hitMarkerTicks\", step: 1, attrs: { opacity: [0, 1] }, ms: 30 },\n { id: \"hitMarkerTicks\", step: 1, attrs: { transform: [about(CX, CY, 1.7), about(CX, CY, 0.88)] }, ms: 90, ease: \"out\" },\n { id: \"hitMarkerTicks\", step: 1, attrs: { transform: [about(CX, CY, 0.88), about(CX, CY, 1)] }, delay: 90, ms: 90, ease: \"in-out\" },\n { id: \"hitMarkerTicks\", step: 1, attrs: { opacity: [1, 0], transform: [about(CX, CY, 1), about(CX, CY, 1.15)] }, delay: MARK_OUT - 180, ms: 180, ease: \"in-out\" },\n snap(\"hitMarkerTicks\", \"transform\", about(CX, CY, 1.7), MARK_OUT + 20),\n // The damage number pops up beside it, floats up and fades.\n { id: \"hitMarkerNumber\", step: 1, attrs: { opacity: [0, \"{{numberOn}}\"] }, delay: 40, ms: 80 },\n { id: \"hitMarkerRise\", step: 1, attrs: { transform: [\"translate(0 6)\", \"translate(8 -36)\"] }, delay: 40, ms: NUMBER_OUT - 40, ease: \"out\" },\n { id: \"hitMarkerNumber\", step: 1, attrs: { opacity: [\"{{numberOn}}\", 0] }, delay: NUMBER_OUT - 260, ms: 260, ease: \"in-out\" },\n snap(\"hitMarkerRise\", \"transform\", \"translate(0 6)\", NUMBER_OUT + 20),\n ],\n },\n};\n\n/** Impacts as vector effects: hit markers. */\nexport const impactEffects: VectorEffect[] = [hitMarker];\n","import type { EaseName, SvgAnimation } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Cartoon and comic as vector effects. They share the comic inker's habits:\n * flat fills with a heavy ink outline, shapes that pop in past their size and\n * settle, and, where a shape is a heap of round puffs, the puffs drawn twice\n * (stroked under, filled over) so their outline is one cloud's. Ids in\n * `<defs>` start with the effect's name; animated elements with its initials.\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 (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\n/** A repeatable 0–1 number for `k`. */\nconst rand = (k: number) => {\n const x = Math.sin(k * 12.9898 + 4.1414) * 43758.5453;\n return x - Math.floor(x);\n};\n\n/** A transform about (`cx`, `cy`): scaled `sx` by `sy`, turned `rot` degrees and moved by (`dx`, `dy`). */\nconst about = (cx: number, cy: number, sx: number, sy = sx, rot = 0, dx = 0, dy = 0) =>\n `translate(${r1(cx + dx)} ${r1(cy + dy)}) rotate(${r1(rot)}) scale(${r2(sx)} ${r2(sy)}) translate(${r1(-cx)} ${r1(-cy)})`;\n\n/** Instant change: the attribute snaps to `value` at `delay`. */\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\n/** Keyframes `[ms, value]` of one attribute as changes, each from the frame before (equal times snap). */\nfunction keys(\n id: string,\n attr: string,\n frames: readonly (readonly [number, string | number])[],\n options: { ease?: EaseName; step?: number } = {},\n): SvgAnimation[] {\n return frames.slice(1).map(([at, value], i): SvgAnimation => {\n const [from, before] = frames[i]!;\n return {\n id,\n ...(options.step === undefined ? {} : { step: options.step }),\n attrs: { [attr]: [before, value] },\n delay: from,\n ms: at - from,\n ease: options.ease ?? \"in-out\",\n };\n });\n}\n\ntype Point = readonly [number, number];\n\n/** A closed outline through `points`. */\nconst outline = (points: readonly Point[]) => `M${points.map(([x, y]) => `${r1(x)} ${r1(y)}`).join(\" L\")} Z`;\n\n/** A star of `points` points, outer radius `r`, inner `inner`, point up, round (`cx`, `cy`). */\nfunction star(cx: number, cy: number, r: number, inner: number, points = 5): string {\n return outline(\n Array.from({ length: points * 2 }, (_, k) => {\n const a = -Math.PI / 2 + (k * Math.PI) / points;\n const rr = k % 2 ? inner : r;\n return [cx + rr * Math.cos(a), cy + rr * Math.sin(a)] as const;\n }),\n );\n}\n\n/** A four-pointed sparkle with curved sides, round (`cx`, `cy`). */\nfunction sparkle(cx: number, cy: number, r: number): string {\n const k = r * 0.18;\n return `M${r1(cx)} ${r1(cy - r)} Q${r1(cx + k)} ${r1(cy - k)} ${r1(cx + r)} ${r1(cy)} Q${r1(cx + k)} ${r1(cy + k)} ${r1(cx)} ${r1(cy + r)} Q${r1(cx - k)} ${r1(cy + k)} ${r1(cx - r)} ${r1(cy)} Q${r1(cx - k)} ${r1(cy - k)} ${r1(cx)} ${r1(cy - r)} Z`;\n}\n\n/** An ellipse as a path. */\nconst ellipse = (cx: number, cy: number, rx: number, ry: number) =>\n `M${r1(cx - rx)} ${r1(cy)} A${r1(rx)} ${r1(ry)} 0 1 0 ${r1(cx + rx)} ${r1(cy)} A${r1(rx)} ${r1(ry)} 0 1 0 ${r1(cx - rx)} ${r1(cy)} Z`;\n\n/** Lettering faces, the comic ones first. */\nconst LETTERING = `'Bangers', 'Luckiest Guy', Impact, 'Arial Black', sans-serif`;\nconst HANDWRITTEN = `'Comic Neue', 'Comic Sans MS', 'Chalkboard SE', 'Marker Felt', cursive`;\n\n// ── Sound effect ───────────────────────────────────────────────────────\n\nconst SFX_X = 200;\nconst SFX_Y = 150;\n\n/** A jagged starburst round the sound effect's centre: `spikes` points of uneven length. */\nfunction jagged(rx: number, ry: number, spikes: number, inner: number, seed: number, turn = 0): string {\n return outline(\n Array.from({ length: spikes * 2 }, (_, k) => {\n const a = turn + (k * Math.PI) / spikes;\n const reach = k % 2 ? inner * (0.92 + 0.16 * rand(k + seed)) : 0.8 + 0.2 * rand(k * 3.1 + seed);\n return [SFX_X + rx * reach * Math.cos(a), SFX_Y + ry * reach * Math.sin(a)] as const;\n }),\n );\n}\n\nconst SFX_OUTER = jagged(178, 132, 15, 0.64, 1);\nconst SFX_INNER = jagged(128, 92, 13, 0.7, 9, 0.2);\n\n/** Little ink flecks flying off the burst. */\nconst SFX_FLECKS = Array.from({ length: 10 }, (_, k) => {\n const a = (k / 10) * Math.PI * 2 + 0.3 * rand(k + 40);\n const [c, s] = [Math.cos(a), Math.sin(a)];\n const [r0, r1_] = [1.0 + 0.06 * rand(k), 1.16 + 0.1 * rand(k + 7)];\n return `M${r1(SFX_X + 182 * r0 * c)} ${r1(SFX_Y + 136 * r0 * s)} L${r1(SFX_X + 182 * r1_ * c)} ${r1(SFX_Y + 136 * r1_ * s)}`;\n}).join(\" \");\n\n/** The burst's pose: scaled `s` and turned `rot`, round the centre. */\nconst sfxPose = (s: number, rot: number) => about(SFX_X, SFX_Y, s, s, rot);\n\n/** The shake after the hit: [ms, dx, dy], dying away. */\nconst SFX_SHAKE: readonly (readonly [number, number, number])[] = [\n [380, 0, 0],\n [420, 7, -4],\n [460, -6, 5],\n [500, 5, 3],\n [540, -5, -3],\n [580, 3, 4],\n [620, -3, -2],\n [660, 2, 1],\n [700, 0, 0],\n];\n\nexport const soundEffect: VectorEffect = {\n kind: \"vector\",\n id: \"sound-effect\",\n name: \"Sound effect\",\n description: \"A comic sound effect: a jagged starburst with halftone dots and a lettered word that pops in with an overshoot, shakes from the hit, holds and bursts away, on a loop.\",\n category: \"comic\",\n tags: [\"comic\", \"cartoon\", \"pow\", \"onomatopoeia\", \"burst\", \"halftone\", \"text\", \"pop\"],\n hold: 300,\n presets: [\n { name: \"BAM!\", values: { word: \"BAM!\", burst: [1, 0.36, 0.64], dots: [0.85, 0.12, 0.45], inner: [1, 0.9, 0.2], letters: [0.93, 0.13, 0.17], background: [1, 0.95, 0.75] } },\n { name: \"ZAP!\", values: { word: \"ZAP!\", burst: [0.49, 0.98, 1], dots: [0.13, 0.64, 0.79], inner: [0.49, 0.23, 0.93], letters: [1, 0.9, 0.2], background: [0.1, 0.1, 0.2] } },\n ],\n derived: (v) => {\n const e = Math.max(0.6, textWidthEm(String(v.word)));\n const size = Math.min(92, 230 / e);\n return { size: r1(size), length: r1(e * size), base: r1(SFX_Y + size * 0.36) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 300\"><!-- {{word: text default='POW!' label='Word'}} {{background: color default=#3FA9F5 label='Background'}} {{burst: color default=#FFD60A label='Burst'}} {{dots: color default=#F08C00 label='Halftone dots'}} {{inner: color default=#EF233C label='Inner burst'}} {{letters: color default=#FFE45C label='Letters'}} {{ink: color default=#111111 label='Ink'}} {{font: text default=\"${LETTERING}\" label='Font'}} --><defs><pattern id=\"soundEffectDots\" patternUnits=\"userSpaceOnUse\" width=\"11\" height=\"11\" patternTransform=\"rotate(22)\"><circle cx=\"5.5\" cy=\"5.5\" r=\"2.9\" fill=\"{{dots}}\"/></pattern><radialGradient id=\"soundEffectRamp\" gradientUnits=\"userSpaceOnUse\" cx=\"${SFX_X}\" cy=\"${SFX_Y}\" r=\"180\"><stop offset=\"0.45\" stop-color=\"#000000\"/><stop offset=\"0.95\" stop-color=\"#FFFFFF\"/></radialGradient><mask id=\"soundEffectFade\"><rect width=\"400\" height=\"300\" fill=\"url(#soundEffectRamp)\"/></mask></defs><rect width=\"400\" height=\"300\" fill=\"{{background}}\"/><g id=\"sfxShake\" transform=\"translate(0 0)\"><g id=\"sfxFlecks\" transform=\"${sfxPose(0.7, 0)}\" opacity=\"0\"><path d=\"${SFX_FLECKS}\" stroke=\"{{ink}}\" stroke-width=\"6\" stroke-linecap=\"round\"/></g><g id=\"sfx\" transform=\"${sfxPose(0, -25)}\"><path d=\"${SFX_OUTER}\" fill=\"{{burst}}\" stroke=\"{{ink}}\" stroke-width=\"6\" stroke-linejoin=\"miter\"/><path d=\"${SFX_OUTER}\" fill=\"url(#soundEffectDots)\" mask=\"url(#soundEffectFade)\"/><path d=\"${SFX_INNER}\" fill=\"{{inner}}\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linejoin=\"miter\"/><g id=\"sfxWord\" transform=\"${about(SFX_X, SFX_Y, 0, 0, -8)}\"><text x=\"${SFX_X + 6}\" y=\"{{base}}\" dy=\"6\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{ink}}\" stroke=\"{{ink}}\" stroke-width=\"10\" stroke-linejoin=\"round\">{{word}}</text><text x=\"${SFX_X}\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{letters}}\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linejoin=\"round\" paint-order=\"stroke\">{{word}}</text></g></g></g></svg>`,\n animate: [\n // The burst slams in past its size, settles, holds, then bursts away.\n ...keys(\"sfx\", \"transform\", [\n [0, sfxPose(0, -25)],\n [160, sfxPose(1.22, 6)],\n [280, sfxPose(0.92, -3)],\n [400, sfxPose(1, 0)],\n ], { ease: \"out\" }),\n ...keys(\"sfx\", \"transform\", [\n [1900, sfxPose(1, 0)],\n [2020, sfxPose(1.1, -4)],\n [2200, sfxPose(0, 14)],\n ]),\n // The word lands a beat later, bigger, and throbs.\n ...keys(\"sfxWord\", \"transform\", [\n [100, about(SFX_X, SFX_Y, 0, 0, -8)],\n [290, about(SFX_X, SFX_Y, 1.35, 1.35, -12)],\n [410, about(SFX_X, SFX_Y, 0.94, 0.94, -6)],\n [520, about(SFX_X, SFX_Y, 1, 1, -8)],\n [1000, about(SFX_X, SFX_Y, 1.06, 1.06, -8)],\n [1400, about(SFX_X, SFX_Y, 1, 1, -8)],\n ], { ease: \"out\" }),\n // Flecks fly off on impact.\n snap(\"sfxFlecks\", \"opacity\", 0, 0),\n snap(\"sfxFlecks\", \"opacity\", 1, 140),\n { id: \"sfxFlecks\", attrs: { transform: [sfxPose(0.7, 0), sfxPose(1.25, 4)] }, delay: 140, ms: 420, ease: \"out\" },\n { id: \"sfxFlecks\", attrs: { opacity: [1, 0] }, delay: 300, ms: 320 },\n // Everything shakes from the hit.\n ...SFX_SHAKE.slice(1).map(([at, dx, dy], i): SvgAnimation => {\n const [from, fx, fy] = SFX_SHAKE[i]!;\n return { id: \"sfxShake\", attrs: { transform: [`translate(${fx} ${fy})`, `translate(${dx} ${dy})`] }, delay: from, ms: at - from, ease: \"linear\" };\n }),\n ],\n },\n};\n\n// ── Speech bubble ──────────────────────────────────────────────────────\n\nconst SB_X = 212;\nconst SB_Y = 112;\n/** Lines of text a bubble holds. */\nconst SB_LINES = 3;\n\n/** Words wrapped into lines no wider than `limit` ems. */\nfunction wrap(words: readonly string[], limit: number): string[] {\n const lines: string[] = [];\n let line = \"\";\n for (const word of words) {\n const next = line ? `${line} ${word}` : word;\n if (line && textWidthEm(next) > limit) {\n lines.push(line);\n line = word;\n } else line = next;\n }\n if (line) lines.push(line);\n return lines;\n}\n\n/** Text set in at most {@link SB_LINES} lines: the lines and their size. */\nfunction setText(text: string): { lines: string[]; size: number } {\n const words = text.split(/\\s+/).filter(Boolean);\n for (let size = 26; size >= 12; size--) {\n const lines = wrap(words, 270 / size);\n if (lines.length <= SB_LINES && lines.every((l) => textWidthEm(l) * size <= 300)) return { lines, size };\n }\n const lines = wrap(words, 270 / 12);\n const kept = [...lines.slice(0, SB_LINES - 1), lines.slice(SB_LINES - 1).join(\" \")].filter(Boolean);\n const widest = Math.max(1, ...kept.map((l) => textWidthEm(l)));\n return { lines: kept, size: Math.max(4, Math.min(12, 300 / widest)) };\n}\n\n/** A cloud's outline: bumps bulging out between points round an ellipse. */\nfunction cloud(cx: number, cy: number, rx: number, ry: number, bumps: number): string {\n const pts = Array.from({ length: bumps }, (_, k) => {\n const a = (k / bumps) * Math.PI * 2 + 0.2;\n return [cx + rx * Math.cos(a), cy + ry * Math.sin(a)] as const;\n });\n return `M${r1(pts[0]![0])} ${r1(pts[0]![1])} ${pts\n .map((p, k) => {\n const [x, y] = pts[(k + 1) % bumps]!;\n const chord = Math.hypot(x - p[0], y - p[1]);\n return `A${r1(chord * 0.6)} ${r1(chord * 0.6)} 0 0 1 ${r1(x)} ${r1(y)}`;\n })\n .join(\" \")} Z`;\n}\n\nexport const speechBubble: VectorEffect = {\n kind: \"vector\",\n id: \"speech-bubble\",\n name: \"Speech bubble\",\n description: \"A comic speech balloon with a tail that pops out of the speaker and types its words in, or a cloudy thought bubble with trailing circles.\",\n category: \"comic\",\n tags: [\"comic\", \"cartoon\", \"speech\", \"bubble\", \"balloon\", \"thought\", \"text\", \"typing\"],\n hold: 300,\n presets: [\n { name: \"Thought\", values: { thought: true, text: \"Hmm… what if we tried it in space?\", background: [0.93, 0.9, 1] } },\n { name: \"Shout\", values: { text: \"LOOK OUT!\", background: [1, 0.36, 0.3], pace: 70 } },\n ],\n derived: (v) => {\n const thought = v.thought === true;\n const { lines, size } = setText(String(v.text));\n const pace = Number(v.pace);\n const lineH = size * 1.22;\n const widest = Math.max(...lines.map((l) => textWidthEm(l) * size), size * 2);\n const rx = Math.min(186, widest / 2 / 0.8 + 26);\n const ry = Math.min(98, (lines.length * lineH) / 2 / 0.78 + 24);\n const tip: Point = [SB_X - rx * 0.62 - 18, Math.min(272, SB_Y + ry + 50)];\n const onRim = (deg: number, k = 1): Point => [SB_X + rx * k * Math.cos((deg * Math.PI) / 180), SB_Y + ry * k * Math.sin((deg * Math.PI) / 180)];\n const [b1, b2] = [onRim(112, 0.9), onRim(136, 0.9)];\n const tail = `M${r1(b1[0])} ${r1(b1[1])} Q${r1((b1[0] + tip[0]) / 2 + 6)} ${r1((b1[1] + tip[1]) / 2)} ${r1(tip[0])} ${r1(tip[1])} Q${r1((b2[0] + tip[0]) / 2 + 2)} ${r1((b2[1] + tip[1]) / 2 - 8)} ${r1(b2[0])} ${r1(b2[1])} Z`;\n const start = onRim(124, 1.18);\n const trail = [0.25, 0.55, 0.85].map((t, i) => ({\n x: r1(start[0] + (tip[0] - start[0]) * t),\n y: r1(start[1] + (tip[1] - start[1]) * t),\n r: [16, 11, 7][i]!,\n }));\n const top = SB_Y - (lines.length * lineH) / 2;\n const out: Record<string, string | number> = {\n size: r1(size),\n outline: thought ? cloud(SB_X, SB_Y, rx * 0.94, ry * 0.92, 11) : ellipse(SB_X, SB_Y, rx, ry),\n tail,\n tailShow: thought ? \"none\" : \"inline\",\n trailShow: thought ? \"inline\" : \"none\",\n pop0: about(tip[0], tip[1], 0),\n popOver: about(tip[0], tip[1], 1.1),\n popUnder: about(tip[0], tip[1], 0.96),\n pop1: about(tip[0], tip[1], 1),\n };\n trail.forEach((c, i) => Object.assign(out, { [`tx${i}`]: c.x, [`ty${i}`]: c.y, [`tr${i}`]: c.r }));\n let at = 480;\n for (let i = 0; i < SB_LINES; i++) {\n const line = lines[i] ?? \"\";\n const ms = Math.max(1, Math.round(Array.from(line).length * pace));\n Object.assign(out, {\n [`line${i}`]: line,\n [`x${i}`]: r1(SB_X - (textWidthEm(line) * size) / 2),\n [`y${i}`]: r1(top + lineH * (i + 0.78)),\n [`at${i}`]: at,\n [`ms${i}`]: ms,\n });\n at += line ? ms + 80 : 0;\n }\n out.outAt = at + 1600;\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 290\"><!-- {{text: text default='Great Scott! It actually works!' label='Text'}} {{thought: bool default=false label='Thought bubble'}} {{pace: float min=15 max=200 default=45 step=5 label='Ms per letter'}} {{background: color default=#8ECAE6 label='Background'}} {{bubble: color default=#FFFFFF label='Bubble'}} {{ink: color default=#111111 label='Ink'}} {{font: text default=\"${HANDWRITTEN}\" label='Font'}} --><rect width=\"400\" height=\"290\" fill=\"{{background}}\"/><g id=\"sbPop\" transform=\"{{pop0}}\"><g display=\"{{trailShow}}\">${[0, 1, 2]\n .map((i) => `<circle id=\"sbTrail${i}\" cx=\"{{tx${i}}}\" cy=\"{{ty${i}}}\" r=\"{{tr${i}}}\" fill=\"{{bubble}}\" stroke=\"{{ink}}\" stroke-width=\"4\" opacity=\"0\"/>`)\n .join(\"\")}</g><path d=\"{{tail}}\" display=\"{{tailShow}}\" fill=\"{{bubble}}\" stroke=\"{{ink}}\" stroke-width=\"5\" stroke-linejoin=\"round\"/><path d=\"{{outline}}\" fill=\"{{bubble}}\" stroke=\"{{ink}}\" stroke-width=\"5\" stroke-linejoin=\"round\"/><path d=\"{{tail}}\" display=\"{{tailShow}}\" fill=\"{{bubble}}\"/>${[0, 1, 2]\n .map((i) => `<text id=\"sbLine${i}\" x=\"{{x${i}}}\" y=\"{{y${i}}}\" font-family=\"{{font}}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\" xml:space=\"preserve\"></text>`)\n .join(\"\")}</g></svg>`,\n animate: [\n // Out of the speaker's mouth: the bubble grows from the tail's tip, past its size and back.\n { id: \"sbPop\", attrs: { transform: [\"{{pop0}}\", \"{{popOver}}\"], opacity: [1, 1] }, ms: 240, ease: \"out\" },\n { id: \"sbPop\", attrs: { transform: [\"{{popOver}}\", \"{{popUnder}}\"] }, delay: 240, ms: 120, ease: \"in-out\" },\n { id: \"sbPop\", attrs: { transform: [\"{{popUnder}}\", \"{{pop1}}\"] }, delay: 360, ms: 120, ease: \"in-out\" },\n // A thought's trailing circles bubble up first.\n ...[0, 1, 2].flatMap((i) => [snap(`sbTrail${2 - i}`, \"opacity\", 0, 0), snap(`sbTrail${2 - i}`, \"opacity\", 1, 40 + i * 70)]),\n ...[0, 1, 2].map((i): SvgAnimation => ({ id: `sbLine${i}`, write: `{{line${i}}}`, delay: n(`at${i}`), ms: n(`ms${i}`), ease: \"linear\" })),\n { id: \"sbPop\", attrs: { opacity: [1, 0] }, delay: n(\"outAt\"), ms: 280 },\n ],\n },\n};\n\n// ── Fight cloud ────────────────────────────────────────────────────────\n\nconst FC_X = 200;\nconst FC_Y = 158;\n/** The cloud's reach (its puffs' outer edge), for placing what pokes out. */\nconst FC_RX = 118;\nconst FC_RY = 84;\n/** One churn of the cloud, and the whole loop, in ms. */\nconst FC_LOOP = 2400;\nconst FC_CHURN = FC_LOOP / 3;\n\n/** The puffs: [x, y, r]. */\nconst FC_PUFFS: readonly (readonly [number, number, number])[] = [\n ...Array.from({ length: 10 }, (_, k) => {\n const a = (k / 10) * Math.PI * 2 + 0.25;\n return [FC_X + 80 * Math.cos(a), FC_Y + 46 * Math.sin(a), 36 + 12 * rand(k + 20)] as const;\n }),\n [FC_X - 28, FC_Y - 6, 46],\n [FC_X + 30, FC_Y + 4, 44],\n];\n\n/** A puff at churn phase `j` (0–3, 3 back where 0 was). */\nfunction puffAt(i: number, j: number) {\n const [x, y, r] = FC_PUFFS[i]!;\n const a = (j / 3) * Math.PI * 2 + rand(i + 3) * Math.PI * 2;\n return { cx: r1(x + 6 * Math.cos(a)), cy: r1(y + 5 * Math.sin(a * 1.0 + 1)), r: r1(r * (1 + 0.14 * Math.sin(a))) };\n}\n\n/** Things poking out of the cloud, pointing along +x from the wrist at the origin. */\nconst FC_FIST = `<rect x=\"-44\" y=\"-9\" width=\"46\" height=\"18\" rx=\"6\" fill=\"{{skin}}\" stroke=\"{{ink}}\" stroke-width=\"4\"/><rect x=\"0\" y=\"-17\" width=\"34\" height=\"34\" rx=\"11\" fill=\"{{skin}}\" stroke=\"{{ink}}\" stroke-width=\"4\"/><path d=\"M24 -9 H33 M24 0 H33 M24 9 H33\" stroke=\"{{ink}}\" stroke-width=\"3\" stroke-linecap=\"round\"/><path d=\"M6 -17 Q12 -24 20 -17\" fill=\"{{skin}}\" stroke=\"{{ink}}\" stroke-width=\"3\"/>`;\nconst FC_FOOT = `<rect x=\"-44\" y=\"-10\" width=\"46\" height=\"20\" fill=\"{{ink}}\" opacity=\"0.85\"/><path d=\"M0 -15 H18 Q40 -15 42 4 V15 H0 Z\" fill=\"{{boot}}\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linejoin=\"round\"/><path d=\"M0 9 H42\" stroke=\"{{ink}}\" stroke-width=\"4\"/>`;\nconst FC_STAR = `<path d=\"${star(20, 0, 20, 9)}\" fill=\"{{star}}\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linejoin=\"round\"/>`;\nconst FC_THINGS = [FC_FIST, FC_FOOT, FC_STAR];\n\n/** What pokes out when: [ms, angle in degrees, thing (0 fist, 1 foot, 2 star)]. */\nconst FC_POKES: readonly (readonly [number, number, number])[] = [\n [0, -35, 0],\n [330, 168, 1],\n [620, -105, 2],\n [880, 12, 0],\n [1180, -152, 0],\n [1450, 78, 1],\n [1720, -62, 2],\n [1930, 200, 0],\n];\n\n/** Where the cloud's edge is at `deg`, as a distance from its centre. */\nconst fcReach = (deg: number) => {\n const a = (deg * Math.PI) / 180;\n return (FC_RX * FC_RY) / Math.hypot(FC_RY * Math.cos(a), FC_RX * Math.sin(a));\n};\n\nconst fcPoke = (deg: number, d: number) => {\n const a = (deg * Math.PI) / 180;\n return `translate(${r1(FC_X + d * Math.cos(a))} ${r1(FC_Y + d * Math.sin(a))}) rotate(${deg}) scale(1)`;\n};\n\nconst FC_SHAKE = [0, 100, 200, 300, 400, 500, 600, 700, 800].map((t, k) => [t, k === 0 || k === 8 ? 0 : r1((rand(k + 60) - 0.5) * 6), k === 0 || k === 8 ? 0 : r1((rand(k + 70) - 0.5) * 5)] as const);\n\nexport const fightCloud: VectorEffect = {\n kind: \"vector\",\n id: \"fight-cloud\",\n name: \"Fight cloud\",\n description: \"A cartoon brawl: a churning dust cloud of puffs with fists, boots and stars poking out at random, little impact marks where they land, shaking the whole time.\",\n category: \"comic\",\n tags: [\"cartoon\", \"comic\", \"fight\", \"brawl\", \"dust\", \"cloud\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Night brawl\", values: { background: [0.12, 0.16, 0.23], dust: [0.6, 0.65, 0.72], marks: [1, 0.85, 0.2] } },\n { name: \"Desert\", values: { background: [0.99, 0.9, 0.54], dust: [0.9, 0.79, 0.63], boot: [0.35, 0.22, 0.12] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 400 300\"><!-- {{background: color default=#FFFFFF label='Background'}} {{dust: color default=#F2E8D5 label='Dust'}} {{ink: color default=#1A1A1A label='Ink'}} {{skin: color default=#FFCC99 label='Fists'}} {{boot: color default=#8B4513 label='Boots'}} {{star: color default=#FFD60A label='Stars'}} {{marks: color default=#EF233C label='Impact marks'}} --><rect width=\"400\" height=\"300\" fill=\"{{background}}\"/><ellipse cx=\"${FC_X}\" cy=\"${FC_Y + 98}\" rx=\"120\" ry=\"12\" fill=\"{{ink}}\" opacity=\"0.12\"/><g id=\"fcShake\" transform=\"translate(0 0)\">${FC_POKES.map(\n ([, deg, thing], k) => `<g id=\"fcPoke${k}\" transform=\"${fcPoke(deg, 0)}\">${FC_THINGS[thing]}</g>`,\n ).join(\"\")}${FC_PUFFS.map((_, i) => {\n const p = puffAt(i, 0);\n return `<circle id=\"fcO${i}\" cx=\"${p.cx}\" cy=\"${p.cy}\" r=\"${p.r}\" fill=\"{{ink}}\" stroke=\"{{ink}}\" stroke-width=\"10\"/>`;\n }).join(\"\")}${FC_PUFFS.map((_, i) => {\n const p = puffAt(i, 0);\n return `<circle id=\"fcF${i}\" cx=\"${p.cx}\" cy=\"${p.cy}\" r=\"${p.r}\" fill=\"{{dust}}\"/>`;\n }).join(\"\")}<path d=\"M150 150 q8 -6 16 0 M222 176 q8 -6 16 0 M196 128 q6 -5 12 0\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"3\" stroke-linecap=\"round\" opacity=\"0.35\"/>${FC_POKES.map(([, deg], k) => {\n const a = (deg * Math.PI) / 180;\n const d = fcReach(deg) + 54;\n const [x, y] = [r1(FC_X + d * Math.cos(a)), r1(FC_Y + d * Math.sin(a))];\n return `<g id=\"fcHit${k}\" transform=\"${about(x, y, 0.3)}\" opacity=\"0\"><path d=\"M${x} ${y - 12} V${y - 22} M${x + 11} ${y - 7} L${x + 19} ${y - 13} M${x - 11} ${y - 7} L${x - 19} ${y - 13} M${x + 13} ${y + 5} L${x + 22} ${y + 8} M${x - 13} ${y + 5} L${x - 22} ${y + 8}\" stroke=\"{{marks}}\" stroke-width=\"4\" stroke-linecap=\"round\"/><path d=\"${star(x, y, 8, 3.5, 4)}\" fill=\"{{marks}}\"/></g>`;\n }).join(\"\")}</g></svg>`,\n animate: [\n // Each puff swells and drifts round its place, three times a loop.\n ...FC_PUFFS.flatMap((_, i) =>\n [0, 1, 2].flatMap((j): SvgAnimation[] => {\n const [a, b] = [puffAt(i, j), puffAt(i, j + 1)];\n const attrs = { cx: [a.cx, b.cx], cy: [a.cy, b.cy], r: [a.r, b.r] } as const;\n return [\n { id: `fcO${i}`, attrs, delay: j * FC_CHURN, ms: FC_CHURN },\n { id: `fcF${i}`, attrs, delay: j * FC_CHURN, ms: FC_CHURN },\n ];\n }),\n ),\n // A fist, boot or star jabs out of the cloud and back, and an impact mark flashes at its tip.\n ...FC_POKES.flatMap(([at, deg], k): SvgAnimation[] => {\n const hidden = fcPoke(deg, 0);\n const out = fcPoke(deg, fcReach(deg) + 14);\n const a = (deg * Math.PI) / 180;\n const d = fcReach(deg) + 54;\n const [x, y] = [FC_X + d * Math.cos(a), FC_Y + d * Math.sin(a)];\n return [\n { id: `fcPoke${k}`, attrs: { transform: [hidden, out] }, delay: at, ms: 110, ease: \"out\" },\n { id: `fcPoke${k}`, attrs: { transform: [out, hidden] }, delay: at + 290, ms: 170, ease: \"in-out\" },\n snap(`fcHit${k}`, \"opacity\", 0, 0),\n snap(`fcHit${k}`, \"opacity\", 1, at + 90),\n { id: `fcHit${k}`, attrs: { transform: [about(x, y, 0.3), about(x, y, 1.2)] }, delay: at + 90, ms: 200, ease: \"out\" },\n { id: `fcHit${k}`, attrs: { opacity: [1, 0] }, delay: at + 200, ms: 200 },\n snap(`fcHit${k}`, \"transform\", about(x, y, 0.3), at + 400),\n ];\n }),\n // The whole scrap jitters.\n ...[0, 1, 2].flatMap((round) =>\n FC_SHAKE.slice(1).map(([t, dx, dy], i): SvgAnimation => {\n const [t0, fx, fy] = FC_SHAKE[i]!;\n return { id: \"fcShake\", attrs: { transform: [`translate(${fx} ${fy})`, `translate(${dx} ${dy})`] }, delay: round * FC_CHURN + t0, ms: t - t0, ease: \"linear\" };\n }),\n ),\n ],\n },\n};\n\n// ── Dizzy stars ────────────────────────────────────────────────────────\n\nconst DZ_X = 150;\nconst DZ_Y = 100;\nconst DZ_RX = 92;\nconst DZ_RY = 24;\nconst DZ_ORBIT = 1600;\nconst DZ_COUNT = 5;\n/** Samples per orbit. */\nconst DZ_SAMPLES = 24;\n\n/** Orbiter `j` at `t` (0–1 round the orbit): its pose, nearer (lower) ones bigger and stronger. */\nfunction dzAt(j: number, t: number) {\n const a = (t + j / DZ_COUNT) * Math.PI * 2;\n const depth = (Math.sin(a) + 1) / 2;\n return {\n transform: `translate(${r1(DZ_X + DZ_RX * Math.cos(a))} ${r1(DZ_Y + DZ_RY * Math.sin(a))}) rotate(${r1(24 * Math.sin(t * Math.PI * 4))}) scale(${r2(0.62 + 0.48 * depth)})`,\n opacity: r2(0.35 + 0.65 * depth),\n };\n}\n\nconst DZ_BIRD = `<ellipse cx=\"0\" cy=\"2\" rx=\"11\" ry=\"7.5\" fill=\"{{bird}}\" stroke=\"{{ink}}\" stroke-width=\"2.5\"/><circle cx=\"9\" cy=\"-5\" r=\"5.5\" fill=\"{{bird}}\" stroke=\"{{ink}}\" stroke-width=\"2.5\"/><path d=\"M14 -6 L20 -4 L14 -2 Z\" fill=\"#F59E0B\" stroke=\"{{ink}}\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/><circle cx=\"10\" cy=\"-6\" r=\"1.3\" fill=\"{{ink}}\"/><path d=\"M-6 0 Q-2 -9 5 -1\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2.5\" stroke-linecap=\"round\"/>`;\n\nexport const dizzyStars: VectorEffect = {\n kind: \"vector\",\n id: \"dizzy-stars\",\n name: \"Dizzy stars\",\n description: \"Cartoon stars (and, if you like, little birds) circling in an ellipse over a dazed head, growing and brightening as they swing round the front and shrinking and fading round the back.\",\n category: \"comic\",\n tags: [\"cartoon\", \"comic\", \"dizzy\", \"stars\", \"orbit\", \"knocked-out\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Tweety\", values: { birds: true, background: [0.88, 0.95, 1] } },\n { name: \"Stars only\", values: { head: false, background: [0.1, 0.1, 0.18], star: [1, 0.85, 0.3] } },\n ],\n derived: (v) => ({\n headShow: v.head === false ? \"none\" : \"inline\",\n birdShow: v.birds === true ? \"inline\" : \"none\",\n starShow: v.birds === true ? \"none\" : \"inline\",\n }),\n motion: {\n svg: `<svg viewBox=\"0 0 300 300\"><!-- {{background: color default=#FFF4E0 label='Background'}} {{star: color default=#FFD60A label='Stars'}} {{bird: color default=#7DD3FC label='Birds'}} {{skin: color default=#FFD9B3 label='Head'}} {{ink: color default=#1F2937 label='Ink'}} {{head: bool default=true label='Head'}} {{birds: bool default=false label='Birds too'}} --><rect width=\"300\" height=\"300\" fill=\"{{background}}\"/><g id=\"dzHead\" display=\"{{headShow}}\" transform=\"rotate(-4 150 290)\"><circle cx=\"150\" cy=\"205\" r=\"74\" fill=\"{{skin}}\" stroke=\"{{ink}}\" stroke-width=\"5\"/><ellipse cx=\"172\" cy=\"134\" rx=\"16\" ry=\"11\" fill=\"{{skin}}\" stroke=\"{{ink}}\" stroke-width=\"4\"/><path d=\"M114 192 l18 18 M132 192 l-18 18 M168 192 l18 18 M186 192 l-18 18\" stroke=\"{{ink}}\" stroke-width=\"5\" stroke-linecap=\"round\"/><path d=\"M122 240 q10 -9 20 0 t20 0 t20 0\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linecap=\"round\"/></g><ellipse cx=\"${DZ_X}\" cy=\"${DZ_Y}\" rx=\"${DZ_RX}\" ry=\"${DZ_RY}\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"2\" stroke-dasharray=\"4 9\" stroke-linecap=\"round\" opacity=\"0.25\"/>${Array.from(\n { length: DZ_COUNT },\n (_, j) => {\n const p = dzAt(j, 0);\n const starShape = `<path d=\"${star(0, 0, 18, 7.5)}\" fill=\"{{star}}\" stroke=\"{{ink}}\" stroke-width=\"2.5\" stroke-linejoin=\"round\"/>`;\n const body = j % 2 ? `<g display=\"{{starShow}}\">${starShape}</g><g display=\"{{birdShow}}\">${DZ_BIRD}</g>` : starShape;\n return `<g id=\"dzStar${j}\" transform=\"${p.transform}\" opacity=\"${p.opacity}\">${body}</g>`;\n },\n ).join(\"\")}</svg>`,\n animate: [\n ...Array.from({ length: DZ_COUNT }, (_, j) =>\n Array.from({ length: DZ_SAMPLES }, (_, k): SvgAnimation => {\n const [a, b] = [dzAt(j, k / DZ_SAMPLES), dzAt(j, (k + 1) / DZ_SAMPLES)];\n return {\n id: `dzStar${j}`,\n attrs: { transform: [a.transform, b.transform], opacity: [a.opacity, b.opacity] },\n delay: (k * DZ_ORBIT) / DZ_SAMPLES,\n ms: DZ_ORBIT / DZ_SAMPLES,\n ease: \"linear\",\n };\n }),\n ).flat(),\n // The head sways, dazed.\n ...keys(\"dzHead\", \"transform\", [\n [0, \"rotate(-4 150 290)\"],\n [DZ_ORBIT / 2, \"rotate(4 150 290)\"],\n [DZ_ORBIT, \"rotate(-4 150 290)\"],\n ]),\n ],\n },\n};\n\n// ── Anime emotes ───────────────────────────────────────────────────────\n\nconst AE_LOOP = 1600;\n\n/** One corner of the anger vein, bulging in towards the centre. */\nconst AE_VEIN = [0, 90, 180, 270].map((deg) => `<path d=\"M58 88 Q86 86 88 58\" transform=\"rotate(${deg} 100 100)\"/>`).join(\"\");\n\nconst AE_SPARKS: readonly (readonly [number, number, number, number])[] = [\n [100, 98, 50, 0],\n [48, 150, 26, 420],\n [154, 46, 24, 760],\n];\n\nconst aeSpark = (x: number, y: number, s: number, rot: number) => `translate(${x} ${y}) rotate(${r1(rot)}) scale(${r2(s)})`;\nconst aeDrop = (y: number, sx: number, sy: number) => `translate(132 ${r1(y)}) scale(${r2(sx)} ${r2(sy)})`;\n\nexport const animeEmotes: VectorEffect = {\n kind: \"vector\",\n id: \"anime-emotes\",\n name: \"Anime emotes\",\n description: \"Anime and manga emote symbols, picked by number: a pulsing anger vein, a sliding sweat drop, twinkling sparkles or a popping exclamation mark.\",\n category: \"comic\",\n tags: [\"comic\", \"cartoon\", \"anime\", \"manga\", \"emote\", \"reaction\", \"icon\", \"loop\"],\n hold: 0,\n presets: [\n { name: \"Sweat drop\", values: { emote: 1 } },\n { name: \"Sparkle\", values: { emote: 2, background: [0.12, 0.1, 0.2] } },\n { name: \"Exclamation\", values: { emote: 3, color: [0.98, 0.75, 0.1] } },\n ],\n derived: (v) => Object.fromEntries([0, 1, 2, 3].map((k) => [`show${k}`, Math.round(Number(v.emote)) === k ? \"inline\" : \"none\"])),\n motion: {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{emote: int min=0 max=3 default=0 label='Emote (0 anger, 1 sweat, 2 sparkle, 3 exclamation)'}} {{background: color default=#FFFFFF label='Background'}} {{color: color default=#E11D48 label='Anger and exclamation'}} {{sweat: color default=#7DD3FC label='Sweat'}} {{sparkle: color default=#FACC15 label='Sparkle'}} {{ink: color default=#1F2937 label='Ink'}} --><rect width=\"200\" height=\"200\" fill=\"{{background}}\"/><g display=\"{{show0}}\"><g id=\"aeAnger\" transform=\"${about(100, 100, 1)}\" fill=\"none\" stroke=\"{{color}}\" stroke-width=\"13\" stroke-linecap=\"round\">${AE_VEIN}</g></g><g display=\"{{show1}}\"><path d=\"M30 196 Q22 70 128 30\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linecap=\"round\" opacity=\"0.25\"/><g id=\"aeSweat\" transform=\"${aeDrop(46, 0.2, 0.2)}\" opacity=\"0\"><path d=\"M0 -30 C8 -15 20 -3 20 10 A20 20 0 0 1 -20 10 C-20 -3 -8 -15 0 -30 Z\" fill=\"{{sweat}}\" stroke=\"{{ink}}\" stroke-width=\"3.5\" stroke-linejoin=\"round\"/><ellipse cx=\"-8\" cy=\"8\" rx=\"4\" ry=\"7\" fill=\"#FFFFFF\" opacity=\"0.8\"/></g></g><g display=\"{{show2}}\">${AE_SPARKS.map(\n ([x, y], i) => `<g id=\"aeSpark${i}\" transform=\"${aeSpark(x, y, 0, 0)}\"><path d=\"${sparkle(0, 0, 1)}\" fill=\"{{sparkle}}\" stroke=\"{{ink}}\" stroke-width=\"0.06\" stroke-linejoin=\"round\"/><circle r=\"0.16\" fill=\"#FFFFFF\"/></g>`,\n ).join(\"\")}</g><g display=\"{{show3}}\"><g id=\"aeBangLines\" transform=\"${about(100, 100, 0.6)}\" opacity=\"0\" stroke=\"{{ink}}\" stroke-width=\"5\" stroke-linecap=\"round\"><path d=\"M56 40 L68 56 M144 40 L132 56 M44 84 L60 88 M156 84 L140 88\"/></g><g id=\"aeBang\" transform=\"${about(100, 160, 0)}\"><path d=\"M88 34 Q100 26 112 34 L106 118 Q100 124 94 118 Z\" fill=\"{{color}}\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linejoin=\"round\"/><circle cx=\"100\" cy=\"148\" r=\"12\" fill=\"{{color}}\" stroke=\"{{ink}}\" stroke-width=\"4\"/></g></g></svg>`,\n animate: [\n // Anger: a heartbeat, twice a loop.\n ...keys(\"aeAnger\", \"transform\", [\n [0, about(100, 100, 1)],\n [140, about(100, 100, 1.28, 1.28, 4)],\n [360, about(100, 100, 0.94, 0.94, -2)],\n [500, about(100, 100, 1.18, 1.18, 3)],\n [760, about(100, 100, 1)],\n [AE_LOOP, about(100, 100, 1)],\n ], { ease: \"out\" }),\n // Sweat: forms, wobbles, slides down the brow and fades.\n ...keys(\"aeSweat\", \"transform\", [\n [0, aeDrop(46, 0.2, 0.2)],\n [200, aeDrop(52, 1.1, 0.9)],\n [340, aeDrop(54, 1, 1)],\n [1250, aeDrop(122, 0.92, 1.1)],\n [1500, aeDrop(136, 0.92, 1.1)],\n ]),\n snap(\"aeSweat\", \"transform\", aeDrop(46, 0.2, 0.2), 1520),\n ...keys(\"aeSweat\", \"opacity\", [\n [0, 0],\n [160, 1],\n [1250, 1],\n [1500, 0],\n ]),\n // Sparkles: each twinkles open with a turn and closes again, one after another.\n ...AE_SPARKS.flatMap(([x, y, s, at], i) =>\n keys(`aeSpark${i}`, \"transform\", [\n [at, aeSpark(x, y, 0, 0)],\n [at + 260, aeSpark(x, y, s, 45)],\n [at + 460, aeSpark(x, y, s * 0.85, 60)],\n [at + 760, aeSpark(x, y, 0, 90)],\n ], { ease: \"out\" }).concat(snap(`aeSpark${i}`, \"transform\", aeSpark(x, y, 0, 0), at + 780)),\n ),\n // Exclamation: pops up past its size with stress lines, holds, then ducks away.\n ...keys(\"aeBang\", \"transform\", [\n [0, about(100, 160, 0)],\n [140, about(100, 160, 1.35, 1.35, -6)],\n [270, about(100, 160, 0.9, 0.9, 3)],\n [380, about(100, 160, 1)],\n [1250, about(100, 160, 1)],\n [1450, about(100, 160, 0)],\n ], { ease: \"out\" }),\n snap(\"aeBangLines\", \"opacity\", 0, 0),\n snap(\"aeBangLines\", \"opacity\", 1, 120),\n { id: \"aeBangLines\", attrs: { transform: [about(100, 100, 0.6), about(100, 100, 1.1)] }, delay: 120, ms: 260, ease: \"out\" },\n { id: \"aeBangLines\", attrs: { opacity: [1, 0] }, delay: 900, ms: 300 },\n snap(\"aeBangLines\", \"transform\", about(100, 100, 0.6), 1220),\n ],\n },\n};\n\n// ── Cartoon poof ───────────────────────────────────────────────────────\n\nconst PF_X = 120;\nconst PF_Y = 138;\n/** Where the object stands. */\nconst PF_FLOOR = 180;\nconst PF_BACK = 1300;\nconst PF_END = 1700;\n\n/** The object a shape control picks (0 ball, 1 crate, 2 star), sitting on the floor. */\nfunction poofShape(shape: unknown): string {\n switch (Math.round(Number(shape))) {\n case 1:\n return \"M84 108 H156 Q160 108 160 112 V176 Q160 180 156 180 H84 Q80 180 80 176 V112 Q80 108 84 108 Z\";\n case 2:\n return star(PF_X, 138, 48, 22);\n default:\n return ellipse(PF_X, 140, 40, 40);\n }\n}\n\n/** The puffs: angle, how far they fly, radius. */\nconst PF_PUFFS = [\n ...Array.from({ length: 9 }, (_, k) => {\n const a = (k / 9) * Math.PI * 2 + 0.4 * rand(k + 80);\n return { a, d: 34 + 22 * rand(k + 90), r: 22 + 12 * rand(k + 100), delay: Math.round(rand(k + 110) * 60) };\n }),\n // The middle stays filled.\n { a: -Math.PI / 2, d: 6, r: 34, delay: 0 },\n];\nconst PF_SPARKS: readonly (readonly [number, number, number])[] = [\n [52, 82, 12],\n [190, 96, 10],\n [176, 196, 8],\n [66, 190, 9],\n];\nconst pfPose = (sx: number, sy: number) => about(PF_X, PF_FLOOR, sx, sy);\nconst pfSpark = (x: number, y: number, s: number, rot: number) => `translate(${x} ${y}) rotate(${rot}) scale(${r2(s)})`;\n\nexport const cartoonPoof: VectorEffect = {\n kind: \"vector\",\n id: \"cartoon-poof\",\n name: \"Cartoon poof\",\n description: \"A cartoon vanishing act: on each click the object squashes, stretches and disappears into a burst of round smoke puffs that swell and fade among sparkles, then pops back.\",\n category: \"comic\",\n tags: [\"cartoon\", \"comic\", \"poof\", \"smoke\", \"vanish\", \"click\", \"interactive\"],\n trigger: \"click\",\n hold: 300,\n presets: [\n { name: \"Crate\", values: { shape: 1, object: [0.72, 0.5, 0.3] } },\n { name: \"Magic star\", values: { shape: 2, object: [0.98, 0.8, 0.15], smoke: [0.86, 0.8, 1], background: [0.15, 0.12, 0.3] } },\n ],\n derived: (v) => ({ shape: poofShape(v.shape) }),\n motion: {\n svg: `<svg viewBox=\"0 0 240 240\"><!-- {{shape: int min=0 max=2 default=0 label='Object (0 ball, 1 crate, 2 star)'}} {{word: text default='POOF!' label='Word'}} {{background: color default=#FFF8EC label='Background'}} {{object: color default=#F97316 label='Object'}} {{smoke: color default=#F1F2F6 label='Smoke'}} {{sparkle: color default=#FACC15 label='Sparkles'}} {{ink: color default=#1F2937 label='Ink'}} {{font: text default=\"${LETTERING}\" label='Font'}} --><rect width=\"240\" height=\"240\" fill=\"{{background}}\"/><ellipse id=\"pfShadow\" cx=\"${PF_X}\" cy=\"${PF_FLOOR + 4}\" rx=\"44\" ry=\"7\" fill=\"{{ink}}\" opacity=\"0.15\"/><g id=\"pfObject\" transform=\"${pfPose(1, 1)}\" opacity=\"1\"><path d=\"{{shape}}\" fill=\"{{object}}\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linejoin=\"round\"/><circle cx=\"108\" cy=\"136\" r=\"4\" fill=\"{{ink}}\"/><circle cx=\"132\" cy=\"136\" r=\"4\" fill=\"{{ink}}\"/><path d=\"M112 150 q8 6 16 0\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"3\" stroke-linecap=\"round\"/></g><g id=\"pfSmoke\" opacity=\"1\"><g>${PF_PUFFS.map(\n (_, k) => `<circle id=\"pfO${k}\" cx=\"${PF_X}\" cy=\"${PF_Y}\" r=\"0\" fill=\"{{ink}}\" stroke=\"{{ink}}\" stroke-width=\"7\"/>`,\n ).join(\"\")}</g><g>${PF_PUFFS.map((_, k) => `<circle id=\"pfF${k}\" cx=\"${PF_X}\" cy=\"${PF_Y}\" r=\"0\" fill=\"{{smoke}}\"/>`).join(\"\")}</g></g>${PF_SPARKS.map(\n ([x, y], i) => `<g id=\"pfSpark${i}\" transform=\"${pfSpark(x, y, 0, 0)}\"><path d=\"${sparkle(0, 0, 1)}\" fill=\"{{sparkle}}\" stroke=\"{{ink}}\" stroke-width=\"0.12\" stroke-linejoin=\"round\"/></g>`,\n ).join(\"\")}<g id=\"pfWord\" transform=\"${about(PF_X, 50, 0)}\" opacity=\"1\"><text x=\"${PF_X}\" y=\"60\" text-anchor=\"middle\" font-family=\"{{font}}\" font-size=\"30\" font-weight=\"900\" fill=\"{{object}}\" stroke=\"{{ink}}\" stroke-width=\"4\" stroke-linejoin=\"round\" paint-order=\"stroke\">{{word}}</text></g></svg>`,\n animate: [\n // Squash, stretch up and vanish; much later, pop back.\n ...keys(\"pfObject\", \"transform\", [\n [0, pfPose(1, 1)],\n [110, pfPose(1.25, 0.72)],\n [230, pfPose(0.6, 1.35)],\n [330, pfPose(0, 0)],\n ], { step: 1, ease: \"out\" }),\n snap(\"pfObject\", \"opacity\", 1, 0, 1),\n snap(\"pfObject\", \"opacity\", 0, 330, 1),\n snap(\"pfObject\", \"opacity\", 1, PF_BACK, 1),\n ...keys(\"pfObject\", \"transform\", [\n [PF_BACK, pfPose(0, 0)],\n [PF_BACK + 220, pfPose(1.12, 1.12)],\n [PF_BACK + 360, pfPose(1, 1)],\n ], { step: 1, ease: \"out\" }),\n ...keys(\"pfShadow\", \"rx\", [\n [0, 44],\n [110, 54],\n [330, 0],\n [PF_BACK, 0],\n [PF_BACK + 220, 48],\n [PF_BACK + 360, 44],\n ], { step: 1 }),\n // The smoke bursts out and swells, then fades.\n ...PF_PUFFS.flatMap(({ a, d, r, delay }, k): SvgAnimation[] => {\n const [x, y] = [r1(PF_X + d * Math.cos(a)), r1(PF_Y + d * Math.sin(a) * 0.8)];\n const [x2, y2] = [r1(PF_X + d * 1.35 * Math.cos(a)), r1(PF_Y + d * 1.35 * Math.sin(a) * 0.8 - 10)];\n return [`pfO${k}`, `pfF${k}`].flatMap((id): SvgAnimation[] => [\n { id, step: 1, attrs: { cx: [PF_X, x], cy: [PF_Y, y], r: [0, r] }, delay: 220 + delay, ms: 380, ease: \"out\" },\n { id, step: 1, attrs: { cx: [x, x2], cy: [y, y2], r: [r, r1(r * 1.15)] }, delay: 600 + delay, ms: 500, ease: \"in-out\" },\n snap(id, \"cx\", PF_X, PF_END, 1),\n snap(id, \"cy\", PF_Y, PF_END, 1),\n snap(id, \"r\", 0, PF_END, 1),\n ]);\n }),\n { id: \"pfSmoke\", step: 1, attrs: { opacity: [1, 0] }, delay: 650, ms: 450 },\n snap(\"pfSmoke\", \"opacity\", 1, PF_END, 1),\n // Sparkles twinkle round the smoke.\n ...PF_SPARKS.flatMap(([x, y, s], i) =>\n keys(`pfSpark${i}`, \"transform\", [\n [300 + i * 90, pfSpark(x, y, 0, 0)],\n [520 + i * 90, pfSpark(x, y, s, 45)],\n [820 + i * 90, pfSpark(x, y, 0, 90)],\n ], { step: 1, ease: \"out\" }).concat(snap(`pfSpark${i}`, \"transform\", pfSpark(x, y, 0, 0), PF_END, 1)),\n ),\n // The word pops above it all and floats off.\n ...keys(\"pfWord\", \"transform\", [\n [260, about(PF_X, 50, 0)],\n [400, about(PF_X, 50, 1.25, 1.25, -6)],\n [500, about(PF_X, 50, 1, 1, -4)],\n [1000, about(PF_X, 50, 1, 1, -4, 0, -10)],\n ], { step: 1, ease: \"out\" }),\n { id: \"pfWord\", step: 1, attrs: { opacity: [1, 0] }, delay: 750, ms: 250 },\n snap(\"pfWord\", \"transform\", about(PF_X, 50, 0), PF_END, 1),\n snap(\"pfWord\", \"opacity\", 1, PF_END, 1),\n ],\n },\n};\n\n// ── Line boil ──────────────────────────────────────────────────────────\n\n/** Turbulence seeds, one per drawing of the boil. */\nconst LB_SEEDS = [2, 9, 17, 23];\n\nconst DOODLE = \"M150 100 m-40 0 a40 40 0 1 0 80 0 a40 40 0 1 0 -80 0 M135 90 v6 M165 90 v6 M132 110 q18 16 36 0 M150 46 v-24 M150 154 v24 M96 100 h-24 M204 100 h24 M112 62 l-16 -16 M188 62 l16 -16 M112 138 l-16 16 M188 138 l16 16\";\nconst HEART = \"M150 172 C100 136 70 110 70 80 C70 56 88 40 110 40 C128 40 142 52 150 66 C158 52 172 40 190 40 C212 40 230 56 230 80 C230 110 200 136 150 172 Z\";\n\nexport const lineBoil: VectorEffect = {\n kind: \"vector\",\n id: \"line-boil\",\n name: \"Line boil\",\n description: \"Hand-drawn line boil on any path: a turbulence filter whose noise is redrawn a few times a second, so the line jitters like traced animation drawings.\",\n category: \"comic\",\n tags: [\"cartoon\", \"hand-drawn\", \"line-boil\", \"sketch\", \"wobble\", \"doodle\", \"filter\"],\n hold: 0,\n presets: [\n { name: \"Heart\", values: { d: HEART, fill: [1, 0.45, 0.55], fillAlpha: 1, ink: [0.35, 0.05, 0.12] } },\n { name: \"Jittery\", values: { wobble: 7, rate: 70 } },\n { name: \"Chalkboard\", values: { paper: [0.13, 0.2, 0.17], ink: [0.95, 0.95, 0.9], wobble: 3, width: 4 } },\n ],\n derived: (v) => Object.fromEntries(LB_SEEDS.map((_, k) => [`at${k}`, Math.round(k * Number(v.rate))])),\n motion: {\n svg: `<svg viewBox=\"0 0 300 200\"><!-- {{rate: float min=40 max=400 default=120 step=10 label='Ms per drawing'}} --><defs><filter id=\"lineBoilWobble\" x=\"-15%\" y=\"-15%\" width=\"130%\" height=\"130%\"><feTurbulence id=\"lineBoilNoise\" type=\"turbulence\" baseFrequency=\"{{frequency: float min=0.005 max=0.1 default=0.03 step=0.005 label='Wobble size (smaller is wider)'}}\" numOctaves=\"2\" seed=\"${LB_SEEDS[0]}\" result=\"lineBoilWarp\"/><feDisplacementMap in=\"SourceGraphic\" in2=\"lineBoilWarp\" scale=\"{{wobble: float min=0 max=12 default=4 step=0.5 label='Wobble'}}\" xChannelSelector=\"R\" yChannelSelector=\"G\"/></filter></defs><rect width=\"300\" height=\"200\" fill=\"{{paper: color default=#FFFDF5 label='Paper'}}\"/><path d=\"{{d: text default='${DOODLE}' label='Path (d)'}}\" fill=\"{{fill: color default=#FDE68A label='Fill'}}\" fill-opacity=\"{{fillAlpha: float min=0 max=1 default=0 label='Fill opacity'}}\" stroke=\"{{ink: color default=#1F2937 label='Line'}}\" stroke-width=\"{{width: float min=1 max=12 default=5 step=0.5 label='Line width'}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\" filter=\"url(#lineBoilWobble)\"/></svg>`,\n animate: LB_SEEDS.map((seed, k): SvgAnimation => ({\n id: \"lineBoilNoise\",\n attrs: { seed: [seed, seed] },\n delay: n(`at${k}`),\n // The last drawing holds a whole beat too, so the loop is even.\n ms: k === LB_SEEDS.length - 1 ? n(\"rate\") : 0,\n })),\n },\n};\n\n/** Cartoon and comic as vector effects: sound-effect bursts, speech bubbles, emotes and puffs. */\nexport const comicEffects: VectorEffect[] = [soundEffect, speechBubble, fightCloud, dizzyStars, animeEmotes, cartoonPoof, lineBoil];\n","import { rgbToHex } from \"../shader/controls.js\";\nimport type { SvgAnimation } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst r1 = (v: number) => Math.round(v * 10) / 10;\n\n/** A derived number in an animation's numeric field (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\nconst SANS = `system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif`;\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// ── Glow ring pulse ────────────────────────────────────────────────────\n\n/** Rings in flight at once, evenly spaced through the loop. */\nconst RINGS = 3;\n/** Rings are born under the core (so they appear without a pop) and fade out by the outer radius. */\nconst RING_FROM = 18;\nconst RING_TO = 112;\n\n/**\n * Each ring grows from the core and fades out over one period, starting a\n * share of the period along: it plays from there to the end, then from the\n * start back to where it began, both linear, so the loop is seamless.\n */\nfunction ringAnimations(k: number): SvgAnimation[] {\n const at = (phase: number) => ({ r: r1(RING_FROM + (RING_TO - RING_FROM) * phase), o: Math.round((1 - phase) * 100) / 100 });\n const id = `glowRingPulseRing${k}`;\n const phase = k / RINGS;\n const from = at(phase);\n const end = at(1);\n const start = at(0);\n const out: SvgAnimation[] = [\n {\n id,\n attrs: { r: [from.r, end.r], opacity: [from.o, end.o], \"stroke-width\": [n(`ws${k}`), n(\"wEnd\")] },\n ms: n(`rest${k}`),\n },\n ];\n if (phase > 0)\n out.push({\n id,\n attrs: { r: [start.r, from.r], opacity: [start.o, from.o], \"stroke-width\": [n(\"wStart\"), n(`ws${k}`)] },\n delay: n(`rest${k}`),\n ms: n(`lead${k}`),\n });\n return out;\n}\n\nexport const glowRingPulse: VectorEffect = {\n kind: \"vector\",\n id: \"glow-ring-pulse\",\n name: \"Glow ring pulse\",\n description: \"Glowing rings pulsing out from a softly breathing core in endless waves, like a beacon or a live indicator.\",\n category: \"glow\",\n tags: [\"glow\", \"ring\", \"pulse\", \"beacon\", \"live\", \"loop\", \"radar\"],\n hold: 0,\n presets: [\n { name: \"Live\", values: { ring: [1, 0.25, 0.35], core: [1, 0.72, 0.75], period: 1.6 } },\n { name: \"Gold\", values: { ring: [1, 0.75, 0.25], core: [1, 0.95, 0.75], background: [0.08, 0.06, 0.03], glow: 8 } },\n { name: \"Light\", values: { background: [0.96, 0.97, 1], ring: [0.31, 0.27, 0.9], core: [0.55, 0.5, 1], glow: 4 } },\n ],\n derived: (v) => {\n const period = Math.round(Number(v.period) * 1000);\n const width = Number(v.width);\n const out: Record<string, number> = { half: Math.round(period / 2), wStart: r1(width * 1.6), wEnd: r1(width * 0.4) };\n for (let k = 0; k < RINGS; k++) {\n const phase = k / RINGS;\n out[`rest${k}`] = Math.round(period * (1 - phase));\n out[`lead${k}`] = period - out[`rest${k}`]!;\n out[`ws${k}`] = r1(width * (1.6 - 1.2 * phase));\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 240 240\"><!-- {{period: float min=0.8 max=6 default=2.4 step=0.1 label='Seconds per wave'}} {{width: float min=1 max=10 default=4 step=0.5 label='Ring width'}} --><defs><filter id=\"glowRingPulseGlow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{glow: float min=0 max=16 default=6 step=0.5 label='Glow'}}\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter><radialGradient id=\"glowRingPulseCoreFill\"><stop offset=\"0\" stop-color=\"#FFFFFF\"/><stop offset=\"0.45\" stop-color=\"{{core: color default=#A5F3FC label='Core'}}\"/><stop offset=\"1\" stop-color=\"{{ring: color default=#22D3EE label='Ring'}}\"/></radialGradient></defs><rect width=\"240\" height=\"240\" fill=\"{{background: color default=#060A14 label='Background'}}\"/><g filter=\"url(#glowRingPulseGlow)\">${Array.from(\n { length: RINGS },\n (_, k) => `<circle id=\"glowRingPulseRing${k}\" cx=\"120\" cy=\"120\" r=\"${r1(RING_FROM + ((RING_TO - RING_FROM) * k) / RINGS)}\" fill=\"none\" stroke=\"{{ring}}\" stroke-width=\"{{ws${k}}}\" opacity=\"${Math.round((1 - k / RINGS) * 100) / 100}\"/>`,\n ).join(\"\")}<circle id=\"glowRingPulseCore\" cx=\"120\" cy=\"120\" r=\"22\" fill=\"url(#glowRingPulseCoreFill)\"/></g></svg>`,\n animate: [\n ...Array.from({ length: RINGS }, (_, k) => ringAnimations(k)).flat(),\n // The core breathes once a period, out and back, so it too loops seamlessly.\n { id: \"glowRingPulseCore\", attrs: { r: [22, 26] }, ms: n(\"half\"), ease: \"in-out\" },\n { id: \"glowRingPulseCore\", attrs: { r: [26, 22] }, delay: n(\"half\"), ms: n(\"half\"), ease: \"in-out\" },\n ],\n },\n};\n\n// ── Glow button ────────────────────────────────────────────────────────\n\n/** The halo's pose: scaled `s` about the button's centre (160, 70). */\nconst haloPose = (s: number) => `translate(160 70) scale(${s}) translate(-160 -70)`;\n\nexport const glowButton: VectorEffect = {\n kind: \"vector\",\n id: \"glow-button\",\n name: \"Glow button\",\n description: \"A pill button with a soft glow that, on hover, brightens, spreads its glow wider and lifts a little.\",\n category: \"glow\",\n tags: [\"glow\", \"button\", \"hover\", \"interactive\", \"ui\", \"cta\", \"neon\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Violet\", values: { accent: [0.55, 0.36, 0.96], background: [0.05, 0.04, 0.09] } },\n { name: \"Mint\", values: { accent: [0.2, 0.9, 0.6], ink: [0.02, 0.15, 0.1], label: \"Start free trial\" } },\n { name: \"Sunset\", values: { accent: [1, 0.45, 0.3], label: \"Join now\" } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.label, 180, 22);\n return { size, length, base: r1(70 + size * 0.35), bright: mixHex(v.accent, [1, 1, 1], 0.3) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 140\"><!-- {{label: text default='Get started' label='Label'}} {{background: color default=#0A0D18 label='Background'}} {{accent: color default=#38BDF8 label='Accent'}} {{ink: color default=#04121C label='Label colour'}} --><defs><filter id=\"glowButtonBlur\" x=\"-60%\" y=\"-120%\" width=\"220%\" height=\"340%\"><feGaussianBlur id=\"glowButtonSpread\" stdDeviation=\"10\"/></filter><linearGradient id=\"glowButtonSheen\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#FFFFFF\" stop-opacity=\"0.35\"/><stop offset=\"0.5\" stop-color=\"#FFFFFF\" stop-opacity=\"0.05\"/><stop offset=\"1\" stop-color=\"#FFFFFF\" stop-opacity=\"0\"/></linearGradient></defs><rect width=\"320\" height=\"140\" fill=\"{{background}}\"/><g opacity=\"0.9\"><g id=\"glowButtonHalo\" transform=\"${haloPose(1)}\" opacity=\"0.55\"><rect x=\"50\" y=\"42\" width=\"220\" height=\"56\" rx=\"28\" fill=\"{{accent}}\" filter=\"url(#glowButtonBlur)\"/></g></g><g id=\"glowButtonLift\" transform=\"translate(0 0)\"><rect id=\"glowButtonFace\" x=\"50\" y=\"42\" width=\"220\" height=\"56\" rx=\"28\" fill=\"{{accent}}\"/><rect x=\"50\" y=\"42\" width=\"220\" height=\"56\" rx=\"28\" fill=\"url(#glowButtonSheen)\"/><text x=\"160\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" letter-spacing=\"0.3\" fill=\"{{ink}}\">{{label}}</text></g></svg>`,\n animate: [\n { id: \"glowButtonHalo\", attrs: { opacity: [0.55, 0.95], transform: [haloPose(1), haloPose(1.08)] }, ms: 320, ease: \"out\" },\n { id: \"glowButtonSpread\", attrs: { stdDeviation: [10, 14] }, ms: 320, ease: \"out\" },\n { id: \"glowButtonLift\", attrs: { transform: [\"translate(0 0)\", \"translate(0 -3)\"] }, ms: 260, ease: \"out\" },\n { id: \"glowButtonFace\", attrs: { fill: [\"{{accent}}\", \"{{bright}}\"] }, ms: 260 },\n ],\n },\n};\n\n/** Glows as vector effects: ring pulses and glowing buttons. */\nexport const glowEffects: VectorEffect[] = [glowRingPulse, glowButton];\n","import { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nconst r1 = (v: number) => Math.round(v * 10) / 10;\n\nconst SANS = `system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif`;\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/** The card's transform about its centre (160, 120): raised `up` units and scaled by `scale`. */\nconst raised = (up: number, scale: number) => `translate(0 ${-up}) translate(160 120) scale(${scale}) translate(-160 -120)`;\n\nexport const liftCard: VectorEffect = {\n kind: \"vector\",\n id: \"lift-card\",\n name: \"Lift card\",\n description: \"A content card that lifts toward you on hover like a material elevation change, rising and growing slightly as its shadow spreads and softens beneath it.\",\n category: \"shadow\",\n tags: [\"shadow\", \"card\", \"hover\", \"interactive\", \"elevation\", \"material\", \"ui\", \"micro-interaction\"],\n trigger: \"hover\",\n hold: 800,\n presets: [\n { name: \"Dark\", values: { background: [0.07, 0.08, 0.11], card: [0.13, 0.15, 0.2], ink: [0.9, 0.92, 0.96], shadow: [0, 0, 0], accent: [0.4, 0.85, 1] } },\n { name: \"Warm\", values: { title: \"Weekend recipes\", background: [0.98, 0.94, 0.88], accent: [0.93, 0.42, 0.25], shadow: [0.35, 0.18, 0.08] } },\n ],\n derived: (v) => {\n const { size, length } = fit(v.title, 116, 17);\n return { size, length, base: r1(82 + size * 0.35) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 320 240\"><!-- {{title: text default='Getting started' label='Title'}} {{background: color default=#EEF1F6 label='Background'}} {{card: color default=#FFFFFF label='Card'}} {{ink: color default=#1F2937 label='Text colour'}} {{accent: color default=#6366F1 label='Accent'}} {{shadow: color default=#0F172A label='Shadow colour'}} --><defs><filter id=\"liftCardTight\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\"><feGaussianBlur stdDeviation=\"2.5\"/></filter><filter id=\"liftCardSoft\" x=\"-40%\" y=\"-40%\" width=\"180%\" height=\"180%\"><feGaussianBlur stdDeviation=\"14\"/></filter></defs><rect width=\"320\" height=\"240\" fill=\"{{background}}\"/><rect id=\"liftCardAmbient\" x=\"70\" y=\"50\" width=\"180\" height=\"140\" rx=\"14\" fill=\"{{shadow}}\" opacity=\"0\" filter=\"url(#liftCardSoft)\" transform=\"${raised(-4, 0.94)}\"/><rect id=\"liftCardKey\" x=\"70\" y=\"50\" width=\"180\" height=\"140\" rx=\"14\" fill=\"{{shadow}}\" opacity=\"0.22\" filter=\"url(#liftCardTight)\" transform=\"translate(0 2)\"/><g id=\"liftCardFace\" transform=\"${raised(0, 1)}\"><rect x=\"70\" y=\"50\" width=\"180\" height=\"140\" rx=\"14\" fill=\"{{card}}\"/><circle cx=\"98\" cy=\"80\" r=\"12\" fill=\"{{accent}}\"/><text x=\"118\" y=\"{{base}}\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\">{{title}}</text><g fill=\"{{ink}}\" opacity=\"0.16\"><rect x=\"86\" y=\"108\" width=\"148\" height=\"8\" rx=\"4\"/><rect x=\"86\" y=\"124\" width=\"148\" height=\"8\" rx=\"4\"/><rect x=\"86\" y=\"140\" width=\"96\" height=\"8\" rx=\"4\"/></g><rect x=\"86\" y=\"160\" width=\"54\" height=\"16\" rx=\"8\" fill=\"{{accent}}\"/></g></svg>`,\n animate: [\n { id: \"liftCardFace\", attrs: { transform: [raised(0, 1), raised(6, 1.02)] }, ms: 260, ease: \"out\" },\n { id: \"liftCardAmbient\", attrs: { opacity: [0, 0.3], transform: [raised(-4, 0.94), raised(-16, 1)] }, ms: 300, ease: \"out\" },\n { id: \"liftCardKey\", attrs: { opacity: [0.22, 0.12], transform: [\"translate(0 2)\", \"translate(0 5)\"] }, ms: 260, ease: \"out\" },\n ],\n },\n};\n\n/** Shadows as vector effects: lifting cards. */\nexport const shadowEffects: VectorEffect[] = [liftCard];\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 video: \"filter\",\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 video: \"filter\",\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 video: \"none\",\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 video: \"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 video: \"interactive\",\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 video: \"interactive\",\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 video: \"interactive\",\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 video: \"interactive\",\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 video: \"interactive\",\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 } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { BACKDROP_CONTROLS, PICTURE } from \"./image.js\";\n\n/*\n * Splashes and splatters. The overlays draw straight colour with coverage\n * alpha (0 where nothing lands), so they sit over a page or picture. The\n * splats that land at clicks read `iClicks` (xy pixels, z the `iTime` of the\n * click, w 1 for a click), the built-in the wrapper declares; with no clicks\n * yet they play a demo on a loop, which `uDemo` turns off.\n */\n\n/** `smin(a, b, k)`: a smooth union of two distances, melting shapes together within `k`. */\nconst SMIN = `\nfloat smin(float a, float b, float k) {\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/** `segment(p, a, b)`: distance from `p` to the segment a–b (x) and how far along it the nearest point is (y). */\nconst SEGMENT = `\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}`.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/**\n * `splatAt(i, demo, period, seed)`: splat `i`, newest first, as (x, y, time,\n * 1) in pixels, or zeros for none, and a seed for its shape. Real clicks win;\n * with the demo on and no clicks yet, one lands every `period` seconds at one\n * of 8 spots in turn, so the demo repeats exactly every 8 periods (needs\n * {@link HASH}).\n */\nconst SPLATS = `\nvec4 splatAt(int i, bool demo, float period, out float seed) {\n if (!demo || iClicks[0].w > 0.5) {\n seed = fract(iClicks[i].z * 0.6180339 + float(i) * 0.1379) * 97.0 + 1.0;\n return iClicks[i];\n }\n float k = floor(iTime / period) - float(i);\n float slot = mod(k, 8.0);\n vec2 h = hash22(vec2(slot * 1.37 + 0.5, 3.7));\n seed = slot * 11.3 + 1.0;\n return vec4((0.15 + 0.7 * h) * iResolution.xy, k * period, 1.0);\n}`.trim();\n\nexport const paintSplatter: ShaderEffect = {\n kind: \"shader\",\n id: \"paint-splatter\",\n name: \"Paint splatter\",\n description: \"Glossy paint splats landing in layers of a few colours, each a blob with spiky rays, satellite drops and thin flung streaks, slowly fading; clicks throw more.\",\n category: \"splatter\",\n tags: [\"splatter\", \"paint\", \"overlay\", \"click\", \"interactive\", \"artistic\", \"playful\"],\n transparent: true,\n loop: 10,\n source: glsl(\n `// Paint splatter: metaball blobs with radial spikes, droplets and streaks, landing on a loop and at clicks.\nuniform vec3 uColorA; // @control color default=#E63946 label=\"Paint 1\"\nuniform vec3 uColorB; // @control color default=#FFB703 label=\"Paint 2\"\nuniform vec3 uColorC; // @control color default=#219EBC label=\"Paint 3\"\nuniform float uSize; // @control min=0.3 max=2.5 default=1 label=\"Splat size\"\nuniform float uSpikes; // @control min=0 max=1 default=0.7 label=\"Spikes\"\nuniform float uDroplets; // @control min=0 max=1 default=0.8 label=\"Droplets\"\nuniform float uFade; // @control min=1 max=9.5 default=8 label=\"Fades after (s)\"\nuniform float uGloss; // @control min=0 max=1 default=0.8 label=\"Gloss\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n ROTATE,\n SMIN,\n SEGMENT,\n OVER,\n SPLATS,\n `// A splat's signed distance in units of its radius; grow runs 0 to 1 as it lands.\nfloat splatShape(vec2 q, float seed, float grow) {\n // The body: a few lobes melted together, with a wobbly rim.\n float s = mix(0.3, 1.0, grow);\n vec2 b = q / s;\n float d = length(b) - 0.5;\n for (int k = 0; k < 5; k++) {\n vec2 h = hash22(vec2(seed, float(k) + 0.5));\n float r = 0.2 + 0.18 * hash12(h * 13.1 + seed);\n d = smin(d, length(b - (h - 0.5) * 0.8) - r, 0.25);\n }\n d = (d + (vnoise(b * 5.0 + seed) - 0.5) * 0.09) * s;\n // Spikes: tapering rays out of the body, the longer ones throwing a drop off their end.\n const float N = 18.0;\n float sector = 6.28318 / N;\n float base = floor(atan(q.y, q.x + 1e-5) / sector);\n for (int k = -1; k <= 1; k++) {\n float id = mod(base + float(k), N);\n vec3 h = vec3(hash22(vec2(id + 0.5, seed)), hash12(vec2(seed, id * 3.1 + 0.7)));\n if (h.z > uSpikes) continue;\n float ang = (id + 0.5 + (h.x - 0.5) * 0.7) * sector;\n vec2 dir = vec2(cos(ang), sin(ang));\n float len = (0.7 + 0.8 * h.y) * grow;\n float t = clamp(dot(q, dir) / len, 0.0, 1.0);\n d = smin(d, length(q - dir * t * len) - mix(0.11, 0.012, sqrt(t)), 0.1);\n if (h.y > 0.5) d = min(d, length(q - dir * (len + (0.1 + 0.25 * h.x) * grow)) - 0.035 - 0.04 * h.x);\n }\n // Satellite drops, and a few thin streaks flung from the rim, each ending in a drop.\n for (int k = 0; k < 12; k++) {\n if (float(k) >= uDroplets * 12.0) break;\n vec3 h = vec3(hash22(vec2(seed + 4.1, float(k) + 0.5)), hash12(vec2(float(k) * 1.7, seed + 2.0)));\n float ang = h.x * 6.28318;\n vec2 dir = vec2(cos(ang), sin(ang));\n float dist = (1.15 + 1.1 * h.y) * grow;\n float r = 0.02 + 0.06 * h.z * h.z;\n if (k < 4) {\n vec2 sg = segment(q, dir * 0.8 * grow, dir * dist);\n d = min(d, sg.x - mix(0.006, 0.02, sg.y));\n d = min(d, length(q - dir * (dist + 0.03)) - 0.035);\n } else {\n d = min(d, length(q - dir * dist) - r);\n }\n }\n return d;\n}\n\nvec3 pick(float h) {\n return h < 0.333 ? uColorA : (h < 0.667 ? uColorB : uColorC);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n vec3 light = normalize(vec3(-0.5, 0.6, 1.0));\n vec4 acc = vec4(0.0);\n // Oldest first, so newer splats land on top.\n for (int i = 7; i >= 0; i--) {\n float seed;\n vec4 s = splatAt(i, uDemo, 1.25, seed);\n if (s.w < 0.5) continue;\n float age = iTime - s.z;\n if (age < 0.0 || age > uFade) continue;\n float R = 0.12 * uSize * (0.7 + 0.6 * hash12(vec2(seed, 9.1)));\n vec2 q = (p - s.xy * px) / R;\n if (dot(q, q) > 7.0) continue;\n mat2 m = rot(seed * 2.4);\n float grow = 1.0 - exp(-age * 14.0);\n float eps = px / R;\n float d = splatShape(m * q, seed, grow);\n float cover = clamp(0.5 - d * R / px, 0.0, 1.0);\n if (cover <= 0.0) continue;\n // A glossy dome: the paint is thickest inside, sloping down at the rim.\n vec2 g = vec2(splatShape(m * (q + vec2(eps, 0.0)), seed, grow), splatShape(m * (q + vec2(0.0, eps)), seed, grow)) - d;\n g /= eps;\n vec3 n = normalize(vec3(g * exp(d / 0.07) * 1.3, 1.0));\n vec3 paint = pick(hash12(vec2(seed, 5.3)));\n vec3 col = paint * (0.72 + 0.28 * dot(n, light)) * mix(0.82, 1.0, smoothstep(0.0, -0.05, d));\n float spec = pow(max(dot(reflect(-light, n), vec3(0.0, 0.0, 1.0)), 0.0), 28.0);\n col = min(col + spec * uGloss * 0.85, vec3(1.0));\n float fade = 1.0 - smoothstep(uFade * 0.55, uFade, age);\n acc = over(acc, col, cover * fade);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Black ink\", values: { uColorA: [0.06, 0.06, 0.07], uColorB: [0.1, 0.1, 0.12], uColorC: [0.04, 0.04, 0.05], uGloss: 0.5 } },\n { name: \"Neon\", values: { uColorA: [1, 0.18, 0.62], uColorB: [0.2, 1, 0.55], uColorC: [0.25, 0.6, 1], uSpikes: 1, uDroplets: 1 } },\n { name: \"Big drops\", values: { uSize: 1.9, uSpikes: 0.35, uDroplets: 0.4, uGloss: 1 } },\n ],\n};\n\nexport const inkSplash: ShaderEffect = {\n kind: \"shader\",\n id: \"ink-splash\",\n name: \"Ink splash\",\n description: \"A drop of ink hitting still water and blooming into a swirling cloud of curling tendrils that sinks and clears.\",\n category: \"splatter\",\n tags: [\"splatter\", \"ink\", \"water\", \"organic\", \"calm\", \"artistic\"],\n loop: 8,\n source: glsl(\n `// Ink splash: a drop falls into water and blooms into a sinking cloud, its tendrils advected by fbm and curled by a vortex ring.\nuniform vec3 uInk; // @control color default=#1E3A8A label=\"Ink\"\nuniform vec3 uInk2; // @control color default=#7C3AED label=\"Second ink\"\nuniform vec3 uBackground; // @control color default=#EEF4F6 label=\"Water\"\nuniform float uSwirl; // @control min=0 max=2 default=1 label=\"Swirl\"\nuniform float uSpread; // @control min=0.4 max=1.6 default=1 label=\"Spread\"\nuniform float uDensity; // @control min=0.3 max=2 default=1 label=\"Density\"\nuniform bool uSurface; // @control default=true label=\"Show surface\"`,\n HASH,\n NOISE,\n FBM,\n ROTATE,\n SEGMENT,\n `// Turns q round a point by an angle that fades out away from it, curling what flows past.\nvec2 curl(vec2 q, vec2 c, float angle, float r) {\n vec2 d = q - c;\n return c + rot(angle * exp(-dot(d, d) / (r * r))) * d;\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 = mod(iTime, 8.0);\n float top = 0.36;\n // Water, a touch darker with depth, under a faint surface line.\n vec3 bg = uBackground * (0.94 + 0.06 * smoothstep(-0.5, top, p.y));\n if (uSurface) {\n bg = mix(bg, uBackground * 1.04 + 0.02, step(top, p.y));\n bg *= 1.0 - 0.08 * exp(-abs(p.y - top) / (2.0 * px));\n }\n float dens = 0.0;\n float hue = 0.0;\n const float hit = 0.45;\n if (t < hit) {\n // The falling drop: a bead with a short tail.\n float y = mix(0.62, top, (t / hit) * (t / hit));\n float d = length((p - vec2(0.0, y)) * vec2(1.0, 0.8)) - 0.022;\n d = min(d, segment(p, vec2(0.0, y), vec2(0.0, y + 0.05)).x - 0.006);\n dens = clamp(0.5 - d / px, 0.0, 1.0) * 2.0;\n } else {\n float tau = t - hit;\n float grow = 1.0 - exp(-tau * 0.6);\n vec2 c = vec2(0.0, top - 0.04 - 0.5 * (1.0 - exp(-tau * 0.42)));\n float R = 0.05 + 0.2 * uSpread * grow;\n vec2 q = p - c;\n // The vortex ring: two lobes curling in opposite ways, the mushroom cap of sinking ink.\n float spin = uSwirl * 1.7 * (1.0 - exp(-tau * 0.5));\n q = curl(q, vec2(-0.6 * R, -0.15 * R), -spin, R * 0.7);\n q = curl(q, vec2(0.6 * R, -0.15 * R), spin, R * 0.7);\n // Fractal flow tears the edges into tendrils.\n vec2 w = vec2(fbm(q / R * 1.2 + vec2(3.1, -tau * 0.25), 5), fbm(q / R * 1.2 + vec2(7.7 + tau * 0.2, 1.3), 5)) - 0.5;\n q += w * R * (0.4 + 0.35 * uSwirl);\n float e = length(q / vec2(1.0, 0.62)) / R;\n float edge = 0.75 + 0.55 * fbm(normalize(q + 1e-5) * 2.2 + vec2(tau * 0.05, 4.0), 4);\n float cloud = smoothstep(edge, edge * 0.35, e);\n float strands = 1.0 - abs(2.0 * fbm(q / R * 2.6 + 9.0, 5) - 1.0);\n dens = cloud * mix(0.6, 1.5, strands * strands) + 0.3 * smoothstep(edge * 1.4, edge * 0.2, e);\n // Fingers trailing down out of the cap.\n for (int j = 0; j < 5; j++) {\n vec2 h = hash22(vec2(float(j) + 0.5, 4.2));\n float x = (h.x - 0.5) * 1.4 * R;\n float len = R * (0.6 + 1.4 * h.y) * smoothstep(0.3, 3.0, tau);\n vec2 sg = segment(q, vec2(x, -0.3 * R), vec2(x * 1.3, -0.3 * R - len));\n dens += exp(-sg.x * sg.x / (R * R * 0.012)) * (1.0 - sg.y * 0.7) * 0.6;\n }\n // The trail the drop left from the surface down to the cloud.\n vec2 tw = p + (vec2(fbm(p * 9.0 + 2.0, 3), 0.0) - 0.5) * 0.04;\n vec2 sg = segment(tw, vec2(0.0, top), c + vec2(0.0, 0.3 * R));\n dens += exp(-sg.x * sg.x / 0.00006) * 0.5 * exp(-tau * 0.35);\n // The ink spreads thinner as it settles, and the water clears before the drop comes round again.\n dens *= mix(1.3, 0.6, grow) * (1.0 - smoothstep(5.6, 7.5, t));\n if (uSurface) dens *= smoothstep(top + 2.0 * px, top - 2.0 * px, p.y);\n hue = smoothstep(0.35, 0.75, fbm(q / R * 1.5 + 11.0, 3));\n }\n // Ink absorbs light: the denser, the deeper its colour.\n vec3 ink = max(mix(uInk, uInk2, hue), vec3(0.02));\n vec3 col = bg * pow(ink, vec3(dens * uDensity * 1.3));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Paper\", values: { uBackground: [0.95, 0.91, 0.84], uInk: [0.1, 0.1, 0.12], uInk2: [0.3, 0.12, 0.1], uSurface: false } },\n { name: \"Crimson\", values: { uInk: [0.62, 0.05, 0.12], uInk2: [0.95, 0.35, 0.2], uSwirl: 1.6 } },\n { name: \"Dark water\", values: { uBackground: [0.08, 0.1, 0.14], uInk: [0.3, 0.9, 1], uInk2: [1, 0.4, 0.9], uDensity: 0.6 } },\n ],\n};\n\nexport const splashCrown: ShaderEffect = {\n kind: \"shader\",\n id: \"splash-crown\",\n name: \"Splash crown\",\n description: \"A milk-drop coronet: a drop falls, a crown of liquid rises with beads on its points and falls back into rippling rings.\",\n category: \"splatter\",\n tags: [\"splatter\", \"liquid\", \"milk\", \"drop\", \"slow-motion\", \"product\"],\n loop: 3,\n source: glsl(\n `// Splash crown: a stylised 2.5D milk-drop coronet, rising and falling back on a 3 s loop.\nuniform vec3 uLiquid; // @control color default=#F6F3EC label=\"Liquid\"\nuniform vec3 uBackground; // @control color default=#1F4E8C label=\"Background\"\nuniform float uHeight; // @control min=0.4 max=1.6 default=1 label=\"Crown height\"\nuniform int uPoints; // @control min=8 max=24 default=16 label=\"Crown points\"\nuniform float uGloss; // @control min=0 max=1 default=0.8 label=\"Gloss\"`,\n HASH,\n `const float SURFACE = -0.2;\nconst float SQUASH = 0.3;\nconst float HIT = 0.6;\n\n// A shaded bead of liquid of radius r at c, painted over col.\nvec3 bead(vec3 col, vec2 p, vec2 c, float r, float px) {\n vec2 d = (p - c) / r;\n float m = clamp(0.5 - (length(d) - 1.0) * r / px, 0.0, 1.0);\n if (m <= 0.0) return col;\n vec3 n = vec3(d, sqrt(max(1.0 - dot(d, d), 0.0)));\n vec3 b = uLiquid * (0.55 + 0.45 * max(dot(n, normalize(vec3(-0.4, 0.6, 0.7))), 0.0));\n b += uGloss * pow(max(dot(n, normalize(vec3(-0.35, 0.5, 1.0))), 0.0), 40.0);\n b = mix(b, uBackground * 0.6 + uLiquid * 0.3, smoothstep(0.75, 1.0, length(d)) * 0.4);\n return mix(col, min(b, vec3(1.0)), m);\n}\n\n// The crown's height at an angle round it: a wall rising into points of varied height.\nfloat crownTop(float theta, float h) {\n float n = float(uPoints);\n float f = theta / 6.28318 * n;\n float id = floor(f);\n float w = abs(fract(f) - 0.5) * 2.0;\n float tall = 0.6 + 0.4 * hash12(vec2(mod(id, n), 2.3));\n return h * (0.68 + 0.5 * tall * pow(1.0 - w, 3.0));\n}\n\n// Droplets on the crown's points, the far ones (back) or the near ones: they bead up, break off and fall.\nvec3 droplets(vec3 col, vec2 p, float tau, float rc, float h, bool back, float px) {\n float n = float(uPoints);\n for (int i = 0; i < 24; i++) {\n if (i >= uPoints) break;\n float th = (float(i) + 0.5) / n * 6.28318;\n float s = sin(th);\n if ((s > 0.0) != back) continue;\n vec2 hh = hash22(vec2(float(i) + 0.5, 7.1));\n float top = crownTop(th, h);\n float r = 0.007 + 0.008 * hh.x;\n float lift = smoothstep(0.08, 0.35, tau);\n float rTip = rc + 0.35 * top;\n vec2 c = vec2(rTip * cos(th), SURFACE + SQUASH * rTip * s + top + r * lift);\n float td = max(tau - (0.35 + 0.15 * hh.y), 0.0);\n // After breaking off: up and outwards, then down under gravity.\n vec2 v = vec2(cos(th) * 0.18, SQUASH * s * 0.18 + 0.35 + 0.2 * hh.y) * uHeight;\n c += v * td - vec2(0.0, 1.6 * td * td);\n if (c.y < SURFACE + SQUASH * rTip * s - 0.01) continue;\n col = bead(col, p, c, r * lift * (1.0 + 0.4 * smoothstep(0.0, 0.2, td)), px);\n }\n return col;\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 = mod(iTime, 3.0);\n float horizon = 0.04;\n // Backdrop and the pool, reflecting the backdrop towards its far edge.\n vec3 col = uBackground * (0.75 + 0.6 * clamp(p.y + 0.2, 0.0, 1.0));\n float fres = smoothstep(horizon - 0.3, horizon, p.y);\n vec3 pool = mix(uLiquid * (0.78 + 0.18 * smoothstep(-0.5, SURFACE, p.y)), uBackground * 0.9 + uLiquid * 0.15, fres * 0.55);\n col = mix(col, pool, smoothstep(horizon + px, horizon - 2.0 * px, p.y));\n float tau = t - HIT;\n if (tau > 0.0) {\n // Ripples spreading over the pool.\n for (int j = 0; j < 3; j++) {\n float rr = 0.09 + (tau - 0.22 * float(j)) * 0.3;\n if (rr < 0.09) continue;\n float de = length(vec2(p.x, (p.y - SURFACE) / SQUASH)) - rr;\n float k = (1.0 - smoothstep(0.4, 2.2, tau)) * (1.0 - 0.25 * float(j)) * step(p.y, horizon);\n col += 0.22 * exp(-de * de / 0.00008) * k;\n col -= uLiquid * 0.12 * exp(-(de + 0.018) * (de + 0.018) / 0.00012) * k;\n }\n }\n float u = tau / 1.15;\n if (u > 0.0 && u < 1.0) {\n float h = 0.2 * uHeight * sin(3.14159 * pow(u, 0.6));\n float rc = 0.06 + 0.1 * (1.0 - exp(-tau * 5.0));\n // The hollow inside the crown.\n float inside = length(vec2(p.x, (p.y - SURFACE) / SQUASH)) / rc;\n col = mix(col, col * 0.78, smoothstep(1.02, 0.95, inside) * smoothstep(0.0, 0.1, h));\n // The crown flares out as it rises: its radius at a pixel's height.\n float r = rc + 0.35 * max(p.y - SURFACE, 0.0);\n float c = p.x / r;\n if (abs(c) < 1.0) {\n float s = sqrt(1.0 - c * c);\n // The far wall, seen from inside.\n float zb = p.y - (SURFACE + SQUASH * r * s);\n float topb = crownTop(atan(s, c), h);\n float mb = clamp(zb / px + 0.5, 0.0, 1.0) * clamp((topb - zb) / px + 0.5, 0.0, 1.0);\n vec3 wallB = uLiquid * (0.6 + 0.25 * (1.0 - s) + 0.15 * smoothstep(0.0, topb, zb));\n col = mix(col, wallB, mb);\n col = droplets(col, p, tau, rc, h, true, px);\n // The near wall: lit from the front, rounder at the sides, thinner and brighter at the top.\n float zf = p.y - (SURFACE - SQUASH * r * s);\n float topf = crownTop(6.28318 - atan(s, c), h);\n float mf = clamp(zf / px + 0.5, 0.0, 1.0) * clamp((topf - zf) / px + 0.5, 0.0, 1.0);\n vec3 wallF = uLiquid * (0.5 + 0.5 * s) * (0.85 + 0.15 * smoothstep(0.0, 0.05, zf));\n wallF += 0.12 * smoothstep(topf - 0.03, topf, zf);\n wallF += uGloss * 0.7 * exp(-(c + 0.45) * (c + 0.45) / 0.01) * smoothstep(0.0, 0.04, zf);\n col = mix(col, min(wallF, vec3(1.0)), mf);\n } else {\n col = droplets(col, p, tau, rc, h, true, px);\n }\n col = droplets(col, p, tau, rc, h, false, px);\n }\n // The falling drop, stretched by its speed.\n if (t < HIT) {\n float y = mix(0.62, SURFACE + 0.02, (t / HIT) * (t / HIT));\n vec2 q = (p - vec2(0.0, y)) * vec2(1.0, 0.8);\n col = bead(col, vec2(0.0, y) + q, vec2(0.0, y), 0.026, px);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Coffee\", values: { uLiquid: [0.42, 0.25, 0.14], uBackground: [0.93, 0.87, 0.78], uGloss: 0.6 } },\n { name: \"Red paint\", values: { uLiquid: [0.86, 0.1, 0.16], uBackground: [0.08, 0.08, 0.1], uPoints: 20, uHeight: 1.3 } },\n ],\n};\n\nexport const gooSplat: ShaderEffect = {\n kind: \"shader\",\n id: \"goo-splat\",\n name: \"Goo splat\",\n description: \"Bright, glossy slime splatting onto the glass with a wobble and running down in drips with fat beads on their ends; clicks splat more.\",\n category: \"splatter\",\n tags: [\"splatter\", \"slime\", \"goo\", \"overlay\", \"click\", \"interactive\", \"playful\"],\n transparent: true,\n loop: 12,\n source: glsl(\n `// Goo splat: jelly blobs hitting the glass, wobbling, and dripping down; on a loop and at clicks.\nuniform vec3 uColorA; // @control color default=#A3E635 label=\"Goo 1\"\nuniform vec3 uColorB; // @control color default=#F472B6 label=\"Goo 2\"\nuniform vec3 uColorC; // @control color default=#22D3EE label=\"Goo 3\"\nuniform float uSize; // @control min=0.3 max=2.5 default=1 label=\"Splat size\"\nuniform float uDrips; // @control min=0 max=1 default=0.8 label=\"Drips\"\nuniform float uFade; // @control min=2 max=11.5 default=9 label=\"Fades after (s)\"\nuniform float uGloss; // @control min=0 max=1 default=0.9 label=\"Gloss\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n SMIN,\n SEGMENT,\n OVER,\n SPLATS,\n `// A splat's signed distance in units of its radius, age seconds after it hit.\nfloat gooShape(vec2 q, float seed, float age) {\n // It lands flattened and wobbles back to round.\n float wob = 0.22 * exp(-age * 5.0) * cos(age * 24.0);\n float grow = 1.0 - exp(-age * 16.0);\n vec2 b = q / vec2(1.0 + wob, 1.0 - wob) / mix(0.4, 1.0, grow);\n float d = length(b) - 0.5;\n for (int k = 0; k < 6; k++) {\n vec2 h = hash22(vec2(seed, float(k) + 0.5));\n float a = h.x * 6.28318;\n d = smin(d, length(b - vec2(cos(a), sin(a)) * (0.35 + 0.3 * h.y)) - 0.18 - 0.14 * hash12(h + seed), 0.2);\n }\n d = (d + (vnoise(b * 3.5 + seed) - 0.5) * 0.08) * mix(0.4, 1.0, grow);\n // Drips sliding down from the bottom, slowing as they thin, each with a bead on its end.\n for (int j = 0; j < 5; j++) {\n vec3 h = vec3(hash22(vec2(seed + 2.7, float(j) + 0.5)), hash12(vec2(float(j) * 3.3, seed)));\n if (h.z > uDrips) continue;\n float x = (h.x - 0.5) * 1.1;\n float len = (0.3 + 1.3 * h.y) * (1.0 - exp(-max(age - 0.25, 0.0) * (0.25 + 0.3 * h.y)));\n float w = 0.05 + 0.05 * h.z;\n vec2 top = vec2(x, -0.25 - 0.2 * (1.0 - abs(h.x - 0.5) * 2.0) * 0.5);\n vec2 sg = segment(q, top, top - vec2(0.0, len));\n d = smin(d, sg.x - w * mix(1.0, 0.7, sg.y), 0.12);\n d = smin(d, length(q - top + vec2(0.0, len + w * 0.4)) - w * 1.45, 0.06);\n }\n // A few round blobs thrown off round it.\n for (int k = 0; k < 5; k++) {\n vec3 h = vec3(hash22(vec2(seed + 9.1, float(k) + 0.5)), hash12(vec2(seed, float(k) * 5.1)));\n float a = h.x * 6.28318;\n d = min(d, length(q - vec2(cos(a), sin(a)) * (0.95 + 0.5 * h.y) * grow) - 0.04 - 0.07 * h.z);\n }\n return d;\n}\n\nvec3 pick(float h) {\n return h < 0.333 ? uColorA : (h < 0.667 ? uColorB : uColorC);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n vec3 light = normalize(vec3(-0.45, 0.6, 1.0));\n vec4 acc = vec4(0.0);\n for (int i = 7; i >= 0; i--) {\n float seed;\n vec4 s = splatAt(i, uDemo, 1.5, seed);\n if (s.w < 0.5) continue;\n float age = iTime - s.z;\n if (age < 0.0 || age > uFade) continue;\n float R = 0.1 * uSize * (0.75 + 0.5 * hash12(vec2(seed, 9.1)));\n vec2 q = (p - s.xy * px) / R;\n // Leave room below for the drips.\n if (abs(q.x) > 1.8 || q.y > 1.8 || q.y < -2.3) continue;\n float eps = px / R;\n float d = gooShape(q, seed, age);\n float cover = clamp(0.5 - d * R / px, 0.0, 1.0);\n if (cover <= 0.0) continue;\n vec2 g = vec2(gooShape(q + vec2(eps, 0.0), seed, age), gooShape(q + vec2(0.0, eps), seed, age)) - d;\n g /= eps;\n vec3 n = normalize(vec3(g * exp(d / 0.12) * 1.6, 1.0));\n vec3 goo = pick(hash12(vec2(seed, 5.3)));\n // Jelly: deeper colour where it is thick, light glowing through near the rim, a wet highlight.\n float thick = smoothstep(0.0, -0.25, d);\n vec3 col = mix(goo * 1.15, goo * 0.62, thick * 0.6) * (0.78 + 0.22 * dot(n, light));\n float fresnel = pow(1.0 - n.z, 2.0);\n col = mix(col, vec3(1.0), fresnel * 0.35);\n // A soft shade inside the lower rim, where the goo curls under.\n col *= 1.0 - 0.25 * smoothstep(0.0, 0.6, -n.y) * (1.0 - thick);\n float spec = pow(max(dot(reflect(-light, n), vec3(0.0, 0.0, 1.0)), 0.0), 40.0);\n float sheen = pow(max(dot(reflect(-light, n), vec3(0.0, 0.0, 1.0)), 0.0), 6.0);\n col = min(col + uGloss * (spec * 0.9 + sheen * 0.12), vec3(1.0));\n float fade = 1.0 - smoothstep(uFade * 0.6, uFade, age);\n acc = over(acc, col, cover * fade * mix(0.97, 0.86, thick));\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Slime\", values: { uColorA: [0.52, 0.9, 0.16], uColorB: [0.4, 0.85, 0.2], uColorC: [0.65, 0.95, 0.3] } },\n { name: \"Bubblegum\", values: { uColorA: [1, 0.55, 0.78], uColorB: [0.75, 0.6, 1], uColorC: [0.5, 0.85, 1], uDrips: 0.5 } },\n { name: \"Big drippy\", values: { uSize: 1.8, uDrips: 1, uFade: 11 } },\n ],\n};\n\nexport const paintRoller: ShaderEffect = {\n kind: \"shader\",\n id: \"paint-roller\",\n name: \"Paint roller\",\n description: \"A paint roller sweeping down the frame, laying a new picture or colour over the old with a stippled, textured edge and thin drips running ahead.\",\n category: \"splatter\",\n video: \"transition\",\n tags: [\"splatter\", \"paint\", \"transition\", \"image\", \"reveal\", \"slideshow\"],\n loop: 6,\n source: glsl(\n `// Paint roller: a roller paints the To picture (or a colour) over the From one, top to bottom, and back again.\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 uUsePaint; // @control default=false label=\"Paint a colour\"\nuniform vec3 uPaint; // @control color default=#F2C14E label=\"Paint colour\"\nuniform float uStipple; // @control min=0 max=1 default=0.6 label=\"Stipple\"\nuniform float uDrips; // @control min=0 max=1 default=0.6 label=\"Drips\"\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 HASH,\n NOISE,\n FBM,\n PICTURE,\n `vec4 paintOf(sampler2D tex, vec2 uv) {\n return uUsePaint ? vec4(uPaint, 1.0) : pictureRGBA(tex, uv);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float px = 1.0 / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 P = vec2(uv.x * aspect, uv.y);\n // Two passes a loop: To over From, then From back over To.\n float t = mod(iTime, 6.0);\n bool second = uAnimate && t >= 3.0;\n float prog = uAnimate ? smoothstep(0.25, 2.75, t - (second ? 3.0 : 0.0)) : uProgress;\n vec4 below = second ? paintOf(uTo, uv) : pictureRGBA(uFrom, uv);\n vec4 fresh = second ? pictureRGBA(uFrom, uv) : paintOf(uTo, uv);\n const float RR = 0.04;\n float edge = mix(1.0 + 2.2 * RR, -0.06, prog);\n float seed = second ? 7.0 : 0.0;\n // The roller's edge: wavy where the nap pressed unevenly.\n float nap = vnoise(vec2(P.x * 40.0, P.y * 25.0) + seed);\n float e = edge + 0.012 * (fbm(vec2(P.x * 9.0 + seed, 1.0), 3) - 0.5) + 0.004 * (nap - 0.5);\n float dist = P.y - e;\n float cover = clamp(dist / px + 0.5, 0.0, 1.0);\n // Stipple: near the edge the paint only catches the high points of the wall.\n float grain = vnoise(P * 260.0 + seed) * 0.6 + vnoise(P * 90.0 + seed) * 0.4;\n float s = clamp(dist / (0.09 * uStipple + 1e-3), 0.0, 1.0);\n cover *= smoothstep(-0.06, 0.06, s * 1.2 - grain);\n // Specks flicked ahead of the roller.\n vec2 cell = floor(P * 55.0);\n vec2 hs = hash22(cell + seed);\n float speck = length(P * 55.0 - cell - hs) - 0.06 - 0.12 * hs.x * hs.y;\n float ahead = smoothstep(-0.08, 0.0, dist) * step(0.72, hash12(cell + 3.1 + seed)) * uStipple;\n cover = max(cover, clamp(0.5 - speck / (55.0 * px), 0.0, 1.0) * ahead);\n vec4 col = mix(below, fresh, cover);\n // Wet paint just laid: a sheen and the roller's texture, fading as it dries.\n float wet = exp(-max(dist, 0.0) / 0.12) * step(0.0, dist);\n col.rgb *= 1.0 + 0.08 * (nap - 0.5) * wet;\n col.rgb += 0.05 * wet;\n // The roller, sitting just below the edge, with its soft shadow on the wall ahead.\n float yr = edge - RR + 0.005;\n float under = yr - RR - P.y;\n col.rgb *= 1.0 - 0.35 * exp(-max(under, 0.0) / 0.02) * step(0.0, under);\n // Thin drips of paint hanging from the roller, each ending in a bead.\n float column = floor(P.x / aspect * 16.0);\n vec2 hd = hash22(vec2(column + seed, 2.9));\n if (hd.y < uDrips) {\n float x = (column + 0.25 + 0.5 * hd.x) / 16.0 * aspect;\n float len = 0.015 + 0.1 * hash12(vec2(column, seed + 5.0)) * uDrips * smoothstep(0.0, 0.25, prog);\n float w = 0.0025 + 0.002 * hd.x;\n vec2 a = vec2(x, yr - RR * 0.7);\n vec2 b = vec2(x, a.y - len);\n float hh = clamp((a.y - P.y) / len, 0.0, 1.0);\n float dd = length(P - mix(a, b, hh)) - w * mix(1.4, 0.8, hh);\n dd = min(dd, length(P - b) - w * 1.7);\n float drip = clamp(0.5 - dd / px, 0.0, 1.0);\n vec3 paint = second ? pictureRGBA(uFrom, vec2(uv.x, clamp(edge, 0.0, 1.0))).rgb : paintOf(uTo, vec2(uv.x, clamp(edge, 0.0, 1.0))).rgb;\n paint *= 0.85 + 0.4 * exp(-pow((P.x - x + w * 0.4) / w, 2.0));\n col = mix(col, vec4(min(paint, vec3(1.0)), 1.0), drip);\n }\n float v = (P.y - yr) / RR;\n if (abs(v) < 1.0) {\n float roll = asin(clamp(v, -1.0, 1.0)) + edge * 40.0;\n float fuzz = vnoise(vec2(P.x * 140.0, roll * 5.0)) * 0.6 + vnoise(vec2(P.x * 50.0, roll * 2.0)) * 0.4;\n // Loaded with the paint it lays: the new picture's colours along the edge, mixed together.\n vec3 load = vec3(0.0);\n for (int k = 0; k < 6; k++) {\n vec2 at = vec2((float(k) + 0.5) / 6.0, clamp(edge + 0.04, 0.0, 1.0));\n load += (second ? pictureRGBA(uFrom, at).rgb : paintOf(uTo, at).rgb) / 6.0;\n }\n vec3 r = mix(load, vec3(0.95), 0.1) * (0.35 + 0.65 * sqrt(1.0 - v * v)) * (0.8 + 0.4 * fuzz);\n r += 0.12 * pow(max(1.0 - abs(v - 0.45) * 3.0, 0.0), 2.0);\n float m = clamp((1.0 - abs(v)) * RR / px, 0.0, 1.0);\n col = mix(col, vec4(min(r, vec3(1.0)), 1.0), m);\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Yellow wall\", values: { uUsePaint: true, uPaint: [0.95, 0.76, 0.31] } },\n { name: \"Clean\", values: { uStipple: 0.15, uDrips: 0 } },\n { name: \"Drippy\", values: { uStipple: 1, uDrips: 1 } },\n ],\n};\n\nexport const waterSplash: ShaderEffect = {\n kind: \"shader\",\n id: \"water-splash\",\n name: \"Water splash\",\n description: \"Drops falling onto a water line and throwing up a jet and clear, glinting droplets that arc back down into small ripples.\",\n category: \"splatter\",\n tags: [\"splatter\", \"water\", \"overlay\", \"drops\", \"liquid\", \"fresh\"],\n transparent: true,\n loop: 8,\n source: glsl(\n `// Water splash: drops land on a surface line, throwing up a jet and droplets that fall back, with ripples.\nuniform vec3 uTint; // @control color default=#CDEBFF label=\"Water\"\nuniform float uLevel; // @control min=0.05 max=0.7 default=0.25 label=\"Surface height\"\nuniform float uSize; // @control min=0.4 max=2 default=1 label=\"Splash size\"\nuniform int uDrops; // @control min=4 max=40 default=26 label=\"Droplets\"\nuniform float uGravity; // @control min=0.5 max=2 default=1 label=\"Gravity\"\nuniform bool uSurface; // @control default=true label=\"Show surface\"`,\n HASH,\n SEGMENT,\n OVER,\n `// A clear bead (a capsule from a to b, radius r): a faint tinted body, a darker rim, a caustic and a glint.\nvec4 waterBead(vec4 acc, vec2 p, vec2 a, vec2 b, float r, float k, float px) {\n vec2 sg = segment(p, a, b);\n float d = sg.x - r;\n float m = clamp(0.5 - d / px, 0.0, 1.0) * k;\n if (m <= 0.0) return acc;\n vec2 c = mix(a, b, sg.y);\n vec2 n = (p - c) / max(r, 1e-5);\n float rim = smoothstep(0.5, 1.0, length(n));\n float glint = 1.0 - smoothstep(0.0, 0.35, length(n - vec2(-0.35, 0.4)));\n float caustic = 1.0 - smoothstep(0.0, 0.55, length(n - vec2(0.15, -0.45)));\n acc = over(acc, uTint, m * 0.3);\n acc = over(acc, uTint * 0.25, rim * m * 0.45);\n acc = over(acc, mix(uTint, vec3(1.0), 0.7), caustic * m * 0.45);\n return over(acc, vec3(1.0), glint * m * 0.95);\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 / iResolution.y;\n float level = uLevel;\n float g = 2.0 * uGravity;\n vec4 acc = vec4(0.0);\n if (uSurface) {\n // The water below the line, and the line itself catching the light.\n float below = level - p.y;\n acc = over(acc, uTint, 0.16 * step(0.0, below) * exp(-max(below, 0.0) / 0.25));\n acc = over(acc, vec3(1.0), 0.6 * exp(-abs(below) / (1.2 * px)));\n }\n const float PERIOD = 1.0;\n float t = mod(iTime, 8.0);\n for (int i = -1; i < 3; i++) {\n float k = floor(t / PERIOD) - float(i);\n float slot = mod(k, 8.0);\n float tau = t - k * PERIOD;\n vec2 h = hash22(vec2(slot * 1.71 + 0.3, 5.9));\n vec2 o = vec2((0.12 + 0.76 * h.x) * aspect, level);\n float size = uSize * (0.7 + 0.5 * h.y);\n if (tau < 0.0) {\n // The drop falling in.\n float tb = -tau;\n if (tb > 0.4) continue;\n vec2 c = o + vec2(0.0, 3.2 * tb * tb + 0.01);\n acc = waterBead(acc, p, c, c + vec2(0.0, 0.03 + 0.08 * tb), 0.008 * size, 1.0, px);\n continue;\n }\n if (tau > 2.2) continue;\n // Ripples on the surface: flattened rings spreading out under the line.\n for (int j = 0; j < 2; j++) {\n float rr = (tau - 0.3 * float(j)) * 0.22 * size;\n if (rr <= 0.0) continue;\n float de = length(vec2(p.x - o.x, (p.y - level + 0.012) / 0.18)) - rr;\n float fade = (1.0 - smoothstep(0.3, 2.2, tau)) * step(p.y, level);\n acc = over(acc, vec3(1.0), 0.55 * exp(-de * de / (4.0 * px * px)) * fade);\n }\n // The jet: a column shooting up and breaking into a drop.\n if (tau < 0.7) {\n float hj = 0.2 * size * sin(3.14159 * tau / 0.7);\n acc = waterBead(acc, p, o, o + vec2(0.0, hj), 0.012 * size * (1.0 - 0.5 * tau / 0.7), 1.0, px);\n }\n // Droplets flung up and out, falling back under gravity.\n for (int j = 0; j < 40; j++) {\n if (j >= uDrops) break;\n vec3 hh = vec3(hash22(vec2(float(j) + 0.5, slot * 3.7 + 1.0)), hash12(vec2(slot + 0.3, float(j) * 1.9)));\n float a = (hh.x - 0.5) * 1.9;\n float speed = (0.55 + 0.65 * hh.y) * sqrt(size) * sqrt(uGravity);\n vec2 v = vec2(sin(a) * 0.8, cos(a)) * speed;\n float td = tau - 0.03 * hh.z;\n if (td <= 0.0) continue;\n vec2 c = o + v * td - vec2(0.0, 0.5 * g * td * td);\n if (c.y < level) continue;\n vec2 vel = v - vec2(0.0, g * td);\n if (abs(p.x - c.x) > 0.06 || abs(p.y - c.y) > 0.06) continue;\n float r = (0.0035 + 0.009 * hh.z * hh.z) * size;\n acc = waterBead(acc, p, c, c - vel * 0.022, r, smoothstep(level, level + 0.01, c.y), px);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Big splash\", values: { uSize: 1.8, uDrops: 40, uGravity: 0.8 } },\n { name: \"No surface\", values: { uSurface: false, uLevel: 0.15, uTint: [1, 1, 1] } },\n ],\n};\n\n/** The splatter shaders: paint, ink, liquid crowns, goo, a paint roller and water. */\nexport const splatterShaders: ShaderEffect[] = [paintSplatter, inkSplash, splashCrown, gooSplat, paintRoller, waterSplash];\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 * Bubbles. Soap bubbles and bubble wrap read the pointer built-ins the\n * wrapper declares (`iClicks[8]`: xy pixels, z the `iTime` of the click, w 1\n * for a click), and play a demo while idle that a `uDemo` control turns off.\n * Soap bubbles are a transparent overlay: straight colour with coverage alpha.\n */\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 soapBubbles: ShaderEffect = {\n kind: \"shader\",\n id: \"soap-bubbles\",\n name: \"Soap bubbles\",\n description: \"Iridescent soap bubbles drifting and wobbling, with swirling thin-film colours, a window highlight and clear centres, popping into droplets at clicks or on their own.\",\n category: \"bubble\",\n tags: [\"bubble\", \"soap\", \"overlay\", \"iridescent\", \"interactive\", \"click\", \"playful\"],\n transparent: true,\n source: glsl(\n `// Soap bubbles: thin-film bubbles drifting up and popping at clicks or when their time is up.\nuniform int uCount; // @control min=1 max=16 default=9 label=\"Bubbles\"\nuniform float uSize; // @control min=0.3 max=2 default=1 label=\"Size\"\nuniform float uRise; // @control min=0 max=0.3 default=0.06 label=\"Rise speed\"\nuniform float uLife; // @control min=2 max=20 default=8 label=\"Lifetime\"\nuniform float uWobble; // @control min=0 max=2 default=1 label=\"Wobble\"\nuniform float uThickness; // @control min=150 max=1200 default=480 label=\"Film thickness (nm)\"\nuniform float uSwirl; // @control min=0 max=3 default=1 label=\"Swirl\"\nuniform float uIridescence; // @control min=0 max=1 default=1 label=\"Iridescence\"\nuniform float uOpacity; // @control min=0.2 max=1 default=0.85 label=\"Opacity\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n OVER,\n `// Bubble i at time t: centre and radius (xyz, in screen heights) and which life it is on (w).\n// age is the seconds into that life, life how long it lasts before popping on its own.\nvec4 bubbleAt(int i, float t, out float age, out float life) {\n vec2 h = hash22(vec2(float(i) * 3.17 + 0.5, 11.3));\n life = uLife * (0.7 + 0.6 * h.x);\n float period = life + 0.8 + 1.5 * h.y;\n float local = t + h.y * period * 7.0;\n float k = floor(local / period);\n age = local - k * period;\n vec2 r = hash22(vec2(float(i) * 1.91 + k * 7.37, k + 2.1));\n float aspect = iResolution.x / iResolution.y;\n float radius = uSize * mix(0.05, 0.12, r.y * r.y);\n vec2 c = vec2((0.08 + 0.84 * r.x) * aspect, 0.1 + 0.45 * hash12(r * 13.1 + 0.7));\n c.y += uRise * age;\n c.x += 0.05 * uWobble * sin(age * (0.7 + r.y) + r.x * 6.28) + 0.02 * sin(age * 1.9 + k);\n return vec4(c, radius * smoothstep(0.0, 0.6, age), k);\n}\n\n// Click j, newest first; idle, the demo pokes a bubble every couple of seconds.\nvec4 clickAt(int j, bool demo) {\n if (!demo || iClicks[0].w > 0.5) return iClicks[j];\n float k = floor(iTime / 2.2) - float(j);\n float tc = k * 2.2;\n int b = int(hash12(vec2(k, 5.3)) * float(uCount));\n float age;\n float life;\n vec4 at = bubbleAt(b, tc, age, life);\n return vec4(at.xy * iResolution.y, tc, 1.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n vec4 acc = vec4(0.0);\n // The clicks are the same for every bubble, so look them up once.\n vec4 clicks[8];\n for (int j = 0; j < 8; j++) clicks[j] = clickAt(j, uDemo);\n // Nothing of a bubble reaches further than this from where it is now: its pop (up to 0.7 s\n // ago, so it has drifted at most this far since) throws droplets out to 3.6 radii + 0.1.\n float drift = 0.7 * (uRise + 0.085 * uWobble + 0.04);\n float far = max(uSize * 0.12, 0.01) * 3.6 + 0.1 + drift + 2.0 * px;\n for (int i = 0; i < 16; i++) {\n if (i >= uCount) break;\n float age;\n float life;\n vec4 b = bubbleAt(i, iTime, age, life);\n vec2 d0 = p - b.xy;\n if (dot(d0, d0) > far * far) continue;\n float birth = iTime - age;\n // It pops when its life is up, or at the first click that lands on it.\n float popAt = birth + life;\n for (int j = 0; j < 8; j++) {\n vec4 c = clicks[j];\n if (c.w < 0.5 || c.z < birth || c.z > iTime || c.z >= popAt) continue;\n float a2;\n float l2;\n vec4 then = bubbleAt(i, c.z, a2, l2);\n if (then.w != b.w || a2 >= l2) continue;\n if (length(c.xy * px - then.xy) < then.z * 1.05 + 0.01) popAt = c.z;\n }\n if (iTime < popAt) {\n float R = b.z;\n vec2 d = p - b.xy;\n if (R < 1e-4 || dot(d, d) > R * R * 1.4) continue;\n // The film wobbles as it drifts.\n float th = atan(d.y, d.x);\n float fi = float(i);\n float wob = 1.0 + uWobble * (0.025 * sin(3.0 * th + iTime * 2.3 + fi) + 0.02 * sin(2.0 * th - iTime * 1.7 + fi * 2.0));\n vec2 n2 = d / (R * wob);\n float r = length(n2);\n float edge = px / R;\n float inside = 1.0 - smoothstep(1.0 - edge, 1.0 + edge, r);\n if (inside <= 0.0) continue;\n float rr = min(r, 1.0);\n float z = sqrt(1.0 - rr * rr);\n // Thin film: a swirling thickness that drains toward the bottom.\n float sw = iTime * 0.25 * uSwirl + fi * 1.7;\n vec2 q = n2 * 1.6 + vec2(sin(sw), cos(sw * 0.8)) * 1.2;\n float flow = vnoise(q * 1.8 + fi * 3.1) + 0.5 * vnoise(q * 3.7 - vec2(sw, -sw) * 0.6);\n float thick = uThickness * (0.35 + 0.55 * flow + 0.3 * (0.5 - 0.5 * n2.y));\n // Light reflected off both faces interferes: a colour per wavelength, shifting with angle.\n float cosT = sqrt(1.0 - (1.0 - z * z) / 1.77);\n vec3 film = 0.5 - 0.5 * cos(6.28318 * 2.0 * 1.33 * thick * cosT / vec3(650.0, 532.0, 450.0));\n film = mix(vec3(0.8), clamp((film - 0.5) * 1.7 + 0.55, 0.0, 1.0), uIridescence);\n float fres = 0.06 + 0.94 * pow(1.0 - z, 3.0);\n vec3 col = film;\n float a = clamp(0.06 + 0.22 * dot(film, vec3(0.333)) + fres, 0.0, 1.0);\n // A bright rim.\n float rim = smoothstep(0.84, 0.99, r);\n col = mix(col, vec3(1.0), rim * 0.3);\n a = max(a, rim * 0.75);\n // A window reflected top left, its panes curved by the bubble, and a glint bottom right.\n vec2 wq = (n2 - vec2(-0.36, 0.38)) * (1.0 + 0.5 * dot(n2, n2));\n wq.x += 0.22 * wq.y;\n vec2 e = abs(wq) - vec2(0.15, 0.12);\n float box = length(max(e, 0.0)) + min(max(e.x, e.y), 0.0) - 0.04;\n float win = 1.0 - smoothstep(-edge * 2.0, edge * 2.0 + 0.012, box);\n float bars = min(smoothstep(0.008, 0.022, abs(wq.x)), smoothstep(0.008, 0.022, abs(wq.y)));\n win *= mix(0.3, 1.0, bars);\n vec2 s = n2 - vec2(0.45, -0.48);\n float glint = exp(-dot(s, s) / 0.004) * 0.7;\n col = mix(col, vec3(1.0), clamp(win + glint, 0.0, 1.0));\n a = max(a, max(win * 0.95, glint));\n acc = over(acc, col, a * inside * uOpacity);\n } else {\n // Popped: a ring snapping outward and droplets thrown off, falling as they shrink.\n float dt = iTime - popAt;\n if (dt > 0.7) continue;\n float a2;\n float l2;\n vec4 then = bubbleAt(i, popAt, a2, l2);\n float R = max(then.z, 0.01);\n vec2 d = p - then.xy;\n float reach = R * 3.6 + 0.1;\n if (dot(d, d) > reach * reach) continue;\n float ringW = px * 1.5 + R * 0.03;\n float x = (length(d) - R * (1.0 + dt * 2.0)) / ringW;\n float ring = exp(-x * x) * (1.0 - smoothstep(0.0, 0.18, dt));\n acc = over(acc, vec3(1.0), ring * 0.8 * uOpacity);\n float fade = 1.0 - dt / 0.7;\n for (int k = 0; k < 12; k++) {\n vec2 hh = hash22(vec2(float(k) + float(i) * 13.0, then.w * 3.3 + 1.0));\n float ang = (float(k) + hh.x * 0.6) / 12.0 * 6.28318;\n vec2 pos = then.xy + vec2(cos(ang), sin(ang)) * R * (1.0 + (0.6 + hh.y) * dt * 2.2) - vec2(0.0, 0.5 * dt * dt);\n float dr = R * 0.05 * (0.6 + hh.y) * fade + px;\n float drop = 1.0 - smoothstep(dr - px, dr + px, length(p - pos));\n vec3 tint = 0.5 + 0.5 * cos(6.28318 * (hh.x + vec3(0.0, 0.33, 0.67)));\n acc = over(acc, mix(vec3(1.0), tint, 0.35), drop * uOpacity * fade);\n }\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Big and slow\", values: { uCount: 5, uSize: 1.7, uRise: 0.03, uLife: 14, uWobble: 1.4 } },\n { name: \"Golden film\", values: { uThickness: 900, uSwirl: 0.6 } },\n { name: \"Many small\", values: { uCount: 16, uSize: 0.5, uRise: 0.1, uLife: 5 } },\n ],\n};\n\nexport const underwaterBubbles: ShaderEffect = {\n kind: \"shader\",\n id: \"underwater-bubbles\",\n name: \"Underwater bubbles\",\n description: \"Bubbles rising and wobbling over a picture tinted blue-green, with caustic light rippling across it.\",\n category: \"bubble\",\n video: \"filter\",\n tags: [\"bubble\", \"image\", \"underwater\", \"water\", \"caustics\", \"ocean\"],\n source: glsl(\n `// Underwater bubbles: a picture under water, bubbles rising through it and caustic light playing across it.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uCount; // @control min=4 max=40 default=22 label=\"Bubbles\"\nuniform float uSize; // @control min=0.3 max=2.5 default=1 label=\"Bubble size\"\nuniform float uSpeed; // @control min=0 max=2 default=0.6 label=\"Rise speed\"\nuniform vec3 uTint; // @control color default=#0E7C86 label=\"Water\"\nuniform float uTintAmount; // @control min=0 max=1 default=0.55 label=\"Tint\"\nuniform float uCaustics; // @control min=0 max=2 default=1 label=\"Caustics\"\nuniform float uWaviness; // @control min=0 max=1 default=0.35 label=\"Waviness\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `// Caustic light: a web of bright lines, slowly shifting.\nfloat caustic(vec2 uv, float t) {\n vec2 p = uv * 6.28318 - 250.0;\n vec2 i = p;\n float c = 1.0;\n for (int n = 0; n < 4; n++) {\n float tt = t * (1.0 - 3.5 / float(n + 1));\n i = p + vec2(cos(tt - i.x) + sin(tt + i.y), sin(tt - i.y) + cos(tt + i.x));\n c += 1.0 / length(vec2(p.x / (sin(i.x + tt) / 0.005), p.y / (cos(i.y + tt) / 0.005)));\n }\n c /= 4.0;\n c = 1.17 - pow(c, 1.4);\n return min(pow(abs(c), 8.0), 1.5);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = fragCoord * px;\n float aspect = iResolution.x / iResolution.y;\n // The water bends the view a little.\n vec2 wave = uWaviness * 0.006 * vec2(sin(p.y * 14.0 + iTime * 1.3) + 0.5 * sin(p.x * 23.0 - iTime * 1.7), cos(p.x * 12.0 - iTime * 1.1));\n vec2 lens = vec2(0.0);\n float cover = 0.0;\n float rim = 0.0;\n float shine = 0.0;\n for (int i = 0; i < 40; i++) {\n if (i >= uCount) break;\n vec2 h = hash22(vec2(float(i) * 2.13 + 0.7, 4.1));\n float h3 = hash12(h * 37.0 + 1.3);\n float R = uSize * mix(0.012, 0.045, h3 * h3);\n // Big bubbles rise faster and sway wider.\n float speed = uSpeed * (0.12 + 3.0 * R);\n float travel = 1.15 + 4.0 * R;\n float y = mod(h.y * travel + iTime * speed, travel) - 2.0 * R - 0.05;\n float x = h.x * aspect + 0.03 * sin(iTime * (1.5 + h3) + h.y * 30.0 + y * 8.0) * (0.5 + 10.0 * R);\n vec2 d = p - vec2(x, y);\n // Squashing and stretching as they wobble up.\n float sq = 1.0 + 0.12 * sin(iTime * 9.0 * (0.6 + h3) + h.x * 20.0) * min(1.0, R * 30.0);\n d *= vec2(1.0 / sq, sq);\n float r = length(d) / R;\n float edge = px / R;\n if (r > 1.0 + 2.0 * edge) continue;\n vec2 n = d / R;\n float rr = min(r, 1.0);\n float z = sqrt(1.0 - rr * rr);\n cover = 1.0 - smoothstep(1.0 - edge, 1.0 + edge, r);\n // A bubble is a small lens that flips what is behind it.\n lens = -n * R * 0.7;\n rim = pow(1.0 - z, 2.5);\n vec2 s = n - vec2(-0.35, 0.4);\n shine = exp(-dot(s, s) / 0.025) + 0.4 * exp(-dot(n - vec2(0.4, -0.45), n - vec2(0.4, -0.45)) / 0.01);\n }\n vec2 suv = uv + wave + lens * vec2(1.0 / aspect, 1.0) * cover;\n vec4 pic = pictureRGBA(uImage, suv);\n vec3 col = pic.rgb;\n // Deeper is bluer and darker; near the surface it is lighter.\n vec3 water = uTint * (0.45 + 0.7 * uv.y);\n col = mix(col, water + col * uTint * 0.9, uTintAmount * (0.65 + 0.35 * (1.0 - uv.y)));\n float light = caustic(p * 0.9 + wave * 20.0, iTime * 0.5);\n col += uCaustics * light * 0.3 * vec3(0.8, 1.0, 0.95) * (0.35 + 0.65 * uv.y);\n // Soft shafts of light from the surface.\n float shafts = vnoise(vec2(p.x * 5.0 + p.y * 1.2, iTime * 0.25));\n col += uCaustics * 0.1 * shafts * uv.y * uv.y * vec3(0.8, 1.0, 1.0);\n col = mix(col, col * 1.1 + 0.04, cover * 0.5);\n col += cover * (rim * 0.85 * vec3(0.85, 1.0, 1.0) + shine * 0.9);\n fragColor = vec4(col, max(pic.a, cover));\n}`,\n ),\n presets: [\n { name: \"Tropical\", values: { uTint: [0.1, 0.65, 0.75], uTintAmount: 0.4, uCaustics: 1.4 } },\n { name: \"Deep\", values: { uTint: [0.03, 0.18, 0.35], uTintAmount: 0.8, uCaustics: 0.5, uCount: 12, uSpeed: 0.4 } },\n { name: \"Fish tank\", values: { uCount: 40, uSize: 0.6, uSpeed: 1.2, uTintAmount: 0.3 } },\n ],\n};\n\nexport const fizz: ShaderEffect = {\n kind: \"shader\",\n id: \"fizz\",\n name: \"Fizz\",\n description: \"Carbonation: tiny bubbles streaming up in columns from nucleation points, growing and speeding up as they rise through the drink.\",\n category: \"bubble\",\n tags: [\"bubble\", \"fizz\", \"drink\", \"champagne\", \"soda\", \"carbonation\", \"background\"],\n source: glsl(\n `// Fizz: bubble streams rising from nucleation points, accelerating and growing, plus a few loose bubbles.\nuniform vec3 uDrink; // @control color default=#E3B23C label=\"Drink\"\nuniform vec3 uBubble; // @control color default=#FFF7DC label=\"Bubbles\"\nuniform int uStreams; // @control min=1 max=24 default=12 label=\"Streams\"\nuniform float uRate; // @control min=2 max=30 default=12 label=\"Bubbles per second\"\nuniform float uAccel; // @control min=0.1 max=3 default=1 label=\"Acceleration\"\nuniform float uSize; // @control min=0.3 max=2.5 default=1 label=\"Size\"\nuniform float uWiggle; // @control min=0 max=2 default=1 label=\"Wiggle\"\nuniform int uLoose; // @control min=0 max=30 default=12 label=\"Loose bubbles\"`,\n HASH,\n `// A bubble at p's offset d from its centre, radius R: how much it covers, and its colour over col.\nvec3 bubble(vec3 col, vec2 d, float R, float px) {\n float dl = length(d);\n float cover = 1.0 - smoothstep(R - px, R + px, dl);\n if (cover <= 0.0) return col;\n float rim = smoothstep(0.35 * R, R, dl);\n col = mix(col, uBubble, cover * (0.2 + 0.7 * rim));\n vec2 s = d + vec2(0.3, -0.3) * R;\n col = mix(col, vec3(1.0), cover * (1.0 - smoothstep(0.0, 0.3 * R + px, length(s))));\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 vec2 uv = fragCoord / iResolution.xy;\n float aspect = iResolution.x / iResolution.y;\n // The drink, lit through the glass: darker below, with a soft highlight band.\n vec3 col = uDrink * (0.6 + 0.5 * uv.y);\n col += uDrink * 0.25 * exp(-(uv.x - 0.3) * (uv.x - 0.3) / 0.012);\n col *= 1.0 - 0.25 * pow(abs(uv.x - 0.5) * 2.0, 3.0);\n const float v0 = 0.03;\n float acc = 0.12 * uAccel;\n for (int s = 0; s < 24; s++) {\n if (s >= uStreams) break;\n vec2 h = hash22(vec2(float(s) * 4.7 + 1.0, 8.3));\n float hs = hash12(h * 29.0 + 3.0);\n vec2 site = vec2((0.04 + 0.92 * h.x) * aspect, 0.02 + 0.4 * h.y * h.y);\n float dy = p.y - site.y;\n if (dy < -0.02 || abs(p.x - site.x) > 0.03 * uSize + 0.02 * uWiggle) continue;\n float rate = uRate * (0.5 + hs);\n // The age a bubble has when it reaches this height: y = v0 t + a t² / 2.\n float ageHere = (-v0 + sqrt(v0 * v0 + 2.0 * acc * max(dy, 0.0))) / acc;\n float nf = floor((iTime - ageHere) * rate - hs * 7.0);\n for (int k = -1; k <= 1; k++) {\n float n = nf + float(k);\n if (hash12(vec2(n, float(s) + 0.5)) < 0.15) continue;\n float age = iTime - (n + hs * 7.0) / rate;\n if (age < 0.0) continue;\n float y = site.y + v0 * age + 0.5 * acc * age * age;\n float R = uSize * (0.0015 + 0.0035 * sqrt(max(y - site.y, 0.0) * 3.0));\n float x = site.x + uWiggle * 0.004 * sin(age * 14.0 + n * 1.3) * min(age, 1.0);\n col = bubble(col, p - vec2(x, y), R, px);\n }\n }\n // Loose bubbles drifting up on their own.\n for (int i = 0; i < 30; i++) {\n if (i >= uLoose) break;\n vec2 h = hash22(vec2(float(i) * 1.9 + 0.3, 2.2));\n float hs = hash12(h * 13.0);\n float R = uSize * mix(0.002, 0.006, hs);\n float y = mod(h.y * 1.2 + iTime * (0.05 + 0.1 * hs) * uAccel, 1.2) - 0.1;\n float x = h.x * aspect + 0.01 * uWiggle * sin(iTime * (1.0 + hs) + h.y * 20.0);\n col = bubble(col, p - vec2(x, y), R, px);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Cola\", values: { uDrink: [0.22, 0.08, 0.03], uBubble: [0.9, 0.75, 0.6], uRate: 20, uStreams: 18, uLoose: 24 } },\n { name: \"Sparkling water\", values: { uDrink: [0.62, 0.82, 0.92], uBubble: [1, 1, 1], uSize: 1.4, uAccel: 1.4 } },\n { name: \"Rosé\", values: { uDrink: [0.95, 0.55, 0.55], uBubble: [1, 0.92, 0.9], uRate: 8 } },\n ],\n};\n\nexport const foam: ShaderEffect = {\n kind: \"shader\",\n id: \"foam\",\n name: \"Foam\",\n description: \"Dense suds of packed bubbles in many sizes, shaded and faintly iridescent, settling slowly as some pop and their neighbours close in.\",\n category: \"bubble\",\n tags: [\"bubble\", \"foam\", \"suds\", \"soap\", \"texture\", \"background\"],\n source: glsl(\n `// Foam: a weighted Voronoi (power diagram) of bubbles, each shaded as a shallow dome with dark walls.\nuniform vec3 uBase; // @control color default=#F2F5FA label=\"Bubbles\"\nuniform vec3 uWall; // @control color default=#6D7E96 label=\"Shadows\"\nuniform float uScale; // @control min=3 max=30 default=9 label=\"Scale\"\nuniform float uVariety; // @control min=0 max=1 default=0.7 label=\"Size variety\"\nuniform float uPopping; // @control min=0 max=1 default=0.3 label=\"Popping\"\nuniform float uSettle; // @control min=0 max=1 default=0.3 label=\"Settling\"\nuniform float uIridescence; // @control min=0 max=1 default=0.45 label=\"Iridescence\"`,\n HASH,\n `// Cell g's bubble: centre (xy, in cell units) and power weight (z). A bubble that has just\n// popped has a negative weight, so its neighbours close over it as it grows back. since is the\n// seconds since it last popped.\nvec3 cellAt(vec2 g, out float since) {\n vec2 h = hash22(g);\n float h3 = hash12(g + 17.3);\n vec2 c = g + 0.5 + 0.6 * (h - 0.5) + 0.08 * vec2(sin(iTime * 0.3 + h.x * 6.28), cos(iTime * 0.27 + h.y * 6.28));\n float w = uVariety * 0.4 * h3 * h3;\n since = 1e3;\n if (hash12(g + 5.1) < uPopping) {\n float period = 9.0 * (0.7 + 0.6 * hash12(g + 9.7));\n float ph = fract(iTime / period + h.x * 3.1);\n since = ph * period;\n w = mix(-0.5, w, smoothstep(0.0, 0.45, ph));\n }\n return vec3(c, w);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale + vec2(0.0, iTime * uSettle * 0.15);\n float px = uScale / iResolution.y;\n vec2 g0 = floor(p);\n // The bubble this point is in: the nearest by power distance.\n float best = 1e9;\n vec2 bc = vec2(0.0);\n vec2 bg = vec2(0.0);\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 g = g0 + vec2(float(i), float(j));\n float s;\n vec3 c = cellAt(g, s);\n vec2 d = p - c.xy;\n float pd = dot(d, d) - c.z;\n if (pd < best) {\n best = pd;\n bc = c.xy;\n bg = g;\n }\n }\n }\n // How far it is to the nearest wall (each wall is a straight bisector), and pops nearby.\n float wall = 1e9;\n float pop = 0.0;\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 g = g0 + vec2(float(i), float(j));\n float s;\n vec3 c = cellAt(g, s);\n if (s < 0.35) {\n float x = (length(p - c.xy) - (0.15 + s * 1.6)) / 0.05;\n pop = max(pop, exp(-x * x) * (1.0 - s / 0.35));\n }\n if (g == bg) continue;\n vec2 d = p - c.xy;\n float len = length(c.xy - bc);\n if (len < 1e-4) continue;\n wall = min(wall, ((dot(d, d) - c.z) - best) / (2.0 * len));\n }\n }\n float d1 = length(p - bc);\n float R = max(d1 + wall, 1e-3);\n float hh = clamp(wall / R, 0.0, 1.0);\n vec2 u = (p - bc) / R;\n // A shallow dome, lit from the top left.\n vec3 n = normalize(vec3(u * 1.1, sqrt(max(1.0 - dot(u, u), 0.0)) + 0.25));\n vec3 L = normalize(vec3(-0.45, 0.6, 0.7));\n float diff = max(dot(n, L), 0.0);\n float spec = pow(max(dot(reflect(-L, n), vec3(0.0, 0.0, 1.0)), 0.0), 28.0);\n float edge = 1.0 - hh;\n // The middle sees through to the foam beneath (darker); toward the walls the film turns bright.\n vec3 col = mix(mix(uWall, uBase, 0.35), uBase, 0.25 + 0.75 * edge * edge);\n col *= 0.75 + 0.35 * diff;\n float cellHash = hash12(bg + 3.3);\n vec3 iri = 0.5 + 0.5 * cos(6.28318 * (cellHash + edge * 1.4 + iTime * 0.04 + vec3(0.0, 0.33, 0.67)));\n col = mix(col, col * (0.6 + 0.8 * iri), uIridescence * 0.5 * edge);\n col += spec * 0.8 * smoothstep(0.1, 0.5, R);\n // The walls between bubbles: a dark seam with a bright lip on each side.\n float seam = 1.0 - smoothstep(0.0, 0.03 + px, wall);\n float lip = smoothstep(0.0, 0.03 + px, wall) * (1.0 - smoothstep(0.03, 0.09 + px, wall));\n col = mix(col, uWall * 0.55, seam * 0.85);\n col += lip * 0.12;\n col += pop * 0.5;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Beer head\", values: { uBase: [1, 0.96, 0.86], uWall: [0.72, 0.5, 0.22], uIridescence: 0, uScale: 14 } },\n { name: \"Bubble bath\", values: { uBase: [1, 0.9, 0.95], uWall: [0.75, 0.5, 0.65], uIridescence: 0.8, uScale: 6 } },\n { name: \"Fine lather\", values: { uScale: 24, uVariety: 0.4, uPopping: 0.6 } },\n ],\n};\n\nexport const bubbleWrap: ShaderEffect = {\n kind: \"shader\",\n id: \"bubble-wrap\",\n name: \"Bubble wrap\",\n description: \"A sheet of bubble wrap seen from above: click a bubble to pop it flat and crinkled, and it fills back up after a while.\",\n category: \"bubble\",\n tags: [\"bubble\", \"interactive\", \"click\", \"playful\", \"texture\", \"satisfying\"],\n source: glsl(\n `// Bubble wrap: rows of air bubbles on a plastic sheet; clicks pop them, and they refill later.\nuniform vec3 uSurface; // @control color default=#5A6B80 label=\"Surface\"\nuniform vec3 uPlastic; // @control color default=#E3F1FB label=\"Plastic\"\nuniform float uRows; // @control min=3 max=20 default=7 label=\"Rows\"\nuniform float uRefill; // @control min=1 max=60 default=10 label=\"Refill after (s)\"\nuniform float uLoop; // @control min=4 max=40 default=14 label=\"Demo loop (s)\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n `// The bubble nearest p (in screen heights): its centre (xy) and cell (zw), on staggered rows.\nvec4 cellOf(vec2 p) {\n float s = 1.0 / uRows;\n float rh = s * 0.866;\n float j0 = floor(p.y / rh);\n vec4 best = vec4(0.0);\n float bd = 1e9;\n for (int k = -1; k <= 1; k++) {\n float j = j0 + float(k);\n float off = 0.5 * mod(j, 2.0);\n float i0 = floor(p.x / s - off - 0.5);\n for (int m = 0; m <= 1; m++) {\n float i = i0 + float(m);\n vec2 c = vec2((i + 0.5 + off) * s, (j + 0.5) * rh);\n float d = length(p - c);\n if (d < bd) {\n bd = d;\n best = vec4(c, i, j);\n }\n }\n }\n return best;\n}\n\n// When the bubble in cell id popped (x) and when it starts to refill (y); x < 0 while it is whole.\nvec2 popOf(vec2 id) {\n if (!uDemo || iClicks[0].w > 0.5) {\n float pop = -1.0;\n for (int j = 7; j >= 0; j--) {\n vec4 c = iClicks[j];\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > uRefill + 0.8) continue;\n vec2 at = c.xy / iResolution.y;\n vec4 cell = cellOf(at);\n if (cell.z != id.x || cell.w != id.y) continue;\n // A click on a bubble that is already flat does nothing.\n if (pop < 0.0 || c.z > pop + uRefill) pop = c.z;\n }\n return vec2(pop, pop + uRefill);\n }\n // Idle: each loop, most bubbles pop at a moment of their own, and all refill as it ends.\n float k = floor(iTime / uLoop);\n float at = (k + 0.04 + 0.8 * hash12(id + k * 7.1)) * uLoop;\n if (hash12(id * 1.3 + k * 3.3 + 0.5) > 0.65 || iTime < at) return vec2(-1.0, 0.0);\n return vec2(at, (k + 1.0) * uLoop - 0.8);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n vec4 cell = cellOf(p);\n float R = 0.4 / uRows;\n vec2 st = popOf(cell.zw);\n float deflated = st.x < 0.0 ? 0.0 : smoothstep(st.x, st.x + 0.06, iTime) * (1.0 - smoothstep(st.y, st.y + 0.8, iTime));\n float h = 1.0 - 0.88 * deflated;\n vec2 q = (p - cell.xy) / R;\n float r = length(q);\n // The surface under the sheet, each bubble's shadow falling down and right.\n vec3 col = uSurface * (0.92 + 0.08 * vnoise(p * 40.0));\n float shadow = length(q - vec2(0.18, -0.24)) ;\n col *= 1.0 - 0.38 * h * (1.0 - smoothstep(0.75, 1.2, shadow));\n col = mix(col, uPlastic, 0.16);\n float edge = px / R;\n float inside = 1.0 - smoothstep(1.0 - edge, 1.0 + edge, r);\n if (inside > 0.0) {\n float rr = min(r, 1.0);\n float z = sqrt(1.0 - rr * rr);\n vec3 n = vec3(q * h, z + 1.0 - h);\n // Popped plastic crinkles.\n vec2 o = cell.zw * 5.3;\n vec2 wr = vec2(vnoise(q * 4.0 + o), vnoise(q * 4.0 + o + 7.7)) - 0.5;\n float crease = 1.0 - smoothstep(0.0, 0.06, abs(vnoise(q * 3.0 + o + 2.1) - 0.5));\n n.xy += deflated * (wr * 1.6 + crease * 0.3);\n n = normalize(n);\n vec3 L = normalize(vec3(-0.5, 0.6, 0.8));\n float diff = max(dot(n, L), 0.0);\n float spec = pow(max(dot(reflect(-L, n), vec3(0.0, 0.0, 1.0)), 0.0), 40.0);\n vec3 b = mix(col, uPlastic, 0.18 + 0.4 * pow(1.0 - z, 2.0) * h);\n b *= 0.82 + 0.3 * diff;\n b += spec * (0.85 * h + 0.5 * deflated);\n b += 0.22 * smoothstep(0.72, 0.96, r) * h * vec3(0.9, 0.97, 1.0);\n b -= 0.12 * crease * deflated;\n // The welded seam round each bubble.\n b *= 1.0 - 0.18 * smoothstep(0.9, 1.0, r);\n // A flash as it pops.\n if (st.x >= 0.0) b += 0.35 * (1.0 - smoothstep(0.0, 0.15, iTime - st.x));\n col = mix(col, b, inside);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"On cardboard\", values: { uSurface: [0.72, 0.54, 0.36] } },\n { name: \"Night\", values: { uSurface: [0.07, 0.08, 0.11], uPlastic: [0.75, 0.85, 1] } },\n { name: \"Big bubbles\", values: { uRows: 4, uRefill: 20 } },\n ],\n};\n\nexport const lavaBubbles: ShaderEffect = {\n kind: \"shader\",\n id: \"lava-bubbles\",\n name: \"Lava bubbles\",\n description: \"Molten bubbles swelling out of a glowing, cracked lava crust and bursting into bright craters with spatter.\",\n category: \"bubble\",\n tags: [\"bubble\", \"lava\", \"magma\", \"fire\", \"volcano\", \"background\"],\n source: glsl(\n `// Lava bubbles: a cracked crust over glowing lava, with bubbles that swell, burst and spatter.\nuniform vec3 uHot; // @control color default=#FFE08A label=\"Hot\"\nuniform vec3 uMolten; // @control color default=#FF4A0D label=\"Molten\"\nuniform vec3 uCrust; // @control color default=#1C0B07 label=\"Crust\"\nuniform float uScale; // @control min=2 max=12 default=4.5 label=\"Scale\"\nuniform float uRate; // @control min=0.05 max=1.5 default=0.35 label=\"Bubbling\"\nuniform float uSize; // @control min=0.2 max=0.9 default=0.55 label=\"Bubble size\"\nuniform float uFlow; // @control min=0 max=1 default=0.25 label=\"Flow\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Glow\"\nuniform float uSpatter; // @control min=0 max=1.5 default=1 label=\"Spatter\"`,\n HASH,\n NOISE,\n FBM,\n `// Temperature (0 crust, 1 white hot) to colour.\nvec3 heat(float t) {\n vec3 c = mix(uCrust, uMolten, smoothstep(0.15, 0.55, t));\n c = mix(c, uHot, smoothstep(0.55, 0.9, t));\n return mix(c, vec3(1.0, 0.98, 0.9), smoothstep(0.9, 1.15, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 q = fragCoord / iResolution.y * uScale;\n vec2 drift = vec2(0.05, 0.02) * iTime * uFlow;\n // The crust: plates of cooled rock with glowing cracks between them.\n vec2 w = vec2(fbm(q * 0.5 + drift, 3), fbm(q * 0.5 - drift + 5.2, 3));\n float f = fbm(q * 0.9 + drift + w * 1.5, 5);\n float crack = 1.0 - smoothstep(0.0, 0.05, abs(fbm(q * 1.6 + w + drift * 1.5, 4) - 0.5));\n float T = 0.12 + 0.55 * (1.0 - smoothstep(0.35, 0.62, f)) + 0.4 * crack * smoothstep(0.65, 0.4, f);\n T += 0.06 * sin(iTime * 1.7 + f * 12.0);\n float spec = 0.0;\n vec2 g0 = floor(q);\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 g = g0 + vec2(float(i), float(j));\n vec2 h = hash22(g + 31.7);\n float period = (0.6 + 0.8 * hash12(g * 1.7 + 4.2)) / uRate;\n float tt = iTime / period + h.x * 5.0;\n float cyc = floor(tt);\n float ph = fract(tt);\n // Only some spots bubble each round.\n if (hash12(g + cyc * 1.3 + 8.8) > 0.55) continue;\n vec2 c = g + 0.25 + 0.5 * hash22(g + cyc * 13.1);\n float R = uSize * 0.5 * (0.5 + 0.5 * hash12(g + cyc * 3.1));\n vec2 d = q - c;\n float dl = length(d);\n if (dl > 2.6) continue;\n if (ph < 0.75) {\n // Swelling: a dome of stretched skin, hotter as it thins.\n float s = ph / 0.75;\n float r = R * pow(s, 0.6);\n if (dl < r) {\n float u = dl / r;\n float z = sqrt(1.0 - u * u);\n float m = smoothstep(1.0, 0.85, u);\n float skin = 0.28 + 0.42 * s * z * z + 0.12 * vnoise(d / r * 3.0 + cyc * 7.0);\n T = mix(T, max(T * 0.7, skin), m);\n vec3 n = vec3(d / r, z);\n spec = max(spec, pow(max(dot(n, normalize(vec3(-0.4, 0.5, 0.8))), 0.0), 24.0) * s * m * 0.7);\n } else {\n // A darker lip of crust pushed up round it.\n float x = (dl - r) / (0.08 * R + 0.02);\n T *= 1.0 - 0.35 * s * exp(-x * x);\n }\n } else {\n // Burst: a bright crater cooling, a ring rolling out and spatter thrown up and landing.\n float b = (ph - 0.75) / 0.25;\n float rc = R * (1.0 + 0.25 * b);\n if (dl < rc) {\n float u = dl / rc;\n T = max(T, mix(1.1, 0.45, b) * (1.0 - 0.35 * u * u));\n }\n float x = (dl - rc * (1.0 + b * 1.2)) / 0.06;\n T += 0.25 * exp(-x * x) * (1.0 - b);\n for (int k = 0; k < 8; k++) {\n if (uSpatter <= 0.0) break;\n vec2 hk = hash22(vec2(float(k), cyc) + g * 3.3);\n float ang = (float(k) + hk.x) / 8.0 * 6.28318;\n float dist = min(rc + b * R * (1.2 + 1.6 * hk.y) * uSpatter, 2.2);\n float alt = sin(3.14159 * b);\n vec2 pos = c + vec2(cos(ang), sin(ang)) * dist;\n float sz = R * 0.09 * (0.6 + hk.y) * (0.6 + 0.8 * alt);\n float drop = 1.0 - smoothstep(sz * 0.5, sz, length(q - pos));\n T = mix(T, max(T, 1.0 - 0.45 * b), drop);\n }\n }\n }\n }\n vec3 col = heat(T);\n col += uMolten * uGlow * 0.35 * smoothstep(0.4, 1.0, T);\n col *= 0.7 + 0.3 * uGlow;\n col += spec * 0.5 * vec3(1.0, 0.9, 0.7);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Sulphur blue\", values: { uHot: [0.75, 0.95, 1], uMolten: [0.1, 0.45, 1], uCrust: [0.02, 0.03, 0.08] } },\n { name: \"Mud pot\", values: { uHot: [0.75, 0.68, 0.58], uMolten: [0.45, 0.38, 0.3], uCrust: [0.2, 0.17, 0.14], uGlow: 0.2, uSpatter: 0.6 } },\n { name: \"Boiling\", values: { uRate: 1.2, uSize: 0.4, uScale: 6 } },\n ],\n};\n\n/** Bubbles: soap, underwater, fizz, foam, bubble wrap and lava. */\nexport const bubbleShaders: ShaderEffect[] = [soapBubbles, underwaterBubbles, fizz, foam, bubbleWrap, lavaBubbles];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\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 float h = clamp(0.5 + 0.5 * (b - a) / max(k, 1e-5), 0.0, 1.0);\n return mix(b, a, h) - k * h * (1.0 - h);\n}`.trim();\n\nexport const reactionDiffusion: ShaderEffect = {\n kind: \"shader\",\n id: \"reaction-diffusion\",\n name: \"Reaction diffusion\",\n description: \"Turing patterns of spots and labyrinth stripes slowly morphing, like a Gray-Scott simulation or an animal's coat.\",\n category: \"organic\",\n tags: [\"organic\", \"background\", \"pattern\", \"turing\", \"biology\", \"animal print\"],\n source: glsl(\n `// Reaction diffusion: a stateless fake of Gray-Scott: thresholded, domain-warped sine gratings.\nuniform vec3 uBase; // @control color default=#FFE8DC label=\"Base\"\nuniform vec3 uInk; // @control color default=#E8505B label=\"Pattern\"\nuniform float uScale; // @control min=2 max=30 default=11 label=\"Scale\"\nuniform float uPattern; // @control min=0 max=1 default=0.6 label=\"Spots to stripes\"\nuniform float uRings; // @control min=0 max=1 default=0 label=\"Rosettes\"\nuniform float uAlign; // @control min=0 max=1 default=0 label=\"Stripe alignment\"\nuniform float uWarp; // @control min=0 max=2 default=0.7 label=\"Warp\"\nuniform float uSpeed; // @control min=0 max=1 default=0.15 label=\"Speed\"\nuniform float uRelief; // @control min=0 max=1 default=0.5 label=\"Relief\"`,\n HASH,\n NOISE,\n FBM,\n `// Seven gratings at golden-angle headings: their sum thresholded at 0 is a labyrinth, high up it is spots.\nfloat turing(vec2 p, float t) {\n float s = 0.0;\n for (int i = 0; i < 7; i++) {\n float fi = float(i);\n // Headings spread over half a turn, narrowed towards one direction by uAlign for stripes.\n float a = (mod(fi * 2.39996 + 1.5708, 3.14159) - 1.5708) * (1.0 - 0.85 * uAlign) + 0.3 * sin(t * 0.37 + fi * 1.3);\n s += cos(dot(p, vec2(cos(a), sin(a))) * 6.28318 + fi * 1.7 + t * (0.3 + 0.07 * fi));\n }\n return s * 0.378;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.y;\n float t = iTime * uSpeed;\n vec2 w = vec2(fbm(uv * 1.7 + vec2(0.0, t * 0.2), 4), fbm(uv * 1.7 + vec2(5.2, 1.3 - t * 0.2), 4)) - 0.5;\n vec2 p = uv * uScale + w * uWarp * 4.0;\n float v = turing(p, t);\n // Regions drift between spots and stripes, as in a real simulation with uneven feed.\n float region = fbm(uv * 1.1 + vec2(9.0, t * 0.05), 3) - 0.5;\n float level = mix(1.05, 0.0, uPattern) + region * 0.7;\n float e = max(fwidth(v), 0.02);\n float m = smoothstep(level - e, level + e, v);\n float band = 0.38;\n float ring = m * (1.0 - smoothstep(level + band - e, level + band + e, v));\n float hole = smoothstep(level + band - e, level + band + e, v) * uRings;\n m = mix(m, ring, uRings);\n vec3 col = uBase * (0.94 + 0.06 * vnoise(fragCoord * 0.35));\n col = mix(col, uInk, m);\n // Rosettes are filled with a deeper shade of the base.\n col = mix(col, mix(uBase, uInk, 0.3) * 0.92, hole);\n // Relief: the pattern is a little raised, lit from the top left.\n vec2 g = vec2(dFdx(v), dFdy(v));\n float lit = dot(g / max(length(g), 1e-5), normalize(vec2(-1.0, 1.0)));\n float edge = smoothstep(level - 0.02, level + 0.02, v) * (1.0 - smoothstep(level, level + 0.3, v));\n col *= 1.0 + uRelief * 0.35 * edge * lit;\n col = mix(col, col * 0.82, uRelief * m * smoothstep(level, level + 1.2, v) * (1.0 - uRings));\n fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}`,\n ),\n presets: [\n { name: \"Coral\", values: { uBase: [1, 0.91, 0.86], uInk: [0.91, 0.31, 0.36], uPattern: 0.62, uRings: 0, uScale: 11, uAlign: 0 } },\n { name: \"Zebra\", values: { uBase: [0.96, 0.95, 0.92], uInk: [0.07, 0.07, 0.08], uPattern: 1, uRings: 0, uScale: 7, uWarp: 0.5, uAlign: 0.65 } },\n {\n name: \"Leopard spots\",\n values: { uBase: [0.85, 0.62, 0.27], uInk: [0.16, 0.1, 0.05], uPattern: 0.45, uRings: 0.9, uScale: 7, uWarp: 0.9, uAlign: 0 },\n },\n ],\n};\n\nexport const cellDivision: ShaderEffect = {\n kind: \"shader\",\n id: \"cell-division\",\n name: \"Cell division\",\n description: \"Cells in a petri dish under the microscope, growing, pinching and splitting in two.\",\n category: \"organic\",\n tags: [\"organic\", \"biology\", \"science\", \"microscope\", \"mitosis\", \"loop\"],\n loop: 8,\n source: glsl(\n `// Cell division: soft cells with nuclei going through mitosis on an 8 s loop, seen through a microscope.\nuniform vec3 uMedium; // @control color default=#E6EEEC label=\"Medium\"\nuniform vec3 uCell; // @control color default=#A7D8C9 label=\"Cytoplasm\"\nuniform vec3 uMembrane; // @control color default=#2F5D62 label=\"Membrane\"\nuniform vec3 uNucleus; // @control color default=#6D3FC0 label=\"Nucleus\"\nuniform float uDensity; // @control min=1.5 max=8 default=3.5 label=\"Cells across\"\nuniform float uStain; // @control min=0 max=1 default=0.65 label=\"Stain\"\nuniform float uVignette; // @control min=0 max=1 default=0.85 label=\"Microscope vignette\"`,\n HASH,\n NOISE,\n ROTATE,\n SMIN,\n `float ellipseDist(vec2 v, vec2 r) {\n return (length(v / r) - 1.0) * min(r.x, r.y);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 c = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec2 p = c * uDensity;\n float px = uDensity / iResolution.y;\n float T = iTime * 6.28318 / 8.0;\n float best = 1e5;\n float bestNuc = 1e5;\n float bestFade = 0.0;\n float bestSoft = 0.0;\n vec2 bestL = vec2(0.0);\n vec2 cell = floor(p);\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 id = cell + vec2(float(i), float(j));\n vec2 h = hash22(id + 0.37);\n float h2 = hash12(id * 1.71 + 4.1);\n vec2 centre = id + 0.5 + (h - 0.5) * 0.24 + 0.05 * vec2(sin(T + h.x * 6.28), cos(T + h.y * 6.28));\n float s = fract(iTime / 8.0 + h2);\n // Fade in and out as cells drift through the focal plane, which hides the wrap of the cycle.\n float fade = smoothstep(0.0, 0.1, s) * (1.0 - smoothstep(0.88, 1.0, s));\n vec2 l = rot(-(h.x * 3.14159 + s * 0.6)) * (p - centre);\n float split = smoothstep(0.45, 0.8, s);\n float r = 0.16 + 0.06 * smoothstep(0.0, 0.45, s);\n float rd = r * mix(1.0, 0.8, split);\n float sep = 0.19 * split + 0.08 * smoothstep(0.8, 1.0, s);\n float ang = atan(l.y, l.x);\n float wob = 0.004 * sin(ang * 3.0 + T * 2.0 + h.y * 9.0) + 0.003 * sin(ang * 5.0 - T * 3.0 + h.x * 7.0);\n float d1 = length(l - vec2(sep, 0.0)) - rd;\n float d2 = length(l + vec2(sep, 0.0)) - rd;\n float d = smin(d1, d2, mix(0.12, 0.004, smoothstep(0.55, 0.85, s))) + wob;\n // Nucleus: round, condenses to a plate (metaphase), pulls apart and rounds up in each daughter.\n float s1 = smoothstep(0.3, 0.42, s);\n float s2 = smoothstep(0.75, 0.92, s);\n vec2 nr = mix(vec2(0.45 * r), vec2(0.1 * r, 0.6 * r), s1);\n nr = mix(nr, vec2(0.42 * rd), s2);\n float nsep = sep * 0.95;\n float nd = min(ellipseDist(l - vec2(nsep, 0.0), nr), ellipseDist(l + vec2(nsep, 0.0), nr));\n float key = d + (1.0 - fade) * 0.25;\n if (key < best) {\n best = key;\n bestNuc = nd;\n bestFade = fade;\n bestSoft = 1.0 - fade;\n bestL = l + h * 7.0;\n }\n }\n }\n float d = best - (1.0 - bestFade) * 0.25;\n float aa = px * 1.5 + bestSoft * 0.05;\n float inside = 1.0 - smoothstep(-aa, aa, d);\n float rim = exp(-abs(d) / (0.012 + bestSoft * 0.04));\n float halo = exp(-max(d, 0.0) / 0.05) * (1.0 - inside);\n float grain = vnoise(bestL * 28.0) * 0.5 + vnoise(bestL * 61.0) * 0.5;\n vec3 col = uMedium * (0.96 + 0.04 * vnoise(p * 9.0));\n vec3 cyto = mix(uCell, uCell * 0.86, grain) * (0.9 + 0.12 * smoothstep(0.0, -0.12, d));\n col = mix(col, cyto, inside * bestFade * 0.9);\n col += halo * 0.18 * bestFade;\n col = mix(col, uMembrane, rim * bestFade * 0.75);\n float nIn = (1.0 - smoothstep(-aa, aa, bestNuc)) * inside;\n float chromatin = 0.75 + 0.25 * vnoise(bestL * 45.0);\n col = mix(col, uNucleus * chromatin, nIn * bestFade * mix(0.25, 0.9, uStain));\n col = mix(col, uNucleus * 0.6, exp(-abs(bestNuc) / 0.01) * inside * bestFade * 0.5 * uStain);\n // Microscope: a round field of view with a soft dark edge.\n float field = (0.5 * min(iResolution.x, iResolution.y) + 0.3 * abs(iResolution.x - iResolution.y)) / iResolution.y;\n float dc = length(c);\n float lens = smoothstep(field, field * 0.9, dc) * (1.0 - 0.25 * pow(dc / field, 2.0));\n col *= mix(1.0, lens, uVignette);\n fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}`,\n ),\n presets: [\n { name: \"Stained\", values: { uMedium: [0.95, 0.9, 0.93], uCell: [0.93, 0.68, 0.8], uMembrane: [0.55, 0.15, 0.4], uNucleus: [0.25, 0.1, 0.55], uStain: 1 } },\n {\n name: \"Fluorescent\",\n values: { uMedium: [0.02, 0.03, 0.05], uCell: [0.1, 0.45, 0.25], uMembrane: [0.4, 1, 0.55], uNucleus: [0.25, 0.45, 1], uStain: 0.9, uVignette: 0.6 },\n },\n ],\n};\n\nexport const coralGrowth: ShaderEffect = {\n kind: \"shader\",\n id: \"coral-growth\",\n name: \"Coral growth\",\n description: \"Branching coral growing outward from the centre in rings, softly translucent, with glowing growing tips.\",\n category: \"organic\",\n tags: [\"organic\", \"background\", \"growth\", \"coral\", \"lichen\", \"underwater\", \"branching\"],\n source: glsl(\n `// Coral growth: arms of branching coral (trees made by folding space) growing outward, banded by growth rings.\nuniform vec3 uWater; // @control color default=#08263A label=\"Background\"\nuniform vec3 uBody; // @control color default=#C2255C label=\"Coral base\"\nuniform vec3 uTip; // @control color default=#FFB4A2 label=\"Coral edges\"\nuniform vec3 uFront; // @control color default=#FFF1C1 label=\"Growth front\"\nuniform int uArms; // @control min=3 max=12 default=7 label=\"Arms\"\nuniform float uThickness; // @control min=0.006 max=0.05 default=0.022 label=\"Thickness\"\nuniform float uSpread; // @control min=10 max=60 default=32 label=\"Branch angle\"\nuniform float uCycle; // @control min=4 max=40 default=14 label=\"Cycle (seconds)\"\nuniform float uRings; // @control min=0 max=1 default=0.5 label=\"Growth rings\"`,\n HASH,\n NOISE,\n ROTATE,\n `// Distance to arm k grown to arc length g from the centre, and how far along the arm the nearest point is.\nvec2 arm(vec2 q, float k, float g) {\n float L = 0.2;\n float sc = 1.0;\n float id = 1.0 + k * 61.0;\n float d = 1e5;\n float along = 0.0;\n float arc = 0.0;\n for (int i = 0; i < 7; i++) {\n float fi = float(i);\n q.x += (vnoise(vec2(q.y * 6.0, id * 3.7)) - 0.5) * 0.12 * sin(3.14159 * clamp(q.y / L, 0.0, 1.0));\n float shown = clamp((g - arc) / sc, 0.0, L);\n if (shown <= 0.0) break;\n float y = clamp(q.y, 0.0, shown);\n float age = clamp((g - arc - y * sc) / 0.12, 0.0, 1.0);\n float w = uThickness * sqrt(sc) * mix(0.6, 1.0, age);\n float dd = length(q - vec2(0.0, y)) * sc - w;\n if (dd < d) {\n d = dd;\n along = arc + y * sc;\n }\n arc += L * sc;\n q.y -= L;\n id = id * 2.0 + step(0.0, q.x);\n q.x = abs(q.x);\n q = rot(radians(uSpread) * (0.6 + 0.8 * hash12(vec2(id, fi)))) * q;\n float s = 0.78 + 0.1 * hash12(vec2(fi, id * 1.3));\n q /= s;\n sc *= s;\n }\n return vec2(d, along);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 c = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n float r = length(c);\n float cyc = fract(iTime / max(uCycle, 0.1));\n float g = 0.95 * (1.0 - pow(1.0 - smoothstep(0.0, 0.85, cyc), 1.5));\n float grow = 1.0 - smoothstep(0.88, 1.0, cyc);\n float n = float(uArms);\n float sector = 6.28318 / n;\n float idx = floor(atan(c.y, c.x) / sector + 0.5);\n float d = r - min(g, 0.05);\n float along = 0.0;\n for (int k = -1; k <= 1; k++) {\n float s = idx + float(k);\n vec2 q = rot(1.5708 - s * sector) * c;\n vec2 a = arm(q, mod(s, n), g);\n if (a.x < d) {\n d = a.x;\n along = a.y;\n }\n }\n vec3 col = uWater * (0.75 + 0.35 * vnoise(c * 5.0 + iTime * 0.05)) * (1.15 - 0.5 * r);\n float coral = (1.0 - smoothstep(-px, px, d)) * grow;\n float inner = clamp(-d / uThickness, 0.0, 1.0);\n // Translucent: thin edges let light through, thick cores are deeper; lit from the top left.\n vec2 grad = vec2(dFdx(d), dFdy(d));\n float lit = dot(grad / max(length(grad), 1e-6), normalize(vec2(-0.6, 0.8)));\n vec3 body = mix(uTip, uBody, smoothstep(0.0, 0.9, inner));\n body *= 0.9 + 0.3 * lit * (1.0 - inner);\n body *= 0.88 + 0.24 * vnoise(c * 140.0);\n body *= 1.0 - uRings * 0.3 * smoothstep(0.7, 1.0, 0.5 + 0.5 * cos(along * 45.0));\n float tip = exp(-max(g - along, 0.0) / 0.035);\n body = mix(body, uFront, tip * 0.75);\n float halo = exp(-max(d, 0.0) / 0.02) * (1.0 - coral) * grow;\n col = mix(col, col * 0.7, halo * 0.6);\n col += uBody * halo * 0.1 + uFront * exp(-max(d, 0.0) / 0.006) * (1.0 - coral) * grow * tip * 0.4;\n col = mix(col, body, coral);\n fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}`,\n ),\n presets: [\n { name: \"Lichen\", values: { uWater: [0.36, 0.37, 0.33], uBody: [0.45, 0.55, 0.3], uTip: [0.85, 0.9, 0.6], uFront: [0.95, 0.97, 0.8], uArms: 11, uThickness: 0.012, uSpread: 45 } },\n { name: \"Bleached\", values: { uWater: [0.02, 0.18, 0.3], uBody: [0.75, 0.78, 0.8], uTip: [1, 1, 0.96], uFront: [0.6, 0.95, 1], uRings: 0.8, uThickness: 0.03 } },\n ],\n};\n\nexport const veins: ShaderEffect = {\n kind: \"shader\",\n id: \"veins\",\n name: \"Veins\",\n description: \"Branching veins or roots with pulses of light travelling out along them.\",\n category: \"organic\",\n tags: [\"organic\", \"background\", \"branching\", \"leaf\", \"roots\", \"blood\", \"fractal\"],\n source: glsl(\n `// Veins: a bounded-depth branching tree by folding space, wiggled with noise, with pulses along its length.\nuniform vec3 uBackground; // @control color default=#2F6A1D label=\"Background\"\nuniform vec3 uVein; // @control color default=#D4F08A label=\"Vein\"\nuniform vec3 uPulse; // @control color default=#FFFDE0 label=\"Pulse\"\nuniform int uDepth; // @control min=2 max=9 default=7 label=\"Depth\"\nuniform int uTrees; // @control min=1 max=3 default=1 label=\"Trunks\"\nuniform float uSpread; // @control min=10 max=80 default=38 label=\"Branch angle\"\nuniform float uWidth; // @control min=0.002 max=0.04 default=0.012 label=\"Width\"\nuniform float uWiggle; // @control min=0 max=0.4 default=0.12 label=\"Wiggle\"\nuniform float uRotation; // @control min=-180 max=180 default=0 label=\"Rotation\"\nuniform float uPulses; // @control min=0 max=2 default=0.8 label=\"Pulse speed\"\nuniform float uGlow; // @control min=0 max=2 default=1 label=\"Glow\"`,\n HASH,\n NOISE,\n FBM,\n ROTATE,\n `// Distance to tree k (world units), its width there, and the distance along it from the root.\nvec3 tree(vec2 q, float k, out float width) {\n float L = 0.34;\n float sc = 1.0;\n float id = 1.0 + k * 97.0;\n float d = 1e5;\n float along = 0.0;\n float arc = 0.0;\n width = uWidth;\n for (int i = 0; i < 9; i++) {\n if (i >= uDepth) break;\n float fi = float(i);\n // Wiggle each segment between its ends, so children stay joined to their parent.\n q.x += (vnoise(vec2(q.y * 5.0, id * 7.13)) - 0.5) * uWiggle * sin(3.14159 * clamp(q.y / L, 0.0, 1.0));\n float h = clamp(q.y / L, 0.0, 1.0);\n float w = uWidth * sc * mix(1.0, 0.75, h);\n float dd = length(q - vec2(0.0, h * L)) * sc - w;\n if (dd < d) {\n d = dd;\n along = arc + h * L * sc;\n width = w;\n }\n arc += L * sc;\n q.y -= L;\n id = id * 2.0 + step(0.0, q.x);\n q.x = abs(q.x);\n q = rot(radians(uSpread) * (0.7 + 0.6 * hash12(vec2(id, fi)))) * q;\n float s = 0.66 + 0.14 * hash12(vec2(fi, id * 1.3));\n q /= s;\n sc *= s;\n }\n return vec3(d, along, 0.0);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 c = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float px = 1.0 / iResolution.y;\n vec2 p = rot(radians(uRotation)) * c;\n p += (vec2(fbm(p * 2.5, 3), fbm(p * 2.5 + 5.3, 3)) - 0.5) * uWiggle * 0.5;\n float aspect = iResolution.x / iResolution.y;\n float d = 1e5;\n float along = 0.0;\n float width = uWidth;\n float seed = 0.0;\n for (int k = 0; k < 3; k++) {\n if (k >= uTrees) break;\n float fk = float(k);\n float x0 = ((fk + 0.5) / float(uTrees) - 0.5) * aspect * 0.8;\n float w;\n vec3 t = tree(p - vec2(x0, -0.62), fk, w);\n if (t.x < d) {\n d = t.x;\n along = t.y;\n width = w;\n seed = fk;\n }\n }\n float mask = 1.0 - smoothstep(-px, px, d);\n float tube = clamp(-d / max(width, px), 0.0, 1.0);\n float glow = exp(-max(d, 0.0) / 0.012);\n // Background with a little cellular texture.\n vec3 col = uBackground * (0.88 + 0.12 * fbm(c * 14.0, 3)) * (1.1 - 0.35 * length(c));\n col = mix(col, uVein, glow * 0.18 * uGlow);\n col = mix(col, uVein * (0.8 + 0.35 * sqrt(tube)), mask);\n // Pulses: bright heads travelling root to tip.\n float f = fract(along * 2.2 - iTime * uPulses * 0.5 + seed * 0.37);\n float pulse = smoothstep(0.65, 0.97, f) * (1.0 - smoothstep(0.97, 1.0, f));\n col += uPulse * pulse * (mask * 0.9 + exp(-max(d, 0.0) / 0.008) * 0.5 * uGlow);\n fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}`,\n ),\n presets: [\n { name: \"Leaf veins\", values: { uBackground: [0.18, 0.42, 0.11], uVein: [0.83, 0.94, 0.54], uPulse: [1, 0.99, 0.88], uSpread: 40, uTrees: 1, uRotation: 0, uWiggle: 0.08 } },\n {\n name: \"Blood vessels\",\n values: { uBackground: [0.93, 0.74, 0.7], uVein: [0.55, 0.04, 0.1], uPulse: [1, 0.25, 0.25], uSpread: 30, uTrees: 2, uRotation: 90, uWiggle: 0.25, uWidth: 0.01, uPulses: 1.4 },\n },\n {\n name: \"Tree roots\",\n values: { uBackground: [0.23, 0.16, 0.11], uVein: [0.79, 0.64, 0.48], uPulse: [0.96, 0.89, 0.71], uSpread: 28, uTrees: 3, uRotation: 180, uWiggle: 0.35, uWidth: 0.016, uDepth: 8 },\n },\n ],\n};\n\nexport const ferrofluid: ShaderEffect = {\n kind: \"shader\",\n id: \"ferrofluid\",\n name: \"Ferrofluid\",\n description: \"A glossy black ferrofluid puddle whose spikes rise as a magnet passes over it, following the pointer.\",\n category: \"organic\",\n tags: [\"organic\", \"interactive\", \"hover\", \"liquid\", \"magnetic\", \"glossy\", \"3d\"],\n source: glsl(\n `// Ferrofluid: a raymarched height field of spiky fluid; the magnet follows the pointer or orbits while idle.\nuniform vec3 uFluid; // @control color default=#050507 label=\"Fluid\"\nuniform vec3 uTable; // @control color default=#E9E7E2 label=\"Surface\"\nuniform vec3 uLight; // @control color default=#FFFFFF label=\"Light\"\nuniform float uStrength; // @control min=0 max=1.5 default=1 label=\"Magnet strength\"\nuniform float uSpikes; // @control min=4 max=16 default=7 label=\"Spike density\"\nuniform float uSize; // @control min=0.3 max=1 default=0.55 label=\"Puddle size\"\nuniform float uGloss; // @control min=0 max=1 default=0.85 label=\"Gloss\"\nuniform bool uDemo; // @control default=true label=\"Orbit when idle\"`,\n `vec3 camRay(vec2 frag, vec3 ro) {\n vec2 uv = (frag - 0.5 * iResolution.xy) / iResolution.y;\n vec3 fw = normalize(vec3(0.0, 0.1, 0.0) - ro);\n vec3 rt = normalize(cross(vec3(0.0, 1.0, 0.0), fw));\n vec3 up = cross(fw, rt);\n return normalize(fw * 1.7 + uv.x * rt + uv.y * up);\n}\n\n// The magnet over the table: xz, and how strongly it pulls (0–1.5).\nvec3 gMagnet;\nvec2 gCentre;\n\nfloat fluidHeight(vec2 xz) {\n float r = length(xz - gCentre) / uSize;\n if (r > 1.05) return 0.0;\n float inside = 1.0 - smoothstep(0.92, 1.05, r);\n float dome = 0.2 * uSize * pow(clamp(1.0 - r * r, 0.0, 1.0), 0.45);\n float near = exp(-dot(xz - gMagnet.xy, xz - gMagnet.xy) / pow(0.42 * uSize, 2.0));\n dome += 0.08 * uSize * gMagnet.z * near * inside;\n // Spikes on a hexagonal lattice, tallest under the magnet and shorter towards the rim.\n vec2 hp = xz * uSpikes / uSize;\n vec2 s = vec2(1.0, 1.732);\n vec2 a = mod(hp, s) - s * 0.5;\n vec2 b = mod(hp - s * 0.5, s) - s * 0.5;\n float dc = min(length(a), length(b));\n float cone = pow(max(1.0 - dc / 0.55, 0.0), 2.2);\n float tall = 0.42 * uSize * gMagnet.z * mix(0.25, 1.0, near) * (1.0 - smoothstep(0.7, 1.0, r));\n return dome + cone * tall;\n}\n\nvec3 environment(vec3 d) {\n vec3 env = mix(vec3(0.03), vec3(0.22), smoothstep(-0.1, 0.7, d.y));\n if (d.y < 0.0) env = uTable * 0.55 * (1.0 - smoothstep(0.0, -0.6, d.y) * 0.4);\n env += uLight * 2.2 * smoothstep(0.88, 0.92, dot(d, normalize(vec3(-0.45, 0.85, 0.25))));\n env += uLight * 1.4 * smoothstep(0.95, 0.975, dot(d, normalize(vec3(0.7, 0.55, -0.45))));\n return env;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec3 ro = vec3(0.0, 1.55, -2.0);\n float t0 = iTime;\n // The magnet: the pointer's spot on the table while hovered, else an orbit that comes and goes.\n vec3 pr = camRay(iPointer.xy, ro);\n vec2 pointerXZ = (ro + pr * (-ro.y / min(pr.y, -0.05))).xz;\n float hov = clamp(iPointer.z, 0.0, 1.0);\n vec2 orbit = uDemo ? vec2(cos(t0 * 0.45), sin(t0 * 0.45)) * 0.35 * uSize : vec2(0.0);\n float idleAmp = uDemo ? 0.55 + 0.45 * sin(t0 * 0.9) : 0.7;\n gMagnet = vec3(mix(orbit, clamp(pointerXZ, vec2(-1.5), vec2(1.5)), hov), uStrength * mix(idleAmp, 1.0, hov));\n gCentre = mix(vec2(0.0), gMagnet.xy, 0.22 * min(gMagnet.z, 1.0));\n vec3 rd = camRay(fragCoord, ro);\n float top = 0.75 * uSize;\n float t = (ro.y - top) / max(-rd.y, 1e-3);\n float lastT = t;\n bool hit = false;\n for (int i = 0; i < 140; i++) {\n vec3 p = ro + rd * t;\n float dy = p.y - fluidHeight(p.xz);\n if (dy < 0.0005) { hit = true; break; }\n lastT = t;\n t += max(dy * 0.28, 0.0015);\n if (t > 12.0) break;\n }\n if (hit) {\n float lo = lastT;\n float hi = t;\n for (int i = 0; i < 6; i++) {\n float m = 0.5 * (lo + hi);\n vec3 p = ro + rd * m;\n if (p.y - fluidHeight(p.xz) < 0.0) hi = m; else lo = m;\n }\n t = hi;\n }\n vec3 p = ro + rd * t;\n vec3 col;\n float hgt = fluidHeight(p.xz);\n if (hit && hgt > 0.0008) {\n float e = 0.0015;\n vec3 n = normalize(vec3(\n fluidHeight(p.xz - vec2(e, 0.0)) - fluidHeight(p.xz + vec2(e, 0.0)),\n 2.0 * e,\n fluidHeight(p.xz - vec2(0.0, e)) - fluidHeight(p.xz + vec2(0.0, e))));\n vec3 v = -rd;\n float fres = 0.04 + 0.96 * pow(1.0 - clamp(dot(n, v), 0.0, 1.0), 5.0);\n vec3 refl = reflect(rd, n);\n vec3 L = normalize(vec3(-0.45, 0.85, 0.25));\n float diff = clamp(dot(n, L), 0.0, 1.0);\n col = uFluid * (0.4 + 0.6 * diff);\n col += environment(refl) * mix(0.05, 1.0, fres) * mix(0.35, 1.0, uGloss);\n col += uLight * pow(clamp(dot(refl, L), 0.0, 1.0), mix(20.0, 260.0, uGloss)) * 2.0 * uGloss;\n } else {\n // The table: soft light falloff and a contact shadow round the puddle.\n vec2 xz = (ro + rd * (-ro.y / min(rd.y, -1e-3))).xz;\n float r = length(xz - gCentre - vec2(0.12, -0.06) * uSize);\n float shadow = mix(0.45, 1.0, smoothstep(uSize * 0.95, uSize * 1.45, r));\n col = uTable * shadow * (1.0 - 0.18 * length(xz) / (1.0 + length(xz)));\n }\n vec2 uv = fragCoord / iResolution.xy;\n col *= 0.85 + 0.15 * pow(16.0 * uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y), 0.25);\n fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}`,\n ),\n presets: [\n { name: \"Studio dark\", values: { uTable: [0.12, 0.12, 0.14], uLight: [0.85, 0.92, 1], uGloss: 1 } },\n { name: \"Gold leaf\", values: { uFluid: [0.25, 0.17, 0.04], uTable: [0.96, 0.93, 0.86], uLight: [1, 0.85, 0.55], uSpikes: 12 } },\n ],\n};\n\nexport const jellyfish: ShaderEffect = {\n kind: \"shader\",\n id: \"jellyfish\",\n name: \"Jellyfish\",\n description: \"Translucent jellyfish pulsing and drifting up through deep water, trailing glowing tentacles.\",\n category: \"organic\",\n tags: [\"organic\", \"background\", \"underwater\", \"ocean\", \"bioluminescent\", \"creature\"],\n source: glsl(\n `// Jellyfish: pulsing translucent bells with trailing tentacles, glowing in deep water.\nuniform vec3 uDeep; // @control color default=#020617 label=\"Deep water\"\nuniform vec3 uShallow; // @control color default=#0B3555 label=\"Upper water\"\nuniform vec3 uGlow; // @control color default=#7DF9FF label=\"Glow\"\nuniform vec3 uAccent; // @control color default=#FF6EC7 label=\"Accent\"\nuniform int uCount; // @control min=1 max=6 default=4 label=\"Jellyfish\"\nuniform float uSize; // @control min=0.05 max=0.3 default=0.12 label=\"Size\"\nuniform float uSpeed; // @control min=0 max=2 default=0.6 label=\"Speed\"\nuniform float uTentacles; // @control min=0.2 max=2 default=1 label=\"Tentacle length\"\nuniform float uLuminance; // @control min=0 max=2 default=1 label=\"Bioluminescence\"`,\n HASH,\n NOISE,\n ROTATE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n // Water: lighter above, faint shafts of light, drifting marine snow.\n vec3 col = mix(uDeep, uShallow, pow(uv.y, 1.4));\n float shafts = vnoise(vec2((p.x + p.y * 0.35) * 7.0, iTime * 0.08)) * vnoise(vec2((p.x + p.y * 0.3) * 13.0, iTime * 0.05 + 4.0));\n col += uShallow * shafts * smoothstep(0.2, 1.0, uv.y) * 0.9;\n vec2 sp = p * 24.0 + vec2(0.0, iTime * 0.25);\n vec2 sc = floor(sp);\n vec2 sh = hash22(sc);\n float snow = smoothstep(0.08, 0.0, length(fract(sp) - sh)) * step(0.82, hash12(sc + 3.7));\n col += vec3(0.5, 0.6, 0.7) * snow * 0.35;\n vec3 light = vec3(0.0);\n for (int i = 0; i < 6; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 seed = hash22(vec2(fi * 3.17 + 1.0, 7.3));\n float depth = 0.6 + 0.4 * seed.y;\n float size = uSize * depth;\n float period = 1.6 + seed.x * 0.9;\n float tau = t / period + seed.y * 5.0;\n float f = fract(tau);\n float contract = smoothstep(0.0, 0.25, f) * (1.0 - smoothstep(0.25, 1.0, f));\n // Each pulse pushes it up a little; it wraps once well off the top.\n float rise = (floor(tau) + smoothstep(0.0, 0.45, f)) * size * 0.45;\n float span = 1.0 + size * (2.0 + 6.0 * uTentacles);\n float y = mod(seed.x * span + rise, span) - size * 6.0 * uTentacles;\n vec2 centre = vec2((0.1 + 0.8 * fract(seed.x * 1.7 + fi * 0.37)) * aspect + 0.04 * sin(t * 0.3 + fi), y);\n float tilt = 0.25 * sin(t * 0.2 + fi * 2.0);\n vec2 q = rot(tilt) * (p - centre) / size;\n float lpx = px / size;\n float bright = uLuminance * depth;\n // Bell: a dome that narrows and heightens as it contracts, edged with scallops.\n float bw = 1.0 - 0.2 * contract;\n float bh = 0.85 + 0.15 * contract;\n vec2 bq = vec2(q.x / bw, q.y / bh);\n float e = length(bq);\n float under = 0.25 * (1.0 - bq.x * bq.x) + 0.04 * sin(bq.x * 18.0);\n float bell = (1.0 - smoothstep(1.0 - lpx * 2.0, 1.0, e)) * smoothstep(under - 0.05, under + 0.02, bq.y);\n float fresnel = pow(clamp(e, 0.0, 1.0), 5.0);\n vec3 bellCol = mix(uGlow * 0.35, uGlow, fresnel) ;\n col = mix(col, bellCol * (0.6 + 0.6 * bright), bell * (0.18 + 0.55 * fresnel) * depth);\n // Gonads: four soft loops inside the bell.\n vec2 gq = vec2(q.x, (q.y - 0.4) * 1.7);\n float petals = length(gq) - 0.2 * (0.7 + 0.3 * cos(4.0 * atan(gq.y, gq.x) + 0.785));\n float gonad = exp(-abs(petals) / 0.025) * bell;\n // Radial canals in the bell.\n float canals = exp(-abs(sin(atan(q.x, q.y - under * 0.5) * 8.0)) * 6.0) * bell * smoothstep(0.3, 0.95, e);\n light += uGlow * canals * 0.12 * bright;\n light += uAccent * gonad * 0.5 * bright;\n // Rim lights round the margin.\n float rim = exp(-abs(bq.y - under) / 0.04) * step(abs(bq.x), 1.0) * (0.6 + 0.4 * sin(bq.x * 18.0 + iTime * 3.0));\n light += uGlow * rim * 0.45 * bright;\n // Tentacles trail below, swaying with a lag that grows with length.\n float down = under * bw - q.y;\n if (down > -0.1) {\n for (int k = 0; k < 8; k++) {\n float fk = float(k);\n float len = uTentacles * 4.5 * (0.6 + 0.4 * hash12(vec2(fi, fk)));\n float x0 = mix(-0.85, 0.85, fk / 7.0) * bw;\n float xo = x0 * (1.0 + 0.12 * down) + sin(down * 2.6 - t * 3.0 + fk * 1.3 + fi) * 0.18 * down;\n float fade = 1.0 - smoothstep(0.0, len, down);\n float line = exp(-abs(q.x - xo) / (0.025 + lpx)) * fade * step(0.0, down);\n light += uGlow * line * 0.4 * bright;\n }\n // Oral arms: two frilly ribbons near the middle.\n for (int k = 0; k < 2; k++) {\n float fk = float(k) * 2.0 - 1.0;\n float xo = fk * 0.12 + sin(down * 2.0 - t * 2.4 + fk) * 0.1 * down;\n float wdt = 0.07 + 0.03 * sin(down * 18.0 + fk * 3.0);\n float arm = (1.0 - smoothstep(wdt - lpx * 2.0, wdt, abs(q.x - xo))) * (1.0 - smoothstep(0.0, uTentacles * 2.2, down)) * step(0.0, down);\n col = mix(col, mix(uAccent, uGlow, 0.4) * (0.5 + 0.5 * bright), arm * 0.35 * depth);\n }\n }\n light += uGlow * exp(-length(q - vec2(0.0, 0.3)) * 1.6) * 0.07 * bright;\n }\n col += light;\n col = 1.0 - exp(-col * 1.2);\n fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}`,\n ),\n presets: [\n { name: \"Moon jelly\", values: { uGlow: [0.75, 0.85, 1], uAccent: [0.85, 0.55, 1], uCount: 5, uSize: 0.1 } },\n { name: \"Sea nettle\", values: { uDeep: [0.03, 0.02, 0.04], uShallow: [0.12, 0.06, 0.08], uGlow: [1, 0.6, 0.3], uAccent: [1, 0.3, 0.2], uCount: 2, uSize: 0.18, uTentacles: 1.8 } },\n ],\n};\n\nexport const fur: ShaderEffect = {\n kind: \"shader\",\n id: \"fur\",\n name: \"Fur\",\n description: \"Soft fur, moss or grass swaying in a breeze, parting around the pointer.\",\n category: \"organic\",\n tags: [\"organic\", \"interactive\", \"hover\", \"texture\", \"soft\", \"nature\"],\n source: glsl(\n `// Fur: tapered strands on jittered grids, the topmost drawn, shaded darker towards the roots;\n// they sway in a breeze and part away from the pointer while it hovers.\nuniform vec3 uRoot; // @control color default=#3B2416 label=\"Root\"\nuniform vec3 uTip; // @control color default=#D9A066 label=\"Tip\"\nuniform float uDensity; // @control min=15 max=160 default=40 label=\"Density\"\nuniform float uLength; // @control min=0.5 max=3.5 default=2.6 label=\"Length\"\nuniform float uWidth; // @control min=0.05 max=0.5 default=0.2 label=\"Strand width\"\nuniform float uLie; // @control min=-180 max=180 default=-80 label=\"Lie direction\"\nuniform float uSway; // @control min=0 max=1 default=0.35 label=\"Breeze\"\nuniform float uClump; // @control min=0 max=1 default=0.5 label=\"Clumping\"\nuniform float uPart; // @control min=0 max=1 default=0.8 label=\"Parting\"`,\n HASH,\n NOISE,\n `// The two slow noise fields that turn the strands, hashed once per pixel on a\n// 3 x 3 lattice that covers every root the pixel looks at.\nmat3 clumpGrid;\nvec2 clumpBase;\nmat3 swayGrid;\nvec2 swayBase;\n\nmat3 noiseGrid(vec2 base) {\n mat3 g;\n for (int x = 0; x < 3; x++) {\n for (int y = 0; y < 3; y++) g[x][y] = hash12(base + vec2(float(x), float(y)));\n }\n return g;\n}\n\n// vnoise(q), with its corners read from a lattice hashed at base.\nfloat gridNoise(vec2 q, vec2 base, mat3 g) {\n vec2 f = fract(q);\n vec2 u = f * f * (3.0 - 2.0 * f);\n ivec2 k = clamp(ivec2(floor(q) - base), 0, 1);\n vec3 c0 = g[k.x];\n vec3 c1 = g[k.x + 1];\n return mix(mix(c0[k.y], c1[k.y], u.x), mix(c0[k.y + 1], c1[k.y + 1], u.x), u.y);\n}\n\nvec2 strandDir(vec2 root, vec2 ptr, float hov) {\n float a = radians(uLie) + (gridNoise(root * 0.07, clumpBase, clumpGrid) - 0.5) * 1.6 * uClump;\n a += uSway * 0.7 * sin(iTime * 1.3 + root.x * 0.05 + root.y * 0.03 + 2.0 * gridNoise(root * 0.02 + iTime * 0.15, swayBase, swayGrid));\n vec2 dir = vec2(cos(a), sin(a));\n if (uPart * hov <= 0.0) return dir;\n vec2 away = root - ptr;\n float reach = 0.16 * uDensity;\n float f = uPart * hov * exp(-dot(away, away) / (reach * reach));\n return normalize(mix(dir, normalize(away + 1e-4), clamp(f * 1.4, 0.0, 1.0)));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uDensity;\n vec2 ptr = iPointer.xy / iResolution.y * uDensity;\n float hov = clamp(iPointer.z, 0.0, 1.0);\n // Every root looked at below lies within 7 cells of p.\n clumpBase = floor((p - 7.0) * 0.07);\n clumpGrid = noiseGrid(clumpBase);\n swayBase = floor((p - 7.0) * 0.02 + iTime * 0.15);\n swayGrid = noiseGrid(swayBase);\n vec2 here = strandDir(p, ptr, hov);\n float top = -1.0;\n float across = 0.0;\n float tint = 0.0;\n vec2 topDir = here;\n // Clumping and breeze turn a strand by at most 0.8 * uClump and 0.7 * uSway, and\n // both fields are smooth, so strands rooted within reach of this pixel point\n // inside a cone around its own direction. Roots whose strands can't reach the\n // pixel, or can't rise above the strand already found, are skipped before their\n // directions are worked out. Roots are visited upstream first, so the topmost\n // strand tends to be found early and the rest skipped. (Hovering parts the fur\n // near the pointer in any direction, so the cone isn't used there.)\n float lie = radians(uLie);\n float R = 1.25 * uLength + uWidth;\n float cp = (gridNoise(p * 0.07, clumpBase, clumpGrid) - 0.5) * 1.6 * uClump;\n float sp = uSway * 0.7 * sin(iTime * 1.3 + p.x * 0.05 + p.y * 0.03 + 2.0 * gridNoise(p * 0.02 + iTime * 0.15, swayBase, swayGrid));\n // Bounds on each field's slope: 0.2376 * uClump and 0.10024 * uSway per cell.\n float dc = 0.2376 * uClump * R;\n float ds = 0.10024 * uSway * R;\n vec2 lo = vec2(max(-0.8 * uClump, cp - dc), max(-0.7 * uSway, sp - ds));\n vec2 hi = vec2(min(0.8 * uClump, cp + dc), min(0.7 * uSway, sp + ds));\n float mid = lie + 0.5 * (lo.x + hi.x + lo.y + hi.y);\n // At most 1.54, under a quarter turn.\n float cone = 0.5 * (hi.x - lo.x + hi.y - lo.y) + 0.04;\n vec2 axis = vec2(cos(mid), sin(mid));\n float cosCone = cos(cone);\n float sinCone = sin(cone);\n float reach = 0.16 * uDensity;\n bool parting = uPart * hov > 0.0;\n // The box roots that reach this pixel lie in, relative to it: behind it within\n // the cone (anywhere within reach where the pointer may be parting the fur).\n float back = 1.25 * uLength;\n vec2 e1 = -back * vec2(cos(mid + cone), sin(mid + cone));\n vec2 e2 = -back * vec2(cos(mid - cone), sin(mid - cone));\n vec2 boxLo = min(vec2(0.0), min(e1, e2));\n vec2 boxHi = max(vec2(0.0), max(e1, e2));\n if (-axis.x >= cosCone) boxHi.x = back;\n if (axis.x >= cosCone) boxLo.x = -back;\n if (-axis.y >= cosCone) boxHi.y = back;\n if (axis.y >= cosCone) boxLo.y = -back;\n float ptrGap = max(length(p - ptr) - R, 0.0);\n if (uPart * hov * exp(-ptrGap * ptrGap / (reach * reach)) * 1.4 > 0.02) {\n boxLo = vec2(-back);\n boxHi = vec2(back);\n }\n boxLo += p - uWidth;\n boxHi += p + uWidth;\n bvec2 up = lessThan(here, vec2(0.0));\n for (int layer = 0; layer < 3; layer++) {\n float fl = float(layer);\n vec2 off = vec2(0.37, 0.71) * fl;\n // Each layer's 5 x 5 cells around the middle of the strands through here,\n // cut to those whose roots (in [id + off, id + off + 1)) can lie in the box.\n vec2 base = floor(p - here * uLength * 0.5 - off);\n ivec2 first = ivec2(max(ceil(boxLo - off - 1.0), base - 2.0) - base);\n ivec2 last = ivec2(min(floor(boxHi - off), base + 2.0) - base);\n for (int row = 0; row < 5; row++) {\n if (row > last.y - first.y) break;\n int j = up.y ? last.y - row : first.y + row;\n for (int column = 0; column < 5; column++) {\n if (column > last.x - first.x) break;\n int i = up.x ? last.x - column : first.x + column;\n vec2 id = base + vec2(float(i), float(j));\n vec2 h = hash22(id + fl * 31.7);\n vec2 root = id + off + h;\n float len = uLength * (0.75 + 0.5 * h.y);\n vec2 rp = p - root;\n float r2 = dot(rp, rp);\n // Too far away, or can't rise above the strand already found (along <= r / len).\n float reachLen = len + uWidth;\n if (r2 >= reachLen * reachLen || top >= 1.0 || (top >= 0.0 && r2 <= top * top * len * len)) continue;\n bool parted = false;\n if (parting) {\n vec2 away = root - ptr;\n parted = uPart * hov * exp(-dot(away, away) / (reach * reach)) * 1.4 > 0.02;\n }\n if (r2 > uWidth * uWidth && !parted) {\n // Off the cone widened by the strand's width: it can't cover this pixel.\n float da = dot(rp, axis);\n if (da < cosCone * sqrt(r2 - uWidth * uWidth) - sinCone * uWidth) continue;\n }\n vec2 dir = strandDir(root, ptr, hov);\n float along = clamp(dot(rp, dir) / len, 0.0, 1.0);\n float w = uWidth * (1.0 - 0.75 * along);\n float dist = length(rp - dir * along * len);\n if (dist < w && along > top) {\n top = along;\n across = dist / w;\n tint = h.x;\n topDir = dir;\n }\n }\n }\n }\n float clump = vnoise(p * 0.07 + 3.0);\n vec3 skin = uRoot * 0.3;\n vec3 col = skin;\n if (top >= 0.0) {\n float h = top;\n col = mix(uRoot, uTip, pow(h, 0.8)) * (0.85 + 0.3 * tint);\n col *= 0.45 + 0.55 * h;\n col *= 0.75 + 0.25 * sqrt(max(1.0 - across * across, 0.0));\n // Strands facing the light (top left) catch a sheen.\n col += uTip * 0.25 * pow(max(dot(topDir, normalize(vec2(-0.6, 0.8))), 0.0), 4.0) * h;\n }\n col *= 0.85 + 0.3 * clump * uClump;\n fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}`,\n ),\n presets: [\n { name: \"Moss\", values: { uRoot: [0.1, 0.2, 0.04], uTip: [0.64, 0.79, 0.23], uDensity: 120, uLength: 1.2, uWidth: 0.3, uSway: 0.12, uClump: 0.9 } },\n { name: \"Fur\", values: { uRoot: [0.23, 0.14, 0.09], uTip: [0.85, 0.63, 0.4], uDensity: 40, uLength: 2.6, uWidth: 0.2, uSway: 0.35, uClump: 0.5 } },\n { name: \"Grass\", values: { uRoot: [0.08, 0.25, 0.07], uTip: [0.71, 0.89, 0.42], uDensity: 28, uLength: 3.5, uWidth: 0.14, uLie: 90, uSway: 0.8, uClump: 0.3 } },\n ],\n};\n\n/** More organic life: growth, cells, veins and creatures (category \"organic\"). */\nexport const growthShaders: ShaderEffect[] = [reactionDiffusion, cellDivision, coralGrowth, veins, ferrofluid, jellyfish, fur];\n","import { 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 * Stickers in shaders. The foil sticker reads the pointer built-ins the\n * wrapper declares (`iPointer`: xy pixels, z how hovered 0–1), drifting on\n * its own while nothing hovers it, which `uDemo` turns off.\n */\n\n/**\n * `hoverPoint(demo, idle)`: the point to tilt towards, in pixels, and how\n * strongly (z): the pointer while it is over the canvas, else (with the demo\n * on) a slow drift at strength `idle`.\n */\nconst HOVER = `\nvec3 hoverPoint(bool demo, float idle) {\n vec2 drift = iResolution.xy * (0.5 + vec2(0.3 * sin(iTime * 0.63), 0.24 * 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/** `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 holoFoilSticker: ShaderEffect = {\n kind: \"shader\",\n id: \"holo-foil-sticker\",\n name: \"Holo foil sticker\",\n description: \"A die-cut sticker cut from any shape's outline, with a thick white border, a drop shadow and holographic foil whose rainbow and sparkles shift as the pointer tilts it.\",\n category: \"sticker\",\n video: \"none\",\n tags: [\"sticker\", \"holographic\", \"foil\", \"die-cut\", \"interactive\", \"hover\", \"rainbow\", \"sparkle\", \"iridescent\"],\n transparent: true,\n source: glsl(\n `// Holo foil sticker: the mask's shape, grown into a white die-cut border, with a soft shadow and rainbow foil that tilts with the pointer.\nuniform sampler2D uMask; // @control wrap=clamp default=${textImage(\"WOW\")} label=\"Shape (alpha)\"\nuniform vec3 uTint; // @control color default=#DADDEA label=\"Face tint\"\nuniform vec3 uBorderColor; // @control color default=#FFFFFF label=\"Border\"\nuniform float uBorder; // @control min=0 max=0.08 default=0.035 label=\"Border width\"\nuniform float uSize; // @control min=0.3 max=1 default=0.8 label=\"Size\"\nuniform float uFoil; // @control min=0 max=1 default=0.85 label=\"Foil\"\nuniform float uSparkle; // @control min=0 max=1 default=0.7 label=\"Sparkle\"\nuniform float uShadow; // @control min=0 max=1 default=0.45 label=\"Shadow\"\nuniform float uTilt; // @control min=0 max=1 default=0.6 label=\"Tilt\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\nuniform vec3 uBackground; // @control color default=#EEF0F6 label=\"Background\"\nuniform float uBackgroundAlpha; // @control min=0 max=1 default=0 label=\"Background opacity\"`,\n HASH,\n NOISE,\n HOVER,\n OVER,\n `// The mask's alpha at uv, nothing outside the picture (so an opaque edge does not smear).\nfloat maskAt(vec2 uv, float lod) {\n vec2 inside = step(vec2(0.0), uv) * step(uv, vec2(1.0));\n return textureLod(uMask, uv, lod).a * inside.x * inside.y;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 res = iResolution.xy;\n float px = min(res.x, res.y);\n vec2 ts = vec2(textureSize(uMask, 0));\n float ia = ts.x / max(ts.y, 1.0);\n // The picture's box, fitted to the frame with room round it for the border and shadow.\n float w = min(res.x * uSize, res.y * uSize * ia);\n vec2 hs = vec2(w, w / ia) * 0.5;\n vec3 hp = hoverPoint(uDemo, 0.7);\n vec2 tilt = clamp((hp.xy - 0.5 * res) / (0.5 * res), -1.0, 1.0) * hp.z * uTilt;\n // Fake perspective: the side the pointer is on leans away.\n vec2 s = (fragCoord - 0.5 * res) / hs;\n vec2 sn = (fragCoord - 0.5 * res) / max(hs.x, hs.y);\n vec2 q = s / max(1.0 - 0.12 * dot(sn, tilt), 0.2);\n vec2 uv = q * 0.5 + 0.5;\n vec2 toUv = 1.0 / (2.0 * hs);\n vec2 rb = uBorder * px * toUv;\n\n // Die cut: the shape grown by the border width (its furthest reach in 24 directions, at three radii,\n // the outer ones read blurrier so the cut comes out round rather than scalloped).\n float a0 = maskAt(uv, 0.0);\n float reach = a0;\n for (int i = 0; i < 24; i++) {\n float ang = float(i) * 0.261799;\n vec2 d = vec2(cos(ang), sin(ang)) * rb;\n reach = max(reach, maskAt(uv + d * 0.85, 2.0));\n reach = max(reach, maskAt(uv + d * 0.55, 1.0));\n reach = max(reach, maskAt(uv + d * 0.28, 0.5));\n }\n float cut = smoothstep(0.2, 0.5, reach);\n float face = smoothstep(0.35, 0.65, a0);\n\n // Shadow: the grown shape blurred (a coarse mip level), dropped and pushed away from the pointer.\n vec2 drop = (vec2(0.0, 0.03) + tilt * 0.025) * px * toUv;\n float sh = 0.0;\n for (int i = 0; i < 8; i++) {\n float ang = float(i) * 0.785398 + 0.39;\n sh += maskAt(uv + drop + vec2(cos(ang), sin(ang)) * rb * 1.3, 3.5);\n }\n sh = smoothstep(0.0, 0.45, sh / 8.0) * uShadow;\n\n vec2 fuv = uv * vec2(ia, 1.0);\n // The face: the picture's own colour (unpremultiplied) under the tint.\n vec4 tex = textureLod(uMask, clamp(uv, 0.0, 1.0), 0.0);\n vec3 base = tex.rgb / max(tex.a, 1e-3) * uTint;\n // Foil: rainbow bands that slide with the tilt, plus a fine diffraction grating whose colours run faster.\n float nz = vnoise(fuv * 5.0);\n float phase = dot(fuv, vec2(0.45, 0.8)) * 0.9 + tilt.x * 1.1 - tilt.y * 0.8 + nz * 0.35 + iTime * 0.04;\n vec3 rainbow = 0.5 + 0.5 * cos(6.28318 * (phase + vec3(0.0, 0.33, 0.67)));\n float grating = 0.5 + 0.5 * sin((fuv.x * 0.6 + fuv.y) * 240.0 + tilt.x * 18.0);\n vec3 diffraction = 0.5 + 0.5 * cos(6.28318 * (phase * 2.4 + grating * 0.18 + vec3(0.0, 0.33, 0.67)));\n vec3 holo = mix(rainbow, diffraction, 0.35);\n float band = exp(-pow(dot(sn, normalize(vec2(1.0, 1.4))) * 1.4 - (tilt.x + tilt.y) * 0.9, 2.0) * 2.5);\n float foil = uFoil * (0.4 + 0.6 * band);\n // Overlay blend keeps the face's darks; light faces (white text) take the foil's colour as metal would.\n vec3 lit = mix(2.0 * base * holo, 1.0 - 2.0 * (1.0 - base) * (1.0 - holo), step(0.5, base));\n vec3 metal = base * pow(holo, vec3(1.4)) * (0.85 + 0.3 * grating) * 1.1;\n vec3 col = mix(base, mix(lit, metal, 0.65), foil);\n // A fine dark line where the print meets the border.\n col *= 1.0 - 0.4 * smoothstep(0.25, 0.5, a0) * (1.0 - smoothstep(0.5, 0.85, a0));\n // Sparkles: glints in a grid, each catching the light at its own tilt.\n vec2 cell = floor(fuv * 26.0);\n vec2 inCell = fract(fuv * 26.0) - 0.5 - (hash22(cell) - 0.5) * 0.5;\n float h = hash12(cell + 7.1);\n float catchLight = pow(0.5 + 0.5 * sin(h * 60.0 + iTime * 2.2 + dot(tilt, vec2(9.0, 7.0))), 14.0);\n float glint = exp(-abs(inCell.x) * 38.0) * exp(-abs(inCell.y) * 7.0) + exp(-abs(inCell.y) * 38.0) * exp(-abs(inCell.x) * 7.0);\n col += step(0.82, h) * catchLight * glint * uSparkle * 1.6;\n\n // The border: white vinyl with a faint sheen of the foil, and a slightly darker cut edge.\n vec3 border = uBorderColor * (0.94 + 0.06 * holo);\n float edge = 1.0 - smoothstep(0.22, 0.6, reach);\n border *= 1.0 - 0.12 * edge;\n vec3 sticker = mix(border, col, face);\n // Gloss: a glare that follows the pointer, and a soft sheen from the top.\n vec2 g = sn - tilt * 0.7;\n sticker += 0.35 * exp(-dot(g, g) * 2.5) + 0.06 * smoothstep(-0.2, 1.0, sn.y);\n\n vec4 acc = vec4(uBackground * uBackgroundAlpha, uBackgroundAlpha);\n acc = over(acc, vec3(0.0), sh * (1.0 - cut));\n acc = over(acc, clamp(sticker, 0.0, 1.0), cut);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Heart\", values: { uMask: SAMPLE_IMAGES.heart, uTint: [1, 1, 1], uFoil: 0.6 } },\n { name: \"Logo on card\", values: { uMask: SAMPLE_IMAGES.logo, uBackgroundAlpha: 1, uBackground: [0.12, 0.13, 0.18], uSize: 0.7 } },\n { name: \"Thick cut\", values: { uBorder: 0.06, uFoil: 1, uSparkle: 1 } },\n ],\n};\n\nexport const stickerPeelReveal: ShaderEffect = {\n kind: \"shader\",\n id: \"sticker-peel-reveal\",\n name: \"Sticker peel reveal\",\n description: \"A picture peels back like a sticker from its bottom-right corner, rolling diagonally over itself with a curl highlight and shadow, to reveal a second picture underneath. Loops back and forth; or turn Animate off and set Progress.\",\n category: \"sticker\",\n video: \"transition\",\n tags: [\"sticker\", \"transition\", \"peel\", \"curl\", \"page\", \"image\", \"reveal\"],\n loop: 4,\n source: glsl(\n `// Sticker peel: the From picture peels from a corner along the diagonal, its paper backing curled over it, revealing the To picture. Progress runs 0 → 1 → 0 when animated.\nuniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Sticker image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Underneath\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.4 label=\"Progress (when still)\"\nuniform float uCurl; // @control min=0.03 max=0.4 default=0.14 label=\"Curl radius\"\nuniform vec3 uBack; // @control color default=#F4F1EA label=\"Backing\"\nuniform float uShowThrough; // @control min=0 max=0.5 default=0.1 label=\"Print showing through\"\nuniform float uShadow; // @control min=0 max=1 default=0.6 label=\"Shadow\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// How far inside the peeled flap a point is (negative outside it), in height units, and its distance s past the fold.\n// The flap is the part from the corner to the fold, turned back over the picture: round a curl of radius r near the fold, then flat.\nfloat flapMargin(vec2 pos, vec2 corner, vec2 dir, float aspect, float fold, float r, out float s, out vec2 orig) {\n float t = dot(pos - corner, dir);\n s = t - fold;\n float l = s < r ? r * asin(clamp(s / r, 0.0, 1.0)) : r * 1.5708 + (s - r);\n orig = pos + dir * ((fold - l) - t);\n float m = min(min(orig.x, aspect - orig.x), min(orig.y, 1.0 - orig.y));\n return min(m, s);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 res = iResolution.xy;\n float aspect = res.x / res.y;\n float p = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n vec2 pos = fragCoord / res.y;\n vec2 corner = vec2(aspect, 0.0);\n vec2 dir = normalize(vec2(-aspect, 1.0));\n float r = uCurl;\n // The fold travels from the corner past the far one, far enough for the curl to leave too.\n float fold = p * (length(vec2(aspect, 1.0)) + r * 2.2);\n float s;\n vec2 orig;\n float m = flapMargin(pos, corner, dir, aspect, fold, r, s, orig);\n vec2 uv = fragCoord / res;\n vec4 col = s > 0.0 ? pictureRGBA(uFrom, uv) : pictureRGBA(uTo, uv);\n // The lifted flap's shadow: soft, thrown down and right, and over the revealed picture by the curl.\n float soft = 0.012 + 0.12 * r;\n float s2;\n vec2 o2;\n float m2 = flapMargin(pos - vec2(0.5, -0.8) * soft, corner, dir, aspect, fold, r, s2, o2);\n float shadow = smoothstep(-soft, soft, m2) * uShadow * 0.6 * smoothstep(0.0, 0.03, p);\n float crease = s < 0.0 ? exp(s / (0.35 * r + 0.01)) * uShadow * 0.45 * smoothstep(0.0, 0.03, p) : 0.0;\n col.rgb *= 1.0 - max(shadow, crease);\n // The flap: the paper backing, lit round the curl, with the print faintly showing through mirrored.\n float flap = smoothstep(-1.0 / res.y, 1.0 / res.y, m);\n if (flap > 0.0) {\n vec3 back = mix(uBack, pictureRGBA(uFrom, orig / vec2(aspect, 1.0)).rgb, uShowThrough);\n float x = clamp(s / r, 0.0, 3.0);\n float light = 0.68 + 0.42 * smoothstep(0.0, 0.6, x) - 0.1 * smoothstep(0.6, 1.8, x);\n light += 0.22 * exp(-pow((x - 0.55) / 0.14, 2.0));\n col = mix(col, vec4(clamp(back * light, 0.0, 1.0), 1.0), flap);\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Tight curl\", values: { uCurl: 0.06, uShadow: 0.8 } },\n { name: \"Kraft backing\", values: { uBack: [0.82, 0.7, 0.52], uShowThrough: 0, uCurl: 0.2 } },\n ],\n};\n\n/** Stickers in shaders: holographic foil and peeling. */\nexport const stickerShaders: ShaderEffect[] = [holoFoilSticker, stickerPeelReveal];\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 video: \"none\",\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 video: \"filter\",\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 video: \"filter\",\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\nvec4 smin4(vec4 a, vec4 b, float k) {\n k = max(k, 1e-4);\n vec4 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}\n\n// Distances to the liquid (negative inside) at four nearby points (xs, ys) at\n// once: a lip along the slumped edge, drips hanging from it, the puddle. Each\n// point sees the drips of the five columns around its own; those columns'\n// drips are worked out once for all four. edge and pool are edgeY and poolY\n// at the points; a point's distance only matters below its entry in matter.\nvec4 liquid(vec4 xs, vec4 ys, vec4 edge, vec4 pool, float m, vec4 matter) {\n float n = float(uDrips);\n float grow = smoothstep(0.0, 0.2, m);\n vec4 e = edge + 0.01 * (1.0 - grow);\n float lip = 0.022 * grow;\n vec4 d = max(ys - e, e - lip - ys);\n vec4 cs = floor(xs * n);\n float c = cs.y;\n // Where any drip's top and head can be, from the bounds of edgeY and poolY.\n float topMin = 1.0 - m * 0.34 - lip * 0.5;\n float topMax = 1.0 - m * 0.04 - lip * 0.5;\n float poolMin = m * 0.088 - 0.006;\n // A drip farther than this beyond where a distance matters can't change it\n // there: the blends that follow can pull a distance down by at most this much.\n vec4 reach = matter + 0.16;\n for (int k = -3; k <= 3; k++) {\n float ci = c + float(k);\n bvec4 near = lessThanEqual(abs(cs - ci), vec4(2.0));\n if (!any(near)) continue;\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 // The nearest this drip can be to each point, before working out its shape:\n // skip it if it can't change any of them.\n float f = pow(m, 1.4) * min(0.2 + 0.95 * h.y, 1.0);\n float headMin = min(topMin, topMin * (1.0 - f) + f * poolMin);\n vec4 gap = vec4(abs(xs - xi) * aspect);\n vec4 rise = max(max(headMin - ys, ys - topMax), 0.0);\n vec4 nearest = sqrt(gap * gap + rise * rise) - 1.3 * w;\n bvec4 counts = bvec4(vec4(near) * step(nearest, d + 0.012 * grow) * step(nearest, reach));\n if (!any(counts)) continue;\n float top = edgeY(xi, m) - lip * 0.5;\n float len = f * max(top - poolY(xi, m), 0.0);\n float head = top - len;\n vec4 along = clamp(ys, head, top);\n // A stem thinning as it runs, then a round, heavier head.\n vec4 r = w * mix(vec4(0.85), vec4(0.6), smoothstep(top, top - 0.3, ys));\n r = mix(r, vec4(w * 1.3), smoothstep(head + 3.0 * w, head, ys));\n vec4 dx = (xs - xi) * aspect;\n vec4 dy = ys - along;\n vec4 dd = smin4(d, sqrt(dx * dx + dy * dy) - r, 0.012 * grow);\n d = mix(d, dd, near);\n }\n return smin4(d, ys - pool, 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 liquid is sampled at four points: under the shadow, here, and a step\n // right and up for its normal. They share three columns of x.\n float eps = 0.0015;\n vec4 xs = uv.x + vec4(-0.004, 0.0, eps / aspect, 0.0);\n vec4 ys = uv.y + vec4(0.009, 0.0, 0.0, eps);\n vec3 edge3 = vec3(edgeY(xs.x, m), edgeY(xs.y, m), edgeY(xs.z, m));\n vec3 pool3 = vec3(poolY(xs.x, m), poolY(xs.y, m), poolY(xs.z, m));\n // The shadow shows below 0.012, the liquid below 4 px (its neighbours a little farther).\n vec4 liq = liquid(xs, ys, edge3.xyzy, pool3.xyzy, m, vec4(0.012, 4.0 * px, vec2(4.0 * px + 0.005)));\n\n // The picture slumped under its edge: squashed towards the bottom, stretched thin at the top.\n float e = edge3.y;\n float h = clamp(uv.y / e, 0.0, 1.0);\n float ys0 = 1.0 - pow(1.0 - h, 1.0 + m * 1.3);\n float xs0 = uv.x + m * 0.006 * sin(uv.y * 40.0 + uv.x * 13.0);\n vec4 col = pictureRGBA(uImage, vec2(xs0, ys0));\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 = liq.x;\n col.rgb *= 1.0 - 0.4 * smoothstep(0.012, -0.004, shadow) * smoothstep(0.0, 0.1, m);\n\n float d = liq.y;\n if (d < 4.0 * px) {\n vec2 g = vec2(liq.z - d, liq.w - 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(pool3.y + 0.04, pool3.y - 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 video: \"filter\",\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 video: \"none\",\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 video: \"none\",\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 video: \"filter\",\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 // Past this distance a streak's glow is far below one level, so sparks farther\n // away are skipped, and so is the whole loop outside the fountain's reach.\n float margin = 30.0 * w;\n float vmax = 1.35 * uHeight * 1.25;\n float xmax = vmax * sin(min(uSpread * 1.2, 1.5708)) * (1.0 - exp(-k * 1.8)) / k;\n float apex = log(1.0 + vmax * k / g) / k;\n float ea = (1.0 - exp(-k * apex)) / k;\n float ymax = vmax * ea - g / k * (apex - ea);\n vec2 rel = p - base;\n bool inReach = abs(rel.x) < xmax + margin && rel.y > -0.01 - margin && rel.y < ymax + margin;\n for (int j = 0; j < 112; j++) {\n if (!inReach) break;\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 // A spark only ever moves to its own side of the base.\n if (a * rel.x < 0.0 && abs(rel.x) > margin) continue;\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 if (any(lessThan(p, min(head, tail) - margin)) || any(greaterThan(p, max(head, tail) + margin))) 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 video: \"stills\",\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 video: \"stills\",\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 video: \"stills\",\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 video: \"stills\",\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 video: \"stills\",\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 video: \"filter\",\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 video: \"stills\",\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 video: \"stills\",\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 video: \"stills\",\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 video: \"stills\",\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 video: \"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 video: \"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 video: \"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 video: \"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 `// Where cell c's particle lands: cells trade places around each 2 × 2 block, turned 1–3 steps.\n// Round the block the corners go (0, 0), (1, 0), (1, 1), (0, 1); worked out rather than looked up in an array.\nvec2 landing(vec2 c) {\n vec2 block = floor(c * 0.5);\n vec2 local = c - block * 2.0;\n float i = local.y < 0.5 ? local.x : 3.0 - local.x;\n float turn = 1.0 + floor(hash12(block + 7.3) * 2.999);\n float r = mod(i + turn, 4.0);\n return block * 2.0 + vec2(r > 0.5 && r < 2.5 ? 1.0 : 0.0, r > 1.5 ? 1.0 : 0.0);\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 // How far a particle's corners stray from the straight line between its two places: the curl, then its turned corners.\n float reach = max(0.7072, 0.6 * abs(uScatter + uSpin * 0.3) + 0.4951) + 0.01;\n // Particles travel at most about 1.5 cells, so the 5 × 5 cells around are every candidate;\n // of those, only the cells within reach (one cell either side of the block) need looking at.\n vec2 lo = max(base - 2.0, ceil(p - 1.5 - reach));\n vec2 hi = min(base + 2.0, floor(p + 0.5 + reach));\n for (int j = 0; j < 5; j++) {\n if (lo.y + float(j) > hi.y) break;\n for (int i = 0; i < 5; i++) {\n if (lo.x + float(i) > hi.x) break;\n vec2 c = lo + vec2(float(i), float(j));\n // It stays in its 2 × 2 block, so skip it if this pixel is out of its reach from there.\n vec2 corner = c - 2.0 * floor(c * 0.5);\n if (any(lessThan(p, c + 0.5 - corner - reach)) || any(greaterThan(p, c + 1.5 - corner + reach))) continue;\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 float z = h.y + lift;\n // Behind what is already here, or (now its lift is known) out of reach: skip it before working out where it is.\n if (z <= top) continue;\n float near = 0.6 * abs(uScatter + uSpin * 0.3) * lift + 0.7072 * (1.0 - 0.3 * lift) + 0.01;\n if (any(lessThan(p, c + 0.5 - corner - near)) || any(greaterThan(p, c + 1.5 - corner + near))) continue;\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 // Out of reach of its corners, however it is turned.\n vec2 rel = p - pos;\n if (dot(rel, rel) > 0.501 * size * size) continue;\n float angle = (h.y - 0.5) * 6.28318 * uSpin * lift;\n vec2 l = rot(-angle) * rel / size;\n float m = max(abs(l.x), abs(l.y));\n if (m <= 0.5) {\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 video: \"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 video: \"none\",\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 video: \"filter\",\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 video: \"filter\",\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 video: \"filter\",\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// No point is further than this from its own shard's site (sites sit in the middle 70% of each cell).\nconst float SHARD_REACH = 1.25;\n\n// Whether grid point q lies on shard c: c's site is the nearest of those in the 3 × 3 cells around q.\nbool onShard(vec2 q, vec2 c) {\n vec2 base = floor(q);\n vec2 off = c - base;\n if (abs(off.x) > 1.0 || abs(off.y) > 1.0) return false;\n float own = distance(q, shardSite(c));\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 n = base + vec2(float(i), float(j));\n if (n != c && distance(q, shardSite(n)) < own) return false;\n }\n }\n return true;\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 float top = -1.0;\n vec2 hitQ = vec2(0.0);\n float hitA = 0.0;\n // Every shard that could reach this pixel (of the 5 × 5 cells around, those whose site, wherever it sits\n // in its cell and however far it is thrown, lands close enough); the one on top (highest h.y) wins.\n float slack = 0.6 * k + SHARD_REACH;\n vec2 lo = max(base - 2.0, ceil((p - slack) / grow - 0.85));\n vec2 hi = min(base + 2.0, floor((p + slack) / grow - 0.15));\n for (int j = 0; j < 5; j++) {\n if (lo.y + float(j) > hi.y) break;\n for (int i = 0; i < 5; i++) {\n if (lo.x + float(i) > hi.x) break;\n vec2 c = lo + vec2(float(i), float(j));\n vec2 h = hash22(c + 41.7);\n if (h.y <= top) continue;\n vec2 site = shardSite(c);\n vec2 centre = site * grow + (h - 0.5) * 1.2 * k;\n vec2 rel = p - centre;\n if (dot(rel, rel) > SHARD_REACH * SHARD_REACH) continue;\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) * rel + site;\n if (onShard(q, c)) {\n top = h.y;\n hitQ = q;\n hitA = a;\n }\n }\n }\n vec4 col = vec4(uBackground, uBackdropAlpha);\n if (top > -1.0) {\n vec2 uv = hitQ / uCount * iResolution.y / iResolution.xy + 0.5;\n col = pictureRGBA(uImage, uv);\n col.rgb *= 1.0 - 0.35 * k * abs(sin(hitA));\n col.rgb += k * 0.35 * smoothstep(0.06, 0.0, shardAt(hitQ).z);\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 video: \"filter\",\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 video: \"filter\",\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 video: \"filter\",\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 video: \"filter\",\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 video: \"filter\",\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 video: \"stills\",\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 video: \"filter\",\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 video: \"filter\",\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 video: \"filter\",\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 `// Sums of colour and colour² over four overlapping squares (down-left, down-right, up-left, up-right),\n// each pixel read once: the shared middle row and column count towards both squares they border.\n// A macro so the image and the test card each get their own loop, rather than every read paying for both.\n#define GATHER(TAP) { \\\\\n vec3 c = TAP(uv); \\\\\n vec3 cc = c * c; \\\\\n m0 = c; m1 = c; m2 = c; m3 = c; \\\\\n s0 = cc; s1 = cc; s2 = cc; s3 = cc; \\\\\n for (int i = 1; i <= 8; i++) { \\\\\n if (i > uRadius) break; \\\\\n float o = float(i); \\\\\n c = TAP(uv - vec2(o * px.x, 0.0)); cc = c * c; m0 += c; s0 += cc; m2 += c; s2 += cc; \\\\\n c = TAP(uv + vec2(o * px.x, 0.0)); cc = c * c; m1 += c; s1 += cc; m3 += c; s3 += cc; \\\\\n c = TAP(uv - vec2(0.0, o * px.y)); cc = c * c; m0 += c; s0 += cc; m1 += c; s1 += cc; \\\\\n c = TAP(uv + vec2(0.0, o * px.y)); cc = c * c; m2 += c; s2 += cc; m3 += c; s3 += cc; \\\\\n } \\\\\n for (int j = 1; j <= 8; j++) { \\\\\n if (j > uRadius) break; \\\\\n for (int i = 1; i <= 8; i++) { \\\\\n if (i > uRadius) break; \\\\\n vec2 o = vec2(float(i), float(j)) * px; \\\\\n c = TAP(uv - o); m0 += c; s0 += c * c; \\\\\n c = TAP(uv + vec2(o.x, -o.y)); m1 += c; s1 += c * c; \\\\\n c = TAP(uv + vec2(-o.x, o.y)); m2 += c; s2 += c * c; \\\\\n c = TAP(uv + o); m3 += c; s3 += c * c; \\\\\n } \\\\\n } \\\\\n}\n\nvec3 imageTap(vec2 uv) {\n return overBackdrop(texture(uImage, uv)).rgb;\n}\n\nvec3 cardTap(vec2 uv) {\n return testCard(fract(uv));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 px = 1.0 / iResolution.xy;\n vec3 m0, m1, m2, m3, s0, s1, s2, s3;\n if (textureSize(uImage, 0).x > 1) GATHER(imageTap) else GATHER(cardTap)\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 { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/*\n * These follow `iTrail`, the built-in the wrapper declares: where the pointer\n * has just been, newest first (xy pixels, z the `iTime` of the point, w 1 for\n * a point, 0 for an empty slot), about one point a frame. Thumbnails and\n * recordings have no pointer, so while the canvas is not hovered (or nothing\n * has moved over it yet) each one, with its `uDemo` control on, makes up a\n * trail of its own along a smooth looping path.\n */\n\n/**\n * `trailPoint(i, demo)`: trail point `i`, newest first, as (x, y, time, 1),\n * or zeros for an empty slot. With the demo on and the pointer not over the\n * canvas (or no trail yet), the points are a looping path taken at `iTime`\n * and then every `dt` seconds back, on a grid of times so they stay put\n * between frames like real points do; the drawing code is the same for both.\n * `speed` is how fast the demo goes round. `TRAIL_POINTS` is the size of\n * `iTrail` (32 points, at most one every 1/30 s: about a second of path).\n * With `walk`, also the cheaper ways through the trail of {@link trailWalk}.\n */\nfunction trailHelper(dt: number, speed: number, walk = false): string {\n return `\nconst int TRAIL_POINTS = 32;\nvec2 demoPath(float t) {\n float s = t * ${speed.toFixed(3)};\n vec2 q = vec2(0.34 * sin(s) + 0.05 * sin(s * 2.3 + 1.0), 0.27 * sin(s * 2.0 + 0.4) + 0.04 * cos(s * 3.1));\n return iResolution.xy * (0.5 + q);\n}\n// Whether a and b are either side of a jump (the pointer left and came back elsewhere), not one stroke.\nbool trailJump(vec4 a, vec4 b) {\n return a.z - b.z > 0.25 && length(a.xy - b.xy) > 0.03 * iResolution.y;\n}\nvec4 trailPoint(int i, bool demo) {\n if (!demo || (iTrail[0].w > 0.5 && iPointer.z > 0.0)) return iTrail[i];\n const float dt = ${dt.toFixed(5)};\n float t = i == 0 ? iTime : (floor(iTime / dt) + 1.0 - float(i)) * dt;\n return vec4(demoPath(t), t, 1.0);\n}${walk ? `\\n${trailWalk(dt, speed)}` : \"\"}`.trim();\n}\n\n/**\n * For walking the whole trail each pixel, cheaply: `trailLive(demo)` once,\n * then `trailAt(i, live)` gives what `trailPoint(i, demo)` does; or, going\n * through the points in order, `trailFrom(i, live)` once and `trailNext(live)`\n * for points i, i + 1, …, which steps the demo path's sines and cosines on\n * by a fixed turn instead of working each one out again.\n */\nfunction trailWalk(dt: number, speed: number): string {\n // The demo path's four phases, as multiples of s, and how far each turns back per point.\n const rates = [1, 2.3, 2, 3.1];\n const turn = rates.map((r) => r * dt * speed);\n const vec = (f: (x: number) => number) => `vec4(${turn.map((x) => f(x).toFixed(8)).join(\", \")})`;\n return `\nbool trailLive(bool demo) {\n return !demo || (iTrail[0].w > 0.5 && iPointer.z > 0.0);\n}\nvec4 trailAt(int i, bool live) {\n if (live) return iTrail[i];\n const float dt = ${dt.toFixed(5)};\n float t = i == 0 ? iTime : (floor(iTime / dt) + 1.0 - float(i)) * dt;\n return vec4(demoPath(t), t, 1.0);\n}\nint gWalkI;\nfloat gWalkBase;\nvec4 gWalkCos;\nvec4 gWalkSin;\n// Starts a walk at point i (1 or more).\nvoid trailFrom(int i, bool live) {\n gWalkI = i;\n if (live) return;\n const float dt = ${dt.toFixed(5)};\n gWalkBase = floor(iTime / dt) + 1.0;\n float s = (gWalkBase - float(i)) * dt * ${speed.toFixed(3)};\n vec4 phase = vec4(s, s * 2.3 + 1.0, s * 2.0 + 0.4, s * 3.1);\n gWalkCos = cos(phase);\n gWalkSin = sin(phase);\n}\n// The walk's next point: as trailAt(i, live) for i = the start, then one more each call.\nvec4 trailNext(bool live) {\n int i = gWalkI;\n gWalkI++;\n if (live) return iTrail[min(i, TRAIL_POINTS - 1)];\n const float dt = ${dt.toFixed(5)};\n vec2 q = vec2(0.34 * gWalkSin.x + 0.05 * gWalkSin.y, 0.27 * gWalkSin.z + 0.04 * gWalkCos.w);\n vec4 point = vec4(iResolution.xy * (0.5 + q), (gWalkBase - float(i)) * dt, 1.0);\n const vec4 turnCos = ${vec(Math.cos)};\n const vec4 turnSin = ${vec(Math.sin)};\n vec4 c = gWalkCos * turnCos + gWalkSin * turnSin;\n gWalkSin = gWalkSin * turnCos - gWalkCos * turnSin;\n gWalkCos = c;\n return point;\n}`.trim();\n}\n\n/** `segment(p, a, b)`: distance from p to the segment ab (x) and how far along it the nearest point is, 0–1 (y). */\nconst SEGMENT = `\nvec2 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-10), 0.0, 1.0);\n return vec2(length(p - a - ab * t), t);\n}`.trim();\n\n/** `catmull(p0, p1, p2, p3, t)`: the Catmull-Rom spline from p1 to p2. */\nconst CATMULL = `\nvec2 catmull(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t) {\n float t2 = t * t;\n float t3 = t2 * t;\n return 0.5 * (2.0 * p1 + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (3.0 * p1 - p0 - 3.0 * p2 + p3) * t3);\n}`.trim();\n\n/**\n * `trailBoxDist(p, p0, p1, p2, p3, scale)`: at most the distance from p to the\n * Catmull-Rom spline from p1 to p2 (and to any chords between points on it),\n * all scaled by `scale`: the distance to the box round its Bezier control\n * points, which hold the whole curve.\n */\nconst CATMULL_BOX = `\nfloat trailBoxDist(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3, float scale) {\n vec2 c1 = p1 + (p2 - p0) / 6.0;\n vec2 c2 = p2 - (p3 - p1) / 6.0;\n vec2 lo = min(min(p1, p2), min(c1, c2)) * scale;\n vec2 hi = max(max(p1, p2), max(c1, c2)) * scale;\n return length(max(max(lo - p, p - hi), 0.0));\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\nexport const cometTrail: ShaderEffect = {\n kind: \"shader\",\n id: \"comet-trail\",\n name: \"Comet trail\",\n description: \"A bright comet head on the pointer with a glowing tail that tapers and fades through where it has just been, shading from head to tail colour.\",\n category: \"trail\",\n tags: [\"trail\", \"interactive\", \"hover\", \"cursor\", \"overlay\", \"glow\", \"comet\"],\n transparent: true,\n source: glsl(\n `// Comet trail: a glowing head on the newest trail point and a tail along the rest, thinning and fading with age.\nuniform vec3 uHead; // @control color default=#FFF1C9 label=\"Head colour\"\nuniform vec3 uTail; // @control color default=#5B7CFF label=\"Tail colour\"\nuniform float uWidth; // @control min=0.002 max=0.06 default=0.016 label=\"Tail width\"\nuniform float uHeadSize; // @control min=0 max=0.08 default=0.02 label=\"Head size\"\nuniform float uGlow; // @control min=0 max=3 default=1.2 label=\"Glow\"\nuniform float uLife; // @control min=0.1 max=3 default=1 label=\"Fade time\"\nuniform float uIntensity; // @control min=0.2 max=3 default=1.2 label=\"Intensity\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n trailHelper(1 / 30, 1.6),\n SEGMENT,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n vec4 a = trailPoint(0, uDemo);\n if (a.w < 0.5) {\n fragColor = vec4(0.0);\n return;\n }\n vec2 head = a.xy * px;\n float core = 0.0;\n float halo = 0.0;\n float bestU = 0.0;\n float bestLight = -1.0;\n for (int k = 0; k < TRAIL_POINTS - 1; k++) {\n vec4 b = trailPoint(k + 1, uDemo);\n if (b.w < 0.5 || trailJump(a, b)) break;\n vec2 s = segment(p, a.xy * px, b.xy * px);\n float u = (float(k) + s.y) / float(TRAIL_POINTS - 1);\n float age = iTime - mix(a.z, b.z, s.y);\n float fade = (1.0 - u) * clamp(1.0 - age / uLife, 0.0, 1.0);\n // Thinner towards the tail, and as it fades.\n float w = uWidth * mix(1.0, 0.12, u) * sqrt(fade);\n float sd = s.x - w;\n float c = (1.0 - smoothstep(-px, px, sd)) * fade;\n float g = exp(-max(sd, 0.0) / (uWidth * 1.4 + px)) * fade * fade * uGlow * 0.6;\n core = max(core, c);\n halo = max(halo, g);\n if (c + g > bestLight) {\n bestLight = c + g;\n bestU = u;\n }\n a = b;\n }\n vec3 tint = mix(uHead, uTail, smoothstep(0.0, 0.75, bestU));\n vec3 col = tint * halo + mix(tint, vec3(1.0), 0.45) * core * 1.5;\n // The head: a white-hot core in a halo of its colour, fading once the pointer rests.\n vec4 h0 = trailPoint(0, uDemo);\n float headFade = clamp(1.0 - (iTime - h0.z) / (uLife * 2.0), 0.0, 1.0);\n float r = length(p - head);\n float sz = max(uHeadSize, px);\n col += vec3(1.0, 0.98, 0.94) * exp(-r * r / (sz * sz * 0.35)) * 2.5 * headFade;\n col += uHead * (sz / (r + sz)) * exp(-r / (sz * 8.0)) * uGlow * headFade;\n fragColor = glow(col * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Fireball\", values: { uHead: [1, 0.93, 0.6], uTail: [1, 0.25, 0.05], uWidth: 0.024, uGlow: 1.8 } },\n { name: \"Ice\", values: { uHead: [0.9, 0.98, 1], uTail: [0.3, 0.85, 1], uWidth: 0.01, uLife: 1.2 } },\n { name: \"Laser\", values: { uHead: [1, 0.6, 0.9], uTail: [0.9, 0.1, 0.6], uWidth: 0.005, uHeadSize: 0.008, uGlow: 2.2 } },\n ],\n};\n\nexport const ribbonTrail: ShaderEffect = {\n kind: \"shader\",\n id: \"ribbon-trail\",\n name: \"Ribbon trail\",\n description: \"A shiny two-tone ribbon flowing smoothly after the pointer, twisting over to show its other side as it goes.\",\n category: \"trail\",\n tags: [\"trail\", \"interactive\", \"hover\", \"cursor\", \"overlay\", \"ribbon\", \"spline\"],\n transparent: true,\n source: glsl(\n `// Ribbon trail: a Catmull-Rom ribbon through the trail points; its width swells and pinches to fake a twist.\nuniform vec3 uColorA; // @control color default=#FF4F9A label=\"Front\"\nuniform vec3 uColorB; // @control color default=#4F6BFF label=\"Back\"\nuniform float uWidth; // @control min=0.01 max=0.12 default=0.055 label=\"Width\"\nuniform float uTwist; // @control min=0 max=40 default=14 label=\"Twist\"\nuniform float uSpin; // @control min=0 max=10 default=2 label=\"Spin\"\nuniform float uShine; // @control min=0 max=1 default=0.7 label=\"Shine\"\nuniform float uLife; // @control min=0.1 max=3 default=1.1 label=\"Fade time\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n trailHelper(1 / 30, 1.5, true),\n SEGMENT,\n CATMULL,\n CATMULL_BOX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n bool live = trailLive(uDemo);\n vec4 a = trailAt(0, live);\n vec4 b = trailAt(1, live);\n if (a.w < 0.5 || b.w < 0.5) {\n fragColor = vec4(0.0);\n return;\n }\n vec2 prev = 2.0 * a.xy - b.xy;\n float best = 1e9;\n float bestU = 0.0;\n float bestFace = 1.0;\n float bestV = 0.0;\n float bestFade = 0.0;\n trailFrom(2, live);\n for (int k = 0; k < TRAIL_POINTS - 1; k++) {\n if (b.w < 0.5 || trailJump(a, b)) break;\n // The point after b: read once, it is the next segment's b.\n vec4 c = k + 2 < TRAIL_POINTS ? trailNext(live) : vec4(0.0);\n vec2 next = c.w > 0.5 && !trailJump(b, c) ? c.xy : 2.0 * b.xy - a.xy;\n vec2 lo = min(min(prev, a.xy), min(b.xy, next)) * px - uWidth - 2.0 * px;\n vec2 hi = max(max(prev, a.xy), max(b.xy, next)) * px + uWidth + 2.0 * px;\n // The ribbon is at most half its width either side of the spline: further off than that, a segment cannot be nearer.\n if (all(greaterThan(p, lo)) && all(lessThan(p, hi)) && trailBoxDist(p, prev, a.xy, b.xy, next, px) - uWidth * 0.5 < best) {\n vec2 q0 = a.xy * px;\n for (int j = 1; j <= 4; j++) {\n float t1 = float(j) / 4.0;\n vec2 q1 = catmull(prev, a.xy, b.xy, next, t1) * px;\n vec2 s = segment(p, q0, q1);\n float tt = (float(j - 1) + s.y) / 4.0;\n float u = (float(k) + tt) / float(TRAIL_POINTS - 1);\n float when = mix(a.z, b.z, tt);\n float fade = clamp(1.0 - (iTime - when) / uLife, 0.0, 1.0);\n // The twist travels with the ribbon: its phase is fixed to when each part was laid.\n float face = cos(when * uTwist + iTime * uSpin);\n float w = uWidth * 0.5 * mix(1.0, 0.15, u) * (0.12 + 0.88 * abs(face)) * sqrt(fade);\n float sd = s.x - w;\n if (sd < best) {\n best = sd;\n bestU = u;\n bestFace = face;\n bestV = s.x / max(w, 1e-5);\n bestFade = fade;\n }\n q0 = q1;\n }\n }\n prev = a.xy;\n a = b;\n b = c;\n }\n float cover = (1.0 - smoothstep(-px, px, best)) * smoothstep(0.0, 0.15, bestFade);\n if (cover <= 0.0) {\n fragColor = vec4(0.0);\n return;\n }\n // Front and back in their own colours, each darkening along the ribbon.\n vec3 base = bestFace >= 0.0 ? uColorA : uColorB;\n vec3 other = bestFace >= 0.0 ? uColorB : uColorA;\n base = mix(base, mix(base, other, 0.35) * 0.75, bestU);\n float lit = 0.45 + 0.55 * abs(bestFace);\n vec3 col = base * lit * (1.0 - 0.3 * bestV * bestV);\n // A sheen across the face, brightest where it faces us.\n float spec = uShine * pow(abs(bestFace), 6.0) * exp(-pow((bestV - 0.25) * 2.5, 2.0));\n col = mix(col, vec3(1.0), clamp(spec, 0.0, 1.0));\n fragColor = vec4(col, cover);\n}`,\n ),\n presets: [\n { name: \"Gold and silver\", values: { uColorA: [1, 0.78, 0.25], uColorB: [0.8, 0.83, 0.88], uShine: 1 } },\n { name: \"Silk\", values: { uColorA: [0.95, 0.3, 0.35], uColorB: [0.55, 0.08, 0.15], uTwist: 6, uSpin: 0.5, uShine: 0.4, uWidth: 0.06 } },\n ],\n};\n\nexport const sparkleTrail: ShaderEffect = {\n kind: \"shader\",\n id: \"sparkle-trail\",\n name: \"Sparkle trail\",\n description: \"Twinkling sparkles and four-point stars shed along the pointer's path, each drifting down a little as it fades out.\",\n category: \"trail\",\n tags: [\"trail\", \"interactive\", \"hover\", \"cursor\", \"overlay\", \"sparkle\", \"magic\", \"particles\"],\n transparent: true,\n source: glsl(\n `// Sparkle trail: stars shed at each trail point, twinkling and drifting down as they fade.\nuniform vec3 uColorA; // @control color default=#FFE27A label=\"Colour 1\"\nuniform vec3 uColorB; // @control color default=#9AD9FF label=\"Colour 2\"\nuniform int uCount; // @control min=1 max=4 default=2 label=\"Sparkles per point\"\nuniform float uSize; // @control min=0.005 max=0.06 default=0.022 label=\"Size\"\nuniform float uSpread; // @control min=0 max=0.1 default=0.025 label=\"Spread\"\nuniform float uFall; // @control min=0 max=0.5 default=0.1 label=\"Drift down\"\nuniform float uLife; // @control min=0.2 max=2 default=1 label=\"Lifetime\"\nuniform float uTwinkle; // @control min=0 max=1 default=0.7 label=\"Twinkle\"\nuniform float uIntensity; // @control min=0.2 max=3 default=1.2 label=\"Intensity\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n trailHelper(1 / 40, 1.4, true),\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n vec3 col = vec3(0.0);\n bool live = trailLive(uDemo);\n // How far a sparkle's light reaches from where it is (twice its largest size), and its sideways sway.\n float reach = 2.5 * uSize + px;\n float side = uSpread + 0.012 + reach;\n // Point 0 is still moving with the pointer, so sparkles come from the settled points after it.\n trailFrom(1, live);\n for (int k = 1; k < TRAIL_POINTS; k++) {\n vec4 q = trailNext(live);\n if (q.w < 0.5) break;\n float age = iTime - q.z;\n if (age < 0.0 || age > uLife) continue;\n // Skip points none of whose sparkles (spread, swaying and drifting down) can reach this pixel.\n vec2 rel = p - q.xy * px;\n float fall = uFall * age * (0.4 + 0.6 * age);\n if (abs(rel.x) > side || rel.y > uSpread + reach || rel.y < -uSpread - fall - reach) continue;\n float life = age / uLife;\n // Points drop off the end of the trail: fade those about to go.\n float keep = 1.0 - smoothstep(float(TRAIL_POINTS) - 6.0, float(TRAIL_POINTS) - 1.0, float(k));\n float env = smoothstep(0.0, 0.08, life) * (1.0 - life) * (1.0 - life) * keep;\n for (int j = 0; j < 4; j++) {\n if (j >= uCount) break;\n vec2 h = hash22(vec2(q.z * 61.37 + float(j) * 7.13, float(j) + 0.5));\n float h3 = hash12(h * 37.1 + q.z);\n vec2 pos = q.xy * px + (h - 0.5) * 2.0 * uSpread;\n pos += vec2(0.012 * sin(age * 3.0 + h.x * 6.28318), -uFall * age * (0.4 + 0.6 * age));\n float s = uSize * (0.45 + 0.8 * h3);\n vec2 d = pos - p;\n if (dot(d, d) > s * s * 4.0) continue;\n // Turn some of them a little.\n float an = (h.y - 0.5) * 0.9;\n d = mat2(cos(an), sin(an), -sin(an), cos(an)) * d;\n float tw = mix(1.0, 0.35 + 0.65 * (0.5 + 0.5 * sin(age * (12.0 + 12.0 * h.y) + h.x * 6.28318)), uTwinkle);\n float rays = exp(-abs(d.x) / (s * 0.05)) * exp(-abs(d.y) / (s * 0.45));\n rays += exp(-abs(d.y) / (s * 0.05)) * exp(-abs(d.x) / (s * 0.45));\n float core = exp(-dot(d, d) / (s * s * 0.02));\n vec3 tint = h3 < 0.5 ? uColorA : uColorB;\n col += (tint * (rays * 0.9 + core * 0.6) + vec3(1.0) * core) * env * tw;\n }\n }\n fragColor = glow(col * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Fairy dust\", values: { uColorA: [1, 0.6, 0.95], uColorB: [0.7, 0.6, 1], uCount: 3, uSize: 0.015, uSpread: 0.04 } },\n { name: \"Gold glitter\", values: { uColorA: [1, 0.82, 0.35], uColorB: [1, 0.95, 0.75], uCount: 4, uSize: 0.012, uFall: 0.25, uTwinkle: 1 } },\n ],\n};\n\nexport const brushTrail: ShaderEffect = {\n kind: \"shader\",\n id: \"brush-trail\",\n name: \"Brush trail\",\n description: \"An ink brush stroke following the pointer, bristle-streaked and breaking up dry at its tail, thinner where it moves faster.\",\n category: \"trail\",\n tags: [\"trail\", \"interactive\", \"hover\", \"cursor\", \"overlay\", \"brush\", \"ink\", \"paint\"],\n transparent: true,\n source: glsl(\n `// Brush trail: a stroke along the trail, its width from speed (pressure), bristle streaks across it, dry at the tail.\nuniform vec3 uInk; // @control color default=#15171D label=\"Ink\"\nuniform float uWidth; // @control min=0.005 max=0.1 default=0.045 label=\"Width\"\nuniform float uPressure; // @control min=0 max=1 default=0.6 label=\"Thinner when fast\"\nuniform float uBristles; // @control min=4 max=80 default=28 label=\"Bristles\"\nuniform float uDry; // @control min=0 max=1 default=0.65 label=\"Dry brush\"\nuniform float uLife; // @control min=0.2 max=6 default=1.5 label=\"Fade time\"\nuniform bool uPaper; // @control default=true label=\"Paper\"\nuniform vec3 uPaperColor; // @control color default=#F4ECDD label=\"Paper colour\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n FBM,\n trailHelper(1 / 30, 1.3, true),\n SEGMENT,\n `// The stroke's width at a point from how fast the segment from a to b was drawn: faster, thinner.\nfloat pressWidth(vec4 a, vec4 b, float px) {\n float speed = length(b.xy - a.xy) * px / max(abs(a.z - b.z), 1.0 / 240.0);\n return uWidth * mix(0.3, 1.0, 1.0 / (1.0 + speed * uPressure * 1.5));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n bool live = trailLive(uDemo);\n vec4 a = trailAt(0, live);\n vec4 b = trailAt(1, live);\n float best = 1e9;\n float bestU = 1.0;\n float bestV = 0.0;\n float bestFade = 0.0;\n // Ragged edges: the same noise for every segment, so read it once.\n float rag = 0.9 + 0.2 * vnoise(p * 180.0);\n if (a.w > 0.5 && b.w > 0.5) {\n // Faster strokes are thinner, never wider than uWidth: ragged, at most 1.1 × that from the line.\n float reach = 1.1 * uWidth;\n trailFrom(2, live);\n for (int k = 0; k < TRAIL_POINTS - 1; k++) {\n if (b.w < 0.5 || trailJump(a, b)) break;\n // The point after b: read once, it is the next segment's b.\n vec4 next = k + 2 < TRAIL_POINTS ? trailNext(live) : vec4(0.0);\n // A segment whose box is further off than the stroke reaches cannot be nearer than the best so far.\n vec2 off = max(max(min(a.xy, b.xy) * px - p, p - max(a.xy, b.xy) * px), 0.0);\n float r = best + reach;\n if (r > 0.0 && dot(off, off) < r * r) {\n // The width where the segment starts is from it, where it ends from the next (or the same at the end).\n float wa = pressWidth(a, b, px);\n float wb = next.w > 0.5 && !trailJump(b, next) ? pressWidth(b, next, px) : wa;\n vec2 s = segment(p, a.xy * px, b.xy * px);\n float u = (float(k) + s.y) / float(TRAIL_POINTS - 1);\n float fade = clamp(1.0 - (iTime - mix(a.z, b.z, s.y)) / uLife, 0.0, 1.0);\n // A rounded start and a tail that thins out.\n float w = mix(wa, wb, s.y) * (1.0 - 0.6 * smoothstep(0.55, 1.0, u)) * smoothstep(0.0, 0.04, u + 0.01);\n w *= 0.4 + 0.6 * fade;\n float sd = s.x - w * rag;\n if (sd < best) {\n vec2 dir = b.xy - a.xy;\n float side = dir.x * (p.y - a.y * px) - dir.y * (p.x - a.x * px);\n best = sd;\n bestU = u;\n bestV = clamp(s.x / max(w, 1e-5), 0.0, 1.0) * (side < 0.0 ? -1.0 : 1.0);\n bestFade = fade;\n }\n }\n a = b;\n b = next;\n }\n }\n // Bristles streak along the stroke (they vary across it); the paper's tooth breaks them up.\n // Away from the stroke nothing shows, so the bristles are not worked out there.\n float cover = (1.0 - smoothstep(-px, px, best)) * smoothstep(0.0, 0.1, bestFade);\n vec3 col = uInk;\n if (cover > 0.0) {\n float bristle = 0.6 * vnoise(vec2(bestV * uBristles, 3.7)) + 0.4 * fbm(p * vec2(55.0, 55.0), 3);\n float dry = uDry * smoothstep(0.15, 1.0, bestU) + 0.35 * uDry * smoothstep(0.6, 1.0, abs(bestV)) + 0.7 * (1.0 - bestFade);\n cover *= smoothstep(dry - 0.06, dry + 0.06, bristle * 1.1);\n // Ink pools darker at the edges and thins where a bristle runs dry.\n col = uInk * (1.0 + 0.6 * (1.0 - bristle) * (1.0 - abs(bestV))) + 0.04 * (1.0 - bristle);\n }\n if (uPaper) {\n vec3 paper = uPaperColor * (0.95 + 0.07 * fbm(p * 9.0, 4)) - 0.03 * smoothstep(0.55, 0.9, vnoise(p * vec2(400.0, 30.0)));\n fragColor = vec4(mix(paper, col, cover * 0.95), 1.0);\n } else {\n fragColor = vec4(col, cover);\n }\n}`,\n ),\n presets: [\n { name: \"Red paint\", values: { uInk: [0.78, 0.1, 0.12], uWidth: 0.05, uDry: 0.4, uBristles: 18 } },\n { name: \"Sumi-e\", values: { uInk: [0.05, 0.05, 0.06], uPressure: 1, uDry: 0.85, uLife: 3, uPaperColor: [0.94, 0.91, 0.84] } },\n { name: \"Chalk on nothing\", values: { uInk: [0.96, 0.96, 0.94], uPaper: false, uDry: 0.9, uBristles: 60 } },\n ],\n};\n\nexport const ghostTrail: ShaderEffect = {\n kind: \"shader\",\n id: \"ghost-trail\",\n name: \"Ghost trail\",\n description: \"Afterimages of a circle, ring or star stamped along the pointer's path, each fainter, smaller and shifted in hue than the one before.\",\n category: \"trail\",\n tags: [\"trail\", \"interactive\", \"hover\", \"cursor\", \"overlay\", \"afterimage\", \"echo\"],\n transparent: true,\n source: glsl(\n `// Ghost trail: a shape stamped at the trail points, fading, shrinking and shifting hue with age.\nuniform int uShape; // @control min=0 max=2 default=1 label=\"Shape (0 circle, 1 ring, 2 star)\"\nuniform vec3 uColor; // @control color default=#56F0FF label=\"Colour\"\nuniform float uSize; // @control min=0.01 max=0.2 default=0.05 label=\"Size\"\nuniform float uSpacing; // @control min=0 max=0.1 default=0.02 label=\"Spacing\"\nuniform float uOpacity; // @control min=0.1 max=1 default=0.85 label=\"Opacity\"\nuniform float uDecay; // @control min=0.3 max=4 default=1.4 label=\"Decay\"\nuniform float uHueShift; // @control min=0 max=1 default=0.3 label=\"Hue shift\"\nuniform float uLife; // @control min=0.1 max=3 default=0.8 label=\"Fade time\"\nuniform bool uShrink; // @control default=true label=\"Shrink with age\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n trailHelper(1 / 50, 1.4),\n `vec3 hueShift(vec3 c, float a) {\n const vec3 k = vec3(0.57735);\n float ca = cos(a);\n return c * ca + cross(k, c) * sin(a) + k * dot(k, c) * (1.0 - ca);\n}\n\nfloat star5(vec2 p, float r, float rf) {\n const vec2 k1 = vec2(0.809016994, -0.587785252);\n const vec2 k2 = vec2(-0.809016994, -0.587785252);\n p.x = abs(p.x);\n p -= 2.0 * max(dot(k1, p), 0.0) * k1;\n p -= 2.0 * max(dot(k2, p), 0.0) * k2;\n p.x = abs(p.x);\n p.y -= r;\n vec2 ba = rf * vec2(-k1.y, k1.x) - vec2(0.0, 1.0);\n float h = clamp(dot(p, ba) / dot(ba, ba), 0.0, r);\n return length(p - ba * h) * sign(p.y * ba.x - p.x * ba.y);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n // Newest first, each stamp going under the ones before it.\n vec4 acc = vec4(0.0);\n vec2 last = vec2(-1e5);\n for (int k = 0; k < TRAIL_POINTS; k++) {\n vec4 q = trailPoint(k, uDemo);\n if (q.w < 0.5) break;\n vec2 c = q.xy * px;\n if (k > 0 && length(c - last) < uSpacing) continue;\n last = c;\n float u = float(k) / float(TRAIL_POINTS - 1);\n float fade = pow(1.0 - u, uDecay) * clamp(1.0 - (iTime - q.z) / uLife, 0.0, 1.0);\n if (fade < 0.003) continue;\n float r = uSize * (uShrink ? mix(1.0, 0.4, u) : 1.0);\n vec2 d = p - c;\n if (dot(d, d) > r * r * 2.6 + 4.0 * px * px) continue;\n float sd;\n float shade = 1.0;\n if (uShape == 1) {\n sd = abs(length(d) - r * 0.82) - r * 0.16;\n } else if (uShape == 2) {\n float an = float(k) * 0.25 + iTime * 0.8;\n d = mat2(cos(an), sin(an), -sin(an), cos(an)) * d;\n sd = star5(d, r, 0.45);\n } else {\n sd = length(d) - r;\n shade = 0.7 + 0.3 * (1.0 - length(d) / r);\n }\n float al = (1.0 - smoothstep(-px, px, sd)) * fade * uOpacity;\n vec3 col = hueShift(uColor, u * uHueShift * 6.28318) * shade;\n // The newest stamp has a bright rim.\n if (k == 0) col = mix(col, vec3(1.0), 0.5 * smoothstep(-3.0 * px, 0.0, sd));\n acc.rgb += (1.0 - acc.a) * col * al;\n acc.a += (1.0 - acc.a) * al;\n }\n fragColor = vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`,\n ),\n presets: [\n { name: \"Bubbles\", values: { uShape: 0, uColor: [1, 0.45, 0.75], uSize: 0.035, uOpacity: 0.6, uHueShift: 0.15 } },\n { name: \"Starry\", values: { uShape: 2, uColor: [1, 0.85, 0.3], uSize: 0.06, uSpacing: 0.035, uHueShift: 0.5 } },\n ],\n};\n\nexport const lightPainting: ShaderEffect = {\n kind: \"shader\",\n id: \"light-painting\",\n name: \"Light painting\",\n description: \"Long-exposure light painting in the dark: the pointer leaves neon tubes with white-hot cores that cycle through colour along the stroke and fade slowly.\",\n category: \"trail\",\n tags: [\"trail\", \"interactive\", \"hover\", \"cursor\", \"neon\", \"glow\", \"long-exposure\", \"light\"],\n source: glsl(\n `// Light painting: a smooth glowing tube through the trail on a dark ground, coloured by when each part was painted.\nuniform vec3 uBackground; // @control color default=#05060C label=\"Background\"\nuniform float uWidth; // @control min=0.002 max=0.03 default=0.007 label=\"Tube width\"\nuniform float uGlow; // @control min=0 max=3 default=1.2 label=\"Glow\"\nuniform float uCycle; // @control min=0 max=2 default=0.4 label=\"Colour cycle\"\nuniform float uHue; // @control min=0 max=1 default=0 label=\"Hue\"\nuniform float uLife; // @control min=0.5 max=10 default=4 label=\"Fade time\"\nuniform float uFlicker; // @control min=0 max=1 default=0.25 label=\"Flicker\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n trailHelper(0.05, 1.1, true),\n SEGMENT,\n CATMULL,\n CATMULL_BOX,\n `vec3 spectrum(float h) {\n return 0.5 + 0.5 * cos(6.28318 * (h + vec3(0.0, 0.33, 0.67)));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n vec2 uv = fragCoord / iResolution.xy;\n // A dark ground with a little vignette and grain.\n vec3 col = uBackground * (1.0 - 0.45 * dot(uv - 0.5, uv - 0.5) * 2.0);\n col += (hash12(fragCoord + fract(iTime) * 113.0) - 0.5) * 0.012;\n\n bool live = trailLive(uDemo);\n vec4 a = trailAt(0, live);\n vec4 b = trailAt(1, live);\n if (a.w > 0.5 && b.w > 0.5) {\n float glowR = uWidth * 4.0 * max(uGlow, 0.05);\n float margin = uWidth * 3.0 + glowR * 6.0 + 2.0 * px;\n vec2 prev = 2.0 * a.xy - b.xy;\n float core = 0.0;\n float halo = 0.0;\n float best = 1e9;\n float bestWhen = a.z;\n trailFrom(2, live);\n for (int k = 0; k < TRAIL_POINTS - 1; k++) {\n if (b.w < 0.5) break;\n // Earlier strokes stay lit, but the jump between strokes is not drawn.\n bool jump = trailJump(a, b);\n // The point after b: read once, it is the next segment's b.\n vec4 c = k + 2 < TRAIL_POINTS ? trailNext(live) : vec4(0.0);\n vec2 next = c.w > 0.5 && !trailJump(b, c) ? c.xy : 2.0 * b.xy - a.xy;\n vec2 lo = min(min(prev, a.xy), min(b.xy, next)) * px - margin;\n vec2 hi = max(max(prev, a.xy), max(b.xy, next)) * px + margin;\n if (!jump && all(greaterThan(p, lo)) && all(lessThan(p, hi))) {\n // Nothing on the segment is brighter than its newer end: skip it when it can be neither nearer\n // nor brighter than what is found.\n float dmin = trailBoxDist(p, prev, a.xy, b.xy, next, px);\n float top = clamp(1.0 - (iTime - max(a.z, b.z)) / uLife, 0.0, 1.0);\n top *= top;\n if (dmin < best || exp(-dmin / glowR) * top > halo || exp(-dmin * dmin / (uWidth * uWidth)) * top > core) {\n vec2 q0 = a.xy * px;\n for (int j = 1; j <= 4; j++) {\n vec2 q1 = catmull(prev, a.xy, b.xy, next, float(j) / 4.0) * px;\n vec2 s = segment(p, q0, q1);\n float when = mix(a.z, b.z, (float(j - 1) + s.y) / 4.0);\n float fade = clamp(1.0 - (iTime - when) / uLife, 0.0, 1.0);\n fade *= fade;\n float d = s.x;\n core = max(core, exp(-d * d / (uWidth * uWidth)) * fade);\n halo = max(halo, exp(-d / glowR) * fade);\n if (d < best) {\n best = d;\n bestWhen = when;\n }\n q0 = q1;\n }\n }\n }\n prev = jump ? 2.0 * b.xy - next : a.xy;\n a = b;\n b = c;\n }\n // Colour from when the light passed, so each part keeps its colour as it fades.\n vec3 tint = spectrum(uHue + bestWhen * uCycle);\n float flicker = 1.0 - uFlicker * 0.35 * hash12(vec2(floor(iTime * 30.0), floor(bestWhen * 20.0)));\n vec3 light = tint * halo * uGlow * 0.9 + mix(tint, vec3(1.0), 0.75) * core * 1.8;\n col += (1.0 - exp(-light * 1.4)) * flicker;\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Sparkler writing\", values: { uCycle: 0, uHue: 0.08, uWidth: 0.004, uGlow: 2, uFlicker: 0.8 } },\n { name: \"Neon tubes\", values: { uWidth: 0.012, uGlow: 0.8, uCycle: 1, uFlicker: 0 } },\n ],\n};\n\n/** Trails: comets, ribbons and brush strokes following the pointer (iTrail) or a path. */\nexport const trailShaders: ShaderEffect[] = [cometTrail, ribbonTrail, sparkleTrail, brushTrail, ghostTrail, lightPainting];\n","import { glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/*\n * Particle systems, all stateless: where a particle is comes from its seed\n * and the time alone (`hash` per particle or per cell), so any frame renders\n * on its own. Fields of many particles give each grid cell one and search\n * the cells around a pixel; smaller systems loop over every particle with an\n * early out. Light is summed and written with `glow`; paper and paint are\n * layered with `over`. The pointer ones read the wrapper's built-ins\n * (`iPointer`, `iClicks`, `iTrail`), never declared here.\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 * `pointerAt(t)`: where the pointer was at time `t`, in pixels: the newest\n * `iTrail` point no later than `t` (the oldest kept if none is), else\n * `iPointer` while there is no trail.\n */\nconst POINTER_AT = `\nvec2 pointerAt(float t) {\n vec2 at = iPointer.xy;\n for (int i = 0; i < 32; i++) {\n if (iTrail[i].w < 0.5) break;\n at = iTrail[i].xy;\n if (iTrail[i].z <= t) break;\n }\n return at;\n}`.trim();\n\n/**\n * `clickAt(i, demo, period)`: click `i`, newest first, as (x, y, time, 1),\n * or zeros for none. With the demo on and no real clicks yet, a synthetic\n * click lands every `period` seconds at a pseudo-random spot (needs HASH).\n */\nconst CLICKS = `\nvec4 clickAt(int i, bool demo, float period) {\n if (!demo || iClicks[0].w > 0.5) return iClicks[i];\n float k = floor(iTime / period) - float(i);\n vec2 h = hash22(vec2(k * 1.37 + 0.5, 3.7));\n return vec4((0.2 + 0.6 * h) * iResolution.xy, k * period, 1.0);\n}`.trim();\n\n/**\n * `cornerHashes(i)`: `hash12` of the four corners of lattice cell `i`\n * (i, i + x, i + y, i + xy), sharing the work between corners in the same\n * row or column; the same numbers as four `hash12` calls, for less.\n */\nconst CORNER_HASHES = `\nvec4 cornerHashes(vec2 i) {\n vec2 x = fract(vec2(i.x, i.x + 1.0) * 0.1031);\n vec2 y = fract(vec2(i.y, i.y + 1.0) * 0.1031);\n vec4 X = x.xyxy;\n vec4 Y = y.xxyy;\n vec4 d = X * (Y + 33.33) + Y * (X + 33.33) + X * (X + 33.33);\n vec4 px = X + d;\n return fract((px + (Y + d)) * px);\n}`.trim();\n\nexport const flowParticles: ShaderEffect = {\n kind: \"shader\",\n id: \"flow-particles\",\n name: \"Flow particles\",\n description: \"Thousands of tiny particles streaming along a swirling curl-noise flow field, coloured by how fast they go.\",\n category: \"particles\",\n tags: [\"particles\", \"flow\", \"field\", \"curl\", \"abstract\", \"background\"],\n source: glsl(\n `// Flow particles: streaks along a curl-noise field. Each pixel walks the field upstream\n// a few steps and lights up where it meets a particle that has passed that way.\nuniform float uScale; // @control min=0.5 max=6 default=2 label=\"Field scale\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uDensity; // @control min=30 max=160 default=80 step=1 label=\"Grid density\"\nuniform float uAmount; // @control min=0.05 max=1 default=0.4 label=\"Particles\"\nuniform float uTail; // @control min=0.1 max=1 default=0.55 label=\"Tail length\"\nuniform float uTurbulence; // @control min=0 max=1 default=0.4 label=\"Turbulence\"\nuniform float uBrightness; // @control min=0.2 max=3 default=1.2 label=\"Brightness\"\nuniform vec3 uSlow; // @control color default=#2B4CFF label=\"Slow colour\"\nuniform vec3 uFast; // @control color default=#7CFFE0 label=\"Fast colour\"\nuniform vec3 uBackground; // @control color default=#04060E label=\"Background\"\nuniform bool uTransparent; // @control default=false label=\"Transparent\"`,\n HASH,\n CORNER_HASHES,\n GLOW,\n `// The gradient of vnoise, worked out exactly (its value is not needed here).\nvec2 vnoiseGrad(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n vec2 du = 6.0 * f * (1.0 - f);\n vec4 h = cornerHashes(i);\n float k = h.x - h.y - h.z + h.w;\n return du * vec2(h.y - h.x + k * u.y, h.z - h.x + k * u.x);\n}\n\n// The curl of the potential vnoise(p + vec2(t, -0.6 t)) + turbulence * 0.5 * vnoise(p * 2.3 - vec2(0.7 t, t) + 9.1)\n// (divergence free, so streams swirl rather than pool), plus a gentle drift.\nvec2 flow(vec2 p, float t) {\n vec2 g = vnoiseGrad(p + vec2(t, -0.6 * t));\n if (uTurbulence > 0.0) g += uTurbulence * 1.15 * vnoiseGrad(p * 2.3 - vec2(0.7 * t, t) + 9.1);\n return vec2(g.y, -g.x) + vec2(0.35, 0.08);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n const int STEPS = 24;\n vec2 q = fragCoord / iResolution.y;\n float cell = 1.0 / uDensity;\n float ft = iTime * uSpeed * 0.04;\n float tail = max(uTail * float(STEPS), 1.0);\n vec3 col = vec3(0.0);\n // The walk stays a few steps in each cell, so its particle is worked out once per cell.\n vec2 cellAt = vec2(-1e9);\n bool alive = false;\n float life = 0.0;\n vec2 at = vec2(0.0);\n vec2 v = vec2(0.0);\n float sp = 0.0;\n for (int k = 0; k < STEPS; k++) {\n // The field barely turns over a step, so it is looked up every other step.\n if ((k & 1) == 0) {\n v = flow(q * uScale, ft);\n sp = length(v);\n }\n // One particle per cell at most; each life starts somewhere new in the cell.\n vec2 c = floor(q * uDensity);\n if (c != cellAt) {\n cellAt = c;\n float h0 = hash12(c + 0.31);\n float phase = iTime * uSpeed * (0.3 + 0.3 * h0) + hash12(c + 7.7);\n life = fract(phase);\n float cyc = floor(phase);\n alive = hash12(c * 1.7 + cyc * 3.1) < uAmount;\n if (alive) at = (c + 0.25 + 0.5 * hash22(c + cyc * 17.13)) * cell;\n }\n // This pixel lies k steps downstream of the particle's start; its head is \"head\" steps along.\n float behind = life * float(STEPS) - float(k);\n if (alive && behind >= 0.0 && behind < tail) {\n vec2 dq = (q - at) / cell;\n float d2 = dot(dq, dq);\n // exp(-14 d^2) > 0.01\n if (d2 < 0.329) {\n float spot = exp(-d2 * 14.0);\n float w = 1.0 - behind / tail;\n float fade = smoothstep(0.0, 0.08, life) * (1.0 - smoothstep(0.75, 1.0, life));\n vec3 hue = mix(uSlow, uFast, smoothstep(0.3, 2.2, sp));\n col += hue * spot * w * w * fade * (0.6 + 1.6 * exp(-behind * 1.2));\n }\n }\n // Walk upstream, farther per step where the flow is fast.\n q -= v / max(sp, 1e-3) * cell * min(0.22 * (0.6 + sp), 0.45);\n }\n col *= uBrightness;\n if (uTransparent) {\n fragColor = glow(col);\n } else {\n fragColor = vec4(uBackground + (1.0 - exp(-col)) * (1.0 - uBackground), 1.0);\n }\n}`,\n ),\n presets: [\n { name: \"Ember stream\", values: { uSlow: [0.6, 0.08, 0.02], uFast: [1, 0.8, 0.35], uBackground: [0.03, 0.01, 0.01], uTurbulence: 0.7 } },\n { name: \"Fine silk\", values: { uDensity: 140, uAmount: 0.8, uTail: 1, uScale: 1.2, uSlow: [0.55, 0.45, 1], uFast: [1, 1, 1] } },\n { name: \"Overlay\", values: { uTransparent: true, uAmount: 0.35, uBrightness: 1.6 } },\n ],\n};\n\nexport const magneticSwarm: ShaderEffect = {\n kind: \"shader\",\n id: \"magnetic-swarm\",\n name: \"Magnetic swarm\",\n description: \"A swarm of glowing particles orbiting an attractor that chases the pointer, flung outward by every click.\",\n category: \"particles\",\n tags: [\"particles\", \"interactive\", \"hover\", \"click\", \"swarm\", \"orbit\", \"overlay\"],\n transparent: true,\n source: glsl(\n `// Magnetic swarm: particles on tilted elliptical orbits around an attractor. The attractor\n// follows the pointer (later for outer groups, read back from iTrail) or drifts while idle.\nuniform int uCount; // @control min=10 max=160 default=110 label=\"Particles\"\nuniform float uRadius; // @control min=0.05 max=0.6 default=0.22 label=\"Orbit radius\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Orbit speed\"\nuniform float uLag; // @control min=0 max=1 default=0.6 label=\"Lag\"\nuniform float uFling; // @control min=0 max=1 default=0.5 label=\"Fling at clicks\"\nuniform float uSize; // @control min=0.3 max=3 default=1 label=\"Size\"\nuniform vec3 uColorA; // @control color default=#6EE7FF label=\"Inner colour\"\nuniform vec3 uColorB; // @control color default=#C084FC label=\"Outer colour\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n ROTATE,\n GLOW,\n POINTER_AT,\n CLICKS,\n `vec2 drift(float t) {\n return iResolution.xy * (0.5 + vec2(0.3 * sin(t * 0.53), 0.24 * sin(t * 0.81 + 1.3)));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n float hover = clamp(iPointer.z, 0.0, 1.0);\n // Four groups, each following the attractor a little later than the last.\n vec2 centres[4];\n for (int g = 0; g < 4; g++) {\n float lag = uLag * float(g) / 3.0;\n vec2 idle = uDemo ? drift(iTime - lag * 1.2) : iResolution.xy * 0.5;\n centres[g] = mix(idle, pointerAt(iTime - lag * 0.25), hover) * px;\n }\n vec4 clicks[4];\n for (int k = 0; k < 4; k++) clicks[k] = clickAt(k, uDemo, 3.0);\n\n vec3 col = vec3(0.0);\n // A faint core at the attractor.\n float dc = length(p - centres[0]);\n col += mix(uColorA, vec3(1.0), 0.5) * (0.25 * exp(-dc * dc / 0.0004) + 0.05 * exp(-dc / 0.05));\n\n for (int i = 0; i < 160; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 h = hash22(vec2(fi, 4.1));\n float h3 = hash12(vec2(fi, 9.7));\n float r = uRadius * (0.25 + 0.75 * sqrt(h.x));\n // Inner orbits run faster, as round a mass.\n float w = uSpeed * (0.7 + 0.6 * h.y) * 0.25 / (r + 0.05);\n float a = iTime * w + h3 * 6.28318;\n float tilt = hash12(vec2(fi, 2.3)) * 3.14159;\n float ecc = 0.2 + 0.8 * hash12(vec2(fi, 5.5));\n vec2 pos = centres[i % 4] + rot(tilt) * vec2(cos(a), sin(a) * ecc) * r;\n float energy = 0.0;\n for (int k = 0; k < 4; k++) {\n vec4 c = clicks[k];\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > 4.0) continue;\n vec2 dir = pos - c.xy * px;\n float d = length(dir);\n float push = uFling * 0.7 * exp(-d * 2.5) * (1.0 - exp(-age * 9.0)) * exp(-age * 1.3);\n pos += (dir / max(d, 1e-4)) * push;\n energy += push;\n }\n vec2 dp = p - pos;\n if (abs(dp.x) > 0.06 || abs(dp.y) > 0.06) continue;\n float dist = length(dp);\n float rr = 0.0035 * uSize * (0.6 + 0.8 * h.y);\n vec3 hue = mix(uColorA, uColorB, smoothstep(0.2, 1.0, r / max(uRadius, 1e-3)));\n float twinkle = 0.75 + 0.25 * sin(iTime * 6.0 + fi * 2.1);\n float core = 1.0 - smoothstep(rr * 0.5, rr + px, dist);\n float halo = exp(-dist / (rr * 2.5)) * 0.4;\n col += hue * (core * 1.6 + halo) * twinkle * (1.0 + energy * 3.0);\n }\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Bee swarm\", values: { uColorA: [1, 0.85, 0.2], uColorB: [1, 0.55, 0.1], uSpeed: 2.2, uRadius: 0.12, uSize: 0.8, uLag: 1 } },\n { name: \"Galaxy\", values: { uCount: 160, uRadius: 0.4, uSpeed: 0.5, uSize: 0.6, uColorA: [1, 0.95, 0.8], uColorB: [0.35, 0.5, 1] } },\n ],\n};\n\nexport const dustInLight: ShaderEffect = {\n kind: \"shader\",\n id: \"dust-in-light\",\n name: \"Dust in light\",\n description: \"Dust motes drifting slowly through a diagonal beam of light, sharp at one depth and soft discs nearer or farther.\",\n category: \"particles\",\n tags: [\"particles\", \"overlay\", \"dust\", \"light\", \"beam\", \"atmosphere\", \"bokeh\"],\n transparent: true,\n source: glsl(\n `// Dust in light: layers of motes, only lit inside a beam; out-of-focus layers become bigger, fainter discs.\nuniform vec3 uColor; // @control color default=#FFE2AA label=\"Light\"\nuniform float uAngle; // @control min=-80 max=80 default=30 label=\"Beam angle\"\nuniform float uOffset; // @control min=-1 max=1 default=-0.3 label=\"Beam position\"\nuniform float uWidth; // @control min=0.05 max=0.9 default=0.32 label=\"Beam width\"\nuniform float uHaze; // @control min=0 max=1 default=0.35 label=\"Haze\"\nuniform float uDensity; // @control min=0 max=1 default=0.55 label=\"Dust\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Drift\"\nuniform float uFocus; // @control min=0 max=1 default=0.45 label=\"Focus depth\"\nuniform float uBlur; // @control min=0 max=1 default=0.6 label=\"Depth of field\"`,\n HASH,\n NOISE,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n float aspect = iResolution.x / iResolution.y;\n float t = iTime * uSpeed;\n\n // The beam: from the top edge, angled, widening and fading as it goes.\n float ang = radians(uAngle);\n vec2 dir = vec2(sin(ang), -cos(ang));\n vec2 o = vec2(aspect * (0.5 + 0.5 * uOffset), 1.05);\n vec2 rel = p - o;\n float along = dot(rel, dir);\n float across = dot(rel, vec2(-dir.y, dir.x));\n float w = uWidth * (0.7 + 0.35 * max(along, 0.0));\n float beam = (1.0 - smoothstep(w * 0.25, w * 0.5, abs(across))) * smoothstep(-0.02, 0.15, along) * exp(-max(along, 0.0) * 0.35);\n // Faint shafts within it, slowly shifting.\n float shafts = 0.75 + 0.25 * vnoise(vec2(across / max(w, 0.01) * 6.0, t * 0.15));\n beam *= shafts;\n vec3 col = uColor * beam * uHaze * 0.3;\n\n if (beam > 0.002) {\n for (int i = 0; i < 4; i++) {\n float fi = float(i);\n float z = (fi + 0.5) / 4.0; // 0 far, 1 near\n float scale = mix(26.0, 9.0, z); // cells per height\n vec2 q = p * scale + vec2(0.012, -0.007) * t * (0.5 + z) * scale + fi * 7.3;\n vec2 base = floor(q);\n float blur = abs(z - uFocus) * uBlur;\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 id = base + vec2(float(x), float(y));\n vec2 h = hash22(id + fi * 13.1);\n if (hash12(id * 1.3 + fi) > uDensity) continue;\n // Each mote wanders slowly round its cell.\n vec2 wander = 0.35 * vec2(sin(t * (0.2 + 0.3 * h.x) + h.y * 6.28), cos(t * (0.17 + 0.25 * h.y) + h.x * 6.28));\n vec2 m = id + 0.5 + (h - 0.5) * 0.4 + wander;\n float d = length(q - m) / scale;\n float r = 0.0018 * (0.6 + 1.6 * z) * (0.6 + 0.8 * h.x);\n float big = r + blur * 0.022 * (0.5 + z);\n if (d > big + px * 2.0) continue;\n float edge = max(px, big * 0.35 * min(blur * 4.0, 1.0));\n float disc = 1.0 - smoothstep(big - edge, big + px * 0.5, d);\n float energy = (r * r) / (big * big);\n // Motes glint as they tumble.\n float glint = 0.55 + 0.45 * sin(t * (1.0 + 2.0 * h.y) + h.x * 30.0);\n col += uColor * disc * mix(1.0, 0.25, min(blur * 3.0, 1.0)) * (0.4 + 2.6 * energy) * glint * beam * 1.6;\n }\n }\n }\n }\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Cathedral\", values: { uAngle: 20, uWidth: 0.2, uHaze: 0.55, uColor: [1, 0.92, 0.75], uDensity: 0.7 } },\n { name: \"Sharp\", values: { uBlur: 0.1, uDensity: 0.8, uWidth: 0.5, uHaze: 0.2 } },\n { name: \"Underwater\", values: { uColor: [0.55, 0.9, 1], uAngle: -15, uSpeed: 0.6, uBlur: 1, uHaze: 0.5 } },\n ],\n};\n\nexport const boids: ShaderEffect = {\n kind: \"shader\",\n id: \"boids\",\n name: \"Boids\",\n description: \"Flocks of small birds or arrows wheeling across the sky in coherent groups that split apart and merge again.\",\n category: \"particles\",\n tags: [\"particles\", \"flock\", \"birds\", \"boids\", \"swarm\", \"nature\"],\n source: glsl(\n `// Boids: each bird follows one of a few flock paths, plus its own place in the formation and\n// a little jitter, and now and then moves over to another flock (so flocks split and merge).\n// It faces along its velocity, found from where it was a moment ago.\nuniform int uCount; // @control min=10 max=120 default=70 label=\"Birds\"\nuniform int uGroups; // @control min=1 max=4 default=3 label=\"Flocks\"\nuniform float uSize; // @control min=0.3 max=3 default=1 label=\"Size\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSpread; // @control min=0.02 max=0.4 default=0.12 label=\"Flock spread\"\nuniform float uJitter; // @control min=0 max=1 default=0.35 label=\"Jitter\"\nuniform bool uArrows; // @control default=false label=\"Arrows instead of birds\"\nuniform vec3 uColor; // @control color default=#1B1A2A label=\"Birds\"\nuniform vec3 uSkyTop; // @control color default=#5B7DB8 label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#F6C29A label=\"Sky bottom\"\nuniform bool uTransparent; // @control default=false label=\"Transparent\"`,\n HASH,\n `float sdSegment(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}\n\nfloat sdTriangle(vec2 p, vec2 p0, vec2 p1, vec2 p2) {\n vec2 e0 = p1 - p0, e1 = p2 - p1, e2 = p0 - p2;\n vec2 v0 = p - p0, v1 = p - p1, v2 = p - p2;\n vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0);\n vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0);\n vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0);\n float s = sign(e0.x * e2.y - e0.y * e2.x);\n vec2 d = min(min(vec2(dot(pq0, pq0), s * (v0.x * e0.y - v0.y * e0.x)),\n vec2(dot(pq1, pq1), s * (v1.x * e1.y - v1.y * e1.x))),\n vec2(dot(pq2, pq2), s * (v2.x * e2.y - v2.y * e2.x)));\n return -sqrt(d.x) * sign(d.y);\n}\n\n// A flock's path: slow sweeps whose frequencies differ a little per flock, so flocks meet and part.\nvec2 flockAt(float g, float t, float aspect) {\n vec2 h = hash22(vec2(g, 1.7));\n return vec2(\n aspect * (0.5 + 0.36 * sin(t * (0.21 + 0.06 * h.x) + h.y * 6.28) + 0.06 * sin(t * 0.57 + g * 2.0)),\n 0.52 + 0.3 * sin(t * (0.29 + 0.08 * h.y) + h.x * 6.28 + 1.7 * g) + 0.05 * sin(t * 0.73 + g * 3.0)\n );\n}\n\nvec2 birdAt(float fi, float t, float aspect) {\n vec2 h = hash22(vec2(fi, 3.1));\n float groups = float(uGroups);\n // Which flock it flies with: switching now and then, gliding over to the next.\n float sw = t * 0.06 * (0.6 + 0.8 * h.y) + h.x * 10.0;\n float k = floor(sw);\n float ga = floor(hash12(vec2(fi, k)) * groups);\n float gb = floor(hash12(vec2(fi, k + 1.0)) * groups);\n vec2 centre = mix(flockAt(ga, t, aspect), flockAt(gb, t, aspect), smoothstep(0.6, 1.0, fract(sw)));\n vec2 o = (hash22(vec2(fi, 8.3)) - 0.5) * 2.0 * uSpread;\n o.x *= 1.6;\n vec2 jitter = uJitter * 0.025 * vec2(sin(t * (1.1 + h.x) + fi), cos(t * (1.3 + h.y) + fi * 1.7));\n return centre + o + jitter;\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 / iResolution.y;\n float t = iTime * uSpeed * 0.5;\n float len = 0.018 * uSize;\n float cover = 0.0;\n // A bird is within its formation offset, jitter and size of the line between the two flocks\n // it is moving between, so first find which pairs of flocks pass near this pixel (bit a * 4 + b).\n float groups = float(uGroups);\n vec2 flocks[4];\n for (int g = 0; g < 4; g++) flocks[g] = flockAt(float(g), t, aspect);\n float margin = 1.89 * uSpread + 0.036 * uJitter + 2.04 * len + 2.0 * px;\n int near = 0;\n for (int a = 0; a < 4; a++) {\n if (a >= uGroups) break;\n for (int b = 0; b < 4; b++) {\n if (b >= uGroups) break;\n vec2 pa = p - flocks[a];\n vec2 ba = flocks[b] - flocks[a];\n vec2 off = pa - ba * clamp(dot(pa, ba) / max(dot(ba, ba), 1e-8), 0.0, 1.0);\n if (dot(off, off) < margin * margin) near |= 1 << (a * 4 + b);\n }\n }\n for (int i = 0; i < 120; i++) {\n if (near == 0 || i >= uCount) break;\n float fi = float(i);\n // birdAt, with the flock centres looked up and far birds dropped before the rest of the work.\n vec2 h = hash22(vec2(fi, 3.1));\n float sw = t * 0.06 * (0.6 + 0.8 * h.y) + h.x * 10.0;\n float k = floor(sw);\n int ga = int(floor(hash12(vec2(fi, k)) * groups));\n float glide = smoothstep(0.6, 1.0, fract(sw));\n int gb = glide > 0.0 ? int(floor(hash12(vec2(fi, k + 1.0)) * groups)) : ga;\n if ((near & (1 << (ga * 4 + gb))) == 0) continue;\n vec2 o = (hash22(vec2(fi, 8.3)) - 0.5) * 2.0 * uSpread;\n o.x *= 1.6;\n vec2 jitter = uJitter * 0.025 * vec2(sin(t * (1.1 + h.x) + fi), cos(t * (1.3 + h.y) + fi * 1.7));\n vec2 pos = mix(flocks[ga], flocks[gb], glide) + o + jitter;\n float scale = 0.7 + 0.5 * hash12(vec2(fi, 6.6));\n float l = len * scale;\n vec2 dp = p - pos;\n if (abs(dp.x) > l * 1.2 || abs(dp.y) > l * 1.2) continue;\n vec2 v = pos - birdAt(fi, t - 0.03, aspect);\n vec2 fwd = v / max(length(v), 1e-6);\n vec2 q = vec2(dot(dp, fwd), dot(dp, vec2(-fwd.y, fwd.x))) / l;\n float sd;\n if (uArrows) {\n sd = max(sdTriangle(q, vec2(0.55, 0.0), vec2(-0.45, 0.38), vec2(-0.45, -0.38)), -sdTriangle(q, vec2(-0.2, 0.0), vec2(-0.6, 0.45), vec2(-0.6, -0.45)));\n } else {\n // A gull's V, flapping.\n float flap = sin(iTime * (9.0 + 4.0 * hash12(vec2(fi, 2.2))) + fi * 1.3);\n float span = 0.55 + 0.15 * flap;\n vec2 tipL = vec2(-0.35 - 0.1 * flap, span);\n vec2 tipR = vec2(-0.35 - 0.1 * flap, -span);\n vec2 elbowL = vec2(-0.05, 0.25 + 0.12 * flap);\n vec2 elbowR = vec2(-0.05, -0.25 - 0.12 * flap);\n vec2 head = vec2(0.3, 0.0);\n float bones = min(min(sdSegment(q, head, elbowL), sdSegment(q, elbowL, tipL)), min(sdSegment(q, head, elbowR), sdSegment(q, elbowR, tipR)));\n float body = sdSegment(q, vec2(-0.25, 0.0), head);\n sd = min(bones - 0.06, body - 0.09);\n }\n cover = max(cover, 1.0 - smoothstep(-px / l, px / l, sd));\n }\n if (uTransparent) {\n fragColor = vec4(uColor, cover);\n } else {\n vec3 sky = mix(uSkyBottom, uSkyTop, smoothstep(0.0, 1.0, p.y));\n fragColor = vec4(mix(sky, uColor, cover), 1.0);\n }\n}`,\n ),\n presets: [\n { name: \"Starlings\", values: { uCount: 120, uSize: 0.5, uGroups: 2, uSpread: 0.2, uJitter: 0.6, uSkyTop: [0.62, 0.6, 0.7], uSkyBottom: [0.95, 0.75, 0.6] } },\n { name: \"Arrows\", values: { uArrows: true, uColor: [0.95, 0.95, 1], uSkyTop: [0.08, 0.1, 0.22], uSkyBottom: [0.2, 0.15, 0.4], uCount: 50 } },\n ],\n};\n\nexport const particleText: ShaderEffect = {\n kind: \"shader\",\n id: \"particle-text\",\n name: \"Particle text\",\n description: \"A title that dissolves into drifting particles, letter by letter, and gathers back into place, on a loop.\",\n category: \"particles\",\n tags: [\"particles\", \"text\", \"title\", \"dissolve\", \"disintegrate\"],\n video: \"none\",\n loop: 6,\n source: glsl(\n `// Particle text: a particle on every cell of a grid where the text's mask is, carried off by a\n// smooth wind field (so a pixel can trace back to the cells that could have reached it). Loops every 6 s.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"FLAIR\")} label=\"Text\"\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Letters\"\nuniform vec3 uDust; // @control color default=#FF7AC6 label=\"Particles\"\nuniform vec3 uBackground; // @control color default=#0B0A14 label=\"Background\"\nuniform bool uTransparent; // @control default=false label=\"Transparent\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Text size\"\nuniform float uDensity; // @control min=40 max=240 default=120 step=1 label=\"Particles per height\"\nuniform float uScatter; // @control min=0.1 max=1.5 default=0.4 label=\"Scatter distance\"\nuniform float uDirection; // @control min=-180 max=180 default=20 label=\"Drift direction\"`,\n HASH,\n CORNER_HASHES,\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\n// Half the size of the text's box in the frame (letters is 0 outside it).\nvec2 lettersHalf() {\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 return 0.5 * vec2(h * aspect, h);\n}\n\n// How far through dissolving the particle at home is (0 in place, 1 gone): left to right, then back together.\nfloat scattered(vec2 home, float phase) {\n float frame = iResolution.x / iResolution.y;\n float sx = clamp(home.x / max(frame * uSize, 0.1) + 0.5, 0.0, 1.0);\n float leave = smoothstep(0.12 + 0.28 * sx, 0.32 + 0.28 * sx, phase);\n float back = smoothstep(0.66, 0.94, phase);\n float a = leave * (1.0 - back);\n return a * a * (3.0 - 2.0 * a);\n}\n\n// vnoise, keeping the corner hashes of the lattice cell it last looked in: the wind is smooth and\n// its lattice coarse, so most lookups land in the same cell as the one before.\nvec2 eddyCellA = vec2(-1e9);\nvec2 eddyCellB = vec2(-1e9);\nvec4 eddyHashA = vec4(0.0);\nvec4 eddyHashB = vec4(0.0);\n\nfloat eddy(vec2 p, inout vec2 cellAt, inout vec4 h) {\n vec2 i = floor(p);\n if (i != cellAt) {\n cellAt = i;\n h = cornerHashes(i);\n }\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n return mix(mix(h.x, h.y, u.x), mix(h.z, h.w, u.x), u.y);\n}\n\n// Group g's gust: its wind (xy) and how much it lifts what it carries (z).\nvec3 gustOf(float g) {\n float ang = radians(uDirection) + (fract(g * 0.618) - 0.5) * 1.2;\n return vec3(vec2(cos(ang), sin(ang)) * (0.3 + 0.18 * g), 0.3 * (0.5 + 0.2 * g));\n}\n\n// Where the wind has carried a particle of group g from home: smooth in home, so it can be inverted.\n// Each of the six groups rides its own gust (speed, heading and eddies), so they spread apart.\nvec2 carried(vec2 home, float phase, float g, vec3 gust) {\n float a = scattered(home, phase);\n // Still at home (most of the frame, most of the time): no need for the eddies.\n if (a <= 0.0) return vec2(0.0);\n float t = phase * 3.0;\n vec2 q = home * 3.0 + g * 5.3;\n vec2 swirl = vec2(eddy(q + vec2(t, 0.0), eddyCellA, eddyHashA), eddy(q + vec2(4.7, t), eddyCellB, eddyHashB)) - 0.5;\n return a * uScatter * (gust.xy + swirl * 0.8 + vec2(0.0, gust.z * a));\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 cell = 1.0 / uDensity;\n float phase = fract(iTime / 6.0);\n\n // Solid letters while (and where) they are whole.\n float solid = letters(p) * (1.0 - smoothstep(0.0, 0.04, scattered(p, phase)));\n vec3 col = uColor;\n float cover = solid;\n\n // Every particle is home outside this part of the loop.\n bool moving = phase > 0.12 && phase < 0.94;\n vec2 box = lettersHalf() + 2.0 * cell;\n for (int gi = 0; gi < 6; gi++) {\n if (!moving) break;\n float g = float(gi);\n vec3 gust = gustOf(g);\n // Trace back to the home a particle of this group here would have come from, then search the cells round it.\n vec2 home = p;\n for (int i = 0; i < 4; i++) home = p - carried(home, phase, g, gust);\n // The cells searched are all off the text.\n if (any(greaterThan(abs(home), box))) continue;\n vec2 base = floor(home / cell);\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 c = base + vec2(float(x), float(y));\n if (floor(hash12(c + 0.73) * 6.0) != g) continue;\n vec2 hc = (c + 0.5) * cell;\n float a = scattered(hc, phase);\n if (a < 0.002 || letters(hc) < 0.5) continue;\n vec2 j = hash22(c);\n vec2 pos = hc + carried(hc, phase, g, gust) + (j - 0.5) * cell * 1.1 * a;\n float r = cell * (0.5 - 0.1 * a) * (0.75 + 0.5 * j.x);\n float d = length(p - pos);\n float disc = (1.0 - smoothstep(r - px, r + px * 0.5, d)) * (1.0 - smoothstep(0.6, 1.0, a) * 0.6 * j.y);\n if (disc > cover) {\n cover = disc;\n col = mix(uColor, uDust, smoothstep(0.0, 0.5, a));\n }\n }\n }\n }\n if (uTransparent) {\n fragColor = vec4(col, cover);\n } else {\n fragColor = vec4(mix(uBackground, col, cover), 1.0);\n }\n}`,\n ),\n presets: [\n { name: \"Ash\", values: { uColor: [0.92, 0.9, 0.86], uDust: [0.45, 0.42, 0.4], uBackground: [0.07, 0.07, 0.07], uDirection: 60, uScatter: 0.9 } },\n { name: \"Gold dust\", values: { uColor: [1, 0.85, 0.45], uDust: [1, 0.6, 0.2], uDensity: 180, uDirection: -10 } },\n ],\n};\n\nexport const confettiCannon: ShaderEffect = {\n kind: \"shader\",\n id: \"confetti-cannon\",\n name: \"Confetti cannon\",\n description: \"Confetti blasting out of both bottom corners and every click in arcs, then flipping and fluttering down.\",\n category: \"particles\",\n tags: [\"particles\", \"confetti\", \"celebration\", \"party\", \"interactive\", \"click\", \"overlay\"],\n transparent: true,\n source: glsl(\n `// Confetti cannon: paper rectangles and dots launched with air drag towards a terminal fall,\n// swaying as they go, spinning in the plane and flipping (squashed and shaded) out of it.\nuniform vec3 uColorA; // @control color default=#FF4D6D label=\"Colour 1\"\nuniform vec3 uColorB; // @control color default=#FFD166 label=\"Colour 2\"\nuniform vec3 uColorC; // @control color default=#06D6A0 label=\"Colour 3\"\nuniform vec3 uColorD; // @control color default=#4D96FF label=\"Colour 4\"\nuniform int uCount; // @control min=10 max=80 default=50 label=\"Pieces per blast\"\nuniform float uInterval; // @control min=1.5 max=8 default=3.5 label=\"Seconds between blasts\"\nuniform float uPower; // @control min=0.5 max=2 default=1 label=\"Power\"\nuniform float uSize; // @control min=0.4 max=2.5 default=1 label=\"Size\"\nuniform float uFall; // @control min=0.2 max=2 default=1 label=\"Fall speed\"\nuniform bool uCannons; // @control default=true label=\"Corner cannons\"\nuniform bool uDemo; // @control default=true label=\"Demo clicks when idle\"`,\n HASH,\n ROTATE,\n OVER,\n CLICKS,\n `const float LIFE = 4.5;\n\n// One blast of count pieces from origin at time age, aimed at angle (radians) give or take spread/2.\nvec4 blast(vec4 acc, vec2 p, vec2 origin, float angle, float spread, float speed, float age, float seed, int count, float px) {\n if (age < 0.0 || age > LIFE) return acc;\n const float k = 2.2;\n float e = (1.0 - exp(-k * age)) / k;\n float fade = 1.0 - smoothstep(LIFE - 1.0, LIFE, age);\n float reach = 0.03 * uSize;\n // Every piece is within its sway and the spread of fall speeds of the fan its launch sweeps out\n // (speeds 0.5 to 1 times speed, within spread of angle, all dropped by the middle fall speed),\n // so skip the blast where this pixel is clear of that.\n float drop = 0.16 * uFall * (age - e);\n vec2 rel = p - origin + vec2(0.0, drop);\n float slack = reach * 1.42 + 0.035 + 0.3 * drop + px;\n float r = length(rel);\n float far = speed * e;\n if (r > far + slack || r < 0.5 * far - slack) return acc;\n if (spread < 6.2 && r > slack) {\n float off = abs(mod(atan(rel.y, rel.x) - angle + 3.14159265, 6.28318531) - 3.14159265);\n if (off > spread * 0.5 + asin(slack / r) + 0.01) return acc;\n }\n for (int j = 0; j < 80; j++) {\n if (j >= count) break;\n float fj = float(j);\n vec2 h = hash22(vec2(fj * 7.13 + 1.0, seed));\n float launch = speed * (0.5 + 0.5 * h.y);\n // The same tests for this piece before working out the rest of it: how far out, then where.\n if (abs(r - launch * e) > slack) continue;\n float a = angle + (h.x - 0.5) * spread;\n vec2 v0 = vec2(cos(a), sin(a)) * launch;\n vec2 dv = rel - v0 * e;\n if (abs(dv.x) > reach + 0.035 || abs(dv.y) > reach + 0.3 * drop) continue;\n vec2 h2 = hash22(h * 53.1 + seed);\n float h3 = hash12(h2 * 17.7 + fj);\n float fall = 0.16 * uFall * (0.7 + 0.6 * h2.x);\n vec2 pos = origin + v0 * e - vec2(0.0, fall * (age - e));\n pos.x += 0.035 * sin(age * (2.0 + 2.0 * h2.y) + h.x * 6.28) * smoothstep(0.3, 1.2, age);\n vec2 dp = p - pos;\n if (abs(dp.x) > reach || abs(dp.y) > reach) continue;\n float spin = age * (2.0 + 5.0 * h2.y) * (h3 < 0.5 ? 1.0 : -1.0) + h.x * 6.28;\n float flip = age * (4.0 + 7.0 * h2.x) + h.y * 6.28;\n float face = cos(flip);\n float squash = max(abs(face), 0.06);\n vec2 q = rot(spin) * dp;\n q.y /= squash;\n float sd;\n if (h3 < 0.65) {\n vec2 d = abs(q) - vec2(0.011, 0.0065) * uSize;\n sd = length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);\n } else {\n sd = length(q) - 0.0065 * uSize;\n }\n float alpha = 1.0 - smoothstep(-px, px / squash, sd);\n if (alpha <= 0.0) continue;\n float pick = fract(h3 * 7.3);\n vec3 col = pick < 0.25 ? uColorA : (pick < 0.5 ? uColorB : (pick < 0.75 ? uColorC : uColorD));\n // Flip shading: dim edge-on, the back a shade darker, a glint face-on.\n col *= (0.5 + 0.5 * abs(face)) * (face < 0.0 ? 0.82 : 1.0);\n col += 0.35 * pow(abs(face), 16.0);\n acc = over(acc, min(col, vec3(1.0)), alpha * fade);\n }\n return acc;\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 / iResolution.y;\n vec4 acc = vec4(0.0);\n if (uCannons) {\n float now = floor(iTime / uInterval);\n for (int m = 3; m >= 0; m--) {\n float n = now - float(m);\n float age = iTime - n * uInterval;\n acc = blast(acc, p, vec2(0.0, -0.02), radians(58.0), 0.7, 2.8 * uPower, age, n * 3.17 + 1.0, uCount, px);\n acc = blast(acc, p, vec2(aspect, -0.02), radians(122.0), 0.7, 2.8 * uPower, age, n * 3.17 + 2.0, uCount, px);\n }\n }\n for (int i = 3; i >= 0; i--) {\n vec4 c = clickAt(i, uDemo, 4.0);\n if (c.w < 0.5) continue;\n acc = blast(acc, p, c.xy * px, radians(90.0), 6.28318, 1.2 * uPower, iTime - c.z, c.z * 1.91 + float(i), uCount / 2 + 5, px);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Gold and silver\", values: { uColorA: [1, 0.82, 0.3], uColorB: [0.85, 0.87, 0.9], uColorC: [1, 0.7, 0.2], uColorD: [0.7, 0.72, 0.78] } },\n { name: \"Clicks only\", values: { uCannons: false, uCount: 60 } },\n { name: \"Big blast\", values: { uCount: 80, uPower: 1.6, uSize: 1.4, uInterval: 5 } },\n ],\n};\n\nexport const fireflies: ShaderEffect = {\n kind: \"shader\",\n id: \"fireflies\",\n name: \"Fireflies\",\n description: \"Fireflies wandering over a dusky meadow, each blinking on and off in its own rhythm and drifting towards the pointer.\",\n category: \"particles\",\n tags: [\"particles\", \"fireflies\", \"night\", \"nature\", \"glow\", \"interactive\", \"hover\"],\n source: glsl(\n `// Fireflies: wandering lights on their own blink cycles, drawn (lazily, through iTrail) to the pointer.\nuniform int uCount; // @control min=5 max=80 default=40 label=\"Fireflies\"\nuniform vec3 uGlow; // @control color default=#D4FF5C label=\"Glow\"\nuniform float uSize; // @control min=0.3 max=3 default=1 label=\"Size\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Wander\"\nuniform float uBlink; // @control min=0.1 max=3 default=1 label=\"Blink rate\"\nuniform float uAttract; // @control min=0 max=1 default=0.6 label=\"Drawn to pointer\"\nuniform bool uMeadow; // @control default=true label=\"Dusky meadow\"\nuniform vec3 uSky; // @control color default=#141B36 label=\"Sky\"\nuniform vec3 uDusk; // @control color default=#4B3A5E label=\"Horizon\"\nuniform vec3 uGrass; // @control color default=#070D0B label=\"Grass\"`,\n HASH,\n NOISE,\n GLOW,\n POINTER_AT,\n `// How much of the grass silhouette covers p (height units).\nfloat grass(vec2 p, float aspect) {\n float ground = 0.1 + 0.04 * vnoise(vec2(p.x * 3.0, 1.0));\n float cover = 1.0 - smoothstep(ground - 0.002, ground + 0.002, p.y);\n for (int i = 0; i < 2; i++) {\n float fi = float(i);\n float n = 70.0 + 50.0 * fi;\n float y = p.y - ground;\n float sway = sin(iTime * 0.8 + p.x * 4.0 + fi) * 0.25 * y;\n float x = p.x * n + sway * n;\n float id = floor(x);\n float hb = (0.04 + 0.11 * hash12(vec2(id, fi))) * (1.0 - 0.35 * fi);\n float lean = (hash12(vec2(id, fi + 5.0)) - 0.5) * 1.5;\n float f = fract(x) - 0.5 - lean * y / hb;\n float blade = step(0.0, y) * step(y, hb) * step(abs(f), 0.5 * (1.0 - y / hb));\n cover = max(cover, blade);\n }\n return cover;\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 / iResolution.y;\n float t = iTime * uSpeed;\n float hover = clamp(iPointer.z, 0.0, 1.0) * uAttract;\n vec3 light = 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.9));\n vec2 g = hash22(vec2(fi, 7.3));\n vec2 home = vec2(h.x * aspect, 0.06 + 0.8 * pow(h.y, 1.4));\n vec2 wander = vec2(\n 0.1 * sin(t * (0.15 + 0.2 * g.x) + g.y * 6.28) + 0.04 * sin(t * (0.6 + 0.5 * g.y) + fi),\n 0.06 * sin(t * (0.12 + 0.18 * g.y) + g.x * 6.28) + 0.03 * cos(t * (0.7 + 0.4 * g.x) + fi * 1.3)\n );\n vec2 pos = home + wander;\n if (hover > 0.0) {\n // Each drifts to its own spot round the pointer, the slow ones following where it was.\n vec2 near = pointerAt(iTime - 0.25 * g.x) * px + (h - 0.5) * 0.3 + wander * 0.6;\n pos = mix(pos, near, hover * (0.4 + 0.5 * g.y));\n }\n vec2 dp = p - pos;\n float r = 0.004 * uSize * (0.7 + 0.6 * g.x);\n if (abs(dp.x) > r * 20.0 || abs(dp.y) > r * 20.0) continue;\n float period = (2.5 + 3.5 * hash12(vec2(fi, 4.4))) / uBlink;\n float ph = fract(iTime / period + h.y * 3.0);\n float blink = smoothstep(0.0, 0.05, ph) * (1.0 - smoothstep(0.08, 0.4, ph));\n float on = 0.04 + blink;\n float d = length(dp);\n float core = 1.0 - smoothstep(r * 0.3, r + px, d);\n float halo = exp(-d / (r * 3.5));\n vec3 hue = mix(uGlow, vec3(1.0, 0.85, 0.4), 0.3 * g.y);\n light += hue * (core * 2.0 + halo) * on;\n }\n if (uMeadow) {\n vec3 sky = mix(uDusk, uSky, smoothstep(0.05, 1.0, p.y));\n float stars = step(0.996, hash12(floor(fragCoord * 0.5))) * smoothstep(0.4, 0.9, p.y) * (0.5 + 0.5 * sin(iTime * 2.0 + p.x * 40.0));\n sky += stars * 0.5;\n vec3 col = mix(sky, uGrass, grass(p, aspect));\n fragColor = vec4(col + (1.0 - exp(-light)) * (1.0 - col), 1.0);\n } else {\n fragColor = glow(light);\n }\n}`,\n ),\n presets: [\n { name: \"Overlay\", values: { uMeadow: false } },\n { name: \"Swarm\", values: { uCount: 80, uBlink: 2, uSize: 0.7, uAttract: 1 } },\n { name: \"Blue spirits\", values: { uGlow: [0.45, 0.8, 1], uSky: [0.03, 0.05, 0.1], uDusk: [0.1, 0.18, 0.25], uBlink: 0.5 } },\n ],\n};\n\n/** Particles: flow fields, swarms, dust, fireflies and confetti. */\nexport const particlesShaders: ShaderEffect[] = [flowParticles, magneticSwarm, dustInLight, boids, particleText, confettiCannon, fireflies];\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 * Debris: things breaking up and falling. Pieces move ballistically with air\n * drag (`ballistic`), tumble as they go and bounce or settle on a floor where\n * there is one. Each piece is found by working back from the pixel to the\n * piece's resting shape (a cell, a shard, a chunk), so loops stay bounded.\n */\n\n/**\n * `ballistic(v, k, g, t)`: how far a piece launched at velocity `v` has moved\n * after `t` seconds, slowed by air drag `k` and pulled down by gravity `g`.\n */\nconst BALLISTIC = `\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}`.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/**\n * `rock(q, r, seed)`: an irregular seven-sided stone of about radius `r`\n * around the origin, from hashed vertices: x is the distance to its outline\n * (negative inside), yz the outward normal of the nearest face.\n * `shadeRock` lights it as bevelled facets with a speckled surface.\n */\nconst ROCK = `\nconst float TAU = 6.28318;\nvec3 rock(vec2 q, float r, float seed) {\n float a = atan(q.y, q.x);\n if (a < 0.0) a += TAU;\n float wedge = TAU / 7.0;\n float i = floor(a / wedge);\n float i1 = i + 1.0;\n vec2 A = vec2(cos(i * wedge), sin(i * wedge)) * r * (0.62 + 0.38 * hash12(vec2(mod(i, 7.0), seed)));\n vec2 B = vec2(cos(i1 * wedge), sin(i1 * wedge)) * r * (0.62 + 0.38 * hash12(vec2(mod(i1, 7.0), seed)));\n vec2 e = B - A;\n vec2 n = normalize(vec2(e.y, -e.x));\n return vec3(dot(q - A, n), n);\n}\n// A stone's colour at local point q, its frame turned by ang: flat top, bevelled faces lit from the upper left.\nvec3 shadeRock(vec2 q, vec3 rk, float r, float ang, vec3 base, float seed) {\n float inner = clamp(-rk.x / (r * 0.3), 0.0, 1.0);\n vec2 face = rot(ang) * rk.yz;\n vec3 n = normalize(vec3(face * (0.25 + 1.3 * (1.0 - inner)), 1.0));\n float diff = clamp(dot(n, normalize(vec3(-0.45, 0.65, 0.6))), 0.0, 1.0);\n float speck = 0.6 * vnoise(q / r * 9.0 + seed * 13.0) + 0.4 * hash12(floor(q / r * 30.0) + seed);\n vec3 col = base * (0.3 + 0.9 * diff) * (0.8 + 0.35 * speck);\n return col * (1.0 - 0.3 * smoothstep(-r * 0.08, 0.0, rk.x));\n}`.trim();\n\nexport const rubbleFall: ShaderEffect = {\n kind: \"shader\",\n id: \"rubble-fall\",\n name: \"Rubble fall\",\n description: \"Chunks of rock and concrete tumbling down, bouncing in puffs of dust and settling on a heap of rubble.\",\n category: \"debris\",\n tags: [\"debris\", \"rubble\", \"rock\", \"falling\", \"dust\", \"overlay\", \"loop\"],\n transparent: true,\n loop: 6,\n source: glsl(\n `// Rubble fall: stones fall, tumble, bounce in dust puffs and crumble into the heap.\nuniform vec3 uRock; // @control color default=#7D746B label=\"Rock\"\nuniform vec3 uConcrete; // @control color default=#B8B2A6 label=\"Concrete\"\nuniform vec3 uDust; // @control color default=#CDBFA6 label=\"Dust\"\nuniform float uCount; // @control min=3 max=20 default=7 label=\"Chunks across\"\nuniform float uSize; // @control min=0.3 max=1 default=0.9 label=\"Chunk size\"\nuniform float uGravity; // @control min=1 max=6 default=3 label=\"Gravity\"\nuniform float uBounce; // @control min=0 max=0.7 default=0.35 label=\"Bounciness\"\nuniform float uPile; // @control min=0 max=0.3 default=0.12 label=\"Heap height\"\nuniform float uDustAmount; // @control min=0 max=1.5 default=1 label=\"Dust\"`,\n HASH,\n NOISE,\n FBM,\n ROTATE,\n OVER,\n ROCK,\n `const float PERIOD = 6.0;\n\nfloat heapTop(float x) {\n return -0.5 + uPile * (0.45 + 0.55 * vnoise(vec2(x * 2.5, 1.7)));\n}\n\n// A puff of dust at 'at', 'age' seconds old: spreading low and wide, thinning as it goes.\nfloat puff(vec2 p, vec2 at, float size, float age, float life, float seed) {\n if (age < 0.0 || age > life) return 0.0;\n float R = size * (1.0 + 2.2 * sqrt(age));\n vec2 d = p - at - vec2(0.0, 0.3 * R);\n d.y *= 1.7;\n float l = length(d);\n if (l > R) return 0.0;\n float fade = 1.0 - age / life;\n float n = fbm(p * 22.0 + seed * 7.3 - vec2(0.0, age * 0.6), 3);\n return smoothstep(R, R * 0.15, l) * fade * fade * (0.3 + 1.1 * n);\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 cw = iResolution.x / iResolution.y / uCount;\n vec4 acc = vec4(0.0);\n\n // The heap: small stones packed below a bumpy top, darker the deeper they lie.\n float gs = max(cw * 0.42 * uSize, 0.015);\n vec2 gc = floor(p / gs);\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 c = gc + vec2(float(i), float(j));\n vec2 h = hash22(c + 5.3);\n vec2 site = (c + 0.25 + 0.5 * h) * gs;\n float top = heapTop(site.x);\n if (site.y > top) continue;\n float r = gs * (0.7 + 0.25 * h.y);\n float ang = h.x * TAU;\n vec2 q = rot(-ang) * (p - site);\n if (length(q) > r * 1.05) continue;\n float seed = c.x * 7.1 + c.y * 1.3;\n vec3 rk = rock(q, r, seed);\n float cover = smoothstep(px, -px, rk.x);\n if (cover <= 0.0) continue;\n float depth = clamp((top - site.y) / max(uPile, 0.03), 0.0, 1.0);\n vec3 base = mix(uRock, uConcrete, step(0.55, h.y)) * (0.85 + 0.3 * h.x);\n acc = over(acc, shadeRock(q, rk, r, ang, base, seed) * (1.0 - 0.6 * depth), cover);\n }\n }\n\n // Falling chunks: three to a column, each falling, bouncing, settling and crumbling once a cycle.\n // Two columns either side, as dust spreads further than the stones reach.\n float dust = 0.0;\n float col = floor(p.x / cw);\n for (int k = -2; k <= 2; k++) {\n float c = col + float(k);\n for (int j = 0; j < 3; j++) {\n vec2 id = vec2(c, float(j));\n vec4 h = vec4(hash22(id + 0.37), hash22(id + 9.1));\n float ta = mod(iTime - (float(j) + h.x) * PERIOD / 3.0, PERIOD);\n float r = cw * 0.42 * uSize * (0.6 + 0.4 * h.y);\n float x0 = (c + 0.5 + 0.3 * (h.z - 0.5)) * cw;\n float rest = heapTop(x0) + r * 0.45;\n float y0 = 0.55 + r + 0.35 * h.w;\n float t1 = sqrt(2.0 * (y0 - rest) / uGravity);\n float vx0 = (h.z - 0.5) * 0.25 * cw;\n float vx1 = (h.w - 0.5) * 1.2 * cw * uBounce;\n float spin = (h.y - 0.5) * 7.0;\n vec2 pos;\n float ang;\n if (ta < t1) {\n pos = vec2(x0 + vx0 * ta, y0 - 0.5 * uGravity * ta * ta);\n ang = h.x * TAU + spin * ta;\n } else {\n // Bounces, each lower by the bounciness, then it rests; it skids and rolls a little, slowing.\n float tau = ta - t1;\n float y = rest;\n float v = uGravity * t1 * uBounce;\n float tb = tau;\n for (int b = 0; b < 3; b++) {\n float dur = 2.0 * v / uGravity;\n if (tb < dur) {\n y = rest + v * tb - 0.5 * uGravity * tb * tb;\n break;\n }\n tb -= dur;\n v *= uBounce;\n }\n pos = vec2(x0 + vx0 * t1 + vx1 * (1.0 - exp(-3.0 * tau)) / 3.0, y);\n ang = h.x * TAU + spin * t1 + spin * 0.5 * (1.0 - exp(-2.5 * tau)) / 2.5;\n dust += puff(p, vec2(x0 + vx0 * t1, rest - r * 0.4), r, tau, 1.6, id.x + id.y * 3.1);\n }\n // At the end of its cycle it crumbles into the heap.\n float crumble = smoothstep(PERIOD - 0.9, PERIOD - 0.15, ta);\n dust += 0.6 * puff(p, pos - vec2(0.0, r * 0.3), r * 0.6, ta - (PERIOD - 0.9), 0.9, id.y + id.x * 1.7);\n vec2 q = rot(-ang) * (p - pos);\n if (length(q) > r * 1.05) continue;\n float seed = id.x * 3.7 + id.y * 11.0;\n vec3 rk = rock(q, r, seed);\n float bits = hash12(floor(q / (r * 0.2)) + id * 3.0);\n float cover = smoothstep(px, -px, rk.x) * step(crumble, bits);\n if (cover <= 0.0) continue;\n vec3 base = mix(uRock, uConcrete, step(0.5, h.z)) * (0.85 + 0.3 * h.w);\n acc = over(acc, shadeRock(q, rk, r, ang, base, seed), cover);\n }\n }\n float n = vnoise(p * 40.0);\n acc = over(acc, uDust * (0.8 + 0.3 * n), clamp(dust * uDustAmount, 0.0, 0.9));\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Demolition\", values: { uRock: [0.55, 0.54, 0.52], uConcrete: [0.78, 0.77, 0.74], uDust: [0.85, 0.84, 0.8], uDustAmount: 1.5, uBounce: 0.25 } },\n { name: \"Boulders\", values: { uCount: 5, uSize: 1, uBounce: 0.18, uGravity: 2.2, uPile: 0.2 } },\n { name: \"Gravel shower\", values: { uCount: 18, uSize: 0.5, uBounce: 0.5, uPile: 0.06, uDustAmount: 0.6 } },\n ],\n};\n\nexport const glassShatter: ShaderEffect = {\n kind: \"shader\",\n id: \"glass-shatter\",\n name: \"Glass shatter\",\n description: \"A picture that cracks like a pane of glass where you click, its shards falling away and spinning before it mends.\",\n category: \"debris\",\n video: \"interactive\",\n tags: [\"debris\", \"glass\", \"shatter\", \"image\", \"click\", \"interactive\", \"break\"],\n source: glsl(\n `// Glass shatter: radial and concentric cracks race out from the click; shards fall away, then it mends.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uBackground; // @control color default=#0B0D14 label=\"Behind the glass\"\nuniform int uSpokes; // @control min=5 max=16 default=12 label=\"Radial cracks\"\nuniform float uGrowth; // @control min=1.3 max=2.5 default=1.6 label=\"Ring spacing\"\nuniform float uScale; // @control min=0.03 max=0.3 default=0.09 label=\"First ring size\"\nuniform float uGravity; // @control min=0.5 max=4 default=1.8 label=\"Gravity\"\nuniform float uSpin; // @control min=0 max=6 default=2.5 label=\"Spin\"\nuniform float uRestore; // @control min=1.5 max=10 default=3.5 label=\"Mends after (s)\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n ROTATE,\n BALLISTIC,\n PICTURE,\n `const float TAU = 6.28318;\n\n// The newest click, or with the demo on and no real clicks yet, one every 5.5 s.\nvec4 lastClick() {\n if (!uDemo || iClicks[0].w > 0.5) return iClicks[0];\n float k = floor(iTime / 5.5);\n vec2 h = hash22(vec2(k * 1.37 + 0.5, 3.7));\n return vec4((0.25 + 0.5 * h) * iResolution.xy, k * 5.5 + 0.4, 1.0);\n}\n\n// The angle of radial crack i (wrapping every uSpokes).\nfloat spoke(float i) {\n float n = float(uSpokes);\n return (i + 0.6 * (hash12(vec2(mod(i, n), 3.1)) - 0.5)) * TAU / n;\n}\n\nconst int RINGS = 8;\n\n// How far out concentric crack j (1 and up) crosses sector s: each ring wider than the last, out past the frame.\nfloat ringAt(float s, float j) {\n return uScale * pow(uGrowth, j - 1.0) * (0.85 + 0.3 * hash12(vec2(s, j + 0.5)));\n}\n\n// The shard q (from the impact) lies on: x its sector, y its ring, z how far to the nearest crack.\nvec3 shardOf(vec2 q) {\n float n = float(uSpokes);\n float a = atan(q.y, q.x);\n if (a < 0.0) a += TAU;\n float s = floor(a / TAU * n);\n if (a < spoke(s)) s -= 1.0;\n else if (a >= spoke(s + 1.0)) s += 1.0;\n float a0 = spoke(s);\n float a1 = spoke(s + 1.0);\n float mid = 0.5 * (a0 + a1);\n float d = dot(q, vec2(cos(mid), sin(mid)));\n float sid = mod(s, n);\n float ring = 0.0;\n float inner = 0.0;\n float outer = 1e3;\n for (int j = 1; j < RINGS; j++) {\n float b = ringAt(sid, float(j));\n if (d < b) {\n outer = b;\n break;\n }\n ring = float(j);\n inner = b;\n }\n float edge = min(outer - d, min(abs(q.x * sin(a0) - q.y * cos(a0)), abs(q.x * sin(a1) - q.y * cos(a1))));\n if (ring > 0.0) edge = min(edge, d - inner);\n return vec3(sid, ring, edge);\n}\n\n// When a shard lets go: the middle first, the outer pane last.\nfloat release(float sid, float ring) {\n return 0.3 + 0.16 * ring + 0.25 * hash12(vec2(sid, ring + 9.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 vec2 toUv = iResolution.y / iResolution.xy;\n vec4 intact = pictureRGBA(uImage, p * toUv + 0.5);\n vec4 click = lastClick();\n float age = click.w > 0.5 ? iTime - click.z : -1.0;\n if (age < 0.0 || age > uRestore + 1.0) {\n fragColor = intact;\n return;\n }\n vec2 c = (click.xy - 0.5 * iResolution.xy) / iResolution.y;\n vec2 q = p - c;\n vec4 col = vec4(uBackground, 1.0);\n\n // Shards that have let go, falling and spinning: the first to fall is in front.\n // A ring at a time: the rings all of whose shards are too far from this pixel, wherever they are\n // in their fall, are passed over whole; later rings let go later, so once one is not yet falling\n // (or would be behind what is already here) neither are the rest.\n float best = 1e3;\n vec4 hit = vec4(0.0);\n vec2 hitCentre = vec2(0.0);\n float n = float(uSpokes);\n float spreadMax = tan(min(0.8 * TAU / n, 1.5));\n for (int j = 0; j < RINGS; j++) {\n float ring = float(j);\n float firstGo = 0.3 + 0.16 * ring;\n float dtHi = age - firstGo;\n if (dtHi <= 0.0 || firstGo >= best) break;\n float dtLo = max(dtHi - 0.25, 0.0);\n // Bounds on this ring's shards: how far out their middles are, how far they reach, how far they have drifted and dropped.\n float span = uScale * pow(uGrowth, ring);\n float lo = j > 0 ? span / uGrowth : 0.0;\n float rcLo = j > 0 ? 0.425 * (lo + span) : 0.561 * span;\n float rcHi = j > 0 ? 0.575 * (lo + span) : 0.759 * span;\n float radial = j > 0 ? 0.5 * max(1.15 * span - 0.85 * lo, 1.15 * lo - 0.85 * span) : rcHi;\n float reachMax = length(vec2(radial, 1.15 * span * spreadMax)) + 0.02;\n float rMin = rcLo + 0.05 * (1.0 - exp(-0.6 * dtLo)) / 0.6 / (1.0 + ring) - reachMax - 0.01;\n float rMax = rcHi + 0.2 * (1.0 - exp(-0.6 * dtHi)) / 0.6 / (1.0 + ring) + reachMax + 0.01;\n float yA = ballistic(vec2(0.0, 0.08), 0.6, uGravity, dtLo).y;\n float yB = ballistic(vec2(0.0, 0.08), 0.6, uGravity, dtHi).y;\n float yLo = min(yA, yB) - 0.02;\n float yHi = max(yA, yB) + 0.02;\n float dNear = length(vec2(q.x, q.y - clamp(q.y, yLo, yHi)));\n float dFar = max(length(q - vec2(0.0, yLo)), length(q - vec2(0.0, yHi)));\n if (dFar < rMin || dNear > rMax) continue;\n // And of its shards, only those whose sector points (near enough) at this pixel from where the impact point has dropped to:\n // each sector's middle lies 0.2–0.8 of the way round its share of the circle.\n float first = 0.0;\n float count = n;\n float slack = reachMax + 0.01;\n if (dNear > slack) {\n vec2 na = normalize(q - vec2(0.0, yLo));\n vec2 nb = normalize(q - vec2(0.0, yHi));\n float w = 0.5 * acos(clamp(dot(na, nb), -1.0, 1.0)) + asin(slack / dNear);\n vec2 bisect = na + nb;\n float toward = atan(bisect.y, bisect.x) / (TAU / n);\n w /= TAU / n;\n first = ceil(toward - w - 0.8);\n count = min(floor(toward + w - 0.2) - first + 1.0, n);\n }\n for (int k = 0; k < 16; k++) {\n if (float(k) >= count) break;\n float sid = mod(first + float(k), n);\n float tr = release(sid, ring);\n float dt = age - tr;\n if (dt <= 0.0 || tr >= best) continue;\n // How far it has drifted (along e) and dropped since it let go: ballistic(), split so the drop can be used first.\n float e = (1.0 - exp(-0.6 * dt)) / 0.6;\n // Seen from where the impact point has dropped to by now, too near or far, or not in this sector's direction.\n vec2 dropped = q - vec2(0.0, 0.08 * e - uGravity / 0.6 * (dt - e));\n float far = length(dropped);\n if (far < rMin || far > rMax) continue;\n // Its two cracks, the direction halfway between them and tan of half the angle they make.\n float a0 = spoke(sid);\n float a1 = spoke(sid + 1.0);\n vec2 d0 = vec2(cos(a0), sin(a0));\n vec2 d1 = vec2(cos(a1), sin(a1));\n vec2 dir = normalize(d0 + d1);\n float spread = (d0.x * d1.y - d0.y * d1.x) / (1.0 + dot(d0, d1));\n // Not pointing (near enough) this way: further off its middle than any of its corners could be.\n float near = length(vec2(radial, 1.15 * span * spread)) + 0.03;\n if (far > near && dot(dropped, dir) < sqrt(far * far - near * near)) continue;\n // Its middle, which it turns about, and how far it reaches from there (ringAt, with the ring's scale worked out above).\n float inner = j > 0 ? lo * (0.85 + 0.3 * hash12(vec2(sid, ring + 0.5))) : 0.0;\n float outer = j + 1 < RINGS ? span * (0.85 + 0.3 * hash12(vec2(sid, ring + 1.5))) : inner * uGrowth;\n float rc = j > 0 ? 0.5 * (inner + outer) : 0.66 * outer;\n float reach = length(vec2(max(outer - rc, rc - inner), outer * spread)) + 0.01;\n vec2 cen = dir * rc;\n vec2 h = hash22(vec2(sid, ring) + 17.3);\n vec2 rel = dropped - cen - normalize(cen + 1e-4) * (0.05 + 0.15 * h.x) / (1.0 + ring) * e;\n if (dot(rel, rel) > reach * reach) continue;\n float ang = (h.y - 0.5) * 2.0 * uSpin * dt;\n // It also turns about its own axis, narrowing and catching the light.\n float tilt = cos(dt * (0.6 + 1.2 * h.x) * uSpin);\n vec2 local = rot(-ang) * rel;\n local.x /= sign(tilt) * max(abs(tilt), 0.05);\n vec2 orig = cen + local;\n // Back on the pane, is that point inside this shard: between its two cracks and its two rings?\n float side0 = d0.x * orig.y - d0.y * orig.x;\n float side1 = d1.x * orig.y - d1.y * orig.x;\n float d = dot(orig, dir);\n float rim = j + 1 < RINGS ? outer : 1e3;\n if (side0 < 0.0 || side1 >= 0.0 || d >= rim) continue;\n // Past every ring inside it (they are a little ragged, so not only the nearest).\n bool past = true;\n for (int i = 1; i < RINGS; i++) {\n if (i > j) break;\n if (d < ringAt(sid, float(i))) {\n past = false;\n break;\n }\n }\n if (!past) continue;\n float edge = min(rim - d, min(abs(side0), abs(side1)));\n if (j > 0) edge = min(edge, d - inner);\n best = tr;\n hit = vec4(orig, tilt, edge);\n hitCentre = cen;\n }\n }\n\n if (best < 1e3) {\n vec2 uv = (c + hit.xy) * toUv + 0.5;\n float rim = smoothstep(0.014, 0.0, hit.w);\n vec2 o = normalize(hit.xy - hitCentre + 1e-4) * rim * 0.008;\n vec4 g = pictureRGBA(uImage, uv);\n vec3 pic = vec3(pictureRGBA(uImage, uv + o).r, g.g, pictureRGBA(uImage, uv - o).b);\n float facing = abs(hit.z);\n pic = mix(pic, vec3(0.7, 0.82, 0.88), 0.2 * (1.0 - facing)) * (0.55 + 0.45 * facing);\n pic += rim * (0.3 + 0.7 * pow(1.0 - facing, 2.0)) * vec3(0.9, 0.97, 1.0);\n pic += vec3(0.8, 0.9, 1.0) * pow(max(1.0 - abs(hit.z - 0.3), 0.0), 24.0) * 0.5;\n col = vec4(pic, g.a);\n } else {\n vec3 own = shardOf(q);\n if (age < release(own.x, own.y)) {\n // Still in place: cracks race out, with a little refraction beside each.\n float r = length(q);\n float reach = smoothstep(age * 5.0, age * 5.0 - 0.05, r);\n float crack = smoothstep(px * 1.6, 0.0, own.z) * reach;\n float near = smoothstep(px * 6.0, px * 1.5, own.z) * reach;\n vec4 pic = pictureRGBA(uImage, (p + vec2(0.003, -0.002) * near) * toUv + 0.5);\n vec3 rgb = pic.rgb * (1.0 - 0.18 * near) * (1.0 + reach * 0.08 * (hash12(own.xy) - 0.5)) + 0.85 * crack;\n float crush = smoothstep(0.03, 0.005, r) * (0.4 + 0.6 * hash12(floor(fragCoord / 2.0)));\n col = vec4(mix(rgb, vec3(0.93, 0.96, 1.0), 0.8 * crush), pic.a);\n }\n }\n // Mended: the pane fades back in whole.\n fragColor = mix(col, intact, smoothstep(uRestore, uRestore + 1.0, age));\n}`,\n ),\n presets: [\n { name: \"Fine crackle\", values: { uSpokes: 16, uGrowth: 1.35, uScale: 0.04, uSpin: 3.5 } },\n { name: \"Big panes\", values: { uSpokes: 7, uGrowth: 2.3, uScale: 0.16, uSpin: 1, uGravity: 1.2 } },\n { name: \"Slow motion\", values: { uGravity: 0.6, uSpin: 1, uRestore: 7 } },\n ],\n};\n\nexport const crumblingText: ShaderEffect = {\n kind: \"shader\",\n id: \"crumbling-text\",\n name: \"Crumbling text\",\n description: \"Stone letters cracking into chunks from one side, the chunks falling away into dust before the word rebuilds.\",\n category: \"debris\",\n video: \"none\",\n tags: [\"debris\", \"text\", \"title\", \"crumble\", \"stone\", \"dust\", \"loop\"],\n loop: 8,\n transparent: true,\n source: glsl(\n `// Crumbling text: chunks crack off from one side, fall and dissolve into dust; then the word rebuilds.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"DECAY\")} label=\"Text\"\nuniform vec3 uColor; // @control color default=#C9BBA4 label=\"Stone\"\nuniform vec3 uDust; // @control color default=#E3D8C6 label=\"Dust\"\nuniform float uChunk; // @control min=4 max=20 default=10 label=\"Chunks (text height)\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Text size\"\nuniform float uGravity; // @control min=0.3 max=4 default=1.4 label=\"Gravity\"\nuniform bool uFromRight; // @control default=false label=\"Crumble from the right\"\nuniform vec3 uBackground; // @control color default=#17141F 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.4 label=\"Crumble (when still)\"`,\n HASH,\n NOISE,\n ROTATE,\n BALLISTIC,\n OVER,\n `const float CYCLE = 8.0;\nconst float LIFE = 1.8;\nfloat textW = 1.0;\nfloat textH = 0.3;\nvec2 origin = vec2(0.0);\nfloat cs = 0.03;\n\nfloat mask(vec2 p) {\n vec2 uv = (p - origin) / vec2(textW, textH);\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// How far across the text x is, 0 on the side it crumbles from.\nfloat side(float x) {\n float s = (x - origin.x) / textW;\n return uFromRight ? 1.0 - s : s;\n}\n\n// Grid coordinates with wobbly cell edges, so chunks break off jagged.\nvec2 warped(vec2 p) {\n vec2 g = (p - origin) / cs;\n return g + 0.64 * (vec2(vnoise(g * 1.1 + 3.7), vnoise(g * 1.1 + 9.2)) - 0.5);\n}\n\n// When chunk id breaks off.\nfloat breakTime(vec2 id) {\n return 0.7 + 3.3 * clamp(side(origin.x + (id.x + 0.5) * cs), 0.0, 1.0) + 0.45 * hash12(id + 2.3);\n}\n\n// Stone at original point q, the chunk turned by ang: grit, and a bevel from the letter edges.\nvec3 stone(vec2 q, float ang) {\n float e = 0.004;\n vec2 g = vec2(mask(q + vec2(e, 0.0)) - mask(q - vec2(e, 0.0)), mask(q + vec2(0.0, e)) - mask(q - vec2(0.0, e)));\n vec3 n = normalize(vec3(-(rot(ang) * g) * 0.8, 1.0));\n float diff = clamp(dot(n, normalize(vec3(-0.5, 0.6, 0.65))), 0.0, 1.0);\n float grit = 0.6 * vnoise(q * 140.0) + 0.4 * vnoise(q * 35.0);\n return uColor * (0.45 + 0.7 * diff) * (0.8 + 0.35 * grit);\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 vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n textH = min(uSize * 0.5, iResolution.x / iResolution.y * uSize / aspect);\n textW = textH * aspect;\n origin = vec2(-0.5 * textW, 0.1 - 0.5 * textH);\n cs = textH / uChunk;\n float dirX = uFromRight ? -1.0 : 1.0;\n float tt = uAnimate ? mod(iTime, CYCLE) : uProgress * CYCLE;\n vec4 acc = vec4(uBackground * uBackgroundAlpha, uBackgroundAlpha);\n\n // The standing text: whole until its chunk breaks off, and grain by grain back again at the end.\n float m = mask(p);\n if (m > 0.0) {\n vec2 w = warped(p);\n float td = breakTime(floor(w));\n float tb = 6.0 + 1.3 * side(p.x);\n float grain = hash12(floor(p / (cs * 0.12)));\n float vis = tt < td ? 1.0 : step(grain, smoothstep(tb, tb + 0.6, tt));\n if (vis > 0.0) {\n vec2 f = fract(w);\n float edge = min(min(f.x, 1.0 - f.x), min(f.y, 1.0 - f.y)) * cs;\n // Cracks open around a chunk just before it goes.\n float warn = smoothstep(td - 0.6, td, tt) * step(tt, td);\n vec3 c = stone(p, 0.0) * (1.0 - 0.75 * warn * smoothstep(px * 2.0, 0.0, edge));\n acc = over(acc, c, m * vis);\n }\n }\n\n // Chunks that have broken off: drifting downwind, falling, spinning and crumbling to dust.\n float dust = 0.0;\n float col0 = floor((p.x - origin.x) / cs);\n float rows = ceil(uChunk);\n for (int k = 0; k < 6; k++) {\n float cx = col0 - dirX * float(k - 2);\n if (cx < -1.0 || cx * cs > textW + cs) continue;\n for (int r = -1; r < 21; r++) {\n if (float(r) > rows) break;\n vec2 id = vec2(cx, float(r));\n float a = tt - breakTime(id);\n if (a <= 0.0 || a > LIFE) continue;\n vec2 h = hash22(id + 4.1);\n vec2 centre = origin + (id + 0.5) * cs;\n vec2 off = ballistic(vec2(dirX * (0.5 + h.x), 0.3 + 1.2 * h.y) * cs, 1.5, uGravity, a);\n // Dust: grains shed as it crumbles, lagging behind it and spreading.\n float da = a - 0.35;\n if (da > 0.0) {\n vec2 dc = centre + off * 0.75 + vec2(dirX * 0.5, 0.3) * cs * da;\n float R = cs * (0.5 + 0.8 * da);\n float dd = length(p - dc) / R;\n if (dd < 1.0 && mask(centre) > 0.2) {\n float speck = step(0.55, hash12(floor((p - dc) / (px * 2.5)) + id));\n dust += (1.0 - dd) * smoothstep(0.0, 0.3, da) * (1.0 - smoothstep(0.5, LIFE - 0.35, da)) * (0.2 + 0.8 * speck);\n }\n }\n vec2 rel = p - centre - off;\n if (length(rel) > cs * 1.3) continue;\n float ang = (h.y - 0.5) * 6.0 * a;\n vec2 q = centre + rot(-ang) * rel;\n if (any(notEqual(floor(warped(q)), id))) continue;\n float mq = mask(q);\n if (mq <= 0.0) continue;\n float bits = hash12(floor((q - centre) / (cs * 0.12)) + id * 7.0);\n float cover = mq * step(smoothstep(0.35, LIFE, a), bits);\n if (cover <= 0.0) continue;\n acc = over(acc, stone(q, ang) * 0.92, cover);\n }\n }\n acc = over(acc, uDust, clamp(dust * 0.7, 0.0, 0.85));\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Sandstone\", values: { uColor: [0.86, 0.66, 0.42], uDust: [0.93, 0.8, 0.6], uChunk: 8 } },\n { name: \"Ruin\", values: { uText: textImage(\"RUIN\"), uColor: [0.78, 0.78, 0.8], uDust: [0.88, 0.88, 0.9], uBackground: [0.08, 0.08, 0.1], uBackgroundAlpha: 1, uFromRight: true } },\n { name: \"Ash\", values: { uColor: [0.32, 0.3, 0.3], uDust: [0.55, 0.53, 0.52], uChunk: 16, uGravity: 0.6 } },\n ],\n};\n\nexport const paperShreds: ShaderEffect = {\n kind: \"shader\",\n id: \"paper-shreds\",\n name: \"Paper shreds\",\n description: \"Strips of shredded paper with faint lines of print fluttering down, twisting and flipping as they fall.\",\n category: \"debris\",\n tags: [\"debris\", \"paper\", \"shredded\", \"falling\", \"office\", \"overlay\"],\n transparent: true,\n source: glsl(\n `// Paper shreds: twisting strips of printed paper flutter down in three depths.\nuniform vec3 uPaper; // @control color default=#F5F2EA label=\"Paper\"\nuniform vec3 uPaper2; // @control color default=#E4DED0 label=\"Second paper\"\nuniform vec3 uInk; // @control color default=#3A3F4A label=\"Ink\"\nuniform float uLines; // @control min=0 max=1 default=0.6 label=\"Print\"\nuniform float uCount; // @control min=3 max=20 default=8 label=\"Strips across\"\nuniform float uLength; // @control min=0.1 max=0.6 default=0.3 label=\"Strip length\"\nuniform float uWidth; // @control min=0.006 max=0.05 default=0.03 label=\"Strip width\"\nuniform float uSpeed; // @control min=0.05 max=0.6 default=0.16 label=\"Fall speed\"\nuniform float uFlutter; // @control min=0 max=1 default=0.5 label=\"Flutter\"\nuniform float uTwist; // @control min=0 max=3 default=1 label=\"Twist\"`,\n HASH,\n ROTATE,\n OVER,\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 vec4 acc = vec4(0.0);\n float cw = iResolution.x / iResolution.y / uCount;\n for (int l = 2; l >= 0; l--) {\n // Farther strips are smaller, slower and a little dimmer.\n float sc = 1.0 - 0.22 * float(l);\n vec2 pl = p / sc;\n float col = floor(pl.x / cw);\n for (int k = -1; k <= 1; k++) {\n float c = col + float(k);\n vec4 h = vec4(hash22(vec2(c, float(l)) + 0.71), hash22(vec2(c, float(l)) + 5.3));\n float L = uLength * (0.7 + 0.5 * h.x);\n float span = 1.0 / sc + L + 0.2;\n float t = iTime * (0.8 + 0.5 * h.y);\n float y = 0.5 / sc + 0.5 * L + 0.1 - mod(iTime * uSpeed * (0.8 + 0.4 * h.z) + h.w * span, span);\n // Swaying side to side as it falls, leaning into each swing.\n float swing = sin(t * 1.7 + h.z * 6.28);\n float x = (c + 0.5 + 0.4 * (h.w - 0.5)) * cw + uFlutter * cw * 0.3 * swing;\n float tilt = uFlutter * 0.45 * cos(t * 1.7 + h.z * 6.28) + 0.5 * (h.x - 0.5);\n vec2 d = rot(-tilt) * (pl - vec2(x, y));\n float s = d.y;\n if (abs(s) > 0.5 * L + px) continue;\n // A gentle curl along its length, and a twist that travels down it.\n float across = d.x - 0.08 * L * sin(t * 0.9 + h.x * 6.0) * (s / L) * (s / L) * 4.0;\n float phase = uTwist * (2.5 * s / L + t * 1.2) + h.y * 6.28;\n float ct = cos(phase);\n float halfW = 0.5 * uWidth * max(abs(ct), 0.04);\n float cover = smoothstep(halfW + px / sc, halfW - px / sc, abs(across)) * smoothstep(0.5 * L + px, 0.5 * L - px, abs(s));\n if (cover <= 0.0) continue;\n vec3 paper = h.z < 0.5 ? uPaper : uPaper2;\n float front = step(0.0, ct);\n // Print: short lines across the strip, cut from the lines of the page.\n float u = across / max(halfW, 1e-4);\n float row = floor(s / 0.011 + h.w * 10.0);\n float word = step(0.35, hash12(vec2(row, floor(u * 1.5 + h.x * 3.0) + c * 3.0)));\n float ink = front * uLines * word * step(0.55, fract(s / 0.011 + h.w * 10.0)) * step(abs(u), 0.85);\n vec3 colour = mix(paper * mix(0.82, 1.0, front), uInk, ink * 0.55);\n // Lit by how squarely it faces us, with a sheen as it turns edge-on.\n colour *= 0.6 + 0.4 * abs(ct);\n colour += 0.12 * pow(1.0 - abs(ct), 4.0);\n acc = over(acc, colour * (1.0 - 0.1 * float(l)), cover);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Ticker tape\", values: { uPaper: [1, 0.84, 0.3], uPaper2: [0.36, 0.75, 0.92], uLines: 0, uWidth: 0.022, uTwist: 1.8, uCount: 12 } },\n { name: \"Kraft\", values: { uPaper: [0.78, 0.63, 0.47], uPaper2: [0.7, 0.55, 0.4], uInk: [0.2, 0.14, 0.1], uLines: 0.3 } },\n { name: \"Storm\", values: { uSpeed: 0.45, uFlutter: 1, uTwist: 2.5, uCount: 14 } },\n ],\n};\n\nexport const leavesBlowing: ShaderEffect = {\n kind: \"shader\",\n id: \"leaves-blowing\",\n name: \"Leaves blowing\",\n description: \"Autumn leaves of several shapes blown across in gusts, tumbling and flipping over as they go.\",\n category: \"debris\",\n tags: [\"debris\", \"leaves\", \"autumn\", \"wind\", \"nature\", \"overlay\"],\n transparent: true,\n source: glsl(\n `// Leaves blowing: maple, oval and oak leaves carried by a gusty wind, tumbling and flipping.\nuniform vec3 uColor1; // @control color default=#C8371D label=\"Red\"\nuniform vec3 uColor2; // @control color default=#E8811F label=\"Orange\"\nuniform vec3 uColor3; // @control color default=#EDB52F label=\"Gold\"\nuniform vec3 uColor4; // @control color default=#7A4A22 label=\"Brown\"\nuniform float uWind; // @control min=-2 max=2 default=0.6 label=\"Wind\"\nuniform float uGust; // @control min=0 max=1 default=0.5 label=\"Gusts\"\nuniform float uDensity; // @control min=0.1 max=1 default=0.35 label=\"Density\"\nuniform float uSize; // @control min=0.02 max=0.12 default=0.06 label=\"Leaf size\"\nuniform float uTumble; // @control min=0 max=2 default=1 label=\"Tumble\"`,\n HASH,\n ROTATE,\n OVER,\n `const float TAU = 6.28318;\n\n// How far the wind has carried things by time t: a steady wind with gusts on top.\nfloat carried(float t) {\n return uWind * (t + uGust * ((1.0 - cos(0.8 * t)) + 0.5 * (cos(1.0) - cos(2.1 * t + 1.0)) / 2.1));\n}\n\n// How far inside a leaf q is (negative outside), the leaf one unit long each way, its stem end down.\nfloat leaf(vec2 q, float shape) {\n if (shape < 1.0) {\n // Oval, pointed at both ends, finely toothed.\n float w = 0.46 * (1.0 - q.y * q.y) * (1.0 + 0.25 * q.y) * (1.0 + 0.05 * sin(q.y * 40.0));\n return w - abs(q.x);\n }\n if (shape < 2.0) {\n // Maple: five pointed lobes, a notch at the stem.\n float a = atan(q.x, q.y);\n float lobe = pow(abs(cos(a * 2.5)), 1.6);\n float r = (0.5 + 0.5 * lobe) * (1.0 - 0.1 * abs(sin(a * 12.5))) * (1.0 - 0.3 * smoothstep(1.9, 3.14, abs(a)));\n return (r - length(q)) * 0.6;\n }\n // Oak: rounded lobes down each side.\n float w = 0.4 * sqrt(max(1.0 - q.y * q.y, 0.0)) * (0.72 + 0.28 * sin(q.y * 11.0 + 1.0));\n return w - abs(q.x);\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 vec4 acc = vec4(0.0);\n float X = carried(iTime);\n float gust = uWind * (1.0 + uGust * (0.8 * sin(0.8 * iTime) + 0.5 * sin(2.1 * iTime + 1.0)));\n for (int l = 2; l >= 0; l--) {\n // Three depths: farther leaves are smaller, slower and hazier.\n float sc = 1.0 - 0.25 * float(l);\n float cs = uSize * 4.5;\n vec2 drift = vec2(X * (0.8 + 0.2 * sc), -0.06 * iTime - 0.05 * uGust * sin(0.8 * iTime));\n vec2 pl = p / sc - drift + float(l) * 7.3;\n vec2 cell = floor(pl / cs);\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 c = cell + vec2(float(i), float(j));\n vec4 h = vec4(hash22(c + 0.13 * float(l)), hash22(c + 3.7 + float(l)));\n if (h.x > uDensity) continue;\n // Bobbing and fluttering about its place in the moving air.\n float t = iTime + h.y * 20.0;\n vec2 centre = (c + 0.5 + 0.4 * (h.zw - 0.5)) * cs\n + cs * vec2(0.12 * sin(t * 1.3), 0.15 * sin(t * 0.9 + h.z * 6.0) + 0.1 * uGust * sin(t * 2.3));\n float r = uSize * (0.75 + 0.5 * h.w);\n vec2 rel = pl - centre;\n if (length(rel) > r * 1.4) continue;\n // Tumbling and flipping faster as the wind carries it further.\n float spinDir = h.z < 0.5 ? -1.0 : 1.0;\n float spin = h.y * TAU + uTumble * spinDir * (X * (2.0 + 2.0 * h.w) + 0.4 * sin(t));\n float flip = h.w * TAU + uTumble * (X * (3.0 + 2.0 * h.y) + t * 0.6);\n float cf = cos(flip);\n vec2 q = rot(-spin) * rel / r;\n q.x /= sign(cf) * max(abs(cf), 0.06);\n float shape = floor(h.z * 2.999 + h.x);\n shape = mod(shape, 3.0);\n float inside = leaf(q, shape);\n // The stem.\n float stemTop = shape == 1.0 ? -0.4 : -0.95;\n float stem = 0.035 - abs(q.x + 0.06 * (q.y + 1.0) * (q.y + 1.0));\n stem = min(stem, min(stemTop - q.y, q.y + 1.35));\n float edge = max(inside, stem);\n float aa = px / (r * sc) * 1.5;\n float cover = smoothstep(-aa, aa, edge);\n if (cover <= 0.0) continue;\n // A colour from the palette, browner at the edges, with darker veins.\n float pick = fract(h.y * 7.0 + h.x * 3.0) * 4.0;\n vec3 colour = pick < 1.0 ? uColor1 : pick < 2.0 ? uColor2 : pick < 3.0 ? uColor3 : uColor4;\n colour = mix(colour, uColor4, 0.5 * smoothstep(0.08, 0.0, inside) * step(-0.5, inside));\n float vein = shape == 1.0\n ? smoothstep(0.05, 0.0, abs(fract(atan(q.x, q.y) / TAU * 5.0 + 0.5) - 0.5) * length(q) * 2.0)\n : max(smoothstep(0.03, 0.0, abs(q.x)), smoothstep(0.04, 0.0, abs(fract((q.y - abs(q.x) * 0.9) * 4.0) - 0.5) * 0.25));\n colour *= 1.0 - 0.3 * vein * step(0.0, inside);\n // Facing us it is lit; turning edge-on it darkens; the underside is paler and duller.\n if (cf < 0.0) colour = mix(colour, vec3(dot(colour, vec3(0.3, 0.5, 0.2))) * 1.15, 0.35);\n colour *= 0.55 + 0.45 * abs(cf);\n colour = mix(colour, colour * 0.75 + vec3(0.05), 0.4 * float(l) / 2.0);\n acc = over(acc, colour, cover);\n }\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Gale\", values: { uWind: 1.6, uGust: 1, uTumble: 1.6, uDensity: 0.7 } },\n { name: \"Lazy drift\", values: { uWind: 0.2, uGust: 0.2, uTumble: 0.5, uDensity: 0.35 } },\n { name: \"Summer green\", values: { uColor1: [0.3, 0.55, 0.2], uColor2: [0.45, 0.68, 0.25], uColor3: [0.62, 0.75, 0.3], uColor4: [0.25, 0.38, 0.15] } },\n ],\n};\n\nexport const sandErosion: ShaderEffect = {\n kind: \"shader\",\n id: \"sand-erosion\",\n name: \"Sand erosion\",\n description: \"A shape of packed sand eroded grain by grain by the wind from one side, the grains streaming away before it reforms.\",\n category: \"debris\",\n video: \"none\",\n tags: [\"debris\", \"sand\", \"erosion\", \"wind\", \"text\", \"particles\", \"disintegrate\", \"loop\"],\n loop: 8,\n transparent: true,\n source: glsl(\n `// Sand erosion: the wind strips a sand shape grain by grain from one side; then it blows back together.\nuniform sampler2D uMask; // @control filter=linear wrap=clamp default=${textImage(\"SAND\")} label=\"Shape (alpha)\"\nuniform vec3 uSand; // @control color default=#E6BE7A label=\"Sand\"\nuniform vec3 uShade; // @control color default=#A8743A label=\"Shadow\"\nuniform float uWind; // @control min=0.3 max=2 default=1 label=\"Wind\"\nuniform float uTurbulence; // @control min=0 max=1 default=0.5 label=\"Turbulence\"\nuniform float uGrain; // @control min=0.003 max=0.015 default=0.007 label=\"Grain size\"\nuniform float uSize; // @control min=0.3 max=1 default=0.85 label=\"Shape size\"\nuniform bool uFromRight; // @control default=false label=\"Wind from the right\"\nuniform vec3 uBackground; // @control color default=#1B1410 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.35 label=\"Erosion (when still)\"`,\n HASH,\n NOISE,\n OVER,\n `const float CYCLE = 8.0;\nconst float LIFE = 1.8;\nconst float BATCH = LIFE / 24.0;\nfloat shapeW = 1.0;\nfloat shapeH = 0.3;\nvec2 origin = vec2(0.0);\nfloat dirX = 1.0;\n\nfloat mask(vec2 p) {\n vec2 uv = (p - origin) / vec2(shapeW, shapeH);\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// The batch of grains source point s goes with: the wind takes a ragged slab at a time, from the windward side.\nfloat batchOf(vec2 s) {\n float x = (s.x - origin.x) / shapeW;\n if (uFromRight) x = 1.0 - x;\n float t = 0.45 + 1.5 * x + 0.5 * (vnoise(s * 9.0) - 0.5) + 0.15 * (vnoise(s * 40.0) - 0.5);\n return floor(t / BATCH);\n}\n\n// How far a grain from s has blown after a seconds: picking up speed downwind, lifting, eddying.\nvec2 blown(float a, vec2 s) {\n float n1 = vnoise(s * 6.0 + vec2(a * 1.3, 0.0)) - 0.5;\n float n2 = vnoise(s * 6.0 + vec2(7.7, a * 1.1)) - 0.5;\n vec2 d = vec2(dirX * uWind * (0.15 * a + 0.55 * a * a), 0.05 * a + 0.03 * a * a);\n return d + uTurbulence * a * vec2(0.08 * n1, 0.22 * n2);\n}\n\nvec3 sand(vec2 cell, float light) {\n vec2 h = hash22(cell + 0.5);\n return mix(uShade, uSand, clamp(light * (0.65 + 0.45 * h.x), 0.0, 1.0)) * (0.9 + 0.2 * h.y);\n}\n\n// Packed sand: fine speckle and a little drift of tone.\nvec3 packed(vec2 p, float light) {\n float speck = hash12(floor(p / (uGrain * 0.45)));\n float tone = vnoise(p * 30.0);\n return mix(uShade, uSand, clamp(light * (0.7 + 0.25 * speck + 0.2 * tone), 0.0, 1.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 vec2 size = vec2(textureSize(uMask, 0));\n float aspect = size.x / max(size.y, 1.0);\n shapeH = min(uSize * 0.6, iResolution.x / iResolution.y * uSize * 0.8 / aspect);\n shapeW = shapeH * aspect;\n origin = vec2(-0.5 * shapeW, -0.5 * shapeH);\n dirX = uFromRight ? -1.0 : 1.0;\n // Erosion time runs up, then back down: the wind carries the grains back to reform it.\n float e = uAnimate ? 4.0 - abs(mod(iTime, CYCLE) - 4.0) : uProgress * 4.0;\n float now = floor(e / BATCH);\n vec4 acc = vec4(uBackground * uBackgroundAlpha, uBackgroundAlpha);\n\n // The standing sand, its windward edge loosening.\n float m = mask(p);\n if (m > 0.0) {\n float left = (batchOf(p) - now) * BATCH;\n if (left > 0.0) {\n float e2 = 0.006;\n float lit = 0.6 + 0.4 * clamp((mask(p + vec2(-e2, e2)) - mask(p + vec2(e2, -e2))) * 2.0 + 0.5, 0.0, 1.0);\n float loose = smoothstep(0.3, 0.0, left);\n float keep = step(loose * 0.7, hash12(floor(p / (uGrain * 0.5)) + 3.1));\n acc = over(acc, packed(p, lit), m * keep);\n }\n }\n\n // Grains in flight, a batch at a time: the oldest (furthest) first.\n if (e > 0.2) {\n for (int k = 23; k >= 0; k--) {\n float b = now - float(k);\n float a = e - b * BATCH;\n if (a < 0.0 || a > LIFE) continue;\n // Where its grains came from, give or take the turbulence: skip the batch unless that is in\n // the shape and in the slab of it this batch was taken from (see batchOf).\n vec2 from = (p - vec2(dirX * uWind * (0.15 * a + 0.55 * a * a), 0.05 * a + 0.03 * a * a) - origin) / vec2(shapeW, shapeH);\n vec2 sway = uTurbulence * a * vec2(0.04, 0.11) / vec2(shapeW, shapeH) + 1e-3;\n if (uFromRight) from.x = 1.0 - from.x;\n float slabLo = max((b * BATCH - 0.775) / 1.5, 0.0);\n float slabHi = min(((b + 1.0) * BATCH - 0.125) / 1.5, 1.0);\n if (from.x + sway.x < slabLo || from.x - sway.x > slabHi || from.y + sway.y < 0.0 || from.y - sway.y > 1.0) continue;\n // Back from where a grain is to where it came from.\n vec2 s = p - blown(a, p);\n s = p - blown(a, s);\n s = p - blown(a, s);\n if (batchOf(s) != b) continue;\n float ms = mask(s);\n if (ms < 0.3) continue;\n vec2 g = s / uGrain;\n vec2 cell = floor(g);\n vec2 h = hash22(cell + 9.7);\n if (h.x < 0.3) continue;\n float rad = (0.25 + 0.25 * h.y) * (1.0 - 0.4 * a / LIFE);\n float d = length(fract(g) - 0.5 - 0.4 * (hash22(cell + 2.3) - 0.5));\n float grain = smoothstep(rad, rad - max(px / uGrain, 0.15), d);\n float fade = 1.0 - smoothstep(LIFE * 0.5, LIFE, a);\n // Each grain, in a thin haze of the finer sand blowing with it.\n acc = over(acc, sand(cell, 0.9), max(grain, 0.22) * fade * ms);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Heart\", values: { uMask: SAMPLE_IMAGES.heart, uSand: [0.95, 0.62, 0.6], uShade: [0.7, 0.3, 0.32] } },\n { name: \"Snow\", values: { uSand: [0.97, 0.98, 1], uShade: [0.62, 0.7, 0.82], uTurbulence: 0.8, uBackground: [0.1, 0.13, 0.2], uBackgroundAlpha: 1 } },\n { name: \"Gale\", values: { uWind: 1.8, uTurbulence: 0.25, uFromRight: true } },\n ],\n};\n\n/** Debris: rubble, shards, crumbling, shreds, leaves and dust. */\nexport const debrisShaders: ShaderEffect[] = [rubbleFall, glassShatter, crumblingText, paperShreds, leavesBlowing, sandErosion];\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 * Impacts go off at each click, read from the `iClicks[8]` built-in the\n * wrapper declares (newest first: xy pixels, z the `iTime` of the click, w 1\n * for a click). Thumbnails and recordings have no pointer, so while there\n * are no clicks each one strikes on a schedule, which a `uDemo` control\n * turns off.\n */\n\n/**\n * `hitAt(i, demo, every)`: hit `i`, newest first, as (x, y, time, 1), or\n * zeros for none. With the demo on and no real clicks yet, a synthetic hit\n * lands every `every` seconds somewhere near the middle (needs {@link HASH}).\n */\nconst HITS = `\nvec4 hitAt(int i, bool demo, float every) {\n if (!demo || iClicks[0].w > 0.5) return iClicks[i];\n float k = floor(iTime / every) - float(i);\n vec2 h = hash22(vec2(k * 1.37 + 0.5, 3.7));\n return vec4((0.3 + 0.4 * h) * iResolution.xy, k * every, 1.0);\n}`.trim();\n\nexport const shockwave: ShaderEffect = {\n kind: \"shader\",\n id: \"shockwave\",\n name: \"Shockwave\",\n description: \"A picture hit by a shockwave from each click: a refracting ring bends it as it spreads, with a bright leading edge, a slight colour split and a flash where it struck.\",\n category: \"impact\",\n video: \"interactive\",\n tags: [\"impact\", \"interactive\", \"click\", \"image\", \"shockwave\", \"distortion\", \"action\"],\n source: glsl(\n `// Shockwave: a refracting ring spreading from each hit (the four newest at once).\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uStrength; // @control min=0 max=2 default=1 label=\"Refraction\"\nuniform float uSpeed; // @control min=0.2 max=3 default=1.1 label=\"Speed\"\nuniform float uWidth; // @control min=0.01 max=0.2 default=0.06 label=\"Ring width\"\nuniform float uLife; // @control min=0.4 max=4 default=1.4 label=\"Lifetime\"\nuniform float uChroma; // @control min=0 max=1 default=0.35 label=\"Colour split\"\nuniform vec3 uEdge; // @control color default=#E0F2FF label=\"Edge\"\nuniform float uFlash; // @control min=0 max=2 default=1 label=\"Flash\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n HITS,\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 off = vec2(0.0);\n float edge = 0.0;\n float shade = 0.0;\n float flash = 0.0;\n for (int i = 0; i < 4; i++) {\n vec4 c = hitAt(i, uDemo, 2.2);\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > uLife) continue;\n vec2 d = (fragCoord - c.xy) * px;\n float r = length(d);\n vec2 dir = d / max(r, 1e-5);\n float life = age / uLife;\n float fade = (1.0 - life) * (1.0 - life);\n float R = age * uSpeed;\n float w = uWidth * (0.6 + life * 1.4);\n float x = (r - R) / w;\n // The ring is a lens: it pushes samples outward ahead of its crest and inward behind it.\n float lens = -x * exp(-x * x) * smoothstep(0.0, 0.04, R);\n off += dir * lens * uStrength * w * 1.2 * fade;\n shade += lens * fade;\n // A thin bright front just ahead of the crest.\n float front = (x - 0.7) * 3.0;\n edge += exp(-front * front) * fade;\n flash += exp(-age * 14.0) * exp(-r * r / (0.03 + age * 0.3));\n }\n vec2 o = off * vec2(iResolution.y / iResolution.x, 1.0);\n vec4 pic = pictureRGBA(uImage, uv - o);\n vec3 col = pic.rgb;\n // Red and blue refract a little more and less than green.\n col.r = picture(uImage, uv - o * (1.0 + uChroma * 1.5)).r;\n col.b = picture(uImage, uv - o * (1.0 - uChroma * 1.5)).b;\n col *= 1.0 + shade * 0.25 * uStrength;\n col += uEdge * edge * 0.55;\n col = mix(col, vec3(1.0), clamp(flash * uFlash, 0.0, 1.0));\n float glow = clamp(edge * 0.55 + flash * uFlash, 0.0, 1.0);\n fragColor = vec4(col, max(pic.a, glow));\n}`,\n ),\n presets: [\n { name: \"Sonic boom\", values: { uStrength: 1.6, uSpeed: 1.8, uWidth: 0.1, uChroma: 0.7, uEdge: [1, 1, 1] } },\n { name: \"Ripple\", values: { uStrength: 0.6, uSpeed: 0.6, uWidth: 0.03, uLife: 2.5, uChroma: 0, uFlash: 0 } },\n { name: \"Plasma\", values: { uEdge: [0.75, 0.4, 1], uChroma: 1, uFlash: 1.6 } },\n ],\n};\n\nexport const groundSlam: ShaderEffect = {\n kind: \"shader\",\n id: \"ground-slam\",\n name: \"Ground slam\",\n description: \"A heavy landing seen side-on: cracks shoot across the ground, a ring of dust rolls out, rocks jump and the camera shakes.\",\n category: \"impact\",\n tags: [\"impact\", \"interactive\", \"click\", \"slam\", \"dust\", \"cracks\", \"rocks\", \"shake\", \"action\"],\n source: glsl(\n `// Ground slam: cracks, a rolling dust ring, jumping rocks and camera shake at each hit on the ground.\nuniform vec3 uSky; // @control color default=#9CC7E8 label=\"Sky\"\nuniform vec3 uGround; // @control color default=#9A7B5A label=\"Ground\"\nuniform vec3 uDust; // @control color default=#D8C3A5 label=\"Dust\"\nuniform vec3 uCrack; // @control color default=#2A1C12 label=\"Cracks\"\nuniform float uHorizon; // @control min=0.3 max=0.8 default=0.6 label=\"Horizon\"\nuniform int uCracks; // @control min=3 max=14 default=9 label=\"Cracks\"\nuniform float uReach; // @control min=0.1 max=0.8 default=0.38 label=\"Crack reach\"\nuniform float uDustAmount; // @control min=0 max=1 default=0.85 label=\"Dust\"\nuniform int uRocks; // @control min=0 max=24 default=12 label=\"Rocks\"\nuniform float uShake; // @control min=0 max=2 default=1 label=\"Shake\"\nuniform float uLife; // @control min=1 max=6 default=2.6 label=\"Lifetime\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n HASH,\n NOISE,\n FBM,\n HITS,\n `const float TILT = 0.28; // How flat the ground looks: circles on it squash to ellipses this tall.\n\n// Where hit c lands on the ground, in y-units: where it was clicked (halfway down the ground for a\n// click in the sky), or, for the idle demo, somewhere in the near ground.\nvec2 landing(vec4 c, float px) {\n vec2 p = c.xy * px;\n if (uDemo && iClicks[0].w < 0.5) return vec2(p.x, uHorizon * (0.25 + 0.2 * fract(c.z * 0.618)));\n return vec2(p.x, p.y < uHorizon ? clamp(p.y, 0.04, uHorizon - 0.06) : uHorizon * 0.4);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n // Camera shake from the newest hit: a hard jolt that rings down.\n vec4 c0 = hitAt(0, uDemo, 3.0);\n float age0 = c0.w > 0.5 ? iTime - c0.z : 99.0;\n if (age0 >= 0.0 && age0 < 1.0) {\n float k = uShake * exp(-age0 * 7.0) * smoothstep(0.0, 0.02, age0);\n p += k * 0.022 * vec2(sin(age0 * 61.0) + 0.5 * sin(age0 * 113.0), cos(age0 * 79.0 + 1.0));\n }\n // Sky and ground.\n float above = p.y - uHorizon;\n vec3 col;\n if (above > 0.0) {\n col = mix(mix(uSky, vec3(1.0), 0.35), uSky * 0.85, smoothstep(0.0, 0.45, above));\n } else {\n float depth = clamp(-above / uHorizon, 0.0, 1.0);\n vec2 g = vec2(p.x / (0.15 + depth), depth * 8.0);\n float grain = fbm(g * 3.0, 4);\n col = uGround * (0.72 + 0.4 * depth) * (0.85 + 0.3 * grain);\n col = mix(col, mix(uSky, uGround, 0.7), exp(-depth * 18.0) * 0.6);\n }\n float dust = 0.0;\n for (int i = 2; i >= 0; i--) {\n vec4 c = hitAt(i, uDemo, 3.0);\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 P = landing(c, px);\n vec2 d = p - P;\n // Size by distance: nearer (lower) hits look bigger.\n float scale = mix(1.5, 0.5, P.y / uHorizon);\n vec2 q = vec2(d.x, d.y / TILT) / scale;\n float r = length(q);\n if (above < 0.0) {\n // A dark dent where it landed.\n float dent = exp(-r * r / 0.004) * (1.0 - life * 0.5);\n col *= 1.0 - 0.45 * dent;\n // Cracks: jittered rays that shoot out fast and wander a little.\n float grow = uReach * (1.0 - exp(-age * 14.0));\n float n = float(uCracks);\n float a = atan(q.y, q.x) / 6.28318 + 0.5;\n float cell = floor(a * n);\n float crack = 0.0;\n for (int j = -1; j <= 1; j++) {\n float k = mod(cell + float(j), n);\n vec2 h = hash22(vec2(k + 0.5, c.z * 1.7 + 3.0));\n float len = grow * (0.45 + 0.55 * h.y);\n float ang = (k + 0.5 + (h.x - 0.5) * 0.7) / n;\n ang += (vnoise(vec2(r * 18.0, k * 5.0 + c.z)) - 0.5) * 0.05;\n float da = abs(fract(a - ang + 0.5) - 0.5) * 6.28318 * r;\n float w = 0.007 * (1.0 - r / max(len, 1e-4)) + 0.001;\n float on = step(r, len) * smoothstep(w, w * 0.3, da);\n crack = max(crack, on);\n }\n col = mix(col, uCrack, crack * (1.0 - smoothstep(0.6, 1.0, life)));\n }\n // A dust ring rolling out over the ground, billowing up as it goes.\n float R = 0.5 * (1.0 - exp(-age * 2.4)) * scale;\n float ringW = 0.07 * scale * (0.5 + life);\n float height = 0.16 * scale * (0.4 + life);\n float s = sqrt(max(R * R - d.x * d.x, 0.0)) * TILT;\n float side = smoothstep(R + ringW, R - ringW * 0.3, abs(d.x));\n float puff = 0.0;\n for (int f = 0; f < 2; f++) {\n float yg = f == 0 ? s : -s;\n float up = d.y - yg;\n puff += smoothstep(-ringW * TILT * 2.0, 0.0, up) * (1.0 - smoothstep(0.0, height, up));\n }\n float churn = fbm(vec2(atan(d.y, d.x) * 2.0, length(d) * 6.0 - age * 1.5) * 2.5 + c.z, 4);\n float densityHere = puff * side * smoothstep(0.25, 0.65, churn) * (1.0 - life) * smoothstep(0.0, 0.08, age);\n // A plume thrown straight up where it landed.\n float plumeH = 0.2 * scale * (1.0 - exp(-age * 5.0));\n float plumeW = 0.05 * scale * (1.0 + 2.0 * life) * (0.6 + 0.6 * clamp(d.y / max(plumeH, 1e-3), 0.0, 1.0));\n float plume = smoothstep(plumeW, plumeW * 0.3, abs(d.x)) * smoothstep(-0.02 * scale, 0.0, d.y) * (1.0 - smoothstep(plumeH * 0.5, plumeH, d.y));\n densityHere = max(densityHere, plume * smoothstep(0.3, 0.6, churn) * (1.0 - life) * (1.0 - life));\n dust = max(dust, densityHere);\n // Rocks thrown up from the impact, landing again around it.\n for (int j = 0; j < 24; j++) {\n if (j >= uRocks) break;\n vec2 h = hash22(vec2(float(j) * 3.7 + 1.0, c.z * 2.3));\n float h3 = hash12(h * 37.0 + c.z);\n float vx = (h.x - 0.5) * 0.6 * scale;\n float vy = (0.5 + 0.9 * h.y) * scale;\n float depthOff = (h3 - 0.5) * 0.12 * scale;\n float t = age;\n float g = 3.2 * scale;\n float flight = 2.0 * vy / g;\n float tt = min(t, flight);\n vec2 pos = P + vec2(vx * tt, depthOff * TILT + max(vy * tt - 0.5 * g * tt * tt, 0.0));\n float rr = (0.005 + 0.01 * h3) * scale;\n float sd = length((p - pos) * vec2(1.0, 1.2)) - rr;\n float a = (1.0 - smoothstep(-px, px, sd)) * (1.0 - smoothstep(0.75, 1.0, life));\n vec3 rc = uGround * (0.35 + 0.35 * h.y);\n rc += 0.15 * smoothstep(rr, -rr, dot(p - pos, vec2(0.6, -0.8)));\n // A shadow under it on the ground.\n vec2 below = (p - vec2(pos.x, P.y + depthOff * TILT)) * vec2(1.0, 3.0);\n float sh = exp(-dot(below, below) / (rr * rr * 4.0));\n col *= 1.0 - 0.3 * sh * step(above, 0.0) * (1.0 - life);\n col = mix(col, rc, a);\n }\n }\n col = mix(col, uDust * (0.85 + 0.25 * smoothstep(0.0, 0.2, p.y)), clamp(dust * uDustAmount, 0.0, 1.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Snowfield\", values: { uSky: [0.7, 0.78, 0.86], uGround: [0.9, 0.93, 0.97], uDust: [1, 1, 1], uCrack: [0.35, 0.45, 0.6] } },\n { name: \"Mars\", values: { uSky: [0.86, 0.6, 0.45], uGround: [0.65, 0.3, 0.17], uDust: [0.85, 0.5, 0.32], uCrack: [0.2, 0.08, 0.04], uShake: 1.5 } },\n { name: \"Tremor\", values: { uCracks: 14, uReach: 0.7, uRocks: 4, uDustAmount: 0.4, uShake: 2 } },\n ],\n};\n\nexport const impactFrame: ShaderEffect = {\n kind: \"shader\",\n id: \"impact-frame\",\n name: \"Impact frame\",\n description: \"An anime fighting-game impact frame: on each hit the picture punches in, flashes white and flickers inverted or two-tone behind radial speed lines, then recovers.\",\n category: \"impact\",\n video: \"interactive\",\n tags: [\"impact\", \"interactive\", \"click\", \"image\", \"anime\", \"manga\", \"speed-lines\", \"flash\", \"action\"],\n source: glsl(\n `// Impact frame: a few held frames of flash, inversion and speed lines at each hit.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform int uMode; // @control min=0 max=2 default=2 label=\"Look (0 inverted, 1 two-tone, 2 flicker)\"\nuniform vec3 uInk; // @control color default=#0B0B12 label=\"Ink\"\nuniform vec3 uPaper; // @control color default=#FFFFFF label=\"Paper\"\nuniform float uLines; // @control min=0 max=1 default=0.6 label=\"Speed lines\"\nuniform float uHold; // @control min=0.1 max=1 default=0.35 label=\"Hold (s)\"\nuniform float uFps; // @control min=6 max=30 default=12 step=1 label=\"Frames per second\"\nuniform float uPunch; // @control min=0 max=0.3 default=0.1 label=\"Punch-in\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n HITS,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec4 c = hitAt(0, uDemo, 2.4);\n float age = c.w > 0.5 ? iTime - c.z : 99.0;\n vec2 hit = c.w > 0.5 ? c.xy / iResolution.xy : vec2(0.5);\n // Held frames: time steps in whole frames while it hits, like hand-drawn animation.\n float frame = floor(max(age, 0.0) * uFps);\n float held = frame / uFps;\n float on = step(0.0, age) * step(held, uHold);\n float recover = age > uHold ? exp(-(age - uHold) * 9.0) : 1.0;\n float k = age >= 0.0 ? recover : 0.0;\n // Punch in towards the hit and jolt a little per frame.\n vec2 jolt = (hash22(vec2(frame, c.z)) - 0.5) * 0.012 * on;\n vec2 st = hit + (uv - hit) / (1.0 + uPunch * k) + jolt;\n vec4 pic = pictureRGBA(uImage, st);\n vec3 col = pic.rgb;\n if (on > 0.5) {\n float lum = dot(col, vec3(0.299, 0.587, 0.114));\n int look = uMode == 2 ? int(mod(frame, 2.0)) : uMode;\n if (look == 0) {\n // Inverted with the contrast pushed hard.\n col = clamp((1.0 - col - 0.5) * 1.8 + 0.5, 0.0, 1.0);\n } else {\n col = mix(uInk, uPaper, smoothstep(0.4, 0.5, lum));\n }\n // Radial speed lines bursting from the hit, redrawn each frame, clear near the middle.\n vec2 d = (uv - hit) * vec2(iResolution.x / iResolution.y, 1.0);\n float r = length(d);\n float a = atan(d.y, d.x) / 6.28318 + 0.5;\n float n = 180.0;\n float cell = floor(a * n);\n float h = hash12(vec2(cell, frame + c.z * 7.0));\n float inLine = abs(fract(a * n) - 0.5) * 2.0;\n float thick = 0.15 + 0.7 * h;\n float start = 0.18 + 0.35 * hash12(vec2(cell + 3.0, frame));\n float line = step(1.0 - uLines * 0.9, h) * step(inLine, thick) * smoothstep(start, start + 0.15, r);\n vec3 lineCol = look == 0 ? vec3(1.0) - uInk : uInk;\n col = mix(col, lineCol, line);\n // The first frame is a white flash.\n if (frame < 0.5) col = mix(uPaper, col, 0.15);\n pic.a = 1.0;\n } else if (age >= 0.0) {\n // Recovering: a brief bright, crisp overshoot settling back.\n col = mix(col, clamp((col - 0.5) * 1.3 + 0.58, 0.0, 1.0), k);\n }\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Shonen red\", values: { uMode: 1, uInk: [0.75, 0.04, 0.08], uPaper: [1, 0.96, 0.9], uLines: 0.8 } },\n { name: \"Negative\", values: { uMode: 0, uLines: 0.4, uHold: 0.25 } },\n { name: \"Long hold\", values: { uHold: 0.8, uFps: 8, uPunch: 0.2 } },\n ],\n};\n\nexport const meteorStrike: ShaderEffect = {\n kind: \"shader\",\n id: \"meteor-strike\",\n name: \"Meteor strike\",\n description: \"A meteor streaking down through a night sky on a burning trail and hitting the ground in a flash, a fireball and a spreading shockwave dome; it loops and strikes where you click.\",\n category: \"impact\",\n tags: [\"impact\", \"interactive\", \"click\", \"meteor\", \"fire\", \"explosion\", \"night\", \"space\", \"action\"],\n loop: 4,\n source: glsl(\n `// Meteor strike: fall, flash, fireball and shockwave dome, every few seconds and where you click.\nuniform vec3 uSky; // @control color default=#0B1026 label=\"Night sky\"\nuniform vec3 uLand; // @control color default=#141826 label=\"Land\"\nuniform vec3 uFire; // @control color default=#FF7A1A label=\"Fire\"\nuniform vec3 uTrail; // @control color default=#7FD6FF label=\"Trail glow\"\nuniform float uPeriod; // @control min=3 max=10 default=4 label=\"Every (seconds)\"\nuniform float uAngle; // @control min=20 max=70 default=38 label=\"Angle (degrees)\"\nuniform float uSize; // @control min=0.4 max=2 default=1 label=\"Size\"\nuniform float uImpactX; // @control min=0.1 max=0.9 default=0.62 label=\"Strikes at\"\nuniform bool uDemo; // @control default=true label=\"Loop on its own\"`,\n HASH,\n NOISE,\n FBM,\n `// Ground height (y-units) at x: low rolling hills.\nfloat land(float x) {\n return 0.2 + 0.035 * sin(x * 3.1 + 1.0) + 0.02 * sin(x * 7.3 + 2.0);\n}\n\nvec3 fireRamp(float t) {\n t = clamp(t, 0.0, 1.0);\n vec3 c = mix(uFire * 0.2, uFire, smoothstep(0.0, 0.4, t));\n c = mix(c, vec3(1.0, 0.85, 0.45), smoothstep(0.4, 0.75, t));\n return mix(c, vec3(1.0, 0.98, 0.92), smoothstep(0.75, 1.0, t));\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float px = 1.0 / iResolution.y;\n vec2 p = fragCoord * px;\n float W = iResolution.x * px;\n // The strike: the newest click while it plays, else the loop.\n float fall = 1.0;\n float t = -99.0;\n float ix = uImpactX * W;\n if (iClicks[0].w > 0.5 && iTime - iClicks[0].z < uPeriod) {\n t = iTime - iClicks[0].z;\n ix = iClicks[0].x * px;\n } else if (uDemo) {\n t = mod(iTime, uPeriod);\n }\n vec2 I = vec2(ix, land(ix));\n float since = t - fall;\n float S = uSize;\n // Night sky with stars.\n vec3 col = mix(uSky * 1.6 + vec3(0.02, 0.02, 0.05), uSky * 0.6, smoothstep(0.0, 1.0, p.y));\n vec2 sc = floor(fragCoord / 3.0);\n float star = step(0.996, hash12(sc)) * (0.5 + 0.5 * sin(iTime * 3.14159 + hash12(sc + 7.0) * 40.0));\n col += vec3(star) * 0.8;\n // The flash lights the whole sky for a moment.\n float flash = since >= 0.0 ? exp(-since * 6.0) : 0.0;\n col += mix(uFire, vec3(1.0), 0.6) * flash * 0.55;\n // Fireball and dome glow from the impact.\n vec3 light = vec3(0.0);\n if (since >= 0.0 && since < uPeriod - fall) {\n float life = clamp(since / max(min(uPeriod - fall, 2.6), 0.1), 0.0, 1.0);\n vec2 d = (p - I) / S;\n float r = length(d);\n // Shockwave dome: a thin shell spreading over the ground.\n float R = 0.9 * (1.0 - exp(-since * 2.2));\n float shell = exp(-pow((r - R) / (0.012 + 0.03 * life), 2.0)) * step(-0.01, d.y);\n float inside = smoothstep(R, R - 0.1, r) * step(0.0, d.y) * 0.12;\n light += mix(uTrail, vec3(1.0), 0.5) * (shell * 0.9 + inside) * (1.0 - life) * (1.0 - life);\n // Fireball: a churning ball rising off the ground and cooling.\n vec2 fb = d - vec2(0.0, 0.05 * since);\n float fr = 0.13 * (1.0 - exp(-since * 5.0)) * (1.0 + 0.4 * life);\n float n = fbm(fb * 9.0 - vec2(0.0, since * 1.2) + I * 3.0, 5);\n float body = smoothstep(fr * (1.0 + 0.35 * n), fr * 0.4, length(fb * vec2(1.0, 1.15)));\n float heat = clamp(body * (1.4 - life * 1.3) + n * 0.2 - 0.1, 0.0, 1.0);\n float fbA = body * (1.0 - smoothstep(0.6, 1.0, life));\n vec3 smoke = mix(vec3(0.08, 0.07, 0.07), uFire * 0.15, heat);\n col = mix(col, mix(smoke, fireRamp(heat), smoothstep(0.1, 0.4, heat)), fbA * step(0.0, d.y + 0.02));\n // Its glow on the sky and ground.\n light += uFire * exp(-r * r / 0.05) * 0.8 * (1.0 - life);\n }\n // The ground, lit from the impact.\n float g = land(p.x);\n if (p.y < g) {\n float n = fbm(vec2(p.x * 8.0, p.y * 20.0), 3);\n vec3 ground = uLand * (0.7 + 0.5 * n);\n ground += light * 0.6 + uFire * flash * 0.3 * exp(-abs(p.x - I.x) * 3.0);\n float rim = exp(-(g - p.y) * 200.0);\n col = mix(ground, ground + uTrail * 0.1, rim);\n // A glowing crater after it lands.\n if (since >= 0.0) {\n float cr = exp(-dot((p - I) * vec2(1.0, 4.0), (p - I) * vec2(1.0, 4.0)) / (0.004 * S * S));\n col += fireRamp(0.7) * cr * exp(-since * 0.8) * 0.9 * (1.0 - smoothstep(0.5, 1.0, since / max(uPeriod - fall, 0.1)));\n }\n } else {\n col += light;\n }\n // The meteor: a white-hot head on a burning trail, falling at the angle onto the impact point.\n if (t >= 0.0 && since < 0.0) {\n float a = radians(uAngle);\n vec2 dir = vec2(cos(a), -sin(a));\n float dist = 1.6;\n vec2 head = I - dir * dist * (-since / fall) * (-since / fall + 0.3) / 1.3;\n vec2 rel = p - head;\n float along = dot(rel, -dir);\n float across = dot(rel, vec2(-dir.y, dir.x));\n float len = 0.55 * S;\n float tw = (0.006 + 0.02 * clamp(along / len, 0.0, 1.0)) * S;\n float flame = fbm(vec2(along * 14.0 - t * 18.0, across * 40.0), 4);\n float tail = step(0.0, along) * exp(-along / len * 2.5) * exp(-pow(across / (tw * (0.7 + flame)), 2.0));\n float glowT = step(0.0, along) * exp(-along / len * 1.5) * exp(-abs(across) / (0.05 * S)) * 0.35;\n float headD = length(rel) / S;\n float core = exp(-headD * headD / 0.00012);\n float halo = exp(-headD / 0.03) * 0.8;\n col += fireRamp(tail * 1.2) * tail * 1.4 + uTrail * glowT + mix(uTrail, vec3(1.0), 0.6) * (halo + core * 2.0);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Steep\", values: { uAngle: 66, uSize: 1.3, uImpactX: 0.5 } },\n { name: \"Alien world\", values: { uSky: [0.12, 0.03, 0.16], uLand: [0.1, 0.05, 0.12], uFire: [0.4, 1, 0.45], uTrail: [0.8, 0.5, 1] } },\n { name: \"Dusk\", values: { uSky: [0.2, 0.12, 0.25], uLand: [0.08, 0.06, 0.08], uFire: [1, 0.45, 0.15], uTrail: [1, 0.8, 0.5], uPeriod: 6 } },\n ],\n};\n\nexport const screenShake: ShaderEffect = {\n kind: \"shader\",\n id: \"screen-shake\",\n name: \"Screen shake\",\n description: \"A picture jolted by each hit: it shakes and twists on damped random offsets while a flash and a vignette pulse in the hit colour.\",\n category: \"impact\",\n video: \"interactive\",\n tags: [\"impact\", \"interactive\", \"click\", \"image\", \"shake\", \"damage\", \"flash\", \"game\", \"action\"],\n source: glsl(\n `// Screen shake: damped random offsets, a little twist and zoom, a flash and a vignette pulse per hit.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmount; // @control min=0 max=2 default=1 label=\"Shake\"\nuniform float uRotation; // @control min=0 max=2 default=0.8 label=\"Twist\"\nuniform float uDamping; // @control min=1 max=12 default=5 label=\"Damping\"\nuniform float uFrequency; // @control min=5 max=60 default=28 label=\"Frequency\"\nuniform vec3 uColor; // @control color default=#FF2A2A label=\"Hit colour\"\nuniform float uFlash; // @control min=0 max=1 default=0.35 label=\"Flash\"\nuniform float uVignette; // @control min=0 max=1 default=0.7 label=\"Vignette pulse\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n HITS,\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 vec2 shake = vec2(0.0);\n float twist = 0.0;\n float flash = 0.0;\n float pulse = 0.0;\n for (int i = 0; i < 4; i++) {\n vec4 c = hitAt(i, uDemo, 1.8);\n if (c.w < 0.5) continue;\n float age = iTime - c.z;\n if (age < 0.0 || age > 3.0) continue;\n float env = exp(-age * uDamping) * smoothstep(0.0, 0.015, age);\n // A first kick away from where it hit, then smooth random jitter.\n vec2 away = normalize(vec2(0.5) - c.xy / iResolution.xy + vec2(1e-3)) * exp(-age * 30.0);\n float s = age * uFrequency;\n vec2 jitter = vec2(vnoise(vec2(s, c.z * 3.0)), vnoise(vec2(s + 17.0, c.z * 5.0))) * 2.0 - 1.0;\n shake += (jitter + away * 0.6) * env;\n twist += (vnoise(vec2(s * 0.8 + 41.0, c.z)) * 2.0 - 1.0) * env;\n flash += exp(-age * 14.0);\n pulse += exp(-age * 4.0) * smoothstep(0.0, 0.03, age);\n }\n // Shake about the centre in a square frame, with a slight zoom so the edges stay filled.\n vec2 q = (uv - 0.5) * vec2(aspect, 1.0);\n float ang = twist * uRotation * 0.06;\n q = mat2(cos(ang), sin(ang), -sin(ang), cos(ang)) * q;\n q = q / (1.0 + 0.04 * uAmount * min(length(shake), 1.0)) + shake * uAmount * 0.03;\n vec2 st = q / vec2(aspect, 1.0) + 0.5;\n vec4 pic = pictureRGBA(uImage, st);\n vec3 col = pic.rgb;\n // Vignette pulse: the edges darken and take the hit colour.\n vec2 e = (uv - 0.5) * vec2(aspect, 1.0);\n float vig = smoothstep(0.25, 0.95, length(e) / max(aspect, 1.0) * 1.4);\n float v = clamp(pulse, 0.0, 1.0) * uVignette * vig;\n col = mix(col, col * 0.3 + uColor * 0.7, v);\n col = mix(col, mix(uColor, vec3(1.0), 0.6), clamp(flash, 0.0, 1.0) * uFlash);\n fragColor = vec4(col, max(pic.a, v));\n}`,\n ),\n presets: [\n { name: \"White hit\", values: { uColor: [1, 1, 1], uFlash: 0.6, uVignette: 0.3 } },\n { name: \"Earthquake\", values: { uAmount: 1.6, uRotation: 0.3, uDamping: 1.5, uFrequency: 14, uFlash: 0, uVignette: 0 } },\n { name: \"Critical\", values: { uAmount: 2, uRotation: 2, uDamping: 8, uFlash: 0.8, uVignette: 1 } },\n ],\n};\n\nexport const impactShaders: ShaderEffect[] = [shockwave, groundSlam, impactFrame, meteorStrike, screenShake];\n","import { 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 * Cartoon and comic shaders: a picture inked and printed as a comic panel,\n * toon-shaded, streaked with speed lines, framed by manga focus lines, or\n * turned into the next picture panel by panel. Inked looks share a Sobel\n * edge finder over brightness and alpha (so a cut-out's outline is inked too).\n */\n\n/**\n * `inkEdge(tex, uv, d)`: Sobel edge strength of an image's brightness and\n * alpha, sampling `d` apart (in uv). Needs {@link PICTURE}.\n */\nconst INK_EDGE = `\nvec2 lumaAlpha(sampler2D tex, vec2 uv) {\n vec4 c = pictureRGBA(tex, uv);\n return vec2(dot(c.rgb, vec3(0.2126, 0.7152, 0.0722)), c.a);\n}\nfloat inkEdge(sampler2D tex, vec2 uv, vec2 d) {\n vec2 tl = lumaAlpha(tex, uv + vec2(-d.x, d.y));\n vec2 t = lumaAlpha(tex, uv + vec2(0.0, d.y));\n vec2 tr = lumaAlpha(tex, uv + d);\n vec2 l = lumaAlpha(tex, uv - vec2(d.x, 0.0));\n vec2 r = lumaAlpha(tex, uv + vec2(d.x, 0.0));\n vec2 bl = lumaAlpha(tex, uv - d);\n vec2 b = lumaAlpha(tex, uv - vec2(0.0, d.y));\n vec2 br = lumaAlpha(tex, 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}`.trim();\n\nexport const comicBook: ShaderEffect = {\n kind: \"shader\",\n id: \"comic-book\",\n name: \"Comic book\",\n description: \"Any picture printed as a comic panel: thick inked outlines, flat posterised colour, Ben-Day dots of cyan, magenta and yellow in the mid-tones, slightly off-register on yellowed paper.\",\n category: \"comic\",\n video: \"filter\",\n tags: [\"comic\", \"cartoon\", \"image\", \"ink\", \"ben-day\", \"print\", \"pop-art\"],\n presets: [\n { name: \"Pop art\", values: { uLevels: 3, uSaturation: 1.8, uDotSize: 9, uPaper: [1, 0.98, 0.94], uMisregister: 0 } },\n { name: \"Old pulp\", values: { uPaper: [0.9, 0.8, 0.6], uMisregister: 2.5, uSaturation: 0.8, uDots: 1 } },\n { name: \"Bold ink\", values: { uLine: 2.6, uThreshold: 0.18, uDots: 0.5 } },\n ],\n source: glsl(\n `// Comic book: inked Sobel outlines over flat colour printed as CMY Ben-Day dots on old paper.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uLine; // @control min=0.5 max=4 default=1.6 label=\"Line weight (px)\"\nuniform float uThreshold; // @control min=0.05 max=1 default=0.28 label=\"Ink threshold\"\nuniform vec3 uInk; // @control color default=#141210 label=\"Ink\"\nuniform int uLevels; // @control min=2 max=8 default=4 label=\"Colour levels\"\nuniform float uSaturation; // @control min=0 max=2 default=1.35 label=\"Saturation\"\nuniform float uDotSize; // @control min=3 max=16 default=6 label=\"Dot size (px)\"\nuniform float uDots; // @control min=0 max=1 default=0.85 label=\"Ben-Day dots\"\nuniform float uMisregister; // @control min=0 max=5 default=1.2 label=\"Misregistration (px)\"\nuniform vec3 uPaper; // @control color default=#F3E7C6 label=\"Paper\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n INK_EDGE,\n `// The picture at uv as flat ink: saturated and posterised, as cyan, magenta and yellow amounts.\nvec3 flatInk(vec2 uv) {\n vec3 c = picture(uImage, uv);\n float l = dot(c, vec3(0.2126, 0.7152, 0.0722));\n c = clamp(mix(vec3(l), c, uSaturation), 0.0, 1.0);\n float n = float(uLevels) - 1.0;\n c = floor(c * n + 0.5) / n;\n return 1.0 - c;\n}\n\n// Coverage of a dot screen at angle a (radians) for an ink amount: dots grow with it and merge when full.\nfloat screenDots(vec2 p, float a, float amount) {\n mat2 r = mat2(cos(a), sin(a), -sin(a), cos(a));\n vec2 q = r * p / uDotSize;\n float d = length(fract(q) - 0.5);\n float radius = sqrt(clamp(amount, 0.0, 1.0)) * 0.72;\n float aa = 0.7 / uDotSize;\n return smoothstep(radius + aa, radius - aa, d);\n}\n\n// Flat ink where it is solid or bare, dots in between.\nfloat printed(vec2 p, float a, float amount) {\n float mid = smoothstep(0.04, 0.2, amount) * smoothstep(0.98, 0.8, amount);\n return mix(amount, screenDots(p, a, amount), uDots * mid);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 px = 1.0 / iResolution.xy;\n vec4 pic = pictureRGBA(uImage, uv);\n // Each plate is printed a little off the others.\n vec2 m = uMisregister * px;\n float cyan = flatInk(uv + vec2(m.x, 0.3 * m.y)).r;\n float magenta = flatInk(uv - vec2(0.6 * m.x, m.y)).g;\n float yellow = flatInk(uv + vec2(-0.4 * m.x, 0.8 * m.y)).b;\n vec3 ink = vec3(\n printed(fragCoord, radians(15.0), cyan),\n printed(fragCoord, radians(75.0), magenta),\n printed(fragCoord, radians(0.0), yellow)\n );\n // Paper with a little fibre and age, then the inks multiplied over it.\n float fibre = vnoise(fragCoord * 0.35) * 0.06 + vnoise(fragCoord * 0.02) * 0.04;\n vec3 paper = uPaper * (0.96 + fibre);\n vec3 col = paper * (1.0 - ink * 0.92);\n // Thick black outlines: a hard threshold on Sobel edges, sampled a line weight apart.\n float edge = inkEdge(uImage, uv, uLine * px);\n float line = smoothstep(uThreshold, uThreshold + 0.08, edge);\n line *= 0.85 + 0.15 * vnoise(fragCoord * 0.2);\n col = mix(col, uInk, clamp(line * 1.2, 0.0, 1.0));\n fragColor = vec4(col, max(pic.a, clamp(line, 0.0, 1.0)));\n}`,\n ),\n};\n\nexport const celShade: ShaderEffect = {\n kind: \"shader\",\n id: \"cel-shade\",\n name: \"Cel shade\",\n description: \"A picture toon-shaded: its brightness stepped into a few crisp bands that keep its colours, with bright highlights and dark inked outlines.\",\n category: \"comic\",\n video: \"filter\",\n tags: [\"cartoon\", \"comic\", \"toon\", \"cel\", \"image\", \"anime\", \"outline\"],\n presets: [\n { name: \"Two-tone\", values: { uBands: 2, uShadow: 0.45, uSaturation: 1.5 } },\n { name: \"Anime\", values: { uBands: 3, uSaturation: 1.25, uHighlight: 0.7, uLine: 1.2, uOutline: [0.18, 0.1, 0.16] } },\n { name: \"Soft\", values: { uBands: 6, uLine: 0.8, uThreshold: 0.45 } },\n ],\n source: glsl(\n `// Cel shade: brightness quantised into crisp bands, colour kept, outlines inked.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uBands; // @control min=2 max=8 default=4 step=1 label=\"Bands\"\nuniform float uShadow; // @control min=0 max=0.8 default=0.25 label=\"Darkest band\"\nuniform float uSaturation; // @control min=0 max=2 default=1.3 label=\"Saturation\"\nuniform float uHighlight; // @control min=0 max=1 default=0.45 label=\"Highlights\"\nuniform vec3 uOutline; // @control color default=#111018 label=\"Outline\"\nuniform float uLine; // @control min=0 max=4 default=1.5 label=\"Outline weight (px)\"\nuniform float uThreshold; // @control min=0.05 max=1 default=0.3 label=\"Outline threshold\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n INK_EDGE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 px = 1.0 / iResolution.xy;\n vec4 pic = pictureRGBA(uImage, uv);\n // A little blur first, so the bands follow forms rather than texture.\n vec3 c = (pic.rgb * 4.0 + picture(uImage, uv + vec2(px.x * 1.5, 0.0)) + picture(uImage, uv - vec2(px.x * 1.5, 0.0)) +\n picture(uImage, uv + vec2(0.0, px.y * 1.5)) + picture(uImage, uv - vec2(0.0, px.y * 1.5))) / 8.0;\n float l = max(dot(c, vec3(0.2126, 0.7152, 0.0722)), 1e-3);\n // Crisp steps, antialiased by how fast brightness changes across the pixel.\n float x = l * uBands;\n float k = floor(x);\n float w = max(fwidth(x), 1e-3) * 0.75;\n float stepped = (k + smoothstep(1.0 - w, 1.0, fract(x))) / uBands;\n float shade = mix(uShadow, 1.0, clamp(stepped + 0.5 / uBands, 0.0, 1.0));\n vec3 hue = c / l;\n hue = max(mix(vec3(1.0), hue, uSaturation), 0.0);\n vec3 col = clamp(hue * shade * 0.9, 0.0, 1.0);\n // A highlight band on the brightest parts.\n float fw = max(fwidth(l), 1e-3);\n float hi = smoothstep(0.8 - fw, 0.8 + fw, l) * uHighlight;\n col = mix(col, vec3(1.0), hi * 0.6);\n float edge = uLine > 0.0 ? inkEdge(uImage, uv, uLine * px) : 0.0;\n float line = smoothstep(uThreshold, uThreshold + 0.06, edge);\n col = mix(col, uOutline, line);\n fragColor = vec4(col, max(pic.a, line));\n}`,\n ),\n};\n\nexport const focusLines: ShaderEffect = {\n kind: \"shader\",\n id: \"focus-lines\",\n name: \"Focus lines\",\n description: \"Manga focus lines: tapering radial speed lines converging on the centre, or the pointer, around a clear middle, flickering and shifting a few times a second.\",\n category: \"comic\",\n tags: [\"comic\", \"manga\", \"anime\", \"speed-lines\", \"focus\", \"interactive\", \"overlay\"],\n transparent: true,\n presets: [\n { name: \"Black on white\", values: { uInk: [0, 0, 0], uPaper: [1, 1, 1], uPaperAlpha: 1 } },\n { name: \"White on black\", values: { uInk: [1, 1, 1], uPaper: [0, 0, 0], uPaperAlpha: 1 } },\n { name: \"Overlay\", values: { uInk: [0, 0, 0], uPaperAlpha: 0, uClear: 0.5 } },\n ],\n source: glsl(\n `// Focus lines: radial wedges converging on a point, with a clear area round it.\nuniform float uLines; // @control min=30 max=300 default=150 step=1 label=\"Lines\"\nuniform float uClear; // @control min=0.05 max=0.9 default=0.42 label=\"Clear area\"\nuniform float uThickness; // @control min=0.05 max=1 default=0.55 label=\"Thickness\"\nuniform float uRate; // @control min=0 max=30 default=12 label=\"Flickers per second\"\nuniform bool uFollow; // @control default=true label=\"Converge on the pointer\"\nuniform vec3 uInk; // @control color default=#000000 label=\"Lines\"\nuniform vec3 uPaper; // @control color default=#FFFFFF label=\"Background\"\nuniform float uPaperAlpha; // @control min=0 max=1 default=1 label=\"Background opacity\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 middle = 0.5 * iResolution.xy;\n float hover = uFollow ? clamp(iPointer.z, 0.0, 1.0) : 0.0;\n vec2 centre = mix(middle, iPointer.xy, hover);\n vec2 d = fragCoord - centre;\n float rpx = length(d);\n // The clear area is an ellipse the frame's shape.\n float r = length(d / (0.5 * iResolution.xy));\n float frame = floor(iTime * uRate);\n float a = atan(d.y, d.x) / 6.28318 + 0.5;\n float s = a * uLines + hash12(vec2(frame, 7.0)) * 0.6;\n float cell = mod(floor(s), uLines);\n vec2 h = hash22(vec2(cell, frame * 1.37 + 3.0));\n float h3 = hash12(vec2(cell * 1.7 + 2.0, frame));\n // Some lines are missing, each starts its own way from the clear area, and widens outwards.\n float present = step(0.18, h.x);\n float start = uClear * (0.85 + 0.45 * h.y);\n float grow = smoothstep(start, start + 0.35 + 0.4 * h3, r);\n float halfWidth = 0.5 * uThickness * (0.35 + 0.65 * h3) * grow;\n float across = (abs(fract(s) - 0.5) - halfWidth) * rpx * 6.28318 / uLines;\n float cover = present * step(start, r) * clamp(0.5 - across, 0.0, 1.0);\n vec4 acc = vec4(uPaper * uPaperAlpha, uPaperAlpha);\n acc = vec4(acc.rgb * (1.0 - cover) + uInk * cover, acc.a * (1.0 - cover) + cover);\n fragColor = vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`,\n ),\n};\n\nexport const actionLines: ShaderEffect = {\n kind: \"shader\",\n id: \"action-lines\",\n name: \"Action lines\",\n description: \"Comic speed lines streaking across a picture at any angle, with the picture smeared along them, so it reads as rushing past.\",\n category: \"comic\",\n video: \"filter\",\n tags: [\"comic\", \"cartoon\", \"speed-lines\", \"motion\", \"image\", \"manga\"],\n presets: [\n { name: \"Ink streaks\", values: { uLineColor: [0.05, 0.05, 0.06], uLineAlpha: 0.9, uCover: 0.4 } },\n { name: \"Diagonal dash\", values: { uAngle: 30, uSpeed: 2.5, uSmear: 0.05, uCover: 0.65 } },\n { name: \"Vertical drop\", values: { uAngle: 270, uDensity: 90, uLength: 0.6 } },\n ],\n source: glsl(\n `// Action lines: speed lines streaking along an angle, the picture smeared the same way.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uAngle; // @control min=0 max=360 default=180 label=\"Direction (°)\"\nuniform float uDensity; // @control min=20 max=200 default=60 step=1 label=\"Line rows\"\nuniform float uCover; // @control min=0 max=1 default=0.5 label=\"Lines\"\nuniform float uLength; // @control min=0.05 max=1 default=0.4 label=\"Line length\"\nuniform float uSpeed; // @control min=0 max=5 default=1.6 label=\"Speed\"\nuniform float uSmear; // @control min=0 max=0.12 default=0.035 label=\"Smear\"\nuniform vec3 uLineColor; // @control color default=#FFFFFF label=\"Line colour\"\nuniform float uLineAlpha; // @control min=0 max=1 default=0.85 label=\"Line opacity\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float ang = radians(uAngle);\n vec2 dir = vec2(cos(ang), sin(ang));\n vec2 perp = vec2(-dir.y, dir.x);\n // Smear: the picture averaged behind each point along the motion, heavier near it.\n vec2 back = -dir * uSmear * vec2(iResolution.y / iResolution.x, 1.0);\n vec4 pic = pictureRGBA(uImage, uv);\n vec3 col = pic.rgb * 0.25;\n float total = 0.25;\n for (int i = 1; i < 8; i++) {\n float k = float(i) / 7.0;\n float w = 1.0 - 0.6 * k;\n col += picture(uImage, uv + back * k) * w;\n total += w;\n }\n col /= total;\n // Streaks in rows across the motion, each its own speed, length and thickness.\n vec2 p = fragCoord - 0.5 * iResolution.xy;\n float rowH = iResolution.y / uDensity;\n float acrossPx = dot(p, perp);\n float row = floor(acrossPx / rowH);\n vec2 h = hash22(vec2(row, 3.7));\n float h3 = hash12(vec2(row, 9.1));\n float present = step(1.0 - uCover, h.x);\n float thick = rowH * (0.08 + 0.3 * h3);\n float dist = abs(acrossPx - (row + 0.5 + 0.3 * (h.y - 0.5)) * rowH);\n float lineMask = clamp(thick * 0.5 - dist + 0.5, 0.0, 1.0);\n float along = dot(p, dir) / iResolution.x;\n float span = uLength * (0.6 + 0.8 * h.y) + 0.3;\n float t = fract((along - iTime * uSpeed * (0.6 + 0.8 * h3)) / span + h.x * 7.0);\n float seg = uLength * (0.6 + 0.8 * h.y) / span;\n // A bright head fading to a thin tail.\n float streak = smoothstep(seg, seg * 0.85, t) * smoothstep(0.0, seg * 0.9, t);\n float m = present * lineMask * streak * uLineAlpha;\n col = mix(col, uLineColor, m);\n fragColor = vec4(col, max(pic.a, m));\n}`,\n ),\n};\n\nexport const transitionComicPanels: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-comic-panels\",\n name: \"Comic panels\",\n description: \"The next picture arrives panel by panel: the frame splits into comic panels with white gutters and black borders, each panel wipes, slides or pops to the new picture in turn, then the gutters close.\",\n category: \"transition\",\n video: \"transition\",\n tags: [\"transition\", \"comic\", \"cartoon\", \"panels\", \"image\", \"slideshow\"],\n loop: 4,\n presets: [\n { name: \"Manga\", values: { uGutterColor: [0.98, 0.98, 0.98], uInk: [0, 0, 0], uGutter: 0.03, uBorder: 4 } },\n { name: \"Night page\", values: { uGutterColor: [0.08, 0.08, 0.1], uInk: [0.95, 0.85, 0.3] } },\n ],\n source: glsl(\n `// Comic panels transition. 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)\"\nuniform float uGutter; // @control min=0.005 max=0.06 default=0.022 label=\"Gutter width\"\nuniform float uBorder; // @control min=0 max=8 default=3 label=\"Border (px)\"\nuniform vec3 uGutterColor; // @control color default=#FFFFFF label=\"Gutters\"\nuniform vec3 uInk; // @control color default=#111111 label=\"Borders\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// Signed distance in pixels from the line through a and b (uv), positive on its left.\nfloat side(vec2 uv, vec2 a, vec2 b) {\n vec2 p = uv * iResolution.xy;\n vec2 pa = a * iResolution.xy;\n vec2 ab = normalize((b - a) * iResolution.xy);\n vec2 q = p - pa;\n return ab.x * q.y - ab.y * q.x;\n}\n\n// Ease out with an overshoot.\nfloat backOut(float t) {\n float s = 2.2;\n t -= 1.0;\n return 1.0 + t * t * ((s + 1.0) * t + s);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float p = uAnimate ? smoothstep(0.08, 0.92, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n // The page: a slanted tier line, one cut above it and two below; distances in pixels.\n float tier = side(uv, vec2(0.0, 0.5), vec2(1.0, 0.55));\n float cutTop = side(uv, vec2(0.6, 1.0), vec2(0.55, 0.5));\n float cutA = side(uv, vec2(0.36, 0.0), vec2(0.31, 0.55));\n float cutB = side(uv, vec2(0.7, 0.0), vec2(0.74, 0.55));\n int panel;\n vec2 lo;\n vec2 size;\n float edge;\n if (tier > 0.0) {\n edge = min(tier, abs(cutTop));\n if (cutTop < 0.0) { panel = 0; lo = vec2(0.0, 0.5); size = vec2(0.6, 0.5); }\n else { panel = 1; lo = vec2(0.55, 0.5); size = vec2(0.45, 0.5); }\n } else {\n edge = -tier;\n if (cutA > 0.0) { panel = 2; lo = vec2(0.0); size = vec2(0.36, 0.55); edge = min(edge, cutA); }\n else if (cutB > 0.0) { panel = 3; lo = vec2(0.31, 0.0); size = vec2(0.43, 0.55); edge = min(edge, min(-cutA, cutB)); }\n else { panel = 4; lo = vec2(0.7, 0.0); size = vec2(0.3, 0.55); edge = min(edge, -cutB); }\n }\n vec2 framePx = min(fragCoord, iResolution.xy - fragCoord);\n edge = min(edge, min(framePx.x, framePx.y));\n // Gutters open at the start and close at the end.\n float open = smoothstep(0.0, 0.14, p) * (1.0 - smoothstep(0.86, 1.0, p));\n float gutter = 0.5 * uGutter * iResolution.y * open;\n float border = uBorder * open;\n // Each panel turns over in its own way, one after another.\n float t = clamp((p - 0.12 - float(panel) * 0.12) / 0.26, 0.0, 1.0);\n float e = 1.0 - pow(1.0 - t, 3.0);\n vec2 local = (uv - lo) / size;\n vec2 st = uv;\n float showTo = 0.0;\n float rim = 1e3;\n if (panel == 0) {\n // Wipe left to right.\n showTo = step(local.x, e * 1.05);\n rim = abs(local.x - e * 1.05) * size.x * iResolution.x;\n } else if (panel == 1) {\n // Slide down from the top.\n showTo = step(1.0 - e, local.y);\n st.y -= (1.0 - e) * size.y;\n rim = abs(local.y - (1.0 - e)) * size.y * iResolution.y;\n } else if (panel == 2) {\n // Pop out of the middle with an overshoot.\n float s = max(backOut(t), 1e-3);\n vec2 c = lo + 0.5 * size;\n vec2 q = (uv - c) / s;\n vec2 qa = abs(q) / size;\n showTo = step(max(qa.x, qa.y), 0.5) * step(1e-3, t);\n st = c + q;\n rim = (0.5 - max(qa.x, qa.y)) * min(size.x * iResolution.x, size.y * iResolution.y) * s;\n } else if (panel == 3) {\n // An iris from the bottom corner.\n vec2 q = local * size * iResolution.xy / iResolution.y;\n float radius = e;\n showTo = step(length(q), radius);\n rim = abs(length(q) - radius) * iResolution.y;\n } else {\n // Slide in from the right.\n showTo = step(1.0 - e, local.x);\n st.x -= (1.0 - e) * size.x;\n rim = abs(local.x - (1.0 - e)) * size.x * iResolution.x;\n }\n showTo = t >= 1.0 ? 1.0 : (t <= 0.0 ? 0.0 : showTo);\n vec4 col = mix(pictureRGBA(uFrom, uv), pictureRGBA(uTo, st), showTo);\n // A thin ink line on the moving edge while it moves.\n float moving = step(0.001, t) * step(t, 0.999);\n col = mix(col, vec4(uInk, 1.0), moving * clamp(2.0 - rim, 0.0, 1.0));\n vec4 frame = mix(vec4(uGutterColor, 1.0), vec4(uInk, 1.0), clamp(edge - gutter + 0.5, 0.0, 1.0));\n // Closed, there is no frame at all: the picture is whole.\n float inside = mix(1.0, clamp(edge - gutter - border + 0.5, 0.0, 1.0), smoothstep(0.0, 0.2, open));\n fragColor = mix(frame, col, inside);\n}`,\n ),\n};\n\n/** Cartoon and comic: inked looks, cel shading, speed lines and panels. */\nexport const comicShaders: ShaderEffect[] = [comicBook, celShade, focusLines, actionLines, transitionComicPanels];\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/** 3D value noise, 0–1: `vnoise3(p)` and `fbm3(p, octaves)`. */\nconst NOISE_3D = `\nfloat hash13(vec3 p3) {\n p3 = fract(p3 * 0.1031);\n p3 += dot(p3, p3.zyx + 31.32);\n return fract((p3.x + p3.y) * p3.z);\n}\nfloat vnoise3(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n vec3 u = f * f * (3.0 - 2.0 * f);\n float a = mix(hash13(i), hash13(i + vec3(1.0, 0.0, 0.0)), u.x);\n float b = mix(hash13(i + vec3(0.0, 1.0, 0.0)), hash13(i + vec3(1.0, 1.0, 0.0)), u.x);\n float c = mix(hash13(i + vec3(0.0, 0.0, 1.0)), hash13(i + vec3(1.0, 0.0, 1.0)), u.x);\n float d = mix(hash13(i + vec3(0.0, 1.0, 1.0)), hash13(i + vec3(1.0, 1.0, 1.0)), u.x);\n return mix(mix(a, b, u.y), mix(c, d, u.y), u.z);\n}\nfloat fbm3(vec3 p, int octaves) {\n float sum = 0.0;\n float amp = 0.5;\n for (int i = 0; i < 6; i++) {\n if (i >= octaves) break;\n sum += amp * vnoise3(p);\n p = p * 2.03 + vec3(11.7, 3.1, 7.9);\n amp *= 0.5;\n }\n return sum;\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 volumetricClouds: ShaderEffect = {\n kind: \"shader\",\n id: \"volumetric-clouds\",\n name: \"Volumetric clouds\",\n description: \"A ray-marched layer of soft, self-shadowed clouds drifting overhead, rimmed with a silver lining toward the sun.\",\n category: \"atmosphere\",\n tags: [\"atmosphere\", \"clouds\", \"sky\", \"background\", \"3d\", \"weather\"],\n source: glsl(\n `// Volumetric clouds: a cloud slab ray-marched with fbm density and a short march toward the sun.\nuniform vec3 uSkyTop; // @control color default=#3A78C9 label=\"Sky (top)\"\nuniform vec3 uSkyHorizon; // @control color default=#B8D8F2 label=\"Sky (horizon)\"\nuniform vec3 uCloudColor; // @control color default=#FFFFFF label=\"Cloud colour\"\nuniform vec3 uShadowColor; // @control color default=#5E6F8A label=\"Shadow colour\"\nuniform vec3 uSunColor; // @control color default=#FFF3DC label=\"Sun colour\"\nuniform float uSunAzimuth; // @control min=-3.1416 max=3.1416 default=0.4 label=\"Sun direction\"\nuniform float uSunHeight; // @control min=0 max=1.5 default=0.35 label=\"Sun height\"\nuniform float uCoverage; // @control min=0 max=1 default=0.5 label=\"Coverage\"\nuniform float uDensity; // @control min=0.1 max=3 default=1 label=\"Density\"\nuniform float uSpeed; // @control min=0 max=3 default=0.6 label=\"Drift speed\"`,\n NOISE_3D,\n `const float BOTTOM = 1.5;\nconst float TOP = 3.2;\n\n// The noise's lattice cell last used, and its eight corner hashes. Successive\n// samples along a ray (and toward the sun) mostly fall in the same cell of the\n// coarse octaves, so they reuse its hashes instead of hashing it again.\nstruct Cell {\n vec3 id;\n vec4 lo;\n vec4 hi;\n};\n\nCell noCell() {\n return Cell(vec3(1e9), vec4(0.0), vec4(0.0));\n}\n\n// vnoise3(p), with its corners taken from the cell when p is still in it.\nfloat cellNoise(vec3 p, inout Cell c) {\n vec3 i = floor(p);\n if (i != c.id) {\n c.id = i;\n c.lo = vec4(hash13(i), hash13(i + vec3(1.0, 0.0, 0.0)), hash13(i + vec3(0.0, 1.0, 0.0)), hash13(i + vec3(1.0, 1.0, 0.0)));\n c.hi = vec4(hash13(i + vec3(0.0, 0.0, 1.0)), hash13(i + vec3(1.0, 0.0, 1.0)), hash13(i + vec3(0.0, 1.0, 1.0)), hash13(i + vec3(1.0, 1.0, 1.0)));\n }\n vec3 f = fract(p);\n vec3 u = f * f * (3.0 - 2.0 * f);\n float a = mix(c.lo.x, c.lo.y, u.x);\n float b = mix(c.lo.z, c.lo.w, u.x);\n float cc = mix(c.hi.x, c.hi.y, u.x);\n float d = mix(c.hi.z, c.hi.w, u.x);\n return mix(mix(a, b, u.y), mix(cc, d, u.y), u.z);\n}\n\n// fbm3(p, octaves) for three octaves or more, the first three through cells c0, c1 and c2.\nfloat cloudNoise(vec3 p, int octaves, inout Cell c0, inout Cell c1, inout Cell c2) {\n float sum = 0.5 * cellNoise(p, c0);\n p = p * 2.03 + vec3(11.7, 3.1, 7.9);\n sum += 0.25 * cellNoise(p, c1);\n p = p * 2.03 + vec3(11.7, 3.1, 7.9);\n sum += 0.125 * cellNoise(p, c2);\n p = p * 2.03 + vec3(11.7, 3.1, 7.9);\n float amp = 0.0625;\n for (int i = 3; i < 6; i++) {\n if (i >= octaves) break;\n sum += amp * vnoise3(p);\n p = p * 2.03 + vec3(11.7, 3.1, 7.9);\n amp *= 0.5;\n }\n return sum;\n}\n\n// The cloud's density at p from its noise to the given octaves; rest stands in\n// for the octaves left out (their average), so the cloud keeps its mass.\nfloat cloudDensity(vec3 p, int octaves, float rest, inout Cell c0, inout Cell c1, inout Cell c2) {\n float h = clamp((p.y - BOTTOM) / (TOP - BOTTOM), 0.0, 1.0);\n // Rounded tops and flat-ish bases.\n float shape = smoothstep(0.0, 0.15, h) * (1.0 - smoothstep(0.45, 1.0, h));\n // Outside the slab there's no cloud, whatever the noise.\n if (shape <= 0.0) return 0.0;\n vec3 q = p * 0.42 + vec3(iTime * uSpeed * 0.12, 0.0, iTime * uSpeed * 0.05);\n float n = cloudNoise(q, octaves, c0, c1, c2) + rest;\n return clamp((n - (1.0 - uCoverage) * 0.75) * 3.0 * shape, 0.0, 1.0) * uDensity;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n vec3 rd = normalize(vec3(p.x, p.y + 0.28, 1.0));\n vec3 sun = normalize(vec3(sin(uSunAzimuth), uSunHeight, cos(uSunAzimuth)));\n float mu = dot(rd, sun);\n\n vec3 sky = mix(uSkyHorizon, uSkyTop, pow(clamp(rd.y, 0.0, 1.0), 0.6));\n sky += uSunColor * (pow(max(mu, 0.0), 600.0) * 2.0 + pow(max(mu, 0.0), 12.0) * 0.25);\n if (rd.y < 0.0) sky = mix(uSkyHorizon, uShadowColor, clamp(-rd.y * 4.0, 0.0, 0.6));\n\n vec3 col = vec3(0.0);\n float trans = 1.0;\n if (rd.y > 0.02) {\n float t0 = BOTTOM / rd.y;\n float t1 = min(TOP / rd.y, t0 + 14.0);\n // Steps of about 0.35 (as long as a ray toward the horizon takes in 40), so\n // short, steep rays take fewer: between 28 and 40 (fewer shows the jitter as grain).\n float steps = clamp(ceil((t1 - t0) / 0.35), 28.0, 40.0);\n float dt = (t1 - t0) / steps;\n float t = t0 + dt * fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453);\n // Henyey-Greenstein: a forward lobe for the silver lining plus a soft back lobe.\n float g = 0.65;\n float hg = (1.0 - g * g) / pow(1.0 + g * g - 2.0 * g * mu, 1.5) / 12.566;\n float phase = mix(0.08, hg * 4.0, 0.7);\n // Noise cells along the ray (m) and toward the sun (l).\n Cell m0 = noCell();\n Cell m1 = noCell();\n Cell m2 = noCell();\n Cell l0 = noCell();\n Cell l1 = noCell();\n Cell l2 = noCell();\n for (int i = 0; i < 40; i++) {\n if (trans < 0.02 || t > 60.0 || float(i) >= steps) break;\n vec3 pos = rd * t;\n // Fine detail where it shows: five octaves near and in front, fewer once\n // the cloud in front hides most of this sample, three far away.\n int oct = t < 18.0 ? (trans > 0.5 ? 5 : trans > 0.15 ? 4 : 3) : 3;\n float rest = t < 18.0 ? 0.5 * (exp2(-float(oct)) - exp2(-5.0)) : 0.0;\n float d = cloudDensity(pos, oct, rest, m0, m1, m2);\n if (d > 0.01) {\n // Light march toward the sun for self-shadowing: the cloud between 0.11 and\n // 0.99 toward it, sampled at the middles of its two halves.\n float shade = 0.0;\n for (int j = 0; j < 2; j++) shade += 2.0 * cloudDensity(pos + sun * (0.33 + 0.44 * float(j)), 3, 0.0, l0, l1, l2);\n float light = exp(-shade * 1.4);\n float powder = 1.0 - exp(-d * 4.0);\n vec3 lit = mix(uShadowColor, uCloudColor, light) + uSunColor * light * powder * phase * 2.5;\n float a = 1.0 - exp(-d * dt * 2.2);\n col += trans * a * lit;\n trans *= 1.0 - a;\n }\n t += dt;\n }\n // Far clouds fade into the horizon haze.\n float haze = exp(-max(t0 - 4.0, 0.0) * 0.06);\n col = mix(sky * (1.0 - trans), col, haze);\n }\n fragColor = vec4(sky * trans + col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Midday\", values: { uSunHeight: 1.2, uCoverage: 0.45, uDensity: 0.9 } },\n {\n name: \"Sunset\",\n values: {\n uSkyTop: [0.24, 0.27, 0.52],\n uSkyHorizon: [1, 0.62, 0.38],\n uCloudColor: [1, 0.78, 0.6],\n uShadowColor: [0.36, 0.25, 0.38],\n uSunColor: [1, 0.55, 0.25],\n uSunAzimuth: 0,\n uSunHeight: 0.08,\n uCoverage: 0.5,\n },\n },\n {\n name: \"Storm\",\n values: {\n uSkyTop: [0.22, 0.25, 0.3],\n uSkyHorizon: [0.45, 0.48, 0.52],\n uCloudColor: [0.62, 0.65, 0.7],\n uShadowColor: [0.12, 0.13, 0.17],\n uSunColor: [0.75, 0.8, 0.9],\n uCoverage: 0.85,\n uDensity: 2.2,\n uSpeed: 1.8,\n },\n },\n ],\n};\n\nexport const fogBanks: ShaderEffect = {\n kind: \"shader\",\n id: \"fog-banks\",\n name: \"Fog banks\",\n description: \"Horizontal banks of fog drifting at different depths and speeds, thickest near the ground, to lay over any scene.\",\n category: \"atmosphere\",\n tags: [\"atmosphere\", \"fog\", \"overlay\", \"moody\", \"weather\"],\n transparent: true,\n source: glsl(\n `// Fog banks: layered bands of fbm fog sliding sideways, near ones lower, faster and denser.\nuniform vec3 uColor; // @control color default=#DCE3EA label=\"Colour\"\nuniform float uDensity; // @control min=0 max=1.5 default=0.8 label=\"Density\"\nuniform float uHeight; // @control min=0.1 max=1 default=0.55 label=\"Height\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform int uLayers; // @control min=1 max=6 default=4 label=\"Layers\"`,\n HASH,\n NOISE,\n FBM,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float y = fragCoord.y / iResolution.y;\n vec4 acc = vec4(0.0);\n // Far layers first (high on screen, slow, thin), near layers painted over them.\n for (int i = 0; i < 6; i++) {\n if (i >= uLayers) break;\n float fi = float(i);\n float near = (fi + 1.0) / float(uLayers);\n float centre = uHeight * mix(0.85, 0.12, near);\n float thick = uHeight * mix(0.12, 0.3, near);\n float band = exp(-pow((y - centre) / thick, 2.0));\n band = max(band, step(y, centre) * mix(0.3, 1.0, near));\n float scale = mix(1.2, 2.6, near);\n vec2 q = vec2(p.x * scale + iTime * uSpeed * mix(0.015, 0.08, near) + fi * 7.3, p.y * scale * 3.0 + fi * 2.1);\n float n = fbm(q + 0.6 * vec2(fbm(q * 0.7 - iTime * 0.02, 3), 0.0), 5);\n float a = smoothstep(0.3, 0.8, n) * band * uDensity * mix(0.35, 0.8, near);\n // Ground haze: everything thickens toward the bottom.\n a = clamp(a + (1.0 - smoothstep(0.0, uHeight * 0.4, y)) * 0.12 * uDensity * near, 0.0, 1.0);\n vec3 c = uColor * mix(0.85, 1.0, n);\n acc = over(acc, c, a);\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Valley morning\", values: { uColor: [0.96, 0.93, 0.88], uDensity: 0.7, uHeight: 0.45, uSpeed: 0.6 } },\n { name: \"Moor\", values: { uColor: [0.66, 0.72, 0.75], uDensity: 1.2, uHeight: 0.8, uSpeed: 1.4, uLayers: 6 } },\n ],\n};\n\nexport const risingSteam: ShaderEffect = {\n kind: \"shader\",\n id: \"rising-steam\",\n name: \"Rising steam\",\n description: \"Wisps of steam curling up from a cup or vent, thinning and fading as they rise.\",\n category: \"atmosphere\",\n tags: [\"atmosphere\", \"steam\", \"overlay\", \"coffee\", \"warm\"],\n transparent: true,\n source: glsl(\n `// Rising steam: stretched noise wisps advected upward from a source, swaying and dissolving.\nuniform vec2 uSource; // @control min=-1 max=1 default=0,-0.6 label=\"Source\"\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Colour\"\nuniform float uWidth; // @control min=0.02 max=0.6 default=0.12 label=\"Width\"\nuniform float uHeight; // @control min=0.2 max=1.5 default=0.8 label=\"Height\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uTurbulence; // @control min=0 max=2 default=0.8 label=\"Curl\"\nuniform float uOpacity; // @control min=0 max=1 default=0.7 label=\"Opacity\"`,\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 h = q.y / uHeight;\n if (h < -0.05 || h > 1.2) { fragColor = vec4(uColor, 0.0); return; }\n float hc = clamp(h, 0.0, 1.0);\n float t = iTime * uSpeed;\n // The plume widens and sways more as it rises.\n float w = uWidth * (0.6 + 1.6 * hc);\n float sway = (sin(q.y * 5.0 - t * 1.1) * 0.5 + sin(q.y * 9.0 - t * 1.7 + 1.3) * 0.3) * uTurbulence * 0.06 * hc;\n vec2 flow = vec2(q.x, q.y - t * 0.25);\n vec2 warp = vec2(fbm(flow * 3.0 + vec2(0.0, -t * 0.2), 4), fbm(flow * 3.0 + vec2(5.2, 1.3), 4)) - 0.5;\n float x = (q.x - sway + warp.x * uTurbulence * 0.25 * hc) / w;\n // Wisps: noise stretched along the rise, so it reads as strands.\n vec2 sq = vec2(x * 2.2, (q.y - t * 0.3) / uHeight * 1.6) + warp * uTurbulence * 1.5;\n float strands = fbm(sq * vec2(1.0, 0.45), 5);\n float body = exp(-x * x * 1.6);\n float wisp = smoothstep(0.42, 0.75, strands + 0.25 * body);\n float a = wisp * body;\n // Born at the source, thinning and fading as it rises.\n a *= smoothstep(-0.05, 0.12, h) * (1.0 - smoothstep(0.35, 1.05, h));\n a *= mix(1.0, 0.55, hc);\n fragColor = vec4(uColor, clamp(a * uOpacity * 1.4, 0.0, 1.0));\n}`,\n ),\n presets: [\n { name: \"Coffee cup\", values: { uSource: [0, -0.5], uWidth: 0.08, uHeight: 0.6, uSpeed: 0.7, uTurbulence: 1, uOpacity: 0.55 } },\n { name: \"Vent\", values: { uSource: [0, -1], uWidth: 0.3, uHeight: 1.3, uSpeed: 1.4, uTurbulence: 0.6, uOpacity: 0.8 } },\n { name: \"Kettle burst\", values: { uSource: [-0.4, -0.3], uWidth: 0.05, uHeight: 1.1, uSpeed: 2.6, uTurbulence: 1.8, uOpacity: 0.95 } },\n ],\n};\n\nexport const mistOverImage: ShaderEffect = {\n kind: \"shader\",\n id: \"mist-over-image\",\n name: \"Mist over image\",\n description: \"Slow mist drifting over a picture, thickest low down and in the distance, with light softly scattering through it.\",\n category: \"atmosphere\",\n video: \"filter\",\n tags: [\"atmosphere\", \"mist\", \"image\", \"fog\", \"moody\", \"photo\"],\n source: glsl(\n `// Mist over image: drifting fbm haze over a picture, weighted to the ground and the horizon, with a soft bloom.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uMistColor; // @control color default=#E4EAF0 label=\"Mist colour\"\nuniform float uDensity; // @control min=0 max=1 default=0.6 label=\"Density\"\nuniform float uHorizon; // @control min=0 max=1 default=0.4 label=\"Horizon\"\nuniform float uGround; // @control min=0 max=1 default=0.6 label=\"Ground mist\"\nuniform float uScatter; // @control min=0 max=1.5 default=0.6 label=\"Light scatter\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Drift speed\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec4 pic = pictureRGBA(uImage, uv);\n float aspect = iResolution.x / iResolution.y;\n float t = iTime * uSpeed;\n\n // Depth proxy: hazier toward the horizon (far away) and right at the bottom (ground mist).\n float far = exp(-pow((uv.y - uHorizon) / 0.18, 2.0));\n float ground = (1.0 - smoothstep(0.0, 0.45, uv.y)) * uGround;\n vec2 q = vec2(uv.x * aspect, uv.y);\n float n1 = fbm(vec2(q.x * 2.0 - t * 0.04, q.y * 6.0) + 3.0, 5);\n float n2 = fbm(vec2(q.x * 3.5 + t * 0.025, q.y * 9.0 - t * 0.01) + 11.0, 4);\n float drift = smoothstep(0.25, 0.8, 0.6 * n1 + 0.4 * n2);\n float mist = clamp((far * 0.7 + ground) * mix(0.45, 1.25, drift) + 0.12, 0.0, 1.0) * uDensity;\n\n // Soft scattering: bright parts of the picture bleed into the mist around them.\n vec3 glow = vec3(0.0);\n for (int i = 0; i < 8; i++) {\n float a = float(i) * 0.785398 + 0.4;\n vec2 o = vec2(cos(a), sin(a) * aspect) * 0.035;\n vec3 s = picture(uImage, uv + o);\n vec3 s2 = picture(uImage, uv + o * 2.4);\n glow += max(s - 0.55, 0.0) + max(s2 - 0.55, 0.0) * 0.6;\n }\n glow /= 8.0;\n vec3 haze = uMistColor + glow * uScatter * 1.6;\n // Mist lifts the blacks and washes out the colour behind it.\n vec3 col = mix(pic.rgb, haze, mist);\n col += glow * uScatter * 0.5 * (1.0 - mist);\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Dawn\", values: { uMistColor: [1, 0.9, 0.8], uDensity: 0.7, uScatter: 1.1, uGround: 0.7 } },\n { name: \"Cold valley\", values: { uMistColor: [0.78, 0.84, 0.9], uDensity: 0.85, uHorizon: 0.5, uScatter: 0.3, uSpeed: 0.6 } },\n ],\n};\n\nexport const skyTimelapse: ShaderEffect = {\n kind: \"shader\",\n id: \"sky-timelapse\",\n name: \"Sky timelapse\",\n description: \"A timelapse sky: layers of clouds racing over at different speeds as the light turns from day to golden hour and back.\",\n category: \"atmosphere\",\n tags: [\"atmosphere\", \"clouds\", \"sky\", \"background\", \"timelapse\"],\n source: glsl(\n `// Sky timelapse: parallax cloud layers on perspective planes, under a sky cycling through the day.\nuniform vec3 uDayTop; // @control color default=#2F6FD0 label=\"Day sky (top)\"\nuniform vec3 uDayHorizon; // @control color default=#A9D3F5 label=\"Day sky (horizon)\"\nuniform vec3 uGoldTop; // @control color default=#3E3A7A label=\"Golden sky (top)\"\nuniform vec3 uGoldHorizon; // @control color default=#FFA45C label=\"Golden sky (horizon)\"\nuniform float uSpeed; // @control min=0 max=4 default=1.5 label=\"Cloud speed\"\nuniform float uCycle; // @control min=0 max=1 default=0.08 label=\"Day cycle speed\"\nuniform float uCoverage; // @control min=0 max=1 default=0.5 label=\"Coverage\"\nuniform int uLayers; // @control min=1 max=4 default=3 label=\"Layers\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float x = (fragCoord.x - 0.5 * iResolution.x) / iResolution.y;\n float y = uv.y;\n // 0 at midday, 1 at golden hour.\n float gold = 0.5 - 0.5 * cos(iTime * uCycle * 6.28318);\n vec3 top = mix(uDayTop, uGoldTop, gold);\n vec3 horizon = mix(uDayHorizon, uGoldHorizon, gold);\n vec3 sky = mix(horizon, top, pow(y, 0.7));\n vec2 sunPos = vec2(0.35, mix(0.85, 0.08, gold));\n float sd = length(vec2(x, y) - sunPos);\n vec3 sunCol = mix(vec3(1.0, 0.97, 0.9), vec3(1.0, 0.6, 0.3), gold);\n sky += sunCol * (smoothstep(0.045, 0.04, sd) + exp(-sd * 6.0) * 0.35);\n\n vec3 litDay = vec3(1.0);\n vec3 litGold = vec3(1.0, 0.72, 0.5);\n vec3 shadowDay = vec3(0.6, 0.66, 0.76);\n vec3 shadowGold = vec3(0.42, 0.3, 0.42);\n vec3 col = sky;\n // Layer 0 is the highest: farthest, smallest-looking and slowest across the screen.\n for (int i = 0; i < 4; i++) {\n if (i >= uLayers) break;\n float fi = float(i);\n float alt = mix(2.4, 0.7, fi / 3.0);\n float z = alt / (y + 0.12);\n vec2 plane = vec2(x * z, z);\n plane += vec2(iTime * uSpeed * 0.35, iTime * uSpeed * 0.12) + fi * 13.1;\n float scale = mix(0.9, 0.5, fi / 3.0);\n vec2 cq = plane * scale;\n int oct = z > 8.0 ? 3 : 5;\n float n = fbm(cq, oct);\n float cover = mix(0.75, 0.35, uCoverage);\n float a = smoothstep(cover, cover + 0.22, n);\n // Toward the sun: a lighter side; a sample offset sunward darkens bellies.\n float n2 = fbm(cq + vec2(0.08, 0.12), oct);\n float shade = clamp(0.5 + (n - n2) * 6.0, 0.0, 1.0);\n vec3 lit = mix(litDay, litGold, gold);\n vec3 shadow = mix(shadowDay, shadowGold, gold) * mix(1.0, 0.8, fi / 3.0);\n vec3 cc = mix(shadow, lit, shade);\n cc += sunCol * exp(-sd * 3.0) * 0.4 * (1.0 - a);\n // Clouds dissolve into the horizon haze.\n a *= smoothstep(0.0, 0.25, y);\n col = mix(col, mix(cc, horizon, exp(-y * 8.0) * 0.6), a);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Fair weather\", values: { uSpeed: 1.2, uCoverage: 0.35, uCycle: 0.05 } },\n { name: \"Racing clouds\", values: { uSpeed: 3.5, uCoverage: 0.65, uCycle: 0.15, uLayers: 4 } },\n ],\n};\n\nexport const smokeCurl: ShaderEffect = {\n kind: \"shader\",\n id: \"smoke-curl\",\n name: \"Smoke curl\",\n description: \"A thin thread of incense or cigarette smoke rising smooth and straight, then breaking into curls and turbulence.\",\n category: \"atmosphere\",\n tags: [\"atmosphere\", \"smoke\", \"incense\", \"overlay\", \"elegant\", \"moody\"],\n transparent: true,\n source: glsl(\n `// Smoke curl: a laminar filament whose path and strands are warped more the higher it rises.\nuniform vec2 uSource; // @control min=-1 max=1 default=0,-0.85 label=\"Source\"\nuniform vec3 uColor; // @control color default=#D9DEE6 label=\"Colour\"\nuniform float uHeight; // @control min=0.3 max=1.6 default=1.1 label=\"Height\"\nuniform float uBreakup; // @control min=0 max=1 default=0.35 label=\"Breakup height\"\nuniform float uTurbulence; // @control min=0 max=2 default=1 label=\"Turbulence\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uThickness; // @control min=0.3 max=3 default=1 label=\"Thickness\"\nuniform float uOpacity; // @control min=0 max=1 default=0.85 label=\"Opacity\"`,\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 px = 1.0 / 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 h = q.y / uHeight;\n if (h < -0.02 || h > 1.15) { fragColor = vec4(uColor, 0.0); return; }\n float hc = clamp(h, 0.0, 1.0);\n float t = iTime * uSpeed;\n // 0 while the stream is laminar, rising to 1 where it has broken up.\n float turb = smoothstep(uBreakup - 0.05, uBreakup + 0.45, hc) * uTurbulence;\n\n // Advected warp: noise carried up with the smoke, swirling the filament into curls.\n vec2 fq = vec2(q.x * 4.0, q.y * 3.0 - t * 0.6);\n vec2 warp = vec2(fbm(fq, 4), fbm(fq + vec2(4.7, 1.9), 4)) - 0.5;\n vec2 warp2 = vec2(fbm(fq * 2.3 + warp * 2.0, 3), fbm(fq * 2.3 + vec2(2.1, 8.4) - warp * 2.0, 3)) - 0.5;\n vec2 w = q + (warp * 0.18 + warp2 * 0.08) * turb * (0.4 + hc);\n\n // The base path: a gentle sway low down, more after the breakup.\n float sway = 0.012 * sin(q.y * 7.0 - t * 1.2) * hc + turb * 0.05 * sin(q.y * 4.0 - t * 0.9 + 1.7);\n float a = 0.0;\n for (int i = 0; i < 3; i++) {\n float fi = float(i);\n // The strands start as one and peel apart above the breakup.\n float split = (fi - 1.0) * turb * 0.035 * hc * (1.0 + sin(w.y * 6.0 + fi * 2.3 - t * 0.7));\n float d = abs(w.x - sway - split);\n float width = (mix(0.0015, 0.016, hc) + turb * 0.008 * hc) * uThickness + px * 0.75;\n float strand = exp(-d * d / (width * width));\n a += strand * (fi == 1.0 ? 1.0 : turb * 0.6);\n }\n // A faint diffuse veil around the curls, and dissolving gaps higher up.\n float veil = smoothstep(0.45, 0.8, fbm(w * 6.0 + vec2(0.0, -t * 0.4), 4)) * turb * 0.25 * hc;\n a = a * mix(1.0, 0.5, hc) + veil;\n float gaps = mix(1.0, smoothstep(0.25, 0.6, fbm(w * 3.0 + vec2(1.3, -t * 0.5), 3)), hc * min(turb, 1.0));\n a *= gaps;\n a *= smoothstep(-0.02, 0.01, h) * (1.0 - smoothstep(0.6, 1.1, h));\n fragColor = vec4(uColor, clamp(a * uOpacity, 0.0, 1.0));\n}`,\n ),\n presets: [\n { name: \"Incense\", values: { uColor: [0.86, 0.88, 0.92], uBreakup: 0.45, uTurbulence: 0.8, uSpeed: 0.7, uThickness: 0.8 } },\n { name: \"Draughty room\", values: { uBreakup: 0.15, uTurbulence: 1.8, uSpeed: 1.4, uThickness: 1.3 } },\n ],\n};\n\nexport const dryIceFog: ShaderEffect = {\n kind: \"shader\",\n id: \"dry-ice-fog\",\n name: \"Dry ice fog\",\n description: \"Dense, low stage fog rolling along the floor and spilling over the edge in a slow, tumbling curtain.\",\n category: \"atmosphere\",\n tags: [\"atmosphere\", \"fog\", \"overlay\", \"stage\", \"spooky\", \"concert\"],\n transparent: true,\n source: glsl(\n `// Dry ice fog: rolling fbm fog hugging a floor, pouring over its edge and pooling below.\nuniform vec3 uColor; // @control color default=#EEF2F7 label=\"Colour\"\nuniform float uFloor; // @control min=0 max=0.8 default=0.38 label=\"Floor height\"\nuniform float uEdge; // @control min=0 max=1.2 default=0.68 label=\"Edge position\"\nuniform float uDepth; // @control min=0.03 max=0.5 default=0.14 label=\"Fog depth\"\nuniform float uDensity; // @control min=0 max=1.5 default=1 label=\"Density\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Flow speed\"\nuniform float uTurbulence; // @control min=0 max=2 default=1 label=\"Turbulence\"`,\n HASH,\n NOISE,\n FBM,\n `float rolling(vec2 q, float t) {\n vec2 warp = vec2(fbm(q * 0.8 + vec2(-t * 0.3, t * 0.1), 4), fbm(q * 0.8 + vec2(3.1, -t * 0.2), 4)) - 0.5;\n return fbm(q + warp * 2.2 * uTurbulence, 5);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float aspect = iResolution.x / iResolution.y;\n float x = uv.x;\n float y = uv.y;\n float t = iTime * uSpeed;\n float a = 0.0;\n\n // On the stage: a dense layer above the floor, billowing higher in places, soft at the top.\n float stage = 1.0 - smoothstep(uEdge - 0.04, uEdge + 0.01, x);\n float n = 0.5;\n if (stage > 0.0) {\n float hy = (y - uFloor) / uDepth;\n n = rolling(vec2(x * aspect * 3.0 - t * 0.35, max(hy, 0.0) * 0.9 + t * 0.05), t);\n float d = n * 1.5 + 0.15 - max(hy, 0.0) * 0.8 - max(-hy, 0.0) * 2.5;\n a = max(a, smoothstep(0.0, 0.7, d) * stage);\n }\n // Over the edge: a curtain falling in an arc, widening as it drops, pooling on the ground.\n if (x > uEdge - 0.04) {\n float dx = max(x - uEdge, 0.0) * aspect;\n float fall = uFloor - dx * dx * 6.0 - dx * 0.4;\n float spread = uDepth * (0.5 + 2.0 * max(uFloor - fall, 0.0));\n float off = (y - fall) / spread;\n float nc = rolling(vec2(dx * 4.0 + off * 0.3, y * 3.0 + t * 0.6), t);\n float curtain = smoothstep(0.0, 0.7, nc * 1.5 + 0.1 - abs(off) * 0.9) * smoothstep(uEdge - 0.04, uEdge, x);\n curtain *= 1.0 - smoothstep(uDepth * 0.5, uDepth * 1.5, y - uFloor);\n float np = rolling(vec2(x * aspect * 3.0 - t * 0.2, y / uDepth * 0.8), t);\n float pool = smoothstep(0.0, 0.7, np * 1.5 + 0.1 - y / (uDepth * 0.8) * 0.8) * smoothstep(uEdge, uEdge + 0.1, x);\n float spill = max(curtain, pool * 0.85);\n if (spill > a) n = mix(n, x > uEdge + 0.05 ? max(nc, np) : nc, 0.5);\n a = max(a, spill);\n }\n a = clamp(a * uDensity, 0.0, 1.0);\n // Denser billows catch more light; thin edges fall slightly into shadow.\n vec3 c = uColor * mix(0.8, 1.05, smoothstep(0.3, 0.75, n));\n fragColor = vec4(c, a);\n}`,\n ),\n presets: [\n { name: \"Concert stage\", values: { uFloor: 0.25, uEdge: 1.2, uDepth: 0.2, uDensity: 1.2, uSpeed: 0.8 } },\n { name: \"Haunted ledge\", values: { uColor: [0.72, 0.9, 0.82], uFloor: 0.5, uEdge: 0.55, uDepth: 0.1, uTurbulence: 1.6 } },\n ],\n};\n\n/** Atmosphere: clouds, fog, steam, mist and drifting wisps. */\nexport const atmosphereShaders: ShaderEffect[] = [\n volumetricClouds,\n fogBanks,\n risingSteam,\n mistOverImage,\n skyTimelapse,\n smokeCurl,\n dryIceFog,\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/** `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/**\n * Reading a silhouette from `uMask` (a `filter=mipmap` image control) placed\n * contained in `uSize` of the frame, centred, in frame units (height 1).\n * `shapeAt(p, blur)` is its coverage read at the mip level for a blur of\n * about `blur` frame units; `coverage(p, radius)` a smooth disc blur of it\n * (16 golden-angle taps at a matching mip level), so glows built from it are\n * smooth at any size. With `gKey` above 0, colours near the picture's corner\n * colour count as clear too, so a photo on a plain ground (the portrait)\n * works as a silhouette; call `setKey()` first. With no image, a disc.\n * Needs `uMask`, `uSize` and a `float gKeyTolerance` set before use.\n */\nconst MASK = `\nvec3 gKeyColour;\nfloat gKeyTolerance;\n\n// The colour in the picture's top-left corner: the ground to key out.\nvoid setKey(float tolerance) {\n gKeyTolerance = tolerance;\n vec4 c = textureLod(uMask, vec2(0.01, 0.99), 0.0);\n gKeyColour = c.rgb / max(c.a, 1e-3);\n}\n\n// Where frame point p falls in the picture (xy) and texels per frame unit (z).\nvec3 maskPlace(vec2 p) {\n vec2 size = vec2(textureSize(uMask, 0));\n float aspect = size.x / size.y;\n float h = min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n return vec3(p / vec2(h * aspect, h) + 0.5, size.y / h);\n}\n\nfloat shapeAt(vec2 p, float blur) {\n if (textureSize(uMask, 0).x <= 1) {\n float d = length(p) - 0.3 * uSize;\n return clamp(0.5 - d / max(blur, 0.004), 0.0, 1.0);\n }\n vec3 m = maskPlace(p);\n if (m.x < 0.0 || m.x > 1.0 || m.y < 0.0 || m.y > 1.0) return 0.0;\n vec4 c = textureLod(uMask, m.xy, log2(max(blur * m.z, 1.0)));\n float a = c.a;\n if (gKeyTolerance > 0.0) {\n float away = distance(c.rgb / max(c.a, 1e-3), gKeyColour);\n a *= smoothstep(gKeyTolerance, gKeyTolerance + 0.12, away);\n }\n return a;\n}\n\nfloat coverage(vec2 p, float radius) {\n float sum = 0.0;\n for (int i = 0; i < 16; i++) {\n float r = radius * sqrt((float(i) + 0.5) / 16.0);\n float a = float(i) * 2.39996;\n sum += shapeAt(p + r * vec2(cos(a), sin(a)), radius * 0.4);\n }\n return sum / 16.0;\n}`.trim();\n\n/** Golden-angle disc offsets of unit radius for an `n`-tap blur, as the GLSL constant `GOLDEN<n>`. */\nfunction goldenTaps(n: number): string {\n const taps = Array.from({ length: n }, (_, i) => {\n const r = Math.sqrt((i + 0.5) / n);\n const a = i * 2.39996;\n return `vec2(${(r * Math.cos(a)).toFixed(5)}, ${(r * Math.sin(a)).toFixed(5)})`;\n });\n return `const vec2 GOLDEN${n}[${n}] = vec2[${n}](${taps.join(\", \")});`;\n}\n\n/** A disc blur of the mask in `n` golden-angle taps, each read at the mip level for a blur of `blur` × the radius. */\nfunction coverageTaps(name: string, n: number, blur: number): string {\n return `\n${goldenTaps(n)}\nfloat ${name}(vec2 p, float radius) {\n float sum = 0.0;\n if (gMaskPlace.w < 0.5) {\n for (int i = 0; i < ${n}; i++) sum += shapeAt(p + radius * GOLDEN${n}[i], radius * ${blur.toFixed(2)});\n } else {\n float lod = log2(max(radius * ${blur.toFixed(2)} * gMaskPlace.z, 1.0));\n for (int i = 0; i < ${n}; i++) sum += shapeLod(p + radius * GOLDEN${n}[i], lod);\n }\n return sum / ${n}.0;\n}`.trim();\n}\n\n/** Taps in `coverageLite`. */\nconst LITE_TAPS = 10;\n\n/**\n * {@link MASK} made cheaper to read many times a pixel, for the glows that\n * do: `setKey()` also works out once where the picture sits, the golden-angle\n * taps are constants and each blur picks its mip level once. `shapeAt` and\n * `coverage` give what MASK's do; `coverageLite(p, radius)` is the same blur\n * in {@link LITE_TAPS} taps a little higher up the mip chain, for wide blurs\n * where the difference does not show.\n */\nconst MASK_FAST = `\nvec3 gKeyColour;\nfloat gKeyTolerance;\n// Picture units per frame unit (xy), texels per frame unit (z), 1 with a picture (w).\nvec4 gMaskPlace;\n\n// The colour in the picture's top-left corner: the ground to key out; and where the picture sits.\nvoid setKey(float tolerance) {\n gKeyTolerance = tolerance;\n vec4 c = textureLod(uMask, vec2(0.01, 0.99), 0.0);\n gKeyColour = c.rgb / max(c.a, 1e-3);\n vec2 size = vec2(textureSize(uMask, 0));\n float aspect = size.x / size.y;\n float h = min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n gMaskPlace = vec4(1.0 / (h * aspect), 1.0 / h, size.y / h, size.x > 1.0 ? 1.0 : 0.0);\n}\n\n// Where frame point p falls in the picture (xy) and texels per frame unit (z).\nvec3 maskPlace(vec2 p) {\n return vec3(p * gMaskPlace.xy + 0.5, gMaskPlace.z);\n}\n\n// The picture's coverage at p read at mip level lod (needs a picture).\nfloat shapeLod(vec2 p, float lod) {\n vec2 uv = p * gMaskPlace.xy + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n vec4 c = textureLod(uMask, uv, lod);\n float a = c.a;\n if (gKeyTolerance > 0.0) {\n float away = distance(c.rgb / max(c.a, 1e-3), gKeyColour);\n a *= smoothstep(gKeyTolerance, gKeyTolerance + 0.12, away);\n }\n return a;\n}\n\nfloat shapeAt(vec2 p, float blur) {\n if (gMaskPlace.w < 0.5) {\n float d = length(p) - 0.3 * uSize;\n return clamp(0.5 - d / max(blur, 0.004), 0.0, 1.0);\n }\n return shapeLod(p, log2(max(blur * gMaskPlace.z, 1.0)));\n}\n\n${coverageTaps(\"coverage\", 16, 0.4)}\n\n${coverageTaps(\"coverageLite\", LITE_TAPS, 0.5)}`.trim();\n\nexport const aura: ShaderEffect = {\n kind: \"shader\",\n id: \"aura\",\n name: \"Aura\",\n description: \"A silhouette wreathed in an energetic aura, flame-like wisps of light rising off its outline and pulsing.\",\n category: \"glow\",\n video: \"stills\",\n tags: [\"glow\", \"aura\", \"energy\", \"flame\", \"silhouette\", \"anime\", \"power-up\"],\n source: glsl(\n `// Aura: a blurred silhouette, lifted and torn by rising fbm, read as tongues of light round the outline.\nuniform sampler2D uMask; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Silhouette\"\nuniform float uKey; // @control min=0 max=0.5 default=0.12 label=\"Key out the corner colour (0 off)\"\nuniform float uSize; // @control min=0.2 max=1 default=1 label=\"Size\"\nuniform vec3 uColor; // @control color default=#FFC93C label=\"Aura\"\nuniform vec3 uCore; // @control color default=#FFF6D5 label=\"Core\"\nuniform vec3 uBackground; // @control color default=#0B0A12 label=\"Background\"\nuniform float uHeight; // @control min=0 max=0.4 default=0.16 label=\"Flame height\"\nuniform float uSpread; // @control min=0.01 max=0.15 default=0.06 label=\"Spread\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uPulse; // @control min=0 max=1 default=0.4 label=\"Pulse\"\nuniform float uIntensity; // @control min=0 max=3 default=1.1 label=\"Intensity\"`,\n HASH,\n NOISE,\n FBM,\n MASK_FAST,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n setKey(uKey);\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float px = 1.0 / iResolution.y;\n // Rising noise: tongues flow up and sway.\n vec2 q = p * 6.0;\n float n = fbm(vec2(q.x, q.y - t * 2.0), 5);\n float n2 = fbm(vec2(q.x * 1.7 + 4.1, q.y * 0.9 - t * 2.9), 4);\n float pulse = 1.0 + uPulse * (0.3 * sin(t * 3.0) + 0.12 * sin(t * 7.3 + 1.0));\n // The silhouette blurred at three widths, swayed and stretched upward by the noise, so light gathers above it.\n // The two wide blurs, torn by the noise anyway, take fewer taps.\n vec2 warp = vec2((n2 - 0.5) * uSpread * 1.5, -(n - 0.3) * uHeight);\n float inner = coverage(p + warp * 0.3, uSpread * 0.5);\n float outer = coverageLite(p + warp, uSpread * 1.4);\n float tall = coverageLite(p + warp * 1.5 - vec2(0.0, uHeight), uSpread * 2.2);\n float field = (inner * 0.9 + outer * 0.8 + tall * 0.6) * pulse;\n // Torn into tongues: the noise breaks the thin outer field into licks, the thick inner field holds.\n float tongues = smoothstep(0.12, 0.95, field * (0.45 + 1.1 * n));\n float wisps = smoothstep(0.55, 0.75, n2) * smoothstep(0.02, 0.3, tall) * 0.5;\n float body = shapeAt(p, 1.5 * px);\n vec3 light = uColor * (tongues * 1.3 + wisps + field * 0.25) + uCore * smoothstep(0.5, 0.9, inner * pulse) * 0.8;\n light *= uIntensity;\n vec3 col = uBackground + (1.0 - exp(-light));\n // The figure in front, its own colours, rim-lit by the aura.\n if (gMaskPlace.w > 0.5 && body > 0.0) {\n vec3 m = maskPlace(p);\n vec4 c = texture(uMask, m.xy);\n vec3 own = c.rgb / max(c.a, 1e-3);\n float rim = 1.0 - coverage(p, uSpread * 0.25);\n vec3 lit = own * mix(vec3(0.75), uColor, 0.25) + uColor * rim * 1.6 * uIntensity * pulse * 0.5;\n col = mix(col, lit, body);\n } else {\n col = mix(col, uBackground * 0.6 + uColor * 0.15, body);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Super saiyan\", values: { uColor: [1, 0.79, 0.24], uCore: [1, 0.97, 0.84], uHeight: 0.22, uSpeed: 1.6, uPulse: 0.6, uIntensity: 1.8 } },\n { name: \"Spirit\", values: { uColor: [0.25, 0.85, 1], uCore: [0.85, 1, 1], uBackground: [0.02, 0.05, 0.09], uHeight: 0.1, uSpeed: 0.6, uPulse: 0.3 } },\n { name: \"Dark\", values: { uColor: [0.55, 0.2, 0.95], uCore: [0.95, 0.75, 1], uBackground: [0.02, 0.01, 0.04], uHeight: 0.18, uSpread: 0.07, uIntensity: 1.6 } },\n ],\n};\n\nexport const bloom: ShaderEffect = {\n kind: \"shader\",\n id: \"bloom\",\n name: \"Bloom\",\n description: \"A picture whose bright areas bleed soft light into their surroundings, with an optional anamorphic lens streak.\",\n category: \"glow\",\n video: \"filter\",\n tags: [\"glow\", \"bloom\", \"image\", \"lens\", \"light\", \"filter\", \"anamorphic\"],\n source: glsl(\n `// Bloom: the brightest parts of the image, blurred at two scales (and streaked sideways), added back as light.\nuniform sampler2D uImage; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uThreshold; // @control min=0 max=1 default=0.6 label=\"Threshold\"\nuniform float uKnee; // @control min=0.01 max=0.5 default=0.2 label=\"Softness\"\nuniform float uRadius; // @control min=0.01 max=0.2 default=0.08 label=\"Radius\"\nuniform float uIntensity; // @control min=0 max=4 default=2.5 label=\"Intensity\"\nuniform vec3 uTint; // @control color default=#FFFFFF label=\"Tint\"\nuniform float uStreak; // @control min=0 max=2 default=0 label=\"Anamorphic streak\"\nuniform vec3 uStreakColor; // @control color default=#7FB2FF label=\"Streak colour\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `// The light above the threshold at uv, read at a mip level (a soft knee, so light fades in smoothly). A coarse\n// level has averaged small lights with their dark surroundings, so its threshold is lowered a little to match.\nvec3 bright(vec2 uv, float lod) {\n vec3 c = textureSize(uImage, 0).x > 1 ? textureLod(uImage, uv, lod).rgb : testCard(fract(uv));\n float l = dot(c, vec3(0.2126, 0.7152, 0.0722));\n float thr = uThreshold * exp2(-max(lod, 0.0) * 0.1);\n float knee = uKnee * exp2(-max(lod, 0.0) * 0.1);\n float k = clamp((l - thr + knee) / (2.0 * knee), 0.0, 1.0);\n float soft = l > thr ? l - thr : k * k * knee * 0.5;\n return c * max(soft, 0.0) / max(l, 1e-4);\n}\n\n// A disc blur of the bright pass, radius r (uv height units): 20 golden-angle taps at a mip level about as\n// coarse as their spacing, so they run together.\nvec3 blurBright(vec2 uv, float r, float texels) {\n float lod = log2(max(r * 0.4 * texels, 1.0));\n vec3 sum = vec3(0.0);\n vec2 aspect = vec2(iResolution.y / iResolution.x, 1.0);\n for (int i = 0; i < 20; i++) {\n float rr = r * sqrt((float(i) + 0.5) / 20.0);\n float a = float(i) * 2.39996;\n sum += bright(uv + rr * vec2(cos(a), sin(a)) * aspect, lod);\n }\n return sum / 20.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float texels = textureSize(uImage, 0).y > 1 ? float(textureSize(uImage, 0).y) : iResolution.y;\n vec3 light = blurBright(uv, uRadius * 0.3, texels) * 0.3 + blurBright(uv, uRadius, texels) * 0.4 + blurBright(uv, uRadius * 3.0, texels) * 0.5;\n light *= uTint;\n if (uStreak > 0.0) {\n // A long horizontal smear of the bright pass, read a little blurred so its taps run together.\n vec3 streak = vec3(0.0);\n float w = 0.0;\n float jitter = fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453) - 0.5;\n float texelsX = textureSize(uImage, 0).x > 1 ? float(textureSize(uImage, 0).x) : iResolution.x;\n float lodStreak = log2(max(0.0125 * texelsX, 1.0));\n for (int i = -24; i <= 24; i++) {\n float f = (float(i) + jitter) / 24.0;\n float k = exp(-abs(f) * 3.5);\n streak += bright(uv + vec2(f * 0.3, 0.0), lodStreak) * k;\n w += k;\n }\n light += dot(streak / w, vec3(0.33)) * uStreakColor * uStreak * 4.0;\n }\n light *= uIntensity;\n vec4 pic = pictureRGBA(uImage, uv);\n // The bloom is light added over the picture, so it also shows where the picture is clear.\n float glowA = clamp(max(light.r, max(light.g, light.b)), 0.0, 1.0);\n float alpha = max(pic.a, glowA);\n vec3 col = (pic.rgb * pic.a + light) / max(alpha, 1e-4);\n fragColor = vec4(col, alpha);\n}`,\n ),\n presets: [\n { name: \"Dreamy\", values: { uThreshold: 0.45, uRadius: 0.12, uIntensity: 1.8, uTint: [1, 0.9, 0.95] } },\n { name: \"Anamorphic night\", values: { uImage: SAMPLE_IMAGES.city, uStreak: 1.2, uThreshold: 0.6, uIntensity: 3 } },\n { name: \"Subtle\", values: { uThreshold: 0.75, uRadius: 0.04, uIntensity: 1.2 } },\n ],\n};\n\nexport const pulsingHalo: ShaderEffect = {\n kind: \"shader\",\n id: \"pulsing-halo\",\n name: \"Pulsing halo\",\n description: \"Soft halo rings behind a centre spot, breathing slowly in and out with a gentle shimmer running round them.\",\n category: \"glow\",\n tags: [\"glow\", \"halo\", \"ring\", \"breathe\", \"overlay\", \"pulse\", \"ui\"],\n transparent: true,\n loop: 4,\n source: glsl(\n `// Pulsing halo: soft rings round the centre that grow and brighten with each breath, shimmering round.\nuniform vec3 uColor; // @control color default=#7DD3FC label=\"Outer colour\"\nuniform vec3 uInner; // @control color default=#E0F2FE label=\"Inner colour\"\nuniform float uRadius; // @control min=0.05 max=0.45 default=0.2 label=\"Radius\"\nuniform float uWidth; // @control min=0.004 max=0.12 default=0.025 label=\"Ring width\"\nuniform int uRings; // @control min=1 max=4 default=2 label=\"Rings\"\nuniform float uSpacing; // @control min=0.02 max=0.2 default=0.07 label=\"Ring spacing\"\nuniform float uBreath; // @control min=0 max=0.5 default=0.12 label=\"Breath\"\nuniform float uPeriod; // @control min=1 max=10 default=4 label=\"Seconds per breath\"\nuniform float uShimmer; // @control min=0 max=1 default=0.5 label=\"Shimmer\"\nuniform float uIntensity; // @control min=0 max=3 default=1.2 label=\"Intensity\"`,\n HASH,\n NOISE,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float d = length(p);\n vec2 dir = p / max(d, 1e-4);\n float phase = 6.28318 * iTime / uPeriod;\n float b = 0.5 - 0.5 * cos(phase);\n float scale = 1.0 + uBreath * (b - 0.3);\n // The shimmer: noise round the ring, drifting on a circle so it repeats every breath.\n vec2 drift = vec2(cos(phase), sin(phase));\n vec3 light = vec3(0.0);\n for (int i = 0; i < 4; i++) {\n if (i >= uRings) break;\n float fi = float(i);\n float r = (uRadius + fi * uSpacing * (1.0 + 0.5 * b)) * scale;\n float w = uWidth * (1.0 + 0.5 * fi);\n float ring = exp(-pow((d - r) / w, 2.0)) + 0.4 * exp(-abs(d - r) / (w * 3.0));\n float s = vnoise(dir * 3.0 + drift * 0.8 + fi * 7.3) * 0.6 + vnoise(dir * 7.0 - drift * 1.3 + fi * 3.1) * 0.4;\n float sh = mix(1.0, 0.35 + 1.3 * s, uShimmer);\n float fade = 1.0 / (1.0 + 0.9 * fi);\n vec3 tint = mix(uInner, uColor, uRings > 1 ? fi / float(uRings - 1) : 0.6);\n light += tint * ring * sh * fade;\n }\n // A faint glow filling the centre, behind whatever sits there.\n light += uInner * 0.18 * exp(-pow(d / (uRadius * scale), 2.0) * 1.5);\n light *= uIntensity * (0.7 + 0.45 * b);\n fragColor = glow(light);\n}`,\n ),\n presets: [\n { name: \"Calm\", values: { uRings: 1, uWidth: 0.04, uPeriod: 6, uShimmer: 0.2 } },\n { name: \"Golden\", values: { uColor: [1, 0.66, 0.2], uInner: [1, 0.93, 0.7], uRings: 3, uShimmer: 0.8 } },\n { name: \"Notify\", values: { uColor: [0.98, 0.3, 0.45], uInner: [1, 0.8, 0.85], uRadius: 0.12, uBreath: 0.35, uPeriod: 1.5, uRings: 3 } },\n ],\n};\n\nexport const neonOutline: ShaderEffect = {\n kind: \"shader\",\n id: \"neon-outline\",\n name: \"Neon outline\",\n description: \"Any shape or word traced in a crisp neon line with a wide soft glow, its colour flowing along the outline and flickering now and then.\",\n category: \"glow\",\n video: \"none\",\n tags: [\"glow\", \"neon\", \"outline\", \"text\", \"logo\", \"overlay\", \"sign\"],\n transparent: true,\n source: glsl(\n `// Neon outline: the mask's edge as a bright tube, a soft halo either side, coloured along the outline.\nuniform sampler2D uMask; // @control filter=mipmap wrap=clamp default=${textImage(\"GLOW\")} label=\"Shape\"\nuniform float uSize; // @control min=0.2 max=1 default=0.85 label=\"Size\"\nuniform vec3 uColorA; // @control color default=#FF3DD8 label=\"Colour\"\nuniform vec3 uColorB; // @control color default=#38E1FF label=\"Gradient to\"\nuniform float uGradient; // @control min=0 max=1 default=1 label=\"Gradient along outline\"\nuniform float uFlow; // @control min=0 max=2 default=0.3 label=\"Gradient flow\"\nuniform float uLine; // @control min=0.5 max=8 default=2 label=\"Line width (px)\"\nuniform float uGlow; // @control min=0.01 max=0.2 default=0.05 label=\"Glow size\"\nuniform float uIntensity; // @control min=0 max=3 default=1.3 label=\"Intensity\"\nuniform float uFlicker; // @control min=0 max=1 default=0.3 label=\"Flicker\"\nuniform float uFill; // @control min=0 max=1 default=0 label=\"Fill\"`,\n HASH,\n MASK,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n setKey(0.0);\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n // The edge, softened a few pixels so its slope gives a smooth distance in pixels.\n float v = coverage(p, 3.0 * px) - 0.5;\n vec2 g = vec2(dFdx(v), dFdy(v));\n float d = abs(v) / max(length(g), 0.02);\n float tube = exp(-pow(d / uLine, 2.0));\n float core = exp(-pow(d / (uLine * 0.4), 2.0));\n // The halo: blurred coverage is half way across the edge, falling off either side.\n float c1 = coverage(p, uGlow * 0.4);\n float c2 = coverage(p, uGlow);\n float halo = (1.0 - abs(2.0 * c1 - 1.0)) * 0.55 + (1.0 - abs(2.0 * c2 - 1.0)) * 0.35;\n float inside = shapeAt(p, px);\n // Colour along the outline, flowing.\n float k = mix(0.0, 0.5 + 0.5 * sin(p.x * 5.0 + p.y * 2.5 - iTime * uFlow * 3.0), uGradient);\n vec3 tint = mix(uColorA, uColorB, k);\n // Flicker: now and then a burst of quick dips, as a tired tube does.\n float burst = step(0.72, hash12(vec2(floor(iTime * 1.7), 3.0)));\n float dip = step(0.45, hash12(vec2(floor(iTime * 24.0), 7.0)));\n float flick = 1.0 - uFlicker * burst * (1.0 - dip) * 0.85;\n vec3 light = tint * (tube * 1.6 + halo) + mix(tint, vec3(1.0), 0.7) * core * 0.9;\n light += tint * inside * uFill * 0.6;\n fragColor = glow(light * uIntensity * flick);\n}`,\n ),\n presets: [\n { name: \"Bar sign\", values: { uColorA: [1, 0.24, 0.4], uGradient: 0, uFlicker: 0.8, uLine: 3 } },\n { name: \"Heart\", values: { uMask: SAMPLE_IMAGES.heart, uSize: 0.7, uColorA: [1, 0.3, 0.55], uColorB: [1, 0.65, 0.3], uFlicker: 0 } },\n { name: \"Filled\", values: { uFill: 0.35, uGlow: 0.09, uColorA: [0.5, 1, 0.4], uColorB: [0.2, 0.8, 1] } },\n ],\n};\n\nexport const backlightGlow: ShaderEffect = {\n kind: \"shader\",\n id: \"backlight-glow\",\n name: \"Backlight glow\",\n description: \"A dark silhouette with a light behind it: radiant rays stream past its edges and glow spills round its rim.\",\n category: \"glow\",\n video: \"none\",\n tags: [\"glow\", \"backlight\", \"silhouette\", \"rays\", \"eclipse\", \"rim\", \"logo\"],\n source: glsl(\n `// Backlight glow: a light behind a mask, marched toward for shafts the shape blocks, with spill and a rim.\nuniform sampler2D uMask; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.logo} label=\"Silhouette\"\nuniform float uKey; // @control min=0 max=0.5 default=0 label=\"Key out the corner colour (0 off)\"\nuniform float uSize; // @control min=0.2 max=1 default=0.6 label=\"Size\"\nuniform vec3 uLight; // @control color default=#FFC46B label=\"Light\"\nuniform vec3 uBackground; // @control color default=#07060D label=\"Background\"\nuniform vec3 uObject; // @control color default=#040308 label=\"Object\"\nuniform float uLightX; // @control min=-0.5 max=0.5 default=0 label=\"Light across\"\nuniform float uLightY; // @control min=-0.5 max=0.5 default=0.04 label=\"Light up\"\nuniform float uGlowSize; // @control min=0.05 max=0.8 default=0.3 label=\"Light size\"\nuniform float uRays; // @control min=0 max=1 default=0.8 label=\"Rays\"\nuniform float uRim; // @control min=0 max=1 default=0.6 label=\"Rim light\"\nuniform float uSpeed; // @control min=0 max=2 default=0.4 label=\"Ray drift\"\nuniform float uIntensity; // @control min=0 max=3 default=1.3 label=\"Intensity\"`,\n HASH,\n NOISE,\n MASK_FAST,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n setKey(uKey);\n float px = 1.0 / iResolution.y;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) * px;\n vec2 L = vec2(uLightX, uLightY);\n vec2 toL = L - p;\n float dl = length(toL);\n // Light reaching here: march toward the light, the shape shadowing what is behind it.\n // 24 jittered steps (decay and sum scaled to match 0.965 per 1/40 of the way); steps three light\n // sizes or more from it add almost nothing, so they skip reading the shape.\n float shafts = 0.0;\n float decay = 1.0;\n float jitter = hash12(fragCoord);\n float far = 3.0 * uGlowSize;\n for (int i = 0; i < 24; i++) {\n float s = (float(i) + jitter) / 24.0;\n float r = dl * (1.0 - s);\n float open = r < far ? 1.0 - shapeAt(p + toL * s, 2.0 * px + 0.01 * s) : 1.0;\n float g = r / uGlowSize;\n shafts += open * exp(-g * g) * decay;\n decay *= 0.94236;\n }\n shafts /= 12.0;\n // Streaks round the light, drifting slowly.\n vec2 dir = -toL / max(dl, 1e-4);\n float a = iTime * uSpeed * 0.2;\n float streak = vnoise(dir * 6.0 + vec2(a, -a)) * 0.6 + vnoise(dir * 15.0 - vec2(a * 2.0, a)) * 0.4;\n float rays = shafts * mix(1.0, 0.25 + 1.5 * streak * streak, uRays);\n // Spill: light wrapping just round the edges.\n float body = shapeAt(p, 1.2 * px);\n float spill = coverage(p, 0.03) * 0.8 + coverageLite(p, 0.08) * 0.5;\n float glowAt = exp(-pow(dl / (uGlowSize * 1.6), 2.0));\n vec3 light = uLight * (rays * 1.4 + spill * (1.0 - body) * glowAt * 1.2) * uIntensity;\n vec3 col = uBackground + (1.0 - exp(-light));\n // The object, dark, its edges facing the light lit.\n float edge = 1.0 - coverage(p, 0.012);\n vec2 grad = vec2(dFdx(edge), dFdy(edge));\n float facing = 0.5 + 0.5 * dot(normalize(grad + 1e-6), normalize(toL + 1e-6));\n vec3 obj = uObject + uLight * edge * uRim * (0.4 + 0.6 * facing) * glowAt * 1.5 * uIntensity;\n col = mix(col, obj, body);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Eclipse\", values: { uLight: [1, 0.95, 0.85], uGlowSize: 0.22, uRays: 0.9, uRim: 0.8 } },\n { name: \"Hero portrait\", values: { uMask: SAMPLE_IMAGES.portrait, uKey: 0.12, uSize: 1, uLightY: 0.12, uLight: [0.6, 0.8, 1] } },\n { name: \"Sunset\", values: { uLight: [1, 0.45, 0.2], uBackground: [0.12, 0.04, 0.1], uLightY: -0.08, uGlowSize: 0.5 } },\n ],\n};\n\nexport const rimLight: ShaderEffect = {\n kind: \"shader\",\n id: \"rim-light\",\n name: \"Rim light\",\n description: \"A picture given a coloured studio kicker light along the edges that face a chosen direction.\",\n category: \"glow\",\n video: \"filter\",\n tags: [\"glow\", \"rim\", \"light\", \"image\", \"portrait\", \"studio\", \"filter\"],\n source: glsl(\n `// Rim light: luminance edges, kept where they face the light, glowing in its colour over the dimmed picture.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform vec3 uColor; // @control color default=#4FD1FF label=\"Light colour\"\nuniform float uAngle; // @control min=0 max=360 default=35 label=\"Light from (°)\"\nuniform float uWidth; // @control min=0.5 max=8 default=3 label=\"Rim width (px)\"\nuniform float uFocus; // @control min=0 max=1 default=1 label=\"Focus on the light side\"\nuniform float uThreshold; // @control min=0 max=0.5 default=0.06 label=\"Threshold\"\nuniform float uIntensity; // @control min=0 max=4 default=2.4 label=\"Intensity\"\nuniform float uDim; // @control min=0 max=1 default=0.3 label=\"Darken picture\"\nuniform bool uBrightSubject; // @control default=false label=\"Subject brighter than background\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `float luma(vec2 uv) {\n vec4 c = pictureRGBA(uImage, uv);\n return dot(c.rgb, vec3(0.2126, 0.7152, 0.0722)) * c.a;\n}\n\n// The luminance gradient (Sobel), sampling d apart in uv: it points from dark to bright.\nvec2 gradient(vec2 uv, vec2 d) {\n float tl = luma(uv + vec2(-d.x, d.y));\n float t = luma(uv + vec2(0.0, d.y));\n float tr = luma(uv + d);\n float l = luma(uv - vec2(d.x, 0.0));\n float r = luma(uv + vec2(d.x, 0.0));\n float bl = luma(uv - d);\n float b = luma(uv - vec2(0.0, d.y));\n float br = luma(uv + vec2(d.x, -d.y));\n return vec2(tr + 2.0 * r + br - tl - 2.0 * l - bl, tl + 2.0 * t + tr - bl - 2.0 * b - br) * 0.25;\n}\n\n// How much rim light an edge sampled d apart gets: its strength, toward the light.\nfloat rimAt(vec2 uv, vec2 d, vec2 toLight) {\n vec2 g = gradient(uv, d);\n float s = length(g);\n // A dark subject on a light ground: its outward normal points to the brighter side.\n vec2 n = (uBrightSubject ? -g : g) / max(s, 1e-5);\n float facing = mix(1.0, smoothstep(0.25, 0.95, dot(n, toLight)), uFocus);\n return smoothstep(uThreshold, uThreshold + 0.12, s) * facing;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float a = radians(uAngle);\n vec2 toLight = vec2(cos(a), sin(a));\n vec2 d = uWidth / iResolution.xy;\n // The light falls on the subject's side of the edge: read it a little toward the light, and keep it where\n // this pixel is on the subject's side (darker than what lies toward the light, or brighter if so set).\n float crisp = rimAt(uv + toLight * d, d, toLight);\n float soft = rimAt(uv + toLight * d * 2.5, d * 3.0, toLight);\n float rise = luma(uv + toLight * d * 3.0) - luma(uv);\n float side = smoothstep(0.0, 0.06, uBrightSubject ? -rise : rise);\n crisp *= side;\n soft *= mix(0.5, 1.0, side);\n vec4 pic = pictureRGBA(uImage, uv);\n vec3 light = uColor * (crisp + 0.45 * soft) * uIntensity + vec3(1.0) * crisp * crisp * 0.12 * uIntensity;\n vec3 col = pic.rgb * (1.0 - uDim) + light * (1.0 - 0.5 * pic.rgb);\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Kicker\", values: { uColor: [1, 0.86, 0.66], uAngle: 160, uDim: 0.2 } },\n { name: \"Cyberpunk\", values: { uColor: [1, 0.2, 0.7], uAngle: 20, uDim: 0.55, uIntensity: 2.5, uWidth: 3.5 } },\n { name: \"Top light\", values: { uColor: [0.85, 0.95, 1], uAngle: 90, uFocus: 0.7 } },\n ],\n};\n\n/** Glows and auras: halos, bloom, outlines and rim light round shapes and pictures. */\nexport const glowShaders: ShaderEffect[] = [aura, bloom, pulsingHalo, neonOutline, backlightGlow, rimLight];\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 * Shadows from shapes and light. The mask effects read a picture's alpha as\n * a silhouette, contained in `uSize` of the frame, and blur it by reading a\n * mip level about as coarse as their taps are apart (see silhouette-morph).\n * The rest are signed-distance shapes, so their shadows can be marched.\n */\n\n/**\n * `shapeAt(p, spacing)`: the `uMask` picture's colour (premultiplied) and\n * alpha at frame point p (height 1, centred), contained in `uSize` of the\n * frame, read at a mip level as coarse as `spacing` (frame units). With no\n * picture, a rounded square. Needs `uMask` and `uSize`.\n */\nconst SHAPE = `\nvec4 shapeAt(vec2 p, float spacing) {\n vec2 size = vec2(textureSize(uMask, 0));\n if (size.x <= 1.0) {\n vec2 q = abs(p) - 0.18 * uSize;\n float a = step(length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - 0.08 * uSize, 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(uMask, uv, log2(max(spacing * size.y / h, 1.0)));\n // Clear texels upload black, so filtered colour is about colour × alpha already.\n return vec4(clamp(c.rgb / max(c.a, 1e-3), 0.0, 1.0) * c.a, c.a);\n}`.trim();\n\n/** `capsule(p, a, b, r)`, `box(p, halfSize, radius)` and `smin(a, b, k)`: 2D distances. */\nconst SDF = `\nfloat capsule(vec2 p, vec2 a, vec2 b, float r) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n return length(pa - ba * h) - r;\n}\nfloat box(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}\nfloat smin(float a, float b, float k) {\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\nexport const longShadow: ShaderEffect = {\n kind: \"shader\",\n id: \"long-shadow\",\n name: \"Long shadow\",\n description: \"The flat-design long shadow: a word or icon casting a long diagonal band across a flat colour, fading along its length and slowly swinging round.\",\n category: \"shadow\",\n video: \"none\",\n tags: [\"shadow\", \"long-shadow\", \"flat\", \"text\", \"logo\", \"icon\", \"mask\"],\n source: glsl(\n `// Long shadow: the shape's mask marched back along a direction, so it casts a long band that fades as it goes.\nuniform sampler2D uMask; // @control filter=mipmap wrap=clamp default=${textImage(\"LONG\")} label=\"Shape (its alpha)\"\nuniform float uSize; // @control min=0.2 max=1 default=0.8 label=\"Shape size\"\nuniform float uAngle; // @control min=0 max=360 default=315 label=\"Direction (°)\"\nuniform float uSwing; // @control min=0 max=60 default=15 label=\"Swing (°)\"\nuniform float uSpin; // @control min=-30 max=30 default=0 label=\"Turn (°/s)\"\nuniform float uLength; // @control min=0 max=1.5 default=0.7 label=\"Length\"\nuniform float uFade; // @control min=0 max=1 default=0.85 label=\"Fade along\"\nuniform vec3 uBackground; // @control color default=#EF5A5A label=\"Background\"\nuniform vec3 uShadow; // @control color default=#B8383F label=\"Shadow\"\nuniform vec3 uColour; // @control color default=#FFFFFF label=\"Shape colour\"\nuniform bool uImageColours; // @control default=false label=\"Use the shape's own colours\"`,\n SHAPE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float a = radians(uAngle + uSpin * iTime + uSwing * sin(iTime * 0.4));\n vec2 dir = vec2(cos(a), sin(a));\n // Look back toward the shape: any copy of it along the way covers this point.\n const int STEPS = 96;\n float spacing = uLength / float(STEPS);\n float shade = 0.0;\n for (int i = 1; i <= STEPS; i++) {\n float m = shapeAt(p - dir * (float(i) * spacing), spacing).a;\n shade = max(shade, m);\n if (shade > 0.99) break;\n }\n // The band fades in one smooth gradient along the direction, from the back of the shape's box to the shadow's end.\n vec2 size = vec2(textureSize(uMask, 0));\n float aspect = size.x <= 1.0 ? 1.0 : size.x / size.y;\n float h = size.x <= 1.0 ? 0.52 * uSize : min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n float reach = 0.5 * h * (abs(dir.x) * aspect + abs(dir.y));\n shade *= 1.0 - uFade * clamp((dot(p, dir) + reach) / (2.0 * reach + uLength), 0.0, 1.0);\n vec3 col = mix(uBackground, uShadow, shade);\n vec4 c = shapeAt(p, 1.0 / iResolution.y);\n vec3 ink = uImageColours ? c.rgb / max(c.a, 1e-4) : uColour;\n fragColor = vec4(mix(col, ink, c.a), 1.0);\n}`,\n ),\n presets: [\n { name: \"Flat\", values: { uFade: 0, uLength: 1.5, uSwing: 0, uBackground: [0.16, 0.71, 0.65], uShadow: [0.11, 0.55, 0.5] } },\n { name: \"Icon\", values: { uMask: SAMPLE_IMAGES.heart, uImageColours: true, uSize: 0.5, uBackground: [0.99, 0.82, 0.32], uShadow: [0.86, 0.62, 0.14] } },\n { name: \"Spinning\", values: { uSwing: 0, uSpin: 20, uFade: 1, uBackground: [0.2, 0.22, 0.32], uShadow: [0.1, 0.11, 0.18] } },\n ],\n};\n\nexport const dropShadowLift: ShaderEffect = {\n kind: \"shader\",\n id: \"drop-shadow-lift\",\n name: \"Drop shadow lift\",\n description: \"A logo or icon resting on a soft drop shadow that lifts off the page when hovered, its shadow growing larger, softer and further below as it scales up.\",\n category: \"shadow\",\n video: \"none\",\n tags: [\"shadow\", \"drop-shadow\", \"hover\", \"interactive\", \"elevation\", \"logo\", \"icon\", \"mask\"],\n source: glsl(\n `// Drop shadow lift: a shape on a blurred copy of its own mask, which spreads and drops as the shape lifts (on hover).\nuniform sampler2D uMask; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.logo} label=\"Object (its alpha)\"\nuniform float uSize; // @control min=0.2 max=1 default=0.55 label=\"Object size\"\nuniform bool uImageColours; // @control default=true label=\"Use the object's own colours\"\nuniform vec3 uColour; // @control color default=#6366F1 label=\"Object colour\"\nuniform vec3 uBackground; // @control color default=#EEF1F7 label=\"Background\"\nuniform vec3 uShadow; // @control color default=#1E2340 label=\"Shadow colour\"\nuniform float uOpacity; // @control min=0 max=1 default=0.45 label=\"Shadow strength\"\nuniform float uRestBlur; // @control min=0 max=0.1 default=0.012 label=\"Blur at rest\"\nuniform float uLiftBlur; // @control min=0 max=0.2 default=0.07 label=\"Blur when lifted\"\nuniform float uLiftDrop; // @control min=0 max=0.15 default=0.06 label=\"Shadow drop when lifted\"\nuniform float uLiftScale; // @control min=0 max=0.2 default=0.06 label=\"Scale when lifted\"\nuniform bool uDemo; // @control default=true label=\"Demo when idle\"`,\n SHAPE,\n `// The mask blurred over a disc of the radius: 24 taps on a golden-angle spiral, each from a mip level as coarse as their spacing.\nfloat blurred(vec2 p, float radius) {\n float sum = 0.0;\n for (int i = 0; i < 24; i++) {\n float r = radius * sqrt((float(i) + 0.5) / 24.0);\n float a = float(i) * 2.39996;\n sum += shapeAt(p + r * vec2(cos(a), sin(a)), radius * 0.35).a;\n }\n return sum / 24.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 // Hovering lifts it; idle, the demo breathes it up and down.\n float idle = uDemo ? smoothstep(0.0, 1.0, 0.5 - 0.5 * cos(iTime * 1.3)) : 0.0;\n float lift = mix(idle, 1.0, clamp(iPointer.z, 0.0, 1.0));\n float k = 1.0 + uLiftScale * lift;\n vec2 rise = vec2(0.0, 0.012 * lift);\n // The shadow spreads a little wider than the object, drops below it and softens.\n float ks = k * (1.0 + 0.05 * lift);\n vec2 drop = vec2(0.0, -(0.008 + uLiftDrop * lift));\n float radius = mix(uRestBlur, uLiftBlur, lift) + px;\n float shadow = blurred((p - drop) / ks, radius / ks) * uOpacity * mix(1.0, 0.7, lift);\n vec3 col = mix(uBackground, uShadow, shadow);\n vec4 c = shapeAt((p - rise) / k, px / k);\n vec3 ink = uImageColours ? c.rgb / max(c.a, 1e-4) : uColour;\n fragColor = vec4(mix(col, ink, c.a), 1.0);\n}`,\n ),\n presets: [\n { name: \"Heart\", values: { uMask: SAMPLE_IMAGES.heart, uBackground: [1, 0.94, 0.95], uShadow: [0.45, 0.05, 0.15], uOpacity: 0.4 } },\n { name: \"Dramatic\", values: { uOpacity: 0.7, uLiftBlur: 0.12, uLiftDrop: 0.12, uLiftScale: 0.1, uBackground: [0.85, 0.87, 0.9] } },\n ],\n};\n\nexport const lightSweepShadows: ShaderEffect = {\n kind: \"shader\",\n id: \"light-sweep-shadows\",\n name: \"Light sweep shadows\",\n description: \"A coloured light drifting across a floor of shapes (or following the pointer), each casting a real soft shadow that swings round as the light moves.\",\n category: \"shadow\",\n tags: [\"shadow\", \"light\", \"soft-shadows\", \"sdf\", \"lamp\", \"interactive\", \"hover\"],\n source: glsl(\n `// Light sweep shadows: soft 2D shadows marched from each point toward a moving light through the shapes' distance field.\nuniform vec3 uLight; // @control color default=#FFC46E label=\"Light colour\"\nuniform float uIntensity; // @control min=0 max=4 default=1.8 label=\"Light strength\"\nuniform float uReach; // @control min=0.1 max=2 default=0.45 label=\"Light reach\"\nuniform float uSoftness; // @control min=0.005 max=0.3 default=0.06 label=\"Shadow softness\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"\nuniform vec3 uFloor; // @control color default=#3A3F52 label=\"Floor\"\nuniform vec3 uShapes; // @control color default=#ECE6DA label=\"Shapes\"\nuniform float uAmbient; // @control min=0 max=1 default=0.12 label=\"Ambient light\"\nuniform bool uFollow; // @control default=true label=\"Follow the pointer\"`,\n ROTATE,\n SDF,\n `float scene(vec2 p) {\n float d = length(p - vec2(-0.45, 0.13)) - 0.09;\n d = min(d, length(p - vec2(0.36, -0.17)) - 0.065);\n d = min(d, length(p - vec2(-0.2, -0.28)) - 0.045);\n d = min(d, box(rot(0.5) * (p - vec2(0.04, 0.0)), vec2(0.1, 0.05), 0.012));\n d = min(d, box(rot(-0.3) * (p - vec2(0.55, 0.2)), vec2(0.03, 0.12), 0.01));\n d = min(d, box(rot(0.9) * (p - vec2(-0.62, -0.22)), vec2(0.05, 0.05), 0.008));\n return d;\n}\n\nvec2 sceneNormal(vec2 p) {\n vec2 e = vec2(0.002, 0.0);\n return normalize(vec2(scene(p + e.xy) - scene(p - e.xy), scene(p + e.yx) - scene(p - e.yx)) + 1e-6);\n}\n\n// How much of the light reaches p: march toward it, keeping the narrowest miss relative to how far along.\nfloat softShadow(vec2 p, vec2 light) {\n vec2 to = light - p;\n float dist = length(to);\n vec2 dir = to / max(dist, 1e-5);\n float res = 1.0;\n float t = 0.004;\n for (int i = 0; i < 56; i++) {\n if (t >= dist) break;\n float d = scene(p + dir * t);\n res = min(res, d / (uSoftness * t));\n if (res < -1.0) break;\n t += clamp(d, 0.004, 0.08);\n }\n res = max(res, -1.0);\n return 0.25 * (1.0 + res) * (1.0 + res) * (2.0 - res);\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 aspect = iResolution.x / iResolution.y;\n float t = iTime * uSpeed;\n vec2 light = vec2(0.42 * aspect * sin(t * 1.06), 0.36 * sin(t * 1.62 + 1.0));\n if (uFollow) light = mix(light, (iPointer.xy - 0.5 * iResolution.xy) * px, clamp(iPointer.z, 0.0, 1.0));\n // Keep the light out of the shapes.\n float inside = scene(light);\n if (inside < 0.03) light += sceneNormal(light) * (0.03 - inside);\n\n vec2 to = light - p;\n float r = length(to);\n float falloff = 1.0 / (1.0 + r * r / (uReach * uReach));\n vec3 lamp = uLight * uIntensity * falloff;\n float d = scene(p);\n // Floor: ambient, plus the light where it gets through.\n vec3 floorCol = uFloor * (uAmbient + lamp * softShadow(p, light));\n // Shapes are lit on top, brighter on the rim that faces the light.\n vec2 n = sceneNormal(p);\n float rim = smoothstep(-0.025, 0.0, d) * max(dot(n, to / max(r, 1e-5)), 0.0);\n vec3 shapeCol = uShapes * (uAmbient + 0.25 + lamp * (0.45 + 0.8 * rim));\n vec3 col = mix(shapeCol, floorCol, smoothstep(-px, px, d));\n // The bulb itself.\n col += uLight * (exp(-r * r / 0.00025) * 2.0 + exp(-r * r / 0.004) * 0.25);\n fragColor = vec4(1.0 - exp(-col * 1.3), 1.0);\n}`,\n ),\n presets: [\n { name: \"Candle\", values: { uLight: [1, 0.6, 0.25], uReach: 0.3, uSoftness: 0.12, uSpeed: 0.3, uFloor: [0.22, 0.17, 0.14] } },\n { name: \"Neon\", values: { uLight: [0.3, 0.85, 1], uIntensity: 2.5, uSoftness: 0.02, uFloor: [0.1, 0.1, 0.18], uShapes: [0.9, 0.3, 0.7] } },\n ],\n};\n\nexport const contactShadow: ShaderEffect = {\n kind: \"shader\",\n id: \"contact-shadow\",\n name: \"Contact shadow\",\n description: \"An object floating up and down above the floor, its contact shadow tightening and darkening as it nears the ground and spreading and fading as it rises.\",\n category: \"shadow\",\n tags: [\"shadow\", \"contact-shadow\", \"float\", \"ground\", \"product\", \"3d\"],\n source: glsl(\n `// Contact shadow: an object bobbing over a floor; a tight dark core and a wide soft shadow, both spreading and fading with height.\nuniform int uShape; // @control min=0 max=2 default=0 label=\"Object (0 ball, 1 cube, 2 pill)\"\nuniform vec3 uObject; // @control color default=#FF7A59 label=\"Object\"\nuniform vec3 uBackground; // @control color default=#F3EEE6 label=\"Wall\"\nuniform vec3 uGround; // @control color default=#E2D8C9 label=\"Floor\"\nuniform vec3 uShadow; // @control color default=#3A2C22 label=\"Shadow colour\"\nuniform float uHeight; // @control min=0 max=0.4 default=0.2 label=\"Float height\"\nuniform float uSpeed; // @control min=0 max=3 default=0.8 label=\"Speed\"\nuniform float uDarkness; // @control min=0 max=1 default=0.8 label=\"Contact darkness\"\nuniform float uSpread; // @control min=0 max=3 default=1.4 label=\"Spread when high\"`,\n SDF,\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 const float horizon = -0.08;\n const float groundY = -0.26;\n const float R = 0.12;\n // Lingers at the top and bottom of each bob, and comes down to just touch.\n float s = 0.5 + 0.5 * sin(iTime * uSpeed * 1.6);\n float h = 0.003 + uHeight * s * s * (3.0 - 2.0 * s);\n\n // Wall above, floor below, a soft crease between.\n vec3 wall = uBackground * (0.92 + 0.08 * smoothstep(horizon, 0.5, p.y));\n vec3 floorCol = uGround * (0.94 + 0.06 * smoothstep(horizon, -0.5, p.y));\n vec3 col = mix(floorCol, wall, smoothstep(-px, px, p.y - horizon));\n col *= 1.0 - 0.06 * exp(-abs(p.y - horizon) * 40.0);\n\n vec2 ext = uShape == 0 ? vec2(R) : (uShape == 1 ? vec2(0.85 * R) : vec2(1.35 * R, 0.55 * R));\n // The shadow on the floor: a squashed core that tightens and darkens near the ground, and a broad soft one.\n vec2 g = p - vec2(0.0, groundY);\n float coreW = ext.x * 0.8 + h * uSpread * 0.35;\n float core = exp(-dot(g / vec2(coreW, coreW * 0.16), g / vec2(coreW, coreW * 0.16)) * 1.6) * exp(-h * 10.0);\n float wideW = ext.x * 1.15 + h * uSpread;\n float wide = exp(-dot(g / vec2(wideW, wideW * 0.22), g / vec2(wideW, wideW * 0.22)) * 1.2) * 0.45 / (1.0 + h * 8.0);\n float shade = uDarkness * (1.0 - (1.0 - core) * (1.0 - wide));\n col = mix(col, uShadow, shade);\n\n // The object.\n vec2 q = p - vec2(0.0, groundY + ext.y + h);\n float d = uShape == 0 ? length(q) - R : (uShape == 1 ? box(q, ext, 0.035) : box(q, ext, ext.y));\n vec2 u = clamp(q / ext, -1.0, 1.0);\n vec3 obj;\n if (uShape == 0) {\n vec3 n = vec3(u, sqrt(max(1.0 - dot(u, u), 0.0)));\n vec3 l = normalize(vec3(-0.45, 0.6, 0.65));\n float diff = max(dot(n, l), 0.0);\n float spec = pow(max(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0), 24.0);\n obj = uObject * (0.35 + 0.75 * diff) + 0.35 * spec;\n } else {\n obj = uObject * (0.88 + 0.16 * u.y - 0.06 * u.x);\n obj += 0.12 * smoothstep(0.7, 1.0, u.y) * smoothstep(1.0, 0.6, abs(u.x));\n }\n // Near the ground the floor shades its underside.\n obj *= 1.0 - 0.35 * exp(-h * 14.0) * smoothstep(-0.2, -1.0, u.y);\n col = mix(obj, col, smoothstep(-px, px, d));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Cube\", values: { uShape: 1, uObject: [0.38, 0.4, 0.95], uBackground: [0.93, 0.94, 0.97], uGround: [0.85, 0.87, 0.92], uShadow: [0.1, 0.12, 0.25] } },\n { name: \"Pill on dark\", values: { uShape: 2, uObject: [0.98, 0.84, 0.3], uBackground: [0.13, 0.14, 0.17], uGround: [0.18, 0.19, 0.23], uShadow: [0, 0, 0], uDarkness: 0.9 } },\n ],\n};\n\nexport const windowShadows: ShaderEffect = {\n kind: \"shader\",\n id: \"window-shadows\",\n name: \"Window shadows\",\n description: \"Warm sunlight through a window falling across a wall or a picture, dappled by the shadows of slowly tilting blinds or rustling leaves.\",\n category: \"shadow\",\n video: \"filter\",\n tags: [\"shadow\", \"light\", \"dappled\", \"window\", \"blinds\", \"leaves\", \"sunlight\", \"warm\", \"image\"],\n source: glsl(\n `// Window shadows: a patch of sunlight from a window, striped by blinds or broken up by leaves, laid over a wall or picture.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform bool uPlainWall; // @control default=false label=\"Plain wall (no image)\"\nuniform vec3 uWall; // @control color default=#E8DCCB label=\"Wall\"\nuniform int uPattern; // @control min=0 max=1 default=1 label=\"Shadows of (0 blinds, 1 leaves)\"\nuniform vec3 uLight; // @control color default=#FFC27A label=\"Light colour\"\nuniform float uIntensity; // @control min=0 max=2 default=0.9 label=\"Light strength\"\nuniform float uShade; // @control min=0 max=1 default=0.45 label=\"Shadow depth\"\nuniform float uAngle; // @control min=-60 max=60 default=-22 label=\"Light angle (°)\"\nuniform float uScale; // @control min=0.4 max=2.5 default=1 label=\"Scale\"\nuniform float uSoftness; // @control min=0 max=1 default=0.35 label=\"Softness\"\nuniform float uSway; // @control min=0 max=2 default=1 label=\"Sway\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n HASH,\n NOISE,\n FBM,\n ROTATE,\n `// The sunlit patch the window throws, slanted, with soft edges.\nfloat windowPatch(vec2 q, float soft) {\n vec2 e = abs(q) - vec2(0.5, 0.4);\n return smoothstep(soft, -soft, max(e.x, e.y));\n}\n\nfloat blinds(vec2 q, float t, float soft) {\n q.x += 0.006 * sin(t * 0.7) * uSway;\n // The slats tilt slowly open and shut.\n float open = clamp(0.5 + 0.22 * sin(t * 0.35 * uSway + 0.4), 0.15, 0.85);\n float f = fract(q.y * 14.0 + 0.04 * sin(q.x * 3.0 + t * 0.5) * uSway);\n float w = 0.03 + soft * 0.25;\n float lit = smoothstep(0.0, w, f) * smoothstep(open + w, open, f);\n // The window's frame and cross bar.\n float bars = smoothstep(0.012 + soft * 0.03, 0.006, abs(q.x)) + smoothstep(0.012 + soft * 0.03, 0.006, abs(q.y - 0.02));\n return lit * (1.0 - clamp(bars, 0.0, 1.0)) * windowPatch(q, 0.02 + soft * 0.06);\n}\n\nfloat leaves(vec2 q, float t, float soft) {\n // Branches sway slowly and the leaves rustle quickly on top.\n vec2 sway = uSway * (vec2(0.05 * sin(t * 0.6 + q.y * 1.5), 0.03 * cos(t * 0.45 + q.x * 1.2))\n + 0.012 * vec2(vnoise(q * 6.0 + t * 1.3), vnoise(q * 6.0 - t * 1.1 + 7.0)));\n float n = fbm((q + sway) * 3.2 + 4.0, 5);\n float s = 0.025 + soft * 0.1;\n float lit = smoothstep(0.5 - s, 0.5 + s, n);\n return lit * windowPatch(q * 0.75, 0.08 + soft * 0.1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n // Light comes in at an angle, so the window's shape is turned and sheared across the wall.\n vec2 q = rot(radians(uAngle)) * p / uScale;\n q.x += q.y * 0.35;\n float lit = uPattern == 0 ? blinds(q, iTime, uSoftness) : leaves(q, iTime, uSoftness);\n\n vec4 base;\n if (uPlainWall) {\n float plaster = vnoise(fragCoord * 0.35) * 0.5 + vnoise(fragCoord * 0.05) * 0.5;\n base = vec4(uWall * (0.96 + 0.06 * plaster), 1.0);\n } else {\n base = pictureRGBA(uImage, uv);\n }\n vec3 light = (1.0 - uShade) * vec3(0.95, 0.96, 1.0) + lit * uShade * uLight * (0.6 + uIntensity);\n vec3 col = base.rgb * light;\n col = col / (1.0 + max(col - 1.0, 0.0));\n fragColor = vec4(col, base.a);\n}`,\n ),\n presets: [\n { name: \"Blinds\", values: { uPattern: 0, uPlainWall: true, uAngle: -30, uSoftness: 0.2, uLight: [1, 0.82, 0.6] } },\n { name: \"Plain wall\", values: { uPlainWall: true } },\n { name: \"Golden hour\", values: { uPlainWall: true, uLight: [1, 0.6, 0.3], uIntensity: 1.4, uShade: 0.7, uSoftness: 0.6, uWall: [0.93, 0.85, 0.78] } },\n ],\n};\n\nexport const shadowPuppets: ShaderEffect = {\n kind: \"shader\",\n id: \"shadow-puppets\",\n name: \"Shadow puppets\",\n description: \"Hand shadow puppets on a lamp-lit wall: a flapping bird, a barking dog or a twitching rabbit, softening as the hand moves away from the wall.\",\n category: \"shadow\",\n tags: [\"shadow\", \"puppet\", \"hands\", \"silhouette\", \"bird\", \"dog\", \"rabbit\", \"warm\", \"playful\"],\n source: glsl(\n `// Shadow puppets: hand shapes built from soft-unioned capsules, cast on a warmly lit wall; the further the hand from the wall, the bigger and softer.\nuniform int uPuppet; // @control min=0 max=2 default=0 label=\"Puppet (0 bird, 1 dog, 2 rabbit)\"\nuniform vec3 uWall; // @control color default=#F2DDB8 label=\"Wall\"\nuniform vec3 uLight; // @control color default=#FFB75E label=\"Lamp colour\"\nuniform vec3 uShadow; // @control color default=#2B1B12 label=\"Shadow colour\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uDepth; // @control min=0 max=1 default=0.6 label=\"Hand moving to and from the wall\"\nuniform float uSoftness; // @control min=0 max=0.1 default=0.035 label=\"Softness away from the wall\"\nuniform float uSize; // @control min=0.5 max=1.5 default=1 label=\"Size\"`,\n HASH,\n NOISE,\n ROTATE,\n SDF,\n `float ellipse(vec2 p, vec2 r) {\n return (length(p / r) - 1.0) * min(r.x, r.y);\n}\n\n// Two hands linked at the thumbs (the head), fingers fanned out as wings.\nfloat bird(vec2 p, float t) {\n float flap = 0.45 * sin(t * 4.0);\n float d = capsule(p, vec2(0.0, -0.02), vec2(0.0, 0.13), 0.028);\n d = smin(d, ellipse(p - vec2(0.0, 0.165), vec2(0.04, 0.035)), 0.02);\n d = min(d, capsule(p, vec2(0.025, 0.17), vec2(0.075, 0.158), 0.009));\n for (int s = 0; s < 2; s++) {\n vec2 q = vec2(s == 0 ? p.x : -p.x, p.y);\n d = smin(d, ellipse(q - vec2(0.08, 0.0), vec2(0.075, 0.045)), 0.03);\n d = smin(d, capsule(q, vec2(0.08, -0.01), vec2(0.3, -0.65), 0.06), 0.03);\n for (int k = 0; k < 4; k++) {\n float fk = float(k);\n float a = 0.55 - fk * 0.22 + flap * (1.0 - fk * 0.12);\n vec2 root = vec2(0.13, 0.02 - fk * 0.018);\n d = smin(d, capsule(q, root, root + (0.2 - fk * 0.02) * vec2(cos(a), sin(a)), 0.019 - fk * 0.002), 0.012);\n }\n }\n return d;\n}\n\n// The back of the hand is the head, the thumb an ear, the little finger a jaw that drops as it barks.\nfloat dog(vec2 p, float t) {\n float bark = max(sin(t * 3.0), 0.0);\n bark *= bark;\n float d = box(p - vec2(-0.02, 0.03), vec2(0.12, 0.065), 0.05);\n d = smin(d, capsule(p, vec2(0.06, 0.04), vec2(0.24, 0.025), 0.038), 0.03);\n vec2 pivot = vec2(0.0, -0.03);\n vec2 jaw = rot(0.4 * bark) * (p - pivot) + pivot;\n d = smin(d, capsule(jaw, vec2(0.02, -0.04), vec2(0.2, -0.045), 0.024), 0.012);\n d = smin(d, capsule(p, vec2(-0.06, 0.08), vec2(-0.1 + 0.04 * sin(t * 1.3), 0.2), 0.042), 0.03);\n d = smin(d, capsule(p, vec2(-0.08, 0.0), vec2(-0.5, -0.65), 0.075), 0.04);\n // A gap between the fingers for an eye.\n return max(d, -(length(p - vec2(0.07, 0.07)) - 0.013));\n}\n\n// Two fingers up as ears, the fist a head with a twitching nose.\nfloat rabbit(vec2 p, float t) {\n float nose = 0.006 * sin(t * 18.0) * step(0.3, sin(t * 0.9));\n float d = ellipse(p, vec2(0.12, 0.085));\n d = smin(d, length(p - vec2(0.11 + nose, -0.025)) - 0.05, 0.04);\n d = smin(d, capsule(p, vec2(-0.04, 0.05), vec2(-0.09 + 0.08 * sin(t * 1.7), 0.32), 0.04), 0.03);\n d = smin(d, capsule(p, vec2(0.0, 0.06), vec2(0.03 + 0.08 * sin(t * 1.7 + 1.2), 0.3), 0.037), 0.03);\n d = smin(d, capsule(p, vec2(-0.06, -0.03), vec2(-0.45, -0.65), 0.075), 0.04);\n return max(d, -(length(p - vec2(0.045, 0.025)) - 0.013));\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 // The lamp's pool of light on the wall, and a little plaster.\n float spot = smoothstep(0.95, 0.05, length((p - vec2(0.04, 0.05)) * vec2(0.75, 1.0)));\n vec3 wall = uWall * mix(vec3(0.16, 0.11, 0.09), uLight * 1.3, spot);\n wall *= 0.95 + 0.07 * vnoise(fragCoord * 0.3) + 0.04 * vnoise(fragCoord * 0.03);\n // Nearer the lamp the shadow grows and its edge blurs.\n float z = uDepth * (0.5 + 0.5 * sin(iTime * 0.45));\n float scale = uSize * (1.0 + 0.3 * z);\n vec2 drift = vec2(0.03 * sin(iTime * 0.4), 0.02 * sin(iTime * 0.7) - 0.04);\n vec2 q = (p - drift) / scale;\n float d = (uPuppet == 0 ? bird(q, t) : (uPuppet == 1 ? dog(q, t) : rabbit(q, t))) * scale;\n float soft = max(0.002 + uSoftness * z, px);\n float cover = 1.0 - smoothstep(-soft, soft, d);\n vec3 col = mix(wall, uShadow * (0.6 + 0.4 * spot), cover * 0.92);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Dog\", values: { uPuppet: 1 } },\n { name: \"Rabbit by candle\", values: { uPuppet: 2, uLight: [1, 0.55, 0.25], uWall: [0.95, 0.8, 0.62], uSoftness: 0.06 } },\n { name: \"Moonlit bird\", values: { uPuppet: 0, uLight: [0.7, 0.8, 1], uWall: [0.78, 0.82, 0.9], uShadow: [0.05, 0.07, 0.13] } },\n ],\n};\n\n/** Shadows: long, soft, moving and contact shadows from shapes and light. */\nexport const shadowShaders: ShaderEffect[] = [longShadow, dropShadowLift, lightSweepShadows, contactShadow, windowShadows, shadowPuppets];\n","import { 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\n/**\n * `centreAt(centre, follow)`: the centre of a distortion in pixels. It drifts\n * gently around `centre` (0–1 across the frame) and moves to the pointer while\n * it hovers, when `follow` is on.\n */\nconst CENTRE = `\nvec2 centreAt(vec2 centre, bool follow) {\n vec2 drift = vec2(0.03 * sin(iTime * 0.37), 0.025 * cos(iTime * 0.29));\n vec2 idle = (centre + drift) * iResolution.xy;\n float h = follow ? clamp(iPointer.z, 0.0, 1.0) : 0.0;\n return mix(idle, iPointer.xy, h);\n}`.trim();\n\nexport const twirl: ShaderEffect = {\n kind: \"shader\",\n id: \"twirl\",\n name: \"Twirl\",\n description: \"A picture twisted into a swirl that winds and unwinds around the pointer or a centre, strongest in the middle.\",\n category: \"distortion\",\n video: \"interactive\",\n tags: [\"distortion\", \"swirl\", \"image\", \"interactive\", \"hover\"],\n source: glsl(\n `// Twirl: the picture swirled around a centre, the twist falling off with radius.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uTwist; // @control min=-12 max=12 default=5 label=\"Twist (radians)\"\nuniform float uRadius; // @control min=0.05 max=1.2 default=0.45 label=\"Radius\"\nuniform float uSpeed; // @control min=0 max=3 default=0.6 label=\"Wind speed (0 holds it)\"\nuniform vec2 uCentre; // @control min=0 max=1 default=0.5,0.5 label=\"Centre\"\nuniform bool uFollow; // @control default=true label=\"Follow the pointer\"\n${BACKDROP_CONTROLS}`,\n ROTATE,\n PICTURE,\n CENTRE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 c = centreAt(uCentre, uFollow);\n vec2 d = fragCoord - c;\n float R = uRadius * iResolution.y;\n float f = clamp(1.0 - length(d) / R, 0.0, 1.0);\n f = f * f * (3.0 - 2.0 * f);\n float swing = cos(iTime * uSpeed);\n d = rot(uTwist * swing * f * f) * d;\n fragColor = pictureRGBA(uImage, (c + d) / iResolution.xy);\n}`,\n ),\n presets: [\n { name: \"Whirlpool\", values: { uTwist: 10, uRadius: 0.8, uSpeed: 0.3 } },\n { name: \"Flick\", values: { uTwist: -3, uRadius: 0.25, uSpeed: 2 } },\n ],\n};\n\nexport const pinchBulge: ShaderEffect = {\n kind: \"shader\",\n id: \"pinch-bulge\",\n name: \"Pinch & bulge\",\n description: \"A picture swelling out like a bubble or sucked in to a point around the pointer or a centre.\",\n category: \"distortion\",\n video: \"interactive\",\n tags: [\"distortion\", \"bulge\", \"pinch\", \"image\", \"interactive\", \"hover\"],\n source: glsl(\n `// Pinch & bulge: the picture bulged out (positive) or pinched in (negative) inside a radius.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uStrength; // @control min=-1 max=1 default=0.7 label=\"Pinch ← → Bulge\"\nuniform float uRadius; // @control min=0.05 max=1 default=0.4 label=\"Radius\"\nuniform bool uAnimate; // @control default=true label=\"Animate (swing between pinch and bulge)\"\nuniform float uSpeed; // @control min=0.1 max=4 default=1 label=\"Swing speed\"\nuniform vec2 uCentre; // @control min=0 max=1 default=0.5,0.5 label=\"Centre\"\nuniform bool uFollow; // @control default=true label=\"Follow the pointer\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n CENTRE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 c = centreAt(uCentre, uFollow);\n vec2 d = fragCoord - c;\n float R = uRadius * iResolution.y;\n float t = length(d) / R;\n float s = uAnimate ? uStrength * cos(iTime * uSpeed) : uStrength;\n float shade = 1.0;\n if (t < 1.0) {\n // A power curve that meets the untouched picture at the rim: above 1 magnifies the middle, below 1 shrinks it.\n float e = exp(s * 1.3);\n d *= pow(max(t, 1e-4), e - 1.0);\n shade = 1.0 + 0.18 * s * (1.0 - t) * (1.0 - t);\n }\n vec4 pic = pictureRGBA(uImage, (c + d) / iResolution.xy);\n fragColor = vec4(pic.rgb * shade, pic.a);\n}`,\n ),\n presets: [\n { name: \"Bubble\", values: { uStrength: 1, uRadius: 0.3, uAnimate: false } },\n { name: \"Black hole\", values: { uStrength: -1, uRadius: 0.6, uAnimate: false } },\n ],\n};\n\nexport const fisheye: ShaderEffect = {\n kind: \"shader\",\n id: \"fisheye\",\n name: \"Fisheye\",\n description: \"A picture seen through a fisheye lens, bulging in the middle and curving to the corners, over the whole frame or in a round lens.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"lens\", \"fisheye\", \"barrel\", \"image\"],\n source: glsl(\n `// Fisheye: an equidistant fisheye projection of a flat picture, framed or in a circle.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uStrength; // @control min=0 max=1 default=0.75 label=\"Strength (field of view)\"\nuniform float uZoom; // @control min=0.5 max=2 default=1 label=\"Zoom\"\nuniform bool uLens; // @control default=false label=\"Round lens\"\nuniform float uRadius; // @control min=0.1 max=0.7 default=0.42 label=\"Lens radius\"\nuniform float uVignette; // @control min=0 max=1 default=0.35 label=\"Vignette\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 mid = 0.5 * iResolution.xy;\n vec2 d = fragCoord - mid;\n // The unit radius: the half diagonal (corners stay corners) or the lens.\n float unit = uLens ? uRadius * iResolution.y : 0.5 * length(iResolution.xy);\n float r = length(d) / unit;\n vec4 col = pictureRGBA(uImage, fragCoord / iResolution.xy);\n if (r < 1.0) {\n // A ray at angle r * fov / 2 lands at tan(angle) on the flat picture.\n float fov = mix(0.02, 2.9, uStrength);\n float src = tan(r * 0.5 * fov) / tan(0.5 * fov);\n vec2 p = mid + d / max(length(d), 1e-5) * src * unit / uZoom;\n vec4 lens = pictureRGBA(uImage, p / iResolution.xy);\n lens.rgb *= 1.0 - uVignette * pow(r, 2.5);\n float edge = uLens ? 1.0 - smoothstep(1.0 - 2.0 / unit, 1.0, r) : 1.0;\n col = mix(col, lens, edge);\n }\n if (uLens) {\n float rim = exp(-pow((r - 1.0) * unit / max(unit * 0.02, 1.5), 2.0));\n col.rgb = mix(col.rgb, vec3(0.06), rim * 0.6);\n } else {\n col.rgb *= 1.0 - uVignette * smoothstep(0.98, 1.0, r);\n }\n fragColor = col;\n}`,\n ),\n presets: [\n { name: \"Doorway peephole\", values: { uLens: true, uStrength: 1, uRadius: 0.48, uVignette: 0.6 } },\n { name: \"Action cam\", values: { uStrength: 0.45, uZoom: 1.1, uVignette: 0.15 } },\n ],\n};\n\nexport const mirrorTiles: ShaderEffect = {\n kind: \"shader\",\n id: \"mirror-tiles\",\n name: \"Mirror tiles\",\n description: \"A picture folded into mirrored kaleidoscope tiles, square or hexagonal, slowly turning and drifting.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"kaleidoscope\", \"mirror\", \"tiles\", \"image\"],\n source: glsl(\n `// Mirror tiles: each tile folds the picture about its centre into mirrored wedges.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uFold; // @control min=2 max=8 step=2 default=6 label=\"Mirror fold\"\nuniform bool uHex; // @control default=false label=\"Hexagonal tiles\"\nuniform float uTiles; // @control min=1 max=8 default=2 label=\"Tiles down\"\nuniform float uZoom; // @control min=0.2 max=2 default=1 label=\"Picture scale\"\nuniform float uSpin; // @control min=-1 max=1 default=0.1 label=\"Spin\"\nuniform float uDrift; // @control min=0 max=1 default=0.2 label=\"Drift\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uTiles;\n p += uDrift * iTime * vec2(0.13, 0.07);\n vec2 q;\n if (uHex) {\n vec2 s = vec2(1.0, 1.7320508);\n vec4 hc = floor(vec4(p, p - vec2(0.5, 0.866)) / s.xyxy) + 0.5;\n vec4 h = vec4(p - hc.xy * s, p - (hc.zw + vec2(0.5, 0.5)) * s);\n q = dot(h.xy, h.xy) < dot(h.zw, h.zw) ? h.xy : h.zw;\n } else {\n q = fract(p) - 0.5;\n }\n float sector = 6.28318 / float(uFold);\n float a = mod(atan(q.y, q.x) + uSpin * iTime, sector);\n a = min(a, sector - a);\n q = length(q) * vec2(cos(a), sin(a));\n vec2 pan = uDrift * 0.15 * vec2(sin(iTime * 0.21), cos(iTime * 0.17));\n fragColor = pictureRGBA(uImage, 0.5 + pan + q * uZoom);\n}`,\n ),\n presets: [\n { name: \"Hex jewel\", values: { uHex: true, uFold: 6, uTiles: 2.5, uZoom: 0.5 } },\n { name: \"Four-way\", values: { uFold: 4, uTiles: 2, uSpin: 0, uDrift: 0.4 } },\n ],\n};\n\nexport const waveWarp: ShaderEffect = {\n kind: \"shader\",\n id: \"wave-warp\",\n name: \"Wave warp\",\n description: \"A picture rippling in sine waves sideways, up and down or both, like a flag or a reflection on water, with lit crests.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"wave\", \"flag\", \"water\", \"image\"],\n source: glsl(\n `// Wave warp: rows and/or columns of the picture shifted along travelling sine waves.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform bool uRows; // @control default=true label=\"Shift rows sideways\"\nuniform bool uColumns; // @control default=false label=\"Shift columns up and down\"\nuniform float uAmplitude; // @control min=0 max=0.08 default=0.02 label=\"Amplitude\"\nuniform float uFrequency; // @control min=0.5 max=40 default=6 label=\"Waves across\"\nuniform float uSpeed; // @control min=-6 max=6 default=2 label=\"Speed\"\nuniform float uShade; // @control min=0 max=1 default=0.3 label=\"Crest shading\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `float wave(float x) {\n return sin(x) + 0.3 * sin(2.3 * x + 1.0);\n}\nfloat slope(float x) {\n return cos(x) + 0.69 * cos(2.3 * x + 1.0);\n}\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float py = uv.y * uFrequency * 6.28318 - iTime * uSpeed;\n float px = uv.x * uFrequency * 6.28318 - iTime * uSpeed;\n vec2 offset = vec2(uRows ? wave(py) : 0.0, uColumns ? wave(px) : 0.0) * uAmplitude;\n float light = (uRows ? slope(py) : 0.0) + (uColumns ? slope(px) : 0.0);\n vec4 pic = pictureRGBA(uImage, uv + offset);\n float k = uShade * 0.18 * light * clamp(uAmplitude * 40.0, 0.0, 1.0);\n fragColor = vec4(pic.rgb * (1.0 + k) + max(k, 0.0) * 0.4, pic.a);\n}`,\n ),\n presets: [\n { name: \"Flag\", values: { uRows: false, uColumns: true, uAmplitude: 0.03, uFrequency: 2, uSpeed: 3, uShade: 0.8 } },\n { name: \"Reflection\", values: { uRows: true, uColumns: false, uAmplitude: 0.006, uFrequency: 32, uSpeed: 3, uShade: 0.2 } },\n { name: \"Jelly\", values: { uRows: true, uColumns: true, uAmplitude: 0.015, uFrequency: 3, uSpeed: 1.5 } },\n ],\n};\n\nexport const ribbedGlass: ShaderEffect = {\n kind: \"shader\",\n id: \"ribbed-glass\",\n name: \"Ribbed glass\",\n description: \"A picture seen through fluted glass: strips of refracted image with bright and dark rib edges, clear or frosted.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"glass\", \"fluted\", \"reeded\", \"frosted\", \"image\"],\n source: glsl(\n `// Ribbed glass: each rib is a little cylinder lens that flips and squeezes the picture behind it.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uWidth; // @control min=4 max=120 default=28 label=\"Rib width (px)\"\nuniform float uAngle; // @control min=-90 max=90 default=0 label=\"Rib angle (°)\"\nuniform float uRefraction; // @control min=0 max=1 default=0.5 label=\"Refraction\"\nuniform float uFrost; // @control min=0 max=1 default=0.15 label=\"Frost\"\nuniform float uHighlight; // @control min=0 max=1 default=0.4 label=\"Edge highlights\"\nuniform vec3 uTint; // @control color default=#F2F7FA label=\"Glass tint\"\n${BACKDROP_CONTROLS}`,\n HASH,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float a = radians(uAngle);\n vec2 across = vec2(cos(a), sin(a));\n float s = dot(fragCoord - 0.5 * iResolution.xy, across) / uWidth;\n float f = fract(s) - 0.5;\n vec2 bend = -across * f * uWidth * 3.0 * uRefraction;\n // Frost: a small disc of samples, jittered per pixel.\n float blur = uFrost * 14.0;\n float spin = hash12(fragCoord) * 6.28318;\n vec4 acc = vec4(0.0);\n for (int i = 0; i < 9; i++) {\n float fi = float(i);\n float ang = fi * 2.39996 + spin;\n vec2 o = blur * sqrt((fi + 0.5) / 9.0) * vec2(cos(ang), sin(ang));\n acc += pictureRGBA(uImage, (fragCoord + bend + o) / iResolution.xy);\n }\n vec4 pic = acc / 9.0;\n vec3 col = pic.rgb * uTint;\n col = mix(col, vec3(dot(col, vec3(0.299, 0.587, 0.114))) + 0.08, uFrost * 0.2);\n float hi = exp(-pow((f - 0.3) * 12.0, 2.0));\n float lo = smoothstep(0.38, 0.5, abs(f));\n col = col * (1.0 - 0.25 * lo * uHighlight) + hi * uHighlight * 0.35;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Reeded\", values: { uWidth: 14, uRefraction: 0.7, uFrost: 0 } },\n { name: \"Wide flutes\", values: { uWidth: 70, uRefraction: 0.4, uHighlight: 0.6 } },\n { name: \"Frosted diagonal\", values: { uAngle: 30, uFrost: 0.8, uWidth: 36 } },\n ],\n};\n\nexport const showerGlass: ShaderEffect = {\n kind: \"shader\",\n id: \"shower-glass\",\n name: \"Shower glass\",\n description: \"A picture blurred and bent behind textured shower-door glass, pebbled or streaked with rain, catching small highlights.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"glass\", \"privacy\", \"rain\", \"pebble\", \"image\"],\n source: glsl(\n `// Shower glass: a bumpy height field refracts and blurs the picture, lit from the top left.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait2} label=\"Image\"\nuniform bool uRain; // @control default=false label=\"Rain pattern (else pebbled)\"\nuniform float uScale; // @control min=4 max=60 default=16 label=\"Bumps down\"\nuniform float uRefraction; // @control min=0 max=1 default=0.5 label=\"Refraction\"\nuniform float uBlur; // @control min=0 max=1 default=0.35 label=\"Blur\"\nuniform float uDim; // @control min=0 max=1 default=0.15 label=\"Dim\"\nuniform float uHighlight; // @control min=0 max=1 default=0.5 label=\"Highlights\"\nuniform float uFlow; // @control min=0 max=1 default=0.1 label=\"Flow\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `// Round domes on a jittered grid: 1 at a pebble's top, 0 between.\nfloat pebbles(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n float d = 8.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 = 0.15 + 0.7 * hash22(i + g);\n d = min(d, length(g + o - f));\n }\n }\n return 1.0 - smoothstep(0.0, 0.75, d);\n}\nfloat height(vec2 p) {\n float t = iTime * uFlow;\n if (uRain) {\n float streak = vnoise(vec2(p.x * 2.5, p.y * 0.3 + t * 2.0));\n return 0.55 * streak + 0.45 * pebbles(p * 1.7 + vec2(0.0, t * 3.0));\n }\n return pebbles(p + vec2(0.0, t) + 0.3 * vnoise(p * 0.7));\n}\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n float e = 0.03;\n vec2 grad = vec2(height(p + vec2(e, 0.0)) - height(p - vec2(e, 0.0)), height(p + vec2(0.0, e)) - height(p - vec2(0.0, e))) / (2.0 * e);\n vec2 uv = fragCoord / iResolution.xy - grad * uRefraction * 0.02;\n float blur = uBlur * 0.012;\n float spin = hash12(fragCoord) * 6.28318;\n vec4 acc = vec4(0.0);\n for (int i = 0; i < 8; i++) {\n float fi = float(i);\n float ang = fi * 2.39996 + spin;\n acc += pictureRGBA(uImage, uv + blur * sqrt((fi + 0.5) / 8.0) * vec2(cos(ang) * iResolution.y / iResolution.x, sin(ang)));\n }\n vec4 pic = acc / 8.0;\n vec3 n = normalize(vec3(-grad * 0.12, 1.0));\n vec3 h = normalize(normalize(vec3(-0.5, 0.6, 0.6)) + vec3(0.0, 0.0, 1.0));\n float spec = pow(max(dot(n, h), 0.0), 60.0);\n float rim = clamp(dot(n.xy, vec2(-0.6, 0.6)) * 2.0, -1.0, 1.0);\n vec3 col = pic.rgb * (1.0 - uDim) * (1.0 + 0.12 * rim * uHighlight) + spec * uHighlight * 0.8;\n fragColor = vec4(col, pic.a);\n}`,\n ),\n presets: [\n { name: \"Rain door\", values: { uRain: true, uScale: 10, uFlow: 0.3, uBlur: 0.3 } },\n { name: \"Privacy\", values: { uScale: 28, uRefraction: 0.8, uBlur: 0.9, uDim: 0.25 } },\n ],\n};\n\nexport const datamosh: ShaderEffect = {\n kind: \"shader\",\n id: \"datamosh\",\n name: \"Datamosh\",\n description: \"A picture breaking down like a corrupted video stream in bursts: macroblocks smear along a false motion field, stick in the wrong place and bleed colour.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"datamosh\", \"glitch\", \"compression\", \"image\"],\n source: glsl(\n `// Datamosh: block motion vectors applied to a stale frame, stuck blocks and smeared chroma, in bursts.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform float uBlock; // @control min=8 max=64 default=24 step=1 label=\"Macroblock (px)\"\nuniform float uAmount; // @control min=0 max=1 default=0.6 label=\"Amount\"\nuniform float uSmear; // @control min=0 max=0.4 default=0.12 label=\"Smear length\"\nuniform float uRate; // @control min=0.2 max=4 default=0.8 label=\"Bursts per second\"\nuniform float uBleed; // @control min=0 max=1 default=0.6 label=\"Colour bleed\"\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 t = iTime * uRate;\n float epoch = floor(t);\n float ph = fract(t);\n float on = step(1.0 - uAmount * 0.85, hash12(vec2(epoch, 7.0))) * smoothstep(0.0, 0.08, ph);\n vec2 block = floor(fragCoord / uBlock);\n // One motion vector per macroblock, from a smooth field that changes each burst.\n vec2 field = block * 0.12 + epoch * vec2(3.1, 1.7);\n vec2 mv = vec2(vnoise(field), vnoise(field + 9.7)) * 2.0 - 1.0;\n vec2 disp = mv * uSmear * ph * on * vec2(iResolution.y / iResolution.x, 1.0);\n // Stuck blocks: content from the wrong place, sliding slowly.\n vec2 bh = hash22(block + epoch * 13.0);\n float stuck = on * step(1.0 - 0.3 * uAmount, bh.x);\n vec2 wrong = (floor(bh * 6.0) - 2.5) * uBlock / iResolution.xy;\n vec2 st = uv + stuck * (wrong + mv * 0.02 * ph);\n // Smear: samples along the motion, weighted towards the oldest.\n vec4 acc = vec4(0.0);\n float wsum = 0.0;\n for (int i = 0; i < 6; i++) {\n float k = float(i) / 5.0;\n float w = 0.4 + k;\n acc += w * pictureRGBA(uImage, st - disp * k);\n wsum += w;\n }\n vec4 pic = acc / wsum;\n // Bleed: chroma from the block's corner, dragged further along the motion.\n vec2 chromaUV = (block * uBlock + 0.5) / iResolution.xy - disp * 1.6;\n vec3 smeared = picture(uImage, chromaUV);\n float y = dot(pic.rgb, vec3(0.299, 0.587, 0.114));\n vec3 chroma = mix(pic.rgb - y, smeared - dot(smeared, vec3(0.299, 0.587, 0.114)), uBleed * on);\n vec3 col = y + chroma * (1.0 + 0.4 * on * uBleed);\n // A faint block grid where the stream is broken.\n vec2 edge = abs(fract(fragCoord / uBlock) - 0.5);\n col *= 1.0 - 0.06 * on * step(0.47, max(edge.x, edge.y));\n fragColor = vec4(clamp(col, 0.0, 1.0), pic.a);\n}`,\n ),\n presets: [\n { name: \"Melted stream\", values: { uAmount: 1, uSmear: 0.3, uRate: 0.4, uBleed: 1 } },\n { name: \"Hiccup\", values: { uAmount: 0.4, uSmear: 0.05, uRate: 2.5, uBlock: 16 } },\n ],\n};\n\nexport const polarWarp: ShaderEffect = {\n kind: \"shader\",\n id: \"polar-warp\",\n name: \"Polar warp\",\n description: \"A picture wrapped into a circle, as a tiny planet or a tunnel, or a circle unrolled into a strip, slowly turning.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"polar\", \"tiny-planet\", \"tunnel\", \"image\"],\n source: glsl(\n `// Polar warp: rectangular → polar (the picture's bottom edge at the centre), or polar → rectangular.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform bool uUnwrap; // @control default=false label=\"Unwrap (polar → rectangular)\"\nuniform bool uInsideOut; // @control default=false label=\"Inside out (tunnel)\"\nuniform float uZoom; // @control min=0.3 max=3 default=1 label=\"Zoom\"\nuniform float uSpin; // @control min=-0.5 max=0.5 default=0.04 label=\"Spin (turns/s)\"\nuniform float uTwist; // @control min=-2 max=2 default=0 label=\"Twist\"\n${BACKDROP_CONTROLS}`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 st;\n if (uUnwrap) {\n // Across is the angle, up is the radius of the circle inscribed in the picture.\n float r = (uInsideOut ? 1.0 - uv.y : uv.y) * 0.5 / uZoom;\n float a = (uv.x + iTime * uSpin + uTwist * r) * 6.28318;\n st = 0.5 + r * vec2(cos(a), sin(a));\n } else {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float r = length(p) * 2.0 / uZoom;\n // The angle runs across the picture and back, so the seam is a mirror and does not show.\n float u = fract(atan(p.y, p.x) / 6.28318 + iTime * uSpin + uTwist * r * 0.25);\n u = 1.0 - abs(1.0 - 2.0 * u);\n float v = uInsideOut ? 1.0 - min(r, 1.0) : min(r, 1.0);\n st = vec2(u, v);\n }\n fragColor = pictureRGBA(uImage, st);\n}`,\n ),\n presets: [\n { name: \"Tiny planet\", values: { uUnwrap: false, uInsideOut: false, uZoom: 1.1, uSpin: 0.03 } },\n { name: \"Tunnel\", values: { uUnwrap: false, uInsideOut: true, uZoom: 0.9, uSpin: -0.05, uTwist: 0.8 } },\n { name: \"Unrolled\", values: { uUnwrap: true, uZoom: 1, uSpin: 0.02 } },\n ],\n};\n\nexport const textureDisplace: ShaderEffect = {\n kind: \"shader\",\n id: \"texture-displace\",\n name: \"Texture displace\",\n description: \"A picture pushed around by a second, scrolling texture, by its red and green or by its light and shade.\",\n category: \"distortion\",\n video: \"filter\",\n tags: [\"distortion\", \"displacement\", \"map\", \"image\"],\n source: glsl(\n `// Texture displace: each pixel moved by a displacement map (or its brightness slope) that scrolls.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform sampler2D uMap; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Displacement map\"\nuniform float uStrength; // @control min=0 max=0.2 default=0.06 label=\"Strength\"\nuniform float uScale; // @control min=0.2 max=4 default=1.5 label=\"Map scale\"\nuniform vec2 uScroll; // @control min=-0.3 max=0.3 default=0.03,0.02 label=\"Scroll\"\nuniform bool uSlope; // @control default=false label=\"Push by brightness slope (else by red/green)\"\n${BACKDROP_CONTROLS}`,\n HASH,\n NOISE,\n PICTURE,\n `// The map, or soft noise while there is none (an empty image control is a 1 × 1 placeholder).\nvec3 mapAt(vec2 p) {\n if (textureSize(uMap, 0).x > 1) return texture(uMap, p).rgb;\n return vec3(vnoise(p * 6.0), vnoise(p * 6.0 + 11.3), vnoise(p * 6.0 + 23.1));\n}\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 m = uv * uScale + uScroll * iTime;\n vec2 offset;\n if (uSlope) {\n float e = 0.03;\n vec3 w = vec3(0.299, 0.587, 0.114);\n float dx = dot(mapAt(m + vec2(e, 0.0)) - mapAt(m - vec2(e, 0.0)), w);\n float dy = dot(mapAt(m + vec2(0.0, e)) - mapAt(m - vec2(0.0, e)), w);\n offset = vec2(dx, dy) / (2.0 * e) * uStrength * 0.1;\n } else {\n offset = (mapAt(m).rg - 0.5) * 2.0 * uStrength;\n }\n fragColor = pictureRGBA(uImage, uv + offset);\n}`,\n ),\n presets: [\n { name: \"Embossed\", values: { uSlope: true, uStrength: 0.08, uScale: 1, uScroll: [0, 0] } },\n { name: \"Drifting channels\", values: { uSlope: false, uStrength: 0.03, uScale: 2, uScroll: [0.05, -0.04] } },\n ],\n};\n\n/** Distortions: swirls, bulges, lenses, mirrors, waves and glass over a picture. */\nexport const distortionShaders: ShaderEffect[] = [\n twirl,\n pinchBulge,\n fisheye,\n mirrorTiles,\n waveWarp,\n ribbedGlass,\n showerGlass,\n datamosh,\n polarWarp,\n textureDisplace,\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 | \"splatter\"\n | \"bubble\"\n | \"sticker\"\n | \"trail\"\n | \"particles\"\n | \"debris\"\n | \"impact\"\n | \"comic\"\n | \"atmosphere\"\n | \"glow\"\n | \"shadow\"\n | \"distortion\"\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 \"splatter\",\n \"bubble\",\n \"sticker\",\n \"trail\",\n \"particles\",\n \"debris\",\n \"impact\",\n \"comic\",\n \"atmosphere\",\n \"glow\",\n \"shadow\",\n \"distortion\",\n \"transition\",\n \"loader\",\n \"data\",\n \"icon\",\n];\n\n/**\n * How a shader effect suits video in its image controls (see\n * `ShaderRenderer.setLiveSource`):\n *\n * - `filter`: it treats each frame on its own, so it works as a live video filter.\n * - `transition`: it blends two pictures, so it works between two clips.\n * - `interactive`: it reacts to the pointer over a picture, and works as well over video.\n * - `stills`: it runs on video but is made for a still picture: it moves the\n * picture to fake motion of its own, or needs shapes or features in fixed places.\n * - `none`: its pictures are not photos (rendered text, a silhouette mask), so video has no place in it.\n */\nexport type VideoUse = \"filter\" | \"transition\" | \"interactive\" | \"stills\" | \"none\";\n\n/** Every {@link VideoUse}, best suited to video first. */\nexport const VIDEO_USES: readonly VideoUse[] = [\"filter\", \"transition\", \"interactive\", \"stills\", \"none\"];\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 * How it suits video in its image controls. Every effect with an image\n * control says; effects without one have nothing to show video in.\n */\n video?: VideoUse;\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 * - Video: shader effects with image controls say how they suit video\n * (`video`, see `VideoUse`); `findEffects({ video: [\"filter\"] })` finds them.\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 { splatterEffects } from \"./splatter.js\";\nimport { bubbleEffects } from \"./bubble.js\";\nimport { stickerEffects } from \"./sticker.js\";\nimport { trailEffects } from \"./trail.js\";\nimport { impactEffects } from \"./impact.js\";\nimport { comicEffects } from \"./comic.js\";\nimport { glowEffects } from \"./glow.js\";\nimport { shadowEffects } from \"./shadow.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 { splatterShaders } from \"./shaders/splatter.js\";\nimport { bubbleShaders } from \"./shaders/bubble.js\";\nimport { growthShaders } from \"./shaders/growth.js\";\nimport { stickerShaders } from \"./shaders/sticker.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 { trailShaders } from \"./shaders/trail.js\";\nimport { particlesShaders } from \"./shaders/particles.js\";\nimport { debrisShaders } from \"./shaders/debris.js\";\nimport { impactShaders } from \"./shaders/impact.js\";\nimport { comicShaders } from \"./shaders/comic.js\";\nimport { atmosphereShaders } from \"./shaders/atmosphere.js\";\nimport { glowShaders } from \"./shaders/glow.js\";\nimport { shadowShaders } from \"./shaders/shadow.js\";\nimport { distortionShaders } from \"./shaders/distortion.js\";\nimport { textEffects } from \"./text.js\";\nimport { CURRENT_COLOR, EFFECT_CATEGORIES, isCurrentColor, vectorEffectControls, type EffectCategory, type EffectDefinition, type ShaderEffect, type VideoUse } 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 VIDEO_USES,\n type EffectCategory,\n type EffectDefinition,\n type EffectPreset,\n type ShaderEffect,\n type VectorControl,\n type VectorEffect,\n type VideoUse,\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 ...splatterShaders,\n ...bubbleShaders,\n ...growthShaders,\n ...stickerShaders,\n ...trailShaders,\n ...particlesShaders,\n ...debrisShaders,\n ...impactShaders,\n ...comicShaders,\n ...atmosphereShaders,\n ...glowShaders,\n ...shadowShaders,\n ...distortionShaders,\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, ...splatterEffects, ...bubbleEffects, ...stickerEffects, ...trailEffects, ...impactEffects, ...comicEffects, ...glowEffects, ...shadowEffects].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 /** Effects that suit video in one of these ways (shader effects with image controls only). */\n video?: readonly VideoUse[];\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 if (query.video && !(e.kind === \"shader\" && e.video && query.video.includes(e.video))) 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,OAAO;AAAA,EACP,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,OAAO;AAAA,EACP,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,OAAO;AAAA,EACP,MAAM,CAAC,SAAS,SAAS,aAAa,QAAQ;AAAA,EAC9C,QAAQ;AAAA,IACN;AAAA,0EACsE,cAAc,SAAS;AAAA;AAAA;AAAA;AAAA,EAI/F,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOF;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,OAAO;AAAA,EACP,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,OAAO;AAAA,EACP,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,OAAO;AAAA,EACP,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,OAAO;AAAA,EACP,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,OAAO;AAAA,EACP,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;;;ACpUK,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;;;AChlBA,IAAMC,MAAK,CAAC,MAAc;AACxB,QAAM,IAAI,KAAK,MAAM,IAAI,GAAG,IAAI;AAChC,SAAO,OAAO,GAAG,GAAG,EAAE,IAAI,IAAI;AAChC;AAGA,IAAMC,KAAI,CAAC,SAAiB,KAAK,IAAI;AAGrC,SAAS,OAAO,MAA4B;AAC1C,MAAI,IAAK,OAAO,eAAgB;AAChC,SAAO,MAAM;AACX,QAAK,IAAI,eAAgB;AACzB,QAAI,IAAI;AACR,QAAI,KAAK,KAAK,IAAK,MAAM,IAAK,IAAI,CAAC;AACnC,SAAK,IAAI,KAAK,KAAK,IAAK,MAAM,GAAI,IAAI,EAAE;AACxC,aAAS,IAAK,MAAM,QAAS,KAAK;AAAA,EACpC;AACF;AAEA,IAAM,WAAW,CAAC,QAA0B,IAAI,IAAI,IAAI,CAAC,MAAM,GAAGD,IAAG,EAAE,CAAC,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAEpG,IAAM,KAAK;AACX,IAAM,KAAK;AACX,IAAM,QAAQ;AACd,IAAM,SAAS;AAaf,SAAS,UAAU,MAAc,MAAqB;AACpD,QAAM,MAAM,OAAO,OAAO,CAAC;AAC3B,QAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,GAAG,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,IAAI,MAAM,GAAG,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE;AACzH,QAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,KAAK,KAAK,GAAG,KAAK,OAAO,IAAI,IAAI,MAAM,GAAG,OAAO,IAAI,IAAI,KAAK,EAAE;AACtJ,QAAM,SAAS,CAAC,MAAc;AAC5B,QAAI,IAAI;AACR,eAAW,KAAK,MAAO,MAAK,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;AACxD,eAAWE,MAAK,QAAQ;AACtB,YAAMC,KAAI,KAAK,MAAM,KAAK,IAAI,IAAID,GAAE,EAAE,GAAG,KAAK,IAAI,IAAIA,GAAE,EAAE,CAAC;AAC3D,WAAKA,GAAE,MAAM,KAAK,IAAI,EAAEC,KAAIA,OAAMD,GAAE,IAAIA,GAAE,EAAE;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,CAAC,UACb;AAAA,IACE,MAAM,KAAK,EAAE,QAAQ,OAAO,GAAG,CAAC,GAAG,MAAa;AAC9C,YAAM,IAAK,IAAI,SAAU,KAAK,KAAK;AACnC,YAAM,IAAI,OAAO,CAAC,IAAI,OAAO;AAC7B,aAAO,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAAA,IACpD,CAAC;AAAA,EACH;AACF,QAAM,OAAO,OAAO;AACpB,QAAM,MAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,OAAO,GAAG,CAAC,GAAG,MAAa,CAAC,KAAK,OAAO,KAAK,IAAK,IAAI,SAAU,KAAK,KAAK,CAAC,GAAG,KAAK,OAAO,KAAK,IAAK,IAAI,SAAU,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1K,QAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM;AACpD,UAAM,KAAM,IAAI,MAAM,IAAI,IAAI,OAAO,QAAS,KAAK,KAAK;AACxD,UAAMC,KAAI,QAAQ,OAAO,IAAI,IAAI;AACjC,WAAO,EAAE,GAAGH,IAAG,KAAKG,KAAI,KAAK,IAAI,CAAC,CAAC,GAAG,GAAGH,IAAG,KAAKG,KAAI,KAAK,IAAI,CAAC,CAAC,GAAG,GAAGH,IAAG,QAAQ,OAAO,IAAI,IAAI,IAAI,EAAE;AAAA,EACxG,CAAC;AACD,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI,cAAc,CAAC,KAAK,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,QAAQ,OAAO,CAAC;AAChF,SAAO,EAAE,KAAK,GAAI,MAAM,GAAI,SAAS,GAAI,MAAM;AACjD;AAEA,IAAM,SAAS,oBAAI,IAAmB;AAGtC,SAAS,SAAS,QAA6C;AAC7D,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,OAAO,KAAK,CAAC,KAAK,CAAC;AAC9D,QAAM,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,OAAO,IAAI,KAAK,EAAE,CAAC;AACjE,QAAM,MAAM,GAAG,IAAI,IAAI,IAAI;AAC3B,MAAI,CAAC,OAAO,IAAI,GAAG,EAAG,QAAO,IAAI,KAAK,UAAU,MAAM,IAAI,CAAC;AAC3D,SAAO,OAAO,IAAI,GAAG;AACvB;AAGA,IAAM,MAAM;AACZ,IAAM,SAAS;AAER,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,YAAY,SAAS,SAAS,SAAS,WAAW,mBAAmB;AAAA,EAC5E,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,OAAO,QAAQ,EAAE,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE;AAAA,IACjG,EAAE,MAAM,QAAQ,QAAQ,EAAE,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,KAAK,IAAI,GAAG,OAAO,EAAE,EAAE;AAAA,IAC5F,EAAE,MAAM,YAAY,QAAQ,EAAE,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,YAAY,CAAC,GAAG,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,EAAE,EAAE;AAAA,EAC1G;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,IAAI,SAAS,CAAC;AACpB,UAAM,MAAuC,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,SAAS,OAAO,EAAE,UAAU,QAAQ,IAAI,KAAK;AACtH,UAAM,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,EAAE,IAAI,KAAK,EAAE,CAAC;AAC5D,WAAO,OAAO,KAAK,EAAE,IAAIA,IAAG,KAAK,OAAO,IAAI,GAAG,KAAKA,IAAG,OAAO,IAAI,GAAG,KAAKA,IAAG,OAAO,IAAI,EAAE,CAAC;AAC3F,MAAE,MAAM,QAAQ,CAAC,GAAG,MAAM;AACxB,UAAI,IAAI,CAAC,EAAE,IAAI,EAAE;AACjB,UAAI,IAAI,CAAC,EAAE,IAAI,EAAE;AACjB,UAAI,IAAI,CAAC,EAAE,IAAI,EAAE;AACjB,UAAI,KAAK,CAAC,EAAE,IAAIA,IAAG,EAAE,IAAI,IAAI;AAC7B,UAAI,KAAK,CAAC,EAAE,IAAIA,IAAG,MAAM,EAAE,IAAI,MAAM,IAAI;AACzC,UAAI,KAAK,CAAC,EAAE,IAAIA,IAAG,MAAM,EAAE,IAAI,MAAM,IAAI;AAAA,IAC3C,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,oiBAAoiB,MAAM;AAAA,MAC7iB,EAAE,QAAQ,MAAM;AAAA,MAChB,CAAC,GAAG,MAAM,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE;AAAA,IACtD,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS;AAAA,MACP,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,SAAS,OAAO,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MAClF,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,SAAS,OAAO,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACrF,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAGC,GAAE,OAAO,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACrF,GAAG,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAsB;AACzD,cAAMG,MAAK,MAAM,IAAI;AACrB,eAAO;AAAA,UACL,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,IAAI,CAAC,IAAIH,GAAE,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAIA,GAAE,KAAK,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,GAAGA,GAAE,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,OAAOG,KAAI,IAAI,KAAK,MAAM,MAAM;AAAA,UAChI,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,IAAI,CAACH,GAAE,KAAK,CAAC,EAAE,GAAGA,GAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAACA,GAAE,KAAK,CAAC,EAAE,GAAGA,GAAE,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAACA,GAAE,KAAK,CAAC,EAAE,GAAGA,GAAE,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,OAAOG,MAAK,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,UAC/J,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,IAAI,CAACH,GAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAACA,GAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,GAAG,CAACA,GAAE,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,OAAO,SAAS,KAAM,IAAI,KAAK,MAAM,SAAS;AAAA,QAC7I;AAAA,MACF,CAAC,EAAE,KAAK;AAAA,MACR,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAACA,GAAE,OAAO,GAAG,CAAC,EAAE,GAAG,OAAO,SAAS,KAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAClG,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,SAAS,OAAO,EAAE,GAAG,OAAO,SAAS,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,IACjG;AAAA,EACF;AACF;AAGO,IAAM,kBAAkC,CAAC,UAAU;;;AClJ1D,IAAMI,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAC/C,IAAMC,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAGhD,IAAMC,KAAI,CAAC,SAAiB,KAAK,IAAI;AAGrC,IAAMC,SAAQ,CAAC,IAAY,IAAY,MAAc,aAAaH,IAAG,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC,WAAWC,IAAG,CAAC,CAAC,eAAeD,IAAG,CAAC,EAAE,CAAC,IAAIA,IAAG,CAAC,EAAE,CAAC;AAGnI,IAAMI,QAAO,CAAC,IAAY,MAAc,OAAwB,WAAiC,EAAE,IAAI,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,EAAE,GAAG,OAAO,IAAI,EAAE;AAEvJ,IAAMC,QAAO;AAGb,IAAM,QAAQ;AACd,IAAM,MAAM;AACZ,IAAM,UAAU;AAEhB,IAAM,UAAU;AAChB,IAAM,YAAY;AAClB,IAAM,OAAO;AAEN,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,UAAU,QAAQ,WAAW,MAAM,UAAU,UAAU,MAAM;AAAA,EACpE,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,IACvE,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACxI,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,wBAAiB,MAAM,GAAG,EAAE;AAAA,EAC/D;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,OAAO,OAAO,EAAE,IAAI;AAC1B,UAAM,IAAI,KAAK,IAAI,KAAK,YAAY,IAAI,CAAC;AACzC,UAAM,OAAOL,IAAG,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC;AACrC,UAAM,QAAQA,IAAG,KAAK,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;AAC5C,UAAM,SAASA,IAAG,OAAO,EAAE;AAC3B,UAAM,OAAOA,IAAG,QAAQ,KAAK;AAC7B,UAAM,SAASA,IAAG,MAAM,MAAM;AAC9B,UAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,KAAK,IAAI,EAAE,SAAS,OAAO,EAAE,IAAI,CAAC,CAAC;AAC/E,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,WAAWA,IAAG,SAAS,EAAE;AAC/B,UAAM,cAAcA,IAAG,WAAW,EAAE;AACpC,UAAM,OAAOA,IAAG,WAAW,EAAE;AAC7B,UAAM,OAAO,CAAC,MAAcG,OAAM,OAAO,QAAQ,CAAC;AAClD,UAAM,OAAO,CAAC,MAAcA,OAAM,SAAS,aAAa,CAAC;AACzD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAOH,IAAG,OAAO,EAAE;AAAA,MACnB,OAAOA,IAAG,MAAM,SAAS,IAAI,OAAO,IAAI;AAAA,MACxC,IAAIA,IAAG,KAAK,IAAI,SAAS,GAAG,EAAE,CAAC;AAAA,MAC/B,MAAM,IAAIA,IAAG,QAAQ,EAAE,CAAC,IAAIA,IAAG,SAAS,EAAE,CAAC,KAAKA,IAAG,QAAQ,EAAE,CAAC,IAAIA,IAAG,SAAS,CAAC,CAAC,IAAIA,IAAG,QAAQ,CAAC,CAAC,IAAIA,IAAG,SAAS,CAAC,CAAC,IAAIA,IAAG,QAAQ,CAAC,CAAC,IAAIA,IAAG,SAAS,CAAC,CAAC,KAAKA,IAAG,QAAQ,CAAC,CAAC,IAAIA,IAAG,SAAS,CAAC,CAAC,IAAIA,IAAG,QAAQ,CAAC,CAAC,IAAIA,IAAG,SAAS,CAAC,CAAC,IAAIA,IAAG,QAAQ,CAAC,CAAC,IAAIA,IAAG,SAAS,EAAE,CAAC;AAAA,MACjQ;AAAA,MACA,WAAW,IAAI,UAAU,EAAE,IAAIA,IAAG,cAAc,EAAE,CAAC,KAAK,UAAU,EAAE,IAAIA,IAAG,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,IAAIA,IAAG,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,IAAIA,IAAG,cAAc,CAAC,CAAC,KAAK,UAAU,CAAC,IAAIA,IAAG,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,IAAIA,IAAG,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,IAAIA,IAAG,cAAc,EAAE,CAAC;AAAA,MAC3R;AAAA,MACA,OAAOA,IAAG,OAAO,CAAC;AAAA,MAClB;AAAA,MACA,OAAO,KAAK,CAAC;AAAA,MACb,OAAO,KAAK,CAAC;AAAA,MACb,UAAU,KAAK,IAAI;AAAA,MACnB,WAAW,KAAK,IAAI;AAAA,MACpB,QAAQ,KAAK,CAAC;AAAA,MACd,QAAQ,KAAK,CAAC;AAAA,MACd,WAAW,KAAK,IAAI;AAAA,MACpB,YAAY,KAAK,IAAI;AAAA,MACrB,GAAG,OAAO,YAAY,CAAC,GAAG,KAAK,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;AAAA,MAC1E,GAAG,OAAO;AAAA,QACR,MAAM,KAAK,EAAE,QAAQ,UAAU,KAAK,GAAG,CAAC,GAAG,MAAM;AAC/C,gBAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,MAAM,IAAI,IAAI,GAAG,IAAI,IAAI;AAC9C,gBAAMM,MAAK,QAAQ,MAAM,IAAI,YAAY,IAAI;AAC7C,iBAAO;AAAA,YACL,CAAC,OAAO,CAAC,IAAI,CAAC,IAAIA,GAAE;AAAA,YACpB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAIA,MAAK,GAAG;AAAA,UAC5B;AAAA,QACF,CAAC,EAAE,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,olBAAolB,GAAG,kIAAkID,KAAI,2LAA2L,OAAO,uEAAuE,MAAM;AAAA,MAC/+B,EAAE,QAAQ,KAAK;AAAA,MACf,CAAC,GAAG,MAAM,kBAAkB,CAAC,SAAS,UAAU,KAAK,IAAI,EAAE;AAAA,IAC7D,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS;AAAA,MACP,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,aAAa,cAAc,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACxF,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,gBAAgB,eAAe,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC3G,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,iBAAiB,WAAW,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACxG,EAAE,IAAI,OAAO,OAAO,YAAY,OAAO,KAAK,IAAIH,GAAE,QAAQ,GAAG,MAAM,SAAS;AAAA,MAC5E,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,cAAc,eAAe,EAAE,GAAG,OAAOA,GAAE,UAAU,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACjH,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,iBAAiB,gBAAgB,EAAE,GAAG,OAAOA,GAAE,YAAY,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1H,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,kBAAkB,YAAY,EAAE,GAAG,OAAOA,GAAE,YAAY,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAEvH,GAAG,MAAM,KAAK,EAAE,QAAQ,UAAU,KAAK,GAAG,CAAC,GAAG,MAAsB;AAClE,cAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,MAAM,IAAI,IAAI,GAAG,IAAI,IAAI;AAC9C,cAAM,KAAK,MAAM,CAAC;AAClB,eAAO;AAAA,UACL,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,YAAY,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,OAAOA,GAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,UACpH,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,aAAa,UAAU,GAAG,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,OAAOA,GAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,QACzH;AAAA,MACF,CAAC,EAAE,KAAK;AAAA,IACV;AAAA,EACF;AACF;AAGA,IAAM,WAAW,CAAC,IAAI,IAAI,KAAK,GAAG;AAClC,IAAM,WAAW;AACjB,IAAM,WAAW;AACjB,IAAMK,SAAQ;AACd,IAAM,iBAAiB;AACvB,IAAM,SAAS;AACf,IAAM,cAAc,SAAS,SAAS,KAAK,iBAAiB,SAAS;AAE9D,IAAM,kBAAgC;AAAA,EAC3C,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,UAAU,UAAU,WAAW,WAAW,MAAM,SAAS;AAAA,EAChE,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IAChF,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC,GAAG,MAAM,IAAI,EAAE,EAAE;AAAA,IAC3G,EAAE,MAAM,SAAS,QAAQ,EAAE,OAAO,CAAC,GAAG,KAAK,IAAI,GAAG,QAAQ,CAAC,GAAG,KAAK,GAAG,GAAG,OAAO,EAAE,EAAE;AAAA,EACtF;AAAA,EACA,SAAS,MAAM;AACb,UAAM,OAAO,CAAC,GAAW,GAAW,MAAc;AAChD,YAAM,KAAM,IAAI,OAAOA,SAAS,KAAK,KAAK;AAC1C,aAAO,CAACP,IAAG,SAAS,CAAC,IAAK,IAAI,KAAK,IAAI,CAAC,CAAC,GAAGA,IAAG,WAAW,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AAAA,IAC5E;AACA,UAAMQ,QAAO,CAAC,MAAc,CAAC,MAAcL,OAAM,SAAS,CAAC,GAAI,UAAU,CAAC;AAC1E,UAAM,UAAU,SAAS;AAAA,MACvB,CAAC,GAAG,MACF,mBAAmB,CAAC,SAAS,CAAC,SAAS,QAAQ,QAAQ,QAAQ,sDAAsD,MAAM,KAAK,EAAE,QAAQI,OAAM,GAAG,CAAC,GAAG,MAAM;AAC3J,cAAM,CAAC,IAAI,EAAE,IAAI,KAAK,GAAG,GAAG,QAAQ;AACpC,eAAO,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,iBAAiB,IAAI,IAAI,eAAe,WAAW;AAAA,MACxG,CAAC,EAAE;AAAA,QACD;AAAA,MACF,CAAC,WAAW,CAAC,gBAAgBC,MAAK,CAAC,EAAE,CAAC,CAAC,iBAAiB,CAAC,SAAS,QAAQ,QAAQ,QAAQ,oGAAoG,IAAI,CAAC,SAAS,WAAW,CAAC,yEAAyE,IAAI,CAAC,IAAI,WAAW,CAAC;AAAA,IAC1T,EAAE,KAAK,EAAE;AACT,WAAO;AAAA,MACL,KAAK,uTAAuT,OAAO;AAAA,MACnU,SAAS,SAAS,QAAQ,CAAC,GAAG,MAAsB;AAClD,cAAM,KAAK,IAAI;AACf,cAAM,MAAM,KAAK;AACjB,cAAM,IAAIA,MAAK,CAAC;AAChB,eAAO;AAAA;AAAA,UAEL,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,UACrF,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,UACjG,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,UAC/F,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI,MAAM,MAAM;AAAA,UACvGJ,MAAK,OAAO,CAAC,IAAI,gBAAgB,GAAG,CAAC;AAAA,UACrC,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC,UAAU,WAAW,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,UACnH,GAAG,MAAM,KAAK,EAAE,QAAQG,OAAM,GAAG,CAACE,IAAG,MAAsB;AACzD,kBAAM,CAAC,IAAI,EAAE,IAAI,KAAK,GAAG,GAAG,QAAQ;AACpC,kBAAM,CAAC,IAAI,EAAE,IAAI,KAAK,GAAG,GAAG,WAAW,GAAG;AAC1C,mBAAO;AAAA,cACLL,MAAK,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC;AAAA,cAC5B,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAIJ,IAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,cAC/GI,MAAK,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,IAAI,UAAU;AAAA,cACvCA,MAAK,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,IAAI,UAAU;AAAA,YACzC;AAAA,UACF,CAAC,EAAE,KAAK;AAAA;AAAA,UAERA,MAAK,OAAO,CAAC,IAAI,KAAK,UAAU,UAAU;AAAA,UAC1CA,MAAK,IAAI,CAAC,IAAI,aAAa,EAAE,CAAC,GAAG,UAAU;AAAA,UAC3CA,MAAK,IAAI,CAAC,IAAI,WAAW,GAAG,UAAU;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,GAAG;AACL;AAGO,IAAM,gBAAgC,CAAC,YAAY,eAAe;;;ACjLzE,IAAMM,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAC/C,IAAMC,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAGhD,IAAMC,KAAI,CAAC,SAAiB,KAAK,IAAI;AAErC,IAAM,QAAQ;AAGd,IAAM,OAAO,yBAAyB,KAAK;AAG3C,SAASC,KAAI,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,MAAMH,IAAG,IAAI,GAAG,QAAQA,IAAG,IAAI,IAAI,EAAE;AAChD;AAKA,IAAM,UAAU,CAAC,WAA6B,IAAI,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAGA,IAAG,CAAC,CAAC,IAAIA,IAAG,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAGxG,SAAS,MAAM,IAAY,IAAY,GAAW,QAAQ,IAAI,QAAQ,MAAc;AAClF,SAAO;AAAA,IACL,MAAM,KAAK,EAAE,QAAQ,IAAI,GAAG,CAAC,GAAG,MAAM;AACpC,YAAM,IAAK,IAAI,MAAO,KAAK,KAAK;AAChC,YAAM,KAAK,KAAK,IAAI,QAAQ,QAAQ,KAAK,IAAI,IAAI,KAAK;AACtD,aAAO,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,IACtD,CAAC;AAAA,EACH;AACF;AAGA,SAAS,KAAK,IAAY,IAAY,GAAW,OAAe,SAAS,GAAW;AAClF,SAAO;AAAA,IACL,MAAM,KAAK,EAAE,QAAQ,SAAS,EAAE,GAAG,CAAC,GAAG,MAAM;AAC3C,YAAM,IAAI,CAAC,KAAK,KAAK,IAAK,IAAI,KAAK,KAAM;AACzC,YAAM,KAAK,IAAI,IAAI,QAAQ;AAC3B,aAAO,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,IACtD,CAAC;AAAA,EACH;AACF;AAGA,IAAMI,SAAQ;AAGd,SAAS,MAAM,IAAY,IAAY,MAAsB;AAC3D,QAAM,IAAI,OAAO;AACjB,MAAI,IAAI;AACR,SAAOA,OAAM,QAAQ,oBAAoB,CAAC,MAAM,OAAOJ,IAAG,MAAM,MAAM,IAAI,MAAM,OAAO,CAAC,IAAI,MAAM,IAAI,MAAM,OAAO,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;AACrI;AAGA,IAAM,SAAS,CAAC,IAAY,IAAY,MAAc,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,EAAE;AAGxI,SAAS,KAAK,IAAY,IAAY,MAAsB;AAC1D,QAAM,IAAI,OAAO;AACjB,QAAM,MAAe,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;AAC1F,SAAO,QAAQ,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,CAAU,CAAC;AACvE;AAOA,SAAS,aAAa,OAAgB,IAAY,IAAY,GAAW;AACvE,UAAQ,KAAK,MAAM,OAAO,KAAK,CAAC,GAAG;AAAA,IACjC,KAAK;AACH,aAAO,EAAE,GAAG,MAAM,IAAI,IAAI,IAAI,IAAI,GAAG,QAAQ,KAAK,IAAI,MAAM,QAAQ,IAAI,KAAK;AAAA,IAC/E,KAAK;AACH,aAAO,EAAE,GAAG,KAAK,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,GAAG,QAAQ,KAAK,IAAI,MAAM,QAAQ,IAAI,KAAK;AAAA,IACxF,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,IAAI,GAAG,QAAQ,IAAI,QAAQ,IAAI,IAAI;AAAA,IACpE;AACE,aAAO,EAAE,GAAG,MAAM,IAAI,IAAI,CAAC,GAAG,QAAQ,IAAI,QAAQ,IAAI,KAAK;AAAA,EAC/D;AACF;AAEA,IAAM,gBAAgB;AAGtB,IAAM,QAAQ,CAAC,OAAe,uBAAuB,EAAE;AAGvD,IAAM,OAAO,CAAC,IAAY,IAAY,GAAW,GAAW,KAAK,GAAG,KAAK,MACvE,aAAa,EAAE,IAAIA,IAAG,KAAK,EAAE,CAAC,YAAYA,IAAG,CAAC,CAAC,WAAWC,IAAG,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,EAAE;AAGpG,IAAMI,QAAO,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;AAKA,IAAM,OAA+E;AAAA,EACnF,CAAC,GAAG,GAAG,IAAI,GAAG,MAAM,CAAC;AAAA,EACrB,CAAC,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;AAAA;AAAA,EAExB,CAAC,KAAK,KAAK,IAAI,IAAI,MAAM,EAAE;AAAA,EAC3B,CAAC,KAAK,KAAK,KAAK,GAAG,MAAM,CAAC;AAAA,EAC1B,CAAC,KAAK,MAAM,IAAI,GAAG,MAAM,GAAG;AAAA,EAC5B,CAAC,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AACzB;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,eAAe,WAAW,SAAS,SAAS,MAAM;AAAA,EAC7E,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,eAAe,QAAQ,EAAE,OAAO,GAAG,OAAO,OAAO,SAAS,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,IACvG,EAAE,MAAM,aAAa,QAAQ,EAAE,OAAO,GAAG,OAAO,OAAO,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IAC1I,EAAE,MAAM,cAAc,QAAQ,EAAE,OAAO,GAAG,OAAO,WAAW,SAAS,CAAC,KAAK,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACjJ;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,GAAG,QAAQ,OAAO,IAAI,aAAa,EAAE,OAAO,KAAK,KAAK,EAAE;AAChE,UAAM,EAAE,MAAM,OAAO,IAAIF,KAAI,EAAE,OAAO,QAAQ,EAAE;AAChD,WAAO,EAAE,GAAG,MAAM,QAAQ,MAAMH,IAAG,SAAS,OAAO,IAAI,EAAE;AAAA,EAC3D;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,gFAAgF,aAAa,qNAAqN,IAAI,0IAA0I,MAAM,WAAW,CAAC,yFAAyF,KAAK,KAAK,KAAK,GAAG,IAAI,CAAC,CAAC,sKAAsK,KAAK,KAAK,KAAK,GAAG,EAAE,CAAC;AAAA,IACnwB,SAAS,KAAK,MAAM,CAAC,EAAE,QAAQ,CAAC,CAACM,KAAI,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,MAAsB;AAC7E,YAAM,CAAC,MAAM,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC;AAC7C,YAAM,KAAKA,MAAK;AAChB,UAAI,OAAO;AACT,eAAO;AAAA,UACLD,MAAK,WAAW,aAAa,KAAK,KAAK,KAAK,GAAG,CAAC,GAAGC,GAAE;AAAA,UACrDD,MAAK,SAAS,aAAa,KAAK,KAAK,KAAK,GAAG,GAAG,EAAE,GAAGC,GAAE;AAAA,UACvDD,MAAK,SAAS,WAAW,GAAGC,GAAE;AAAA,UAC9BD,MAAK,aAAa,gBAAgB,MAAMC,GAAE;AAAA,QAC5C;AACF,YAAM,OAAO,MAAM,KAAK,MAAM,IAAI,QAAQ;AAC1C,aAAO;AAAA,QACL,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,KAAK,KAAK,KAAK,IAAI,EAAE,GAAG,KAAK,KAAK,KAAK,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK;AAAA,QACtH,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,KAAK,KAAK,KAAK,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,KAAK,GAAG,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK;AAAA,QAC/I,EAAE,IAAI,aAAa,MAAM,GAAG,OAAO,EAAE,cAAc,CAAC,OAAO,IAAI,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK;AAAA,MAC5F;AAAA,IACF,CAAC,EAAE,OAAO;AAAA;AAAA,MAER,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3E,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,IAC5E,CAAC;AAAA,EACH;AACF;AAUA,IAAM,UAAU;AAChB,IAAM,UAAU;AAEhB,IAAM,YAAY,UAAU;AAC5B,IAAM,YAAY,IAAI,UAAU;AAChC,IAAM,UAAU;AAEhB,IAAM,aAAa,CAAC,MAClB,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,SAAS,GAAG,CAAC,IAAI,WAAW,SAAS,GAAG,CAAC,IAAI,SAAS,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG;AACvI,IAAM,WAAW,CAAC,MAAc,CAAC,CAAC,WAAW,IAAI,SAAS,GAAG,CAAC,IAAI,WAAW,SAAS,GAAG,CAAC,IAAI,WAAW,IAAI,SAAS,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG;AAEzJ,IAAM,aAAa,CAAC,MAAc,oBAAoB,CAAC,IAAI,CAAC;AAErD,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,eAAe,QAAQ,QAAQ,WAAW,OAAO;AAAA,EAC5E,SAAS;AAAA,EACT,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,SAAS,CAAC,KAAK,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,QAAQ,EAAE;AAAA,IAChG,EAAE,MAAM,YAAY,QAAQ,EAAE,YAAY,CAAC,KAAK,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO,UAAU,EAAE;AAAA,EAC5H;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAIH,KAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAMH,IAAG,MAAM,OAAO,IAAI,GAAG,MAAMA,IAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACjF;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,kVAAkV,IAAI,odAAod,WAAW,SAAS,CAAC,0EAA0E,SAAS,SAAS,CAAC,qFAAqF,YAAY,CAAC,SAAS,YAAY,CAAC,SAAS,OAAO,SAAS,OAAO,yLAAyL,MAAM,WAAW,CAAC,oIAAoI,OAAO,QAAQ,OAAO,YAAY,UAAU,OAAO,aAAa,UAAU,OAAO,yCAAyC,UAAU,CAAC,QAAQ,UAAU,CAAC,YAAY,UAAU,UAAU,EAAE,aAAa,UAAU,UAAU,EAAE,0CAA0C,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,sRAAsR,OAAO,QAAQ,OAAO,YAAY,UAAU,OAAO,aAAa,UAAU,OAAO,oKAAoK,WAAW,SAAS,CAAC,cAAc,OAAO,QAAQ,OAAO,YAAY,UAAU,OAAO,aAAa,UAAU,OAAO;AAAA,IAClyE,SAAS;AAAA,MACP,EAAE,IAAI,cAAc,OAAO,EAAE,QAAQ,CAAC,WAAW,SAAS,GAAG,WAAW,OAAO,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7G,EAAE,IAAI,YAAY,OAAO,EAAE,QAAQ,CAAC,SAAS,SAAS,GAAG,SAAS,OAAO,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MACvG,EAAE,IAAI,UAAU,OAAO,EAAE,WAAW,CAAC,WAAW,SAAS,GAAG,WAAW,OAAO,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5G,EAAE,IAAI,eAAe,OAAO,EAAE,IAAI,CAAC,YAAY,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,YAAY,GAAG,UAAU,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,IAC9H;AAAA,EACF;AACF;AAKA,IAAM,cAAc;AAEpB,IAAM,SAAiE;AAAA,EACrE,CAAC,IAAI,IAAI,IAAI,IAAI;AAAA,EACjB,CAAC,KAAK,KAAK,IAAI,IAAI;AAAA,EACnB,CAAC,KAAK,IAAI,GAAG,IAAI;AAAA,EACjB,CAAC,IAAI,KAAK,GAAG,GAAG;AAClB;AAEA,IAAM,UAAU;AAET,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,eAAe,QAAQ,WAAW,cAAc,WAAW,SAAS,MAAM;AAAA,EAC5F,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE;AAAA,IAC7H,EAAE,MAAM,kBAAkB,QAAQ,EAAE,OAAO,GAAG,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,OAAO,OAAO,EAAE;AAAA,IAC7F,EAAE,MAAM,SAAS,QAAQ,EAAE,OAAO,GAAG,OAAO,OAAO,OAAO,EAAE,EAAE;AAAA,EAChE;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,GAAG,QAAQ,OAAO,IAAI,aAAa,EAAE,OAAO,KAAK,KAAK,EAAE;AAChE,UAAM,EAAE,MAAM,OAAO,IAAIG,KAAI,EAAE,OAAO,QAAQ,EAAE;AAChD,UAAM,SAAS,KAAK,MAAM,OAAO,EAAE,KAAK,IAAI,GAAI;AAChD,UAAM,SAAS,OAAO,YAAY,OAAO,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAEG,GAAE,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,MAAMA,MAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,MAAMA,MAAK,MAAM,IAAI,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;AAEzK,WAAO,EAAE,GAAG,MAAM,QAAQ,MAAMN,IAAG,SAAS,OAAO,IAAI,GAAG,QAAQ,OAAO,KAAK,MAAM,SAAS,IAAI,GAAG,MAAM,KAAK,MAAM,SAAS,IAAI,GAAG,MAAM,KAAK,MAAM,SAAS,IAAI,GAAG,GAAG,OAAO;AAAA,EAClL;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,+hBAA+hB,IAAI,gQAAgQ,WAAW,geAAge,cAAc,CAAC,khBAAkhB,MAAM,WAAW,CAAC,0uBAA0uB,OAAO;AAAA,MACrjF,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,kBAAkB,CAAC,QAAQ,OAAO,yCAAyC,CAAC,IAAI,CAAC;AAAA,IAClG,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,YAAY,OAAO,EAAE,mBAAmB,CAAC,qCAAqC,gCAAgC,WAAW,KAAK,EAAE,GAAG,IAAIE,GAAE,QAAQ,GAAG,MAAM,SAAS;AAAA,MACzK,EAAE,IAAI,aAAa,OAAO,EAAE,mBAAmB,CAAC,sCAAsC,iCAAiC,CAAC,cAAc,GAAG,KAAK,EAAE,GAAG,IAAIA,GAAE,QAAQ,GAAG,MAAM,SAAS;AAAA,MACnL,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,uCAAuC,qCAAqC,EAAE,GAAG,IAAIA,GAAE,OAAO,GAAG,MAAM,SAAS;AAAA,MACpJ,GAAG,OAAO,QAAQ,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,MAAsB;AAAA,QACrD,EAAE,IAAI,QAAQ,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,wBAAwB,aAAa,CAAC,IAAI,CAAC,WAAW,IAAI,cAAc,EAAE,GAAG,OAAOA,GAAE,IAAI,CAAC,EAAE,GAAG,IAAIA,GAAE,MAAM,GAAG,MAAM,MAAM;AAAA,QACtL,EAAE,IAAI,QAAQ,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,IAAI,gBAAgB,aAAa,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,OAAOA,GAAE,IAAI,CAAC,EAAE,GAAG,IAAIA,GAAE,MAAM,GAAG,MAAM,SAAS;AAAA,MAC5L,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAKA,IAAM,QAAgH;AAAA,EACpH,CAAC,SAAS,IAAI,IAAI,GAAG;AAAA,EACrB,CAAC,QAAQ,KAAK,IAAI,CAAC;AAAA,EACnB,CAAC,SAAS,KAAK,IAAI,EAAE;AAAA,EACrB,CAAC,QAAQ,IAAI,KAAK,EAAE;AAAA,EACpB,CAAC,QAAQ,KAAK,KAAK,EAAE;AAAA,EACrB,CAAC,SAAS,KAAK,KAAK,CAAC;AACvB;AACA,IAAM,gBAAgB,CAAC,UAAU,UAAU,UAAU,UAAU,UAAU,QAAQ;AAGjF,SAAS,aAAa,MAAiC,GAAW,GAAW,QAAwB;AACnG,QAAM,MAAM,CAAC,MAAc,YAAY,CAAC,wHAAwH,CAAC,WAAW,MAAM;AAClL,QAAM,QAAQ,CAAC,MAAc,YAAY,CAAC;AAC1C,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC;AAAA,IACrD,KAAK;AACH,aAAO,IAAI,KAAK,GAAG,GAAG,IAAI,EAAE,CAAC,IAAI,MAAM,KAAK,GAAG,GAAG,IAAI,EAAE,CAAC;AAAA,IAC3D,KAAK;AACH,aAAO,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC;AAAA,IACnD,KAAK;AACH,aAAO,IAAI,MAAM,GAAG,GAAG,IAAI,IAAI,GAAG,CAAC,IAAI,YAAY,CAAC,QAAQ,IAAI,CAAC,uCAAuC,KAAK,oEAA+D,MAAM,MAAM,GAAG,GAAG,IAAI,IAAI,GAAG,CAAC;AAAA,IAC5M,KAAK;AACH,aACE,IAAI,OAAO,GAAG,GAAG,EAAE,CAAC,IACpB,eAAe,IAAI,EAAE,SAAS,IAAI,CAAC,uCAAuC,IAAI,EAAE,SAAS,IAAI,CAAC,qCAAqC,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,IAAI,CAAC,6EACrL,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;AAAA,IAE1B,KAAK;AACH,aAAO,0BAA0B,IAAI,EAAE,oJAAoJ,IAAI,EAAE,iDAAiD,MAAM,eAAe,CAAC,uNAAuN,IAAI,EAAE;AAAA,EACze;AACF;AAGA,IAAM,UAAU;AAChB,IAAM,aAAa;AAEZ,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,QAAQ,UAAU,WAAW,OAAO,WAAW,cAAc,MAAM;AAAA,EACrF,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,IAAI,CAAC,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC,KAAK,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,IACxI,EAAE,MAAM,cAAc,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE;AAAA,EAC5G;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAIC,KAAI,EAAE,OAAO,IAAI,EAAE;AAC5C,UAAM,QAAQH,IAAG,KAAK,IAAI,IAAI,SAAS,EAAE,CAAC;AAC1C,WAAO,EAAE,MAAM,QAAQ,OAAO,OAAOA,IAAG,MAAM,QAAQ,CAAC,GAAG,UAAUA,IAAG,MAAM,OAAO,IAAI,EAAE;AAAA,EAC5F;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,gdAAgd,IAAI,4VAA4V,MAAM,YAAY,CAAC,mTAAmT,MAAM;AAAA,MAC/nC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,WAAW,CAAC,gBAAgB,KAAK,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC,iBAAiB,aAAa,MAAM,GAAG,GAAG,cAAc,CAAC,CAAE,CAAC;AAAA,IACvI,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS,MAAM,QAAQ,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,MAAsB;AACzD,YAAMM,MAAK,MAAM,IAAI;AACrB,YAAM,MAAM,aAAa,IAAI;AAC7B,aAAO;AAAA,QACL,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAOA,KAAI,IAAI,GAAG;AAAA,QAC7D,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,KAAK,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,EAAE,GAAG,OAAOA,KAAI,IAAI,KAAK,MAAM,MAAM;AAAA,QACvH,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,KAAK,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC,EAAE,GAAG,OAAOA,MAAK,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,QAC3H,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,QACpH,EAAE,IAAI,IAAI,CAAC,IAAI,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,KAAK,IAAI,GAAG;AAAA,MACtE;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAKA,IAAM,YAAY,CAAC,IAAY,IAAY,MAAc,KAAK,KAAK,KAAK,IAAI,GAAG,GAAG,EAAE;AACpF,IAAM,WAAW,UAAU,KAAK,KAAK,GAAG;AACxC,IAAM,SAA2B,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC;AAEjF,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,SAAS,eAAe,UAAU,YAAY,OAAO,SAAS,QAAQ;AAAA,EACjG,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,YAAY,QAAQ,EAAE,OAAO,YAAY,KAAK,2BAAiB,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE;AAAA,IAChG,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,QAAQ,KAAK,2BAAiB,KAAK,CAAC,KAAK,KAAK,IAAI,GAAG,WAAW,GAAG,MAAM,KAAK,EAAE;AAAA,EACnH;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,OAAOH,KAAI,EAAE,OAAO,KAAK,EAAE;AACjC,UAAM,MAAMA,KAAI,EAAE,KAAK,KAAK,EAAE;AAE9B,WAAO,EAAE,MAAM,KAAK,MAAM,QAAQ,KAAK,QAAQ,MAAMH,IAAG,MAAM,KAAK,OAAO,IAAI,GAAG,SAAS,IAAI,MAAM,WAAW,IAAI,QAAQ,MAAMC,IAAG,MAAM,OAAO,EAAE,IAAI,IAAI,GAAG,EAAE;AAAA,EAClK;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,oXAA0W,IAAI,iqCAAiqC,QAAQ,wnBAAwnB,OAAO;AAAA,MACzpE,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,oBAAoB,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,IAAK,IAAI,CAAE;AAAA,IAC7E,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,IAAI;AAAA,MAC/D,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,UAAU,MAAM,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,MAAM,MAAM,EAAE,GAAG,UAAU,MAAM,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACvI,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,MAAM,MAAM,EAAE,GAAG,UAAU,GAAG,GAAG,EAAE,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAEpI,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MAC7G,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG;AAAA,MAC1EI,MAAK,SAAS,MAAM,KAAK,GAAG;AAAA,MAC5BA,MAAK,SAAS,MAAM,IAAI,GAAG;AAAA;AAAA,MAE3B,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,kBAAkB,kBAAkB,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI,MAAM,MAAM;AAAA,MACrH,EAAE,IAAI,QAAQ,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,oBAAoB,gBAAgB,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MACzH,GAAG,OAAO,IAAI,CAAC,GAAG,OAAqB,EAAE,IAAI,QAAQ,CAAC,IAAI,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,GAAG,EAAE;AAAA;AAAA,MAEpH,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,UAAU,GAAG,GAAG,EAAE,GAAG,UAAU,MAAM,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACrH,EAAE,IAAI,SAAS,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,IAAI;AAAA,MAC/DA,MAAK,SAAS,aAAa,UAAU,KAAK,CAAC;AAAA,MAC3C,GAAG,OAAO,IAAI,CAAC,GAAG,OAAqB,EAAE,IAAI,QAAQ,CAAC,IAAI,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,IAAI,EAAE;AAAA,IAC3G;AAAA,EACF;AACF;AAIA,IAAM,SAAS;AACf,IAAM,SAAS;AAEf,IAAM,YAAY,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAClD,IAAM,aAAa,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAGnD,IAAM,QAAQ,MAAM;AAClB,QAAM,IAAI,SAAS;AACnB,QAAMC,MAAK,CAAC,MAAc,CAAC,IAAK,IAAI,UAAW,UAAU,SAAS;AAClE,QAAM,QAAQ,WAAW,IAAI,CAAC,IAAI,MAAM,CAAC,SAAS,IAAIA,IAAG,CAAC,CAAC,CAAU;AACrE,QAAM,OAAO,UAAU,IAAI,CAAC,IAAI,MAAM,CAAC,IAAIA,IAAG,CAAC,CAAC,CAAU,EAAE,QAAQ;AACpE,SAAO,QAAQ,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;AACpC,GAAG;AACH,IAAM,YAAY;AAClB,IAAM,WAAW;AAEV,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,QAAQ,SAAS,aAAa,WAAW,SAAS,UAAU,MAAM;AAAA,EACpF,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,aAAa,QAAQ,EAAE,MAAM,CAAC,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,OAAO,MAAM,KAAK,EAAE;AAAA,IAChI,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,MAAM,SAAS,MAAM,MAAM,MAAM,EAAE;AAAA,IACnJ,EAAE,MAAM,gBAAgB,QAAQ,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,MAAM,KAAK,GAAG,GAAG,OAAO,KAAK,EAAE;AAAA,EACpH;AAAA,EACA,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,IAAI,GAAG,QAAQ,EAAE,OAAO,IAAI,EAAE;AAAA,EACxE,QAAQ;AAAA,IACN,KAAK,yoEAAyoE,IAAI,+BAA+B,IAAI,oEAAoE,IAAI,8DAA8D,IAAI,+DAA+D,CAAC,SAAS,IAAI,CAAC,KAAK,MAAM,0KAA0K,CAAC,SAAS,IAAI,CAAC,wBAAwB,SAAS,CAAC,6CAA6C,CAAC,SAAS,IAAI,CAAC,wBAAwB,SAAS,CAAC,kFAAkF,CAAC,SAAS,IAAI,CAAC,wBAAwB,SAAS,CAAC;AAAA,IACp1F,SAAS;AAAA,MACP,EAAE,IAAI,UAAU,OAAO,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,WAAW,MAAM,SAAS;AAAA,MACjF,EAAE,IAAI,QAAQ,OAAO,EAAE,WAAW,CAAC,kBAAkB,aAAa,MAAM,KAAK,EAAE,GAAG,IAAI,WAAW,MAAM,SAAS;AAAA;AAAA,MAEhH,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,WAAW,IAAI,IAAI;AAAA,MACpE,EAAE,IAAI,QAAQ,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,UAAU,IAAI,IAAI;AAAA,IACrE;AAAA,EACF;AACF;AAGO,IAAM,iBAAiC,CAAC,aAAa,aAAa,aAAa,cAAc,YAAY,SAAS;;;ACrbzH,IAAMC,MAAK,CAAC,MAAc;AACxB,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE,IAAI;AAC/B,SAAO,OAAO,GAAG,GAAG,EAAE,IAAI,IAAI;AAChC;AACA,IAAMC,MAAK,CAAC,MAAc;AACxB,QAAM,IAAI,KAAK,MAAM,IAAI,GAAG,IAAI;AAChC,SAAO,OAAO,GAAG,GAAG,EAAE,IAAI,IAAI;AAChC;AAGA,IAAMC,KAAI,CAAC,SAAiB,KAAK,IAAI;AAGrC,IAAM,MAAM,CAAC,GAA6B,UAAkB,KAAa,QAAgB;AACvF,QAAM,IAAI,OAAO,CAAC;AAClB,SAAO,OAAO,SAAS,CAAC,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC,IAAI;AAChE;AAKA,IAAMC,WAAU,CAAC,WAA6B,IAAI,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAGH,IAAG,CAAC,CAAC,IAAIA,IAAG,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAKxG,IAAM,aAAa,CAAC,MAAc,IAAIA,IAAG,CAAC,CAAC,CAAC,OAAOA,IAAG,CAAC,CAAC,IAAIA,IAAG,CAAC,CAAC,UAAUA,IAAG,CAAC,CAAC,OAAOA,IAAG,CAAC,CAAC,IAAIA,IAAG,CAAC,CAAC,UAAUA,IAAG,CAAC,CAAC,CAAC;AAGrH,IAAM,WAAW,CAAC,MAChBG;AAAA,EACE,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,MAAM;AACnC,UAAM,IAAI,CAAC,KAAK,KAAK,IAAK,IAAI,KAAK,KAAM;AACzC,UAAM,KAAK,IAAI,IAAI,IAAI,OAAO,IAAI;AAClC,WAAO,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,EAC5C,CAAC;AACH;AAGF,IAAM,WAAW;AACjB,IAAM,YAAY;AAClB,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,KAAK,CAAC,MAAc,aAAa,CAAC,IAAI,QAAQ;AACpD,IAAM,SAAS,CAAC,IAAY,OAAe,SAAS,EAAE,IAAI,EAAE;AAErD,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,UAAU,SAAS,UAAU,eAAe,WAAW,MAAM;AAAA,EAC7E,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,iBAAiB,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,KAAK,GAAG,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,IAAI,EAAE;AAAA,IAC3I,EAAE,MAAM,eAAe,QAAQ,EAAE,QAAQ,CAAC,KAAK,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,YAAY,CAAC,KAAK,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE;AAAA,EACjI;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,OAAO,IAAI,EAAE,MAAM,IAAI,GAAG,EAAE;AAClC,UAAM,MAAM,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG;AACtC,UAAMC,QAAO,KAAK,MAAM,OAAO,EAAE,KAAK,CAAC,MAAM;AAC7C,UAAM,OAAO,CAAC,GAAW,MAAc,OAAe,IAAIJ,IAAG,IAAI,CAAC,IAAIA,IAAG,CAAC,CAAC,KAAKA,IAAG,EAAE,CAAC,IAAIA,IAAG,CAAC,CAAC;AAC/F,WAAO;AAAA,MACL,MAAMI,QAAO,SAAS,IAAI,IAAI,WAAW,IAAI;AAAA,MAC7C,OAAOA,QAAO,IAAI;AAAA,MAClB,IAAIJ,IAAG,CAAC,OAAO,IAAI;AAAA,MACnB,IAAIA,IAAG,CAAC,OAAO,GAAG;AAAA,MAClB,IAAIA,IAAG,OAAO,IAAI;AAAA,MAClB,MAAM,MAAMA,IAAG,CAAC,IAAI,CAAC,KAAKA,IAAG,CAAC,GAAG,CAAC,IAAIA,IAAG,CAAC,OAAO,GAAG,CAAC,KAAKA,IAAG,CAAC,GAAG,CAAC,IAAIA,IAAG,OAAO,GAAG,CAAC,OAAOA,IAAG,IAAI,CAAC;AAAA,MACnG,OAAO,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,KAAK,OAAO,KAAK,CAAC,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,KAAK,OAAO,MAAM,CAAC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AAAA,MACtJ,WAAWA,IAAG,KAAK,IAAI,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,mnBAAmnB,GAAG,SAAS,CAAC,kRAAkR,OAAO,KAAK,GAAG,CAAC;AAAA,IACv6B,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,qBAAqB,OAAO,EAAE,WAAW,CAAC,GAAG,SAAS,GAAG,GAAG,WAAW,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACxG,EAAE,IAAI,oBAAoB,OAAO,EAAE,WAAW,CAAC,cAAc,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACpH,EAAE,IAAI,oBAAoB,OAAO,EAAE,WAAW,CAAC,OAAO,KAAK,GAAG,GAAG,OAAO,GAAG,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAEvG,EAAE,IAAI,oBAAoB,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,CAAC,GAAG,OAAO,MAAM,IAAI,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MACrH,EAAE,IAAI,oBAAoB,OAAO,EAAE,WAAW,CAAC,OAAO,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA;AAAA,MAErH,EAAE,IAAI,qBAAqB,OAAO,EAAE,WAAW,CAAC,GAAG,WAAW,GAAG,GAAG,cAAc,EAAE,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,MAC5H,EAAE,IAAI,qBAAqB,OAAO,EAAE,WAAW,CAAC,GAAG,cAAc,EAAE,GAAG,GAAG,UAAU,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MAC9H,EAAE,IAAI,oBAAoB,OAAO,EAAE,WAAW,CAAC,cAAc,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,MACpI,EAAE,IAAI,oBAAoB,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,CAAC,GAAG,OAAO,KAAK,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS;AAAA,IACzH;AAAA,EACF;AACF;AAKA,IAAMK,QAAO;AAGb,IAAM,QAAiB,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,MAAM;AAC1D,QAAM,IAAI,IAAI;AACd,QAAM,KAAK,CAAC,IAAI,GAAG;AACnB,QAAM,KAAK,CAAC,KAAK,GAAG;AACpB,QAAM,KAAK,CAAC,KAAK,CAAC;AAClB,QAAM,KAAK,CAAC,KAAK,EAAE;AACnB,QAAM,IAAI,CAAC,OAAe,IAAI,MAAM,IAAI,GAAG,CAAC,IAAK,KAAK,IAAI,MAAM,IAAI,IAAI,GAAG,CAAC,IAAK,KAAK,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC,IAAK,KAAK,IAAI,GAAG,CAAC;AAC7H,SAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;AACpB,CAAC;AAGD,SAAS,YAAY,QAAuD;AAC1E,QAAM,SAAkB,CAAC;AACzB,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,IAAI,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAClC,UAAM,IAAI,MAAM,KAAK,IAAI,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC;AACjD,UAAM,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;AACrB,UAAM,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;AACrB,UAAM,IAAI,KAAK,MAAM,IAAI,EAAE,KAAK;AAChC,WAAO,KAAK,CAAC,EAAE,CAAC,IAAK,KAAK,IAAK,QAAQ,EAAE,CAAC,IAAK,KAAK,IAAK,MAAM,CAAC;AAChE,WAAO,KAAM,KAAK,MAAM,IAAI,EAAE,IAAI,MAAO,KAAK,EAAE;AAAA,EAClD,CAAC;AACD,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAGA,SAAS,WAAW,QAA0B,GAAoC;AAChF,QAAM,UAAU,CAAC,CAAC;AAClB,WAASC,KAAI,GAAGA,KAAI,OAAO,QAAQA,KAAK,SAAQ,KAAK,QAAQA,KAAI,CAAC,IAAK,KAAK,MAAM,OAAOA,EAAC,EAAG,CAAC,IAAI,OAAOA,KAAI,CAAC,EAAG,CAAC,GAAG,OAAOA,EAAC,EAAG,CAAC,IAAI,OAAOA,KAAI,CAAC,EAAG,CAAC,CAAC,CAAC;AACvJ,QAAM,SAAS,IAAI,QAAQ,QAAQ,SAAS,CAAC;AAC7C,MAAI,IAAI;AACR,SAAO,IAAI,OAAO,SAAS,KAAK,QAAQ,CAAC,IAAK,OAAQ;AACtD,QAAM,OAAO,QAAQ,CAAC,IAAK,QAAQ,IAAI,CAAC,KAAM;AAC9C,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,SAAS,QAAQ,IAAI,CAAC,KAAM,IAAI,CAAC;AACpE,QAAM,IAAI,OAAO,IAAI,CAAC;AACtB,QAAM,IAAI,OAAO,CAAC;AAClB,SAAO,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,MAAM,IAAI,IAAI,EAAE;AAC3F;AAGA,IAAM,QAAQ,CAAC,MAAcL,IAAG,OAAQ,OAAO,KAAMI,QAAO,EAAE;AAE9D,IAAM,UAAU,MAAM,KAAK,EAAE,QAAQA,MAAK,GAAG,CAAC,GAAG,MAAM,CAAC;AAEjD,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,QAAQ,QAAQ,aAAa,cAAc,QAAQ,QAAQ;AAAA,EAC3E,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,sBAAsB,QAAQ,EAAE,YAAY,MAAM,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,IAAI,MAAM,EAAE,EAAE;AAAA,IACtI,EAAE,MAAM,eAAe,QAAQ,EAAE,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,MAAM,IAAI,OAAO,MAAM,EAAE;AAAA,IAC9H,EAAE,MAAM,eAAe,QAAQ,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,KAAK,IAAI,EAAE;AAAA,EAC3G;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,UAAU,IAAI,EAAE,SAAS,IAAI,GAAG,EAAE;AACxC,UAAM,OAAO,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE;AACjC,UAAM,MAAM,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG;AACnC,UAAM,OAAO,KAAK,MAAM,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE,CAAC;AAC7C,UAAM,OAAO,YAAY,UAAU,CAAC;AACpC,UAAM,QAAQ,YAAY,CAAC,UAAU,CAAC;AACtC,UAAM,OAAO,CAAC,QAA0B,IAAI,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAGL,IAAG,CAAC,CAAC,IAAIA,IAAG,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAC/F,UAAM,MAAuC;AAAA,MAC3C,MAAM,KAAK,KAAK,MAAM;AAAA,MACtB,OAAO,KAAK,MAAM,MAAM;AAAA,MACxB,QAAQ,KAAK,KAAK;AAAA,MAClB,cAAc,EAAE,UAAU,QAAQ,IAAI;AAAA,MACtC,IAAIA,IAAG,EAAE,eAAe,OAAO,OAAO,MAAM,IAAI;AAAA,MAChD,IAAIA,IAAG,IAAI;AAAA,MACX,UAAUA,KAAI,EAAE,eAAe,OAAO,OAAO,MAAM,QAAQ,GAAG;AAAA,MAC9D,UAAUA,IAAG,OAAO,GAAG;AAAA,MACvB,MAAM,KAAK,MAAM,MAAM,GAAG;AAAA,MAC1B,OAAO,KAAK,MAAM,MAAM,GAAG;AAAA,IAC7B;AACA,eAAW,KAAK,SAAS;AACvB,YAAM,OAAO,IAAI,IAAI,QAAQ;AAC7B,YAAM,EAAE,GAAG,EAAE,IAAI,WAAW,KAAK,QAAQ,MAAM,CAAC,CAAC;AACjD,UAAI,IAAI,CAAC,EAAE,IAAIA,IAAG,EAAE,CAAC,CAAC;AACtB,UAAI,IAAI,CAAC,EAAE,IAAIA,IAAG,EAAE,CAAC,CAAC;AACtB,UAAI,IAAI,CAAC,EAAE,IAAIA,IAAG,KAAK,OAAO,CAAC,CAAE;AACjC,UAAI,KAAK,CAAC,EAAE,IAAI,KAAK,MAAM,IAAI,GAAG;AAClC,UAAI,MAAM,CAAC,EAAE,IAAI,KAAK,OAAO,IAAI,QAAQ,GAAG;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,uxBAAuxB,QAAQ;AAAA,MAClyB,CAAC,MACC,wBAAwB,CAAC,6BAA6B,CAAC,SAAS,CAAC,oCAAoC,CAAC,wCAAwC,CAAC;AAAA,IACnJ,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS,QAAQ,QAAQ,CAAC,MAAsB;AAAA;AAAA,MAE9C,EAAE,IAAI,iBAAiB,CAAC,IAAI,OAAO,IAAI,IAAI,qBAAqB,mBAAmB,IAAI,CAAC,KAAK,IAAI,GAAGC,IAAG,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,OAAOC,GAAE,KAAK,CAAC,EAAE,GAAG,IAAIA,GAAE,MAAM,GAAG,MAAM,MAAM;AAAA,MACrL,EAAE,IAAI,kBAAkB,CAAC,IAAI,OAAO,EAAE,IAAI,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAOA,GAAE,KAAK,CAAC,EAAE,GAAG,IAAIA,GAAE,MAAM,GAAG,MAAM,MAAM;AAAA,MAC9I,EAAE,IAAI,kBAAkB,CAAC,IAAI,OAAO,EAAE,IAAI,CAAC,UAAU,cAAc,GAAG,IAAI,CAAC,UAAU,cAAc,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAOA,GAAE,MAAM,CAAC,EAAE,GAAG,IAAIA,GAAE,OAAO,GAAG,MAAM,SAAS;AAAA,IAC/K,CAAC;AAAA,EACH;AACF;AAGO,IAAM,eAA+B,CAAC,cAAc,WAAW;;;AC5MtE,IAAMK,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAGhD,IAAMC,SAAQ,CAAC,IAAY,IAAY,MAAc,aAAa,EAAE,IAAI,EAAE,WAAWD,IAAG,CAAC,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,EAAE;AAGnH,IAAME,QAAO,CAAC,IAAY,MAAc,OAAwB,WAAiC;AAAA,EAC/F;AAAA,EACA,MAAM;AAAA,EACN,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,EAAE;AAAA,EAChC;AAAA,EACA,IAAI;AACN;AAEA,IAAMC,QAAO;AAGb,IAAMC,MAAK;AACX,IAAMC,MAAK;AACX,IAAM,QAAQ,CAAC,OAAe,UAC5B,CAAC,IAAI,KAAK,KAAK,GAAG,EACf,IAAI,CAAC,QAAQ;AACZ,QAAM,IAAK,MAAM,KAAK,KAAM;AAC5B,QAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;AACxC,SAAO,IAAIL,IAAGI,MAAK,QAAQ,CAAC,CAAC,IAAIJ,IAAGK,MAAK,QAAQ,CAAC,CAAC,KAAKL,IAAGI,MAAK,QAAQ,CAAC,CAAC,IAAIJ,IAAGK,MAAK,QAAQ,CAAC,CAAC;AAClG,CAAC,EACA,KAAK,GAAG;AAGb,IAAM,WAAW;AACjB,IAAM,aAAa;AAEZ,IAAM,YAA0B;AAAA,EACrC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,UAAU,eAAe,MAAM,SAAS,QAAQ,OAAO,OAAO,UAAU,WAAW;AAAA,EAC1F,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,CAAC,GAAG,KAAK,GAAG,GAAG,QAAQ,CAAC,GAAG,KAAK,GAAG,GAAG,QAAQ,IAAI,EAAE;AAAA,IACtF,EAAE,MAAM,YAAY,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,MAAM,GAAG,GAAG,QAAQ,KAAK,QAAQ,EAAE,EAAE;AAAA,IACvG,EAAE,MAAM,aAAa,QAAQ,EAAE,YAAY,MAAM,EAAE;AAAA,EACrD;AAAA,EACA,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,aAAa,IAAI,EAAE;AAAA,EAClD,QAAQ;AAAA,IACN,KAAK,owBAAowBD,GAAE,IAAIC,MAAK,CAAC,KAAKA,MAAK,CAAC,KAAKD,GAAE,IAAIC,MAAK,CAAC,KAAKA,MAAK,CAAC,KAAKD,MAAK,CAAC,IAAIC,GAAE,KAAKD,MAAK,CAAC,KAAKA,MAAK,CAAC,IAAIC,GAAE,KAAKD,MAAK,CAAC,4CAA4CH,OAAMG,KAAIC,KAAI,GAAG,CAAC,yDAAyD,MAAM,GAAG,EAAE,CAAC,2KAA2KD,MAAK,EAAE,QAAQC,MAAK,EAAE,kBAAkBF,KAAI;AAAA,IAC9sC,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,kBAAkB,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG;AAAA,MACpE,EAAE,IAAI,kBAAkB,MAAM,GAAG,OAAO,EAAE,WAAW,CAACF,OAAMG,KAAIC,KAAI,GAAG,GAAGJ,OAAMG,KAAIC,KAAI,IAAI,CAAC,EAAE,GAAG,IAAI,IAAI,MAAM,MAAM;AAAA,MACtH,EAAE,IAAI,kBAAkB,MAAM,GAAG,OAAO,EAAE,WAAW,CAACJ,OAAMG,KAAIC,KAAI,IAAI,GAAGJ,OAAMG,KAAIC,KAAI,CAAC,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,MAAM,SAAS;AAAA,MAClI,EAAE,IAAI,kBAAkB,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAACJ,OAAMG,KAAIC,KAAI,CAAC,GAAGJ,OAAMG,KAAIC,KAAI,IAAI,CAAC,EAAE,GAAG,OAAO,WAAW,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAChKH,MAAK,kBAAkB,aAAaD,OAAMG,KAAIC,KAAI,GAAG,GAAG,WAAW,EAAE;AAAA;AAAA,MAErE,EAAE,IAAI,mBAAmB,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,cAAc,EAAE,GAAG,OAAO,IAAI,IAAI,GAAG;AAAA,MAC7F,EAAE,IAAI,iBAAiB,MAAM,GAAG,OAAO,EAAE,WAAW,CAAC,kBAAkB,kBAAkB,EAAE,GAAG,OAAO,IAAI,IAAI,aAAa,IAAI,MAAM,MAAM;AAAA,MAC1I,EAAE,IAAI,mBAAmB,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,gBAAgB,CAAC,EAAE,GAAG,OAAO,aAAa,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC5HH,MAAK,iBAAiB,aAAa,kBAAkB,aAAa,EAAE;AAAA,IACtE;AAAA,EACF;AACF;AAGO,IAAM,gBAAgC,CAAC,SAAS;;;AC/DvD,IAAMI,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAC/C,IAAMC,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAGhD,IAAMC,KAAI,CAAC,SAAiB,KAAK,IAAI;AAGrC,IAAM,OAAO,CAAC,MAAc;AAC1B,QAAM,IAAI,KAAK,IAAI,IAAI,UAAU,MAAM,IAAI;AAC3C,SAAO,IAAI,KAAK,MAAM,CAAC;AACzB;AAGA,IAAMC,SAAQ,CAAC,IAAY,IAAY,IAAY,KAAK,IAAI,MAAM,GAAG,KAAK,GAAG,KAAK,MAChF,aAAaH,IAAG,KAAK,EAAE,CAAC,IAAIA,IAAG,KAAK,EAAE,CAAC,YAAYA,IAAG,GAAG,CAAC,WAAWC,IAAG,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC,eAAeD,IAAG,CAAC,EAAE,CAAC,IAAIA,IAAG,CAAC,EAAE,CAAC;AAGxH,IAAMI,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;AAGA,SAAS,KACP,IACA,MACA,QACA,UAA8C,CAAC,GAC/B;AAChB,SAAO,OAAO,MAAM,CAAC,EAAE,IAAI,CAAC,CAACC,KAAI,KAAK,GAAG,MAAoB;AAC3D,UAAM,CAAC,MAAM,MAAM,IAAI,OAAO,CAAC;AAC/B,WAAO;AAAA,MACL;AAAA,MACA,GAAI,QAAQ,SAAS,SAAY,CAAC,IAAI,EAAE,MAAM,QAAQ,KAAK;AAAA,MAC3D,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE;AAAA,MACjC,OAAO;AAAA,MACP,IAAIA,MAAK;AAAA,MACT,MAAM,QAAQ,QAAQ;AAAA,IACxB;AAAA,EACF,CAAC;AACH;AAKA,IAAMC,WAAU,CAAC,WAA6B,IAAI,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAGN,IAAG,CAAC,CAAC,IAAIA,IAAG,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAGxG,SAASO,MAAK,IAAY,IAAY,GAAW,OAAe,SAAS,GAAW;AAClF,SAAOD;AAAA,IACL,MAAM,KAAK,EAAE,QAAQ,SAAS,EAAE,GAAG,CAAC,GAAG,MAAM;AAC3C,YAAM,IAAI,CAAC,KAAK,KAAK,IAAK,IAAI,KAAK,KAAM;AACzC,YAAM,KAAK,IAAI,IAAI,QAAQ;AAC3B,aAAO,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,IACtD,CAAC;AAAA,EACH;AACF;AAGA,SAAS,QAAQ,IAAY,IAAY,GAAmB;AAC1D,QAAM,IAAI,IAAI;AACd,SAAO,IAAIN,IAAG,EAAE,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,KAAKA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,KAAKA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,KAAKA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,KAAKA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC,IAAIA,IAAG,EAAE,CAAC,IAAIA,IAAG,KAAK,CAAC,CAAC;AACrP;AAGA,IAAM,UAAU,CAAC,IAAY,IAAY,IAAY,OACnD,IAAIA,IAAG,KAAK,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC,KAAKA,IAAG,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC,UAAUA,IAAG,KAAK,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC,KAAKA,IAAG,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC,UAAUA,IAAG,KAAK,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC;AAGnI,IAAM,YAAY;AAClB,IAAM,cAAc;AAIpB,IAAM,QAAQ;AACd,IAAM,QAAQ;AAGd,SAAS,OAAO,IAAY,IAAY,QAAgB,OAAe,MAAc,OAAO,GAAW;AACrG,SAAOM;AAAA,IACL,MAAM,KAAK,EAAE,QAAQ,SAAS,EAAE,GAAG,CAAC,GAAG,MAAM;AAC3C,YAAM,IAAI,OAAQ,IAAI,KAAK,KAAM;AACjC,YAAM,QAAQ,IAAI,IAAI,SAAS,OAAO,OAAO,KAAK,IAAI,IAAI,KAAK,MAAM,MAAM,KAAK,IAAI,MAAM,IAAI;AAC9F,aAAO,CAAC,QAAQ,KAAK,QAAQ,KAAK,IAAI,CAAC,GAAG,QAAQ,KAAK,QAAQ,KAAK,IAAI,CAAC,CAAC;AAAA,IAC5E,CAAC;AAAA,EACH;AACF;AAEA,IAAM,YAAY,OAAO,KAAK,KAAK,IAAI,MAAM,CAAC;AAC9C,IAAM,YAAY,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,GAAG;AAGjD,IAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,MAAM;AACtD,QAAM,IAAK,IAAI,KAAM,KAAK,KAAK,IAAI,MAAM,KAAK,IAAI,EAAE;AACpD,QAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;AACxC,QAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAM,OAAO,KAAK,CAAC,GAAG,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC;AACjE,SAAO,IAAIN,IAAG,QAAQ,MAAM,KAAK,CAAC,CAAC,IAAIA,IAAG,QAAQ,MAAM,KAAK,CAAC,CAAC,KAAKA,IAAG,QAAQ,MAAM,MAAM,CAAC,CAAC,IAAIA,IAAG,QAAQ,MAAM,MAAM,CAAC,CAAC;AAC5H,CAAC,EAAE,KAAK,GAAG;AAGX,IAAM,UAAU,CAAC,GAAW,QAAgBG,OAAM,OAAO,OAAO,GAAG,GAAG,GAAG;AAGzE,IAAM,YAA4D;AAAA,EAChE,CAAC,KAAK,GAAG,CAAC;AAAA,EACV,CAAC,KAAK,GAAG,EAAE;AAAA,EACX,CAAC,KAAK,IAAI,CAAC;AAAA,EACX,CAAC,KAAK,GAAG,CAAC;AAAA,EACV,CAAC,KAAK,IAAI,EAAE;AAAA,EACZ,CAAC,KAAK,GAAG,CAAC;AAAA,EACV,CAAC,KAAK,IAAI,EAAE;AAAA,EACZ,CAAC,KAAK,GAAG,CAAC;AAAA,EACV,CAAC,KAAK,GAAG,CAAC;AACZ;AAEO,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,WAAW,OAAO,gBAAgB,SAAS,YAAY,QAAQ,KAAK;AAAA,EACpF,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,QAAQ,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,MAAM,IAAI,EAAE,EAAE;AAAA,IAC3K,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,QAAQ,OAAO,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,KAAK,GAAG,GAAG,YAAY,CAAC,KAAK,KAAK,GAAG,EAAE,EAAE;AAAA,EAC7K;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,IAAI,KAAK,IAAI,KAAK,YAAY,OAAO,EAAE,IAAI,CAAC,CAAC;AACnD,UAAM,OAAO,KAAK,IAAI,IAAI,MAAM,CAAC;AACjC,WAAO,EAAE,MAAMH,IAAG,IAAI,GAAG,QAAQA,IAAG,IAAI,IAAI,GAAG,MAAMA,IAAG,QAAQ,OAAO,IAAI,EAAE;AAAA,EAC/E;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,qZAAqZ,SAAS,mRAAmR,KAAK,SAAS,KAAK,uVAAuV,QAAQ,KAAK,CAAC,CAAC,0BAA0B,UAAU,0FAA0F,QAAQ,GAAG,GAAG,CAAC,cAAc,SAAS,0FAA0F,SAAS,yEAAyE,SAAS,4GAA4GG,OAAM,OAAO,OAAO,GAAG,GAAG,EAAE,CAAC,cAAc,QAAQ,CAAC,sQAAsQ,KAAK;AAAA,IACnzD,SAAS;AAAA;AAAA,MAEP,GAAG,KAAK,OAAO,aAAa;AAAA,QAC1B,CAAC,GAAG,QAAQ,GAAG,GAAG,CAAC;AAAA,QACnB,CAAC,KAAK,QAAQ,MAAM,CAAC,CAAC;AAAA,QACtB,CAAC,KAAK,QAAQ,MAAM,EAAE,CAAC;AAAA,QACvB,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC;AAAA,MACrB,GAAG,EAAE,MAAM,MAAM,CAAC;AAAA,MAClB,GAAG,KAAK,OAAO,aAAa;AAAA,QAC1B,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC;AAAA,QACpB,CAAC,MAAM,QAAQ,KAAK,EAAE,CAAC;AAAA,QACvB,CAAC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAAA,MACvB,CAAC;AAAA;AAAA,MAED,GAAG,KAAK,WAAW,aAAa;AAAA,QAC9B,CAAC,KAAKA,OAAM,OAAO,OAAO,GAAG,GAAG,EAAE,CAAC;AAAA,QACnC,CAAC,KAAKA,OAAM,OAAO,OAAO,MAAM,MAAM,GAAG,CAAC;AAAA,QAC1C,CAAC,KAAKA,OAAM,OAAO,OAAO,MAAM,MAAM,EAAE,CAAC;AAAA,QACzC,CAAC,KAAKA,OAAM,OAAO,OAAO,GAAG,GAAG,EAAE,CAAC;AAAA,QACnC,CAAC,KAAMA,OAAM,OAAO,OAAO,MAAM,MAAM,EAAE,CAAC;AAAA,QAC1C,CAAC,MAAMA,OAAM,OAAO,OAAO,GAAG,GAAG,EAAE,CAAC;AAAA,MACtC,GAAG,EAAE,MAAM,MAAM,CAAC;AAAA;AAAA,MAElBC,MAAK,aAAa,WAAW,GAAG,CAAC;AAAA,MACjCA,MAAK,aAAa,WAAW,GAAG,GAAG;AAAA,MACnC,EAAE,IAAI,aAAa,OAAO,EAAE,WAAW,CAAC,QAAQ,KAAK,CAAC,GAAG,QAAQ,MAAM,CAAC,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MAC/G,EAAE,IAAI,aAAa,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA;AAAA,MAEnE,GAAG,UAAU,MAAM,CAAC,EAAE,IAAI,CAAC,CAACC,KAAI,IAAI,EAAE,GAAG,MAAoB;AAC3D,cAAM,CAAC,MAAM,IAAI,EAAE,IAAI,UAAU,CAAC;AAClC,eAAO,EAAE,IAAI,YAAY,OAAO,EAAE,WAAW,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,MAAM,IAAIA,MAAK,MAAM,MAAM,SAAS;AAAA,MAClJ,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAIA,IAAM,OAAO;AACb,IAAM,OAAO;AAEb,IAAM,WAAW;AAGjB,SAAS,KAAK,OAA0B,OAAyB;AAC/D,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO;AACX,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,OAAO,GAAG,IAAI,IAAI,IAAI,KAAK;AACxC,QAAI,QAAQ,YAAY,IAAI,IAAI,OAAO;AACrC,YAAM,KAAK,IAAI;AACf,aAAO;AAAA,IACT,MAAO,QAAO;AAAA,EAChB;AACA,MAAI,KAAM,OAAM,KAAK,IAAI;AACzB,SAAO;AACT;AAGA,SAAS,QAAQ,MAAiD;AAChE,QAAM,QAAQ,KAAK,MAAM,KAAK,EAAE,OAAO,OAAO;AAC9C,WAAS,OAAO,IAAI,QAAQ,IAAI,QAAQ;AACtC,UAAMG,SAAQ,KAAK,OAAO,MAAM,IAAI;AACpC,QAAIA,OAAM,UAAU,YAAYA,OAAM,MAAM,CAAC,MAAM,YAAY,CAAC,IAAI,QAAQ,GAAG,EAAG,QAAO,EAAE,OAAAA,QAAO,KAAK;AAAA,EACzG;AACA,QAAM,QAAQ,KAAK,OAAO,MAAM,EAAE;AAClC,QAAM,OAAO,CAAC,GAAG,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,MAAM,MAAM,WAAW,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,OAAO,OAAO;AAClG,QAAM,SAAS,KAAK,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC;AAC7D,SAAO,EAAE,OAAO,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,MAAM,CAAC,EAAE;AACtE;AAGA,SAAS,MAAM,IAAY,IAAY,IAAY,IAAY,OAAuB;AACpF,QAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM;AAClD,UAAM,IAAK,IAAI,QAAS,KAAK,KAAK,IAAI;AACtC,WAAO,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,EACtD,CAAC;AACD,SAAO,IAAIR,IAAG,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC,IAAIA,IAAG,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC,IAAI,IAC5C,IAAI,CAAC,GAAG,MAAM;AACb,UAAM,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,KAAK,KAAK;AAClC,UAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;AAC3C,WAAO,IAAIA,IAAG,QAAQ,GAAG,CAAC,IAAIA,IAAG,QAAQ,GAAG,CAAC,UAAUA,IAAG,CAAC,CAAC,IAAIA,IAAG,CAAC,CAAC;AAAA,EACvE,CAAC,EACA,KAAK,GAAG,CAAC;AACd;AAEO,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,WAAW,UAAU,UAAU,WAAW,WAAW,QAAQ,QAAQ;AAAA,EACrF,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,WAAW,QAAQ,EAAE,SAAS,MAAM,MAAM,2CAAsC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE;AAAA,IACrH,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,aAAa,YAAY,CAAC,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE;AAAA,EACvF;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,UAAU,EAAE,YAAY;AAC9B,UAAM,EAAE,OAAO,KAAK,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC;AAC9C,UAAM,OAAO,OAAO,EAAE,IAAI;AAC1B,UAAM,QAAQ,OAAO;AACrB,UAAM,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,YAAY,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC;AAC5E,UAAM,KAAK,KAAK,IAAI,KAAK,SAAS,IAAI,MAAM,EAAE;AAC9C,UAAM,KAAK,KAAK,IAAI,IAAK,MAAM,SAAS,QAAS,IAAI,OAAO,EAAE;AAC9D,UAAM,MAAa,CAAC,OAAO,KAAK,OAAO,IAAI,KAAK,IAAI,KAAK,OAAO,KAAK,EAAE,CAAC;AACxE,UAAM,QAAQ,CAAC,KAAa,IAAI,MAAa,CAAC,OAAO,KAAK,IAAI,KAAK,IAAK,MAAM,KAAK,KAAM,GAAG,GAAG,OAAO,KAAK,IAAI,KAAK,IAAK,MAAM,KAAK,KAAM,GAAG,CAAC;AAC9I,UAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,KAAK,GAAG,GAAG,MAAM,KAAK,GAAG,CAAC;AAClD,UAAM,OAAO,IAAIA,IAAG,GAAG,CAAC,CAAC,CAAC,IAAIA,IAAG,GAAG,CAAC,CAAC,CAAC,KAAKA,KAAI,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAIA,KAAI,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,IAAIA,IAAG,IAAI,CAAC,CAAC,CAAC,IAAIA,IAAG,IAAI,CAAC,CAAC,CAAC,KAAKA,KAAI,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAIA,KAAI,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAIA,IAAG,GAAG,CAAC,CAAC,CAAC,IAAIA,IAAG,GAAG,CAAC,CAAC,CAAC;AAC3N,UAAM,QAAQ,MAAM,KAAK,IAAI;AAC7B,UAAM,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,IAAI,CAAC,GAAG,OAAO;AAAA,MAC9C,GAAGA,IAAG,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC;AAAA,MACxC,GAAGA,IAAG,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC;AAAA,MACxC,GAAG,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;AAAA,IAClB,EAAE;AACF,UAAM,MAAM,OAAQ,MAAM,SAAS,QAAS;AAC5C,UAAM,MAAuC;AAAA,MAC3C,MAAMA,IAAG,IAAI;AAAA,MACb,SAAS,UAAU,MAAM,MAAM,MAAM,KAAK,MAAM,KAAK,MAAM,EAAE,IAAI,QAAQ,MAAM,MAAM,IAAI,EAAE;AAAA,MAC3F;AAAA,MACA,UAAU,UAAU,SAAS;AAAA,MAC7B,WAAW,UAAU,WAAW;AAAA,MAChC,MAAMG,OAAM,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;AAAA,MAC7B,SAASA,OAAM,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG;AAAA,MAClC,UAAUA,OAAM,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI;AAAA,MACpC,MAAMA,OAAM,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;AAAA,IAC/B;AACA,UAAM,QAAQ,CAAC,GAAG,MAAM,OAAO,OAAO,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;AACjG,QAAIE,MAAK;AACT,aAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,YAAM,OAAO,MAAM,CAAC,KAAK;AACzB,YAAM,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,KAAK,IAAI,EAAE,SAAS,IAAI,CAAC;AACjE,aAAO,OAAO,KAAK;AAAA,QACjB,CAAC,OAAO,CAAC,EAAE,GAAG;AAAA,QACd,CAAC,IAAI,CAAC,EAAE,GAAGL,IAAG,OAAQ,YAAY,IAAI,IAAI,OAAQ,CAAC;AAAA,QACnD,CAAC,IAAI,CAAC,EAAE,GAAGA,IAAG,MAAM,SAAS,IAAI,KAAK;AAAA,QACtC,CAAC,KAAK,CAAC,EAAE,GAAGK;AAAA,QACZ,CAAC,KAAK,CAAC,EAAE,GAAG;AAAA,MACd,CAAC;AACD,MAAAA,OAAM,OAAO,KAAK,KAAK;AAAA,IACzB;AACA,QAAI,QAAQA,MAAK;AACjB,WAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,kZAAkZ,WAAW,2IAA2I,CAAC,GAAG,GAAG,CAAC,EACljB,IAAI,CAAC,MAAM,sBAAsB,CAAC,aAAa,CAAC,eAAe,CAAC,cAAc,CAAC,uEAAuE,EACtJ,KAAK,EAAE,CAAC,8RAA8R,CAAC,GAAG,GAAG,CAAC,EAC9S,IAAI,CAAC,MAAM,mBAAmB,CAAC,WAAW,CAAC,aAAa,CAAC,+GAA+G,EACxK,KAAK,EAAE,CAAC;AAAA,IACX,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,YAAY,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACxG,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,eAAe,cAAc,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,MAC1G,EAAE,IAAI,SAAS,OAAO,EAAE,WAAW,CAAC,gBAAgB,UAAU,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA;AAAA,MAEvG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAACD,MAAK,UAAU,IAAI,CAAC,IAAI,WAAW,GAAG,CAAC,GAAGA,MAAK,UAAU,IAAI,CAAC,IAAI,WAAW,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;AAAA,MAC1H,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,OAAqB,EAAE,IAAI,SAAS,CAAC,IAAI,OAAO,SAAS,CAAC,MAAM,OAAOF,GAAE,KAAK,CAAC,EAAE,GAAG,IAAIA,GAAE,KAAK,CAAC,EAAE,GAAG,MAAM,SAAS,EAAE;AAAA,MACxI,EAAE,IAAI,SAAS,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAOA,GAAE,OAAO,GAAG,IAAI,IAAI;AAAA,IACxE;AAAA,EACF;AACF;AAIA,IAAM,OAAO;AACb,IAAM,OAAO;AAEb,IAAM,QAAQ;AACd,IAAM,QAAQ;AAEd,IAAM,UAAU;AAChB,IAAM,WAAW,UAAU;AAG3B,IAAM,WAA2D;AAAA,EAC/D,GAAG,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,MAAM;AACtC,UAAM,IAAK,IAAI,KAAM,KAAK,KAAK,IAAI;AACnC,WAAO,CAAC,OAAO,KAAK,KAAK,IAAI,CAAC,GAAG,OAAO,KAAK,KAAK,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,IAAI,EAAE,CAAC;AAAA,EAClF,CAAC;AAAA,EACD,CAAC,OAAO,IAAI,OAAO,GAAG,EAAE;AAAA,EACxB,CAAC,OAAO,IAAI,OAAO,GAAG,EAAE;AAC1B;AAGA,SAAS,OAAO,GAAW,GAAW;AACpC,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI,SAAS,CAAC;AAC5B,QAAM,IAAK,IAAI,IAAK,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,KAAK;AAC1D,SAAO,EAAE,IAAIF,IAAG,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,GAAG,IAAIA,IAAG,IAAI,IAAI,KAAK,IAAI,IAAI,IAAM,CAAC,CAAC,GAAG,GAAGA,IAAG,KAAK,IAAI,OAAO,KAAK,IAAI,CAAC,EAAE,EAAE;AACnH;AAGA,IAAM,UAAU;AAChB,IAAM,UAAU;AAChB,IAAM,UAAU,YAAYO,MAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAC9C,IAAM,YAAY,CAAC,SAAS,SAAS,OAAO;AAG5C,IAAM,WAA2D;AAAA,EAC/D,CAAC,GAAG,KAAK,CAAC;AAAA,EACV,CAAC,KAAK,KAAK,CAAC;AAAA,EACZ,CAAC,KAAK,MAAM,CAAC;AAAA,EACb,CAAC,KAAK,IAAI,CAAC;AAAA,EACX,CAAC,MAAM,MAAM,CAAC;AAAA,EACd,CAAC,MAAM,IAAI,CAAC;AAAA,EACZ,CAAC,MAAM,KAAK,CAAC;AAAA,EACb,CAAC,MAAM,KAAK,CAAC;AACf;AAGA,IAAM,UAAU,CAAC,QAAgB;AAC/B,QAAM,IAAK,MAAM,KAAK,KAAM;AAC5B,SAAQ,QAAQ,QAAS,KAAK,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC;AAC9E;AAEA,IAAM,SAAS,CAAC,KAAa,MAAc;AACzC,QAAM,IAAK,MAAM,KAAK,KAAM;AAC5B,SAAO,aAAaP,IAAG,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAIA,IAAG,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,GAAG;AAC7F;AAEA,IAAM,WAAW,CAAC,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,KAAK,MAAM,IAAI,IAAIA,KAAI,KAAK,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,MAAM,KAAK,MAAM,IAAI,IAAIA,KAAI,KAAK,IAAI,EAAE,IAAI,OAAO,CAAC,CAAC,CAAU;AAE9L,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,SAAS,SAAS,QAAQ,SAAS,MAAM;AAAA,EACpE,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,eAAe,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE;AAAA,IAClH,EAAE,MAAM,UAAU,QAAQ,EAAE,YAAY,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,KAAK,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EACjH;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,0bAA0b,IAAI,SAAS,OAAO,EAAE,gGAAgG,SAAS;AAAA,MAC5jB,CAAC,CAAC,EAAE,KAAK,KAAK,GAAG,MAAM,gBAAgB,CAAC,gBAAgB,OAAO,KAAK,CAAC,CAAC,KAAK,UAAU,KAAK,CAAC;AAAA,IAC7F,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,IAAI,CAAC,GAAG,MAAM;AAClC,YAAM,IAAI,OAAO,GAAG,CAAC;AACrB,aAAO,kBAAkB,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,CAAC;AAAA,IACjE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,IAAI,CAAC,GAAG,MAAM;AACnC,YAAM,IAAI,OAAO,GAAG,CAAC;AACrB,aAAO,kBAAkB,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,CAAC;AAAA,IACjE,CAAC,EAAE,KAAK,EAAE,CAAC,8JAA8J,SAAS,IAAI,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM;AACpM,YAAM,IAAK,MAAM,KAAK,KAAM;AAC5B,YAAM,IAAI,QAAQ,GAAG,IAAI;AACzB,YAAM,CAAC,GAAG,CAAC,IAAI,CAACA,IAAG,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,GAAGA,IAAG,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;AACtE,aAAO,eAAe,CAAC,gBAAgBG,OAAM,GAAG,GAAG,GAAG,CAAC,2BAA2B,CAAC,IAAI,IAAI,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,IAAI,IAAI,EAAE,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,IAAI,IAAI,EAAE,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,0EAA0EI,MAAK,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC;AAAA,IAC3W,CAAC,EAAE,KAAK,EAAE,CAAC;AAAA,IACX,SAAS;AAAA;AAAA,MAEP,GAAG,SAAS;AAAA,QAAQ,CAAC,GAAG,MACtB,CAAC,GAAG,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAsB;AACvC,gBAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;AAC9C,gBAAM,QAAQ,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;AAClE,iBAAO;AAAA,YACL,EAAE,IAAI,MAAM,CAAC,IAAI,OAAO,OAAO,IAAI,UAAU,IAAI,SAAS;AAAA,YAC1D,EAAE,IAAI,MAAM,CAAC,IAAI,OAAO,OAAO,IAAI,UAAU,IAAI,SAAS;AAAA,UAC5D;AAAA,QACF,CAAC;AAAA,MACH;AAAA;AAAA,MAEA,GAAG,SAAS,QAAQ,CAAC,CAACF,KAAI,GAAG,GAAG,MAAsB;AACpD,cAAM,SAAS,OAAO,KAAK,CAAC;AAC5B,cAAM,MAAM,OAAO,KAAK,QAAQ,GAAG,IAAI,EAAE;AACzC,cAAM,IAAK,MAAM,KAAK,KAAM;AAC5B,cAAM,IAAI,QAAQ,GAAG,IAAI;AACzB,cAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,IAAI,CAAC,GAAG,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC;AAC9D,eAAO;AAAA,UACL,EAAE,IAAI,SAAS,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,QAAQ,GAAG,EAAE,GAAG,OAAOA,KAAI,IAAI,KAAK,MAAM,MAAM;AAAA,UACzF,EAAE,IAAI,SAAS,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,KAAK,MAAM,EAAE,GAAG,OAAOA,MAAK,KAAK,IAAI,KAAK,MAAM,SAAS;AAAA,UAClGD,MAAK,QAAQ,CAAC,IAAI,WAAW,GAAG,CAAC;AAAA,UACjCA,MAAK,QAAQ,CAAC,IAAI,WAAW,GAAGC,MAAK,EAAE;AAAA,UACvC,EAAE,IAAI,QAAQ,CAAC,IAAI,OAAO,EAAE,WAAW,CAACF,OAAM,GAAG,GAAG,GAAG,GAAGA,OAAM,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,OAAOE,MAAK,IAAI,IAAI,KAAK,MAAM,MAAM;AAAA,UACpH,EAAE,IAAI,QAAQ,CAAC,IAAI,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAOA,MAAK,KAAK,IAAI,IAAI;AAAA,UACxED,MAAK,QAAQ,CAAC,IAAI,aAAaD,OAAM,GAAG,GAAG,GAAG,GAAGE,MAAK,GAAG;AAAA,QAC3D;AAAA,MACF,CAAC;AAAA;AAAA,MAED,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA,QAAQ,CAACI,WACpB,SAAS,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,MAAoB;AACtD,gBAAM,CAAC,IAAI,IAAI,EAAE,IAAI,SAAS,CAAC;AAC/B,iBAAO,EAAE,IAAI,WAAW,OAAO,EAAE,WAAW,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAOA,SAAQ,WAAW,IAAI,IAAI,IAAI,IAAI,MAAM,SAAS;AAAA,QAC/J,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAIA,IAAM,OAAO;AACb,IAAM,OAAO;AACb,IAAM,QAAQ;AACd,IAAM,QAAQ;AACd,IAAM,WAAW;AACjB,IAAM,WAAW;AAEjB,IAAM,aAAa;AAGnB,SAAS,KAAK,GAAW,GAAW;AAClC,QAAM,KAAK,IAAI,IAAI,YAAY,KAAK,KAAK;AACzC,QAAM,SAAS,KAAK,IAAI,CAAC,IAAI,KAAK;AAClC,SAAO;AAAA,IACL,WAAW,aAAaT,IAAG,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAIA,IAAG,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,YAAYA,IAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,WAAWC,IAAG,OAAO,OAAO,KAAK,CAAC;AAAA,IACxK,SAASA,IAAG,OAAO,OAAO,KAAK;AAAA,EACjC;AACF;AAEA,IAAM,UAAU;AAET,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,SAAS,SAAS,SAAS,eAAe,MAAM;AAAA,EAC3E,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,OAAO,MAAM,YAAY,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE;AAAA,IACvE,EAAE,MAAM,cAAc,QAAQ,EAAE,MAAM,OAAO,YAAY,CAAC,KAAK,KAAK,IAAI,GAAG,MAAM,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE;AAAA,EACpG;AAAA,EACA,SAAS,CAAC,OAAO;AAAA,IACf,UAAU,EAAE,SAAS,QAAQ,SAAS;AAAA,IACtC,UAAU,EAAE,UAAU,OAAO,WAAW;AAAA,IACxC,UAAU,EAAE,UAAU,OAAO,SAAS;AAAA,EACxC;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,i6BAAi6B,IAAI,SAAS,IAAI,SAAS,KAAK,SAAS,KAAK,iHAAiH,MAAM;AAAA,MACxkC,EAAE,QAAQ,SAAS;AAAA,MACnB,CAAC,GAAG,MAAM;AACR,cAAM,IAAI,KAAK,GAAG,CAAC;AACnB,cAAM,YAAY,YAAYM,MAAK,GAAG,GAAG,IAAI,GAAG,CAAC;AACjD,cAAM,OAAO,IAAI,IAAI,6BAA6B,SAAS,iCAAiC,OAAO,SAAS;AAC5G,eAAO,gBAAgB,CAAC,gBAAgB,EAAE,SAAS,cAAc,EAAE,OAAO,KAAK,IAAI;AAAA,MACrF;AAAA,IACF,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS;AAAA,MACP,GAAG,MAAM;AAAA,QAAK,EAAE,QAAQ,SAAS;AAAA,QAAG,CAAC,GAAG,MACtC,MAAM,KAAK,EAAE,QAAQ,WAAW,GAAG,CAACG,IAAG,MAAoB;AACzD,gBAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,GAAG,KAAK,IAAI,IAAI,KAAK,UAAU,CAAC;AACtE,iBAAO;AAAA,YACL,IAAI,SAAS,CAAC;AAAA,YACd,OAAO,EAAE,WAAW,CAAC,EAAE,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;AAAA,YAChF,OAAQ,IAAI,WAAY;AAAA,YACxB,IAAI,WAAW;AAAA,YACf,MAAM;AAAA,UACR;AAAA,QACF,CAAC;AAAA,MACH,EAAE,KAAK;AAAA;AAAA,MAEP,GAAG,KAAK,UAAU,aAAa;AAAA,QAC7B,CAAC,GAAG,oBAAoB;AAAA,QACxB,CAAC,WAAW,GAAG,mBAAmB;AAAA,QAClC,CAAC,UAAU,oBAAoB;AAAA,MACjC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAIA,IAAM,UAAU;AAGhB,IAAM,UAAU,CAAC,GAAG,IAAI,KAAK,GAAG,EAAE,IAAI,CAAC,QAAQ,mDAAmD,GAAG,cAAc,EAAE,KAAK,EAAE;AAE5H,IAAM,YAAoE;AAAA,EACxE,CAAC,KAAK,IAAI,IAAI,CAAC;AAAA,EACf,CAAC,IAAI,KAAK,IAAI,GAAG;AAAA,EACjB,CAAC,KAAK,IAAI,IAAI,GAAG;AACnB;AAEA,IAAM,UAAU,CAAC,GAAW,GAAW,GAAW,QAAgB,aAAa,CAAC,IAAI,CAAC,YAAYV,IAAG,GAAG,CAAC,WAAWC,IAAG,CAAC,CAAC;AACxH,IAAM,SAAS,CAAC,GAAW,IAAY,OAAe,iBAAiBD,IAAG,CAAC,CAAC,WAAWC,IAAG,EAAE,CAAC,IAAIA,IAAG,EAAE,CAAC;AAEhG,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,SAAS,WAAW,SAAS,SAAS,SAAS,YAAY,QAAQ,MAAM;AAAA,EAChF,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,cAAc,QAAQ,EAAE,OAAO,EAAE,EAAE;AAAA,IAC3C,EAAE,MAAM,WAAW,QAAQ,EAAE,OAAO,GAAG,YAAY,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IACtE,EAAE,MAAM,eAAe,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EACxE;AAAA,EACA,SAAS,CAAC,MAAM,OAAO,YAAY,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,OAAO,EAAE,KAAK,CAAC,MAAM,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,EAC/H,QAAQ;AAAA,IACN,KAAK,mfAAmfE,OAAM,KAAK,KAAK,CAAC,CAAC,6EAA6E,OAAO,kLAAkL,OAAO,IAAI,KAAK,GAAG,CAAC,iRAAiR,UAAU;AAAA,MAC7jC,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,iBAAiB,CAAC,gBAAgB,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC,cAAc,QAAQ,GAAG,GAAG,CAAC,CAAC;AAAA,IACpG,EAAE,KAAK,EAAE,CAAC,6DAA6DA,OAAM,KAAK,KAAK,GAAG,CAAC,+KAA+KA,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,IAC5R,SAAS;AAAA;AAAA,MAEP,GAAG,KAAK,WAAW,aAAa;AAAA,QAC9B,CAAC,GAAGA,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,QACtB,CAAC,KAAKA,OAAM,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,QACpC,CAAC,KAAKA,OAAM,KAAK,KAAK,MAAM,MAAM,EAAE,CAAC;AAAA,QACrC,CAAC,KAAKA,OAAM,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,QACpC,CAAC,KAAKA,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,QACxB,CAAC,SAASA,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,MAC9B,GAAG,EAAE,MAAM,MAAM,CAAC;AAAA;AAAA,MAElB,GAAG,KAAK,WAAW,aAAa;AAAA,QAC9B,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,CAAC;AAAA,QACxB,CAAC,KAAK,OAAO,IAAI,KAAK,GAAG,CAAC;AAAA,QAC1B,CAAC,KAAK,OAAO,IAAI,GAAG,CAAC,CAAC;AAAA,QACtB,CAAC,MAAM,OAAO,KAAK,MAAM,GAAG,CAAC;AAAA,QAC7B,CAAC,MAAM,OAAO,KAAK,MAAM,GAAG,CAAC;AAAA,MAC/B,CAAC;AAAA,MACDC,MAAK,WAAW,aAAa,OAAO,IAAI,KAAK,GAAG,GAAG,IAAI;AAAA,MACvD,GAAG,KAAK,WAAW,WAAW;AAAA,QAC5B,CAAC,GAAG,CAAC;AAAA,QACL,CAAC,KAAK,CAAC;AAAA,QACP,CAAC,MAAM,CAAC;AAAA,QACR,CAAC,MAAM,CAAC;AAAA,MACV,CAAC;AAAA;AAAA,MAED,GAAG,UAAU;AAAA,QAAQ,CAAC,CAAC,GAAG,GAAG,GAAGC,GAAE,GAAG,MACnC,KAAK,UAAU,CAAC,IAAI,aAAa;AAAA,UAC/B,CAACA,KAAI,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,UACxB,CAACA,MAAK,KAAK,QAAQ,GAAG,GAAG,GAAG,EAAE,CAAC;AAAA,UAC/B,CAACA,MAAK,KAAK,QAAQ,GAAG,GAAG,IAAI,MAAM,EAAE,CAAC;AAAA,UACtC,CAACA,MAAK,KAAK,QAAQ,GAAG,GAAG,GAAG,EAAE,CAAC;AAAA,QACjC,GAAG,EAAE,MAAM,MAAM,CAAC,EAAE,OAAOD,MAAK,UAAU,CAAC,IAAI,aAAa,QAAQ,GAAG,GAAG,GAAG,CAAC,GAAGC,MAAK,GAAG,CAAC;AAAA,MAC5F;AAAA;AAAA,MAEA,GAAG,KAAK,UAAU,aAAa;AAAA,QAC7B,CAAC,GAAGF,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,QACtB,CAAC,KAAKA,OAAM,KAAK,KAAK,MAAM,MAAM,EAAE,CAAC;AAAA,QACrC,CAAC,KAAKA,OAAM,KAAK,KAAK,KAAK,KAAK,CAAC,CAAC;AAAA,QAClC,CAAC,KAAKA,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,QACxB,CAAC,MAAMA,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,QACzB,CAAC,MAAMA,OAAM,KAAK,KAAK,CAAC,CAAC;AAAA,MAC3B,GAAG,EAAE,MAAM,MAAM,CAAC;AAAA,MAClBC,MAAK,eAAe,WAAW,GAAG,CAAC;AAAA,MACnCA,MAAK,eAAe,WAAW,GAAG,GAAG;AAAA,MACrC,EAAE,IAAI,eAAe,OAAO,EAAE,WAAW,CAACD,OAAM,KAAK,KAAK,GAAG,GAAGA,OAAM,KAAK,KAAK,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AAAA,MAC1H,EAAE,IAAI,eAAe,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MACrEC,MAAK,eAAe,aAAaD,OAAM,KAAK,KAAK,GAAG,GAAG,IAAI;AAAA,IAC7D;AAAA,EACF;AACF;AAIA,IAAM,OAAO;AACb,IAAM,OAAO;AAEb,IAAM,WAAW;AACjB,IAAM,UAAU;AAChB,IAAM,SAAS;AAGf,SAAS,UAAU,OAAwB;AACzC,UAAQ,KAAK,MAAM,OAAO,KAAK,CAAC,GAAG;AAAA,IACjC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAOI,MAAK,MAAM,KAAK,IAAI,EAAE;AAAA,IAC/B;AACE,aAAO,QAAQ,MAAM,KAAK,IAAI,EAAE;AAAA,EACpC;AACF;AAGA,IAAM,WAAW;AAAA,EACf,GAAG,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM;AACrC,UAAM,IAAK,IAAI,IAAK,KAAK,KAAK,IAAI,MAAM,KAAK,IAAI,EAAE;AACnD,WAAO,EAAE,GAAG,GAAG,KAAK,KAAK,KAAK,IAAI,EAAE,GAAG,GAAG,KAAK,KAAK,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,EAAE;AAAA,EAC3G,CAAC;AAAA;AAAA,EAED,EAAE,GAAG,CAAC,KAAK,KAAK,GAAG,GAAG,GAAG,GAAG,IAAI,OAAO,EAAE;AAC3C;AACA,IAAM,YAA4D;AAAA,EAChE,CAAC,IAAI,IAAI,EAAE;AAAA,EACX,CAAC,KAAK,IAAI,EAAE;AAAA,EACZ,CAAC,KAAK,KAAK,CAAC;AAAA,EACZ,CAAC,IAAI,KAAK,CAAC;AACb;AACA,IAAM,SAAS,CAAC,IAAY,OAAeJ,OAAM,MAAM,UAAU,IAAI,EAAE;AACvE,IAAM,UAAU,CAAC,GAAW,GAAW,GAAW,QAAgB,aAAa,CAAC,IAAI,CAAC,YAAY,GAAG,WAAWF,IAAG,CAAC,CAAC;AAE7G,IAAM,cAA4B;AAAA,EACvC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,SAAS,QAAQ,SAAS,UAAU,SAAS,aAAa;AAAA,EAC5E,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,EAAE;AAAA,IAChE,EAAE,MAAM,cAAc,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,YAAY,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE;AAAA,EAC9H;AAAA,EACA,SAAS,CAAC,OAAO,EAAE,OAAO,UAAU,EAAE,KAAK,EAAE;AAAA,EAC7C,QAAQ;AAAA,IACN,KAAK,2aAA2a,SAAS,wGAAwG,IAAI,SAAS,WAAW,CAAC,+EAA+E,OAAO,GAAG,CAAC,CAAC,wVAAwV,SAAS;AAAA,MACp/B,CAAC,GAAG,MAAM,kBAAkB,CAAC,SAAS,IAAI,SAAS,IAAI;AAAA,IACzD,EAAE,KAAK,EAAE,CAAC,UAAU,SAAS,IAAI,CAAC,GAAG,MAAM,kBAAkB,CAAC,SAAS,IAAI,SAAS,IAAI,4BAA4B,EAAE,KAAK,EAAE,CAAC,WAAW,UAAU;AAAA,MACjJ,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,iBAAiB,CAAC,gBAAgB,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC,cAAc,QAAQ,GAAG,GAAG,CAAC,CAAC;AAAA,IACpG,EAAE,KAAK,EAAE,CAAC,6BAA6BE,OAAM,MAAM,IAAI,CAAC,CAAC,0BAA0B,IAAI;AAAA,IACvF,SAAS;AAAA;AAAA,MAEP,GAAG,KAAK,YAAY,aAAa;AAAA,QAC/B,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;AAAA,QAChB,CAAC,KAAK,OAAO,MAAM,IAAI,CAAC;AAAA,QACxB,CAAC,KAAK,OAAO,KAAK,IAAI,CAAC;AAAA,QACvB,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC;AAAA,MACpB,GAAG,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC;AAAA,MAC3BC,MAAK,YAAY,WAAW,GAAG,GAAG,CAAC;AAAA,MACnCA,MAAK,YAAY,WAAW,GAAG,KAAK,CAAC;AAAA,MACrCA,MAAK,YAAY,WAAW,GAAG,SAAS,CAAC;AAAA,MACzC,GAAG,KAAK,YAAY,aAAa;AAAA,QAC/B,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC;AAAA,QACtB,CAAC,UAAU,KAAK,OAAO,MAAM,IAAI,CAAC;AAAA,QAClC,CAAC,UAAU,KAAK,OAAO,GAAG,CAAC,CAAC;AAAA,MAC9B,GAAG,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC;AAAA,MAC3B,GAAG,KAAK,YAAY,MAAM;AAAA,QACxB,CAAC,GAAG,EAAE;AAAA,QACN,CAAC,KAAK,EAAE;AAAA,QACR,CAAC,KAAK,CAAC;AAAA,QACP,CAAC,SAAS,CAAC;AAAA,QACX,CAAC,UAAU,KAAK,EAAE;AAAA,QAClB,CAAC,UAAU,KAAK,EAAE;AAAA,MACpB,GAAG,EAAE,MAAM,EAAE,CAAC;AAAA;AAAA,MAEd,GAAG,SAAS,QAAQ,CAAC,EAAE,GAAG,GAAG,GAAG,MAAM,GAAG,MAAsB;AAC7D,cAAM,CAAC,GAAG,CAAC,IAAI,CAACJ,IAAG,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,GAAGA,IAAG,OAAO,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC;AAC5E,cAAM,CAAC,IAAI,EAAE,IAAI,CAACA,IAAG,OAAO,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,GAAGA,IAAG,OAAO,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;AACjG,eAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,OAAuB;AAAA,UAC5D,EAAE,IAAI,MAAM,GAAG,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,OAAO,IAAI,KAAK,MAAM,MAAM;AAAA,UAC5G,EAAE,IAAI,MAAM,GAAG,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,GAAGA,IAAG,IAAI,IAAI,CAAC,EAAE,GAAG,OAAO,MAAM,OAAO,IAAI,KAAK,MAAM,SAAS;AAAA,UACtHI,MAAK,IAAI,MAAM,MAAM,QAAQ,CAAC;AAAA,UAC9BA,MAAK,IAAI,MAAM,MAAM,QAAQ,CAAC;AAAA,UAC9BA,MAAK,IAAI,KAAK,GAAG,QAAQ,CAAC;AAAA,QAC5B,CAAC;AAAA,MACH,CAAC;AAAA,MACD,EAAE,IAAI,WAAW,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MAC1EA,MAAK,WAAW,WAAW,GAAG,QAAQ,CAAC;AAAA;AAAA,MAEvC,GAAG,UAAU;AAAA,QAAQ,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,MAC/B,KAAK,UAAU,CAAC,IAAI,aAAa;AAAA,UAC/B,CAAC,MAAM,IAAI,IAAI,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,UAClC,CAAC,MAAM,IAAI,IAAI,QAAQ,GAAG,GAAG,GAAG,EAAE,CAAC;AAAA,UACnC,CAAC,MAAM,IAAI,IAAI,QAAQ,GAAG,GAAG,GAAG,EAAE,CAAC;AAAA,QACrC,GAAG,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,OAAOA,MAAK,UAAU,CAAC,IAAI,aAAa,QAAQ,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;AAAA,MACtG;AAAA;AAAA,MAEA,GAAG,KAAK,UAAU,aAAa;AAAA,QAC7B,CAAC,KAAKD,OAAM,MAAM,IAAI,CAAC,CAAC;AAAA,QACxB,CAAC,KAAKA,OAAM,MAAM,IAAI,MAAM,MAAM,EAAE,CAAC;AAAA,QACrC,CAAC,KAAKA,OAAM,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC;AAAA,QAC/B,CAAC,KAAMA,OAAM,MAAM,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA,MAC1C,GAAG,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC;AAAA,MAC3B,EAAE,IAAI,UAAU,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,IAAI,IAAI;AAAA,MACzEC,MAAK,UAAU,aAAaD,OAAM,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC;AAAA,MACzDC,MAAK,UAAU,WAAW,GAAG,QAAQ,CAAC;AAAA,IACxC;AAAA,EACF;AACF;AAKA,IAAM,WAAW,CAAC,GAAG,GAAG,IAAI,EAAE;AAE9B,IAAM,SAAS;AACf,IAAMO,SAAQ;AAEP,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,WAAW,cAAc,aAAa,UAAU,UAAU,UAAU,QAAQ;AAAA,EACnF,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,SAAS,QAAQ,EAAE,GAAGA,QAAO,MAAM,CAAC,GAAG,MAAM,IAAI,GAAG,WAAW,GAAG,KAAK,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACpG,EAAE,MAAM,WAAW,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,EAAE;AAAA,IACnD,EAAE,MAAM,cAAc,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI,GAAG,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,QAAQ,GAAG,OAAO,EAAE,EAAE;AAAA,EAC1G;AAAA,EACA,SAAS,CAAC,MAAM,OAAO,YAAY,SAAS,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAAA,EACrG,QAAQ;AAAA,IACN,KAAK,6XAA6X,SAAS,CAAC,CAAC,2UAA2U,MAAM;AAAA,IAC9tB,SAAS,SAAS,IAAI,CAAC,MAAM,OAAqB;AAAA,MAChD,IAAI;AAAA,MACJ,OAAO,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;AAAA,MAC5B,OAAOT,GAAE,KAAK,CAAC,EAAE;AAAA;AAAA,MAEjB,IAAI,MAAM,SAAS,SAAS,IAAIA,GAAE,MAAM,IAAI;AAAA,IAC9C,EAAE;AAAA,EACJ;AACF;AAGO,IAAM,eAA+B,CAAC,aAAa,cAAc,YAAY,YAAY,aAAa,aAAa,QAAQ;;;AC3uBlI,IAAMU,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAG/C,IAAMC,KAAI,CAAC,SAAiB,KAAK,IAAI;AAErC,IAAMC,QAAO;AAGb,IAAMC,UAAS,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,SAASC,KAAI,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,MAAMJ,IAAG,IAAI,GAAG,QAAQA,IAAG,IAAI,IAAI,EAAE;AAChD;AAKA,IAAM,QAAQ;AAEd,IAAM,YAAY;AAClB,IAAM,UAAU;AAOhB,SAAS,eAAe,GAA2B;AACjD,QAAMK,MAAK,CAACC,YAAmB,EAAE,GAAGN,IAAG,aAAa,UAAU,aAAaM,MAAK,GAAG,GAAG,KAAK,OAAO,IAAIA,UAAS,GAAG,IAAI,IAAI;AAC1H,QAAM,KAAK,oBAAoB,CAAC;AAChC,QAAM,QAAQ,IAAI;AAClB,QAAM,OAAOD,IAAG,KAAK;AACrB,QAAM,MAAMA,IAAG,CAAC;AAChB,QAAM,QAAQA,IAAG,CAAC;AAClB,QAAM,MAAsB;AAAA,IAC1B;AAAA,MACE;AAAA,MACA,OAAO,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,gBAAgB,CAACJ,GAAE,KAAK,CAAC,EAAE,GAAGA,GAAE,MAAM,CAAC,EAAE;AAAA,MAChG,IAAIA,GAAE,OAAO,CAAC,EAAE;AAAA,IAClB;AAAA,EACF;AACA,MAAI,QAAQ;AACV,QAAI,KAAK;AAAA,MACP;AAAA,MACA,OAAO,EAAE,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,gBAAgB,CAACA,GAAE,QAAQ,GAAGA,GAAE,KAAK,CAAC,EAAE,CAAC,EAAE;AAAA,MACtG,OAAOA,GAAE,OAAO,CAAC,EAAE;AAAA,MACnB,IAAIA,GAAE,OAAO,CAAC,EAAE;AAAA,IAClB,CAAC;AACH,SAAO;AACT;AAEO,IAAM,gBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,QAAQ,SAAS,UAAU,QAAQ,QAAQ,OAAO;AAAA,EACjE,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,MAAM,IAAI,GAAG,QAAQ,IAAI,EAAE;AAAA,IACtF,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,EAAE,EAAE;AAAA,IAClH,EAAE,MAAM,SAAS,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,MAAM,EAAE,EAAE;AAAA,EACnH;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,SAAS,KAAK,MAAM,OAAO,EAAE,MAAM,IAAI,GAAI;AACjD,UAAM,QAAQ,OAAO,EAAE,KAAK;AAC5B,UAAM,MAA8B,EAAE,MAAM,KAAK,MAAM,SAAS,CAAC,GAAG,QAAQD,IAAG,QAAQ,GAAG,GAAG,MAAMA,IAAG,QAAQ,GAAG,EAAE;AACnH,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAM,QAAQ,IAAI;AAClB,UAAI,OAAO,CAAC,EAAE,IAAI,KAAK,MAAM,UAAU,IAAI,MAAM;AACjD,UAAI,OAAO,CAAC,EAAE,IAAI,SAAS,IAAI,OAAO,CAAC,EAAE;AACzC,UAAI,KAAK,CAAC,EAAE,IAAIA,IAAG,SAAS,MAAM,MAAM,MAAM;AAAA,IAChD;AACA,WAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,83BAA83B,MAAM;AAAA,MACv4B,EAAE,QAAQ,MAAM;AAAA,MAChB,CAAC,GAAG,MAAM,gCAAgC,CAAC,0BAA0BA,IAAG,aAAc,UAAU,aAAa,IAAK,KAAK,CAAC,qDAAqD,CAAC,gBAAgB,KAAK,OAAO,IAAI,IAAI,SAAS,GAAG,IAAI,GAAG;AAAA,IACvO,EAAE,KAAK,EAAE,CAAC;AAAA,IACV,SAAS;AAAA,MACP,GAAG,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM,eAAe,CAAC,CAAC,EAAE,KAAK;AAAA;AAAA,MAEnE,EAAE,IAAI,qBAAqB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,IAAIC,GAAE,MAAM,GAAG,MAAM,SAAS;AAAA,MACjF,EAAE,IAAI,qBAAqB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,OAAOA,GAAE,MAAM,GAAG,IAAIA,GAAE,MAAM,GAAG,MAAM,SAAS;AAAA,IACrG;AAAA,EACF;AACF;AAKA,IAAM,WAAW,CAAC,MAAc,2BAA2B,CAAC;AAErD,IAAM,aAA2B;AAAA,EACtC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,QAAQ,UAAU,SAAS,eAAe,MAAM,OAAO,MAAM;AAAA,EACpE,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,UAAU,QAAQ,EAAE,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,IACzF,EAAE,MAAM,QAAQ,QAAQ,EAAE,QAAQ,CAAC,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG,OAAO,mBAAmB,EAAE;AAAA,IACvG,EAAE,MAAM,UAAU,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,GAAG,GAAG,OAAO,WAAW,EAAE;AAAA,EAC1E;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAIG,KAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAMJ,IAAG,KAAK,OAAO,IAAI,GAAG,QAAQG,QAAO,EAAE,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE;AAAA,EAC9F;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,4vBAA4vB,SAAS,CAAC,CAAC,qdAAqdD,KAAI;AAAA,IACruC,SAAS;AAAA,MACP,EAAE,IAAI,kBAAkB,OAAO,EAAE,SAAS,CAAC,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MACzH,EAAE,IAAI,oBAAoB,OAAO,EAAE,cAAc,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAClF,EAAE,IAAI,kBAAkB,OAAO,EAAE,WAAW,CAAC,kBAAkB,iBAAiB,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC1G,EAAE,IAAI,kBAAkB,OAAO,EAAE,MAAM,CAAC,cAAc,YAAY,EAAE,GAAG,IAAI,IAAI;AAAA,IACjF;AAAA,EACF;AACF;AAGO,IAAM,cAA8B,CAAC,eAAe,UAAU;;;ACtIrE,IAAMK,MAAK,CAAC,MAAc,KAAK,MAAM,IAAI,EAAE,IAAI;AAE/C,IAAMC,QAAO;AAGb,SAASC,KAAI,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,MAAMF,IAAG,IAAI,GAAG,QAAQA,IAAG,IAAI,IAAI,EAAE;AAChD;AAGA,IAAM,SAAS,CAAC,IAAY,UAAkB,eAAe,CAAC,EAAE,8BAA8B,KAAK;AAE5F,IAAM,WAAyB;AAAA,EACpC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM,CAAC,UAAU,QAAQ,SAAS,eAAe,aAAa,YAAY,MAAM,mBAAmB;AAAA,EACnG,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,IACP,EAAE,MAAM,QAAQ,QAAQ,EAAE,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,MAAM,CAAC,EAAE,EAAE;AAAA,IACvJ,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,mBAAmB,YAAY,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE;AAAA,EAC/I;AAAA,EACA,SAAS,CAAC,MAAM;AACd,UAAM,EAAE,MAAM,OAAO,IAAIE,KAAI,EAAE,OAAO,KAAK,EAAE;AAC7C,WAAO,EAAE,MAAM,QAAQ,MAAMF,IAAG,KAAK,OAAO,IAAI,EAAE;AAAA,EACpD;AAAA,EACA,QAAQ;AAAA,IACN,KAAK,0xBAA0xB,OAAO,IAAI,IAAI,CAAC,sMAAsM,OAAO,GAAG,CAAC,CAAC,6NAA6NC,KAAI;AAAA,IACluC,SAAS;AAAA,MACP,EAAE,IAAI,gBAAgB,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAClG,EAAE,IAAI,mBAAmB,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,GAAG,WAAW,CAAC,OAAO,IAAI,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3H,EAAE,IAAI,eAAe,OAAO,EAAE,SAAS,CAAC,MAAM,IAAI,GAAG,WAAW,CAAC,kBAAkB,gBAAgB,EAAE,GAAG,IAAI,KAAK,MAAM,MAAM;AAAA,IAC/H;AAAA,EACF;AACF;AAGO,IAAM,gBAAgC,CAAC,QAAQ;;;AC1CtD,IAAME,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,IAAMC,YAAW,CAAC,QAA0B,IAAI,IAAI,IAAI,CAAC,MAAM,GAAGD,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,IACEC,UAAS,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA,IAEzBA,UAAS,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,IAE9GA,UAAS,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,IACEA,UAAS,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;AAAA,IACjEA,UAAS,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IAClDA,UAAS,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,IACEA,UAAS,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;AAAA,IACxDA,UAAS,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;AAAA,IACxFA,UAAS,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,IAAMC,OAAM;AACZ,IAAM,QAAQ;AACd,IAAM,UAAU;AAGhB,IAAM,QAAQ,CAAC,OAAeA,QAAQ,QAAQA,QAAO,KAAK,IAAI,IAAI,IAAI,IAAK;AAG3E,IAAMC,QAAO,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,OAAOA,MAAK,GAAG,CAAC;AAC7C,QAAM,KAAK,IAAI,IAAI,IAAI,OAAO,OAAOA,MAAK,GAAG,CAAC;AAC9C,QAAM,OAAO,IAAI,IAAI,KAAKA,MAAK,GAAG,CAAC,IAAI,OAAO;AAC9C,SAAO,iBAAiBH,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,wwBAAwwBE,OAAM,EAAE,qIAAqIA,IAAG,wBAAwB,MAAMA,IAAG,gDAAgDA,IAAG,wBAAwB,MAAMA,IAAG,4BAA4B,MAAM;AAAA,MACljC,CAAC,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE,CAAC,QAAQA,IAAG;AAAA,IACpD,EAAE,KAAK,EAAE,CAAC,kCAAkCA,IAAG,uGAAuGA,IAAG,iFAAiFA,IAAG,kBAAkBA,OAAM,EAAE,0FAA0F,MAAM,IAAI,CAAC,CAAC;AAAA,IAC7W,SAAS;AAAA;AAAA,MAEP,EAAE,IAAI,QAAQ,OAAO,EAAE,GAAG,CAACA,MAAK,KAAK,GAAG,QAAQ,CAAC,MAAMA,MAAK,MAAM,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,MACtF,EAAE,IAAI,QAAQ,OAAO,EAAE,GAAG,CAAC,OAAOA,IAAG,GAAG,QAAQ,CAAC,MAAM,OAAO,MAAMA,IAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MACvF,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAACA,MAAK,KAAK,GAAG,QAAQ,CAAC,MAAMA,MAAK,MAAM,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,MACvF,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,CAAC,OAAOA,IAAG,GAAG,QAAQ,CAAC,MAAM,OAAO,MAAMA,IAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MACxF,GAAI,CAAC,OAAO,MAAM,EAAY,QAAQ,CAAC,OAAuB;AAAA,QAC5D,EAAE,IAAI,OAAO,EAAE,IAAI,CAACA,MAAK,KAAK,EAAE,GAAG,GAAG,OAAO;AAAA,QAC7C,EAAE,IAAI,OAAO,EAAE,IAAI,CAAC,OAAOA,IAAG,EAAE,GAAG,GAAG,QAAQ;AAAA,MAChD,CAAC;AAAA,MACD,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAACA,MAAK,KAAK,GAAG,IAAI,CAACA,OAAM,IAAI,QAAQ,EAAE,EAAE,GAAG,GAAG,OAAO;AAAA,MACjF,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,OAAOA,IAAG,GAAG,IAAI,CAAC,QAAQ,IAAIA,OAAM,EAAE,EAAE,GAAG,GAAG,QAAQ;AAAA,MAClF,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAACA,OAAM,IAAI,QAAQ,EAAE,EAAE,GAAG,GAAG,OAAO;AAAA,MAC/D,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAIA,OAAM,EAAE,EAAE,GAAG,GAAG,QAAQ;AAAA;AAAA,MAEhE,GAAG,MAAM,QAAQ,CAAC,GAAG,MAAsB;AAAA,QACzC,EAAE,IAAI,OAAO,CAAC,IAAI,OAAO,EAAE,GAAG,CAACA,MAAK,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,OAAOA,IAAG,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,IAAIF,IAAG,MAAM,MAAMG,MAAK,IAAI,GAAG,CAAC,CAAC,IAAI,KAAKH,IAAG,MAAM,MAAMG,MAAK,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,CAACH,IAAG,MAAM,MAAMG,MAAK,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,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","names":["HEART","at","room","circle","r2","n","s","d","at","r1","r2","n","about","snap","SANS","at","DROPS","pose","_","r1","r2","n","fit","HEART","snap","at","r1","r2","n","outline","star","DOTS","k","r2","about","snap","SANS","CX","CY","r1","r2","n","about","snap","at","outline","star","lines","round","_","HEART","r1","n","SANS","mixHex","fit","at","phase","r1","SANS","fit","r1","about","snap","SANS","at","stroke","r2","polyline","TOP","rand","n","r2","n","snap","SPARKLE","pose","at","HEART","heartPose","_","DOTS","n","at","stroke","r1","n","at","DEG","r2","n","polyline","arc","circle","star","r1","HEART","outline","pair","pose","at","stages","DOTS","_","OVER","OVER","SMIN","HOVER","OVER","GLOW","OVER","SEGMENT","SMIN","GLOW","OVER","GLOW","OVER","SEGMENT","GLOW","GLOW","OVER","CLICKS","OVER","OVER","GLOW","n","r1","n","fit","mixHex","keys","HEAVY","SANS","SLOTS","at","rand","link","DRIPS","r1","n","outline","at"]}