@pixerate/flair 0.7.0 → 0.9.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/morph.ts","../src/catalog/shaders/morph.ts","../src/catalog/shaders/overlay.ts","../src/catalog/shaders/retro.ts","../src/catalog/shaders/text.ts","../src/catalog/shaders/treatments.ts","../src/catalog/text.ts","../src/catalog/types.ts","../src/catalog/vector.ts","../src/catalog/index.ts"],"sourcesContent":["/**\n * GLSL helpers the catalog's shaders are built from. Each effect's source\n * inlines the helpers it uses, so a source stays self-contained: copy it into\n * any Shadertoy-style host and it compiles.\n */\n\n/** Hashes: `hash12` (vec2 → float), `hash22` (vec2 → vec2), both 0–1. */\nexport const HASH = `\nfloat hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\nvec2 hash22(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.xx + p3.yz) * p3.zy);\n}`.trim();\n\n/** Smooth value noise, 0–1 (needs {@link HASH}). */\nexport const NOISE = `\nfloat vnoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n float a = hash12(i);\n float b = hash12(i + vec2(1.0, 0.0));\n float c = hash12(i + vec2(0.0, 1.0));\n float d = hash12(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}`.trim();\n\n/** Fractal noise: `fbm(p, octaves)`, about 0–1 (needs {@link NOISE}). */\nexport const FBM = `\nfloat fbm(vec2 p, int octaves) {\n float sum = 0.0;\n float amp = 0.5;\n mat2 turn = mat2(0.8, 0.6, -0.6, 0.8);\n for (int i = 0; i < 8; i++) {\n if (i >= octaves) break;\n sum += amp * vnoise(p);\n p = turn * p * 2.02 + 17.0;\n amp *= 0.5;\n }\n return sum;\n}`.trim();\n\n/** Inigo Quilez's cosine palette: `palette(t, a, b, c, d)`. */\nexport const PALETTE = `\nvec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {\n return a + b * cos(6.28318 * (c * t + d));\n}`.trim();\n\n/** Mixes colours in Oklab, so blends stay bright: `oklabMix(a, b, t)` on sRGB colours. */\nexport const OKLAB_MIX = `\nvec3 toOklab(vec3 c) {\n c = pow(max(c, 0.0), vec3(2.2));\n vec3 lms = mat3(0.4122, 0.2119, 0.0883, 0.5363, 0.6807, 0.2817, 0.0514, 0.1074, 0.6300) * c;\n lms = pow(lms, vec3(1.0 / 3.0));\n return mat3(0.2105, 1.9780, 0.0259, 0.7936, -2.4286, 0.7828, -0.0041, 0.4506, -0.8087) * lms;\n}\nvec3 fromOklab(vec3 c) {\n vec3 lms = mat3(1.0, 1.0, 1.0, 0.3963, -0.1056, -0.0895, 0.2158, -0.0639, -1.2915) * c;\n lms = lms * lms * lms;\n vec3 rgb = mat3(4.0767, -1.2684, -0.0042, -3.3077, 2.6098, -0.7034, 0.2310, -0.3413, 1.7076) * lms;\n return pow(max(rgb, 0.0), vec3(1.0 / 2.2));\n}\nvec3 oklabMix(vec3 a, vec3 b, float t) {\n return fromOklab(mix(toOklab(a), toOklab(b), t));\n}`.trim();\n\n/** 2D rotation matrix: `rot(angle)`. */\nexport const ROTATE = `\nmat2 rot(float a) {\n float c = cos(a);\n float s = sin(a);\n return mat2(c, s, -s, c);\n}`.trim();\n\n/** Joins helpers and a body into one source, a blank line apart. */\nexport function glsl(...parts: string[]): string {\n return parts.map((p) => p.trim()).join(\"\\n\\n\") + \"\\n\";\n}\n","import { FBM, glsl, HASH, NOISE, OKLAB_MIX, ROTATE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const aurora: ShaderEffect = {\n kind: \"shader\",\n id: \"aurora\",\n name: \"Aurora\",\n description: \"Soft curtains of light drifting over a night sky.\",\n category: \"gradient\",\n tags: [\"background\", \"hero\", \"calm\", \"night\"],\n source: glsl(\n `// Aurora: curtains of light drifting over a night sky.\nuniform vec3 uSky; // @control color default=#050816 label=\"Sky\"\nuniform vec3 uGlowA; // @control color default=#22D3A6 label=\"Glow A\"\nuniform vec3 uGlowB; // @control color default=#7C3AED label=\"Glow B\"\nuniform float uSpeed; // @control min=0 max=2 default=0.35 label=\"Speed\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"\nuniform float uHeight; // @control min=0 max=1 default=0.55 label=\"Height\"`,\n HASH,\n NOISE,\n FBM,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n vec3 col = uSky * (0.6 + 0.4 * uv.y);\n for (int i = 0; i < 3; i++) {\n float fi = float(i);\n float x = uv.x * (1.4 + 0.3 * fi) + fi * 3.7;\n float wave = fbm(vec2(x * 1.5 + t * 0.4, t * 0.25 + fi), 4);\n float centre = uHeight + 0.18 * (wave - 0.5) + 0.06 * fi;\n float band = exp(-pow((uv.y - centre) * (7.0 + 2.0 * fi), 2.0));\n float rays = 0.55 + 0.45 * fbm(vec2(x * 12.0, t * 0.6 + fi * 9.0), 3);\n float above = smoothstep(centre - 0.05, centre + 0.35, uv.y) * 0.35;\n vec3 glow = mix(uGlowA, uGlowB, clamp(uv.y * 1.4 - 0.2 + 0.25 * fi, 0.0, 1.0));\n col += glow * (band * rays + above * band) * 0.6 * uIntensity;\n }\n float stars = step(0.997, hash12(floor(fragCoord * 0.5))) * smoothstep(0.3, 1.0, uv.y);\n col += stars * 0.6 * (0.5 + 0.5 * sin(iTime * 3.0 + hash12(floor(fragCoord)) * 40.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Arctic\", values: { uGlowA: [0.13, 0.83, 0.65], uGlowB: [0.49, 0.23, 0.93] } },\n { name: \"Ember\", values: { uSky: [0.06, 0.02, 0.03], uGlowA: [1, 0.45, 0.1], uGlowB: [0.9, 0.1, 0.4] } },\n { name: \"Ice\", values: { uSky: [0.01, 0.03, 0.06], uGlowA: [0.5, 0.9, 1], uGlowB: [0.2, 0.4, 1] } },\n ],\n};\n\nexport const meshGradient: ShaderEffect = {\n kind: \"shader\",\n id: \"mesh-gradient\",\n name: \"Mesh gradient\",\n description: \"Four colours blended across a slowly warping mesh, mixed in Oklab.\",\n category: \"gradient\",\n tags: [\"background\", \"hero\", \"brand\", \"soft\"],\n source: glsl(\n `// Mesh gradient: four colours on drifting points, blended in Oklab.\nuniform vec3 uColorA; // @control color default=#FF6B6B label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#FFD93D label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#6BCB77 label=\"Colour C\"\nuniform vec3 uColorD; // @control color default=#4D96FF label=\"Colour D\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Speed\"\nuniform float uWarp; // @control min=0 max=1 default=0.35 label=\"Warp\"\nuniform float uGrain; // @control min=0 max=0.2 default=0.04 label=\"Grain\"`,\n HASH,\n NOISE,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = iTime * uSpeed;\n vec2 w = uv + uWarp * 0.3 * vec2(vnoise(uv * 2.0 + t), vnoise(uv * 2.0 - t + 5.0)) - uWarp * 0.15;\n vec2 pa = vec2(0.2, 0.2) + 0.15 * vec2(sin(t * 1.1), cos(t * 0.9));\n vec2 pb = vec2(0.8, 0.25) + 0.15 * vec2(cos(t * 0.7), sin(t * 1.3));\n vec2 pc = vec2(0.25, 0.8) + 0.15 * vec2(sin(t * 0.8 + 2.0), cos(t * 1.2));\n vec2 pd = vec2(0.8, 0.8) + 0.15 * vec2(cos(t * 1.0 + 1.0), sin(t * 0.6));\n vec4 d = vec4(distance(w, pa), distance(w, pb), distance(w, pc), distance(w, pd));\n vec4 k = 1.0 / (d * d + 0.02);\n k /= dot(k, vec4(1.0));\n vec3 ab = oklabMix(uColorA, uColorB, k.y / max(k.x + k.y, 1e-4));\n vec3 cd = oklabMix(uColorC, uColorD, k.w / max(k.z + k.w, 1e-4));\n vec3 col = oklabMix(ab, cd, k.z + k.w);\n col += (hash12(fragCoord + fract(iTime) * 100.0) - 0.5) * uGrain;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Sunset\", values: { uColorA: [1, 0.42, 0.42], uColorB: [1, 0.85, 0.24], uColorC: [0.9, 0.3, 0.6], uColorD: [0.36, 0.2, 0.7] } },\n { name: \"Lagoon\", values: { uColorA: [0.0, 0.6, 0.7], uColorB: [0.5, 0.95, 0.85], uColorC: [0.1, 0.3, 0.6], uColorD: [0.85, 0.95, 1] } },\n { name: \"Mono\", values: { uColorA: [0.1, 0.1, 0.12], uColorB: [0.3, 0.3, 0.34], uColorC: [0.2, 0.2, 0.24], uColorD: [0.6, 0.6, 0.65] } },\n ],\n};\n\nexport const conicSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"conic-sweep\",\n name: \"Conic sweep\",\n description: \"A rotating conic gradient with a soft glowing core.\",\n category: \"gradient\",\n tags: [\"background\", \"spotlight\", \"brand\"],\n loop: 10,\n source: glsl(\n `// Conic sweep: a rotating conic gradient with a glowing core.\nuniform vec3 uColorA; // @control color default=#0EA5E9 label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#A855F7 label=\"Colour B\"\nuniform vec3 uColorC; // @control color default=#F43F5E label=\"Colour C\"\nuniform float uTurns; // @control min=-3 max=3 default=1 step=1 label=\"Turns per loop\"\nuniform float uCore; // @control min=0 max=1 default=0.4 label=\"Core glow\"\nuniform vec2 uCenter; // @control min=-0.5 max=0.5 default=0,0 label=\"Centre\"`,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y - uCenter;\n float a = atan(p.y, p.x) / 6.28318 + 0.5;\n a = fract(a + iTime * uTurns / 10.0);\n float s = a * 3.0;\n vec3 col = s < 1.0 ? oklabMix(uColorA, uColorB, s)\n : s < 2.0 ? oklabMix(uColorB, uColorC, s - 1.0)\n : oklabMix(uColorC, uColorA, s - 2.0);\n float r = length(p);\n col *= 0.75 + 0.25 * smoothstep(0.9, 0.0, r);\n col += uCore * exp(-r * 6.0);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const silk: ShaderEffect = {\n kind: \"shader\",\n id: \"silk\",\n name: \"Silk\",\n description: \"Folds of glossy fabric rippling in a slow breeze.\",\n category: \"gradient\",\n tags: [\"background\", \"luxury\", \"soft\"],\n source: glsl(\n `// Silk: glossy folds of fabric rippling slowly.\nuniform vec3 uBase; // @control color default=#3B0764 label=\"Base\"\nuniform vec3 uSheen; // @control color default=#F0ABFC label=\"Sheen\"\nuniform float uSpeed; // @control min=0 max=2 default=0.4 label=\"Speed\"\nuniform float uFolds; // @control min=1 max=10 default=5 label=\"Folds\"\nuniform float uGloss; // @control min=0 max=2 default=1 label=\"Gloss\"`,\n ROTATE,\n `float folds(vec2 p, float t) {\n float h = 0.0;\n for (int i = 1; i <= 4; i++) {\n float fi = float(i);\n h += sin(p.x * uFolds * fi * 0.7 + t * (1.0 + 0.3 * fi) + sin(p.y * 2.0 * fi + t)) / fi;\n }\n return h;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = rot(0.6) * (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float e = 0.002;\n float hx = (folds(p + vec2(e, 0.0), t) - folds(p - vec2(e, 0.0), t)) / (2.0 * e);\n float hy = (folds(p + vec2(0.0, e), t) - folds(p - vec2(0.0, e), t)) / (2.0 * e);\n vec3 n = normalize(vec3(-hx * 0.12, -hy * 0.12, 1.0));\n vec3 l = normalize(vec3(-0.4, 0.6, 0.7));\n float diff = clamp(dot(n, l), 0.0, 1.0);\n float spec = pow(clamp(dot(reflect(-l, n), vec3(0.0, 0.0, 1.0)), 0.0, 1.0), 20.0) * uGloss;\n vec3 col = uBase * (0.35 + 0.9 * diff) + uSheen * (spec + 0.12 * pow(diff, 6.0));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Champagne\", values: { uBase: [0.55, 0.42, 0.25], uSheen: [1, 0.95, 0.8] } },\n { name: \"Midnight\", values: { uBase: [0.04, 0.08, 0.2], uSheen: [0.6, 0.75, 1] } },\n ],\n};\n\nexport const duotoneFlow: ShaderEffect = {\n kind: \"shader\",\n id: \"gradient-flow\",\n name: \"Gradient flow\",\n description: \"Two colours flowing through each other along a warped noise field.\",\n category: \"gradient\",\n tags: [\"background\", \"brand\", \"liquid\"],\n source: glsl(\n `// Gradient flow: two colours flowing through a warped noise field.\nuniform vec3 uColorA; // @control color default=#1E3A8A label=\"Colour A\"\nuniform vec3 uColorB; // @control color default=#F97316 label=\"Colour B\"\nuniform float uSpeed; // @control min=0 max=2 default=0.25 label=\"Speed\"\nuniform float uScale; // @control min=0.5 max=6 default=2 label=\"Scale\"\nuniform float uContrast; // @control min=0.5 max=4 default=1.5 label=\"Contrast\"`,\n HASH,\n NOISE,\n FBM,\n OKLAB_MIX,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y * uScale;\n float t = iTime * uSpeed;\n vec2 q = vec2(fbm(p + t, 4), fbm(p + vec2(5.2, 1.3) - t, 4));\n float f = fbm(p + 3.0 * q + vec2(1.7, 9.2) + 0.5 * t, 5);\n f = clamp((f - 0.5) * uContrast + 0.5, 0.0, 1.0);\n fragColor = vec4(oklabMix(uColorA, uColorB, smoothstep(0.0, 1.0, f)), 1.0);\n}`,\n ),\n};\n","/**\n * Sample pictures for the catalog's image effects: small SVGs as `data:` URLs,\n * so image controls have something to show with nothing to download.\n */\n\n/** An ASCII SVG as a base64 `data:image/svg+xml` URL. */\nexport function svgDataUrl(svg: string): string {\n const base64 =\n typeof btoa === \"function\" ? btoa(svg) : (globalThis as { Buffer?: { from(s: string): { toString(e: string): string } } }).Buffer!.from(svg).toString(\"base64\");\n return `data:image/svg+xml;base64,${base64}`;\n}\n\nconst LANDSCAPE = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<defs><linearGradient id=\"s\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#3b4cb8\"/><stop offset=\"1\" stop-color=\"#ffa36b\"/></linearGradient></defs>\n<rect width=\"640\" height=\"360\" fill=\"url(#s)\"/>\n<circle cx=\"420\" cy=\"170\" r=\"62\" fill=\"#ffe9b0\"/>\n<path d=\"M0 250 Q120 190 240 240 T480 230 T640 220 V360 H0Z\" fill=\"#2c4a52\"/>\n<path d=\"M0 290 Q160 240 320 290 T640 280 V360 H0Z\" fill=\"#1b2f33\"/>\n<path d=\"M0 330 Q200 300 400 330 T640 325 V360 H0Z\" fill=\"#0f1c1f\"/>\n</svg>`;\n\nconst CITY = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<rect width=\"640\" height=\"360\" fill=\"#0d1028\"/>\n<circle cx=\"520\" cy=\"80\" r=\"34\" fill=\"#f5f3d7\"/>\n<g fill=\"#252a52\"><rect x=\"20\" y=\"170\" width=\"70\" height=\"190\"/><rect x=\"110\" y=\"120\" width=\"60\" height=\"240\"/><rect x=\"190\" y=\"200\" width=\"80\" height=\"160\"/><rect x=\"290\" y=\"90\" width=\"55\" height=\"270\"/><rect x=\"365\" y=\"160\" width=\"90\" height=\"200\"/><rect x=\"475\" y=\"130\" width=\"60\" height=\"230\"/><rect x=\"555\" y=\"190\" width=\"70\" height=\"170\"/></g>\n<g fill=\"#ffcf5a\"><rect x=\"125\" y=\"140\" width=\"8\" height=\"8\"/><rect x=\"150\" y=\"170\" width=\"8\" height=\"8\"/><rect x=\"305\" y=\"110\" width=\"8\" height=\"8\"/><rect x=\"320\" y=\"150\" width=\"8\" height=\"8\"/><rect x=\"380\" y=\"180\" width=\"8\" height=\"8\"/><rect x=\"420\" y=\"220\" width=\"8\" height=\"8\"/><rect x=\"490\" y=\"150\" width=\"8\" height=\"8\"/><rect x=\"40\" y=\"200\" width=\"8\" height=\"8\"/><rect x=\"215\" y=\"230\" width=\"8\" height=\"8\"/><rect x=\"575\" y=\"215\" width=\"8\" height=\"8\"/></g>\n</svg>`;\n\nconst PORTRAIT = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\">\n<rect width=\"640\" height=\"360\" fill=\"#f2e6d8\"/>\n<circle cx=\"320\" cy=\"150\" r=\"70\" fill=\"#c98b6b\"/>\n<path d=\"M190 360 Q200 240 320 240 Q440 240 450 360Z\" fill=\"#33415c\"/>\n<path d=\"M250 130 Q260 60 320 62 Q385 60 392 135 Q370 100 320 100 Q275 100 250 130Z\" fill=\"#2b1d16\"/>\n<circle cx=\"295\" cy=\"150\" r=\"6\" fill=\"#2b1d16\"/><circle cx=\"345\" cy=\"150\" r=\"6\" fill=\"#2b1d16\"/>\n<path d=\"M300 185 Q320 198 340 185\" stroke=\"#7a3e2c\" stroke-width=\"5\" fill=\"none\"/>\n</svg>`;\n\n// A second portrait, the face larger and right of centre, for morphing with PORTRAIT.\n// Features (viewBox units): eyes (396, 175) and (464, 175), mouth (430, 229), chin (430, 270), hairline (430, 80).\nconst PORTRAIT_2 = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 360\" width=\"640\" height=\"360\">\n<rect width=\"640\" height=\"360\" fill=\"#d3e4e6\"/>\n<path d=\"M255 360 Q268 300 430 297 Q592 300 605 360Z\" fill=\"#a4372f\"/>\n<rect x=\"408\" y=\"250\" width=\"44\" height=\"52\" fill=\"#d9a07c\"/>\n<circle cx=\"430\" cy=\"175\" r=\"95\" fill=\"#e8b48f\"/>\n<path d=\"M332 172 Q330 66 430 64 Q530 66 528 172 Q520 112 470 100 Q420 128 352 116 Q336 140 332 172Z\" fill=\"#8a3b1e\"/>\n<circle cx=\"396\" cy=\"175\" r=\"8\" fill=\"#3a2418\"/><circle cx=\"464\" cy=\"175\" r=\"8\" fill=\"#3a2418\"/>\n<path d=\"M424 186 Q430 206 436 186\" stroke=\"#c48262\" stroke-width=\"5\" fill=\"none\"/>\n<path d=\"M403 225 Q430 244 457 225\" stroke=\"#9c4a35\" stroke-width=\"7\" fill=\"none\" stroke-linecap=\"round\"/>\n</svg>`;\n\n// Flat shapes on transparent, for silhouette morphs and masks.\nconst LOGO = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" width=\"512\" height=\"512\">\n<path fill=\"#6366f1\" fill-rule=\"evenodd\" d=\"M256 56a200 200 0 1 1 0 400a200 200 0 1 1 0-400zm0 92a108 108 0 1 0 0 216a108 108 0 1 0 0-216z\"/>\n<circle cx=\"256\" cy=\"256\" r=\"52\" fill=\"#6366f1\"/>\n</svg>`;\n\nconst HEART = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" width=\"512\" height=\"512\">\n<path fill=\"#f43f5e\" d=\"M256 452C120 352 40 272 40 172C40 102 95 58 160 58C205 58 238 84 256 118C274 84 307 58 352 58C417 58 472 102 472 172C472 272 392 352 256 452Z\"/>\n</svg>`;\n\n/** 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} 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 * `picture(tex, uv)`: the image, or a test card while there is none (an empty\n * image control is bound to a 1 × 1 placeholder), so effects show something\n * before an image is chosen.\n */\nexport const PICTURE = `\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}\nvec3 picture(sampler2D tex, vec2 uv) {\n return textureSize(tex, 0).x > 1 ? texture(tex, uv).rgb : testCard(fract(uv));\n}`.trim();\n\nexport const imageRipple: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ripple\",\n name: \"Ripple\",\n description: \"An image rippling as if seen through water, from the pointer or the centre.\",\n category: \"image\",\n tags: [\"image\", \"water\", \"interactive\", \"distortion\"],\n source: glsl(\n `// Ripple: an image rippling as if under water.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmplitude; // @control min=0 max=0.05 default=0.012 label=\"Amplitude\"\nuniform float uFrequency; // @control min=5 max=80 default=30 label=\"Frequency\"\nuniform float uSpeed; // @control min=0 max=6 default=2 label=\"Speed\"`,\n 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 vec3 col = picture(uImage, uv + offset);\n col += 0.6 * max(wave, 0.0) * uAmplitude * 8.0;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const imageGlitch: ShaderEffect = {\n kind: \"shader\",\n id: \"image-glitch\",\n name: \"Glitch\",\n description: \"Digital glitch on an image: RGB split, slice displacement and blocky corruption in bursts.\",\n category: \"image\",\n tags: [\"image\", \"glitch\", \"cyber\", \"transition\"],\n source: glsl(\n `// Glitch: RGB split, slice displacement and blocky corruption in bursts.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmount; // @control min=0 max=1 default=0.5 label=\"Amount\"\nuniform float uSplit; // @control min=0 max=0.05 default=0.012 label=\"RGB split\"\nuniform float uRate; // @control min=0.5 max=12 default=4 label=\"Bursts per second\"`,\n 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 vec3 col = vec3(\n picture(uImage, st + vec2(split, 0.0)).r,\n picture(uImage, st).g,\n picture(uImage, st - vec2(split, 0.0)).b\n );\n col = mix(col, col.bgr, corrupt);\n col *= 0.92 + 0.08 * sin(fragCoord.y * 2.0);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const imageDuotone: ShaderEffect = {\n kind: \"shader\",\n id: \"image-duotone\",\n name: \"Duotone\",\n description: \"An image mapped onto two colours, with a slow light sweep.\",\n category: \"image\",\n tags: [\"image\", \"brand\", \"editorial\", \"colour\"],\n source: glsl(\n `// Duotone: an image mapped onto two colours, with a light sweep.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uShadow; // @control color default=#1E1B4B label=\"Shadows\"\nuniform vec3 uHighlight; // @control color default=#FB7185 label=\"Highlights\"\nuniform float uContrast; // @control min=0.5 max=3 default=1.2 label=\"Contrast\"\nuniform float uSweep; // @control min=0 max=1 default=0.3 label=\"Light sweep\"`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec3 src = picture(uImage, uv);\n float l = dot(src, vec3(0.2126, 0.7152, 0.0722));\n l = clamp((l - 0.5) * uContrast + 0.5, 0.0, 1.0);\n float sweep = exp(-pow((uv.x + uv.y * 0.4 - fract(iTime * 0.15) * 2.0 + 0.4) * 6.0, 2.0));\n vec3 col = mix(uShadow, uHighlight, l) + sweep * uSweep;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Spotify\", values: { uShadow: [0.07, 0.1, 0.35], uHighlight: [0.12, 0.84, 0.38] } },\n { name: \"Newsprint\", values: { uShadow: [0.1, 0.1, 0.1], uHighlight: [0.96, 0.94, 0.88] } },\n ],\n};\n\nexport const imagePixelate: ShaderEffect = {\n kind: \"shader\",\n id: \"image-pixelate\",\n name: \"Pixel reveal\",\n description: \"An image resolving from big blocks to full detail, then back, in a loop.\",\n category: \"image\",\n tags: [\"image\", \"reveal\", \"transition\", \"8-bit\"],\n loop: 4,\n source: glsl(\n `// Pixel reveal: an image resolving from blocks to full detail and back.\nuniform sampler2D uImage; // @control filter=nearest wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uMaxBlock; // @control min=4 max=128 default=48 label=\"Largest block (px)\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=1 label=\"Detail (when still)\"`,\n 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 vec3 col = picture(uImage, cell / iResolution.xy);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const imageHalftone: ShaderEffect = {\n kind: \"shader\",\n id: \"image-halftone\",\n name: \"Halftone\",\n description: \"An image printed as rotated halftone dots, breathing slightly.\",\n category: \"image\",\n tags: [\"image\", \"print\", \"comic\", \"pop-art\"],\n source: glsl(\n `// Halftone: an image as rotated print dots.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform vec3 uInk; // @control color default=#111827 label=\"Ink\"\nuniform vec3 uPaper; // @control color default=#FEF3C7 label=\"Paper\"\nuniform float uSpacing; // @control min=3 max=30 default=8 label=\"Dot spacing (px)\"\nuniform float uAngle; // @control min=0 max=90 default=45 label=\"Screen angle (°)\"`,\n 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 float l = dot(picture(uImage, centre / iResolution.xy), 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), 1.0);\n}`,\n ),\n};\n\nexport const crt: ShaderEffect = {\n kind: \"shader\",\n id: \"crt\",\n name: \"CRT screen\",\n description: \"An image on a curved CRT: scanlines, shadow mask, bloom and flicker.\",\n category: \"image\",\n tags: [\"image\", \"retro\", \"screen\", \"arcade\"],\n source: glsl(\n `// CRT screen: an image on a curved tube with scanlines and a shadow mask.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uCurve; // @control min=0 max=0.5 default=0.15 label=\"Curvature\"\nuniform float uScanlines; // @control min=0 max=1 default=0.5 label=\"Scanlines\"\nuniform float uMask; // @control min=0 max=1 default=0.35 label=\"Shadow mask\"\nuniform float uFlicker; // @control min=0 max=0.2 default=0.03 label=\"Flicker\"`,\n 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, 1.0);\n return;\n }\n vec3 col = picture(uImage, st);\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, 1.0);\n}`,\n ),\n};\n\nexport const filmGrain: ShaderEffect = {\n kind: \"shader\",\n id: \"film-look\",\n name: \"Film look\",\n description: \"An image graded like film: grain, gate weave, halation and vignette.\",\n category: \"image\",\n tags: [\"image\", \"cinematic\", \"grain\", \"vintage\"],\n source: glsl(\n `// Film look: grain, gate weave, halation and vignette.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uGrain; // @control min=0 max=0.3 default=0.08 label=\"Grain\"\nuniform float uWeave; // @control min=0 max=0.01 default=0.0015 label=\"Gate weave\"\nuniform float uHalation; // @control min=0 max=1 default=0.3 label=\"Halation\"\nuniform float uVignette; // @control min=0 max=1 default=0.45 label=\"Vignette\"\nuniform vec3 uTint; // @control color default=#FFF1DC label=\"Print tint\"`,\n 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 vec3 col = picture(uImage, uv);\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, 1.0);\n}`,\n ),\n};\n\nconst TRANSITIONS: { type: TransitionType; id: string; name: string; description: string }[] = [\n { type: \"linearWipe\", id: \"wipe\", name: \"Wipe\", description: \"A soft-edged wipe from one image to the next.\" },\n { type: \"radialIris\", id: \"iris\", name: \"Iris\", description: \"A circle opening from the centre onto the next image.\" },\n { type: \"blockDissolve\", id: \"block-dissolve\", name: \"Block dissolve\", description: \"Random blocks switching to the next image.\" },\n { type: \"gridWipe\", id: \"grid-wipe\", name: \"Grid wipe\", description: \"A diagonal cascade of cells revealing the next image.\" },\n { type: \"glassWipe\", id: \"glass-wipe\", name: \"Glass wipe\", description: \"A refracting glass edge sweeping across.\" },\n { type: \"twister\", id: \"twister\", name: \"Twister\", description: \"A swirl that twists one image into the next.\" },\n { type: \"lightLeak\", id: \"light-leak\", name: \"Light leak\", description: \"A warm flare of light burning through to the next image.\" },\n { type: \"crossZoom\", id: \"cross-zoom\", name: \"Cross zoom\", description: \"A zoom blur punching through to the next image.\" },\n];\n\n/** The transitions (see `getTransitionGLSL`) as looping effects between two images. */\nexport const transitions: ShaderEffect[] = TRANSITIONS.map(({ type, id, name, description }) => ({\n kind: \"shader\",\n id: `transition-${id}`,\n name,\n description: `${description} Loops back and forth; or turn Animate off and set Progress.`,\n category: \"transition\",\n tags: [\"transition\", \"image\", \"slideshow\"],\n loop: 4,\n source: glsl(\n `// ${name} transition between two images. Progress runs 0 → 1 → 0 when animated.\nuniform sampler2D uFrom; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"From image\"\nuniform sampler2D uTo; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"To image\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"`,\n 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 = vec4(flair_transition(uFrom, uTo, uv, p).rgb, 1.0);\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 { 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, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES, textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { 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)`: 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\nvec3 cover(sampler2D tex, vec2 uv) {\n return picture(tex, 0.5 + (uv - 0.5) * coverScale(tex));\n}\n\nfloat luma(vec3 c) {\n return dot(c, vec3(0.2126, 0.7152, 0.0722));\n}`.trim();\n\nexport const featureMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"feature-morph\",\n name: \"Feature morph\",\n description: \"The classic face morph: two pictures warp so five matching points (eyes, mouth, chin, hairline) meet while they cross-fade.\",\n category: \"morph\",\n tags: [\"morph\", \"face\", \"warp\", \"image\", \"transition\"],\n loop: 4,\n source: glsl(\n `// Feature morph: both images warp towards in-between positions of five matching points while they cross-fade.\n${pair(SAMPLE_IMAGES.portrait, SAMPLE_IMAGES.portrait2)}\nuniform vec2 uFromA; // @control min=0 max=1 default=0.461,0.583 label=\"From: left eye\"\nuniform vec2 uFromB; // @control min=0 max=1 default=0.539,0.583 label=\"From: right eye\"\nuniform vec2 uFromC; // @control min=0 max=1 default=0.5,0.472 label=\"From: mouth\"\nuniform vec2 uFromD; // @control min=0 max=1 default=0.5,0.389 label=\"From: chin\"\nuniform vec2 uFromE; // @control min=0 max=1 default=0.5,0.778 label=\"From: hairline\"\nuniform vec2 uToA; // @control min=0 max=1 default=0.619,0.514 label=\"To: left eye\"\nuniform vec2 uToB; // @control min=0 max=1 default=0.725,0.514 label=\"To: right eye\"\nuniform vec2 uToC; // @control min=0 max=1 default=0.672,0.364 label=\"To: mouth\"\nuniform vec2 uToD; // @control min=0 max=1 default=0.672,0.25 label=\"To: chin\"\nuniform vec2 uToE; // @control min=0 max=1 default=0.672,0.778 label=\"To: hairline\"\nuniform bool uShowPoints; // @control default=false label=\"Show points\"`,\n 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 vec3 colA = picture(uFrom, toImage(warp(x, m, a), scaleA));\n vec3 colB = picture(uTo, toImage(warp(x, m, b), scaleB));\n vec3 col = mix(colA, colB, smoothstep(0.2, 0.8, t));\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 col = mix(col, vec3(0.0), smoothstep(px * 1.5, 0.0, abs(d - 0.012)) * 0.6);\n col = mix(col, vec3(1.0, 0.85, 0.2), smoothstep(px, 0.0, abs(d - 0.012)));\n }\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [{ name: \"Show points\", values: { uShowPoints: true, uAnimate: false, uProgress: 0.5 } }],\n};\n\nexport const silhouetteMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"silhouette-morph\",\n name: \"Silhouette morph\",\n description: \"One silhouette or logo flowing into another as a gooey blob, its colour blending from the first shape's to the second's.\",\n category: \"morph\",\n tags: [\"morph\", \"shape\", \"logo\", \"goo\", \"blob\", \"text\"],\n loop: 4,\n source: glsl(\n `// Silhouette morph: blurred alpha masks of two shapes mixed by progress and thresholded, so one flows into the other.\nuniform sampler2D uFrom; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.logo} label=\"From shape\"\nuniform sampler2D uTo; // @control filter=mipmap wrap=clamp default=${SAMPLE_IMAGES.heart} label=\"To shape\"\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uSize; // @control min=0.2 max=1 default=0.75 label=\"Shape size\"\nuniform float uGoo; // @control min=0 max=0.3 default=0.1 label=\"Gooeyness\"\nuniform float uEdge; // @control min=0 max=0.05 default=0.004 label=\"Edge softness\"\nuniform bool uImageColours; // @control default=true label=\"Use the shapes' own colours\"\nuniform vec3 uColourA; // @control color default=#6366F1 label=\"From colour\"\nuniform vec3 uColourB; // @control color default=#F43F5E label=\"To colour\"\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"`,\n `// A shape's colour (premultiplied) and alpha at frame point p (height 1, centred), the image contained in\n// uSize of the frame, read from a mip level about as coarse as the spacing (in frame units), so sparse blur\n// taps still sum smoothly. With no image, a disc (fallback 0) or a rounded square (1).\nvec4 shapeAt(sampler2D tex, vec2 p, float spacing, int fallback) {\n vec2 size = vec2(textureSize(tex, 0));\n if (size.x <= 1.0) {\n float d = fallback == 0 ? length(p) - 0.3 * uSize : length(max(abs(p) - 0.2 * uSize, 0.0)) - 0.08 * uSize;\n float a = step(d, 0.0);\n return vec4(vec3(a), a);\n }\n float aspect = size.x / size.y;\n float h = min(uSize, iResolution.x / iResolution.y * uSize / aspect);\n vec2 uv = p / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return vec4(0.0);\n vec4 c = textureLod(tex, uv, log2(max(spacing * size.y / h, 1.0)));\n // Clear texels upload black, so filtered colour is already about colour × alpha: divide it out, then weight by alpha.\n return vec4(clamp(c.rgb / max(c.a, 1e-3), 0.0, 1.0) * c.a, c.a);\n}\n\n// A disc blur of the shape: 28 taps on a golden-angle spiral.\nvec4 blurred(sampler2D tex, vec2 p, float radius, int fallback) {\n vec4 sum = vec4(0.0);\n for (int i = 0; i < 28; i++) {\n float r = radius * sqrt((float(i) + 0.5) / 28.0);\n float a = float(i) * 2.39996;\n sum += shapeAt(tex, p + r * vec2(cos(a), sin(a)), radius * 0.35, fallback);\n }\n return sum / 28.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = uAnimate ? smoothstep(0.1, 0.9, 0.5 - 0.5 * cos(iTime * 6.28318 / 4.0)) : uProgress;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n // Shapes are sharp at either end and softest half way, where the blobs merge.\n float radius = uGoo * sin(3.14159 * t) + 1.0 / iResolution.y;\n vec4 a = blurred(uFrom, p, radius, 0);\n vec4 b = blurred(uTo, p, radius, 1);\n float field = mix(a.a, b.a, t);\n float w = uEdge + fwidth(field) * 0.75;\n float inside = smoothstep(0.5 - w, 0.5 + w, field);\n // Each shape's colour here (or the other's, where only one shape reaches), blended by progress.\n vec3 ca = uImageColours ? a.rgb / max(a.a, 1e-4) : uColourA;\n vec3 cb = uImageColours ? b.rgb / max(b.a, 1e-4) : uColourB;\n ca = mix(cb, ca, smoothstep(0.0, 0.05, a.a));\n cb = mix(ca, cb, smoothstep(0.0, 0.05, b.a));\n vec3 tint = mix(ca, cb, smoothstep(0.2, 0.8, t));\n // A little roundness: the thick middle of a blob is lighter than its rim.\n tint *= 0.82 + 0.25 * smoothstep(0.5, 1.0, field);\n fragColor = vec4(mix(uBackground, tint, inside), 1.0);\n}`,\n ),\n presets: [\n {\n name: \"Hello → World\",\n values: { uFrom: textImage(\"HELLO\"), uTo: textImage(\"WORLD\"), uImageColours: false, uSize: 0.9, uGoo: 0.05, uColourA: [0.98, 0.75, 0.14], uColourB: [0.13, 0.83, 0.93] },\n },\n { name: \"Blobby\", values: { uGoo: 0.25, uBackground: [1, 0.97, 0.93] } },\n ],\n};\n\nexport const transitionLiquidMorph: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-liquid-morph\",\n name: \"Liquid morph\",\n description: \"Both images swept along a flowing, swirling current that peaks half way, dissolving one into the other like ink in water.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"liquid\", \"image\", \"flow\"],\n loop: 4,\n source: glsl(\n `// Liquid morph: both images advected along a domain-warped fbm current, strongest at mid-progress, while cross-fading.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uStrength; // @control min=0 max=0.5 default=0.1 label=\"Strength\"\nuniform float uScale; // @control min=0.5 max=8 default=2.5 label=\"Scale\"\nuniform float uFlow; // @control min=0 max=2 default=0.4 label=\"Flow speed\"`,\n 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 vec3 a = cover(uFrom, uv + d);\n vec3 b = cover(uTo, uv - d);\n float k = smoothstep(0.25, 0.75, t + (flow.x + flow.y) * 0.6 * s);\n fragColor = vec4(mix(a, b, k), 1.0);\n}`,\n ),\n presets: [\n { name: \"Gentle\", values: { uStrength: 0.08, uScale: 1.5, uFlow: 0.2 } },\n { name: \"Turbulent\", values: { uStrength: 0.35, uScale: 4, uFlow: 1.2 } },\n ],\n};\n\nexport const transitionDisplacement: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-displacement\",\n name: \"Displacement\",\n description: \"Each image's brightness pushes it out in one direction as the next slides in, warped by its own light and dark.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"displacement\", \"image\", \"warp\"],\n loop: 4,\n source: glsl(\n `// Displacement: From's luminance drives a directional warp out, To's luminance the same warp in reverse.\n${pair(SAMPLE_IMAGES.city, SAMPLE_IMAGES.landscape)}\nuniform float uStrength; // @control min=0 max=1 default=0.4 label=\"Strength\"\nuniform float uAngle; // @control min=0 max=360 default=0 label=\"Direction (°)\"`,\n 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 vec3 a = cover(uFrom, uv + dir * t * uStrength * la);\n vec3 b = cover(uTo, uv - dir * (1.0 - t) * uStrength * lb);\n fragColor = vec4(mix(a, b, smoothstep(0.2, 0.8, t)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Upward smear\", values: { uStrength: 0.6, uAngle: 90 } },\n { name: \"Subtle\", values: { uStrength: 0.12, uAngle: 30 } },\n ],\n};\n\nexport const transitionLuma: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-luma\",\n name: \"Luma fade\",\n description: \"Pixels switch to the next image in order of brightness, shadows first or highlights first, along a soft edge.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"luma\", \"image\", \"dissolve\"],\n loop: 4,\n source: glsl(\n `// Luma fade: each pixel switches when progress passes its brightness, with a soft edge.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uSoftness; // @control min=0.01 max=0.5 default=0.1 label=\"Softness\"\nuniform bool uLightFirst; // @control default=false label=\"Light first\"\nuniform int uSource; // @control min=0 max=1 default=0 label=\"Brightness of (0 From, 1 To)\"`,\n PICTURE,\n COMMON,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float t = progress();\n vec3 a = cover(uFrom, uv);\n vec3 b = cover(uTo, uv);\n float l = clamp(luma(uSource == 0 ? a : b), 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 = vec4(mix(a, b, smoothstep(l - uSoftness, l + uSoftness, front)), 1.0);\n}`,\n ),\n presets: [\n { name: \"Highlights first\", values: { uLightFirst: true, uSoftness: 0.06 } },\n { name: \"Hard threshold\", values: { uSoftness: 0.01, uSource: 1 } },\n ],\n};\n\nexport const transitionParticleSwap: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-particle-swap\",\n name: \"Particle swap\",\n description: \"The image breaks into square particles that tumble along curved, staggered paths and land as the next image.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"particles\", \"image\", \"mosaic\"],\n loop: 4,\n source: glsl(\n `// Particle swap: each cell of From flies to a neighbouring cell's place, shrinking and spinning on the way, and lands as To.\n${pair(SAMPLE_IMAGES.landscape, SAMPLE_IMAGES.city)}\nuniform float uParticle; // @control min=6 max=80 default=20 label=\"Particle size (px)\"\nuniform float uScatter; // @control min=0 max=0.8 default=0.45 label=\"Scatter\"\nuniform float uSpin; // @control min=0 max=2 default=0.6 label=\"Spin & curl\"\nuniform vec3 uBackground; // @control color default=#0B0B12 label=\"Background\"`,\n HASH,\n ROTATE,\n PICTURE,\n COMMON,\n `const vec2 RING[4] = vec2[4](vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0));\n\n// Where cell c's particle lands: cells trade places around each 2 × 2 block, turned 1–3 steps.\nvec2 landing(vec2 c) {\n vec2 block = floor(c * 0.5);\n vec2 local = c - block * 2.0;\n int i = local.y < 0.5 ? int(local.x) : 3 - int(local.x);\n int turn = 1 + int(hash12(block + 7.3) * 2.999);\n return block * 2.0 + RING[(i + turn) % 4];\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float t = progress();\n vec2 p = fragCoord / uParticle;\n vec2 grid = iResolution.xy / uParticle;\n vec2 base = floor(p);\n vec3 col = uBackground;\n float top = -1.0;\n vec2 hitFrom = vec2(0.0);\n vec2 hitTo = vec2(0.0);\n float hitT = 0.0;\n float hitCover = 0.0;\n // Particles travel at most about 1.5 cells, so the 5 × 5 cells around are every candidate.\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 c = base + vec2(float(i), float(j));\n vec2 h = hash22(c);\n // Staggered: a sweep from the left plus some randomness.\n float delay = 0.5 * (0.55 * clamp(c.x / grid.x, 0.0, 1.0) + 0.45 * h.x);\n float k = smoothstep(0.0, 1.0, clamp((t - delay) / 0.5, 0.0, 1.0));\n float lift = sin(3.14159 * k);\n vec2 from = c + 0.5;\n vec2 to = landing(c) + 0.5;\n vec2 path = to - from;\n vec2 side = normalize(vec2(-path.y, path.x) + (h - 0.5) * 0.8);\n vec2 pos = mix(from, to, k) + side * lift * (uScatter + uSpin * 0.3) * (h.y > 0.5 ? 0.6 : -0.6);\n float size = 1.0 - 0.3 * lift;\n float angle = (h.y - 0.5) * 6.28318 * uSpin * lift;\n vec2 l = rot(-angle) * (p - pos) / size;\n float m = max(abs(l.x), abs(l.y));\n float z = h.y + lift;\n if (m <= 0.5 && z > top) {\n top = z;\n hitFrom = from + l;\n hitTo = to + l;\n hitT = k;\n hitCover = 1.0 - smoothstep(0.5 - 1.5 / uParticle, 0.5, m) * min(lift * 8.0, 1.0);\n }\n }\n }\n if (top > -1.0) {\n vec3 a = cover(uFrom, hitFrom / grid);\n vec3 b = cover(uTo, hitTo / grid);\n vec3 particle = mix(a, b, hitT) * (1.0 + 0.15 * sin(3.14159 * hitT));\n col = mix(col, particle, hitCover);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Confetti\", values: { uParticle: 10, uScatter: 0.8, uSpin: 1.6 } },\n { name: \"Tiles\", values: { uParticle: 48, uScatter: 0.2, uSpin: 0.15 } },\n ],\n};\n\nexport const transitionInkBleed: ShaderEffect = {\n kind: \"shader\",\n id: \"transition-ink-bleed\",\n name: \"Ink bleed\",\n description: \"The next image bleeds through the first like wet ink on paper, spreading from a few seeds with dark, pooled edges.\",\n category: \"transition\",\n tags: [\"transition\", \"morph\", \"ink\", \"watercolour\", \"image\", \"organic\"],\n loop: 4,\n source: glsl(\n `// Ink bleed: To spreads through From along an fbm threshold grown from seeds, with a wet, darkened fringe.\n${pair(SAMPLE_IMAGES.city, SAMPLE_IMAGES.landscape)}\nuniform float uScale; // @control min=0.5 max=8 default=3 label=\"Scale\"\nuniform float uEdge; // @control min=0.005 max=0.2 default=0.05 label=\"Edge width\"\nuniform vec3 uInk; // @control color default=#1B1F3B label=\"Ink\"`,\n 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 vec3 a = cover(uFrom, uv + bleed);\n vec3 b = cover(uTo, uv - bleed);\n vec3 col = mix(a, b, wet);\n col = mix(col, col * 0.82, soak * 0.6);\n col = mix(col, uInk, pool * 0.85);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Sepia wash\", values: { uInk: [0.36, 0.23, 0.12], uEdge: 0.08, uScale: 2 } },\n { name: \"Crisp\", values: { uEdge: 0.015, uScale: 5 } },\n ],\n};\n\n/** Shaders that turn one image into another: true morphs (category \"morph\") and morph-like transitions. */\nexport const morphShaders: ShaderEffect[] = [\n featureMorph,\n silhouetteMorph,\n transitionLiquidMorph,\n transitionDisplacement,\n transitionLuma,\n transitionParticleSwap,\n transitionInkBleed,\n];\n","import { FBM, glsl, HASH, NOISE } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\n/**\n * `glow(c)`: light as a colour over whatever is behind it. Its alpha is its\n * brightest channel, so it brightens what is under it like a screen blend.\n */\nconst GLOW = `\nvec4 glow(vec3 c) {\n c = 1.0 - exp(-max(c, 0.0));\n float a = max(c.r, max(c.g, c.b));\n return vec4(c / max(a, 1e-4), a);\n}`.trim();\n\n/**\n * `over(acc, colour, alpha)`: paints a colour over a premultiplied\n * accumulator; `unpremultiply(acc)` turns it into straight colour and coverage.\n */\nconst OVER = `\nvec4 over(vec4 acc, vec3 c, float a) {\n return vec4(acc.rgb * (1.0 - a) + c * a, acc.a * (1.0 - a) + a);\n}\nvec4 unpremultiply(vec4 acc) {\n return vec4(acc.rgb / max(acc.a, 1e-4), acc.a);\n}`.trim();\n\nexport const rainOnGlass: ShaderEffect = {\n kind: \"shader\",\n id: \"rain-on-glass\",\n name: \"Rain on glass\",\n description: \"Raindrops sliding down a window in fits and starts, leaving beaded trails behind them.\",\n category: \"overlay\",\n tags: [\"overlay\", \"rain\", \"weather\", \"moody\", \"window\"],\n transparent: true,\n source: glsl(\n `// Rain on glass: drops sliding down a pane, leaving trails of beads.\nuniform float uDensity; // @control min=0 max=1 default=0.7 label=\"Density\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uSize; // @control min=0.5 max=2 default=1 label=\"Drop size\"\nuniform vec3 uTint; // @control color default=#CFE3F0 label=\"Tint\"`,\n HASH,\n OVER,\n `// One drop of radius r at offset d: a faint tinted body, a darker rim and a bright highlight.\nvec4 paintDrop(vec4 acc, vec2 d, float r, float px) {\n float dist = length(d);\n if (dist > r + px) return acc;\n float m = (1.0 - smoothstep(r - 1.5 * px, r, dist)) * smoothstep(0.0, 2.0 * px, r);\n vec2 n = d / max(r, 1e-5);\n float l = length(n);\n float rim = smoothstep(0.45, 1.0, l) * m;\n float spec = (1.0 - smoothstep(0.0, 0.3, length(n - vec2(-0.3, 0.38)))) * m;\n float caustic = (1.0 - smoothstep(0.0, 0.5, length(n - vec2(0.15, -0.5)))) * m;\n acc = over(acc, uTint, m * 0.2);\n acc = over(acc, vec3(0.0, 0.02, 0.05), rim * 0.5);\n acc = over(acc, mix(uTint, vec3(1.0), 0.6), caustic * 0.3);\n return over(acc, vec3(1.0), spec * 0.9);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n vec4 acc = vec4(0.0);\n\n // Condensation: still beads slowly forming and drying up.\n float beads = 30.0 / uSize;\n vec2 bq = p * beads;\n vec2 bid = floor(bq);\n vec2 bh = hash22(bid);\n float life = fract(iTime * 0.04 + bh.x * 7.0);\n float br = (0.12 + 0.18 * bh.y) / beads * sin(3.14159 * life);\n if (hash12(bid + 5.0) < uDensity) acc = paintDrop(acc, (fract(bq) - 0.5 - (bh - 0.5) * 0.4) / beads, br, px);\n\n // Running drops: one per cell at most, sliding down a wavy path with a trail above.\n for (int i = 0; i < 2; i++) {\n float fi = float(i);\n vec2 cell = vec2(0.12, 0.3) * uSize * (1.0 - 0.3 * fi);\n vec2 q = p / cell + vec2(fi * 3.7, 0.0);\n float column = floor(q.x);\n q.y += t * 0.15 + hash12(vec2(column, fi)) * 9.0;\n vec2 id = floor(q);\n vec2 f = fract(q) - 0.5;\n vec2 h = hash22(id + fi * 17.0);\n if (h.x > uDensity) continue;\n float tt = t * 1.2 + h.y * 6.28318;\n float y = -0.38 * sin(tt + sin(tt + sin(tt) * 0.5));\n float base = (h.y - 0.5) * 0.3;\n float wobble = h.x * 6.28318;\n float x = base + 0.03 * sin(y * 9.0 + wobble);\n float aspect = cell.x / cell.y;\n float r = cell.y * (0.05 + 0.04 * fract(h.x * 13.7));\n vec2 d = vec2((f.x - x) * aspect, f.y - y) * cell.y;\n d.y *= d.y > 0.0 ? 0.8 : 1.0;\n acc = paintDrop(acc, d, r, px);\n if (f.y > y) {\n float rows = 10.0;\n float row = floor(f.y * rows);\n float tx = base + 0.03 * sin((row + 0.5) / rows * 9.0 + wobble);\n vec2 bd = vec2((f.x - tx) * aspect, (fract(f.y * rows) - 0.5) / rows) * cell.y;\n float fade = 1.0 - clamp((f.y - y) / (0.5 - y), 0.0, 1.0);\n float keep = step(0.35, hash12(id * 3.1 + vec2(row, fi)));\n acc = paintDrop(acc, bd, r * 0.35 * fade * keep, px);\n }\n }\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Storm\", values: { uDensity: 1, uSpeed: 1.8, uSize: 1.3 } },\n { name: \"Drizzle\", values: { uDensity: 0.4, uSpeed: 0.6, uSize: 0.7 } },\n ],\n};\n\nexport const snowfall: ShaderEffect = {\n kind: \"shader\",\n id: \"snowfall\",\n name: \"Snowfall\",\n description: \"Layers of snowflakes drifting down on the wind, the far ones smaller and softer.\",\n category: \"overlay\",\n tags: [\"overlay\", \"snow\", \"winter\", \"festive\", \"particles\"],\n transparent: true,\n source: glsl(\n `// Snowfall: layered flakes drifting with the wind, far layers smaller and blurrier.\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Colour\"\nuniform float uDensity; // @control min=0 max=1 default=0.6 label=\"Density\"\nuniform float uWind; // @control min=-2 max=2 default=0.3 label=\"Wind\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Fall speed\"\nuniform float uSize; // @control min=0.2 max=2 default=1 label=\"Size\"\nuniform int uLayers; // @control min=1 max=6 default=4 label=\"Layers\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float px = 1.0 / iResolution.y;\n float a = 0.0;\n for (int i = 0; i < 6; i++) {\n if (i >= uLayers) break;\n float fi = float(i);\n // Layer 0 is the farthest: smaller, slower, softer and fainter.\n float depth = (fi + 1.0) / float(uLayers);\n float scale = mix(22.0, 6.0, depth);\n vec2 vel = vec2(uWind * 0.12 * (0.4 + depth), -uSpeed * mix(0.06, 0.25, depth));\n vec2 q = (p - vel * iTime) * scale + fi * 11.3;\n vec2 id = floor(q);\n vec2 h = hash22(id);\n if (hash12(id + 3.7) > uDensity) continue;\n float phase = iTime * (0.4 + 0.6 * h.x) + h.y * 6.28318;\n vec2 centre = (h - 0.5) * 0.3 + vec2(sin(phase) * 0.12, cos(phase * 0.7) * 0.05);\n float d = length(fract(q) - 0.5 - centre);\n float r = 0.06 * uSize * (0.6 + 0.8 * hash12(id + 9.1));\n float soft = max(px * scale * 1.5, r * mix(0.9, 0.3, depth));\n float flake = 1.0 - smoothstep(r - soft, r, d);\n a = max(a, flake * mix(0.45, 1.0, depth));\n }\n fragColor = vec4(uColor, a);\n}`,\n ),\n presets: [\n { name: \"Dust motes\", values: { uColor: [1, 0.85, 0.63], uDensity: 0.25, uWind: 0.05, uSpeed: 0.08, uSize: 0.6, uLayers: 3 } },\n { name: \"Blizzard\", values: { uDensity: 0.9, uWind: 1.6, uSpeed: 2, uLayers: 6 } },\n ],\n};\n\nexport const lensFlare: ShaderEffect = {\n kind: \"shader\",\n id: \"lens-flare\",\n name: \"Lens flare\",\n description: \"An anamorphic lens flare: a long horizontal streak and a chain of ghosts through the centre, following the pointer.\",\n category: \"overlay\",\n tags: [\"overlay\", \"cinematic\", \"light\", \"interactive\", \"sci-fi\"],\n transparent: true,\n source: glsl(\n `// Lens flare: an anamorphic streak and ghosts along the line through the centre.\nuniform vec2 uSource; // @control min=-1 max=1 default=-0.45,0.4 label=\"Source\"\nuniform vec3 uColor; // @control color default=#FFC98A label=\"Colour\"\nuniform float uStreak; // @control min=0 max=2 default=1 label=\"Streak length\"\nuniform float uIntensity; // @control min=0 max=2 default=1 label=\"Intensity\"`,\n HASH,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec2 src = iMouse.z > 0.0\n ? (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y\n : uSource * vec2(aspect, 1.0) * 0.5;\n vec2 d = p - src;\n float r = length(d);\n vec3 col = uColor * (exp(-r * 20.0) * 1.5 + 0.015 / (r + 0.015) * 0.3);\n // The anamorphic streak: a bright thin line and a wider, fainter one, blue-shifted.\n vec3 streakColor = mix(uColor, vec3(0.45, 0.65, 1.0), 0.6);\n float len = uStreak + 1e-3;\n col += streakColor * exp(-abs(d.y) * 220.0) * exp(-abs(d.x) / (0.5 * len));\n col += streakColor * 0.4 * exp(-abs(d.y) * 60.0) * exp(-abs(d.x) / (0.25 * len));\n // Ghosts sit on the line from the source through the centre, mostly on the far side.\n for (int i = 0; i < 7; i++) {\n float fi = float(i);\n float along = mix(-1.6, 0.6, hash12(vec2(fi, 1.7)));\n float gr = mix(0.015, 0.11, hash12(vec2(fi, 4.1)));\n float gd = length(p - src * along);\n vec3 tint = mix(uColor, vec3(0.4, 0.85, 1.0), hash12(vec2(fi, 8.3)));\n float disc = (1.0 - smoothstep(gr * 0.6, gr, gd)) * 0.12;\n float ring = exp(-abs(gd - gr) * 90.0) * 0.18;\n col += tint * (hash12(vec2(fi, 2.9)) > 0.6 ? ring : disc);\n }\n fragColor = glow(col * uIntensity);\n}`,\n ),\n presets: [\n { name: \"Sci-fi blue\", values: { uColor: [0.5, 0.7, 1], uStreak: 1.8 } },\n { name: \"Golden hour\", values: { uColor: [1, 0.7, 0.28], uStreak: 0.6, uIntensity: 1.3 } },\n ],\n};\n\nexport const vignetteGrain: ShaderEffect = {\n kind: \"shader\",\n id: \"vignette-grain\",\n name: \"Vignette & grain\",\n description: \"Darkened corners and fine animated film grain to lay over any picture.\",\n category: \"overlay\",\n tags: [\"overlay\", \"cinematic\", \"film\", \"grain\", \"vintage\"],\n transparent: true,\n source: glsl(\n `// Vignette & grain: darkened corners and fine grain, nothing else.\nuniform float uStrength; // @control min=0 max=1 default=0.6 label=\"Strength\"\nuniform float uRoundness; // @control min=0 max=1 default=0.5 label=\"Roundness\"\nuniform float uSoftness; // @control min=0.05 max=1 default=0.5 label=\"Softness\"\nuniform float uGrain; // @control min=0 max=0.3 default=0.08 label=\"Grain\"\nuniform float uGrainSize; // @control min=1 max=4 default=1.5 label=\"Grain size (px)\"`,\n HASH,\n OVER,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float aspect = iResolution.x / iResolution.y;\n // 0 at the centre, 1 at the edges; rounder shapes measure across the frame's aspect.\n vec2 q = abs(fragCoord / iResolution.xy - 0.5) * 2.0;\n q.x *= mix(1.0, aspect, uRoundness * 0.5);\n float n = mix(8.0, 2.0, uRoundness);\n float dist = pow(pow(q.x, n) + pow(q.y, n), 1.0 / n);\n float dark = smoothstep(1.25 - uSoftness * 1.2, 1.3, dist) * uStrength;\n vec4 acc = over(vec4(0.0), vec3(0.0), dark);\n float frame = mod(floor(iTime * 24.0), 64.0);\n float g = hash12(floor(fragCoord / uGrainSize) + frame * vec2(17.31, 31.73)) - 0.5;\n acc = over(acc, vec3(step(0.0, g)), abs(g) * uGrain * 2.0);\n fragColor = unpremultiply(acc);\n}`,\n ),\n presets: [\n { name: \"Subtle\", values: { uStrength: 0.35, uGrain: 0.04 } },\n { name: \"Gritty\", values: { uStrength: 0.8, uSoftness: 0.3, uGrain: 0.18, uGrainSize: 2 } },\n ],\n};\n\nexport const scanlineSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"scanline-sweep\",\n name: \"Scanline sweep\",\n description: \"A bright scanning line with a glow and fading trail passing across, like a scanner or hologram.\",\n category: \"overlay\",\n tags: [\"overlay\", \"scan\", \"hologram\", \"sci-fi\", \"tech\"],\n transparent: true,\n source: glsl(\n `// Scanline sweep: a glowing line with a faint trail crossing the frame at intervals.\nuniform float uAngle; // @control min=0 max=360 default=270 label=\"Direction (°)\"\nuniform float uSpeed; // @control min=0.1 max=3 default=1 label=\"Speed\"\nuniform float uWidth; // @control min=0.001 max=0.05 default=0.006 label=\"Width\"\nuniform vec3 uColor; // @control color default=#4FF0FF label=\"Colour\"\nuniform float uInterval; // @control min=0 max=5 default=1 label=\"Pause (s)\"\nuniform float uTrail; // @control min=0 max=1 default=0.5 label=\"Trail\"`,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float px = 1.0 / iResolution.y;\n float a = radians(uAngle);\n vec2 dir = vec2(cos(a), sin(a));\n float s = dot(p, dir);\n // Start and end far enough past the frame that the trail has gone before the next pass.\n float trailLength = 0.02 + 0.2 * uTrail;\n float reach = 0.5 * (abs(dir.x) * aspect + abs(dir.y)) + uWidth * 6.0 + trailLength * 4.0;\n float sweep = 1.5 / uSpeed;\n float k = mod(iTime, sweep + uInterval) / sweep;\n float d = s - mix(-reach, reach, k);\n float core = 1.0 - smoothstep(uWidth * 0.5, uWidth * 0.5 + px, abs(d));\n float halo = exp(-abs(d) / (uWidth * 3.0)) * 0.6;\n float trail = d < 0.0 ? exp(d / trailLength) * 0.35 * uTrail : 0.0;\n trail *= 0.75 + 0.25 * sin(fragCoord.y * 2.0);\n fragColor = glow(uColor * (core * 1.5 + halo + trail));\n}`,\n ),\n presets: [\n { name: \"Hologram\", values: { uAngle: 90, uColor: [0.3, 1, 0.6], uSpeed: 0.6, uInterval: 0, uTrail: 0.9 } },\n { name: \"Barcode scanner\", values: { uAngle: 0, uColor: [1, 0.15, 0.15], uSpeed: 2, uInterval: 0.2, uWidth: 0.003 } },\n ],\n};\n\nexport const spotlight: ShaderEffect = {\n kind: \"shader\",\n id: \"spotlight\",\n name: \"Spotlight\",\n description: \"Darkness everywhere but a soft circle of light that follows the pointer or wanders on its own.\",\n category: \"overlay\",\n tags: [\"overlay\", \"interactive\", \"reveal\", \"focus\", \"dramatic\"],\n transparent: true,\n source: glsl(\n `// Spotlight: dark everywhere but a soft circle, at the pointer or drifting.\nuniform float uRadius; // @control min=0.05 max=0.8 default=0.25 label=\"Radius\"\nuniform float uSoftness; // @control min=0 max=1 default=0.4 label=\"Softness\"\nuniform float uDarkness; // @control min=0 max=1 default=0.85 label=\"Darkness\"\nuniform float uSpeed; // @control min=0 max=2 default=0.3 label=\"Drift speed\"\nuniform vec3 uShade; // @control color default=#05050A label=\"Shade\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float px = 1.0 / iResolution.y;\n float t = iTime * uSpeed;\n vec2 centre = iMouse.z > 0.0\n ? (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y\n : vec2(sin(t * 2.0) * 0.32 * aspect, sin(t * 3.0 + 0.5) * 0.28);\n float r = length(p - centre);\n float dark = smoothstep(uRadius * (1.0 - uSoftness) - px, uRadius + px, r);\n fragColor = vec4(uShade, dark * uDarkness);\n}`,\n ),\n presets: [\n { name: \"Stage\", values: { uRadius: 0.35, uSoftness: 0.15, uDarkness: 0.95, uSpeed: 0.15 } },\n { name: \"Torch\", values: { uRadius: 0.18, uSoftness: 0.7, uDarkness: 1, uShade: [0.02, 0.01, 0] } },\n ],\n};\n\nexport const embers: ShaderEffect = {\n kind: \"shader\",\n id: \"embers\",\n name: \"Embers\",\n description: \"Glowing sparks rising from below, swaying and flickering out as they cool.\",\n category: \"overlay\",\n tags: [\"overlay\", \"fire\", \"sparks\", \"particles\", \"warm\"],\n transparent: true,\n source: glsl(\n `// Embers: sparks rising, swaying and flickering out as they cool.\nuniform int uCount; // @control min=5 max=80 default=40 label=\"Sparks\"\nuniform vec3 uHeat; // @control color default=#FF7A1A label=\"Heat\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Rise speed\"\nuniform float uSize; // @control min=0.3 max=3 default=1 label=\"Size\"`,\n HASH,\n GLOW,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n vec3 col = vec3(0.0);\n for (int i = 0; i < 80; i++) {\n if (i >= uCount) break;\n float fi = float(i);\n vec2 h = hash22(vec2(fi, 1.3));\n float clock = iTime * uSpeed * 0.18 * (0.6 + 0.8 * h.y) + h.x;\n float life = fract(clock);\n // Each life starts somewhere new along the bottom.\n vec2 seed = vec2(fi, floor(clock));\n float x = hash12(seed) * aspect + 0.04 * sin(life * 8.0 + fi) + life * 0.15 * (hash12(seed + 2.0) - 0.5);\n float y = life * (0.5 + 0.7 * hash12(seed + 4.0)) - 0.02;\n float r = 0.005 * uSize * (0.5 + hash12(seed + 6.0));\n vec2 d = p - vec2(x, y);\n d.y *= 0.6;\n float dist = length(d);\n if (dist > r * 14.0) continue;\n float fade = smoothstep(0.0, 0.08, life) * (1.0 - smoothstep(0.45, 1.0, life));\n float flicker = 0.6 + 0.4 * sin(iTime * 17.0 + fi * 3.7) * sin(iTime * 7.3 + fi);\n vec3 heat = mix(vec3(1.0, 0.95, 0.75), uHeat, smoothstep(0.0, 0.5, life));\n heat = mix(heat, uHeat * vec3(0.8, 0.25, 0.1), smoothstep(0.5, 1.0, life));\n float core = 1.0 - smoothstep(r * 0.4, r, dist);\n float halo = exp(-dist / (r * 2.5)) * 0.35;\n col += heat * (core * 1.5 + halo) * fade * flicker;\n }\n fragColor = glow(col);\n}`,\n ),\n presets: [\n { name: \"Bonfire\", values: { uCount: 80, uSpeed: 1.6, uSize: 1.3 } },\n { name: \"Magic sparks\", values: { uHeat: [0.55, 0.4, 1], uCount: 30, uSpeed: 0.6 } },\n ],\n};\n\nexport const shineSweep: ShaderEffect = {\n kind: \"shader\",\n id: \"shine-sweep\",\n name: \"Shine sweep\",\n description: \"A soft diagonal gloss band gliding across now and then, for cards and buttons.\",\n category: \"overlay\",\n tags: [\"overlay\", \"ui\", \"gloss\", \"premium\", \"button\"],\n transparent: true,\n source: glsl(\n `// Shine sweep: a soft gloss band crossing the frame at intervals.\nuniform float uAngle; // @control min=-60 max=60 default=25 label=\"Tilt (°)\"\nuniform float uWidth; // @control min=0.02 max=0.5 default=0.15 label=\"Width\"\nuniform float uIntensity; // @control min=0 max=1 default=0.6 label=\"Intensity\"\nuniform float uInterval; // @control min=1 max=8 default=3 label=\"Every (s)\"\nuniform vec3 uColor; // @control color default=#FFFFFF label=\"Colour\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float aspect = iResolution.x / iResolution.y;\n float slope = tan(radians(uAngle));\n float s = p.x + p.y * slope;\n float reach = 0.5 * aspect + 0.5 * abs(slope) + uWidth;\n // Each sweep takes 0.9 s, then waits for the next.\n float k = clamp(mod(iTime, uInterval) / 0.9, 0.0, 1.0);\n k = k * k * (3.0 - 2.0 * k);\n float d = (s - mix(-reach, reach, k)) / uWidth;\n float band = exp(-d * d * 4.0) * 0.7 + exp(-d * d * 60.0) * 0.5;\n fragColor = vec4(uColor, clamp(band * uIntensity, 0.0, 1.0));\n}`,\n ),\n presets: [\n { name: \"Gold foil\", values: { uColor: [1, 0.9, 0.6], uWidth: 0.25, uIntensity: 0.5 } },\n { name: \"Quick glint\", values: { uWidth: 0.06, uIntensity: 0.9, uInterval: 1.5, uAngle: 35 } },\n ],\n};\n\nexport const frostCreep: ShaderEffect = {\n kind: \"shader\",\n id: \"frost-creep\",\n name: \"Frost creep\",\n description: \"Ice crystals creeping in from the edges of the frame and melting back.\",\n category: \"overlay\",\n tags: [\"overlay\", \"ice\", \"winter\", \"frozen\", \"reveal\"],\n transparent: true,\n loop: 8,\n source: glsl(\n `// Frost creep: crystalline frost growing in from the edges.\nuniform bool uAnimate; // @control default=true label=\"Animate\"\nuniform float uCoverage; // @control min=0 max=1 default=0.6 label=\"Coverage (when still)\"\nuniform float uScale; // @control min=1 max=10 default=4 label=\"Crystal size\"\nuniform vec3 uColor; // @control color default=#DDF2FF label=\"Frost\"`,\n HASH,\n NOISE,\n FBM,\n `// Voronoi: x = distance to the nearest point, y = to the second, zw = the nearest cell.\nvec4 voronoi(vec2 q) {\n vec2 id = floor(q);\n vec2 f = fract(q);\n float f1 = 8.0;\n float f2 = 8.0;\n vec2 nearest = id;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 o = vec2(float(i), float(j));\n float d = length(o + hash22(id + o) - f);\n if (d < f1) {\n f2 = f1;\n f1 = d;\n nearest = id + o;\n } else if (d < f2) {\n f2 = d;\n }\n }\n }\n return vec4(f1, f2, nearest);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = fragCoord / iResolution.y;\n float coverage = uAnimate ? 0.5 - 0.5 * cos(iTime * 6.28318 / 8.0) : uCoverage;\n // Distance in from the nearest edge, roughened by noise and stepped per crystal.\n float edge = min(min(fragCoord.x, iResolution.x - fragCoord.x), min(fragCoord.y, iResolution.y - fragCoord.y)) / iResolution.y;\n vec4 v = voronoi(p * uScale * 3.0);\n float n = fbm(p * uScale * 0.8, 5);\n float g = edge + (n - 0.5) * 0.3 + (hash12(v.zw) - 0.5) * 0.04;\n float front = mix(-0.25, 0.75, coverage);\n float frost = 1.0 - smoothstep(front - 0.06, front, g);\n if (frost <= 0.0) {\n fragColor = vec4(0.0);\n return;\n }\n // Facets catch the light differently; their edges and fine needles glint.\n float facet = hash12(v.zw + 3.1);\n float ridges = 1.0 - smoothstep(0.0, 0.06, v.y - v.x);\n float needles = smoothstep(0.55, 0.8, fbm(p * uScale * vec2(6.0, 1.5) + v.zw, 3));\n float fresh = 1.0 - smoothstep(0.0, 0.35, front - g);\n float rim = smoothstep(front - 0.06, front - 0.015, g);\n vec3 col = mix(uColor * vec3(0.8, 0.9, 1.0), vec3(1.0), facet * 0.4 + ridges * 0.6 + rim * 0.5 + needles * 0.4);\n float alpha = frost * clamp(0.35 + 0.25 * (1.0 - fresh) + 0.2 * facet + 0.35 * ridges + 0.25 * needles + 0.3 * rim, 0.0, 1.0);\n fragColor = vec4(min(col, 1.0), alpha);\n}`,\n ),\n presets: [\n { name: \"Hoarfrost\", values: { uAnimate: false, uCoverage: 0.85, uScale: 6 } },\n { name: \"Icy blue\", values: { uColor: [0.62, 0.83, 1], uScale: 2.5 } },\n ],\n};\n\n/** Effects drawn over other content: transparent where there is nothing to draw (see `ShaderEffect.transparent`). */\nexport const overlayEffects: ShaderEffect[] = [\n rainOnGlass,\n snowfall,\n lensFlare,\n vignetteGrain,\n scanlineSweep,\n spotlight,\n embers,\n shineSweep,\n frostCreep,\n];\n","import { glsl, HASH } from \"../glsl.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const synthwaveGrid: ShaderEffect = {\n kind: \"shader\",\n id: \"synthwave\",\n name: \"Synthwave\",\n description: \"A neon perspective grid racing towards a striped retro sun.\",\n category: \"retro\",\n tags: [\"background\", \"80s\", \"neon\", \"music\", \"loop\"],\n loop: 1,\n source: glsl(\n `// Synthwave: a neon grid racing towards a striped sun.\nuniform vec3 uSkyTop; // @control color default=#12002B label=\"Sky top\"\nuniform vec3 uSkyBottom; // @control color default=#7A1A6B label=\"Sky bottom\"\nuniform vec3 uSunTop; // @control color default=#FFE45E label=\"Sun top\"\nuniform vec3 uSunBottom; // @control color default=#FF3D7F label=\"Sun bottom\"\nuniform vec3 uGrid; // @control color default=#00F0FF label=\"Grid\"\nuniform float uHorizon; // @control min=0.2 max=0.7 default=0.42 label=\"Horizon\"`,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float horizon = uHorizon - 0.5;\n vec3 col;\n if (p.y > horizon) {\n float h = (p.y - horizon) / (0.5 - horizon);\n col = mix(uSkyBottom, uSkyTop, h);\n vec2 s = p - vec2(0.0, horizon + 0.18);\n float sun = smoothstep(0.2, 0.195, length(s));\n float bands = step(0.0, sin((s.y + 0.2) * 60.0 - 1.5)) + step(0.06, s.y);\n sun *= clamp(bands, 0.0, 1.0);\n col = mix(col, mix(uSunBottom, uSunTop, clamp(s.y / 0.2 * 0.5 + 0.5, 0.0, 1.0)), sun);\n col += uSunBottom * 0.25 * exp(-length(s) * 4.0);\n } else {\n float depth = (horizon - p.y);\n vec2 g = vec2(p.x / depth, 1.0 / depth);\n g.y += iTime * 2.0;\n vec2 grid = abs(fract(g * 0.5) - 0.5) / fwidth(g * 0.5);\n float line = 1.0 - clamp(min(grid.x, grid.y), 0.0, 1.0);\n float fade = smoothstep(0.0, 0.25, depth);\n col = mix(uSkyTop * 0.4, uSkyBottom * 0.3, uv.y);\n col += uGrid * line * fade + uGrid * 0.25 * exp(-depth * 20.0);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const tvStatic: ShaderEffect = {\n kind: \"shader\",\n id: \"tv-static\",\n name: \"TV static\",\n description: \"Analogue snow with rolling bars and scanlines.\",\n category: \"retro\",\n tags: [\"glitch\", \"analogue\", \"transition\", \"noise\"],\n source: glsl(\n `// TV static: analogue snow with a rolling bar and scanlines.\nuniform float uAmount; // @control min=0 max=1 default=0.9 label=\"Snow\"\nuniform float uScanlines; // @control min=0 max=1 default=0.35 label=\"Scanlines\"\nuniform float uRoll; // @control min=0 max=1 default=0.3 label=\"Rolling bar\"\nuniform vec3 uTint; // @control color default=#E6E6E6 label=\"Tint\"`,\n HASH,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n float n = hash12(floor(fragCoord * 0.5) + floor(iTime * 30.0) * 17.31);\n float scan = 1.0 - uScanlines * 0.5 * (1.0 + sin(fragCoord.y * 3.14159));\n float bar = 1.0 + uRoll * 0.6 * smoothstep(0.15, 0.0, abs(fract(uv.y - iTime * 0.2) - 0.5) - 0.3);\n vec3 col = uTint * mix(0.5, n, uAmount) * scan * bar;\n col *= smoothstep(1.2, 0.4, length(uv - 0.5) * 1.4);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n};\n\nexport const digitalRain: ShaderEffect = {\n kind: \"shader\",\n id: \"digital-rain\",\n name: \"Digital rain\",\n description: \"Columns of glyph-like characters raining down a terminal.\",\n category: \"retro\",\n tags: [\"hacker\", \"code\", \"tech\", \"cyber\"],\n source: glsl(\n `// Digital rain: glyph-like cells raining down in columns.\nuniform vec3 uBackground; // @control color default=#000000 label=\"Background\"\nuniform vec3 uGlyph; // @control color default=#22FF66 label=\"Glyph\"\nuniform float uCell; // @control min=6 max=40 default=14 label=\"Cell size (px)\"\nuniform float uSpeed; // @control min=0 max=4 default=1 label=\"Speed\"`,\n HASH,\n `float glyph(vec2 cell, vec2 f) {\n vec2 g = floor(f * vec2(3.0, 5.0));\n float on = step(0.45, hash12(g + cell * 13.7 + floor(iTime * 4.0 * hash12(cell))));\n vec2 inset = abs(fract(f * vec2(3.0, 5.0)) - 0.5);\n return on * step(max(inset.x, inset.y), 0.38);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 q = fragCoord / uCell;\n vec2 cell = floor(q);\n vec2 f = fract(q);\n float col = cell.x;\n float speed = (0.5 + hash12(vec2(col, 1.0))) * uSpeed * 8.0;\n float offset = hash12(vec2(col, 2.0)) * 100.0;\n float head = fract((iTime * speed + offset) / 40.0) * (iResolution.y / uCell + 30.0);\n float y = iResolution.y / uCell - cell.y;\n float trail = head - y;\n float lit = trail >= 0.0 ? exp(-trail * 0.15) : 0.0;\n float isHead = step(abs(trail), 0.5);\n float g = glyph(cell, f);\n vec3 c = uBackground + uGlyph * g * lit + vec3(0.8) * g * isHead;\n fragColor = vec4(c, 1.0);\n}`,\n ),\n};\n\nexport const pixelSunset: ShaderEffect = {\n kind: \"shader\",\n id: \"dither-gradient\",\n name: \"Dithered gradient\",\n description: \"A 1-bit Bayer-dithered gradient wave, like an old Mac or Game Boy screen.\",\n category: \"retro\",\n tags: [\"pixel\", \"1-bit\", \"lo-fi\", \"background\"],\n source: glsl(\n `// Dithered gradient: a Bayer-dithered gradient wave in two colours.\nuniform vec3 uDark; // @control color default=#0F380F label=\"Dark\"\nuniform vec3 uLight; // @control color default=#9BBC0F label=\"Light\"\nuniform float uPixel; // @control min=1 max=12 default=4 step=1 label=\"Pixel size\"\nuniform float uSpeed; // @control min=0 max=2 default=0.5 label=\"Speed\"`,\n `float bayer4(vec2 p) {\n vec2 q = mod(floor(p), 4.0);\n int i = int(q.x) + int(q.y) * 4;\n int m[16] = int[16](0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5);\n return (float(m[i]) + 0.5) / 16.0;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 px = floor(fragCoord / uPixel);\n vec2 uv = px * uPixel / iResolution.xy;\n float v = uv.y + 0.15 * sin(uv.x * 6.0 + iTime * uSpeed * 2.0) + 0.1 * sin(uv.x * 13.0 - iTime * uSpeed * 3.0);\n v = clamp(v, 0.0, 1.0);\n float on = step(bayer4(px), v);\n fragColor = vec4(mix(uDark, uLight, on), 1.0);\n}`,\n ),\n presets: [\n { name: \"Mac\", values: { uDark: [0.05, 0.05, 0.05], uLight: [0.93, 0.93, 0.9] } },\n { name: \"Amber\", values: { uDark: [0.1, 0.04, 0], uLight: [1, 0.69, 0] } },\n ],\n};\n","import { FBM, glsl, HASH, NOISE, PALETTE } from \"../glsl.js\";\nimport { textImage } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\n\nexport const shaderText: ShaderEffect = {\n kind: \"shader\",\n id: \"shader-text\",\n name: \"Shader text\",\n description: \"A title filled with a living texture (plasma, fire, caustics or liquid chrome), with a soft glow and outline.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"plasma\", \"fire\", \"chrome\", \"glow\"],\n source: glsl(\n `// Shader text: the letters of a text image filled with an animated pattern.\nuniform sampler2D uText; // @control filter=linear wrap=clamp default=${textImage(\"FLAIR\")} label=\"Text\"\nuniform int uFill; // @control min=0 max=3 default=0 label=\"Fill (0 plasma, 1 fire, 2 caustics, 3 chrome)\"\nuniform vec3 uBackground; // @control color default=#0A0A12 label=\"Background\"\nuniform vec3 uTint; // @control color default=#FFFFFF label=\"Tint\"\nuniform float uSize; // @control min=0.3 max=1 default=0.9 label=\"Text size\"\nuniform float uSpeed; // @control min=0 max=3 default=1 label=\"Speed\"\nuniform float uGlow; // @control min=0 max=2 default=0.6 label=\"Glow\"\nuniform float uOutline; // @control min=0 max=0.02 default=0.004 label=\"Outline width\"\nuniform vec3 uOutlineColor; // @control color default=#FFFFFF label=\"Outline\"`,\n HASH,\n NOISE,\n FBM,\n PALETTE,\n `// The text image's alpha at frame point p (height 1, centred), the image contained in uSize of the frame.\nfloat letters(vec2 p) {\n vec2 size = vec2(textureSize(uText, 0));\n float aspect = size.x / max(size.y, 1.0);\n float frame = iResolution.x / iResolution.y;\n float h = min(uSize, frame * uSize / aspect);\n vec2 uv = p / vec2(h * aspect, h) + 0.5;\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;\n return texture(uText, uv).a;\n}\n\nvec3 plasmaFill(vec2 p, float t) {\n float v = sin(p.x * 6.0 + t) + sin(p.y * 7.0 - t * 1.3) + sin((p.x + p.y) * 5.0 + t * 0.7) + sin(length(p * 8.0) - t * 2.0);\n return palette(v * 0.125 + 0.5 + t * 0.05, vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.0, 0.33, 0.67));\n}\n\nvec3 fireFill(vec2 p, float t) {\n float n = fbm(vec2(p.x * 5.0, p.y * 3.0 - t * 1.8), 5);\n float heat = clamp(1.1 - (p.y + 0.3) * 1.6 + (n - 0.5) * 1.2, 0.0, 1.0);\n return vec3(1.0, 0.35, 0.05) * heat * 1.4 + vec3(1.0, 0.85, 0.3) * pow(heat, 3.0) + vec3(0.25, 0.0, 0.0);\n}\n\nvec3 causticsFill(vec2 p, float t) {\n vec2 q = p * 6.0;\n vec2 i = q;\n float c = 1.0;\n for (int n = 0; n < 5; n++) {\n float tn = t * 0.5 * (1.0 - 3.5 / float(n + 1));\n i = q + vec2(cos(tn - i.x) + sin(tn + i.y), sin(tn - i.y) + cos(tn + i.x));\n c += 1.0 / length(vec2(q.x / (sin(i.x + tn) / 0.005), q.y / (cos(i.y + tn) / 0.005)));\n }\n c = 1.17 - pow(c / 5.0, 1.4);\n float light = pow(abs(c), 8.0);\n return clamp(vec3(0.0, 0.3, 0.5) + light * vec3(0.7, 1.0, 1.0), 0.0, 1.0);\n}\n\n// Liquid chrome: a horizon reflection bent by the letters' bevel and a slow warp.\nvec3 chromeFill(vec2 p, float t, vec2 normal) {\n float warp = fbm(p * 3.0 + vec2(t * 0.3, -t * 0.2), 4) - 0.5;\n float y = p.y * 2.5 + normal.y * 1.5 + warp * 1.2 + 0.15 * sin(p.x * 4.0 + t);\n vec3 sky = mix(vec3(0.85, 0.9, 1.0), vec3(0.3, 0.4, 0.6), clamp(y, 0.0, 1.0));\n vec3 ground = mix(vec3(0.25, 0.2, 0.2), vec3(0.05), clamp(-y, 0.0, 1.0));\n vec3 col = y > 0.0 ? sky : ground;\n col += smoothstep(0.06, 0.0, abs(y)) * 0.9;\n return col + pow(max(0.0, normal.x * 0.7 + normal.y * 0.7), 6.0) * 0.8;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;\n float t = iTime * uSpeed;\n float mask = letters(p);\n // A soft bevel from the mask's slope, for chrome's reflections.\n float e = 0.004;\n vec2 normal = vec2(letters(p + vec2(e, 0.0)) - letters(p - vec2(e, 0.0)), letters(p + vec2(0.0, e)) - letters(p - vec2(0.0, e)));\n // Glow and outline: the mask's average and maximum on rings round the point.\n float glow = 0.0;\n float ring = 0.0;\n for (int i = 0; i < 12; i++) {\n float a = float(i) * 0.5236;\n vec2 dir = vec2(cos(a), sin(a));\n glow += letters(p + dir * 0.02) + letters(p + dir * 0.05) * 0.6;\n ring = max(ring, letters(p + dir * uOutline));\n }\n glow /= 19.2;\n vec3 fill = uFill == 0 ? plasmaFill(p, t) : uFill == 1 ? fireFill(p, t) : uFill == 2 ? causticsFill(p, t) : chromeFill(p, t, normal * 2.0);\n fill *= uTint;\n vec3 col = uBackground + fill * glow * uGlow;\n col = mix(col, uOutlineColor, clamp(ring - mask, 0.0, 1.0) * step(0.0001, uOutline));\n col = mix(col, fill, mask);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Inferno\", values: { uFill: 1, uBackground: [0.05, 0.01, 0.0], uGlow: 1.2, uOutline: 0 } },\n { name: \"Pool\", values: { uFill: 2, uBackground: [0.0, 0.08, 0.14], uOutlineColor: [0.7, 0.95, 1] } },\n { name: \"Chrome\", values: { uFill: 3, uBackground: [0.06, 0.06, 0.08], uGlow: 0.3, uOutline: 0.002 } },\n ],\n};\n\n/** Shader effects that fill or animate text, drawn from a text image (see `textImage`). */\nexport const textShaders: ShaderEffect[] = [shaderText];\n","import { FBM, glsl, HASH, NOISE, ROTATE } from \"../glsl.js\";\nimport { SAMPLE_IMAGES } from \"../images.js\";\nimport type { ShaderEffect } from \"../types.js\";\nimport { PICTURE } from \"./image.js\";\n\nexport const imageKenBurns: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ken-burns\",\n name: \"Ken Burns\",\n description: \"A slow documentary-style pan and zoom across an image, easing in and out and back again.\",\n category: \"image\",\n tags: [\"image\", \"camera\", \"documentary\", \"slideshow\"],\n loop: 12,\n source: glsl(\n `// Ken Burns: a slow, eased pan and zoom across a cover-fitted image, there and back.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uZoomStart; // @control min=1 max=3 default=1.05 label=\"Start zoom\"\nuniform float uZoomEnd; // @control min=1 max=3 default=1.4 label=\"End zoom\"\nuniform float uAngle; // @control min=0 max=360 default=20 label=\"Pan direction (°)\"\nuniform float uDuration; // @control min=2 max=30 default=6 label=\"Duration (s)\"`,\n 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 vec3 col = picture(uImage, 0.5 + (uv - 0.5) * window + pan);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Push in\", values: { uZoomStart: 1.0, uZoomEnd: 1.5, uAngle: 0 } },\n { name: \"Pull out\", values: { uZoomStart: 1.6, uZoomEnd: 1.05, uAngle: 200 } },\n { name: \"Slow drift\", values: { uZoomStart: 1.2, uZoomEnd: 1.25, uAngle: 0, uDuration: 12 } },\n ],\n};\n\nexport const imageAscii: ShaderEffect = {\n kind: \"shader\",\n id: \"image-ascii\",\n name: \"ASCII art\",\n description: \"An image drawn as text characters picked by brightness, in one ink or the picture's own colours.\",\n category: \"image\",\n tags: [\"image\", \"ascii\", \"text\", \"terminal\", \"retro\"],\n source: glsl(\n `// ASCII art: each cell of the image becomes a character, denser for brighter cells.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uCell; // @control min=4 max=32 default=9 label=\"Cell size (px)\"\nuniform int uColourMode; // @control min=0 max=1 default=0 label=\"Colour (0 ink, 1 original)\"\nuniform vec3 uInk; // @control color default=#A3E635 label=\"Ink\"\nuniform vec3 uBackground; // @control color default=#0A0F0A label=\"Background\"`,\n 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 vec3 src = picture(uImage, (id + 0.5) * cell / iResolution.xy);\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), 1.0);\n}`,\n ),\n presets: [\n { name: \"Terminal\", values: { uColourMode: 0, uInk: [0.64, 0.9, 0.21], uBackground: [0.04, 0.06, 0.04] } },\n { name: \"Colour\", values: { uColourMode: 1, uBackground: [0.02, 0.02, 0.03] } },\n { name: \"Typewriter\", values: { uColourMode: 0, uInk: [0.1, 0.1, 0.12], uBackground: [0.96, 0.94, 0.88], uCell: 7 } },\n ],\n};\n\nexport const imageShatter: ShaderEffect = {\n kind: \"shader\",\n id: \"image-shatter\",\n name: \"Shatter\",\n description: \"An image breaking into glass-like shards that fly apart, spin and reassemble in a loop.\",\n category: \"image\",\n tags: [\"image\", \"shatter\", \"transition\", \"voronoi\", \"explode\"],\n loop: 5,\n source: glsl(\n `// Shatter: Voronoi shards of the image fly apart, spin and come back together.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform bool uAuto; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=0.5 label=\"Progress (when still)\"\nuniform float uCount; // @control min=3 max=30 default=8 label=\"Shards (across height)\"\nuniform float uSpread; // @control min=0 max=2 default=0.6 label=\"Spread\"\nuniform float uSpin; // @control min=0 max=6.28 default=1.5 label=\"Spin\"\nuniform vec3 uBackground; // @control color default=#0B0B12 label=\"Background\"`,\n HASH,\n ROTATE,\n PICTURE,\n `vec2 shardSite(vec2 cell) {\n return cell + 0.15 + 0.7 * hash22(cell);\n}\n\n// The shard (cell) under grid point q, and how far q is from its edge (xy: cell, z: edge gap).\nvec3 shardAt(vec2 q) {\n vec2 base = floor(q);\n float d1 = 1e9;\n float d2 = 1e9;\n vec2 id = base;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 c = base + vec2(float(i), float(j));\n float d = distance(q, shardSite(c));\n if (d < d1) {\n d2 = d1;\n d1 = d;\n id = c;\n } else if (d < d2) {\n d2 = d;\n }\n }\n }\n return vec3(id, d2 - d1);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n float k = uAuto ? smoothstep(0.2, 0.8, 0.5 - 0.5 * cos(iTime * 6.28318 / 5.0)) : uProgress;\n vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * uCount;\n // Shard centres move out from the middle; shards keep their size, so gaps open between them.\n float grow = 1.0 + uSpread * k;\n vec2 base = floor(p / grow);\n vec3 col = uBackground;\n float top = -1.0;\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 c = base + vec2(float(i), float(j));\n vec2 site = shardSite(c);\n vec2 h = hash22(c + 41.7);\n vec2 centre = site * grow + (h - 0.5) * 1.2 * k;\n float a = (h.x - 0.5) * 2.0 * uSpin * k;\n // Back to where this pixel would sit in the unbroken image, if it is on this shard.\n vec2 q = rot(-a) * (p - centre) + site;\n vec3 s = shardAt(q);\n if (s.x == c.x && s.y == c.y && h.y > top) {\n top = h.y;\n vec2 uv = q / uCount * iResolution.y / iResolution.xy + 0.5;\n vec3 shard = picture(uImage, uv);\n shard *= 1.0 - 0.35 * k * abs(sin(a));\n shard += k * 0.35 * smoothstep(0.06, 0.0, s.z);\n col = shard;\n }\n }\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Burst\", values: { uCount: 6, uSpread: 1.4, uSpin: 3 } },\n { name: \"Crackle\", values: { uCount: 18, uSpread: 0.15, uSpin: 0.4 } },\n ],\n};\n\nexport const imageMelt: ShaderEffect = {\n kind: \"shader\",\n id: \"image-melt\",\n name: \"Melt\",\n description: \"An image melting and dripping downwards in slow, noisy runs.\",\n category: \"image\",\n tags: [\"image\", \"melt\", \"drip\", \"psychedelic\", \"distortion\"],\n source: glsl(\n `// Melt: noise-driven runs drag the image downwards.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uAmount; // @control min=0 max=0.6 default=0.18 label=\"Amount\"\nuniform float uSpeed; // @control min=0 max=2 default=0.35 label=\"Flow speed\"\nuniform float uScale; // @control min=1 max=20 default=6 label=\"Scale\"`,\n 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 vec3 col = picture(uImage, st);\n // A little sheen along the leading edges of the runs.\n col += 0.12 * smoothstep(0.55, 0.9, drips) * uAmount * 4.0;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Slow ooze\", values: { uAmount: 0.12, uSpeed: 0.15, uScale: 4 } },\n { name: \"Meltdown\", values: { uAmount: 0.45, uSpeed: 0.8, uScale: 9 } },\n ],\n};\n\nexport const imageRisograph: ShaderEffect = {\n kind: \"shader\",\n id: \"image-risograph\",\n name: \"Risograph\",\n description: \"An image printed in two posterized, slightly misregistered inks on grainy paper.\",\n category: \"image\",\n tags: [\"image\", \"print\", \"riso\", \"editorial\", \"poster\"],\n source: glsl(\n `// Risograph: two posterized ink layers, out of register, on grainy paper.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uLevels; // @control min=2 max=8 default=4 label=\"Levels\"\nuniform vec3 uInkA; // @control color default=#FF48B0 label=\"Ink A\"\nuniform vec3 uInkB; // @control color default=#0078BF label=\"Ink B\"\nuniform float uOffset; // @control min=0 max=20 default=4 label=\"Misregistration (px)\"\nuniform float uGrain; // @control min=0 max=1 default=0.4 label=\"Grain\"\nuniform vec3 uPaper; // @control color default=#F5EFE0 label=\"Paper\"`,\n 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 vec3 a = picture(uImage, uv + shift);\n vec3 b = picture(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, 1.0);\n}`,\n ),\n presets: [\n { name: \"Pink & blue\", values: { uInkA: [1, 0.28, 0.69], uInkB: [0, 0.47, 0.75] } },\n { name: \"Sunflower & teal\", values: { uInkA: [1, 0.71, 0], uInkB: [0, 0.51, 0.54], uLevels: 3 } },\n { name: \"Red & black\", values: { uInkA: [1, 0.25, 0.25], uInkB: [0.15, 0.15, 0.17], uOffset: 2, uGrain: 0.6 } },\n ],\n};\n\nexport const imageThermal: ShaderEffect = {\n kind: \"shader\",\n id: \"image-thermal\",\n name: \"Thermal\",\n description: \"An image seen through a heat camera or night-vision goggles.\",\n category: \"image\",\n tags: [\"image\", \"thermal\", \"night-vision\", \"surveillance\", \"colour\"],\n source: glsl(\n `// Thermal: brightness mapped to a heat palette, or to green night-vision phosphor.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uMode; // @control min=0 max=1 default=0 label=\"Palette (0 thermal, 1 night vision)\"\nuniform float uNoise; // @control min=0 max=0.5 default=0.04 label=\"Noise\"\nuniform float uContrast; // @control min=0.5 max=3 default=1.3 label=\"Contrast\"`,\n 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 vec3 src = 0.4 * picture(uImage, uv) + 0.15 * (picture(uImage, uv + vec2(px.x, 0.0)) + picture(uImage, uv - vec2(px.x, 0.0)) +\n picture(uImage, uv + vec2(0.0, px.y)) + picture(uImage, uv - vec2(0.0, px.y)));\n float l = dot(src, 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, 1.0);\n}`,\n ),\n presets: [\n { name: \"Thermal\", values: { uMode: 0, uNoise: 0.04, uContrast: 1.3 } },\n { name: \"Night vision\", values: { uMode: 1, uNoise: 0.2, uContrast: 1.8 } },\n ],\n};\n\nexport const imageEdgeGlow: ShaderEffect = {\n kind: \"shader\",\n id: \"image-edge-glow\",\n name: \"Edge glow\",\n description: \"An image's edges traced as glowing neon lines over a dimmed picture, with a travelling pulse.\",\n category: \"image\",\n tags: [\"image\", \"neon\", \"edges\", \"outline\", \"cyber\"],\n loop: 2,\n source: glsl(\n `// Edge glow: Sobel edges as neon lines and a soft halo over the dimmed image.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uThreshold; // @control min=0 max=1 default=0.15 label=\"Threshold\"\nuniform vec3 uGlow; // @control color default=#22D3EE label=\"Glow colour\"\nuniform float uWidth; // @control min=0.5 max=4 default=1.5 label=\"Glow width (px)\"\nuniform float uDim; // @control min=0 max=1 default=0.75 label=\"Dim image\"\nuniform float uPulse; // @control min=0 max=1 default=0.4 label=\"Pulse\"`,\n PICTURE,\n `float luma(vec2 uv) {\n return dot(picture(uImage, uv), vec3(0.2126, 0.7152, 0.0722));\n}\n\n// Sobel edge strength, sampling d apart (in uv).\nfloat sobel(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 float gx = tr + 2.0 * r + br - tl - 2.0 * l - bl;\n float gy = tl + 2.0 * t + tr - bl - 2.0 * b - br;\n return length(vec2(gx, gy));\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 vec3 col = picture(uImage, uv) * (1.0 - uDim);\n col += uGlow * (line + 0.45 * halo) * pulse;\n col += vec3(1.0) * line * line * 0.35 * pulse;\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Cyan\", values: { uGlow: [0.13, 0.83, 0.93] } },\n { name: \"Magenta blackout\", values: { uGlow: [0.93, 0.28, 0.6], uDim: 1, uThreshold: 0.1 } },\n ],\n};\n\nexport const imageTiltShift: ShaderEffect = {\n kind: \"shader\",\n id: \"image-tilt-shift\",\n name: \"Tilt-shift\",\n description: \"An image blurred outside a sharp horizontal band, with punchy colour, so it looks like a miniature.\",\n category: \"image\",\n tags: [\"image\", \"blur\", \"miniature\", \"photography\", \"depth\"],\n source: glsl(\n `// Tilt-shift: blur away from a focus band, plus saturation, for the miniature look.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.city} label=\"Image\"\nuniform float uFocus; // @control min=0 max=1 default=0.45 label=\"Focus position\"\nuniform float uBand; // @control min=0 max=0.6 default=0.12 label=\"Focus band width\"\nuniform float uBlur; // @control min=0 max=30 default=12 label=\"Blur (px)\"\nuniform float uSaturation; // @control min=0 max=2 default=1.4 label=\"Saturation\"`,\n 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 vec3 sum = vec3(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 sum += picture(uImage, uv + r * vec2(cos(a), sin(a)) / iResolution.xy);\n }\n vec3 col = sum / 24.0;\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, 1.0);\n}`,\n ),\n presets: [\n { name: \"Model village\", values: { uFocus: 0.4, uBand: 0.1, uBlur: 16, uSaturation: 1.6 } },\n { name: \"Subtle\", values: { uBand: 0.25, uBlur: 6, uSaturation: 1.15 } },\n ],\n};\n\nexport const imageSlitScan: ShaderEffect = {\n kind: \"shader\",\n id: \"image-slit-scan\",\n name: \"Slit-scan\",\n description: \"An image smeared into time-stretched streaks, like a slit-scan photograph.\",\n category: \"image\",\n tags: [\"image\", \"slit-scan\", \"smear\", \"experimental\", \"distortion\"],\n source: glsl(\n `// Slit-scan: rows (or columns) squeeze towards a moving slit and smear into streaks.\nuniform sampler2D uImage; // @control filter=linear wrap=mirror default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uDirection; // @control min=0 max=1 default=0 label=\"Direction (0 horizontal, 1 vertical)\"\nuniform float uStretch; // @control min=0 max=1 default=0.45 label=\"Stretch\"\nuniform float uSpeed; // @control min=0 max=3 default=0.6 label=\"Speed\"`,\n 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 vec3 col = vec3(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 col += picture(uImage, st);\n }\n fragColor = vec4(col / 8.0, 1.0);\n}`,\n ),\n presets: [\n { name: \"Drift\", values: { uDirection: 0, uStretch: 0.3, uSpeed: 0.3 } },\n { name: \"Waterfall\", values: { uDirection: 1, uStretch: 0.7, uSpeed: 1.2 } },\n ],\n};\n\nexport const imageMosaic: ShaderEffect = {\n kind: \"shader\",\n id: \"image-mosaic\",\n name: \"Mosaic flip\",\n description: \"Hexagonal or triangular tiles flipping over from the left to reveal an image, then back.\",\n category: \"image\",\n tags: [\"image\", \"reveal\", \"transition\", \"tiles\", \"hexagon\"],\n loop: 6,\n source: glsl(\n `// Mosaic flip: tiles turn over in a wave from the left, background on one face, image on the other.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform int uShape; // @control min=0 max=1 default=0 label=\"Tile shape (0 hexagon, 1 triangle)\"\nuniform float uSize; // @control min=10 max=160 default=48 label=\"Tile size (px)\"\nuniform bool uAuto; // @control default=true label=\"Animate\"\nuniform float uProgress; // @control min=0 max=1 default=1 label=\"Progress (when still)\"\nuniform vec3 uBackground; // @control color default=#0F172A label=\"Background\"`,\n 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 vec3 col = uBackground * 0.6;\n if (e < 1.0 - gap + 0.001) {\n vec3 face = flip < 0.5\n ? uBackground * (0.9 + 0.2 * hash12(centre * 3.17)) + 0.04\n : picture(uImage, (centre + hf) * uSize / iResolution.xy);\n col = face * (0.5 + 0.5 * squash);\n }\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Hexagons\", values: { uShape: 0, uSize: 48 } },\n { name: \"Triangles\", values: { uShape: 1, uSize: 64 } },\n ],\n};\n\nexport const imageChromaticLens: ShaderEffect = {\n kind: \"shader\",\n id: \"image-chromatic-lens\",\n name: \"Chromatic lens\",\n description: \"An image through a cheap wide lens: barrel distortion and colour fringes growing towards the edges.\",\n category: \"image\",\n tags: [\"image\", \"lens\", \"aberration\", \"distortion\", \"vintage\"],\n source: glsl(\n `// Chromatic lens: barrel distortion with red, green and blue bent by different amounts.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label=\"Image\"\nuniform float uDistortion; // @control min=-0.5 max=1 default=0.25 label=\"Distortion\"\nuniform float uAberration; // @control min=0 max=0.1 default=0.025 label=\"Aberration\"\nuniform float uVignette; // @control min=0 max=1 default=0.4 label=\"Vignette\"`,\n 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 vec3 col = vec3(\n picture(uImage, lens(c, uDistortion + uAberration, aspect)).r,\n picture(uImage, lens(c, uDistortion, aspect)).g,\n picture(uImage, lens(c, uDistortion - uAberration, aspect)).b\n );\n col *= 1.0 - uVignette * smoothstep(0.25, 0.95, length(c));\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Fisheye\", values: { uDistortion: 0.7, uAberration: 0.04, uVignette: 0.6 } },\n { name: \"Fringe only\", values: { uDistortion: 0, uAberration: 0.05, uVignette: 0.2 } },\n ],\n};\n\nexport const imageOilPaint: ShaderEffect = {\n kind: \"shader\",\n id: \"image-oil-paint\",\n name: \"Oil paint\",\n description: \"An image repainted in flat, edge-keeping brush dabs, like an oil painting.\",\n category: \"image\",\n tags: [\"image\", \"painterly\", \"artistic\", \"kuwahara\", \"filter\"],\n source: glsl(\n `// Oil paint: a four-sector Kuwahara filter, each pixel takes the calmest neighbourhood's colour.\nuniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.portrait} label=\"Image\"\nuniform int uRadius; // @control min=1 max=8 default=4 label=\"Brush radius (px)\"\nuniform float uSharpness; // @control min=0.5 max=8 default=4 label=\"Sharpness\"\nuniform float uSaturation; // @control min=0 max=2 default=1.15 label=\"Saturation\"`,\n PICTURE,\n `void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 uv = fragCoord / iResolution.xy;\n vec2 px = 1.0 / iResolution.xy;\n // Sums of colour and colour² over four overlapping squares: down-left, down-right, up-left, up-right.\n vec3 m0 = vec3(0.0), m1 = vec3(0.0), m2 = vec3(0.0), m3 = vec3(0.0);\n vec3 s0 = vec3(0.0), s1 = vec3(0.0), s2 = vec3(0.0), s3 = vec3(0.0);\n for (int j = 0; j <= 8; j++) {\n if (j > uRadius) break;\n for (int i = 0; i <= 8; i++) {\n if (i > uRadius) break;\n vec2 o = vec2(float(i), float(j)) * px;\n vec3 c = picture(uImage, uv + vec2(-o.x, -o.y));\n m0 += c;\n s0 += c * c;\n c = picture(uImage, uv + vec2(o.x, -o.y));\n m1 += c;\n s1 += c * c;\n c = picture(uImage, uv + vec2(-o.x, o.y));\n m2 += c;\n s2 += c * c;\n c = picture(uImage, uv + o);\n m3 += c;\n s3 += c * c;\n }\n }\n float n = float((uRadius + 1) * (uRadius + 1));\n m0 /= n; m1 /= n; m2 /= n; m3 /= n;\n // Weight each square by how calm (low-variance) it is; sharpness sets how strongly the calmest wins.\n vec4 v = vec4(\n dot(abs(s0 / n - m0 * m0), vec3(1.0)),\n dot(abs(s1 / n - m1 * m1), vec3(1.0)),\n dot(abs(s2 / n - m2 * m2), vec3(1.0)),\n dot(abs(s3 / n - m3 * m3), vec3(1.0))\n );\n vec4 w = pow(v * 100.0 + 1e-3, vec4(-uSharpness));\n vec3 col = (m0 * w.x + m1 * w.y + m2 * w.z + m3 * w.w) / (w.x + w.y + w.z + w.w);\n float l = dot(col, vec3(0.2126, 0.7152, 0.0722));\n col = mix(vec3(l), col, uSaturation);\n fragColor = vec4(col, 1.0);\n}`,\n ),\n presets: [\n { name: \"Broad strokes\", values: { uRadius: 7, uSharpness: 6, uSaturation: 1.3 } },\n { name: \"Watercolour\", values: { uRadius: 3, uSharpness: 1.5, uSaturation: 0.9 } },\n ],\n};\n\n/** More image treatments: each takes an image control and changes the picture. */\nexport const imageTreatments: ShaderEffect[] = [\n imageKenBurns,\n imageAscii,\n imageShatter,\n imageMelt,\n imageRisograph,\n imageThermal,\n imageEdgeGlow,\n imageTiltShift,\n imageSlitScan,\n imageMosaic,\n imageChromaticLens,\n imageOilPaint,\n];\n","import { rgbToHex } from \"../shader/controls.js\";\nimport type { SvgAnimation, SvgMotion } from \"../vector/motion.js\";\nimport { textWidthEm } from \"./images.js\";\nimport type { VectorEffect } from \"./types.js\";\n\n/*\n * Text effects take any word or phrase: `derived` works out a font size from\n * its length (see `textWidthEm`) and, where it can, `textLength` stretches it\n * to the width that size predicts, so it fills the same box in any font.\n */\n\nconst r1 = (n: number) => Math.round(n * 10) / 10;\n\n/** A line fitted to `width` units, at most `max` high: its font size, width and left edge (centred on 200). */\nfunction fit(text: string, width: number, max: number, ems = textWidthEm(text)) {\n const e = Math.max(0.6, ems);\n const size = Math.min(max, width / e);\n return { size: r1(size), length: r1(e * size), left: r1(200 - (e * size) / 2) };\n}\n\n/** Letters as code points, so emoji and accents count once. */\nconst lettersOf = (text: unknown) => Array.from(String(text));\n\n/** `a` mixed `t` of the way to `b`, colours as written by vector controls ([r, g, b] 0–1). */\nconst mixHex = (a: unknown, b: unknown, t: number) => {\n const x = (Array.isArray(a) ? a : [1, 1, 1]) as number[];\n const y = (Array.isArray(b) ? b : [1, 1, 1]) as number[];\n return rgbToHex([0, 1, 2].map((i) => x[i]! + (y[i]! - x[i]!) * t));\n};\n\n/** Instant changes: the attribute holds each value from its time on (flicker, jumps). */\nconst holds = (id: string, attr: string, keys: readonly (readonly [number, string | number])[]): SvgAnimation[] =>\n keys.map(([delay, value]) => ({ id, attrs: { [attr]: [value, value] }, delay, ms: 0 }));\n\n/** A derived number in an animation's numeric field (`ms`, `delay`). */\nconst n = (name: string) => `{{${name}}}` as unknown as number;\n\nconst MONO = `ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace`;\n/** A monospace letter's advance, in ems. */\nconst MONO_EM = 0.6;\nconst HEAVY = `'Arial Black', 'Helvetica Neue', Impact, system-ui, sans-serif`;\nconst SANS = `system-ui, 'Helvetica Neue', Arial, sans-serif`;\n\n/** The caret's blinks after typing: on and off every 500 ms. */\nconst BLINKS = 7;\n\nexport const typewriter: VectorEffect = {\n kind: \"vector\",\n id: \"typewriter\",\n name: \"Typewriter\",\n description: \"Letters typed out one at a time behind a block caret, which then blinks.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"typing\", \"terminal\", \"caption\"],\n hold: 300,\n presets: [\n { name: \"Terminal\", values: { paper: [0.03, 0.05, 0.04], ink: [0.3, 1, 0.45] } },\n { name: \"Paper\", values: { paper: [0.98, 0.95, 0.88], ink: [0.15, 0.13, 0.12], pace: 120 } },\n ],\n // Monospace, so the caret lands after the last letter however long the text is.\n derived: (v) => {\n const count = Math.max(1, lettersOf(v.text).length);\n const size = r1(Math.min(44, 340 / ((count + 1) * MONO_EM)));\n const left = r1(200 - ((count + 1) * MONO_EM * size) / 2);\n const typing = Math.round(count * Number(v.pace));\n return {\n size,\n left,\n base: r1(100 + size * 0.35),\n end: r1(left + count * MONO_EM * size),\n typing,\n ...Object.fromEntries(Array.from({ length: BLINKS }, (_, k) => [`blink${k}`, typing + k * 500])),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Hello, world.' label='Text'}} {{paper: color default=#111827 label='Background'}} {{ink: color default=#F9FAFB label='Text colour'}} {{pace: float min=30 max=300 default=90 step=5 label='Ms per letter'}} --><rect width=\"400\" height=\"200\" fill=\"{{paper}}\"/><text id=\"typed\" x=\"{{left}}\" y=\"{{base}}\" font-family=\"${MONO}\" font-size=\"{{size}}\" fill=\"{{ink}}\" xml:space=\"preserve\">{{text}}</text><text id=\"caret\" x=\"{{end}}\" y=\"{{base}}\" font-family=\"${MONO}\" font-size=\"{{size}}\" fill=\"{{ink}}\" opacity=\"0\">▌</text></svg>`,\n animate: [\n { id: \"typed\", write: \"{{text}}\", caret: \"▌\", ms: n(\"typing\"), ease: \"linear\" },\n // Hidden while the writer shows its own caret, then blinking where it stopped.\n ...holds(\"caret\", \"opacity\", [[0, 0], ...Array.from({ length: BLINKS }, (_, k) => [n(`blink${k}`), k % 2 ? 0 : 1] as const)]),\n ],\n },\n};\n\nexport const scrambleText: VectorEffect = {\n kind: \"vector\",\n id: \"scramble-text\",\n name: \"Scramble text\",\n description: \"Random glyphs flickering, then settling into the real word letter by letter, left to right.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"decode\", \"hacker\", \"cyber\", \"reveal\"],\n hold: 1200,\n presets: [\n { name: \"Matrix\", values: { background: [0, 0.03, 0.01], ink: [0.4, 1, 0.5], accent: [0.1, 0.7, 0.25], glyphs: \"01\" } },\n { name: \"Amber\", values: { background: [0.08, 0.04, 0], ink: [1, 0.72, 0.2], accent: [0.9, 0.4, 0.05] } },\n ],\n derived: (v) => {\n const count = Math.max(1, lettersOf(v.text).length);\n const size = r1(Math.min(60, 360 / (count * MONO_EM)));\n const width = r1(count * MONO_EM * size);\n const base = r1(100 + size * 0.35);\n return { size, base, barX: r1(200 - width / 2), barY: r1(base + size * 0.3), barW: width, decode: Math.round(count * Number(v.pace)), glowWide: Number(v.glow) * 2 };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='ACCESS GRANTED' label='Text'}} {{glyphs: text default='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&@$*+' label='Scramble glyphs'}} {{background: color default=#05070D label='Background'}} {{ink: color default=#E2E8F0 label='Text colour'}} {{accent: color default=#22D3EE label='Accent'}} {{pace: float min=20 max=250 default=70 step=5 label='Ms per letter'}} {{glow: float min=0 max=6 default=2 step=0.5 label='Glow'}} --><defs><filter id=\"glow\" x=\"-20%\" y=\"-50%\" width=\"140%\" height=\"200%\"><feGaussianBlur stdDeviation=\"{{glowWide}}\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text id=\"word\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" font-family=\"${MONO}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\" filter=\"url(#glow)\" xml:space=\"preserve\">{{text}}</text><rect id=\"bar\" x=\"{{barX}}\" y=\"{{barY}}\" width=\"0\" height=\"3\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n // Pure noise for a moment (the scramble runs before the change starts), then it decodes.\n { id: \"word\", write: \"{{text}}\", scramble: \"{{glyphs}}\", delay: 500, ms: n(\"decode\"), ease: \"linear\" },\n { id: \"bar\", attrs: { width: [0, n(\"barW\")] }, delay: 500, ms: n(\"decode\"), ease: \"linear\" },\n ],\n },\n};\n\n/** Kinetic stagger's letter slots: one element per letter, so each can move on its own. */\nconst SLOTS = 20;\n\nexport const kineticStagger: VectorEffect = {\n kind: \"vector\",\n id: \"kinetic-stagger\",\n name: \"Kinetic stagger\",\n description: \"Each letter springs up into place in turn, rising, turning and overshooting, then an underline sweeps beneath.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"kinetic\", \"typography\", \"headline\", \"intro\"],\n hold: 1200,\n presets: [\n { name: \"Poster\", values: { background: [0.98, 0.87, 0.2], ink: [0.07, 0.07, 0.07], accent: [0.9, 0.15, 0.2] } },\n { name: \"Midnight\", values: { background: [0.04, 0.05, 0.12], ink: [0.95, 0.96, 1], accent: [0.55, 0.45, 1], stagger: 80 } },\n ],\n // Up to SLOTS letters, each centred in its estimated advance; unused slots stay empty.\n derived: (v) => {\n const letters = lettersOf(v.text).slice(0, SLOTS);\n const widths = letters.map((c) => textWidthEm(c));\n const ems = Math.max(0.6, widths.reduce((a, b) => a + b, 0));\n const size = Math.min(92, 370 / ems);\n const base = 100 + size * 0.35;\n const stagger = Number(v.stagger);\n const out: Record<string, string | number> = {\n size: r1(size),\n base: r1(base),\n rise: r1(base - size * 0.1),\n drop: r1(base + size * 0.6),\n lineX: r1(200 - (ems * size) / 2),\n lineY: r1(base + size * 0.2),\n lineW: r1(ems * size),\n lineAt: Math.round(letters.length * stagger + 400),\n };\n let x = 200 - (ems * size) / 2;\n for (let i = 0; i < SLOTS; i++) {\n const w = (widths[i] ?? 0) * size;\n out[`c${i}`] = letters[i]?.trim() ?? \"\";\n out[`x${i}`] = r1(x + w / 2);\n out[`d${i}`] = Math.round(i * stagger);\n out[`e${i}`] = Math.round(i * stagger + 380);\n x += w;\n }\n return out;\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Kinetic' label='Text'}} {{background: color default=#F8FAFC label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#F43F5E label='Underline'}} {{stagger: float min=20 max=200 default=55 step=5 label='Ms between letters'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/>${Array.from(\n { length: SLOTS },\n (_, i) =>\n `<text id=\"l${i}\" text-anchor=\"middle\" transform=\"translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)\" opacity=\"0\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{ink}}\">{{c${i}}}</text>`,\n ).join(\"\")}<rect id=\"line\" x=\"{{lineX}}\" y=\"{{lineY}}\" width=\"0\" height=\"6\" rx=\"3\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n ...Array.from({ length: SLOTS }, (_, i): SvgAnimation[] => [\n {\n id: `l${i}`,\n attrs: { transform: [`translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)`, `translate({{x${i}}} {{rise}}) rotate(5) scale(1.12)`], opacity: [0, 1] },\n delay: n(`d${i}`),\n ms: 380,\n ease: \"out\",\n },\n { id: `l${i}`, attrs: { transform: [`translate({{x${i}}} {{rise}}) rotate(5) scale(1.12)`, `translate({{x${i}}} {{base}}) rotate(0) scale(1)`] }, delay: n(`e${i}`), ms: 260, ease: \"in-out\" },\n ]).flat(),\n { id: \"line\", attrs: { width: [0, n(\"lineW\")] }, delay: n(\"lineAt\"), ms: 500, ease: \"in-out\" },\n ],\n },\n};\n\nexport const neonSign: VectorEffect = {\n kind: \"vector\",\n id: \"neon-sign\",\n name: \"Neon sign\",\n description: \"Glowing neon tube lettering that stutters on, then keeps one faulty letter buzzing.\",\n category: \"text\",\n tags: [\"text\", \"neon\", \"glow\", \"sign\", \"night\", \"retro\"],\n hold: 400,\n presets: [\n { name: \"Hot pink\", values: { tube: [1, 0.2, 0.65], wall: [0.06, 0.02, 0.07] } },\n { name: \"Ice\", values: { tube: [0.35, 0.85, 1], wall: [0.02, 0.04, 0.08], glow: 5 } },\n { name: \"Lime\", values: { tube: [0.6, 1, 0.2], wall: [0.03, 0.05, 0.02] } },\n ],\n // The word in three runs, so the buzzing letter can flicker on its own.\n derived: (v) => {\n const letters = lettersOf(v.text);\n const k = Math.min(Math.max(0, Math.round(Number(v.faulty)) - 1), Math.max(0, letters.length - 1));\n const { size, length } = fit(String(v.text), 340, 84);\n return {\n head: letters.slice(0, k).join(\"\"),\n mid: letters[k] ?? \"\",\n tail: letters.slice(k + 1).join(\"\"),\n size,\n length,\n base: r1(100 + size * 0.3),\n far: Number(v.glow) * 3,\n core: mixHex(v.tube, [1, 1, 1], 0.6),\n };\n },\n motion: ((): SvgMotion => {\n const word = `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"'Pacifico', 'Brush Script MT', 'Segoe Script', 'Snell Roundhand', cursive\" font-size=\"{{size}}\"`;\n const runs = (id: string) => `<tspan>{{head}}</tspan><tspan id=\"${id}\">{{mid}}</tspan><tspan>{{tail}}</tspan>`;\n // Start-up: the tubes catch, drop out and catch again.\n const startUp = [[0, 0], [150, 0.85], [210, 0], [330, 1], [390, 0.15], [450, 1], [620, 0.35], [680, 1]] as const;\n const buzz = [[0, 1], [1300, 0.15], [1350, 1], [1420, 0.2], [1520, 1], [2100, 0.1], [2160, 1], [2230, 0.25], [2280, 1]] as const;\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Open late' label='Text'}} {{tube: color default=#FF3DA5 label='Tube'}} {{wall: color default=#120612 label='Wall'}} {{glow: float min=0.5 max=8 default=3.5 step=0.5 label='Glow'}} {{faulty: int min=1 max=24 default=6 label='Buzzing letter'}} --><defs><filter id=\"neon\" x=\"-30%\" y=\"-80%\" width=\"160%\" height=\"260%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{glow}}\" result=\"near\"/><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"{{far}}\" result=\"far\"/><feMerge><feMergeNode in=\"far\"/><feMergeNode in=\"far\"/><feMergeNode in=\"near\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter><filter id=\"haze\" x=\"-50%\" y=\"-100%\" width=\"200%\" height=\"300%\"><feGaussianBlur stdDeviation=\"30\"/></filter></defs><rect width=\"400\" height=\"200\" fill=\"{{wall}}\"/><g id=\"sign\" opacity=\"0\"><ellipse cx=\"200\" cy=\"100\" rx=\"170\" ry=\"55\" fill=\"{{tube}}\" opacity=\"0.18\" filter=\"url(#haze)\"/><text ${word} fill=\"{{tube}}\" stroke=\"{{tube}}\" stroke-width=\"1.5\" filter=\"url(#neon)\">${runs(\"buzzGlow\")}</text><text ${word} fill=\"{{core}}\">${runs(\"buzzCore\")}</text></g></svg>`,\n animate: [\n ...holds(\"sign\", \"opacity\", startUp),\n // fill-opacity rather than opacity: browsers ignore opacity on a <tspan>.\n ...[\"buzzGlow\", \"buzzCore\"].flatMap((id) => [...holds(id, \"fill-opacity\", buzz), ...holds(id, \"stroke-opacity\", buzz)]),\n ],\n };\n })(),\n};\n\nexport const strokeDrawText: VectorEffect = {\n kind: \"vector\",\n id: \"stroke-draw-text\",\n name: \"Stroke draw text\",\n description: \"A word's outline traced on along every letter, then its fill fading in.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"draw-on\", \"outline\", \"reveal\", \"handwriting\"],\n hold: 1200,\n presets: [\n { name: \"Blueprint\", values: { background: [0.05, 0.2, 0.45], outline: [0.85, 0.93, 1], fill: [0.85, 0.93, 1], fillOpacity: 0.15 } },\n { name: \"Gold\", values: { background: [0.07, 0.06, 0.05], outline: [1, 0.8, 0.35], fill: [0.85, 0.6, 0.15] } },\n ],\n // <text> takes no pathLength, so `draw` cannot measure it: the dash grows instead, longer than any letter's outline.\n derived: (v) => {\n const { size, length } = fit(String(v.text), 360, 100);\n return { size, length, base: r1(100 + size * 0.35), dash: Math.round(size * 6) };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Draw' label='Text'}} {{background: color default=#FFFBF5 label='Background'}} {{outline: color default=#1E293B label='Outline'}} {{fill: color default=#F97316 label='Fill'}} {{width: float min=0.5 max=6 default=2 step=0.5 label='Outline width'}} {{fillOpacity: float min=0 max=1 default=1 label='Fill opacity'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text id=\"word\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" fill=\"{{fill}}\" fill-opacity=\"0\" stroke=\"{{outline}}\" stroke-width=\"{{width}}\" stroke-linejoin=\"round\" stroke-dasharray=\"0 {{dash}}\">{{text}}</text></svg>`,\n animate: [\n { id: \"word\", attrs: { \"stroke-dasharray\": [\"0 {{dash}}\", \"{{dash}} 0\"] }, ms: 2000, ease: \"in-out\" },\n { id: \"word\", attrs: { \"fill-opacity\": [0, n(\"fillOpacity\")] }, delay: 1500, ms: 700, ease: \"out\" },\n ],\n },\n};\n\nexport const splitReveal: VectorEffect = {\n kind: \"vector\",\n id: \"split-reveal\",\n name: \"Split reveal\",\n description: \"A line draws across, then the title's top half rises out from behind it while the bottom half drops down.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"reveal\", \"mask\", \"editorial\", \"intro\"],\n hold: 1400,\n presets: [\n { name: \"Light\", values: { background: [0.97, 0.96, 0.94], ink: [0.08, 0.08, 0.1], line: [0.85, 0.2, 0.15] } },\n { name: \"Gold on black\", values: { background: [0.02, 0.02, 0.02], ink: [0.96, 0.84, 0.55], line: [0.96, 0.84, 0.55] } },\n ],\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), 360, 88);\n return {\n size,\n length,\n base: r1(100 + size * 0.36),\n shift: r1(size * 0.8),\n lineX1: r1(left - 10),\n lineX2: r1(400 - left + 10),\n captionY: r1(100 + size * 0.36 + 30),\n };\n },\n motion: ((): SvgMotion => {\n const word = `<text x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"800\" fill=\"{{ink}}\">{{text}}</text>`;\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Chapter One' label='Text'}} {{caption: text default='The beginning' label='Caption'}} {{background: color default=#0F172A label='Background'}} {{ink: color default=#F8FAFC label='Text colour'}} {{line: color default=#38BDF8 label='Line'}} --><defs><clipPath id=\"above\"><rect width=\"400\" height=\"100\"/></clipPath><clipPath id=\"below\"><rect y=\"100\" width=\"400\" height=\"100\"/></clipPath></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g clip-path=\"url(#above)\"><g id=\"top\" transform=\"translate(0 {{shift}})\">${word}</g></g><g clip-path=\"url(#below)\"><g id=\"bottom\" transform=\"translate(0 -{{shift}})\">${word}</g></g><path id=\"line\" d=\"M{{lineX1}} 100 H{{lineX2}}\" stroke=\"{{line}}\" stroke-width=\"2.5\" stroke-linecap=\"round\"/><text id=\"caption\" x=\"200\" y=\"{{captionY}}\" text-anchor=\"middle\" font-family=\"${SANS}\" font-size=\"13\" letter-spacing=\"3\" fill=\"{{ink}}\" opacity=\"0\">{{caption}}</text></svg>`,\n animate: [\n { id: \"line\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"top\", attrs: { transform: [\"translate(0 {{shift}})\", \"translate(0 0)\"] }, delay: 450, ms: 800, ease: \"out\" },\n { id: \"bottom\", attrs: { transform: [\"translate(0 -{{shift}})\", \"translate(0 0)\"] }, delay: 450, ms: 800, ease: \"out\" },\n { id: \"line\", attrs: { opacity: [1, 0] }, delay: 1100, ms: 400 },\n { id: \"caption\", attrs: { opacity: [0, 0.75] }, delay: 1100, ms: 500, ease: \"out\" },\n ],\n };\n })(),\n};\n\nexport const highlighter: VectorEffect = {\n kind: \"vector\",\n id: \"highlighter\",\n name: \"Highlighter\",\n description: \"A marker swipe drawn left to right behind a phrase, rough-edged like a real highlighter pen.\",\n category: \"text\",\n tags: [\"text\", \"highlight\", \"marker\", \"emphasis\", \"explainer\", \"callout\"],\n hold: 1400,\n presets: [\n { name: \"Pink\", values: { marker: [1, 0.55, 0.78] } },\n { name: \"Mint\", values: { marker: [0.55, 0.95, 0.7] } },\n { name: \"Dark\", values: { background: [0.07, 0.08, 0.1], ink: [0.97, 0.97, 0.98], marker: [0.55, 0.2, 0.95] } },\n ],\n // The swipe runs a little past the phrase at both ends, across its lower half, with a ragged second pass.\n derived: (v) => {\n const { size, length, left } = fit(String(v.text), 330, 56);\n const base = 100 + size * 0.35;\n const x0 = left - size * 0.25;\n const x1 = 400 - left + size * 0.2;\n const y = base - size * 0.3;\n return {\n size,\n length,\n base: r1(base),\n swipe: `M${r1(x0)} ${r1(y + size * 0.05)} Q${r1((x0 + x1) / 2)} ${r1(y - size * 0.06)} ${r1(x1)} ${r1(y - size * 0.02)}`,\n ragged: `M${r1(x0 + size * 0.15)} ${r1(y + size * 0.3)} L${r1(x1 - size * 0.1)} ${r1(y + size * 0.26)}`,\n thick: r1(size * 0.72),\n thin: r1(size * 0.16),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='Ship it faster' label='Phrase'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#111827 label='Text colour'}} {{marker: color default=#FDE047 label='Marker'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g transform=\"rotate(-1.2 200 100)\" opacity=\"0.9\"><path id=\"swipe\" d=\"{{swipe}}\" fill=\"none\" stroke=\"{{marker}}\" stroke-width=\"{{thick}}\"/><path id=\"ragged\" d=\"{{ragged}}\" fill=\"none\" stroke=\"{{marker}}\" stroke-width=\"{{thin}}\" stroke-linecap=\"round\"/></g><text id=\"phrase\" x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\" opacity=\"0\">{{text}}</text></svg>`,\n animate: [\n { id: \"phrase\", attrs: { opacity: [0, 1] }, ms: 300, ease: \"out\" },\n { id: \"swipe\", draw: true, delay: 350, ms: 650, ease: \"in-out\" },\n { id: \"ragged\", draw: true, delay: 420, ms: 620, ease: \"in-out\" },\n ],\n },\n};\n\n/** Word cycle's timing: how long each word rests, and how long a roll to the next takes. */\nconst SHOW_MS = 1000;\nconst ROLL_MS = 450;\nconst CYCLE_WORDS = 4;\n\nexport const wordCycle: VectorEffect = {\n kind: \"vector\",\n id: \"word-cycle\",\n name: \"Word cycle\",\n description: \"A fixed lead-in with the last word rolling through alternatives like a slot machine, an underline resizing to each.\",\n category: \"text\",\n tags: [\"text\", \"headline\", \"rotating\", \"hero\", \"marketing\", \"slot\"],\n hold: 0,\n presets: [\n { name: \"Dark\", values: { background: [0.05, 0.06, 0.1], ink: [0.95, 0.96, 1], accent: [0.4, 0.85, 0.65] } },\n { name: \"Warm\", values: { background: [1, 0.96, 0.9], ink: [0.2, 0.12, 0.08], accent: [0.93, 0.35, 0.15] } },\n ],\n // The lead-in and the longest word share the line; the reel ends with word 1 again, so the loop is seamless.\n derived: (v) => {\n const words = Array.from({ length: CYCLE_WORDS }, (_, i) => String(v[`word${i + 1}`]));\n const lead = textWidthEm(String(v.prefix));\n const ems = words.map((w) => Math.max(0.6, textWidthEm(w)));\n const total = lead + 0.3 + Math.max(...ems);\n const size = Math.min(52, 370 / total);\n const left = 200 - (total * size) / 2;\n const base = 100 + size * 0.35;\n const step = size * 1.3;\n const wx = left + (lead + 0.3) * size;\n return {\n size: r1(size),\n base: r1(base),\n px: r1(left),\n plen: r1(Math.max(0.6, lead) * size),\n wx: r1(wx),\n clipX: r1(wx - 4),\n clipY: r1(base - size * 1.0),\n clipW: r1(Math.max(...ems) * size + 8),\n clipH: r1(size * 1.32),\n underY: r1(base + size * 0.18),\n ...Object.fromEntries(\n [...words, words[0]!].flatMap((_, k) => [\n [`y${k}`, r1(base + k * step)],\n [`o${k}`, r1(k * step)],\n [`len${k}`, r1(ems[k % CYCLE_WORDS]! * size)],\n ]),\n ),\n ...Object.fromEntries(words.map((w, k) => [`w${k}`, w])),\n };\n },\n motion: {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{prefix: text default='We build' label='Lead-in'}} {{word1: text default=apps label='Word 1'}} {{word2: text default=brands label='Word 2'}} {{word3: text default=websites label='Word 3'}} {{word4: text default=games label='Word 4'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#6366F1 label='Accent'}} --><defs><clipPath id=\"window\"><rect x=\"{{clipX}}\" y=\"{{clipY}}\" width=\"{{clipW}}\" height=\"{{clipH}}\"/></clipPath></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text x=\"{{px}}\" y=\"{{base}}\" textLength=\"{{plen}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"700\" fill=\"{{ink}}\">{{prefix}}</text><g clip-path=\"url(#window)\"><g id=\"reel\" transform=\"translate(0 -0)\">${Array.from(\n { length: CYCLE_WORDS + 1 },\n (_, k) =>\n `<text x=\"{{wx}}\" y=\"{{y${k}}}\" textLength=\"{{len${k}}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${SANS}\" font-size=\"{{size}}\" font-weight=\"800\" fill=\"{{accent}}\">{{w${k % CYCLE_WORDS}}}</text>`,\n ).join(\"\")}</g></g><rect id=\"under\" x=\"{{wx}}\" y=\"{{underY}}\" width=\"{{len0}}\" height=\"4\" rx=\"2\" fill=\"{{accent}}\"/></svg>`,\n animate: Array.from({ length: CYCLE_WORDS }, (_, i): SvgAnimation[] => {\n const at = { delay: (i + 1) * SHOW_MS + i * ROLL_MS, ms: ROLL_MS, ease: \"in-out\" as const };\n return [\n { id: \"reel\", attrs: { transform: [`translate(0 -{{o${i}}})`, `translate(0 -{{o${i + 1}}})`] }, ...at },\n { id: \"under\", attrs: { width: [n(`len${i}`), n(`len${i + 1}`)] }, ...at },\n ];\n }).flat(),\n },\n};\n\n/** Liquid fill's wave: crests along y = 0, two 100-unit periods either side of the picture, filled down below it. */\nconst WAVE = `M-200 0${\" q25 -8 50 0 t50 0\".repeat(8)} V320 H-200Z`;\n\nexport const liquidFill: VectorEffect = {\n kind: \"vector\",\n id: \"liquid-fill\",\n name: \"Liquid fill\",\n description: \"A title filling up with liquid, its wavy surface rising through the letters.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"liquid\", \"water\", \"progress\", \"fill\"],\n hold: 900,\n presets: [\n { name: \"Gradient sweep\", values: { liquid: [0.98, 0.25, 0.55], liquid2: [0.35, 0.4, 1], empty: [0.93, 0.93, 0.96] } },\n { name: \"Lava\", values: { liquid: [1, 0.35, 0.05], liquid2: [1, 0.8, 0.1], empty: [0.15, 0.08, 0.06], background: [0.06, 0.03, 0.02] } },\n { name: \"Juice\", values: { liquid: [1, 0.6, 0.1], liquid2: [1, 0.75, 0.25] } },\n ],\n // The surface starts under the letters and ends above their caps.\n derived: (v) => {\n const { size, length } = fit(String(v.text), 360, 110);\n const base = 100 + size * 0.36;\n return { size, length, base: r1(base), low: r1(base + 12), high: r1(base - size * 0.82 - 12) };\n },\n motion: ((): SvgMotion => {\n const word = `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\"`;\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='FILL' label='Text'}} {{background: color default=#FFFFFF label='Background'}} {{empty: color default=#E0F2FE label='Empty'}} {{liquid: color default=#0284C7 label='Liquid'}} {{liquid2: color default=#38BDF8 label='Liquid sweep'}} --><defs><clipPath id=\"letters\"><text ${word}>{{text}}</text></clipPath><linearGradient id=\"liq\" gradientUnits=\"userSpaceOnUse\" x1=\"0\" y1=\"0\" x2=\"400\" y2=\"0\" spreadMethod=\"repeat\"><stop offset=\"0\" stop-color=\"{{liquid}}\"/><stop offset=\"0.5\" stop-color=\"{{liquid2}}\"/><stop offset=\"1\" stop-color=\"{{liquid}}\"/></linearGradient></defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><text ${word} fill=\"{{empty}}\" stroke=\"{{liquid}}\" stroke-width=\"1.5\" stroke-opacity=\"0.5\">{{text}}</text><g clip-path=\"url(#letters)\"><g id=\"level\" transform=\"translate(0 {{low}})\"><path id=\"back\" d=\"${WAVE}\" fill=\"{{liquid}}\" opacity=\"0.45\" transform=\"translate(-50 -5)\"/><path id=\"wave\" d=\"${WAVE}\" fill=\"url(#liq)\" transform=\"translate(0 0)\"/></g></g></svg>`,\n animate: [\n { id: \"level\", attrs: { transform: [\"translate(0 {{low}})\", \"translate(0 {{high}})\"] }, ms: 2800, ease: \"out\" },\n { id: \"wave\", attrs: { transform: [\"translate(0 0)\", \"translate(-200 0)\"] }, ms: 3000, ease: \"linear\" },\n { id: \"back\", attrs: { transform: [\"translate(-50 -5)\", \"translate(150 -5)\"] }, ms: 3000, ease: \"linear\" },\n // The sweep: the repeating gradient slides along, visible when the two liquid colours differ.\n { id: \"liq\", attrs: { x1: [0, 400], x2: [400, 800] }, ms: 3000, ease: \"linear\" },\n ],\n };\n })(),\n};\n\n/** Glitch text's bands: where the word is cut into slices, as fractions from its cap line to its baseline. */\nconst BANDS = [0.3, 0.55, 0.8];\n/** Glitch text's jumps: [ms, red offset, cyan offset, each band's shift], in units of the word's size; rests between bursts. */\nconst GLITCH = (() => {\n let seed = 7;\n const rand = () => ((seed = (seed * 16807) % 2147483647) / 2147483647) * 2 - 1;\n const rest = { red: [-0.02, 0], cyan: [0.02, 0], bands: [0, 0, 0, 0] };\n const keys: { at: number; red: number[]; cyan: number[]; bands: number[] }[] = [{ at: 0, ...rest }];\n for (const [start, count] of [[250, 6], [1050, 3], [1650, 8]] as const) {\n for (let k = 0; k < count; k++)\n keys.push({\n at: start + k * 55,\n red: [rand() * 0.12, rand() * 0.04],\n cyan: [rand() * 0.12, rand() * 0.04],\n bands: [0, 1, 2, 3].map(() => (rand() > 0.1 ? rand() * 0.25 : 0)),\n });\n keys.push({ at: start + count * 55, ...rest });\n }\n return keys;\n})();\n\nexport const glitchText: VectorEffect = {\n kind: \"vector\",\n id: \"glitch-text\",\n name: \"Glitch text\",\n description: \"A title breaking up in bursts: red and cyan copies split apart and slices of the letters jump sideways.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"glitch\", \"cyber\", \"rgb-split\", \"error\"],\n hold: 400,\n presets: [\n { name: \"Classic\", values: { left: [1, 0, 0.2], right: [0, 1, 1] } },\n { name: \"Vapor\", values: { left: [1, 0.3, 0.85], right: [0.4, 0.6, 1], background: [0.08, 0.02, 0.12], amount: 1.4 } },\n ],\n derived: (v) => {\n const { size, length } = fit(String(v.text), 340, 100);\n const base = 100 + size * 0.36;\n const top = base - size * 0.78;\n const cuts = [0, ...BANDS.map((f) => r1(top + f * (base - top))), 200];\n const unit = size * Number(v.amount);\n const shift = ([x, y]: number[]) => `translate(${r1(x! * unit)} ${r1(y! * unit)})`;\n return {\n size,\n length,\n base: r1(base),\n ...Object.fromEntries([0, 1, 2, 3].flatMap((b) => [[`cut${b}`, cuts[b]!], [`band${b}`, r1(cuts[b + 1]! - cuts[b]!)]])),\n ...Object.fromEntries(\n GLITCH.flatMap((key, k) => [\n [`red${k}`, shift(key.red)],\n [`cyan${k}`, shift(key.cyan)],\n ...key.bands.map((x, b) => [`b${b}_${k}`, shift([x, 0])]),\n ]),\n ),\n };\n },\n motion: ((): SvgMotion => {\n const word = (paint: string) =>\n `<text x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" ${paint}>{{text}}</text>`;\n const jumps = (id: string, value: (k: number) => string) =>\n GLITCH.map((key, k): SvgAnimation => ({ id, attrs: { transform: [value(k), value(k)] }, delay: key.at, ms: 0 }));\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='GLITCH' label='Text'}} {{background: color default=#07070B label='Background'}} {{ink: color default=#F5F5F5 label='Text colour'}} {{left: color default=#FF0040 label='Red copy'}} {{right: color default=#00F0FF label='Cyan copy'}} {{amount: float min=0 max=3 default=1 step=0.1 label='Intensity'}} --><defs>${[0, 1, 2, 3]\n .map((b) => `<clipPath id=\"slice${b}\"><rect x=\"-100\" y=\"{{cut${b}}}\" width=\"600\" height=\"{{band${b}}}\"/></clipPath>`)\n .join(\"\")}</defs><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/><g id=\"red\" style=\"mix-blend-mode:screen\">${word(`fill=\"{{left}}\"`)}</g><g id=\"cyan\" style=\"mix-blend-mode:screen\">${word(`fill=\"{{right}}\"`)}</g>${[0, 1, 2, 3]\n .map((b) => `<g clip-path=\"url(#slice${b})\"><g id=\"s${b}\">${word(`fill=\"{{ink}}\"`)}</g></g>`)\n .join(\"\")}</svg>`,\n animate: [\n ...jumps(\"red\", (k) => `{{red${k}}}`),\n ...jumps(\"cyan\", (k) => `{{cyan${k}}}`),\n ...[0, 1, 2, 3].flatMap((b) => jumps(`s${b}`, (k) => `{{b${b}_${k}}}`)),\n ],\n };\n })(),\n};\n\n/** Extruded text's layers, back to front, and the directions the extrude swings between (degrees, 0 = right, 90 = down). */\nconst LAYERS = 12;\nconst EXTRUDE_FROM = 40;\nconst EXTRUDE_TO = 140;\n\nexport const extrudedText: VectorEffect = {\n kind: \"vector\",\n id: \"extruded-text\",\n name: \"Extruded text\",\n description: \"Retro 3D block lettering: stacked shaded layers extrude out of the title and swing as the light moves.\",\n category: \"text\",\n tags: [\"text\", \"title\", \"3d\", \"retro\", \"extrude\", \"80s\"],\n hold: 600,\n presets: [\n { name: \"Arcade\", values: { face: [0.2, 0.95, 1], side: [0.85, 0.2, 0.75], shade: [0.2, 0.05, 0.3], background: [0.05, 0.02, 0.12] } },\n { name: \"Diner\", values: { face: [1, 1, 1], side: [0.9, 0.15, 0.2], shade: [0.35, 0.03, 0.06], background: [0.98, 0.9, 0.75], outline: [0.1, 0.1, 0.12] } },\n ],\n // Each layer sits a step further back along the extrude direction, shaded from the side colour to the shadow.\n derived: (v) => {\n const { size, length } = fit(String(v.text), 320, 96);\n const step = size * 0.03 * Number(v.depth);\n const at = (deg: number, i: number) => {\n const a = (deg * Math.PI) / 180;\n return `translate(${r1(Math.cos(a) * step * i)} ${r1(Math.sin(a) * step * i)})`;\n };\n return {\n size,\n length,\n base: r1(92 + size * 0.35),\n ...Object.fromEntries(\n Array.from({ length: LAYERS }, (_, k) => {\n const i = LAYERS - k;\n return [\n [`fill${i}`, mixHex(v.side, v.shade, i / LAYERS)],\n [`a${i}`, at(EXTRUDE_FROM, i)],\n [`b${i}`, at(EXTRUDE_TO, i)],\n ];\n }).flat(),\n ),\n };\n },\n motion: ((): SvgMotion => {\n const word = (paint: string) =>\n `x=\"200\" y=\"{{base}}\" text-anchor=\"middle\" textLength=\"{{length}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"${HEAVY}\" font-size=\"{{size}}\" font-weight=\"900\" stroke-linejoin=\"round\" ${paint}`;\n const layers = Array.from({ length: LAYERS }, (_, k) => LAYERS - k);\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{text: text default='RETRO' label='Text'}} {{background: color default=#FFE8C2 label='Background'}} {{face: color default=#FFD23F label='Face'}} {{outline: color default=#1A1423 label='Outline'}} {{side: color default=#EE4266 label='Extrude'}} {{shade: color default=#3B1F2B label='Shadow'}} {{depth: float min=0.2 max=2 default=1 step=0.1 label='Depth'}} --><rect width=\"400\" height=\"200\" fill=\"{{background}}\"/>${layers\n .map((i) => `<text id=\"e${i}\" transform=\"translate(0 0)\" ${word(`fill=\"{{fill${i}}}\" stroke=\"{{fill${i}}}\" stroke-width=\"2\"`)}>{{text}}</text>`)\n .join(\"\")}<text ${word(`fill=\"{{face}}\" stroke=\"{{outline}}\" stroke-width=\"2.5\" paint-order=\"stroke\"`)}>{{text}}</text></svg>`,\n animate: layers.flatMap((i): SvgAnimation[] => [\n { id: `e${i}`, attrs: { transform: [\"translate(0 0)\", `{{a${i}}}`] }, ms: 700, ease: \"out\" },\n { id: `e${i}`, attrs: { transform: [`{{a${i}}}`, `{{b${i}}}`] }, delay: 1200, ms: 1500, ease: \"in-out\" },\n { id: `e${i}`, attrs: { transform: [`{{b${i}}}`, `{{a${i}}}`] }, delay: 3200, ms: 1500, ease: \"in-out\" },\n ]),\n };\n })(),\n};\n\n/** Animated titles and type, as vector effects. */\nexport const textEffects: VectorEffect[] = [\n typewriter,\n scrambleText,\n kineticStagger,\n neonSign,\n strokeDrawText,\n splitReveal,\n highlighter,\n wordCycle,\n liquidFill,\n glitchText,\n extrudedText,\n];\n","import {\n checkControlValue,\n controlFromDeclaration,\n hexToRgb,\n rgbToHex,\n type ControlDef,\n type ControlType,\n type ControlValue,\n} from \"../shader/controls.js\";\nimport type { SvgMotion } from \"../vector/motion.js\";\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 | \"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 \"transition\",\n \"loader\",\n \"data\",\n \"icon\",\n];\n\n/** Named control values: a look an effect can be switched to. */\nexport interface EffectPreset {\n name: string;\n values: Record<string, ControlValue>;\n}\n\ninterface EffectBase {\n /** Stable id, kebab-case: `aurora`, `image-glitch`. */\n id: string;\n name: string;\n /** One sentence: what it looks like. */\n description: string;\n category: EffectCategory;\n tags: readonly string[];\n presets?: readonly EffectPreset[];\n}\n\n/**\n * A WebGL2 fragment shader (Shadertoy-style `mainImage`). Its controls are the\n * `// @control` uniforms in `source`; run it with `ShaderRenderer`,\n * `ShaderFrames`, `ThumbnailPool`, `recordGif` or `standaloneHtml`.\n */\nexport interface ShaderEffect extends EffectBase {\n kind: \"shader\";\n source: string;\n /** Seconds after which it repeats exactly, when it loops seamlessly. */\n loop?: number;\n /**\n * Draws over other content: `fragColor.a` is coverage (0 where there is\n * nothing to draw), so render it on a transparent canvas\n * (`ShaderRenderer`'s `alpha` option) to layer it over a page or picture.\n */\n transparent?: boolean;\n}\n\n/**\n * A control of a vector effect, declared in a list rather than in the\n * picture (see {@link VectorEffect.controls}). The same shape as a shader's\n * controls (see `ControlDef`) less what only sources have; `vec3` colours\n * are written into the picture as `#rrggbb`.\n */\nexport type VectorControl = Pick<ControlDef, \"name\" | \"type\" | \"default\"> &\n Partial<Pick<ControlDef, \"label\" | \"color\" | \"min\" | \"max\" | \"step\">>;\n\n/**\n * An animated SVG picture (see `SvgMotion`) whose controls are declared in\n * the picture itself, the way a shader's are declared in its source. The\n * first `{{name: type …}}` declares a control and every `{{name}}` is\n * replaced by its value (see {@link vectorControls} and\n * {@link renderVectorEffect}); run the result with `SvgPlayer`.\n */\nexport interface VectorEffect extends EffectBase {\n kind: \"vector\";\n motion: SvgMotion;\n /**\n * Controls declared outside the picture, for effects written before\n * controls were declared inline. A control declared in the picture wins\n * over one of the same name here.\n */\n controls?: readonly VectorControl[];\n /**\n * More placeholders worked out from the control values (a bar's height\n * from its value, say), filled in after the controls.\n */\n derived?: (values: Record<string, ControlValue>) => Record<string, string | number>;\n /** Ms to rest on the last frame before it loops (default 600). */\n hold?: number;\n}\n\nexport type EffectDefinition = ShaderEffect | VectorEffect;\n\n/** The types a vector effect's `{{name: type …}}` placeholder can declare. */\nexport const VECTOR_CONTROL_TYPES = [\"float\", \"int\", \"bool\", \"color\", \"text\"] as const;\n\n/**\n * A placeholder: `{{name}}`, or a declaration `{{name: type attributes}}`\n * whose attributes are a shader `@control`'s (`min`, `max`, `step`,\n * `default`, `label`). Quote values with spaces in single quotes inside an\n * SVG attribute: `fill=\"{{accent: color default=#6366F1 label='Accent'}}\"`.\n */\nconst PLACEHOLDER = /\\{\\{\\s*([A-Za-z_]\\w*)\\s*(?::\\s*([A-Za-z0-9]*)([^}]*))?\\}\\}/g;\n\n/** Every string in a motion, the markup first, then each animation's values in order. */\nfunction motionStrings(motion: SvgMotion): string[] {\n const out: string[] = [];\n const walk = (v: unknown) => {\n if (typeof v === \"string\") out.push(v);\n else if (Array.isArray(v)) v.forEach(walk);\n else if (v && typeof v === \"object\") Object.values(v).forEach(walk);\n };\n walk(motion);\n return out;\n}\n\n/**\n * The controls a vector effect's picture declares, in the order they are\n * first declared: `{{word: text default=SLOP label=Word}}`, `{{accent:\n * color default=#6366F1}}`, `{{width: float min=2 max=20 default=8 step=1}}`,\n * `{{shadow: bool default=true}}`. A name declared twice counts once (the\n * first wins), and declarations with an unknown type are left out (see\n * {@link vectorControlIssues}). A control only `derived` reads can be\n * declared in an XML comment: `<!-- {{drip: float default=1}} -->`.\n */\nexport function vectorControls(motion: SvgMotion): ControlDef[] {\n const controls: ControlDef[] = [];\n const seen = new Set<string>();\n for (const text of motionStrings(motion)) {\n for (const [, name, type, attributes] of text.matchAll(PLACEHOLDER)) {\n if (type === undefined || seen.has(name!) || !(VECTOR_CONTROL_TYPES as readonly string[]).includes(type)) continue;\n seen.add(name!);\n const colour = type === \"color\";\n controls.push(controlFromDeclaration(name!, colour ? \"vec3\" : (type as ControlType), `${attributes}${colour ? \" color\" : \"\"}`, controls.length + 1));\n }\n }\n return controls;\n}\n\n/** A vector effect's controls: those its picture declares, then any in its `controls` list it does not. */\nexport function vectorEffectControls(effect: Pick<VectorEffect, \"motion\" | \"controls\">): ControlDef[] {\n const declared = vectorControls(effect.motion);\n const names = new Set(declared.map((c) => c.name));\n const listed = (effect.controls ?? []).filter((c) => !names.has(c.name));\n return [...declared, ...listed.map((c, i) => vectorControlDef(c, declared.length + i + 1))];\n}\n\n/**\n * Problems with a picture's placeholders, as sentences: declarations of an\n * unknown type, and a name declared twice in different ways.\n */\nexport function vectorControlIssues(motion: SvgMotion): string[] {\n const issues: string[] = [];\n const declarations = new Map<string, string>();\n for (const text of motionStrings(motion)) {\n for (const [whole, name, type] of text.matchAll(PLACEHOLDER)) {\n if (type === undefined) continue;\n if (!(VECTOR_CONTROL_TYPES as readonly string[]).includes(type))\n issues.push(`${whole}: a control's type is one of ${VECTOR_CONTROL_TYPES.join(\", \")}`);\n else if (declarations.has(name!) && declarations.get(name!) !== whole)\n issues.push(`\"${name}\" is declared twice; declare it once and write {{${name}}} everywhere else`);\n else declarations.set(name!, whole);\n }\n }\n return issues;\n}\n\n/** A vector control's value written into the picture: colours as hex, vectors space-separated, the rest as they are. */\nfunction written(control: Pick<ControlDef, \"color\">, value: ControlValue): string | number | boolean {\n if (control.color && Array.isArray(value)) return rgbToHex(value);\n if (Array.isArray(value)) return value.join(\" \");\n return value;\n}\n\nconst escapeMarkup = (text: string) =>\n text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#39;\");\n\n/** A vector control as a full `ControlDef`, so editors treat both kinds of effect alike. */\nexport function vectorControlDef(control: VectorControl, line = 0): ControlDef {\n const min = control.min ?? 0;\n return {\n name: control.name,\n type: control.type,\n label: control.label ?? control.name,\n color: control.color ?? false,\n min,\n max: control.max ?? Math.max(min + 1, 1),\n step: control.step ?? (control.type === \"int\" ? 1 : 0.01),\n default: control.default,\n line,\n };\n}\n\n/**\n * A vector effect's motion with its controls filled in. A string that is\n * only a placeholder (an animation's `\"{{width}}\"`) becomes the value\n * itself, so numbers stay numbers; elsewhere a placeholder becomes its text,\n * escaped in the markup so any text is safe to show. Comments are dropped\n * from the markup. Colours also take \"#RRGGBB\"; missing values, and values a\n * control cannot take, use defaults. Placeholders no control or derived\n * value fills stay put.\n */\nexport function renderVectorEffect(\n effect: Pick<VectorEffect, \"motion\" | \"controls\" | \"derived\">,\n values: Record<string, ControlValue> = {},\n): SvgMotion {\n const filled: Record<string, ControlValue> = {};\n const placeholders = new Map<string, string | number | boolean>();\n for (const control of vectorEffectControls(effect)) {\n const given = values[control.name];\n const check = given === undefined ? undefined : checkControlValue(control, given);\n filled[control.name] = check?.ok ? check.value : control.default;\n placeholders.set(control.name, written(control, filled[control.name]!));\n }\n for (const [name, value] of Object.entries(effect.derived?.(filled) ?? {})) placeholders.set(name, value);\n const fill = (text: string, markup: boolean): string | number | boolean => {\n const whole = /^\\{\\{\\s*([A-Za-z_]\\w*)\\s*(?::[^}]*)?\\}\\}$/.exec(text);\n if (!markup && whole && placeholders.has(whole[1]!)) return placeholders.get(whole[1]!)!;\n return text.replace(PLACEHOLDER, (match, name: string) => {\n if (!placeholders.has(name)) return match;\n const value = String(placeholders.get(name));\n return markup ? escapeMarkup(value) : value;\n });\n };\n const walk = (v: unknown): unknown => {\n if (typeof v === \"string\") return fill(v, false);\n if (Array.isArray(v)) return v.map(walk);\n if (v && typeof v === \"object\") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));\n return v;\n };\n const { svg, ...rest } = effect.motion;\n // Comments hold declarations, not picture, and a value with \"--\" in one would break the markup.\n return { svg: fill(svg.replace(/<!--[\\s\\S]*?-->/g, \"\"), true) as string, ...(walk(rest) as Omit<SvgMotion, \"svg\">) };\n}\n\n/** A colour control for vector effects. */\nexport function colorControl(name: string, hex: string, label?: string): VectorControl {\n return { name, type: \"vec3\", color: true, default: hexToRgb(hex) ?? [1, 1, 1], label: label ?? name };\n}\n\n/** A number control for vector effects. */\nexport function numberControl(\n name: string,\n value: number,\n min: number,\n max: number,\n label?: string,\n step?: number,\n): VectorControl {\n return { name, type: \"float\", default: value, min, max, label: label ?? name, step };\n}\n","import type { SvgAnimation } from \"../vector/motion.js\";\nimport type { VectorEffect } from \"./types.js\";\n\nexport const spinner: VectorEffect = {\n kind: \"vector\",\n id: \"spinner\",\n name: \"Spinner\",\n description: \"An arc chasing its tail: the classic indeterminate loader.\",\n category: \"loader\",\n tags: [\"loader\", \"ui\", \"minimal\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#6366F1 label='Arc'}} {{track: color default=#E5E7EB label='Track'}} {{width: float min=2 max=20 default=8 step=1 label='Stroke width'}} --><circle cx=\"50\" cy=\"50\" r=\"38\" fill=\"none\" stroke=\"{{track}}\" stroke-width=\"{{width}}\"/><g id=\"spin\" transform=\"rotate(0 50 50)\"><circle id=\"arc\" cx=\"50\" cy=\"50\" r=\"38\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" pathLength=\"1\" stroke-dasharray=\"0.25 1\"/></g></svg>`,\n animate: [\n { id: \"spin\", attrs: { transform: [\"rotate(0 50 50)\", \"rotate(720 50 50)\"] }, ms: 1600, ease: \"linear\" },\n { id: \"arc\", attrs: { \"stroke-dasharray\": [\"0.08 1\", \"0.6 1\"] }, ms: 800, ease: \"in-out\" },\n { id: \"arc\", attrs: { \"stroke-dasharray\": [\"0.6 1\", \"0.08 1\"] }, delay: 800, ms: 800, ease: \"in-out\" },\n ],\n },\n};\n\nexport const bouncingDots: VectorEffect = {\n kind: \"vector\",\n id: \"bouncing-dots\",\n name: \"Bouncing dots\",\n description: \"Three dots hopping in turn, for typing indicators and loaders.\",\n category: \"loader\",\n tags: [\"loader\", \"chat\", \"typing\", \"ui\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 120 60\"><!-- {{accent: color default=#0EA5E9 label='Dots'}} {{height: float min=4 max=30 default=18 step=1 label='Bounce height'}} --><circle id=\"a\" cx=\"30\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/><circle id=\"b\" cx=\"60\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/><circle id=\"c\" cx=\"90\" cy=\"40\" r=\"9\" fill=\"{{accent}}\"/></svg>`,\n animate: [\"a\", \"b\", \"c\"].flatMap((id, i): SvgAnimation[] => [\n { id, attrs: { transform: [\"translate(0 0)\", \"translate(0 -{{height}})\"] }, delay: i * 150, ms: 250, ease: \"out\" as const },\n { id, attrs: { transform: [\"translate(0 -{{height}})\", \"translate(0 0)\"] }, delay: i * 150 + 250, ms: 250, ease: \"in-out\" as const },\n { id, attrs: { opacity: [0.5, 1] }, delay: i * 150, ms: 250 },\n { id, attrs: { opacity: [1, 0.5] }, delay: i * 150 + 250, ms: 250 },\n ]),\n },\n};\n\nexport const progressRing: VectorEffect = {\n kind: \"vector\",\n id: \"progress-ring\",\n name: \"Progress ring\",\n description: \"A ring filling up to a percentage while the number counts with it.\",\n category: \"data\",\n tags: [\"progress\", \"kpi\", \"dashboard\", \"loader\"],\n derived: (v) => ({ fraction: Math.min(1, Math.max(0, Number(v.value) / 100)) }),\n motion: {\n svg: `<svg viewBox=\"0 0 120 120\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#22C55E label='Ring'}} {{track: color default=#E5E7EB label='Track'}} {{text: color default=#111827 label='Text'}} {{value: float min=0 max=100 default=72 step=1 label='Percent'}} --><circle cx=\"60\" cy=\"60\" r=\"48\" fill=\"none\" stroke=\"{{track}}\" stroke-width=\"10\"/><circle id=\"ring\" cx=\"60\" cy=\"60\" r=\"48\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"10\" stroke-linecap=\"round\" transform=\"rotate(-90 60 60)\"/><text id=\"label\" x=\"60\" y=\"68\" text-anchor=\"middle\" font-size=\"24\" font-weight=\"700\" fill=\"{{text}}\">0%</text></svg>`,\n animate: [\n { id: \"ring\", draw: [0, \"{{fraction}}\"] as unknown as [number, number], ms: 1600, ease: \"out\" },\n { id: \"label\", count: [0, \"{{value}}\"] as unknown as [number, number], format: \"{n}%\", ms: 1600, ease: \"out\" },\n ],\n },\n};\n\nexport const pulsePing: VectorEffect = {\n kind: \"vector\",\n id: \"pulse-ping\",\n name: \"Pulse ping\",\n description: \"Rings radiating from a dot, like a live indicator or radar ping.\",\n category: \"loader\",\n tags: [\"live\", \"notification\", \"location\", \"status\"],\n hold: 0,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#EF4444 label='Colour'}} --><circle id=\"r1\" cx=\"50\" cy=\"50\" r=\"8\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\"/><circle id=\"r2\" cx=\"50\" cy=\"50\" r=\"8\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\"/><circle cx=\"50\" cy=\"50\" r=\"9\" fill=\"{{accent}}\"/></svg>`,\n animate: [\n { id: \"r1\", attrs: { r: [8, 44], opacity: [0.9, 0], \"stroke-width\": [4, 1] }, ms: 1400, ease: \"out\" },\n { id: \"r2\", attrs: { r: [8, 44], opacity: [0.9, 0], \"stroke-width\": [4, 1] }, delay: 700, ms: 1400, ease: \"out\" },\n ],\n },\n};\n\nexport const successCheck: VectorEffect = {\n kind: \"vector\",\n id: \"success-check\",\n name: \"Success check\",\n description: \"A circle drawing itself closed, then a tick, then a little pop.\",\n category: \"icon\",\n tags: [\"success\", \"confirmation\", \"ui\", \"feedback\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#16A34A label='Colour'}} {{width: float min=2 max=12 default=6 step=1 label='Stroke width'}} --><g id=\"badge\" transform=\"translate(50 50) scale(1) translate(-50 -50)\"><circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><path id=\"tick\" d=\"M31 52 L44 64 L70 37\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></g></svg>`,\n animate: [\n { id: \"circle\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"tick\", draw: true, delay: 500, ms: 400, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(50 50) scale(1) translate(-50 -50)\", \"translate(50 50) scale(1.12) translate(-50 -50)\"] }, delay: 850, ms: 150, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(50 50) scale(1.12) translate(-50 -50)\", \"translate(50 50) scale(1) translate(-50 -50)\"] }, delay: 1000, ms: 250, ease: \"in-out\" },\n ],\n },\n};\n\nexport const errorCross: VectorEffect = {\n kind: \"vector\",\n id: \"error-cross\",\n name: \"Error cross\",\n description: \"A circle and a cross drawing on, with a short shake.\",\n category: \"icon\",\n tags: [\"error\", \"failure\", \"ui\", \"feedback\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#DC2626 label='Colour'}} {{width: float min=2 max=12 default=6 step=1 label='Stroke width'}} --><g id=\"badge\" transform=\"translate(0 0)\"><circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><path id=\"a\" d=\"M36 36 L64 64\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><path id=\"b\" d=\"M64 36 L36 64\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/></g></svg>`,\n animate: [\n { id: \"circle\", draw: true, ms: 600, ease: \"in-out\" },\n { id: \"a\", draw: true, delay: 500, ms: 250, ease: \"out\" },\n { id: \"b\", draw: true, delay: 700, ms: 250, ease: \"out\" },\n { id: \"badge\", attrs: { transform: [\"translate(0 0)\", \"translate(-6 0)\"] }, delay: 950, ms: 60, ease: \"linear\" },\n { id: \"badge\", attrs: { transform: [\"translate(-6 0)\", \"translate(6 0)\"] }, delay: 1010, ms: 100, ease: \"linear\" },\n { id: \"badge\", attrs: { transform: [\"translate(6 0)\", \"translate(0 0)\"] }, delay: 1110, ms: 80, ease: \"out\" },\n ],\n },\n};\n\nexport const heartbeat: VectorEffect = {\n kind: \"vector\",\n id: \"heartbeat\",\n name: \"Heartbeat\",\n description: \"A heart beating twice, with an ECG line tracing beneath it.\",\n category: \"icon\",\n tags: [\"health\", \"like\", \"love\", \"pulse\"],\n hold: 300,\n motion: {\n svg: `<svg viewBox=\"0 0 200 120\"><!-- {{accent: color default=#F43F5E label='Heart'}} {{line: color default=#94A3B8 label='Line'}} --><g id=\"heart\" transform=\"translate(100 46) scale(1)\"><path d=\"M0 22 C-30 0 -30 -26 -10 -26 C-3 -26 0 -20 0 -16 C0 -20 3 -26 10 -26 C30 -26 30 0 0 22Z\" fill=\"{{accent}}\"/></g><path id=\"ecg\" d=\"M10 100 H70 L80 86 L90 112 L100 76 L110 104 L118 100 H190\" fill=\"none\" stroke=\"{{line}}\" stroke-width=\"3\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></svg>`,\n animate: [\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1)\", \"translate(100 46) scale(1.18)\"] }, ms: 120, ease: \"out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1.18)\", \"translate(100 46) scale(1)\"] }, delay: 120, ms: 160, ease: \"in-out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1)\", \"translate(100 46) scale(1.12)\"] }, delay: 300, ms: 120, ease: \"out\" },\n { id: \"heart\", attrs: { transform: [\"translate(100 46) scale(1.12)\", \"translate(100 46) scale(1)\"] }, delay: 420, ms: 300, ease: \"in-out\" },\n { id: \"ecg\", draw: true, ms: 900, ease: \"linear\" },\n ],\n },\n};\n\nexport const barChart: VectorEffect = {\n kind: \"vector\",\n id: \"bar-chart\",\n name: \"Bar chart\",\n description: \"Bars growing into place one after another, values counting above them.\",\n category: \"data\",\n tags: [\"chart\", \"dashboard\", \"report\", \"explainer\"],\n hold: 1500,\n derived: (v) =>\n Object.fromEntries(\n [\"a\", \"b\", \"c\", \"d\"].flatMap((k) => {\n const h = Math.min(100, Math.max(0, Number(v[k]))) * 1.1;\n return [\n [`${k}_height`, +h.toFixed(2)],\n [`${k}_label_y`, +(134 - h).toFixed(2)],\n ];\n }),\n ),\n motion: {\n svg: `<svg viewBox=\"0 0 240 160\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#6366F1 label='Bars'}} {{text: color default=#334155 label='Text'}} {{a: float min=0 max=100 default=40 step=1 label='Bar 1'}} {{b: float min=0 max=100 default=65 step=1 label='Bar 2'}} {{c: float min=0 max=100 default=50 step=1 label='Bar 3'}} {{d: float min=0 max=100 default=90 step=1 label='Bar 4'}} --><line x1=\"20\" y1=\"140\" x2=\"220\" y2=\"140\" stroke=\"{{text}}\" stroke-opacity=\"0.3\" stroke-width=\"2\"/>${[\"a\", \"b\", \"c\", \"d\"]\n .map(\n (k, i) =>\n `<g id=\"bar-${k}\" transform=\"translate(${40 + i * 48} 140) scale(1 0)\"><rect x=\"0\" y=\"-1\" width=\"32\" height=\"1\" rx=\"0.02\" fill=\"{{accent}}\"/></g><text id=\"label-${k}\" x=\"${56 + i * 48}\" y=\"132\" text-anchor=\"middle\" font-size=\"12\" fill=\"{{text}}\" opacity=\"0\">0</text>`,\n )\n .join(\"\")}</svg>`,\n animate: [\"a\", \"b\", \"c\", \"d\"].flatMap((k, i): SvgAnimation[] => [\n { id: `bar-${k}`, attrs: { transform: [`translate(${40 + i * 48} 140) scale(1 0)`, `translate(${40 + i * 48} 140) scale(1 {{${k}_height}})`] }, delay: i * 180, ms: 700, ease: \"out\" as const },\n { id: `label-${k}`, attrs: { y: [132, `{{${k}_label_y}}`], opacity: [0, 1] }, delay: i * 180, ms: 700, ease: \"out\" as const },\n { id: `label-${k}`, count: [0, `{{${k}}}`] as unknown as [number, number], delay: i * 180, ms: 700, ease: \"out\" as const },\n ]),\n },\n};\n\nexport const lineChart: VectorEffect = {\n kind: \"vector\",\n id: \"line-chart\",\n name: \"Line chart\",\n description: \"A trend line drawing across with a marker riding its tip and the area fading in below.\",\n category: \"data\",\n tags: [\"chart\", \"trend\", \"growth\", \"dashboard\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 240 140\"><!-- {{accent: color default=#0EA5E9 label='Line'}} {{grid: color default=#CBD5E1 label='Grid'}} --><defs><linearGradient id=\"fill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"{{accent}}\" stop-opacity=\"0.35\"/><stop offset=\"1\" stop-color=\"{{accent}}\" stop-opacity=\"0\"/></linearGradient></defs><g stroke=\"{{grid}}\" stroke-width=\"1\"><line x1=\"20\" y1=\"30\" x2=\"220\" y2=\"30\"/><line x1=\"20\" y1=\"70\" x2=\"220\" y2=\"70\"/><line x1=\"20\" y1=\"110\" x2=\"220\" y2=\"110\"/></g><path id=\"area\" d=\"M20 110 L60 92 L100 98 L140 64 L180 70 L220 30 L220 120 L20 120Z\" fill=\"url(#fill)\" opacity=\"0\"/><path id=\"trend\" d=\"M20 110 L60 92 L100 98 L140 64 L180 70 L220 30\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"3\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><circle id=\"marker\" r=\"5\" fill=\"#fff\" stroke=\"{{accent}}\" stroke-width=\"3\"/></svg>`,\n animate: [\n { id: \"trend\", draw: true, ms: 1400, ease: \"in-out\" },\n { id: \"marker\", along: \"trend\", ms: 1400, ease: \"in-out\" },\n { id: \"area\", attrs: { opacity: [0, 1] }, delay: 900, ms: 600 },\n ],\n },\n};\n\nexport const statCounter: VectorEffect = {\n kind: \"vector\",\n id: \"stat-counter\",\n name: \"Stat counter\",\n description: \"A headline number counting up, with its caption and underline sweeping in.\",\n category: \"data\",\n tags: [\"kpi\", \"number\", \"headline\", \"explainer\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 240 120\" font-family=\"system-ui, sans-serif\"><!-- {{accent: color default=#F59E0B label='Accent'}} {{text: color default=#0F172A label='Text'}} {{value: float min=0 max=100000 default=1250 step=1 label='Value'}} {{caption: text default='happy customers' label='Caption'}} --><text id=\"number\" x=\"120\" y=\"62\" text-anchor=\"middle\" font-size=\"44\" font-weight=\"800\" fill=\"{{text}}\">0</text><path id=\"underline\" d=\"M60 78 H180\" stroke=\"{{accent}}\" stroke-width=\"6\" stroke-linecap=\"round\"/><text id=\"caption\" x=\"120\" y=\"104\" text-anchor=\"middle\" font-size=\"13\" fill=\"{{text}}\" opacity=\"0\">{{caption}}</text></svg>`,\n animate: [\n { id: \"number\", count: [0, \"{{value}}\"] as unknown as [number, number], ms: 1500, ease: \"out\" },\n { id: \"underline\", draw: true, delay: 300, ms: 900, ease: \"in-out\" },\n { id: \"caption\", attrs: { opacity: [0, 1], y: [112, 104] }, delay: 800, ms: 500, ease: \"out\" },\n ],\n },\n};\n\nexport const timelineTrack: VectorEffect = {\n kind: \"vector\",\n id: \"timeline-track\",\n name: \"Timeline track\",\n description: \"A vertical line drawing down with nodes popping along milestones.\",\n category: \"data\",\n tags: [\"timeline\", \"roadmap\", \"milestones\", \"history\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 100 400\"><!-- {{track: color default=#E5E7EB label='Track'}} {{accent: color default=#F97316 label='Accent'}} {{width: float min=1 max=8 default=3 step=0.5 label='Line width'}} --><line x1=\"50\" y1=\"20\" x2=\"50\" y2=\"380\" stroke=\"{{track}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><path id=\"line\" d=\"M50 20 L50 380\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/><g id=\"n1\" transform=\"translate(50 60) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n2\" transform=\"translate(50 160) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n3\" transform=\"translate(50 260) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g><g id=\"n4\" transform=\"translate(50 360) scale(0)\"><circle r=\"8\" fill=\"{{accent}}\"/><circle r=\"4\" fill=\"#ffffff\"/></g></svg>`,\n animate: [\n { id: \"line\", draw: true, ms: 1400, ease: \"in-out\" },\n { id: \"n1\", attrs: { transform: [\"translate(50 60) scale(0)\", \"translate(50 60) scale(1)\"] }, delay: 200, ms: 250, ease: \"out\" },\n { id: \"n2\", attrs: { transform: [\"translate(50 160) scale(0)\", \"translate(50 160) scale(1)\"] }, delay: 550, ms: 250, ease: \"out\" },\n { id: \"n3\", attrs: { transform: [\"translate(50 260) scale(0)\", \"translate(50 260) scale(1)\"] }, delay: 900, ms: 250, ease: \"out\" },\n { id: \"n4\", attrs: { transform: [\"translate(50 360) scale(0)\", \"translate(50 360) scale(1)\"] }, delay: 1300, ms: 250, ease: \"out\" },\n ],\n },\n};\n\nexport const route: VectorEffect = {\n kind: \"vector\",\n id: \"route\",\n name: \"Route\",\n description: \"A dashed journey drawing between two pins, with a traveller following it.\",\n category: \"data\",\n tags: [\"map\", \"travel\", \"delivery\", \"journey\"],\n hold: 1200,\n motion: {\n svg: `<svg viewBox=\"0 0 240 150\"><!-- {{accent: color default=#8B5CF6 label='Route'}} {{pin: color default=#0F172A label='Pins'}} --><path id=\"path\" d=\"M30 120 C60 40 120 140 150 70 S210 30 210 30\" fill=\"none\" stroke=\"{{accent}}\" stroke-width=\"4\" stroke-linecap=\"round\"/><circle cx=\"30\" cy=\"120\" r=\"7\" fill=\"{{pin}}\"/><g id=\"end\" opacity=\"0\"><circle cx=\"210\" cy=\"30\" r=\"9\" fill=\"{{pin}}\"/><circle cx=\"210\" cy=\"30\" r=\"3.5\" fill=\"#fff\"/></g><g id=\"traveller\"><circle r=\"7\" fill=\"{{accent}}\"/><circle r=\"3\" fill=\"#fff\"/></g></svg>`,\n animate: [\n { id: \"path\", draw: true, ms: 1800, ease: \"in-out\" },\n { id: \"traveller\", along: \"path\", ms: 1800, ease: \"in-out\" },\n { id: \"end\", attrs: { opacity: [0, 1] }, delay: 1600, ms: 300 },\n ],\n },\n};\n\nexport const blobMorph: VectorEffect = {\n kind: \"vector\",\n id: \"blob-morph\",\n name: \"Blob morph\",\n description: \"An organic blob shape-shifting through three forms.\",\n category: \"organic\",\n tags: [\"shape\", \"background\", \"playful\", \"brand\"],\n hold: 0,\n motion: (() => {\n const shapes = [\n \"M100 30 C140 30 170 60 170 100 C170 140 140 170 100 170 C60 170 30 140 30 100 C30 60 60 30 100 30Z\",\n \"M100 20 C150 40 180 70 160 110 C140 160 120 175 85 165 C45 155 25 120 40 80 C55 40 70 15 100 20Z\",\n \"M110 35 C155 25 175 85 165 120 C155 160 105 180 70 160 C35 140 20 100 45 70 C65 45 80 40 110 35Z\",\n ];\n const step = 1200;\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{colorA: color default=#F472B6 label='Colour A'}} {{colorB: color default=#818CF8 label='Colour B'}} --><defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"{{colorA}}\"/><stop offset=\"1\" stop-color=\"{{colorB}}\"/></linearGradient></defs><path id=\"blob\" d=\"${shapes[0]}\" fill=\"url(#g)\"/></svg>`,\n animate: shapes.map((d, i) => ({\n id: \"blob\",\n attrs: { d: [d, shapes[(i + 1) % shapes.length]!] as [string, string] },\n delay: i * step,\n ms: step,\n ease: \"in-out\" as const,\n })),\n };\n })(),\n};\n\nexport const signature: VectorEffect = {\n kind: \"vector\",\n id: \"signature\",\n name: \"Signature\",\n description: \"A handwritten flourish drawing itself as if by pen.\",\n category: \"icon\",\n tags: [\"handwriting\", \"draw-on\", \"personal\", \"reveal\"],\n hold: 1500,\n motion: {\n svg: `<svg viewBox=\"0 0 260 120\"><!-- {{ink: color default=#1E293B label='Ink'}} {{width: float min=1 max=8 default=3 step=0.5 label='Pen width'}} --><path id=\"sig\" d=\"M20 80 C40 20 60 20 55 70 C52 95 70 95 85 60 C95 40 100 75 110 70 C120 65 125 40 135 55 C145 70 150 75 165 50 C175 35 185 60 190 65 C200 75 215 40 240 45\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"dash\" d=\"M70 100 Q140 92 220 98\" fill=\"none\" stroke=\"{{ink}}\" stroke-width=\"{{width}}\" stroke-linecap=\"round\"/></svg>`,\n animate: [\n { id: \"sig\", draw: true, ms: 1800, ease: \"in-out\" },\n { id: \"dash\", draw: true, delay: 1700, ms: 400, ease: \"out\" },\n ],\n },\n};\n\nexport const equalizer: VectorEffect = {\n kind: \"vector\",\n id: \"equalizer\",\n name: \"Equalizer\",\n description: \"Audio level bars dancing, for now-playing badges and voice states.\",\n category: \"loader\",\n tags: [\"music\", \"audio\", \"voice\", \"now-playing\"],\n hold: 0,\n motion: (() => {\n const heights = [\n [0.3, 0.9, 0.5, 0.3],\n [0.7, 0.4, 1.0, 0.7],\n [0.5, 1.0, 0.3, 0.5],\n [0.9, 0.5, 0.7, 0.9],\n [0.4, 0.8, 0.6, 0.4],\n ];\n const beat = 250;\n return {\n svg: `<svg viewBox=\"0 0 100 100\"><!-- {{accent: color default=#10B981 label='Bars'}} -->${heights\n .map((_, i) => `<g id=\"bar${i}\" transform=\"translate(${14 + i * 16} 85) scale(1 ${heights[i]![0]})\"><rect x=\"0\" y=\"-70\" width=\"10\" height=\"70\" rx=\"5\" fill=\"{{accent}}\"/></g>`)\n .join(\"\")}</svg>`,\n animate: heights.flatMap((h, i) =>\n [0, 1, 2].map((k) => ({\n id: `bar${i}`,\n attrs: { transform: [`translate(${14 + i * 16} 85) scale(1 ${h[k]})`, `translate(${14 + i * 16} 85) scale(1 ${h[k + 1]})`] as [string, string] },\n delay: k * beat,\n ms: beat,\n ease: \"in-out\" as const,\n })),\n ),\n };\n })(),\n};\n\nexport const confetti: VectorEffect = {\n kind: \"vector\",\n id: \"confetti\",\n name: \"Confetti burst\",\n description: \"A burst of confetti flying out and fluttering down.\",\n category: \"icon\",\n tags: [\"celebration\", \"success\", \"party\", \"reward\"],\n hold: 400,\n motion: (() => {\n const pieces = Array.from({ length: 18 }, (_, i) => {\n const angle = (i / 18) * Math.PI * 2 + (i % 3) * 0.2;\n const dist = 55 + (i % 4) * 12;\n const x = Math.round(Math.cos(angle) * dist);\n const y = Math.round(Math.sin(angle) * dist * 0.8 - 20);\n const spin = (i % 2 ? 1 : -1) * (180 + (i % 5) * 60);\n return { i, x, y, spin, fill: [\"{{a}}\", \"{{b}}\", \"{{c}}\"][i % 3]! };\n });\n return {\n svg: `<svg viewBox=\"0 0 200 200\"><!-- {{a: color default=#F43F5E label='Colour A'}} {{b: color default=#FACC15 label='Colour B'}} {{c: color default=#22D3EE label='Colour C'}} -->${pieces\n .map((p) => `<rect id=\"p${p.i}\" x=\"-4\" y=\"-2\" width=\"8\" height=\"4\" rx=\"1\" fill=\"${p.fill}\" transform=\"translate(100 110) rotate(0)\" opacity=\"0\"/>`)\n .join(\"\")}</svg>`,\n animate: pieces.flatMap((p): SvgAnimation[] => [\n { id: `p${p.i}`, attrs: { opacity: [0, 1] }, ms: 50 },\n {\n id: `p${p.i}`,\n attrs: { transform: [\"translate(100 110) rotate(0)\", `translate(${100 + p.x} ${110 + p.y}) rotate(${p.spin})`] as [string, string] },\n ms: 600,\n ease: \"out\" as const,\n },\n {\n id: `p${p.i}`,\n attrs: {\n transform: [`translate(${100 + p.x} ${110 + p.y}) rotate(${p.spin})`, `translate(${100 + p.x * 1.2} ${180 + p.y * 0.2}) rotate(${p.spin * 2})`] as [string, string],\n },\n delay: 600,\n ms: 1000,\n ease: \"in-out\" as const,\n },\n { id: `p${p.i}`, attrs: { opacity: [1, 0] }, delay: 1300, ms: 300 },\n ]),\n };\n })(),\n};\n\n\n/** Flow network's nodes and links, left to right, with the critical path through them. */\nconst NODES: Record<string, [number, number]> = {\n s: [40, 120], a: [120, 60], b: [120, 180], c: [280, 50], d: [290, 130], e: [280, 200], t: [360, 120],\n};\nconst HUB: [number, number] = [200, 120];\nconst link = ([x1, y1]: [number, number], [x2, y2]: [number, number]) => {\n const mid = (x1 + x2) / 2;\n return `M${x1} ${y1} C${mid} ${y1} ${mid} ${y2} ${x2} ${y2}`;\n};\nconst LINKS: { from: [number, number]; to: [number, number]; column: number }[] = [\n { from: NODES.s!, to: NODES.a!, column: 0 },\n { from: NODES.s!, to: NODES.b!, column: 0 },\n { from: NODES.a!, to: HUB, column: 1 },\n { from: NODES.b!, to: HUB, column: 1 },\n { from: HUB, to: NODES.c!, column: 2 },\n { from: HUB, to: NODES.d!, column: 2 },\n { from: HUB, to: NODES.e!, column: 2 },\n { from: NODES.c!, to: NODES.t!, column: 3 },\n { from: NODES.d!, to: NODES.t!, column: 3 },\n { from: NODES.e!, to: NODES.t!, column: 3 },\n];\nconst CRITICAL = [NODES.s!, NODES.b!, HUB, NODES.c!, NODES.t!]\n .map((p, i, all) => (i === 0 ? \"\" : link(all[i - 1]!, p).replace(/^M[\\d.]+ [\\d.]+ /, i === 1 ? `M${all[0]![0]} ${all[0]![1]} ` : \"\")))\n .filter(Boolean)\n .join(\" \");\n/** The column a node is reached in, so it appears as the links arrive. */\nconst NODE_COLUMN: Record<string, number> = { s: 0, a: 1, b: 1, c: 3, d: 3, e: 3, t: 4 };\nconst COLUMN_MS = 280;\nconst PATH_START = 1500;\nconst PATH_MS = 1800;\n\nexport const flowNetwork: VectorEffect = {\n kind: \"vector\",\n id: \"flow-network\",\n name: \"Flow network\",\n description: \"A node graph linking up, then a glowing critical path racing through it to a pulsing hub.\",\n category: \"data\",\n tags: [\"network\", \"graph\", \"dag\", \"workflow\", \"tech\", \"explainer\"],\n hold: 1200,\n presets: [\n { name: \"Light\", values: { background: [0.93, 0.95, 0.96], link: [0.37, 0.72, 0.69], path: [0.96, 0.62, 0.04], ink: [0.2, 0.25, 0.33] } },\n { name: \"Neon\", values: { background: [0.04, 0.02, 0.1], link: [0.13, 0.83, 0.93], path: [0.96, 0.45, 0.71], ink: [0.85, 0.85, 1] } },\n ],\n motion: {\n svg: `<svg viewBox=\"0 0 400 240\" font-family=\"system-ui, sans-serif\"><!-- {{label: text default='Critical path' label='Hub label'}} {{background: color default=#0B1220 label='Background'}} {{link: color default=#4FD1C5 label='Links'}} {{path: color default=#F5A524 label='Critical path'}} {{ink: color default=#CBD5E1 label='Label'}} {{glow: float min=0 max=6 default=2.5 step=0.5 label='Glow'}} --><defs><filter id=\"glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\"><feGaussianBlur stdDeviation=\"{{glow}}\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs><rect width=\"400\" height=\"240\" fill=\"{{background}}\"/>${LINKS.map(\n (l, i) => `<path id=\"l${i}\" d=\"${link(l.from, l.to)}\" fill=\"none\" stroke=\"{{link}}\" stroke-width=\"1.6\" stroke-opacity=\"0.75\" filter=\"url(#glow)\"/>`,\n ).join(\"\")}<path id=\"crit\" d=\"${CRITICAL}\" fill=\"none\" stroke=\"{{path}}\" stroke-width=\"3\" stroke-linecap=\"round\" filter=\"url(#glow)\"/>${[0, 1]\n .map((i) => `<circle id=\"ring${i}\" cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"10\" fill=\"none\" stroke=\"{{link}}\" stroke-width=\"2\" opacity=\"0\"/>`)\n .join(\"\")}${Object.entries(NODES)\n .map(([id, [x, y]]) => `<circle id=\"n${id}\" cx=\"${x}\" cy=\"${y}\" r=\"6\" fill=\"{{background}}\" stroke=\"{{link}}\" stroke-width=\"2.5\" filter=\"url(#glow)\" opacity=\"0\"/>`)\n .join(\"\")}<g id=\"hub\" opacity=\"0\"><circle cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"13\" fill=\"{{link}}\" fill-opacity=\"0.25\" stroke=\"{{link}}\" stroke-width=\"2\" filter=\"url(#glow)\"/><circle cx=\"${HUB[0]}\" cy=\"${HUB[1]}\" r=\"6\" fill=\"{{link}}\"/></g><text id=\"caption\" x=\"${HUB[0]}\" y=\"${HUB[1] + 34}\" text-anchor=\"middle\" font-size=\"12\" font-weight=\"600\" fill=\"{{ink}}\" opacity=\"0\">{{label}}</text>${[0, 1, 2]\n .map((i) => `<circle id=\"pkt${i}\" r=\"2.5\" fill=\"{{link}}\" filter=\"url(#glow)\" opacity=\"0\"/>`)\n .join(\"\")}<circle id=\"comet\" r=\"5\" fill=\"#FFFFFF\" stroke=\"{{path}}\" stroke-width=\"2\" filter=\"url(#glow)\" opacity=\"0\"/></svg>`,\n animate: [\n ...LINKS.map((l, i): SvgAnimation => ({ id: `l${i}`, draw: true, delay: l.column * COLUMN_MS, ms: 500, ease: \"out\" })),\n ...Object.keys(NODES).map((id): SvgAnimation => ({ id: `n${id}`, attrs: { opacity: [0, 1] }, delay: Math.max(0, NODE_COLUMN[id]! * COLUMN_MS - 120), ms: 250 })),\n { id: \"hub\", attrs: { opacity: [0, 1] }, delay: 2 * COLUMN_MS - 120, ms: 300 },\n { id: \"caption\", attrs: { opacity: [0, 1], y: [HUB[1] + 40, HUB[1] + 34] }, delay: 2 * COLUMN_MS, ms: 400, ease: \"out\" },\n // Data packets drift along a few links while the path waits.\n ...[3, 5, 8].map((link, i): SvgAnimation[] => [\n { id: `pkt${i}`, attrs: { opacity: [0, 1] }, delay: 1000 + i * 150, ms: 150 },\n { id: `pkt${i}`, along: `l${link}`, delay: 1000 + i * 150, ms: 1100, ease: \"in-out\" },\n { id: `pkt${i}`, attrs: { opacity: [1, 0] }, delay: 2000 + i * 150, ms: 200 },\n ]).flat(),\n { id: \"crit\", draw: true, delay: PATH_START, ms: PATH_MS, ease: \"in-out\" },\n { id: \"comet\", attrs: { opacity: [0, 1] }, delay: PATH_START, ms: 150 },\n { id: \"comet\", along: \"crit\", delay: PATH_START, ms: PATH_MS, ease: \"in-out\" },\n { id: \"comet\", attrs: { opacity: [1, 0] }, delay: PATH_START + PATH_MS, ms: 300 },\n // Rings pulse out from the hub as the comet passes it, halfway along.\n ...[0, 1].map((i): SvgAnimation => ({\n id: `ring${i}`,\n attrs: { r: [10, 52], opacity: [0.9, 0], \"stroke-width\": [3, 0.5] },\n delay: PATH_START + PATH_MS / 2 + i * 350,\n ms: 1200,\n ease: \"out\",\n })),\n ],\n },\n};\n\n/** Drip text's drips: where each leaves the word, as a fraction of its width, and how it runs. */\nconst DRIP_TOP = 106;\nconst DRIPS = [\n { at: 0.067, width: 11, length: 34, delay: 0, ms: 1500 },\n { at: 0.18, width: 8, length: 18, delay: 260, ms: 1100 },\n { at: 0.3, width: 13, length: 50, delay: 120, ms: 1800 },\n { at: 0.453, width: 9, length: 22, delay: 380, ms: 1200 },\n { at: 0.587, width: 10, length: 28, delay: 200, ms: 1400 },\n { at: 0.693, width: 12, length: 42, delay: 60, ms: 1700 },\n { at: 0.793, width: 11, length: 32, delay: 300, ms: 1500 },\n];\n\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.\",\n category: \"text\",\n tags: [\"title\", \"text\", \"drip\", \"slime\", \"y2k\", \"headline\"],\n hold: 1200,\n presets: [\n { name: \"Slime\", values: { fill: [0.55, 0.93, 0.25], outline: [0.06, 0.2, 0.04], shine: [0.85, 1, 0.7] } },\n { name: \"Molten gold\", values: { fill: [1, 0.78, 0.2], outline: [0.35, 0.16, 0], shine: [1, 0.96, 0.75], drip: 1.5 } },\n ],\n // The word is stretched to a width set by its length (textLength), so the drips land under its letters in any font.\n derived: (v) => {\n const letters = Math.max(1, Array.from(String(v.word).trim()).length);\n const width = Math.min(380, letters * 75);\n const left = 200 - width / 2;\n return {\n width,\n ...Object.fromEntries(\n DRIPS.flatMap((d, i) => {\n const x = Math.round((left + d.at * width) * 10) / 10;\n const length = Math.round(d.length * Number(v.drip) * 10) / 10;\n return [\n [`x${i}`, x],\n [`left${i}`, x - d.width / 2],\n [`shine${i}`, x - d.width * 0.25],\n [`len${i}`, length],\n [`tip${i}`, DRIP_TOP + length],\n ];\n }),\n ),\n };\n },\n motion: (() => {\n const word = `<text x=\"200\" y=\"120\" text-anchor=\"middle\" textLength=\"{{width}}\" lengthAdjust=\"spacingAndGlyphs\" font-family=\"'Arial Black', Impact, system-ui, sans-serif\" font-size=\"104\" font-weight=\"900\" stroke-linejoin=\"round\"`;\n const drips = (layer: \"o\" | \"f\", paint: string) =>\n DRIPS.map(\n (d, i) =>\n `<rect id=\"${layer}r${i}\" x=\"{{left${i}}}\" y=\"${DRIP_TOP}\" width=\"${d.width}\" height=\"0\" rx=\"${d.width / 2}\" ${paint}/><circle id=\"${layer}c${i}\" cx=\"{{x${i}}}\" cy=\"${DRIP_TOP}\" r=\"${d.width * 0.72}\" ${paint}/>`,\n ).join(\"\");\n const outline = `fill=\"{{outline}}\" stroke=\"{{outline}}\" stroke-width=\"{{stroke}}\"`;\n const pop = (from: number, to: number) =>\n [`translate(200 100) scale(${from}) translate(-200 -100)`, `translate(200 100) scale(${to}) translate(-200 -100)`] as [string, string];\n return {\n svg: `<svg viewBox=\"0 0 400 200\"><!-- {{word: text default=SLOP label='Word'}} {{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'}} --><g id=\"word\" transform=\"${pop(0.6, 1)[0]}\" opacity=\"0\">${drips(\"o\", outline)}${word} fill=\"none\" stroke=\"{{outline}}\" stroke-width=\"{{stroke}}\">{{word}}</text>${drips(\"f\", `fill=\"{{fill}}\"`)}${word} fill=\"{{fill}}\">{{word}}</text>${DRIPS.map(\n (d, i) => `<circle id=\"s${i}\" cx=\"{{shine${i}}}\" cy=\"${DRIP_TOP}\" r=\"${d.width * 0.2}\" fill=\"{{shine}}\" opacity=\"0\"/>`,\n ).join(\"\")}</g></svg>`,\n animate: [\n { id: \"word\", attrs: { transform: pop(0.6, 1.08), opacity: [0, 1] }, ms: 260, ease: \"out\" },\n { id: \"word\", attrs: { transform: pop(1.08, 1) }, delay: 260, ms: 200, ease: \"in-out\" },\n ...DRIPS.flatMap((d, i): SvgAnimation[] => {\n const at = { delay: 400 + d.delay, ms: d.ms, ease: \"in-out\" as const };\n const tip = `{{tip${i}}}` as unknown as number;\n return [\n ...([\"o\", \"f\"] as const).flatMap((layer): SvgAnimation[] => [\n { id: `${layer}r${i}`, attrs: { height: [0, `{{len${i}}}` as unknown as number] }, ...at },\n { id: `${layer}c${i}`, attrs: { cy: [DRIP_TOP, tip] }, ...at },\n ]),\n { id: `s${i}`, attrs: { cy: [DRIP_TOP, tip], opacity: [0, 0.9] }, ...at },\n ];\n }),\n ],\n };\n })(),\n};\n\n/** Viewfinder's timecode runs this many seconds (at 25 fps) before it loops back to zero. */\nconst VIEWFINDER_SECONDS = 10;\n\nexport const viewfinder: VectorEffect = {\n kind: \"vector\",\n id: \"viewfinder\",\n name: \"Viewfinder\",\n description: \"A camera viewfinder over the picture: corner brackets, a blinking REC light and a running timecode.\",\n category: \"overlay\",\n tags: [\"overlay\", \"camera\", \"recording\", \"vlog\", \"frame\"],\n hold: 0,\n presets: [\n { name: \"Night vision\", values: { color: [0.45, 1, 0.45], rec: [0.45, 1, 0.45] } },\n { name: \"Live\", values: { label: \"LIVE\", timecode: false } },\n ],\n derived: (v) => ({ timecodeOpacity: v.timecode ? 1 : 0 }),\n motion: {\n svg: `<svg viewBox=\"0 0 320 180\" font-family=\"ui-monospace, Menlo, Consolas, monospace\"><!-- {{color: color default=#FFFFFF label='Frame'}} {{rec: color default=#EF4444 label='Record light'}} {{timecode: bool default=true label='Timecode'}} --><g fill=\"none\" stroke=\"{{color}}\" stroke-width=\"2.5\" stroke-linecap=\"square\"><path d=\"M16 42 V16 H42\"/><path d=\"M278 16 H304 V42\"/><path d=\"M304 138 V164 H278\"/><path d=\"M42 164 H16 V138\"/><path d=\"M154 90 H166 M160 84 V96\" stroke-width=\"1.5\" opacity=\"0.8\"/></g><circle id=\"dot\" cx=\"34\" cy=\"33\" r=\"4.5\" fill=\"{{rec}}\"/><text x=\"44\" y=\"37.5\" font-size=\"12\" font-weight=\"700\" fill=\"{{color}}\">{{label: text default=REC label='Label'}}</text><text x=\"296\" y=\"37.5\" text-anchor=\"end\" font-size=\"12\" fill=\"{{color}}\" opacity=\"{{timecodeOpacity}}\">00:00:<tspan id=\"sec\">00</tspan>:<tspan id=\"ff\">00</tspan></text></svg>`,\n animate: Array.from({ length: VIEWFINDER_SECONDS }, (_, s): SvgAnimation[] => [\n { id: \"sec\", count: [s, s], format: s < 10 ? \"0{n}\" : \"{n}\", delay: s * 1000, ms: 1 },\n // Frames 00–24: the single digits padded with a zero, then the rest.\n { id: \"ff\", count: [0, 9.49], format: \"0{n}\", delay: s * 1000, ms: 400, ease: \"linear\" },\n { id: \"ff\", count: [10, 24.49], format: \"{n}\", delay: s * 1000 + 400, ms: 600, ease: \"linear\" },\n { id: \"dot\", attrs: { opacity: [0, 1] }, delay: s * 1000, ms: 1 },\n { id: \"dot\", attrs: { opacity: [1, 0] }, delay: s * 1000 + 600, ms: 1 },\n ]).flat(),\n },\n};\n\nexport const vectorEffects: VectorEffect[] = [\n spinner,\n bouncingDots,\n pulsePing,\n equalizer,\n progressRing,\n barChart,\n lineChart,\n statCounter,\n route,\n timelineTrack,\n successCheck,\n errorCross,\n heartbeat,\n signature,\n confetti,\n blobMorph,\n dripText,\n flowNetwork,\n viewfinder,\n];\n","/**\n * The effect catalog: ready-made shader and vector effects, each with\n * controls and presets, to drop into a product or start an edit from.\n *\n * - Browsing: `EFFECTS`, `getEffect`, `findEffects`, `EFFECT_CATEGORIES`.\n * - Controls: `effectControls`, `effectDefaults`.\n * - Vector effects: their pictures declare their controls (`vectorControls`),\n * and `renderVectorEffect` fills them in.\n *\n * @packageDocumentation\n */\n\nimport { controlValue, parseControls, type ControlDef, type ControlValue } from \"../shader/controls.js\";\nimport { aurora, conicSweep, duotoneFlow, meshGradient, silk } from \"./shaders/gradients.js\";\nimport {\n crt,\n filmGrain,\n imageDuotone,\n imageGlitch,\n imageHalftone,\n imagePixelate,\n imageRipple,\n transitions,\n} from \"./shaders/image.js\";\nimport { blackHole, bokeh, godRays, lightRibbons, nebula, neonRipple, sparkles, starfield } from \"./shaders/light.js\";\nimport { caustics, flames, lavaLamp, marble, plasma, smoke } from \"./shaders/organic.js\";\nimport { barberStripes, dotWave, hexPulse, kaleidoscope, moire, neonCircuit, truchet, voronoi } from \"./shaders/patterns.js\";\nimport { morphEffects } from \"./morph.js\";\nimport { morphShaders } from \"./shaders/morph.js\";\nimport { overlayEffects } from \"./shaders/overlay.js\";\nimport { digitalRain, pixelSunset, synthwaveGrid, tvStatic } from \"./shaders/retro.js\";\nimport { textShaders } from \"./shaders/text.js\";\nimport { imageTreatments } from \"./shaders/treatments.js\";\nimport { textEffects } from \"./text.js\";\nimport { EFFECT_CATEGORIES, vectorEffectControls, type EffectCategory, type EffectDefinition, type ShaderEffect } from \"./types.js\";\nimport { vectorEffects } from \"./vector.js\";\n\nexport {\n colorControl,\n EFFECT_CATEGORIES,\n numberControl,\n renderVectorEffect,\n VECTOR_CONTROL_TYPES,\n vectorControlDef,\n vectorControlIssues,\n vectorControls,\n vectorEffectControls,\n type EffectCategory,\n type EffectDefinition,\n type EffectPreset,\n type ShaderEffect,\n type VectorControl,\n type VectorEffect,\n} from \"./types.js\";\nexport { SAMPLE_IMAGES, svgDataUrl, textImage } from \"./images.js\";\nexport { FBM, glsl, HASH, NOISE, OKLAB_MIX, PALETTE, ROTATE } from \"./glsl.js\";\n\n/** The catalog's shader effects. */\nexport const SHADER_EFFECTS: readonly ShaderEffect[] = [\n meshGradient,\n aurora,\n duotoneFlow,\n conicSweep,\n silk,\n marble,\n smoke,\n lavaLamp,\n plasma,\n caustics,\n flames,\n dotWave,\n truchet,\n hexPulse,\n voronoi,\n moire,\n kaleidoscope,\n barberStripes,\n neonCircuit,\n bokeh,\n godRays,\n sparkles,\n neonRipple,\n lightRibbons,\n starfield,\n nebula,\n blackHole,\n synthwaveGrid,\n digitalRain,\n pixelSunset,\n tvStatic,\n imageRipple,\n imageGlitch,\n imageDuotone,\n imageHalftone,\n imagePixelate,\n ...imageTreatments,\n crt,\n filmGrain,\n ...overlayEffects,\n ...textShaders,\n ...morphShaders,\n ...transitions,\n];\n\n/** Every effect in the catalog, shaders first, grouped by category. */\nexport const EFFECTS: readonly EffectDefinition[] = [...SHADER_EFFECTS, ...vectorEffects, ...textEffects, ...morphEffects].sort(\n (a, b) => EFFECT_CATEGORIES.indexOf(a.category) - EFFECT_CATEGORIES.indexOf(b.category),\n);\n\nconst byId = new Map(EFFECTS.map((e) => [e.id, e]));\n\n/** The effect with this id, or undefined. */\nexport function getEffect(id: string): EffectDefinition | undefined {\n return byId.get(id);\n}\n\nexport interface EffectQuery {\n /** Words to look for in the name, description, tags and id (all must match). */\n text?: string;\n category?: EffectCategory;\n kind?: EffectDefinition[\"kind\"];\n /** Effects with every one of these tags. */\n tags?: readonly string[];\n}\n\n/** Effects matching a query, in catalog order. */\nexport function findEffects(query: EffectQuery = {}): EffectDefinition[] {\n const words = (query.text ?? \"\").toLowerCase().split(/\\s+/).filter(Boolean);\n return EFFECTS.filter((e) => {\n if (query.category && e.category !== query.category) return false;\n if (query.kind && e.kind !== query.kind) return false;\n if (query.tags && !query.tags.every((t) => e.tags.includes(t))) return false;\n const haystack = [e.id, e.name, e.description, e.category, ...e.tags].join(\" \").toLowerCase();\n return words.every((w) => haystack.includes(w));\n });\n}\n\n/** An effect's controls: a shader's `@control` uniforms, or a vector effect's declared controls. */\nexport function effectControls(effect: EffectDefinition): ControlDef[] {\n return effect.kind === \"shader\" ? parseControls(effect.source) : vectorEffectControls(effect);\n}\n\n/** An effect's values: each control's default, overridden by `values` (and a preset by name, when given). */\nexport function effectDefaults(\n effect: EffectDefinition,\n options: { preset?: string; values?: Record<string, ControlValue> } = {},\n): Record<string, ControlValue> {\n const preset = options.preset ? effect.presets?.find((p) => p.name === options.preset)?.values : undefined;\n const merged = { ...preset, ...options.values };\n return Object.fromEntries(effectControls(effect).map((c) => [c.name, controlValue(c, merged)]));\n}\n"],"mappings":"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","names":["r1","HEART","pair","_","n","SLOTS","link"]}