morpha-studio-sdk 0.1.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.
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/dist/index.cjs +6983 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1030 -0
- package/dist/index.d.ts +1030 -0
- package/dist/index.js +6935 -0
- package/dist/index.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/shapes.ts","../../editor/src/google-fonts.ts","../../editor/src/bunny-fonts.ts","../../editor/src/fontshare-fonts.ts","../../editor/src/fontsource-fonts.ts","../../editor/src/velvetyne-fonts.ts","../../editor/src/font-sources.ts","../../src/schemas.ts","../../src/tools.ts","../../src/blank-project.ts","../../src/captions.ts","../src/render.ts","../src/client.ts"],"sourcesContent":["// Shape registry — the single source of truth for every shape primitive\n// Metamorpha can draw. Both the Zod schema (`src/schemas.ts`) and the canvas\n// renderer (`editor/src/renderer.ts`) derive from this list, so adding a new\n// shape means appending ONE entry here.\n//\n// Each entry has:\n// - `id` — the `kind` string stored on a shape layer (and the schema enum).\n// - `label` — the human name shown in pickers / the Inspector.\n// - `trace` — writes a closed canvas path into the 2D context. The caller\n// has already done `ctx.beginPath()`; `trace` must NOT begin or\n// fill the path. All coordinates fit inside the bbox\n// `(0, 0)–(w, h)` (the renderer has moved the origin to the\n// layer's top-left after rotate + scale + flip).\n//\n// `rect` MUST stay in the set and remain first — older projects depend on the\n// schema default `.default(\"rect\")`.\n\n// Minimal structural 2D-context type — just the path-building surface every\n// `trace` uses. Defined locally (rather than referencing the ambient\n// `CanvasRenderingContext2D`) so this module typechecks in the Worker build,\n// whose tsconfig has no DOM lib. Both `CanvasRenderingContext2D` and\n// `OffscreenCanvasRenderingContext2D` are structurally assignable to it, so\n// `renderer.ts`'s `Ctx2D` union flows in without a cast.\nexport interface ShapeCtx2D {\n moveTo(x: number, y: number): void;\n lineTo(x: number, y: number): void;\n closePath(): void;\n rect(x: number, y: number, w: number, h: number): void;\n arc(\n x: number,\n y: number,\n radius: number,\n startAngle: number,\n endAngle: number,\n counterclockwise?: boolean,\n ): void;\n arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void;\n ellipse(\n x: number,\n y: number,\n radiusX: number,\n radiusY: number,\n rotation: number,\n startAngle: number,\n endAngle: number,\n counterclockwise?: boolean,\n ): void;\n bezierCurveTo(\n cp1x: number,\n cp1y: number,\n cp2x: number,\n cp2y: number,\n x: number,\n y: number,\n ): void;\n}\n\nexport interface ShapeDef {\n id: string;\n label: string;\n trace: (ctx: ShapeCtx2D, w: number, h: number) => void;\n}\n\n// --- path-building primitives -------------------------------------------------\n\n// Regular polygon inscribed in the bbox. `startAngle` is the angle (radians)\n// of the first vertex measured from the centre; subsequent vertices step\n// evenly. Default `-PI/2` puts the first vertex straight up (point-up).\nconst polygon = (\n ctx: ShapeCtx2D,\n w: number,\n h: number,\n sides: number,\n startAngle = -Math.PI / 2,\n): void => {\n const cx = w / 2;\n const cy = h / 2;\n const rx = w / 2;\n const ry = h / 2;\n for (let i = 0; i < sides; i++) {\n const a = startAngle + (i * 2 * Math.PI) / sides;\n const px = cx + rx * Math.cos(a);\n const py = cy + ry * Math.sin(a);\n if (i === 0) ctx.moveTo(px, py);\n else ctx.lineTo(px, py);\n }\n ctx.closePath();\n};\n\n// Star / burst: `points` outer spikes alternating with `points` inner valleys.\n// `innerRatio` is the inner radius as a fraction of the outer radius.\nconst starPath = (\n ctx: ShapeCtx2D,\n w: number,\n h: number,\n points: number,\n innerRatio: number,\n startAngle = -Math.PI / 2,\n): void => {\n const cx = w / 2;\n const cy = h / 2;\n const outerX = w / 2;\n const outerY = h / 2;\n const steps = points * 2;\n for (let i = 0; i < steps; i++) {\n const ratio = i % 2 === 0 ? 1 : innerRatio;\n const a = startAngle + (i * Math.PI) / points;\n const px = cx + ratio * outerX * Math.cos(a);\n const py = cy + ratio * outerY * Math.sin(a);\n if (i === 0) ctx.moveTo(px, py);\n else ctx.lineTo(px, py);\n }\n ctx.closePath();\n};\n\n// Trace a polyline of [x, y] fractions of the bbox and close it.\nconst poly = (\n ctx: ShapeCtx2D,\n w: number,\n h: number,\n pts: ReadonlyArray<readonly [number, number]>,\n): void => {\n for (let i = 0; i < pts.length; i++) {\n const px = pts[i][0] * w;\n const py = pts[i][1] * h;\n if (i === 0) ctx.moveTo(px, py);\n else ctx.lineTo(px, py);\n }\n ctx.closePath();\n};\n\n// Rounded rectangle clamped so the radius never exceeds half the shorter side.\nconst roundRectPath = (\n ctx: ShapeCtx2D,\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n): void => {\n const rr = Math.max(0, Math.min(r, w / 2, h / 2));\n ctx.moveTo(x + rr, y);\n ctx.lineTo(x + w - rr, y);\n ctx.arcTo(x + w, y, x + w, y + rr, rr);\n ctx.lineTo(x + w, y + h - rr);\n ctx.arcTo(x + w, y + h, x + w - rr, y + h, rr);\n ctx.lineTo(x + rr, y + h);\n ctx.arcTo(x, y + h, x, y + h - rr, rr);\n ctx.lineTo(x, y + rr);\n ctx.arcTo(x, y, x + rr, y, rr);\n ctx.closePath();\n};\n\n// --- the registry -------------------------------------------------------------\n\n// The `as const` keeps every `id` / `label` as a string literal (so `ShapeKind`\n// is a precise union); `satisfies` still structurally checks each entry against\n// `ShapeDef`. `trace` callbacks keep their inferred function types either way.\nexport const SHAPE_DEFS = [\n // --- the historic 8 ---------------------------------------------------------\n {\n id: \"rect\",\n label: \"Rectangle\",\n trace: (ctx, w, h) => {\n ctx.rect(0, 0, w, h);\n },\n },\n {\n id: \"ellipse\",\n label: \"Ellipse\",\n trace: (ctx, w, h) => {\n ctx.ellipse(w / 2, h / 2, w / 2, h / 2, 0, 0, Math.PI * 2);\n },\n },\n {\n id: \"triangle\",\n label: \"Triangle\",\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.5, 0],\n [1, 1],\n [0, 1],\n ]);\n },\n },\n {\n id: \"star\",\n label: \"Star\",\n // Classic 5-point star, point-up; inner radius 0.4 of the outer.\n trace: (ctx, w, h) => starPath(ctx, w, h, 5, 0.4),\n },\n {\n id: \"pentagon\",\n label: \"Pentagon\",\n trace: (ctx, w, h) => polygon(ctx, w, h, 5),\n },\n {\n id: \"hexagon\",\n label: \"Hexagon\",\n // Flat-top: first vertex offset 30° from straight-up.\n trace: (ctx, w, h) => polygon(ctx, w, h, 6, -Math.PI / 2 + Math.PI / 6),\n },\n {\n id: \"arrow\",\n label: \"Arrow\",\n // Right-pointing block arrow: shaft on the left at half-height, triangular\n // head spanning the right 40% at full height.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0, 0.25],\n [0.6, 0.25],\n [0.6, 0],\n [1, 0.5],\n [0.6, 1],\n [0.6, 0.75],\n [0, 0.75],\n ]);\n },\n },\n {\n id: \"heart\",\n label: \"Heart\",\n trace: (ctx, w, h) => {\n const topY = h * 0.28;\n ctx.moveTo(w / 2, topY);\n ctx.bezierCurveTo(w * 0.4, h * -0.05, w * -0.18, h * 0.32, w / 2, h);\n ctx.bezierCurveTo(w * 1.18, h * 0.32, w * 0.6, h * -0.05, w / 2, topY);\n ctx.closePath();\n },\n },\n\n // --- geometric --------------------------------------------------------------\n {\n id: \"rounded-rect\",\n label: \"Rounded Rectangle\",\n trace: (ctx, w, h) => {\n roundRectPath(ctx, 0, 0, w, h, Math.min(w, h) * 0.18);\n },\n },\n {\n id: \"diamond\",\n label: \"Diamond\",\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.5, 0],\n [1, 0.5],\n [0.5, 1],\n [0, 0.5],\n ]);\n },\n },\n {\n id: \"parallelogram\",\n label: \"Parallelogram\",\n // Top edge shifted right, bottom edge shifted left — 25% skew.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.25, 0],\n [1, 0],\n [0.75, 1],\n [0, 1],\n ]);\n },\n },\n {\n id: \"trapezoid\",\n label: \"Trapezoid\",\n // Wide base, narrower top inset 25% on each side.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.25, 0],\n [0.75, 0],\n [1, 1],\n [0, 1],\n ]);\n },\n },\n {\n id: \"semicircle\",\n label: \"Semicircle\",\n // Flat side on the bottom; the arc fills the upper bbox.\n trace: (ctx, w, h) => {\n ctx.moveTo(0, h);\n ctx.lineTo(0, h);\n ctx.ellipse(w / 2, h, w / 2, h, 0, Math.PI, 2 * Math.PI);\n ctx.lineTo(0, h);\n ctx.closePath();\n },\n },\n {\n id: \"ring\",\n label: \"Ring\",\n // Donut: outer ellipse + an inner ellipse wound the opposite direction so\n // the non-zero fill rule punches a hole. Hole radius 0.5 of the outer.\n trace: (ctx, w, h) => {\n ctx.ellipse(w / 2, h / 2, w / 2, h / 2, 0, 0, Math.PI * 2);\n ctx.moveTo(w / 2 + w * 0.25, h / 2);\n ctx.ellipse(w / 2, h / 2, w * 0.25, h * 0.25, 0, 0, Math.PI * 2, true);\n },\n },\n {\n id: \"pill\",\n label: \"Pill\",\n // Horizontal capsule. Height is clamped so it always reads as a pill — a\n // full-bbox capsule collapses to a plain circle in a square bbox.\n trace: (ctx, w, h) => {\n const ph = Math.min(h, w * 0.6);\n const py = (h - ph) / 2;\n roundRectPath(ctx, 0, py, w, ph, ph / 2);\n },\n },\n {\n id: \"cross\",\n label: \"Cross\",\n // Plus / cross: arms one-third of the bbox thick.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [1 / 3, 0],\n [2 / 3, 0],\n [2 / 3, 1 / 3],\n [1, 1 / 3],\n [1, 2 / 3],\n [2 / 3, 2 / 3],\n [2 / 3, 1],\n [1 / 3, 1],\n [1 / 3, 2 / 3],\n [0, 2 / 3],\n [0, 1 / 3],\n [1 / 3, 1 / 3],\n ]);\n },\n },\n\n // --- polygons ---------------------------------------------------------------\n {\n id: \"heptagon\",\n label: \"Heptagon\",\n trace: (ctx, w, h) => polygon(ctx, w, h, 7),\n },\n {\n id: \"octagon\",\n label: \"Octagon\",\n // Flat-top: first vertex offset half a step so top + bottom run flat.\n trace: (ctx, w, h) => polygon(ctx, w, h, 8, -Math.PI / 2 + Math.PI / 8),\n },\n\n // --- stars / bursts ---------------------------------------------------------\n {\n id: \"star-4\",\n label: \"4-Point Star\",\n trace: (ctx, w, h) => starPath(ctx, w, h, 4, 0.38),\n },\n {\n id: \"star-6\",\n label: \"6-Point Star\",\n trace: (ctx, w, h) => starPath(ctx, w, h, 6, 0.5),\n },\n {\n id: \"sparkle\",\n label: \"Sparkle\",\n // Four-point sparkle with concave waist — a slim inner ratio gives the\n // pinched, glinting look.\n trace: (ctx, w, h) => starPath(ctx, w, h, 4, 0.18),\n },\n {\n id: \"burst\",\n label: \"Burst\",\n // Many-point starburst / explosion badge.\n trace: (ctx, w, h) => starPath(ctx, w, h, 12, 0.68),\n },\n\n // --- arrows -----------------------------------------------------------------\n {\n id: \"arrow-left\",\n label: \"Arrow Left\",\n // Mirror of `arrow`.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [1, 0.25],\n [0.4, 0.25],\n [0.4, 0],\n [0, 0.5],\n [0.4, 1],\n [0.4, 0.75],\n [1, 0.75],\n ]);\n },\n },\n {\n id: \"double-arrow\",\n label: \"Double Arrow\",\n // A head at each horizontal end joined by a central shaft.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0, 0.5],\n [0.25, 0],\n [0.25, 0.25],\n [0.75, 0.25],\n [0.75, 0],\n [1, 0.5],\n [0.75, 1],\n [0.75, 0.75],\n [0.25, 0.75],\n [0.25, 1],\n ]);\n },\n },\n {\n id: \"chevron\",\n label: \"Chevron\",\n // Right-pointing chevron (an open arrowhead with a notched back).\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0, 0],\n [0.5, 0],\n [1, 0.5],\n [0.5, 1],\n [0, 1],\n [0.5, 0.5],\n ]);\n },\n },\n {\n id: \"block-arrow-up\",\n label: \"Block Arrow Up\",\n // Up-pointing block arrow: triangular head over a centred shaft.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.5, 0],\n [1, 0.45],\n [0.7, 0.45],\n [0.7, 1],\n [0.3, 1],\n [0.3, 0.45],\n [0, 0.45],\n ]);\n },\n },\n {\n id: \"curve\",\n label: \"Arrow / Curve\",\n // A stroked quadratic bezier with an arrowhead — the editable line/arrow\n // primitive. Its real geometry lives in the shape's `points` (control\n // points), stroke_width and arrow_head, and the renderer STROKES it (this\n // trace is only the picker glyph + a fallback when no points are stored):\n // a filled curved-arrow silhouette swooping up to a head on the right.\n trace: (ctx, w, h) => {\n const X = (f: number) => f * w;\n const Y = (f: number) => f * h;\n ctx.moveTo(X(0.08), Y(0.8));\n ctx.bezierCurveTo(X(0.3), Y(0.3), X(0.54), Y(0.24), X(0.72), Y(0.34));\n ctx.lineTo(X(0.68), Y(0.14));\n ctx.lineTo(X(0.98), Y(0.44));\n ctx.lineTo(X(0.62), Y(0.6));\n ctx.lineTo(X(0.66), Y(0.46));\n ctx.bezierCurveTo(X(0.5), Y(0.4), X(0.32), Y(0.48), X(0.2), Y(0.88));\n ctx.closePath();\n },\n },\n\n // --- symbols ----------------------------------------------------------------\n {\n id: \"lightning\",\n label: \"Lightning Bolt\",\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.55, 0],\n [0.1, 0.55],\n [0.42, 0.55],\n [0.32, 1],\n [0.85, 0.4],\n [0.5, 0.4],\n [0.72, 0],\n ]);\n },\n },\n {\n id: \"speech-bubble\",\n label: \"Speech Bubble\",\n // Rounded body occupying the top 78% + a tail dropping from the lower-left.\n trace: (ctx, w, h) => {\n const bodyH = h * 0.78;\n const r = Math.min(w, bodyH) * 0.22;\n const rr = Math.max(0, Math.min(r, w / 2, bodyH / 2));\n ctx.moveTo(rr, 0);\n ctx.lineTo(w - rr, 0);\n ctx.arcTo(w, 0, w, rr, rr);\n ctx.lineTo(w, bodyH - rr);\n ctx.arcTo(w, bodyH, w - rr, bodyH, rr);\n // tail\n ctx.lineTo(w * 0.4, bodyH);\n ctx.lineTo(w * 0.2, h);\n ctx.lineTo(w * 0.24, bodyH);\n ctx.lineTo(rr, bodyH);\n ctx.arcTo(0, bodyH, 0, bodyH - rr, rr);\n ctx.lineTo(0, rr);\n ctx.arcTo(0, 0, rr, 0, rr);\n ctx.closePath();\n },\n },\n {\n id: \"location-pin\",\n label: \"Location Pin\",\n // Map marker: a circular head that tapers to a point at the bottom centre.\n trace: (ctx, w, h) => {\n const cx = w / 2;\n const cy = h * 0.36;\n const r = Math.min(w / 2, h * 0.36);\n // start at the bottom tip, sweep up around the head, back to the tip\n ctx.moveTo(cx, h);\n ctx.bezierCurveTo(\n cx - r * 0.55,\n cy + r * 0.95,\n cx - r,\n cy + r * 0.45,\n cx - r,\n cy,\n );\n ctx.arc(cx, cy, r, Math.PI, 0, false);\n ctx.bezierCurveTo(\n cx + r,\n cy + r * 0.45,\n cx + r * 0.55,\n cy + r * 0.95,\n cx,\n h,\n );\n ctx.closePath();\n },\n },\n {\n id: \"checkmark\",\n label: \"Checkmark\",\n // A tick stroke given thickness — a two-segment polyline outlined.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.0, 0.55],\n [0.16, 0.4],\n [0.4, 0.62],\n [0.84, 0.12],\n [1.0, 0.28],\n [0.4, 0.92],\n ]);\n },\n },\n {\n id: \"x-mark\",\n label: \"X Mark\",\n // A thick cross / multiplication mark.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0.15, 0.0],\n [0.5, 0.32],\n [0.85, 0.0],\n [1.0, 0.15],\n [0.68, 0.5],\n [1.0, 0.85],\n [0.85, 1.0],\n [0.5, 0.68],\n [0.15, 1.0],\n [0.0, 0.85],\n [0.32, 0.5],\n [0.0, 0.15],\n ]);\n },\n },\n {\n id: \"shield\",\n label: \"Shield\",\n // Crest: flat shoulders, sides curving inward to a point at the bottom.\n trace: (ctx, w, h) => {\n ctx.moveTo(w / 2, 0);\n ctx.lineTo(w, h * 0.15);\n ctx.lineTo(w, h * 0.5);\n ctx.bezierCurveTo(w, h * 0.8, w * 0.75, h * 0.95, w / 2, h);\n ctx.bezierCurveTo(w * 0.25, h * 0.95, 0, h * 0.8, 0, h * 0.5);\n ctx.lineTo(0, h * 0.15);\n ctx.closePath();\n },\n },\n {\n id: \"cloud\",\n label: \"Cloud\",\n // Union of a soft-cornered base slab and three puff circles — every\n // subpath is wound the same way, so the non-zero fill merges them into\n // one cloud silhouette (rounded flat base from the slab, bumpy top from\n // the puffs). The slab's bottom edge is the lowest point.\n trace: (ctx, w, h) => {\n const TAU = Math.PI * 2;\n const puff = (px: number, py: number, r: number): void => {\n ctx.moveTo(px + r, py);\n ctx.arc(px, py, r, 0, TAU);\n };\n roundRectPath(ctx, w * 0.14, h * 0.5, w * 0.72, h * 0.34, Math.min(w, h) * 0.16);\n puff(w * 0.32, h * 0.54, w * 0.2); // left bump\n puff(w * 0.52, h * 0.38, w * 0.26); // tall middle bump\n puff(w * 0.72, h * 0.52, w * 0.22); // right bump\n },\n },\n {\n id: \"crescent\",\n label: \"Crescent Moon\",\n // Lune traced as two arcs meeting at the horns: the outer rim (the long\n // way round a disc) then the inner bite (a same-radius disc offset right).\n // Tracing only the real boundary avoids the stray fill a full-circle\n // subtraction leaves where the cutting disc pokes past the outer rim.\n trace: (ctx, w, h) => {\n const R = Math.min(w, h) / 2;\n const cx = w / 2;\n const cy = h / 2;\n const d = R * 0.5; // cutting-disc offset → crescent thickness\n const u = d / 2; // x of the two circle intersections, relative to cx\n const yi = Math.sqrt(Math.max(0, R * R - u * u));\n // outer rim: top horn → (round the left) → bottom horn\n ctx.arc(cx, cy, R, Math.atan2(-yi, u), Math.atan2(yi, u), true);\n // inner bite: bottom horn → (round the left of the offset disc) → top horn\n ctx.arc(cx + d, cy, R, Math.atan2(yi, u - d), Math.atan2(-yi, u - d), false);\n ctx.closePath();\n },\n },\n {\n id: \"teardrop\",\n label: \"Teardrop\",\n // Round at the bottom, tapering to a point at the top centre.\n trace: (ctx, w, h) => {\n const cx = w / 2;\n const cy = h * 0.62;\n const r = Math.min(w / 2, h * 0.38);\n ctx.moveTo(cx, 0);\n ctx.bezierCurveTo(cx + r * 0.95, cy - r * 0.7, cx + r, cy, cx + r, cy);\n ctx.arc(cx, cy, r, 0, Math.PI, false);\n ctx.bezierCurveTo(cx - r, cy, cx - r * 0.95, cy - r * 0.7, cx, 0);\n ctx.closePath();\n },\n },\n {\n id: \"banner\",\n label: \"Banner\",\n // Ribbon: a horizontal band with V-notched ends.\n trace: (ctx, w, h) => {\n poly(ctx, w, h, [\n [0, 0.15],\n [0.85, 0.15],\n [1, 0.5],\n [0.85, 0.85],\n [0, 0.85],\n [0.15, 0.5],\n ]);\n },\n },\n] as const satisfies readonly ShapeDef[];\n\n// The shape kind — a string union of every registry id. Derived from the\n// `as const` `SHAPE_DEFS` literal so adding an entry above widens it for free.\nexport type ShapeKind = (typeof SHAPE_DEFS)[number][\"id\"];\n\n// Stable lookup by id. Built once at module load.\nexport const SHAPE_DEF_BY_ID: Readonly<Record<ShapeKind, ShapeDef>> =\n Object.fromEntries(SHAPE_DEFS.map((d) => [d.id, d])) as Record<\n ShapeKind,\n ShapeDef\n >;\n\n// Readonly non-empty tuple of every shape id, for `z.enum`. `rect` is first so\n// the schema default (`.default(\"rect\")`) lines up with element [0]. The cast\n// preserves the literal union while satisfying `z.enum`'s tuple constraint.\nexport const SHAPE_IDS = SHAPE_DEFS.map((d) => d.id) as [\n ShapeKind,\n ...ShapeKind[],\n];\n","// AUTO-GENERATED by scripts/build-fonts.mjs — do not edit by hand.\n// The full Google Fonts family catalogue, bundled so the editor's text-layer\n// font picker is a searchable dropdown over every family. Regenerate with:\n// node scripts/build-fonts.mjs\n//\n// GOOGLE_FONT_WEIGHTS maps each family to the NUMERIC weights it actually\n// ships (no italic axis — the italic toggle is separate). The Inspector\n// filters its weight-picker by this so Anton (which only ships 400) doesn't\n// offer Thin / Light / Bold / Black options the browser would just faux-\n// synthesize without visible effect.\n\nexport const GOOGLE_FONTS: string[] = [\"ABeeZee\",\"Abel\",\"Abhaya Libre\",\"Aboreto\",\"Abril Fatface\",\"Abyssinica SIL\",\"Aclonica\",\"Acme\",\"Actor\",\"Adamina\",\"ADLaM Display\",\"Advent Pro\",\"Afacad\",\"Afacad Flux\",\"Agbalumo\",\"Agdasima\",\"Agu Display\",\"Aguafina Script\",\"Akatab\",\"Akaya Kanadaka\",\"Akaya Telivigala\",\"Akronim\",\"Akshar\",\"Akt\",\"Aladin\",\"Alan Sans\",\"Alata\",\"Alatsi\",\"Albert Sans\",\"Aldrich\",\"Alef\",\"Alegreya\",\"Alegreya Sans\",\"Alegreya Sans SC\",\"Alegreya SC\",\"Aleo\",\"Alex Brush\",\"Alexandria\",\"Alfa Slab One\",\"Alice\",\"Alike\",\"Alike Angular\",\"Alkalami\",\"Alkatra\",\"Allan\",\"Allerta\",\"Allerta Stencil\",\"Allison\",\"Allkin\",\"Allura\",\"Almarai\",\"Almendra\",\"Almendra Display\",\"Almendra SC\",\"Alumni Sans\",\"Alumni Sans Collegiate One\",\"Alumni Sans Inline One\",\"Alumni Sans Pinstripe\",\"Alumni Sans SC\",\"Alyamama\",\"Amarante\",\"Amaranth\",\"Amarna\",\"Amatic SC\",\"Amethysta\",\"Amiko\",\"Amiri\",\"Amiri Quran\",\"Amita\",\"Anaheim\",\"Ancizar Sans\",\"Ancizar Serif\",\"Andada Pro\",\"Andika\",\"Anek Bangla\",\"Anek Devanagari\",\"Anek Gujarati\",\"Anek Gurmukhi\",\"Anek Kannada\",\"Anek Latin\",\"Anek Malayalam\",\"Anek Odia\",\"Anek Tamil\",\"Anek Telugu\",\"Angkor\",\"Annapurna SIL\",\"Annie Use Your Telescope\",\"Anonymous Pro\",\"Anta\",\"Antic\",\"Antic Didone\",\"Antic Slab\",\"Anton\",\"Anton SC\",\"Antonio\",\"Anuphan\",\"Anybody\",\"Aoboshi One\",\"AR One Sans\",\"Arapey\",\"Arbutus\",\"Arbutus Slab\",\"Architects Daughter\",\"Archivo\",\"Archivo Black\",\"Archivo Narrow\",\"Are You Serious\",\"Aref Ruqaa\",\"Aref Ruqaa Ink\",\"Arima\",\"Arimo\",\"Arizonia\",\"Armata\",\"Arsenal\",\"Arsenal SC\",\"Artifika\",\"Arvo\",\"Arya\",\"Asap\",\"Asap Condensed\",\"Asar\",\"Asimovian\",\"Asset\",\"Assistant\",\"Asta Sans\",\"Astloch\",\"Asul\",\"Athiti\",\"Atkinson Hyperlegible\",\"Atkinson Hyperlegible Mono\",\"Atkinson Hyperlegible Next\",\"Atma\",\"Atomic Age\",\"Aubrey\",\"Audiowide\",\"Autour One\",\"Average\",\"Average Sans\",\"Averia Gruesa Libre\",\"Averia Libre\",\"Averia Sans Libre\",\"Averia Serif Libre\",\"Azeret Mono\",\"B612\",\"B612 Mono\",\"Babylonica\",\"Bacasime Antique\",\"Bad Script\",\"Badeen Display\",\"Bagel Fat One\",\"Bahiana\",\"Bahianita\",\"Bai Jamjuree\",\"Bakbak One\",\"Ballet\",\"Baloo 2\",\"Baloo Bhai 2\",\"Baloo Bhaijaan 2\",\"Baloo Bhaina 2\",\"Baloo Chettan 2\",\"Baloo Da 2\",\"Baloo Paaji 2\",\"Baloo Tamma 2\",\"Baloo Tammudu 2\",\"Baloo Thambi 2\",\"Balsamiq Sans\",\"Balthazar\",\"Bangers\",\"Barlow\",\"Barlow Condensed\",\"Barlow Semi Condensed\",\"Barriecito\",\"Barrio\",\"Basic\",\"Baskervville\",\"Baskervville SC\",\"Battambang\",\"Baumans\",\"Bayon\",\"BBH Bartle\",\"BBH Bogle\",\"BBH Hegarty\",\"Be Vietnam Pro\",\"Beau Rivage\",\"Bebas Neue\",\"Beiruti\",\"Belanosima\",\"Belgrano\",\"Bellefair\",\"Belleza\",\"Bellota\",\"Bellota Text\",\"BenchNine\",\"Benne\",\"Bentham\",\"Berkshire Swash\",\"Besley\",\"Betania Patmos\",\"Betania Patmos GDL\",\"Betania Patmos In\",\"Betania Patmos In GDL\",\"Beth Ellen\",\"Bevan\",\"BhuTuka Expanded One\",\"Big Shoulders\",\"Big Shoulders Inline\",\"Big Shoulders Stencil\",\"Bigelow Rules\",\"Bigshot One\",\"Bilbo\",\"Bilbo Swash Caps\",\"BioRhyme\",\"BioRhyme Expanded\",\"Birthstone\",\"Birthstone Bounce\",\"Biryani\",\"Bitcount\",\"Bitcount Grid Double\",\"Bitcount Grid Double Ink\",\"Bitcount Grid Single\",\"Bitcount Grid Single Ink\",\"Bitcount Ink\",\"Bitcount Prop Double\",\"Bitcount Prop Double Ink\",\"Bitcount Prop Single\",\"Bitcount Prop Single Ink\",\"Bitcount Single\",\"Bitcount Single Ink\",\"Bitter\",\"BIZ UDGothic\",\"BIZ UDMincho\",\"BIZ UDPGothic\",\"BIZ UDPMincho\",\"BJCree\",\"Black And White Picture\",\"Black Han Sans\",\"Black Ops One\",\"Blaka\",\"Blaka Hollow\",\"Blaka Ink\",\"Blinker\",\"Bodoni Moda\",\"Bodoni Moda SC\",\"Bokor\",\"Boldonse\",\"Bona Nova\",\"Bona Nova SC\",\"Bonbon\",\"Bonheur Royale\",\"Boogaloo\",\"Borel\",\"Bowlby One\",\"Bowlby One SC\",\"Bpmf Huninn\",\"Bpmf Iansui\",\"Bpmf Zihi Kai Std\",\"Braah One\",\"Brawler\",\"Bree Serif\",\"Bricolage Grotesque\",\"Bruno Ace\",\"Bruno Ace SC\",\"Brygada 1918\",\"Bubblegum Sans\",\"Bubbler One\",\"Buda\",\"Buenard\",\"Bungee\",\"Bungee Hairline\",\"Bungee Inline\",\"Bungee Outline\",\"Bungee Shade\",\"Bungee Spice\",\"Bungee Tint\",\"Butcherman\",\"Butterfly Kids\",\"Bytesized\",\"Cabin\",\"Cabin Condensed\",\"Cabin Sketch\",\"Cactus Classical Serif\",\"Caesar Dressing\",\"Cagliostro\",\"Cairo\",\"Cairo Play\",\"Cal Sans\",\"Caladea\",\"Calistoga\",\"Calligraffitti\",\"Cambay\",\"Cambo\",\"Candal\",\"Cantarell\",\"Cantata One\",\"Cantora One\",\"Caprasimo\",\"Capriola\",\"Caramel\",\"Carattere\",\"Cardo\",\"Carlito\",\"Carme\",\"Carrois Gothic\",\"Carrois Gothic SC\",\"Carter One\",\"Cascadia Code\",\"Cascadia Mono\",\"Castoro\",\"Castoro Titling\",\"Catamaran\",\"Caudex\",\"Cause\",\"Caveat\",\"Caveat Brush\",\"Cedarville Cursive\",\"Ceviche One\",\"Chakra Petch\",\"Changa\",\"Changa One\",\"Chango\",\"Charis SIL\",\"Charm\",\"Charmonman\",\"Chathura\",\"Chau Philomene One\",\"Chela One\",\"Chelsea Market\",\"Chenla\",\"Cherish\",\"Cherry Bomb One\",\"Cherry Cream Soda\",\"Cherry Swash\",\"Chewy\",\"Chicle\",\"Chilanka\",\"Chiron GoRound TC\",\"Chiron Hei HK\",\"Chiron Sung HK\",\"Chivo\",\"Chivo Mono\",\"Chocolate Classical Sans\",\"Chokokutai\",\"Chonburi\",\"Cinzel\",\"Cinzel Decorative\",\"Clicker Script\",\"Climate Crisis\",\"Coda\",\"Codystar\",\"Coiny\",\"Combo\",\"Comfortaa\",\"Comforter\",\"Comforter Brush\",\"Comic Neue\",\"Comic Relief\",\"Coming Soon\",\"Comme\",\"Commissioner\",\"Concert One\",\"Condiment\",\"Content\",\"Contrail One\",\"Convergence\",\"Cookie\",\"Copse\",\"Coral Pixels\",\"Corben\",\"Corinthia\",\"Cormorant\",\"Cormorant Garamond\",\"Cormorant Infant\",\"Cormorant SC\",\"Cormorant Unicase\",\"Cormorant Upright\",\"Cossette Texte\",\"Cossette Titre\",\"Courgette\",\"Courier Prime\",\"Cousine\",\"Coustard\",\"Covered By Your Grace\",\"Crafty Girls\",\"Creepster\",\"Crete Round\",\"Crimson Pro\",\"Crimson Text\",\"Croissant One\",\"Crushed\",\"Cuprum\",\"Cute Font\",\"Cutive\",\"Cutive Mono\",\"Dai Banna SIL\",\"Damion\",\"Dancing Script\",\"Danfo\",\"Dangrek\",\"Darker Grotesque\",\"Darumadrop One\",\"Datatype\",\"David Libre\",\"Dawning of a New Day\",\"Days One\",\"Dekko\",\"Dela Gothic One\",\"Delicious Handrawn\",\"Delius\",\"Delius Swash Caps\",\"Delius Unicase\",\"Della Respira\",\"Denk One\",\"Devonshire\",\"Dhurjati\",\"Didact Gothic\",\"Diphylleia\",\"Diplomata\",\"Diplomata SC\",\"DM Mono\",\"DM Sans\",\"DM Serif Display\",\"DM Serif Text\",\"Do Hyeon\",\"Dokdo\",\"Domine\",\"Donegal One\",\"Dongle\",\"Doppio One\",\"Dorsa\",\"Dosis\",\"DotGothic16\",\"Doto\",\"Dr Sugiyama\",\"Duru Sans\",\"Dynalight\",\"DynaPuff\",\"Eagle Lake\",\"East Sea Dokdo\",\"Eater\",\"EB Garamond\",\"Economica\",\"Eczar\",\"Edu AU VIC WA NT Arrows\",\"Edu AU VIC WA NT Dots\",\"Edu AU VIC WA NT Guides\",\"Edu AU VIC WA NT Hand\",\"Edu AU VIC WA NT Pre\",\"Edu NSW ACT Cursive\",\"Edu NSW ACT Foundation\",\"Edu NSW ACT Hand Pre\",\"Edu QLD Beginner\",\"Edu QLD Hand\",\"Edu SA Beginner\",\"Edu SA Hand\",\"Edu TAS Beginner\",\"Edu VIC WA NT Beginner\",\"Edu VIC WA NT Hand\",\"Edu VIC WA NT Hand Pre\",\"El Messiri\",\"Electrolize\",\"Elms Sans\",\"Elsie\",\"Elsie Swash Caps\",\"Emblema One\",\"Emilys Candy\",\"Encode Sans\",\"Encode Sans Condensed\",\"Encode Sans Expanded\",\"Encode Sans SC\",\"Encode Sans Semi Condensed\",\"Encode Sans Semi Expanded\",\"Engagement\",\"Englebert\",\"Enriqueta\",\"Ephesis\",\"Epilogue\",\"Epunda Sans\",\"Epunda Slab\",\"Erica One\",\"Esteban\",\"Estedad\",\"Estonia\",\"Euphoria Script\",\"Ewert\",\"Exile\",\"Exo\",\"Exo 2\",\"Expletus Sans\",\"Explora\",\"Faculty Glyphic\",\"Fahkwang\",\"Familjen Grotesk\",\"Fanwood Text\",\"Farro\",\"Farsan\",\"Fascinate\",\"Fascinate Inline\",\"Faster One\",\"Fasthand\",\"Fauna One\",\"Faustina\",\"Federant\",\"Federo\",\"Felipa\",\"Fenix\",\"Festive\",\"Figtree\",\"Finger Paint\",\"Finlandica Headline\",\"Finlandica Text\",\"Fira Code\",\"Fira Mono\",\"Fira Sans\",\"Fira Sans Condensed\",\"Fira Sans Extra Condensed\",\"Fjalla One\",\"Fjord One\",\"Flamenco\",\"Flavors\",\"Fleur De Leah\",\"Flow Block\",\"Flow Circular\",\"Flow Rounded\",\"Foldit\",\"Fondamento\",\"Fontdiner Swanky\",\"Forum\",\"Fragment Mono\",\"Francois One\",\"Frank Ruhl Libre\",\"Fraunces\",\"Freckle Face\",\"Fredericka the Great\",\"Fredoka\",\"Freehand\",\"Freeman\",\"Fresca\",\"Frijole\",\"Fruktur\",\"Fugaz One\",\"Fuggles\",\"Funnel Display\",\"Funnel Sans\",\"Fustat\",\"Fuzzy Bubbles\",\"Ga Maamli\",\"Gabarito\",\"Gabriela\",\"Gaegu\",\"Gafata\",\"Gajraj One\",\"Galada\",\"Galdeano\",\"Galindo\",\"Gamja Flower\",\"Gantari\",\"Gasoek One\",\"Gayathri\",\"Geist\",\"Geist Mono\",\"Gelasio\",\"Gemunu Libre\",\"Genos\",\"Gentium Book Plus\",\"Gentium Plus\",\"Geo\",\"Geologica\",\"Geom\",\"Georama\",\"Geostar\",\"Geostar Fill\",\"Germania One\",\"GFS Didot\",\"GFS Neohellenic\",\"Gideon Roman\",\"Gidole\",\"Gidugu\",\"Gilda Display\",\"Girassol\",\"Give You Glory\",\"Glass Antiqua\",\"Glegoo\",\"Gloock\",\"Gloria Hallelujah\",\"Glory\",\"Gluten\",\"Goblin One\",\"Gochi Hand\",\"Goldman\",\"Golos Text\",\"Google Sans\",\"Google Sans Code\",\"Google Sans Flex\",\"Gorditas\",\"Gothic A1\",\"Gotu\",\"Goudy Bookletter 1911\",\"Gowun Batang\",\"Gowun Dodum\",\"Graduate\",\"Grand Hotel\",\"Grandiflora One\",\"Grandstander\",\"Grape Nuts\",\"Gravitas One\",\"Great Vibes\",\"Grechen Fuemen\",\"Grenze\",\"Grenze Gotisch\",\"Grey Qo\",\"Griffy\",\"Gruppo\",\"Gudea\",\"Gugi\",\"Gulzar\",\"Gupter\",\"Gurajada\",\"Gveret Levin\",\"Gwendolyn\",\"Habibi\",\"Hachi Maru Pop\",\"Hahmlet\",\"Halant\",\"Hammersmith One\",\"Hanalei\",\"Hanalei Fill\",\"Handjet\",\"Handlee\",\"Hanken Grotesk\",\"Hanuman\",\"Happy Monkey\",\"Harmattan\",\"Headland One\",\"Hedvig Letters Sans\",\"Hedvig Letters Serif\",\"Heebo\",\"Henny Penny\",\"Hepta Slab\",\"Herr Von Muellerhoff\",\"Hi Melody\",\"Hina Mincho\",\"Hind\",\"Hind Guntur\",\"Hind Madurai\",\"Hind Mysuru\",\"Hind Siliguri\",\"Hind Vadodara\",\"Holtwood One SC\",\"Homemade Apple\",\"Homenaje\",\"Honk\",\"Host Grotesk\",\"Hubballi\",\"Hubot Sans\",\"Huninn\",\"Hurricane\",\"Iansui\",\"Ibarra Real Nova\",\"IBM Plex Mono\",\"IBM Plex Sans\",\"IBM Plex Sans Arabic\",\"IBM Plex Sans Condensed\",\"IBM Plex Sans Devanagari\",\"IBM Plex Sans Hebrew\",\"IBM Plex Sans JP\",\"IBM Plex Sans KR\",\"IBM Plex Sans Thai\",\"IBM Plex Sans Thai Looped\",\"IBM Plex Serif\",\"Iceberg\",\"Iceland\",\"Idiqlat\",\"IM Fell Double Pica\",\"IM Fell Double Pica SC\",\"IM Fell DW Pica\",\"IM Fell DW Pica SC\",\"IM Fell English\",\"IM Fell English SC\",\"IM Fell French Canon\",\"IM Fell French Canon SC\",\"IM Fell Great Primer\",\"IM Fell Great Primer SC\",\"Imbue\",\"Imperial Script\",\"Imprima\",\"Inclusive Sans\",\"Inconsolata\",\"Inder\",\"Indie Flower\",\"Ingrid Darling\",\"Inika\",\"Inknut Antiqua\",\"Inria Sans\",\"Inria Serif\",\"Inspiration\",\"Instrument Sans\",\"Instrument Serif\",\"Intel One Mono\",\"Inter\",\"Inter Tight\",\"Iosevka Charon\",\"Iosevka Charon Mono\",\"Irish Grover\",\"Island Moments\",\"Istok Web\",\"Italiana\",\"Italianno\",\"Itim\",\"Jacquard 12\",\"Jacquard 12 Charted\",\"Jacquard 24\",\"Jacquard 24 Charted\",\"Jacquarda Bastarda 9\",\"Jacquarda Bastarda 9 Charted\",\"Jacques Francois\",\"Jacques Francois Shadow\",\"Jaini\",\"Jaini Purva\",\"Jaldi\",\"Jaro\",\"Jersey 10\",\"Jersey 10 Charted\",\"Jersey 15\",\"Jersey 15 Charted\",\"Jersey 20\",\"Jersey 20 Charted\",\"Jersey 25\",\"Jersey 25 Charted\",\"JetBrains Mono\",\"Jim Nightshade\",\"Joan\",\"Jockey One\",\"Jolly Lodger\",\"Jomhuria\",\"Jomolhari\",\"Josefin Sans\",\"Josefin Slab\",\"Jost\",\"Joti One\",\"Jua\",\"Judson\",\"Julee\",\"Julius Sans One\",\"Junge\",\"Jura\",\"Just Another Hand\",\"Just Me Again Down Here\",\"K2D\",\"Kablammo\",\"Kadwa\",\"Kaisei Decol\",\"Kaisei HarunoUmi\",\"Kaisei Opti\",\"Kaisei Tokumin\",\"Kalam\",\"Kalnia\",\"Kalnia Glaze\",\"Kameron\",\"Kanchenjunga\",\"Kanit\",\"Kantumruy Pro\",\"Kapakana\",\"Karantina\",\"Karla\",\"Karla Tamil Inclined\",\"Karla Tamil Upright\",\"Karma\",\"Katibeh\",\"Kaushan Script\",\"Kavivanar\",\"Kavoon\",\"Kay Pho Du\",\"Kdam Thmor Pro\",\"Keania One\",\"Kedebideri\",\"Kelly Slab\",\"Kenia\",\"Khand\",\"Khmer\",\"Khula\",\"Kings\",\"Kirang Haerang\",\"Kite One\",\"Kiwi Maru\",\"Klee One\",\"Knewave\",\"Kodchasan\",\"Kode Mono\",\"Koh Santepheap\",\"KoHo\",\"Kolker Brush\",\"Konkhmer Sleokchher\",\"Kosugi\",\"Kosugi Maru\",\"Kotta One\",\"Koulen\",\"Kranky\",\"Kreon\",\"Kristi\",\"Krona One\",\"Krub\",\"Kufam\",\"Kulim Park\",\"Kumar One\",\"Kumar One Outline\",\"Kumbh Sans\",\"Kurale\",\"La Belle Aurore\",\"Labrada\",\"Lacquer\",\"Laila\",\"Lakki Reddy\",\"Lalezar\",\"Lancelot\",\"Langar\",\"Lateef\",\"Lato\",\"Lavishly Yours\",\"League Gothic\",\"League Script\",\"League Spartan\",\"Leckerli One\",\"Ledger\",\"Lekton\",\"Lemon\",\"Lemonada\",\"Lexend\",\"Lexend Deca\",\"Lexend Exa\",\"Lexend Giga\",\"Lexend Mega\",\"Lexend Peta\",\"Lexend Tera\",\"Lexend Zetta\",\"Libertinus Keyboard\",\"Libertinus Math\",\"Libertinus Mono\",\"Libertinus Sans\",\"Libertinus Serif\",\"Libertinus Serif Display\",\"Libre Barcode 128\",\"Libre Barcode 128 Text\",\"Libre Barcode 39\",\"Libre Barcode 39 Extended\",\"Libre Barcode 39 Extended Text\",\"Libre Barcode 39 Text\",\"Libre Barcode EAN13 Text\",\"Libre Baskerville\",\"Libre Bodoni\",\"Libre Caslon Display\",\"Libre Caslon Text\",\"Libre Franklin\",\"Licorice\",\"Life Savers\",\"Lilex\",\"Lilita One\",\"Lily Script One\",\"Limelight\",\"Linden Hill\",\"LINE Seed JP\",\"Linefont\",\"Lisu Bosa\",\"Liter\",\"Literata\",\"Liu Jian Mao Cao\",\"Livvic\",\"Lobster\",\"Lobster Two\",\"Londrina Outline\",\"Londrina Shadow\",\"Londrina Sketch\",\"Londrina Solid\",\"Long Cang\",\"Lora\",\"Love Light\",\"Love Ya Like A Sister\",\"Loved by the King\",\"Lovers Quarrel\",\"Luckiest Guy\",\"Lugrasimo\",\"Lumanosimo\",\"Lunasima\",\"Lusitana\",\"Lustria\",\"Luxurious Roman\",\"Luxurious Script\",\"LXGW Marker Gothic\",\"LXGW WenKai Mono TC\",\"LXGW WenKai TC\",\"M PLUS 1\",\"M PLUS 1 Code\",\"M PLUS 1p\",\"M PLUS 2\",\"M PLUS Code Latin\",\"M PLUS Rounded 1c\",\"M PLUS U\",\"Ma Shan Zheng\",\"Macondo\",\"Macondo Swash Caps\",\"Mada\",\"Madimi One\",\"Magra\",\"Maiden Orange\",\"Maitree\",\"Major Mono Display\",\"Mako\",\"Mali\",\"Mallanna\",\"Maname\",\"Mandali\",\"Manjari\",\"Manrope\",\"Mansalva\",\"Manuale\",\"Manufacturing Consent\",\"Marcellus\",\"Marcellus SC\",\"Marck Script\",\"Margarine\",\"Marhey\",\"Markazi Text\",\"Marko One\",\"Marmelad\",\"Martel\",\"Martel Sans\",\"Martian Mono\",\"Marvel\",\"Matangi\",\"Mate\",\"Mate SC\",\"Matemasie\",\"Maven Pro\",\"McLaren\",\"Mea Culpa\",\"Meddon\",\"MedievalSharp\",\"Medula One\",\"Meera Inimai\",\"Megrim\",\"Meie Script\",\"Menbere\",\"Meow Script\",\"Merienda\",\"Merriweather\",\"Merriweather Sans\",\"Metal\",\"Metal Mania\",\"Metamorphous\",\"Metrophobic\",\"Michroma\",\"Micro 5\",\"Micro 5 Charted\",\"Milonga\",\"Miltonian\",\"Miltonian Tattoo\",\"Mina\",\"Mingzat\",\"Miniver\",\"Miranda Sans\",\"Miriam Libre\",\"Mirza\",\"Miss Fajardose\",\"Mitr\",\"Mochiy Pop One\",\"Mochiy Pop P One\",\"Modak\",\"Modern Antiqua\",\"Moderustic\",\"Mogra\",\"Mohave\",\"Moirai One\",\"Molengo\",\"Molle\",\"Momo Signature\",\"Momo Trust Display\",\"Momo Trust Sans\",\"Mona Sans\",\"Monda\",\"Monofett\",\"Monomakh\",\"Monomaniac One\",\"Monoton\",\"Monsieur La Doulaise\",\"Montaga\",\"Montagu Slab\",\"MonteCarlo\",\"Montez\",\"Montserrat\",\"Montserrat Alternates\",\"Montserrat Underline\",\"Moo Lah Lah\",\"Mooli\",\"Moon Dance\",\"Moul\",\"Moulpali\",\"Mountains of Christmas\",\"Mouse Memoirs\",\"Mozilla Headline\",\"Mozilla Text\",\"Mr Bedfort\",\"Mr Dafoe\",\"Mr De Haviland\",\"Mrs Saint Delafield\",\"Mrs Sheppards\",\"Ms Madi\",\"Mukta\",\"Mukta Mahee\",\"Mukta Malar\",\"Mukta Vaani\",\"Mulish\",\"Murecho\",\"MuseoModerno\",\"My Soul\",\"Mynerve\",\"Mystery Quest\",\"Nabla\",\"Namdhinggo\",\"Nanum Brush Script\",\"Nanum Gothic\",\"Nanum Gothic Coding\",\"Nanum Myeongjo\",\"Nanum Pen Script\",\"Narnoor\",\"Nata Sans\",\"National Park\",\"Neonderthaw\",\"Nerko One\",\"Neucha\",\"Neuton\",\"New Amsterdam\",\"New Rocker\",\"New Tegomin\",\"News Cycle\",\"Newsreader\",\"Niconne\",\"Niramit\",\"Nixie One\",\"Nobile\",\"Nokora\",\"Norican\",\"Nosifer\",\"Notable\",\"Nothing You Could Do\",\"Noticia Text\",\"Noto Color Emoji\",\"Noto Emoji\",\"Noto Kufi Arabic\",\"Noto Music\",\"Noto Naskh Arabic\",\"Noto Nastaliq Urdu\",\"Noto Rashi Hebrew\",\"Noto Sans\",\"Noto Sans Adlam\",\"Noto Sans Adlam Unjoined\",\"Noto Sans Anatolian Hieroglyphs\",\"Noto Sans Arabic\",\"Noto Sans Armenian\",\"Noto Sans Avestan\",\"Noto Sans Balinese\",\"Noto Sans Bamum\",\"Noto Sans Bassa Vah\",\"Noto Sans Batak\",\"Noto Sans Bengali\",\"Noto Sans Bhaiksuki\",\"Noto Sans Brahmi\",\"Noto Sans Buginese\",\"Noto Sans Buhid\",\"Noto Sans Canadian Aboriginal\",\"Noto Sans Carian\",\"Noto Sans Caucasian Albanian\",\"Noto Sans Chakma\",\"Noto Sans Cham\",\"Noto Sans Cherokee\",\"Noto Sans Chorasmian\",\"Noto Sans Coptic\",\"Noto Sans Cuneiform\",\"Noto Sans Cypriot\",\"Noto Sans Cypro Minoan\",\"Noto Sans Deseret\",\"Noto Sans Devanagari\",\"Noto Sans Display\",\"Noto Sans Duployan\",\"Noto Sans Egyptian Hieroglyphs\",\"Noto Sans Elbasan\",\"Noto Sans Elymaic\",\"Noto Sans Ethiopic\",\"Noto Sans Georgian\",\"Noto Sans Glagolitic\",\"Noto Sans Gothic\",\"Noto Sans Grantha\",\"Noto Sans Gujarati\",\"Noto Sans Gunjala Gondi\",\"Noto Sans Gurmukhi\",\"Noto Sans Hanifi Rohingya\",\"Noto Sans Hanunoo\",\"Noto Sans Hatran\",\"Noto Sans Hebrew\",\"Noto Sans HK\",\"Noto Sans Imperial Aramaic\",\"Noto Sans Indic Siyaq Numbers\",\"Noto Sans Inscriptional Pahlavi\",\"Noto Sans Inscriptional Parthian\",\"Noto Sans Javanese\",\"Noto Sans JP\",\"Noto Sans Kaithi\",\"Noto Sans Kannada\",\"Noto Sans Kawi\",\"Noto Sans Kayah Li\",\"Noto Sans Kharoshthi\",\"Noto Sans Khmer\",\"Noto Sans Khojki\",\"Noto Sans Khudawadi\",\"Noto Sans KR\",\"Noto Sans Lao\",\"Noto Sans Lao Looped\",\"Noto Sans Lepcha\",\"Noto Sans Limbu\",\"Noto Sans Linear A\",\"Noto Sans Linear B\",\"Noto Sans Lisu\",\"Noto Sans Lycian\",\"Noto Sans Lydian\",\"Noto Sans Mahajani\",\"Noto Sans Malayalam\",\"Noto Sans Mandaic\",\"Noto Sans Manichaean\",\"Noto Sans Marchen\",\"Noto Sans Masaram Gondi\",\"Noto Sans Math\",\"Noto Sans Mayan Numerals\",\"Noto Sans Medefaidrin\",\"Noto Sans Meetei Mayek\",\"Noto Sans Mende Kikakui\",\"Noto Sans Meroitic\",\"Noto Sans Miao\",\"Noto Sans Modi\",\"Noto Sans Mongolian\",\"Noto Sans Mono\",\"Noto Sans Mro\",\"Noto Sans Multani\",\"Noto Sans Myanmar\",\"Noto Sans Nabataean\",\"Noto Sans Nag Mundari\",\"Noto Sans Nandinagari\",\"Noto Sans New Tai Lue\",\"Noto Sans Newa\",\"Noto Sans NKo\",\"Noto Sans NKo Unjoined\",\"Noto Sans Nushu\",\"Noto Sans Ogham\",\"Noto Sans Ol Chiki\",\"Noto Sans Old Hungarian\",\"Noto Sans Old Italic\",\"Noto Sans Old North Arabian\",\"Noto Sans Old Permic\",\"Noto Sans Old Persian\",\"Noto Sans Old Sogdian\",\"Noto Sans Old South Arabian\",\"Noto Sans Old Turkic\",\"Noto Sans Oriya\",\"Noto Sans Osage\",\"Noto Sans Osmanya\",\"Noto Sans Pahawh Hmong\",\"Noto Sans Palmyrene\",\"Noto Sans Pau Cin Hau\",\"Noto Sans PhagsPa\",\"Noto Sans Phoenician\",\"Noto Sans Psalter Pahlavi\",\"Noto Sans Rejang\",\"Noto Sans Runic\",\"Noto Sans Samaritan\",\"Noto Sans Saurashtra\",\"Noto Sans SC\",\"Noto Sans Sharada\",\"Noto Sans Shavian\",\"Noto Sans Siddham\",\"Noto Sans SignWriting\",\"Noto Sans Sinhala\",\"Noto Sans Sogdian\",\"Noto Sans Sora Sompeng\",\"Noto Sans Soyombo\",\"Noto Sans Sundanese\",\"Noto Sans Sunuwar\",\"Noto Sans Syloti Nagri\",\"Noto Sans Symbols\",\"Noto Sans Symbols 2\",\"Noto Sans Syriac\",\"Noto Sans Syriac Eastern\",\"Noto Sans Syriac Western\",\"Noto Sans Tagalog\",\"Noto Sans Tagbanwa\",\"Noto Sans Tai Le\",\"Noto Sans Tai Tham\",\"Noto Sans Tai Viet\",\"Noto Sans Takri\",\"Noto Sans Tamil\",\"Noto Sans Tamil Supplement\",\"Noto Sans Tangsa\",\"Noto Sans TC\",\"Noto Sans Telugu\",\"Noto Sans Thaana\",\"Noto Sans Thai\",\"Noto Sans Thai Looped\",\"Noto Sans Tifinagh\",\"Noto Sans Tirhuta\",\"Noto Sans Ugaritic\",\"Noto Sans Vai\",\"Noto Sans Vithkuqi\",\"Noto Sans Wancho\",\"Noto Sans Warang Citi\",\"Noto Sans Yi\",\"Noto Sans Zanabazar Square\",\"Noto Serif\",\"Noto Serif Ahom\",\"Noto Serif Armenian\",\"Noto Serif Balinese\",\"Noto Serif Bengali\",\"Noto Serif Devanagari\",\"Noto Serif Display\",\"Noto Serif Dives Akuru\",\"Noto Serif Dogra\",\"Noto Serif Ethiopic\",\"Noto Serif Georgian\",\"Noto Serif Grantha\",\"Noto Serif Gujarati\",\"Noto Serif Gurmukhi\",\"Noto Serif Hebrew\",\"Noto Serif Hentaigana\",\"Noto Serif HK\",\"Noto Serif JP\",\"Noto Serif Kannada\",\"Noto Serif Khitan Small Script\",\"Noto Serif Khmer\",\"Noto Serif Khojki\",\"Noto Serif KR\",\"Noto Serif Lao\",\"Noto Serif Makasar\",\"Noto Serif Malayalam\",\"Noto Serif Myanmar\",\"Noto Serif NP Hmong\",\"Noto Serif Old Uyghur\",\"Noto Serif Oriya\",\"Noto Serif Ottoman Siyaq\",\"Noto Serif SC\",\"Noto Serif Sinhala\",\"Noto Serif Tamil\",\"Noto Serif Tangut\",\"Noto Serif TC\",\"Noto Serif Telugu\",\"Noto Serif Thai\",\"Noto Serif Tibetan\",\"Noto Serif Todhri\",\"Noto Serif Toto\",\"Noto Serif Vithkuqi\",\"Noto Serif Yezidi\",\"Noto Traditional Nushu\",\"Noto Znamenny Musical Notation\",\"Nova Cut\",\"Nova Flat\",\"Nova Mono\",\"Nova Oval\",\"Nova Round\",\"Nova Script\",\"Nova Slim\",\"Nova Square\",\"NTR\",\"Numans\",\"Nunito\",\"Nunito Sans\",\"Nuosu SIL\",\"Odibee Sans\",\"Odor Mean Chey\",\"Offside\",\"Oi\",\"Ojuju\",\"Old Standard TT\",\"Oldenburg\",\"Ole\",\"Oleo Script\",\"Oleo Script Swash Caps\",\"Onest\",\"Oooh Baby\",\"Open Sans\",\"Oranienbaum\",\"Orbit\",\"Orbitron\",\"Oregano\",\"Orelega One\",\"Orienta\",\"Original Surfer\",\"Oswald\",\"Outfit\",\"Over the Rainbow\",\"Overlock\",\"Overlock SC\",\"Overpass\",\"Overpass Mono\",\"Ovo\",\"Oxanium\",\"Oxygen\",\"Oxygen Mono\",\"Pacifico\",\"Padauk\",\"Padyakke Expanded One\",\"Palanquin\",\"Palanquin Dark\",\"Palette Mosaic\",\"Pangolin\",\"Paprika\",\"Parastoo\",\"Parisienne\",\"Parkinsans\",\"Passero One\",\"Passion One\",\"Passions Conflict\",\"Pathway Extreme\",\"Pathway Gothic One\",\"Patrick Hand\",\"Patrick Hand SC\",\"Pattaya\",\"Patua One\",\"Pavanam\",\"Paytone One\",\"Peddana\",\"Peralta\",\"Permanent Marker\",\"Petemoss\",\"Petit Formal Script\",\"Petrona\",\"Phetsarath\",\"Philosopher\",\"Phudu\",\"Piazzolla\",\"Piedra\",\"Pinyon Script\",\"Pirata One\",\"Pixelify Sans\",\"Plaster\",\"Platypi\",\"Play\",\"Playball\",\"Playfair\",\"Playfair Display\",\"Playfair Display SC\",\"Playpen Sans\",\"Playpen Sans Arabic\",\"Playpen Sans Deva\",\"Playpen Sans Hebrew\",\"Playpen Sans Thai\",\"Playwrite AR\",\"Playwrite AR Guides\",\"Playwrite AT\",\"Playwrite AT Guides\",\"Playwrite AU NSW\",\"Playwrite AU NSW Guides\",\"Playwrite AU QLD\",\"Playwrite AU QLD Guides\",\"Playwrite AU SA\",\"Playwrite AU SA Guides\",\"Playwrite AU TAS\",\"Playwrite AU TAS Guides\",\"Playwrite AU VIC\",\"Playwrite AU VIC Guides\",\"Playwrite BE VLG\",\"Playwrite BE VLG Guides\",\"Playwrite BE WAL\",\"Playwrite BE WAL Guides\",\"Playwrite BR\",\"Playwrite BR Guides\",\"Playwrite CA\",\"Playwrite CA Guides\",\"Playwrite CL\",\"Playwrite CL Guides\",\"Playwrite CO\",\"Playwrite CO Guides\",\"Playwrite CU\",\"Playwrite CU Guides\",\"Playwrite CZ\",\"Playwrite CZ Guides\",\"Playwrite DE Grund\",\"Playwrite DE Grund Guides\",\"Playwrite DE LA\",\"Playwrite DE LA Guides\",\"Playwrite DE SAS\",\"Playwrite DE SAS Guides\",\"Playwrite DE VA\",\"Playwrite DE VA Guides\",\"Playwrite DK Loopet\",\"Playwrite DK Loopet Guides\",\"Playwrite DK Uloopet\",\"Playwrite DK Uloopet Guides\",\"Playwrite ES\",\"Playwrite ES Deco\",\"Playwrite ES Deco Guides\",\"Playwrite ES Guides\",\"Playwrite FR Moderne\",\"Playwrite FR Moderne Guides\",\"Playwrite FR Trad\",\"Playwrite FR Trad Guides\",\"Playwrite GB J\",\"Playwrite GB J Guides\",\"Playwrite GB S\",\"Playwrite GB S Guides\",\"Playwrite HR\",\"Playwrite HR Guides\",\"Playwrite HR Lijeva\",\"Playwrite HR Lijeva Guides\",\"Playwrite HU\",\"Playwrite HU Guides\",\"Playwrite ID\",\"Playwrite ID Guides\",\"Playwrite IE\",\"Playwrite IE Guides\",\"Playwrite IN\",\"Playwrite IN Guides\",\"Playwrite IS\",\"Playwrite IS Guides\",\"Playwrite IT Moderna\",\"Playwrite IT Moderna Guides\",\"Playwrite IT Trad\",\"Playwrite IT Trad Guides\",\"Playwrite MX\",\"Playwrite MX Guides\",\"Playwrite NG Modern\",\"Playwrite NG Modern Guides\",\"Playwrite NL\",\"Playwrite NL Guides\",\"Playwrite NO\",\"Playwrite NO Guides\",\"Playwrite NZ\",\"Playwrite NZ Basic\",\"Playwrite NZ Basic Guides\",\"Playwrite NZ Guides\",\"Playwrite PE\",\"Playwrite PE Guides\",\"Playwrite PL\",\"Playwrite PL Guides\",\"Playwrite PT\",\"Playwrite PT Guides\",\"Playwrite RO\",\"Playwrite RO Guides\",\"Playwrite SK\",\"Playwrite SK Guides\",\"Playwrite TZ\",\"Playwrite TZ Guides\",\"Playwrite US Modern\",\"Playwrite US Modern Guides\",\"Playwrite US Trad\",\"Playwrite US Trad Guides\",\"Playwrite VN\",\"Playwrite VN Guides\",\"Playwrite ZA\",\"Playwrite ZA Guides\",\"Plus Jakarta Sans\",\"Pochaevsk\",\"Podkova\",\"Poetsen One\",\"Poiret One\",\"Poller One\",\"Poltawski Nowy\",\"Poly\",\"Pompiere\",\"Ponnala\",\"Ponomar\",\"Pontano Sans\",\"Poor Story\",\"Poppins\",\"Port Lligat Sans\",\"Port Lligat Slab\",\"Potta One\",\"Pragati Narrow\",\"Praise\",\"Prata\",\"Preahvihear\",\"Press Start 2P\",\"Pridi\",\"Princess Sofia\",\"Prociono\",\"Prompt\",\"Prosto One\",\"Protest Guerrilla\",\"Protest Revolution\",\"Protest Riot\",\"Protest Strike\",\"Proza Libre\",\"PT Mono\",\"PT Sans\",\"PT Sans Caption\",\"PT Sans Narrow\",\"PT Serif\",\"PT Serif Caption\",\"Public Sans\",\"Puppies Play\",\"Puritan\",\"Purple Purse\",\"Qahiri\",\"Quando\",\"Quantico\",\"Quattrocento\",\"Quattrocento Sans\",\"Questrial\",\"Quicksand\",\"Quintessential\",\"Qwigley\",\"Qwitcher Grypen\",\"Racing Sans One\",\"Radio Canada\",\"Radio Canada Big\",\"Radley\",\"Rajdhani\",\"Rakkas\",\"Raleway\",\"Raleway Dots\",\"Ramabhadra\",\"Ramaraja\",\"Rambla\",\"Rammetto One\",\"Rampart One\",\"Ramsina\",\"Ranchers\",\"Rancho\",\"Ranga\",\"Rasa\",\"Rationale\",\"Ravi Prakash\",\"Readex Pro\",\"Recursive\",\"Red Hat Display\",\"Red Hat Mono\",\"Red Hat Text\",\"Red Rose\",\"Redacted\",\"Redacted Script\",\"Reddit Mono\",\"Reddit Sans\",\"Reddit Sans Condensed\",\"Redressed\",\"Reem Kufi\",\"Reem Kufi Fun\",\"Reem Kufi Ink\",\"Reenie Beanie\",\"Reggae One\",\"REM\",\"Rethink Sans\",\"Revalia\",\"Rhodium Libre\",\"Ribeye\",\"Ribeye Marrow\",\"Righteous\",\"Risque\",\"Road Rage\",\"Roboto\",\"Roboto Condensed\",\"Roboto Flex\",\"Roboto Mono\",\"Roboto Serif\",\"Roboto Slab\",\"Rochester\",\"Rock 3D\",\"Rock Salt\",\"RocknRoll One\",\"Rokkitt\",\"Romanesco\",\"Ropa Sans\",\"Rosario\",\"Rosarivo\",\"Rouge Script\",\"Rowdies\",\"Rozha One\",\"Rubik\",\"Rubik 80s Fade\",\"Rubik Beastly\",\"Rubik Broken Fax\",\"Rubik Bubbles\",\"Rubik Burned\",\"Rubik Dirt\",\"Rubik Distressed\",\"Rubik Doodle Shadow\",\"Rubik Doodle Triangles\",\"Rubik Gemstones\",\"Rubik Glitch\",\"Rubik Glitch Pop\",\"Rubik Iso\",\"Rubik Lines\",\"Rubik Maps\",\"Rubik Marker Hatch\",\"Rubik Maze\",\"Rubik Microbe\",\"Rubik Mono One\",\"Rubik Moonrocks\",\"Rubik Pixels\",\"Rubik Puddles\",\"Rubik Scribble\",\"Rubik Spray Paint\",\"Rubik Storm\",\"Rubik Vinyl\",\"Rubik Wet Paint\",\"Ruda\",\"Rufina\",\"Ruge Boogie\",\"Ruluko\",\"Rum Raisin\",\"Ruslan Display\",\"Russo One\",\"Ruthie\",\"Ruwudu\",\"Rye\",\"Sacramento\",\"Sahitya\",\"Sail\",\"Saira\",\"Saira Condensed\",\"Saira Extra Condensed\",\"Saira Semi Condensed\",\"Saira Stencil\",\"Salsa\",\"Sanchez\",\"Sancreek\",\"Sankofa Display\",\"Sansation\",\"Sansita\",\"Sansita Swashed\",\"Sarabun\",\"Sarala\",\"Sarina\",\"Sarpanch\",\"Sassy Frass\",\"Satisfy\",\"Savate\",\"Sawarabi Gothic\",\"Sawarabi Mincho\",\"Scada\",\"Scheherazade New\",\"Schibsted Grotesk\",\"Schoolbell\",\"Science Gothic\",\"Scope One\",\"Seaweed Script\",\"Secular One\",\"Sedan\",\"Sedan SC\",\"Sedgwick Ave\",\"Sedgwick Ave Display\",\"Sekuya\",\"Sen\",\"Send Flowers\",\"Sevillana\",\"Seymour One\",\"Shadows Into Light\",\"Shadows Into Light Two\",\"Shafarik\",\"Shalimar\",\"Shantell Sans\",\"Shanti\",\"Share\",\"Share Tech\",\"Share Tech Mono\",\"Shippori Antique\",\"Shippori Antique B1\",\"Shippori Mincho\",\"Shippori Mincho B1\",\"Shizuru\",\"Shojumaru\",\"Short Stack\",\"Shrikhand\",\"Siemreap\",\"Sigmar\",\"Sigmar One\",\"Signika\",\"Signika Negative\",\"Silkscreen\",\"Simonetta\",\"Single Day\",\"Sintony\",\"Sirin Stencil\",\"Sirivennela\",\"Six Caps\",\"Sixtyfour\",\"Sixtyfour Convergence\",\"Skranji\",\"Slabo 13px\",\"Slabo 27px\",\"Slackey\",\"Slackside One\",\"Smokum\",\"Smooch\",\"Smooch Sans\",\"Smythe\",\"SN Pro\",\"Sniglet\",\"Snippet\",\"Snowburst One\",\"Sofadi One\",\"Sofia\",\"Sofia Sans\",\"Sofia Sans Condensed\",\"Sofia Sans Extra Condensed\",\"Sofia Sans Semi Condensed\",\"Solitreo\",\"Solway\",\"Sometype Mono\",\"Song Myung\",\"Sono\",\"Sonsie One\",\"Sora\",\"Sorts Mill Goudy\",\"Sour Gummy\",\"Source Code Pro\",\"Source Sans 3\",\"Source Serif 4\",\"Space Grotesk\",\"Space Mono\",\"Special Elite\",\"Special Gothic\",\"Special Gothic Condensed One\",\"Special Gothic Expanded One\",\"Spectral\",\"Spectral SC\",\"Spicy Rice\",\"Spinnaker\",\"Spirax\",\"Splash\",\"Spline Sans\",\"Spline Sans Mono\",\"Squada One\",\"Square Peg\",\"Sree Krushnadevaraya\",\"Sriracha\",\"Srisakdi\",\"Staatliches\",\"Stack Sans Headline\",\"Stack Sans Notch\",\"Stack Sans Text\",\"Stalemate\",\"Stalinist One\",\"Stardos Stencil\",\"Stick\",\"Stick No Bills\",\"Stint Ultra Condensed\",\"Stint Ultra Expanded\",\"STIX Two Math\",\"STIX Two Text\",\"Stoke\",\"Story Script\",\"Strait\",\"Strichpunkt Sans\",\"Style Script\",\"Stylish\",\"Sue Ellen Francisco\",\"Suez One\",\"Sulphur Point\",\"Sumana\",\"Sunflower\",\"Sunshiney\",\"Supermercado One\",\"Sura\",\"Suranna\",\"Suravaram\",\"SUSE\",\"SUSE Mono\",\"Suwannaphum\",\"Swanky and Moo Moo\",\"Syncopate\",\"Syne\",\"Syne Mono\",\"Syne Tactile\",\"Tac One\",\"Tagesschrift\",\"Tai Heritage Pro\",\"Tajawal\",\"Tangerine\",\"Tapestry\",\"Taprom\",\"TASA Explorer\",\"TASA Orbiter\",\"Tauri\",\"Taviraj\",\"Teachers\",\"Teko\",\"Tektur\",\"Telex\",\"Tenali Ramakrishna\",\"Tenor Sans\",\"Text Me One\",\"Texturina\",\"Thasadith\",\"The Girl Next Door\",\"The Nautigal\",\"Tienne\",\"TikTok Sans\",\"Tillana\",\"Tilt Neon\",\"Tilt Prism\",\"Tilt Warp\",\"Timmana\",\"Tinos\",\"Tiny5\",\"Tiro Bangla\",\"Tiro Devanagari Hindi\",\"Tiro Devanagari Marathi\",\"Tiro Devanagari Sanskrit\",\"Tiro Gurmukhi\",\"Tiro Kannada\",\"Tiro Tamil\",\"Tiro Telugu\",\"Tirra\",\"Titan One\",\"Titillium Web\",\"Tomorrow\",\"Tourney\",\"Trade Winds\",\"Train One\",\"Triodion\",\"Trirong\",\"Trispace\",\"Trocchi\",\"Trochut\",\"Truculenta\",\"Trykker\",\"Tsukimi Rounded\",\"Tuffy\",\"Tulpen One\",\"Turret Road\",\"Twinkle Star\",\"Ubuntu\",\"Ubuntu Condensed\",\"Ubuntu Mono\",\"Ubuntu Sans\",\"Ubuntu Sans Mono\",\"Uchen\",\"Ultra\",\"Unbounded\",\"Uncial Antiqua\",\"Underdog\",\"Unica One\",\"UnifrakturCook\",\"UnifrakturMaguntia\",\"Unkempt\",\"Unlock\",\"Unna\",\"UoqMunThenKhung\",\"Updock\",\"Urbanist\",\"Vampiro One\",\"Varela\",\"Varela Round\",\"Varta\",\"Vast Shadow\",\"Vazirmatn\",\"Vend Sans\",\"Vesper Libre\",\"Viaoda Libre\",\"Vibes\",\"Vibur\",\"Victor Mono\",\"Vidaloka\",\"Viga\",\"Vina Sans\",\"Voces\",\"Volkhov\",\"Vollkorn\",\"Vollkorn SC\",\"Voltaire\",\"VT323\",\"Vujahday Script\",\"Waiting for the Sunrise\",\"Wallpoet\",\"Walter Turncoat\",\"Warnes\",\"Water Brush\",\"Waterfall\",\"Wavefont\",\"WDXL Lubrifont JP N\",\"WDXL Lubrifont SC\",\"WDXL Lubrifont TC\",\"Wellfleet\",\"Wendy One\",\"Whisper\",\"WindSong\",\"Winky Rough\",\"Winky Sans\",\"Wire One\",\"Wittgenstein\",\"Wix Madefor Display\",\"Wix Madefor Text\",\"Work Sans\",\"Workbench\",\"Xanh Mono\",\"Yaldevi\",\"Yanone Kaffeesatz\",\"Yantramanav\",\"Yarndings 12\",\"Yarndings 12 Charted\",\"Yarndings 20\",\"Yarndings 20 Charted\",\"Yatra One\",\"Yellowtail\",\"Yeon Sung\",\"Yeseva One\",\"Yesteryear\",\"Yomogi\",\"Young Serif\",\"Yrsa\",\"Ysabeau\",\"Ysabeau Infant\",\"Ysabeau Office\",\"Ysabeau SC\",\"Yuji Boku\",\"Yuji Hentaigana Akari\",\"Yuji Hentaigana Akebono\",\"Yuji Mai\",\"Yuji Syuku\",\"Yusei Magic\",\"Zain\",\"Zalando Sans\",\"Zalando Sans Expanded\",\"Zalando Sans SemiExpanded\",\"ZCOOL KuaiLe\",\"ZCOOL QingKe HuangYou\",\"ZCOOL XiaoWei\",\"Zen Antique\",\"Zen Antique Soft\",\"Zen Dots\",\"Zen Kaku Gothic Antique\",\"Zen Kaku Gothic New\",\"Zen Kurenaido\",\"Zen Loop\",\"Zen Maru Gothic\",\"Zen Old Mincho\",\"Zen Tokyo Zoo\",\"Zeyada\",\"Zhi Mang Xing\",\"Zilla Slab\",\"Zilla Slab Highlight\"];\n\nexport const GOOGLE_FONT_WEIGHTS: Record<string, number[]> = {\"ABeeZee\":[400],\"Abel\":[400],\"Abhaya Libre\":[400,500,600,700,800],\"Aboreto\":[400],\"Abril Fatface\":[400],\"Abyssinica SIL\":[400],\"Aclonica\":[400],\"Acme\":[400],\"Actor\":[400],\"Adamina\":[400],\"ADLaM Display\":[400],\"Advent Pro\":[100,200,300,400,500,600,700,800,900],\"Afacad\":[400,500,600,700],\"Afacad Flux\":[100,200,300,400,500,600,700,800,900],\"Agbalumo\":[400],\"Agdasima\":[400,700],\"Agu Display\":[400],\"Aguafina Script\":[400],\"Akatab\":[400,500,600,700,800,900],\"Akaya Kanadaka\":[400],\"Akaya Telivigala\":[400],\"Akronim\":[400],\"Akshar\":[300,400,500,600,700],\"Akt\":[100,200,300,400,500,600,700,800,900],\"Aladin\":[400],\"Alan Sans\":[300,400,500,600,700,800,900],\"Alata\":[400],\"Alatsi\":[400],\"Albert Sans\":[100,200,300,400,500,600,700,800,900],\"Aldrich\":[400],\"Alef\":[400,700],\"Alegreya\":[400,500,600,700,800,900],\"Alegreya Sans\":[100,300,400,500,700,800,900],\"Alegreya Sans SC\":[100,300,400,500,700,800,900],\"Alegreya SC\":[400,500,700,800,900],\"Aleo\":[100,200,300,400,500,600,700,800,900],\"Alex Brush\":[400],\"Alexandria\":[100,200,300,400,500,600,700,800,900],\"Alfa Slab One\":[400],\"Alice\":[400],\"Alike\":[400],\"Alike Angular\":[400],\"Alkalami\":[400],\"Alkatra\":[400,500,600,700],\"Allan\":[400,700],\"Allerta\":[400],\"Allerta Stencil\":[400],\"Allison\":[400],\"Allkin\":[400],\"Allura\":[400],\"Almarai\":[300,400,700,800],\"Almendra\":[400,700],\"Almendra Display\":[400],\"Almendra SC\":[400],\"Alumni Sans\":[100,200,300,400,500,600,700,800,900],\"Alumni Sans Collegiate One\":[400],\"Alumni Sans Inline One\":[400],\"Alumni Sans Pinstripe\":[400],\"Alumni Sans SC\":[100,200,300,400,500,600,700,800,900],\"Alyamama\":[300,400,500,600,700,800,900],\"Amarante\":[400],\"Amaranth\":[400,700],\"Amarna\":[100,200,300,400,500,600,700],\"Amatic SC\":[400,700],\"Amethysta\":[400],\"Amiko\":[400,600,700],\"Amiri\":[400,700],\"Amiri Quran\":[400],\"Amita\":[400,700],\"Anaheim\":[400,500,600,700,800],\"Ancizar Sans\":[100,200,300,400,500,600,700,800,900],\"Ancizar Serif\":[300,400,500,600,700,800,900],\"Andada Pro\":[400,500,600,700,800],\"Andika\":[400,700],\"Anek Bangla\":[100,200,300,400,500,600,700,800],\"Anek Devanagari\":[100,200,300,400,500,600,700,800],\"Anek Gujarati\":[100,200,300,400,500,600,700,800],\"Anek Gurmukhi\":[100,200,300,400,500,600,700,800],\"Anek Kannada\":[100,200,300,400,500,600,700,800],\"Anek Latin\":[100,200,300,400,500,600,700,800],\"Anek Malayalam\":[100,200,300,400,500,600,700,800],\"Anek Odia\":[100,200,300,400,500,600,700,800],\"Anek Tamil\":[100,200,300,400,500,600,700,800],\"Anek Telugu\":[100,200,300,400,500,600,700,800],\"Angkor\":[400],\"Annapurna SIL\":[400,700],\"Annie Use Your Telescope\":[400],\"Anonymous Pro\":[400,700],\"Anta\":[400],\"Antic\":[400],\"Antic Didone\":[400],\"Antic Slab\":[400],\"Anton\":[400],\"Anton SC\":[400],\"Antonio\":[100,200,300,400,500,600,700],\"Anuphan\":[100,200,300,400,500,600,700],\"Anybody\":[100,200,300,400,500,600,700,800,900],\"Aoboshi One\":[400],\"AR One Sans\":[400,500,600,700],\"Arapey\":[400],\"Arbutus\":[400],\"Arbutus Slab\":[400],\"Architects Daughter\":[400],\"Archivo\":[100,200,300,400,500,600,700,800,900],\"Archivo Black\":[400],\"Archivo Narrow\":[400,500,600,700],\"Are You Serious\":[400],\"Aref Ruqaa\":[400,700],\"Aref Ruqaa Ink\":[400,700],\"Arima\":[100,200,300,400,500,600,700],\"Arimo\":[400,500,600,700],\"Arizonia\":[400],\"Armata\":[400],\"Arsenal\":[400,700],\"Arsenal SC\":[400,700],\"Artifika\":[400],\"Arvo\":[400,700],\"Arya\":[400,700],\"Asap\":[100,200,300,400,500,600,700,800,900],\"Asap Condensed\":[200,300,400,500,600,700,800,900],\"Asar\":[400],\"Asimovian\":[400],\"Asset\":[400],\"Assistant\":[200,300,400,500,600,700,800],\"Asta Sans\":[300,400,500,600,700,800],\"Astloch\":[400,700],\"Asul\":[400,700],\"Athiti\":[200,300,400,500,600,700],\"Atkinson Hyperlegible\":[400,700],\"Atkinson Hyperlegible Mono\":[200,300,400,500,600,700,800],\"Atkinson Hyperlegible Next\":[200,300,400,500,600,700,800],\"Atma\":[300,400,500,600,700],\"Atomic Age\":[400],\"Aubrey\":[400],\"Audiowide\":[400],\"Autour One\":[400],\"Average\":[400],\"Average Sans\":[400],\"Averia Gruesa Libre\":[400],\"Averia Libre\":[300,400,700],\"Averia Sans Libre\":[300,400,700],\"Averia Serif Libre\":[300,400,700],\"Azeret Mono\":[100,200,300,400,500,600,700,800,900],\"B612\":[400,700],\"B612 Mono\":[400,700],\"Babylonica\":[400],\"Bacasime Antique\":[400],\"Bad Script\":[400],\"Badeen Display\":[400],\"Bagel Fat One\":[400],\"Bahiana\":[400],\"Bahianita\":[400],\"Bai Jamjuree\":[200,300,400,500,600,700],\"Bakbak One\":[400],\"Ballet\":[400],\"Baloo 2\":[400,500,600,700,800],\"Baloo Bhai 2\":[400,500,600,700,800],\"Baloo Bhaijaan 2\":[400,500,600,700,800],\"Baloo Bhaina 2\":[400,500,600,700,800],\"Baloo Chettan 2\":[400,500,600,700,800],\"Baloo Da 2\":[400,500,600,700,800],\"Baloo Paaji 2\":[400,500,600,700,800],\"Baloo Tamma 2\":[400,500,600,700,800],\"Baloo Tammudu 2\":[400,500,600,700,800],\"Baloo Thambi 2\":[400,500,600,700,800],\"Balsamiq Sans\":[400,700],\"Balthazar\":[400],\"Bangers\":[400],\"Barlow\":[100,200,300,400,500,600,700,800,900],\"Barlow Condensed\":[100,200,300,400,500,600,700,800,900],\"Barlow Semi Condensed\":[100,200,300,400,500,600,700,800,900],\"Barriecito\":[400],\"Barrio\":[400],\"Basic\":[400],\"Baskervville\":[400,500,600,700],\"Baskervville SC\":[400,500,600,700],\"Battambang\":[100,300,400,700,900],\"Baumans\":[400],\"Bayon\":[400],\"BBH Bartle\":[400],\"BBH Bogle\":[400],\"BBH Hegarty\":[400],\"Be Vietnam Pro\":[100,200,300,400,500,600,700,800,900],\"Beau Rivage\":[400],\"Bebas Neue\":[400],\"Beiruti\":[200,300,400,500,600,700,800,900],\"Belanosima\":[400,600,700],\"Belgrano\":[400],\"Bellefair\":[400],\"Belleza\":[400],\"Bellota\":[300,400,700],\"Bellota Text\":[300,400,700],\"BenchNine\":[300,400,700],\"Benne\":[400],\"Bentham\":[400],\"Berkshire Swash\":[400],\"Besley\":[400,500,600,700,800,900],\"Betania Patmos\":[400],\"Betania Patmos GDL\":[400],\"Betania Patmos In\":[400],\"Betania Patmos In GDL\":[400],\"Beth Ellen\":[400],\"Bevan\":[400],\"BhuTuka Expanded One\":[400],\"Big Shoulders\":[100,200,300,400,500,600,700,800,900],\"Big Shoulders Inline\":[100,200,300,400,500,600,700,800,900],\"Big Shoulders Stencil\":[100,200,300,400,500,600,700,800,900],\"Bigelow Rules\":[400],\"Bigshot One\":[400],\"Bilbo\":[400],\"Bilbo Swash Caps\":[400],\"BioRhyme\":[200,300,400,500,600,700,800],\"BioRhyme Expanded\":[200,300,400,700,800],\"Birthstone\":[400],\"Birthstone Bounce\":[400,500],\"Biryani\":[200,300,400,600,700,800,900],\"Bitcount\":[100,200,300,400,500,600,700,800,900],\"Bitcount Grid Double\":[100,200,300,400,500,600,700,800,900],\"Bitcount Grid Double Ink\":[100,200,300,400,500,600,700,800,900],\"Bitcount Grid Single\":[100,200,300,400,500,600,700,800,900],\"Bitcount Grid Single Ink\":[100,200,300,400,500,600,700,800,900],\"Bitcount Ink\":[100,200,300,400,500,600,700,800,900],\"Bitcount Prop Double\":[100,200,300,400,500,600,700,800,900],\"Bitcount Prop Double Ink\":[100,200,300,400,500,600,700,800,900],\"Bitcount Prop Single\":[100,200,300,400,500,600,700,800,900],\"Bitcount Prop Single Ink\":[100,200,300,400,500,600,700,800,900],\"Bitcount Single\":[100,200,300,400,500,600,700,800,900],\"Bitcount Single Ink\":[100,200,300,400,500,600,700,800,900],\"Bitter\":[100,200,300,400,500,600,700,800,900],\"BIZ UDGothic\":[400,700],\"BIZ UDMincho\":[400,700],\"BIZ UDPGothic\":[400,700],\"BIZ UDPMincho\":[400,700],\"BJCree\":[400,500,600,700],\"Black And White Picture\":[400],\"Black Han Sans\":[400],\"Black Ops One\":[400],\"Blaka\":[400],\"Blaka Hollow\":[400],\"Blaka Ink\":[400],\"Blinker\":[100,200,300,400,600,700,800,900],\"Bodoni Moda\":[400,500,600,700,800,900],\"Bodoni Moda SC\":[400,500,600,700,800,900],\"Bokor\":[400],\"Boldonse\":[400],\"Bona Nova\":[400,700],\"Bona Nova SC\":[400,700],\"Bonbon\":[400],\"Bonheur Royale\":[400],\"Boogaloo\":[400],\"Borel\":[400],\"Bowlby One\":[400],\"Bowlby One SC\":[400],\"Bpmf Huninn\":[400],\"Bpmf Iansui\":[400],\"Bpmf Zihi Kai Std\":[400],\"Braah One\":[400],\"Brawler\":[400,700],\"Bree Serif\":[400],\"Bricolage Grotesque\":[200,300,400,500,600,700,800],\"Bruno Ace\":[400],\"Bruno Ace SC\":[400],\"Brygada 1918\":[400,500,600,700],\"Bubblegum Sans\":[400],\"Bubbler One\":[400],\"Buda\":[300],\"Buenard\":[400,500,600,700],\"Bungee\":[400],\"Bungee Hairline\":[400],\"Bungee Inline\":[400],\"Bungee Outline\":[400],\"Bungee Shade\":[400],\"Bungee Spice\":[400],\"Bungee Tint\":[400],\"Butcherman\":[400],\"Butterfly Kids\":[400],\"Bytesized\":[400],\"Cabin\":[400,500,600,700],\"Cabin Condensed\":[400,500,600,700],\"Cabin Sketch\":[400,700],\"Cactus Classical Serif\":[400],\"Caesar Dressing\":[400],\"Cagliostro\":[400],\"Cairo\":[100,200,300,400,500,600,700,800,900],\"Cairo Play\":[100,200,300,400,500,600,700,800,900],\"Cal Sans\":[400],\"Caladea\":[400,700],\"Calistoga\":[400],\"Calligraffitti\":[400],\"Cambay\":[400,700],\"Cambo\":[400],\"Candal\":[400],\"Cantarell\":[400,700],\"Cantata One\":[400],\"Cantora One\":[400],\"Caprasimo\":[400],\"Capriola\":[400],\"Caramel\":[400],\"Carattere\":[400],\"Cardo\":[400,700],\"Carlito\":[400,700],\"Carme\":[400],\"Carrois Gothic\":[400],\"Carrois Gothic SC\":[400],\"Carter One\":[400],\"Cascadia Code\":[200,300,400,500,600,700],\"Cascadia Mono\":[200,300,400,500,600,700],\"Castoro\":[400],\"Castoro Titling\":[400],\"Catamaran\":[100,200,300,400,500,600,700,800,900],\"Caudex\":[400,700],\"Cause\":[100,200,300,400,500,600,700,800,900],\"Caveat\":[400,500,600,700],\"Caveat Brush\":[400],\"Cedarville Cursive\":[400],\"Ceviche One\":[400],\"Chakra Petch\":[300,400,500,600,700],\"Changa\":[200,300,400,500,600,700,800],\"Changa One\":[400],\"Chango\":[400],\"Charis SIL\":[400,700],\"Charm\":[400,700],\"Charmonman\":[400,700],\"Chathura\":[100,300,400,700,800],\"Chau Philomene One\":[400],\"Chela One\":[400],\"Chelsea Market\":[400],\"Chenla\":[400],\"Cherish\":[400],\"Cherry Bomb One\":[400],\"Cherry Cream Soda\":[400],\"Cherry Swash\":[400,700],\"Chewy\":[400],\"Chicle\":[400],\"Chilanka\":[400],\"Chiron GoRound TC\":[200,300,400,500,600,700,800,900],\"Chiron Hei HK\":[200,300,400,500,600,700,800,900],\"Chiron Sung HK\":[200,300,400,500,600,700,800,900],\"Chivo\":[100,200,300,400,500,600,700,800,900],\"Chivo Mono\":[100,200,300,400,500,600,700,800,900],\"Chocolate Classical Sans\":[400],\"Chokokutai\":[400],\"Chonburi\":[400],\"Cinzel\":[400,500,600,700,800,900],\"Cinzel Decorative\":[400,700,900],\"Clicker Script\":[400],\"Climate Crisis\":[400],\"Coda\":[400,800],\"Codystar\":[300,400],\"Coiny\":[400],\"Combo\":[400],\"Comfortaa\":[300,400,500,600,700],\"Comforter\":[400],\"Comforter Brush\":[400],\"Comic Neue\":[300,400,700],\"Comic Relief\":[400,700],\"Coming Soon\":[400],\"Comme\":[100,200,300,400,500,600,700,800,900],\"Commissioner\":[100,200,300,400,500,600,700,800,900],\"Concert One\":[400],\"Condiment\":[400],\"Content\":[400,700],\"Contrail One\":[400],\"Convergence\":[400],\"Cookie\":[400],\"Copse\":[400],\"Coral Pixels\":[400],\"Corben\":[400,700],\"Corinthia\":[400,700],\"Cormorant\":[300,400,500,600,700],\"Cormorant Garamond\":[300,400,500,600,700],\"Cormorant Infant\":[300,400,500,600,700],\"Cormorant SC\":[300,400,500,600,700],\"Cormorant Unicase\":[300,400,500,600,700],\"Cormorant Upright\":[300,400,500,600,700],\"Cossette Texte\":[400,700],\"Cossette Titre\":[400,700],\"Courgette\":[400],\"Courier Prime\":[400,700],\"Cousine\":[400,700],\"Coustard\":[400,900],\"Covered By Your Grace\":[400],\"Crafty Girls\":[400],\"Creepster\":[400],\"Crete Round\":[400],\"Crimson Pro\":[200,300,400,500,600,700,800,900],\"Crimson Text\":[400,600,700],\"Croissant One\":[400],\"Crushed\":[400],\"Cuprum\":[400,500,600,700],\"Cute Font\":[400],\"Cutive\":[400],\"Cutive Mono\":[400],\"Dai Banna SIL\":[300,400,500,600,700],\"Damion\":[400],\"Dancing Script\":[400,500,600,700],\"Danfo\":[400],\"Dangrek\":[400],\"Darker Grotesque\":[300,400,500,600,700,800,900],\"Darumadrop One\":[400],\"Datatype\":[100,200,300,400,500,600,700,800,900],\"David Libre\":[400,500,700],\"Dawning of a New Day\":[400],\"Days One\":[400],\"Dekko\":[400],\"Dela Gothic One\":[400],\"Delicious Handrawn\":[400],\"Delius\":[400],\"Delius Swash Caps\":[400],\"Delius Unicase\":[400,700],\"Della Respira\":[400],\"Denk One\":[400],\"Devonshire\":[400],\"Dhurjati\":[400],\"Didact Gothic\":[400],\"Diphylleia\":[400],\"Diplomata\":[400],\"Diplomata SC\":[400],\"DM Mono\":[300,400,500],\"DM Sans\":[100,200,300,400,500,600,700,800,900],\"DM Serif Display\":[400],\"DM Serif Text\":[400],\"Do Hyeon\":[400],\"Dokdo\":[400],\"Domine\":[400,500,600,700],\"Donegal One\":[400],\"Dongle\":[300,400,700],\"Doppio One\":[400],\"Dorsa\":[400],\"Dosis\":[200,300,400,500,600,700,800],\"DotGothic16\":[400],\"Doto\":[100,200,300,400,500,600,700,800,900],\"Dr Sugiyama\":[400],\"Duru Sans\":[400],\"Dynalight\":[400],\"DynaPuff\":[400,500,600,700],\"Eagle Lake\":[400],\"East Sea Dokdo\":[400],\"Eater\":[400],\"EB Garamond\":[400,500,600,700,800],\"Economica\":[400,700],\"Eczar\":[400,500,600,700,800],\"Edu AU VIC WA NT Arrows\":[400,500,600,700],\"Edu AU VIC WA NT Dots\":[400,500,600,700],\"Edu AU VIC WA NT Guides\":[400,500,600,700],\"Edu AU VIC WA NT Hand\":[400,500,600,700],\"Edu AU VIC WA NT Pre\":[400,500,600,700],\"Edu NSW ACT Cursive\":[400,500,600,700],\"Edu NSW ACT Foundation\":[400,500,600,700],\"Edu NSW ACT Hand Pre\":[400,500,600,700],\"Edu QLD Beginner\":[400,500,600,700],\"Edu QLD Hand\":[400,500,600,700],\"Edu SA Beginner\":[400,500,600,700],\"Edu SA Hand\":[400,500,600,700],\"Edu TAS Beginner\":[400,500,600,700],\"Edu VIC WA NT Beginner\":[400,500,600,700],\"Edu VIC WA NT Hand\":[400,500,600,700],\"Edu VIC WA NT Hand Pre\":[400,500,600,700],\"El Messiri\":[400,500,600,700],\"Electrolize\":[400],\"Elms Sans\":[100,200,300,400,500,600,700,800,900],\"Elsie\":[400,900],\"Elsie Swash Caps\":[400,900],\"Emblema One\":[400],\"Emilys Candy\":[400],\"Encode Sans\":[100,200,300,400,500,600,700,800,900],\"Encode Sans Condensed\":[100,200,300,400,500,600,700,800,900],\"Encode Sans Expanded\":[100,200,300,400,500,600,700,800,900],\"Encode Sans SC\":[100,200,300,400,500,600,700,800,900],\"Encode Sans Semi Condensed\":[100,200,300,400,500,600,700,800,900],\"Encode Sans Semi Expanded\":[100,200,300,400,500,600,700,800,900],\"Engagement\":[400],\"Englebert\":[400],\"Enriqueta\":[400,500,600,700],\"Ephesis\":[400],\"Epilogue\":[100,200,300,400,500,600,700,800,900],\"Epunda Sans\":[300,400,500,600,700,800,900],\"Epunda Slab\":[300,400,500,600,700,800,900],\"Erica One\":[400],\"Esteban\":[400],\"Estedad\":[100,200,300,400,500,600,700,800,900],\"Estonia\":[400],\"Euphoria Script\":[400],\"Ewert\":[400],\"Exile\":[400],\"Exo\":[100,200,300,400,500,600,700,800,900],\"Exo 2\":[100,200,300,400,500,600,700,800,900],\"Expletus Sans\":[400,500,600,700],\"Explora\":[400],\"Faculty Glyphic\":[400],\"Fahkwang\":[200,300,400,500,600,700],\"Familjen Grotesk\":[400,500,600,700],\"Fanwood Text\":[400],\"Farro\":[300,400,500,700],\"Farsan\":[400],\"Fascinate\":[400],\"Fascinate Inline\":[400],\"Faster One\":[400],\"Fasthand\":[400],\"Fauna One\":[400],\"Faustina\":[300,400,500,600,700,800],\"Federant\":[400],\"Federo\":[400],\"Felipa\":[400],\"Fenix\":[400],\"Festive\":[400],\"Figtree\":[300,400,500,600,700,800,900],\"Finger Paint\":[400],\"Finlandica Headline\":[100,200,300,400,500,600,700,800,900],\"Finlandica Text\":[100,200,300,400,500,600,700,800,900],\"Fira Code\":[300,400,500,600,700],\"Fira Mono\":[400,500,700],\"Fira Sans\":[100,200,300,400,500,600,700,800,900],\"Fira Sans Condensed\":[100,200,300,400,500,600,700,800,900],\"Fira Sans Extra Condensed\":[100,200,300,400,500,600,700,800,900],\"Fjalla One\":[400],\"Fjord One\":[400],\"Flamenco\":[300,400],\"Flavors\":[400],\"Fleur De Leah\":[400],\"Flow Block\":[400],\"Flow Circular\":[400],\"Flow Rounded\":[400],\"Foldit\":[100,200,300,400,500,600,700,800,900],\"Fondamento\":[400],\"Fontdiner Swanky\":[400],\"Forum\":[400],\"Fragment Mono\":[400],\"Francois One\":[400],\"Frank Ruhl Libre\":[300,400,500,600,700,800,900],\"Fraunces\":[100,200,300,400,500,600,700,800,900],\"Freckle Face\":[400],\"Fredericka the Great\":[400],\"Fredoka\":[300,400,500,600,700],\"Freehand\":[400],\"Freeman\":[400],\"Fresca\":[400],\"Frijole\":[400],\"Fruktur\":[400],\"Fugaz One\":[400],\"Fuggles\":[400],\"Funnel Display\":[300,400,500,600,700,800],\"Funnel Sans\":[300,400,500,600,700,800],\"Fustat\":[200,300,400,500,600,700,800],\"Fuzzy Bubbles\":[400,700],\"Ga Maamli\":[400],\"Gabarito\":[400,500,600,700,800,900],\"Gabriela\":[400],\"Gaegu\":[300,400,700],\"Gafata\":[400],\"Gajraj One\":[400],\"Galada\":[400],\"Galdeano\":[400],\"Galindo\":[400],\"Gamja Flower\":[400],\"Gantari\":[100,200,300,400,500,600,700,800,900],\"Gasoek One\":[400],\"Gayathri\":[100,400,700],\"Geist\":[100,200,300,400,500,600,700,800,900],\"Geist Mono\":[100,200,300,400,500,600,700,800,900],\"Gelasio\":[400,500,600,700],\"Gemunu Libre\":[200,300,400,500,600,700,800],\"Genos\":[100,200,300,400,500,600,700,800,900],\"Gentium Book Plus\":[400,700],\"Gentium Plus\":[400,700],\"Geo\":[400],\"Geologica\":[100,200,300,400,500,600,700,800,900],\"Geom\":[300,400,500,600,700,800,900],\"Georama\":[100,200,300,400,500,600,700,800,900],\"Geostar\":[400],\"Geostar Fill\":[400],\"Germania One\":[400],\"GFS Didot\":[400],\"GFS Neohellenic\":[400,700],\"Gideon Roman\":[400],\"Gidole\":[400],\"Gidugu\":[400],\"Gilda Display\":[400],\"Girassol\":[400],\"Give You Glory\":[400],\"Glass Antiqua\":[400],\"Glegoo\":[400,700],\"Gloock\":[400],\"Gloria Hallelujah\":[400],\"Glory\":[100,200,300,400,500,600,700,800],\"Gluten\":[100,200,300,400,500,600,700,800,900],\"Goblin One\":[400],\"Gochi Hand\":[400],\"Goldman\":[400,700],\"Golos Text\":[400,500,600,700,800,900],\"Google Sans\":[400,500,600,700],\"Google Sans Code\":[300,400,500,600,700,800],\"Google Sans Flex\":[100,200,300,400,500,600,700,800,900],\"Gorditas\":[400,700],\"Gothic A1\":[100,200,300,400,500,600,700,800,900],\"Gotu\":[400],\"Goudy Bookletter 1911\":[400],\"Gowun Batang\":[400,700],\"Gowun Dodum\":[400],\"Graduate\":[400],\"Grand Hotel\":[400],\"Grandiflora One\":[400],\"Grandstander\":[100,200,300,400,500,600,700,800,900],\"Grape Nuts\":[400],\"Gravitas One\":[400],\"Great Vibes\":[400],\"Grechen Fuemen\":[400],\"Grenze\":[100,200,300,400,500,600,700,800,900],\"Grenze Gotisch\":[100,200,300,400,500,600,700,800,900],\"Grey Qo\":[400],\"Griffy\":[400],\"Gruppo\":[400],\"Gudea\":[400,700],\"Gugi\":[400],\"Gulzar\":[400],\"Gupter\":[400,500,700],\"Gurajada\":[400],\"Gveret Levin\":[400],\"Gwendolyn\":[400,700],\"Habibi\":[400],\"Hachi Maru Pop\":[400],\"Hahmlet\":[100,200,300,400,500,600,700,800,900],\"Halant\":[300,400,500,600,700],\"Hammersmith One\":[400],\"Hanalei\":[400],\"Hanalei Fill\":[400],\"Handjet\":[100,200,300,400,500,600,700,800,900],\"Handlee\":[400],\"Hanken Grotesk\":[100,200,300,400,500,600,700,800,900],\"Hanuman\":[100,200,300,400,500,600,700,800,900],\"Happy Monkey\":[400],\"Harmattan\":[400,500,600,700],\"Headland One\":[400],\"Hedvig Letters Sans\":[400],\"Hedvig Letters Serif\":[400],\"Heebo\":[100,200,300,400,500,600,700,800,900],\"Henny Penny\":[400],\"Hepta Slab\":[100,200,300,400,500,600,700,800,900],\"Herr Von Muellerhoff\":[400],\"Hi Melody\":[400],\"Hina Mincho\":[400],\"Hind\":[300,400,500,600,700],\"Hind Guntur\":[300,400,500,600,700],\"Hind Madurai\":[300,400,500,600,700],\"Hind Mysuru\":[300,400,500,600,700],\"Hind Siliguri\":[300,400,500,600,700],\"Hind Vadodara\":[300,400,500,600,700],\"Holtwood One SC\":[400],\"Homemade Apple\":[400],\"Homenaje\":[400],\"Honk\":[400],\"Host Grotesk\":[300,400,500,600,700,800],\"Hubballi\":[400],\"Hubot Sans\":[200,300,400,500,600,700,800,900],\"Huninn\":[400],\"Hurricane\":[400],\"Iansui\":[400],\"Ibarra Real Nova\":[400,500,600,700],\"IBM Plex Mono\":[100,200,300,400,500,600,700],\"IBM Plex Sans\":[100,200,300,400,500,600,700],\"IBM Plex Sans Arabic\":[100,200,300,400,500,600,700],\"IBM Plex Sans Condensed\":[100,200,300,400,500,600,700],\"IBM Plex Sans Devanagari\":[100,200,300,400,500,600,700],\"IBM Plex Sans Hebrew\":[100,200,300,400,500,600,700],\"IBM Plex Sans JP\":[100,200,300,400,500,600,700],\"IBM Plex Sans KR\":[100,200,300,400,500,600,700],\"IBM Plex Sans Thai\":[100,200,300,400,500,600,700],\"IBM Plex Sans Thai Looped\":[100,200,300,400,500,600,700],\"IBM Plex Serif\":[100,200,300,400,500,600,700],\"Iceberg\":[400],\"Iceland\":[400],\"Idiqlat\":[200,300,400],\"IM Fell Double Pica\":[400],\"IM Fell Double Pica SC\":[400],\"IM Fell DW Pica\":[400],\"IM Fell DW Pica SC\":[400],\"IM Fell English\":[400],\"IM Fell English SC\":[400],\"IM Fell French Canon\":[400],\"IM Fell French Canon SC\":[400],\"IM Fell Great Primer\":[400],\"IM Fell Great Primer SC\":[400],\"Imbue\":[100,200,300,400,500,600,700,800,900],\"Imperial Script\":[400],\"Imprima\":[400],\"Inclusive Sans\":[300,400,500,600,700],\"Inconsolata\":[200,300,400,500,600,700,800,900],\"Inder\":[400],\"Indie Flower\":[400],\"Ingrid Darling\":[400],\"Inika\":[400,700],\"Inknut Antiqua\":[300,400,500,600,700,800,900],\"Inria Sans\":[300,400,700],\"Inria Serif\":[300,400,700],\"Inspiration\":[400],\"Instrument Sans\":[400,500,600,700],\"Instrument Serif\":[400],\"Intel One Mono\":[300,400,500,600,700],\"Inter\":[100,200,300,400,500,600,700,800,900],\"Inter Tight\":[100,200,300,400,500,600,700,800,900],\"Iosevka Charon\":[300,400,500,700],\"Iosevka Charon Mono\":[300,400,500,700],\"Irish Grover\":[400],\"Island Moments\":[400],\"Istok Web\":[400,700],\"Italiana\":[400],\"Italianno\":[400],\"Itim\":[400],\"Jacquard 12\":[400],\"Jacquard 12 Charted\":[400],\"Jacquard 24\":[400],\"Jacquard 24 Charted\":[400],\"Jacquarda Bastarda 9\":[400],\"Jacquarda Bastarda 9 Charted\":[400],\"Jacques Francois\":[400],\"Jacques Francois Shadow\":[400],\"Jaini\":[400],\"Jaini Purva\":[400],\"Jaldi\":[400,700],\"Jaro\":[400],\"Jersey 10\":[400],\"Jersey 10 Charted\":[400],\"Jersey 15\":[400],\"Jersey 15 Charted\":[400],\"Jersey 20\":[400],\"Jersey 20 Charted\":[400],\"Jersey 25\":[400],\"Jersey 25 Charted\":[400],\"JetBrains Mono\":[100,200,300,400,500,600,700,800],\"Jim Nightshade\":[400],\"Joan\":[400],\"Jockey One\":[400],\"Jolly Lodger\":[400],\"Jomhuria\":[400],\"Jomolhari\":[400],\"Josefin Sans\":[100,200,300,400,500,600,700],\"Josefin Slab\":[100,200,300,400,500,600,700],\"Jost\":[100,200,300,400,500,600,700,800,900],\"Joti One\":[400],\"Jua\":[400],\"Judson\":[400,700],\"Julee\":[400],\"Julius Sans One\":[400],\"Junge\":[400],\"Jura\":[300,400,500,600,700],\"Just Another Hand\":[400],\"Just Me Again Down Here\":[400],\"K2D\":[100,200,300,400,500,600,700,800],\"Kablammo\":[400],\"Kadwa\":[400,700],\"Kaisei Decol\":[400,500,700],\"Kaisei HarunoUmi\":[400,500,700],\"Kaisei Opti\":[400,500,700],\"Kaisei Tokumin\":[400,500,700,800],\"Kalam\":[300,400,700],\"Kalnia\":[100,200,300,400,500,600,700],\"Kalnia Glaze\":[100,200,300,400,500,600,700],\"Kameron\":[400,500,600,700],\"Kanchenjunga\":[400,500,600,700],\"Kanit\":[100,200,300,400,500,600,700,800,900],\"Kantumruy Pro\":[100,200,300,400,500,600,700],\"Kapakana\":[300,400],\"Karantina\":[300,400,700],\"Karla\":[200,300,400,500,600,700,800],\"Karla Tamil Inclined\":[400,700],\"Karla Tamil Upright\":[400,700],\"Karma\":[300,400,500,600,700],\"Katibeh\":[400],\"Kaushan Script\":[400],\"Kavivanar\":[400],\"Kavoon\":[400],\"Kay Pho Du\":[400,500,600,700],\"Kdam Thmor Pro\":[400],\"Keania One\":[400],\"Kedebideri\":[400,500,600,700,800,900],\"Kelly Slab\":[400],\"Kenia\":[400],\"Khand\":[300,400,500,600,700],\"Khmer\":[400],\"Khula\":[300,400,600,700,800],\"Kings\":[400],\"Kirang Haerang\":[400],\"Kite One\":[400],\"Kiwi Maru\":[300,400,500],\"Klee One\":[400,600],\"Knewave\":[400],\"Kodchasan\":[200,300,400,500,600,700],\"Kode Mono\":[400,500,600,700],\"Koh Santepheap\":[100,300,400,700,900],\"KoHo\":[200,300,400,500,600,700],\"Kolker Brush\":[400],\"Konkhmer Sleokchher\":[400],\"Kosugi\":[400],\"Kosugi Maru\":[400],\"Kotta One\":[400],\"Koulen\":[400],\"Kranky\":[400],\"Kreon\":[300,400,500,600,700],\"Kristi\":[400],\"Krona One\":[400],\"Krub\":[200,300,400,500,600,700],\"Kufam\":[400,500,600,700,800,900],\"Kulim Park\":[200,300,400,600,700],\"Kumar One\":[400],\"Kumar One Outline\":[400],\"Kumbh Sans\":[100,200,300,400,500,600,700,800,900],\"Kurale\":[400],\"La Belle Aurore\":[400],\"Labrada\":[100,200,300,400,500,600,700,800,900],\"Lacquer\":[400],\"Laila\":[300,400,500,600,700],\"Lakki Reddy\":[400],\"Lalezar\":[400],\"Lancelot\":[400],\"Langar\":[400],\"Lateef\":[200,300,400,500,600,700,800],\"Lato\":[100,300,400,700,900],\"Lavishly Yours\":[400],\"League Gothic\":[400],\"League Script\":[400],\"League Spartan\":[100,200,300,400,500,600,700,800,900],\"Leckerli One\":[400],\"Ledger\":[400],\"Lekton\":[400,700],\"Lemon\":[400],\"Lemonada\":[300,400,500,600,700],\"Lexend\":[100,200,300,400,500,600,700,800,900],\"Lexend Deca\":[100,200,300,400,500,600,700,800,900],\"Lexend Exa\":[100,200,300,400,500,600,700,800,900],\"Lexend Giga\":[100,200,300,400,500,600,700,800,900],\"Lexend Mega\":[100,200,300,400,500,600,700,800,900],\"Lexend Peta\":[100,200,300,400,500,600,700,800,900],\"Lexend Tera\":[100,200,300,400,500,600,700,800,900],\"Lexend Zetta\":[100,200,300,400,500,600,700,800,900],\"Libertinus Keyboard\":[400],\"Libertinus Math\":[400],\"Libertinus Mono\":[400],\"Libertinus Sans\":[400,700],\"Libertinus Serif\":[400,600,700],\"Libertinus Serif Display\":[400],\"Libre Barcode 128\":[400],\"Libre Barcode 128 Text\":[400],\"Libre Barcode 39\":[400],\"Libre Barcode 39 Extended\":[400],\"Libre Barcode 39 Extended Text\":[400],\"Libre Barcode 39 Text\":[400],\"Libre Barcode EAN13 Text\":[400],\"Libre Baskerville\":[400,500,600,700],\"Libre Bodoni\":[400,500,600,700],\"Libre Caslon Display\":[400],\"Libre Caslon Text\":[400,700],\"Libre Franklin\":[100,200,300,400,500,600,700,800,900],\"Licorice\":[400],\"Life Savers\":[400,700,800],\"Lilex\":[100,200,300,400,500,600,700],\"Lilita One\":[400],\"Lily Script One\":[400],\"Limelight\":[400],\"Linden Hill\":[400],\"LINE Seed JP\":[100,400,700,800],\"Linefont\":[100,200,300,400,500,600,700,800,900],\"Lisu Bosa\":[200,300,400,500,600,700,800,900],\"Liter\":[400],\"Literata\":[200,300,400,500,600,700,800,900],\"Liu Jian Mao Cao\":[400],\"Livvic\":[100,200,300,400,500,600,700,900],\"Lobster\":[400],\"Lobster Two\":[400,700],\"Londrina Outline\":[400],\"Londrina Shadow\":[400],\"Londrina Sketch\":[400],\"Londrina Solid\":[100,300,400,900],\"Long Cang\":[400],\"Lora\":[400,500,600,700],\"Love Light\":[400],\"Love Ya Like A Sister\":[400],\"Loved by the King\":[400],\"Lovers Quarrel\":[400],\"Luckiest Guy\":[400],\"Lugrasimo\":[400],\"Lumanosimo\":[400],\"Lunasima\":[400,700],\"Lusitana\":[400,700],\"Lustria\":[400],\"Luxurious Roman\":[400],\"Luxurious Script\":[400],\"LXGW Marker Gothic\":[400],\"LXGW WenKai Mono TC\":[300,400,700],\"LXGW WenKai TC\":[300,400,700],\"M PLUS 1\":[100,200,300,400,500,600,700,800,900],\"M PLUS 1 Code\":[100,200,300,400,500,600,700],\"M PLUS 1p\":[100,300,400,500,700,800,900],\"M PLUS 2\":[100,200,300,400,500,600,700,800,900],\"M PLUS Code Latin\":[100,200,300,400,500,600,700],\"M PLUS Rounded 1c\":[100,300,400,500,700,800,900],\"M PLUS U\":[100,200,300,400,500,600,700,800,900],\"Ma Shan Zheng\":[400],\"Macondo\":[400],\"Macondo Swash Caps\":[400],\"Mada\":[200,300,400,500,600,700,800,900],\"Madimi One\":[400],\"Magra\":[400,700],\"Maiden Orange\":[400],\"Maitree\":[200,300,400,500,600,700],\"Major Mono Display\":[400],\"Mako\":[400],\"Mali\":[200,300,400,500,600,700],\"Mallanna\":[400],\"Maname\":[400],\"Mandali\":[400],\"Manjari\":[100,400,700],\"Manrope\":[200,300,400,500,600,700,800],\"Mansalva\":[400],\"Manuale\":[300,400,500,600,700,800],\"Manufacturing Consent\":[400],\"Marcellus\":[400],\"Marcellus SC\":[400],\"Marck Script\":[400],\"Margarine\":[400],\"Marhey\":[300,400,500,600,700],\"Markazi Text\":[400,500,600,700],\"Marko One\":[400],\"Marmelad\":[400],\"Martel\":[200,300,400,600,700,800,900],\"Martel Sans\":[200,300,400,600,700,800,900],\"Martian Mono\":[100,200,300,400,500,600,700,800],\"Marvel\":[400,700],\"Matangi\":[300,400,500,600,700,800,900],\"Mate\":[400],\"Mate SC\":[400],\"Matemasie\":[400],\"Maven Pro\":[400,500,600,700,800,900],\"McLaren\":[400],\"Mea Culpa\":[400],\"Meddon\":[400],\"MedievalSharp\":[400],\"Medula One\":[400],\"Meera Inimai\":[400],\"Megrim\":[400],\"Meie Script\":[400],\"Menbere\":[100,200,300,400,500,600,700],\"Meow Script\":[400],\"Merienda\":[300,400,500,600,700,800,900],\"Merriweather\":[300,400,500,600,700,800,900],\"Merriweather Sans\":[300,400,500,600,700,800],\"Metal\":[400],\"Metal Mania\":[400],\"Metamorphous\":[400],\"Metrophobic\":[400],\"Michroma\":[400],\"Micro 5\":[400],\"Micro 5 Charted\":[400],\"Milonga\":[400],\"Miltonian\":[400],\"Miltonian Tattoo\":[400],\"Mina\":[400,700],\"Mingzat\":[400],\"Miniver\":[400],\"Miranda Sans\":[400,500,600,700],\"Miriam Libre\":[400,500,600,700],\"Mirza\":[400,500,600,700],\"Miss Fajardose\":[400],\"Mitr\":[200,300,400,500,600,700],\"Mochiy Pop One\":[400],\"Mochiy Pop P One\":[400],\"Modak\":[400],\"Modern Antiqua\":[400],\"Moderustic\":[300,400,500,600,700,800],\"Mogra\":[400],\"Mohave\":[300,400,500,600,700],\"Moirai One\":[400],\"Molengo\":[400],\"Molle\":[400],\"Momo Signature\":[400],\"Momo Trust Display\":[400],\"Momo Trust Sans\":[200,300,400,500,600,700,800],\"Mona Sans\":[200,300,400,500,600,700,800,900],\"Monda\":[400,500,600,700],\"Monofett\":[400],\"Monomakh\":[400],\"Monomaniac One\":[400],\"Monoton\":[400],\"Monsieur La Doulaise\":[400],\"Montaga\":[400],\"Montagu Slab\":[100,200,300,400,500,600,700],\"MonteCarlo\":[400],\"Montez\":[400],\"Montserrat\":[100,200,300,400,500,600,700,800,900],\"Montserrat Alternates\":[100,200,300,400,500,600,700,800,900],\"Montserrat Underline\":[100,200,300,400,500,600,700,800,900],\"Moo Lah Lah\":[400],\"Mooli\":[400],\"Moon Dance\":[400],\"Moul\":[400],\"Moulpali\":[400],\"Mountains of Christmas\":[400,700],\"Mouse Memoirs\":[400],\"Mozilla Headline\":[200,300,400,500,600,700],\"Mozilla Text\":[200,300,400,500,600,700],\"Mr Bedfort\":[400],\"Mr Dafoe\":[400],\"Mr De Haviland\":[400],\"Mrs Saint Delafield\":[400],\"Mrs Sheppards\":[400],\"Ms Madi\":[400],\"Mukta\":[200,300,400,500,600,700,800],\"Mukta Mahee\":[200,300,400,500,600,700,800],\"Mukta Malar\":[200,300,400,500,600,700,800],\"Mukta Vaani\":[200,300,400,500,600,700,800],\"Mulish\":[100,200,300,400,500,600,700,800,900],\"Murecho\":[100,200,300,400,500,600,700,800,900],\"MuseoModerno\":[100,200,300,400,500,600,700,800,900],\"My Soul\":[400],\"Mynerve\":[400],\"Mystery Quest\":[400],\"Nabla\":[400],\"Namdhinggo\":[400,500,600,700,800],\"Nanum Brush Script\":[400],\"Nanum Gothic\":[400,700,800],\"Nanum Gothic Coding\":[400,700],\"Nanum Myeongjo\":[400,700,800],\"Nanum Pen Script\":[400],\"Narnoor\":[400,500,600,700,800],\"Nata Sans\":[100,200,300,400,500,600,700,800,900],\"National Park\":[200,300,400,500,600,700,800],\"Neonderthaw\":[400],\"Nerko One\":[400],\"Neucha\":[400],\"Neuton\":[200,300,400,700,800],\"New Amsterdam\":[400],\"New Rocker\":[400],\"New Tegomin\":[400],\"News Cycle\":[400,700],\"Newsreader\":[200,300,400,500,600,700,800],\"Niconne\":[400],\"Niramit\":[200,300,400,500,600,700],\"Nixie One\":[400],\"Nobile\":[400,500,700],\"Nokora\":[100,200,300,400,500,600,700,800,900],\"Norican\":[400],\"Nosifer\":[400],\"Notable\":[400],\"Nothing You Could Do\":[400],\"Noticia Text\":[400,700],\"Noto Color Emoji\":[400],\"Noto Emoji\":[300,400,500,600,700],\"Noto Kufi Arabic\":[100,200,300,400,500,600,700,800,900],\"Noto Music\":[400],\"Noto Naskh Arabic\":[400,500,600,700],\"Noto Nastaliq Urdu\":[400,500,600,700],\"Noto Rashi Hebrew\":[100,200,300,400,500,600,700,800,900],\"Noto Sans\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Adlam\":[400,500,600,700],\"Noto Sans Adlam Unjoined\":[400,500,600,700],\"Noto Sans Anatolian Hieroglyphs\":[400],\"Noto Sans Arabic\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Armenian\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Avestan\":[400],\"Noto Sans Balinese\":[400,500,600,700],\"Noto Sans Bamum\":[400,500,600,700],\"Noto Sans Bassa Vah\":[400,500,600,700],\"Noto Sans Batak\":[400],\"Noto Sans Bengali\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Bhaiksuki\":[400],\"Noto Sans Brahmi\":[400],\"Noto Sans Buginese\":[400],\"Noto Sans Buhid\":[400],\"Noto Sans Canadian Aboriginal\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Carian\":[400],\"Noto Sans Caucasian Albanian\":[400],\"Noto Sans Chakma\":[400],\"Noto Sans Cham\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Cherokee\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Chorasmian\":[400],\"Noto Sans Coptic\":[400],\"Noto Sans Cuneiform\":[400],\"Noto Sans Cypriot\":[400],\"Noto Sans Cypro Minoan\":[400],\"Noto Sans Deseret\":[400],\"Noto Sans Devanagari\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Display\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Duployan\":[400,700],\"Noto Sans Egyptian Hieroglyphs\":[400],\"Noto Sans Elbasan\":[400],\"Noto Sans Elymaic\":[400],\"Noto Sans Ethiopic\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Georgian\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Glagolitic\":[400],\"Noto Sans Gothic\":[400],\"Noto Sans Grantha\":[400],\"Noto Sans Gujarati\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Gunjala Gondi\":[400,500,600,700],\"Noto Sans Gurmukhi\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Hanifi Rohingya\":[400,500,600,700],\"Noto Sans Hanunoo\":[400],\"Noto Sans Hatran\":[400],\"Noto Sans Hebrew\":[100,200,300,400,500,600,700,800,900],\"Noto Sans HK\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Imperial Aramaic\":[400],\"Noto Sans Indic Siyaq Numbers\":[400],\"Noto Sans Inscriptional Pahlavi\":[400],\"Noto Sans Inscriptional Parthian\":[400],\"Noto Sans Javanese\":[400,500,600,700],\"Noto Sans JP\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Kaithi\":[400],\"Noto Sans Kannada\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Kawi\":[400,500,600,700],\"Noto Sans Kayah Li\":[400,500,600,700],\"Noto Sans Kharoshthi\":[400],\"Noto Sans Khmer\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Khojki\":[400],\"Noto Sans Khudawadi\":[400],\"Noto Sans KR\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Lao\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Lao Looped\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Lepcha\":[400],\"Noto Sans Limbu\":[400],\"Noto Sans Linear A\":[400],\"Noto Sans Linear B\":[400],\"Noto Sans Lisu\":[400,500,600,700],\"Noto Sans Lycian\":[400],\"Noto Sans Lydian\":[400],\"Noto Sans Mahajani\":[400],\"Noto Sans Malayalam\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Mandaic\":[400],\"Noto Sans Manichaean\":[400],\"Noto Sans Marchen\":[400],\"Noto Sans Masaram Gondi\":[400],\"Noto Sans Math\":[400],\"Noto Sans Mayan Numerals\":[400],\"Noto Sans Medefaidrin\":[400,500,600,700],\"Noto Sans Meetei Mayek\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Mende Kikakui\":[400],\"Noto Sans Meroitic\":[400],\"Noto Sans Miao\":[400],\"Noto Sans Modi\":[400],\"Noto Sans Mongolian\":[400],\"Noto Sans Mono\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Mro\":[400],\"Noto Sans Multani\":[400],\"Noto Sans Myanmar\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Nabataean\":[400],\"Noto Sans Nag Mundari\":[400,500,600,700],\"Noto Sans Nandinagari\":[400],\"Noto Sans New Tai Lue\":[400,500,600,700],\"Noto Sans Newa\":[400],\"Noto Sans NKo\":[400],\"Noto Sans NKo Unjoined\":[400,500,600,700],\"Noto Sans Nushu\":[400],\"Noto Sans Ogham\":[400],\"Noto Sans Ol Chiki\":[400,500,600,700],\"Noto Sans Old Hungarian\":[400],\"Noto Sans Old Italic\":[400],\"Noto Sans Old North Arabian\":[400],\"Noto Sans Old Permic\":[400],\"Noto Sans Old Persian\":[400],\"Noto Sans Old Sogdian\":[400],\"Noto Sans Old South Arabian\":[400],\"Noto Sans Old Turkic\":[400],\"Noto Sans Oriya\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Osage\":[400],\"Noto Sans Osmanya\":[400],\"Noto Sans Pahawh Hmong\":[400],\"Noto Sans Palmyrene\":[400],\"Noto Sans Pau Cin Hau\":[400],\"Noto Sans PhagsPa\":[400],\"Noto Sans Phoenician\":[400],\"Noto Sans Psalter Pahlavi\":[400],\"Noto Sans Rejang\":[400],\"Noto Sans Runic\":[400],\"Noto Sans Samaritan\":[400],\"Noto Sans Saurashtra\":[400],\"Noto Sans SC\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Sharada\":[400],\"Noto Sans Shavian\":[400],\"Noto Sans Siddham\":[400],\"Noto Sans SignWriting\":[400],\"Noto Sans Sinhala\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Sogdian\":[400],\"Noto Sans Sora Sompeng\":[400,500,600,700],\"Noto Sans Soyombo\":[400],\"Noto Sans Sundanese\":[400,500,600,700],\"Noto Sans Sunuwar\":[400],\"Noto Sans Syloti Nagri\":[400],\"Noto Sans Symbols\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Symbols 2\":[400],\"Noto Sans Syriac\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Syriac Eastern\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Syriac Western\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Tagalog\":[400],\"Noto Sans Tagbanwa\":[400],\"Noto Sans Tai Le\":[400],\"Noto Sans Tai Tham\":[400,500,600,700],\"Noto Sans Tai Viet\":[400],\"Noto Sans Takri\":[400],\"Noto Sans Tamil\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Tamil Supplement\":[400],\"Noto Sans Tangsa\":[400,500,600,700],\"Noto Sans TC\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Telugu\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Thaana\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Thai\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Thai Looped\":[100,200,300,400,500,600,700,800,900],\"Noto Sans Tifinagh\":[400],\"Noto Sans Tirhuta\":[400],\"Noto Sans Ugaritic\":[400],\"Noto Sans Vai\":[400],\"Noto Sans Vithkuqi\":[400,500,600,700],\"Noto Sans Wancho\":[400],\"Noto Sans Warang Citi\":[400],\"Noto Sans Yi\":[400],\"Noto Sans Zanabazar Square\":[400],\"Noto Serif\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Ahom\":[400],\"Noto Serif Armenian\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Balinese\":[400],\"Noto Serif Bengali\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Devanagari\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Display\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Dives Akuru\":[400],\"Noto Serif Dogra\":[400],\"Noto Serif Ethiopic\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Georgian\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Grantha\":[400],\"Noto Serif Gujarati\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Gurmukhi\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Hebrew\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Hentaigana\":[200,300,400,500,600,700,800,900],\"Noto Serif HK\":[200,300,400,500,600,700,800,900],\"Noto Serif JP\":[200,300,400,500,600,700,800,900],\"Noto Serif Kannada\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Khitan Small Script\":[400],\"Noto Serif Khmer\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Khojki\":[400,500,600,700],\"Noto Serif KR\":[200,300,400,500,600,700,800,900],\"Noto Serif Lao\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Makasar\":[400],\"Noto Serif Malayalam\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Myanmar\":[100,200,300,400,500,600,700,800,900],\"Noto Serif NP Hmong\":[400,500,600,700],\"Noto Serif Old Uyghur\":[400],\"Noto Serif Oriya\":[400,500,600,700],\"Noto Serif Ottoman Siyaq\":[400],\"Noto Serif SC\":[200,300,400,500,600,700,800,900],\"Noto Serif Sinhala\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Tamil\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Tangut\":[400],\"Noto Serif TC\":[200,300,400,500,600,700,800,900],\"Noto Serif Telugu\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Thai\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Tibetan\":[100,200,300,400,500,600,700,800,900],\"Noto Serif Todhri\":[400],\"Noto Serif Toto\":[400,500,600,700],\"Noto Serif Vithkuqi\":[400,500,600,700],\"Noto Serif Yezidi\":[400,500,600,700],\"Noto Traditional Nushu\":[300,400,500,600,700],\"Noto Znamenny Musical Notation\":[400],\"Nova Cut\":[400],\"Nova Flat\":[400],\"Nova Mono\":[400],\"Nova Oval\":[400],\"Nova Round\":[400],\"Nova Script\":[400],\"Nova Slim\":[400],\"Nova Square\":[400],\"NTR\":[400],\"Numans\":[400],\"Nunito\":[100,200,300,400,500,600,700,800,900],\"Nunito Sans\":[100,200,300,400,500,600,700,800,900],\"Nuosu SIL\":[400],\"Odibee Sans\":[400],\"Odor Mean Chey\":[400],\"Offside\":[400],\"Oi\":[400],\"Ojuju\":[200,300,400,500,600,700,800],\"Old Standard TT\":[400,700],\"Oldenburg\":[400],\"Ole\":[400],\"Oleo Script\":[400,700],\"Oleo Script Swash Caps\":[400,700],\"Onest\":[100,200,300,400,500,600,700,800,900],\"Oooh Baby\":[400],\"Open Sans\":[300,400,500,600,700,800],\"Oranienbaum\":[400],\"Orbit\":[400],\"Orbitron\":[400,500,600,700,800,900],\"Oregano\":[400],\"Orelega One\":[400],\"Orienta\":[400],\"Original Surfer\":[400],\"Oswald\":[200,300,400,500,600,700],\"Outfit\":[100,200,300,400,500,600,700,800,900],\"Over the Rainbow\":[400],\"Overlock\":[400,700,900],\"Overlock SC\":[400],\"Overpass\":[100,200,300,400,500,600,700,800,900],\"Overpass Mono\":[300,400,500,600,700],\"Ovo\":[400],\"Oxanium\":[200,300,400,500,600,700,800],\"Oxygen\":[300,400,700],\"Oxygen Mono\":[400],\"Pacifico\":[400],\"Padauk\":[400,700],\"Padyakke Expanded One\":[400],\"Palanquin\":[100,200,300,400,500,600,700],\"Palanquin Dark\":[400,500,600,700],\"Palette Mosaic\":[400],\"Pangolin\":[400],\"Paprika\":[400],\"Parastoo\":[400,500,600,700],\"Parisienne\":[400],\"Parkinsans\":[300,400,500,600,700,800],\"Passero One\":[400],\"Passion One\":[400,700,900],\"Passions Conflict\":[400],\"Pathway Extreme\":[100,200,300,400,500,600,700,800,900],\"Pathway Gothic One\":[400],\"Patrick Hand\":[400],\"Patrick Hand SC\":[400],\"Pattaya\":[400],\"Patua One\":[400],\"Pavanam\":[400],\"Paytone One\":[400],\"Peddana\":[400],\"Peralta\":[400],\"Permanent Marker\":[400],\"Petemoss\":[400],\"Petit Formal Script\":[400],\"Petrona\":[100,200,300,400,500,600,700,800,900],\"Phetsarath\":[400,700],\"Philosopher\":[400,700],\"Phudu\":[300,400,500,600,700,800,900],\"Piazzolla\":[100,200,300,400,500,600,700,800,900],\"Piedra\":[400],\"Pinyon Script\":[400],\"Pirata One\":[400],\"Pixelify Sans\":[400,500,600,700],\"Plaster\":[400],\"Platypi\":[300,400,500,600,700,800],\"Play\":[400,700],\"Playball\":[400],\"Playfair\":[300,400,500,600,700,800,900],\"Playfair Display\":[400,500,600,700,800,900],\"Playfair Display SC\":[400,700,900],\"Playpen Sans\":[100,200,300,400,500,600,700,800],\"Playpen Sans Arabic\":[100,200,300,400,500,600,700,800],\"Playpen Sans Deva\":[100,200,300,400,500,600,700,800],\"Playpen Sans Hebrew\":[100,200,300,400,500,600,700,800],\"Playpen Sans Thai\":[100,200,300,400,500,600,700,800],\"Playwrite AR\":[100,200,300,400],\"Playwrite AR Guides\":[400],\"Playwrite AT\":[100,200,300,400],\"Playwrite AT Guides\":[400],\"Playwrite AU NSW\":[100,200,300,400],\"Playwrite AU NSW Guides\":[400],\"Playwrite AU QLD\":[100,200,300,400],\"Playwrite AU QLD Guides\":[400],\"Playwrite AU SA\":[100,200,300,400],\"Playwrite AU SA Guides\":[400],\"Playwrite AU TAS\":[100,200,300,400],\"Playwrite AU TAS Guides\":[400],\"Playwrite AU VIC\":[100,200,300,400],\"Playwrite AU VIC Guides\":[400],\"Playwrite BE VLG\":[100,200,300,400],\"Playwrite BE VLG Guides\":[400],\"Playwrite BE WAL\":[100,200,300,400],\"Playwrite BE WAL Guides\":[400],\"Playwrite BR\":[100,200,300,400],\"Playwrite BR Guides\":[400],\"Playwrite CA\":[100,200,300,400],\"Playwrite CA Guides\":[400],\"Playwrite CL\":[100,200,300,400],\"Playwrite CL Guides\":[400],\"Playwrite CO\":[100,200,300,400],\"Playwrite CO Guides\":[400],\"Playwrite CU\":[100,200,300,400],\"Playwrite CU Guides\":[400],\"Playwrite CZ\":[100,200,300,400],\"Playwrite CZ Guides\":[400],\"Playwrite DE Grund\":[100,200,300,400],\"Playwrite DE Grund Guides\":[400],\"Playwrite DE LA\":[100,200,300,400],\"Playwrite DE LA Guides\":[400],\"Playwrite DE SAS\":[100,200,300,400],\"Playwrite DE SAS Guides\":[400],\"Playwrite DE VA\":[100,200,300,400],\"Playwrite DE VA Guides\":[400],\"Playwrite DK Loopet\":[100,200,300,400],\"Playwrite DK Loopet Guides\":[400],\"Playwrite DK Uloopet\":[100,200,300,400],\"Playwrite DK Uloopet Guides\":[400],\"Playwrite ES\":[100,200,300,400],\"Playwrite ES Deco\":[100,200,300,400],\"Playwrite ES Deco Guides\":[400],\"Playwrite ES Guides\":[400],\"Playwrite FR Moderne\":[100,200,300,400],\"Playwrite FR Moderne Guides\":[400],\"Playwrite FR Trad\":[100,200,300,400],\"Playwrite FR Trad Guides\":[400],\"Playwrite GB J\":[100,200,300,400],\"Playwrite GB J Guides\":[400],\"Playwrite GB S\":[100,200,300,400],\"Playwrite GB S Guides\":[400],\"Playwrite HR\":[100,200,300,400],\"Playwrite HR Guides\":[400],\"Playwrite HR Lijeva\":[100,200,300,400],\"Playwrite HR Lijeva Guides\":[400],\"Playwrite HU\":[100,200,300,400],\"Playwrite HU Guides\":[400],\"Playwrite ID\":[100,200,300,400],\"Playwrite ID Guides\":[400],\"Playwrite IE\":[100,200,300,400],\"Playwrite IE Guides\":[400],\"Playwrite IN\":[100,200,300,400],\"Playwrite IN Guides\":[400],\"Playwrite IS\":[100,200,300,400],\"Playwrite IS Guides\":[400],\"Playwrite IT Moderna\":[100,200,300,400],\"Playwrite IT Moderna Guides\":[400],\"Playwrite IT Trad\":[100,200,300,400],\"Playwrite IT Trad Guides\":[400],\"Playwrite MX\":[100,200,300,400],\"Playwrite MX Guides\":[400],\"Playwrite NG Modern\":[100,200,300,400],\"Playwrite NG Modern Guides\":[400],\"Playwrite NL\":[100,200,300,400],\"Playwrite NL Guides\":[400],\"Playwrite NO\":[100,200,300,400],\"Playwrite NO Guides\":[400],\"Playwrite NZ\":[100,200,300,400],\"Playwrite NZ Basic\":[100,200,300,400],\"Playwrite NZ Basic Guides\":[400],\"Playwrite NZ Guides\":[400],\"Playwrite PE\":[100,200,300,400],\"Playwrite PE Guides\":[400],\"Playwrite PL\":[100,200,300,400],\"Playwrite PL Guides\":[400],\"Playwrite PT\":[100,200,300,400],\"Playwrite PT Guides\":[400],\"Playwrite RO\":[100,200,300,400],\"Playwrite RO Guides\":[400],\"Playwrite SK\":[100,200,300,400],\"Playwrite SK Guides\":[400],\"Playwrite TZ\":[100,200,300,400],\"Playwrite TZ Guides\":[400],\"Playwrite US Modern\":[100,200,300,400],\"Playwrite US Modern Guides\":[400],\"Playwrite US Trad\":[100,200,300,400],\"Playwrite US Trad Guides\":[400],\"Playwrite VN\":[100,200,300,400],\"Playwrite VN Guides\":[400],\"Playwrite ZA\":[100,200,300,400],\"Playwrite ZA Guides\":[400],\"Plus Jakarta Sans\":[200,300,400,500,600,700,800],\"Pochaevsk\":[400],\"Podkova\":[400,500,600,700,800],\"Poetsen One\":[400],\"Poiret One\":[400],\"Poller One\":[400],\"Poltawski Nowy\":[400,500,600,700],\"Poly\":[400],\"Pompiere\":[400],\"Ponnala\":[400],\"Ponomar\":[400],\"Pontano Sans\":[300,400,500,600,700],\"Poor Story\":[400],\"Poppins\":[100,200,300,400,500,600,700,800,900],\"Port Lligat Sans\":[400],\"Port Lligat Slab\":[400],\"Potta One\":[400],\"Pragati Narrow\":[400,700],\"Praise\":[400],\"Prata\":[400],\"Preahvihear\":[400],\"Press Start 2P\":[400],\"Pridi\":[200,300,400,500,600,700],\"Princess Sofia\":[400],\"Prociono\":[400],\"Prompt\":[100,200,300,400,500,600,700,800,900],\"Prosto One\":[400],\"Protest Guerrilla\":[400],\"Protest Revolution\":[400],\"Protest Riot\":[400],\"Protest Strike\":[400],\"Proza Libre\":[400,500,600,700,800],\"PT Mono\":[400],\"PT Sans\":[400,700],\"PT Sans Caption\":[400,700],\"PT Sans Narrow\":[400,700],\"PT Serif\":[400,700],\"PT Serif Caption\":[400],\"Public Sans\":[100,200,300,400,500,600,700,800,900],\"Puppies Play\":[400],\"Puritan\":[400,700],\"Purple Purse\":[400],\"Qahiri\":[400],\"Quando\":[400],\"Quantico\":[400,700],\"Quattrocento\":[400,700],\"Quattrocento Sans\":[400,700],\"Questrial\":[400],\"Quicksand\":[300,400,500,600,700],\"Quintessential\":[400],\"Qwigley\":[400],\"Qwitcher Grypen\":[400,700],\"Racing Sans One\":[400],\"Radio Canada\":[300,400,500,600,700],\"Radio Canada Big\":[400,500,600,700],\"Radley\":[400],\"Rajdhani\":[300,400,500,600,700],\"Rakkas\":[400],\"Raleway\":[100,200,300,400,500,600,700,800,900],\"Raleway Dots\":[400],\"Ramabhadra\":[400],\"Ramaraja\":[400],\"Rambla\":[400,700],\"Rammetto One\":[400],\"Rampart One\":[400],\"Ramsina\":[400],\"Ranchers\":[400],\"Rancho\":[400],\"Ranga\":[400,700],\"Rasa\":[300,400,500,600,700],\"Rationale\":[400],\"Ravi Prakash\":[400],\"Readex Pro\":[200,300,400,500,600,700],\"Recursive\":[100,300,400,500,600,700,800,900],\"Red Hat Display\":[300,400,500,600,700,800,900],\"Red Hat Mono\":[300,400,500,600,700],\"Red Hat Text\":[300,400,500,600,700],\"Red Rose\":[300,400,500,600,700],\"Redacted\":[400],\"Redacted Script\":[300,400,700],\"Reddit Mono\":[200,300,400,500,600,700,800,900],\"Reddit Sans\":[200,300,400,500,600,700,800,900],\"Reddit Sans Condensed\":[200,300,400,500,600,700,800,900],\"Redressed\":[400],\"Reem Kufi\":[400,500,600,700],\"Reem Kufi Fun\":[400,500,600,700],\"Reem Kufi Ink\":[400],\"Reenie Beanie\":[400],\"Reggae One\":[400],\"REM\":[100,200,300,400,500,600,700,800,900],\"Rethink Sans\":[400,500,600,700,800],\"Revalia\":[400],\"Rhodium Libre\":[400],\"Ribeye\":[400],\"Ribeye Marrow\":[400],\"Righteous\":[400],\"Risque\":[400],\"Road Rage\":[400],\"Roboto\":[100,200,300,400,500,600,700,800,900],\"Roboto Condensed\":[100,200,300,400,500,600,700,800,900],\"Roboto Flex\":[100,200,300,400,500,600,700,800,900],\"Roboto Mono\":[100,200,300,400,500,600,700],\"Roboto Serif\":[100,200,300,400,500,600,700,800,900],\"Roboto Slab\":[100,200,300,400,500,600,700,800,900],\"Rochester\":[400],\"Rock 3D\":[400],\"Rock Salt\":[400],\"RocknRoll One\":[400],\"Rokkitt\":[100,200,300,400,500,600,700,800,900],\"Romanesco\":[400],\"Ropa Sans\":[400],\"Rosario\":[300,400,500,600,700],\"Rosarivo\":[400],\"Rouge Script\":[400],\"Rowdies\":[300,400,700],\"Rozha One\":[400],\"Rubik\":[300,400,500,600,700,800,900],\"Rubik 80s Fade\":[400],\"Rubik Beastly\":[400],\"Rubik Broken Fax\":[400],\"Rubik Bubbles\":[400],\"Rubik Burned\":[400],\"Rubik Dirt\":[400],\"Rubik Distressed\":[400],\"Rubik Doodle Shadow\":[400],\"Rubik Doodle Triangles\":[400],\"Rubik Gemstones\":[400],\"Rubik Glitch\":[400],\"Rubik Glitch Pop\":[400],\"Rubik Iso\":[400],\"Rubik Lines\":[400],\"Rubik Maps\":[400],\"Rubik Marker Hatch\":[400],\"Rubik Maze\":[400],\"Rubik Microbe\":[400],\"Rubik Mono One\":[400],\"Rubik Moonrocks\":[400],\"Rubik Pixels\":[400],\"Rubik Puddles\":[400],\"Rubik Scribble\":[400],\"Rubik Spray Paint\":[400],\"Rubik Storm\":[400],\"Rubik Vinyl\":[400],\"Rubik Wet Paint\":[400],\"Ruda\":[400,500,600,700,800,900],\"Rufina\":[400,700],\"Ruge Boogie\":[400],\"Ruluko\":[400],\"Rum Raisin\":[400],\"Ruslan Display\":[400],\"Russo One\":[400],\"Ruthie\":[400],\"Ruwudu\":[400,500,600,700],\"Rye\":[400],\"Sacramento\":[400],\"Sahitya\":[400,700],\"Sail\":[400],\"Saira\":[100,200,300,400,500,600,700,800,900],\"Saira Condensed\":[100,200,300,400,500,600,700,800,900],\"Saira Extra Condensed\":[100,200,300,400,500,600,700,800,900],\"Saira Semi Condensed\":[100,200,300,400,500,600,700,800,900],\"Saira Stencil\":[100,200,300,400,500,600,700,800,900],\"Salsa\":[400],\"Sanchez\":[400],\"Sancreek\":[400],\"Sankofa Display\":[400],\"Sansation\":[300,400,700],\"Sansita\":[400,700,800,900],\"Sansita Swashed\":[300,400,500,600,700,800,900],\"Sarabun\":[100,200,300,400,500,600,700,800],\"Sarala\":[400,700],\"Sarina\":[400],\"Sarpanch\":[400,500,600,700,800,900],\"Sassy Frass\":[400],\"Satisfy\":[400],\"Savate\":[200,300,400,500,600,700,800,900],\"Sawarabi Gothic\":[400],\"Sawarabi Mincho\":[400],\"Scada\":[400,700],\"Scheherazade New\":[400,500,600,700],\"Schibsted Grotesk\":[400,500,600,700,800,900],\"Schoolbell\":[400],\"Science Gothic\":[100,200,300,400,500,600,700,800,900],\"Scope One\":[400],\"Seaweed Script\":[400],\"Secular One\":[400],\"Sedan\":[400],\"Sedan SC\":[400],\"Sedgwick Ave\":[400],\"Sedgwick Ave Display\":[400],\"Sekuya\":[400],\"Sen\":[400,500,600,700,800],\"Send Flowers\":[400],\"Sevillana\":[400],\"Seymour One\":[400],\"Shadows Into Light\":[400],\"Shadows Into Light Two\":[400],\"Shafarik\":[400],\"Shalimar\":[400],\"Shantell Sans\":[300,400,500,600,700,800],\"Shanti\":[400],\"Share\":[400,700],\"Share Tech\":[400],\"Share Tech Mono\":[400],\"Shippori Antique\":[400],\"Shippori Antique B1\":[400],\"Shippori Mincho\":[400,500,600,700,800],\"Shippori Mincho B1\":[400,500,600,700,800],\"Shizuru\":[400],\"Shojumaru\":[400],\"Short Stack\":[400],\"Shrikhand\":[400],\"Siemreap\":[400],\"Sigmar\":[400],\"Sigmar One\":[400],\"Signika\":[300,400,500,600,700],\"Signika Negative\":[300,400,500,600,700],\"Silkscreen\":[400,700],\"Simonetta\":[400,900],\"Single Day\":[400],\"Sintony\":[400,700],\"Sirin Stencil\":[400],\"Sirivennela\":[400],\"Six Caps\":[400],\"Sixtyfour\":[400],\"Sixtyfour Convergence\":[400],\"Skranji\":[400,700],\"Slabo 13px\":[400],\"Slabo 27px\":[400],\"Slackey\":[400],\"Slackside One\":[400],\"Smokum\":[400],\"Smooch\":[400],\"Smooch Sans\":[100,200,300,400,500,600,700,800,900],\"Smythe\":[400],\"SN Pro\":[200,300,400,500,600,700,800,900],\"Sniglet\":[400,800],\"Snippet\":[400],\"Snowburst One\":[400],\"Sofadi One\":[400],\"Sofia\":[400],\"Sofia Sans\":[100,200,300,400,500,600,700,800,900],\"Sofia Sans Condensed\":[100,200,300,400,500,600,700,800,900],\"Sofia Sans Extra Condensed\":[100,200,300,400,500,600,700,800,900],\"Sofia Sans Semi Condensed\":[100,200,300,400,500,600,700,800,900],\"Solitreo\":[400],\"Solway\":[300,400,500,700,800],\"Sometype Mono\":[400,500,600,700],\"Song Myung\":[400],\"Sono\":[200,300,400,500,600,700,800],\"Sonsie One\":[400],\"Sora\":[100,200,300,400,500,600,700,800],\"Sorts Mill Goudy\":[400],\"Sour Gummy\":[100,200,300,400,500,600,700,800,900],\"Source Code Pro\":[200,300,400,500,600,700,800,900],\"Source Sans 3\":[200,300,400,500,600,700,800,900],\"Source Serif 4\":[200,300,400,500,600,700,800,900],\"Space Grotesk\":[300,400,500,600,700],\"Space Mono\":[400,700],\"Special Elite\":[400],\"Special Gothic\":[400,500,600,700],\"Special Gothic Condensed One\":[400],\"Special Gothic Expanded One\":[400],\"Spectral\":[200,300,400,500,600,700,800],\"Spectral SC\":[200,300,400,500,600,700,800],\"Spicy Rice\":[400],\"Spinnaker\":[400],\"Spirax\":[400],\"Splash\":[400],\"Spline Sans\":[300,400,500,600,700],\"Spline Sans Mono\":[300,400,500,600,700],\"Squada One\":[400],\"Square Peg\":[400],\"Sree Krushnadevaraya\":[400],\"Sriracha\":[400],\"Srisakdi\":[400,700],\"Staatliches\":[400],\"Stack Sans Headline\":[200,300,400,500,600,700],\"Stack Sans Notch\":[200,300,400,500,600,700],\"Stack Sans Text\":[200,300,400,500,600,700],\"Stalemate\":[400],\"Stalinist One\":[400],\"Stardos Stencil\":[400,700],\"Stick\":[400],\"Stick No Bills\":[200,300,400,500,600,700,800],\"Stint Ultra Condensed\":[400],\"Stint Ultra Expanded\":[400],\"STIX Two Math\":[400],\"STIX Two Text\":[400,500,600,700],\"Stoke\":[300,400],\"Story Script\":[400],\"Strait\":[400],\"Strichpunkt Sans\":[400,500,600,700,800,900],\"Style Script\":[400],\"Stylish\":[400],\"Sue Ellen Francisco\":[400],\"Suez One\":[400],\"Sulphur Point\":[300,400,700],\"Sumana\":[400,700],\"Sunflower\":[300,500,700],\"Sunshiney\":[400],\"Supermercado One\":[400],\"Sura\":[400,700],\"Suranna\":[400],\"Suravaram\":[400],\"SUSE\":[100,200,300,400,500,600,700,800,900],\"SUSE Mono\":[100,200,300,400,500,600,700,800],\"Suwannaphum\":[100,300,400,700,900],\"Swanky and Moo Moo\":[400],\"Syncopate\":[400,700],\"Syne\":[400,500,600,700,800],\"Syne Mono\":[400],\"Syne Tactile\":[400],\"Tac One\":[400],\"Tagesschrift\":[400],\"Tai Heritage Pro\":[400,700],\"Tajawal\":[200,300,400,500,700,800,900],\"Tangerine\":[400,700],\"Tapestry\":[400],\"Taprom\":[400],\"TASA Explorer\":[400,500,600,700,800],\"TASA Orbiter\":[400,500,600,700,800],\"Tauri\":[400],\"Taviraj\":[100,200,300,400,500,600,700,800,900],\"Teachers\":[400,500,600,700,800],\"Teko\":[300,400,500,600,700],\"Tektur\":[400,500,600,700,800,900],\"Telex\":[400],\"Tenali Ramakrishna\":[400],\"Tenor Sans\":[400],\"Text Me One\":[400],\"Texturina\":[100,200,300,400,500,600,700,800,900],\"Thasadith\":[400,700],\"The Girl Next Door\":[400],\"The Nautigal\":[400,700],\"Tienne\":[400,700,900],\"TikTok Sans\":[300,400,500,600,700,800,900],\"Tillana\":[400,500,600,700,800],\"Tilt Neon\":[400],\"Tilt Prism\":[400],\"Tilt Warp\":[400],\"Timmana\":[400],\"Tinos\":[400,700],\"Tiny5\":[400],\"Tiro Bangla\":[400],\"Tiro Devanagari Hindi\":[400],\"Tiro Devanagari Marathi\":[400],\"Tiro Devanagari Sanskrit\":[400],\"Tiro Gurmukhi\":[400],\"Tiro Kannada\":[400],\"Tiro Tamil\":[400],\"Tiro Telugu\":[400],\"Tirra\":[400,500,600,700,800,900],\"Titan One\":[400],\"Titillium Web\":[200,300,400,600,700,900],\"Tomorrow\":[100,200,300,400,500,600,700,800,900],\"Tourney\":[100,200,300,400,500,600,700,800,900],\"Trade Winds\":[400],\"Train One\":[400],\"Triodion\":[400],\"Trirong\":[100,200,300,400,500,600,700,800,900],\"Trispace\":[100,200,300,400,500,600,700,800],\"Trocchi\":[400],\"Trochut\":[400,700],\"Truculenta\":[100,200,300,400,500,600,700,800,900],\"Trykker\":[400],\"Tsukimi Rounded\":[300,400,500,600,700],\"Tuffy\":[400,700],\"Tulpen One\":[400],\"Turret Road\":[200,300,400,500,700,800],\"Twinkle Star\":[400],\"Ubuntu\":[300,400,500,700],\"Ubuntu Condensed\":[400],\"Ubuntu Mono\":[400,700],\"Ubuntu Sans\":[100,200,300,400,500,600,700,800],\"Ubuntu Sans Mono\":[400,500,600,700],\"Uchen\":[400],\"Ultra\":[400],\"Unbounded\":[200,300,400,500,600,700,800,900],\"Uncial Antiqua\":[400],\"Underdog\":[400],\"Unica One\":[400],\"UnifrakturCook\":[700],\"UnifrakturMaguntia\":[400],\"Unkempt\":[400,700],\"Unlock\":[400],\"Unna\":[400,700],\"UoqMunThenKhung\":[400],\"Updock\":[400],\"Urbanist\":[100,200,300,400,500,600,700,800,900],\"Vampiro One\":[400],\"Varela\":[400],\"Varela Round\":[400],\"Varta\":[300,400,500,600,700],\"Vast Shadow\":[400],\"Vazirmatn\":[100,200,300,400,500,600,700,800,900],\"Vend Sans\":[300,400,500,600,700],\"Vesper Libre\":[400,500,700,900],\"Viaoda Libre\":[400],\"Vibes\":[400],\"Vibur\":[400],\"Victor Mono\":[100,200,300,400,500,600,700],\"Vidaloka\":[400],\"Viga\":[400],\"Vina Sans\":[400],\"Voces\":[400],\"Volkhov\":[400,700],\"Vollkorn\":[400,500,600,700,800,900],\"Vollkorn SC\":[400,600,700,900],\"Voltaire\":[400],\"VT323\":[400],\"Vujahday Script\":[400],\"Waiting for the Sunrise\":[400],\"Wallpoet\":[400],\"Walter Turncoat\":[400],\"Warnes\":[400],\"Water Brush\":[400],\"Waterfall\":[400],\"Wavefont\":[100,200,300,400,500,600,700,800,900],\"WDXL Lubrifont JP N\":[400],\"WDXL Lubrifont SC\":[400],\"WDXL Lubrifont TC\":[400],\"Wellfleet\":[400],\"Wendy One\":[400],\"Whisper\":[400],\"WindSong\":[400,500],\"Winky Rough\":[300,400,500,600,700,800,900],\"Winky Sans\":[300,400,500,600,700,800,900],\"Wire One\":[400],\"Wittgenstein\":[400,500,600,700,800,900],\"Wix Madefor Display\":[400,500,600,700,800],\"Wix Madefor Text\":[400,500,600,700,800],\"Work Sans\":[100,200,300,400,500,600,700,800,900],\"Workbench\":[400],\"Xanh Mono\":[400],\"Yaldevi\":[200,300,400,500,600,700],\"Yanone Kaffeesatz\":[200,300,400,500,600,700],\"Yantramanav\":[100,300,400,500,700,900],\"Yarndings 12\":[400],\"Yarndings 12 Charted\":[400],\"Yarndings 20\":[400],\"Yarndings 20 Charted\":[400],\"Yatra One\":[400],\"Yellowtail\":[400],\"Yeon Sung\":[400],\"Yeseva One\":[400],\"Yesteryear\":[400],\"Yomogi\":[400],\"Young Serif\":[400],\"Yrsa\":[300,400,500,600,700],\"Ysabeau\":[100,200,300,400,500,600,700,800,900],\"Ysabeau Infant\":[100,200,300,400,500,600,700,800,900],\"Ysabeau Office\":[100,200,300,400,500,600,700,800,900],\"Ysabeau SC\":[100,200,300,400,500,600,700,800,900],\"Yuji Boku\":[400],\"Yuji Hentaigana Akari\":[400],\"Yuji Hentaigana Akebono\":[400],\"Yuji Mai\":[400],\"Yuji Syuku\":[400],\"Yusei Magic\":[400],\"Zain\":[200,300,400,700,800,900],\"Zalando Sans\":[200,300,400,500,600,700,800,900],\"Zalando Sans Expanded\":[200,300,400,500,600,700,800,900],\"Zalando Sans SemiExpanded\":[200,300,400,500,600,700,800,900],\"ZCOOL KuaiLe\":[400],\"ZCOOL QingKe HuangYou\":[400],\"ZCOOL XiaoWei\":[400],\"Zen Antique\":[400],\"Zen Antique Soft\":[400],\"Zen Dots\":[400],\"Zen Kaku Gothic Antique\":[300,400,500,700,900],\"Zen Kaku Gothic New\":[300,400,500,700,900],\"Zen Kurenaido\":[400],\"Zen Loop\":[400],\"Zen Maru Gothic\":[300,400,500,700,900],\"Zen Old Mincho\":[400,500,600,700,900],\"Zen Tokyo Zoo\":[400],\"Zeyada\":[400],\"Zhi Mang Xing\":[400],\"Zilla Slab\":[300,400,500,600,700],\"Zilla Slab Highlight\":[400,700]};\n","// bunny-fonts.ts\n// AUTO-GENERATED by scripts/build-fonts.mjs — do not edit by hand.\n// Loaded by editor/src/font-sources.ts; the loader uses priority dispatch so\n// only families NOT already in google-fonts.ts are included (Google-overlap\n// would be unreachable dead weight in the bundle).\n\nexport interface BunnyFont {\n family: string;\n slug: string;\n weights: number[];\n italics: boolean;\n category?: string;\n}\n\nexport const BUNNY_FONTS: ReadonlyArray<BunnyFont> = [\n { family: \"42dot Sans\", slug: \"42dot-sans\", weights: [300,400,500,600,700,800], italics: false, category: \"sans-serif\" },\n { family: \"Arima Madurai\", slug: \"arima-madurai\", weights: [100,200,300,400,500,700,800,900], italics: false, category: \"display\" },\n { family: \"BBH Sans Bartle\", slug: \"bbh-sans-bartle\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"BBH Sans Bogle\", slug: \"bbh-sans-bogle\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"BBH Sans Hegarty\", slug: \"bbh-sans-hegarty\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Big Shoulders Display\", slug: \"big-shoulders-display\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Inline Display\", slug: \"big-shoulders-inline-display\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Inline Text\", slug: \"big-shoulders-inline-text\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Stencil Display\", slug: \"big-shoulders-stencil-display\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Stencil Text\", slug: \"big-shoulders-stencil-text\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Text\", slug: \"big-shoulders-text\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Briem Hand\", slug: \"briem-hand\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"handwriting\" },\n { family: \"Coda Caption\", slug: \"coda-caption\", weights: [800], italics: false, category: \"sans-serif\" },\n { family: \"Finlandica\", slug: \"finlandica\", weights: [400,500,600,700], italics: true, category: \"sans-serif\" },\n { family: \"Fredoka One\", slug: \"fredoka-one\", weights: [400], italics: false, category: \"display\" },\n { family: \"Gentium Book Basic\", slug: \"gentium-book-basic\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Kantumruy\", slug: \"kantumruy\", weights: [300,400,700], italics: false, category: \"sans-serif\" },\n { family: \"Material Symbols\", slug: \"material-symbols\", weights: [100,200,300,400,500,600,700], italics: false, category: \"monospace\" },\n { family: \"Merienda One\", slug: \"merienda-one\", weights: [400], italics: false, category: \"handwriting\" },\n { family: \"Montserrat Subrayada\", slug: \"montserrat-subrayada\", weights: [400,700], italics: false, category: \"sans-serif\" },\n { family: \"Noto Sans Phags Pa\", slug: \"noto-sans-phags-pa\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Pushster\", slug: \"pushster\", weights: [400], italics: false, category: \"display\" },\n { family: \"Saira Stencil One\", slug: \"saira-stencil-one\", weights: [400], italics: false, category: \"display\" },\n { family: \"Source Sans Pro\", slug: \"source-sans-pro\", weights: [200,300,400,600,700,900], italics: true, category: \"sans-serif\" },\n { family: \"Source Serif Pro\", slug: \"source-serif-pro\", weights: [200,300,400,600,700,900], italics: true, category: \"serif\" },\n];\n","// fontshare-fonts.ts\n// AUTO-GENERATED by scripts/build-fonts.mjs — do not edit by hand.\n// Loaded by editor/src/font-sources.ts; the loader uses priority dispatch so\n// only families NOT already in google-fonts.ts are included (Google-overlap\n// would be unreachable dead weight in the bundle).\n\nexport interface FontshareFont {\n family: string;\n slug: string;\n weights: number[];\n italics: boolean;\n category?: string;\n}\n\nexport const FONTSHARE_FONTS: ReadonlyArray<FontshareFont> = [\n { family: \"Aktura\", slug: \"aktura\", weights: [400], italics: false, category: \"serif, blackletter, display\" },\n { family: \"Alpino\", slug: \"alpino\", weights: [0,100,300,400,500,700,900], italics: false, category: \"sans\" },\n { family: \"Amulya\", slug: \"amulya\", weights: [0,300,400,500,700], italics: true, category: \"sans\" },\n { family: \"Array\", slug: \"array\", weights: [400,600,700], italics: false, category: \"display\" },\n { family: \"Author\", slug: \"author\", weights: [0,200,300,400,500,600,700], italics: true, category: \"sans\" },\n { family: \"Bespoke Sans\", slug: \"bespoke-sans\", weights: [0,300,400,500,700,800], italics: true, category: \"sans\" },\n { family: \"Bespoke Serif\", slug: \"bespoke-serif\", weights: [0,300,400,500,700,800], italics: true, category: \"serif\" },\n { family: \"Bespoke Slab\", slug: \"bespoke-slab\", weights: [0,300,400,500,700,800], italics: true, category: \"slab\" },\n { family: \"Bespoke Stencil\", slug: \"bespoke-stencil\", weights: [0,300,400,500,700,800], italics: true, category: \"sans\" },\n { family: \"Bevellier\", slug: \"bevellier\", weights: [0,100,200,300,400,500,600,700,900], italics: true, category: \"display\" },\n { family: \"Bonny\", slug: \"bonny\", weights: [0,100,300,400,500,700], italics: false, category: \"serif\" },\n { family: \"Boska\", slug: \"boska\", weights: [0,200,300,400,500,700,900], italics: true, category: \"serif, display\" },\n { family: \"Boxing\", slug: \"boxing\", weights: [400], italics: false, category: \"display\" },\n { family: \"Britney\", slug: \"britney\", weights: [0,300,400,700,1000], italics: false, category: \"script\" },\n { family: \"Cabinet Grotesk\", slug: \"cabinet-grotesk\", weights: [0,100,200,300,400,500,700,800,900], italics: false, category: \"sans\" },\n { family: \"Chillax\", slug: \"chillax\", weights: [0,200,300,400,500,600,700], italics: false, category: \"sans\" },\n { family: \"Chubbo\", slug: \"chubbo\", weights: [0,200,300,400,500,700], italics: true, category: \"display\" },\n { family: \"Clash Display\", slug: \"clash-display\", weights: [0,200,300,400,500,600,700], italics: false, category: \"sans\" },\n { family: \"Clash Grotesk\", slug: \"clash-grotesk\", weights: [0,200,300,400,500,600,700], italics: false, category: \"sans\" },\n { family: \"Comico\", slug: \"comico\", weights: [400], italics: false, category: \"handwritten\" },\n { family: \"Erode\", slug: \"erode\", weights: [0,300,400,500,600,700], italics: true, category: \"serif\" },\n { family: \"Excon\", slug: \"excon\", weights: [0,100,300,400,500,700,900], italics: false, category: \"sans\" },\n { family: \"Expose\", slug: \"expose\", weights: [0,400,500,700,900], italics: false, category: \"sans\" },\n { family: \"Gambarino\", slug: \"gambarino\", weights: [400], italics: false, category: \"serif\" },\n { family: \"Gambetta\", slug: \"gambetta\", weights: [0,300,400,500,600,700], italics: true, category: \"serif\" },\n { family: \"General Sans\", slug: \"general-sans\", weights: [0,200,300,400,500,600,700], italics: true, category: \"sans\" },\n { family: \"Hoover\", slug: \"hoover\", weights: [0,100,300,400,500,700], italics: false, category: \"slab\" },\n { family: \"Kihim\", slug: \"kihim\", weights: [400], italics: false, category: \"display\" },\n { family: \"Kohinoor Zerone\", slug: \"kohinoor-zerone\", weights: [100,200], italics: false, category: \"display\" },\n { family: \"Kola\", slug: \"kola\", weights: [400], italics: false, category: \"display\" },\n { family: \"Melodrama\", slug: \"melodrama\", weights: [0,300,400,500,600,700], italics: false, category: \"sans, display\" },\n { family: \"Neco\", slug: \"neco\", weights: [0,400,500,700,900], italics: true, category: \"serif\" },\n { family: \"New Title\", slug: \"new-title\", weights: [0,200,300,400,500,700], italics: false, category: \"sans, display\" },\n { family: \"Nippo\", slug: \"nippo\", weights: [0,200,300,400,500,700], italics: false, category: \"display\" },\n { family: \"Pally\", slug: \"pally\", weights: [0,400,500,700], italics: false, category: \"sans\" },\n { family: \"Panchang\", slug: \"panchang\", weights: [0,200,300,400,500,600,700,800], italics: false, category: \"sans\" },\n { family: \"Paquito\", slug: \"paquito\", weights: [0,400,500,700], italics: false, category: \"serif, slab\" },\n { family: \"Pencerio\", slug: \"pencerio\", weights: [50], italics: false, category: \"script\" },\n { family: \"Pilcrow Rounded\", slug: \"pilcrow-rounded\", weights: [0,400,500,600,700,900], italics: false, category: \"sans\" },\n { family: \"Plein\", slug: \"plein\", weights: [0,300,400,500,700,900], italics: true, category: \"sans\" },\n { family: \"Pramukh Rounded\", slug: \"pramukh-rounded\", weights: [0,200,300,350,400,600,700,800,900], italics: true, category: \"sans\" },\n { family: \"Quilon\", slug: \"quilon\", weights: [0,400,500,600,700], italics: false, category: \"sans\" },\n { family: \"Ranade\", slug: \"ranade\", weights: [0,100,300,400,500,700], italics: true, category: \"sans\" },\n { family: \"Recia\", slug: \"recia\", weights: [0,300,400,500,600,700], italics: true, category: \"serif\" },\n { family: \"Rosaline\", slug: \"rosaline\", weights: [400], italics: false, category: \"script\" },\n { family: \"Roundo\", slug: \"roundo\", weights: [0,200,300,400,500,600,700], italics: false, category: \"sans\" },\n { family: \"Rowan\", slug: \"rowan\", weights: [0,300,400,500,600,700], italics: true, category: \"serif\" },\n { family: \"RX100\", slug: \"rx-100\", weights: [400], italics: false, category: \"sans\" },\n { family: \"Satoshi\", slug: \"satoshi\", weights: [0,300,400,500,700,900], italics: true, category: \"sans\" },\n { family: \"Segment\", slug: \"segment\", weights: [400], italics: false, category: \"display\" },\n { family: \"Sentient\", slug: \"sentient\", weights: [0,200,300,400,500,700], italics: true, category: \"serif\" },\n { family: \"Sharpie\", slug: \"sharpie\", weights: [0,300,400,700,800,900], italics: false, category: \"display\" },\n { family: \"Stardom\", slug: \"stardom\", weights: [400], italics: false, category: \"display\" },\n { family: \"Striper\", slug: \"striper\", weights: [400], italics: false, category: \"display\" },\n { family: \"Styro\", slug: \"styro\", weights: [0,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Supreme\", slug: \"supreme\", weights: [0,100,200,300,400,500,700,800], italics: true, category: \"sans\" },\n { family: \"Switzer\", slug: \"switzer\", weights: [0,100,200,300,400,500,600,700,800,900], italics: true, category: \"sans\" },\n { family: \"Synonym\", slug: \"synonym\", weights: [0,200,300,400,500,600,700], italics: false, category: \"sans\" },\n { family: \"Tabular\", slug: \"tabular\", weights: [0,300,400,500,600,700], italics: true, category: \"sans\" },\n { family: \"Tanker\", slug: \"tanker\", weights: [400], italics: false, category: \"sans\" },\n { family: \"Technor\", slug: \"technor\", weights: [0,200,300,400,500,600,700,900], italics: false, category: \"sans\" },\n { family: \"Telma\", slug: \"telma\", weights: [0,300,400,500,700,900], italics: false, category: \"script\" },\n { family: \"Trench Slab\", slug: \"trench-slab\", weights: [0,300,400,500,600,700], italics: false, category: \"slab\" },\n { family: \"Zina\", slug: \"zina\", weights: [400], italics: false, category: \"display\" },\n { family: \"Zodiak\", slug: \"zodiak\", weights: [0,100,300,400,700,800,900], italics: true, category: \"serif\" },\n];\n","// fontsource-fonts.ts\n// AUTO-GENERATED by scripts/build-fonts.mjs — do not edit by hand.\n// Loaded by editor/src/font-sources.ts; the loader uses priority dispatch so\n// only families NOT already in google-fonts.ts are included (Google-overlap\n// would be unreachable dead weight in the bundle).\n\nexport interface FontsourceFont {\n family: string;\n slug: string;\n weights: number[];\n italics: boolean;\n category?: string;\n}\n\nexport const FONTSOURCE_FONTS: ReadonlyArray<FontsourceFont> = [\n { family: \"42dot Sans\", slug: \"42dot-sans\", weights: [300,400,500,600,700,800], italics: false, category: \"sans-serif\" },\n { family: \"Adwaita Mono\", slug: \"adwaita-mono\", weights: [400,700], italics: true, category: \"monospace\" },\n { family: \"Adwaita Sans\", slug: \"adwaita-sans\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"sans-serif\" },\n { family: \"Aileron\", slug: \"aileron\", weights: [100,300,400,600,700,800], italics: true, category: \"sans-serif\" },\n { family: \"Apfel Grotezk\", slug: \"apfel-grotezk\", weights: [400,700], italics: false, category: \"sans-serif\" },\n { family: \"Argentum Sans\", slug: \"argentum-sans\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"sans-serif\" },\n { family: \"Arima Madurai\", slug: \"arima-madurai\", weights: [100,200,300,400,500,700,800,900], italics: false, category: \"display\" },\n { family: \"Bagnard\", slug: \"bagnard\", weights: [400], italics: false, category: \"serif\" },\n { family: \"Bagnard Sans\", slug: \"bagnard-sans\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"BBH Sans Bartle\", slug: \"bbh-sans-bartle\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"BBH Sans Bogle\", slug: \"bbh-sans-bogle\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"BBH Sans Hegarty\", slug: \"bbh-sans-hegarty\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Big Shoulders Display\", slug: \"big-shoulders-display\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Inline Display\", slug: \"big-shoulders-inline-display\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Inline Text\", slug: \"big-shoulders-inline-text\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Stencil Display\", slug: \"big-shoulders-stencil-display\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Stencil Text\", slug: \"big-shoulders-stencil-text\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"Big Shoulders Text\", slug: \"big-shoulders-text\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"display\" },\n { family: \"BJ Cree\", slug: \"bj-cree\", weights: [400,500,600,700], italics: false, category: \"serif\" },\n { family: \"Blackout Midnight\", slug: \"blackout-midnight\", weights: [400], italics: false, category: \"display\" },\n { family: \"Blackout Sunrise\", slug: \"blackout-sunrise\", weights: [400], italics: false, category: \"display\" },\n { family: \"Blackout Two AM\", slug: \"blackout-two-am\", weights: [400], italics: false, category: \"display\" },\n { family: \"Bluu Next\", slug: \"bluu-next\", weights: [700], italics: true, category: \"sans-serif\" },\n { family: \"Bravura\", slug: \"bravura\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Bravura Text\", slug: \"bravura-text\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Briem Hand\", slug: \"briem-hand\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"handwriting\" },\n { family: \"Chunk Five\", slug: \"chunk-five\", weights: [800], italics: false, category: \"serif\" },\n { family: \"Clear Sans\", slug: \"clear-sans\", weights: [100,300,400,500,700], italics: true, category: \"sans-serif\" },\n { family: \"Coda Caption\", slug: \"coda-caption\", weights: [800], italics: false, category: \"sans-serif\" },\n { family: \"Comic Mono\", slug: \"comic-mono\", weights: [400,700], italics: false, category: \"monospace\" },\n { family: \"Commit Mono\", slug: \"commit-mono\", weights: [200,300,400,500,600,700], italics: true, category: \"monospace\" },\n { family: \"Cooper Hewitt\", slug: \"cooper-hewitt\", weights: [100,200,300,400,500,600,700,800], italics: true, category: \"sans-serif\" },\n { family: \"DejaVu Math\", slug: \"dejavu-math\", weights: [400], italics: false, category: \"display\" },\n { family: \"DejaVu Mono\", slug: \"dejavu-mono\", weights: [400,700], italics: true, category: \"monospace\" },\n { family: \"DejaVu Sans\", slug: \"dejavu-sans\", weights: [400,700], italics: true, category: \"sans-serif\" },\n { family: \"DejaVu Serif\", slug: \"dejavu-serif\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"DSEG Weather\", slug: \"dseg-weather\", weights: [400], italics: false, category: \"other\" },\n { family: \"DSEG14 Classic\", slug: \"dseg14-classic\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG14 Classic Mini\", slug: \"dseg14-classic-mini\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG14 Modern\", slug: \"dseg14-modern\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG14 Modern Mini\", slug: \"dseg14-modern-mini\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG7 Classic\", slug: \"dseg7-classic\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG7 Classic Mini\", slug: \"dseg7-classic-mini\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG7 Modern\", slug: \"dseg7-modern\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG7 Modern Mini\", slug: \"dseg7-modern-mini\", weights: [300,400,700], italics: true, category: \"other\" },\n { family: \"DSEG7 SEGG CHAN\", slug: \"dseg7-segg-chan\", weights: [400], italics: false, category: \"other\" },\n { family: \"DSEG7 SEGG CHAN Mini\", slug: \"dseg7-segg-chan-mini\", weights: [400], italics: false, category: \"other\" },\n { family: \"Finlandica\", slug: \"finlandica\", weights: [400,500,600,700], italics: true, category: \"sans-serif\" },\n { family: \"FiraGO\", slug: \"firago\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"sans-serif\" },\n { family: \"Fredoka One\", slug: \"fredoka-one\", weights: [400], italics: false, category: \"display\" },\n { family: \"Fusion Kai G\", slug: \"fusion-kai-g\", weights: [400], italics: false, category: \"handwriting\" },\n { family: \"Fusion Kai J\", slug: \"fusion-kai-j\", weights: [400], italics: false, category: \"handwriting\" },\n { family: \"Fusion Kai T\", slug: \"fusion-kai-t\", weights: [400], italics: false, category: \"handwriting\" },\n { family: \"Fusion Pixel 10px Monospaced JP\", slug: \"fusion-pixel-10px-monospaced-jp\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 10px Monospaced KR\", slug: \"fusion-pixel-10px-monospaced-kr\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 10px Monospaced SC\", slug: \"fusion-pixel-10px-monospaced-sc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 10px Monospaced TC\", slug: \"fusion-pixel-10px-monospaced-tc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 10px Proportional JP\", slug: \"fusion-pixel-10px-proportional-jp\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 10px Proportional KR\", slug: \"fusion-pixel-10px-proportional-kr\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 10px Proportional SC\", slug: \"fusion-pixel-10px-proportional-sc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 10px Proportional TC\", slug: \"fusion-pixel-10px-proportional-tc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Monospaced JP\", slug: \"fusion-pixel-12px-monospaced-jp\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Monospaced KR\", slug: \"fusion-pixel-12px-monospaced-kr\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Monospaced SC\", slug: \"fusion-pixel-12px-monospaced-sc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Monospaced TC\", slug: \"fusion-pixel-12px-monospaced-tc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Proportional JP\", slug: \"fusion-pixel-12px-proportional-jp\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Proportional KR\", slug: \"fusion-pixel-12px-proportional-kr\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Proportional SC\", slug: \"fusion-pixel-12px-proportional-sc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 12px Proportional TC\", slug: \"fusion-pixel-12px-proportional-tc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Monospaced JP\", slug: \"fusion-pixel-8px-monospaced-jp\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Monospaced KR\", slug: \"fusion-pixel-8px-monospaced-kr\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Monospaced SC\", slug: \"fusion-pixel-8px-monospaced-sc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Monospaced TC\", slug: \"fusion-pixel-8px-monospaced-tc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Proportional JP\", slug: \"fusion-pixel-8px-proportional-jp\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Proportional KR\", slug: \"fusion-pixel-8px-proportional-kr\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Proportional SC\", slug: \"fusion-pixel-8px-proportional-sc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Fusion Pixel 8px Proportional TC\", slug: \"fusion-pixel-8px-proportional-tc\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Geist Sans\", slug: \"geist-sans\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"sans-serif\" },\n { family: \"Genjyuu Gothic\", slug: \"genjyuu-gothic\", weights: [100,200,300,400,500,700,900], italics: false, category: \"sans-serif\" },\n { family: \"Gentium Book Basic\", slug: \"gentium-book-basic\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Hauora Sans\", slug: \"hauora-sans\", weights: [200,300,400,500,600,700,800], italics: false, category: \"sans-serif\" },\n { family: \"iA Writer Duo\", slug: \"ia-writer-duo\", weights: [400,700], italics: true, category: \"monospace\" },\n { family: \"iA Writer Mono\", slug: \"ia-writer-mono\", weights: [400,700], italics: true, category: \"monospace\" },\n { family: \"iA Writer Quattro\", slug: \"ia-writer-quattro\", weights: [400,700], italics: true, category: \"sans-serif\" },\n { family: \"Iosevka\", slug: \"iosevka\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"monospace\" },\n { family: \"Iosevka Aile\", slug: \"iosevka-aile\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"monospace\" },\n { family: \"Iosevka Curly\", slug: \"iosevka-curly\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"monospace\" },\n { family: \"Iosevka Curly Slab\", slug: \"iosevka-curly-slab\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"monospace\" },\n { family: \"Iosevka Etoile\", slug: \"iosevka-etoile\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"monospace\" },\n { family: \"Junction\", slug: \"junction\", weights: [300,400,700], italics: false, category: \"sans-serif\" },\n { family: \"Karmilla\", slug: \"karmilla\", weights: [400,700], italics: false, category: \"sans-serif\" },\n { family: \"League Mono\", slug: \"league-mono\", weights: [100,200,300,400,500,600,700,800], italics: false, category: \"monospace\" },\n { family: \"Lextrall\", slug: \"lextrall\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"sans-serif\" },\n { family: \"Libre Caslon Condensed\", slug: \"libre-caslon-condensed\", weights: [400,500,600,700], italics: true, category: \"serif\" },\n { family: \"LXGW WenKai\", slug: \"lxgw-wenkai\", weights: [300,500,700], italics: false, category: \"sans-serif\" },\n { family: \"Maple Mono\", slug: \"maple-mono\", weights: [100,200,300,400,500,600,700,800], italics: true, category: \"monospace\" },\n { family: \"Material Icons\", slug: \"material-icons\", weights: [400], italics: false, category: \"icons\" },\n { family: \"Material Icons Outlined\", slug: \"material-icons-outlined\", weights: [400], italics: false, category: \"icons\" },\n { family: \"Material Icons Round\", slug: \"material-icons-round\", weights: [400], italics: false, category: \"icons\" },\n { family: \"Material Icons Sharp\", slug: \"material-icons-sharp\", weights: [400], italics: false, category: \"icons\" },\n { family: \"Material Icons Two Tone\", slug: \"material-icons-two-tone\", weights: [400], italics: false, category: \"icons\" },\n { family: \"Material Symbols\", slug: \"material-symbols\", weights: [100,200,300,400,500,600,700], italics: false, category: \"monospace\" },\n { family: \"Material Symbols Outlined\", slug: \"material-symbols-outlined\", weights: [100,200,300,400,500,600,700], italics: false, category: \"icons\" },\n { family: \"Material Symbols Rounded\", slug: \"material-symbols-rounded\", weights: [100,200,300,400,500,600,700], italics: false, category: \"icons\" },\n { family: \"Material Symbols Sharp\", slug: \"material-symbols-sharp\", weights: [100,200,300,400,500,600,700], italics: false, category: \"icons\" },\n { family: \"Merienda One\", slug: \"merienda-one\", weights: [400], italics: false, category: \"handwriting\" },\n { family: \"Metropolis\", slug: \"metropolis\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"sans-serif\" },\n { family: \"Monaspace Argon\", slug: \"monaspace-argon\", weights: [200,300,400,500,600,700,800], italics: true, category: \"monospace\" },\n { family: \"Monaspace Krypton\", slug: \"monaspace-krypton\", weights: [200,300,400,500,600,700,800], italics: true, category: \"monospace\" },\n { family: \"Monaspace Neon\", slug: \"monaspace-neon\", weights: [200,300,400,500,600,700,800], italics: true, category: \"monospace\" },\n { family: \"Monaspace Radon\", slug: \"monaspace-radon\", weights: [200,300,400,500,600,700,800], italics: true, category: \"handwriting\" },\n { family: \"Monaspace Xenon\", slug: \"monaspace-xenon\", weights: [200,300,400,500,600,700,800], italics: true, category: \"serif\" },\n { family: \"Mononoki\", slug: \"mononoki\", weights: [400,700], italics: true, category: \"monospace\" },\n { family: \"Montserrat Subrayada\", slug: \"montserrat-subrayada\", weights: [400,700], italics: false, category: \"sans-serif\" },\n { family: \"Nebula Sans\", slug: \"nebula-sans\", weights: [300,400,500,600,700,900], italics: true, category: \"sans-serif\" },\n { family: \"Norwester\", slug: \"norwester\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Noto Mono\", slug: \"noto-mono\", weights: [400], italics: false, category: \"monospace\" },\n { family: \"Open Runde\", slug: \"open-runde\", weights: [400,500,600,700], italics: false, category: \"sans-serif\" },\n { family: \"Open Sauce One\", slug: \"open-sauce-one\", weights: [300,400,500,600,700,800,900], italics: true, category: \"sans-serif\" },\n { family: \"Open Sauce Sans\", slug: \"open-sauce-sans\", weights: [300,400,500,600,700,800,900], italics: true, category: \"sans-serif\" },\n { family: \"Open Sauce Two\", slug: \"open-sauce-two\", weights: [300,400,500,600,700,800,900], italics: true, category: \"sans-serif\" },\n { family: \"OpenDyslexic\", slug: \"opendyslexic\", weights: [400,700], italics: true, category: \"sans-serif\" },\n { family: \"Ostrich Sans\", slug: \"ostrich-sans\", weights: [300,400,700,900], italics: false, category: \"sans-serif\" },\n { family: \"Peace Sans\", slug: \"peace-sans\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Pitagon Sans\", slug: \"pitagon-sans\", weights: [400,500,600,700,800,900], italics: false, category: \"sans-serif\" },\n { family: \"Pitagon Sans Mono\", slug: \"pitagon-sans-mono\", weights: [100,200,300,400,500,600,700,800], italics: true, category: \"monospace\" },\n { family: \"Pitagon Sans Text\", slug: \"pitagon-sans-text\", weights: [200,300,400,500,600,700,800], italics: true, category: \"sans-serif\" },\n { family: \"Pitagon Serif\", slug: \"pitagon-serif\", weights: [100,200,300,400,500,600,700,800,900], italics: true, category: \"serif\" },\n { family: \"Pretendard\", slug: \"pretendard\", weights: [100,200,300,400,500,600,700,800,900], italics: false, category: \"sans-serif\" },\n { family: \"Pushster\", slug: \"pushster\", weights: [400], italics: false, category: \"display\" },\n { family: \"Redaction\", slug: \"redaction\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Redaction 10\", slug: \"redaction-10\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Redaction 100\", slug: \"redaction-100\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Redaction 20\", slug: \"redaction-20\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Redaction 35\", slug: \"redaction-35\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Redaction 50\", slug: \"redaction-50\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Redaction 70\", slug: \"redaction-70\", weights: [400,700], italics: true, category: \"serif\" },\n { family: \"Rubik One\", slug: \"rubik-one\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"Saira Stencil One\", slug: \"saira-stencil-one\", weights: [400], italics: false, category: \"display\" },\n { family: \"Source Sans Pro\", slug: \"source-sans-pro\", weights: [200,300,400,600,700,900], italics: true, category: \"sans-serif\" },\n { family: \"Source Serif Pro\", slug: \"source-serif-pro\", weights: [200,300,400,600,700,900], italics: true, category: \"serif\" },\n { family: \"Syne Italic\", slug: \"syne-italic\", weights: [400], italics: true, category: \"sans-serif\" },\n { family: \"Uncut Sans\", slug: \"uncut-sans\", weights: [300,400,500,600,700], italics: true, category: \"sans-serif\" },\n { family: \"Unifont\", slug: \"unifont\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"UnifontEX\", slug: \"unifontex\", weights: [400], italics: false, category: \"monospace\" },\n { family: \"WIN95FA\", slug: \"win95fa\", weights: [400], italics: false, category: \"sans-serif\" },\n { family: \"YakuHanJP\", slug: \"yakuhanjp\", weights: [100,200,300,400,500,700,900], italics: false, category: \"other\" },\n { family: \"YakuHanJPs\", slug: \"yakuhanjps\", weights: [100,200,300,400,500,700,900], italics: false, category: \"other\" },\n { family: \"YakuHanMP\", slug: \"yakuhanmp\", weights: [100,200,300,400,500,700,900], italics: false, category: \"other\" },\n { family: \"YakuHanMPs\", slug: \"yakuhanmps\", weights: [100,200,300,400,500,700,900], italics: false, category: \"other\" },\n { family: \"YakuHanRP\", slug: \"yakuhanrp\", weights: [100,300,400,500,700,800,900], italics: false, category: \"other\" },\n { family: \"YakuHanRPs\", slug: \"yakuhanrps\", weights: [100,300,400,500,700,800,900], italics: false, category: \"other\" },\n];\n","// velvetyne-fonts.ts\n//\n// Curated catalog of Velvetyne (https://velvetyne.fr/) libre faces. Velvetyne\n// has no public catalog API; we ship a hand-picked set served via jsDelivr's\n// GitHub mirror (https://cdn.jsdelivr.net/gh/velvetyne/…). Adding a face\n// means picking a repo, finding its `*.woff2` (or `.woff`) path with the\n// GitHub tree API, and slotting it in below. URLs are stable as long as the\n// upstream repo keeps the file.\n//\n// Unlike Bunny / Fontshare / Fontsource (CSS endpoints), Velvetyne faces are\n// loaded by the editor via the FontFace API — each entry below lists the\n// faces explicitly so a (family, weight, italic) request can be served.\n\nexport interface VelvetyneFace {\n weight: number;\n italic: boolean;\n src: string;\n}\n\nexport interface VelvetyneFont {\n family: string;\n weights: number[];\n italics: boolean;\n category?: string;\n faces: VelvetyneFace[];\n}\n\nconst GH = \"https://cdn.jsdelivr.net/gh/velvetyne\";\n\nexport const VELVETYNE_FONTS: ReadonlyArray<VelvetyneFont> = [\n {\n family: \"Bluu Next\",\n weights: [700],\n italics: true,\n category: \"display\",\n faces: [\n {\n weight: 700,\n italic: false,\n src: `${GH}/BluuNext@master/Fonts/webfonts/bluunext-bold-webfont.woff2`,\n },\n {\n weight: 700,\n italic: true,\n src: `${GH}/BluuNext@master/Fonts/webfonts/bluunext-bolditalic-webfont.woff2`,\n },\n ],\n },\n {\n family: \"Sporting Grotesque\",\n weights: [400, 700],\n italics: false,\n category: \"sans-serif\",\n faces: [\n {\n weight: 400,\n italic: false,\n src: `${GH}/Sporting-Grotesque@main/webfonts/Regular/Sporting_Grotesque-Regular_web.woff2`,\n },\n {\n weight: 700,\n italic: false,\n src: `${GH}/Sporting-Grotesque@main/webfonts/Bold/Sporting_Grotesque-Bold_web.woff2`,\n },\n ],\n },\n {\n family: \"Trickster\",\n weights: [400],\n italics: false,\n category: \"display\",\n faces: [\n {\n weight: 400,\n italic: false,\n src: `${GH}/Trickster@master/webfonts/Trickster-Regular.woff2`,\n },\n ],\n },\n {\n family: \"BilboINC\",\n weights: [400],\n italics: false,\n category: \"display\",\n faces: [\n {\n weight: 400,\n italic: false,\n src: `${GH}/BilboINC@master/Fonts/webfonts/BilboINC-Regular_web.woff2`,\n },\n ],\n },\n {\n family: \"Daubenton\",\n weights: [400],\n italics: false,\n category: \"serif\",\n faces: [\n {\n // Daubenton ships .woff only (no .woff2). The FontFace API decodes\n // .woff fine across modern browsers — slightly larger payload.\n weight: 400,\n italic: false,\n src: `${GH}/Daubenton@master/fonts/webfonts/daubentonwebfont.woff`,\n },\n ],\n },\n];\n","// Font source registry — Google + Bunny + Fontshare + Fontsource + Velvetyne.\n//\n// Each source ships a static family catalog (a sibling `<source>-fonts.ts`\n// module, refreshed by `scripts/build-fonts.mjs`). At load time the editor\n// looks up a family's source via `getFontSource(family)` and dispatches to\n// the right URL pattern:\n//\n// google → fonts.googleapis.com/css2 (per-face)\n// bunny → fonts.bunny.net/css (per-face, Google-compatible)\n// fontshare → api.fontshare.com/v2/css (one URL per family, all weights)\n// fontsource → cdn.jsdelivr.net/fontsource (one URL per family, all weights)\n// velvetyne → direct font file URLs (FontFace API, per-face)\n//\n// Overlap rule: when a family exists in more than one catalog, the first\n// hit in PRIORITY order wins. Google is the priority root because the existing\n// loader path is well-tested; the other sources only \"own\" their EXCLUSIVE\n// families. The picker uses the same priority to dedupe what it lists.\n\nimport { GOOGLE_FONTS } from \"./google-fonts.ts\";\nimport { BUNNY_FONTS } from \"./bunny-fonts.ts\";\nimport { FONTSHARE_FONTS } from \"./fontshare-fonts.ts\";\nimport { FONTSOURCE_FONTS } from \"./fontsource-fonts.ts\";\nimport { VELVETYNE_FONTS } from \"./velvetyne-fonts.ts\";\n\nexport type FontSource =\n | \"google\"\n | \"bunny\"\n | \"fontshare\"\n | \"fontsource\"\n | \"velvetyne\";\n\n// A single (weight, italic) face for sources that load files directly\n// (Velvetyne). Other sources resolve faces via their CSS endpoint.\nexport interface FontFaceFile {\n weight: number;\n italic: boolean;\n /** Direct font file URL (woff2 preferred). */\n src: string;\n}\n\n// One family in a source's catalog. Slug is the source-specific URL token\n// (e.g. Bunny \"be-vietnam-pro\" for \"Be Vietnam Pro\"); Fontshare/Fontsource\n// also use slugs. Velvetyne has no slug — its faces are explicit file URLs.\nexport interface FontCatalogEntry {\n family: string;\n source: FontSource;\n /** Slug used in the source's URL pattern. Optional for Velvetyne. */\n slug?: string;\n /** Available numeric weights (no italic flag — italic is a separate axis). */\n weights: number[];\n /** True if any italic face is available. */\n italics: boolean;\n /** Velvetyne only: explicit per-face file URLs. */\n faces?: FontFaceFile[];\n /** \"sans-serif\" | \"serif\" | \"display\" | \"handwriting\" | \"monospace\" — best-effort. */\n category?: string;\n}\n\n// Priority order. When a family appears in multiple catalogs the FIRST source\n// in this list wins — both for loader dispatch and for picker dedup.\nconst PRIORITY: FontSource[] = [\n \"google\",\n \"fontshare\",\n \"fontsource\",\n \"bunny\",\n \"velvetyne\",\n];\n\n// Catalog lookup is case-insensitive on family. The picker is allowed to\n// drop hits whose family already appeared in a higher-priority catalog.\nconst norm = (s: string): string => s.trim().toLowerCase();\n\n// Source → Map<lower-family, entry>. Built once at module load.\nconst indexBySource: Record<FontSource, Map<string, FontCatalogEntry>> = {\n google: new Map(GOOGLE_FONTS.map((f) => [norm(f), googleEntry(f)])),\n bunny: new Map(BUNNY_FONTS.map((e) => [norm(e.family), { ...e, source: \"bunny\" as FontSource }])),\n fontshare: new Map(\n FONTSHARE_FONTS.map((e) => [norm(e.family), { ...e, source: \"fontshare\" as FontSource }]),\n ),\n fontsource: new Map(\n FONTSOURCE_FONTS.map((e) => [norm(e.family), { ...e, source: \"fontsource\" as FontSource }]),\n ),\n velvetyne: new Map(\n VELVETYNE_FONTS.map((e) => [norm(e.family), { ...e, source: \"velvetyne\" as FontSource }]),\n ),\n};\n\n// Google entries are bare strings in google-fonts.ts (the file predates this\n// module). Wrap them into a uniform entry with no per-family slug (Google's\n// CSS2 URL takes the family name directly).\nfunction googleEntry(family: string): FontCatalogEntry {\n return {\n family,\n source: \"google\",\n weights: [], // resolved per-face by the existing Google loader\n italics: true, // assume yes; the Google CSS2 endpoint 400s harmlessly when not\n };\n}\n\n// Resolve a family → source via the priority order. Returns null when the\n// family is in no catalog (likely a user-uploaded custom_font; the loader\n// then falls back to the existing FontFace path for project.custom_fonts).\nexport const getFontSource = (family: string): FontSource | null => {\n const key = norm(family);\n for (const s of PRIORITY) {\n if (indexBySource[s].has(key)) return s;\n }\n return null;\n};\n\n// Resolve to the full catalog entry (or null). Used by the loader for slug\n// + face URLs; used by the picker for badge + filter.\nexport const getFontEntry = (family: string): FontCatalogEntry | null => {\n const key = norm(family);\n for (const s of PRIORITY) {\n const e = indexBySource[s].get(key);\n if (e) return e;\n }\n return null;\n};\n\n// Catalog for the picker, deduped by priority. The picker should render the\n// returned array as-is (already sorted by source priority, then alphabetical\n// within each source).\nexport const allFontEntries = (): FontCatalogEntry[] => {\n const seen = new Set<string>();\n const out: FontCatalogEntry[] = [];\n for (const s of PRIORITY) {\n const sorted = [...indexBySource[s].values()].sort((a, b) =>\n a.family.localeCompare(b.family),\n );\n for (const e of sorted) {\n const key = norm(e.family);\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(e);\n }\n }\n return out;\n};\n\n// ── URL builders ────────────────────────────────────────────────────────────\n\n// Bunny mirrors Google's CSS2 axis syntax; safe to reuse the same format.\n// Returns a stylesheet URL — inject as <link>.\nexport const bunnyCssUrl = (\n slug: string,\n weight: number,\n italic: boolean,\n): string => {\n const axis = italic ? `ital,wght@1,${weight}` : `wght@${weight}`;\n return `https://fonts.bunny.net/css?family=${slug}:${axis}&display=swap`;\n};\n\n// Fontshare exposes a single CSS endpoint per family that ships every face;\n// loading once covers all weights/italics for that family. Wasteful vs Google\n// but simple + reliable.\nexport const fontshareCssUrl = (slug: string): string =>\n `https://api.fontshare.com/v2/css?f[]=${slug}&display=swap`;\n\n// Fontsource via jsDelivr — `index.css` contains every face for the family.\nexport const fontsourceCssUrl = (slug: string): string =>\n `https://cdn.jsdelivr.net/fontsource/css/${slug}@latest/index.css`;\n\n// Pick a Velvetyne face for (weight, italic). Falls back to the nearest\n// available weight (closest numeric distance, italic match preferred).\nexport const velvetyneFaceFor = (\n entry: FontCatalogEntry,\n weight: number,\n italic: boolean,\n): FontFaceFile | null => {\n const faces = entry.faces ?? [];\n if (faces.length === 0) return null;\n const score = (f: FontFaceFile): number =>\n Math.abs(f.weight - weight) + (f.italic === italic ? 0 : 1000);\n return faces.slice().sort((a, b) => score(a) - score(b))[0] ?? null;\n};\n","import { z } from \"zod\";\nimport { SHAPE_IDS } from \"./shapes.ts\";\n\nconst hexColor = z.string().regex(/^#[0-9a-fA-F]{6}$/u, \"expected #rrggbb\");\n\n// Optional per-layer \"colour label\" — a small swatch shown at the leftmost\n// edge of the Inspector LayersList row, like Finder tags or DAW track\n// colours. Pure UI metadata; the renderer ignores it. The eight values map\n// to the 8-swatch picker in LayerContextMenu.\nexport const colorLabelSchema = z.enum([\n \"red\",\n \"orange\",\n \"yellow\",\n \"green\",\n \"cyan\",\n \"blue\",\n \"violet\",\n \"magenta\",\n]);\nexport type ColorLabel = z.infer<typeof colorLabelSchema>;\n\n// One colour stop in a gradient fill. `pos` is the stop position along the\n// gradient axis, 0..1. `opacity` is per-stop alpha (the stop's effective\n// colour at paint time is colour blended with opacity). Multiple stops at\n// the same `pos` are allowed and render as a hard step.\nexport const fillStopSchema = z\n .object({\n pos: z.number().min(0).max(1),\n color: hexColor,\n opacity: z.number().min(0).max(1).default(1),\n })\n .strict();\n\n// A solid fill — used wherever a single colour was used pre-Fill. `opacity`\n// is multiplied with any ambient globalAlpha at paint time so animation /\n// layer opacity still composes.\nexport const solidFillSchema = z\n .object({\n type: z.literal(\"solid\"),\n color: hexColor,\n opacity: z.number().min(0).max(1).default(1),\n })\n .strict();\n\n// Linear gradient. `angle` follows CSS `linear-gradient(<deg>, ...)` semantics:\n// 0° points UP (first stop at the bottom, last at the top), 90° points right,\n// 180° points down. The gradient line crosses the centre of the fill rect\n// and extends just far enough that the rect is fully covered at any angle.\nexport const linearGradientSchema = z\n .object({\n type: z.literal(\"linear\"),\n stops: z.array(fillStopSchema).min(2),\n angle: z.number().default(180),\n })\n .strict();\n\n// Radial gradient. `cx` / `cy` are fractions of the fill rect (0.5,0.5 =\n// centre). `radius` is a fraction of half the rect's longer side — 1 reaches\n// the farther edge midpoint, sqrt(2) ≈ 1.41 reaches the corner.\nexport const radialGradientSchema = z\n .object({\n type: z.literal(\"radial\"),\n stops: z.array(fillStopSchema).min(2),\n cx: z.number().default(0.5),\n cy: z.number().default(0.5),\n radius: z.number().positive().default(1),\n })\n .strict();\n\n// Mask fill — silhouettes a single colour through the alpha channel of an\n// existing image layer. `layer_id` names the source image layer (e.g.\n// \"image.title\"); the renderer reads that layer's already-decoded bitmap\n// from the images map and uses its alpha as the mask, so `color` appears\n// only where the masking image is opaque. Use case: brand-coloured logos\n// that adopt a new tint without re-exporting the artwork, silhouette title\n// cards over a video, swatch-driven recolours of stock art. Paints nothing\n// when the named layer is missing or its bitmap hasn't decoded yet.\nexport const maskFillSchema = z\n .object({\n type: z.literal(\"mask\"),\n layer_id: z.string().min(1),\n color: hexColor,\n opacity: z.number().min(0).max(1).default(1),\n })\n .strict();\n\n// A paintable fill. Used as: canvas backdrop (palette.fill), shape body\n// (shapes[].fill), optional image-layer backdrop (image_layers[].fill),\n// optional video-layer backdrop (video_layers[].fill), and optional group\n// backdrop (groups[].fill). Discriminator is `type`.\nexport const fillSchema = z.discriminatedUnion(\"type\", [\n solidFillSchema,\n linearGradientSchema,\n radialGradientSchema,\n maskFillSchema,\n]);\n\n// Per-character text span. Applied on top of the layer's base text styling.\n// `start` and `end` are UTF-16 code-unit offsets into the layer's `text`\n// field (matching JS string indexing); ranges may overlap and later spans\n// win for the property they set. Empty spans (start >= end) are ignored at\n// paint time. `color` is the foreground colour for the segment in\n// \"#rrggbb\" form; absent fields fall through to the layer's base style.\nexport const textSpanSchema = z\n .object({\n start: z.number().int().nonnegative(),\n end: z.number().int().nonnegative(),\n bold: z.boolean().optional(),\n italic: z.boolean().optional(),\n color: hexColor.optional(),\n })\n .strict();\nexport type TextSpan = z.infer<typeof textSpanSchema>;\n\n// One per image layer on the project. (x, y) is the CENTRE of the layer's\n// bounding box in canvas coords (1080×1920); width/height the box extents.\n// Centre-anchor matches Premiere/FCP/Motion conventions and aligns with the\n// renderer's transform pivot — scale + rotation always pivot at (x, y).\n// Animations on the layer go under `image.<id>` in project.animations.\n//\n// The CANVAS BACKDROP is also represented here, as a regular image_layer\n// with `pinned: true` + `is_background: true` + no filename. The renderer\n// paints `is_background` layers across the full canvas regardless of\n// x/y/width/height. Pinned layers are forced to the bottom of the root\n// z-stack and refuse deletion / reorder from the UI + tools.\nexport const imageLayerSchema = z\n .object({\n id: z.string().min(1),\n // Optional for `is_background` (the canvas backdrop has no bitmap).\n // Worker / tool layer enforces non-empty for regular image layers.\n filename: z.string().min(1).optional(),\n // Optional friendly label shown in the Inspector + Timeline lane.\n // When unset/empty, callers fall back to the filename stem. Mirrors\n // groupSchema.name so renaming an image works the same way as a group.\n name: z.string().optional(),\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n rotation: z.number().default(0),\n // Normalized rotation / scale pivot in the layer's bbox: 0 = left/top edge,\n // 0.5 = centre (default), 1 = right/bottom edge. The Inspector picker\n // snaps to {0, 0.5, 1} × {0, 0.5, 1} (9 anchor cells); the schema accepts\n // any value in [0, 1] so agents can drive it freely.\n pivotX: z.number().min(0).max(1).default(0.5),\n pivotY: z.number().min(0).max(1).default(0.5),\n // Optional backdrop fill painted in the layer's local rect BEFORE the\n // image bitmap. Shows through any transparent PNG areas. Separate from\n // the existing `tintColor` overlay (which paints OVER opaque pixels).\n // null (default) = no backdrop. For `is_background` layers this is the\n // ONLY visual paint (the canvas backdrop).\n fill: fillSchema.nullable().default(null),\n // When true, the layer is non-deletable, non-reorderable, forced to the\n // bottom of the root z-stack regardless of `layer_order`. Used for the\n // canvas backdrop today.\n pinned: z.boolean().optional(),\n // When true, the layer is the canvas backdrop: rendered at\n // (0, 0, canvas_width, canvas_height) ignoring its own x/y/width/height,\n // with no bitmap loaded (filename is optional/empty). Only `fill` paints.\n is_background: z.boolean().optional(),\n locked: z.boolean().optional(),\n hidden: z.boolean().optional(),\n matte_source_id: z.string().nullable().optional(),\n text: z.string().optional(),\n text_size: z.number().positive().optional(),\n font_family: z.string().optional(),\n text_color: hexColor.optional(),\n line_height: z.number().positive().optional(),\n letter_spacing: z.number().optional(),\n text_align: z.enum([\"left\", \"center\", \"right\"]).optional(),\n line_beat_frames: z.number().int().positive().optional(),\n spans: z.array(textSpanSchema).optional(),\n // Optional Inspector colour-label tag.\n color_label: colorLabelSchema.optional(),\n })\n .strict();\n\n// One per video layer on the project. Mirrors imageLayerSchema field-for-field:\n// (x, y) is the CENTRE of the layer's bounding box; animations go under\n// `video.<id>` in project.animations. `clip` is the relative filename under\n// the project's clips bucket (`users/<userId>/clips/<projectId>/`), the same\n// path image filenames take under the assets bucket.\nexport const videoLayerSchema = z\n .object({\n id: z.string().min(1),\n clip: z.string().min(1),\n name: z.string().optional(),\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n rotation: z.number().default(0),\n // See imageLayerSchema.pivotX/pivotY.\n pivotX: z.number().min(0).max(1).default(0.5),\n pivotY: z.number().min(0).max(1).default(0.5),\n // Source-time in-point: frame within the source mp4 where playback of\n // this slice begins. 0 = start of the source.\n source_in_frame: z.number().int().nonnegative().default(0),\n // Source-time out-point: frame within the source mp4 where playback of\n // this slice stops. null = play to the source's natural end. Resolved\n // against the loaded videoEl's duration via `videoWindow()`.\n source_out_frame: z.number().int().nonnegative().nullable().default(null),\n // Project-timeline frame where this slice begins playing.\n timeline_start_frame: z.number().int().nonnegative().default(0),\n // Optional backdrop fill painted behind the video pixels. Visible in\n // letterbox areas when fit=contain and as a fallback when the video\n // hasn't loaded. null (default) = legacy behaviour (black).\n fill: fillSchema.nullable().default(null),\n locked: z.boolean().optional(),\n hidden: z.boolean().optional(),\n matte_source_id: z.string().nullable().optional(),\n speed_keyframes: z\n .array(\n z\n .object({\n frame: z.number().int().nonnegative(),\n rate: z.number().min(0.1).max(8),\n })\n .strict(),\n )\n .optional(),\n // Optional Inspector colour-label tag.\n color_label: colorLabelSchema.optional(),\n })\n .strict();\nexport type SpeedKeyframe = NonNullable<\n z.infer<typeof videoLayerSchema>[\"speed_keyframes\"]\n>[number];\n\n// Text layers — a first-class layer type, distinct from image layers. Element\n// ids are `text.<id>`; animations/styles/track-loops key off `text.<id>` and\n// they sit in `layer_order` and group `children` exactly like any other leaf.\n// The renderer draws live typeset text (multi-line, auto-fit to the box) into\n// the same transformed box used for image layers, so a text layer animates\n// identically to any other leaf. Looping is the general `track_loops`\n// mechanism — there is no text-specific sequencing.\nexport const textLayerSchema = z\n .object({\n id: z.string().min(1),\n // The text to render. Newlines are honoured as hard line breaks.\n text: z.string().default(\"\"),\n // Optional friendly label — the Inspector/Timeline name and the basis for\n // the layer's auto-derived <morpha-video> embed attribute.\n name: z.string().optional(),\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n rotation: z.number().default(0),\n // See imageLayerSchema.pivotX/pivotY.\n pivotX: z.number().min(0).max(1).default(0.5),\n pivotY: z.number().min(0).max(1).default(0.5),\n // Google Fonts family name (e.g. \"Anton\"). Loaded from the Google Fonts\n // CSS2 API before rendering — see editor/src/fonts.ts.\n font_family: z.string().default(\"Anton\"),\n // Desired font size in px; the renderer shrinks from here to fit the box.\n // Omitted ⇒ derived from the layer box height.\n text_size: z.number().positive().optional(),\n // How text fills its box. \"shrink\" (default): word-wrap, then auto-shrink\n // the font from text_size until the whole block fits — so a longer line\n // renders smaller. \"wrap\": hold text_size FIXED and only word-wrap\n // (hard-breaking a single word too wide to fit), never shrink — so every\n // line keeps the same height. Captions use \"wrap\" to stop the per-line\n // size bounce.\n text_autofit: z.enum([\"shrink\", \"wrap\"]).optional(),\n // Text fill colour as #rrggbb. Defaults to white when omitted.\n text_color: z.string().optional(),\n // Optional backdrop fill painted in the layer's local rect behind the text.\n fill: fillSchema.nullable().default(null),\n // Multiplier on font size for line spacing. 1.0 = single, 1.4 = 140%.\n // Default 1.2 when omitted — matches today's hard-coded behaviour.\n line_height: z.number().positive().optional(),\n // Pixel tracking between glyphs. May be negative. Default 0.\n letter_spacing: z.number().optional(),\n // Horizontal alignment of each line within the layer's box. Default\n // \"center\" when omitted — matches today's renderer.\n text_align: z.enum([\"left\", \"center\", \"right\"]).optional(),\n // Vertical alignment of the text BLOCK within the box. \"middle\" (default,\n // matches today's renderer) centres it; \"bottom\" pins it to the box floor\n // so extra wrapped lines grow upward from a fixed baseline (captions use\n // this so a line that wraps doesn't shift the others); \"top\" pins the top.\n text_valign: z.enum([\"top\", \"middle\", \"bottom\"]).optional(),\n // Font weight 100..900 (Thin..Black). Default 400 when omitted; the\n // renderer also lets the canvas faux-synthesize weights a static font\n // doesn't ship.\n font_weight: z.number().int().min(100).max(900).optional(),\n // Italic toggle. Default \"normal\".\n font_style: z.enum([\"normal\", \"italic\"]).optional(),\n // Case transform applied before layout/measure. Default \"none\".\n text_transform: z.enum([\"none\", \"uppercase\", \"lowercase\"]).optional(),\n // Outline stroked UNDER the fill. stroke_width in px (0 / omitted = no\n // outline); stroke_color is #rrggbb (renderer defaults to white).\n stroke_width: z.number().min(0).optional(),\n stroke_color: hexColor.optional(),\n // First-class drop shadow for the text fill. `color` is any CSS colour\n // (rgba allowed for soft shadows). null / omitted ⇒ no shadow.\n text_shadow: z\n .object({\n offsetX: z.number(),\n offsetY: z.number(),\n blur: z.number().min(0),\n color: z.string(),\n })\n .nullable()\n .optional(),\n // Track matte: when set, this text layer (the host) shows only through\n // the referenced leaf's alpha. Mirrors image/video/shape layers.\n matte_source_id: z.string().nullable().optional(),\n locked: z.boolean().optional(),\n hidden: z.boolean().optional(),\n // Optional Inspector colour-label tag.\n color_label: colorLabelSchema.optional(),\n })\n .strict();\n\nexport type TextLayer = z.infer<typeof textLayerSchema>;\n\n// Resolve a video layer's playback window against the source's actual\n// duration. `sourceDurationSeconds` comes from the loaded HTMLVideoElement\n// (or, in headless contexts, the source mp4's probed duration). Returns\n// project-frame [startFrame, endFrame) and the matching source-time\n// [sourceInSeconds, sourceOutSeconds). Single source of truth for the\n// renderer, preview, export, and timeline UI — every call site should\n// route through this rather than re-deriving the math.\nexport const videoWindow = (\n layer: VideoLayer,\n sourceDurationSeconds: number,\n): {\n startFrame: number;\n endFrame: number;\n sourceInSeconds: number;\n sourceOutSeconds: number;\n windowFrames: number;\n} => {\n const FPS = 30;\n const sourceDurationFrames = Math.max(\n 0,\n Math.floor(sourceDurationSeconds * FPS),\n );\n const inFrame = Math.max(\n 0,\n Math.min(sourceDurationFrames, layer.source_in_frame),\n );\n const rawOut =\n layer.source_out_frame === null ? sourceDurationFrames : layer.source_out_frame;\n const outFrame = Math.max(\n inFrame,\n Math.min(sourceDurationFrames, rawOut),\n );\n const windowFrames = Math.max(0, outFrame - inFrame);\n const startFrame = Math.max(0, layer.timeline_start_frame);\n return {\n startFrame,\n endFrame: startFrame + windowFrames,\n sourceInSeconds: inFrame / FPS,\n sourceOutSeconds: outFrame / FPS,\n windowFrames,\n };\n};\n\n// Normalise a video layer's speed-ramp keyframes for evaluation: deduped on\n// `frame`, sorted, clamped to the legal rate range [0.1, 8]. Returns an\n// empty array when the layer has no speed_keyframes or the array is empty\n// (the caller treats that as \"constant rate 1, no remap needed\").\nexport const resolveSpeedKeyframes = (\n layer: VideoLayer,\n): Array<{ frame: number; rate: number }> => {\n const raw = layer.speed_keyframes ?? [];\n if (raw.length === 0) return [];\n const byFrame = new Map<number, number>();\n for (const kf of raw) {\n if (!Number.isFinite(kf.frame) || !Number.isFinite(kf.rate)) continue;\n const r = Math.max(0.1, Math.min(8, kf.rate));\n byFrame.set(Math.round(kf.frame), r);\n }\n const list = [...byFrame.entries()]\n .map(([frame, rate]) => ({ frame, rate }))\n .sort((a, b) => a.frame - b.frame);\n return list;\n};\n\n// Build a frame-indexed table `srcFrame[i]` of the source-frame the playback\n// should be at when the project timeline is at `timeline_start_frame + i`.\n// Implements the standard trapezoidal integration of the rate curve, with\n// `hold` extrapolation before the first speed keyframe and after the last\n// (rate clamped to the boundary's value). The first entry (`i = 0`) is\n// pinned to `source_in_frame` so the trim's in-point stays exact.\n//\n// Length is bounded by `maxLength` (typically the layer's playback window in\n// project-frames) so the renderer can hit any frame inside the window via a\n// single table lookup. Callers that need a value past the table's tail\n// re-apply the constant boundary rate themselves (`sourceFrameFor`).\nexport const buildSourceFrameTable = (\n layer: VideoLayer,\n maxLength: number,\n): number[] => {\n const ramp = resolveSpeedKeyframes(layer);\n const out: number[] = [];\n if (maxLength <= 0) return out;\n const sourceIn = layer.source_in_frame ?? 0;\n if (ramp.length === 0) {\n // Constant rate 1: source advances 1:1 with the timeline.\n for (let i = 0; i < maxLength; i++) out.push(sourceIn + i);\n return out;\n }\n const tStart = layer.timeline_start_frame ?? 0;\n let acc = 0;\n for (let i = 0; i < maxLength; i++) {\n if (i === 0) {\n out.push(sourceIn);\n continue;\n }\n // Trapezoid: average of rate at timeline-frame (tStart + i - 1) and\n // (tStart + i), each evaluated by linear interpolation of the rate\n // curve with `hold` outside the first/last keyframe.\n const ra = rateAtTimelineFrame(ramp, tStart + i - 1);\n const rb = rateAtTimelineFrame(ramp, tStart + i);\n acc += (ra + rb) / 2;\n out.push(sourceIn + acc);\n }\n return out;\n};\n\n// Linear-interp the rate curve at a given timeline frame, with `hold`\n// outside the first/last keyframe. Used by `buildSourceFrameTable`'s\n// trapezoidal integrator and by `sourceFrameFor`'s extrapolation tail.\nconst rateAtTimelineFrame = (\n ramp: Array<{ frame: number; rate: number }>,\n timelineFrame: number,\n): number => {\n if (ramp.length === 0) return 1;\n if (timelineFrame <= ramp[0].frame) return ramp[0].rate;\n if (timelineFrame >= ramp[ramp.length - 1].frame) {\n return ramp[ramp.length - 1].rate;\n }\n for (let i = 1; i < ramp.length; i++) {\n const a = ramp[i - 1];\n const b = ramp[i];\n if (timelineFrame <= b.frame) {\n const span = b.frame - a.frame;\n if (span <= 0) return b.rate;\n const t = (timelineFrame - a.frame) / span;\n return a.rate + (b.rate - a.rate) * t;\n }\n }\n return ramp[ramp.length - 1].rate;\n};\n\n// Map a project-timeline frame to the source-frame for a given video layer,\n// honouring `speed_keyframes` when present. `table` is the cached output of\n// `buildSourceFrameTable(layer, …)`; supply null to fall back to the legacy\n// 1:1 mapping (used when the layer has no speed keyframes, or the caller\n// hasn't built a table). Returns a float source-frame; callers convert to\n// seconds via `/ FPS` (or to an integer via Math.floor / round).\nexport const sourceFrameFor = (\n layer: VideoLayer,\n timelineFrame: number,\n table: number[] | null,\n): number => {\n const tStart = layer.timeline_start_frame ?? 0;\n const idx = timelineFrame - tStart;\n if (idx < 0) return layer.source_in_frame ?? 0;\n if (!table || table.length === 0) {\n return (layer.source_in_frame ?? 0) + idx;\n }\n if (idx < table.length) return table[idx];\n // Past the table — constant-rate extrapolate from the last entry.\n const ramp = resolveSpeedKeyframes(layer);\n const tailRate = ramp.length > 0 ? ramp[ramp.length - 1].rate : 1;\n const last = table[table.length - 1];\n return last + (idx - (table.length - 1)) * tailRate;\n};\n\n// Shape primitives. The set is the data-driven shape registry in\n// `./shapes.ts` — `SHAPE_IDS` is the readonly tuple of every registry id, so\n// adding a shape there widens this enum automatically. `rect` is the historic\n// default — older projects with no `kind` field parse as `rect` via\n// `.default(\"rect\")`. The renderer's `traceShapePath` looks the kind up in the\n// same registry to pick the canvas path.\nexport const shapeKindSchema = z.enum(SHAPE_IDS).default(\"rect\");\n\n// (x, y) is the CENTRE of the shape's bounding box. See imageLayerSchema.\n// `fill` is the shape body (solid colour or gradient). The legacy\n// `color: \"#rrggbb\"` form is migrated to `fill: { type: \"solid\", color }`\n// by `migrateColorsToFills` during preprocess.\nexport const shapeSchema = z\n .object({\n id: z.string().min(1),\n kind: shapeKindSchema,\n // Optional friendly label shown in the Inspector + Timeline lane.\n // When unset/empty, callers fall back to the shape's `kind`.\n name: z.string().optional(),\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n fill: fillSchema,\n rotation: z.number().default(0),\n // See imageLayerSchema.pivotX/pivotY.\n pivotX: z.number().min(0).max(1).default(0.5),\n pivotY: z.number().min(0).max(1).default(0.5),\n locked: z.boolean().optional(),\n hidden: z.boolean().optional(),\n matte_source_id: z.string().nullable().optional(),\n // Optional Inspector colour-label tag.\n color_label: colorLabelSchema.optional(),\n // Curve / arrow geometry (only used by kind \"curve\"). `points` are control\n // points as FRACTIONS of the bbox — a quadratic bezier [start, bend, end];\n // the renderer strokes through them instead of filling the kind's trace.\n // `stroke_width` is in px (the `fill` solid colour is used as the stroke).\n // `arrow_head` adds a triangular head at the end, or both ends.\n points: z.array(z.object({ x: z.number(), y: z.number() })).optional(),\n stroke_width: z.number().positive().optional(),\n arrow_head: z.enum([\"none\", \"end\", \"both\"]).optional(),\n })\n .strict();\n\nexport const easingSchema = z.enum([\n \"linear\",\n \"easeIn\",\n \"easeOut\",\n \"easeInOut\",\n \"outQuart\",\n \"outExpo\",\n \"outBack\",\n \"inBack\",\n \"inOutBack\",\n \"cubicBezier\",\n // \"hold\" is a step-end function: the value sits at the PREVIOUS keyframe's\n // value across the whole interior of this segment, then jumps to this\n // keyframe's value exactly at this keyframe's frame. Matches AE / Premiere\n // / FCP \"Hold\" interpolation.\n \"hold\",\n]);\n\nexport const keyframeSchema = z\n .object({\n frame: z.number().int().nonnegative(),\n value: z.number(),\n easing: easingSchema.default(\"linear\"),\n bezier: z\n .tuple([z.number(), z.number(), z.number(), z.number()])\n .optional(),\n })\n .strict();\n\nexport const trackPropertySchema = z.enum([\n \"x\",\n \"y\",\n \"width\",\n \"height\",\n \"opacity\",\n \"scale\",\n \"rotation\",\n]);\n\nexport const elementTracksSchema = z.partialRecord(\n trackPropertySchema,\n z.array(keyframeSchema),\n);\n\nexport const animationsSchema = z.record(z.string(), elementTracksSchema);\n\n// Track-level extrapolation mode. Determines what `evaluateTrack` returns\n// past the last keyframe (and, symmetrically, before the first):\n// - \"hold\" — current default. Holds the boundary keyframe's value\n// forever. AE / Premiere \"Hold\" extrapolation.\n// - \"loop\" — wraps the playhead frame into [firstKf.frame, lastKf.frame]\n// so the animation cycles. Reference: AE \"Loop Out / Cycle\".\n// - \"ping-pong\" — same wrap but reverses direction on alternate cycles.\n// Reference: AE \"Loop Out / PingPong\".\n// - \"cycle\" — wraps like \"loop\" but offsets each cycle by\n// (lastKf.value - firstKf.value), so a finite curve becomes\n// an endless ramp. Reference: AE \"Loop Out / Continue +\n// Offset\" (used for scrolling text, endless rotation).\nexport const loopModeSchema = z.enum([\"hold\", \"loop\", \"ping-pong\", \"cycle\"]);\nexport const trackLoopsSchema = z.partialRecord(\n trackPropertySchema,\n loopModeSchema,\n);\nexport const projectLoopsSchema = z.record(z.string(), trackLoopsSchema);\n\nexport type LoopMode = z.infer<typeof loopModeSchema>;\nexport type TrackLoops = z.infer<typeof trackLoopsSchema>;\n\n// Colour-valued keyframe. Same time + easing model as the numeric\n// `keyframeSchema`; `value` is a full Fill (solid / linear / radial).\n// Adjacent keyframes are interpolated stop-by-stop with position-union\n// resampling (see `evaluateColorTrack` in src/animation.ts), so a\n// 2-stop → 5-stop gradient still produces a continuous crossfade.\nexport const colorKeyframeSchema = z\n .object({\n frame: z.number().int().nonnegative(),\n value: fillSchema,\n easing: easingSchema.default(\"linear\"),\n bezier: z\n .tuple([z.number(), z.number(), z.number(), z.number()])\n .optional(),\n })\n .strict();\n\n// Color-track property keys. Mirrors `trackPropertySchema` but for Fill-\n// valued tracks. Today there's exactly one: \"fill\" (the element's body or\n// backdrop fill). Future colour-valued properties (border colour, tint\n// colour) would land here so the timeline UI + tools find them in one place.\nexport const colorTrackPropertySchema = z.enum([\"fill\"]);\n\nexport const elementColorTracksSchema = z.partialRecord(\n colorTrackPropertySchema,\n z.array(colorKeyframeSchema),\n);\n\n// `project.color_tracks[elementId][property]` parallel to `animations`.\n// Numeric `animations` keep their narrow type; Fill-valued tracks live here\n// so every consumer that walks one map doesn't have to discriminate the\n// keyframe value's runtime shape.\n//\n// Element id conventions mirror `animations`: leaf ids prefixed `video.` /\n// `image.` / `shapes.` / `group.`, plus the project-level pseudo-id\n// `\"palette\"` for the canvas backdrop fill track.\nexport const colorTracksSchema = z.record(z.string(), elementColorTracksSchema);\n\nexport type ColorKeyframe = z.infer<typeof colorKeyframeSchema>;\nexport type ColorTrackProperty = z.infer<typeof colorTrackPropertySchema>;\nexport type ElementColorTracks = z.infer<typeof elementColorTracksSchema>;\nexport type ColorTracks = z.infer<typeof colorTracksSchema>;\n\n// How the source pixels (video frame, image bitmap) map into the layer's\n// (width, height) box. Mirrors iMovie's Fit/Crop and Premiere's Scale-to-\n// Frame-Size / Stretch options:\n// - cover = fill the box, crop overflow, preserve aspect (iMovie \"Crop\")\n// - contain = fit the whole source inside the box, preserve aspect\n// (iMovie \"Fit\" / Premiere \"Set to Frame Size\")\n// - stretch = ignore aspect, scale to box (Premiere when source aspect is\n// manually overridden)\n// Default in the renderer when unset: \"cover\" for video layers, \"stretch\" for\n// image layers — videos behave like a TV screen by default; images stretch to\n// their layer box because callers usually pre-size them in PNG export.\nexport const fitModeSchema = z.enum([\"cover\", \"contain\", \"stretch\"]);\n\n// One stop of an alpha-mask gradient — `offset` is a position along the\n// gradient line (0 at the line's start, 1 at the line's end) and `alpha`\n// is the alpha multiplier applied to the image at that point.\nexport const maskGradientStopSchema = z\n .object({\n offset: z.number().min(0).max(1),\n alpha: z.number().min(0).max(1),\n })\n .strict();\n\n// Linear alpha-mask gradient applied as a multiplicative alpha modulation\n// on the rendered layer bitmap. Matches the gradient stop model in\n// Figma / Photoshop / Sketch — an angle plus an ordered list of alpha\n// stops along the gradient line. Used for the \"sandwich\" trick (a layer\n// shown in front of the caption fading out across the layer), without\n// requiring a separately-uploaded cropped asset.\n//\n// `angle` is in degrees, CSS-style: 0 = bottom→top, 90 = left→right,\n// 180 = top→bottom, 270 = right→left. The angle determines which way the\n// gradient line points across the layer's bounding box.\n// `stops` is sorted by offset; min 2 stops.\nexport const maskGradientSchema = z\n .object({\n type: z.literal(\"linear\").default(\"linear\"),\n angle: z.number().default(180),\n stops: z.array(maskGradientStopSchema).min(2),\n })\n .strict();\n\nexport const layerStyleSchema = z\n .object({\n borderRadius: z.number().nonnegative().optional(),\n borderWidth: z.number().nonnegative().optional(),\n borderColor: hexColor.optional(),\n boxShadow: z.string().optional(),\n fit: fitModeSchema.optional(),\n // Object-position for cover/contain fit modes. 0..1 along each axis;\n // (0.5, 0.5) = centre (default when unset). For cover, this picks which\n // slice of the source survives cropping (0,0 = keep top-left, crop the\n // bottom + right). For contain, it positions the letterboxed source\n // inside the destination box (0,0 = align top-left, empty space on right\n // + bottom). Ignored when fit is \"stretch\".\n anchorX: z.number().min(0).max(1).optional(),\n anchorY: z.number().min(0).max(1).optional(),\n // Optional tint overlay for image layers. tintColor is the hex tint;\n // tintStrength (0..1) blends from \"no tint\" (0) to \"fully tinted —\n // image silhouette filled with tintColor\" (1). Painted with\n // source-atop so only opaque pixels are coloured. tintStrength alone\n // (no color) and tintColor alone (no strength) both render as no-op.\n tintColor: hexColor.optional(),\n tintStrength: z.number().min(0).max(1).optional(),\n // Optional alpha-mask gradient — fades the layer's alpha along a\n // gradient line. See maskGradientSchema.\n alphaMask: maskGradientSchema.optional(),\n // Mirror flags. Applied in `applyTransform` to flip layer CONTENT around\n // the layer's centre without affecting the selection bbox.\n flipX: z.boolean().optional(),\n flipY: z.boolean().optional(),\n // CSS-style filter effects applied via `ctx.filter`. All optional;\n // missing → no-op. `blur` in canvas px; brightness/contrast/saturation\n // are multipliers (1.0 = unchanged); hueRotate in degrees.\n blur: z.number().min(0).max(100).optional(),\n brightness: z.number().min(0).max(3).optional(),\n contrast: z.number().min(0).max(3).optional(),\n saturation: z.number().min(0).max(3).optional(),\n hueRotate: z.number().min(-360).max(360).optional(),\n // Photoshop-style layer blend mode. Maps to Canvas's\n // globalCompositeOperation at render time (\"normal\" → \"source-over\").\n // Applies to every layer kind (image / video / shape / text / group).\n blend_mode: z\n .enum([\n \"normal\",\n \"multiply\",\n \"screen\",\n \"overlay\",\n \"darken\",\n \"lighten\",\n \"color-dodge\",\n \"color-burn\",\n \"hard-light\",\n \"soft-light\",\n \"difference\",\n \"exclusion\",\n \"hue\",\n \"saturation\",\n \"color\",\n \"luminosity\",\n ])\n .optional(),\n // Chroma key (green-screen removal) for video / image layers. `color` is\n // the key colour (#rrggbb, default green). `similarity` (0..1) widens the\n // matched colour range; `smoothness` (0..1) softens the alpha falloff at\n // the edge. Pixels close to `color` are made transparent at render time.\n chroma_key: z\n .object({\n color: hexColor.default(\"#00ff00\"),\n similarity: z.number().min(0).max(1).default(0.4),\n smoothness: z.number().min(0).max(1).default(0.1),\n })\n .optional(),\n })\n .strict();\n\nexport type ChromaKey = NonNullable<\n z.infer<typeof layerStyleSchema>[\"chroma_key\"]\n>;\nexport type MaskGradient = z.infer<typeof maskGradientSchema>;\nexport type MaskGradientStop = z.infer<typeof maskGradientStopSchema>;\nexport type BlendMode = NonNullable<\n z.infer<typeof layerStyleSchema>[\"blend_mode\"]\n>;\n\nexport const BLEND_MODES = [\n \"normal\",\n \"multiply\",\n \"screen\",\n \"overlay\",\n \"darken\",\n \"lighten\",\n \"color-dodge\",\n \"color-burn\",\n \"hard-light\",\n \"soft-light\",\n \"difference\",\n \"exclusion\",\n \"hue\",\n \"saturation\",\n \"color\",\n \"luminosity\",\n] as const satisfies ReadonlyArray<BlendMode>;\n\nexport const stylesSchema = z.record(z.string(), layerStyleSchema);\n\n// One per audio overlay on the project. Plays a decoded audio buffer at a\n// frame-aligned start with optional linear fades. `endFrame` is optional —\n// when omitted the overlay plays the source asset's full natural length.\n// Filename references an asset in the project's R2 prefix (same bucket\n// images live in). 30 fps; convert seconds with frames = round(s * 30).\nexport const audioOverlaySchema = z\n .object({\n id: z.string().min(1),\n filename: z.string().min(1),\n startFrame: z.number().int().nonnegative(),\n gain: z.number().min(0).max(2).default(1),\n fadeInFrames: z.number().int().nonnegative().default(0),\n fadeOutFrames: z.number().int().nonnegative().default(0),\n endFrame: z.number().int().nonnegative().optional(),\n muted: z.boolean().optional(),\n soloed: z.boolean().optional(),\n })\n .strict();\n\nexport type AudioOverlay = z.infer<typeof audioOverlaySchema>;\n\n// A layer group. Holds an ordered list of children — each child is the\n// element id of an image layer (\"image.<id>\"), shape (\"shapes.<id>\"), or\n// another group (\"group.<id>\"). Groups can nest arbitrarily.\n//\n// pivotX / pivotY are the rotate/scale pivot in canvas coords; defaulted to\n// the children's bounding-box centre at create time and then frozen so a\n// later child move/animation doesn't silently swing the pivot. The group\n// itself has no body, no styles, no border — it exists purely to compose a\n// transform onto its descendants. Animations under \"group.<id>\" use the same\n// five tracks as a leaf (x, y, scale, rotation, opacity). Group's x/y act as\n// translation offsets applied around (pivotX, pivotY) — there is no separate\n// base position for groups.\nexport const groupSchema = z\n .object({\n id: z.string().min(1),\n name: z.string().default(\"\"),\n pivotX: z.number(),\n pivotY: z.number(),\n children: z.array(z.string()).default([]),\n // Optional backdrop fill painted behind the group's children. The rect is\n // centred on (pivotX, pivotY) in group-local space and sized by\n // (box_width, box_height); it transforms with the group (rotate/scale/\n // translate from x/y tracks). null (default) or zero box = no backdrop.\n fill: fillSchema.nullable().default(null),\n box_width: z.number().nonnegative().default(0),\n box_height: z.number().nonnegative().default(0),\n // Track matte — same primitive as a leaf layer's `matte_source_id`: the\n // group's composited children are shown only where the named source layer\n // (a shapes/image/video leaf) is opaque. A group is a layer of sorts, so\n // anything a leaf can host, it can too. Used e.g. to show a marching\n // chevron strip + black backing only inside an arrow / band shape.\n matte_source_id: z.string().nullable().optional(),\n locked: z.boolean().optional(),\n hidden: z.boolean().optional(),\n // Optional Inspector colour-label tag.\n color_label: colorLabelSchema.optional(),\n })\n .strict();\nexport type Group = z.infer<typeof groupSchema>;\n\n// Schema version. Bumped when on-disk JSON gains a meaning that older\n// readers can't infer:\n// 1 = post-rev1-migration shape with top-left anchored x/y (legacy).\n// 2 = current. (x, y) on image_layers / shapes / clip_inset is the\n// CENTRE of the bounding box. migrateProject converts < 2 → 2.\nexport const SCHEMA_VERSION = 2 as const;\n\n// Strip deprecated clip_frame fields from raw input before validation. The\n// pre-refactor schema modelled the source video as a built-in singleton\n// \"clip_frame\" layer with its viewport in `layout.clip_inset` and its\n// animations/styles keyed by the literal string \"clip_frame\". The new model\n// represents source videos as ordinary `video_layers[]`, so the legacy fields\n// are dropped here. The worker's project GET route is responsible for the\n// data-side migration (populating video_layers from the legacy shortlist);\n// this preprocess just keeps the parser tolerant of any leftovers.\nconst stripLegacyClipFrame = (raw: unknown): unknown => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return raw;\n const next = { ...(raw as Record<string, unknown>) };\n if (next.layout && typeof next.layout === \"object\") {\n const layoutNext = { ...(next.layout as Record<string, unknown>) };\n delete layoutNext.clip_inset;\n if (Object.keys(layoutNext).length === 0) delete next.layout;\n else next.layout = layoutNext;\n }\n if (next.animations && typeof next.animations === \"object\") {\n const anim = { ...(next.animations as Record<string, unknown>) };\n delete anim.clip_frame;\n next.animations = anim;\n }\n if (next.styles && typeof next.styles === \"object\") {\n const styles = { ...(next.styles as Record<string, unknown>) };\n delete styles.clip_frame;\n next.styles = styles;\n }\n if (Array.isArray(next.layer_order)) {\n next.layer_order = (next.layer_order as unknown[]).filter(\n (id) => id !== \"clip_frame\",\n );\n }\n return next;\n};\n\n// Convert legacy `translateX` / `translateY` keyframe tracks to absolute\n// `x` / `y` keyframes by adding the layer's base x/y. Convert `rotation`\n// keyframes (which were additive offsets from the layer's base rotation)\n// to absolute angles by adding the base rotation. Group entries have no\n// base — their translate keyframes were already absolute, so they're\n// renamed without offset; group rotation was never additive either.\n//\n// Lossless and value-preserving: a project rendered with the old base+offset\n// renderer and the post-migration project rendered with the new \"track wins\n// over base when present\" renderer produce identical frames.\nconst migrateTranslateToAbsolute = (raw: unknown): unknown => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return raw;\n const r = raw as Record<string, unknown>;\n const animations = r.animations;\n if (!animations || typeof animations !== \"object\") return r;\n\n const baseByEid = new Map<\n string,\n { x: number; y: number; rotation: number }\n >();\n const collect = (kind: string, list: unknown) => {\n if (!Array.isArray(list)) return;\n for (const raw of list) {\n if (!raw || typeof raw !== \"object\") continue;\n const l = raw as Record<string, unknown>;\n if (typeof l.id !== \"string\") continue;\n baseByEid.set(`${kind}.${l.id}`, {\n x: typeof l.x === \"number\" ? l.x : 0,\n y: typeof l.y === \"number\" ? l.y : 0,\n rotation: typeof l.rotation === \"number\" ? l.rotation : 0,\n });\n }\n };\n collect(\"image\", r.image_layers);\n collect(\"video\", r.video_layers);\n collect(\"shapes\", r.shapes);\n\n type LegacyTracks = Record<\n string,\n Array<{ frame: number; value: number; easing?: unknown; bezier?: unknown }>\n >;\n // Detect \"is this a legacy project\" by sniffing the WHOLE animations map\n // for any `translateX` / `translateY` track. The conversion is idempotent\n // for x/y (it gates on the legacy track being present), but rotation needs\n // a project-wide signal: in the new shape rotation values are absolute, so\n // re-applying the base-rotation offset on every load would compound. We\n // run the rotation conversion only when the project still carries legacy\n // translate tracks.\n let isLegacy = false;\n for (const tracksRaw of Object.values(\n animations as Record<string, unknown>,\n )) {\n if (!tracksRaw || typeof tracksRaw !== \"object\") continue;\n const t = tracksRaw as Record<string, unknown>;\n if (t.translateX !== undefined || t.translateY !== undefined) {\n isLegacy = true;\n break;\n }\n }\n\n for (const [eid, tracksRaw] of Object.entries(\n animations as Record<string, unknown>,\n )) {\n if (!tracksRaw || typeof tracksRaw !== \"object\") continue;\n const tracks = tracksRaw as LegacyTracks;\n const isGroup = eid.startsWith(\"group.\");\n const base = isGroup ? null : (baseByEid.get(eid) ?? null);\n\n if (Array.isArray(tracks.translateX) && !tracks.x) {\n const offset = base?.x ?? 0;\n tracks.x = tracks.translateX.map((kf) => ({\n ...kf,\n value: offset + kf.value,\n }));\n }\n if (Array.isArray(tracks.translateY) && !tracks.y) {\n const offset = base?.y ?? 0;\n tracks.y = tracks.translateY.map((kf) => ({\n ...kf,\n value: offset + kf.value,\n }));\n }\n if (isLegacy && Array.isArray(tracks.rotation) && base) {\n const offset = base.rotation;\n if (offset !== 0) {\n tracks.rotation = tracks.rotation.map((kf) => ({\n ...kf,\n value: offset + kf.value,\n }));\n }\n }\n delete tracks.translateX;\n delete tracks.translateY;\n }\n return r;\n};\n\n// Convert legacy single-hex shape colour to the Fill discriminated union.\n// Pre-Fill, a shape's body was `shapes[i].color = \"#rrggbb\"`; it moves to\n// `shapes[i].fill = { type: \"solid\", color, opacity: 1 }`. Idempotent —\n// re-running on a post-migration project is a no-op.\nconst migrateShapeColorsToFills = (raw: unknown): unknown => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return raw;\n const r = { ...(raw as Record<string, unknown>) };\n if (Array.isArray(r.shapes)) {\n r.shapes = (r.shapes as unknown[]).map((shape) => {\n if (!shape || typeof shape !== \"object\" || Array.isArray(shape)) return shape;\n const s = { ...(shape as Record<string, unknown>) };\n if (typeof s.color === \"string\" && s.fill === undefined) {\n s.fill = { type: \"solid\", color: s.color, opacity: 1 };\n }\n delete s.color;\n return s;\n });\n }\n return r;\n};\n\n// Unified canvas-background migration. The canvas backdrop is no longer a\n// sentinel `project.background` field; it's a regular `image_layers[]`\n// entry with `pinned: true` + `is_background: true`. This collapses every\n// historical shape into the new model in one step, idempotently:\n//\n// 1. Pre-Fill: palette.background = \"#rrggbb\"\n// 2. Mid-Fill: palette = { fill: <Fill> }\n// 3. Pre-this-refactor: background = { id: \"canvas\", name?, fill: <Fill> }\n// 4. Already-migrated: image_layers[] contains a pinned is_background\n// layer — leave untouched.\n//\n// All cases produce a single pinned image_layer at the FRONT of\n// image_layers[] (so the layer tree's root resolution can promote it to the\n// bottom of the z-stack), id \"background\", with the resolved fill. The\n// migration also rekeys any colour-track keys \"palette\" or\n// \"background.canvas\" to \"image.<bgId>\" so animations on the backdrop keep\n// firing after the rename.\nconst migrateBackgroundToImageLayer = (raw: unknown): unknown => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return raw;\n const r = { ...(raw as Record<string, unknown>) };\n\n const imageLayers = Array.isArray(r.image_layers)\n ? [...(r.image_layers as unknown[])]\n : [];\n\n // 4. Idempotency: if a pinned is_background layer already exists, do\n // nothing destructive — just normalise the `palette` / `background` /\n // colour-track keys away.\n const findBgIdx = (list: unknown[]): number =>\n list.findIndex(\n (l) =>\n l != null &&\n typeof l === \"object\" &&\n (l as { is_background?: unknown }).is_background === true,\n );\n let bgIdx = findBgIdx(imageLayers);\n let bgId: string = \"background\";\n\n if (bgIdx < 0) {\n // Discover the fill + optional name from legacy shapes in priority order.\n let resolvedFill: unknown = null;\n let resolvedName: string | undefined;\n\n // 3. background: { id, name?, fill }\n if (\n r.background &&\n typeof r.background === \"object\" &&\n !Array.isArray(r.background) &&\n \"fill\" in (r.background as object)\n ) {\n const bg = r.background as { fill?: unknown; name?: unknown };\n resolvedFill = bg.fill;\n if (typeof bg.name === \"string\" && bg.name.length > 0) {\n resolvedName = bg.name;\n }\n }\n\n // 2. palette: { fill }\n if (\n resolvedFill === null &&\n r.palette &&\n typeof r.palette === \"object\" &&\n !Array.isArray(r.palette) &&\n \"fill\" in (r.palette as object)\n ) {\n resolvedFill = (r.palette as { fill: unknown }).fill;\n }\n\n // 1. palette: { background: \"#rrggbb\" }\n if (\n resolvedFill === null &&\n r.palette &&\n typeof r.palette === \"object\" &&\n !Array.isArray(r.palette)\n ) {\n const p = r.palette as { background?: unknown };\n if (typeof p.background === \"string\") {\n resolvedFill = { type: \"solid\", color: p.background, opacity: 1 };\n }\n }\n\n // No legacy fill found at all — seed a sensible black backdrop so the\n // resulting project is always renderable.\n if (resolvedFill === null) {\n resolvedFill = { type: \"solid\", color: \"#000000\", opacity: 1 };\n }\n\n // Dedup the new id against any pre-existing image_layers ids — collide\n // only in pathological cases, but a \"background\" image layer in the\n // wild from a hand-edit would clash without this.\n const existingIds = new Set(\n imageLayers\n .filter(\n (l): l is Record<string, unknown> =>\n l != null && typeof l === \"object\" && !Array.isArray(l),\n )\n .map((l) => (typeof l.id === \"string\" ? l.id : \"\")),\n );\n let candidate = \"background\";\n let n = 2;\n while (existingIds.has(candidate)) {\n candidate = `background-${n++}`;\n }\n bgId = candidate;\n\n const bgLayer: Record<string, unknown> = {\n id: bgId,\n // Geometry is ignored by the renderer for is_background layers, but\n // the schema still requires it. Seed with the canonical canvas.\n x: 540,\n y: 960,\n width: 1080,\n height: 1920,\n rotation: 0,\n fill: resolvedFill,\n pinned: true,\n is_background: true,\n };\n if (resolvedName !== undefined) bgLayer.name = resolvedName;\n\n imageLayers.unshift(bgLayer);\n bgIdx = 0;\n } else {\n const existing = imageLayers[bgIdx] as Record<string, unknown>;\n if (typeof existing.id === \"string\") bgId = existing.id;\n }\n r.image_layers = imageLayers;\n\n // The new schema doesn't have these fields any more.\n delete r.palette;\n delete r.background;\n\n // Rekey colour tracks: legacy \"palette\" and \"background.canvas\" → the new\n // element id \"image.<bgId>\". If both exist (pathological), the later wins\n // (background.canvas, since it's the more recent shape).\n if (\n r.color_tracks &&\n typeof r.color_tracks === \"object\" &&\n !Array.isArray(r.color_tracks)\n ) {\n const ct = { ...(r.color_tracks as Record<string, unknown>) };\n const target = `image.${bgId}`;\n if (ct[\"palette\"] !== undefined && ct[target] === undefined) {\n ct[target] = ct[\"palette\"];\n }\n delete ct[\"palette\"];\n if (ct[\"background.canvas\"] !== undefined) {\n // Only overwrite the target when the explicit one is present — the\n // explicit one is the more-recent shape and supersedes \"palette\".\n ct[target] = ct[\"background.canvas\"];\n delete ct[\"background.canvas\"];\n }\n r.color_tracks = ct;\n }\n\n // Rekey animations: same rule, in case someone wrote a track under\n // \"background.canvas\" (no animatable numeric properties on the backdrop\n // today, but be tolerant).\n if (\n r.animations &&\n typeof r.animations === \"object\" &&\n !Array.isArray(r.animations)\n ) {\n const a = { ...(r.animations as Record<string, unknown>) };\n const target = `image.${bgId}`;\n if (a[\"background.canvas\"] !== undefined && a[target] === undefined) {\n a[target] = a[\"background.canvas\"];\n }\n delete a[\"background.canvas\"];\n r.animations = a;\n }\n\n // Rekey layer_order: legacy \"background.canvas\" entries are dropped\n // entirely. The pinned layer doesn't participate in layer_order — the\n // tree resolver places it at the bottom of root order independently.\n if (Array.isArray(r.layer_order)) {\n r.layer_order = (r.layer_order as unknown[]).filter(\n (id) => id !== \"background.canvas\",\n );\n }\n\n return r;\n};\n\n// Older projects modelled a text layer as an image_layer carrying a `text`\n// field (the pre-text_layers design). Move each such layer into text_layers,\n// drop the deprecated `filename` / `line_beat_frames` fields, and rekey every\n// \"image.<id>\" reference to \"text.<id>\" across layer_order, animations,\n// styles, color_tracks, track_loops, and group children. Idempotent — a\n// project with no text-bearing image_layers passes through untouched.\nconst migrateImageTextLayers = (raw: unknown): unknown => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return raw;\n const p = raw as Record<string, unknown>;\n if (!Array.isArray(p.image_layers)) return raw;\n\n const rekey = new Map<string, string>();\n const movedTextLayers: Record<string, unknown>[] = [];\n const keptImages: unknown[] = [];\n\n for (const entry of p.image_layers) {\n if (\n entry &&\n typeof entry === \"object\" &&\n !Array.isArray(entry) &&\n typeof (entry as Record<string, unknown>).text === \"string\" &&\n ((entry as Record<string, unknown>).text as string).length > 0\n ) {\n const l = entry as Record<string, unknown>;\n const id = String(l.id);\n rekey.set(`image.${id}`, `text.${id}`);\n const tl: Record<string, unknown> = {\n id,\n text: l.text,\n x: l.x,\n y: l.y,\n width: l.width,\n height: l.height,\n };\n if (l.name !== undefined) tl.name = l.name;\n if (l.rotation !== undefined) tl.rotation = l.rotation;\n if (l.font_family !== undefined) tl.font_family = l.font_family;\n if (l.text_size !== undefined) tl.text_size = l.text_size;\n if (l.text_color !== undefined) tl.text_color = l.text_color;\n if (l.fill !== undefined) tl.fill = l.fill;\n // `line_beat_frames` is intentionally dropped — the line-sequencing\n // hack is gone; looping is the general track_loops mechanism.\n movedTextLayers.push(tl);\n } else {\n keptImages.push(entry);\n }\n }\n\n if (rekey.size === 0) return raw;\n\n const remapId = (id: unknown): unknown =>\n typeof id === \"string\" && rekey.has(id) ? rekey.get(id)! : id;\n\n const next: Record<string, unknown> = { ...p };\n next.image_layers = keptImages;\n next.text_layers = [\n ...(Array.isArray(p.text_layers) ? p.text_layers : []),\n ...movedTextLayers,\n ];\n\n if (Array.isArray(p.layer_order)) {\n next.layer_order = p.layer_order.map(remapId);\n }\n for (const field of [\"animations\", \"styles\", \"color_tracks\", \"track_loops\"]) {\n const rec = p[field];\n if (rec && typeof rec === \"object\" && !Array.isArray(rec)) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(rec as Record<string, unknown>)) {\n out[rekey.has(k) ? rekey.get(k)! : k] = v;\n }\n next[field] = out;\n }\n }\n if (Array.isArray(p.groups)) {\n next.groups = p.groups.map((g) => {\n if (g && typeof g === \"object\" && !Array.isArray(g)) {\n const gr = g as Record<string, unknown>;\n if (Array.isArray(gr.children)) {\n return { ...gr, children: gr.children.map(remapId) };\n }\n }\n return g;\n });\n }\n return next;\n};\n\nconst preprocessProject = (raw: unknown): unknown =>\n migrateImageTextLayers(\n migrateBackgroundToImageLayer(\n migrateShapeColorsToFills(\n migrateTranslateToAbsolute(stripLegacyClipFrame(raw)),\n ),\n ),\n );\n\n// A \"public property\" exposes one layer's content as a partner-overridable\n// attribute on the <morpha-video> embed (e.g. `name=\"title\"` mapped to\n// `image.title.filename`). The embed SDK reads HTML attributes by `name`,\n// matches the schema entry, and substitutes the target layer's field before\n// rendering. `default_value` is what partners get when they don't override.\n//\n// { name: \"title\", type: \"image\", layer_id: \"image.title\",\n// default_value: \"drop-003-title.png\" }\n//\n// Type semantics:\n// \"image\" → swaps the targeted image_layer.filename (absolute URL allowed\n// from the partner side; the SDK fetches it directly).\n// \"text\" → reserved for a future text-layer kind. No-op in v1.\n// \"number\" → reserved for numeric overrides (opacity, scale). No-op in v1.\n// \"color\" → reserved for shape/palette colour overrides. No-op in v1.\nconst publicPropertySchema = z\n .object({\n name: z.string().min(1).regex(/^[a-z][a-z0-9-]*$/),\n type: z.enum([\"text\", \"image\", \"number\", \"color\"]),\n layer_id: z.string().min(1),\n default_value: z.string().default(\"\"),\n })\n .strict();\n\n// ── Loop section ───────────────────────────────────────────────────────────\n// When `project.loop` has 1+ passes the WHOLE composition is a looped section:\n// it plays once per pass, so N passes ⇒ the comp repeats N times. Before pass\n// i renders, every override in passes[i] is applied to the project — so each\n// repeat can show different text / colour / position / any layer field. Empty\n// `loop` ⇒ the comp plays once. This is the general looping mechanism: an\n// explicit array of property-sets, not a text-specific hack.\nconst loopOverrideSchema = z\n .object({\n // Target layer: text.<id> / image.<id> / shapes.<id> / video.<id>.\n elementId: z.string().min(1),\n // The layer field this pass overrides — e.g. \"text\", \"text_color\",\n // \"font_family\", \"filename\". Applied for this pass only.\n field: z.string().min(1),\n // The value to set for this pass.\n value: z.union([z.string(), z.number()]),\n })\n .strict();\n\nconst loopPassSchema = z\n .object({\n // Optional human label for the pass (shown in the Inspector).\n label: z.string().optional(),\n overrides: z.array(loopOverrideSchema).default([]),\n })\n .strict();\n\nexport type LoopOverride = z.infer<typeof loopOverrideSchema>;\nexport type LoopPass = z.infer<typeof loopPassSchema>;\n\n// A custom (non-Google-Fonts) typeface registered on the project. Text layers\n// reference it by `family` via their `font_family`, exactly like a Google\n// family. `src` is EITHER a full URL (https://…, data:…) OR an uploaded asset\n// filename — resolved against the project's asset bucket the same way image\n// filenames are. The font loader (editor/src/fonts.ts) loads each via the\n// FontFace API into document.fonts before the synchronous render loop.\nconst customFontSchema = z\n .object({\n family: z.string().min(1),\n src: z.string().min(1),\n // Optional specific face this src provides. When omitted the face is\n // treated as the family's 400/normal baseline.\n weight: z.number().int().min(1).max(1000).optional(),\n style: z.enum([\"normal\", \"italic\"]).optional(),\n })\n .strict();\n\nexport type CustomFont = z.infer<typeof customFontSchema>;\n\nexport const projectSchema = z.preprocess(\n preprocessProject,\n z\n .object({\n project_id: z.string().min(1),\n // Human-readable label shown in the project picker. Optional — falls\n // back to project_id when missing or empty so the dropdown is never\n // blank for older projects that pre-date this field.\n name: z.string().optional(),\n schema_version: z.literal(SCHEMA_VERSION),\n image_layers: z.array(imageLayerSchema).default([]),\n video_layers: z.array(videoLayerSchema).default([]),\n // Text layers — first-class leaf type, addressed as text.<id>.\n text_layers: z.array(textLayerSchema).default([]),\n shapes: z.array(shapeSchema).default([]),\n animations: animationsSchema.default({}),\n styles: stylesSchema.default({}),\n // Ordered list of ROOT-LEVEL element ids defining the top of the z-stack\n // tree (later in array = higher z = on top). Element ids:\n // \"video.<id>\", \"image.<id>\", \"shapes.<id>\", \"group.<id>\". Children of\n // any group are ordered by that group's `children` field, NOT here.\n // Empty → canonical fallback (ungrouped video layers, then shapes, then\n // image layers, then groups, all in array order). Missing-from-array but\n // present-and-ungrouped → appended (defaults to top); present-in-array\n // but grouped or missing → silently skipped.\n layer_order: z.array(z.string()).default([]),\n // Layer groups. See groupSchema. Empty by default; older projects parse\n // cleanly because the field defaults to [].\n groups: z.array(groupSchema).default([]),\n // First-class composition duration in seconds (drives the timeline /\n // export length). Old projects without this field default to 30s — the\n // App.tsx load path then seeds the field intelligently the first time\n // (probed mp4 length when the project has a video layer, else 30).\n // 30 fps; durationInFrames = ceil(duration_seconds * 30).\n duration_seconds: z.number().positive().default(30),\n // Audio overlays — independent sound clips scheduled at frame-aligned\n // starts. Played in the editor preview via WebAudio and mixed into the\n // MP4 export's AAC track alongside any source-mp4 audio. Default [] so\n // older projects parse cleanly.\n audio_overlays: z.array(audioOverlaySchema).default([]),\n // Timeline markers — named cue points on the timeline ruler (beat\n // markers, action cues, \"CTA here\" notes). Frame-aligned, purely\n // editorial — they don't affect the render. Default [] so older\n // projects parse cleanly.\n markers: z\n .array(\n z\n .object({\n id: z.string().min(1),\n frame: z.number().int().nonnegative(),\n label: z.string().default(\"\"),\n color: z.string().optional(), // #rrggbb, optional accent override\n })\n .strict(),\n )\n .default([]),\n // Loop section — see loopPassSchema. Empty ⇒ the comp plays once;\n // N passes ⇒ pass i applying its overrides plays in the loop region\n // (see loop_start_frame / loop_end_frame) once each. The region is a\n // SUB-SECTION of the video, not the whole video — frames outside\n // [loop_start_frame, loop_end_frame) play linearly once.\n loop: z.array(loopPassSchema).default([]),\n // Loop region — the sub-section of the video that repeats. Frame\n // numbers in the video's local frame space (0 = video start). If\n // loop_end_frame is null, the region ends at the video's last frame.\n // Defaults cover the whole video for back-compat with projects whose\n // loop was authored before this field existed.\n loop_start_frame: z.number().int().min(0).default(0),\n loop_end_frame: z.number().int().min(1).nullable().default(null),\n // Per-element, per-property extrapolation mode for animation tracks.\n // Default {} so older projects parse cleanly — when a track isn't\n // listed here, evaluateTrack uses \"hold\" (the historic behaviour).\n // See loopModeSchema for the four modes.\n track_loops: projectLoopsSchema.default({}),\n // Fill-valued keyframe tracks, parallel to `animations`. Element id\n // conventions mirror `animations`, with the addition of the project-\n // level pseudo-id \"palette\" for the canvas backdrop. Default {} so\n // older projects parse cleanly — when no track exists for an\n // element/property, the renderer falls back to the static field.\n color_tracks: colorTracksSchema.default({}),\n // The version this project state is checkpointed against. null when\n // no version exists yet (brand-new project or pre-versions JSON).\n // Set by the worker on save_version / restore_version; the editor\n // reads it to identify which entry in the Versions list is \"current\".\n current_version_id: z.string().nullable().default(null),\n // Unix ms of the last mutation. Bumped on every editor edit (via\n // scheduleSave) and reset to the version's timestamp on save/restore.\n // `last_modified_at > <currentVersion.timestamp>` ⇒ project is dirty.\n last_modified_at: z.number().int().nonnegative().default(0),\n // Allowlist of bare hostnames (no scheme, no port) where this project's\n // <morpha-video> embed is permitted to render. Worker checks the\n // request's Origin header against this list and 403s mismatches. Empty\n // ⇒ embedding disabled (the embed endpoint returns 404 for the project).\n embed_origins: z.array(z.string()).default([]),\n // Partner-overridable attributes exposed via the <morpha-video> tag.\n // See publicPropertySchema above for shape + semantics.\n public_properties: z.array(publicPropertySchema).default([]),\n // Custom (non-Google) typefaces registered on the project. See\n // customFontSchema. Text layers reference them by family name via\n // font_family. Default [] so older projects parse cleanly.\n custom_fonts: z.array(customFontSchema).default([]),\n // Composition canvas dimensions in pixels. Drives renderer, export, and\n // embed render size. Defaults to 1080×1920 (vertical 9:16) so existing\n // R2 projects parse unchanged. Picker in PlayerPanel exposes three\n // platform presets + a Pro-gated Custom row.\n canvas_width: z.number().int().positive().default(1080),\n canvas_height: z.number().int().positive().default(1920),\n })\n .strict(),\n);\n\nexport type Easing = z.infer<typeof easingSchema>;\nexport type Keyframe = z.infer<typeof keyframeSchema>;\nexport type TrackProperty = z.infer<typeof trackPropertySchema>;\nexport type ElementTracks = z.infer<typeof elementTracksSchema>;\nexport type Animations = z.infer<typeof animationsSchema>;\nexport type Project = z.infer<typeof projectSchema>;\nexport type ImageLayer = z.infer<typeof imageLayerSchema>;\nexport type VideoLayer = z.infer<typeof videoLayerSchema>;\nexport type ShapeKind = z.infer<typeof shapeKindSchema>;\nexport type Shape = z.infer<typeof shapeSchema>;\nexport type LayerStyle = z.infer<typeof layerStyleSchema>;\nexport type Styles = z.infer<typeof stylesSchema>;\nexport type FitMode = z.infer<typeof fitModeSchema>;\nexport type PublicProperty = z.infer<typeof publicPropertySchema>;\nexport type FillStop = z.infer<typeof fillStopSchema>;\nexport type SolidFill = z.infer<typeof solidFillSchema>;\nexport type LinearGradient = z.infer<typeof linearGradientSchema>;\nexport type RadialGradient = z.infer<typeof radialGradientSchema>;\nexport type MaskFill = z.infer<typeof maskFillSchema>;\nexport type Fill = z.infer<typeof fillSchema>;\n\n// Legacy source-clip entry. Pre-refactor, projects had a global \"shortlist\" of\n// candidate source clips and the editor flipped between them via an active-\n// entry index. The new model represents source clips as ordinary\n// `video_layers[]`. The shortlist schema is retained for the worker's project\n// GET migration: it reads any existing shortlist file and converts each entry\n// into a video_layer. Older JSON stored `label` as `performer` — preprocess\n// transparently maps that.\nexport const shortlistEntrySchema = z.preprocess((v) => {\n if (\n v &&\n typeof v === \"object\" &&\n !Array.isArray(v) &&\n \"performer\" in v &&\n !(\"label\" in v)\n ) {\n const { performer, ...rest } = v as Record<string, unknown>;\n return { ...rest, label: performer };\n }\n return v;\n}, z\n .object({\n clip: z.string().min(1),\n label: z.string().min(1),\n })\n .strict());\n\nexport const shortlistSchema = z\n .object({\n project_id: z.string().min(1),\n entries: z.array(shortlistEntrySchema),\n })\n .strict();\n\nexport type ShortlistEntry = z.infer<typeof shortlistEntrySchema>;\nexport type Shortlist = z.infer<typeof shortlistSchema>;\n\n// Server-backed version. One row per saved version of a project; restoring\n// rewrites the live project to `project`. We keep the inner project as the\n// validated schema so a version can never carry a malformed payload.\nexport const versionSchema = z\n .object({\n id: z.string().min(1),\n name: z.string(),\n /** Unix ms — sort key for the picker. */\n timestamp: z.number().int().nonnegative(),\n /** \"manual\" = user pressed Save; \"agent\" = MCP/HTTP tool wrote it. */\n source: z.enum([\"manual\", \"agent\"]).default(\"manual\"),\n /** Discriminator for the Figma / Google Docs split:\n * \"bookmark\" — user/agent deliberately marked a milestone. Surfaces in\n * the main Bookmarks list, gets a V<n> pill, and is the\n * only kind the embed snippet can pin to.\n * \"auto\" — background auto-snapshot written by the editor every\n * ~10 mutations or 5 min of edit activity. Surfaces only\n * in the Auto-history drawer; never referenced externally.\n * Default = \"bookmark\" so legacy rows (missing the field) parse as\n * bookmarks — they were all deliberate saves before this split. */\n kind: z.enum([\"bookmark\", \"auto\"]).default(\"bookmark\"),\n /** Stable, monotonic per-project version number assigned at save time.\n * v1 = first version saved, v<n> = nth. Deleting a version leaves gaps —\n * numbers never re-shuffle, so any external reference (snippet, MCP call,\n * shared link) keeps pointing at the same content for its lifetime.\n * Assigned across BOTH kinds at save time; the editor's bookmarks-only\n * V<n> display label is computed by filtering to kind==\"bookmark\" and\n * indexing, NOT by reading this field directly.\n * Optional only for backwards-compat with legacy versions saved before\n * the field was introduced; the worker backfills missing values on read\n * by timestamp-ascending order and persists the result. */\n version_number: z.number().int().positive().optional(),\n project: projectSchema,\n })\n .strict();\n\nexport type Version = z.infer<typeof versionSchema>;\n\n// Tree node returned by resolveLayerTree. id is always set; children is\n// populated only on group nodes (an empty array still means \"this is a\n// group with no kids\", which is renderably distinct from a leaf).\nexport type LayerNode = { id: string; children?: LayerNode[] };\n\nconst collectPresentIds = (project: Project): Set<string> => {\n const present = new Set<string>();\n for (const v of project.video_layers) present.add(`video.${v.id}`);\n for (const s of project.shapes) present.add(`shapes.${s.id}`);\n for (const l of project.image_layers) present.add(`image.${l.id}`);\n for (const t of project.text_layers) present.add(`text.${t.id}`);\n for (const g of project.groups ?? []) present.add(`group.${g.id}`);\n return present;\n};\n\nconst collectGroupedIds = (project: Project): Set<string> => {\n const out = new Set<string>();\n for (const g of project.groups ?? []) {\n for (const child of g.children) out.add(child);\n }\n return out;\n};\n\n// Pinned image_layer ids. Layers marked `pinned: true` are forced to the\n// BOTTOM of the root z-stack regardless of where they appear in\n// `layer_order` (which silently ignores them). Today only the canvas\n// backdrop is pinned, but the mechanism is general — any pinned-tagged\n// layer behaves the same way.\nconst collectPinnedRootIds = (project: Project): string[] =>\n project.image_layers\n .filter((l) => l.pinned === true)\n .map((l) => `image.${l.id}`);\n\n// Resolve the project's render tree. Each entry is a root-level id; group\n// nodes carry a nested `children` list. Same precedence rules as the old\n// flat resolver, just applied at root and recursed into each group:\n// - non-empty `layer_order` is filtered to root-level present ids, then\n// any unlisted ungrouped ids are appended in canonical order;\n// - empty `layer_order` falls back to canonical (ungrouped video layers,\n// then ungrouped shapes, then ungrouped image layers, then ungrouped\n// groups), all in array order.\n// - PINNED image layers are pre-pended at root (= bottom of z) regardless\n// of layer_order; non-pinned layers sit above them. Render order in\n// the tree is back-to-front, so the pinned layer paints first.\n// A given element id appears at most once in the whole tree.\nexport const resolveLayerTree = (project: Project): LayerNode[] => {\n const present = collectPresentIds(project);\n const grouped = collectGroupedIds(project);\n const groupById = new Map<string, Group>();\n for (const g of project.groups ?? []) groupById.set(g.id, g);\n const pinnedRoot = new Set(collectPinnedRootIds(project));\n\n const seen = new Set<string>();\n const buildNode = (id: string): LayerNode | null => {\n if (!present.has(id)) return null;\n if (seen.has(id)) return null;\n seen.add(id);\n if (id.startsWith(\"group.\")) {\n const g = groupById.get(id.slice(\"group.\".length));\n if (!g) return null;\n const children: LayerNode[] = [];\n for (const childId of g.children) {\n const node = buildNode(childId);\n if (node) children.push(node);\n }\n return { id, children };\n }\n return { id };\n };\n\n const rootIds: string[] = [];\n const seenRoot = new Set<string>();\n const pushRoot = (id: string) => {\n if (seenRoot.has(id)) return;\n if (grouped.has(id)) return;\n if (!present.has(id)) return;\n if (pinnedRoot.has(id)) return;\n seenRoot.add(id);\n rootIds.push(id);\n };\n\n const explicit = project.layer_order ?? [];\n for (const id of explicit) pushRoot(id);\n for (const v of project.video_layers) pushRoot(`video.${v.id}`);\n for (const s of project.shapes) pushRoot(`shapes.${s.id}`);\n for (const l of project.image_layers) {\n if (l.pinned === true) continue;\n pushRoot(`image.${l.id}`);\n }\n for (const t of project.text_layers) pushRoot(`text.${t.id}`);\n for (const g of project.groups ?? []) pushRoot(`group.${g.id}`);\n\n const out: LayerNode[] = [];\n // Pinned layers come FIRST in tree order (= back of z-stack, painted\n // before everything else). Preserve their relative order from\n // image_layers[].\n for (const id of pinnedRoot) {\n const node = buildNode(id);\n if (node) out.push(node);\n }\n for (const id of rootIds) {\n const node = buildNode(id);\n if (node) out.push(node);\n }\n return out;\n};\n\nconst flattenTree = (nodes: LayerNode[], leavesOnly: boolean): string[] => {\n const out: string[] = [];\n const walk = (ns: LayerNode[]) => {\n for (const n of ns) {\n const isGroup = n.children !== undefined;\n if (isGroup) {\n if (!leavesOnly) out.push(n.id);\n walk(n.children!);\n } else {\n out.push(n.id);\n }\n }\n };\n walk(nodes);\n return out;\n};\n\n// Flat render-order list of every element id in the project, depth-first.\n// Includes group ids interleaved with their descendants. Backwards-compatible\n// with the pre-groups behaviour for projects that have no groups (the result\n// is identical to the old shapes-then-images list).\nexport const resolveLayerOrder = (project: Project): string[] =>\n flattenTree(resolveLayerTree(project), false);\n\n// Flat render-order list of LEAF ids only (video + shape + image layers).\n// Use this for hit-testing and any consumer that wants to address visual\n// layers and not the abstract groups containing them.\nexport const resolveLeafOrder = (project: Project): string[] =>\n flattenTree(resolveLayerTree(project), true);\n\n// The immediate parent group's bare id (no \"group.\" prefix), or null if the\n// element sits at the tree root or isn't referenced by any group.\nexport const findParentGroup = (\n project: Project,\n elementId: string,\n): string | null => {\n for (const g of project.groups ?? []) {\n if (g.children.includes(elementId)) return g.id;\n }\n return null;\n};\n\n// Ancestor group ids (bare, no prefix) from root-most to immediate parent,\n// excluding the element itself. Empty for root-level elements / unknown ids.\n// The maxDepth bound is defensive — dispatchers refuse cycles, but a hand-\n// edited file could in principle produce one.\nexport const getAncestorGroupChain = (\n project: Project,\n elementId: string,\n): string[] => {\n const chain: string[] = [];\n let current = elementId;\n const maxDepth = (project.groups ?? []).length + 1;\n for (let i = 0; i < maxDepth; i++) {\n const parentGid = findParentGroup(project, current);\n if (parentGid === null) break;\n chain.unshift(parentGid);\n current = `group.${parentGid}`;\n }\n return chain;\n};\n\n// All descendant element ids of a group (depth-first, leaves and nested\n// groups). Used by ungroup to splice children back in, by renderer hit-test\n// to pick a leaf for drill-down, and to enforce group cycle prevention.\nexport const getGroupDescendants = (\n project: Project,\n groupId: string,\n): string[] => {\n const groupById = new Map<string, Group>();\n for (const g of project.groups ?? []) groupById.set(g.id, g);\n const out: string[] = [];\n const seen = new Set<string>();\n const walk = (gid: string) => {\n if (seen.has(gid)) return;\n seen.add(gid);\n const g = groupById.get(gid);\n if (!g) return;\n for (const child of g.children) {\n out.push(child);\n if (child.startsWith(\"group.\")) walk(child.slice(\"group.\".length));\n }\n };\n walk(groupId);\n return out;\n};\n\n// Validate raw JSON as a Project. Kept as a named function so callers that\n// already invoke `migrateProject(raw)` keep working — the historical v0/v1\n// transforms are gone (data has been wiped), so this is now just a parse.\nexport const migrateProject = (raw: unknown): Project => projectSchema.parse(raw);\n\n","// Pure tool dispatchers — single source of truth for the agent-callable\n// catalog. Each dispatcher takes a Project (already validated) and tool args,\n// returns { project, result }. No I/O, no store access, no UI dependencies.\n//\n// Two surfaces wrap these:\n// 1. Editor adapter (`editor/src/llm-tools.ts`) — runs the dispatcher on the\n// live zustand `project`, then `setState` + `scheduleSave` so the running\n// editor reflects + persists the change.\n// 2. Headless callers — the Worker's `POST /api/tool/<name>` HTTP route\n// and the MCP server at `worker/src/routes/mcp.ts`. Both load the\n// project from R2, run the dispatcher, write back on `result.ok`.\n//\n// Element id convention (matches schema layer_order):\n// - \"video.<id>\" — video layers (a source mp4 rendered into the layer\n// box; multiple per project allowed, audio mixes in\n// preview + export).\n// - \"image.<id>\" — image layers\n// - \"shapes.<id>\" — shape layers\n// - \"group.<id>\" — layer groups (transform composes onto descendants)\nimport { SHAPE_DEFS, SHAPE_IDS } from \"./shapes.ts\";\n// Cross-tree import: the font catalogues live in editor/src/ (the editor is\n// their primary consumer); the agent-facing list_fonts tool reuses them so\n// every source the picker knows about is also discoverable via MCP.\nimport {\n allFontEntries,\n type FontSource,\n} from \"../editor/src/font-sources.ts\";\nimport {\n fillSchema,\n findParentGroup,\n getGroupDescendants,\n resolveLayerTree,\n type AudioOverlay,\n type ColorKeyframe,\n type Easing,\n type ElementColorTracks,\n type ElementTracks,\n type Fill,\n type Group,\n type ImageLayer,\n type Keyframe,\n type LayerStyle,\n type LoopPass,\n type Project,\n type Shape,\n type ShapeKind,\n type TextLayer,\n type TrackProperty,\n type VideoLayer,\n} from \"./schemas.ts\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type ToolFunction = {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n};\n\nexport type ToolResult =\n | { ok: true; data?: unknown }\n | { ok: false; error: string };\n\nexport type ToolOutcome = {\n project: Project;\n result: ToolResult;\n};\n\nexport type ToolDispatch<Args = Record<string, unknown>> = (\n project: Project,\n args: Args,\n) => ToolOutcome;\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nconst cloneProject = (p: Project): Project =>\n structuredClone(p) as Project;\n\nconst HEX = /^#[0-9a-fA-F]{6}$/;\n\n// Accept either the `\"#rrggbb\"` shorthand (promoted to a solid Fill at full\n// opacity) or a Fill-shaped object (validated through `fillSchema`). Returns\n// the parsed Fill, or null if neither shape matched.\nconst coerceFill = (input: unknown): Fill | null => {\n if (typeof input === \"string\") {\n if (!HEX.test(input)) return null;\n return { type: \"solid\", color: input, opacity: 1 };\n }\n if (!input || typeof input !== \"object\") return null;\n const parsed = fillSchema.safeParse(input);\n return parsed.success ? parsed.data : null;\n};\n\n// Static x/y for the leaf-layer behind an elementId. Groups have no static\n// position — their x/y track values are direct translation offsets around the\n// frozen pivot — so this returns zeros for them. Used by apply_preset to\n// turn delta-style tuple values (slide/shake) into absolute keyframes.\nconst baseForElement = (\n project: Project,\n elementId: string,\n): { x: number; y: number } => {\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const l = project.image_layers.find((x) => x.id === id);\n if (l) return { x: l.x, y: l.y };\n } else if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n const v = project.video_layers.find((x) => x.id === id);\n if (v) return { x: v.x, y: v.y };\n } else if (elementId.startsWith(\"shapes.\")) {\n const id = elementId.slice(\"shapes.\".length);\n const s = project.shapes.find((x) => x.id === id);\n if (s) return { x: s.x, y: s.y };\n } else if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n const t = project.text_layers.find((x) => x.id === id);\n if (t) return { x: t.x, y: t.y };\n }\n return { x: 0, y: 0 };\n};\n\nconst VALID_PROPS: TrackProperty[] = [\n \"x\",\n \"y\",\n \"width\",\n \"height\",\n \"scale\",\n \"rotation\",\n \"opacity\",\n];\n\nconst VALID_EASINGS: Easing[] = [\n \"linear\",\n \"easeIn\",\n \"easeOut\",\n \"easeInOut\",\n \"outQuart\",\n \"outExpo\",\n \"outBack\",\n \"inBack\",\n \"inOutBack\",\n \"cubicBezier\",\n \"hold\",\n];\n\nconst ensureTrack = (\n project: Project,\n elementId: string,\n property: TrackProperty,\n): Keyframe[] => {\n if (!project.animations[elementId]) {\n project.animations[elementId] = {} as ElementTracks;\n }\n const tracks = project.animations[elementId];\n if (!tracks[property]) {\n tracks[property] = [];\n }\n return tracks[property] as Keyframe[];\n};\n\nconst sortByFrame = (kfs: Keyframe[]) => {\n kfs.sort((a, b) => a.frame - b.frame);\n};\n\n// Upsert a keyframe at exactly `frame` on `elementId.property`. If a keyframe\n// already exists at that frame, its value (and optionally easing) are updated;\n// otherwise a new one is inserted with linear easing as the default.\nconst upsertKeyframe = (\n project: Project,\n elementId: string,\n property: TrackProperty,\n frame: number,\n value: number,\n easing?: Easing,\n): void => {\n const kfs = ensureTrack(project, elementId, property);\n const idx = kfs.findIndex((k) => k.frame === frame);\n if (idx >= 0) {\n kfs[idx] = { ...kfs[idx], value, ...(easing ? { easing } : {}) };\n } else {\n kfs.push({ frame, value, easing: easing ?? \"linear\" });\n }\n sortByFrame(kfs);\n};\n\n// Force project.layer_order to be a complete list of root-level element ids,\n// in the same order resolveLayerTree would return. The schema permits the\n// resolver to invent missing entries (so old files round-trip cleanly), but\n// dispatchers that splice into the root list need a definite ordering — call\n// this on the cloned project before any layer_order mutation.\nconst normalizeRoot = (project: Project): void => {\n project.layer_order = resolveLayerTree(project).map((n) => n.id);\n};\n\n// Base-position centre of a child element. Used to seed a new group's pivot.\n// Returns null for unknown ids; the caller defaults to the canvas centre.\nconst childBaseCenter = (\n project: Project,\n childId: string,\n): { x: number; y: number } | null => {\n if (childId.startsWith(\"video.\")) {\n const id = childId.slice(\"video.\".length);\n const v = project.video_layers.find((x) => x.id === id);\n return v ? { x: v.x, y: v.y } : null;\n }\n if (childId.startsWith(\"image.\")) {\n const id = childId.slice(\"image.\".length);\n const l = project.image_layers.find((x) => x.id === id);\n return l ? { x: l.x, y: l.y } : null;\n }\n if (childId.startsWith(\"shapes.\")) {\n const id = childId.slice(\"shapes.\".length);\n const s = project.shapes.find((x) => x.id === id);\n return s ? { x: s.x, y: s.y } : null;\n }\n if (childId.startsWith(\"text.\")) {\n const id = childId.slice(\"text.\".length);\n const t = project.text_layers.find((x) => x.id === id);\n return t ? { x: t.x, y: t.y } : null;\n }\n if (childId.startsWith(\"group.\")) {\n const id = childId.slice(\"group.\".length);\n const g = project.groups.find((x) => x.id === id);\n return g ? { x: g.pivotX, y: g.pivotY } : null;\n }\n return null;\n};\n\n// Layer ids are 6 lowercase hex chars — opaque tokens generated at creation,\n// never derived from name/filename/text content. Matches the pattern every\n// major motion / NLE / design editor uses (After Effects, Premiere, FCP,\n// Figma, Illustrator): ids are storage keys, names are user-facing labels,\n// and the two carry no relationship. The pre-2026-05 model derived ids from\n// names, which drifted as layers were renamed (e.g. `image.raj` long after\n// the layer was renamed to \"character\"). Opaque ids end the bug class.\n// The pinned background image_layer keeps its `\"background\"` sentinel id;\n// that is the only non-hex layer id allowed.\nexport const LAYER_ID_FORMAT = /^[0-9a-f]{6}$/;\nexport const BACKGROUND_LAYER_ID = \"background\";\n\nexport type LayerKind = \"image\" | \"video\" | \"text\" | \"shapes\" | \"group\";\n\nconst allLayerIdsForKind = (project: Project, kind: LayerKind): Set<string> => {\n const out = new Set<string>();\n const arr =\n kind === \"image\"\n ? project.image_layers\n : kind === \"video\"\n ? project.video_layers\n : kind === \"text\"\n ? project.text_layers\n : kind === \"shapes\"\n ? project.shapes\n : project.groups;\n for (const l of arr) out.add(l.id);\n return out;\n};\n\nexport const generateLayerId = (project: Project, kind: LayerKind): string => {\n const existing = allLayerIdsForKind(project, kind);\n for (let attempt = 0; attempt < 100; attempt += 1) {\n const buf = new Uint8Array(3);\n crypto.getRandomValues(buf);\n const id = Array.from(buf)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n if (!existing.has(id)) return id;\n }\n // 100 collisions in a row on a 16M-id space is astronomically unlikely;\n // throw rather than spin forever if the rng is broken.\n throw new Error(\n `generateLayerId: 100 collisions on ${kind} (existing=${existing.size})`,\n );\n};\n\n// Rewrite every reference to `oldElementId` so they point at `newElementId`.\n// Mutates `project` in place — call on a cloned project. Covers every\n// reference site found in `projectSchema`:\n// - the layer's own `.id` field (bare suffix after the dot)\n// - `layer_order[]`\n// - keys of `animations` / `styles` / `track_loops` / `color_tracks`\n// - `groups[*].children[]`\n// - `matte_source_id` on every layer kind (image / video / text / shapes / group)\n// - `mask`-type `.fill.layer_id` on every layer's fill\n// - `loop[*].overrides[*].elementId`\n// - `public_properties[*].layer_id`\n// Both ids must share the same kind prefix; the function throws otherwise.\nexport const rekeyElementId = (\n project: Project,\n oldElementId: string,\n newElementId: string,\n): void => {\n if (oldElementId === newElementId) return;\n const oldDot = oldElementId.indexOf(\".\");\n const newDot = newElementId.indexOf(\".\");\n if (oldDot < 1 || newDot < 1) {\n throw new Error(`rekeyElementId: ids must contain \"kind.\" prefix`);\n }\n const oldKind = oldElementId.slice(0, oldDot);\n const newKind = newElementId.slice(0, newDot);\n if (oldKind !== newKind) {\n throw new Error(`rekeyElementId: kind mismatch ${oldKind} → ${newKind}`);\n }\n const oldBare = oldElementId.slice(oldDot + 1);\n const newBare = newElementId.slice(newDot + 1);\n\n // 1. The layer's own .id field\n const arr =\n oldKind === \"image\"\n ? project.image_layers\n : oldKind === \"video\"\n ? project.video_layers\n : oldKind === \"text\"\n ? project.text_layers\n : oldKind === \"shapes\"\n ? project.shapes\n : oldKind === \"group\"\n ? project.groups\n : null;\n if (!arr) {\n throw new Error(`rekeyElementId: unknown kind ${oldKind}`);\n }\n for (const layer of arr as { id: string }[]) {\n if (layer.id === oldBare) layer.id = newBare;\n }\n\n // 2. layer_order\n project.layer_order = project.layer_order.map((id) =>\n id === oldElementId ? newElementId : id,\n );\n\n // 3. animations / styles / track_loops / color_tracks — top-level Records\n const rekeyMap = <V>(rec: Record<string, V> | undefined): void => {\n if (!rec) return;\n if (oldElementId in rec) {\n rec[newElementId] = rec[oldElementId];\n delete rec[oldElementId];\n }\n };\n rekeyMap(project.animations as Record<string, unknown> as Record<string, ElementTracks>);\n rekeyMap(project.styles as unknown as Record<string, LayerStyle>);\n rekeyMap(project.track_loops as unknown as Record<string, unknown>);\n rekeyMap(project.color_tracks as unknown as Record<string, ElementColorTracks>);\n\n // 4. groups[*].children[]\n for (const g of project.groups) {\n g.children = g.children.map((id) =>\n id === oldElementId ? newElementId : id,\n );\n }\n\n // 5. matte_source_id on every layer kind\n const fixMatte = (layer: { matte_source_id?: string | null }): void => {\n if (layer.matte_source_id === oldElementId) {\n layer.matte_source_id = newElementId;\n }\n };\n project.image_layers.forEach(fixMatte);\n project.video_layers.forEach(fixMatte);\n project.text_layers.forEach(fixMatte);\n project.shapes.forEach(fixMatte);\n project.groups.forEach(fixMatte);\n\n // 6. mask-type fills (.fill.layer_id) — discriminated union, check type\n const fixMaskFill = (layer: { fill?: Fill | null }): void => {\n if (layer.fill && layer.fill.type === \"mask\") {\n if (layer.fill.layer_id === oldElementId) {\n layer.fill.layer_id = newElementId;\n }\n }\n };\n project.image_layers.forEach(fixMaskFill);\n project.video_layers.forEach(fixMaskFill);\n project.text_layers.forEach(fixMaskFill);\n project.shapes.forEach(fixMaskFill);\n project.groups.forEach(fixMaskFill);\n\n // 7. loop[*].overrides[*].elementId\n if (project.loop) {\n for (const pass of project.loop) {\n for (const ov of pass.overrides) {\n if (ov.elementId === oldElementId) ov.elementId = newElementId;\n }\n }\n }\n\n // 8. public_properties[*].layer_id\n if (project.public_properties) {\n for (const pp of project.public_properties) {\n if (pp.layer_id === oldElementId) pp.layer_id = newElementId;\n }\n }\n};\n\n// Walk every layer in the project and re-id any whose current id doesn't\n// match LAYER_ID_FORMAT (other than the pinned background sentinel). Used by\n// the one-shot `POST /api/migrate-layer-ids` route to normalize legacy\n// projects whose ids were derived from layer names (e.g. `image.raj`,\n// `text.label-raj`). Mutates `project` in place; returns the list of rekeys\n// performed so the route can report what changed.\nexport const normalizeProjectLayerIds = (\n project: Project,\n): Array<{ from: string; to: string }> => {\n const rekeys: Array<{ from: string; to: string }> = [];\n const kinds: LayerKind[] = [\"image\", \"video\", \"text\", \"shapes\", \"group\"];\n for (const kind of kinds) {\n // Snapshot the list of (kind, oldBareId) BEFORE mutating — the array's\n // element identity is preserved across rekeyElementId calls, but we want\n // a stable iteration order regardless of any future reshape.\n const arr =\n kind === \"image\"\n ? project.image_layers\n : kind === \"video\"\n ? project.video_layers\n : kind === \"text\"\n ? project.text_layers\n : kind === \"shapes\"\n ? project.shapes\n : project.groups;\n const snapshot = arr.map((l) => l);\n for (const layer of snapshot) {\n // Pinned background image keeps its sentinel id forever.\n if (kind === \"image\" && (layer as ImageLayer).is_background) continue;\n if (layer.id === BACKGROUND_LAYER_ID) continue;\n if (LAYER_ID_FORMAT.test(layer.id)) continue;\n const oldElementId = `${kind}.${layer.id}`;\n const newBare = generateLayerId(project, kind);\n const newElementId = `${kind}.${newBare}`;\n rekeyElementId(project, oldElementId, newElementId);\n rekeys.push({ from: oldElementId, to: newElementId });\n }\n }\n return rekeys;\n};\n\nconst COMP_W = 1080;\nconst COMP_H = 1920;\n\n// ---------------------------------------------------------------------------\n// describe_video\n// ---------------------------------------------------------------------------\n\n// Locate the canvas-backdrop image_layer id (\"background\" by convention,\n// but tolerant of migrated projects where the id may differ). Returns null\n// only for a project that's never been through `projectSchema.parse` — the\n// preprocess guarantees one exists.\nconst findBackgroundLayer = (project: Project): ImageLayer | null => {\n for (const l of project.image_layers) {\n if (l.is_background) return l;\n }\n return null;\n};\nconst backgroundElementId = (project: Project): string | null => {\n const l = findBackgroundLayer(project);\n return l ? `image.${l.id}` : null;\n};\n// Resolve the agent-facing alias `\"background.canvas\"` to the actual\n// element id (`\"image.<bgId>\"`). Agents written against the previous\n// schema keep working — they pass \"background.canvas\" and the dispatcher\n// rewrites it on the fly. Everything else passes through unchanged.\nconst resolveBackgroundAlias = (\n project: Project,\n elementId: string,\n): string => {\n if (elementId === \"background.canvas\") {\n const eid = backgroundElementId(project);\n if (eid) return eid;\n }\n return elementId;\n};\n\ntype ElementType = \"image\" | \"video\" | \"text\" | \"shapes\" | \"group\";\n\nconst elementTypeOf = (elementId: string): ElementType | null => {\n if (elementId.startsWith(\"image.\")) return \"image\";\n if (elementId.startsWith(\"video.\")) return \"video\";\n if (elementId.startsWith(\"text.\")) return \"text\";\n if (elementId.startsWith(\"shapes.\")) return \"shapes\";\n if (elementId.startsWith(\"group.\")) return \"group\";\n return null;\n};\n\n// Bare id from an element id. Prefix length is always `type.length + 1` (the\n// dot): image.→6, video.→6, text.→5, shapes.→7, group.→6.\nconst bareIdOf = (elementId: string, type: ElementType): string =>\n elementId.slice(type.length + 1);\n\n// Which properties carry a non-empty animation track for this element —\n// transform tracks (`animations`) plus the fill colour track (`color_tracks`,\n// surfaced as the pseudo-property \"fill\"). Returns just the keys, never the\n// keyframe arrays themselves — that's the whole point of the overview.\nconst animatedProps = (project: Project, elementId: string): string[] => {\n const out: string[] = [];\n const tracks = project.animations[elementId] as\n | Record<string, unknown[]>\n | undefined;\n if (tracks) {\n for (const k of Object.keys(tracks)) {\n if (Array.isArray(tracks[k]) && tracks[k].length > 0) out.push(k);\n }\n }\n const color = project.color_tracks?.[elementId];\n if (color?.fill && (color.fill as unknown[]).length > 0) out.push(\"fill\");\n return out;\n};\n\n// One node of the describe_video overview tree. Cheap: geometry + name + the\n// type-specific label + which properties are animated. NO keyframe arrays, NO\n// styles — pull those per-element via inspect_layers.\ntype OverviewNode = {\n elementId: string;\n type: ElementType;\n name: string | null;\n filename?: string;\n clip?: string;\n text?: string;\n kind?: ShapeKind;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n rotation?: number;\n pivotX?: number;\n pivotY?: number;\n childCount?: number;\n animated?: string[];\n children?: OverviewNode[];\n};\n\nconst overviewNode = (\n project: Project,\n node: { id: string; children?: { id: string; children?: unknown[] }[] },\n): OverviewNode | null => {\n const elementId = node.id;\n const type = elementTypeOf(elementId);\n if (!type) return null;\n const id = bareIdOf(elementId, type);\n const animated = animatedProps(project, elementId);\n const animField = animated.length > 0 ? { animated } : {};\n\n if (type === \"group\") {\n const g = project.groups.find((x) => x.id === id);\n if (!g) return null;\n const children = (node.children ?? [])\n .map((c) => overviewNode(project, c as { id: string }))\n .filter((n): n is OverviewNode => n !== null)\n .reverse();\n return {\n elementId,\n type,\n name: g.name ?? null,\n pivotX: g.pivotX,\n pivotY: g.pivotY,\n childCount: g.children.length,\n ...animField,\n children,\n };\n }\n if (type === \"image\") {\n const l = project.image_layers.find((x) => x.id === id);\n if (!l) return null;\n return {\n elementId,\n type,\n name: l.name ?? null,\n filename: l.filename,\n x: l.x,\n y: l.y,\n width: l.width,\n height: l.height,\n rotation: l.rotation,\n ...animField,\n };\n }\n if (type === \"video\") {\n const v = project.video_layers.find((x) => x.id === id);\n if (!v) return null;\n return {\n elementId,\n type,\n name: v.name ?? null,\n clip: v.clip,\n x: v.x,\n y: v.y,\n width: v.width,\n height: v.height,\n rotation: v.rotation,\n ...animField,\n };\n }\n if (type === \"text\") {\n const t = project.text_layers.find((x) => x.id === id);\n if (!t) return null;\n const text = t.text.length > 60 ? `${t.text.slice(0, 60)}…` : t.text;\n return {\n elementId,\n type,\n name: t.name ?? null,\n text,\n x: t.x,\n y: t.y,\n width: t.width,\n height: t.height,\n rotation: t.rotation,\n ...animField,\n };\n }\n const s = project.shapes.find((x) => x.id === id);\n if (!s) return null;\n return {\n elementId,\n type,\n name: s.name ?? null,\n kind: s.kind,\n x: s.x,\n y: s.y,\n width: s.width,\n height: s.height,\n rotation: s.rotation,\n ...animField,\n };\n};\n\n// describe_video — a cheap STRUCTURAL OVERVIEW (the project's table of\n// contents), not a full dump. Returns canvas meta + the backdrop summary + a\n// z-ordered tree of every layer with its geometry and which properties are\n// animated. It deliberately OMITS keyframe arrays and styles — those are the\n// unbounded part. To get full per-element detail (keyframes, styles, every\n// field) before mutating a specific layer, call inspect_layers([elementId]).\nconst describeVideo: ToolDispatch<Record<string, never>> = (project) => {\n const bg = findBackgroundLayer(project);\n const bgElementId = bg ? `image.${bg.id}` : null;\n // resolveLayerTree returns roots back-to-front (render order); the canvas\n // backdrop is pinned at the bottom — drop it from the tree (reported in\n // `background`) and reverse so the tree reads top-of-z first.\n const tree = resolveLayerTree(project)\n .filter((n) => n.id !== bgElementId)\n .map((n) => overviewNode(project, n))\n .filter((n): n is OverviewNode => n !== null)\n .reverse();\n\n const layerCount =\n project.image_layers.length -\n (bg ? 1 : 0) +\n project.video_layers.length +\n project.text_layers.length +\n project.shapes.length +\n project.groups.length;\n\n const data = {\n project_id: project.project_id,\n name: project.name ?? null,\n canvas_width: project.canvas_width,\n canvas_height: project.canvas_height,\n duration_seconds: project.duration_seconds,\n // Agent-facing summary of the canvas backdrop.\n background: bg\n ? { elementId: `image.${bg.id}`, name: bg.name, fill: bg.fill }\n : null,\n // Embed allowlist — hostnames permitted to load this project through the\n // public <morpha-video> embed. Empty ⇒ embedding is OFF.\n embed_origins: project.embed_origins,\n public_properties: project.public_properties,\n // Loop section — see set_loop. Empty ⇒ the comp plays once.\n loop: project.loop,\n layer_count: layerCount,\n // Overview tree, top of z-stack first. Each node lists which properties are\n // animated but NOT the keyframes — call inspect_layers for those.\n tree,\n hint: \"Call inspect_layers([elementId, …]) for full detail (keyframes, styles, every property) on the layers you're about to change. Don't guess values from this overview.\",\n };\n return { project, result: { ok: true, data } };\n};\n\n// ---------------------------------------------------------------------------\n// inspect_layers — full per-element drill-in (the \"open this layer\" half of the\n// structural browser). Returns each named element's complete record: all its\n// own fields plus its animation tracks, colour tracks, track-loop modes, and\n// style. Tiny per call, so the agent pulls detail only for the handful of\n// layers it's about to touch instead of dumping the whole project.\n// ---------------------------------------------------------------------------\n\ntype InspectLayersArgs = { elementIds?: unknown; elementId?: unknown };\n\nconst fullLayerRecord = (\n project: Project,\n elementId: string,\n): Record<string, unknown> | null => {\n const type = elementTypeOf(elementId);\n if (!type) return null;\n const id = bareIdOf(elementId, type);\n let layer:\n | ImageLayer\n | VideoLayer\n | TextLayer\n | Shape\n | Group\n | undefined;\n switch (type) {\n case \"image\":\n layer = project.image_layers.find((x) => x.id === id);\n break;\n case \"video\":\n layer = project.video_layers.find((x) => x.id === id);\n break;\n case \"text\":\n layer = project.text_layers.find((x) => x.id === id);\n break;\n case \"shapes\":\n layer = project.shapes.find((x) => x.id === id);\n break;\n case \"group\":\n layer = project.groups.find((x) => x.id === id);\n break;\n }\n if (!layer) return null;\n return {\n elementId,\n type,\n ...layer,\n animations: project.animations[elementId] ?? null,\n color_tracks: project.color_tracks?.[elementId] ?? null,\n track_loops: project.track_loops?.[elementId] ?? null,\n style: project.styles[elementId] ?? null,\n };\n};\n\nconst inspectLayers: ToolDispatch<InspectLayersArgs> = (project, args) => {\n const ids: string[] = Array.isArray(args.elementIds)\n ? (args.elementIds.filter((x) => typeof x === \"string\") as string[])\n : typeof args.elementId === \"string\"\n ? [args.elementId]\n : [];\n if (ids.length === 0) {\n return {\n project,\n result: { ok: false, error: \"elementIds (a string array) is required\" },\n };\n }\n const layers: Record<string, unknown>[] = [];\n const notFound: string[] = [];\n for (const elementId of ids) {\n const rec = fullLayerRecord(project, elementId);\n if (rec) layers.push(rec);\n else notFound.push(elementId);\n }\n if (layers.length === 0) {\n return {\n project,\n result: {\n ok: false,\n error: `no such element(s): ${notFound.join(\", \")}. Call describe_video for valid ids.`,\n },\n };\n }\n return {\n project,\n result: {\n ok: true,\n data: { layers, ...(notFound.length > 0 ? { notFound } : {}) },\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// move_layer\n// ---------------------------------------------------------------------------\n\ntype MoveLayerArgs = {\n elementId: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n rotation?: number;\n};\n\nconst moveLayer: ToolDispatch<MoveLayerArgs> = (project, args) => {\n const { elementId, x, y, width, height, rotation } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n\n const next = cloneProject(project);\n\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const idx = next.image_layers.findIndex((l: ImageLayer) => l.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `image layer not found: ${id}` } };\n }\n const cur = next.image_layers[idx];\n next.image_layers[idx] = {\n ...cur,\n x: x ?? cur.x,\n y: y ?? cur.y,\n width: width ?? cur.width,\n height: height ?? cur.height,\n rotation: rotation ?? cur.rotation,\n };\n return {\n project: next,\n result: {\n ok: true,\n data: { id: elementId, x: next.image_layers[idx].x, y: next.image_layers[idx].y },\n },\n };\n }\n\n if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n const idx = next.video_layers.findIndex((v: VideoLayer) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `video layer not found: ${id}` } };\n }\n const cur = next.video_layers[idx];\n next.video_layers[idx] = {\n ...cur,\n x: x ?? cur.x,\n y: y ?? cur.y,\n width: width ?? cur.width,\n height: height ?? cur.height,\n rotation: rotation ?? cur.rotation,\n };\n return {\n project: next,\n result: {\n ok: true,\n data: { id: elementId, x: next.video_layers[idx].x, y: next.video_layers[idx].y },\n },\n };\n }\n\n if (elementId.startsWith(\"shapes.\")) {\n const id = elementId.slice(\"shapes.\".length);\n const idx = next.shapes.findIndex((s: Shape) => s.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `shape not found: ${id}` } };\n }\n const cur = next.shapes[idx];\n next.shapes[idx] = {\n ...cur,\n x: x ?? cur.x,\n y: y ?? cur.y,\n width: width ?? cur.width,\n height: height ?? cur.height,\n rotation: rotation ?? cur.rotation,\n };\n return {\n project: next,\n result: { ok: true, data: { id: elementId, x: next.shapes[idx].x, y: next.shapes[idx].y } },\n };\n }\n\n if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n const idx = next.text_layers.findIndex((t: TextLayer) => t.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `text layer not found: ${id}` } };\n }\n const cur = next.text_layers[idx];\n next.text_layers[idx] = {\n ...cur,\n x: x ?? cur.x,\n y: y ?? cur.y,\n width: width ?? cur.width,\n height: height ?? cur.height,\n rotation: rotation ?? cur.rotation,\n };\n return {\n project: next,\n result: {\n ok: true,\n data: { id: elementId, x: next.text_layers[idx].x, y: next.text_layers[idx].y },\n },\n };\n }\n\n if (elementId.startsWith(\"group.\")) {\n const id = elementId.slice(\"group.\".length);\n const idx = next.groups.findIndex((g: Group) => g.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `group not found: ${id}` } };\n }\n if (width !== undefined || height !== undefined) {\n return {\n project,\n result: { ok: false, error: \"groups have no width/height; resize their children individually\" },\n };\n }\n if (rotation !== undefined) {\n return {\n project,\n result: {\n ok: false,\n error: \"set group rotation via add_keyframe on group.<id> (rotation track)\",\n },\n };\n }\n const cur = next.groups[idx];\n next.groups[idx] = {\n ...cur,\n pivotX: x ?? cur.pivotX,\n pivotY: y ?? cur.pivotY,\n };\n return {\n project: next,\n result: {\n ok: true,\n data: {\n id: elementId,\n pivotX: next.groups[idx].pivotX,\n pivotY: next.groups[idx].pivotY,\n },\n },\n };\n }\n\n return { project, result: { ok: false, error: `unknown elementId: ${elementId}` } };\n};\n\n// ---------------------------------------------------------------------------\n// set_pivot\n// ---------------------------------------------------------------------------\n\n// Discrete 9-cell anchor → normalized {x,y} pivot in the leaf's bbox. Centre\n// matches the un-anchored default; corners and edge midpoints fan out from it.\nconst ANCHOR_TO_PIVOT: Record<string, { x: number; y: number }> = {\n tl: { x: 0, y: 0 },\n t: { x: 0.5, y: 0 },\n tr: { x: 1, y: 0 },\n l: { x: 0, y: 0.5 },\n c: { x: 0.5, y: 0.5 },\n r: { x: 1, y: 0.5 },\n bl: { x: 0, y: 1 },\n b: { x: 0.5, y: 1 },\n br: { x: 1, y: 1 },\n};\n\ntype SetPivotArgs = {\n elementId: string;\n anchor: \"tl\" | \"t\" | \"tr\" | \"l\" | \"c\" | \"r\" | \"bl\" | \"b\" | \"br\";\n};\n\nconst setPivot: ToolDispatch<SetPivotArgs> = (project, args) => {\n const { elementId, anchor } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (elementId.startsWith(\"group.\")) {\n return {\n project,\n result: {\n ok: false,\n error:\n \"groups carry an absolute pivot in canvas coords — set it via move_layer with x/y on group.<id>\",\n },\n };\n }\n const piv = ANCHOR_TO_PIVOT[anchor];\n if (!piv) {\n return {\n project,\n result: {\n ok: false,\n error: `unknown anchor: ${anchor}; must be one of tl|t|tr|l|c|r|bl|b|br`,\n },\n };\n }\n const next = cloneProject(project);\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const idx = next.image_layers.findIndex((l: ImageLayer) => l.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `image layer not found: ${id}` } };\n }\n next.image_layers[idx] = { ...next.image_layers[idx], pivotX: piv.x, pivotY: piv.y };\n } else if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n const idx = next.video_layers.findIndex((v: VideoLayer) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `video layer not found: ${id}` } };\n }\n next.video_layers[idx] = { ...next.video_layers[idx], pivotX: piv.x, pivotY: piv.y };\n } else if (elementId.startsWith(\"shapes.\")) {\n const id = elementId.slice(\"shapes.\".length);\n const idx = next.shapes.findIndex((s: Shape) => s.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `shape not found: ${id}` } };\n }\n next.shapes[idx] = { ...next.shapes[idx], pivotX: piv.x, pivotY: piv.y };\n } else if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n const idx = next.text_layers.findIndex((t: TextLayer) => t.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `text layer not found: ${id}` } };\n }\n next.text_layers[idx] = { ...next.text_layers[idx], pivotX: piv.x, pivotY: piv.y };\n } else {\n return { project, result: { ok: false, error: `unknown elementId: ${elementId}` } };\n }\n return {\n project: next,\n result: { ok: true, data: { elementId, anchor, pivotX: piv.x, pivotY: piv.y } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_keyframe / remove_keyframe\n// ---------------------------------------------------------------------------\n\ntype AddKeyframeArgs = {\n elementId: string;\n property: string;\n frame: number;\n value: number;\n easing?: string;\n};\n\nconst addKeyframe: ToolDispatch<AddKeyframeArgs> = (project, args) => {\n const { elementId, property, frame, value, easing } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (!VALID_PROPS.includes(property as TrackProperty)) {\n return { project, result: { ok: false, error: `invalid property: ${property}` } };\n }\n if (!Number.isFinite(frame) || frame < 0) {\n return { project, result: { ok: false, error: `invalid frame: ${frame}` } };\n }\n if (!Number.isFinite(value)) {\n return { project, result: { ok: false, error: `invalid value: ${value}` } };\n }\n const easingArg =\n easing && VALID_EASINGS.includes(easing as Easing)\n ? (easing as Easing)\n : undefined;\n const next = cloneProject(project);\n upsertKeyframe(\n next,\n elementId,\n property as TrackProperty,\n Math.round(frame),\n value,\n easingArg,\n );\n return {\n project: next,\n result: { ok: true, data: { elementId, property, frame: Math.round(frame), value } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_keyframes_batch — add/replace many keyframes across many layers in ONE\n// call. Functionally equivalent to N invocations of add_keyframe but collapses\n// the per-call HTTP/MCP round-trip overhead — the difference between 1 call\n// and 300 when an agent is keyframing a 100-element starfield. All entries are\n// validated up front; if any entry is invalid the whole batch is rejected\n// (atomic).\n// ---------------------------------------------------------------------------\n\ntype SetKeyframesBatchArgs = {\n keyframes?: unknown;\n};\n\nconst setKeyframesBatch: ToolDispatch<SetKeyframesBatchArgs> = (project, args) => {\n const kfs = args.keyframes;\n if (!Array.isArray(kfs)) {\n return {\n project,\n result: { ok: false, error: \"keyframes must be an array of entries\" },\n };\n }\n if (kfs.length === 0) {\n return { project, result: { ok: false, error: \"keyframes array is empty\" } };\n }\n type Op = {\n elementId: string;\n property: TrackProperty;\n frame: number;\n value: number;\n easing?: Easing;\n };\n const ops: Op[] = [];\n for (let i = 0; i < kfs.length; i++) {\n const k = kfs[i] as\n | undefined\n | null\n | {\n elementId?: unknown;\n property?: unknown;\n frame?: unknown;\n value?: unknown;\n easing?: unknown;\n };\n if (!k || typeof k !== \"object\") {\n return { project, result: { ok: false, error: `entry ${i}: not an object` } };\n }\n const { elementId, property, frame, value, easing } = k;\n if (typeof elementId !== \"string\" || !elementId) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: elementId is required` },\n };\n }\n if (\n typeof property !== \"string\" ||\n !VALID_PROPS.includes(property as TrackProperty)\n ) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: invalid property: ${property}` },\n };\n }\n if (typeof frame !== \"number\" || !Number.isFinite(frame) || frame < 0) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: invalid frame: ${frame}` },\n };\n }\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: invalid value: ${value}` },\n };\n }\n let easingArg: Easing | undefined;\n if (easing !== undefined && easing !== null) {\n if (\n typeof easing !== \"string\" ||\n !VALID_EASINGS.includes(easing as Easing)\n ) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: invalid easing: ${easing}` },\n };\n }\n easingArg = easing as Easing;\n }\n ops.push({\n elementId,\n property: property as TrackProperty,\n frame: Math.round(frame),\n value,\n easing: easingArg,\n });\n }\n const next = cloneProject(project);\n for (const op of ops) {\n upsertKeyframe(next, op.elementId, op.property, op.frame, op.value, op.easing);\n }\n return {\n project: next,\n result: { ok: true, data: { count: ops.length } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_keyframes — many keyframes on ONE element's ONE property, with an\n// optional loop mode applied in the same call. The idiomatic batch form when\n// every dot in a ripple / snowflake / spinner / equaliser-bar gets its own\n// track: it factors elementId + property out of the loop body (so the payload\n// is just `{frame, value, easing?}` per kf), AND folds set_track_loop into\n// the same call so an endless ripple takes one call instead of two.\n// ---------------------------------------------------------------------------\n\ntype AddKeyframesArgs = {\n elementId?: unknown;\n property?: unknown;\n keyframes?: unknown;\n loop?: unknown;\n};\n\nconst addKeyframes: ToolDispatch<AddKeyframesArgs> = (project, args) => {\n const { elementId, property, keyframes, loop } = args;\n if (typeof elementId !== \"string\" || !elementId) {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (\n typeof property !== \"string\" ||\n !VALID_PROPS.includes(property as TrackProperty)\n ) {\n return { project, result: { ok: false, error: `invalid property: ${property}` } };\n }\n if (!Array.isArray(keyframes) || keyframes.length === 0) {\n return {\n project,\n result: { ok: false, error: \"keyframes must be a non-empty array\" },\n };\n }\n let loopMode: LoopModeArg | undefined;\n if (loop !== undefined && loop !== null) {\n if (typeof loop !== \"string\" || !VALID_LOOP_MODES.includes(loop as LoopModeArg)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid loop mode: ${loop} (valid: ${VALID_LOOP_MODES.join(\", \")})`,\n },\n };\n }\n loopMode = loop as LoopModeArg;\n }\n // Validate every keyframe before mutating, so the batch is atomic.\n type Kf = { frame: number; value: number; easing?: Easing };\n const ops: Kf[] = [];\n for (let i = 0; i < keyframes.length; i++) {\n const k = keyframes[i] as\n | undefined\n | null\n | { frame?: unknown; value?: unknown; easing?: unknown };\n if (!k || typeof k !== \"object\") {\n return { project, result: { ok: false, error: `entry ${i}: not an object` } };\n }\n const { frame, value, easing } = k;\n if (typeof frame !== \"number\" || !Number.isFinite(frame) || frame < 0) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: invalid frame: ${frame}` },\n };\n }\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: invalid value: ${value}` },\n };\n }\n let easingArg: Easing | undefined;\n if (easing !== undefined && easing !== null) {\n if (\n typeof easing !== \"string\" ||\n !VALID_EASINGS.includes(easing as Easing)\n ) {\n return {\n project,\n result: { ok: false, error: `entry ${i}: invalid easing: ${easing}` },\n };\n }\n easingArg = easing as Easing;\n }\n ops.push({ frame: Math.round(frame), value, easing: easingArg });\n }\n const next = cloneProject(project);\n const prop = property as TrackProperty;\n for (const op of ops) {\n upsertKeyframe(next, elementId, prop, op.frame, op.value, op.easing);\n }\n // Optional: fold the loop-mode update into the same call. \"hold\" is the\n // default — clear any existing override; other modes write to track_loops.\n if (loopMode !== undefined) {\n if (loopMode === \"hold\") {\n if (next.track_loops?.[elementId]) {\n const tracks = { ...next.track_loops[elementId] };\n delete tracks[prop];\n if (Object.keys(tracks).length === 0) {\n const allLoops = { ...next.track_loops };\n delete allLoops[elementId];\n next.track_loops = allLoops;\n } else {\n next.track_loops = { ...next.track_loops, [elementId]: tracks };\n }\n }\n } else {\n const loops = { ...(next.track_loops ?? {}) };\n const tracks = { ...(loops[elementId] ?? {}) };\n tracks[prop] = loopMode;\n loops[elementId] = tracks;\n next.track_loops = loops;\n }\n }\n return {\n project: next,\n result: {\n ok: true,\n data: {\n elementId,\n property: prop,\n count: ops.length,\n loop: loopMode ?? null,\n },\n },\n };\n};\n\ntype RemoveKeyframeArgs = {\n elementId: string;\n property: string;\n frame: number;\n};\n\n// shift_track — bulk-shift every keyframe's VALUE on one property by a delta.\n// Mirrors the \"select all keyframes + nudge layer\" gesture in After Effects /\n// Premiere / FCP: shifts the whole animation curve by `delta` while preserving\n// every keyframe's relative spacing. For x / y / rotation / scale / opacity /\n// width / height. Doesn't touch the keyframe TIMES — only their values.\ntype ShiftTrackArgs = {\n elementId: string;\n property: string;\n delta: number;\n};\n\nconst shiftTrack: ToolDispatch<ShiftTrackArgs> = (project, args) => {\n const { elementId, property, delta } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (!VALID_PROPS.includes(property as TrackProperty)) {\n return { project, result: { ok: false, error: `invalid property: ${property}` } };\n }\n if (typeof delta !== \"number\" || !Number.isFinite(delta)) {\n return { project, result: { ok: false, error: \"delta must be a finite number\" } };\n }\n const next = cloneProject(project);\n const tracks = next.animations[elementId];\n const kfs = tracks?.[property as TrackProperty];\n if (!kfs || kfs.length === 0) {\n return {\n project,\n result: {\n ok: false,\n error: `no keyframes on ${elementId}.${property} to shift`,\n },\n };\n }\n for (const k of kfs) k.value += delta;\n return {\n project: next,\n result: {\n ok: true,\n data: { elementId, property, delta, shifted: kfs.length },\n },\n };\n};\n\nconst removeKeyframe: ToolDispatch<RemoveKeyframeArgs> = (project, args) => {\n const { elementId, property, frame } = args;\n if (!VALID_PROPS.includes(property as TrackProperty)) {\n return { project, result: { ok: false, error: `invalid property: ${property}` } };\n }\n const next = cloneProject(project);\n const kfs = next.animations[elementId]?.[property as TrackProperty] ?? [];\n const idx = kfs.findIndex((k) => k.frame === Math.round(frame));\n if (idx < 0) {\n return {\n project,\n result: {\n ok: false,\n error: `no keyframe at frame ${frame} on ${elementId}.${property}`,\n },\n };\n }\n kfs.splice(idx, 1);\n return { project: next, result: { ok: true } };\n};\n\n// ---------------------------------------------------------------------------\n// set_track_loop — extrapolation mode for one property's animation track.\n// ---------------------------------------------------------------------------\n\nconst VALID_LOOP_MODES = [\"hold\", \"loop\", \"ping-pong\", \"cycle\"] as const;\ntype LoopModeArg = (typeof VALID_LOOP_MODES)[number];\ntype SetTrackLoopArgs = {\n elementId: string;\n property: string;\n mode: string;\n};\n\nconst setTrackLoop: ToolDispatch<SetTrackLoopArgs> = (project, args) => {\n const { elementId, property, mode } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (!VALID_PROPS.includes(property as TrackProperty)) {\n return {\n project,\n result: { ok: false, error: `invalid property: ${property}` },\n };\n }\n if (!VALID_LOOP_MODES.includes(mode as LoopModeArg)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid mode: ${mode} (valid: ${VALID_LOOP_MODES.join(\", \")})`,\n },\n };\n }\n const next = cloneProject(project);\n // hold is the default — clear the override so the project stays compact.\n if (mode === \"hold\") {\n if (next.track_loops?.[elementId]) {\n const tracks = { ...next.track_loops[elementId] };\n delete tracks[property as TrackProperty];\n if (Object.keys(tracks).length === 0) {\n const allLoops = { ...next.track_loops };\n delete allLoops[elementId];\n next.track_loops = allLoops;\n } else {\n next.track_loops = { ...next.track_loops, [elementId]: tracks };\n }\n }\n return {\n project: next,\n result: { ok: true, data: { elementId, property, mode: \"hold\" } },\n };\n }\n const loops = { ...(next.track_loops ?? {}) };\n const tracks = { ...(loops[elementId] ?? {}) };\n tracks[property as TrackProperty] = mode as LoopModeArg;\n loops[elementId] = tracks;\n next.track_loops = loops;\n return {\n project: next,\n result: { ok: true, data: { elementId, property, mode } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_image_layer\n// ---------------------------------------------------------------------------\n//\n// Headless callers should pre-check that the asset exists at\n// users/<userId>/assets/<projectId>/<filename> in R2; this dispatcher does\n// NOT verify the file. The editor adapter retains its XHR HEAD pre-check.\n\ntype AddImageLayerArgs = {\n filename: string;\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\nconst addImageLayer: ToolDispatch<AddImageLayerArgs> = (project, args) => {\n const { filename, x, y, width, height } = args;\n if (!filename) {\n return { project, result: { ok: false, error: \"filename is required\" } };\n }\n if (!Number.isFinite(width) || width <= 0) {\n return { project, result: { ok: false, error: `invalid width: ${width}` } };\n }\n if (!Number.isFinite(height) || height <= 0) {\n return { project, result: { ok: false, error: `invalid height: ${height}` } };\n }\n const next = cloneProject(project);\n const id = generateLayerId(next, \"image\");\n const layer: ImageLayer = {\n id,\n filename,\n x,\n y,\n width,\n height,\n rotation: 0,\n pivotX: 0.5,\n pivotY: 0.5,\n fill: null,\n };\n next.image_layers = [...next.image_layers, layer];\n return {\n project: next,\n result: { ok: true, data: { id, elementId: `image.${id}` } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_video_layer\n// ---------------------------------------------------------------------------\n//\n// Mirrors add_image_layer. Headless callers should pre-check that the clip\n// exists at users/<userId>/clips/<projectId>/<clip> in R2; this dispatcher\n// does NOT verify the file. The editor adapter retains its XHR HEAD check.\n\ntype AddVideoLayerArgs = {\n clip: string;\n x: number;\n y: number;\n width: number;\n height: number;\n name?: string;\n};\n\nconst addVideoLayer: ToolDispatch<AddVideoLayerArgs> = (project, args) => {\n const { clip, x, y, width, height, name } = args;\n if (!clip) {\n return { project, result: { ok: false, error: \"clip is required\" } };\n }\n if (!Number.isFinite(width) || width <= 0) {\n return { project, result: { ok: false, error: `invalid width: ${width}` } };\n }\n if (!Number.isFinite(height) || height <= 0) {\n return { project, result: { ok: false, error: `invalid height: ${height}` } };\n }\n const next = cloneProject(project);\n const id = generateLayerId(next, \"video\");\n const layer: VideoLayer = {\n id,\n clip,\n ...(name && name.length > 0 ? { name } : {}),\n x,\n y,\n width,\n height,\n rotation: 0,\n pivotX: 0.5,\n pivotY: 0.5,\n source_in_frame: 0,\n source_out_frame: null,\n timeline_start_frame: 0,\n fill: null,\n };\n next.video_layers = [...next.video_layers, layer];\n return {\n project: next,\n result: { ok: true, data: { id, elementId: `video.${id}` } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_shape\n// ---------------------------------------------------------------------------\n\ntype AddShapeArgs = {\n kind: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n color?: string;\n};\n\nconst DEFAULT_SHAPE_W = 320;\nconst DEFAULT_SHAPE_H = 180;\nconst COMPOSITION_W = 1080;\nconst COMPOSITION_H = 1920;\n\n// Every shape in the registry is valid. Derive from SHAPE_IDS so this stays in\n// lockstep with src/shapes.ts and the MCP enum (which also derives from it).\nconst SHAPE_KINDS = new Set<ShapeKind>(SHAPE_IDS);\n\nconst addShape: ToolDispatch<AddShapeArgs> = (project, args) => {\n const { kind, x, y, width, height, color } = args;\n if (!SHAPE_KINDS.has(kind as ShapeKind)) {\n return {\n project,\n result: {\n ok: false,\n error: `unsupported shape kind: ${kind} (expected one of ${[...SHAPE_KINDS].join(\" | \")})`,\n },\n };\n }\n if (color !== undefined && !HEX.test(color)) {\n return {\n project,\n result: { ok: false, error: `invalid color (expected #rrggbb): ${color}` },\n };\n }\n const next = cloneProject(project);\n const id = generateLayerId(next, \"shapes\");\n const w = width ?? DEFAULT_SHAPE_W;\n const h = height ?? DEFAULT_SHAPE_H;\n const shape: Shape = {\n id,\n kind: kind as ShapeKind,\n // (x, y) is the CENTRE of the shape's bounding box — default to canvas\n // centre when the caller omits a position.\n x: x ?? COMPOSITION_W / 2,\n y: y ?? COMPOSITION_H / 2,\n width: w,\n height: h,\n fill: { type: \"solid\", color: color ?? \"#ffffff\", opacity: 1 },\n rotation: 0,\n pivotX: 0.5,\n pivotY: 0.5,\n };\n next.shapes = [...next.shapes, shape];\n return {\n project: next,\n result: { ok: true, data: { id, elementId: `shapes.${id}` } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_curve — the editable line / arrow primitive: a stroked quadratic bezier\n// with an arrowhead. Draw it by endpoints (x1,y1)→(x2,y2) with an optional\n// perpendicular `bend` (px; 0 = straight, +/- curves either way). Stored as a\n// kind:\"curve\" shape whose bbox bounds the control points and whose `points`\n// are bbox fractions, so it scales / rotates / animates like any other shape.\n// ---------------------------------------------------------------------------\n\ntype AddCurveArgs = {\n x1: number;\n y1: number;\n x2: number;\n y2: number;\n bend?: number;\n color?: string;\n stroke_width?: number;\n arrow_head?: \"none\" | \"end\" | \"both\";\n};\n\nconst addCurve: ToolDispatch<AddCurveArgs> = (project, args) => {\n const { x1, y1, x2, y2 } = args;\n for (const [k, v] of Object.entries({ x1, y1, x2, y2 })) {\n if (typeof v !== \"number\" || !Number.isFinite(v)) {\n return {\n project,\n result: { ok: false, error: `${k} must be a finite number` },\n };\n }\n }\n const color = args.color ?? \"#ffffff\";\n if (!HEX.test(color)) {\n return {\n project,\n result: { ok: false, error: `invalid color (expected #rrggbb): ${color}` },\n };\n }\n const sw = args.stroke_width && args.stroke_width > 0 ? args.stroke_width : 10;\n const head = args.arrow_head ?? \"end\";\n const bend = args.bend ?? 0;\n // Control point: the segment midpoint pushed perpendicular by `bend`.\n const mx = (x1 + x2) / 2;\n const my = (y1 + y2) / 2;\n const dx = x2 - x1;\n const dy = y2 - y1;\n const len = Math.hypot(dx, dy) || 1;\n const cxp = mx + (-dy / len) * bend;\n const cyp = my + (dx / len) * bend;\n // Bbox bounds the three control points, padded for the stroke + arrowhead.\n const pad = Math.max(sw * 2, 30);\n const minX = Math.min(x1, x2, cxp) - pad;\n const maxX = Math.max(x1, x2, cxp) + pad;\n const minY = Math.min(y1, y2, cyp) - pad;\n const maxY = Math.max(y1, y2, cyp) + pad;\n const w = Math.max(1, maxX - minX);\n const h = Math.max(1, maxY - minY);\n const frac = (px: number, py: number) => ({\n x: (px - minX) / w,\n y: (py - minY) / h,\n });\n const next = cloneProject(project);\n const id = generateLayerId(next, \"shapes\");\n const shape: Shape = {\n id,\n kind: \"curve\",\n x: (minX + maxX) / 2,\n y: (minY + maxY) / 2,\n width: w,\n height: h,\n fill: { type: \"solid\", color, opacity: 1 },\n rotation: 0,\n pivotX: 0.5,\n pivotY: 0.5,\n points: [frac(x1, y1), frac(cxp, cyp), frac(x2, y2)],\n stroke_width: sw,\n arrow_head: head,\n };\n next.shapes = [...next.shapes, shape];\n return {\n project: next,\n result: { ok: true, data: { id, elementId: `shapes.${id}` } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// duplicate_layer — composition primitive. Clone a leaf (image / video / shape\n// / text) `count` times, applying a cumulative per-step transform: copy i sits\n// at base + i·(dx, dy), rotated base + i·d_rotation, scaled base · d_scale^i.\n// One call replaces the dozens the LLM would otherwise make for a circle of\n// stars, a row of chevrons, a fractal, a staggered grid, etc. Styles are\n// copied so clones match; animations are not (animate the result afterwards,\n// e.g. group them + a cycle-loop track for endless marching).\n// ---------------------------------------------------------------------------\n\ntype DuplicateLayerArgs = {\n elementId: string;\n count?: number;\n dx?: number;\n dy?: number;\n d_rotation?: number;\n d_scale?: number;\n};\n\n// Generic clone-with-offset over any leaf list (all share id/x/y/w/h/rotation).\n// Mutates `list` and `next.styles` in place; returns the new element ids.\nconst duplicateInList = <\n T extends {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n rotation?: number;\n },\n>(\n list: T[],\n next: Project,\n baseId: string,\n prefix: string,\n count: number,\n dx: number,\n dy: number,\n dr: number,\n ds: number,\n): string[] | null => {\n const src = list.find((l) => l.id === baseId);\n if (!src) return null;\n const used = new Set(list.map((l) => l.id));\n const newIds: string[] = [];\n for (let i = 1; i <= count; i += 1) {\n let id = `${baseId}-${i}`;\n let bump = 1;\n while (used.has(id)) {\n id = `${baseId}-${i}-${bump}`;\n bump += 1;\n }\n used.add(id);\n const scale = Math.pow(ds, i);\n const copy: T = {\n ...src,\n id,\n x: src.x + dx * i,\n y: src.y + dy * i,\n width: Math.max(1, src.width * scale),\n height: Math.max(1, src.height * scale),\n rotation: (src.rotation ?? 0) + dr * i,\n };\n list.push(copy);\n const newElementId = `${prefix}${id}`;\n const srcStyle = next.styles?.[`${prefix}${baseId}`];\n if (srcStyle) {\n next.styles = next.styles ?? {};\n next.styles[newElementId] = { ...srcStyle };\n }\n newIds.push(newElementId);\n }\n return newIds;\n};\n\nconst duplicateLayer: ToolDispatch<DuplicateLayerArgs> = (project, args) => {\n const { elementId } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n const count = Math.max(1, Math.min(1000, Math.floor(args.count ?? 1)));\n const dx = args.dx ?? 0;\n const dy = args.dy ?? 0;\n const dr = args.d_rotation ?? 0;\n const ds = args.d_scale ?? 1;\n const next = cloneProject(project);\n\n let ids: string[] | null = null;\n if (elementId.startsWith(\"shapes.\")) {\n ids = duplicateInList(next.shapes, next, elementId.slice(7), \"shapes.\", count, dx, dy, dr, ds);\n } else if (elementId.startsWith(\"image.\")) {\n ids = duplicateInList(next.image_layers, next, elementId.slice(6), \"image.\", count, dx, dy, dr, ds);\n } else if (elementId.startsWith(\"text.\")) {\n ids = duplicateInList(next.text_layers, next, elementId.slice(5), \"text.\", count, dx, dy, dr, ds);\n } else if (elementId.startsWith(\"video.\")) {\n ids = duplicateInList(next.video_layers, next, elementId.slice(6), \"video.\", count, dx, dy, dr, ds);\n } else {\n return {\n project,\n result: {\n ok: false,\n error: \"duplicate_layer supports image / video / shape / text leaves (not groups)\",\n },\n };\n }\n if (ids === null) {\n return { project, result: { ok: false, error: `layer not found: ${elementId}` } };\n }\n return { project: next, result: { ok: true, data: { ids, count: ids.length } } };\n};\n\n// ---------------------------------------------------------------------------\n// remove_layer\n// ---------------------------------------------------------------------------\n\ntype RemoveLayerArgs = { elementId: string };\n\nconst detachFromTree = (project: Project, elementId: string): void => {\n project.layer_order = project.layer_order.filter((x) => x !== elementId);\n for (const g of project.groups) {\n g.children = g.children.filter((x) => x !== elementId);\n }\n};\n\nconst removeLayer: ToolDispatch<RemoveLayerArgs> = (project, args) => {\n const { elementId } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (elementId.startsWith(\"group.\")) {\n return {\n project,\n result: {\n ok: false,\n error: \"use ungroup_layers on a group; remove_layer is for video/image/shape leaves\",\n },\n };\n }\n const next = cloneProject(project);\n if (elementId.startsWith(\"shapes.\")) {\n const id = elementId.slice(\"shapes.\".length);\n const idx = next.shapes.findIndex((s) => s.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `shape not found: ${id}` } };\n }\n next.shapes.splice(idx, 1);\n delete next.animations[elementId];\n delete next.styles[elementId];\n detachFromTree(next, elementId);\n return { project: next, result: { ok: true } };\n }\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const idx = next.image_layers.findIndex((l) => l.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `image layer not found: ${id}` } };\n }\n // Pinned layers (e.g. the canvas backdrop) refuse deletion.\n if (next.image_layers[idx].pinned === true) {\n return {\n project,\n result: {\n ok: false,\n error: `cannot delete pinned layer: ${elementId}`,\n },\n };\n }\n next.image_layers.splice(idx, 1);\n delete next.animations[elementId];\n delete next.styles[elementId];\n detachFromTree(next, elementId);\n return { project: next, result: { ok: true } };\n }\n if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n const idx = next.video_layers.findIndex((v) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `video layer not found: ${id}` } };\n }\n next.video_layers.splice(idx, 1);\n delete next.animations[elementId];\n delete next.styles[elementId];\n detachFromTree(next, elementId);\n return { project: next, result: { ok: true } };\n }\n if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n const idx = next.text_layers.findIndex((t) => t.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `text layer not found: ${id}` } };\n }\n next.text_layers.splice(idx, 1);\n delete next.animations[elementId];\n delete next.styles[elementId];\n detachFromTree(next, elementId);\n return { project: next, result: { ok: true } };\n }\n return { project, result: { ok: false, error: `unknown elementId: ${elementId}` } };\n};\n\n// ---------------------------------------------------------------------------\n// reorder_layer\n// ---------------------------------------------------------------------------\n\ntype ReorderLayerArgs = { elementId: string; newIndex: number };\n\n// Reorder within siblings — newIndex is 0-based within the element's parent\n// (root list when ungrouped, or the parent group's `children` when nested).\n// 0 = bottom of that subtree; last index = top of that subtree.\nconst reorderLayer: ToolDispatch<ReorderLayerArgs> = (project, args) => {\n const { elementId, newIndex } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (!Number.isFinite(newIndex)) {\n return { project, result: { ok: false, error: `invalid newIndex: ${newIndex}` } };\n }\n // Pinned image_layers refuse reorder — they're forced to the bottom of\n // root z by `resolveLayerTree` regardless of position in layer_order.\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const layer = project.image_layers.find((l) => l.id === id);\n if (layer?.pinned === true) {\n return {\n project,\n result: {\n ok: false,\n error: `cannot reorder pinned layer: ${elementId}`,\n },\n };\n }\n }\n const next = cloneProject(project);\n normalizeRoot(next);\n const parentGid = findParentGroup(next, elementId);\n const siblings: string[] =\n parentGid === null\n ? next.layer_order\n : (next.groups.find((g) => g.id === parentGid)?.children ?? []);\n const oldIdx = siblings.indexOf(elementId);\n if (oldIdx < 0) {\n return { project, result: { ok: false, error: `layer not found: ${elementId}` } };\n }\n const target = Math.max(0, Math.min(siblings.length - 1, Math.round(newIndex)));\n if (target === oldIdx) {\n return {\n project,\n result: { ok: true, data: { newIndex: target, totalSiblings: siblings.length } },\n };\n }\n const [item] = siblings.splice(oldIdx, 1);\n siblings.splice(target, 0, item);\n return {\n project: next,\n result: { ok: true, data: { newIndex: target, totalSiblings: siblings.length } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_style\n// ---------------------------------------------------------------------------\n\ntype SetStyleArgs = {\n elementId: string;\n borderRadius?: number;\n borderWidth?: number;\n borderColor?: string;\n boxShadow?: string | null;\n fit?: \"stretch\" | \"cover\" | \"contain\";\n anchorX?: number;\n anchorY?: number;\n tintColor?: string;\n tintStrength?: number;\n alphaMask?: unknown;\n chroma_key?: unknown;\n blend_mode?: string;\n};\n\nconst BLEND_MODE_VALUES: ReadonlyArray<string> = [\n \"normal\",\n \"multiply\",\n \"screen\",\n \"overlay\",\n \"darken\",\n \"lighten\",\n \"color-dodge\",\n \"color-burn\",\n \"hard-light\",\n \"soft-light\",\n \"difference\",\n \"exclusion\",\n \"hue\",\n \"saturation\",\n \"color\",\n \"luminosity\",\n];\n\nconst FIT_VALUES: ReadonlyArray<\"stretch\" | \"cover\" | \"contain\"> = [\n \"stretch\",\n \"cover\",\n \"contain\",\n];\n\nconst setStyle: ToolDispatch<SetStyleArgs> = (project, args) => {\n const {\n elementId,\n borderRadius,\n borderWidth,\n borderColor,\n boxShadow,\n fit,\n anchorX,\n anchorY,\n tintColor,\n tintStrength,\n alphaMask,\n chroma_key,\n blend_mode,\n } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (elementId.startsWith(\"group.\")) {\n // Groups have no styled body, but they CAN carry a blend_mode that\n // affects how their composite blits onto the parent canvas. Allow that\n // single field through; reject everything else.\n const onlyBlend =\n blend_mode !== undefined &&\n borderRadius === undefined &&\n borderWidth === undefined &&\n borderColor === undefined &&\n boxShadow === undefined &&\n fit === undefined &&\n anchorX === undefined &&\n anchorY === undefined &&\n tintColor === undefined &&\n tintStrength === undefined &&\n alphaMask === undefined &&\n chroma_key === undefined;\n if (!onlyBlend) {\n return {\n project,\n result: {\n ok: false,\n error:\n \"groups have no styles; set_style on group.<id> accepts blend_mode only\",\n },\n };\n }\n }\n if (blend_mode !== undefined && !BLEND_MODE_VALUES.includes(blend_mode)) {\n return {\n project,\n result: { ok: false, error: `invalid blend_mode: ${blend_mode}` },\n };\n }\n if (borderColor !== undefined && !HEX.test(borderColor)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid borderColor (expected #rrggbb): ${borderColor}`,\n },\n };\n }\n if (tintColor !== undefined && !HEX.test(tintColor)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid tintColor (expected #rrggbb): ${tintColor}`,\n },\n };\n }\n if (fit !== undefined && !FIT_VALUES.includes(fit)) {\n return {\n project,\n result: { ok: false, error: `invalid fit: ${fit}` },\n };\n }\n for (const [name, v] of [\n [\"anchorX\", anchorX],\n [\"anchorY\", anchorY],\n [\"tintStrength\", tintStrength],\n ] as const) {\n if (v !== undefined && (typeof v !== \"number\" || v < 0 || v > 1)) {\n return {\n project,\n result: { ok: false, error: `${name} must be a number in [0, 1]` },\n };\n }\n }\n // alphaMask validation. `null` clears the mask; an object sets it; undefined\n // leaves the existing mask untouched. Mirrors maskGradientSchema in shape.\n let validatedAlphaMask:\n | { type: \"linear\"; angle: number; stops: Array<{ offset: number; alpha: number }> }\n | null\n | undefined = undefined;\n if (alphaMask !== undefined) {\n if (alphaMask === null) {\n validatedAlphaMask = null;\n } else if (typeof alphaMask !== \"object\") {\n return { project, result: { ok: false, error: \"alphaMask must be an object or null\" } };\n } else {\n const m = alphaMask as Record<string, unknown>;\n const type = m.type === undefined ? \"linear\" : m.type;\n if (type !== \"linear\") {\n return { project, result: { ok: false, error: \"alphaMask.type must be 'linear'\" } };\n }\n const angle = m.angle === undefined ? 180 : m.angle;\n if (typeof angle !== \"number\" || !Number.isFinite(angle)) {\n return { project, result: { ok: false, error: \"alphaMask.angle must be a finite number\" } };\n }\n const stops = m.stops;\n if (!Array.isArray(stops) || stops.length < 2) {\n return {\n project,\n result: { ok: false, error: \"alphaMask.stops must be an array of ≥ 2 stops\" },\n };\n }\n const validStops: Array<{ offset: number; alpha: number }> = [];\n for (const s of stops) {\n if (typeof s !== \"object\" || s === null) {\n return { project, result: { ok: false, error: \"each stop must be {offset, alpha}\" } };\n }\n const so = (s as { offset?: unknown }).offset;\n const sa = (s as { alpha?: unknown }).alpha;\n if (typeof so !== \"number\" || so < 0 || so > 1) {\n return { project, result: { ok: false, error: \"stop.offset must be a number in [0, 1]\" } };\n }\n if (typeof sa !== \"number\" || sa < 0 || sa > 1) {\n return { project, result: { ok: false, error: \"stop.alpha must be a number in [0, 1]\" } };\n }\n validStops.push({ offset: so, alpha: sa });\n }\n validatedAlphaMask = { type: \"linear\", angle, stops: validStops };\n }\n }\n // chroma_key validation. `null` clears it; an object sets it (with defaults\n // for any omitted field); undefined leaves the existing key untouched.\n let validatedChroma:\n | { color: string; similarity: number; smoothness: number }\n | null\n | undefined = undefined;\n if (chroma_key !== undefined) {\n if (chroma_key === null) {\n validatedChroma = null;\n } else if (typeof chroma_key !== \"object\") {\n return {\n project,\n result: { ok: false, error: \"chroma_key must be an object or null\" },\n };\n } else {\n const k = chroma_key as Record<string, unknown>;\n const color = k.color === undefined ? \"#00ff00\" : k.color;\n if (typeof color !== \"string\" || !HEX.test(color)) {\n return {\n project,\n result: { ok: false, error: \"chroma_key.color must be #rrggbb\" },\n };\n }\n const similarity = k.similarity === undefined ? 0.4 : k.similarity;\n const smoothness = k.smoothness === undefined ? 0.1 : k.smoothness;\n for (const [n, v] of [\n [\"similarity\", similarity],\n [\"smoothness\", smoothness],\n ] as const) {\n if (typeof v !== \"number\" || v < 0 || v > 1) {\n return {\n project,\n result: { ok: false, error: `chroma_key.${n} must be in [0, 1]` },\n };\n }\n }\n validatedChroma = {\n color,\n similarity: similarity as number,\n smoothness: smoothness as number,\n };\n }\n }\n // boxShadow: null / \"\" / \"none\" / \"null\" all CLEAR the shadow; any other\n // string sets it. Models asked to \"remove the shadow\" reach for these, so\n // accept them all rather than storing a bogus \"null\" CSS value.\n let boxShadowPatch: string | undefined;\n let clearBoxShadow = false;\n if (boxShadow !== undefined) {\n const trimmed = typeof boxShadow === \"string\" ? boxShadow.trim() : \"\";\n const lowered = trimmed.toLowerCase();\n if (\n boxShadow === null ||\n trimmed === \"\" ||\n lowered === \"none\" ||\n lowered === \"null\"\n ) {\n clearBoxShadow = true;\n } else {\n boxShadowPatch = boxShadow as string;\n }\n }\n const next = cloneProject(project);\n const existing = next.styles[elementId] ?? {};\n const merged: LayerStyle = {\n ...existing,\n ...(borderRadius !== undefined ? { borderRadius } : {}),\n ...(borderWidth !== undefined ? { borderWidth } : {}),\n ...(borderColor !== undefined ? { borderColor } : {}),\n ...(boxShadowPatch !== undefined ? { boxShadow: boxShadowPatch } : {}),\n ...(fit !== undefined ? { fit } : {}),\n ...(anchorX !== undefined ? { anchorX } : {}),\n ...(anchorY !== undefined ? { anchorY } : {}),\n ...(tintColor !== undefined ? { tintColor } : {}),\n ...(tintStrength !== undefined ? { tintStrength } : {}),\n ...(blend_mode !== undefined\n ? { blend_mode: blend_mode as LayerStyle[\"blend_mode\"] }\n : {}),\n };\n if (clearBoxShadow) delete merged.boxShadow;\n if (validatedAlphaMask !== undefined) {\n if (validatedAlphaMask === null) {\n delete merged.alphaMask;\n } else {\n merged.alphaMask = validatedAlphaMask;\n }\n }\n if (validatedChroma !== undefined) {\n if (validatedChroma === null) {\n delete merged.chroma_key;\n } else {\n merged.chroma_key = validatedChroma;\n }\n }\n const clean: LayerStyle = {};\n if (merged.borderRadius != null) clean.borderRadius = merged.borderRadius;\n if (merged.borderWidth != null) clean.borderWidth = merged.borderWidth;\n if (merged.borderColor) clean.borderColor = merged.borderColor;\n if (merged.boxShadow) clean.boxShadow = merged.boxShadow;\n if (merged.fit) clean.fit = merged.fit;\n if (merged.anchorX != null) clean.anchorX = merged.anchorX;\n if (merged.anchorY != null) clean.anchorY = merged.anchorY;\n if (merged.tintColor) clean.tintColor = merged.tintColor;\n if (merged.tintStrength != null && merged.tintStrength > 0) {\n clean.tintStrength = merged.tintStrength;\n }\n if (merged.alphaMask) clean.alphaMask = merged.alphaMask;\n if (merged.chroma_key) clean.chroma_key = merged.chroma_key;\n // blend_mode is dropped when it's \"normal\" (the default) so the JSON\n // stays compact and renderers don't waste a save/restore on no-op blends.\n if (merged.blend_mode && merged.blend_mode !== \"normal\") {\n clean.blend_mode = merged.blend_mode;\n }\n if (Object.keys(clean).length === 0) {\n delete next.styles[elementId];\n } else {\n next.styles[elementId] = clean;\n }\n return { project: next, result: { ok: true } };\n};\n\n// ---------------------------------------------------------------------------\n// set_layer_fill\n// ---------------------------------------------------------------------------\n\ntype SetLayerFillArgs = { elementId: string; fill: unknown };\n\nconst setLayerFill: ToolDispatch<SetLayerFillArgs> = (project, args) => {\n const { fill } = args;\n if (!args.elementId || typeof args.elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n // Accept the legacy alias \"background.canvas\" and rewrite it to the\n // canvas backdrop's actual element id. Agents written against the\n // previous schema keep working.\n const elementId = resolveBackgroundAlias(project, args.elementId);\n const bgLayer = findBackgroundLayer(project);\n const isBackgroundLayer =\n bgLayer !== null && elementId === `image.${bgLayer.id}`;\n // is_background image_layers are the canvas backdrop — fill is required,\n // null is rejected (matches the old \"background.canvas\" semantics).\n const allowsNull =\n !isBackgroundLayer && (\n elementId.startsWith(\"image.\") ||\n elementId.startsWith(\"video.\") ||\n elementId.startsWith(\"text.\") ||\n elementId.startsWith(\"group.\")\n );\n if (fill === null) {\n if (!allowsNull) {\n return {\n project,\n result: { ok: false, error: \"shape and canvas-backdrop fills are required; null is not allowed\" },\n };\n }\n const next = cloneProject(project);\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const idx = next.image_layers.findIndex((l) => l.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.image_layers[idx] = { ...next.image_layers[idx], fill: null };\n } else if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n const idx = next.video_layers.findIndex((v) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.video_layers[idx] = { ...next.video_layers[idx], fill: null };\n } else if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n const idx = next.text_layers.findIndex((t) => t.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.text_layers[idx] = { ...next.text_layers[idx], fill: null };\n } else if (elementId.startsWith(\"group.\")) {\n const id = elementId.slice(\"group.\".length);\n const idx = next.groups.findIndex((g) => g.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown group: ${elementId}` } };\n }\n next.groups[idx] = { ...next.groups[idx], fill: null };\n }\n return { project: next, result: { ok: true } };\n }\n if (fill === undefined) {\n return { project, result: { ok: false, error: \"fill is required\" } };\n }\n const coerced = coerceFill(fill);\n if (!coerced) {\n return {\n project,\n result: { ok: false, error: \"invalid fill (expected #rrggbb or Fill object)\" },\n };\n }\n const next = cloneProject(project);\n if (elementId.startsWith(\"shapes.\")) {\n const id = elementId.slice(\"shapes.\".length);\n const idx = next.shapes.findIndex((s) => s.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown shape: ${elementId}` } };\n }\n next.shapes[idx] = { ...next.shapes[idx], fill: coerced };\n } else if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const idx = next.image_layers.findIndex((l) => l.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.image_layers[idx] = { ...next.image_layers[idx], fill: coerced };\n } else if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n const idx = next.video_layers.findIndex((v) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.video_layers[idx] = { ...next.video_layers[idx], fill: coerced };\n } else if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n const idx = next.text_layers.findIndex((t) => t.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.text_layers[idx] = { ...next.text_layers[idx], fill: coerced };\n } else if (elementId.startsWith(\"group.\")) {\n const id = elementId.slice(\"group.\".length);\n const idx = next.groups.findIndex((g) => g.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown group: ${elementId}` } };\n }\n next.groups[idx] = { ...next.groups[idx], fill: coerced };\n } else {\n return { project, result: { ok: false, error: `unknown elementId: ${elementId}` } };\n }\n return { project: next, result: { ok: true } };\n};\n\n// ---------------------------------------------------------------------------\n// set_group_box\n// ---------------------------------------------------------------------------\n\ntype SetGroupBoxArgs = {\n elementId: string;\n box_width: number;\n box_height: number;\n};\n\nconst setGroupBox: ToolDispatch<SetGroupBoxArgs> = (project, args) => {\n const { elementId, box_width, box_height } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (!elementId.startsWith(\"group.\")) {\n return {\n project,\n result: { ok: false, error: \"set_group_box only applies to group.<id>\" },\n };\n }\n for (const [k, v] of Object.entries({ box_width, box_height })) {\n if (typeof v !== \"number\" || !Number.isFinite(v) || v < 0) {\n return {\n project,\n result: { ok: false, error: `${k} must be a non-negative finite number` },\n };\n }\n }\n const id = elementId.slice(\"group.\".length);\n const idx = project.groups.findIndex((g) => g.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown group: ${elementId}` } };\n }\n const next = cloneProject(project);\n next.groups[idx] = {\n ...next.groups[idx],\n box_width,\n box_height,\n };\n return { project: next, result: { ok: true } };\n};\n\n// ---------------------------------------------------------------------------\n// color keyframe helpers\n// ---------------------------------------------------------------------------\n\nconst COLOR_PROPS = [\"fill\"] as const;\ntype ColorProperty = (typeof COLOR_PROPS)[number];\n\n// Verify an elementId is a valid colour-track target: a known leaf, group,\n// or image_layer (including the pinned canvas-backdrop image_layer). The\n// caller is responsible for resolving any \"background.canvas\" alias before\n// reaching here (see resolveBackgroundAlias).\nconst isValidColorTarget = (project: Project, elementId: string): boolean => {\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n return project.image_layers.some((l) => l.id === id);\n }\n if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n return project.video_layers.some((v) => v.id === id);\n }\n if (elementId.startsWith(\"shapes.\")) {\n const id = elementId.slice(\"shapes.\".length);\n return project.shapes.some((s) => s.id === id);\n }\n if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n return project.text_layers.some((t) => t.id === id);\n }\n if (elementId.startsWith(\"group.\")) {\n const id = elementId.slice(\"group.\".length);\n return project.groups.some((g) => g.id === id);\n }\n return false;\n};\n\n// ---------------------------------------------------------------------------\n// add_color_keyframe\n// ---------------------------------------------------------------------------\n\ntype AddColorKeyframeArgs = {\n elementId: string;\n property: string;\n frame: number;\n value: unknown;\n easing?: string;\n};\n\nconst addColorKeyframe: ToolDispatch<AddColorKeyframeArgs> = (project, args) => {\n const { property, frame, value, easing } = args;\n if (!args.elementId || typeof args.elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n const elementId = resolveBackgroundAlias(project, args.elementId);\n if (!isValidColorTarget(project, elementId)) {\n return {\n project,\n result: { ok: false, error: `unknown elementId: ${elementId}` },\n };\n }\n if (!COLOR_PROPS.includes(property as ColorProperty)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid color property: ${property} (only \"fill\" is supported)`,\n },\n };\n }\n if (!Number.isFinite(frame) || frame < 0) {\n return { project, result: { ok: false, error: `invalid frame: ${frame}` } };\n }\n if (easing !== undefined && !VALID_EASINGS.includes(easing as Easing)) {\n return { project, result: { ok: false, error: `invalid easing: ${easing}` } };\n }\n const coerced = coerceFill(value);\n if (!coerced) {\n return {\n project,\n result: { ok: false, error: \"invalid fill value (expected #rrggbb or Fill object)\" },\n };\n }\n const next = cloneProject(project);\n if (!next.color_tracks[elementId]) {\n next.color_tracks[elementId] = {} as ElementColorTracks;\n }\n const tracks = next.color_tracks[elementId];\n if (!tracks.fill) tracks.fill = [];\n const kfs = tracks.fill as ColorKeyframe[];\n const targetFrame = Math.round(frame);\n const idx = kfs.findIndex((k) => k.frame === targetFrame);\n const resolvedEasing = (easing as Easing | undefined) ?? \"linear\";\n if (idx >= 0) {\n kfs[idx] = {\n ...kfs[idx],\n value: coerced,\n easing: resolvedEasing,\n };\n } else {\n kfs.push({ frame: targetFrame, value: coerced, easing: resolvedEasing });\n }\n kfs.sort((a, b) => a.frame - b.frame);\n return {\n project: next,\n result: {\n ok: true,\n data: { elementId, property: \"fill\", frame: targetFrame },\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// remove_color_keyframe\n// ---------------------------------------------------------------------------\n\ntype RemoveColorKeyframeArgs = {\n elementId: string;\n property: string;\n frame: number;\n};\n\nconst removeColorKeyframe: ToolDispatch<RemoveColorKeyframeArgs> = (\n project,\n args,\n) => {\n const { property, frame } = args;\n if (!args.elementId || typeof args.elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n const elementId = resolveBackgroundAlias(project, args.elementId);\n if (!isValidColorTarget(project, elementId)) {\n return {\n project,\n result: { ok: false, error: `unknown elementId: ${elementId}` },\n };\n }\n if (!COLOR_PROPS.includes(property as ColorProperty)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid color property: ${property} (only \"fill\" is supported)`,\n },\n };\n }\n if (!Number.isFinite(frame) || frame < 0) {\n return { project, result: { ok: false, error: `invalid frame: ${frame}` } };\n }\n const tracks = project.color_tracks?.[elementId];\n const kfs = tracks?.fill;\n const targetFrame = Math.round(frame);\n if (!kfs || kfs.length === 0) {\n return { project, result: { ok: true, data: { removed: false } } };\n }\n const idx = kfs.findIndex((k) => k.frame === targetFrame);\n if (idx < 0) {\n return { project, result: { ok: true, data: { removed: false } } };\n }\n const next = cloneProject(project);\n const nextKfs = next.color_tracks[elementId].fill as ColorKeyframe[];\n nextKfs.splice(idx, 1);\n if (nextKfs.length === 0) {\n delete next.color_tracks[elementId].fill;\n if (Object.keys(next.color_tracks[elementId]).length === 0) {\n delete next.color_tracks[elementId];\n }\n }\n return { project: next, result: { ok: true, data: { removed: true } } };\n};\n\n// ---------------------------------------------------------------------------\n// set_duration\n// ---------------------------------------------------------------------------\n\ntype SetDurationArgs = { seconds: number };\n\nconst MIN_DURATION_SECONDS = 1;\nconst MAX_DURATION_SECONDS = 600;\n\nconst setDuration: ToolDispatch<SetDurationArgs> = (project, args) => {\n const { seconds } = args;\n if (!Number.isFinite(seconds) || seconds <= 0) {\n return { project, result: { ok: false, error: `invalid seconds: ${seconds}` } };\n }\n const clamped = Math.max(\n MIN_DURATION_SECONDS,\n Math.min(MAX_DURATION_SECONDS, seconds),\n );\n if (project.duration_seconds === clamped) {\n return {\n project,\n result: { ok: true, data: { duration_seconds: clamped } },\n };\n }\n const next = cloneProject(project);\n next.duration_seconds = clamped;\n return {\n project: next,\n result: { ok: true, data: { duration_seconds: clamped } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// fade_layer\n// ---------------------------------------------------------------------------\n\ntype FadeLayerArgs = {\n elementId: string;\n fromFrame: number;\n toFrame: number;\n fromOpacity: number;\n toOpacity: number;\n};\n\nconst fadeLayer: ToolDispatch<FadeLayerArgs> = (project, args) => {\n const { elementId, fromFrame, toFrame, fromOpacity, toOpacity } = args;\n if (!elementId) {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n for (const [k, v] of Object.entries({ fromFrame, toFrame, fromOpacity, toOpacity })) {\n if (!Number.isFinite(v as number)) {\n return { project, result: { ok: false, error: `invalid ${k}: ${v}` } };\n }\n }\n if (fromFrame < 0 || toFrame < 0) {\n return { project, result: { ok: false, error: \"frames must be non-negative\" } };\n }\n const next = cloneProject(project);\n upsertKeyframe(next, elementId, \"opacity\", Math.round(fromFrame), fromOpacity);\n upsertKeyframe(next, elementId, \"opacity\", Math.round(toFrame), toOpacity);\n return {\n project: next,\n result: {\n ok: true,\n data: {\n elementId,\n fromFrame: Math.round(fromFrame),\n toFrame: Math.round(toFrame),\n fromOpacity,\n toOpacity,\n },\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_layer_visible\n// ---------------------------------------------------------------------------\n\ntype SetLayerVisibleArgs = { elementId: string; visible: boolean };\n\nconst setLayerVisible: ToolDispatch<SetLayerVisibleArgs> = (project, args) => {\n const { elementId, visible } = args;\n if (!elementId) {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (typeof visible !== \"boolean\") {\n return {\n project,\n result: { ok: false, error: `visible must be a boolean (got ${typeof visible})` },\n };\n }\n const next = cloneProject(project);\n upsertKeyframe(next, elementId, \"opacity\", 0, visible ? 1 : 0);\n return {\n project: next,\n result: { ok: true, data: { elementId, visible } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// apply_preset\n// ---------------------------------------------------------------------------\n\nexport type AnimationPreset =\n | \"fade-in\"\n | \"fade-out\"\n | \"pulse\"\n | \"slide-in-left\"\n | \"slide-in-right\"\n | \"slide-up\"\n | \"shake\"\n | \"pop\";\n\nconst VALID_PRESETS: AnimationPreset[] = [\n \"fade-in\",\n \"fade-out\",\n \"pulse\",\n \"slide-in-left\",\n \"slide-in-right\",\n \"slide-up\",\n \"shake\",\n \"pop\",\n];\n\ntype PresetTuple = {\n property: TrackProperty;\n frame: number;\n value: number;\n easing?: Easing;\n};\n\n// Tuple table — duplicated from editor/src/store.ts intentionally so the pure\n// dispatcher has zero editor dependencies. Keep in sync if you add presets.\nconst PRESET_TUPLES: Record<AnimationPreset, PresetTuple[]> = {\n \"fade-in\": [\n { property: \"opacity\", frame: 0, value: 0 },\n { property: \"opacity\", frame: 30, value: 1, easing: \"outQuart\" },\n ],\n \"fade-out\": [\n { property: \"opacity\", frame: 0, value: 1 },\n { property: \"opacity\", frame: 30, value: 0, easing: \"easeInOut\" },\n ],\n pulse: [\n { property: \"scale\", frame: 0, value: 1 },\n { property: \"scale\", frame: 15, value: 1.2, easing: \"outBack\" },\n { property: \"scale\", frame: 30, value: 1, easing: \"easeInOut\" },\n ],\n // Slide / shake values are DELTAS from the layer's base x/y; applyPreset\n // bakes the layer's base in at apply time so the keyframes that land on\n // the project are absolute canvas-space positions.\n \"slide-in-left\": [\n { property: \"x\", frame: 0, value: -200 },\n { property: \"x\", frame: 30, value: 0, easing: \"outBack\" },\n ],\n \"slide-in-right\": [\n { property: \"x\", frame: 0, value: 200 },\n { property: \"x\", frame: 30, value: 0, easing: \"outBack\" },\n ],\n \"slide-up\": [\n { property: \"y\", frame: 0, value: 200 },\n { property: \"y\", frame: 30, value: 0, easing: \"outBack\" },\n ],\n shake: [\n { property: \"x\", frame: 0, value: 0, easing: \"linear\" },\n { property: \"x\", frame: 8, value: -15, easing: \"linear\" },\n { property: \"x\", frame: 16, value: 15, easing: \"linear\" },\n { property: \"x\", frame: 24, value: -15, easing: \"linear\" },\n { property: \"x\", frame: 32, value: 0, easing: \"linear\" },\n ],\n pop: [\n { property: \"scale\", frame: 0, value: 0 },\n { property: \"scale\", frame: 10, value: 1.1, easing: \"outBack\" },\n { property: \"scale\", frame: 20, value: 1, easing: \"easeInOut\" },\n ],\n};\n\ntype ApplyPresetArgs = {\n elementId: string;\n preset: string;\n startFrame?: number;\n};\n\nconst applyPreset: ToolDispatch<ApplyPresetArgs> = (project, args) => {\n const { elementId, preset, startFrame } = args;\n if (!elementId) {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (!VALID_PRESETS.includes(preset as AnimationPreset)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid preset: ${preset} (valid: ${VALID_PRESETS.join(\", \")})`,\n },\n };\n }\n const sf = startFrame === undefined ? 0 : Math.round(startFrame);\n const tuples = PRESET_TUPLES[preset as AnimationPreset];\n const next = cloneProject(project);\n const base = baseForElement(next, elementId);\n const writes: Array<{ property: TrackProperty; frame: number; value: number }> = [];\n for (const t of tuples) {\n const frame = Math.max(0, Math.round(sf + t.frame));\n const value =\n t.property === \"x\"\n ? base.x + t.value\n : t.property === \"y\"\n ? base.y + t.value\n : t.value;\n upsertKeyframe(next, elementId, t.property, frame, value, t.easing ?? \"easeInOut\");\n writes.push({ property: t.property, frame, value });\n }\n return {\n project: next,\n result: { ok: true, data: { elementId, preset, startFrame: sf, writes } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// apply_preset_stagger — apply the same preset to a list of layers with a\n// per-element startFrame offset. For diagonal pop-in grids, sequential reveal\n// lists, ring-pulse sweeps: one call instead of N. The startFrame for entry i\n// is `startFrame + i * stagger` (both default to 0 and 1 respectively).\n// ---------------------------------------------------------------------------\n\ntype ApplyPresetStaggerArgs = {\n elementIds?: unknown;\n preset?: unknown;\n startFrame?: unknown;\n stagger?: unknown;\n};\n\nconst applyPresetStagger: ToolDispatch<ApplyPresetStaggerArgs> = (project, args) => {\n const ids = args.elementIds;\n if (!Array.isArray(ids) || ids.length === 0) {\n return {\n project,\n result: { ok: false, error: \"elementIds must be a non-empty array of layer ids\" },\n };\n }\n for (let i = 0; i < ids.length; i++) {\n if (typeof ids[i] !== \"string\" || !ids[i]) {\n return {\n project,\n result: { ok: false, error: `elementIds[${i}] must be a non-empty string` },\n };\n }\n }\n const preset = args.preset;\n if (typeof preset !== \"string\" || !preset) {\n return { project, result: { ok: false, error: \"preset is required\" } };\n }\n if (!VALID_PRESETS.includes(preset as AnimationPreset)) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid preset: ${preset} (valid: ${VALID_PRESETS.join(\", \")})`,\n },\n };\n }\n const startFrameRaw = args.startFrame ?? 0;\n const startFrame = Number(startFrameRaw);\n if (!Number.isFinite(startFrame) || startFrame < 0) {\n return {\n project,\n result: { ok: false, error: \"startFrame must be a non-negative number\" },\n };\n }\n const staggerRaw = args.stagger ?? 1;\n const stagger = Number(staggerRaw);\n if (!Number.isFinite(stagger)) {\n return { project, result: { ok: false, error: \"stagger must be a finite number\" } };\n }\n let cur = project;\n for (let i = 0; i < ids.length; i++) {\n const sf = Math.max(0, Math.round(startFrame + i * stagger));\n const { project: nextP, result } = applyPreset(cur, {\n elementId: ids[i] as string,\n preset,\n startFrame: sf,\n });\n if (!result.ok) {\n return {\n project,\n result: {\n ok: false,\n error: `applying preset to ${ids[i]}: ${result.error ?? \"unknown\"}`,\n },\n };\n }\n cur = nextP;\n }\n return {\n project: cur,\n result: {\n ok: true,\n data: { count: ids.length, preset, startFrame, stagger },\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// group_layers / ungroup_layers / set_group_parent / rename_group\n// ---------------------------------------------------------------------------\n\ntype GroupLayersArgs = { elementIds: string[]; name?: string };\n\n// Wrap a set of sibling elements in a new group. The new group is created at\n// the position of the FIRST listed element within its parent; remaining\n// listed elements are removed from the parent and become the group's\n// children in their existing render-order. The group's pivot is seeded to\n// the centroid of its children's base centres at create time and then frozen.\nconst groupLayers: ToolDispatch<GroupLayersArgs> = (project, args) => {\n const { elementIds, name } = args;\n if (!Array.isArray(elementIds) || elementIds.length === 0) {\n return { project, result: { ok: false, error: \"elementIds must be a non-empty array\" } };\n }\n const idSet = new Set(elementIds);\n if (idSet.size !== elementIds.length) {\n return { project, result: { ok: false, error: \"elementIds contains duplicates\" } };\n }\n const present = new Set<string>();\n for (const v of project.video_layers) present.add(`video.${v.id}`);\n for (const s of project.shapes) present.add(`shapes.${s.id}`);\n for (const l of project.image_layers) present.add(`image.${l.id}`);\n for (const t of project.text_layers) present.add(`text.${t.id}`);\n for (const g of project.groups) present.add(`group.${g.id}`);\n for (const id of elementIds) {\n if (!present.has(id)) {\n return { project, result: { ok: false, error: `unknown elementId: ${id}` } };\n }\n }\n const parents = new Set(elementIds.map((id) => findParentGroup(project, id)));\n if (parents.size !== 1) {\n return {\n project,\n result: { ok: false, error: \"elementIds must all share the same parent (root or one group)\" },\n };\n }\n const [parentGid] = [...parents];\n\n const centers: Array<{ x: number; y: number }> = [];\n for (const id of elementIds) {\n const c = childBaseCenter(project, id);\n if (c) centers.push(c);\n }\n const pivotX = centers.length\n ? centers.reduce((a, c) => a + c.x, 0) / centers.length\n : COMP_W / 2;\n const pivotY = centers.length\n ? centers.reduce((a, c) => a + c.y, 0) / centers.length\n : COMP_H / 2;\n\n const next = cloneProject(project);\n const newId = generateLayerId(next, \"group\");\n const groupElementId = `group.${newId}`;\n\n normalizeRoot(next);\n\n const siblings: string[] =\n parentGid === null\n ? next.layer_order\n : (next.groups.find((g) => g.id === parentGid)!.children);\n const orderedChildren = siblings.filter((cid) => idSet.has(cid));\n const firstIdx = siblings.findIndex((cid) => idSet.has(cid));\n\n // Splice children out and insert the group placeholder at firstIdx\n const filtered = siblings.filter((cid) => !idSet.has(cid));\n filtered.splice(firstIdx, 0, groupElementId);\n if (parentGid === null) {\n next.layer_order = filtered;\n } else {\n next.groups.find((g) => g.id === parentGid)!.children = filtered;\n }\n\n next.groups = [\n ...next.groups,\n {\n id: newId,\n name: name ?? \"\",\n pivotX,\n pivotY,\n children: orderedChildren,\n fill: null,\n box_width: 0,\n box_height: 0,\n },\n ];\n\n return {\n project: next,\n result: {\n ok: true,\n data: { id: newId, elementId: groupElementId, pivotX, pivotY, children: orderedChildren },\n },\n };\n};\n\ntype UngroupLayersArgs = { groupId: string };\n\n// Dissolve a group: its children are spliced into the group's parent at the\n// group's old position, the group entry is removed, and the group's animation\n// + style records are dropped. Children survive at their last positions; the\n// group's keyframes do NOT bake onto the children.\nconst ungroupLayers: ToolDispatch<UngroupLayersArgs> = (project, args) => {\n const { groupId } = args;\n if (!groupId || typeof groupId !== \"string\") {\n return { project, result: { ok: false, error: \"groupId is required\" } };\n }\n const groupIdx = project.groups.findIndex((g) => g.id === groupId);\n if (groupIdx < 0) {\n return { project, result: { ok: false, error: `group not found: ${groupId}` } };\n }\n const groupElementId = `group.${groupId}`;\n const parentGid = findParentGroup(project, groupElementId);\n\n const next = cloneProject(project);\n normalizeRoot(next);\n const group = next.groups[groupIdx];\n const children = [...group.children];\n\n if (parentGid === null) {\n const idx = next.layer_order.indexOf(groupElementId);\n if (idx >= 0) {\n next.layer_order.splice(idx, 1, ...children);\n } else {\n next.layer_order.push(...children);\n }\n } else {\n const pg = next.groups.find((g) => g.id === parentGid)!;\n const idx = pg.children.indexOf(groupElementId);\n if (idx >= 0) {\n pg.children.splice(idx, 1, ...children);\n } else {\n pg.children.push(...children);\n }\n }\n next.groups.splice(groupIdx, 1);\n delete next.animations[groupElementId];\n delete next.styles[groupElementId];\n\n return {\n project: next,\n result: { ok: true, data: { groupId, elementId: groupElementId, children } },\n };\n};\n\ntype SetGroupParentArgs = {\n elementId: string;\n parentGroupId: string | null;\n index?: number;\n};\n\n// Move an element from its current parent (root or another group) into the\n// children of `parentGroupId` (null = root) at `index` (defaults to end).\n// Cycle prevention: a group cannot be placed inside itself or any of its\n// descendants. video, shape, image, and group ids are all valid.\nconst setGroupParent: ToolDispatch<SetGroupParentArgs> = (project, args) => {\n const { elementId, parentGroupId, index } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n const present = new Set<string>();\n for (const v of project.video_layers) present.add(`video.${v.id}`);\n for (const s of project.shapes) present.add(`shapes.${s.id}`);\n for (const l of project.image_layers) present.add(`image.${l.id}`);\n for (const t of project.text_layers) present.add(`text.${t.id}`);\n for (const g of project.groups) present.add(`group.${g.id}`);\n if (!present.has(elementId)) {\n return { project, result: { ok: false, error: `unknown elementId: ${elementId}` } };\n }\n // Pinned image_layers (e.g. canvas backdrop) refuse parent change — they\n // belong at the bottom of root z and can't be nested into a group.\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const layer = project.image_layers.find((l) => l.id === id);\n if (layer?.pinned === true) {\n return {\n project,\n result: {\n ok: false,\n error: `cannot move pinned layer: ${elementId}`,\n },\n };\n }\n }\n if (parentGroupId !== null && parentGroupId !== undefined) {\n if (!present.has(`group.${parentGroupId}`)) {\n return {\n project,\n result: { ok: false, error: `unknown parentGroupId: ${parentGroupId}` },\n };\n }\n if (elementId.startsWith(\"group.\")) {\n const movedId = elementId.slice(\"group.\".length);\n if (movedId === parentGroupId) {\n return { project, result: { ok: false, error: \"a group cannot be its own parent\" } };\n }\n const descendants = getGroupDescendants(project, movedId);\n if (descendants.includes(`group.${parentGroupId}`)) {\n return {\n project,\n result: {\n ok: false,\n error: \"cycle: cannot place a group inside one of its descendants\",\n },\n };\n }\n }\n }\n\n const next = cloneProject(project);\n normalizeRoot(next);\n const currentParent = findParentGroup(next, elementId);\n\n if (currentParent === null) {\n next.layer_order = next.layer_order.filter((id) => id !== elementId);\n } else {\n const pg = next.groups.find((g) => g.id === currentParent)!;\n pg.children = pg.children.filter((id) => id !== elementId);\n }\n\n const target =\n parentGroupId == null\n ? next.layer_order\n : next.groups.find((g) => g.id === parentGroupId)!.children;\n const insertIdx =\n index === undefined\n ? target.length\n : Math.max(0, Math.min(target.length, Math.round(index)));\n target.splice(insertIdx, 0, elementId);\n\n return {\n project: next,\n result: {\n ok: true,\n data: { elementId, parentGroupId: parentGroupId ?? null, index: insertIdx },\n },\n };\n};\n\ntype RenameGroupArgs = { groupId: string; name: string };\n\nconst renameGroup: ToolDispatch<RenameGroupArgs> = (project, args) => {\n const { groupId, name } = args;\n if (!groupId) return { project, result: { ok: false, error: \"groupId is required\" } };\n if (typeof name !== \"string\") {\n return { project, result: { ok: false, error: \"name must be a string\" } };\n }\n const next = cloneProject(project);\n const idx = next.groups.findIndex((g) => g.id === groupId);\n if (idx < 0) {\n return { project, result: { ok: false, error: `group not found: ${groupId}` } };\n }\n next.groups[idx] = { ...next.groups[idx], name };\n return { project: next, result: { ok: true, data: { groupId, name } } };\n};\n\n// ---------------------------------------------------------------------------\n// add_audio_overlay / remove_audio_overlay / update_audio_overlay\n// ---------------------------------------------------------------------------\n//\n// Asset must already exist at users/<userId>/assets/<projectId>/<filename>.\n// This dispatcher does NOT verify the file (consistent with add_image_layer);\n// the editor adapter and HTTP/MCP routes do their own pre-checks.\n\ntype AddAudioOverlayArgs = {\n filename: string;\n startFrame: number;\n gain?: number;\n fadeInFrames?: number;\n fadeOutFrames?: number;\n endFrame?: number;\n};\n\nconst reserveAudioOverlayId = (existing: Set<string>): string => {\n let n = existing.size + 1;\n let id = `audio_${n}`;\n while (existing.has(id)) {\n n += 1;\n id = `audio_${n}`;\n }\n return id;\n};\n\nconst addAudioOverlay: ToolDispatch<AddAudioOverlayArgs> = (project, args) => {\n const { filename, startFrame, gain, fadeInFrames, fadeOutFrames, endFrame } =\n args;\n if (!filename || typeof filename !== \"string\") {\n return { project, result: { ok: false, error: \"filename is required\" } };\n }\n if (!Number.isFinite(startFrame) || startFrame < 0) {\n return {\n project,\n result: { ok: false, error: `invalid startFrame: ${startFrame}` },\n };\n }\n if (gain !== undefined && (!Number.isFinite(gain) || gain < 0 || gain > 2)) {\n return {\n project,\n result: { ok: false, error: `gain must be in [0, 2]: ${gain}` },\n };\n }\n if (\n fadeInFrames !== undefined &&\n (!Number.isFinite(fadeInFrames) || fadeInFrames < 0)\n ) {\n return {\n project,\n result: {\n ok: false,\n error: `fadeInFrames must be a non-negative integer: ${fadeInFrames}`,\n },\n };\n }\n if (\n fadeOutFrames !== undefined &&\n (!Number.isFinite(fadeOutFrames) || fadeOutFrames < 0)\n ) {\n return {\n project,\n result: {\n ok: false,\n error: `fadeOutFrames must be a non-negative integer: ${fadeOutFrames}`,\n },\n };\n }\n if (endFrame !== undefined) {\n if (!Number.isFinite(endFrame) || endFrame < 0) {\n return {\n project,\n result: { ok: false, error: `invalid endFrame: ${endFrame}` },\n };\n }\n if (Math.round(endFrame) <= Math.round(startFrame)) {\n return {\n project,\n result: {\n ok: false,\n error: \"endFrame must be greater than startFrame\",\n },\n };\n }\n }\n const next = cloneProject(project);\n const existing = new Set((next.audio_overlays ?? []).map((o) => o.id));\n const id = reserveAudioOverlayId(existing);\n const overlay: AudioOverlay = {\n id,\n filename,\n startFrame: Math.round(startFrame),\n gain: gain ?? 1,\n fadeInFrames:\n fadeInFrames === undefined ? 0 : Math.round(fadeInFrames),\n fadeOutFrames:\n fadeOutFrames === undefined ? 0 : Math.round(fadeOutFrames),\n ...(endFrame !== undefined ? { endFrame: Math.round(endFrame) } : {}),\n };\n next.audio_overlays = [...(next.audio_overlays ?? []), overlay];\n return { project: next, result: { ok: true, data: overlay } };\n};\n\ntype RemoveAudioOverlayArgs = { id: string };\n\nconst removeAudioOverlay: ToolDispatch<RemoveAudioOverlayArgs> = (\n project,\n args,\n) => {\n const { id } = args;\n if (!id || typeof id !== \"string\") {\n return { project, result: { ok: false, error: \"id is required\" } };\n }\n const overlays = project.audio_overlays ?? [];\n const idx = overlays.findIndex((o) => o.id === id);\n if (idx < 0) {\n return {\n project,\n result: { ok: false, error: `audio overlay not found: ${id}` },\n };\n }\n const next = cloneProject(project);\n next.audio_overlays.splice(idx, 1);\n return { project: next, result: { ok: true, data: { id } } };\n};\n\ntype UpdateAudioOverlayArgs = {\n id: string;\n startFrame?: number;\n gain?: number;\n fadeInFrames?: number;\n fadeOutFrames?: number;\n endFrame?: number | null;\n filename?: string;\n};\n\nconst updateAudioOverlay: ToolDispatch<UpdateAudioOverlayArgs> = (\n project,\n args,\n) => {\n const {\n id,\n startFrame,\n gain,\n fadeInFrames,\n fadeOutFrames,\n endFrame,\n filename,\n } = args;\n if (!id || typeof id !== \"string\") {\n return { project, result: { ok: false, error: \"id is required\" } };\n }\n const overlays = project.audio_overlays ?? [];\n const idx = overlays.findIndex((o) => o.id === id);\n if (idx < 0) {\n return {\n project,\n result: { ok: false, error: `audio overlay not found: ${id}` },\n };\n }\n if (startFrame !== undefined && (!Number.isFinite(startFrame) || startFrame < 0)) {\n return {\n project,\n result: { ok: false, error: `invalid startFrame: ${startFrame}` },\n };\n }\n if (gain !== undefined && (!Number.isFinite(gain) || gain < 0 || gain > 2)) {\n return {\n project,\n result: { ok: false, error: `gain must be in [0, 2]: ${gain}` },\n };\n }\n if (\n fadeInFrames !== undefined &&\n (!Number.isFinite(fadeInFrames) || fadeInFrames < 0)\n ) {\n return {\n project,\n result: {\n ok: false,\n error: `fadeInFrames must be a non-negative integer: ${fadeInFrames}`,\n },\n };\n }\n if (\n fadeOutFrames !== undefined &&\n (!Number.isFinite(fadeOutFrames) || fadeOutFrames < 0)\n ) {\n return {\n project,\n result: {\n ok: false,\n error: `fadeOutFrames must be a non-negative integer: ${fadeOutFrames}`,\n },\n };\n }\n if (endFrame !== undefined && endFrame !== null) {\n if (!Number.isFinite(endFrame) || endFrame < 0) {\n return {\n project,\n result: { ok: false, error: `invalid endFrame: ${endFrame}` },\n };\n }\n }\n if (filename !== undefined && (typeof filename !== \"string\" || filename.length === 0)) {\n return {\n project,\n result: { ok: false, error: \"filename must be a non-empty string\" },\n };\n }\n const next = cloneProject(project);\n const cur = next.audio_overlays[idx];\n const merged: AudioOverlay = {\n ...cur,\n ...(filename !== undefined ? { filename } : {}),\n ...(startFrame !== undefined\n ? { startFrame: Math.round(startFrame) }\n : {}),\n ...(gain !== undefined ? { gain } : {}),\n ...(fadeInFrames !== undefined\n ? { fadeInFrames: Math.round(fadeInFrames) }\n : {}),\n ...(fadeOutFrames !== undefined\n ? { fadeOutFrames: Math.round(fadeOutFrames) }\n : {}),\n };\n if (endFrame === null) {\n delete merged.endFrame;\n } else if (endFrame !== undefined) {\n merged.endFrame = Math.round(endFrame);\n }\n if (\n merged.endFrame !== undefined &&\n merged.endFrame <= merged.startFrame\n ) {\n return {\n project,\n result: { ok: false, error: \"endFrame must be greater than startFrame\" },\n };\n }\n next.audio_overlays[idx] = merged;\n return { project: next, result: { ok: true, data: merged } };\n};\n\n// ---------------------------------------------------------------------------\n// set_video_layer_trim — patch a video_layer's trim window\n// ---------------------------------------------------------------------------\n\ntype SetVideoLayerTrimArgs = {\n elementId: string;\n source_in_frame?: number;\n source_out_frame?: number | null;\n timeline_start_frame?: number;\n};\n\nconst setVideoLayerTrim: ToolDispatch<SetVideoLayerTrimArgs> = (\n project,\n args,\n) => {\n const { elementId, source_in_frame, source_out_frame, timeline_start_frame } = args;\n if (!elementId || !elementId.startsWith(\"video.\")) {\n return {\n project,\n result: { ok: false, error: `elementId must be video.<id>: ${elementId}` },\n };\n }\n const id = elementId.slice(\"video.\".length);\n const idx = project.video_layers.findIndex((v) => v.id === id);\n if (idx < 0) {\n return {\n project,\n result: { ok: false, error: `video layer not found: ${elementId}` },\n };\n }\n if (\n source_in_frame !== undefined &&\n (!Number.isFinite(source_in_frame) || source_in_frame < 0)\n ) {\n return {\n project,\n result: { ok: false, error: `invalid source_in_frame: ${source_in_frame}` },\n };\n }\n if (source_out_frame !== undefined && source_out_frame !== null) {\n if (!Number.isFinite(source_out_frame) || source_out_frame < 0) {\n return {\n project,\n result: { ok: false, error: `invalid source_out_frame: ${source_out_frame}` },\n };\n }\n }\n if (\n timeline_start_frame !== undefined &&\n (!Number.isFinite(timeline_start_frame) || timeline_start_frame < 0)\n ) {\n return {\n project,\n result: {\n ok: false,\n error: `invalid timeline_start_frame: ${timeline_start_frame}`,\n },\n };\n }\n const next = cloneProject(project);\n const cur = next.video_layers[idx];\n const merged: VideoLayer = {\n ...cur,\n ...(source_in_frame !== undefined\n ? { source_in_frame: Math.round(source_in_frame) }\n : {}),\n ...(timeline_start_frame !== undefined\n ? { timeline_start_frame: Math.round(timeline_start_frame) }\n : {}),\n };\n if (source_out_frame === null) {\n merged.source_out_frame = null;\n } else if (source_out_frame !== undefined) {\n merged.source_out_frame = Math.round(source_out_frame);\n }\n if (\n merged.source_out_frame !== null &&\n merged.source_out_frame <= merged.source_in_frame\n ) {\n return {\n project,\n result: {\n ok: false,\n error: \"source_out_frame must be greater than source_in_frame\",\n },\n };\n }\n next.video_layers[idx] = merged;\n return { project: next, result: { ok: true, data: merged } };\n};\n\n// ---------------------------------------------------------------------------\n// set_embed_origins / add_embed_origin / remove_embed_origin\n// ---------------------------------------------------------------------------\n//\n// `embed_origins` is the per-project allowlist of hostnames permitted to load\n// the project through the public <morpha-video> embed. An empty list\n// turns embedding OFF — the unauthenticated /api/embed route 404s the project.\n// Entries are bare, lowercased hostnames; scheme, port, and path are stripped\n// on the way in, so \"https://shop.example.com:443/x\" and \"shop.example.com\"\n// both normalize to \"shop.example.com\" (matching the worker's exact-hostname\n// Origin check in worker/src/embed.ts). The HTTP + MCP routes mirror the\n// resulting list into KV after the write (syncEmbedIndex) so the public embed\n// route can resolve the project without auth.\n\nconst normalizeOrigin = (raw: string): string =>\n raw\n .trim()\n .toLowerCase()\n .replace(/^[a-z][a-z0-9+.-]*:\\/\\//, \"\") // strip scheme\n .replace(/[/?#].*$/, \"\") // strip path / query / fragment\n .replace(/:\\d+$/, \"\"); // strip port\n\ntype SetEmbedOriginsArgs = { origins?: unknown };\n\nconst setEmbedOrigins: ToolDispatch<SetEmbedOriginsArgs> = (project, args) => {\n const { origins } = args;\n if (!Array.isArray(origins)) {\n return {\n project,\n result: {\n ok: false,\n error: \"origins must be an array of hostname strings\",\n },\n };\n }\n const out: string[] = [];\n for (const o of origins) {\n if (typeof o !== \"string\") {\n return {\n project,\n result: { ok: false, error: \"every origin must be a string\" },\n };\n }\n const host = normalizeOrigin(o);\n if (host && !out.includes(host)) out.push(host);\n }\n const next = cloneProject(project);\n next.embed_origins = out;\n return { project: next, result: { ok: true, data: { embed_origins: out } } };\n};\n\n// ---------------------------------------------------------------------------\n// set_custom_font — register a custom (non-Google) typeface on the project\n// ---------------------------------------------------------------------------\n//\n// Adds (or replaces) an entry in project.custom_fonts so text layers can use it\n// by `family` via their font_family, exactly like a Google family. `src` is\n// EITHER a full URL (https://…, data:…) OR an uploaded asset filename in the\n// project's asset bucket (uploaded via /api/upload-asset). Like add_image_layer\n// this does NOT verify an uploaded filename exists. Dedupes by family+weight+\n// style, replacing a matching face. The editor/embed font loader (fonts.ts)\n// decodes each via the FontFace API before the first render. NOTE: a pasted URL\n// only loads if that host sends permissive CORS headers; uploading the font\n// (served same-origin) is the robust path.\n\ntype SetCustomFontArgs = {\n family?: unknown;\n src?: unknown;\n weight?: unknown;\n style?: unknown;\n};\n\nconst setCustomFont: ToolDispatch<SetCustomFontArgs> = (project, args) => {\n const family = typeof args.family === \"string\" ? args.family.trim() : \"\";\n const src = typeof args.src === \"string\" ? args.src.trim() : \"\";\n if (!family) {\n return { project, result: { ok: false, error: \"family is required\" } };\n }\n if (!src) {\n return {\n project,\n result: {\n ok: false,\n error: \"src is required (a font URL or an uploaded asset filename)\",\n },\n };\n }\n let weight = 400;\n if (args.weight !== undefined && args.weight !== null) {\n const w = Number(args.weight);\n if (!Number.isFinite(w) || w < 1 || w > 1000) {\n return {\n project,\n result: { ok: false, error: \"weight must be a number between 1 and 1000\" },\n };\n }\n weight = Math.round(w);\n }\n let style: \"normal\" | \"italic\" = \"normal\";\n if (args.style !== undefined && args.style !== null) {\n if (args.style !== \"normal\" && args.style !== \"italic\") {\n return {\n project,\n result: { ok: false, error: \"style must be 'normal' or 'italic'\" },\n };\n }\n style = args.style;\n }\n const next = cloneProject(project);\n const list = [...(next.custom_fonts ?? [])];\n const faceKey = (f: { family: string; weight?: number; style?: string }) =>\n `${f.family.trim().toLowerCase()}|${f.weight ?? 400}|${f.style ?? \"normal\"}`;\n const entry = { family, src, weight, style };\n const existing = list.findIndex((f) => faceKey(f) === faceKey(entry));\n if (existing >= 0) list[existing] = entry;\n else list.push(entry);\n next.custom_fonts = list;\n return {\n project: next,\n result: { ok: true, data: { custom_fonts: next.custom_fonts } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// list_fonts — discover families across all sources (+ the project's custom\n// fonts) so an agent can pick one to use in set_layer_text / add_text_layer.\n// ---------------------------------------------------------------------------\n\ntype ListFontsArgs = {\n q?: unknown;\n source?: unknown;\n limit?: unknown;\n};\n\nconst VALID_SOURCES: ReadonlyArray<FontSource | \"custom\"> = [\n \"google\",\n \"bunny\",\n \"fontshare\",\n \"fontsource\",\n \"velvetyne\",\n \"custom\",\n];\n\nconst listFonts: ToolDispatch<ListFontsArgs> = (project, args) => {\n const q = typeof args.q === \"string\" ? args.q.trim().toLowerCase() : \"\";\n const srcRaw = typeof args.source === \"string\" ? args.source.trim().toLowerCase() : \"\";\n if (srcRaw && !VALID_SOURCES.includes(srcRaw as FontSource | \"custom\")) {\n return {\n project,\n result: {\n ok: false,\n error: `source must be one of: ${VALID_SOURCES.join(\", \")}`,\n },\n };\n }\n let limit = 50;\n if (args.limit !== undefined && args.limit !== null) {\n const n = Number(args.limit);\n if (!Number.isFinite(n) || n < 1) {\n return {\n project,\n result: { ok: false, error: \"limit must be a positive number\" },\n };\n }\n limit = Math.max(1, Math.min(1000, Math.floor(n)));\n }\n\n // Project's user-uploaded faces, surfaced as source: \"custom\".\n const customs = (project.custom_fonts ?? []).map((c) => ({\n family: c.family,\n source: \"custom\" as const,\n weights: c.weight ? [c.weight] : [400],\n italics: c.style === \"italic\",\n }));\n // Dedupe customs by family (one entry per family, weights merged).\n const customByFamily = new Map<string, (typeof customs)[number]>();\n for (const c of customs) {\n const key = c.family.toLowerCase();\n const existing = customByFamily.get(key);\n if (!existing) customByFamily.set(key, { ...c, weights: [...c.weights] });\n else {\n for (const w of c.weights) if (!existing.weights.includes(w)) existing.weights.push(w);\n existing.italics = existing.italics || c.italics;\n }\n }\n const customEntries = [...customByFamily.values()];\n\n // Cross-source catalog (Google + the four added sources, deduped by priority).\n const catalog = allFontEntries().map((e) => ({\n family: e.family,\n source: e.source,\n weights: e.weights,\n italics: e.italics,\n }));\n\n const all = [...customEntries, ...catalog];\n const filtered = all.filter((e) => {\n if (srcRaw && e.source !== srcRaw) return false;\n if (q && !e.family.toLowerCase().includes(q)) return false;\n return true;\n });\n const returned = filtered.slice(0, limit);\n return {\n project,\n result: {\n ok: true,\n data: {\n fonts: returned,\n total: filtered.length,\n returned: returned.length,\n sources: VALID_SOURCES,\n },\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_matte_source — track matte (one layer masks another's alpha)\n// ---------------------------------------------------------------------------\n\ntype SetMatteSourceArgs = {\n elementId: string;\n matte_source_id: string | null;\n};\n\nconst isLeafElementId = (id: string): boolean =>\n id.startsWith(\"image.\") ||\n id.startsWith(\"video.\") ||\n id.startsWith(\"shapes.\") ||\n id.startsWith(\"text.\");\n\nconst setMatteSource: ToolDispatch<SetMatteSourceArgs> = (project, args) => {\n const { elementId, matte_source_id } = args;\n if (!elementId || typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n const isGroupHost = elementId.startsWith(\"group.\");\n if (!isLeafElementId(elementId) && !isGroupHost) {\n return {\n project,\n result: {\n ok: false,\n error: \"matte can be set on a leaf (image/video/shapes/text.<id>) or a group.<id>\",\n },\n };\n }\n if (\n matte_source_id !== null &&\n matte_source_id !== undefined &&\n typeof matte_source_id !== \"string\"\n ) {\n return {\n project,\n result: { ok: false, error: \"matte_source_id must be a string or null\" },\n };\n }\n if (typeof matte_source_id === \"string\") {\n if (isGroupHost) {\n // A group is masked by a shape's path (vector clip), so its matte source\n // must be a shape leaf.\n if (!matte_source_id.startsWith(\"shapes.\")) {\n return {\n project,\n result: {\n ok: false,\n error: \"a group's matte source must be a shape (shapes.<id>) — its path clips the group's children\",\n },\n };\n }\n } else if (!isLeafElementId(matte_source_id)) {\n return {\n project,\n result: {\n ok: false,\n error: \"matte_source_id must be a leaf element id (image.<id>, video.<id>, shapes.<id>, text.<id>)\",\n },\n };\n }\n if (matte_source_id === elementId) {\n return {\n project,\n result: { ok: false, error: \"matte_source_id cannot reference the host layer\" },\n };\n }\n }\n const next = cloneProject(project);\n const value =\n matte_source_id === null || matte_source_id === undefined\n ? null\n : matte_source_id;\n if (elementId.startsWith(\"image.\")) {\n const id = elementId.slice(\"image.\".length);\n const idx = next.image_layers.findIndex((l) => l.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.image_layers[idx] = { ...next.image_layers[idx], matte_source_id: value };\n } else if (elementId.startsWith(\"video.\")) {\n const id = elementId.slice(\"video.\".length);\n const idx = next.video_layers.findIndex((v) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown layer: ${elementId}` } };\n }\n next.video_layers[idx] = { ...next.video_layers[idx], matte_source_id: value };\n } else if (elementId.startsWith(\"shapes.\")) {\n const id = elementId.slice(\"shapes.\".length);\n const idx = next.shapes.findIndex((s) => s.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown shape: ${elementId}` } };\n }\n next.shapes[idx] = { ...next.shapes[idx], matte_source_id: value };\n } else if (elementId.startsWith(\"text.\")) {\n const id = elementId.slice(\"text.\".length);\n const idx = next.text_layers.findIndex((t) => t.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown text layer: ${elementId}` } };\n }\n next.text_layers[idx] = { ...next.text_layers[idx], matte_source_id: value };\n } else if (elementId.startsWith(\"group.\")) {\n const id = elementId.slice(\"group.\".length);\n const idx = next.groups.findIndex((g) => g.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `unknown group: ${elementId}` } };\n }\n next.groups[idx] = { ...next.groups[idx], matte_source_id: value };\n }\n return { project: next, result: { ok: true, data: { elementId, matte_source_id: value } } };\n};\n\n// ---------------------------------------------------------------------------\n// add_speed_keyframe / remove_speed_keyframe — video time-remap curve\n// ---------------------------------------------------------------------------\n\ntype AddSpeedKeyframeArgs = {\n elementId: string;\n frame: number;\n rate: number;\n};\n\nconst addSpeedKeyframe: ToolDispatch<AddSpeedKeyframeArgs> = (project, args) => {\n const { elementId, frame, rate } = args;\n if (!elementId || !elementId.startsWith(\"video.\")) {\n return { project, result: { ok: false, error: \"elementId must be video.<id>\" } };\n }\n if (!Number.isFinite(frame) || frame < 0) {\n return { project, result: { ok: false, error: `invalid frame: ${frame}` } };\n }\n if (!Number.isFinite(rate) || rate < 0.1 || rate > 8) {\n return { project, result: { ok: false, error: `invalid rate: ${rate} (must be in [0.1, 8])` } };\n }\n const id = elementId.slice(\"video.\".length);\n const idx = project.video_layers.findIndex((v) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `video layer not found: ${elementId}` } };\n }\n const next = cloneProject(project);\n const cur = next.video_layers[idx];\n const list = [...(cur.speed_keyframes ?? [])];\n const f = Math.round(frame);\n const existing = list.findIndex((k) => k.frame === f);\n if (existing >= 0) list[existing] = { frame: f, rate };\n else list.push({ frame: f, rate });\n list.sort((a, b) => a.frame - b.frame);\n next.video_layers[idx] = { ...cur, speed_keyframes: list };\n return { project: next, result: { ok: true, data: { elementId, frame: f, rate } } };\n};\n\ntype RemoveSpeedKeyframeArgs = { elementId: string; frame: number };\n\nconst removeSpeedKeyframe: ToolDispatch<RemoveSpeedKeyframeArgs> = (project, args) => {\n const { elementId, frame } = args;\n if (!elementId || !elementId.startsWith(\"video.\")) {\n return { project, result: { ok: false, error: \"elementId must be video.<id>\" } };\n }\n const id = elementId.slice(\"video.\".length);\n const idx = project.video_layers.findIndex((v) => v.id === id);\n if (idx < 0) {\n return { project, result: { ok: false, error: `video layer not found: ${elementId}` } };\n }\n const next = cloneProject(project);\n const cur = next.video_layers[idx];\n const f = Math.round(frame);\n const list = (cur.speed_keyframes ?? []).filter((k) => k.frame !== f);\n if (list.length === (cur.speed_keyframes ?? []).length) {\n return { project, result: { ok: false, error: `no speed keyframe at frame ${f} on ${elementId}` } };\n }\n next.video_layers[idx] = {\n ...cur,\n speed_keyframes: list.length > 0 ? list : undefined,\n };\n return { project: next, result: { ok: true } };\n};\n\ntype EmbedOriginArg = { origin?: unknown };\n\nconst addEmbedOrigin: ToolDispatch<EmbedOriginArg> = (project, args) => {\n const { origin } = args;\n if (typeof origin !== \"string\") {\n return {\n project,\n result: { ok: false, error: \"origin must be a string\" },\n };\n }\n const host = normalizeOrigin(origin);\n if (!host) {\n return {\n project,\n result: { ok: false, error: \"origin is empty after normalization\" },\n };\n }\n if (project.embed_origins.includes(host)) {\n // Idempotent — already allowlisted; return the same project ref so the\n // route's `outcome.project !== project` guard skips a redundant write.\n return {\n project,\n result: {\n ok: true,\n data: { embed_origins: project.embed_origins, added: false },\n },\n };\n }\n const next = cloneProject(project);\n next.embed_origins = [...project.embed_origins, host];\n return {\n project: next,\n result: {\n ok: true,\n data: { embed_origins: next.embed_origins, added: true },\n },\n };\n};\n\nconst removeEmbedOrigin: ToolDispatch<EmbedOriginArg> = (project, args) => {\n const { origin } = args;\n if (typeof origin !== \"string\") {\n return {\n project,\n result: { ok: false, error: \"origin must be a string\" },\n };\n }\n const host = normalizeOrigin(origin);\n if (!project.embed_origins.includes(host)) {\n // Idempotent — not present; same project ref so the route skips the write.\n return {\n project,\n result: {\n ok: true,\n data: { embed_origins: project.embed_origins, removed: false },\n },\n };\n }\n const next = cloneProject(project);\n next.embed_origins = project.embed_origins.filter((h) => h !== host);\n return {\n project: next,\n result: {\n ok: true,\n data: { embed_origins: next.embed_origins, removed: true },\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_layer_text\n// ---------------------------------------------------------------------------\n//\n// Edit an existing text layer (text.<id>) — patch its text content, font,\n// size, or colour. Pass only the fields you want to change. Use\n// add_text_layer to create a new text layer; set_layer_text never creates\n// one and never touches image layers.\n\nconst DEFAULT_TEXT_FONT = \"Hanken Grotesk\";\n\n// Validate + assign the optional text-style props shared by set_layer_text and\n// add_text_layer. Mutates `layer`; returns an error message on the first bad\n// field, else null.\nconst applyTextStyleProps = (\n layer: TextLayer,\n args: Record<string, unknown>,\n): string | null => {\n if (args.font_weight !== undefined) {\n const w = args.font_weight;\n if (typeof w !== \"number\" || !Number.isFinite(w) || w < 100 || w > 900) {\n return \"font_weight must be a number 100..900\";\n }\n layer.font_weight = Math.round(w);\n }\n if (args.font_style !== undefined) {\n const v = args.font_style;\n if (v === \"normal\" || v === \"italic\") layer.font_style = v;\n else return 'font_style must be \"normal\" or \"italic\"';\n }\n if (args.text_transform !== undefined) {\n const v = args.text_transform;\n if (v === \"none\" || v === \"uppercase\" || v === \"lowercase\") {\n layer.text_transform = v;\n } else {\n return 'text_transform must be \"none\", \"uppercase\", or \"lowercase\"';\n }\n }\n if (args.letter_spacing !== undefined) {\n const v = args.letter_spacing;\n if (typeof v !== \"number\" || !Number.isFinite(v)) {\n return \"letter_spacing must be a number\";\n }\n layer.letter_spacing = v;\n }\n if (args.line_height !== undefined) {\n const v = args.line_height;\n if (typeof v !== \"number\" || !(v > 0)) {\n return \"line_height must be a positive number\";\n }\n layer.line_height = v;\n }\n if (args.text_align !== undefined) {\n const v = args.text_align;\n if (v === \"left\" || v === \"center\" || v === \"right\") layer.text_align = v;\n else return 'text_align must be \"left\", \"center\", or \"right\"';\n }\n if (args.text_autofit !== undefined) {\n const v = args.text_autofit;\n if (v === \"shrink\" || v === \"wrap\") layer.text_autofit = v;\n else return 'text_autofit must be \"shrink\" or \"wrap\"';\n }\n if (args.text_valign !== undefined) {\n const v = args.text_valign;\n if (v === \"top\" || v === \"middle\" || v === \"bottom\") layer.text_valign = v;\n else return 'text_valign must be \"top\", \"middle\", or \"bottom\"';\n }\n if (args.stroke_width !== undefined) {\n const v = args.stroke_width;\n if (typeof v !== \"number\" || !(v >= 0)) {\n return \"stroke_width must be a number >= 0\";\n }\n layer.stroke_width = v;\n }\n if (args.stroke_color !== undefined) {\n const v = args.stroke_color;\n if (typeof v !== \"string\" || !HEX.test(v)) {\n return \"stroke_color must be a #rrggbb hex string\";\n }\n layer.stroke_color = v;\n }\n if (args.text_shadow !== undefined) {\n const v = args.text_shadow;\n if (v === null) {\n layer.text_shadow = null;\n } else if (typeof v === \"object\") {\n const sh = v as Record<string, unknown>;\n if (\n typeof sh.offsetX !== \"number\" ||\n typeof sh.offsetY !== \"number\" ||\n typeof sh.blur !== \"number\" ||\n !(sh.blur >= 0) ||\n typeof sh.color !== \"string\"\n ) {\n return \"text_shadow must be { offsetX, offsetY, blur>=0, color } or null\";\n }\n layer.text_shadow = {\n offsetX: sh.offsetX,\n offsetY: sh.offsetY,\n blur: sh.blur,\n color: sh.color,\n };\n } else {\n return \"text_shadow must be an object or null\";\n }\n }\n return null;\n};\n\ntype SetLayerTextArgs = {\n elementId?: unknown;\n text?: unknown;\n text_size?: unknown;\n font_family?: unknown;\n text_color?: unknown;\n font_weight?: unknown;\n font_style?: unknown;\n text_transform?: unknown;\n letter_spacing?: unknown;\n line_height?: unknown;\n text_align?: unknown;\n stroke_width?: unknown;\n stroke_color?: unknown;\n text_shadow?: unknown;\n};\n\nconst setLayerText: ToolDispatch<SetLayerTextArgs> = (project, args) => {\n const { elementId } = args;\n if (typeof elementId !== \"string\" || !elementId.startsWith(\"text.\")) {\n return {\n project,\n result: {\n ok: false,\n error: \"elementId must be a text layer id (text.<id>)\",\n },\n };\n }\n const id = elementId.slice(\"text.\".length);\n const next = cloneProject(project);\n const layer = next.text_layers.find((t) => t.id === id);\n if (!layer) {\n return {\n project,\n result: { ok: false, error: `text layer not found: ${elementId}` },\n };\n }\n\n const { text, text_size, font_family, text_color } = args;\n\n if (text !== undefined) {\n if (typeof text !== \"string\") {\n return {\n project,\n result: { ok: false, error: \"text must be a string\" },\n };\n }\n layer.text = text;\n }\n if (text_size !== undefined) {\n if (typeof text_size !== \"number\" || !(text_size > 0)) {\n return {\n project,\n result: { ok: false, error: \"text_size must be a positive number\" },\n };\n }\n layer.text_size = text_size;\n }\n if (font_family !== undefined) {\n if (typeof font_family !== \"string\" || font_family.trim().length === 0) {\n return {\n project,\n result: { ok: false, error: \"font_family must be a non-empty string\" },\n };\n }\n layer.font_family = font_family.trim();\n }\n if (text_color !== undefined) {\n if (typeof text_color !== \"string\" || !HEX.test(text_color)) {\n return {\n project,\n result: {\n ok: false,\n error: \"text_color must be a #rrggbb hex string\",\n },\n };\n }\n layer.text_color = text_color;\n }\n\n const styleErr = applyTextStyleProps(layer, args as Record<string, unknown>);\n if (styleErr) {\n return { project, result: { ok: false, error: styleErr } };\n }\n\n return {\n project: next,\n result: {\n ok: true,\n data: {\n elementId,\n text: layer.text,\n text_size: layer.text_size ?? null,\n font_family: layer.font_family,\n text_color: layer.text_color ?? null,\n font_weight: layer.font_weight ?? null,\n font_style: layer.font_style ?? null,\n text_transform: layer.text_transform ?? null,\n letter_spacing: layer.letter_spacing ?? null,\n line_height: layer.line_height ?? null,\n text_align: layer.text_align ?? null,\n stroke_width: layer.stroke_width ?? null,\n stroke_color: layer.stroke_color ?? null,\n },\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_text_layer\n// ---------------------------------------------------------------------------\n//\n// Create a new text layer. Mints a fresh `text.<id>`, appends a TextLayer to\n// project.text_layers, and appends the element id to layer_order so it lands\n// at the top of the root z-stack. A text layer is a first-class leaf — it\n// animates, groups, and z-orders exactly like an image or shape.\n\ntype AddTextLayerArgs = {\n text?: unknown;\n x?: unknown;\n y?: unknown;\n width?: unknown;\n height?: unknown;\n font_family?: unknown;\n text_size?: unknown;\n text_color?: unknown;\n font_weight?: unknown;\n font_style?: unknown;\n text_transform?: unknown;\n letter_spacing?: unknown;\n line_height?: unknown;\n text_align?: unknown;\n stroke_width?: unknown;\n stroke_color?: unknown;\n text_shadow?: unknown;\n};\n\nconst DEFAULT_TEXT_W = 900;\nconst DEFAULT_TEXT_H = 320;\n\nconst addTextLayer: ToolDispatch<AddTextLayerArgs> = (project, args) => {\n const { text, x, y, width, height, font_family, text_size, text_color } =\n args;\n if (text !== undefined && typeof text !== \"string\") {\n return { project, result: { ok: false, error: \"text must be a string\" } };\n }\n if (\n font_family !== undefined &&\n (typeof font_family !== \"string\" || font_family.trim().length === 0)\n ) {\n return {\n project,\n result: { ok: false, error: \"font_family must be a non-empty string\" },\n };\n }\n if (\n text_size !== undefined &&\n (typeof text_size !== \"number\" || !(text_size > 0))\n ) {\n return {\n project,\n result: { ok: false, error: \"text_size must be a positive number\" },\n };\n }\n if (\n text_color !== undefined &&\n (typeof text_color !== \"string\" || !HEX.test(text_color))\n ) {\n return {\n project,\n result: { ok: false, error: \"text_color must be a #rrggbb hex string\" },\n };\n }\n for (const [k, v] of [\n [\"x\", x],\n [\"y\", y],\n ] as const) {\n if (v !== undefined && (typeof v !== \"number\" || !Number.isFinite(v))) {\n return {\n project,\n result: { ok: false, error: `${k} must be a finite number` },\n };\n }\n }\n for (const [k, v] of [\n [\"width\", width],\n [\"height\", height],\n ] as const) {\n if (\n v !== undefined &&\n (typeof v !== \"number\" || !Number.isFinite(v) || v <= 0)\n ) {\n return {\n project,\n result: { ok: false, error: `${k} must be a positive number` },\n };\n }\n }\n\n const next = cloneProject(project);\n const id = generateLayerId(next, \"text\");\n\n // Derive a default text_size from the existing text layers (median of their\n // explicit text_size values); fall back to ~10% of the canvas height.\n let resolvedTextSize: number | undefined;\n if (typeof text_size === \"number\") {\n resolvedTextSize = text_size;\n } else {\n const sizes = next.text_layers\n .map((t) => t.text_size)\n .filter((s): s is number => typeof s === \"number\" && s > 0)\n .sort((a, b) => a - b);\n if (sizes.length > 0) {\n const mid = Math.floor(sizes.length / 2);\n resolvedTextSize =\n sizes.length % 2 === 1\n ? sizes[mid]\n : (sizes[mid - 1] + sizes[mid]) / 2;\n } else {\n resolvedTextSize = Math.round(next.canvas_height * 0.1);\n }\n }\n\n const layer: TextLayer = {\n id,\n text: typeof text === \"string\" ? text : \"\",\n x: typeof x === \"number\" ? x : next.canvas_width / 2,\n y: typeof y === \"number\" ? y : next.canvas_height / 2,\n width: typeof width === \"number\" ? width : DEFAULT_TEXT_W,\n height: typeof height === \"number\" ? height : DEFAULT_TEXT_H,\n rotation: 0,\n pivotX: 0.5,\n pivotY: 0.5,\n font_family:\n typeof font_family === \"string\" ? font_family.trim() : DEFAULT_TEXT_FONT,\n ...(resolvedTextSize !== undefined ? { text_size: resolvedTextSize } : {}),\n ...(typeof text_color === \"string\" ? { text_color } : {}),\n fill: null,\n };\n const styleErr = applyTextStyleProps(layer, args as Record<string, unknown>);\n if (styleErr) {\n return { project, result: { ok: false, error: styleErr } };\n }\n next.text_layers = [...next.text_layers, layer];\n next.layer_order = [...next.layer_order, `text.${id}`];\n return {\n project: next,\n result: { ok: true, data: { id, elementId: `text.${id}` } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// add_caption_track\n// ---------------------------------------------------------------------------\n//\n// Build a caption track from pre-timed lines. The editor derives the lines\n// from the clip's Whisper transcript (word timings → ~5-word lines); an agent\n// can pass its own. Two modes:\n// • \"line-sync\" (default) — one text layer per line, each shown only during\n// its [startFrame, endFrame) window via hold-eased opacity keyframes (the\n// \"active line\" karaoke read). Hold easing makes the lines snap on/off.\n// • \"static\" — a single layer with every line joined by newlines.\n// A style preset maps to the text layer's font / colour / outline. Lines\n// default to a lower-third band spanning most of the canvas width. Every\n// created layer is named \"Captions …\" so callers can detect / clear the track.\n\ntype CaptionLineArg = {\n text?: unknown;\n startFrame?: unknown;\n endFrame?: unknown;\n};\ntype AddCaptionTrackArgs = {\n lines?: unknown;\n mode?: unknown;\n style?: unknown;\n x?: unknown;\n y?: unknown;\n width?: unknown;\n height?: unknown;\n};\n\nexport const CAPTION_STYLE_PRESETS: Record<string, Record<string, unknown>> = {\n classic: {\n font_family: \"Hanken Grotesk\",\n font_weight: 800,\n text_color: \"#FFFFFF\",\n text_align: \"center\",\n text_shadow: { offsetX: 0, offsetY: 2, blur: 10, color: \"rgba(0,0,0,0.5)\" },\n },\n \"bold-outline\": {\n font_family: \"Anton\",\n text_color: \"#FFFFFF\",\n text_transform: \"uppercase\",\n text_align: \"center\",\n // A thin outline reads cleanly over busy footage; a heavy one (was 10px)\n // swallows the white fill and the text becomes unreadable.\n stroke_width: 4,\n stroke_color: \"#000000\",\n },\n \"word-pop\": {\n font_family: \"Anton\",\n text_color: \"#FF7A66\",\n text_transform: \"uppercase\",\n text_align: \"center\",\n stroke_width: 8,\n stroke_color: \"#FFFFFF\",\n },\n};\n\n// Shared marker prefix for caption layers (the editor's EnrichmentPanel checks\n// for it to flip \"Add captions\" → \"Captions added\").\nexport const CAPTION_LAYER_NAME = \"Captions\";\n\nconst addCaptionTrack: ToolDispatch<AddCaptionTrackArgs> = (project, args) => {\n if (!Array.isArray(args.lines) || args.lines.length === 0) {\n return {\n project,\n result: { ok: false, error: \"lines must be a non-empty array\" },\n };\n }\n const lines: { text: string; startFrame: number; endFrame: number }[] = [];\n for (const raw of args.lines as CaptionLineArg[]) {\n if (!raw || typeof raw !== \"object\") {\n return {\n project,\n result: { ok: false, error: \"each line must be an object\" },\n };\n }\n const text = typeof raw.text === \"string\" ? raw.text : \"\";\n if (text.trim().length === 0) continue;\n const startFrame =\n typeof raw.startFrame === \"number\" && Number.isFinite(raw.startFrame)\n ? Math.max(0, Math.round(raw.startFrame))\n : 0;\n const endRaw =\n typeof raw.endFrame === \"number\" && Number.isFinite(raw.endFrame)\n ? Math.round(raw.endFrame)\n : startFrame + 30;\n lines.push({ text, startFrame, endFrame: Math.max(startFrame + 1, endRaw) });\n }\n if (lines.length === 0) {\n return {\n project,\n result: { ok: false, error: \"no non-empty caption lines\" },\n };\n }\n\n const mode = args.mode === \"static\" ? \"static\" : \"line-sync\";\n const styleKey =\n typeof args.style === \"string\" && args.style in CAPTION_STYLE_PRESETS\n ? args.style\n : \"classic\";\n const stylePreset = CAPTION_STYLE_PRESETS[styleKey];\n\n const cw = project.canvas_width;\n const ch = project.canvas_height;\n const x = typeof args.x === \"number\" ? args.x : cw / 2;\n // Default the band so its BOTTOM sits at ~0.8·height (the lower-third spot a\n // single caption line used to occupy): with bottom valign below, a 1-line\n // caption stays put and a wrapped 2-line caption grows UPWARD instead of\n // shifting. y is the box centre, so centre = bottom − height/2.\n const height =\n typeof args.height === \"number\" ? args.height : Math.round(ch * 0.16);\n const y =\n typeof args.y === \"number\" ? args.y : Math.round(ch * 0.8 - height / 2);\n const width = typeof args.width === \"number\" ? args.width : Math.round(cw * 0.86);\n // Fixed caption text size + \"wrap\" autofit + \"bottom\" valign → every line is\n // the SAME height AND pinned to a fixed baseline. ~10% of canvas width pairs\n // with the short-chunk caption lines (≤~18 chars). \"wrap\" holds the size\n // fixed and word-wraps a long line onto a second line (hard-breaking a single\n // over-wide word) instead of shrinking it; \"bottom\" makes that extra line\n // grow upward so the caption never bounces size OR position line-to-line.\n const captionTextSize = Math.round(cw * 0.1);\n const baseTextArgs = {\n x,\n y,\n width,\n height,\n text_size: captionTextSize,\n text_autofit: \"wrap\",\n text_valign: \"bottom\",\n ...stylePreset,\n };\n\n let cur = project;\n const created: string[] = [];\n const setName = (proj: Project, elementId: string, name: string) => {\n const id = elementId.slice(\"text.\".length);\n const tl = proj.text_layers.find((t) => t.id === id);\n if (tl) tl.name = name;\n };\n\n if (mode === \"static\") {\n const out = addTextLayer(cur, {\n ...baseTextArgs,\n text: lines.map((l) => l.text).join(\"\\n\"),\n });\n if (!out.result.ok) return out;\n cur = out.project;\n const elementId = (out.result.data as { elementId: string }).elementId;\n setName(cur, elementId, CAPTION_LAYER_NAME);\n created.push(elementId);\n return {\n project: cur,\n result: { ok: true, data: { elementIds: created, count: 1, mode } },\n };\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const out = addTextLayer(cur, { ...baseTextArgs, text: line.text });\n if (!out.result.ok) return out;\n cur = out.project;\n const elementId = (out.result.data as { elementId: string }).elementId;\n setName(cur, elementId, `${CAPTION_LAYER_NAME} ${i + 1}`);\n created.push(elementId);\n // Hold-eased opacity: hidden until startFrame, on through the window, off\n // after. (hold easing holds the boundary value past each keyframe.)\n if (line.startFrame > 0) {\n upsertKeyframe(cur, elementId, \"opacity\", 0, 0, \"hold\");\n }\n upsertKeyframe(cur, elementId, \"opacity\", line.startFrame, 1, \"hold\");\n upsertKeyframe(cur, elementId, \"opacity\", line.endFrame, 0, \"hold\");\n }\n\n return {\n project: cur,\n result: { ok: true, data: { elementIds: created, count: created.length, mode } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// rename_layer\n// ---------------------------------------------------------------------------\n//\n// Sets (or clears) the human-readable `name` of a video / image / shape layer\n// — the label shown in the Inspector and the basis for the layer's auto-\n// derived <morpha-video> embed attribute. Symmetric with rename_group.\n// An empty name clears it (callers fall back to the filename stem).\n\ntype RenameLayerArgs = { elementId?: unknown; name?: unknown };\n\nconst renameLayer: ToolDispatch<RenameLayerArgs> = (project, args) => {\n const { elementId, name } = args;\n if (typeof elementId !== \"string\") {\n return { project, result: { ok: false, error: \"elementId is required\" } };\n }\n if (typeof name !== \"string\") {\n return { project, result: { ok: false, error: \"name must be a string\" } };\n }\n const next = cloneProject(project);\n const apply = (layer: { name?: string }): ToolOutcome => {\n if (name.trim().length === 0) delete layer.name;\n else layer.name = name;\n return { project: next, result: { ok: true, data: { elementId, name } } };\n };\n if (elementId.startsWith(\"image.\")) {\n const l = next.image_layers.find((x) => x.id === elementId.slice(6));\n if (!l) {\n return { project, result: { ok: false, error: `layer not found: ${elementId}` } };\n }\n return apply(l);\n }\n if (elementId.startsWith(\"video.\")) {\n const l = next.video_layers.find((x) => x.id === elementId.slice(6));\n if (!l) {\n return { project, result: { ok: false, error: `layer not found: ${elementId}` } };\n }\n return apply(l);\n }\n if (elementId.startsWith(\"shapes.\")) {\n const l = next.shapes.find((x) => x.id === elementId.slice(7));\n if (!l) {\n return { project, result: { ok: false, error: `layer not found: ${elementId}` } };\n }\n return apply(l);\n }\n if (elementId.startsWith(\"text.\")) {\n const l = next.text_layers.find((x) => x.id === elementId.slice(5));\n if (!l) {\n return { project, result: { ok: false, error: `layer not found: ${elementId}` } };\n }\n return apply(l);\n }\n return {\n project,\n result: {\n ok: false,\n error:\n \"elementId must be a video / image / shape / text layer — use rename_group for groups\",\n },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_loop\n// ---------------------------------------------------------------------------\n//\n// Builds the project's loop section as one pass per value. Each pass carries a\n// single override that sets `field` of `elementId` to that pass's value, so\n// the whole composition repeats once per value with that one field varying —\n// the common case being a caption text layer cycling through several strings.\n// `values: []` clears the loop (the comp plays once).\n\ntype SetLoopArgs = {\n elementId?: unknown;\n field?: unknown;\n values?: unknown;\n};\n\nconst setLoop: ToolDispatch<SetLoopArgs> = (project, args) => {\n const { elementId, field, values } = args;\n if (typeof elementId !== \"string\" || elementId.trim().length === 0) {\n return {\n project,\n result: { ok: false, error: \"elementId is required\" },\n };\n }\n if (!Array.isArray(values)) {\n return {\n project,\n result: { ok: false, error: \"values must be an array of strings\" },\n };\n }\n if (!values.every((v) => typeof v === \"string\")) {\n return {\n project,\n result: { ok: false, error: \"values must be an array of strings\" },\n };\n }\n const resolvedField =\n typeof field === \"string\" && field.trim().length > 0 ? field : \"text\";\n const loop: LoopPass[] = (values as string[]).map((value) => ({\n overrides: [{ elementId, field: resolvedField, value }],\n }));\n const next = cloneProject(project);\n next.loop = loop;\n return {\n project: next,\n result: { ok: true, data: { loop } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_canvas_size\n// ---------------------------------------------------------------------------\n//\n// Resize the composition canvas. Every layer's base rect, group pivots, and\n// x/y/width/height animation keyframes scale by the width/height ratio so the\n// composition keeps its proportions in the new frame. Mirrors the editor's\n// CanvasSizePill behaviour.\n\ntype SetCanvasSizeArgs = { width?: unknown; height?: unknown };\n\nconst setCanvasSize: ToolDispatch<SetCanvasSizeArgs> = (project, args) => {\n const { width, height } = args;\n const validDim = (n: unknown): n is number =>\n typeof n === \"number\" && Number.isInteger(n) && n > 0;\n if (!validDim(width) || !validDim(height)) {\n return {\n project,\n result: {\n ok: false,\n error: \"width and height must be positive integers (pixels)\",\n },\n };\n }\n if (project.canvas_width === width && project.canvas_height === height) {\n return {\n project,\n result: {\n ok: true,\n data: { canvas_width: width, canvas_height: height },\n },\n };\n }\n const sx = width / project.canvas_width;\n const sy = height / project.canvas_height;\n const next = cloneProject(project);\n next.canvas_width = width;\n next.canvas_height = height;\n const scaleRect = (r: {\n x: number;\n y: number;\n width: number;\n height: number;\n }): void => {\n r.x *= sx;\n r.y *= sy;\n r.width *= sx;\n r.height *= sy;\n };\n next.image_layers.forEach(scaleRect);\n next.video_layers.forEach(scaleRect);\n next.shapes.forEach(scaleRect);\n next.text_layers.forEach(scaleRect);\n for (const g of next.groups) {\n g.pivotX *= sx;\n g.pivotY *= sy;\n }\n // Scale every spatial track keyframe; scale/rotation/opacity stay put.\n for (const tracks of Object.values(next.animations)) {\n for (const prop of [\"x\", \"y\", \"width\", \"height\"] as const) {\n const kfs = tracks[prop];\n if (!kfs) continue;\n const factor = prop === \"x\" || prop === \"width\" ? sx : sy;\n for (const kf of kfs) kf.value *= factor;\n }\n }\n return {\n project: next,\n result: { ok: true, data: { canvas_width: width, canvas_height: height } },\n };\n};\n\n// ---------------------------------------------------------------------------\n// set_video_clip\n// ---------------------------------------------------------------------------\n//\n// Repoint an existing video layer at a different uploaded clip, keeping its\n// id, position, size, animations, styles, and trim window — only the source\n// mp4 changes. The clip must already exist at users/<userId>/clips/<projectId>/\n// <clip> (same precondition as add_video_layer); this dispatcher does not\n// verify it.\n\ntype SetVideoClipArgs = { elementId?: unknown; clip?: unknown };\n\nconst setVideoClip: ToolDispatch<SetVideoClipArgs> = (project, args) => {\n const { elementId, clip } = args;\n if (typeof elementId !== \"string\" || !elementId.startsWith(\"video.\")) {\n return {\n project,\n result: {\n ok: false,\n error: \"elementId must be a video layer id (video.<id>)\",\n },\n };\n }\n if (typeof clip !== \"string\" || clip.trim().length === 0) {\n return {\n project,\n result: { ok: false, error: \"clip must be a non-empty string\" },\n };\n }\n const id = elementId.slice(\"video.\".length);\n const next = cloneProject(project);\n const layer = next.video_layers.find((l) => l.id === id);\n if (!layer) {\n return {\n project,\n result: { ok: false, error: `video layer not found: ${elementId}` },\n };\n }\n layer.clip = clip;\n return { project: next, result: { ok: true, data: { elementId, clip } } };\n};\n\n// ---------------------------------------------------------------------------\n// set_image_filename\n// ---------------------------------------------------------------------------\n//\n// Repoint an existing image layer at a different uploaded asset, keeping its\n// id, position, size, animations, and styles — only the bitmap changes. The\n// asset must already exist at users/<userId>/assets/<projectId>/<filename>\n// (same precondition as add_image_layer); this dispatcher does not verify it.\n\ntype SetImageFilenameArgs = { elementId?: unknown; filename?: unknown };\n\nconst setImageFilename: ToolDispatch<SetImageFilenameArgs> = (project, args) => {\n const { elementId, filename } = args;\n if (typeof elementId !== \"string\" || !elementId.startsWith(\"image.\")) {\n return {\n project,\n result: {\n ok: false,\n error: \"elementId must be an image layer id (image.<id>)\",\n },\n };\n }\n if (typeof filename !== \"string\" || filename.trim().length === 0) {\n return {\n project,\n result: { ok: false, error: \"filename must be a non-empty string\" },\n };\n }\n const id = elementId.slice(\"image.\".length);\n const next = cloneProject(project);\n const layer = next.image_layers.find((l) => l.id === id);\n if (!layer) {\n return {\n project,\n result: { ok: false, error: `image layer not found: ${elementId}` },\n };\n }\n if (layer.is_background) {\n return {\n project,\n result: {\n ok: false,\n error: \"the canvas backdrop has no bitmap — use set_layer_fill\",\n },\n };\n }\n layer.filename = filename;\n return { project: next, result: { ok: true, data: { elementId, filename } } };\n};\n\n// ---------------------------------------------------------------------------\n// Catalog + dispatch table\n// ---------------------------------------------------------------------------\n\nexport const dispatch: Record<string, ToolDispatch<never>> = {\n describe_video: describeVideo as ToolDispatch<never>,\n inspect_layers: inspectLayers as ToolDispatch<never>,\n move_layer: moveLayer as ToolDispatch<never>,\n set_pivot: setPivot as ToolDispatch<never>,\n add_keyframe: addKeyframe as ToolDispatch<never>,\n add_keyframes: addKeyframes as ToolDispatch<never>,\n set_keyframes_batch: setKeyframesBatch as ToolDispatch<never>,\n remove_keyframe: removeKeyframe as ToolDispatch<never>,\n shift_track: shiftTrack as ToolDispatch<never>,\n set_track_loop: setTrackLoop as ToolDispatch<never>,\n add_image_layer: addImageLayer as ToolDispatch<never>,\n add_video_layer: addVideoLayer as ToolDispatch<never>,\n add_shape: addShape as ToolDispatch<never>,\n add_curve: addCurve as ToolDispatch<never>,\n duplicate_layer: duplicateLayer as ToolDispatch<never>,\n remove_layer: removeLayer as ToolDispatch<never>,\n reorder_layer: reorderLayer as ToolDispatch<never>,\n set_style: setStyle as ToolDispatch<never>,\n set_layer_fill: setLayerFill as ToolDispatch<never>,\n set_group_box: setGroupBox as ToolDispatch<never>,\n add_color_keyframe: addColorKeyframe as ToolDispatch<never>,\n remove_color_keyframe: removeColorKeyframe as ToolDispatch<never>,\n fade_layer: fadeLayer as ToolDispatch<never>,\n set_layer_visible: setLayerVisible as ToolDispatch<never>,\n apply_preset: applyPreset as ToolDispatch<never>,\n apply_preset_stagger: applyPresetStagger as ToolDispatch<never>,\n group_layers: groupLayers as ToolDispatch<never>,\n ungroup_layers: ungroupLayers as ToolDispatch<never>,\n set_group_parent: setGroupParent as ToolDispatch<never>,\n rename_group: renameGroup as ToolDispatch<never>,\n set_duration: setDuration as ToolDispatch<never>,\n add_audio_overlay: addAudioOverlay as ToolDispatch<never>,\n remove_audio_overlay: removeAudioOverlay as ToolDispatch<never>,\n update_audio_overlay: updateAudioOverlay as ToolDispatch<never>,\n set_video_layer_trim: setVideoLayerTrim as ToolDispatch<never>,\n set_embed_origins: setEmbedOrigins as ToolDispatch<never>,\n add_embed_origin: addEmbedOrigin as ToolDispatch<never>,\n remove_embed_origin: removeEmbedOrigin as ToolDispatch<never>,\n set_custom_font: setCustomFont as ToolDispatch<never>,\n list_fonts: listFonts as ToolDispatch<never>,\n set_layer_text: setLayerText as ToolDispatch<never>,\n add_text_layer: addTextLayer as ToolDispatch<never>,\n add_caption_track: addCaptionTrack as ToolDispatch<never>,\n rename_layer: renameLayer as ToolDispatch<never>,\n set_loop: setLoop as ToolDispatch<never>,\n set_canvas_size: setCanvasSize as ToolDispatch<never>,\n set_image_filename: setImageFilename as ToolDispatch<never>,\n set_video_clip: setVideoClip as ToolDispatch<never>,\n set_matte_source: setMatteSource as ToolDispatch<never>,\n add_speed_keyframe: addSpeedKeyframe as ToolDispatch<never>,\n remove_speed_keyframe: removeSpeedKeyframe as ToolDispatch<never>,\n};\n\nexport const TOOL_DEFINITIONS: ToolFunction[] = [\n {\n type: \"function\",\n function: {\n name: \"describe_video\",\n description:\n \"Structural OVERVIEW of the composition (the table of contents) — canvas size, duration, the backdrop summary, and a z-ordered tree (top of stack first) of every layer with its elementId, type, name, type label (filename/clip/text/kind), geometry (x/y/width/height), and which properties are animated. Does NOT include keyframe values or styles — those are unbounded. Start here, then call inspect_layers([elementId, …]) for full detail on the specific layers you'll change. Don't guess keyframe/style values from this overview.\",\n parameters: { type: \"object\", properties: {} },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"inspect_layers\",\n description:\n \"Full per-element drill-in — the 'open this layer' half of the browser. Returns each named element's COMPLETE record: all of its own fields plus its animation tracks (every keyframe), colour/fill tracks, track-loop (extrapolation) modes, and style. Pass the elementIds you read from describe_video; pull detail only for the handful of layers you're about to mutate, not the whole project.\",\n parameters: {\n type: \"object\",\n properties: {\n elementIds: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Element ids to inspect (image.<id>, video.<id>, text.<id>, shapes.<id>, group.<id>). Read them from describe_video's tree.\",\n },\n },\n required: [\"elementIds\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"move_layer\",\n description:\n \"Set static position/size/rotation of a layer. Writes x/y/w/h/rotation directly on image.<id>, video.<id>, and shapes.<id>; for group.<id> sets pivotX/pivotY (no width/height/rotation — use add_keyframe for group rotation). Note: when a layer has an x / y / rotation keyframe track, the track OVERRIDES the static value at every frame with a keyframe — use add_keyframe to animate, move_layer to set the un-animated default.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"video.<id>, image.<id>, shapes.<id>, or group.<id>.\",\n },\n x: { type: \"number\", description: \"Centre x in 1080-wide base coords.\" },\n y: { type: \"number\", description: \"Centre y in 1920-tall base coords.\" },\n width: { type: \"number\", description: \"Width in px (must be > 0).\" },\n height: { type: \"number\", description: \"Height in px (must be > 0).\" },\n rotation: { type: \"number\", description: \"Rotation in degrees, clockwise.\" },\n },\n required: [\"elementId\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_pivot\",\n description:\n \"Set the rotation / scale pivot anchor for an image, video, shape, or text leaf. Picks one of the 9 standard bbox anchors — corners, edge midpoints, or centre — so the layer rotates and scales around that point instead of its centre. The pivot is normalized to the bbox, so resizing the layer keeps the pivot anchored to the same corner / edge / centre. Static (not animated). For groups, use move_layer with x/y to set the group's absolute pivotX/pivotY instead.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"image.<id>, video.<id>, shapes.<id>, or text.<id>.\",\n },\n anchor: {\n type: \"string\",\n enum: [\"tl\", \"t\", \"tr\", \"l\", \"c\", \"r\", \"bl\", \"b\", \"br\"],\n description:\n \"Which of the 9 bbox anchors to pivot around. tl/t/tr = top row; l/c/r = middle row; bl/b/br = bottom row. c = centre (the default).\",\n },\n },\n required: [\"elementId\", \"anchor\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_keyframe\",\n description:\n \"Add or overwrite a keyframe on a layer's animation track. For leaves (image/video/shape), x/y/rotation keyframes are ABSOLUTE canvas-space values: x and y are the layer centre's pixel position (canvas is 1080×1920), rotation is degrees. For groups, x/y keyframes are translation offsets applied around the group's frozen pivot, and rotation is the group's absolute angle. scale orbits the layer/pivot centre (1 = no change). opacity is 0..1. 30 fps. When a keyframe track is present on a property, it OVERRIDES the layer's static base value at every frame.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\", description: \"Layer id (video.<id>, image.<id>, shapes.<id>, or group.<id>).\" },\n property: {\n type: \"string\",\n enum: [\"x\", \"y\", \"width\", \"height\", \"scale\", \"rotation\", \"opacity\"],\n },\n frame: {\n type: \"number\",\n description: \"Frame number, 0-indexed. 30 fps so frame 30 = 1 second.\",\n },\n value: { type: \"number\", description: \"Track value at this frame.\" },\n easing: {\n type: \"string\",\n enum: VALID_EASINGS,\n description: \"Interpolation to the next keyframe. Default linear.\",\n },\n },\n required: [\"elementId\", \"property\", \"frame\", \"value\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_keyframes_batch\",\n description:\n \"Add or overwrite MANY keyframes across MANY layers in ONE call — functionally equivalent to N add_keyframe calls but with one HTTP/MCP round-trip. Pass an array of entries; each entry has the same fields as add_keyframe. Validated atomically: any invalid entry rejects the whole batch. Use this whenever you'd call add_keyframe more than a couple of times (rippling grids, twinkling starfields, staggered text reveals).\",\n parameters: {\n type: \"object\",\n properties: {\n keyframes: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description:\n \"Layer id (video.<id>, image.<id>, shapes.<id>, text.<id>, or group.<id>).\",\n },\n property: {\n type: \"string\",\n enum: [\"x\", \"y\", \"width\", \"height\", \"scale\", \"rotation\", \"opacity\"],\n },\n frame: {\n type: \"number\",\n description: \"Frame number, 0-indexed (30 fps).\",\n },\n value: { type: \"number\", description: \"Track value at this frame.\" },\n easing: {\n type: \"string\",\n enum: VALID_EASINGS,\n description: \"Interpolation to the next keyframe. Default linear.\",\n },\n },\n required: [\"elementId\", \"property\", \"frame\", \"value\"],\n },\n description: \"One or more keyframe entries to apply.\",\n },\n },\n required: [\"keyframes\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_keyframes\",\n description:\n \"Add many keyframes to ONE element's ONE property in a single call, with an optional loop mode applied in the same call. The idiomatic form when every layer in a multi-element animation gets its own track (ripple dot pulse, snowflake fall, equaliser-bar wave). Factors elementId + property out of the loop body and folds set_track_loop in. Use set_keyframes_batch instead when you need to mix elements/properties in one atomic call.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description:\n \"Layer id (video.<id>, image.<id>, shapes.<id>, text.<id>, or group.<id>).\",\n },\n property: {\n type: \"string\",\n enum: [\"x\", \"y\", \"width\", \"height\", \"scale\", \"rotation\", \"opacity\"],\n },\n keyframes: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n frame: { type: \"number\", description: \"Frame number, 0-indexed (30 fps).\" },\n value: { type: \"number\", description: \"Track value at this frame.\" },\n easing: {\n type: \"string\",\n enum: VALID_EASINGS,\n description: \"Interpolation to the next keyframe. Default linear.\",\n },\n },\n required: [\"frame\", \"value\"],\n },\n description: \"Keyframes for this track (one or more).\",\n },\n loop: {\n type: \"string\",\n enum: VALID_LOOP_MODES,\n description:\n \"Optional extrapolation mode applied to this track in the same call. Default 'hold'.\",\n },\n },\n required: [\"elementId\", \"property\", \"keyframes\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"remove_keyframe\",\n description: \"Remove the keyframe at frame N on a layer's track. Removing the last keyframe from a track restores the layer's static base value across the timeline.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\" },\n property: {\n type: \"string\",\n enum: [\"x\", \"y\", \"width\", \"height\", \"scale\", \"rotation\", \"opacity\"],\n },\n frame: { type: \"number\" },\n },\n required: [\"elementId\", \"property\", \"frame\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"shift_track\",\n description:\n \"Bulk-shift every keyframe's VALUE on one property of one layer by `delta`. Mirrors the 'select all keyframes + nudge layer' gesture in After Effects / Premiere / FCP — preserves the relative spacing of the animation but slides the whole curve. Keyframe TIMES are untouched. Use for 'move all x by -30px' on a complex animation, retiming a fade by adjusting its base opacity, rotating an existing wobble by 10°, etc.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\" },\n property: {\n type: \"string\",\n enum: [\"x\", \"y\", \"width\", \"height\", \"scale\", \"rotation\", \"opacity\"],\n },\n delta: {\n type: \"number\",\n description: \"Added to every keyframe's value on this track. Negative shifts the curve down/left.\",\n },\n },\n required: [\"elementId\", \"property\", \"delta\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_track_loop\",\n description:\n \"Set the extrapolation mode for one property's animation track. Modes: \\\"hold\\\" (default — holds the boundary keyframe's value past the ends), \\\"loop\\\" (wraps frames past the last keyframe back to the first, restarting the animation), \\\"ping-pong\\\" (alternates direction each cycle, bouncing back and forth), \\\"cycle\\\" (wraps like loop but each cycle adds the boundary delta — used for endless rotation or scrolling). Has no effect on tracks with fewer than 2 keyframes.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\", description: \"Layer id (video/image/shape/group).\" },\n property: {\n type: \"string\",\n enum: [\"x\", \"y\", \"width\", \"height\", \"scale\", \"rotation\", \"opacity\"],\n },\n mode: {\n type: \"string\",\n enum: [\"hold\", \"loop\", \"ping-pong\", \"cycle\"],\n },\n },\n required: [\"elementId\", \"property\", \"mode\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_image_layer\",\n description:\n \"Add an image layer. The asset must already exist at users/<userId>/assets/<projectId>/<filename> (uploaded via the editor's drag-drop or /api/upload-asset). To duplicate an existing layer, reuse its filename — the editor auto-assigns a fresh id.\",\n parameters: {\n type: \"object\",\n properties: {\n filename: { type: \"string\", description: \"Asset filename in the project's assets bucket, e.g. star.png.\" },\n x: { type: \"number\", description: \"Centre x in 1080-wide base coords.\" },\n y: { type: \"number\", description: \"Centre y in 1920-tall base coords.\" },\n width: { type: \"number\", description: \"Width in px (must be > 0).\" },\n height: { type: \"number\", description: \"Height in px (must be > 0).\" },\n },\n required: [\"filename\", \"x\", \"y\", \"width\", \"height\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_video_layer\",\n description:\n \"Add a video layer. The clip must already exist at users/<userId>/clips/<projectId>/<clip> (uploaded via /api/upload-clip). To duplicate an existing layer, reuse its clip filename — the editor auto-assigns a fresh id.\",\n parameters: {\n type: \"object\",\n properties: {\n clip: { type: \"string\", description: \"Clip filename in the project's clips bucket, e.g. demo.mp4.\" },\n x: { type: \"number\", description: \"Centre x in 1080-wide base coords.\" },\n y: { type: \"number\", description: \"Centre y in 1920-tall base coords.\" },\n width: { type: \"number\", description: \"Width in px (must be > 0).\" },\n height: { type: \"number\", description: \"Height in px (must be > 0).\" },\n name: { type: \"string\", description: \"Optional friendly label shown in the Inspector + Timeline.\" },\n },\n required: [\"clip\", \"x\", \"y\", \"width\", \"height\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_shape\",\n description: `Add a shape layer. \\`kind\\` selects the primitive: ${SHAPE_DEFS.map(\n (d) => d.id,\n ).join(\n \" | \",\n )}. All are native vector shapes; never substitute an image layer for one. Default-positioned in canvas centre if x/y/w/h omitted.`,\n parameters: {\n type: \"object\",\n properties: {\n kind: {\n type: \"string\",\n enum: [...SHAPE_IDS],\n },\n x: { type: \"number\" },\n y: { type: \"number\" },\n width: { type: \"number\" },\n height: { type: \"number\" },\n color: { type: \"string\", description: \"Fill colour as #rrggbb.\" },\n },\n required: [\"kind\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_curve\",\n description:\n \"Draw an editable arrow / curved line — a stroked quadratic bezier with an arrowhead. Specify the two endpoints (x1,y1)→(x2,y2) in canvas pixels; `bend` pushes the midpoint perpendicular (px, 0 = straight line, positive/negative curves either way). `color` #rrggbb, `stroke_width` px, `arrow_head` none|end|both (default end). Use this for callout arrows (e.g. swooping into a link).\",\n parameters: {\n type: \"object\",\n properties: {\n x1: { type: \"number\", description: \"Start x (canvas px).\" },\n y1: { type: \"number\", description: \"Start y (canvas px).\" },\n x2: { type: \"number\", description: \"End x (canvas px) — the arrowhead end.\" },\n y2: { type: \"number\", description: \"End y (canvas px).\" },\n bend: {\n type: \"number\",\n description: \"Perpendicular bow of the curve in px. 0 = straight.\",\n },\n color: { type: \"string\", description: \"Stroke colour as #rrggbb.\" },\n stroke_width: { type: \"number\", description: \"Line thickness in px.\" },\n arrow_head: { type: \"string\", enum: [\"none\", \"end\", \"both\"] },\n },\n required: [\"x1\", \"y1\", \"x2\", \"y2\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"duplicate_layer\",\n description:\n \"Composition primitive: clone a leaf (image.<id> / video.<id> / shapes.<id> / text.<id>) `count` times, applying a cumulative per-step transform — copy i is offset by i·(dx,dy) px, rotated by i·d_rotation°, and scaled by d_scale^i. One call instead of dozens: a circle of stars (dx/dy + d_rotation), a row of chevrons (dx), a fractal (d_scale<1 + d_rotation), a staggered grid. Styles are copied; animate the result afterwards (e.g. group + a cycle-loop track for endless marching).\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\", description: \"Leaf to clone (e.g. shapes.chevron-1).\" },\n count: { type: \"number\", description: \"Number of copies to create.\" },\n dx: { type: \"number\", description: \"Per-step x offset in px.\" },\n dy: { type: \"number\", description: \"Per-step y offset in px.\" },\n d_rotation: { type: \"number\", description: \"Per-step rotation in degrees.\" },\n d_scale: { type: \"number\", description: \"Per-step size multiplier (1 = no change).\" },\n },\n required: [\"elementId\", \"count\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"remove_layer\",\n description: \"Delete a video, image, or shape layer.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\", description: \"image.<id> or shapes.<id>.\" },\n },\n required: [\"elementId\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"reorder_layer\",\n description:\n \"Move a layer within its parent's siblings. newIndex is 0-based among siblings (root list when ungrouped, or the parent group's children when nested). 0 = bottom of that subtree; last = top.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\" },\n newIndex: { type: \"number\", description: \"0-based index among siblings of the same parent.\" },\n },\n required: [\"elementId\", \"newIndex\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_style\",\n description:\n \"Set style fields on a layer. Only the fields you pass are changed; omit a field to leave it untouched. Covers border/radius/shadow plus image-only fields: fit (stretch|cover|contain), anchorX/anchorY (0..1, where the source anchors when cropping/letterboxing under cover/contain), tintColor (#rrggbb) + tintStrength (0..1) for a colour overlay painted source-atop, and alphaMask (linear gradient — see below) for a multiplicative alpha fade across the layer.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\" },\n borderRadius: { type: \"number\" },\n borderWidth: { type: \"number\" },\n borderColor: { type: \"string\", description: \"#rrggbb.\" },\n boxShadow: {\n type: [\"string\", \"null\"],\n description:\n \"CSS box-shadow string, e.g. \\\"0 4px 12px rgba(0,0,0,0.5)\\\". Pass an empty string \\\"\\\" or null to REMOVE the shadow.\",\n },\n fit: {\n type: \"string\",\n enum: [\"stretch\", \"cover\", \"contain\"],\n description:\n \"Fit mode (image + video layers). Default: stretch for image layers, cover for video layers.\",\n },\n anchorX: {\n type: \"number\",\n description:\n \"Object-position X (0..1). 0=left, 1=right, 0.5=centre. Only meaningful with fit=cover|contain.\",\n },\n anchorY: {\n type: \"number\",\n description:\n \"Object-position Y (0..1). 0=top, 1=bottom, 0.5=centre. Only meaningful with fit=cover|contain.\",\n },\n tintColor: {\n type: \"string\",\n description:\n \"#rrggbb tint colour painted source-atop over the image (image layers only).\",\n },\n tintStrength: {\n type: \"number\",\n description:\n \"Tint blend strength 0..1. 0=no tint, 1=image silhouette filled with tintColor. Default 0 (no tint).\",\n },\n alphaMask: {\n description:\n \"Linear alpha-mask gradient (image layers). Multiplies the layer's alpha along a gradient line — used to fade a layer out partway across (the front half of a 'sandwich' covering text below it). Object: { type: 'linear', angle: number (deg, CSS-style; 0=to top, 90=to right, 180=to bottom, 270=to left), stops: [{offset:0..1, alpha:0..1}, ...] (≥2 stops, ordered by offset) }. Pass null to clear.\",\n oneOf: [\n { type: \"null\" },\n {\n type: \"object\",\n properties: {\n type: { type: \"string\", enum: [\"linear\"] },\n angle: { type: \"number\" },\n stops: {\n type: \"array\",\n minItems: 2,\n items: {\n type: \"object\",\n properties: {\n offset: { type: \"number\", minimum: 0, maximum: 1 },\n alpha: { type: \"number\", minimum: 0, maximum: 1 },\n },\n required: [\"offset\", \"alpha\"],\n },\n },\n },\n required: [\"stops\"],\n },\n ],\n },\n chroma_key: {\n description:\n \"Green-screen key (video / image layers). Makes pixels near `color` transparent at render time so layers below show through. Object: { color: '#rrggbb' (default '#00ff00'), similarity: 0..1 (match radius, default 0.4), smoothness: 0..1 (edge feather, default 0.1) }. Pass null to clear.\",\n oneOf: [\n { type: \"null\" },\n {\n type: \"object\",\n properties: {\n color: { type: \"string\" },\n similarity: { type: \"number\", minimum: 0, maximum: 1 },\n smoothness: { type: \"number\", minimum: 0, maximum: 1 },\n },\n },\n ],\n },\n blend_mode: {\n type: \"string\",\n enum: [\n \"normal\",\n \"multiply\",\n \"screen\",\n \"overlay\",\n \"darken\",\n \"lighten\",\n \"color-dodge\",\n \"color-burn\",\n \"hard-light\",\n \"soft-light\",\n \"difference\",\n \"exclusion\",\n \"hue\",\n \"saturation\",\n \"color\",\n \"luminosity\",\n ],\n description:\n \"Photoshop-style layer blend mode (Canvas globalCompositeOperation). 'normal' is the default. Applies to every layer kind; allowed on group.<id> too (the only set_style field that is).\",\n },\n },\n required: [\"elementId\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_layer_fill\",\n description:\n \"Set a layer's fill. The canvas backdrop is the pinned is_background image_layer (its element id is exposed via describe_video as background.elementId; the literal 'background.canvas' is also accepted as a synonym); null is rejected on the backdrop. Shapes require a Fill (null/missing is rejected). Image / video / group layers accept a Fill object (or `#rrggbb` hex) to paint a backdrop, or `null` to clear it. Shapes paint their body; image/video paint behind the bitmap; groups paint a rect centred on the pivot sized by (box_width, box_height).\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"shapes.<id> / image.<id> / video.<id> / group.<id>. The pinned is_background image_layer is the canvas backdrop; the literal 'background.canvas' is accepted as a synonym.\",\n },\n fill: {\n description:\n \"Either '#rrggbb' (promoted to solid), a Fill object (solid | linear | radial | mask), or null (image/video/group only — clears the backdrop).\",\n },\n },\n required: [\"elementId\", \"fill\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_group_box\",\n description:\n \"Set a group's backdrop rect size. The rect is centred on (pivotX, pivotY) in group-local space and transforms with the group. Either dimension at 0 hides the backdrop entirely.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\", description: \"group.<id>.\" },\n box_width: {\n type: \"number\",\n description: \"Backdrop width in px (non-negative).\",\n },\n box_height: {\n type: \"number\",\n description: \"Backdrop height in px (non-negative).\",\n },\n },\n required: [\"elementId\", \"box_width\", \"box_height\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_color_keyframe\",\n description:\n \"Add or overwrite a colour keyframe on a fill track. Targets a leaf (shapes.<id>, image.<id>, video.<id>, group.<id>). The canvas backdrop is the pinned is_background image_layer (the literal 'background.canvas' is accepted as a synonym for its element id). The value is a Fill — adjacent keyframes crossfade stop-by-stop. 30 fps; frame is 0-indexed.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description:\n \"Element id (shapes/image/video/group prefixed). The pinned is_background image_layer is the canvas backdrop; 'background.canvas' is also accepted as a synonym.\",\n },\n property: {\n type: \"string\",\n enum: [\"fill\"],\n description: \"Currently only 'fill' is supported.\",\n },\n frame: {\n type: \"number\",\n description: \"Frame number, 0-indexed. 30 fps so frame 30 = 1 second.\",\n },\n value: {\n description:\n \"Either '#rrggbb' (promoted to solid) or a Fill object (solid | linear | radial | mask).\",\n },\n easing: {\n type: \"string\",\n enum: VALID_EASINGS,\n description: \"Interpolation to the next keyframe. Default linear.\",\n },\n },\n required: [\"elementId\", \"property\", \"frame\", \"value\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"remove_color_keyframe\",\n description:\n \"Remove the colour keyframe at an exact frame on a fill track. No-op when no track or no matching keyframe exists. Removing the last keyframe drops the track entry.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"Element id. The canvas backdrop is the pinned is_background image_layer; 'background.canvas' is accepted as a synonym.\",\n },\n property: {\n type: \"string\",\n enum: [\"fill\"],\n },\n frame: { type: \"number\" },\n },\n required: [\"elementId\", \"property\", \"frame\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_duration\",\n description:\n \"Set the project's first-class composition duration in seconds. This drives the timeline length and the export length — not the source mp4. Clamped to [1, 600] seconds.\",\n parameters: {\n type: \"object\",\n properties: {\n seconds: {\n type: \"number\",\n description: \"Composition duration in seconds. Clamped to [1, 600].\",\n },\n },\n required: [\"seconds\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"fade_layer\",\n description:\n \"Fade a layer's opacity between two frames in one call.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\" },\n fromFrame: { type: \"number\" },\n toFrame: { type: \"number\" },\n fromOpacity: { type: \"number\", description: \"0..1.\" },\n toOpacity: { type: \"number\", description: \"0..1.\" },\n },\n required: [\"elementId\", \"fromFrame\", \"toFrame\", \"fromOpacity\", \"toOpacity\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_layer_visible\",\n description:\n \"Show or hide a layer instantly by writing a single opacity keyframe (1 or 0) at frame 0.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\" },\n visible: { type: \"boolean\" },\n },\n required: [\"elementId\", \"visible\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"apply_preset\",\n description:\n \"Apply a canned animation preset to a layer.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\" },\n preset: { type: \"string\", enum: VALID_PRESETS },\n startFrame: { type: \"number\", description: \"Frame to anchor on. Default 0.\" },\n },\n required: [\"elementId\", \"preset\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"apply_preset_stagger\",\n description:\n \"Apply the same preset to a LIST of layers with a per-element startFrame offset — one call instead of N apply_preset calls. For diagonal pop-in grids, sequential list reveals, ring-pulse sweeps. The startFrame for entry i is `startFrame + i * stagger`. Order the elementIds in the visual order you want the animation to cascade.\",\n parameters: {\n type: \"object\",\n properties: {\n elementIds: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Layers to animate, ordered as the cascade should fire (first id gets startFrame; each next gets +stagger frames).\",\n },\n preset: { type: \"string\", enum: VALID_PRESETS },\n startFrame: {\n type: \"number\",\n description: \"Base frame for the first element. Default 0.\",\n },\n stagger: {\n type: \"number\",\n description: \"Frames between successive elements. Default 1.\",\n },\n },\n required: [\"elementIds\", \"preset\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"group_layers\",\n description:\n \"Wrap sibling elements in a new group. The group composes its x/y/scale/rotation/opacity onto its descendants and pivots rotate/scale at its (pivotX, pivotY), seeded to the centroid of its children at create time. The group's x/y track values are translation offsets applied around the pivot — groups have no static body of their own. All listed elementIds must currently share the same parent (root, or one existing group).\",\n parameters: {\n type: \"object\",\n properties: {\n elementIds: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Element ids of the elements to wrap. Must all share the same parent.\",\n },\n name: { type: \"string\", description: \"Optional human-readable label.\" },\n },\n required: [\"elementIds\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"ungroup_layers\",\n description:\n \"Dissolve a group: its children are spliced into the group's parent at the group's old position. The group's animation tracks are discarded — children survive at their last positions but inherit none of the group's keyframes.\",\n parameters: {\n type: \"object\",\n properties: {\n groupId: {\n type: \"string\",\n description: \"Bare group id (no 'group.' prefix), e.g. \\\"header\\\" for group.header.\",\n },\n },\n required: [\"groupId\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_group_parent\",\n description:\n \"Move an element into a group (or out to root). Refuses to place a group inside its own descendants.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"Full element id: video.<id>, image.<id>, shapes.<id>, or group.<id>.\",\n },\n parentGroupId: {\n type: [\"string\", \"null\"],\n description: \"Bare group id of the new parent, or null to move to root.\",\n },\n index: {\n type: \"number\",\n description: \"0-based insert position among the new parent's children. Defaults to end.\",\n },\n },\n required: [\"elementId\", \"parentGroupId\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"rename_group\",\n description: \"Rename a group. Pure cosmetic — labels appear in the Inspector and describe_video output.\",\n parameters: {\n type: \"object\",\n properties: {\n groupId: { type: \"string\" },\n name: { type: \"string\" },\n },\n required: [\"groupId\", \"name\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_audio_overlay\",\n description:\n \"Add an audio overlay (mp3/m4a/wav/ogg) scheduled at a frame-aligned start. The asset must already exist at users/<userId>/assets/<projectId>/<filename>. 30 fps; convert seconds with frames = round(s * 30). Plays in the editor preview and is mixed into the MP4 export.\",\n parameters: {\n type: \"object\",\n properties: {\n filename: {\n type: \"string\",\n description: \"Audio asset filename in the project's assets bucket.\",\n },\n startFrame: {\n type: \"number\",\n description: \"Frame at which the overlay starts (0-indexed, 30 fps).\",\n },\n gain: {\n type: \"number\",\n description: \"Linear gain 0..2. Default 1.\",\n },\n fadeInFrames: {\n type: \"number\",\n description: \"Linear fade-in length in frames. Default 0.\",\n },\n fadeOutFrames: {\n type: \"number\",\n description: \"Linear fade-out length in frames. Default 0.\",\n },\n endFrame: {\n type: \"number\",\n description:\n \"Optional end frame; omit to play the asset's full natural length from startFrame.\",\n },\n },\n required: [\"filename\", \"startFrame\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"remove_audio_overlay\",\n description: \"Delete an audio overlay by id.\",\n parameters: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"Overlay id (e.g. audio_1).\" },\n },\n required: [\"id\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"update_audio_overlay\",\n description:\n \"Patch an existing audio overlay. Only the fields you pass are changed. Pass endFrame:null to clear it (revert to natural-length playback).\",\n parameters: {\n type: \"object\",\n properties: {\n id: { type: \"string\" },\n filename: { type: \"string\" },\n startFrame: { type: \"number\" },\n gain: { type: \"number\", description: \"Linear gain 0..2.\" },\n fadeInFrames: { type: \"number\" },\n fadeOutFrames: { type: \"number\" },\n endFrame: {\n type: [\"number\", \"null\"],\n description: \"End frame, or null to clear and use the asset's natural length.\",\n },\n },\n required: [\"id\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_video_layer_trim\",\n description:\n \"Patch a video layer's trim window: source_in_frame (frame in source to start), source_out_frame (frame in source to stop, or null for natural end), timeline_start_frame (where on the project timeline the slice begins). Only the fields you pass are changed. Use this to clip out a segment of a source mp4: duplicate the layer first (in the editor) so you have two pointing at the same clip, then set disjoint source windows.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"video.<id> of the layer to trim.\",\n },\n source_in_frame: {\n type: \"number\",\n description: \"Frame in the source mp4 where playback begins (0-indexed, 30 fps).\",\n },\n source_out_frame: {\n type: [\"number\", \"null\"],\n description:\n \"Frame in the source mp4 where playback stops, or null to clear and play to the source's natural end.\",\n },\n timeline_start_frame: {\n type: \"number\",\n description: \"Project-timeline frame where this slice begins playing.\",\n },\n },\n required: [\"elementId\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_embed_origins\",\n description:\n \"Replace the project's embed allowlist — the hostnames permitted to load this project through the public <morpha-video> embed. Pass the full desired list; it overwrites the previous one. An empty array turns embedding OFF (the public embed endpoint 404s the project). Each entry is normalized to a bare lowercased hostname (scheme, port, and path stripped, e.g. \\\"https://example.com/x\\\" → \\\"example.com\\\"); duplicates are dropped.\",\n parameters: {\n type: \"object\",\n properties: {\n origins: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Full desired allowlist. Each entry may be a bare hostname or a URL; it is normalized to a bare lowercased hostname. Empty array disables embedding.\",\n },\n },\n required: [\"origins\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_embed_origin\",\n description:\n \"Add one hostname to the project's embed allowlist (the hostnames permitted to load the public <morpha-video> embed). Idempotent — re-adding an existing entry is a no-op. The origin is normalized to a bare lowercased hostname (scheme/port/path stripped).\",\n parameters: {\n type: \"object\",\n properties: {\n origin: {\n type: \"string\",\n description:\n \"Hostname or URL to allow, e.g. \\\"example.com\\\" or \\\"https://example.com\\\". Normalized to a bare lowercased hostname.\",\n },\n },\n required: [\"origin\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"remove_embed_origin\",\n description:\n \"Remove one hostname from the project's embed allowlist. Idempotent — removing an entry that isn't present is a no-op. Removing the last entry turns embedding OFF (the public embed endpoint 404s the project).\",\n parameters: {\n type: \"object\",\n properties: {\n origin: {\n type: \"string\",\n description:\n \"Hostname or URL to remove. Normalized the same way as add_embed_origin before matching.\",\n },\n },\n required: [\"origin\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_custom_font\",\n description:\n \"Register a custom (non-Google) typeface on the project so text layers can use it by family name via font_family (exactly like a Google family). `src` is EITHER a full URL (https://…) OR a font file already uploaded to the project's asset bucket (/api/upload-asset; .woff2/.woff/.ttf/.otf). Like add_image_layer, this does NOT verify an uploaded filename exists. Dedupes by family+weight+style, replacing a matching face. After registering, set a text layer's font_family to this family (add_text_layer / set_layer_text). NOTE: a pasted URL only loads if that host sends permissive CORS headers — uploading the font (served same-origin) is the robust path.\",\n parameters: {\n type: \"object\",\n properties: {\n family: {\n type: \"string\",\n description:\n \"Family name text layers will reference via font_family, e.g. \\\"Mylius Modern\\\".\",\n },\n src: {\n type: \"string\",\n description:\n \"A full font URL (https://…/font.woff2) OR an uploaded asset filename in the project's bucket.\",\n },\n weight: {\n type: \"number\",\n description:\n \"Optional specific weight (1-1000) this src provides. Omit for the 400/normal baseline.\",\n },\n style: {\n type: \"string\",\n enum: [\"normal\", \"italic\"],\n description: \"Optional face style. Defaults to normal.\",\n },\n },\n required: [\"family\", \"src\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"list_fonts\",\n description:\n \"List available font families across every source the editor knows about (Google + Bunny + Fontshare + Fontsource + Velvetyne) PLUS the project's user-uploaded custom_fonts (surfaced as source: \\\"custom\\\"). Use this to discover families before set_layer_text / add_text_layer when you don't know what to pick. Returns { fonts: [{family, source, weights, italics}], total, returned, sources }. Filter via `q` (case-insensitive substring on family) and/or `source`; cap with `limit` (default 50, max 1000). Picking any returned family in font_family Just Works — the editor's loader dispatches to the right CSS/FontFace endpoint by source.\",\n parameters: {\n type: \"object\",\n properties: {\n q: {\n type: \"string\",\n description:\n \"Case-insensitive substring filter on family name. Omit to list everything.\",\n },\n source: {\n type: \"string\",\n enum: [\"google\", \"bunny\", \"fontshare\", \"fontsource\", \"velvetyne\", \"custom\"],\n description:\n \"Restrict to one source. Omit to span every source. \\\"custom\\\" returns only the project's uploaded faces.\",\n },\n limit: {\n type: \"number\",\n description: \"Max entries to return (default 50, max 1000).\",\n },\n },\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_layer_text\",\n description:\n \"Edit an existing text layer (text.<id>). Patches its text content, font, size, colour, and full type styling — pass only the fields you want to change. Does NOT create layers and does NOT touch image layers; use add_text_layer to make a new one. `font_family` is a Google Fonts family name (e.g. \\\"Anton\\\", \\\"Bebas Neue\\\"). `text_size` is the font size in px (omit to keep the current size). `text_color` is #rrggbb. Styling: font_weight (100-900, e.g. 800 for a black/heavy logo look), font_style (italic), text_transform (uppercase/lowercase), letter_spacing (px, may be negative for tight tracking), line_height (multiplier), text_align, text_autofit (\\\"shrink\\\"=auto-shrink to fit, \\\"wrap\\\"=fixed size + word-wrap), text_valign (top/middle/bottom block alignment), an outline via stroke_width + stroke_color, and a text_shadow. To make text MASK another layer (video/image-filled letterforms) use set_matte_source with this layer's id as the matte source. Only `elementId` is required.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"Text layer id, text.<id>.\",\n },\n text: {\n type: \"string\",\n description: \"The text to render. Newlines are honoured as hard line breaks.\",\n },\n text_size: {\n type: \"number\",\n description: \"Font size in px.\",\n },\n font_family: {\n type: \"string\",\n description: \"Google Fonts family name, e.g. \\\"Anton\\\".\",\n },\n text_color: {\n type: \"string\",\n description: \"Text fill colour as #rrggbb.\",\n },\n font_weight: {\n type: \"number\",\n description: \"Font weight 100..900 (400 regular, 700 bold, 800 black). Default 400; the canvas synthesizes weights a static font doesn't ship.\",\n },\n font_style: {\n type: \"string\",\n enum: [\"normal\", \"italic\"],\n description: \"Italic toggle. Default normal.\",\n },\n text_transform: {\n type: \"string\",\n enum: [\"none\", \"uppercase\", \"lowercase\"],\n description: \"Case transform applied before layout. Default none.\",\n },\n letter_spacing: {\n type: \"number\",\n description: \"Tracking between glyphs in px; may be negative. Default 0.\",\n },\n line_height: {\n type: \"number\",\n description: \"Line height as a multiple of font size (1.2 = 120%).\",\n },\n text_align: {\n type: \"string\",\n enum: [\"left\", \"center\", \"right\"],\n description: \"Horizontal alignment of each line. Default center.\",\n },\n text_autofit: {\n type: \"string\",\n enum: [\"shrink\", \"wrap\"],\n description:\n \"How text fits its box. \\\"shrink\\\" (default): word-wrap then auto-shrink the font from text_size until the block fits — a longer line renders smaller. \\\"wrap\\\": hold text_size FIXED and only word-wrap (hard-breaking a single over-wide word), never shrink — every line keeps the same height. Captions use \\\"wrap\\\".\",\n },\n text_valign: {\n type: \"string\",\n enum: [\"top\", \"middle\", \"bottom\"],\n description:\n \"Vertical alignment of the text block within its box. \\\"middle\\\" (default) centres it; \\\"bottom\\\" pins it to the box floor so extra wrapped lines grow upward from a fixed baseline (captions use this so a wrapped line doesn't shift the others); \\\"top\\\" pins the ceiling.\",\n },\n stroke_width: {\n type: \"number\",\n description: \"Outline width in px (0 = no outline).\",\n },\n stroke_color: {\n type: \"string\",\n description: \"Outline colour as #rrggbb. Defaults to white when a width is set.\",\n },\n text_shadow: {\n type: [\"object\", \"null\"],\n description: \"Drop shadow { offsetX, offsetY, blur, color }; color is any CSS colour (rgba allowed). null clears it.\",\n properties: {\n offsetX: { type: \"number\" },\n offsetY: { type: \"number\" },\n blur: { type: \"number\" },\n color: { type: \"string\" },\n },\n },\n },\n required: [\"elementId\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_text_layer\",\n description:\n \"Create a new text layer — a first-class leaf that animates, groups, and z-orders exactly like an image or shape. The renderer draws live typeset text (multi-line, auto-fit to the box). Defaults: x/y = canvas centre, width 900, height 320, font_family \\\"Anton\\\", text_size derived from existing text layers (or ~10% of canvas height). Also accepts full type styling: font_weight (100-900), font_style (italic), text_transform, letter_spacing, line_height, text_align, text_autofit (\\\"shrink\\\"=auto-shrink to fit / \\\"wrap\\\"=fixed size + word-wrap), text_valign (top/middle/bottom), an outline (stroke_width + stroke_color), and text_shadow. Returns the new layer's id + element id (text.<id>).\",\n parameters: {\n type: \"object\",\n properties: {\n text: {\n type: \"string\",\n description: \"The text to render. Newlines are honoured as hard line breaks.\",\n },\n x: { type: \"number\", description: \"Centre x in canvas px. Defaults to canvas centre.\" },\n y: { type: \"number\", description: \"Centre y in canvas px. Defaults to canvas centre.\" },\n width: { type: \"number\", description: \"Box width in px (> 0). Default 900.\" },\n height: { type: \"number\", description: \"Box height in px (> 0). Default 320.\" },\n font_family: {\n type: \"string\",\n description: \"Google Fonts family name, e.g. \\\"Anton\\\". Default \\\"Anton\\\".\",\n },\n text_size: {\n type: \"number\",\n description:\n \"Font size in px. Omit to derive from existing text layers (median) or the canvas height.\",\n },\n text_color: {\n type: \"string\",\n description: \"Text fill colour as #rrggbb. Defaults to white.\",\n },\n font_weight: {\n type: \"number\",\n description: \"Font weight 100..900 (400 regular, 700 bold, 800 black). Default 400.\",\n },\n font_style: {\n type: \"string\",\n enum: [\"normal\", \"italic\"],\n description: \"Italic toggle. Default normal.\",\n },\n text_transform: {\n type: \"string\",\n enum: [\"none\", \"uppercase\", \"lowercase\"],\n description: \"Case transform applied before layout. Default none.\",\n },\n letter_spacing: {\n type: \"number\",\n description: \"Tracking between glyphs in px; may be negative. Default 0.\",\n },\n line_height: {\n type: \"number\",\n description: \"Line height as a multiple of font size (1.2 = 120%).\",\n },\n text_align: {\n type: \"string\",\n enum: [\"left\", \"center\", \"right\"],\n description: \"Horizontal alignment of each line. Default center.\",\n },\n text_autofit: {\n type: \"string\",\n enum: [\"shrink\", \"wrap\"],\n description:\n \"How text fits its box. \\\"shrink\\\" (default): word-wrap then auto-shrink the font from text_size until the block fits — a longer line renders smaller. \\\"wrap\\\": hold text_size FIXED and only word-wrap (hard-breaking a single over-wide word), never shrink — every line keeps the same height. Captions use \\\"wrap\\\".\",\n },\n text_valign: {\n type: \"string\",\n enum: [\"top\", \"middle\", \"bottom\"],\n description:\n \"Vertical alignment of the text block within its box. \\\"middle\\\" (default) centres it; \\\"bottom\\\" pins it to the box floor so extra wrapped lines grow upward from a fixed baseline (captions use this so a wrapped line doesn't shift the others); \\\"top\\\" pins the ceiling.\",\n },\n stroke_width: {\n type: \"number\",\n description: \"Outline width in px (0 = no outline).\",\n },\n stroke_color: {\n type: \"string\",\n description: \"Outline colour as #rrggbb. Defaults to white when a width is set.\",\n },\n text_shadow: {\n type: [\"object\", \"null\"],\n description: \"Drop shadow { offsetX, offsetY, blur, color }; color is any CSS colour (rgba allowed). null clears it.\",\n properties: {\n offsetX: { type: \"number\" },\n offsetY: { type: \"number\" },\n blur: { type: \"number\" },\n color: { type: \"string\" },\n },\n },\n },\n required: [],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_caption_track\",\n description:\n \"Build a caption track from pre-timed lines (e.g. derived from transcribe_clip's word timings). mode \\\"line-sync\\\" (default) creates one text layer per line, each shown only during its [startFrame, endFrame) window via hold-eased opacity keyframes — the active-line karaoke read; mode \\\"static\\\" makes a single layer with all lines joined. `style` picks a preset look. Lines default to a lower-third band. Returns the created text element ids.\",\n parameters: {\n type: \"object\",\n properties: {\n lines: {\n type: \"array\",\n description:\n \"Caption lines in order. Each: { text, startFrame, endFrame } — frames are 0-indexed at 30fps.\",\n items: {\n type: \"object\",\n properties: {\n text: { type: \"string\" },\n startFrame: {\n type: \"number\",\n description: \"Project frame the line appears.\",\n },\n endFrame: {\n type: \"number\",\n description:\n \"Project frame the line disappears (defaults to startFrame + 30).\",\n },\n },\n required: [\"text\", \"startFrame\"],\n },\n },\n mode: {\n type: \"string\",\n enum: [\"line-sync\", \"static\"],\n description:\n \"\\\"line-sync\\\" (default): one timed layer per line. \\\"static\\\": one layer with all lines.\",\n },\n style: {\n type: \"string\",\n enum: [\"classic\", \"bold-outline\", \"word-pop\"],\n description: \"Caption look preset. Default \\\"classic\\\".\",\n },\n x: { type: \"number\", description: \"Caption band centre x. Default canvas centre.\" },\n y: {\n type: \"number\",\n description: \"Caption band centre y. Default lower third (~80% of height).\",\n },\n width: { type: \"number\", description: \"Band width. Default ~86% of canvas width.\" },\n height: { type: \"number\", description: \"Band height. Default ~16% of canvas height.\" },\n },\n required: [\"lines\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"rename_layer\",\n description:\n \"Set the human-readable name of a video / image / shape / text layer — the label shown in the Inspector, and the basis for the layer's auto-derived <morpha-video> embed attribute (so renaming a layer to \\\"caption\\\" makes the embed attribute `caption`). Pass an empty string to clear the name. For groups use rename_group.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"video.<id>, image.<id>, shapes.<id>, or text.<id>.\",\n },\n name: {\n type: \"string\",\n description:\n \"New label. Empty string clears it (callers fall back to the filename stem).\",\n },\n },\n required: [\"elementId\", \"name\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_loop\",\n description:\n \"Set the project's loop section: the whole composition repeats once per value, with one field of one layer varying across the repeats. Builds one pass per value, each setting `field` of `elementId` to that value — e.g. a caption text layer cycling through several strings. Pass an empty `values` array to clear the loop (the comp plays once).\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description:\n \"Target layer — text.<id>, image.<id>, shapes.<id>, or video.<id>.\",\n },\n field: {\n type: \"string\",\n description:\n 'The layer field each pass overrides — e.g. \"text\", \"text_color\", \"filename\". Defaults to \"text\".',\n },\n values: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"One value per loop pass. Empty array clears the loop.\",\n },\n },\n required: [\"elementId\", \"values\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_canvas_size\",\n description:\n \"Resize the composition canvas to width × height pixels. Every layer's position/size, group pivots, and x/y/width/height animation keyframes scale by the width/height ratio, so the composition keeps its proportions in the new frame. Common sizes: 1080×1920 (9:16 Reels/TikTok/Shorts), 1080×1350 (4:5 Instagram), 1080×1080 (1:1 square), 1920×1080 (16:9 YouTube).\",\n parameters: {\n type: \"object\",\n properties: {\n width: {\n type: \"number\",\n description: \"Canvas width in px (positive integer).\",\n },\n height: {\n type: \"number\",\n description: \"Canvas height in px (positive integer).\",\n },\n },\n required: [\"width\", \"height\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_image_filename\",\n description:\n \"Repoint an existing image layer at a different uploaded asset — keeps the layer's id, position, size, animations, and styles; only the bitmap changes. The asset must already exist at users/<userId>/assets/<projectId>/<filename> (uploaded via the editor's drag-drop or /api/upload-asset). Use this to swap a layer's image WITHOUT losing its keyframes — `remove_layer` + `add_image_layer` would mint a new id and drop the animations.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"Image layer id, image.<id>.\",\n },\n filename: {\n type: \"string\",\n description:\n \"Asset filename in the project's assets bucket, e.g. drake.png.\",\n },\n },\n required: [\"elementId\", \"filename\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_video_clip\",\n description:\n \"Repoint an existing video layer at a different uploaded clip — keeps the layer's id, position, size, animations, styles, and trim window; only the source mp4 changes. The clip must already exist at users/<userId>/clips/<projectId>/<clip> (uploaded via the editor's '+ Add video' button or /api/upload-clip). Use this to swap a video layer's source WITHOUT losing its keyframes.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"Video layer id, video.<id>.\",\n },\n clip: {\n type: \"string\",\n description:\n \"Clip filename in the project's clips bucket, e.g. mickey-tiktok.mp4.\",\n },\n },\n required: [\"elementId\", \"clip\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"set_matte_source\",\n description:\n \"Set (or clear) a track matte — the host shows only where the matte source is opaque. The HOST can be a leaf (image.<id>, video.<id>, shapes.<id>, text.<id>) OR a group.<id> (a group is a layer of sorts): a group host clips ALL its composited children to the source shape's path — e.g. a marching chevron strip + black backing shown only inside an arrow / band shape. For a leaf host the source can be any leaf (use a text.<id> source for video-/image-filled letterforms); for a group host the source must be a shape (shapes.<id>). Make the source layer hidden so it acts purely as the stencil. Pass null to clear.\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n description: \"Host being masked: image/video/shapes/text.<id>, or group.<id>.\",\n },\n matte_source_id: {\n type: [\"string\", \"null\"],\n description:\n \"Element id of the layer whose alpha drives the mask, or null to clear.\",\n },\n },\n required: [\"elementId\", \"matte_source_id\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"add_speed_keyframe\",\n description:\n \"Add or overwrite a speed-ramp (time-remap) keyframe on a video layer. `rate` is the playback rate at `frame`: 1 = real-time, 0.5 = half-speed, 2 = double-speed. Range: rate in [0.1, 8].\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\", description: \"video.<id>.\" },\n frame: { type: \"number\", description: \"Project-timeline frame number.\" },\n rate: {\n type: \"number\",\n description: \"Playback rate at this frame (1 = real-time, in [0.1, 8]).\",\n },\n },\n required: [\"elementId\", \"frame\", \"rate\"],\n },\n },\n },\n {\n type: \"function\",\n function: {\n name: \"remove_speed_keyframe\",\n description:\n \"Remove the speed-ramp keyframe at `frame` on a video layer. Removing the last keyframe clears the speed_keyframes array entirely (restoring 1× playback).\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: { type: \"string\", description: \"video.<id>.\" },\n frame: { type: \"number\", description: \"Project-timeline frame number.\" },\n },\n required: [\"elementId\", \"frame\"],\n },\n },\n },\n];\n","import type { Project } from \"./schemas.ts\";\n\n// The single source of truth for \"what a blank project is\". A fresh project\n// the user creates via the editor's New button, and the editor store's\n// boot-time placeholder, both come from here — so the empty starting state is\n// defined in exactly one place.\n//\n// The body mirrors the minimal valid project the schema accepts: a single\n// pinned `is_background` image_layer (the canvas backdrop — the renderer paints\n// its fill across the whole canvas and ignores x/y/width/height, but the schema\n// still requires them) and empty collections for everything else.\n\nexport type BlankProjectOpts = {\n projectId: string;\n name?: string | null;\n /** Defaults to now. The editor placeholder passes 0 as a sentinel. */\n lastModifiedAt?: number;\n canvasWidth?: number;\n canvasHeight?: number;\n};\n\nexport const blankProject = (opts: BlankProjectOpts): Project => {\n const canvasWidth = opts.canvasWidth ?? 1080;\n const canvasHeight = opts.canvasHeight ?? 1920;\n return {\n project_id: opts.projectId,\n ...(opts.name ? { name: opts.name } : {}),\n schema_version: 2,\n image_layers: [\n {\n id: \"background\",\n x: canvasWidth / 2,\n y: canvasHeight / 2,\n width: canvasWidth,\n height: canvasHeight,\n rotation: 0,\n pivotX: 0.5,\n pivotY: 0.5,\n fill: { type: \"solid\", color: \"#000000\", opacity: 1 },\n pinned: true,\n is_background: true,\n },\n ],\n video_layers: [],\n text_layers: [],\n shapes: [],\n animations: {},\n styles: {},\n layer_order: [],\n groups: [],\n duration_seconds: 30,\n audio_overlays: [],\n markers: [],\n loop: [],\n loop_start_frame: 0,\n loop_end_frame: null,\n track_loops: {},\n color_tracks: {},\n current_version_id: null,\n last_modified_at: opts.lastModifiedAt ?? Date.now(),\n embed_origins: [],\n public_properties: [],\n custom_fonts: [],\n canvas_width: canvasWidth,\n canvas_height: canvasHeight,\n };\n};\n","// Auto-caption helpers shared by the editor (client-side enrichment) and the\n// worker MCP. Turns a clip's Whisper transcript into a synced caption track and\n// nests it with the video: the caption text layers go in a group named\n// \"captions\", and that group is grouped together with the video layer.\n//\n// Pure — operates on a Project via the shared tool dispatchers in ./tools.ts.\n// The transcript itself lives in an R2 side-car (not the project JSON), so the\n// I/O layer fetches it and passes the words in.\n\nimport { dispatch, type ToolDispatch } from \"./tools.ts\";\nimport { findParentGroup, type Project } from \"./schemas.ts\";\n\nexport interface CaptionLine {\n text: string;\n startFrame: number;\n endFrame: number;\n}\n\nexport interface TranscriptWordLike {\n word: string;\n start: number;\n end: number;\n}\n\nconst FPS = 30;\n// Chunking bounds — short, punchy lines that fill the caption band at a big\n// size (TikTok/Reels style). Smaller = bigger on-screen text.\nconst MAX_CHARS = 18;\nconst MAX_WORDS = 3;\nconst PAUSE_SECONDS = 0.6;\n// Caption band as a fraction of canvas width — big, ~80%-filling text.\nconst BAND_WIDTH_FRACTION = 0.82;\n\n// Join transcript word tokens into display text. Whisper emits punctuation /\n// hyphen continuations as their own tokens (\"-class\", \",\", \"'s\"); attach those\n// to the preceding word instead of inserting a space, so captions read\n// \"working-class\", not \"working -class\".\nconst joinWords = (ws: ReadonlyArray<{ word: string }>): string =>\n ws\n .reduce((acc, x) => {\n const w = (x.word ?? \"\").trim();\n if (!w) return acc;\n if (!acc) return w;\n if (/^[-'’.,!?;:%)\\]]/.test(w)) return acc + w;\n return `${acc} ${w}`;\n }, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n// Group a flat word-timed transcript into caption lines. Breaks on\n// sentence-ending punctuation, a char/word cap, or a speech gap. Line windows\n// are gapless (each line holds until the next appears; the last gets a short\n// tail), matching the line-sync caption read.\nexport const transcriptToCaptionLines = (\n words: ReadonlyArray<TranscriptWordLike>,\n fps: number = FPS,\n): CaptionLine[] => {\n const clean = (words ?? []).filter(\n (w) =>\n w &&\n typeof w.word === \"string\" &&\n Number.isFinite(w.start) &&\n Number.isFinite(w.end),\n );\n if (clean.length === 0) return [];\n\n const groups: TranscriptWordLike[][] = [];\n let cur: TranscriptWordLike[] = [];\n const flush = () => {\n if (cur.length) {\n groups.push(cur);\n cur = [];\n }\n };\n for (let i = 0; i < clean.length; i++) {\n const w = clean[i];\n cur.push(w);\n const text = joinWords(cur);\n const endsSentence = /[.?!][\"')\\]]?$/.test(w.word.trim());\n const next = clean[i + 1];\n const gap = next ? next.start - w.end : 0;\n if (\n endsSentence ||\n cur.length >= MAX_WORDS ||\n text.length >= MAX_CHARS ||\n (next && gap > PAUSE_SECONDS)\n ) {\n flush();\n }\n }\n flush();\n\n const lines: CaptionLine[] = groups.map((g) => {\n const first = g[0];\n const last = g[g.length - 1];\n return {\n text: joinWords(g),\n startFrame: Math.max(0, Math.round(first.start * fps)),\n endFrame: Math.round(last.end * fps),\n };\n });\n\n // Gapless windows: a line stays up until the next one starts; the last line\n // gets a ~0.4s tail. Guarantee endFrame > startFrame.\n for (let i = 0; i < lines.length; i++) {\n lines[i].endFrame =\n i < lines.length - 1\n ? lines[i + 1].startFrame\n : lines[i].endFrame + Math.round(0.4 * fps);\n if (lines[i].endFrame <= lines[i].startFrame) {\n lines[i].endFrame = lines[i].startFrame + 1;\n }\n }\n return lines.filter((l) => l.text.length > 0);\n};\n\nconst clipStem = (filename: string): string =>\n filename.replace(/\\.[^.]+$/, \"\");\n\nexport const videoElementIdForClip = (\n project: Project,\n clip: string,\n): string | null => {\n const v = project.video_layers.find((x) => x.clip === clip);\n return v ? `video.${v.id}` : null;\n};\n\n// True when this video already sits in a group that contains a \"captions\"\n// group — the idempotency guard so we never double-caption.\nexport const hasCaptionsForClip = (\n project: Project,\n videoElementId: string,\n): boolean => {\n const parentId = findParentGroup(project, videoElementId);\n if (!parentId) return false;\n const parent = project.groups.find((g) => g.id === parentId);\n if (!parent) return false;\n return parent.children.some((cid) => {\n if (!cid.startsWith(\"group.\")) return false;\n const g = project.groups.find((x) => x.id === cid.slice(\"group.\".length));\n return (g?.name ?? \"\").trim().toLowerCase() === \"captions\";\n });\n};\n\n// Remove the \"captions\" track for a clip: drop every text layer inside the\n// clip's \"captions\" group, then dissolve the now-empty group. Used by the\n// \"restart captioning\" path so a rebuild regenerates rather than no-op'ing on\n// the hasCaptionsForClip guard. No-op (ok: true, removed: 0) when the clip has\n// no captions. Pure — mirrors hasCaptionsForClip's lookup.\nexport const removeCaptionsForClip = (\n project: Project,\n videoElementId: string,\n): { project: Project; ok: boolean; removed: number } => {\n const parentId = findParentGroup(project, videoElementId);\n if (!parentId) return { project, ok: true, removed: 0 };\n const parent = project.groups.find((g) => g.id === parentId);\n if (!parent) return { project, ok: true, removed: 0 };\n const capChildId = parent.children.find((cid) => {\n if (!cid.startsWith(\"group.\")) return false;\n const g = project.groups.find((x) => x.id === cid.slice(\"group.\".length));\n return (g?.name ?? \"\").trim().toLowerCase() === \"captions\";\n });\n if (!capChildId) return { project, ok: true, removed: 0 };\n\n const capGroupId = capChildId.slice(\"group.\".length);\n const capGroup = project.groups.find((g) => g.id === capGroupId);\n const childIds = capGroup ? [...capGroup.children] : [];\n\n const removeLayer = dispatch.remove_layer as ToolDispatch;\n const ungroupLayers = dispatch.ungroup_layers as ToolDispatch;\n\n let cur = project;\n let removed = 0;\n for (const cid of childIds) {\n const out = removeLayer(cur, { elementId: cid });\n if (out.result.ok) {\n cur = out.project;\n removed += 1;\n }\n }\n // Dissolve the now-empty \"captions\" group (ungroup takes the bare id).\n const un = ungroupLayers(cur, { groupId: capGroupId });\n if (un.result.ok) cur = un.project;\n return { project: cur, ok: true, removed };\n};\n\nexport interface BuildCaptionsResult {\n project: Project;\n ok: boolean;\n error?: string;\n captionsGroupId?: string;\n lineCount?: number;\n}\n\n// Add a caption track for `clip`, wrap the caption layers in a \"captions\"\n// group, and group that with the video layer. Idempotent + no-op when there's\n// nothing to caption. Returns the (possibly unchanged) project.\nexport const buildCaptionsForClip = (\n project: Project,\n opts: { clip: string; lines: CaptionLine[]; style?: string },\n): BuildCaptionsResult => {\n const { clip, lines } = opts;\n const style = opts.style ?? \"bold-outline\";\n\n const videoElementId = videoElementIdForClip(project, clip);\n if (!videoElementId) {\n return { project, ok: false, error: `no video layer references clip ${clip}` };\n }\n if (lines.length === 0) {\n return { project, ok: false, error: \"no caption lines\" };\n }\n if (hasCaptionsForClip(project, videoElementId)) {\n return { project, ok: true, lineCount: 0 }; // already captioned — no-op\n }\n\n const addCaptionTrack = dispatch.add_caption_track as ToolDispatch;\n const groupLayers = dispatch.group_layers as ToolDispatch;\n const reorderLayer = dispatch.reorder_layer as ToolDispatch;\n\n // 1. caption text layers (line-sync, lower-third bold-outline by default).\n // Wide band so the short lines render big (~80% of canvas width).\n const track = addCaptionTrack(project, {\n lines,\n mode: \"line-sync\",\n style,\n width: Math.round(project.canvas_width * BAND_WIDTH_FRACTION),\n });\n if (!track.result.ok) {\n return { project, ok: false, error: `add_caption_track failed: ${track.result.error}` };\n }\n const captionIds = (track.result.data as { elementIds?: string[] }).elementIds ?? [];\n if (captionIds.length === 0) {\n return { project, ok: false, error: \"caption track produced no layers\" };\n }\n let cur = track.project;\n\n // 2. wrap them in a \"captions\" group.\n const capGroup = groupLayers(cur, { elementIds: captionIds, name: \"captions\" });\n if (!capGroup.result.ok) {\n return { project: cur, ok: false, error: `group captions failed: ${capGroup.result.error}` };\n }\n const captionsGroupId = (capGroup.result.data as { elementId: string }).elementId;\n cur = capGroup.project;\n\n // 3. group [video, captions] together — only when they share a parent (both\n // freshly at root is the common case). If the video is already nested, leave\n // the captions group adjacent rather than failing.\n if (findParentGroup(cur, videoElementId) === findParentGroup(cur, captionsGroupId)) {\n const video = cur.video_layers.find((v) => `video.${v.id}` === videoElementId);\n const parentName = (video?.name && video.name.trim()) || clipStem(clip);\n const parent = groupLayers(cur, {\n elementIds: [videoElementId, captionsGroupId],\n name: parentName,\n });\n if (parent.result.ok) cur = parent.project;\n }\n\n // Captions must sit ABOVE the video — reorder the video to the bottom of its\n // parent so a full-frame clip never hides the captions (correct by\n // construction; index 0 = bottom of the sibling stack).\n const reorder = reorderLayer(cur, { elementId: videoElementId, newIndex: 0 });\n if (reorder.result.ok) cur = reorder.project;\n\n return { project: cur, ok: true, captionsGroupId, lineCount: lines.length };\n};\n","export interface RenderFrameOptions {\n /** Project id, served at `${origin}/api/project/<id>`. */\n projectId: string;\n /** Composition frame (0-indexed, 30 fps). Default 0. */\n frame?: number;\n /** Origin serving /render-canvas + /api/project + /clips. Default https://morphastudio.ai */\n origin?: string;\n /** Bearer token for the Morpha account (forwarded to the project/clip fetches). */\n token?: string;\n /** Canvas width in px. Default 1080. */\n width?: number;\n /** Canvas height in px. Default 1920. */\n height?: number;\n /**\n * Browser channel. Defaults to system Chrome (\"chrome\") so HEVC decodes via\n * the OS decoder (macOS/Windows). Use \"chromium\" for H.264/VP9/AV1 only.\n */\n channel?: string;\n /**\n * Milliseconds to wait for page load + the render-ready flag. Default 90000.\n * The render page can spend up to ~60s loading + seeking a large\n * non-faststart 4K/HEVC clip on a cold cache (it must read to the moov),\n * so this default leaves headroom above that; raise it for very large clips.\n */\n timeoutMs?: number;\n}\n\n/**\n * Render one composited frame to a PNG Buffer. The video frame is decoded and\n * every overlay (captions/shapes/text) composited by a REAL browser — no\n * ffmpeg. With the default `channel: \"chrome\"`, HEVC/AV1/H.264 all decode (HEVC\n * needs the OS decoder, i.e. macOS/Windows). Requires `playwright` installed\n * (optional peer dependency) and Google Chrome available on the machine.\n */\nexport const renderFrame = async (opts: RenderFrameOptions): Promise<Buffer> => {\n let pw: typeof import(\"playwright\");\n try {\n pw = await import(\"playwright\");\n } catch {\n throw new Error(\n \"renderFrame() needs Playwright. Install it: `npm i playwright`, and have Google Chrome available.\",\n );\n }\n const origin = opts.origin ?? \"https://morphastudio.ai\";\n const frame = Math.max(0, Math.round(opts.frame ?? 0));\n const width = Math.max(64, Math.round(opts.width ?? 1080));\n const height = Math.max(64, Math.round(opts.height ?? 1920));\n const timeout = opts.timeoutMs ?? 90_000;\n\n const browser = await pw.chromium.launch({\n channel: opts.channel ?? \"chrome\",\n headless: true,\n });\n try {\n const ctx = await browser.newContext({ viewport: { width, height } });\n if (opts.token) {\n await ctx.setExtraHTTPHeaders({ Authorization: `Bearer ${opts.token}` });\n }\n const page = await ctx.newPage();\n const url = `${origin}/render-canvas?project=${encodeURIComponent(opts.projectId)}&frame=${frame}`;\n // `domcontentloaded`, not `networkidle`: a <video preload=\"auto\"> streaming\n // a large non-faststart clip keeps the network busy well past the 500ms\n // idle window, which would block (or time out) goto before the page can\n // paint. The page's structured readiness flag is the real sync point.\n await page.goto(url, { waitUntil: \"domcontentloaded\", timeout });\n\n // Wait for a terminal state. New page: __morphaRenderStatus.done. Old page\n // (legacy build): the bare __morphaRenderReady boolean. Either resolves.\n try {\n await page.waitForFunction(\n () => {\n const w = window as unknown as {\n __morphaRenderStatus?: { done?: boolean };\n __morphaRenderReady?: boolean;\n };\n if (w.__morphaRenderStatus) {\n return w.__morphaRenderStatus.done === true;\n }\n return w.__morphaRenderReady === true;\n },\n { timeout },\n );\n } catch {\n throw new Error(\n `Morpha render timed out after ${Math.round(timeout / 1000)}s for project ${opts.projectId} frame ${frame} — the clip may still be loading; raise timeoutMs for very large clips.`,\n );\n }\n\n // Read the structured status. null on older deployments that only set the\n // legacy boolean — there we can't distinguish black from good, so return\n // the buffer exactly as before (no regression).\n const status = (await page.evaluate(() => {\n return (\n (window as unknown as { __morphaRenderStatus?: unknown })\n .__morphaRenderStatus ?? null\n );\n })) as {\n ok?: boolean;\n error?: string;\n videoLayersExpected?: number;\n videoLayersFailed?: number;\n } | null;\n\n if (status && status.ok === false) {\n const expected = status.videoLayersExpected ?? 0;\n const failed = status.videoLayersFailed ?? 0;\n throw new Error(\n `Morpha render incomplete for project ${opts.projectId} frame ${frame}: ` +\n (status.error ?? \"render reported not-ok\") +\n (expected\n ? ` (${failed}/${expected} video layer(s) failed to decode within ${Math.round(\n timeout / 1000,\n )}s — raise timeoutMs for very large clips)`\n : \"\"),\n );\n }\n\n return await page.locator(\"canvas\").first().screenshot({ type: \"png\" });\n } finally {\n await browser.close();\n }\n};\n","// A thin, typed HTTP client for a hosted Morpha account — the programmatic\n// equivalent of driving Morpha over MCP. It wraps the same Worker endpoints\n// the MCP server and editor use:\n//\n// GET /api/project/:id -> fetch a project's JSON\n// GET /api/tools -> the tool catalog\n// POST /api/tool/:name -> load -> dispatch one tool -> write back\n//\n// plus renderFrame() (a real browser, no ffmpeg — see ./render.ts). Auth is a\n// Bearer API key (mp_…). Every tool you can call over MCP, you can call here\n// with `client.callTool(projectId, name, args)` — same catalog, same effects.\n\nimport { migrateProject, projectSchema, type Project } from \"../../src/schemas.ts\";\nimport type { ToolFunction, ToolResult } from \"../../src/tools.ts\";\nimport { renderFrame, type RenderFrameOptions } from \"./render.ts\";\n\nexport interface MorphaClientOptions {\n /** API origin. Default https://morphastudio.ai */\n origin?: string;\n /** Bearer API key (mp_…), sent as `Authorization: Bearer <token>`. Required\n * against a hosted account; omit only when pointing at a dev origin whose\n * auth is bypassed. */\n token?: string;\n /** Custom fetch implementation (tests, proxies, Node <18). Defaults to the\n * global `fetch`. */\n fetch?: typeof fetch;\n}\n\n/** The outcome of a `callTool` round-trip. `result.ok` may be `false` for a\n * tool-level failure (e.g. a missing asset) — that is a normal, non-throwing\n * outcome the caller inspects; only transport/HTTP errors throw. */\nexport interface ToolCallResult {\n result: ToolResult;\n /** The project AFTER the tool ran (the server has already persisted it when\n * `result.ok` and the tool changed anything). */\n project: Project;\n /** Tappable link that opens this project in the editor. */\n editorUrl?: string;\n}\n\nexport interface MorphaClient {\n /** Fetch a hosted project's JSON (migrated + schema-validated). */\n getProject(projectId: string): Promise<Project>;\n /** The hosted tool catalog (same set you can `callTool`) — OpenAI tool shape:\n * each entry is `{ type: \"function\", function: { name, description, parameters } }`. */\n listTools(): Promise<ToolFunction[]>;\n /**\n * Call one tool against a hosted project — the HTTP equivalent of an MCP\n * `tools/call`. The server loads the project, dispatches the tool, and writes\n * the result back. Returns `{ result, project, editorUrl }`. Throws only on\n * transport/HTTP errors; a tool-level failure comes back as `result.ok:false`.\n */\n callTool(\n projectId: string,\n name: string,\n args?: Record<string, unknown>,\n ): Promise<ToolCallResult>;\n /**\n * Render one composited frame of a hosted project to a PNG (real browser, no\n * ffmpeg). Convenience wrapper over the standalone `renderFrame()` with this\n * client's `origin`/`token` applied; pass `opts` to override width/height/\n * channel/timeoutMs.\n */\n renderFrame(\n projectId: string,\n frame?: number,\n opts?: Omit<RenderFrameOptions, \"projectId\" | \"frame\">,\n ): Promise<Buffer>;\n}\n\nconst safeText = async (res: Response): Promise<string> => {\n try {\n return await res.text();\n } catch {\n return \"\";\n }\n};\n\n/**\n * Create a typed client for a hosted Morpha account. Everything you can do over\n * MCP, you can do here:\n *\n * ```ts\n * import { createClient } from \"morpha-studio-sdk\";\n * const morpha = createClient({ token: process.env.MORPHA_TOKEN });\n * await morpha.callTool(\"my-project\", \"add_text_layer\", { text: \"HELLO\", x: 540, y: 600 });\n * const png = await morpha.renderFrame(\"my-project\", 150);\n * ```\n */\nexport const createClient = (options: MorphaClientOptions = {}): MorphaClient => {\n const origin = (options.origin ?? \"https://morphastudio.ai\").replace(/\\/+$/, \"\");\n const token = options.token;\n const doFetch = options.fetch ?? globalThis.fetch;\n if (typeof doFetch !== \"function\") {\n throw new Error(\n \"No fetch available — pass options.fetch (Node <18) or run on Node >=18.\",\n );\n }\n\n const headers = (extra?: Record<string, string>): Record<string, string> => {\n const h: Record<string, string> = { Accept: \"application/json\", ...extra };\n if (token) h.Authorization = `Bearer ${token}`;\n return h;\n };\n\n const getProject = async (projectId: string): Promise<Project> => {\n const res = await doFetch(\n `${origin}/api/project/${encodeURIComponent(projectId)}`,\n { headers: headers() },\n );\n if (!res.ok) {\n throw new Error(\n `getProject(${projectId}) failed: HTTP ${res.status} ${await safeText(res)}`.trim(),\n );\n }\n return projectSchema.parse(migrateProject(await res.json()));\n };\n\n const listTools = async (): Promise<ToolFunction[]> => {\n const res = await doFetch(`${origin}/api/tools`, { headers: headers() });\n if (!res.ok) {\n throw new Error(`listTools failed: HTTP ${res.status} ${await safeText(res)}`.trim());\n }\n const json = (await res.json()) as { tools?: ToolFunction[] };\n return json.tools ?? [];\n };\n\n const callTool = async (\n projectId: string,\n name: string,\n args: Record<string, unknown> = {},\n ): Promise<ToolCallResult> => {\n const res = await doFetch(`${origin}/api/tool/${encodeURIComponent(name)}`, {\n method: \"POST\",\n headers: headers({ \"Content-Type\": \"application/json\" }),\n body: JSON.stringify({ projectId, args }),\n });\n const json = (await res.json().catch(() => null)) as\n | (Partial<ToolCallResult> & { error?: string })\n | null;\n if (!res.ok) {\n const msg =\n json && typeof json.error === \"string\" ? json.error : `HTTP ${res.status}`;\n throw new Error(`callTool(${name}) failed: ${msg}`);\n }\n if (!json || !json.result || !json.project) {\n throw new Error(`callTool(${name}) returned an unexpected response shape`);\n }\n return json as ToolCallResult;\n };\n\n const renderFrameForProject = (\n projectId: string,\n frame = 0,\n opts: Omit<RenderFrameOptions, \"projectId\" | \"frame\"> = {},\n ): Promise<Buffer> =>\n renderFrame({ origin, token, ...opts, projectId, frame });\n\n return { getProject, listTools, callTool, renderFrame: renderFrameForProject };\n};\n"],"mappings":"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","names":["raw","tracks","next","removeLayer","ungroupLayers","addCaptionTrack","groupLayers","reorderLayer"]}
|