@a-company/atelier 0.29.0 → 0.36.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../math/src/easing.ts","../../math/src/spring.ts","../../math/src/lerp.ts","../../math/src/color.ts","../../math/src/path.ts","../../core/src/resolver/delta-resolver.ts","../../core/src/resolver/easing-resolver.ts","../../core/src/expressions/expression-evaluator.ts","../../core/src/resolver/frame-resolver.ts","../../core/src/validation/overlap-validator.ts","../../core/src/builder/document-builder.ts","../../core/src/units/resolve-units.ts","../../core/src/presets/preset-resolver.ts","../../core/src/state/state-machine.ts","../../core/src/templates/template-resolver.ts","../../core/src/audio/audio-timing.ts","../../canvas/src/styles.ts","../../canvas/src/apply-properties.ts","../../canvas/src/renderers/shape-renderer.ts","../../canvas/src/renderers/text-renderer.ts","../../canvas/src/renderers/image-renderer.ts","../../canvas/src/renderers/video-renderer.ts","../../canvas/src/renderers/ref-renderer.ts","../../canvas/src/render-frame.ts","../../canvas/src/image-cache.ts","../src/index.ts","../src/commands/validate.ts","../../schema/src/units.ts","../../schema/src/coordinates.ts","../../schema/src/color.ts","../../schema/src/shape.ts","../../schema/src/easing.ts","../../schema/src/shadow.ts","../../schema/src/layer.ts","../../schema/src/interaction.ts","../../schema/src/delta.ts","../../schema/src/state.ts","../../schema/src/preset.ts","../../schema/src/variable.ts","../../schema/src/asset.ts","../../schema/src/document.ts","../../schema/src/validate.ts","../../schema/src/parse.ts","../src/commands/info.ts","../src/commands/still.ts","../src/commands/render.ts","../src/commands/render-pipeline.ts","../src/commands/export-svg.ts","../../svg/src/render-svg.ts","../../svg/src/svg-properties.ts","../../svg/src/svg-gradients.ts","../../svg/src/svg-shapes.ts","../../svg/src/svg-text.ts","../../svg/src/svg-filters.ts","../../svg/src/svg-clip.ts","../src/commands/export-lottie.ts","../../lottie/src/map-colors.ts","../../lottie/src/map-shapes.ts","../../lottie/src/map-easing.ts","../../lottie/src/map-keyframes.ts","../../lottie/src/map-layers.ts","../../lottie/src/warnings.ts","../../lottie/src/export-lottie.ts","../src/commands/assets.ts","../src/commands/variables.ts"],"sourcesContent":["/**\n * Linear easing — no acceleration.\n */\nexport function linear(t: number): number {\n return t;\n}\n\n/**\n * Cubic bezier easing — CSS-compatible.\n * Implements the same algorithm as CSS cubic-bezier().\n * @param x1 - first control point x\n * @param y1 - first control point y\n * @param x2 - second control point x\n * @param y2 - second control point y\n */\nexport function cubicBezier(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n): (t: number) => number {\n // Use binary search to find the parametric t value that gives us our x,\n // then compute the corresponding y. This is the standard algorithm used\n // by browsers for CSS transitions.\n\n return (t: number): number => {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n\n // Binary search for the parametric t value that gives us our x\n let lo = 0;\n let hi = 1;\n let mid: number = 0;\n\n for (let i = 0; i < 20; i++) {\n mid = (lo + hi) / 2;\n const x = sampleBezier(x1, x2, mid);\n if (Math.abs(x - t) < 1e-6) break;\n if (x < t) lo = mid;\n else hi = mid;\n }\n\n mid = (lo + hi) / 2;\n return sampleBezier(y1, y2, mid);\n };\n}\n\n/** Sample a single axis of a cubic bezier at parametric t */\nfunction sampleBezier(p1: number, p2: number, t: number): number {\n // B(t) = 3(1-t)^2*t*p1 + 3(1-t)*t^2*p2 + t^3\n return 3 * (1 - t) * (1 - t) * t * p1 + 3 * (1 - t) * t * t * p2 + t * t * t;\n}\n\n/** Common CSS easing presets */\nexport const easeIn = cubicBezier(0.42, 0, 1, 1);\nexport const easeOut = cubicBezier(0, 0, 0.58, 1);\nexport const easeInOut = cubicBezier(0.42, 0, 0.58, 1);\n\n/**\n * Step easing — jumps between discrete values.\n * @param steps - number of steps\n * @param position - \"start\" or \"end\" (default \"end\")\n */\nexport function step(\n steps: number,\n position: \"start\" | \"end\" = \"end\",\n): (t: number) => number {\n return (t: number): number => {\n if (t <= 0) return position === \"start\" ? 1 / steps : 0;\n if (t >= 1) return 1;\n\n const s = Math.floor(t * steps);\n if (position === \"start\") {\n return Math.min((s + 1) / steps, 1);\n }\n return s / steps;\n };\n}\n","export interface SpringConfig {\n mass?: number; // default 1\n stiffness?: number; // default 100\n damping?: number; // default 10\n velocity?: number; // default 0\n}\n\n/**\n * Creates a spring easing function.\n * Uses damped harmonic oscillator physics.\n * Returns a function that takes t (0-1) and returns the spring value.\n *\n * The spring always goes from 0 to 1, but may overshoot.\n */\nexport function spring(config: SpringConfig = {}): (t: number) => number {\n const {\n mass = 1,\n stiffness = 100,\n damping = 10,\n velocity = 0,\n } = config;\n\n const w0 = Math.sqrt(stiffness / mass); // natural frequency\n const zeta = damping / (2 * Math.sqrt(stiffness * mass)); // damping ratio\n\n // Determine total duration to normalize t\n // We pre-calculate a reasonable duration where the spring settles\n const duration = estimateSettleTime(zeta, w0);\n\n return (t: number): number => {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n\n const time = t * duration;\n let value: number;\n\n if (zeta < 1) {\n // Underdamped\n const wd = w0 * Math.sqrt(1 - zeta * zeta);\n const A = 1;\n const B = (zeta * w0 + velocity) / wd;\n value =\n 1 -\n Math.exp(-zeta * w0 * time) *\n (A * Math.cos(wd * time) + B * Math.sin(wd * time));\n } else if (zeta === 1) {\n // Critically damped\n value = 1 - Math.exp(-w0 * time) * (1 + (w0 + velocity) * time);\n } else {\n // Overdamped\n const s1 = -w0 * (zeta - Math.sqrt(zeta * zeta - 1));\n const s2 = -w0 * (zeta + Math.sqrt(zeta * zeta - 1));\n const A = (velocity - s2) / (s1 - s2);\n const B = 1 - A;\n value = 1 - A * Math.exp(s1 * time) - B * Math.exp(s2 * time);\n }\n\n return value;\n };\n}\n\n/**\n * Estimates the time for a spring to settle within 0.1% of target.\n */\nfunction estimateSettleTime(zeta: number, w0: number): number {\n if (zeta >= 1) {\n return 10 / (zeta * w0);\n }\n // For underdamped: settling ~ -ln(0.001) / (zeta * w0)\n return Math.log(1000) / (zeta * w0);\n}\n","/**\n * Linear interpolation between two numbers.\n */\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\n/**\n * Clamp a value between min and max.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Interpolate between two multi-dimensional values.\n * Arrays must be the same length.\n */\nexport function lerpArray(a: number[], b: number[], t: number): number[] {\n return a.map((v, i) => lerp(v, b[i], t));\n}\n\n/**\n * Re-maps a value from one range to another.\n */\nexport function remap(\n value: number,\n inMin: number,\n inMax: number,\n outMin: number,\n outMax: number,\n): number {\n const t = (value - inMin) / (inMax - inMin);\n return lerp(outMin, outMax, t);\n}\n","import { lerp, clamp } from \"./lerp.js\";\n\nexport interface RGBA {\n r: number; // 0-255\n g: number; // 0-255\n b: number; // 0-255\n a: number; // 0-1\n}\n\nexport interface HSLA {\n h: number; // 0-360\n s: number; // 0-100\n l: number; // 0-100\n a: number; // 0-1\n}\n\n/**\n * Parse a hex color string to RGBA.\n * Supports: #RGB, #RGBA, #RRGGBB, #RRGGBBAA\n */\nexport function hexToRgba(hex: string): RGBA {\n let h = hex.replace(\"#\", \"\");\n\n if (h.length === 3)\n h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + \"ff\";\n else if (h.length === 4)\n h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];\n else if (h.length === 6) h = h + \"ff\";\n\n return {\n r: parseInt(h.slice(0, 2), 16),\n g: parseInt(h.slice(2, 4), 16),\n b: parseInt(h.slice(4, 6), 16),\n a: parseInt(h.slice(6, 8), 16) / 255,\n };\n}\n\n/**\n * Convert RGBA to hex string.\n */\nexport function rgbaToHex(color: RGBA): string {\n const r = clamp(Math.round(color.r), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n const g = clamp(Math.round(color.g), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n const b = clamp(Math.round(color.b), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n const a = clamp(Math.round(color.a * 255), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n return `#${r}${g}${b}${a === \"ff\" ? \"\" : a}`;\n}\n\n/**\n * Interpolate between two RGBA colors.\n */\nexport function lerpRgba(a: RGBA, b: RGBA, t: number): RGBA {\n return {\n r: lerp(a.r, b.r, t),\n g: lerp(a.g, b.g, t),\n b: lerp(a.b, b.b, t),\n a: lerp(a.a, b.a, t),\n };\n}\n\n/**\n * Convert RGBA to HSLA.\n */\nexport function rgbaToHsla(color: RGBA): HSLA {\n const r = color.r / 255;\n const g = color.g / 255;\n const b = color.b / 255;\n\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const d = max - min;\n const l = (max + min) / 2;\n\n let h = 0;\n let s = 0;\n\n if (d !== 0) {\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;\n else if (max === g) h = ((b - r) / d + 2) / 6;\n else h = ((r - g) / d + 4) / 6;\n }\n\n return { h: h * 360, s: s * 100, l: l * 100, a: color.a };\n}\n\n/**\n * Convert HSLA to RGBA.\n */\nexport function hslaToRgba(color: HSLA): RGBA {\n const h = color.h / 360;\n const s = color.s / 100;\n const l = color.l / 100;\n\n let r: number, g: number, b: number;\n\n if (s === 0) {\n r = g = b = l;\n } else {\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n r = hueToRgb(p, q, h + 1 / 3);\n g = hueToRgb(p, q, h);\n b = hueToRgb(p, q, h - 1 / 3);\n }\n\n return {\n r: Math.round(r * 255),\n g: Math.round(g * 255),\n b: Math.round(b * 255),\n a: color.a,\n };\n}\n\nfunction hueToRgb(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n}\n\n/**\n * Interpolate between two HSLA colors (shortest hue path).\n */\nexport function lerpHsla(a: HSLA, b: HSLA, t: number): HSLA {\n // Handle hue wrapping — take the shortest path\n let dh = b.h - a.h;\n if (dh > 180) dh -= 360;\n if (dh < -180) dh += 360;\n\n return {\n h: (((a.h + dh * t) % 360) + 360) % 360,\n s: lerp(a.s, b.s, t),\n l: lerp(a.l, b.l, t),\n a: lerp(a.a, b.a, t),\n };\n}\n","/**\n * Path interpolation utilities for motion paths.\n * Evaluates position and tangent along a path defined by points with bezier handles.\n */\n\nexport interface PathPoint2D {\n x: number;\n y: number;\n in?: { x: number; y: number };\n out?: { x: number; y: number };\n}\n\nexport interface PathPosition {\n x: number;\n y: number;\n /** Tangent angle in degrees */\n angle: number;\n}\n\n/**\n * Compute the length of a single cubic bezier segment using subdivision.\n */\nfunction bezierSegmentLength(\n p0x: number, p0y: number,\n c0x: number, c0y: number,\n c1x: number, c1y: number,\n p1x: number, p1y: number,\n steps = 32,\n): number {\n let length = 0;\n let prevX = p0x;\n let prevY = p0y;\n for (let i = 1; i <= steps; i++) {\n const t = i / steps;\n const mt = 1 - t;\n const x = mt * mt * mt * p0x + 3 * mt * mt * t * c0x + 3 * mt * t * t * c1x + t * t * t * p1x;\n const y = mt * mt * mt * p0y + 3 * mt * mt * t * c0y + 3 * mt * t * t * c1y + t * t * t * p1y;\n const dx = x - prevX;\n const dy = y - prevY;\n length += Math.sqrt(dx * dx + dy * dy);\n prevX = x;\n prevY = y;\n }\n return length;\n}\n\n/**\n * Evaluate a cubic bezier at parameter t, returning position and tangent.\n */\nfunction evalBezier(\n p0x: number, p0y: number,\n c0x: number, c0y: number,\n c1x: number, c1y: number,\n p1x: number, p1y: number,\n t: number,\n): PathPosition {\n const mt = 1 - t;\n const x = mt * mt * mt * p0x + 3 * mt * mt * t * c0x + 3 * mt * t * t * c1x + t * t * t * p1x;\n const y = mt * mt * mt * p0y + 3 * mt * mt * t * c0y + 3 * mt * t * t * c1y + t * t * t * p1y;\n\n // Tangent (first derivative)\n const tx = 3 * mt * mt * (c0x - p0x) + 6 * mt * t * (c1x - c0x) + 3 * t * t * (p1x - c1x);\n const ty = 3 * mt * mt * (c0y - p0y) + 6 * mt * t * (c1y - c0y) + 3 * t * t * (p1y - c1y);\n\n const angle = Math.atan2(ty, tx) * (180 / Math.PI);\n\n return { x, y, angle };\n}\n\n/**\n * Build a lookup table of cumulative segment lengths for a path.\n */\nfunction buildSegmentLengths(points: PathPoint2D[], closed: boolean): number[] {\n const segCount = closed ? points.length : points.length - 1;\n const lengths: number[] = [];\n\n for (let i = 0; i < segCount; i++) {\n const p0 = points[i];\n const p1 = points[(i + 1) % points.length];\n\n const c0x = p0.x + (p0.out?.x ?? 0);\n const c0y = p0.y + (p0.out?.y ?? 0);\n const c1x = p1.x + (p1.in?.x ?? 0);\n const c1y = p1.y + (p1.in?.y ?? 0);\n\n lengths.push(bezierSegmentLength(p0.x, p0.y, c0x, c0y, c1x, c1y, p1.x, p1.y));\n }\n\n return lengths;\n}\n\n/**\n * Evaluate a point along a path at a given progress (0–1).\n * Uses arc-length parameterization for uniform speed.\n */\nexport function evaluatePathAtProgress(\n points: PathPoint2D[],\n progress: number,\n closed = false,\n): PathPosition {\n if (points.length < 2) {\n return { x: points[0]?.x ?? 0, y: points[0]?.y ?? 0, angle: 0 };\n }\n\n // Clamp progress\n const t = Math.max(0, Math.min(1, progress));\n\n const segLengths = buildSegmentLengths(points, closed);\n const totalLength = segLengths.reduce((a, b) => a + b, 0);\n\n if (totalLength === 0) {\n return { x: points[0].x, y: points[0].y, angle: 0 };\n }\n\n const targetLength = t * totalLength;\n\n // Find which segment the target length falls in\n let accumulated = 0;\n for (let i = 0; i < segLengths.length; i++) {\n const segLen = segLengths[i];\n if (accumulated + segLen >= targetLength || i === segLengths.length - 1) {\n // Progress within this segment\n const segProgress = segLen === 0 ? 0 : (targetLength - accumulated) / segLen;\n\n const p0 = points[i];\n const p1 = points[(i + 1) % points.length];\n\n const c0x = p0.x + (p0.out?.x ?? 0);\n const c0y = p0.y + (p0.out?.y ?? 0);\n const c1x = p1.x + (p1.in?.x ?? 0);\n const c1y = p1.y + (p1.in?.y ?? 0);\n\n return evalBezier(p0.x, p0.y, c0x, c0y, c1x, c1y, p1.x, p1.y, segProgress);\n }\n accumulated += segLen;\n }\n\n // Fallback (shouldn't reach here)\n const last = points[points.length - 1];\n return { x: last.x, y: last.y, angle: 0 };\n}\n","import type { Delta, FrameRange } from \"@a-company/atelier-types\";\nimport { lerp, clamp, hexToRgba, lerpRgba, rgbaToHex } from \"@a-company/atelier-math\";\nimport { resolveEasing } from \"./easing-resolver.js\";\nimport { isExpression, evaluateExpression, type ExpressionContext } from \"../expressions/expression-evaluator.js\";\n\n/**\n * Check if a frame is within a delta's range (inclusive).\n */\nexport function isFrameInRange(frame: number, range: FrameRange): boolean {\n return frame >= range[0] && frame <= range[1];\n}\n\n/**\n * Compute the progress (0-1) of a frame within a delta's range.\n */\nexport function computeProgress(frame: number, range: FrameRange): number {\n const [start, end] = range;\n if (start === end) return 1; // instantaneous\n return clamp((frame - start) / (end - start), 0, 1);\n}\n\n/**\n * Resolve a single delta's value at a given frame.\n * Returns undefined if the frame is outside the delta's range.\n * Returns the interpolated value if within range.\n *\n * If `from` or `to` is an expression object `{ expr: \"...\" }`,\n * it is evaluated with the current animation context before interpolation.\n */\nexport function resolveDeltaValue(delta: Delta, frame: number): unknown | undefined {\n if (!isFrameInRange(frame, delta.range)) {\n return undefined;\n }\n\n const progress = computeProgress(frame, delta.range);\n const easingFn = resolveEasing(delta.easing);\n const easedProgress = easingFn(progress);\n\n const exprCtx: ExpressionContext = {\n t: easedProgress,\n progress,\n frame,\n duration: delta.range[1] - delta.range[0],\n };\n\n const from = isExpression(delta.from)\n ? evaluateExpression(delta.from.expr, exprCtx)\n : delta.from;\n\n const to = isExpression(delta.to)\n ? evaluateExpression(delta.to.expr, exprCtx)\n : delta.to;\n\n return interpolateValue(from, to, easedProgress);\n}\n\n/**\n * Interpolate between two values based on eased progress.\n * Handles numbers, strings (pass-through at threshold), and nested objects.\n */\nexport function interpolateValue(from: unknown, to: unknown, t: number): unknown {\n // Number interpolation\n if (typeof from === \"number\" && typeof to === \"number\") {\n return lerp(from, to, t);\n }\n\n // Hex color interpolation\n if (typeof from === \"string\" && typeof to === \"string\") {\n if (from.startsWith(\"#\") && to.startsWith(\"#\")) {\n return rgbaToHex(lerpRgba(hexToRgba(from), hexToRgba(to), t));\n }\n // Non-color strings — snap at end\n return t >= 1 ? to : from;\n }\n\n // Boolean interpolation — snap at midpoint for frame-precise control\n if (typeof from === \"boolean\" && typeof to === \"boolean\") {\n return t >= 0.5 ? to : from;\n }\n\n // For unknown types, snap at end\n return t >= 1 ? to : from;\n}\n\n/**\n * Given multiple deltas for the SAME layer+property, find the active one\n * at a given frame and return its resolved value.\n *\n * If no delta is active at this frame, holds the `to` value of the most\n * recent completed delta (the one whose range ended most recently before\n * this frame). This prevents properties from reverting after animation ends.\n *\n * Assumes no overlaps (validated elsewhere).\n */\nexport function resolvePropertyAtFrame(\n deltas: Delta[],\n frame: number,\n): unknown | undefined {\n // Check for an active delta first\n for (const delta of deltas) {\n if (isFrameInRange(frame, delta.range)) {\n return resolveDeltaValue(delta, frame);\n }\n }\n\n // No active delta — hold the `to` value of the most recently completed delta\n let lastCompleted: Delta | undefined;\n for (const delta of deltas) {\n if (frame > delta.range[1]) {\n if (!lastCompleted || delta.range[1] > lastCompleted.range[1]) {\n lastCompleted = delta;\n }\n }\n }\n\n if (!lastCompleted) return undefined;\n\n // If the held `to` value is an expression, evaluate at t=1\n if (isExpression(lastCompleted.to)) {\n return evaluateExpression(lastCompleted.to.expr, {\n t: 1,\n progress: 1,\n frame,\n duration: lastCompleted.range[1] - lastCompleted.range[0],\n });\n }\n\n return lastCompleted.to;\n}\n","import type { Easing } from \"@a-company/atelier-types\";\nimport { linear, cubicBezier, easeIn, easeOut, easeInOut, step, spring } from \"@a-company/atelier-math\";\n\n/**\n * Converts an Easing type definition into an executable easing function.\n * Returns a function (t: number) => number where t is 0-1.\n */\nexport function resolveEasing(easing: Easing | undefined): (t: number) => number {\n if (!easing) return linear;\n\n // String presets\n if (typeof easing === \"string\") {\n switch (easing) {\n case \"linear\": return linear;\n case \"ease-in\": return easeIn;\n case \"ease-out\": return easeOut;\n case \"ease-in-out\": return easeInOut;\n default: return linear;\n }\n }\n\n // Object easing definitions\n switch (easing.type) {\n case \"linear\":\n return linear;\n case \"cubic-bezier\":\n return cubicBezier(easing.x1, easing.y1, easing.x2, easing.y2);\n case \"spring\":\n return spring({\n mass: easing.mass,\n stiffness: easing.stiffness,\n damping: easing.damping,\n velocity: easing.velocity,\n });\n case \"step\":\n return step(easing.steps, easing.position);\n default:\n return linear;\n }\n}\n","/**\n * Safe recursive descent expression evaluator.\n * No eval(), no Function(), no code generation.\n *\n * Supports:\n * - Numbers: 42, 3.14, -1\n * - Operators: + - * / % **\n * - Parentheses: (expr)\n * - Math functions: sin, cos, tan, abs, min, max, floor, ceil, round, sqrt, pow, clamp, sign, log\n * - Constants: pi, tau, e\n * - Context variables: t, frame, duration, progress\n * - Comparison: <, >, <=, >=, ==, !=\n * - Ternary: condition ? trueExpr : falseExpr\n */\n\n/** Context variables available during expression evaluation */\nexport interface ExpressionContext {\n /** Eased progress 0–1 */\n t: number;\n /** Raw progress 0–1 (before easing) */\n progress: number;\n /** Current frame number */\n frame: number;\n /** Delta duration in frames */\n duration: number;\n}\n\n// ── Tokenizer ───────────────────────────────────────────────\n\ntype TokenType =\n | \"number\"\n | \"ident\"\n | \"op\"\n | \"lparen\"\n | \"rparen\"\n | \"comma\"\n | \"question\"\n | \"colon\"\n | \"compare\"\n | \"eof\";\n\ninterface Token {\n type: TokenType;\n value: string;\n}\n\nfunction tokenize(expr: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n\n while (i < expr.length) {\n const ch = expr[i];\n\n // Whitespace\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\n\" || ch === \"\\r\") {\n i++;\n continue;\n }\n\n // Numbers\n if ((ch >= \"0\" && ch <= \"9\") || ch === \".\") {\n let num = \"\";\n while (i < expr.length && ((expr[i] >= \"0\" && expr[i] <= \"9\") || expr[i] === \".\")) {\n num += expr[i++];\n }\n tokens.push({ type: \"number\", value: num });\n continue;\n }\n\n // Identifiers (variables, functions, constants)\n if ((ch >= \"a\" && ch <= \"z\") || (ch >= \"A\" && ch <= \"Z\") || ch === \"_\") {\n let id = \"\";\n while (i < expr.length && ((expr[i] >= \"a\" && expr[i] <= \"z\") || (expr[i] >= \"A\" && expr[i] <= \"Z\") || (expr[i] >= \"0\" && expr[i] <= \"9\") || expr[i] === \"_\")) {\n id += expr[i++];\n }\n tokens.push({ type: \"ident\", value: id });\n continue;\n }\n\n // Comparison operators (must check before single-char ops)\n if (ch === \"<\" || ch === \">\" || ch === \"!\" || ch === \"=\") {\n if (i + 1 < expr.length && expr[i + 1] === \"=\") {\n tokens.push({ type: \"compare\", value: ch + \"=\" });\n i += 2;\n continue;\n }\n if (ch === \"<\" || ch === \">\") {\n tokens.push({ type: \"compare\", value: ch });\n i++;\n continue;\n }\n }\n\n // Power operator\n if (ch === \"*\" && i + 1 < expr.length && expr[i + 1] === \"*\") {\n tokens.push({ type: \"op\", value: \"**\" });\n i += 2;\n continue;\n }\n\n // Operators\n if (ch === \"+\" || ch === \"-\" || ch === \"*\" || ch === \"/\" || ch === \"%\") {\n tokens.push({ type: \"op\", value: ch });\n i++;\n continue;\n }\n\n // Grouping and function calls\n if (ch === \"(\") { tokens.push({ type: \"lparen\", value: \"(\" }); i++; continue; }\n if (ch === \")\") { tokens.push({ type: \"rparen\", value: \")\" }); i++; continue; }\n if (ch === \",\") { tokens.push({ type: \"comma\", value: \",\" }); i++; continue; }\n\n // Ternary\n if (ch === \"?\") { tokens.push({ type: \"question\", value: \"?\" }); i++; continue; }\n if (ch === \":\") { tokens.push({ type: \"colon\", value: \":\" }); i++; continue; }\n\n throw new Error(`Expression: unexpected character '${ch}' at position ${i}`);\n }\n\n tokens.push({ type: \"eof\", value: \"\" });\n return tokens;\n}\n\n// ── Parser + Evaluator ──────────────────────────────────────\n\nconst CONSTANTS: Record<string, number> = {\n pi: Math.PI,\n PI: Math.PI,\n tau: Math.PI * 2,\n TAU: Math.PI * 2,\n e: Math.E,\n E: Math.E,\n};\n\nconst FUNCTIONS: Record<string, (...args: number[]) => number> = {\n sin: Math.sin,\n cos: Math.cos,\n tan: Math.tan,\n abs: Math.abs,\n floor: Math.floor,\n ceil: Math.ceil,\n round: Math.round,\n sqrt: Math.sqrt,\n sign: Math.sign,\n log: Math.log,\n min: (...args) => Math.min(...args),\n max: (...args) => Math.max(...args),\n pow: (a, b) => Math.pow(a, b),\n clamp: (v, lo, hi) => Math.min(Math.max(v, lo), hi),\n};\n\nclass Parser {\n private tokens: Token[];\n private pos = 0;\n private ctx: ExpressionContext;\n\n constructor(tokens: Token[], ctx: ExpressionContext) {\n this.tokens = tokens;\n this.ctx = ctx;\n }\n\n private peek(): Token {\n return this.tokens[this.pos];\n }\n\n private consume(expectedType?: TokenType): Token {\n const tok = this.tokens[this.pos++];\n if (expectedType && tok.type !== expectedType) {\n throw new Error(`Expression: expected ${expectedType} but got ${tok.type} '${tok.value}'`);\n }\n return tok;\n }\n\n /** Entry: ternary (lowest precedence) */\n parse(): number {\n const result = this.parseTernary();\n if (this.peek().type !== \"eof\") {\n throw new Error(`Expression: unexpected token '${this.peek().value}'`);\n }\n return result;\n }\n\n /** ternary: comparison ? expr : expr */\n private parseTernary(): number {\n const condition = this.parseComparison();\n if (this.peek().type === \"question\") {\n this.consume(); // ?\n const trueVal = this.parseTernary();\n this.consume(\"colon\"); // :\n const falseVal = this.parseTernary();\n return condition ? trueVal : falseVal;\n }\n return condition;\n }\n\n /** comparison: additive (< | > | <= | >= | == | !=) additive */\n private parseComparison(): number {\n let left = this.parseAdditive();\n while (this.peek().type === \"compare\") {\n const op = this.consume().value;\n const right = this.parseAdditive();\n switch (op) {\n case \"<\": left = left < right ? 1 : 0; break;\n case \">\": left = left > right ? 1 : 0; break;\n case \"<=\": left = left <= right ? 1 : 0; break;\n case \">=\": left = left >= right ? 1 : 0; break;\n case \"==\": left = left === right ? 1 : 0; break;\n case \"!=\": left = left !== right ? 1 : 0; break;\n }\n }\n return left;\n }\n\n /** additive: multiplicative (('+' | '-') multiplicative)* */\n private parseAdditive(): number {\n let left = this.parseMultiplicative();\n while (this.peek().type === \"op\" && (this.peek().value === \"+\" || this.peek().value === \"-\")) {\n const op = this.consume().value;\n const right = this.parseMultiplicative();\n left = op === \"+\" ? left + right : left - right;\n }\n return left;\n }\n\n /** multiplicative: power (('*' | '/' | '%') power)* */\n private parseMultiplicative(): number {\n let left = this.parsePower();\n while (this.peek().type === \"op\" && (this.peek().value === \"*\" || this.peek().value === \"/\" || this.peek().value === \"%\")) {\n const op = this.consume().value;\n const right = this.parsePower();\n if (op === \"*\") left = left * right;\n else if (op === \"/\") left = right !== 0 ? left / right : 0;\n else left = left % right;\n }\n return left;\n }\n\n /** power: unary ('**' unary)* (right-associative) */\n private parsePower(): number {\n const base = this.parseUnary();\n if (this.peek().type === \"op\" && this.peek().value === \"**\") {\n this.consume();\n const exp = this.parsePower(); // right-associative\n return Math.pow(base, exp);\n }\n return base;\n }\n\n /** unary: ('-' | '+') unary | primary */\n private parseUnary(): number {\n if (this.peek().type === \"op\" && (this.peek().value === \"-\" || this.peek().value === \"+\")) {\n const op = this.consume().value;\n const val = this.parseUnary();\n return op === \"-\" ? -val : val;\n }\n return this.parsePrimary();\n }\n\n /** primary: number | ident | function(args) | '(' expr ')' */\n private parsePrimary(): number {\n const tok = this.peek();\n\n // Number literal\n if (tok.type === \"number\") {\n this.consume();\n return parseFloat(tok.value);\n }\n\n // Identifier: constant, context variable, or function\n if (tok.type === \"ident\") {\n this.consume();\n const name = tok.value;\n\n // Function call\n if (this.peek().type === \"lparen\") {\n this.consume(); // (\n const args: number[] = [];\n if (this.peek().type !== \"rparen\") {\n args.push(this.parseTernary());\n while (this.peek().type === \"comma\") {\n this.consume(); // ,\n args.push(this.parseTernary());\n }\n }\n this.consume(\"rparen\"); // )\n\n const fn = FUNCTIONS[name];\n if (!fn) throw new Error(`Expression: unknown function '${name}'`);\n return fn(...args);\n }\n\n // Constant\n if (name in CONSTANTS) return CONSTANTS[name];\n\n // Context variable\n if (name in this.ctx) return (this.ctx as unknown as Record<string, number>)[name];\n\n throw new Error(`Expression: unknown variable '${name}'`);\n }\n\n // Parenthesized expression\n if (tok.type === \"lparen\") {\n this.consume(); // (\n const val = this.parseTernary();\n this.consume(\"rparen\"); // )\n return val;\n }\n\n throw new Error(`Expression: unexpected token '${tok.value}'`);\n }\n}\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Check if a value is an expression object { expr: string }.\n */\nexport function isExpression(value: unknown): value is { expr: string } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"expr\" in value &&\n typeof (value as Record<string, unknown>).expr === \"string\"\n );\n}\n\n/**\n * Evaluate an expression string with the given context.\n * Returns a number. Throws on syntax errors or unknown identifiers.\n */\nexport function evaluateExpression(expr: string, ctx: ExpressionContext): number {\n const tokens = tokenize(expr);\n const parser = new Parser(tokens, ctx);\n return parser.parse();\n}\n","import type { AtelierDocument, Layer, Delta, AnimatableProperty } from \"@a-company/atelier-types\";\nimport { resolvePropertyAtFrame } from \"./delta-resolver.js\";\n\n/** A resolved layer at a specific frame — all animated properties computed */\nexport interface ResolvedLayer {\n id: string;\n /** Original layer definition */\n layer: Layer;\n /** Computed property overrides from active deltas */\n computedProperties: Partial<Record<AnimatableProperty, unknown>>;\n /** Seconds into source video to seek to — only present for video visual layers */\n videoSourceTime?: number;\n}\n\n/** The resolved state of an entire document at a specific frame */\nexport interface ResolvedFrame {\n /** Frame number that was resolved */\n frame: number;\n /** State name that was resolved */\n stateName: string;\n /** All layers with their computed properties */\n layers: ResolvedLayer[];\n}\n\n/**\n * Resolve all layers at a given frame within a named state.\n * This is the main entry point for frame resolution.\n * @param overrideDeltas - Optional pre-merged deltas (used for hierarchical state resolution)\n */\nexport function resolveFrame(\n doc: AtelierDocument,\n stateName: string,\n frame: number,\n overrideDeltas?: Delta[],\n): ResolvedFrame {\n const state = doc.states[stateName];\n if (!state) {\n throw new Error(`State \"${stateName}\" not found in document \"${doc.name}\"`);\n }\n\n // Group deltas by layer+property\n const deltasByLayerProperty = groupDeltas(overrideDeltas ?? state.deltas);\n\n // Resolve each layer\n const resolvedLayers: ResolvedLayer[] = doc.layers.map((layer) => {\n const computedProperties: Partial<Record<AnimatableProperty, unknown>> = {};\n\n // Find all animated properties for this layer\n const layerDeltas = deltasByLayerProperty.get(layer.id);\n if (layerDeltas) {\n for (const [property, deltas] of layerDeltas) {\n const value = resolvePropertyAtFrame(deltas, frame);\n if (value !== undefined) {\n computedProperties[property as AnimatableProperty] = value;\n }\n }\n }\n\n const resolvedLayer: ResolvedLayer = { id: layer.id, layer, computedProperties };\n\n if (layer.visual.type === \"video\") {\n const video = layer.visual;\n const fps = doc.canvas.fps;\n const startFrame = video.startFrame ?? 0;\n const sourceOffset = video.sourceOffset ?? 0;\n const playbackRate = video.playbackRate ?? 1.0;\n const relativeFrame = Math.max(0, frame - startFrame);\n const sourceTime = (relativeFrame / fps) * playbackRate + sourceOffset;\n resolvedLayer.videoSourceTime =\n video.sourceEnd !== undefined ? Math.min(sourceTime, video.sourceEnd) : sourceTime;\n }\n\n return resolvedLayer;\n });\n\n return { frame, stateName, layers: resolvedLayers };\n}\n\n/**\n * Group deltas by layer ID, then by property name.\n */\nfunction groupDeltas(\n deltas: Delta[],\n): Map<string, Map<string, Delta[]>> {\n const map = new Map<string, Map<string, Delta[]>>();\n\n for (const delta of deltas) {\n let layerMap = map.get(delta.layer);\n if (!layerMap) {\n layerMap = new Map();\n map.set(delta.layer, layerMap);\n }\n\n let propDeltas = layerMap.get(delta.property);\n if (!propDeltas) {\n propDeltas = [];\n layerMap.set(delta.property, propDeltas);\n }\n\n propDeltas.push(delta);\n }\n\n return map;\n}\n","import type { Delta, FrameRange } from \"@a-company/atelier-types\";\n\nexport interface OverlapError {\n layerId: string;\n property: string;\n existingRange: FrameRange;\n newRange: FrameRange;\n message: string;\n}\n\n/**\n * Check if two frame ranges overlap.\n * Boundary-touching ranges (e.g., [0-50] and [50-90]) are allowed —\n * only ranges that share more than a single boundary frame are overlaps.\n */\nexport function rangesOverlap(a: FrameRange, b: FrameRange): boolean {\n return a[0] < b[1] && b[0] < a[1];\n}\n\n/**\n * Validate that a new delta doesn't overlap with existing deltas\n * on the same layer+property.\n */\nexport function validateNoOverlap(\n existing: Delta[],\n newDelta: Delta,\n): OverlapError | null {\n for (const delta of existing) {\n if (\n delta.layer === newDelta.layer &&\n delta.property === newDelta.property &&\n rangesOverlap(delta.range, newDelta.range)\n ) {\n return {\n layerId: newDelta.layer,\n property: newDelta.property,\n existingRange: delta.range,\n newRange: newDelta.range,\n message: `Overlapping delta on layer \"${newDelta.layer}\" property \"${newDelta.property}\": ` +\n `existing [${delta.range[0]}-${delta.range[1]}] overlaps with new [${newDelta.range[0]}-${newDelta.range[1]}]`,\n };\n }\n }\n return null;\n}\n\n/**\n * Validate all deltas in a state have no overlaps.\n * Returns all overlap errors found.\n */\nexport function validateAllDeltas(deltas: Delta[]): OverlapError[] {\n const errors: OverlapError[] = [];\n\n for (let i = 0; i < deltas.length; i++) {\n for (let j = i + 1; j < deltas.length; j++) {\n const a = deltas[i];\n const b = deltas[j];\n\n if (\n a.layer === b.layer &&\n a.property === b.property &&\n rangesOverlap(a.range, b.range)\n ) {\n errors.push({\n layerId: a.layer,\n property: a.property,\n existingRange: a.range,\n newRange: b.range,\n message: `Overlapping deltas on layer \"${a.layer}\" property \"${a.property}\": ` +\n `[${a.range[0]}-${a.range[1]}] overlaps with [${b.range[0]}-${b.range[1]}]`,\n });\n }\n }\n }\n\n return errors;\n}\n","import type {\n AtelierDocument, Canvas, Layer, State, Delta, Preset,\n Variable, Asset,\n} from \"@a-company/atelier-types\";\nimport { validateNoOverlap } from \"../validation/overlap-validator.js\";\n\n/**\n * Fluent builder for constructing AtelierDocument objects.\n * Validates constraints (like no-overlap) as you build.\n */\nexport class DocumentBuilder {\n private doc: AtelierDocument;\n\n constructor(name: string, canvas: Canvas) {\n this.doc = {\n version: \"1.0\",\n name,\n canvas,\n layers: [],\n states: {},\n };\n }\n\n /** Set document description */\n description(desc: string): this {\n this.doc.description = desc;\n return this;\n }\n\n /** Add tags to the document */\n tags(...tags: string[]): this {\n this.doc.tags = [...(this.doc.tags ?? []), ...tags];\n return this;\n }\n\n /** Add a variable definition */\n variable(id: string, variable: Variable): this {\n if (!this.doc.variables) this.doc.variables = {};\n this.doc.variables[id] = variable;\n return this;\n }\n\n /** Add an asset reference */\n asset(id: string, asset: Asset): this {\n if (!this.doc.assets) this.doc.assets = {};\n this.doc.assets[id] = asset;\n return this;\n }\n\n /** Add a preset */\n preset(id: string, preset: Preset): this {\n if (!this.doc.presets) this.doc.presets = {};\n this.doc.presets[id] = preset;\n return this;\n }\n\n /** Add a layer */\n addLayer(layer: Layer): this {\n // Check for duplicate IDs\n if (this.doc.layers.some(l => l.id === layer.id)) {\n throw new Error(`Layer with id \"${layer.id}\" already exists`);\n }\n this.doc.layers.push(layer);\n return this;\n }\n\n /** Add a state */\n addState(name: string, state: Omit<State, \"deltas\"> & { deltas?: Delta[] }): this {\n if (this.doc.states[name]) {\n throw new Error(`State \"${name}\" already exists`);\n }\n this.doc.states[name] = { ...state, deltas: state.deltas ?? [] };\n return this;\n }\n\n /** Add a delta to an existing state, with overlap validation */\n addDelta(stateName: string, delta: Delta): this {\n const state = this.doc.states[stateName];\n if (!state) {\n throw new Error(`State \"${stateName}\" not found`);\n }\n\n // Verify the layer exists\n if (!this.doc.layers.some(l => l.id === delta.layer)) {\n throw new Error(`Layer \"${delta.layer}\" not found — add the layer before adding deltas`);\n }\n\n // Check for overlaps\n const overlap = validateNoOverlap(state.deltas, delta);\n if (overlap) {\n throw new Error(overlap.message);\n }\n\n state.deltas.push(delta);\n return this;\n }\n\n /** Build and return the final document */\n build(): AtelierDocument {\n return JSON.parse(JSON.stringify(this.doc)) as AtelierDocument;\n }\n}\n\n/**\n * Create a new DocumentBuilder.\n * Convenience function for starting a builder chain.\n */\nexport function createDocument(name: string, canvas: Canvas): DocumentBuilder {\n return new DocumentBuilder(name, canvas);\n}\n","import type { UnitValue } from \"@a-company/atelier-types\";\n\n/**\n * Check if a UnitValue is a percentage string.\n */\nexport function isPercentage(value: UnitValue): value is `${number}%` {\n return typeof value === \"string\" && value.endsWith(\"%\");\n}\n\n/**\n * Parse a percentage string to its numeric value (0-100).\n */\nexport function parsePercentage(value: `${number}%`): number {\n return parseFloat(value);\n}\n\n/**\n * Resolve a UnitValue to pixels given a reference dimension.\n * Pixel values pass through unchanged.\n * Percentage values are computed relative to the reference.\n */\nexport function resolveUnit(value: UnitValue, reference: number): number {\n if (isPercentage(value)) {\n return (parsePercentage(value) / 100) * reference;\n }\n return value;\n}\n","import type { Preset, Delta, FrameRange } from \"@a-company/atelier-types\";\n\n/**\n * Expand a preset into concrete deltas for a specific layer and start frame.\n *\n * @param preset - The preset to expand\n * @param layerId - Target layer ID\n * @param startFrame - Frame to start the preset from\n * @param duration - Total duration to map preset offsets into\n */\nexport function expandPreset(\n preset: Preset,\n layerId: string,\n startFrame: number,\n duration: number,\n): Delta[] {\n return preset.deltas.map((pd, index) => {\n let range: FrameRange;\n if (pd.offset) {\n range = [startFrame + pd.offset[0], startFrame + pd.offset[1]];\n } else {\n range = [startFrame, startFrame + duration];\n }\n\n return {\n id: `preset-${layerId}-${index}`,\n layer: layerId,\n property: pd.property,\n range,\n from: pd.from,\n to: pd.to,\n easing: pd.easing,\n };\n });\n}\n","import type { AtelierDocument, Easing, State, Delta } from \"@a-company/atelier-types\";\nimport { resolveFrame, type ResolvedFrame } from \"../resolver/frame-resolver.js\";\nimport { resolveEasing } from \"../resolver/easing-resolver.js\";\n\nexport interface StateTransition {\n from: string;\n to: string;\n at: number; // frame at which transition occurs\n}\n\nexport interface PlaybackState {\n stateName: string;\n frame: number;\n resolved: ResolvedFrame;\n isComplete: boolean;\n}\n\nexport interface ActiveTransition {\n fromState: string;\n toState: string;\n duration: number;\n easingFn: (t: number) => number;\n transitionFrame: number; // how many frames into the transition\n}\n\nexport class StateMachine {\n private currentState: string;\n private currentFrame = 0;\n private transitions: StateTransition[] = [];\n private activeTransition: ActiveTransition | null = null;\n\n constructor(\n private doc: AtelierDocument,\n initialState?: string,\n ) {\n // Default to first state\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) throw new Error(\"Document has no states\");\n this.currentState = initialState ?? stateNames[0];\n if (!doc.states[this.currentState]) {\n throw new Error(`State \"${this.currentState}\" not found`);\n }\n }\n\n /** Get current state name */\n get state(): string {\n return this.currentState;\n }\n\n /** Get current frame */\n get frame(): number {\n return this.currentFrame;\n }\n\n /** Get all state names */\n get stateNames(): string[] {\n return Object.keys(this.doc.states);\n }\n\n /** Get current state duration */\n get duration(): number {\n return this.doc.states[this.currentState].duration;\n }\n\n /** Check if current state playback is complete */\n get isComplete(): boolean {\n return this.currentFrame >= this.duration - 1;\n }\n\n /** Check if currently in a transition blend */\n isTransitioning(): boolean {\n return this.activeTransition !== null;\n }\n\n /** Get transition progress (0–1) with easing applied, or null if not transitioning */\n getTransitionProgress(): number | null {\n if (!this.activeTransition) return null;\n const { transitionFrame, duration, easingFn } = this.activeTransition;\n const rawProgress = Math.min(transitionFrame / duration, 1);\n return easingFn(rawProgress);\n }\n\n // ── Hierarchical State Support ────────────────────────────\n\n /**\n * Resolve the ancestor chain for a state (root → … → parent → self).\n * Throws on circular parent references.\n */\n resolveAncestorChain(stateName: string): string[] {\n const chain: string[] = [];\n const visited = new Set<string>();\n let current: string | undefined = stateName;\n\n while (current) {\n if (visited.has(current)) {\n throw new Error(`Circular parent reference detected: \"${current}\" already in chain [${chain.join(\" → \")}]`);\n }\n visited.add(current);\n chain.unshift(current); // prepend so root is first\n const stateObj: State | undefined = this.doc.states[current];\n if (!stateObj) {\n throw new Error(`Parent state \"${current}\" not found`);\n }\n current = stateObj.parent;\n }\n\n return chain;\n }\n\n /**\n * Collect merged deltas from ancestor chain.\n * Child overrides parent deltas for the same layer+property combination.\n * Deltas for different layer+property pairs are accumulated from all ancestors.\n */\n collectDeltas(stateName: string): Delta[] {\n const chain = this.resolveAncestorChain(stateName);\n // Walk root → child. Later entries override earlier for same layer+property.\n const deltaMap = new Map<string, Delta[]>();\n\n for (const ancestorName of chain) {\n const state = this.doc.states[ancestorName];\n // Group this state's deltas by layer+property\n const stateGroups = new Map<string, Delta[]>();\n for (const delta of state.deltas) {\n const key = `${delta.layer}:${delta.property}`;\n if (!stateGroups.has(key)) stateGroups.set(key, []);\n stateGroups.get(key)!.push(delta);\n }\n // Child replaces parent for same key\n for (const [key, deltas] of stateGroups) {\n deltaMap.set(key, deltas);\n }\n }\n\n // Flatten all deltas\n const result: Delta[] = [];\n for (const deltas of deltaMap.values()) {\n result.push(...deltas);\n }\n return result;\n }\n\n // ── Playback ──────────────────────────────────────────────\n\n /** Advance to next frame, returns resolved frame */\n tick(): PlaybackState {\n // Handle active transition\n if (this.activeTransition) {\n this.activeTransition.transitionFrame++;\n if (this.activeTransition.transitionFrame >= this.activeTransition.duration) {\n // Transition complete\n this.activeTransition = null;\n }\n }\n\n const resolved = this.resolveCurrentFrame();\n const result: PlaybackState = {\n stateName: this.currentState,\n frame: this.currentFrame,\n resolved,\n isComplete: this.isComplete,\n };\n if (this.currentFrame < this.duration - 1) {\n this.currentFrame++;\n }\n return result;\n }\n\n /** Resolve the current frame, blending if in transition */\n private resolveCurrentFrame(): ResolvedFrame {\n if (this.activeTransition) {\n const progress = this.getTransitionProgress()!;\n const fromResolved = resolveFrame(\n this.doc, this.activeTransition.fromState, this.currentFrame,\n this.collectDeltas(this.activeTransition.fromState),\n );\n const toResolved = resolveFrame(\n this.doc, this.activeTransition.toState, this.currentFrame,\n this.collectDeltas(this.activeTransition.toState),\n );\n return blendResolvedFrames(fromResolved, toResolved, progress);\n }\n\n // Check if current state has a parent — use merged deltas\n const state = this.doc.states[this.currentState];\n if (state.parent) {\n const mergedDeltas = this.collectDeltas(this.currentState);\n return resolveFrame(this.doc, this.currentState, this.currentFrame, mergedDeltas);\n }\n\n return resolveFrame(this.doc, this.currentState, this.currentFrame);\n }\n\n /** Transition to a different state (instant or blended) */\n transition(stateName: string, startFrame = 0): void {\n if (!this.doc.states[stateName]) {\n throw new Error(`State \"${stateName}\" not found`);\n }\n\n const fromState = this.currentState;\n const currentStateObj = this.doc.states[fromState];\n const transConfig = currentStateObj.transitions?.[stateName];\n\n this.transitions.push({\n from: fromState,\n to: stateName,\n at: this.currentFrame,\n });\n\n if (transConfig && transConfig.duration > 0) {\n // Start a smooth transition\n this.activeTransition = {\n fromState,\n toState: stateName,\n duration: transConfig.duration,\n easingFn: resolveEasing(transConfig.easing),\n transitionFrame: 0,\n };\n }\n\n this.currentState = stateName;\n this.currentFrame = startFrame;\n }\n\n /**\n * Start a smooth transition to target state with explicit duration/easing.\n * This ignores any transitions config on the state.\n */\n transitionTo(targetState: string, duration: number, easing?: Easing): void {\n if (!this.doc.states[targetState]) {\n throw new Error(`State \"${targetState}\" not found`);\n }\n\n const fromState = this.currentState;\n this.transitions.push({\n from: fromState,\n to: targetState,\n at: this.currentFrame,\n });\n\n this.activeTransition = {\n fromState,\n toState: targetState,\n duration,\n easingFn: resolveEasing(easing),\n transitionFrame: 0,\n };\n\n this.currentState = targetState;\n this.currentFrame = 0;\n }\n\n /** Seek to a specific frame in current state */\n seek(frame: number): void {\n this.currentFrame = Math.max(0, Math.min(frame, this.duration - 1));\n }\n\n /** Reset to initial state */\n reset(stateName?: string): void {\n if (stateName) {\n if (!this.doc.states[stateName]) throw new Error(`State \"${stateName}\" not found`);\n this.currentState = stateName;\n }\n this.currentFrame = 0;\n this.activeTransition = null;\n }\n\n /** Get transition history */\n get history(): ReadonlyArray<StateTransition> {\n return this.transitions;\n }\n\n /** Resolve a specific frame without advancing */\n resolveAt(stateName: string, frame: number): ResolvedFrame {\n if (!this.doc.states[stateName]) throw new Error(`State \"${stateName}\" not found`);\n const state = this.doc.states[stateName];\n if (state.parent) {\n return resolveFrame(this.doc, stateName, frame, this.collectDeltas(stateName));\n }\n return resolveFrame(this.doc, stateName, frame);\n }\n\n /** Play through entire current state, calling callback on each frame */\n playThrough(onFrame: (state: PlaybackState) => void): void {\n this.currentFrame = 0;\n while (!this.isComplete) {\n onFrame(this.tick());\n }\n onFrame(this.tick()); // last frame\n }\n}\n\n// ── Frame Blending ────────────────────────────────────────────\n\nimport type { ResolvedLayer } from \"../resolver/frame-resolver.js\";\nimport type { AnimatableProperty } from \"@a-company/atelier-types\";\nimport { interpolateValue } from \"../resolver/delta-resolver.js\";\n\n/**\n * Blend two resolved frames together for smooth state transitions.\n * Numeric properties are lerped, colors are color-lerped, discrete values snap at t >= 0.5.\n */\nexport function blendResolvedFrames(\n frameA: ResolvedFrame,\n frameB: ResolvedFrame,\n t: number,\n): ResolvedFrame {\n // Build layer maps\n const mapA = new Map<string, ResolvedLayer>();\n const mapB = new Map<string, ResolvedLayer>();\n for (const l of frameA.layers) mapA.set(l.id, l);\n for (const l of frameB.layers) mapB.set(l.id, l);\n\n // Get all unique layer IDs\n const allIds = new Set([...mapA.keys(), ...mapB.keys()]);\n const blendedLayers: ResolvedLayer[] = [];\n\n for (const id of allIds) {\n const layerA = mapA.get(id);\n const layerB = mapB.get(id);\n\n if (layerA && layerB) {\n // Both exist — blend computed properties\n blendedLayers.push(blendLayers(layerA, layerB, t));\n } else if (layerA && !layerB) {\n // Only in A — fade out (set opacity toward 0)\n blendedLayers.push(fadeLayer(layerA, 1 - t));\n } else if (!layerA && layerB) {\n // Only in B — fade in (set opacity from 0)\n blendedLayers.push(fadeLayer(layerB, t));\n }\n }\n\n return {\n frame: frameB.frame,\n stateName: frameB.stateName,\n layers: blendedLayers,\n };\n}\n\nfunction blendLayers(a: ResolvedLayer, b: ResolvedLayer, t: number): ResolvedLayer {\n const allProps = new Set([\n ...Object.keys(a.computedProperties),\n ...Object.keys(b.computedProperties),\n ]);\n\n const blended: Partial<Record<AnimatableProperty, unknown>> = {};\n\n for (const prop of allProps) {\n const valA = a.computedProperties[prop as AnimatableProperty];\n const valB = b.computedProperties[prop as AnimatableProperty];\n\n if (valA !== undefined && valB !== undefined) {\n blended[prop as AnimatableProperty] = interpolateValue(valA, valB, t);\n } else if (valA !== undefined) {\n blended[prop as AnimatableProperty] = valA;\n } else {\n blended[prop as AnimatableProperty] = valB;\n }\n }\n\n return {\n id: a.id,\n layer: a.layer,\n computedProperties: blended,\n };\n}\n\nfunction fadeLayer(layer: ResolvedLayer, opacity: number): ResolvedLayer {\n const cp = { ...layer.computedProperties };\n const existingOpacity = (cp.opacity as number) ?? 1;\n cp.opacity = existingOpacity * opacity;\n return {\n id: layer.id,\n layer: layer.layer,\n computedProperties: cp,\n };\n}\n","import type { AtelierDocument } from \"@a-company/atelier-types\";\n\nexport interface TemplateBindings {\n [variableName: string]: unknown;\n}\n\nexport interface TemplateError {\n variable: string;\n message: string;\n}\n\nexport type TemplateResult =\n | {\n success: true;\n document: AtelierDocument;\n }\n | {\n success: false;\n errors: TemplateError[];\n };\n\n/**\n * Instantiate a template document by substituting variable values.\n * Walks the document tree, replacing {{variableName}} patterns with bound values.\n */\nexport function instantiateTemplate(\n template: AtelierDocument,\n bindings: TemplateBindings,\n): TemplateResult {\n // 1. Validate all required variables have bindings\n const errors: TemplateError[] = [];\n const variables = template.variables ?? {};\n\n for (const [name, variable] of Object.entries(variables)) {\n if (bindings[name] === undefined && variable.default === undefined) {\n errors.push({ variable: name, message: `Required variable \"${name}\" not provided` });\n }\n }\n\n // Check for unknown bindings\n for (const name of Object.keys(bindings)) {\n if (!variables[name]) {\n errors.push({ variable: name, message: `Unknown variable \"${name}\"` });\n }\n }\n\n if (errors.length > 0) return { success: false, errors };\n\n // 2. Merge bindings with defaults\n const resolved: Record<string, unknown> = {};\n for (const [name, variable] of Object.entries(variables)) {\n resolved[name] = bindings[name] ?? variable.default;\n }\n\n // 3. Deep clone and substitute\n const doc = JSON.parse(JSON.stringify(template)) as AtelierDocument;\n substituteInObject(doc as unknown as Record<string, unknown>, resolved);\n\n // 4. Remove variables section (no longer a template)\n delete doc.variables;\n\n return { success: true, document: doc };\n}\n\n/**\n * Recursively substitute {{variableName}} patterns in string values.\n */\nfunction substituteInObject(obj: Record<string, unknown>, bindings: Record<string, unknown>): void {\n for (const key of Object.keys(obj)) {\n const value = obj[key];\n if (typeof value === \"string\") {\n obj[key] = substituteString(value, bindings);\n } else if (Array.isArray(value)) {\n substituteInArray(value, bindings);\n } else if (value !== null && typeof value === \"object\") {\n substituteInObject(value as Record<string, unknown>, bindings);\n }\n }\n}\n\nfunction substituteInArray(arr: unknown[], bindings: Record<string, unknown>): void {\n for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n if (typeof value === \"string\") {\n arr[i] = substituteString(value, bindings);\n } else if (Array.isArray(value)) {\n substituteInArray(value, bindings);\n } else if (value !== null && typeof value === \"object\") {\n substituteInObject(value as Record<string, unknown>, bindings);\n }\n }\n}\n\n/**\n * Replace {{variableName}} in a string with the bound value.\n * If the entire string is a single {{var}}, return the raw value (preserving type).\n * Otherwise, interpolate into the string.\n */\nfunction substituteString(str: string, bindings: Record<string, unknown>): unknown {\n // Exact match: entire string is {{varName}} -> return raw value\n const exactMatch = str.match(/^\\{\\{(\\w+)\\}\\}$/);\n if (exactMatch) {\n const name = exactMatch[1];\n return name in bindings ? bindings[name] : str;\n }\n\n // Partial match: replace all {{varName}} occurrences with string values\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (_, name: string) => {\n return name in bindings ? String(bindings[name]) : `{{${name}}}`;\n });\n}\n\n/**\n * List all variables used in a document (scan for {{variableName}} patterns).\n */\nexport function findTemplateVariables(doc: AtelierDocument): string[] {\n const vars = new Set<string>();\n scanForVariables(doc, vars);\n return Array.from(vars);\n}\n\nfunction scanForVariables(value: unknown, vars: Set<string>): void {\n if (typeof value === \"string\") {\n const matches = value.matchAll(/\\{\\{(\\w+)\\}\\}/g);\n for (const match of matches) {\n vars.add(match[1]);\n }\n } else if (Array.isArray(value)) {\n for (const item of value) scanForVariables(item, vars);\n } else if (value !== null && typeof value === \"object\") {\n for (const v of Object.values(value as Record<string, unknown>)) {\n scanForVariables(v, vars);\n }\n }\n}\n","import type { Audio } from \"@a-company/atelier-types\";\n\n/** Audio playback state at a given frame */\nexport interface AudioPlaybackState {\n /** Whether audio should be playing at this frame */\n shouldPlay: boolean;\n /** Current position in the audio track (seconds) */\n currentTime: number;\n /** Effective volume (0–1) */\n volume: number;\n}\n\n/**\n * Convert a frame number to time in seconds.\n */\nexport function frameToTime(frame: number, fps: number): number {\n return frame / fps;\n}\n\n/**\n * Convert time in seconds to a frame number (floored).\n */\nexport function timeToFrame(time: number, fps: number): number {\n return Math.floor(time * fps);\n}\n\n/**\n * Compute the audio playback state for a given frame.\n *\n * @param audio - Audio configuration from a state\n * @param frame - Current frame number within the state\n * @param fps - Frames per second from canvas config\n * @param stateDuration - Total state duration in frames\n * @returns AudioPlaybackState with shouldPlay, currentTime, and volume\n */\nexport function computeAudioState(\n audio: Audio,\n frame: number,\n fps: number,\n stateDuration: number,\n): AudioPlaybackState {\n const startFrame = audio.startFrame ?? 0;\n const offset = audio.offset ?? 0;\n const volume = audio.volume ?? 1;\n const loop = audio.loop ?? false;\n\n // Before audio starts\n if (frame < startFrame) {\n return { shouldPlay: false, currentTime: 0, volume };\n }\n\n // Time elapsed since audio started\n const elapsedFrames = frame - startFrame;\n const elapsedTime = frameToTime(elapsedFrames, fps);\n\n // Total available playback time (from startFrame to end of state)\n const availableFrames = stateDuration - startFrame;\n const availableTime = frameToTime(availableFrames, fps);\n\n if (!loop) {\n // Non-looping: audio plays from offset, stops at end of state\n const currentTime = offset + elapsedTime;\n return {\n shouldPlay: frame < stateDuration,\n currentTime,\n volume,\n };\n }\n\n // Looping: wrap elapsed time around available duration\n // The audio segment length is the available time\n const segmentDuration = availableTime;\n if (segmentDuration <= 0) {\n return { shouldPlay: false, currentTime: 0, volume };\n }\n\n const wrappedTime = elapsedTime % segmentDuration;\n const currentTime = offset + wrappedTime;\n\n return {\n shouldPlay: frame < stateDuration,\n currentTime,\n volume,\n };\n}\n\n/**\n * Compute audio cue points — frames where audio events occur.\n *\n * @param audio - Audio configuration\n * @param stateDuration - Total state duration in frames\n * @returns Array of { frame, event } describing audio events\n */\nexport function computeAudioCues(\n audio: Audio,\n stateDuration: number,\n): Array<{ frame: number; event: \"start\" | \"end\" | \"loop\" }> {\n const startFrame = audio.startFrame ?? 0;\n const loop = audio.loop ?? false;\n const cues: Array<{ frame: number; event: \"start\" | \"end\" | \"loop\" }> = [];\n\n if (startFrame < stateDuration) {\n cues.push({ frame: startFrame, event: \"start\" });\n }\n\n if (loop) {\n // In loop mode, audio restarts each full cycle\n const availableFrames = stateDuration - startFrame;\n if (availableFrames > 0) {\n // Loop points at each full cycle\n for (let i = 1; startFrame + i * availableFrames < stateDuration; i++) {\n cues.push({ frame: startFrame + i * availableFrames, event: \"loop\" });\n }\n }\n }\n\n // Audio ends when state ends\n if (stateDuration > startFrame) {\n cues.push({ frame: stateDuration - 1, event: \"end\" });\n }\n\n return cues;\n}\n","import type { Fill, Stroke, Color, RGBAColor, HSLAColor } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"./canvas-types.js\";\n\n/**\n * Convert an Atelier Color to a CSS color string.\n */\nexport function colorToCSS(color: Color): string {\n if (typeof color === \"string\") return color; // hex string\n\n if (\"r\" in color) {\n const c = color as RGBAColor;\n return `rgba(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)}, ${c.a})`;\n }\n\n if (\"h\" in color) {\n const c = color as HSLAColor;\n return `hsla(${c.h}, ${c.s}%, ${c.l}%, ${c.a})`;\n }\n\n return \"#000000\";\n}\n\n/**\n * Apply a Fill to the canvas context's fillStyle.\n */\nexport function applyFill(ctx: RenderContext, fill: Fill, width: number, height: number): void {\n switch (fill.type) {\n case \"solid\":\n ctx.fillStyle = colorToCSS(fill.color);\n break;\n\n case \"linear-gradient\": {\n const rad = (fill.angle * Math.PI) / 180;\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const halfW = width / 2;\n const halfH = height / 2;\n const grad = ctx.createLinearGradient(\n halfW - cos * halfW, halfH - sin * halfH,\n halfW + cos * halfW, halfH + sin * halfH,\n );\n for (const stop of fill.stops) {\n grad.addColorStop(stop.offset, colorToCSS(stop.color));\n }\n ctx.fillStyle = grad as unknown as string;\n break;\n }\n\n case \"radial-gradient\": {\n const cx = typeof fill.center.x === \"number\" ? fill.center.x : (parseFloat(fill.center.x) / 100) * width;\n const cy = typeof fill.center.y === \"number\" ? fill.center.y : (parseFloat(fill.center.y) / 100) * height;\n const r = typeof fill.radius === \"number\" ? fill.radius : (parseFloat(fill.radius) / 100) * Math.max(width, height);\n const grad = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);\n for (const stop of fill.stops) {\n grad.addColorStop(stop.offset, colorToCSS(stop.color));\n }\n ctx.fillStyle = grad as unknown as string;\n break;\n }\n }\n}\n\n/**\n * Apply a Stroke to the canvas context.\n * @param pathLength - total perimeter of the shape (needed for strokeStart/strokeEnd trim)\n */\nexport function applyStroke(ctx: RenderContext, stroke: Stroke, pathLength: number): void {\n ctx.strokeStyle = colorToCSS(stroke.color);\n ctx.lineWidth = stroke.width;\n if (stroke.lineCap) ctx.lineCap = stroke.lineCap;\n if (stroke.lineJoin) ctx.lineJoin = stroke.lineJoin;\n\n const start = stroke.strokeStart ?? 0;\n const end = stroke.strokeEnd ?? 1;\n\n if (start !== 0 || end !== 1) {\n const visible = (end - start) * pathLength;\n ctx.setLineDash([Math.max(visible, 0), pathLength + 1]);\n ctx.lineDashOffset = -start * pathLength;\n } else if (stroke.dash) {\n ctx.setLineDash(stroke.dash);\n }\n}\n","import type { Layer, Visual, ShapeVisual, TextVisual, ImageVisual, Color, BlendMode, LinearGradientFill, RadialGradientFill } from \"@a-company/atelier-types\";\nimport { colorToCSS } from \"./styles.js\";\nimport { evaluatePathAtProgress } from \"@a-company/atelier-math\";\nimport type { ResolvedLayer } from \"@a-company/atelier-core\";\n\n/**\n * Effective values for a layer at a given frame,\n * with computed properties merged over defaults.\n */\nexport interface EffectiveLayer {\n /** Original layer */\n layer: Layer;\n /** Visual with animated property overrides applied */\n visual: Visual;\n /** Effective frame position (may be animated) */\n x: number;\n y: number;\n /** Effective bounds */\n width: number;\n height: number;\n /** Effective transform values */\n opacity: number;\n rotation: number;\n scaleX: number;\n scaleY: number;\n anchorX: number;\n anchorY: number;\n /** Resolved shadow (if layer has shadow or shadow is animated) */\n shadow?: {\n color: string;\n blur: number;\n offsetX: number;\n offsetY: number;\n };\n /** Blend mode for compositing */\n blendMode: string;\n /** Motion path auto-rotation in degrees (applied additively to rotation) */\n motionPathAngle: number;\n /** Whether this layer is visible (may be animated) */\n visible: boolean;\n /** Color tint overlay */\n tint?: {\n color: string;\n amount: number;\n };\n}\n\n/**\n * Resolve a UnitValue to pixels. Percentages resolve against a reference dimension.\n */\nfunction resolveUnit(value: number | string, reference: number): number {\n if (typeof value === \"string\" && value.endsWith(\"%\")) {\n return (parseFloat(value) / 100) * reference;\n }\n return value as number;\n}\n\n/**\n * Build the effective layer values by merging computed properties over layer defaults.\n * @param resolved - The resolved layer from frame resolution\n * @param parentWidth - Parent/canvas width for percentage resolution\n * @param parentHeight - Parent/canvas height for percentage resolution\n */\nexport function buildEffectiveLayer(\n resolved: ResolvedLayer,\n parentWidth: number,\n parentHeight: number,\n): EffectiveLayer {\n const { layer, computedProperties } = resolved;\n const cp = computedProperties as Record<string, unknown>;\n\n const hasShadow = layer.shadow || cp[\"shadow.blur\"] !== undefined || cp[\"shadow.color\"] !== undefined;\n const hasTint = layer.tint || cp[\"tint.amount\"] !== undefined || cp[\"tint.color\"] !== undefined;\n\n // Resolve base position\n let x = resolveUnit((cp[\"frame.x\"] ?? layer.frame.x) as number | string, parentWidth);\n let y = resolveUnit((cp[\"frame.y\"] ?? layer.frame.y) as number | string, parentHeight);\n let motionPathAngle = 0;\n\n // Motion path overrides position when progress is animated\n const motionProgress = cp[\"motionPath.progress\"] as number | undefined;\n if (motionProgress !== undefined && layer.motionPath && layer.motionPath.points.length >= 2) {\n const pos = evaluatePathAtProgress(layer.motionPath.points, motionProgress, layer.motionPath.closed);\n x = pos.x;\n y = pos.y;\n if (layer.motionPath.autoRotate) {\n motionPathAngle = pos.angle + (layer.motionPath.autoRotateOffset ?? 0);\n }\n }\n\n return {\n layer,\n visual: buildEffectiveVisual(layer.visual, cp),\n x,\n y,\n width: resolveUnit((cp[\"bounds.width\"] ?? layer.bounds.width) as number | string, parentWidth),\n height: resolveUnit((cp[\"bounds.height\"] ?? layer.bounds.height) as number | string, parentHeight),\n opacity: (cp[\"opacity\"] as number) ?? layer.opacity ?? 1,\n rotation: (cp[\"rotation\"] as number) ?? layer.rotation ?? 0,\n scaleX: (cp[\"scale.x\"] as number) ?? layer.scale?.x ?? 1,\n scaleY: (cp[\"scale.y\"] as number) ?? layer.scale?.y ?? 1,\n anchorX: (cp[\"anchorPoint.x\"] as number) ?? layer.anchorPoint?.x ?? 0,\n anchorY: (cp[\"anchorPoint.y\"] as number) ?? layer.anchorPoint?.y ?? 0,\n shadow: hasShadow ? {\n color: colorToCSS((cp[\"shadow.color\"] ?? layer.shadow?.color ?? \"#00000080\") as Color),\n blur: (cp[\"shadow.blur\"] as number) ?? layer.shadow?.blur ?? 0,\n offsetX: (cp[\"shadow.offsetX\"] as number) ?? layer.shadow?.offsetX ?? 0,\n offsetY: (cp[\"shadow.offsetY\"] as number) ?? layer.shadow?.offsetY ?? 0,\n } : undefined,\n blendMode: (layer.blendMode as BlendMode) ?? \"normal\",\n motionPathAngle,\n visible: (cp[\"visible\"] as boolean) ?? layer.visible ?? true,\n tint: hasTint ? {\n color: colorToCSS((cp[\"tint.color\"] ?? layer.tint?.color ?? \"#FF0000\") as Color),\n amount: (cp[\"tint.amount\"] as number) ?? layer.tint?.amount ?? 0,\n } : undefined,\n };\n}\n\n/**\n * Build an effective visual by applying computed property overrides.\n * Returns the original visual if no visual properties are animated.\n */\nfunction buildEffectiveVisual(visual: Visual, cp: Record<string, unknown>): Visual {\n const hasVisualOverride =\n cp[\"visual.fill.color\"] !== undefined ||\n cp[\"visual.fill.angle\"] !== undefined ||\n cp[\"visual.fill.center.x\"] !== undefined ||\n cp[\"visual.fill.center.y\"] !== undefined ||\n cp[\"visual.fill.radius\"] !== undefined ||\n cp[\"visual.stroke.color\"] !== undefined ||\n cp[\"visual.stroke.width\"] !== undefined ||\n cp[\"visual.stroke.start\"] !== undefined ||\n cp[\"visual.stroke.end\"] !== undefined ||\n cp[\"visual.shape.cornerRadius\"] !== undefined ||\n cp[\"visual.style.fontSize\"] !== undefined ||\n cp[\"visual.style.color\"] !== undefined;\n\n const hasImageOverride =\n cp[\"visual.image.sourceRect.x\"] !== undefined ||\n cp[\"visual.image.sourceRect.y\"] !== undefined ||\n cp[\"visual.image.sourceRect.width\"] !== undefined ||\n cp[\"visual.image.sourceRect.height\"] !== undefined ||\n cp[\"visual.image.frameIndex\"] !== undefined;\n\n if (!hasVisualOverride && !hasImageOverride) return visual;\n\n if (visual.type === \"shape\") {\n const v: ShapeVisual = { ...visual };\n\n if (cp[\"visual.shape.cornerRadius\"] !== undefined && v.shape.type === \"rect\") {\n v.shape = { ...v.shape, cornerRadius: cp[\"visual.shape.cornerRadius\"] as number };\n }\n\n if (v.fill) {\n if (cp[\"visual.fill.color\"] !== undefined && v.fill.type === \"solid\") {\n v.fill = { ...v.fill, color: cp[\"visual.fill.color\"] as string };\n }\n if (cp[\"visual.fill.angle\"] !== undefined && v.fill.type === \"linear-gradient\") {\n v.fill = { ...v.fill, angle: cp[\"visual.fill.angle\"] as number } as LinearGradientFill;\n }\n if (v.fill.type === \"radial-gradient\") {\n const cx = cp[\"visual.fill.center.x\"];\n const cy = cp[\"visual.fill.center.y\"];\n const r = cp[\"visual.fill.radius\"];\n if (cx !== undefined || cy !== undefined || r !== undefined) {\n const f = v.fill as RadialGradientFill;\n v.fill = {\n ...f,\n center: {\n x: cx !== undefined ? (cx as number) : f.center.x,\n y: cy !== undefined ? (cy as number) : f.center.y,\n },\n radius: r !== undefined ? (r as number) : f.radius,\n } as RadialGradientFill;\n }\n }\n }\n\n if (v.stroke) {\n const strokeColor = cp[\"visual.stroke.color\"] ?? v.stroke.color;\n const strokeWidth = (cp[\"visual.stroke.width\"] as number) ?? v.stroke.width;\n const strokeStart = (cp[\"visual.stroke.start\"] as number | undefined) ?? v.stroke.strokeStart;\n const strokeEnd = (cp[\"visual.stroke.end\"] as number | undefined) ?? v.stroke.strokeEnd;\n if (\n strokeColor !== v.stroke.color ||\n strokeWidth !== v.stroke.width ||\n strokeStart !== v.stroke.strokeStart ||\n strokeEnd !== v.stroke.strokeEnd\n ) {\n v.stroke = {\n ...v.stroke,\n color: strokeColor as string,\n width: strokeWidth,\n strokeStart,\n strokeEnd,\n };\n }\n }\n\n return v;\n }\n\n if (visual.type === \"text\") {\n const v: TextVisual = { ...visual };\n const fontSize = (cp[\"visual.style.fontSize\"] as number) ?? v.style.fontSize;\n const color = cp[\"visual.style.color\"] ?? v.style.color;\n if (fontSize !== v.style.fontSize || color !== v.style.color) {\n v.style = { ...v.style, fontSize, color: color as string };\n }\n return v;\n }\n\n if (visual.type === \"image\" && hasImageOverride) {\n const v: ImageVisual = { ...visual };\n\n // Merge animated sourceRect fields\n if (\n cp[\"visual.image.sourceRect.x\"] !== undefined ||\n cp[\"visual.image.sourceRect.y\"] !== undefined ||\n cp[\"visual.image.sourceRect.width\"] !== undefined ||\n cp[\"visual.image.sourceRect.height\"] !== undefined\n ) {\n const base = v.sourceRect ?? { x: 0, y: 0, width: 0, height: 0 };\n v.sourceRect = {\n x: (cp[\"visual.image.sourceRect.x\"] as number) ?? base.x,\n y: (cp[\"visual.image.sourceRect.y\"] as number) ?? base.y,\n width: (cp[\"visual.image.sourceRect.width\"] as number) ?? base.width,\n height: (cp[\"visual.image.sourceRect.height\"] as number) ?? base.height,\n };\n }\n\n // Merge animated frameIndex\n if (cp[\"visual.image.frameIndex\"] !== undefined) {\n v.frameIndex = Math.floor(cp[\"visual.image.frameIndex\"] as number);\n }\n\n return v;\n }\n\n return visual;\n}\n","import type { ShapeVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport { applyFill, applyStroke } from \"../styles.js\";\n\nexport function renderShape(ctx: RenderContext, eff: EffectiveLayer): void {\n const visual = eff.visual as ShapeVisual;\n const { shape } = visual;\n const { width, height } = eff;\n\n switch (shape.type) {\n case \"rect\":\n renderRect(ctx, width, height, shape.cornerRadius, visual);\n break;\n case \"ellipse\":\n renderEllipse(ctx, width, height, visual);\n break;\n case \"path\":\n renderPath(ctx, shape.points, shape.closed, visual);\n break;\n }\n}\n\n// ── Perimeter helpers ───────────────────────────────────────\n\nfunction rectPerimeter(w: number, h: number): number {\n return 2 * (w + h);\n}\n\nfunction ellipsePerimeter(w: number, h: number): number {\n const a = w / 2;\n const b = h / 2;\n // Ramanujan approximation\n return Math.PI * (3 * (a + b) - Math.sqrt((3 * a + b) * (a + 3 * b)));\n}\n\nfunction dist(x1: number, y1: number, x2: number, y2: number): number {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction pathPerimeter(\n points: { x: number; y: number; in?: { x: number; y: number }; out?: { x: number; y: number } }[],\n closed: boolean | undefined,\n): number {\n let length = 0;\n for (let i = 1; i < points.length; i++) {\n const prev = points[i - 1];\n const curr = points[i];\n if (prev.out && curr.in) {\n // Approximate bezier with chord * 1.2\n length += dist(prev.x, prev.y, curr.x, curr.y) * 1.2;\n } else {\n length += dist(prev.x, prev.y, curr.x, curr.y);\n }\n }\n if (closed && points.length > 1) {\n const first = points[0];\n const last = points[points.length - 1];\n length += dist(last.x, last.y, first.x, first.y);\n }\n return length;\n}\n\n// ── Renderers ───────────────────────────────────────────────\n\nfunction renderRect(\n ctx: RenderContext,\n width: number,\n height: number,\n cornerRadius: number | [number, number, number, number] | undefined,\n visual: ShapeVisual,\n): void {\n if (visual.fill) {\n applyFill(ctx, visual.fill, width, height);\n if (cornerRadius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(0, 0, width, height, cornerRadius);\n ctx.fill();\n } else {\n ctx.fillRect(0, 0, width, height);\n }\n }\n if (visual.stroke) {\n const perimeter = rectPerimeter(width, height);\n applyStroke(ctx, visual.stroke, perimeter);\n if (cornerRadius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(0, 0, width, height, cornerRadius);\n ctx.stroke();\n } else {\n ctx.strokeRect(0, 0, width, height);\n }\n }\n}\n\nfunction renderEllipse(\n ctx: RenderContext,\n width: number,\n height: number,\n visual: ShapeVisual,\n): void {\n ctx.beginPath();\n ctx.ellipse(width / 2, height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);\n\n if (visual.fill) {\n applyFill(ctx, visual.fill, width, height);\n ctx.fill();\n }\n if (visual.stroke) {\n const perimeter = ellipsePerimeter(width, height);\n applyStroke(ctx, visual.stroke, perimeter);\n ctx.stroke();\n }\n}\n\nfunction renderPath(\n ctx: RenderContext,\n points: { x: number; y: number; in?: { x: number; y: number }; out?: { x: number; y: number } }[],\n closed: boolean | undefined,\n visual: ShapeVisual,\n): void {\n if (points.length < 2) return;\n\n ctx.beginPath();\n ctx.moveTo(points[0].x, points[0].y);\n\n for (let i = 1; i < points.length; i++) {\n const prev = points[i - 1];\n const curr = points[i];\n\n if (prev.out && curr.in) {\n ctx.bezierCurveTo(\n prev.x + prev.out.x, prev.y + prev.out.y,\n curr.x + curr.in.x, curr.y + curr.in.y,\n curr.x, curr.y,\n );\n } else {\n ctx.lineTo(curr.x, curr.y);\n }\n }\n\n if (closed) ctx.closePath();\n\n if (visual.fill) {\n applyFill(ctx, visual.fill, 0, 0);\n ctx.fill();\n }\n if (visual.stroke) {\n const perimeter = pathPerimeter(points, closed);\n applyStroke(ctx, visual.stroke, perimeter);\n ctx.stroke();\n }\n}\n","import type { TextVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport { colorToCSS } from \"../styles.js\";\n\nexport function renderText(ctx: RenderContext, eff: EffectiveLayer): void {\n const visual = eff.visual as TextVisual;\n const { style } = visual;\n\n // Build font string\n const fontStyle = style.fontStyle ?? \"normal\";\n const fontWeight = style.fontWeight ?? \"normal\";\n const fontSize = style.fontSize;\n const fontFamily = style.fontFamily;\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;\n\n // Set alignment — position text within its bounding box\n const align = style.textAlign ?? \"left\";\n ctx.textAlign = align;\n ctx.textBaseline = \"top\";\n\n // Set color\n ctx.fillStyle = colorToCSS(style.color);\n\n // Canvas 2D textAlign anchors at the draw point, so offset within bounds:\n // \"left\" → draw at x=0 (text flows right from left edge)\n // \"center\" → draw at x=width/2 (text centers within bounds)\n // \"right\" → draw at x=width (text flows left from right edge)\n let textX = 0;\n if (align === \"center\") {\n textX = eff.width / 2;\n } else if (align === \"right\") {\n textX = eff.width;\n }\n\n ctx.fillText(visual.content, textX, 0);\n}\n","import type { ImageVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport type { ImageCache } from \"../image-cache.js\";\n\n/**\n * Render an image layer to the canvas.\n * Supports sourceRect cropping and spritesheet grid animation.\n * If the image hasn't loaded yet, triggers a cache load and returns\n * (the image will appear on the next re-render).\n */\nexport function renderImage(ctx: RenderContext, eff: EffectiveLayer, imageCache: ImageCache): void {\n const visual = eff.visual as ImageVisual;\n const src = visual.src;\n if (!src) return;\n\n const img = imageCache.get(src);\n if (!img) {\n imageCache.load(src);\n return;\n }\n\n // Spritesheet grid computation takes precedence over manual sourceRect\n if (visual.spritesheet) {\n const { columns, rows, frameWidth, frameHeight, frameCount } = visual.spritesheet;\n const maxFrames = frameCount ?? (columns * rows);\n const idx = Math.max(0, Math.min(Math.floor(visual.frameIndex ?? 0), maxFrames - 1));\n const col = idx % columns;\n const row = Math.floor(idx / columns);\n const sx = col * frameWidth;\n const sy = row * frameHeight;\n (ctx.drawImage as Function)(img, sx, sy, frameWidth, frameHeight, 0, 0, eff.width, eff.height);\n return;\n }\n\n // Manual sourceRect crop\n if (visual.sourceRect) {\n const sr = visual.sourceRect;\n (ctx.drawImage as Function)(img, sr.x, sr.y, sr.width, sr.height, 0, 0, eff.width, eff.height);\n return;\n }\n\n // Default: draw full image to bounds\n ctx.drawImage(img, 0, 0, eff.width, eff.height);\n}\n","import type { VideoVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext, VideoFrameProvider } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\n\n/**\n * Render a video layer to the canvas at the given source time.\n * Delegates actual frame extraction to the injected VideoFrameProvider,\n * which may be backed by HTMLVideoElement (preview) or WebCodecs (export).\n * Returns without drawing if the provider returns null — caller retries next tick.\n */\nexport function renderVideo(\n ctx: RenderContext,\n eff: EffectiveLayer,\n sourceTime: number,\n provider: VideoFrameProvider,\n): void {\n const visual = eff.visual as VideoVisual;\n const src = visual.src;\n if (!src) return;\n\n const frame = provider(src, sourceTime, eff.width, eff.height);\n if (!frame) return;\n\n ctx.drawImage(frame as unknown, 0, 0, eff.width, eff.height);\n}\n","import type { AtelierDocument, RefVisual, ImageVisual } from \"@a-company/atelier-types\";\nimport { resolveFrame } from \"@a-company/atelier-core\";\nimport type { RenderContext, DocumentResolver } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport { buildEffectiveLayer } from \"../apply-properties.js\";\nimport { renderShape } from \"./shape-renderer.js\";\nimport { renderText } from \"./text-renderer.js\";\nimport { renderImage } from \"./image-renderer.js\";\nimport type { ImageCache } from \"../image-cache.js\";\n\nexport interface RefRenderOpts {\n documentResolver?: DocumentResolver;\n maxRefDepth?: number;\n imageCache?: ImageCache;\n /** Internal: tracks visited refs for cycle detection */\n _visitedRefs?: Set<string>;\n /** Internal: current recursion depth */\n _depth?: number;\n}\n\n/**\n * Render a ref layer. If a documentResolver is provided, resolves and renders\n * the sub-document inline. Otherwise falls back to a placeholder rectangle.\n */\nexport function renderRef(\n ctx: RenderContext,\n eff: EffectiveLayer,\n opts?: RefRenderOpts,\n _parentDoc?: AtelierDocument,\n): void {\n const visual = eff.visual as RefVisual;\n const resolver = opts?.documentResolver;\n\n if (!resolver) {\n renderPlaceholder(ctx, eff, `REF: ${visual.src}`);\n return;\n }\n\n const depth = opts?._depth ?? 0;\n const maxDepth = opts?.maxRefDepth ?? 4;\n\n if (depth >= maxDepth) {\n renderPlaceholder(ctx, eff, \"MAX DEPTH\");\n return;\n }\n\n const visitedRefs = opts?._visitedRefs ?? new Set<string>();\n\n if (visitedRefs.has(visual.src)) {\n renderPlaceholder(ctx, eff, \"CYCLE\");\n return;\n }\n\n const subDoc = resolver(visual.src);\n if (!subDoc) {\n renderPlaceholder(ctx, eff, \"NOT FOUND\");\n return;\n }\n\n // Determine which state and frame to render\n const stateNames = Object.keys(subDoc.states);\n if (stateNames.length === 0) {\n renderPlaceholder(ctx, eff, \"NO STATES\");\n return;\n }\n\n const stateName = visual.state ?? stateNames[0];\n const stateObj = subDoc.states[stateName];\n if (!stateObj) {\n renderPlaceholder(ctx, eff, `STATE? ${stateName}`);\n return;\n }\n\n const maxFrame = Math.max(0, stateObj.duration - 1);\n const frame = Math.min(visual.frame ?? 0, maxFrame);\n\n // Resolve the sub-document frame\n const resolved = resolveFrame(subDoc, stateName, frame);\n\n // Mark as visited for cycle detection\n visitedRefs.add(visual.src);\n\n // Scale to fit eff bounds\n const scaleX = eff.width / subDoc.canvas.width;\n const scaleY = eff.height / subDoc.canvas.height;\n\n ctx.save();\n ctx.scale(scaleX, scaleY);\n\n // Build and render sub-doc layers\n const { width: subW, height: subH } = subDoc.canvas;\n\n for (const resolvedLayer of resolved.layers) {\n const subEff = buildEffectiveLayer(resolvedLayer, subW, subH);\n\n if (!subEff.visible) continue;\n if (subEff.opacity <= 0) continue;\n\n // Resolve asset for images\n if (resolvedLayer.layer.visual.type === \"image\") {\n const iv = subEff.visual as ImageVisual;\n if (!iv.src && iv.assetId && subDoc.assets?.[iv.assetId]) {\n iv.src = subDoc.assets[iv.assetId].src;\n }\n }\n\n ctx.save();\n ctx.globalAlpha = subEff.opacity;\n ctx.translate(subEff.x, subEff.y);\n\n switch (resolvedLayer.layer.visual.type) {\n case \"shape\":\n renderShape(ctx, subEff);\n break;\n case \"text\":\n renderText(ctx, subEff);\n break;\n case \"image\":\n if (opts?.imageCache) renderImage(ctx, subEff, opts.imageCache);\n break;\n case \"ref\":\n renderRef(ctx, subEff, {\n ...opts,\n _visitedRefs: visitedRefs,\n _depth: depth + 1,\n }, subDoc);\n break;\n case \"group\":\n break;\n }\n\n ctx.restore();\n }\n\n ctx.restore();\n\n // Remove from visited after rendering (allow same ref in different branches)\n visitedRefs.delete(visual.src);\n}\n\n/** Render a dashed placeholder rectangle with label */\nfunction renderPlaceholder(ctx: RenderContext, eff: EffectiveLayer, label: string): void {\n const { width, height } = eff;\n\n ctx.strokeStyle = \"#888888\";\n ctx.lineWidth = 2;\n ctx.setLineDash([6, 4]);\n ctx.strokeRect(0, 0, width, height);\n ctx.setLineDash([]);\n\n ctx.fillStyle = \"#888888\";\n ctx.font = `${Math.max(12, Math.min(16, height * 0.15))}px sans-serif`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(label, width / 2, height / 2, width - 8);\n}\n","import type { AtelierDocument, ImageVisual, VideoVisual, Shape } from \"@a-company/atelier-types\";\nimport type { ResolvedFrame } from \"@a-company/atelier-core\";\nimport type { RenderContext, DocumentResolver, VideoFrameProvider } from \"./canvas-types.js\";\nimport { buildEffectiveLayer, type EffectiveLayer } from \"./apply-properties.js\";\nimport { renderShape } from \"./renderers/shape-renderer.js\";\nimport { renderText } from \"./renderers/text-renderer.js\";\nimport { renderImage } from \"./renderers/image-renderer.js\";\nimport { renderVideo } from \"./renderers/video-renderer.js\";\nimport { renderRef } from \"./renderers/ref-renderer.js\";\nimport type { ImageCache } from \"./image-cache.js\";\n\n/** Options for renderFrame */\nexport interface RenderOptions {\n imageCache?: ImageCache;\n documentResolver?: DocumentResolver;\n maxRefDepth?: number;\n videoFrameProvider?: VideoFrameProvider;\n}\n\n/**\n * Render a resolved frame to a Canvas 2D context.\n * Clears the canvas and draws all visible layers in order.\n */\nexport function renderFrame(\n ctx: RenderContext,\n resolvedFrame: ResolvedFrame,\n doc: AtelierDocument,\n optsOrCache?: RenderOptions | ImageCache,\n): void {\n // Backward compatible: detect old ImageCache arg vs new RenderOptions\n let imageCache: ImageCache | undefined;\n let documentResolver: DocumentResolver | undefined;\n let videoFrameProvider: VideoFrameProvider | undefined;\n let maxRefDepth = 4;\n\n if (optsOrCache && typeof (optsOrCache as ImageCache).get === \"function\") {\n imageCache = optsOrCache as ImageCache;\n } else if (optsOrCache) {\n const opts = optsOrCache as RenderOptions;\n imageCache = opts.imageCache;\n documentResolver = opts.documentResolver;\n videoFrameProvider = opts.videoFrameProvider;\n maxRefDepth = opts.maxRefDepth ?? 4;\n }\n const { width, height } = doc.canvas;\n\n // Clear canvas\n ctx.fillStyle = doc.canvas.background ?? \"transparent\";\n ctx.fillRect(0, 0, width, height);\n\n // Build effective layers into a map for ancestor transform lookups\n const effMap = new Map<string, EffectiveLayer>();\n const effList: EffectiveLayer[] = [];\n const videoSourceTimeMap = new Map<string, number>();\n\n for (const resolvedLayer of resolvedFrame.layers) {\n const eff = buildEffectiveLayer(resolvedLayer, width, height);\n effMap.set(resolvedLayer.layer.id, eff);\n effList.push(eff);\n if (resolvedLayer.videoSourceTime !== undefined) {\n videoSourceTimeMap.set(resolvedLayer.layer.id, resolvedLayer.videoSourceTime);\n }\n }\n\n // Render each layer in order (painters algorithm — first = back)\n for (const eff of effList) {\n const { layer } = eff;\n\n // Skip invisible layers\n if (!eff.visible) continue;\n\n // Skip fully transparent layers\n if (eff.opacity <= 0) continue;\n\n // Resolve assetId → src for image visuals\n if (layer.visual.type === \"image\") {\n const iv = eff.visual as ImageVisual;\n if (!iv.src && iv.assetId && doc.assets?.[iv.assetId]) {\n iv.src = doc.assets[iv.assetId].src;\n }\n }\n\n // Resolve assetId → src for video visuals\n if (layer.visual.type === \"video\") {\n const vv = eff.visual as VideoVisual;\n if (!vv.src && vv.assetId && doc.assets?.[vv.assetId]) {\n vv.src = doc.assets[vv.assetId].src;\n }\n }\n\n ctx.save();\n\n // Apply ancestor transforms (group/parent inheritance)\n applyAncestorTransforms(ctx, layer.id, effMap, doc);\n\n // Apply transforms\n ctx.globalAlpha = eff.opacity;\n\n // Apply blend mode\n if (eff.blendMode !== \"normal\") {\n ctx.globalCompositeOperation = blendModeToComposite(eff.blendMode);\n }\n\n ctx.translate(eff.x, eff.y);\n\n // Apply anchor-relative transforms\n const anchorPixelX = eff.anchorX * eff.width;\n const anchorPixelY = eff.anchorY * eff.height;\n\n // Combine explicit rotation with motion path auto-rotation\n const totalRotation = eff.rotation + eff.motionPathAngle;\n\n if (totalRotation !== 0 || eff.scaleX !== 1 || eff.scaleY !== 1) {\n ctx.translate(anchorPixelX, anchorPixelY);\n if (totalRotation !== 0) {\n ctx.rotate((totalRotation * Math.PI) / 180);\n }\n if (eff.scaleX !== 1 || eff.scaleY !== 1) {\n ctx.scale(eff.scaleX, eff.scaleY);\n }\n ctx.translate(-anchorPixelX, -anchorPixelY);\n }\n\n // Apply shadow if present\n if (eff.shadow) {\n ctx.shadowColor = eff.shadow.color;\n ctx.shadowBlur = eff.shadow.blur;\n ctx.shadowOffsetX = eff.shadow.offsetX;\n ctx.shadowOffsetY = eff.shadow.offsetY;\n }\n\n // Apply clip path if present\n if (layer.clipPath) {\n applyClipPath(ctx, layer.clipPath, eff.width, eff.height);\n }\n\n // Tint requires offscreen compositing — draw to offscreen if tint is active\n const hasTint = eff.tint && eff.tint.amount > 0 && ctx.createOffscreen;\n let renderCtx = ctx;\n let offscreen: { ctx: RenderContext; canvas: unknown } | null = null;\n\n if (hasTint) {\n offscreen = ctx.createOffscreen!(eff.width, eff.height);\n renderCtx = offscreen.ctx;\n }\n\n // Ref rendering options (passed through for sub-doc composition)\n const refOpts = { documentResolver, maxRefDepth, imageCache };\n\n // Dispatch to type-specific renderer\n switch (layer.visual.type) {\n case \"shape\":\n renderShape(renderCtx, eff);\n break;\n case \"text\":\n renderText(renderCtx, eff);\n break;\n case \"image\":\n if (imageCache) renderImage(renderCtx, eff, imageCache);\n break;\n case \"video\":\n if (videoFrameProvider) {\n renderVideo(renderCtx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider);\n }\n break;\n case \"group\":\n // Groups are structural containers — no visual output\n break;\n case \"ref\":\n renderRef(renderCtx, eff, refOpts, doc);\n break;\n }\n\n // Apply tint via multiply composite on offscreen canvas\n if (hasTint && offscreen && eff.tint) {\n const offCtx = offscreen.ctx;\n // Draw tint color over the content using multiply\n offCtx.save();\n offCtx.globalCompositeOperation = \"multiply\";\n offCtx.fillStyle = eff.tint.color;\n offCtx.fillRect(0, 0, eff.width, eff.height);\n offCtx.restore();\n\n // Clip to original content shape using destination-in\n offCtx.save();\n offCtx.globalCompositeOperation = \"destination-in\";\n // Re-render the content to create the alpha mask\n switch (layer.visual.type) {\n case \"shape\": renderShape(offCtx, eff); break;\n case \"text\": renderText(offCtx, eff); break;\n case \"image\": if (imageCache) renderImage(offCtx, eff, imageCache); break;\n case \"video\": if (videoFrameProvider) renderVideo(offCtx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider); break;\n case \"ref\": renderRef(offCtx, eff, refOpts, doc); break;\n }\n offCtx.restore();\n\n // Blend tinted offscreen back with original at tint.amount alpha\n // First draw original content\n switch (layer.visual.type) {\n case \"shape\": renderShape(ctx, eff); break;\n case \"text\": renderText(ctx, eff); break;\n case \"image\": if (imageCache) renderImage(ctx, eff, imageCache); break;\n case \"video\": if (videoFrameProvider) renderVideo(ctx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider); break;\n case \"ref\": renderRef(ctx, eff, refOpts, doc); break;\n }\n // Then overlay tinted version at tint amount\n const prevAlpha = ctx.globalAlpha;\n ctx.globalAlpha = eff.tint.amount;\n ctx.drawImage(offscreen.canvas, 0, 0, eff.width, eff.height);\n ctx.globalAlpha = prevAlpha;\n }\n\n ctx.restore();\n }\n}\n\n/** Apply a shape as a clipping region */\nfunction applyClipPath(ctx: RenderContext, shape: Shape, width: number, height: number): void {\n ctx.beginPath();\n switch (shape.type) {\n case \"rect\":\n if (shape.cornerRadius && ctx.roundRect) {\n ctx.roundRect(0, 0, width, height, shape.cornerRadius);\n } else {\n // Manual rect path for clipping (fillRect doesn't create a path)\n ctx.moveTo(0, 0);\n ctx.lineTo(width, 0);\n ctx.lineTo(width, height);\n ctx.lineTo(0, height);\n ctx.closePath();\n }\n break;\n case \"ellipse\":\n ctx.ellipse(width / 2, height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n case \"path\":\n if (shape.points.length >= 2) {\n ctx.moveTo(shape.points[0].x, shape.points[0].y);\n for (let i = 1; i < shape.points.length; i++) {\n const prev = shape.points[i - 1];\n const curr = shape.points[i];\n if (prev.out && curr.in) {\n ctx.bezierCurveTo(\n prev.x + prev.out.x, prev.y + prev.out.y,\n curr.x + curr.in.x, curr.y + curr.in.y,\n curr.x, curr.y,\n );\n } else {\n ctx.lineTo(curr.x, curr.y);\n }\n }\n if (shape.closed) ctx.closePath();\n }\n break;\n }\n ctx.clip();\n}\n\n/** Map Atelier blend mode names to Canvas 2D globalCompositeOperation values */\nfunction blendModeToComposite(mode: string): string {\n const map: Record<string, string> = {\n \"multiply\": \"multiply\",\n \"screen\": \"screen\",\n \"overlay\": \"overlay\",\n \"darken\": \"darken\",\n \"lighten\": \"lighten\",\n \"color-dodge\": \"color-dodge\",\n \"color-burn\": \"color-burn\",\n \"hard-light\": \"hard-light\",\n \"soft-light\": \"soft-light\",\n \"difference\": \"difference\",\n \"exclusion\": \"exclusion\",\n \"hue\": \"hue\",\n \"saturation\": \"saturation\",\n \"color\": \"color\",\n \"luminosity\": \"luminosity\",\n };\n return map[mode] ?? \"source-over\";\n}\n\n/**\n * Walk the parentId chain and apply each ancestor's transforms.\n * This makes child layers inherit parent position/rotation/scale.\n */\nfunction applyAncestorTransforms(\n ctx: RenderContext,\n layerId: string,\n effMap: Map<string, EffectiveLayer>,\n doc: AtelierDocument,\n): void {\n // Collect ancestor chain (excluding self)\n const chain: EffectiveLayer[] = [];\n const layer = doc.layers.find((l) => l.id === layerId);\n let parentId = layer?.parentId;\n const visited = new Set<string>();\n\n while (parentId && !visited.has(parentId)) {\n visited.add(parentId);\n const parentEff = effMap.get(parentId);\n if (!parentEff) break;\n chain.push(parentEff);\n parentId = parentEff.layer.parentId;\n }\n\n // Apply from root ancestor down to direct parent\n for (let i = chain.length - 1; i >= 0; i--) {\n const p = chain[i];\n ctx.translate(p.x, p.y);\n\n const ax = p.anchorX * p.width;\n const ay = p.anchorY * p.height;\n\n if (p.rotation !== 0 || p.scaleX !== 1 || p.scaleY !== 1) {\n ctx.translate(ax, ay);\n if (p.rotation !== 0) ctx.rotate((p.rotation * Math.PI) / 180);\n if (p.scaleX !== 1 || p.scaleY !== 1) ctx.scale(p.scaleX, p.scaleY);\n ctx.translate(-ax, -ay);\n }\n }\n}\n","/**\n * A loaded image entry that can be drawn via RenderContext.drawImage.\n */\nexport interface CachedImage {\n complete: boolean;\n image: unknown;\n}\n\n/**\n * Simple image cache for loading and caching images.\n * Browser-agnostic — the actual Image constructor is injected via createImage.\n * Triggers an onLoad callback when an image finishes loading so the\n * renderer can re-render the current frame.\n */\nexport class ImageCache {\n private cache = new Map<string, CachedImage>();\n private loading = new Set<string>();\n private onLoad?: () => void;\n private createImage?: (src: string, onLoad: () => void, onError: () => void) => unknown;\n\n constructor(opts?: {\n onLoad?: () => void;\n createImage?: (src: string, onLoad: () => void, onError: () => void) => unknown;\n }) {\n this.onLoad = opts?.onLoad;\n this.createImage = opts?.createImage;\n }\n\n get(src: string): unknown | null {\n const entry = this.cache.get(src);\n return entry?.complete ? entry.image : null;\n }\n\n load(src: string): void {\n if (this.cache.has(src) || this.loading.has(src)) return;\n if (!this.createImage) return;\n this.loading.add(src);\n const image = this.createImage(\n src,\n () => {\n this.cache.set(src, { complete: true, image });\n this.loading.delete(src);\n this.onLoad?.();\n },\n () => {\n this.loading.delete(src);\n },\n );\n }\n}\n","// @a-company/atelier-cli — CLI tool: validate, preview, render, info commands\n\n// Command registration functions (for programmatic use)\nexport { validateCommand, validateFile } from \"./commands/validate.js\";\nexport { infoCommand, getInfo } from \"./commands/info.js\";\nexport type { DocumentInfo } from \"./commands/info.js\";\nexport { stillCommand, resolveStill } from \"./commands/still.js\";\nexport { renderCommand } from \"./commands/render.js\";\nexport { exportSvgCommand } from \"./commands/export-svg.js\";\nexport { exportLottieCommand } from \"./commands/export-lottie.js\";\nexport { assetsCommand, getAssets } from \"./commands/assets.js\";\nexport type { AssetInfo } from \"./commands/assets.js\";\nexport { variablesCommand, getVariables } from \"./commands/variables.js\";\nexport type { VariableInfo } from \"./commands/variables.js\";\nexport {\n checkFfmpeg,\n buildFfmpegArgs,\n renderDocument,\n} from \"./commands/render-pipeline.js\";\nexport type {\n RenderFormat,\n RenderOptions,\n RenderResult,\n ProgressInfo,\n} from \"./commands/render-pipeline.js\";\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { validateAllDeltas } from \"@a-company/atelier-core\";\n\n/**\n * Validate an .atelier file: parse YAML, check schema, check delta overlaps.\n * Returns { valid, errors } for programmatic use.\n */\nexport function validateFile(filePath: string): {\n valid: boolean;\n errors: string[];\n} {\n const absPath = resolve(filePath);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n return { valid: false, errors: [`Cannot read file: ${absPath}`] };\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n return {\n valid: false,\n errors: result.errors.map(\n (e) => `${e.path}: ${e.message}`,\n ),\n };\n }\n\n // Check all states for delta overlaps\n const overlapErrors: string[] = [];\n for (const [stateName, state] of Object.entries(result.data.states)) {\n const overlaps = validateAllDeltas(state.deltas);\n for (const overlap of overlaps) {\n overlapErrors.push(`State \"${stateName}\": ${overlap.message}`);\n }\n }\n\n if (overlapErrors.length > 0) {\n return { valid: false, errors: overlapErrors };\n }\n\n return { valid: true, errors: [] };\n}\n\n/**\n * Register the `validate` subcommand on the Commander program.\n */\nexport function validateCommand(program: Command): void {\n program\n .command(\"validate <file>\")\n .description(\"Validate an .atelier YAML file\")\n .action((file: string) => {\n const { valid, errors } = validateFile(file);\n if (valid) {\n console.log(\"Valid\");\n } else {\n console.error(\"Validation errors:\");\n for (const error of errors) {\n console.error(` - ${error}`);\n }\n process.exit(1);\n }\n });\n}\n","import { z } from \"zod\";\n\n/** Pixel value — any number */\nexport const PixelSchema = z.number();\n\n/** Percentage string like \"50%\" */\nexport const PercentageSchema = z.string().regex(/^-?\\d+(\\.\\d+)?%$/, {\n message: \"Percentage must be a number followed by %, e.g. \\\"50%\\\"\",\n});\n\n/** Either pixel or percentage */\nexport const UnitValueSchema = z.union([PixelSchema, PercentageSchema]);\n","import { z } from \"zod\";\nimport { UnitValueSchema } from \"./units.js\";\n\nexport const FrameSchema = z.object({\n x: UnitValueSchema,\n y: UnitValueSchema,\n});\n\nexport const BoundsSchema = z.object({\n width: UnitValueSchema,\n height: UnitValueSchema,\n});\n\nexport const AnchorPointSchema = z.object({\n x: z.number().min(0).max(1),\n y: z.number().min(0).max(1),\n});\n","import { z } from \"zod\";\n\nexport const RGBAColorSchema = z.object({\n r: z.number().min(0).max(255),\n g: z.number().min(0).max(255),\n b: z.number().min(0).max(255),\n a: z.number().min(0).max(1),\n});\n\nexport const HSLAColorSchema = z.object({\n h: z.number().min(0).max(360),\n s: z.number().min(0).max(100),\n l: z.number().min(0).max(100),\n a: z.number().min(0).max(1),\n});\n\nexport const HexColorSchema = z.string().regex(/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, {\n message: \"Color must be a hex string: #RGB, #RGBA, #RRGGBB, or #RRGGBBAA\",\n});\n\nexport const ColorSchema = z.union([RGBAColorSchema, HSLAColorSchema, HexColorSchema]);\n","import { z } from \"zod\";\nimport { ColorSchema } from \"./color.js\";\nimport { UnitValueSchema } from \"./units.js\";\n\nexport const PathPointSchema = z.object({\n x: z.number(),\n y: z.number(),\n in: z.object({ x: z.number(), y: z.number() }).optional(),\n out: z.object({ x: z.number(), y: z.number() }).optional(),\n});\n\nexport const RectShapeSchema = z.object({\n type: z.literal(\"rect\"),\n cornerRadius: z.union([\n z.number().min(0),\n z.tuple([z.number().min(0), z.number().min(0), z.number().min(0), z.number().min(0)]),\n ]).optional(),\n});\n\nexport const EllipseShapeSchema = z.object({\n type: z.literal(\"ellipse\"),\n});\n\nexport const PathShapeSchema = z.object({\n type: z.literal(\"path\"),\n points: z.array(PathPointSchema).min(2, \"Path must have at least 2 points\"),\n closed: z.boolean().optional(),\n});\n\nexport const ShapeSchema = z.discriminatedUnion(\"type\", [\n RectShapeSchema,\n EllipseShapeSchema,\n PathShapeSchema,\n]);\n\nexport const GradientStopSchema = z.object({\n offset: z.number().min(0).max(1),\n color: ColorSchema,\n});\n\nexport const SolidFillSchema = z.object({\n type: z.literal(\"solid\"),\n color: ColorSchema,\n});\n\nexport const LinearGradientFillSchema = z.object({\n type: z.literal(\"linear-gradient\"),\n angle: z.number(),\n stops: z.array(GradientStopSchema).min(2, \"Gradient needs at least 2 stops\"),\n});\n\nexport const RadialGradientFillSchema = z.object({\n type: z.literal(\"radial-gradient\"),\n center: z.object({ x: UnitValueSchema, y: UnitValueSchema }),\n radius: UnitValueSchema,\n stops: z.array(GradientStopSchema).min(2, \"Gradient needs at least 2 stops\"),\n});\n\nexport const FillSchema = z.discriminatedUnion(\"type\", [\n SolidFillSchema,\n LinearGradientFillSchema,\n RadialGradientFillSchema,\n]);\n\nexport const StrokeSchema = z.object({\n color: ColorSchema,\n width: z.number().min(0),\n dash: z.array(z.number().min(0)).optional(),\n lineCap: z.enum([\"butt\", \"round\", \"square\"]).optional(),\n lineJoin: z.enum([\"miter\", \"round\", \"bevel\"]).optional(),\n strokeStart: z.number().min(0).max(1).optional(),\n strokeEnd: z.number().min(0).max(1).optional(),\n});\n\nexport const TextStyleSchema = z.object({\n fontFamily: z.string().min(1, \"fontFamily is required\"),\n fontSize: z.number().positive(\"fontSize must be positive\"),\n fontWeight: z.union([z.number(), z.enum([\"normal\", \"bold\"])]).optional(),\n fontStyle: z.enum([\"normal\", \"italic\"]).optional(),\n textAlign: z.enum([\"left\", \"center\", \"right\"]).optional(),\n lineHeight: z.number().positive().optional(),\n letterSpacing: z.number().optional(),\n color: ColorSchema,\n});\n","import { z } from \"zod\";\n\nexport const LinearEasingSchema = z.object({ type: z.literal(\"linear\") });\n\nexport const CubicBezierEasingSchema = z.object({\n type: z.literal(\"cubic-bezier\"),\n x1: z.number().min(0).max(1),\n y1: z.number(),\n x2: z.number().min(0).max(1),\n y2: z.number(),\n});\n\nexport const SpringEasingSchema = z.object({\n type: z.literal(\"spring\"),\n mass: z.number().positive().optional(),\n stiffness: z.number().positive().optional(),\n damping: z.number().positive().optional(),\n velocity: z.number().optional(),\n});\n\nexport const StepEasingSchema = z.object({\n type: z.literal(\"step\"),\n steps: z.number().int().positive(),\n position: z.enum([\"start\", \"end\"]).optional(),\n});\n\nexport const EasingPresetSchema = z.enum([\"linear\", \"ease-in\", \"ease-out\", \"ease-in-out\"]);\n\nexport const EasingSchema = z.union([\n LinearEasingSchema,\n CubicBezierEasingSchema,\n SpringEasingSchema,\n StepEasingSchema,\n EasingPresetSchema,\n]);\n","import { z } from \"zod\";\nimport { ColorSchema } from \"./color.js\";\n\nexport const ShadowSchema = z.object({\n color: ColorSchema,\n blur: z.number().min(0),\n offsetX: z.number().optional(),\n offsetY: z.number().optional(),\n});\n","import { z } from \"zod\";\nimport { ShapeSchema, FillSchema, StrokeSchema, TextStyleSchema, PathPointSchema } from \"./shape.js\";\nimport { FrameSchema, BoundsSchema, AnchorPointSchema } from \"./coordinates.js\";\nimport { ShadowSchema } from \"./shadow.js\";\nimport { InteractionSchema } from \"./interaction.js\";\n\nexport const BlendModeSchema = z.enum([\n \"normal\", \"multiply\", \"screen\", \"overlay\",\n \"darken\", \"lighten\", \"color-dodge\", \"color-burn\",\n \"hard-light\", \"soft-light\", \"difference\", \"exclusion\",\n \"hue\", \"saturation\", \"color\", \"luminosity\",\n]);\n\nexport const MotionPathSchema = z.object({\n points: z.array(PathPointSchema).min(2, \"Motion path must have at least 2 points\"),\n closed: z.boolean().optional(),\n autoRotate: z.boolean().optional(),\n autoRotateOffset: z.number().optional(),\n});\n\nexport const ShapeVisualSchema = z.object({\n type: z.literal(\"shape\"),\n shape: ShapeSchema,\n fill: FillSchema.optional(),\n stroke: StrokeSchema.optional(),\n});\n\nexport const TextVisualSchema = z.object({\n type: z.literal(\"text\"),\n content: z.string(),\n style: TextStyleSchema,\n});\n\nexport const SpritesheetConfigSchema = z.object({\n columns: z.number().int().positive(),\n rows: z.number().int().positive(),\n frameCount: z.number().int().positive().optional(),\n frameWidth: z.number().positive(),\n frameHeight: z.number().positive(),\n});\n\nexport const SourceRectSchema = z.object({\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n});\n\nexport const ImageVisualSchema = z.object({\n type: z.literal(\"image\"),\n assetId: z.string().min(1, \"assetId is required\"),\n src: z.string().optional(),\n sourceRect: SourceRectSchema.optional(),\n spritesheet: SpritesheetConfigSchema.optional(),\n frameIndex: z.number().int().min(0).optional(),\n});\n\nexport const VideoVisualSchema = z.object({\n type: z.literal(\"video\"),\n assetId: z.string().min(1, \"assetId is required\"),\n src: z.string().optional(),\n startFrame: z.number().int().min(0).optional(),\n sourceOffset: z.number().min(0).optional(),\n sourceEnd: z.number().positive().optional(),\n playbackRate: z.number().positive().optional(),\n volume: z.number().min(0).max(1).optional(),\n muted: z.boolean().optional(),\n objectFit: z.enum([\"contain\", \"cover\", \"fill\"]).optional(),\n});\n\nexport const GroupVisualSchema = z.object({\n type: z.literal(\"group\"),\n});\n\nexport const RefVisualSchema = z.object({\n type: z.literal(\"ref\"),\n src: z.string().min(1, \"src is required\"),\n state: z.string().optional(),\n frame: z.number().int().min(0).optional(),\n});\n\nexport const VisualSchema = z.discriminatedUnion(\"type\", [\n ShapeVisualSchema,\n TextVisualSchema,\n ImageVisualSchema,\n VideoVisualSchema,\n GroupVisualSchema,\n RefVisualSchema,\n]);\n\nexport const LayerSchema = z.object({\n id: z.string().min(1, \"Layer id is required\"),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n visual: VisualSchema,\n frame: FrameSchema,\n bounds: BoundsSchema,\n anchorPoint: AnchorPointSchema.optional(),\n parentId: z.string().optional(),\n opacity: z.number().min(0).max(1).optional(),\n rotation: z.number().optional(),\n scale: z.object({ x: z.number(), y: z.number() }).optional(),\n visible: z.boolean().optional(),\n shadow: ShadowSchema.optional(),\n blendMode: BlendModeSchema.optional(),\n motionPath: MotionPathSchema.optional(),\n clipPath: ShapeSchema.optional(),\n tint: z.object({\n color: z.string(),\n amount: z.number().min(0).max(1),\n }).optional(),\n interactions: z.array(InteractionSchema).optional(),\n});\n","import { z } from \"zod\";\n\nexport const TriggerTypeSchema = z.enum([\n \"click\", \"hover\", \"pointerdown\", \"pointerup\", \"timer\", \"signal\",\n]);\n\nexport const TriggerSchema = z.object({\n type: TriggerTypeSchema,\n delay: z.number().nonnegative(\"Timer delay must be non-negative\").optional(),\n signal: z.string().optional(),\n}).refine(\n (t) => t.type !== \"timer\" || t.delay !== undefined,\n { message: \"Timer trigger requires a delay\" },\n).refine(\n (t) => t.type !== \"signal\" || t.signal !== undefined,\n { message: \"Signal trigger requires a signal name\" },\n);\n\nexport const ActionTypeSchema = z.enum([\n \"go-to-state\", \"emit-signal\", \"set-variable\", \"toggle-visibility\",\n]);\n\nexport const ActionSchema = z.object({\n type: ActionTypeSchema,\n state: z.string().optional(),\n signal: z.string().optional(),\n variable: z.string().optional(),\n value: z.unknown().optional(),\n targetLayer: z.string().optional(),\n}).refine(\n (a) => a.type !== \"go-to-state\" || a.state !== undefined,\n { message: \"go-to-state action requires a state name\" },\n).refine(\n (a) => a.type !== \"emit-signal\" || a.signal !== undefined,\n { message: \"emit-signal action requires a signal name\" },\n).refine(\n (a) => a.type !== \"set-variable\" || (a.variable !== undefined && a.value !== undefined),\n { message: \"set-variable action requires variable and value\" },\n);\n\nexport const InteractionSchema = z.object({\n id: z.string().min(1, \"Interaction id is required\"),\n trigger: TriggerSchema,\n action: ActionSchema,\n description: z.string().optional(),\n});\n","import { z } from \"zod\";\nimport { EasingSchema } from \"./easing.js\";\n\nexport const AnimatablePropertySchema = z.enum([\n \"frame.x\",\n \"frame.y\",\n \"bounds.width\",\n \"bounds.height\",\n \"opacity\",\n \"rotation\",\n \"scale.x\",\n \"scale.y\",\n \"anchorPoint.x\",\n \"anchorPoint.y\",\n \"visual.shape.cornerRadius\",\n \"visual.fill.color\",\n \"visual.stroke.color\",\n \"visual.stroke.width\",\n \"visual.stroke.start\",\n \"visual.stroke.end\",\n \"visual.style.fontSize\",\n \"visual.style.color\",\n \"shadow.color\",\n \"shadow.blur\",\n \"shadow.offsetX\",\n \"shadow.offsetY\",\n \"motionPath.progress\",\n \"visual.fill.angle\",\n \"visual.fill.center.x\",\n \"visual.fill.center.y\",\n \"visual.fill.radius\",\n \"visual.image.sourceRect.x\",\n \"visual.image.sourceRect.y\",\n \"visual.image.sourceRect.width\",\n \"visual.image.sourceRect.height\",\n \"visual.image.frameIndex\",\n \"visible\",\n \"tint.color\",\n \"tint.amount\",\n]);\n\nexport const FrameRangeSchema = z.tuple([\n z.number().int().min(0, \"Frame start must be >= 0\"),\n z.number().int().min(0, \"Frame end must be >= 0\"),\n]).refine(([start, end]) => end >= start, {\n message: \"Frame range end must be >= start\",\n});\n\nexport const DeltaSchema = z.object({\n id: z.string().optional(),\n name: z.string().optional(),\n layer: z.string().min(1, \"Delta must reference a layer id\"),\n property: AnimatablePropertySchema,\n range: FrameRangeSchema,\n from: z.unknown(),\n to: z.unknown(),\n easing: EasingSchema.optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n});\n","import { z } from \"zod\";\nimport { DeltaSchema } from \"./delta.js\";\nimport { EasingSchema } from \"./easing.js\";\n\nexport const AudioSchema = z.object({\n src: z.string().min(1, \"Audio src is required\"),\n offset: z.number().min(0, \"Audio offset must be non-negative\").optional(),\n volume: z.number().min(0).max(1, \"Audio volume must be 0–1\").optional(),\n loop: z.boolean().optional(),\n startFrame: z.number().int().min(0, \"Audio startFrame must be a non-negative integer\").optional(),\n});\n\nexport const StateTransitionConfigSchema = z.object({\n duration: z.number().int().positive(\"Transition duration must be a positive integer (frames)\"),\n easing: EasingSchema.optional(),\n});\n\nexport const StateSchema = z.object({\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n parent: z.string().optional(),\n duration: z.number().int().positive(\"State duration must be a positive integer (frames)\"),\n deltas: z.array(DeltaSchema),\n audio: AudioSchema.optional(),\n transitions: z.record(z.string(), StateTransitionConfigSchema).optional(),\n});\n","import { z } from \"zod\";\nimport { AnimatablePropertySchema } from \"./delta.js\";\nimport { EasingSchema } from \"./easing.js\";\n\nexport const PresetDeltaSchema = z.object({\n property: AnimatablePropertySchema,\n offset: z.tuple([z.number().int().min(0), z.number().int().min(0)]).optional(),\n from: z.unknown(),\n to: z.unknown(),\n easing: EasingSchema.optional(),\n});\n\nexport const PresetSchema = z.object({\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n deltas: z.array(PresetDeltaSchema).min(1, \"Preset must have at least one delta\"),\n});\n","import { z } from \"zod\";\n\nexport const VariableTypeSchema = z.enum([\"string\", \"number\", \"color\", \"asset\", \"boolean\"]);\n\nexport const VariableSchema = z.object({\n type: VariableTypeSchema,\n default: z.unknown().optional(),\n description: z.string().optional(),\n});\n","import { z } from \"zod\";\n\nexport const AssetTypeSchema = z.enum([\"image\", \"svg\", \"font\", \"animation\", \"audio\", \"video\"]);\n\nexport const AssetSchema = z.object({\n type: AssetTypeSchema,\n src: z.string().min(1, \"Asset src is required\"),\n description: z.string().optional(),\n spritesheet: z.object({\n columns: z.number().int().positive(),\n rows: z.number().int().positive(),\n frameCount: z.number().int().positive().optional(),\n frameWidth: z.number().positive(),\n frameHeight: z.number().positive(),\n }).optional(),\n videoMeta: z.object({\n duration: z.number().positive(\"videoMeta.duration must be positive\"),\n fps: z.number().positive(\"videoMeta.fps must be positive\"),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n }).optional(),\n});\n","import { z } from \"zod\";\nimport { LayerSchema } from \"./layer.js\";\nimport { StateSchema } from \"./state.js\";\nimport { PresetSchema } from \"./preset.js\";\nimport { VariableSchema } from \"./variable.js\";\nimport { AssetSchema } from \"./asset.js\";\n\nexport const CanvasSchema = z.object({\n width: z.number().int().positive(\"Canvas width must be a positive integer\"),\n height: z.number().int().positive(\"Canvas height must be a positive integer\"),\n fps: z.number().int().positive(\"FPS must be a positive integer\"),\n background: z.string().optional(),\n});\n\nexport const AtelierDocumentSchema = z.object({\n version: z.string().min(1, \"Version is required\"),\n name: z.string().min(1, \"Animation name is required\"),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n canvas: CanvasSchema,\n variables: z.record(z.string(), VariableSchema).optional(),\n assets: z.record(z.string(), AssetSchema).optional(),\n presets: z.record(z.string(), PresetSchema).optional(),\n layers: z.array(LayerSchema),\n states: z.record(z.string(), StateSchema),\n});\n","import type { AtelierDocument, Layer, Delta, VideoVisual } from \"@a-company/atelier-types\";\nimport { AtelierDocumentSchema } from \"./document.js\";\nimport { LayerSchema } from \"./layer.js\";\nimport { DeltaSchema } from \"./delta.js\";\nimport type { z } from \"zod\";\n\n/** Validation result — either success with typed data or failure with readable errors */\nexport type ValidationResult<T> =\n | { success: true; data: T }\n | { success: false; errors: ValidationError[] };\n\nexport interface ValidationError {\n path: string;\n message: string;\n}\n\n/** Format Zod errors into flat, AI-readable error messages */\nfunction formatErrors(error: z.ZodError): ValidationError[] {\n return error.issues.map((issue) => ({\n path: issue.path.join(\".\") || \"(root)\",\n message: issue.message,\n }));\n}\n\n/** Validate a complete AtelierDocument */\nexport function validateDocument(input: unknown): ValidationResult<AtelierDocument> {\n const result = AtelierDocumentSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data as AtelierDocument };\n }\n return { success: false, errors: formatErrors(result.error) };\n}\n\n/** Validate a single Layer */\nexport function validateLayer(input: unknown): ValidationResult<Layer> {\n const result = LayerSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data as Layer };\n }\n return { success: false, errors: formatErrors(result.error) };\n}\n\n/** Validate a single Delta */\nexport function validateDelta(input: unknown): ValidationResult<Delta> {\n const result = DeltaSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data as Delta };\n }\n return { success: false, errors: formatErrors(result.error) };\n}\n\n/**\n * Validate a VideoVisual layer against semantic constraints (^valid-video-layer gate).\n * Checks beyond Zod: sourceEnd > sourceOffset, sourceEnd ≤ videoMeta.duration.\n */\nexport function validateVideoLayer(\n visual: VideoVisual,\n videoMetaDuration?: number,\n): ValidationResult<VideoVisual> {\n const errors: ValidationError[] = [];\n\n if (!visual.assetId) {\n errors.push({ path: \"assetId\", message: \"assetId is required\" });\n }\n\n const sourceOffset = visual.sourceOffset ?? 0;\n if (visual.sourceEnd !== undefined) {\n if (visual.sourceEnd <= sourceOffset) {\n errors.push({\n path: \"sourceEnd\",\n message: `sourceEnd (${visual.sourceEnd}) must be greater than sourceOffset (${sourceOffset})`,\n });\n }\n if (videoMetaDuration !== undefined && visual.sourceEnd > videoMetaDuration) {\n errors.push({\n path: \"sourceEnd\",\n message: `sourceEnd (${visual.sourceEnd}) exceeds asset duration (${videoMetaDuration})`,\n });\n }\n }\n\n if (videoMetaDuration !== undefined && sourceOffset >= videoMetaDuration) {\n errors.push({\n path: \"sourceOffset\",\n message: `sourceOffset (${sourceOffset}) is at or beyond asset duration (${videoMetaDuration})`,\n });\n }\n\n if (errors.length > 0) return { success: false, errors };\n return { success: true, data: visual };\n}\n","import { parse as yamlParse, stringify as yamlStringify } from \"yaml\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { validateDocument } from \"./validate.js\";\nimport type { ValidationResult } from \"./validate.js\";\n\n/**\n * Parse a YAML string into a validated AtelierDocument.\n * Returns validation errors if the YAML is invalid or doesn't match the schema.\n */\nexport function parseAtelier(yamlString: string): ValidationResult<AtelierDocument> {\n let parsed: unknown;\n try {\n parsed = yamlParse(yamlString);\n } catch (err) {\n return {\n success: false,\n errors: [{ path: \"(yaml)\", message: `YAML parse error: ${(err as Error).message}` }],\n };\n }\n return validateDocument(parsed);\n}\n\n/**\n * Serialize an AtelierDocument to YAML string.\n */\nexport function serializeAtelier(doc: AtelierDocument): string {\n return yamlStringify(doc, { indent: 2 });\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\n\n/**\n * Info summary for an AtelierDocument.\n */\nexport interface DocumentInfo {\n name: string;\n description?: string;\n canvas: {\n width: number;\n height: number;\n fps: number;\n background?: string;\n };\n layers: {\n count: number;\n items: { id: string; type: string }[];\n };\n states: {\n count: number;\n items: { name: string; duration: number; deltaCount: number }[];\n };\n presets: {\n count: number;\n };\n}\n\n/**\n * Extract summary info from a parsed AtelierDocument.\n */\nexport function getInfo(doc: AtelierDocument): DocumentInfo {\n return {\n name: doc.name,\n description: doc.description,\n canvas: {\n width: doc.canvas.width,\n height: doc.canvas.height,\n fps: doc.canvas.fps,\n background: doc.canvas.background,\n },\n layers: {\n count: doc.layers.length,\n items: doc.layers.map((layer) => ({\n id: layer.id,\n type: layer.visual.type,\n })),\n },\n states: {\n count: Object.keys(doc.states).length,\n items: Object.entries(doc.states).map(([name, state]) => ({\n name,\n duration: state.duration,\n deltaCount: state.deltas.length,\n })),\n },\n presets: {\n count: doc.presets ? Object.keys(doc.presets).length : 0,\n },\n };\n}\n\n/**\n * Format a DocumentInfo for terminal output.\n */\nfunction formatInfo(info: DocumentInfo): string {\n const lines: string[] = [];\n\n lines.push(`Name: ${info.name}`);\n if (info.description) {\n lines.push(`Description: ${info.description}`);\n }\n\n const bg = info.canvas.background\n ? `, background: ${info.canvas.background}`\n : \"\";\n lines.push(\n `Canvas: ${info.canvas.width}x${info.canvas.height} @ ${info.canvas.fps}fps${bg}`,\n );\n\n lines.push(`Layers: ${info.layers.count}`);\n for (const layer of info.layers.items) {\n lines.push(` - ${layer.id} (${layer.type})`);\n }\n\n lines.push(`States: ${info.states.count}`);\n for (const state of info.states.items) {\n lines.push(\n ` - ${state.name}: ${state.duration} frames, ${state.deltaCount} deltas`,\n );\n }\n\n if (info.presets.count > 0) {\n lines.push(`Presets: ${info.presets.count}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `info` subcommand on the Commander program.\n */\nexport function infoCommand(program: Command): void {\n program\n .command(\"info <file>\")\n .description(\"Display summary info for an .atelier file\")\n .action((file: string) => {\n const doc = readAndParse(file);\n const info = getInfo(doc);\n console.log(formatInfo(info));\n });\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { resolveFrame } from \"@a-company/atelier-core\";\nimport type { ResolvedFrame } from \"@a-company/atelier-core\";\n\n/**\n * Resolve a single frame from a document, returning the resolved frame data.\n * If stateName is not provided, uses the first state.\n * If frame is not provided, uses frame 0.\n */\nexport function resolveStill(\n doc: AtelierDocument,\n stateName?: string,\n frame?: number,\n): ResolvedFrame {\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) {\n throw new Error(\"Document has no states\");\n }\n\n const resolvedStateName = stateName ?? stateNames[0];\n if (!(resolvedStateName in doc.states)) {\n throw new Error(\n `State \"${resolvedStateName}\" not found. Available: ${stateNames.join(\", \")}`,\n );\n }\n\n const resolvedFrame = frame ?? 0;\n return resolveFrame(doc, resolvedStateName, resolvedFrame);\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `still` subcommand on the Commander program.\n */\nexport function stillCommand(program: Command): void {\n program\n .command(\"still <file>\")\n .description(\n \"Resolve a single frame and output as JSON or render as PNG\",\n )\n .option(\"-s, --state <name>\", \"State name (defaults to first state)\")\n .option(\n \"-f, --frame <number>\",\n \"Frame number (defaults to 0)\",\n \"0\",\n )\n .option(\n \"--format <type>\",\n \"Output format: json | png (default: json)\",\n \"json\",\n )\n .option(\"-o, --output <path>\", \"Output file path (default: stdout)\")\n .action(\n async (\n file: string,\n options: { state?: string; frame: string; format: string; output?: string },\n ) => {\n const doc = readAndParse(file);\n\n const frameNumber = parseInt(options.frame, 10);\n if (isNaN(frameNumber) || frameNumber < 0) {\n console.error(\n `Invalid frame number: ${options.frame}`,\n );\n process.exit(1);\n return;\n }\n\n if (options.format !== \"json\" && options.format !== \"png\") {\n console.error(`Unknown format: \"${options.format}\". Use json or png.`);\n process.exit(1);\n return;\n }\n\n try {\n const resolved = resolveStill(\n doc,\n options.state,\n frameNumber,\n );\n\n if (options.format === \"json\") {\n const json = JSON.stringify(resolved, null, 2);\n if (options.output) {\n writeFileSync(resolve(options.output), json, \"utf-8\");\n } else {\n console.log(json);\n }\n } else {\n // PNG format — dynamic import of canvas\n let canvasMod: typeof import(\"canvas\");\n try {\n canvasMod = await import(\"canvas\");\n } catch {\n console.error(\"PNG output requires the 'canvas' package. Install it: npm i canvas\");\n process.exit(1);\n return;\n }\n\n const { renderFrame } = await import(\"@a-company/atelier-canvas\");\n\n const { createCanvas } = canvasMod;\n const cvs = createCanvas(doc.canvas.width, doc.canvas.height);\n const ctx = cvs.getContext(\"2d\");\n renderFrame(ctx as unknown as import(\"@a-company/atelier-canvas\").RenderContext, resolved, doc);\n\n const buffer = cvs.toBuffer(\"image/png\");\n if (options.output) {\n writeFileSync(resolve(options.output), buffer);\n } else {\n process.stdout.write(buffer);\n }\n }\n } catch (err) {\n console.error(\n (err as Error).message,\n );\n process.exit(1);\n }\n },\n );\n}\n","/**\n * `atelier render <file>` — render an animation to MP4 or GIF via FFmpeg.\n *\n * Usage:\n * atelier render animation.atelier → animation.mp4\n * atelier render animation.atelier -f gif → animation.gif\n * atelier render animation.atelier -o out/video.mp4 → custom path\n * atelier render animation.atelier -s intro outro → specific states\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { resolve, basename, extname } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport {\n checkFfmpeg,\n renderDocument,\n type RenderFormat,\n} from \"./render-pipeline.js\";\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\nfunction inferFormat(output: string | undefined): RenderFormat {\n if (!output) return \"mp4\";\n const ext = extname(output).toLowerCase();\n if (ext === \".gif\") return \"gif\";\n return \"mp4\";\n}\n\n/** Register the `render` subcommand on the Commander program. */\nexport function renderCommand(program: Command): void {\n program\n .command(\"render <file>\")\n .description(\"Render animation to MP4 or GIF via FFmpeg\")\n .option(\"-o, --output <path>\", \"Output file path\")\n .option(\"-f, --format <type>\", \"Output format: mp4 | gif\")\n .option(\n \"-s, --state <names...>\",\n \"State(s) to render (default: all in order)\",\n )\n .action(\n async (\n file: string,\n options: {\n output?: string;\n format?: string;\n state?: string[];\n },\n ) => {\n // Check FFmpeg availability\n const hasFfmpeg = await checkFfmpeg();\n if (!hasFfmpeg) {\n console.error(\"FFmpeg is not installed or not in PATH.\");\n console.error(\"Install it:\");\n console.error(\" macOS: brew install ffmpeg\");\n console.error(\" Ubuntu: sudo apt install ffmpeg\");\n console.error(\" Windows: https://ffmpeg.org/download.html\");\n process.exit(1);\n return;\n }\n\n const doc = readAndParse(file);\n\n // Resolve format\n let format: RenderFormat;\n if (options.format) {\n if (options.format !== \"mp4\" && options.format !== \"gif\") {\n console.error(\n `Unknown format: \"${options.format}\". Use mp4 or gif.`,\n );\n process.exit(1);\n return;\n }\n format = options.format;\n } else {\n format = inferFormat(options.output);\n }\n\n // Resolve output path\n const inputName = basename(file, extname(file));\n const output = options.output ?? `${inputName}.${format}`;\n\n const startTime = Date.now();\n\n try {\n const result = await renderDocument(doc, {\n output: resolve(output),\n format,\n states: options.state,\n onProgress: ({ frame, totalFrames, state, percent }) => {\n const elapsed = (Date.now() - startTime) / 1000;\n const rate = elapsed > 0 ? frame / elapsed : 0;\n const remaining =\n rate > 0 ? (totalFrames - frame) / rate : 0;\n process.stderr.write(\n `\\rRendering: frame ${frame}/${totalFrames} (${percent}%) - state \"${state}\" - ETA ${remaining.toFixed(1)}s`,\n );\n },\n });\n\n process.stderr.write(\"\\n\");\n console.log(\n `Done: ${result.totalFrames} frames \\u2192 ${result.output} (${(result.durationMs / 1000).toFixed(1)}s)`,\n );\n } catch (err) {\n process.stderr.write(\"\\n\");\n console.error((err as Error).message);\n process.exit(1);\n }\n },\n );\n}\n","/**\n * Core render pipeline — renders an Atelier document to MP4 or GIF via FFmpeg.\n * Pure pipeline with no Commander dependency; testable in isolation.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { resolveFrame } from \"@a-company/atelier-core\";\nimport { renderFrame, ImageCache } from \"@a-company/atelier-canvas\";\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport type RenderFormat = \"mp4\" | \"gif\";\n\nexport interface RenderOptions {\n output: string;\n format: RenderFormat;\n states?: string[];\n onProgress?: (info: ProgressInfo) => void;\n}\n\nexport interface ProgressInfo {\n frame: number;\n totalFrames: number;\n state: string;\n percent: number;\n}\n\nexport interface RenderResult {\n output: string;\n format: RenderFormat;\n totalFrames: number;\n states: string[];\n durationMs: number;\n}\n\n// ─── FFmpeg Helpers ──────────────────────────────────────────\n\n/** Check whether FFmpeg is available on the system PATH. */\nexport async function checkFfmpeg(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"ffmpeg\", [\"-version\"], { stdio: \"pipe\" });\n proc.on(\"error\", () => resolve(false));\n proc.on(\"close\", (code) => resolve(code === 0));\n });\n}\n\n/** Build the FFmpeg argument array for the given format. Pure function. */\nexport function buildFfmpegArgs(\n width: number,\n height: number,\n fps: number,\n format: RenderFormat,\n output: string,\n): string[] {\n const input = [\n \"-y\",\n \"-f\", \"rawvideo\",\n \"-pix_fmt\", \"bgra\",\n \"-s\", `${width}x${height}`,\n \"-r\", String(fps),\n \"-i\", \"pipe:0\",\n ];\n\n if (format === \"mp4\") {\n return [\n ...input,\n \"-c:v\", \"libx264\",\n \"-pix_fmt\", \"yuv420p\",\n \"-preset\", \"medium\",\n \"-crf\", \"18\",\n \"-movflags\", \"+faststart\",\n output,\n ];\n }\n\n // GIF — single-pass palette generation (stdin-compatible)\n return [\n ...input,\n \"-vf\", \"split[s0][s1];[s0]palettegen=stats_mode=single[p];[s1][p]paletteuse=dither=sierra2_4a\",\n \"-loop\", \"0\",\n output,\n ];\n}\n\n// ─── Image Pre-loading ───────────────────────────────────────\n\n/**\n * Scan document layers for image visuals, pre-load them with node-canvas\n * loadImage, and return a populated ImageCache ready for rendering.\n */\nasync function preloadImages(\n doc: AtelierDocument,\n loadImage: (src: string) => Promise<unknown>,\n): Promise<ImageCache> {\n const sources = new Set<string>();\n\n for (const layer of doc.layers) {\n if (layer.visual.type === \"image\") {\n const iv = layer.visual as { src?: string; assetId?: string };\n if (iv.src) {\n sources.add(iv.src);\n } else if (iv.assetId && doc.assets?.[iv.assetId]) {\n sources.add(doc.assets[iv.assetId].src);\n }\n }\n }\n\n if (sources.size === 0) {\n return new ImageCache();\n }\n\n // Load all images in parallel\n const preloaded = new Map<string, unknown>();\n await Promise.all(\n [...sources].map(async (src) => {\n try {\n preloaded.set(src, await loadImage(src));\n } catch {\n // Images that fail to load will render as blank\n }\n }),\n );\n\n // Create ImageCache pre-populated with loaded images.\n // createImage returns the pre-loaded image and fires onLoad on next tick\n // so that the ImageCache internal `image` variable is assigned first.\n const imageCache = new ImageCache({\n createImage: (src, onLoad, onError) => {\n const img = preloaded.get(src);\n if (img) {\n process.nextTick(onLoad);\n return img;\n }\n process.nextTick(onError);\n return {};\n },\n });\n\n for (const src of preloaded.keys()) {\n imageCache.load(src);\n }\n\n // Wait for nextTick callbacks to populate the cache\n await new Promise<void>((resolve) => process.nextTick(resolve));\n\n return imageCache;\n}\n\n// ─── Main Render Loop ────────────────────────────────────────\n\n/**\n * Render an Atelier document to a video/GIF file via FFmpeg.\n * Dynamically imports `canvas` (node-canvas) — fails with a helpful\n * message if the native dependency is not installed.\n */\nexport async function renderDocument(\n doc: AtelierDocument,\n opts: RenderOptions,\n): Promise<RenderResult> {\n // Dynamic import — canvas requires native compilation.\n // Use a variable to avoid TypeScript resolving the module at compile time.\n const canvasModuleName = \"canvas\";\n let createCanvas: (w: number, h: number) => unknown;\n let loadImage: (src: string) => Promise<unknown>;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const canvasModule = await import(/* webpackIgnore: true */ canvasModuleName);\n createCanvas = canvasModule.createCanvas;\n loadImage = canvasModule.loadImage;\n } catch {\n throw new Error(\n \"The 'canvas' package is not installed.\\n\" +\n \"Install it with:\\n\" +\n \" npm install canvas\\n\" +\n \"Prerequisites vary by OS:\\n\" +\n \" macOS: brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman\\n\" +\n \" Ubuntu: sudo apt install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev\\n\" +\n \"See: https://github.com/Automattic/node-canvas#compiling\",\n );\n }\n\n const { width, height, fps } = doc.canvas;\n const { output, format, states, onProgress } = opts;\n\n // H.264 requires even dimensions\n if (format === \"mp4\" && (width % 2 !== 0 || height % 2 !== 0)) {\n throw new Error(\n `H.264 requires even dimensions. Canvas is ${width}\\u00d7${height}. ` +\n `Try ${width + (width % 2)}\\u00d7${height + (height % 2)}.`,\n );\n }\n\n // Resolve which states to render\n const allStates = Object.keys(doc.states);\n const renderStates = states ?? allStates;\n for (const s of renderStates) {\n if (!(s in doc.states)) {\n throw new Error(\n `State \"${s}\" not found. Available: ${allStates.join(\", \")}`,\n );\n }\n }\n\n // Total frame count across all states\n let totalFrames = 0;\n for (const s of renderStates) {\n totalFrames += doc.states[s].duration;\n }\n\n if (totalFrames === 0) {\n throw new Error(\"Nothing to render \\u2014 all states have duration 0\");\n }\n\n // Pre-load images before the render loop\n const imageCache = await preloadImages(doc, loadImage);\n\n // Create node-canvas\n const canvas = createCanvas(width, height) as { getContext(id: \"2d\"): unknown; toBuffer(format: \"raw\"): Buffer };\n const ctx = canvas.getContext(\"2d\");\n\n // Spawn FFmpeg\n const ffmpegArgs = buildFfmpegArgs(width, height, fps, format, output);\n const ffmpeg = spawn(\"ffmpeg\", ffmpegArgs, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n let stderrOutput = \"\";\n ffmpeg.stderr?.on(\"data\", (chunk: Buffer) => {\n stderrOutput += chunk.toString();\n });\n\n const startTime = Date.now();\n let frameIndex = 0;\n\n for (const stateName of renderStates) {\n const duration = doc.states[stateName].duration;\n for (let f = 0; f < duration; f++) {\n const resolved = resolveFrame(doc, stateName, f);\n renderFrame(ctx as never, resolved, doc, imageCache);\n\n const raw = canvas.toBuffer(\"raw\");\n const canWrite = ffmpeg.stdin!.write(raw);\n if (!canWrite) {\n await new Promise<void>((resolve) =>\n ffmpeg.stdin!.once(\"drain\", resolve),\n );\n }\n\n frameIndex++;\n onProgress?.({\n frame: frameIndex,\n totalFrames,\n state: stateName,\n percent: Math.round((frameIndex / totalFrames) * 100),\n });\n }\n }\n\n // Close stdin and wait for FFmpeg to exit\n ffmpeg.stdin!.end();\n\n const exitCode = await new Promise<number | null>((resolve) => {\n ffmpeg.on(\"close\", resolve);\n });\n\n if (exitCode !== 0) {\n throw new Error(\n `FFmpeg exited with code ${exitCode}.\\n${stderrOutput.slice(-500)}`,\n );\n }\n\n return {\n output,\n format,\n totalFrames,\n states: renderStates,\n durationMs: Date.now() - startTime,\n };\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { renderFrameSVG } from \"@a-company/atelier-svg\";\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/** Register the `export-svg` subcommand on the Commander program. */\nexport function exportSvgCommand(program: Command): void {\n program\n .command(\"export-svg <file>\")\n .description(\"Export a frame as SVG\")\n .option(\"-s, --state <name>\", \"State name (defaults to first state)\")\n .option(\"-f, --frame <number>\", \"Frame number (defaults to 0)\", \"0\")\n .option(\"-o, --output <path>\", \"Output file path (default: stdout)\")\n .option(\"--xml-declaration\", \"Include XML declaration\")\n .action(\n (\n file: string,\n options: { state?: string; frame: string; output?: string; xmlDeclaration?: boolean },\n ) => {\n const doc = readAndParse(file);\n\n const frameNumber = parseInt(options.frame, 10);\n if (isNaN(frameNumber) || frameNumber < 0) {\n console.error(`Invalid frame number: ${options.frame}`);\n process.exit(1);\n return;\n }\n\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) {\n console.error(\"Document has no states\");\n process.exit(1);\n return;\n }\n\n const stateName = options.state ?? stateNames[0];\n if (!doc.states[stateName]) {\n console.error(`State \"${stateName}\" not found. Available: ${stateNames.join(\", \")}`);\n process.exit(1);\n return;\n }\n\n try {\n const svg = renderFrameSVG(doc, stateName, frameNumber, {\n xmlDeclaration: options.xmlDeclaration,\n });\n\n if (options.output) {\n writeFileSync(resolve(options.output), svg, \"utf-8\");\n } else {\n console.log(svg);\n }\n } catch (err) {\n console.error((err as Error).message);\n process.exit(1);\n }\n },\n );\n}\n","import type { AtelierDocument, ImageVisual, RefVisual } from \"@a-company/atelier-types\";\nimport { resolveFrame, type ResolvedFrame } from \"@a-company/atelier-core\";\nimport { buildEffectiveLayer, type EffectiveLayer, type DocumentResolver } from \"@a-company/atelier-canvas\";\nimport { buildTransform, buildStyleAttrs } from \"./svg-properties.js\";\nimport { renderShapeSVG } from \"./svg-shapes.js\";\nimport { renderTextSVG } from \"./svg-text.js\";\nimport { buildShadowFilter, buildTintFilter, resetFilterCounter } from \"./svg-filters.js\";\nimport { resetGradientCounter } from \"./svg-gradients.js\";\nimport { buildClipPathDef, resetClipCounter } from \"./svg-clip.js\";\nimport { escapeXml } from \"./svg-properties.js\";\n\nexport interface RenderSVGOptions {\n /** Include XML declaration (default: false) */\n xmlDeclaration?: boolean;\n /** Include viewBox attribute (default: true) */\n viewBox?: boolean;\n /** Indent size in spaces (default: 2) */\n indent?: number;\n /** Resolves ref layer src paths to loaded AtelierDocuments */\n documentResolver?: DocumentResolver;\n /** Maximum ref nesting depth (default: 4) */\n maxRefDepth?: number;\n}\n\n/**\n * Render a resolved frame as an SVG string.\n * If no resolved frame is provided, resolves the given state and frame.\n */\nexport function renderFrameSVG(\n doc: AtelierDocument,\n stateOrFrame: string | ResolvedFrame,\n frame?: number,\n opts?: RenderSVGOptions,\n): string {\n // Reset counters for deterministic IDs\n resetGradientCounter();\n resetFilterCounter();\n resetClipCounter();\n\n let resolved: ResolvedFrame;\n if (typeof stateOrFrame === \"string\") {\n resolved = resolveFrame(doc, stateOrFrame, frame ?? 0);\n } else {\n resolved = stateOrFrame;\n }\n\n const { width, height } = doc.canvas;\n const indent = opts?.indent ?? 2;\n const pad = \" \".repeat(indent);\n\n // Build effective layers\n const effLayers: EffectiveLayer[] = resolved.layers.map(rl =>\n buildEffectiveLayer(rl, width, height),\n );\n\n // Collect all defs and layer elements\n const allDefs: string[] = [];\n const layerElements: string[] = [];\n\n for (let i = 0; i < effLayers.length; i++) {\n const eff = effLayers[i];\n const layer = resolved.layers[i].layer;\n\n // Skip invisible or fully transparent\n if (!eff.visible) continue;\n if (eff.opacity <= 0) continue;\n\n // Resolve asset for images\n if (layer.visual.type === \"image\") {\n const iv = eff.visual as ImageVisual;\n if (!iv.src && iv.assetId && doc.assets?.[iv.assetId]) {\n (eff.visual as ImageVisual).src = doc.assets[iv.assetId].src;\n }\n }\n\n // Build transform\n const transform = buildTransform(eff);\n const styleAttrs = buildStyleAttrs(eff);\n\n // Build shadow filter\n const filterResult = buildShadowFilter(eff);\n if (filterResult) allDefs.push(filterResult.defs);\n\n // Build tint filter\n const tintResult = buildTintFilter(eff);\n if (tintResult) allDefs.push(tintResult.defs);\n\n // Build clip path\n let clipAttr = \"\";\n if (layer.clipPath) {\n const clipResult = buildClipPathDef(layer.clipPath, eff.width, eff.height);\n if (clipResult.defs) {\n allDefs.push(clipResult.defs);\n clipAttr = ` clip-path=\"${clipResult.clipRef}\"`;\n }\n }\n\n // Build group attributes\n const gAttrs: string[] = [];\n if (transform) gAttrs.push(`transform=\"${transform}\"`);\n if (styleAttrs) gAttrs.push(styleAttrs);\n // Apply combined or individual filters\n if (filterResult && tintResult) {\n // When both shadow and tint exist, we need a combined filter\n // For simplicity, apply shadow filter and tint separately via style\n gAttrs.push(`filter=\"${filterResult.filterRef}\"`);\n // Tint is a second filter — wrap content in nested group\n } else if (filterResult) {\n gAttrs.push(`filter=\"${filterResult.filterRef}\"`);\n } else if (tintResult) {\n gAttrs.push(`filter=\"${tintResult.filterRef}\"`);\n }\n if (clipAttr) gAttrs.push(clipAttr.trim());\n\n // Render visual content\n let content = \"\";\n let layerDefs = \"\";\n\n switch (layer.visual.type) {\n case \"shape\": {\n const result = renderShapeSVG(eff, eff.visual as import(\"@a-company/atelier-types\").ShapeVisual);\n content = result.elements;\n layerDefs = result.defs;\n break;\n }\n case \"text\":\n content = renderTextSVG(eff, eff.visual as import(\"@a-company/atelier-types\").TextVisual);\n break;\n case \"image\": {\n const iv = eff.visual as ImageVisual;\n if (iv.src) {\n if (iv.spritesheet) {\n // Spritesheet: compute source rect and use full sheet dimensions for inner image\n const { columns, rows, frameWidth, frameHeight, frameCount } = iv.spritesheet;\n const maxFrames = frameCount ?? (columns * rows);\n const idx = Math.max(0, Math.min(Math.floor(iv.frameIndex ?? 0), maxFrames - 1));\n const col = idx % columns;\n const row = Math.floor(idx / columns);\n const sx = col * frameWidth;\n const sy = row * frameHeight;\n const imgW = columns * frameWidth;\n const imgH = rows * frameHeight;\n content = `<svg viewBox=\"${sx} ${sy} ${frameWidth} ${frameHeight}\" width=\"${eff.width}\" height=\"${eff.height}\">` +\n `<image href=\"${escapeXml(iv.src)}\" width=\"${imgW}\" height=\"${imgH}\" />` +\n `</svg>`;\n } else if (iv.sourceRect) {\n // Manual sourceRect: viewBox crops from image coordinate space\n const sr = iv.sourceRect;\n content = `<svg viewBox=\"${sr.x} ${sr.y} ${sr.width} ${sr.height}\" width=\"${eff.width}\" height=\"${eff.height}\">` +\n `<image href=\"${escapeXml(iv.src)}\" width=\"${eff.width}\" height=\"${eff.height}\" />` +\n `</svg>`;\n } else {\n content = `<image href=\"${escapeXml(iv.src)}\" width=\"${eff.width}\" height=\"${eff.height}\" />`;\n }\n }\n break;\n }\n case \"group\":\n // Groups are structural — no visual content in SVG either\n break;\n case \"ref\": {\n const refVisual = eff.visual as RefVisual;\n const refContent = renderRefSVG(eff, refVisual, doc, opts);\n content = refContent;\n break;\n }\n }\n\n if (layerDefs) allDefs.push(layerDefs);\n\n if (content) {\n const gOpen = gAttrs.length > 0 ? `<g ${gAttrs.join(\" \")}>` : \"<g>\";\n layerElements.push(`${pad}${gOpen}${content}</g>`);\n }\n }\n\n // Build SVG\n const lines: string[] = [];\n\n if (opts?.xmlDeclaration) {\n lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n }\n\n const viewBox = opts?.viewBox !== false ? ` viewBox=\"0 0 ${width} ${height}\"` : \"\";\n const bg = doc.canvas.background;\n\n lines.push(`<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"${viewBox}>`);\n\n // Defs section\n if (allDefs.length > 0) {\n lines.push(`${pad}<defs>`);\n for (const def of allDefs) {\n lines.push(`${pad}${pad}${def}`);\n }\n lines.push(`${pad}</defs>`);\n }\n\n // Background\n if (bg && bg !== \"transparent\") {\n lines.push(`${pad}<rect width=\"${width}\" height=\"${height}\" fill=\"${bg}\" />`);\n }\n\n // Layers\n lines.push(...layerElements);\n\n lines.push(\"</svg>\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Render a ref layer as SVG. Uses documentResolver to inline sub-doc content,\n * or falls back to a dashed placeholder rectangle.\n */\nfunction renderRefSVG(\n eff: EffectiveLayer,\n visual: RefVisual,\n _parentDoc: AtelierDocument,\n opts?: RenderSVGOptions,\n _depth?: number,\n _visitedRefs?: Set<string>,\n): string {\n const resolver = opts?.documentResolver;\n\n if (!resolver) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" />`;\n }\n\n const depth = _depth ?? 0;\n const maxDepth = opts?.maxRefDepth ?? 4;\n if (depth >= maxDepth) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#c33\" stroke-dasharray=\"4 2\" /><text x=\"${eff.width / 2}\" y=\"${eff.height / 2}\" text-anchor=\"middle\" dominant-baseline=\"middle\" fill=\"#c33\" font-size=\"12\">MAX DEPTH</text>`;\n }\n\n const visitedRefs = _visitedRefs ?? new Set<string>();\n if (visitedRefs.has(visual.src)) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#c33\" stroke-dasharray=\"4 2\" /><text x=\"${eff.width / 2}\" y=\"${eff.height / 2}\" text-anchor=\"middle\" dominant-baseline=\"middle\" fill=\"#c33\" font-size=\"12\">CYCLE</text>`;\n }\n\n const subDoc = resolver(visual.src);\n if (!subDoc) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" /><text x=\"${eff.width / 2}\" y=\"${eff.height / 2}\" text-anchor=\"middle\" dominant-baseline=\"middle\" fill=\"#999\" font-size=\"12\">NOT FOUND</text>`;\n }\n\n const stateNames = Object.keys(subDoc.states);\n if (stateNames.length === 0) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" />`;\n }\n\n const stateName = visual.state ?? stateNames[0];\n const stateObj = subDoc.states[stateName];\n if (!stateObj) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" />`;\n }\n\n const maxFrame = Math.max(0, stateObj.duration - 1);\n const frame = Math.min(visual.frame ?? 0, maxFrame);\n\n visitedRefs.add(visual.src);\n\n // Render sub-doc as nested <svg> with viewBox for scaling\n const subW = subDoc.canvas.width;\n const subH = subDoc.canvas.height;\n const resolved = resolveFrame(subDoc, stateName, frame);\n\n const subParts: string[] = [];\n for (const rl of resolved.layers) {\n const subEff = buildEffectiveLayer(rl, subW, subH);\n if (!subEff.visible || subEff.opacity <= 0) continue;\n\n // Resolve asset\n if (rl.layer.visual.type === \"image\") {\n const iv = subEff.visual as ImageVisual;\n if (!iv.src && iv.assetId && subDoc.assets?.[iv.assetId]) {\n iv.src = subDoc.assets[iv.assetId].src;\n }\n }\n\n const transform = buildTransform(subEff);\n const styleAttrs = buildStyleAttrs(subEff);\n const gAttrs: string[] = [];\n if (transform) gAttrs.push(`transform=\"${transform}\"`);\n if (styleAttrs) gAttrs.push(styleAttrs);\n\n let childContent = \"\";\n switch (rl.layer.visual.type) {\n case \"shape\": {\n const result = renderShapeSVG(subEff, subEff.visual as import(\"@a-company/atelier-types\").ShapeVisual);\n childContent = result.elements;\n break;\n }\n case \"text\":\n childContent = renderTextSVG(subEff, subEff.visual as import(\"@a-company/atelier-types\").TextVisual);\n break;\n case \"image\": {\n const iv = subEff.visual as ImageVisual;\n if (iv.src) {\n childContent = `<image href=\"${escapeXml(iv.src)}\" width=\"${subEff.width}\" height=\"${subEff.height}\" />`;\n }\n break;\n }\n case \"ref\": {\n const refV = subEff.visual as RefVisual;\n childContent = renderRefSVG(subEff, refV, subDoc, opts, depth + 1, visitedRefs);\n break;\n }\n }\n\n if (childContent) {\n const gOpen = gAttrs.length > 0 ? `<g ${gAttrs.join(\" \")}>` : \"<g>\";\n subParts.push(`${gOpen}${childContent}</g>`);\n }\n }\n\n visitedRefs.delete(visual.src);\n\n return `<svg x=\"0\" y=\"0\" width=\"${eff.width}\" height=\"${eff.height}\" viewBox=\"0 0 ${subW} ${subH}\">${subParts.join(\"\")}</svg>`;\n}\n","import type { EffectiveLayer } from \"@a-company/atelier-canvas\";\n\n/** Build SVG transform attribute from effective layer values */\nexport function buildTransform(eff: EffectiveLayer): string {\n const parts: string[] = [];\n\n // Translate to position\n if (eff.x !== 0 || eff.y !== 0) {\n parts.push(`translate(${eff.x}, ${eff.y})`);\n }\n\n const totalRotation = eff.rotation + eff.motionPathAngle;\n if (totalRotation !== 0 || eff.scaleX !== 1 || eff.scaleY !== 1) {\n const ax = eff.anchorX * eff.width;\n const ay = eff.anchorY * eff.height;\n\n // Move to anchor, apply rotation/scale, move back\n if (ax !== 0 || ay !== 0) {\n parts.push(`translate(${ax}, ${ay})`);\n }\n if (totalRotation !== 0) {\n parts.push(`rotate(${totalRotation})`);\n }\n if (eff.scaleX !== 1 || eff.scaleY !== 1) {\n parts.push(`scale(${eff.scaleX}, ${eff.scaleY})`);\n }\n if (ax !== 0 || ay !== 0) {\n parts.push(`translate(${-ax}, ${-ay})`);\n }\n }\n\n return parts.length > 0 ? parts.join(\" \") : \"\";\n}\n\n/** Build common SVG style attributes */\nexport function buildStyleAttrs(eff: EffectiveLayer): string {\n const attrs: string[] = [];\n\n if (eff.opacity < 1) {\n attrs.push(`opacity=\"${eff.opacity}\"`);\n }\n\n if (eff.blendMode !== \"normal\") {\n attrs.push(`style=\"mix-blend-mode: ${eff.blendMode}\"`);\n }\n\n return attrs.join(\" \");\n}\n\n/** Escape XML special characters */\nexport function escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n","import type { Fill, LinearGradientFill, RadialGradientFill, Color, RGBAColor, HSLAColor } from \"@a-company/atelier-types\";\n\nlet gradientIdCounter = 0;\n\nexport function resetGradientCounter(): void {\n gradientIdCounter = 0;\n}\n\n/** Convert an Atelier Color to a CSS color string */\nexport function colorToCSS(color: Color): string {\n if (typeof color === \"string\") return color;\n if (\"r\" in color) {\n const c = color as RGBAColor;\n return `rgba(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)}, ${c.a})`;\n }\n if (\"h\" in color) {\n const c = color as HSLAColor;\n return `hsla(${c.h}, ${c.s}%, ${c.l}%, ${c.a})`;\n }\n return \"#000000\";\n}\n\n/** Generate SVG gradient defs and return the fill reference */\nexport function buildGradientDef(fill: Fill, width: number, height: number): { defs: string; fillRef: string } {\n if (fill.type === \"solid\") {\n return { defs: \"\", fillRef: colorToCSS(fill.color) };\n }\n\n if (fill.type === \"linear-gradient\") {\n return buildLinearGradient(fill, width, height);\n }\n\n if (fill.type === \"radial-gradient\") {\n return buildRadialGradient(fill, width, height);\n }\n\n return { defs: \"\", fillRef: \"none\" };\n}\n\nfunction buildLinearGradient(fill: LinearGradientFill, _width: number, _height: number): { defs: string; fillRef: string } {\n const id = `grad-${++gradientIdCounter}`;\n const rad = (fill.angle * Math.PI) / 180;\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n\n // Map angle to x1,y1,x2,y2 (0-1 percentages)\n const x1 = 0.5 - cos * 0.5;\n const y1 = 0.5 - sin * 0.5;\n const x2 = 0.5 + cos * 0.5;\n const y2 = 0.5 + sin * 0.5;\n\n const stops = fill.stops.map(s =>\n `<stop offset=\"${s.offset}\" stop-color=\"${colorToCSS(s.color)}\" />`\n ).join(\"\");\n\n const def = `<linearGradient id=\"${id}\" x1=\"${x1}\" y1=\"${y1}\" x2=\"${x2}\" y2=\"${y2}\">${stops}</linearGradient>`;\n return { defs: def, fillRef: `url(#${id})` };\n}\n\nfunction buildRadialGradient(fill: RadialGradientFill, width: number, height: number): { defs: string; fillRef: string } {\n const id = `grad-${++gradientIdCounter}`;\n\n const cx = typeof fill.center.x === \"number\" ? fill.center.x : (parseFloat(fill.center.x) / 100) * width;\n const cy = typeof fill.center.y === \"number\" ? fill.center.y : (parseFloat(fill.center.y) / 100) * height;\n const r = typeof fill.radius === \"number\" ? fill.radius : (parseFloat(fill.radius) / 100) * Math.max(width, height);\n\n const stops = fill.stops.map(s =>\n `<stop offset=\"${s.offset}\" stop-color=\"${colorToCSS(s.color)}\" />`\n ).join(\"\");\n\n const def = `<radialGradient id=\"${id}\" cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" gradientUnits=\"userSpaceOnUse\">${stops}</radialGradient>`;\n return { defs: def, fillRef: `url(#${id})` };\n}\n","import type { ShapeVisual, Shape, RectShape, PathShape, Stroke } from \"@a-company/atelier-types\";\nimport type { EffectiveLayer } from \"@a-company/atelier-canvas\";\nimport { buildGradientDef, colorToCSS } from \"./svg-gradients.js\";\n\n/** Render a shape visual as SVG elements */\nexport function renderShapeSVG(\n eff: EffectiveLayer,\n visual: ShapeVisual,\n): { elements: string; defs: string } {\n const { shape } = visual;\n const defs: string[] = [];\n\n let fillAttr = \"none\";\n if (visual.fill) {\n const gradResult = buildGradientDef(visual.fill, eff.width, eff.height);\n if (gradResult.defs) defs.push(gradResult.defs);\n fillAttr = gradResult.fillRef;\n }\n\n let strokeAttrs = \"\";\n if (visual.stroke) {\n strokeAttrs = buildStrokeAttrs(visual.stroke);\n }\n\n const element = buildShapeElement(shape, eff.width, eff.height, fillAttr, strokeAttrs);\n return { elements: element, defs: defs.join(\"\") };\n}\n\nfunction buildShapeElement(\n shape: Shape,\n width: number,\n height: number,\n fill: string,\n strokeAttrs: string,\n): string {\n switch (shape.type) {\n case \"rect\":\n return buildRectElement(shape, width, height, fill, strokeAttrs);\n case \"ellipse\":\n return buildEllipseElement(width, height, fill, strokeAttrs);\n case \"path\":\n return buildPathElement(shape, fill, strokeAttrs);\n }\n}\n\nfunction buildRectElement(\n shape: RectShape,\n width: number,\n height: number,\n fill: string,\n strokeAttrs: string,\n): string {\n let rx = \"\";\n if (shape.cornerRadius) {\n const r = typeof shape.cornerRadius === \"number\" ? shape.cornerRadius : shape.cornerRadius[0];\n rx = ` rx=\"${r}\" ry=\"${r}\"`;\n }\n return `<rect width=\"${width}\" height=\"${height}\" fill=\"${fill}\"${rx}${strokeAttrs ? \" \" + strokeAttrs : \"\"} />`;\n}\n\nfunction buildEllipseElement(\n width: number,\n height: number,\n fill: string,\n strokeAttrs: string,\n): string {\n const cx = width / 2;\n const cy = height / 2;\n const rx = width / 2;\n const ry = height / 2;\n return `<ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${rx}\" ry=\"${ry}\" fill=\"${fill}\"${strokeAttrs ? \" \" + strokeAttrs : \"\"} />`;\n}\n\nfunction buildPathElement(\n shape: PathShape,\n fill: string,\n strokeAttrs: string,\n): string {\n if (shape.points.length < 2) return \"\";\n\n const d: string[] = [];\n d.push(`M ${shape.points[0].x} ${shape.points[0].y}`);\n\n for (let i = 1; i < shape.points.length; i++) {\n const prev = shape.points[i - 1];\n const curr = shape.points[i];\n\n if (prev.out && curr.in) {\n d.push(`C ${prev.x + prev.out.x} ${prev.y + prev.out.y} ${curr.x + curr.in.x} ${curr.y + curr.in.y} ${curr.x} ${curr.y}`);\n } else {\n d.push(`L ${curr.x} ${curr.y}`);\n }\n }\n\n if (shape.closed) d.push(\"Z\");\n\n return `<path d=\"${d.join(\" \")}\" fill=\"${fill}\"${strokeAttrs ? \" \" + strokeAttrs : \"\"} />`;\n}\n\nfunction buildStrokeAttrs(stroke: Stroke): string {\n const parts: string[] = [];\n parts.push(`stroke=\"${colorToCSS(stroke.color)}\"`);\n parts.push(`stroke-width=\"${stroke.width}\"`);\n\n if (stroke.lineCap) parts.push(`stroke-linecap=\"${stroke.lineCap}\"`);\n if (stroke.lineJoin) parts.push(`stroke-linejoin=\"${stroke.lineJoin}\"`);\n if (stroke.dash) parts.push(`stroke-dasharray=\"${stroke.dash.join(\" \")}\"`);\n\n return parts.join(\" \");\n}\n","import type { TextVisual } from \"@a-company/atelier-types\";\nimport type { EffectiveLayer } from \"@a-company/atelier-canvas\";\nimport { colorToCSS } from \"./svg-gradients.js\";\nimport { escapeXml } from \"./svg-properties.js\";\n\n/** Render a text visual as SVG elements */\nexport function renderTextSVG(eff: EffectiveLayer, visual: TextVisual): string {\n const { style } = visual;\n\n const attrs: string[] = [];\n\n // Font attributes\n attrs.push(`font-family=\"${escapeXml(style.fontFamily)}\"`);\n attrs.push(`font-size=\"${style.fontSize}\"`);\n\n if (style.fontWeight && style.fontWeight !== \"normal\") {\n attrs.push(`font-weight=\"${style.fontWeight}\"`);\n }\n if (style.fontStyle && style.fontStyle !== \"normal\") {\n attrs.push(`font-style=\"${style.fontStyle}\"`);\n }\n\n // Color\n attrs.push(`fill=\"${colorToCSS(style.color)}\"`);\n\n // Text alignment\n const align = style.textAlign ?? \"left\";\n let textAnchor = \"start\";\n let x = 0;\n if (align === \"center\") {\n textAnchor = \"middle\";\n x = eff.width / 2;\n } else if (align === \"right\") {\n textAnchor = \"end\";\n x = eff.width;\n }\n attrs.push(`text-anchor=\"${textAnchor}\"`);\n\n // Letter spacing\n if (style.letterSpacing) {\n attrs.push(`letter-spacing=\"${style.letterSpacing}\"`);\n }\n\n // SVG text baseline: use dominant-baseline for top alignment\n attrs.push(`dominant-baseline=\"hanging\"`);\n\n return `<text x=\"${x}\" y=\"0\" ${attrs.join(\" \")}>${escapeXml(visual.content)}</text>`;\n}\n","import type { EffectiveLayer } from \"@a-company/atelier-canvas\";\n\nlet filterIdCounter = 0;\n\nexport function resetFilterCounter(): void {\n filterIdCounter = 0;\n}\n\n/** Build SVG filter definition for shadow effects */\nexport function buildShadowFilter(eff: EffectiveLayer): { defs: string; filterRef: string } | null {\n if (!eff.shadow) return null;\n\n const id = `filter-${++filterIdCounter}`;\n const { color, blur, offsetX, offsetY } = eff.shadow;\n\n const def = [\n `<filter id=\"${id}\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">`,\n `<feDropShadow dx=\"${offsetX}\" dy=\"${offsetY}\" stdDeviation=\"${blur / 2}\" flood-color=\"${color}\" />`,\n `</filter>`,\n ].join(\"\");\n\n return { defs: def, filterRef: `url(#${id})` };\n}\n\n/** Build SVG filter definition for tint effect (feFlood + feBlend multiply) */\nexport function buildTintFilter(eff: EffectiveLayer): { defs: string; filterRef: string } | null {\n if (!eff.tint || eff.tint.amount <= 0) return null;\n\n const id = `filter-${++filterIdCounter}`;\n const { color, amount } = eff.tint;\n\n const def = [\n `<filter id=\"${id}\" x=\"0%\" y=\"0%\" width=\"100%\" height=\"100%\">`,\n `<feFlood flood-color=\"${color}\" flood-opacity=\"${amount}\" result=\"tint\" />`,\n `<feBlend in=\"SourceGraphic\" in2=\"tint\" mode=\"multiply\" />`,\n `</filter>`,\n ].join(\"\");\n\n return { defs: def, filterRef: `url(#${id})` };\n}\n","import type { Shape } from \"@a-company/atelier-types\";\n\nlet clipIdCounter = 0;\n\nexport function resetClipCounter(): void {\n clipIdCounter = 0;\n}\n\n/** Build SVG clipPath definition */\nexport function buildClipPathDef(shape: Shape, width: number, height: number): { defs: string; clipRef: string } {\n const id = `clip-${++clipIdCounter}`;\n let pathContent = \"\";\n\n switch (shape.type) {\n case \"rect\":\n if (shape.cornerRadius) {\n const r = typeof shape.cornerRadius === \"number\" ? shape.cornerRadius : shape.cornerRadius[0];\n pathContent = `<rect width=\"${width}\" height=\"${height}\" rx=\"${r}\" ry=\"${r}\" />`;\n } else {\n pathContent = `<rect width=\"${width}\" height=\"${height}\" />`;\n }\n break;\n case \"ellipse\":\n pathContent = `<ellipse cx=\"${width / 2}\" cy=\"${height / 2}\" rx=\"${width / 2}\" ry=\"${height / 2}\" />`;\n break;\n case \"path\": {\n if (shape.points.length < 2) return { defs: \"\", clipRef: \"\" };\n const d: string[] = [];\n d.push(`M ${shape.points[0].x} ${shape.points[0].y}`);\n for (let i = 1; i < shape.points.length; i++) {\n const prev = shape.points[i - 1];\n const curr = shape.points[i];\n if (prev.out && curr.in) {\n d.push(`C ${prev.x + prev.out.x} ${prev.y + prev.out.y} ${curr.x + curr.in.x} ${curr.y + curr.in.y} ${curr.x} ${curr.y}`);\n } else {\n d.push(`L ${curr.x} ${curr.y}`);\n }\n }\n if (shape.closed) d.push(\"Z\");\n pathContent = `<path d=\"${d.join(\" \")}\" />`;\n break;\n }\n }\n\n const def = `<clipPath id=\"${id}\">${pathContent}</clipPath>`;\n return { defs: def, clipRef: `url(#${id})` };\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { exportToLottie } from \"@a-company/atelier-lottie\";\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/** Register the `export-lottie` subcommand on the Commander program. */\nexport function exportLottieCommand(program: Command): void {\n program\n .command(\"export-lottie <file>\")\n .description(\"Export a document to Lottie JSON format\")\n .option(\"-s, --state <name>\", \"State name (defaults to first state)\")\n .option(\"-o, --output <path>\", \"Output file path (default: stdout)\")\n .action(\n (\n file: string,\n options: { state?: string; output?: string },\n ) => {\n const doc = readAndParse(file);\n\n try {\n const { json, warnings } = exportToLottie(doc, {\n state: options.state,\n });\n\n // Print warnings to stderr\n for (const warning of warnings) {\n console.error(`Warning: ${warning}`);\n }\n\n const output = JSON.stringify(json, null, 2);\n if (options.output) {\n writeFileSync(resolve(options.output), output, \"utf-8\");\n } else {\n console.log(output);\n }\n } catch (err) {\n console.error((err as Error).message);\n process.exit(1);\n }\n },\n );\n}\n","import type { Color, RGBAColor, HSLAColor } from \"@a-company/atelier-types\";\n\n/** Convert an Atelier color to Lottie [r, g, b, a] format (0–1 range) */\nexport function colorToLottie(color: Color): number[] {\n if (typeof color === \"string\") {\n return hexToLottie(color);\n }\n\n if (\"r\" in color) {\n const c = color as RGBAColor;\n return [c.r / 255, c.g / 255, c.b / 255, c.a];\n }\n\n if (\"h\" in color) {\n const c = color as HSLAColor;\n const rgb = hslToRgb(c.h, c.s, c.l);\n return [rgb[0] / 255, rgb[1] / 255, rgb[2] / 255, c.a];\n }\n\n return [0, 0, 0, 1];\n}\n\nfunction hexToLottie(hex: string): number[] {\n const clean = hex.replace(\"#\", \"\");\n if (clean.length === 3 || clean.length === 4) {\n const r = parseInt(clean[0] + clean[0], 16) / 255;\n const g = parseInt(clean[1] + clean[1], 16) / 255;\n const b = parseInt(clean[2] + clean[2], 16) / 255;\n const a = clean.length === 4 ? parseInt(clean[3] + clean[3], 16) / 255 : 1;\n return [r, g, b, a];\n }\n const r = parseInt(clean.slice(0, 2), 16) / 255;\n const g = parseInt(clean.slice(2, 4), 16) / 255;\n const b = parseInt(clean.slice(4, 6), 16) / 255;\n const a = clean.length === 8 ? parseInt(clean.slice(6, 8), 16) / 255 : 1;\n return [r, g, b, a];\n}\n\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n s = s / 100;\n l = l / 100;\n const a = s * Math.min(l, 1 - l);\n const f = (n: number) => {\n const k = (n + h / 30) % 12;\n return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n };\n return [Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255)];\n}\n","import type { ShapeVisual, Fill, Stroke } from \"@a-company/atelier-types\";\nimport type { LottieShapeItem } from \"./lottie-types.js\";\nimport { colorToLottie } from \"./map-colors.js\";\n\n/** Map an Atelier shape visual to Lottie shape items */\nexport function mapShapeVisual(\n visual: ShapeVisual,\n width: number,\n height: number,\n): LottieShapeItem[] {\n const items: LottieShapeItem[] = [];\n\n // Shape geometry\n switch (visual.shape.type) {\n case \"rect\":\n items.push({\n ty: \"rc\",\n nm: \"Rectangle\",\n d: 1,\n s: { a: 0, k: [width, height] },\n p: { a: 0, k: [width / 2, height / 2] },\n r: { a: 0, k: typeof visual.shape.cornerRadius === \"number\" ? visual.shape.cornerRadius : 0 },\n });\n break;\n case \"ellipse\":\n items.push({\n ty: \"el\",\n nm: \"Ellipse\",\n d: 1,\n s: { a: 0, k: [width, height] },\n p: { a: 0, k: [width / 2, height / 2] },\n });\n break;\n case \"path\": {\n const vertices = visual.shape.points.map(p => [p.x, p.y]);\n const inTangents = visual.shape.points.map(p => p.in ? [p.in.x, p.in.y] : [0, 0]);\n const outTangents = visual.shape.points.map(p => p.out ? [p.out.x, p.out.y] : [0, 0]);\n items.push({\n ty: \"sh\",\n nm: \"Path\",\n ks: {\n a: 0,\n k: {\n c: visual.shape.closed ?? false,\n v: vertices,\n i: inTangents,\n o: outTangents,\n },\n },\n });\n break;\n }\n }\n\n // Fill\n if (visual.fill) {\n items.push(mapFill(visual.fill, width, height));\n }\n\n // Stroke\n if (visual.stroke) {\n items.push(mapStroke(visual.stroke));\n }\n\n return items;\n}\n\nfunction mapFill(fill: Fill, _width: number, _height: number): LottieShapeItem {\n if (fill.type === \"solid\") {\n const color = colorToLottie(fill.color);\n return {\n ty: \"fl\",\n nm: \"Fill\",\n c: { a: 0, k: color.slice(0, 3) },\n o: { a: 0, k: (color[3] ?? 1) * 100 },\n r: 1,\n };\n }\n\n if (fill.type === \"linear-gradient\") {\n const stops: number[] = [];\n for (const stop of fill.stops) {\n const c = colorToLottie(stop.color);\n stops.push(stop.offset, c[0], c[1], c[2]);\n }\n return {\n ty: \"gf\",\n nm: \"Gradient Fill\",\n t: 1, // linear\n s: { a: 0, k: [0, 0] },\n e: { a: 0, k: [100, 0] },\n g: { p: fill.stops.length, k: { a: 0, k: stops } },\n r: 1,\n o: { a: 0, k: 100 },\n };\n }\n\n if (fill.type === \"radial-gradient\") {\n const stops: number[] = [];\n for (const stop of fill.stops) {\n const c = colorToLottie(stop.color);\n stops.push(stop.offset, c[0], c[1], c[2]);\n }\n return {\n ty: \"gf\",\n nm: \"Gradient Fill\",\n t: 2, // radial\n s: { a: 0, k: [50, 50] },\n e: { a: 0, k: [100, 50] },\n g: { p: fill.stops.length, k: { a: 0, k: stops } },\n r: 1,\n o: { a: 0, k: 100 },\n };\n }\n\n return { ty: \"fl\", nm: \"Fill\", c: { a: 0, k: [0, 0, 0] }, o: { a: 0, k: 100 }, r: 1 };\n}\n\nfunction mapStroke(stroke: Stroke): LottieShapeItem {\n const color = colorToLottie(stroke.color);\n return {\n ty: \"st\",\n nm: \"Stroke\",\n c: { a: 0, k: color.slice(0, 3) },\n o: { a: 0, k: (color[3] ?? 1) * 100 },\n w: { a: 0, k: stroke.width },\n lc: stroke.lineCap === \"round\" ? 2 : stroke.lineCap === \"square\" ? 3 : 1,\n lj: stroke.lineJoin === \"round\" ? 2 : stroke.lineJoin === \"bevel\" ? 3 : 1,\n };\n}\n","import type { Easing } from \"@a-company/atelier-types\";\n\nexport interface LottieEasing {\n i: { x: number[]; y: number[] };\n o: { x: number[]; y: number[] };\n}\n\n/** Map an Atelier easing to Lottie bezier easing curves */\nexport function mapEasing(easing: Easing | undefined): LottieEasing | { h: 1 } {\n if (!easing) return linearEasing();\n\n if (typeof easing === \"string\") {\n switch (easing) {\n case \"ease-in\":\n return bezierEasing(0.42, 0, 1, 1);\n case \"ease-out\":\n return bezierEasing(0, 0, 0.58, 1);\n case \"ease-in-out\":\n return bezierEasing(0.42, 0, 0.58, 1);\n default:\n return linearEasing();\n }\n }\n\n switch (easing.type) {\n case \"linear\":\n return linearEasing();\n case \"cubic-bezier\":\n return bezierEasing(easing.x1, easing.y1, easing.x2, easing.y2);\n case \"spring\":\n // Approximate spring as a cubic-bezier (lossy)\n return bezierEasing(0.25, 0.1, 0.25, 1);\n case \"step\":\n // Steps map to hold keyframes\n return { h: 1 };\n default:\n return linearEasing();\n }\n}\n\nfunction linearEasing(): LottieEasing {\n return {\n i: { x: [0.833], y: [0.833] },\n o: { x: [0.167], y: [0.167] },\n };\n}\n\nfunction bezierEasing(x1: number, y1: number, x2: number, y2: number): LottieEasing {\n return {\n i: { x: [x2], y: [y2] },\n o: { x: [x1], y: [y1] },\n };\n}\n\n/** Check if an easing is lossy (spring/step → approximated) */\nexport function isLossyEasing(easing: Easing | undefined): string | null {\n if (!easing || typeof easing === \"string\") return null;\n if (easing.type === \"spring\") return \"Spring easing approximated as cubic-bezier\";\n if (easing.type === \"step\") return \"Step easing mapped to hold keyframes\";\n return null;\n}\n","import type { Delta, AnimatableProperty } from \"@a-company/atelier-types\";\nimport type { LottieAnimatedValue, LottieAnimatedMultiValue, LottieKeyframe, LottieMultiKeyframe } from \"./lottie-types.js\";\nimport { mapEasing, isLossyEasing } from \"./map-easing.js\";\n\n/** Map deltas for a single layer+property to Lottie animated value */\nexport function mapDeltasToAnimated(\n deltas: Delta[],\n property: AnimatableProperty,\n warnings: string[],\n): LottieAnimatedValue {\n if (deltas.length === 0) {\n return { a: 0, k: 0 };\n }\n\n // Check for lossy easings\n for (const d of deltas) {\n const lossyMsg = isLossyEasing(d.easing);\n if (lossyMsg) warnings.push(`${property}: ${lossyMsg}`);\n }\n\n // If expressions, warn and use static\n for (const d of deltas) {\n if (isExpression(d.from) || isExpression(d.to)) {\n warnings.push(`${property}: Expression values not supported in Lottie, using static values`);\n return { a: 0, k: typeof d.from === \"number\" ? d.from : 0 };\n }\n }\n\n // Single delta — simple animated value\n if (deltas.length === 1) {\n const d = deltas[0];\n const fromVal = resolveValue(d.from, property);\n const toVal = resolveValue(d.to, property);\n\n if (fromVal === toVal) {\n return { a: 0, k: fromVal };\n }\n\n const easing = mapEasing(d.easing);\n const kfs: LottieKeyframe[] = [];\n\n if (\"h\" in easing) {\n kfs.push({ t: d.range[0], s: [fromVal], h: 1 });\n kfs.push({ t: d.range[1], s: [toVal] });\n } else {\n kfs.push({ t: d.range[0], s: [fromVal], e: [toVal], i: easing.i, o: easing.o });\n kfs.push({ t: d.range[1], s: [toVal] });\n }\n\n return { a: 1, k: kfs };\n }\n\n // Multiple deltas — chain keyframes\n const sorted = [...deltas].sort((a, b) => a.range[0] - b.range[0]);\n const kfs: LottieKeyframe[] = [];\n\n for (const d of sorted) {\n const fromVal = resolveValue(d.from, property);\n const toVal = resolveValue(d.to, property);\n const easing = mapEasing(d.easing);\n\n if (\"h\" in easing) {\n kfs.push({ t: d.range[0], s: [fromVal], h: 1 });\n } else {\n kfs.push({ t: d.range[0], s: [fromVal], e: [toVal], i: easing.i, o: easing.o });\n }\n }\n\n // Final keyframe\n const last = sorted[sorted.length - 1];\n kfs.push({ t: last.range[1], s: [resolveValue(last.to, property)] });\n\n return { a: 1, k: kfs };\n}\n\n/** Map position deltas (frame.x, frame.y) to Lottie multi-dimensional animated value */\nexport function mapPositionDeltas(\n xDeltas: Delta[],\n yDeltas: Delta[],\n baseX: number,\n baseY: number,\n warnings: string[],\n): LottieAnimatedMultiValue {\n const hasXAnim = xDeltas.length > 0;\n const hasYAnim = yDeltas.length > 0;\n\n if (!hasXAnim && !hasYAnim) {\n return { a: 0, k: [baseX, baseY, 0] };\n }\n\n // Collect all unique frame points\n const frames = new Set<number>();\n for (const d of [...xDeltas, ...yDeltas]) {\n frames.add(d.range[0]);\n frames.add(d.range[1]);\n }\n const sortedFrames = [...frames].sort((a, b) => a - b);\n\n if (sortedFrames.length < 2) {\n return { a: 0, k: [baseX, baseY, 0] };\n }\n\n // Build multi-dimensional keyframes\n const kfs: LottieMultiKeyframe[] = [];\n for (let i = 0; i < sortedFrames.length; i++) {\n const f = sortedFrames[i];\n const x = resolveAtFrame(xDeltas, f, baseX);\n const y = resolveAtFrame(yDeltas, f, baseY);\n\n if (i < sortedFrames.length - 1) {\n const nextF = sortedFrames[i + 1];\n const nextX = resolveAtFrame(xDeltas, nextF, baseX);\n const nextY = resolveAtFrame(yDeltas, nextF, baseY);\n\n // Find the active delta's easing\n const activeX = xDeltas.find(d => d.range[0] <= f && d.range[1] >= f);\n const activeY = yDeltas.find(d => d.range[0] <= f && d.range[1] >= f);\n const easing = mapEasing(activeX?.easing ?? activeY?.easing);\n\n if (\"h\" in easing) {\n kfs.push({ t: f, s: [x, y, 0], h: 1 });\n } else {\n kfs.push({ t: f, s: [x, y, 0], e: [nextX, nextY, 0], i: easing.i, o: easing.o });\n }\n } else {\n kfs.push({ t: f, s: [x, y, 0] });\n }\n }\n\n // Check for lossy warnings\n for (const d of [...xDeltas, ...yDeltas]) {\n const msg = isLossyEasing(d.easing);\n if (msg) warnings.push(`position: ${msg}`);\n }\n\n return { a: 1, k: kfs };\n}\n\nfunction resolveAtFrame(deltas: Delta[], frame: number, base: number): number {\n for (const d of deltas) {\n if (frame >= d.range[0] && frame <= d.range[1]) {\n const from = typeof d.from === \"number\" ? d.from : base;\n const to = typeof d.to === \"number\" ? d.to : base;\n const progress = d.range[0] === d.range[1] ? 1 : (frame - d.range[0]) / (d.range[1] - d.range[0]);\n return from + (to - from) * progress;\n }\n }\n // Hold last completed value\n let lastCompleted: Delta | undefined;\n for (const d of deltas) {\n if (frame > d.range[1]) {\n if (!lastCompleted || d.range[1] > lastCompleted.range[1]) {\n lastCompleted = d;\n }\n }\n }\n if (lastCompleted) return typeof lastCompleted.to === \"number\" ? lastCompleted.to : base;\n return base;\n}\n\nfunction resolveValue(val: unknown, _property: AnimatableProperty): number {\n if (typeof val === \"number\") return val;\n if (typeof val === \"string\" && val.startsWith(\"#\")) {\n // Color — for Lottie, colors are handled separately\n return 0;\n }\n return 0;\n}\n\nfunction isExpression(val: unknown): boolean {\n return typeof val === \"object\" && val !== null && \"expr\" in val;\n}\n","import type { AtelierDocument, Layer, Delta, State, UnitValue } from \"@a-company/atelier-types\";\nimport type { LottieLayer, LottieTransform, LottieTextData } from \"./lottie-types.js\";\nimport { mapShapeVisual } from \"./map-shapes.js\";\nimport { mapDeltasToAnimated, mapPositionDeltas } from \"./map-keyframes.js\";\nimport { colorToLottie } from \"./map-colors.js\";\n\n/** Resolve a UnitValue to a plain number (percentages treated as 0 for Lottie) */\nfunction toNum(v: UnitValue): number {\n return typeof v === \"number\" ? v : 0;\n}\n\n/** Map all layers in a document+state to Lottie layers */\nexport function mapLayers(\n doc: AtelierDocument,\n state: State,\n warnings: string[],\n): LottieLayer[] {\n const layerIndexMap = new Map<string, number>();\n doc.layers.forEach((l, i) => layerIndexMap.set(l.id, i));\n\n return doc.layers.map((layer, index) => {\n const deltas = state.deltas.filter(d => d.layer === layer.id);\n return mapLayer(layer, index, deltas, layerIndexMap, doc, warnings);\n });\n}\n\nfunction mapLayer(\n layer: Layer,\n index: number,\n deltas: Delta[],\n layerIndexMap: Map<string, number>,\n doc: AtelierDocument,\n warnings: string[],\n): LottieLayer {\n const duration = getMaxFrame(deltas, doc);\n\n const base: LottieLayer = {\n ty: getLayerType(layer),\n nm: layer.id,\n ind: index,\n ip: 0,\n op: duration,\n st: 0,\n ks: buildTransform(layer, deltas, warnings),\n };\n\n // Parent\n if (layer.parentId) {\n const parentIdx = layerIndexMap.get(layer.parentId);\n if (parentIdx !== undefined) {\n base.parent = parentIdx;\n }\n }\n\n // Blend mode\n if (layer.blendMode) {\n base.bm = mapBlendMode(layer.blendMode);\n }\n\n // Shape layer\n if (layer.visual.type === \"shape\") {\n base.shapes = mapShapeVisual(layer.visual, toNum(layer.bounds.width), toNum(layer.bounds.height));\n }\n\n // Text layer\n if (layer.visual.type === \"text\") {\n const color = colorToLottie(layer.visual.style.color);\n base.t = {\n d: {\n k: [{\n s: {\n s: layer.visual.style.fontSize,\n f: layer.visual.style.fontFamily,\n t: layer.visual.content,\n fc: color.slice(0, 3),\n j: layer.visual.style.textAlign === \"center\" ? 1 :\n layer.visual.style.textAlign === \"right\" ? 2 : 0,\n },\n t: 0,\n }],\n },\n } as LottieTextData;\n }\n\n // Image layer\n if (layer.visual.type === \"image\") {\n base.refId = layer.visual.assetId;\n base.w = toNum(layer.bounds.width);\n base.h = toNum(layer.bounds.height);\n\n if (layer.visual.spritesheet) {\n warnings.push(`Layer \"${layer.id}\": Spritesheet animation not supported in Lottie export`);\n }\n if (layer.visual.sourceRect) {\n warnings.push(`Layer \"${layer.id}\": sourceRect cropping not supported in Lottie export`);\n }\n }\n\n // Tint warning\n if (layer.tint && layer.tint.amount > 0) {\n warnings.push(`Layer \"${layer.id}\": Tint effect not supported in Lottie export`);\n }\n\n return base;\n}\n\nfunction getLayerType(layer: Layer): number {\n switch (layer.visual.type) {\n case \"shape\": return 4;\n case \"text\": return 5;\n case \"image\": return 2;\n case \"group\": return 3; // null layer\n case \"ref\": return 0; // precomp\n default: return 4;\n }\n}\n\nfunction buildTransform(\n layer: Layer,\n deltas: Delta[],\n warnings: string[],\n): LottieTransform {\n // Group deltas by property\n const byProp = new Map<string, Delta[]>();\n for (const d of deltas) {\n if (!byProp.has(d.property)) byProp.set(d.property, []);\n byProp.get(d.property)!.push(d);\n }\n\n const xDeltas = byProp.get(\"frame.x\") ?? [];\n const yDeltas = byProp.get(\"frame.y\") ?? [];\n const opacityDeltas = byProp.get(\"opacity\") ?? [];\n const rotationDeltas = byProp.get(\"rotation\") ?? [];\n const scaleXDeltas = byProp.get(\"scale.x\") ?? [];\n const scaleYDeltas = byProp.get(\"scale.y\") ?? [];\n\n // Position\n const position = mapPositionDeltas(\n xDeltas, yDeltas,\n typeof layer.frame.x === \"number\" ? layer.frame.x : 0,\n typeof layer.frame.y === \"number\" ? layer.frame.y : 0,\n warnings,\n );\n\n // Opacity (Lottie uses 0–100)\n let opacity;\n if (opacityDeltas.length > 0) {\n const raw = mapDeltasToAnimated(opacityDeltas, \"opacity\", warnings);\n // Scale 0-1 to 0-100\n if (raw.a === 0) {\n opacity = { a: 0 as const, k: (raw.k as number) * 100 };\n } else {\n const kfs = (raw.k as Array<{ t: number; s: [number]; e?: [number]; [key: string]: unknown }>).map(kf => ({\n ...kf,\n s: [kf.s[0] * 100] as [number],\n e: kf.e ? [kf.e[0] * 100] as [number] : undefined,\n }));\n opacity = { a: 1 as const, k: kfs };\n }\n } else {\n opacity = { a: 0 as const, k: (layer.opacity ?? 1) * 100 };\n }\n\n // Rotation\n const rotation = rotationDeltas.length > 0\n ? mapDeltasToAnimated(rotationDeltas, \"rotation\", warnings)\n : { a: 0 as const, k: layer.rotation ?? 0 };\n\n // Scale (Lottie uses 0–100)\n const baseScaleX = (layer.scale?.x ?? 1) * 100;\n const baseScaleY = (layer.scale?.y ?? 1) * 100;\n let scale;\n if (scaleXDeltas.length > 0 || scaleYDeltas.length > 0) {\n // Simplified: use x deltas for now\n scale = { a: 0 as const, k: [baseScaleX, baseScaleY, 100] };\n if (scaleXDeltas.length > 0 || scaleYDeltas.length > 0) {\n warnings.push(\"Scale animation partially mapped to Lottie\");\n }\n } else {\n scale = { a: 0 as const, k: [baseScaleX, baseScaleY, 100] };\n }\n\n // Anchor point\n const ax = (layer.anchorPoint?.x ?? 0) * toNum(layer.bounds.width);\n const ay = (layer.anchorPoint?.y ?? 0) * toNum(layer.bounds.height);\n\n return {\n o: opacity,\n r: rotation,\n p: position,\n a: { a: 0, k: [ax, ay, 0] },\n s: scale,\n };\n}\n\nfunction getMaxFrame(deltas: Delta[], doc: AtelierDocument): number {\n let max = 0;\n for (const state of Object.values(doc.states)) {\n if (state.duration > max) max = state.duration;\n }\n for (const d of deltas) {\n if (d.range[1] > max) max = d.range[1];\n }\n return max || 60;\n}\n\nfunction mapBlendMode(mode: string): number {\n const map: Record<string, number> = {\n normal: 0, multiply: 1, screen: 2, overlay: 3,\n darken: 4, lighten: 5, \"color-dodge\": 6, \"color-burn\": 7,\n \"hard-light\": 8, \"soft-light\": 9, difference: 10, exclusion: 11,\n hue: 12, saturation: 13, color: 14, luminosity: 15,\n };\n return map[mode] ?? 0;\n}\n","import type { AtelierDocument, State } from \"@a-company/atelier-types\";\n\n/** Check for unsupported features and collect warnings */\nexport function collectUnsupportedWarnings(doc: AtelierDocument, state: State): string[] {\n const warnings: string[] = [];\n\n // Audio not supported\n if (state.audio) {\n warnings.push(\"Audio tracks are not supported in Lottie format and will be dropped\");\n }\n\n // Expressions not supported\n for (const delta of state.deltas) {\n if (isExpression(delta.from) || isExpression(delta.to)) {\n warnings.push(`Expression values on \"${delta.layer}.${delta.property}\" not supported in Lottie`);\n }\n }\n\n // Shadow not supported in base Lottie\n for (const layer of doc.layers) {\n if (layer.shadow) {\n warnings.push(`Shadow on layer \"${layer.id}\" is not supported in base Lottie format`);\n }\n }\n\n // Motion path not directly mapped\n for (const layer of doc.layers) {\n if (layer.motionPath) {\n warnings.push(`Motion path on layer \"${layer.id}\" is not directly mappable to Lottie`);\n }\n }\n\n // Clip paths have limited support\n for (const layer of doc.layers) {\n if (layer.clipPath) {\n warnings.push(`Clip path on layer \"${layer.id}\" mapped as Lottie mask (partial support)`);\n }\n }\n\n // States/transitions\n if (Object.keys(doc.states).length > 1) {\n warnings.push(\"Multiple states flattened to single timeline in Lottie export\");\n }\n\n return warnings;\n}\n\nfunction isExpression(val: unknown): boolean {\n return typeof val === \"object\" && val !== null && \"expr\" in val;\n}\n","import type { AtelierDocument } from \"@a-company/atelier-types\";\nimport type { LottieAnimation, LottieAsset } from \"./lottie-types.js\";\nimport { mapLayers } from \"./map-layers.js\";\nimport { collectUnsupportedWarnings } from \"./warnings.js\";\n\nexport interface ExportLottieOptions {\n /** State to export (defaults to first state) */\n state?: string;\n}\n\nexport interface ExportLottieResult {\n /** The Lottie JSON animation */\n json: LottieAnimation;\n /** Warnings about unsupported features */\n warnings: string[];\n}\n\n/**\n * Export an Atelier document to Lottie JSON format.\n * This is a lossy conversion — not all features are supported.\n */\nexport function exportToLottie(\n doc: AtelierDocument,\n opts?: ExportLottieOptions,\n): ExportLottieResult {\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) {\n throw new Error(\"Document has no states to export\");\n }\n\n const stateName = opts?.state ?? stateNames[0];\n const state = doc.states[stateName];\n if (!state) {\n throw new Error(`State \"${stateName}\" not found`);\n }\n\n const warnings: string[] = [];\n\n // Collect unsupported feature warnings\n warnings.push(...collectUnsupportedWarnings(doc, state));\n\n // Map layers\n const layers = mapLayers(doc, state, warnings);\n\n // Map assets\n const assets: LottieAsset[] = [];\n if (doc.assets) {\n for (const [id, asset] of Object.entries(doc.assets)) {\n if (asset.type === \"image\") {\n assets.push({\n id,\n w: 100,\n h: 100,\n p: asset.src,\n e: 0,\n });\n }\n }\n }\n\n const json: LottieAnimation = {\n v: \"5.7.4\",\n fr: doc.canvas.fps,\n ip: 0,\n op: state.duration,\n w: doc.canvas.width,\n h: doc.canvas.height,\n nm: doc.name,\n layers,\n ...(assets.length > 0 ? { assets } : {}),\n };\n\n // Deduplicate warnings\n const uniqueWarnings = [...new Set(warnings)];\n\n return { json, warnings: uniqueWarnings };\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument, ImageVisual } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\n\n/** Asset summary entry */\nexport interface AssetInfo {\n assetId: string;\n type: string;\n src: string;\n description?: string;\n usedByLayers: string[];\n usedByStates: string[];\n}\n\n/**\n * Extract asset info from a parsed AtelierDocument.\n */\nexport function getAssets(doc: AtelierDocument): AssetInfo[] {\n const assets = doc.assets ?? {};\n return Object.entries(assets).map(([assetId, asset]) => {\n const usedByLayers = doc.layers\n .filter(l => l.visual.type === \"image\" && (l.visual as ImageVisual).assetId === assetId)\n .map(l => l.id);\n\n const usedByStates = Object.entries(doc.states)\n .filter(([, state]) => state.audio?.src === assetId)\n .map(([name]) => name);\n\n return {\n assetId,\n type: asset.type,\n src: asset.src,\n description: asset.description,\n usedByLayers,\n usedByStates,\n };\n });\n}\n\n/**\n * Format asset info for terminal output.\n */\nfunction formatAssets(assets: AssetInfo[]): string {\n if (assets.length === 0) return \"No assets registered.\";\n\n const lines: string[] = [`Assets: ${assets.length}`];\n for (const a of assets) {\n const desc = a.description ? ` — ${a.description}` : \"\";\n lines.push(` - ${a.assetId} (${a.type}): ${a.src}${desc}`);\n if (a.usedByLayers.length > 0) {\n lines.push(` Layers: ${a.usedByLayers.join(\", \")}`);\n }\n if (a.usedByStates.length > 0) {\n lines.push(` States: ${a.usedByStates.join(\", \")}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `assets` subcommand on the Commander program.\n */\nexport function assetsCommand(program: Command): void {\n program\n .command(\"assets <file>\")\n .description(\"List all assets in an .atelier file with usage info\")\n .action((file: string) => {\n const doc = readAndParse(file);\n const assets = getAssets(doc);\n console.log(formatAssets(assets));\n });\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { findTemplateVariables } from \"@a-company/atelier-core\";\n\n/** Variable summary entry */\nexport interface VariableInfo {\n name: string;\n type: string;\n description?: string;\n default?: unknown;\n referenced: boolean;\n}\n\n/**\n * Extract variable info from a parsed AtelierDocument.\n */\nexport function getVariables(doc: AtelierDocument): { variables: VariableInfo[]; undeclared: string[] } {\n const variables = doc.variables ?? {};\n const referenced = findTemplateVariables(doc);\n\n const entries = Object.entries(variables).map(([name, variable]) => ({\n name,\n type: variable.type,\n description: variable.description,\n default: variable.default,\n referenced: referenced.includes(name),\n }));\n\n const undeclared = referenced.filter(r => !variables[r]);\n\n return { variables: entries, undeclared };\n}\n\n/**\n * Format variable info for terminal output.\n */\nfunction formatVariables(info: { variables: VariableInfo[]; undeclared: string[] }): string {\n if (info.variables.length === 0 && info.undeclared.length === 0) return \"No variables declared or referenced.\";\n\n const lines: string[] = [];\n\n if (info.variables.length > 0) {\n lines.push(`Variables: ${info.variables.length}`);\n for (const v of info.variables) {\n const desc = v.description ? ` — ${v.description}` : \"\";\n const def = v.default !== undefined ? ` [default: ${JSON.stringify(v.default)}]` : \"\";\n const ref = v.referenced ? \"\" : \" (unused)\";\n lines.push(` - {{${v.name}}} (${v.type})${def}${desc}${ref}`);\n }\n }\n\n if (info.undeclared.length > 0) {\n lines.push(`Undeclared references: ${info.undeclared.length}`);\n for (const name of info.undeclared) {\n lines.push(` - {{${name}}} (not declared in variables)`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `variables` subcommand on the Commander program.\n */\nexport function variablesCommand(program: Command): void {\n program\n .command(\"variables <file>\")\n .description(\"List all variables in an .atelier file with usage info\")\n .action((file: string) => {\n const doc = readAndParse(file);\n const info = getVariables(doc);\n console.log(formatVariables(info));\n });\n}\n"],"mappings":"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","names":["init_dist","import_zod","z","yamlParse","init_dist","import_node_fs","import_node_path","import_node_fs","import_node_path","init_dist","readAndParse","renderFrame","import_node_fs","import_node_path","init_dist","resolve","readAndParse","import_node_fs","import_node_path","init_dist","colorToCSS","readAndParse","import_node_fs","import_node_path","r","g","b","a","isExpression","kfs","buildTransform","readAndParse","import_node_fs","import_node_path","readAndParse","import_node_fs","import_node_path","init_dist","readAndParse"]}
1
+ {"version":3,"sources":["../../math/src/easing.ts","../../math/src/spring.ts","../../math/src/lerp.ts","../../math/src/color.ts","../../math/src/path.ts","../../core/src/resolver/delta-resolver.ts","../../core/src/resolver/easing-resolver.ts","../../core/src/expressions/expression-evaluator.ts","../../core/src/resolver/frame-resolver.ts","../../core/src/validation/overlap-validator.ts","../../core/src/builder/document-builder.ts","../../core/src/units/resolve-units.ts","../../core/src/presets/preset-resolver.ts","../../core/src/state/state-machine.ts","../../core/src/templates/template-resolver.ts","../../core/src/audio/audio-timing.ts","../../canvas/src/styles.ts","../../canvas/src/apply-properties.ts","../../canvas/src/renderers/shape-renderer.ts","../../canvas/src/renderers/text-renderer.ts","../../canvas/src/renderers/image-renderer.ts","../../canvas/src/renderers/video-renderer.ts","../../canvas/src/renderers/ref-renderer.ts","../../canvas/src/render-frame.ts","../../canvas/src/image-cache.ts","../src/index.ts","../src/commands/validate.ts","../../schema/src/units.ts","../../schema/src/coordinates.ts","../../schema/src/color.ts","../../schema/src/shape.ts","../../schema/src/easing.ts","../../schema/src/shadow.ts","../../schema/src/layer.ts","../../schema/src/interaction.ts","../../schema/src/delta.ts","../../schema/src/state.ts","../../schema/src/preset.ts","../../schema/src/variable.ts","../../schema/src/asset.ts","../../schema/src/document.ts","../../schema/src/recipe.ts","../../schema/src/validate.ts","../../schema/src/parse.ts","../src/commands/info.ts","../src/commands/still.ts","../src/commands/render.ts","../src/commands/render-pipeline.ts","../src/commands/export-svg.ts","../../svg/src/render-svg.ts","../../svg/src/svg-properties.ts","../../svg/src/svg-gradients.ts","../../svg/src/svg-shapes.ts","../../svg/src/svg-text.ts","../../svg/src/svg-filters.ts","../../svg/src/svg-clip.ts","../src/commands/export-lottie.ts","../../lottie/src/map-colors.ts","../../lottie/src/map-shapes.ts","../../lottie/src/map-easing.ts","../../lottie/src/map-keyframes.ts","../../lottie/src/map-layers.ts","../../lottie/src/warnings.ts","../../lottie/src/export-lottie.ts","../src/commands/export-image.ts","../src/lib/render-image.ts","../src/commands/carousel.ts","../src/lib/recipe.ts","../src/commands/assets.ts","../src/commands/variables.ts","../src/lib/video-project.ts","../src/lib/silence-detect.ts","../src/lib/cut-model.ts","../src/commands/trim.ts","../src/lib/whisper.ts","../src/lib/transcript-model.ts","../src/lib/caption-builder.ts","../src/commands/transcribe.ts","../src/commands/transcript.ts","../src/commands/captions.ts","../src/commands/recipe.ts","../src/commands/apply-recipe.ts"],"sourcesContent":["/**\n * Linear easing — no acceleration.\n */\nexport function linear(t: number): number {\n return t;\n}\n\n/**\n * Cubic bezier easing — CSS-compatible.\n * Implements the same algorithm as CSS cubic-bezier().\n * @param x1 - first control point x\n * @param y1 - first control point y\n * @param x2 - second control point x\n * @param y2 - second control point y\n */\nexport function cubicBezier(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n): (t: number) => number {\n // Use binary search to find the parametric t value that gives us our x,\n // then compute the corresponding y. This is the standard algorithm used\n // by browsers for CSS transitions.\n\n return (t: number): number => {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n\n // Binary search for the parametric t value that gives us our x\n let lo = 0;\n let hi = 1;\n let mid: number = 0;\n\n for (let i = 0; i < 20; i++) {\n mid = (lo + hi) / 2;\n const x = sampleBezier(x1, x2, mid);\n if (Math.abs(x - t) < 1e-6) break;\n if (x < t) lo = mid;\n else hi = mid;\n }\n\n mid = (lo + hi) / 2;\n return sampleBezier(y1, y2, mid);\n };\n}\n\n/** Sample a single axis of a cubic bezier at parametric t */\nfunction sampleBezier(p1: number, p2: number, t: number): number {\n // B(t) = 3(1-t)^2*t*p1 + 3(1-t)*t^2*p2 + t^3\n return 3 * (1 - t) * (1 - t) * t * p1 + 3 * (1 - t) * t * t * p2 + t * t * t;\n}\n\n/** Common CSS easing presets */\nexport const easeIn = cubicBezier(0.42, 0, 1, 1);\nexport const easeOut = cubicBezier(0, 0, 0.58, 1);\nexport const easeInOut = cubicBezier(0.42, 0, 0.58, 1);\n\n/**\n * Step easing — jumps between discrete values.\n * @param steps - number of steps\n * @param position - \"start\" or \"end\" (default \"end\")\n */\nexport function step(\n steps: number,\n position: \"start\" | \"end\" = \"end\",\n): (t: number) => number {\n return (t: number): number => {\n if (t <= 0) return position === \"start\" ? 1 / steps : 0;\n if (t >= 1) return 1;\n\n const s = Math.floor(t * steps);\n if (position === \"start\") {\n return Math.min((s + 1) / steps, 1);\n }\n return s / steps;\n };\n}\n","export interface SpringConfig {\n mass?: number; // default 1\n stiffness?: number; // default 100\n damping?: number; // default 10\n velocity?: number; // default 0\n}\n\n/**\n * Creates a spring easing function.\n * Uses damped harmonic oscillator physics.\n * Returns a function that takes t (0-1) and returns the spring value.\n *\n * The spring always goes from 0 to 1, but may overshoot.\n */\nexport function spring(config: SpringConfig = {}): (t: number) => number {\n const {\n mass = 1,\n stiffness = 100,\n damping = 10,\n velocity = 0,\n } = config;\n\n const w0 = Math.sqrt(stiffness / mass); // natural frequency\n const zeta = damping / (2 * Math.sqrt(stiffness * mass)); // damping ratio\n\n // Determine total duration to normalize t\n // We pre-calculate a reasonable duration where the spring settles\n const duration = estimateSettleTime(zeta, w0);\n\n return (t: number): number => {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n\n const time = t * duration;\n let value: number;\n\n if (zeta < 1) {\n // Underdamped\n const wd = w0 * Math.sqrt(1 - zeta * zeta);\n const A = 1;\n const B = (zeta * w0 + velocity) / wd;\n value =\n 1 -\n Math.exp(-zeta * w0 * time) *\n (A * Math.cos(wd * time) + B * Math.sin(wd * time));\n } else if (zeta === 1) {\n // Critically damped\n value = 1 - Math.exp(-w0 * time) * (1 + (w0 + velocity) * time);\n } else {\n // Overdamped\n const s1 = -w0 * (zeta - Math.sqrt(zeta * zeta - 1));\n const s2 = -w0 * (zeta + Math.sqrt(zeta * zeta - 1));\n const A = (velocity - s2) / (s1 - s2);\n const B = 1 - A;\n value = 1 - A * Math.exp(s1 * time) - B * Math.exp(s2 * time);\n }\n\n return value;\n };\n}\n\n/**\n * Estimates the time for a spring to settle within 0.1% of target.\n */\nfunction estimateSettleTime(zeta: number, w0: number): number {\n if (zeta >= 1) {\n return 10 / (zeta * w0);\n }\n // For underdamped: settling ~ -ln(0.001) / (zeta * w0)\n return Math.log(1000) / (zeta * w0);\n}\n","/**\n * Linear interpolation between two numbers.\n */\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\n/**\n * Clamp a value between min and max.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Interpolate between two multi-dimensional values.\n * Arrays must be the same length.\n */\nexport function lerpArray(a: number[], b: number[], t: number): number[] {\n return a.map((v, i) => lerp(v, b[i], t));\n}\n\n/**\n * Re-maps a value from one range to another.\n */\nexport function remap(\n value: number,\n inMin: number,\n inMax: number,\n outMin: number,\n outMax: number,\n): number {\n const t = (value - inMin) / (inMax - inMin);\n return lerp(outMin, outMax, t);\n}\n","import { lerp, clamp } from \"./lerp.js\";\n\nexport interface RGBA {\n r: number; // 0-255\n g: number; // 0-255\n b: number; // 0-255\n a: number; // 0-1\n}\n\nexport interface HSLA {\n h: number; // 0-360\n s: number; // 0-100\n l: number; // 0-100\n a: number; // 0-1\n}\n\n/**\n * Parse a hex color string to RGBA.\n * Supports: #RGB, #RGBA, #RRGGBB, #RRGGBBAA\n */\nexport function hexToRgba(hex: string): RGBA {\n let h = hex.replace(\"#\", \"\");\n\n if (h.length === 3)\n h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + \"ff\";\n else if (h.length === 4)\n h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];\n else if (h.length === 6) h = h + \"ff\";\n\n return {\n r: parseInt(h.slice(0, 2), 16),\n g: parseInt(h.slice(2, 4), 16),\n b: parseInt(h.slice(4, 6), 16),\n a: parseInt(h.slice(6, 8), 16) / 255,\n };\n}\n\n/**\n * Convert RGBA to hex string.\n */\nexport function rgbaToHex(color: RGBA): string {\n const r = clamp(Math.round(color.r), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n const g = clamp(Math.round(color.g), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n const b = clamp(Math.round(color.b), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n const a = clamp(Math.round(color.a * 255), 0, 255)\n .toString(16)\n .padStart(2, \"0\");\n return `#${r}${g}${b}${a === \"ff\" ? \"\" : a}`;\n}\n\n/**\n * Interpolate between two RGBA colors.\n */\nexport function lerpRgba(a: RGBA, b: RGBA, t: number): RGBA {\n return {\n r: lerp(a.r, b.r, t),\n g: lerp(a.g, b.g, t),\n b: lerp(a.b, b.b, t),\n a: lerp(a.a, b.a, t),\n };\n}\n\n/**\n * Convert RGBA to HSLA.\n */\nexport function rgbaToHsla(color: RGBA): HSLA {\n const r = color.r / 255;\n const g = color.g / 255;\n const b = color.b / 255;\n\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const d = max - min;\n const l = (max + min) / 2;\n\n let h = 0;\n let s = 0;\n\n if (d !== 0) {\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;\n else if (max === g) h = ((b - r) / d + 2) / 6;\n else h = ((r - g) / d + 4) / 6;\n }\n\n return { h: h * 360, s: s * 100, l: l * 100, a: color.a };\n}\n\n/**\n * Convert HSLA to RGBA.\n */\nexport function hslaToRgba(color: HSLA): RGBA {\n const h = color.h / 360;\n const s = color.s / 100;\n const l = color.l / 100;\n\n let r: number, g: number, b: number;\n\n if (s === 0) {\n r = g = b = l;\n } else {\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n r = hueToRgb(p, q, h + 1 / 3);\n g = hueToRgb(p, q, h);\n b = hueToRgb(p, q, h - 1 / 3);\n }\n\n return {\n r: Math.round(r * 255),\n g: Math.round(g * 255),\n b: Math.round(b * 255),\n a: color.a,\n };\n}\n\nfunction hueToRgb(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n}\n\n/**\n * Interpolate between two HSLA colors (shortest hue path).\n */\nexport function lerpHsla(a: HSLA, b: HSLA, t: number): HSLA {\n // Handle hue wrapping — take the shortest path\n let dh = b.h - a.h;\n if (dh > 180) dh -= 360;\n if (dh < -180) dh += 360;\n\n return {\n h: (((a.h + dh * t) % 360) + 360) % 360,\n s: lerp(a.s, b.s, t),\n l: lerp(a.l, b.l, t),\n a: lerp(a.a, b.a, t),\n };\n}\n","/**\n * Path interpolation utilities for motion paths.\n * Evaluates position and tangent along a path defined by points with bezier handles.\n */\n\nexport interface PathPoint2D {\n x: number;\n y: number;\n in?: { x: number; y: number };\n out?: { x: number; y: number };\n}\n\nexport interface PathPosition {\n x: number;\n y: number;\n /** Tangent angle in degrees */\n angle: number;\n}\n\n/**\n * Compute the length of a single cubic bezier segment using subdivision.\n */\nfunction bezierSegmentLength(\n p0x: number, p0y: number,\n c0x: number, c0y: number,\n c1x: number, c1y: number,\n p1x: number, p1y: number,\n steps = 32,\n): number {\n let length = 0;\n let prevX = p0x;\n let prevY = p0y;\n for (let i = 1; i <= steps; i++) {\n const t = i / steps;\n const mt = 1 - t;\n const x = mt * mt * mt * p0x + 3 * mt * mt * t * c0x + 3 * mt * t * t * c1x + t * t * t * p1x;\n const y = mt * mt * mt * p0y + 3 * mt * mt * t * c0y + 3 * mt * t * t * c1y + t * t * t * p1y;\n const dx = x - prevX;\n const dy = y - prevY;\n length += Math.sqrt(dx * dx + dy * dy);\n prevX = x;\n prevY = y;\n }\n return length;\n}\n\n/**\n * Evaluate a cubic bezier at parameter t, returning position and tangent.\n */\nfunction evalBezier(\n p0x: number, p0y: number,\n c0x: number, c0y: number,\n c1x: number, c1y: number,\n p1x: number, p1y: number,\n t: number,\n): PathPosition {\n const mt = 1 - t;\n const x = mt * mt * mt * p0x + 3 * mt * mt * t * c0x + 3 * mt * t * t * c1x + t * t * t * p1x;\n const y = mt * mt * mt * p0y + 3 * mt * mt * t * c0y + 3 * mt * t * t * c1y + t * t * t * p1y;\n\n // Tangent (first derivative)\n const tx = 3 * mt * mt * (c0x - p0x) + 6 * mt * t * (c1x - c0x) + 3 * t * t * (p1x - c1x);\n const ty = 3 * mt * mt * (c0y - p0y) + 6 * mt * t * (c1y - c0y) + 3 * t * t * (p1y - c1y);\n\n const angle = Math.atan2(ty, tx) * (180 / Math.PI);\n\n return { x, y, angle };\n}\n\n/**\n * Build a lookup table of cumulative segment lengths for a path.\n */\nfunction buildSegmentLengths(points: PathPoint2D[], closed: boolean): number[] {\n const segCount = closed ? points.length : points.length - 1;\n const lengths: number[] = [];\n\n for (let i = 0; i < segCount; i++) {\n const p0 = points[i];\n const p1 = points[(i + 1) % points.length];\n\n const c0x = p0.x + (p0.out?.x ?? 0);\n const c0y = p0.y + (p0.out?.y ?? 0);\n const c1x = p1.x + (p1.in?.x ?? 0);\n const c1y = p1.y + (p1.in?.y ?? 0);\n\n lengths.push(bezierSegmentLength(p0.x, p0.y, c0x, c0y, c1x, c1y, p1.x, p1.y));\n }\n\n return lengths;\n}\n\n/**\n * Evaluate a point along a path at a given progress (0–1).\n * Uses arc-length parameterization for uniform speed.\n */\nexport function evaluatePathAtProgress(\n points: PathPoint2D[],\n progress: number,\n closed = false,\n): PathPosition {\n if (points.length < 2) {\n return { x: points[0]?.x ?? 0, y: points[0]?.y ?? 0, angle: 0 };\n }\n\n // Clamp progress\n const t = Math.max(0, Math.min(1, progress));\n\n const segLengths = buildSegmentLengths(points, closed);\n const totalLength = segLengths.reduce((a, b) => a + b, 0);\n\n if (totalLength === 0) {\n return { x: points[0].x, y: points[0].y, angle: 0 };\n }\n\n const targetLength = t * totalLength;\n\n // Find which segment the target length falls in\n let accumulated = 0;\n for (let i = 0; i < segLengths.length; i++) {\n const segLen = segLengths[i];\n if (accumulated + segLen >= targetLength || i === segLengths.length - 1) {\n // Progress within this segment\n const segProgress = segLen === 0 ? 0 : (targetLength - accumulated) / segLen;\n\n const p0 = points[i];\n const p1 = points[(i + 1) % points.length];\n\n const c0x = p0.x + (p0.out?.x ?? 0);\n const c0y = p0.y + (p0.out?.y ?? 0);\n const c1x = p1.x + (p1.in?.x ?? 0);\n const c1y = p1.y + (p1.in?.y ?? 0);\n\n return evalBezier(p0.x, p0.y, c0x, c0y, c1x, c1y, p1.x, p1.y, segProgress);\n }\n accumulated += segLen;\n }\n\n // Fallback (shouldn't reach here)\n const last = points[points.length - 1];\n return { x: last.x, y: last.y, angle: 0 };\n}\n","import type { Delta, FrameRange } from \"@a-company/atelier-types\";\nimport { lerp, clamp, hexToRgba, lerpRgba, rgbaToHex } from \"@a-company/atelier-math\";\nimport { resolveEasing } from \"./easing-resolver.js\";\nimport { isExpression, evaluateExpression, type ExpressionContext } from \"../expressions/expression-evaluator.js\";\n\n/**\n * Check if a frame is within a delta's range (inclusive).\n */\nexport function isFrameInRange(frame: number, range: FrameRange): boolean {\n return frame >= range[0] && frame <= range[1];\n}\n\n/**\n * Compute the progress (0-1) of a frame within a delta's range.\n */\nexport function computeProgress(frame: number, range: FrameRange): number {\n const [start, end] = range;\n if (start === end) return 1; // instantaneous\n return clamp((frame - start) / (end - start), 0, 1);\n}\n\n/**\n * Resolve a single delta's value at a given frame.\n * Returns undefined if the frame is outside the delta's range.\n * Returns the interpolated value if within range.\n *\n * If `from` or `to` is an expression object `{ expr: \"...\" }`,\n * it is evaluated with the current animation context before interpolation.\n */\nexport function resolveDeltaValue(delta: Delta, frame: number): unknown | undefined {\n if (!isFrameInRange(frame, delta.range)) {\n return undefined;\n }\n\n const progress = computeProgress(frame, delta.range);\n const easingFn = resolveEasing(delta.easing);\n const easedProgress = easingFn(progress);\n\n const exprCtx: ExpressionContext = {\n t: easedProgress,\n progress,\n frame,\n duration: delta.range[1] - delta.range[0],\n };\n\n const from = isExpression(delta.from)\n ? evaluateExpression(delta.from.expr, exprCtx)\n : delta.from;\n\n const to = isExpression(delta.to)\n ? evaluateExpression(delta.to.expr, exprCtx)\n : delta.to;\n\n return interpolateValue(from, to, easedProgress);\n}\n\n/**\n * Interpolate between two values based on eased progress.\n * Handles numbers, strings (pass-through at threshold), and nested objects.\n */\nexport function interpolateValue(from: unknown, to: unknown, t: number): unknown {\n // Number interpolation\n if (typeof from === \"number\" && typeof to === \"number\") {\n return lerp(from, to, t);\n }\n\n // Hex color interpolation\n if (typeof from === \"string\" && typeof to === \"string\") {\n if (from.startsWith(\"#\") && to.startsWith(\"#\")) {\n return rgbaToHex(lerpRgba(hexToRgba(from), hexToRgba(to), t));\n }\n // Non-color strings — snap at end\n return t >= 1 ? to : from;\n }\n\n // Boolean interpolation — snap at midpoint for frame-precise control\n if (typeof from === \"boolean\" && typeof to === \"boolean\") {\n return t >= 0.5 ? to : from;\n }\n\n // For unknown types, snap at end\n return t >= 1 ? to : from;\n}\n\n/**\n * Given multiple deltas for the SAME layer+property, find the active one\n * at a given frame and return its resolved value.\n *\n * If no delta is active at this frame, holds the `to` value of the most\n * recent completed delta (the one whose range ended most recently before\n * this frame). This prevents properties from reverting after animation ends.\n *\n * Assumes no overlaps (validated elsewhere).\n */\nexport function resolvePropertyAtFrame(\n deltas: Delta[],\n frame: number,\n): unknown | undefined {\n // Check for an active delta first\n for (const delta of deltas) {\n if (isFrameInRange(frame, delta.range)) {\n return resolveDeltaValue(delta, frame);\n }\n }\n\n // No active delta — hold the `to` value of the most recently completed delta\n let lastCompleted: Delta | undefined;\n for (const delta of deltas) {\n if (frame > delta.range[1]) {\n if (!lastCompleted || delta.range[1] > lastCompleted.range[1]) {\n lastCompleted = delta;\n }\n }\n }\n\n if (!lastCompleted) return undefined;\n\n // If the held `to` value is an expression, evaluate at t=1\n if (isExpression(lastCompleted.to)) {\n return evaluateExpression(lastCompleted.to.expr, {\n t: 1,\n progress: 1,\n frame,\n duration: lastCompleted.range[1] - lastCompleted.range[0],\n });\n }\n\n return lastCompleted.to;\n}\n","import type { Easing } from \"@a-company/atelier-types\";\nimport { linear, cubicBezier, easeIn, easeOut, easeInOut, step, spring } from \"@a-company/atelier-math\";\n\n/**\n * Converts an Easing type definition into an executable easing function.\n * Returns a function (t: number) => number where t is 0-1.\n */\nexport function resolveEasing(easing: Easing | undefined): (t: number) => number {\n if (!easing) return linear;\n\n // String presets\n if (typeof easing === \"string\") {\n switch (easing) {\n case \"linear\": return linear;\n case \"ease-in\": return easeIn;\n case \"ease-out\": return easeOut;\n case \"ease-in-out\": return easeInOut;\n default: return linear;\n }\n }\n\n // Object easing definitions\n switch (easing.type) {\n case \"linear\":\n return linear;\n case \"cubic-bezier\":\n return cubicBezier(easing.x1, easing.y1, easing.x2, easing.y2);\n case \"spring\":\n return spring({\n mass: easing.mass,\n stiffness: easing.stiffness,\n damping: easing.damping,\n velocity: easing.velocity,\n });\n case \"step\":\n return step(easing.steps, easing.position);\n default:\n return linear;\n }\n}\n","/**\n * Safe recursive descent expression evaluator.\n * No eval(), no Function(), no code generation.\n *\n * Supports:\n * - Numbers: 42, 3.14, -1\n * - Operators: + - * / % **\n * - Parentheses: (expr)\n * - Math functions: sin, cos, tan, abs, min, max, floor, ceil, round, sqrt, pow, clamp, sign, log\n * - Constants: pi, tau, e\n * - Context variables: t, frame, duration, progress\n * - Comparison: <, >, <=, >=, ==, !=\n * - Ternary: condition ? trueExpr : falseExpr\n */\n\n/** Context variables available during expression evaluation */\nexport interface ExpressionContext {\n /** Eased progress 0–1 */\n t: number;\n /** Raw progress 0–1 (before easing) */\n progress: number;\n /** Current frame number */\n frame: number;\n /** Delta duration in frames */\n duration: number;\n}\n\n// ── Tokenizer ───────────────────────────────────────────────\n\ntype TokenType =\n | \"number\"\n | \"ident\"\n | \"op\"\n | \"lparen\"\n | \"rparen\"\n | \"comma\"\n | \"question\"\n | \"colon\"\n | \"compare\"\n | \"eof\";\n\ninterface Token {\n type: TokenType;\n value: string;\n}\n\nfunction tokenize(expr: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n\n while (i < expr.length) {\n const ch = expr[i];\n\n // Whitespace\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\n\" || ch === \"\\r\") {\n i++;\n continue;\n }\n\n // Numbers\n if ((ch >= \"0\" && ch <= \"9\") || ch === \".\") {\n let num = \"\";\n while (i < expr.length && ((expr[i] >= \"0\" && expr[i] <= \"9\") || expr[i] === \".\")) {\n num += expr[i++];\n }\n tokens.push({ type: \"number\", value: num });\n continue;\n }\n\n // Identifiers (variables, functions, constants)\n if ((ch >= \"a\" && ch <= \"z\") || (ch >= \"A\" && ch <= \"Z\") || ch === \"_\") {\n let id = \"\";\n while (i < expr.length && ((expr[i] >= \"a\" && expr[i] <= \"z\") || (expr[i] >= \"A\" && expr[i] <= \"Z\") || (expr[i] >= \"0\" && expr[i] <= \"9\") || expr[i] === \"_\")) {\n id += expr[i++];\n }\n tokens.push({ type: \"ident\", value: id });\n continue;\n }\n\n // Comparison operators (must check before single-char ops)\n if (ch === \"<\" || ch === \">\" || ch === \"!\" || ch === \"=\") {\n if (i + 1 < expr.length && expr[i + 1] === \"=\") {\n tokens.push({ type: \"compare\", value: ch + \"=\" });\n i += 2;\n continue;\n }\n if (ch === \"<\" || ch === \">\") {\n tokens.push({ type: \"compare\", value: ch });\n i++;\n continue;\n }\n }\n\n // Power operator\n if (ch === \"*\" && i + 1 < expr.length && expr[i + 1] === \"*\") {\n tokens.push({ type: \"op\", value: \"**\" });\n i += 2;\n continue;\n }\n\n // Operators\n if (ch === \"+\" || ch === \"-\" || ch === \"*\" || ch === \"/\" || ch === \"%\") {\n tokens.push({ type: \"op\", value: ch });\n i++;\n continue;\n }\n\n // Grouping and function calls\n if (ch === \"(\") { tokens.push({ type: \"lparen\", value: \"(\" }); i++; continue; }\n if (ch === \")\") { tokens.push({ type: \"rparen\", value: \")\" }); i++; continue; }\n if (ch === \",\") { tokens.push({ type: \"comma\", value: \",\" }); i++; continue; }\n\n // Ternary\n if (ch === \"?\") { tokens.push({ type: \"question\", value: \"?\" }); i++; continue; }\n if (ch === \":\") { tokens.push({ type: \"colon\", value: \":\" }); i++; continue; }\n\n throw new Error(`Expression: unexpected character '${ch}' at position ${i}`);\n }\n\n tokens.push({ type: \"eof\", value: \"\" });\n return tokens;\n}\n\n// ── Parser + Evaluator ──────────────────────────────────────\n\nconst CONSTANTS: Record<string, number> = {\n pi: Math.PI,\n PI: Math.PI,\n tau: Math.PI * 2,\n TAU: Math.PI * 2,\n e: Math.E,\n E: Math.E,\n};\n\nconst FUNCTIONS: Record<string, (...args: number[]) => number> = {\n sin: Math.sin,\n cos: Math.cos,\n tan: Math.tan,\n abs: Math.abs,\n floor: Math.floor,\n ceil: Math.ceil,\n round: Math.round,\n sqrt: Math.sqrt,\n sign: Math.sign,\n log: Math.log,\n min: (...args) => Math.min(...args),\n max: (...args) => Math.max(...args),\n pow: (a, b) => Math.pow(a, b),\n clamp: (v, lo, hi) => Math.min(Math.max(v, lo), hi),\n};\n\nclass Parser {\n private tokens: Token[];\n private pos = 0;\n private ctx: ExpressionContext;\n\n constructor(tokens: Token[], ctx: ExpressionContext) {\n this.tokens = tokens;\n this.ctx = ctx;\n }\n\n private peek(): Token {\n return this.tokens[this.pos];\n }\n\n private consume(expectedType?: TokenType): Token {\n const tok = this.tokens[this.pos++];\n if (expectedType && tok.type !== expectedType) {\n throw new Error(`Expression: expected ${expectedType} but got ${tok.type} '${tok.value}'`);\n }\n return tok;\n }\n\n /** Entry: ternary (lowest precedence) */\n parse(): number {\n const result = this.parseTernary();\n if (this.peek().type !== \"eof\") {\n throw new Error(`Expression: unexpected token '${this.peek().value}'`);\n }\n return result;\n }\n\n /** ternary: comparison ? expr : expr */\n private parseTernary(): number {\n const condition = this.parseComparison();\n if (this.peek().type === \"question\") {\n this.consume(); // ?\n const trueVal = this.parseTernary();\n this.consume(\"colon\"); // :\n const falseVal = this.parseTernary();\n return condition ? trueVal : falseVal;\n }\n return condition;\n }\n\n /** comparison: additive (< | > | <= | >= | == | !=) additive */\n private parseComparison(): number {\n let left = this.parseAdditive();\n while (this.peek().type === \"compare\") {\n const op = this.consume().value;\n const right = this.parseAdditive();\n switch (op) {\n case \"<\": left = left < right ? 1 : 0; break;\n case \">\": left = left > right ? 1 : 0; break;\n case \"<=\": left = left <= right ? 1 : 0; break;\n case \">=\": left = left >= right ? 1 : 0; break;\n case \"==\": left = left === right ? 1 : 0; break;\n case \"!=\": left = left !== right ? 1 : 0; break;\n }\n }\n return left;\n }\n\n /** additive: multiplicative (('+' | '-') multiplicative)* */\n private parseAdditive(): number {\n let left = this.parseMultiplicative();\n while (this.peek().type === \"op\" && (this.peek().value === \"+\" || this.peek().value === \"-\")) {\n const op = this.consume().value;\n const right = this.parseMultiplicative();\n left = op === \"+\" ? left + right : left - right;\n }\n return left;\n }\n\n /** multiplicative: power (('*' | '/' | '%') power)* */\n private parseMultiplicative(): number {\n let left = this.parsePower();\n while (this.peek().type === \"op\" && (this.peek().value === \"*\" || this.peek().value === \"/\" || this.peek().value === \"%\")) {\n const op = this.consume().value;\n const right = this.parsePower();\n if (op === \"*\") left = left * right;\n else if (op === \"/\") left = right !== 0 ? left / right : 0;\n else left = left % right;\n }\n return left;\n }\n\n /** power: unary ('**' unary)* (right-associative) */\n private parsePower(): number {\n const base = this.parseUnary();\n if (this.peek().type === \"op\" && this.peek().value === \"**\") {\n this.consume();\n const exp = this.parsePower(); // right-associative\n return Math.pow(base, exp);\n }\n return base;\n }\n\n /** unary: ('-' | '+') unary | primary */\n private parseUnary(): number {\n if (this.peek().type === \"op\" && (this.peek().value === \"-\" || this.peek().value === \"+\")) {\n const op = this.consume().value;\n const val = this.parseUnary();\n return op === \"-\" ? -val : val;\n }\n return this.parsePrimary();\n }\n\n /** primary: number | ident | function(args) | '(' expr ')' */\n private parsePrimary(): number {\n const tok = this.peek();\n\n // Number literal\n if (tok.type === \"number\") {\n this.consume();\n return parseFloat(tok.value);\n }\n\n // Identifier: constant, context variable, or function\n if (tok.type === \"ident\") {\n this.consume();\n const name = tok.value;\n\n // Function call\n if (this.peek().type === \"lparen\") {\n this.consume(); // (\n const args: number[] = [];\n if (this.peek().type !== \"rparen\") {\n args.push(this.parseTernary());\n while (this.peek().type === \"comma\") {\n this.consume(); // ,\n args.push(this.parseTernary());\n }\n }\n this.consume(\"rparen\"); // )\n\n const fn = FUNCTIONS[name];\n if (!fn) throw new Error(`Expression: unknown function '${name}'`);\n return fn(...args);\n }\n\n // Constant\n if (name in CONSTANTS) return CONSTANTS[name];\n\n // Context variable\n if (name in this.ctx) return (this.ctx as unknown as Record<string, number>)[name];\n\n throw new Error(`Expression: unknown variable '${name}'`);\n }\n\n // Parenthesized expression\n if (tok.type === \"lparen\") {\n this.consume(); // (\n const val = this.parseTernary();\n this.consume(\"rparen\"); // )\n return val;\n }\n\n throw new Error(`Expression: unexpected token '${tok.value}'`);\n }\n}\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Check if a value is an expression object { expr: string }.\n */\nexport function isExpression(value: unknown): value is { expr: string } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"expr\" in value &&\n typeof (value as Record<string, unknown>).expr === \"string\"\n );\n}\n\n/**\n * Evaluate an expression string with the given context.\n * Returns a number. Throws on syntax errors or unknown identifiers.\n */\nexport function evaluateExpression(expr: string, ctx: ExpressionContext): number {\n const tokens = tokenize(expr);\n const parser = new Parser(tokens, ctx);\n return parser.parse();\n}\n","import type { AtelierDocument, Layer, Delta, AnimatableProperty } from \"@a-company/atelier-types\";\nimport { resolvePropertyAtFrame } from \"./delta-resolver.js\";\n\n/** A resolved layer at a specific frame — all animated properties computed */\nexport interface ResolvedLayer {\n id: string;\n /** Original layer definition */\n layer: Layer;\n /** Computed property overrides from active deltas */\n computedProperties: Partial<Record<AnimatableProperty, unknown>>;\n /** Seconds into source video to seek to — only present for video visual layers */\n videoSourceTime?: number;\n}\n\n/** The resolved state of an entire document at a specific frame */\nexport interface ResolvedFrame {\n /** Frame number that was resolved */\n frame: number;\n /** State name that was resolved */\n stateName: string;\n /** All layers with their computed properties */\n layers: ResolvedLayer[];\n}\n\n/**\n * Resolve all layers at a given frame within a named state.\n * This is the main entry point for frame resolution.\n * @param overrideDeltas - Optional pre-merged deltas (used for hierarchical state resolution)\n */\nexport function resolveFrame(\n doc: AtelierDocument,\n stateName: string,\n frame: number,\n overrideDeltas?: Delta[],\n): ResolvedFrame {\n const state = doc.states[stateName];\n if (!state) {\n throw new Error(`State \"${stateName}\" not found in document \"${doc.name}\"`);\n }\n\n // Group deltas by layer+property\n const deltasByLayerProperty = groupDeltas(overrideDeltas ?? state.deltas);\n\n // Resolve each layer\n const resolvedLayers: ResolvedLayer[] = doc.layers.map((layer) => {\n const computedProperties: Partial<Record<AnimatableProperty, unknown>> = {};\n\n // Find all animated properties for this layer\n const layerDeltas = deltasByLayerProperty.get(layer.id);\n if (layerDeltas) {\n for (const [property, deltas] of layerDeltas) {\n const value = resolvePropertyAtFrame(deltas, frame);\n if (value !== undefined) {\n computedProperties[property as AnimatableProperty] = value;\n }\n }\n }\n\n const resolvedLayer: ResolvedLayer = { id: layer.id, layer, computedProperties };\n\n if (layer.visual.type === \"video\") {\n const video = layer.visual;\n const fps = doc.canvas.fps;\n const startFrame = video.startFrame ?? 0;\n const sourceOffset = video.sourceOffset ?? 0;\n const playbackRate = video.playbackRate ?? 1.0;\n const relativeFrame = Math.max(0, frame - startFrame);\n const sourceTime = (relativeFrame / fps) * playbackRate + sourceOffset;\n resolvedLayer.videoSourceTime =\n video.sourceEnd !== undefined ? Math.min(sourceTime, video.sourceEnd) : sourceTime;\n }\n\n return resolvedLayer;\n });\n\n return { frame, stateName, layers: resolvedLayers };\n}\n\n/**\n * Group deltas by layer ID, then by property name.\n */\nfunction groupDeltas(\n deltas: Delta[],\n): Map<string, Map<string, Delta[]>> {\n const map = new Map<string, Map<string, Delta[]>>();\n\n for (const delta of deltas) {\n let layerMap = map.get(delta.layer);\n if (!layerMap) {\n layerMap = new Map();\n map.set(delta.layer, layerMap);\n }\n\n let propDeltas = layerMap.get(delta.property);\n if (!propDeltas) {\n propDeltas = [];\n layerMap.set(delta.property, propDeltas);\n }\n\n propDeltas.push(delta);\n }\n\n return map;\n}\n","import type { Delta, FrameRange } from \"@a-company/atelier-types\";\n\nexport interface OverlapError {\n layerId: string;\n property: string;\n existingRange: FrameRange;\n newRange: FrameRange;\n message: string;\n}\n\n/**\n * Check if two frame ranges overlap.\n * Boundary-touching ranges (e.g., [0-50] and [50-90]) are allowed —\n * only ranges that share more than a single boundary frame are overlaps.\n */\nexport function rangesOverlap(a: FrameRange, b: FrameRange): boolean {\n return a[0] < b[1] && b[0] < a[1];\n}\n\n/**\n * Validate that a new delta doesn't overlap with existing deltas\n * on the same layer+property.\n */\nexport function validateNoOverlap(\n existing: Delta[],\n newDelta: Delta,\n): OverlapError | null {\n for (const delta of existing) {\n if (\n delta.layer === newDelta.layer &&\n delta.property === newDelta.property &&\n rangesOverlap(delta.range, newDelta.range)\n ) {\n return {\n layerId: newDelta.layer,\n property: newDelta.property,\n existingRange: delta.range,\n newRange: newDelta.range,\n message: `Overlapping delta on layer \"${newDelta.layer}\" property \"${newDelta.property}\": ` +\n `existing [${delta.range[0]}-${delta.range[1]}] overlaps with new [${newDelta.range[0]}-${newDelta.range[1]}]`,\n };\n }\n }\n return null;\n}\n\n/**\n * Validate all deltas in a state have no overlaps.\n * Returns all overlap errors found.\n */\nexport function validateAllDeltas(deltas: Delta[]): OverlapError[] {\n const errors: OverlapError[] = [];\n\n for (let i = 0; i < deltas.length; i++) {\n for (let j = i + 1; j < deltas.length; j++) {\n const a = deltas[i];\n const b = deltas[j];\n\n if (\n a.layer === b.layer &&\n a.property === b.property &&\n rangesOverlap(a.range, b.range)\n ) {\n errors.push({\n layerId: a.layer,\n property: a.property,\n existingRange: a.range,\n newRange: b.range,\n message: `Overlapping deltas on layer \"${a.layer}\" property \"${a.property}\": ` +\n `[${a.range[0]}-${a.range[1]}] overlaps with [${b.range[0]}-${b.range[1]}]`,\n });\n }\n }\n }\n\n return errors;\n}\n","import type {\n AtelierDocument, Canvas, Layer, State, Delta, Preset,\n Variable, Asset,\n} from \"@a-company/atelier-types\";\nimport { validateNoOverlap } from \"../validation/overlap-validator.js\";\n\n/**\n * Fluent builder for constructing AtelierDocument objects.\n * Validates constraints (like no-overlap) as you build.\n */\nexport class DocumentBuilder {\n private doc: AtelierDocument;\n\n constructor(name: string, canvas: Canvas) {\n this.doc = {\n version: \"1.0\",\n name,\n canvas,\n layers: [],\n states: {},\n };\n }\n\n /** Set document description */\n description(desc: string): this {\n this.doc.description = desc;\n return this;\n }\n\n /** Add tags to the document */\n tags(...tags: string[]): this {\n this.doc.tags = [...(this.doc.tags ?? []), ...tags];\n return this;\n }\n\n /** Add a variable definition */\n variable(id: string, variable: Variable): this {\n if (!this.doc.variables) this.doc.variables = {};\n this.doc.variables[id] = variable;\n return this;\n }\n\n /** Add an asset reference */\n asset(id: string, asset: Asset): this {\n if (!this.doc.assets) this.doc.assets = {};\n this.doc.assets[id] = asset;\n return this;\n }\n\n /** Add a preset */\n preset(id: string, preset: Preset): this {\n if (!this.doc.presets) this.doc.presets = {};\n this.doc.presets[id] = preset;\n return this;\n }\n\n /** Add a layer */\n addLayer(layer: Layer): this {\n // Check for duplicate IDs\n if (this.doc.layers.some(l => l.id === layer.id)) {\n throw new Error(`Layer with id \"${layer.id}\" already exists`);\n }\n this.doc.layers.push(layer);\n return this;\n }\n\n /** Add a state */\n addState(name: string, state: Omit<State, \"deltas\"> & { deltas?: Delta[] }): this {\n if (this.doc.states[name]) {\n throw new Error(`State \"${name}\" already exists`);\n }\n this.doc.states[name] = { ...state, deltas: state.deltas ?? [] };\n return this;\n }\n\n /** Add a delta to an existing state, with overlap validation */\n addDelta(stateName: string, delta: Delta): this {\n const state = this.doc.states[stateName];\n if (!state) {\n throw new Error(`State \"${stateName}\" not found`);\n }\n\n // Verify the layer exists\n if (!this.doc.layers.some(l => l.id === delta.layer)) {\n throw new Error(`Layer \"${delta.layer}\" not found — add the layer before adding deltas`);\n }\n\n // Check for overlaps\n const overlap = validateNoOverlap(state.deltas, delta);\n if (overlap) {\n throw new Error(overlap.message);\n }\n\n state.deltas.push(delta);\n return this;\n }\n\n /** Build and return the final document */\n build(): AtelierDocument {\n return JSON.parse(JSON.stringify(this.doc)) as AtelierDocument;\n }\n}\n\n/**\n * Create a new DocumentBuilder.\n * Convenience function for starting a builder chain.\n */\nexport function createDocument(name: string, canvas: Canvas): DocumentBuilder {\n return new DocumentBuilder(name, canvas);\n}\n","import type { UnitValue } from \"@a-company/atelier-types\";\n\n/**\n * Check if a UnitValue is a percentage string.\n */\nexport function isPercentage(value: UnitValue): value is `${number}%` {\n return typeof value === \"string\" && value.endsWith(\"%\");\n}\n\n/**\n * Parse a percentage string to its numeric value (0-100).\n */\nexport function parsePercentage(value: `${number}%`): number {\n return parseFloat(value);\n}\n\n/**\n * Resolve a UnitValue to pixels given a reference dimension.\n * Pixel values pass through unchanged.\n * Percentage values are computed relative to the reference.\n */\nexport function resolveUnit(value: UnitValue, reference: number): number {\n if (isPercentage(value)) {\n return (parsePercentage(value) / 100) * reference;\n }\n return value;\n}\n","import type { Preset, Delta, FrameRange } from \"@a-company/atelier-types\";\n\n/**\n * Expand a preset into concrete deltas for a specific layer and start frame.\n *\n * @param preset - The preset to expand\n * @param layerId - Target layer ID\n * @param startFrame - Frame to start the preset from\n * @param duration - Total duration to map preset offsets into\n */\nexport function expandPreset(\n preset: Preset,\n layerId: string,\n startFrame: number,\n duration: number,\n): Delta[] {\n return preset.deltas.map((pd, index) => {\n let range: FrameRange;\n if (pd.offset) {\n range = [startFrame + pd.offset[0], startFrame + pd.offset[1]];\n } else {\n range = [startFrame, startFrame + duration];\n }\n\n return {\n id: `preset-${layerId}-${index}`,\n layer: layerId,\n property: pd.property,\n range,\n from: pd.from,\n to: pd.to,\n easing: pd.easing,\n };\n });\n}\n","import type { AtelierDocument, Easing, State, Delta } from \"@a-company/atelier-types\";\nimport { resolveFrame, type ResolvedFrame } from \"../resolver/frame-resolver.js\";\nimport { resolveEasing } from \"../resolver/easing-resolver.js\";\n\nexport interface StateTransition {\n from: string;\n to: string;\n at: number; // frame at which transition occurs\n}\n\nexport interface PlaybackState {\n stateName: string;\n frame: number;\n resolved: ResolvedFrame;\n isComplete: boolean;\n}\n\nexport interface ActiveTransition {\n fromState: string;\n toState: string;\n duration: number;\n easingFn: (t: number) => number;\n transitionFrame: number; // how many frames into the transition\n}\n\nexport class StateMachine {\n private currentState: string;\n private currentFrame = 0;\n private transitions: StateTransition[] = [];\n private activeTransition: ActiveTransition | null = null;\n\n constructor(\n private doc: AtelierDocument,\n initialState?: string,\n ) {\n // Default to first state\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) throw new Error(\"Document has no states\");\n this.currentState = initialState ?? stateNames[0];\n if (!doc.states[this.currentState]) {\n throw new Error(`State \"${this.currentState}\" not found`);\n }\n }\n\n /** Get current state name */\n get state(): string {\n return this.currentState;\n }\n\n /** Get current frame */\n get frame(): number {\n return this.currentFrame;\n }\n\n /** Get all state names */\n get stateNames(): string[] {\n return Object.keys(this.doc.states);\n }\n\n /** Get current state duration */\n get duration(): number {\n return this.doc.states[this.currentState].duration;\n }\n\n /** Check if current state playback is complete */\n get isComplete(): boolean {\n return this.currentFrame >= this.duration - 1;\n }\n\n /** Check if currently in a transition blend */\n isTransitioning(): boolean {\n return this.activeTransition !== null;\n }\n\n /** Get transition progress (0–1) with easing applied, or null if not transitioning */\n getTransitionProgress(): number | null {\n if (!this.activeTransition) return null;\n const { transitionFrame, duration, easingFn } = this.activeTransition;\n const rawProgress = Math.min(transitionFrame / duration, 1);\n return easingFn(rawProgress);\n }\n\n // ── Hierarchical State Support ────────────────────────────\n\n /**\n * Resolve the ancestor chain for a state (root → … → parent → self).\n * Throws on circular parent references.\n */\n resolveAncestorChain(stateName: string): string[] {\n const chain: string[] = [];\n const visited = new Set<string>();\n let current: string | undefined = stateName;\n\n while (current) {\n if (visited.has(current)) {\n throw new Error(`Circular parent reference detected: \"${current}\" already in chain [${chain.join(\" → \")}]`);\n }\n visited.add(current);\n chain.unshift(current); // prepend so root is first\n const stateObj: State | undefined = this.doc.states[current];\n if (!stateObj) {\n throw new Error(`Parent state \"${current}\" not found`);\n }\n current = stateObj.parent;\n }\n\n return chain;\n }\n\n /**\n * Collect merged deltas from ancestor chain.\n * Child overrides parent deltas for the same layer+property combination.\n * Deltas for different layer+property pairs are accumulated from all ancestors.\n */\n collectDeltas(stateName: string): Delta[] {\n const chain = this.resolveAncestorChain(stateName);\n // Walk root → child. Later entries override earlier for same layer+property.\n const deltaMap = new Map<string, Delta[]>();\n\n for (const ancestorName of chain) {\n const state = this.doc.states[ancestorName];\n // Group this state's deltas by layer+property\n const stateGroups = new Map<string, Delta[]>();\n for (const delta of state.deltas) {\n const key = `${delta.layer}:${delta.property}`;\n if (!stateGroups.has(key)) stateGroups.set(key, []);\n stateGroups.get(key)!.push(delta);\n }\n // Child replaces parent for same key\n for (const [key, deltas] of stateGroups) {\n deltaMap.set(key, deltas);\n }\n }\n\n // Flatten all deltas\n const result: Delta[] = [];\n for (const deltas of deltaMap.values()) {\n result.push(...deltas);\n }\n return result;\n }\n\n // ── Playback ──────────────────────────────────────────────\n\n /** Advance to next frame, returns resolved frame */\n tick(): PlaybackState {\n // Handle active transition\n if (this.activeTransition) {\n this.activeTransition.transitionFrame++;\n if (this.activeTransition.transitionFrame >= this.activeTransition.duration) {\n // Transition complete\n this.activeTransition = null;\n }\n }\n\n const resolved = this.resolveCurrentFrame();\n const result: PlaybackState = {\n stateName: this.currentState,\n frame: this.currentFrame,\n resolved,\n isComplete: this.isComplete,\n };\n if (this.currentFrame < this.duration - 1) {\n this.currentFrame++;\n }\n return result;\n }\n\n /** Resolve the current frame, blending if in transition */\n private resolveCurrentFrame(): ResolvedFrame {\n if (this.activeTransition) {\n const progress = this.getTransitionProgress()!;\n const fromResolved = resolveFrame(\n this.doc, this.activeTransition.fromState, this.currentFrame,\n this.collectDeltas(this.activeTransition.fromState),\n );\n const toResolved = resolveFrame(\n this.doc, this.activeTransition.toState, this.currentFrame,\n this.collectDeltas(this.activeTransition.toState),\n );\n return blendResolvedFrames(fromResolved, toResolved, progress);\n }\n\n // Check if current state has a parent — use merged deltas\n const state = this.doc.states[this.currentState];\n if (state.parent) {\n const mergedDeltas = this.collectDeltas(this.currentState);\n return resolveFrame(this.doc, this.currentState, this.currentFrame, mergedDeltas);\n }\n\n return resolveFrame(this.doc, this.currentState, this.currentFrame);\n }\n\n /** Transition to a different state (instant or blended) */\n transition(stateName: string, startFrame = 0): void {\n if (!this.doc.states[stateName]) {\n throw new Error(`State \"${stateName}\" not found`);\n }\n\n const fromState = this.currentState;\n const currentStateObj = this.doc.states[fromState];\n const transConfig = currentStateObj.transitions?.[stateName];\n\n this.transitions.push({\n from: fromState,\n to: stateName,\n at: this.currentFrame,\n });\n\n if (transConfig && transConfig.duration > 0) {\n // Start a smooth transition\n this.activeTransition = {\n fromState,\n toState: stateName,\n duration: transConfig.duration,\n easingFn: resolveEasing(transConfig.easing),\n transitionFrame: 0,\n };\n }\n\n this.currentState = stateName;\n this.currentFrame = startFrame;\n }\n\n /**\n * Start a smooth transition to target state with explicit duration/easing.\n * This ignores any transitions config on the state.\n */\n transitionTo(targetState: string, duration: number, easing?: Easing): void {\n if (!this.doc.states[targetState]) {\n throw new Error(`State \"${targetState}\" not found`);\n }\n\n const fromState = this.currentState;\n this.transitions.push({\n from: fromState,\n to: targetState,\n at: this.currentFrame,\n });\n\n this.activeTransition = {\n fromState,\n toState: targetState,\n duration,\n easingFn: resolveEasing(easing),\n transitionFrame: 0,\n };\n\n this.currentState = targetState;\n this.currentFrame = 0;\n }\n\n /** Seek to a specific frame in current state */\n seek(frame: number): void {\n this.currentFrame = Math.max(0, Math.min(frame, this.duration - 1));\n }\n\n /** Reset to initial state */\n reset(stateName?: string): void {\n if (stateName) {\n if (!this.doc.states[stateName]) throw new Error(`State \"${stateName}\" not found`);\n this.currentState = stateName;\n }\n this.currentFrame = 0;\n this.activeTransition = null;\n }\n\n /** Get transition history */\n get history(): ReadonlyArray<StateTransition> {\n return this.transitions;\n }\n\n /** Resolve a specific frame without advancing */\n resolveAt(stateName: string, frame: number): ResolvedFrame {\n if (!this.doc.states[stateName]) throw new Error(`State \"${stateName}\" not found`);\n const state = this.doc.states[stateName];\n if (state.parent) {\n return resolveFrame(this.doc, stateName, frame, this.collectDeltas(stateName));\n }\n return resolveFrame(this.doc, stateName, frame);\n }\n\n /** Play through entire current state, calling callback on each frame */\n playThrough(onFrame: (state: PlaybackState) => void): void {\n this.currentFrame = 0;\n while (!this.isComplete) {\n onFrame(this.tick());\n }\n onFrame(this.tick()); // last frame\n }\n}\n\n// ── Frame Blending ────────────────────────────────────────────\n\nimport type { ResolvedLayer } from \"../resolver/frame-resolver.js\";\nimport type { AnimatableProperty } from \"@a-company/atelier-types\";\nimport { interpolateValue } from \"../resolver/delta-resolver.js\";\n\n/**\n * Blend two resolved frames together for smooth state transitions.\n * Numeric properties are lerped, colors are color-lerped, discrete values snap at t >= 0.5.\n */\nexport function blendResolvedFrames(\n frameA: ResolvedFrame,\n frameB: ResolvedFrame,\n t: number,\n): ResolvedFrame {\n // Build layer maps\n const mapA = new Map<string, ResolvedLayer>();\n const mapB = new Map<string, ResolvedLayer>();\n for (const l of frameA.layers) mapA.set(l.id, l);\n for (const l of frameB.layers) mapB.set(l.id, l);\n\n // Get all unique layer IDs\n const allIds = new Set([...mapA.keys(), ...mapB.keys()]);\n const blendedLayers: ResolvedLayer[] = [];\n\n for (const id of allIds) {\n const layerA = mapA.get(id);\n const layerB = mapB.get(id);\n\n if (layerA && layerB) {\n // Both exist — blend computed properties\n blendedLayers.push(blendLayers(layerA, layerB, t));\n } else if (layerA && !layerB) {\n // Only in A — fade out (set opacity toward 0)\n blendedLayers.push(fadeLayer(layerA, 1 - t));\n } else if (!layerA && layerB) {\n // Only in B — fade in (set opacity from 0)\n blendedLayers.push(fadeLayer(layerB, t));\n }\n }\n\n return {\n frame: frameB.frame,\n stateName: frameB.stateName,\n layers: blendedLayers,\n };\n}\n\nfunction blendLayers(a: ResolvedLayer, b: ResolvedLayer, t: number): ResolvedLayer {\n const allProps = new Set([\n ...Object.keys(a.computedProperties),\n ...Object.keys(b.computedProperties),\n ]);\n\n const blended: Partial<Record<AnimatableProperty, unknown>> = {};\n\n for (const prop of allProps) {\n const valA = a.computedProperties[prop as AnimatableProperty];\n const valB = b.computedProperties[prop as AnimatableProperty];\n\n if (valA !== undefined && valB !== undefined) {\n blended[prop as AnimatableProperty] = interpolateValue(valA, valB, t);\n } else if (valA !== undefined) {\n blended[prop as AnimatableProperty] = valA;\n } else {\n blended[prop as AnimatableProperty] = valB;\n }\n }\n\n return {\n id: a.id,\n layer: a.layer,\n computedProperties: blended,\n };\n}\n\nfunction fadeLayer(layer: ResolvedLayer, opacity: number): ResolvedLayer {\n const cp = { ...layer.computedProperties };\n const existingOpacity = (cp.opacity as number) ?? 1;\n cp.opacity = existingOpacity * opacity;\n return {\n id: layer.id,\n layer: layer.layer,\n computedProperties: cp,\n };\n}\n","import type { AtelierDocument } from \"@a-company/atelier-types\";\n\nexport interface TemplateBindings {\n [variableName: string]: unknown;\n}\n\nexport interface TemplateError {\n variable: string;\n message: string;\n}\n\nexport type TemplateResult =\n | {\n success: true;\n document: AtelierDocument;\n }\n | {\n success: false;\n errors: TemplateError[];\n };\n\n/**\n * Instantiate a template document by substituting variable values.\n * Walks the document tree, replacing {{variableName}} patterns with bound values.\n */\nexport function instantiateTemplate(\n template: AtelierDocument,\n bindings: TemplateBindings,\n): TemplateResult {\n // 1. Validate all required variables have bindings\n const errors: TemplateError[] = [];\n const variables = template.variables ?? {};\n\n for (const [name, variable] of Object.entries(variables)) {\n if (bindings[name] === undefined && variable.default === undefined) {\n errors.push({ variable: name, message: `Required variable \"${name}\" not provided` });\n }\n }\n\n // Check for unknown bindings\n for (const name of Object.keys(bindings)) {\n if (!variables[name]) {\n errors.push({ variable: name, message: `Unknown variable \"${name}\"` });\n }\n }\n\n if (errors.length > 0) return { success: false, errors };\n\n // 2. Merge bindings with defaults\n const resolved: Record<string, unknown> = {};\n for (const [name, variable] of Object.entries(variables)) {\n resolved[name] = bindings[name] ?? variable.default;\n }\n\n // 3. Deep clone and substitute\n const doc = JSON.parse(JSON.stringify(template)) as AtelierDocument;\n substituteInObject(doc as unknown as Record<string, unknown>, resolved);\n\n // 4. Remove variables section (no longer a template)\n delete doc.variables;\n\n return { success: true, document: doc };\n}\n\n/**\n * Recursively substitute {{variableName}} patterns in string values.\n */\nfunction substituteInObject(obj: Record<string, unknown>, bindings: Record<string, unknown>): void {\n for (const key of Object.keys(obj)) {\n const value = obj[key];\n if (typeof value === \"string\") {\n obj[key] = substituteString(value, bindings);\n } else if (Array.isArray(value)) {\n substituteInArray(value, bindings);\n } else if (value !== null && typeof value === \"object\") {\n substituteInObject(value as Record<string, unknown>, bindings);\n }\n }\n}\n\nfunction substituteInArray(arr: unknown[], bindings: Record<string, unknown>): void {\n for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n if (typeof value === \"string\") {\n arr[i] = substituteString(value, bindings);\n } else if (Array.isArray(value)) {\n substituteInArray(value, bindings);\n } else if (value !== null && typeof value === \"object\") {\n substituteInObject(value as Record<string, unknown>, bindings);\n }\n }\n}\n\n/**\n * Replace {{variableName}} in a string with the bound value.\n * If the entire string is a single {{var}}, return the raw value (preserving type).\n * Otherwise, interpolate into the string.\n */\nfunction substituteString(str: string, bindings: Record<string, unknown>): unknown {\n // Exact match: entire string is {{varName}} -> return raw value\n const exactMatch = str.match(/^\\{\\{(\\w+)\\}\\}$/);\n if (exactMatch) {\n const name = exactMatch[1];\n return name in bindings ? bindings[name] : str;\n }\n\n // Partial match: replace all {{varName}} occurrences with string values\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (_, name: string) => {\n return name in bindings ? String(bindings[name]) : `{{${name}}}`;\n });\n}\n\n/**\n * List all variables used in a document (scan for {{variableName}} patterns).\n */\nexport function findTemplateVariables(doc: AtelierDocument): string[] {\n const vars = new Set<string>();\n scanForVariables(doc, vars);\n return Array.from(vars);\n}\n\nfunction scanForVariables(value: unknown, vars: Set<string>): void {\n if (typeof value === \"string\") {\n const matches = value.matchAll(/\\{\\{(\\w+)\\}\\}/g);\n for (const match of matches) {\n vars.add(match[1]);\n }\n } else if (Array.isArray(value)) {\n for (const item of value) scanForVariables(item, vars);\n } else if (value !== null && typeof value === \"object\") {\n for (const v of Object.values(value as Record<string, unknown>)) {\n scanForVariables(v, vars);\n }\n }\n}\n","import type { Audio } from \"@a-company/atelier-types\";\n\n/** Audio playback state at a given frame */\nexport interface AudioPlaybackState {\n /** Whether audio should be playing at this frame */\n shouldPlay: boolean;\n /** Current position in the audio track (seconds) */\n currentTime: number;\n /** Effective volume (0–1) */\n volume: number;\n}\n\n/**\n * Convert a frame number to time in seconds.\n */\nexport function frameToTime(frame: number, fps: number): number {\n return frame / fps;\n}\n\n/**\n * Convert time in seconds to a frame number (floored).\n */\nexport function timeToFrame(time: number, fps: number): number {\n return Math.floor(time * fps);\n}\n\n/**\n * Compute the audio playback state for a given frame.\n *\n * @param audio - Audio configuration from a state\n * @param frame - Current frame number within the state\n * @param fps - Frames per second from canvas config\n * @param stateDuration - Total state duration in frames\n * @returns AudioPlaybackState with shouldPlay, currentTime, and volume\n */\nexport function computeAudioState(\n audio: Audio,\n frame: number,\n fps: number,\n stateDuration: number,\n): AudioPlaybackState {\n const startFrame = audio.startFrame ?? 0;\n const offset = audio.offset ?? 0;\n const volume = audio.volume ?? 1;\n const loop = audio.loop ?? false;\n\n // Before audio starts\n if (frame < startFrame) {\n return { shouldPlay: false, currentTime: 0, volume };\n }\n\n // Time elapsed since audio started\n const elapsedFrames = frame - startFrame;\n const elapsedTime = frameToTime(elapsedFrames, fps);\n\n // Total available playback time (from startFrame to end of state)\n const availableFrames = stateDuration - startFrame;\n const availableTime = frameToTime(availableFrames, fps);\n\n if (!loop) {\n // Non-looping: audio plays from offset, stops at end of state\n const currentTime = offset + elapsedTime;\n return {\n shouldPlay: frame < stateDuration,\n currentTime,\n volume,\n };\n }\n\n // Looping: wrap elapsed time around available duration\n // The audio segment length is the available time\n const segmentDuration = availableTime;\n if (segmentDuration <= 0) {\n return { shouldPlay: false, currentTime: 0, volume };\n }\n\n const wrappedTime = elapsedTime % segmentDuration;\n const currentTime = offset + wrappedTime;\n\n return {\n shouldPlay: frame < stateDuration,\n currentTime,\n volume,\n };\n}\n\n/**\n * Compute audio cue points — frames where audio events occur.\n *\n * @param audio - Audio configuration\n * @param stateDuration - Total state duration in frames\n * @returns Array of { frame, event } describing audio events\n */\nexport function computeAudioCues(\n audio: Audio,\n stateDuration: number,\n): Array<{ frame: number; event: \"start\" | \"end\" | \"loop\" }> {\n const startFrame = audio.startFrame ?? 0;\n const loop = audio.loop ?? false;\n const cues: Array<{ frame: number; event: \"start\" | \"end\" | \"loop\" }> = [];\n\n if (startFrame < stateDuration) {\n cues.push({ frame: startFrame, event: \"start\" });\n }\n\n if (loop) {\n // In loop mode, audio restarts each full cycle\n const availableFrames = stateDuration - startFrame;\n if (availableFrames > 0) {\n // Loop points at each full cycle\n for (let i = 1; startFrame + i * availableFrames < stateDuration; i++) {\n cues.push({ frame: startFrame + i * availableFrames, event: \"loop\" });\n }\n }\n }\n\n // Audio ends when state ends\n if (stateDuration > startFrame) {\n cues.push({ frame: stateDuration - 1, event: \"end\" });\n }\n\n return cues;\n}\n","import type { Fill, Stroke, Color, RGBAColor, HSLAColor } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"./canvas-types.js\";\n\n/**\n * Convert an Atelier Color to a CSS color string.\n */\nexport function colorToCSS(color: Color): string {\n if (typeof color === \"string\") return color; // hex string\n\n if (\"r\" in color) {\n const c = color as RGBAColor;\n return `rgba(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)}, ${c.a})`;\n }\n\n if (\"h\" in color) {\n const c = color as HSLAColor;\n return `hsla(${c.h}, ${c.s}%, ${c.l}%, ${c.a})`;\n }\n\n return \"#000000\";\n}\n\n/**\n * Apply a Fill to the canvas context's fillStyle.\n */\nexport function applyFill(ctx: RenderContext, fill: Fill, width: number, height: number): void {\n switch (fill.type) {\n case \"solid\":\n ctx.fillStyle = colorToCSS(fill.color);\n break;\n\n case \"linear-gradient\": {\n const rad = (fill.angle * Math.PI) / 180;\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const halfW = width / 2;\n const halfH = height / 2;\n const grad = ctx.createLinearGradient(\n halfW - cos * halfW, halfH - sin * halfH,\n halfW + cos * halfW, halfH + sin * halfH,\n );\n for (const stop of fill.stops) {\n grad.addColorStop(stop.offset, colorToCSS(stop.color));\n }\n ctx.fillStyle = grad as unknown as string;\n break;\n }\n\n case \"radial-gradient\": {\n const cx = typeof fill.center.x === \"number\" ? fill.center.x : (parseFloat(fill.center.x) / 100) * width;\n const cy = typeof fill.center.y === \"number\" ? fill.center.y : (parseFloat(fill.center.y) / 100) * height;\n const r = typeof fill.radius === \"number\" ? fill.radius : (parseFloat(fill.radius) / 100) * Math.max(width, height);\n const grad = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);\n for (const stop of fill.stops) {\n grad.addColorStop(stop.offset, colorToCSS(stop.color));\n }\n ctx.fillStyle = grad as unknown as string;\n break;\n }\n }\n}\n\n/**\n * Apply a Stroke to the canvas context.\n * @param pathLength - total perimeter of the shape (needed for strokeStart/strokeEnd trim)\n */\nexport function applyStroke(ctx: RenderContext, stroke: Stroke, pathLength: number): void {\n ctx.strokeStyle = colorToCSS(stroke.color);\n ctx.lineWidth = stroke.width;\n if (stroke.lineCap) ctx.lineCap = stroke.lineCap;\n if (stroke.lineJoin) ctx.lineJoin = stroke.lineJoin;\n\n const start = stroke.strokeStart ?? 0;\n const end = stroke.strokeEnd ?? 1;\n\n if (start !== 0 || end !== 1) {\n const visible = (end - start) * pathLength;\n ctx.setLineDash([Math.max(visible, 0), pathLength + 1]);\n ctx.lineDashOffset = -start * pathLength;\n } else if (stroke.dash) {\n ctx.setLineDash(stroke.dash);\n }\n}\n","import type { Layer, Visual, ShapeVisual, TextVisual, ImageVisual, Color, BlendMode, LinearGradientFill, RadialGradientFill } from \"@a-company/atelier-types\";\nimport { colorToCSS } from \"./styles.js\";\nimport { evaluatePathAtProgress } from \"@a-company/atelier-math\";\nimport type { ResolvedLayer } from \"@a-company/atelier-core\";\n\n/**\n * Effective values for a layer at a given frame,\n * with computed properties merged over defaults.\n */\nexport interface EffectiveLayer {\n /** Original layer */\n layer: Layer;\n /** Visual with animated property overrides applied */\n visual: Visual;\n /** Effective frame position (may be animated) */\n x: number;\n y: number;\n /** Effective bounds */\n width: number;\n height: number;\n /** Effective transform values */\n opacity: number;\n rotation: number;\n scaleX: number;\n scaleY: number;\n anchorX: number;\n anchorY: number;\n /** Resolved shadow (if layer has shadow or shadow is animated) */\n shadow?: {\n color: string;\n blur: number;\n offsetX: number;\n offsetY: number;\n };\n /** Blend mode for compositing */\n blendMode: string;\n /** Motion path auto-rotation in degrees (applied additively to rotation) */\n motionPathAngle: number;\n /** Whether this layer is visible (may be animated) */\n visible: boolean;\n /** Color tint overlay */\n tint?: {\n color: string;\n amount: number;\n };\n}\n\n/**\n * Resolve a UnitValue to pixels. Percentages resolve against a reference dimension.\n */\nfunction resolveUnit(value: number | string, reference: number): number {\n if (typeof value === \"string\" && value.endsWith(\"%\")) {\n return (parseFloat(value) / 100) * reference;\n }\n return value as number;\n}\n\n/**\n * Build the effective layer values by merging computed properties over layer defaults.\n * @param resolved - The resolved layer from frame resolution\n * @param parentWidth - Parent/canvas width for percentage resolution\n * @param parentHeight - Parent/canvas height for percentage resolution\n */\nexport function buildEffectiveLayer(\n resolved: ResolvedLayer,\n parentWidth: number,\n parentHeight: number,\n): EffectiveLayer {\n const { layer, computedProperties } = resolved;\n const cp = computedProperties as Record<string, unknown>;\n\n const hasShadow = layer.shadow || cp[\"shadow.blur\"] !== undefined || cp[\"shadow.color\"] !== undefined;\n const hasTint = layer.tint || cp[\"tint.amount\"] !== undefined || cp[\"tint.color\"] !== undefined;\n\n // Resolve base position\n let x = resolveUnit((cp[\"frame.x\"] ?? layer.frame.x) as number | string, parentWidth);\n let y = resolveUnit((cp[\"frame.y\"] ?? layer.frame.y) as number | string, parentHeight);\n let motionPathAngle = 0;\n\n // Motion path overrides position when progress is animated\n const motionProgress = cp[\"motionPath.progress\"] as number | undefined;\n if (motionProgress !== undefined && layer.motionPath && layer.motionPath.points.length >= 2) {\n const pos = evaluatePathAtProgress(layer.motionPath.points, motionProgress, layer.motionPath.closed);\n x = pos.x;\n y = pos.y;\n if (layer.motionPath.autoRotate) {\n motionPathAngle = pos.angle + (layer.motionPath.autoRotateOffset ?? 0);\n }\n }\n\n return {\n layer,\n visual: buildEffectiveVisual(layer.visual, cp),\n x,\n y,\n width: resolveUnit((cp[\"bounds.width\"] ?? layer.bounds.width) as number | string, parentWidth),\n height: resolveUnit((cp[\"bounds.height\"] ?? layer.bounds.height) as number | string, parentHeight),\n opacity: (cp[\"opacity\"] as number) ?? layer.opacity ?? 1,\n rotation: (cp[\"rotation\"] as number) ?? layer.rotation ?? 0,\n scaleX: (cp[\"scale.x\"] as number) ?? layer.scale?.x ?? 1,\n scaleY: (cp[\"scale.y\"] as number) ?? layer.scale?.y ?? 1,\n anchorX: (cp[\"anchorPoint.x\"] as number) ?? layer.anchorPoint?.x ?? 0,\n anchorY: (cp[\"anchorPoint.y\"] as number) ?? layer.anchorPoint?.y ?? 0,\n shadow: hasShadow ? {\n color: colorToCSS((cp[\"shadow.color\"] ?? layer.shadow?.color ?? \"#00000080\") as Color),\n blur: (cp[\"shadow.blur\"] as number) ?? layer.shadow?.blur ?? 0,\n offsetX: (cp[\"shadow.offsetX\"] as number) ?? layer.shadow?.offsetX ?? 0,\n offsetY: (cp[\"shadow.offsetY\"] as number) ?? layer.shadow?.offsetY ?? 0,\n } : undefined,\n blendMode: (layer.blendMode as BlendMode) ?? \"normal\",\n motionPathAngle,\n visible: (cp[\"visible\"] as boolean) ?? layer.visible ?? true,\n tint: hasTint ? {\n color: colorToCSS((cp[\"tint.color\"] ?? layer.tint?.color ?? \"#FF0000\") as Color),\n amount: (cp[\"tint.amount\"] as number) ?? layer.tint?.amount ?? 0,\n } : undefined,\n };\n}\n\n/**\n * Build an effective visual by applying computed property overrides.\n * Returns the original visual if no visual properties are animated.\n */\nfunction buildEffectiveVisual(visual: Visual, cp: Record<string, unknown>): Visual {\n const hasVisualOverride =\n cp[\"visual.fill.color\"] !== undefined ||\n cp[\"visual.fill.angle\"] !== undefined ||\n cp[\"visual.fill.center.x\"] !== undefined ||\n cp[\"visual.fill.center.y\"] !== undefined ||\n cp[\"visual.fill.radius\"] !== undefined ||\n cp[\"visual.stroke.color\"] !== undefined ||\n cp[\"visual.stroke.width\"] !== undefined ||\n cp[\"visual.stroke.start\"] !== undefined ||\n cp[\"visual.stroke.end\"] !== undefined ||\n cp[\"visual.shape.cornerRadius\"] !== undefined ||\n cp[\"visual.style.fontSize\"] !== undefined ||\n cp[\"visual.style.color\"] !== undefined;\n\n const hasImageOverride =\n cp[\"visual.image.sourceRect.x\"] !== undefined ||\n cp[\"visual.image.sourceRect.y\"] !== undefined ||\n cp[\"visual.image.sourceRect.width\"] !== undefined ||\n cp[\"visual.image.sourceRect.height\"] !== undefined ||\n cp[\"visual.image.frameIndex\"] !== undefined;\n\n if (!hasVisualOverride && !hasImageOverride) return visual;\n\n if (visual.type === \"shape\") {\n const v: ShapeVisual = { ...visual };\n\n if (cp[\"visual.shape.cornerRadius\"] !== undefined && v.shape.type === \"rect\") {\n v.shape = { ...v.shape, cornerRadius: cp[\"visual.shape.cornerRadius\"] as number };\n }\n\n if (v.fill) {\n if (cp[\"visual.fill.color\"] !== undefined && v.fill.type === \"solid\") {\n v.fill = { ...v.fill, color: cp[\"visual.fill.color\"] as string };\n }\n if (cp[\"visual.fill.angle\"] !== undefined && v.fill.type === \"linear-gradient\") {\n v.fill = { ...v.fill, angle: cp[\"visual.fill.angle\"] as number } as LinearGradientFill;\n }\n if (v.fill.type === \"radial-gradient\") {\n const cx = cp[\"visual.fill.center.x\"];\n const cy = cp[\"visual.fill.center.y\"];\n const r = cp[\"visual.fill.radius\"];\n if (cx !== undefined || cy !== undefined || r !== undefined) {\n const f = v.fill as RadialGradientFill;\n v.fill = {\n ...f,\n center: {\n x: cx !== undefined ? (cx as number) : f.center.x,\n y: cy !== undefined ? (cy as number) : f.center.y,\n },\n radius: r !== undefined ? (r as number) : f.radius,\n } as RadialGradientFill;\n }\n }\n }\n\n if (v.stroke) {\n const strokeColor = cp[\"visual.stroke.color\"] ?? v.stroke.color;\n const strokeWidth = (cp[\"visual.stroke.width\"] as number) ?? v.stroke.width;\n const strokeStart = (cp[\"visual.stroke.start\"] as number | undefined) ?? v.stroke.strokeStart;\n const strokeEnd = (cp[\"visual.stroke.end\"] as number | undefined) ?? v.stroke.strokeEnd;\n if (\n strokeColor !== v.stroke.color ||\n strokeWidth !== v.stroke.width ||\n strokeStart !== v.stroke.strokeStart ||\n strokeEnd !== v.stroke.strokeEnd\n ) {\n v.stroke = {\n ...v.stroke,\n color: strokeColor as string,\n width: strokeWidth,\n strokeStart,\n strokeEnd,\n };\n }\n }\n\n return v;\n }\n\n if (visual.type === \"text\") {\n const v: TextVisual = { ...visual };\n const fontSize = (cp[\"visual.style.fontSize\"] as number) ?? v.style.fontSize;\n const color = cp[\"visual.style.color\"] ?? v.style.color;\n if (fontSize !== v.style.fontSize || color !== v.style.color) {\n v.style = { ...v.style, fontSize, color: color as string };\n }\n return v;\n }\n\n if (visual.type === \"image\" && hasImageOverride) {\n const v: ImageVisual = { ...visual };\n\n // Merge animated sourceRect fields\n if (\n cp[\"visual.image.sourceRect.x\"] !== undefined ||\n cp[\"visual.image.sourceRect.y\"] !== undefined ||\n cp[\"visual.image.sourceRect.width\"] !== undefined ||\n cp[\"visual.image.sourceRect.height\"] !== undefined\n ) {\n const base = v.sourceRect ?? { x: 0, y: 0, width: 0, height: 0 };\n v.sourceRect = {\n x: (cp[\"visual.image.sourceRect.x\"] as number) ?? base.x,\n y: (cp[\"visual.image.sourceRect.y\"] as number) ?? base.y,\n width: (cp[\"visual.image.sourceRect.width\"] as number) ?? base.width,\n height: (cp[\"visual.image.sourceRect.height\"] as number) ?? base.height,\n };\n }\n\n // Merge animated frameIndex\n if (cp[\"visual.image.frameIndex\"] !== undefined) {\n v.frameIndex = Math.floor(cp[\"visual.image.frameIndex\"] as number);\n }\n\n return v;\n }\n\n return visual;\n}\n","import type { ShapeVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport { applyFill, applyStroke } from \"../styles.js\";\n\nexport function renderShape(ctx: RenderContext, eff: EffectiveLayer): void {\n const visual = eff.visual as ShapeVisual;\n const { shape } = visual;\n const { width, height } = eff;\n\n switch (shape.type) {\n case \"rect\":\n renderRect(ctx, width, height, shape.cornerRadius, visual);\n break;\n case \"ellipse\":\n renderEllipse(ctx, width, height, visual);\n break;\n case \"path\":\n renderPath(ctx, shape.points, shape.closed, visual);\n break;\n }\n}\n\n// ── Perimeter helpers ───────────────────────────────────────\n\nfunction rectPerimeter(w: number, h: number): number {\n return 2 * (w + h);\n}\n\nfunction ellipsePerimeter(w: number, h: number): number {\n const a = w / 2;\n const b = h / 2;\n // Ramanujan approximation\n return Math.PI * (3 * (a + b) - Math.sqrt((3 * a + b) * (a + 3 * b)));\n}\n\nfunction dist(x1: number, y1: number, x2: number, y2: number): number {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction pathPerimeter(\n points: { x: number; y: number; in?: { x: number; y: number }; out?: { x: number; y: number } }[],\n closed: boolean | undefined,\n): number {\n let length = 0;\n for (let i = 1; i < points.length; i++) {\n const prev = points[i - 1];\n const curr = points[i];\n if (prev.out && curr.in) {\n // Approximate bezier with chord * 1.2\n length += dist(prev.x, prev.y, curr.x, curr.y) * 1.2;\n } else {\n length += dist(prev.x, prev.y, curr.x, curr.y);\n }\n }\n if (closed && points.length > 1) {\n const first = points[0];\n const last = points[points.length - 1];\n length += dist(last.x, last.y, first.x, first.y);\n }\n return length;\n}\n\n// ── Renderers ───────────────────────────────────────────────\n\nfunction renderRect(\n ctx: RenderContext,\n width: number,\n height: number,\n cornerRadius: number | [number, number, number, number] | undefined,\n visual: ShapeVisual,\n): void {\n if (visual.fill) {\n applyFill(ctx, visual.fill, width, height);\n if (cornerRadius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(0, 0, width, height, cornerRadius);\n ctx.fill();\n } else {\n ctx.fillRect(0, 0, width, height);\n }\n }\n if (visual.stroke) {\n const perimeter = rectPerimeter(width, height);\n applyStroke(ctx, visual.stroke, perimeter);\n if (cornerRadius && ctx.roundRect) {\n ctx.beginPath();\n ctx.roundRect(0, 0, width, height, cornerRadius);\n ctx.stroke();\n } else {\n ctx.strokeRect(0, 0, width, height);\n }\n }\n}\n\nfunction renderEllipse(\n ctx: RenderContext,\n width: number,\n height: number,\n visual: ShapeVisual,\n): void {\n ctx.beginPath();\n ctx.ellipse(width / 2, height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);\n\n if (visual.fill) {\n applyFill(ctx, visual.fill, width, height);\n ctx.fill();\n }\n if (visual.stroke) {\n const perimeter = ellipsePerimeter(width, height);\n applyStroke(ctx, visual.stroke, perimeter);\n ctx.stroke();\n }\n}\n\nfunction renderPath(\n ctx: RenderContext,\n points: { x: number; y: number; in?: { x: number; y: number }; out?: { x: number; y: number } }[],\n closed: boolean | undefined,\n visual: ShapeVisual,\n): void {\n if (points.length < 2) return;\n\n ctx.beginPath();\n ctx.moveTo(points[0].x, points[0].y);\n\n for (let i = 1; i < points.length; i++) {\n const prev = points[i - 1];\n const curr = points[i];\n\n if (prev.out && curr.in) {\n ctx.bezierCurveTo(\n prev.x + prev.out.x, prev.y + prev.out.y,\n curr.x + curr.in.x, curr.y + curr.in.y,\n curr.x, curr.y,\n );\n } else {\n ctx.lineTo(curr.x, curr.y);\n }\n }\n\n if (closed) ctx.closePath();\n\n if (visual.fill) {\n applyFill(ctx, visual.fill, 0, 0);\n ctx.fill();\n }\n if (visual.stroke) {\n const perimeter = pathPerimeter(points, closed);\n applyStroke(ctx, visual.stroke, perimeter);\n ctx.stroke();\n }\n}\n","import type { TextVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport { colorToCSS } from \"../styles.js\";\n\nexport function renderText(ctx: RenderContext, eff: EffectiveLayer): void {\n const visual = eff.visual as TextVisual;\n const { style } = visual;\n\n // Build font string\n const fontStyle = style.fontStyle ?? \"normal\";\n const fontWeight = style.fontWeight ?? \"normal\";\n const fontSize = style.fontSize;\n const fontFamily = style.fontFamily;\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;\n\n // Set alignment — position text within its bounding box\n const align = style.textAlign ?? \"left\";\n ctx.textAlign = align;\n ctx.textBaseline = \"top\";\n\n // Set color\n ctx.fillStyle = colorToCSS(style.color);\n\n // Canvas 2D textAlign anchors at the draw point, so offset within bounds:\n // \"left\" → draw at x=0 (text flows right from left edge)\n // \"center\" → draw at x=width/2 (text centers within bounds)\n // \"right\" → draw at x=width (text flows left from right edge)\n let textX = 0;\n if (align === \"center\") {\n textX = eff.width / 2;\n } else if (align === \"right\") {\n textX = eff.width;\n }\n\n ctx.fillText(visual.content, textX, 0);\n}\n","import type { ImageVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport type { ImageCache } from \"../image-cache.js\";\n\n/**\n * Render an image layer to the canvas.\n * Supports sourceRect cropping and spritesheet grid animation.\n * If the image hasn't loaded yet, triggers a cache load and returns\n * (the image will appear on the next re-render).\n */\nexport function renderImage(ctx: RenderContext, eff: EffectiveLayer, imageCache: ImageCache): void {\n const visual = eff.visual as ImageVisual;\n const src = visual.src;\n if (!src) return;\n\n const img = imageCache.get(src);\n if (!img) {\n imageCache.load(src);\n return;\n }\n\n // Spritesheet grid computation takes precedence over manual sourceRect\n if (visual.spritesheet) {\n const { columns, rows, frameWidth, frameHeight, frameCount } = visual.spritesheet;\n const maxFrames = frameCount ?? (columns * rows);\n const idx = Math.max(0, Math.min(Math.floor(visual.frameIndex ?? 0), maxFrames - 1));\n const col = idx % columns;\n const row = Math.floor(idx / columns);\n const sx = col * frameWidth;\n const sy = row * frameHeight;\n (ctx.drawImage as Function)(img, sx, sy, frameWidth, frameHeight, 0, 0, eff.width, eff.height);\n return;\n }\n\n // Manual sourceRect crop\n if (visual.sourceRect) {\n const sr = visual.sourceRect;\n (ctx.drawImage as Function)(img, sr.x, sr.y, sr.width, sr.height, 0, 0, eff.width, eff.height);\n return;\n }\n\n // Default: draw full image to bounds\n ctx.drawImage(img, 0, 0, eff.width, eff.height);\n}\n","import type { VideoVisual } from \"@a-company/atelier-types\";\nimport type { RenderContext, VideoFrameProvider } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\n\n/**\n * Render a video layer to the canvas at the given source time.\n * Delegates actual frame extraction to the injected VideoFrameProvider,\n * which may be backed by HTMLVideoElement (preview) or WebCodecs (export).\n * Returns without drawing if the provider returns null — caller retries next tick.\n */\nexport function renderVideo(\n ctx: RenderContext,\n eff: EffectiveLayer,\n sourceTime: number,\n provider: VideoFrameProvider,\n): void {\n const visual = eff.visual as VideoVisual;\n const src = visual.src;\n if (!src) return;\n\n const frame = provider(src, sourceTime, eff.width, eff.height);\n if (!frame) return;\n\n ctx.drawImage(frame as unknown, 0, 0, eff.width, eff.height);\n}\n","import type { AtelierDocument, RefVisual, ImageVisual } from \"@a-company/atelier-types\";\nimport { resolveFrame } from \"@a-company/atelier-core\";\nimport type { RenderContext, DocumentResolver } from \"../canvas-types.js\";\nimport type { EffectiveLayer } from \"../apply-properties.js\";\nimport { buildEffectiveLayer } from \"../apply-properties.js\";\nimport { renderShape } from \"./shape-renderer.js\";\nimport { renderText } from \"./text-renderer.js\";\nimport { renderImage } from \"./image-renderer.js\";\nimport type { ImageCache } from \"../image-cache.js\";\n\nexport interface RefRenderOpts {\n documentResolver?: DocumentResolver;\n maxRefDepth?: number;\n imageCache?: ImageCache;\n /** Internal: tracks visited refs for cycle detection */\n _visitedRefs?: Set<string>;\n /** Internal: current recursion depth */\n _depth?: number;\n}\n\n/**\n * Render a ref layer. If a documentResolver is provided, resolves and renders\n * the sub-document inline. Otherwise falls back to a placeholder rectangle.\n */\nexport function renderRef(\n ctx: RenderContext,\n eff: EffectiveLayer,\n opts?: RefRenderOpts,\n _parentDoc?: AtelierDocument,\n): void {\n const visual = eff.visual as RefVisual;\n const resolver = opts?.documentResolver;\n\n if (!resolver) {\n renderPlaceholder(ctx, eff, `REF: ${visual.src}`);\n return;\n }\n\n const depth = opts?._depth ?? 0;\n const maxDepth = opts?.maxRefDepth ?? 4;\n\n if (depth >= maxDepth) {\n renderPlaceholder(ctx, eff, \"MAX DEPTH\");\n return;\n }\n\n const visitedRefs = opts?._visitedRefs ?? new Set<string>();\n\n if (visitedRefs.has(visual.src)) {\n renderPlaceholder(ctx, eff, \"CYCLE\");\n return;\n }\n\n const subDoc = resolver(visual.src);\n if (!subDoc) {\n renderPlaceholder(ctx, eff, \"NOT FOUND\");\n return;\n }\n\n // Determine which state and frame to render\n const stateNames = Object.keys(subDoc.states);\n if (stateNames.length === 0) {\n renderPlaceholder(ctx, eff, \"NO STATES\");\n return;\n }\n\n const stateName = visual.state ?? stateNames[0];\n const stateObj = subDoc.states[stateName];\n if (!stateObj) {\n renderPlaceholder(ctx, eff, `STATE? ${stateName}`);\n return;\n }\n\n const maxFrame = Math.max(0, stateObj.duration - 1);\n const frame = Math.min(visual.frame ?? 0, maxFrame);\n\n // Resolve the sub-document frame\n const resolved = resolveFrame(subDoc, stateName, frame);\n\n // Mark as visited for cycle detection\n visitedRefs.add(visual.src);\n\n // Scale to fit eff bounds\n const scaleX = eff.width / subDoc.canvas.width;\n const scaleY = eff.height / subDoc.canvas.height;\n\n ctx.save();\n ctx.scale(scaleX, scaleY);\n\n // Build and render sub-doc layers\n const { width: subW, height: subH } = subDoc.canvas;\n\n for (const resolvedLayer of resolved.layers) {\n const subEff = buildEffectiveLayer(resolvedLayer, subW, subH);\n\n if (!subEff.visible) continue;\n if (subEff.opacity <= 0) continue;\n\n // Resolve asset for images\n if (resolvedLayer.layer.visual.type === \"image\") {\n const iv = subEff.visual as ImageVisual;\n if (!iv.src && iv.assetId && subDoc.assets?.[iv.assetId]) {\n iv.src = subDoc.assets[iv.assetId].src;\n }\n }\n\n ctx.save();\n ctx.globalAlpha = subEff.opacity;\n ctx.translate(subEff.x, subEff.y);\n\n switch (resolvedLayer.layer.visual.type) {\n case \"shape\":\n renderShape(ctx, subEff);\n break;\n case \"text\":\n renderText(ctx, subEff);\n break;\n case \"image\":\n if (opts?.imageCache) renderImage(ctx, subEff, opts.imageCache);\n break;\n case \"ref\":\n renderRef(ctx, subEff, {\n ...opts,\n _visitedRefs: visitedRefs,\n _depth: depth + 1,\n }, subDoc);\n break;\n case \"group\":\n break;\n }\n\n ctx.restore();\n }\n\n ctx.restore();\n\n // Remove from visited after rendering (allow same ref in different branches)\n visitedRefs.delete(visual.src);\n}\n\n/** Render a dashed placeholder rectangle with label */\nfunction renderPlaceholder(ctx: RenderContext, eff: EffectiveLayer, label: string): void {\n const { width, height } = eff;\n\n ctx.strokeStyle = \"#888888\";\n ctx.lineWidth = 2;\n ctx.setLineDash([6, 4]);\n ctx.strokeRect(0, 0, width, height);\n ctx.setLineDash([]);\n\n ctx.fillStyle = \"#888888\";\n ctx.font = `${Math.max(12, Math.min(16, height * 0.15))}px sans-serif`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(label, width / 2, height / 2, width - 8);\n}\n","import type { AtelierDocument, ImageVisual, VideoVisual, Shape } from \"@a-company/atelier-types\";\nimport type { ResolvedFrame } from \"@a-company/atelier-core\";\nimport type { RenderContext, DocumentResolver, VideoFrameProvider } from \"./canvas-types.js\";\nimport { buildEffectiveLayer, type EffectiveLayer } from \"./apply-properties.js\";\nimport { renderShape } from \"./renderers/shape-renderer.js\";\nimport { renderText } from \"./renderers/text-renderer.js\";\nimport { renderImage } from \"./renderers/image-renderer.js\";\nimport { renderVideo } from \"./renderers/video-renderer.js\";\nimport { renderRef } from \"./renderers/ref-renderer.js\";\nimport type { ImageCache } from \"./image-cache.js\";\n\n/** Options for renderFrame */\nexport interface RenderOptions {\n imageCache?: ImageCache;\n documentResolver?: DocumentResolver;\n maxRefDepth?: number;\n videoFrameProvider?: VideoFrameProvider;\n}\n\n/**\n * Render a resolved frame to a Canvas 2D context.\n * Clears the canvas and draws all visible layers in order.\n */\nexport function renderFrame(\n ctx: RenderContext,\n resolvedFrame: ResolvedFrame,\n doc: AtelierDocument,\n optsOrCache?: RenderOptions | ImageCache,\n): void {\n // Backward compatible: detect old ImageCache arg vs new RenderOptions\n let imageCache: ImageCache | undefined;\n let documentResolver: DocumentResolver | undefined;\n let videoFrameProvider: VideoFrameProvider | undefined;\n let maxRefDepth = 4;\n\n if (optsOrCache && typeof (optsOrCache as ImageCache).get === \"function\") {\n imageCache = optsOrCache as ImageCache;\n } else if (optsOrCache) {\n const opts = optsOrCache as RenderOptions;\n imageCache = opts.imageCache;\n documentResolver = opts.documentResolver;\n videoFrameProvider = opts.videoFrameProvider;\n maxRefDepth = opts.maxRefDepth ?? 4;\n }\n const { width, height } = doc.canvas;\n\n // Clear canvas\n ctx.fillStyle = doc.canvas.background ?? \"transparent\";\n ctx.fillRect(0, 0, width, height);\n\n // Build effective layers into a map for ancestor transform lookups\n const effMap = new Map<string, EffectiveLayer>();\n const effList: EffectiveLayer[] = [];\n const videoSourceTimeMap = new Map<string, number>();\n\n for (const resolvedLayer of resolvedFrame.layers) {\n const eff = buildEffectiveLayer(resolvedLayer, width, height);\n effMap.set(resolvedLayer.layer.id, eff);\n effList.push(eff);\n if (resolvedLayer.videoSourceTime !== undefined) {\n videoSourceTimeMap.set(resolvedLayer.layer.id, resolvedLayer.videoSourceTime);\n }\n }\n\n // Render each layer in order (painters algorithm — first = back)\n for (const eff of effList) {\n const { layer } = eff;\n\n // Skip invisible layers\n if (!eff.visible) continue;\n\n // Skip fully transparent layers\n if (eff.opacity <= 0) continue;\n\n // Resolve assetId → src for image visuals\n if (layer.visual.type === \"image\") {\n const iv = eff.visual as ImageVisual;\n if (!iv.src && iv.assetId && doc.assets?.[iv.assetId]) {\n iv.src = doc.assets[iv.assetId].src;\n }\n }\n\n // Resolve assetId → src for video visuals\n if (layer.visual.type === \"video\") {\n const vv = eff.visual as VideoVisual;\n if (!vv.src && vv.assetId && doc.assets?.[vv.assetId]) {\n vv.src = doc.assets[vv.assetId].src;\n }\n }\n\n ctx.save();\n\n // Apply ancestor transforms (group/parent inheritance)\n applyAncestorTransforms(ctx, layer.id, effMap, doc);\n\n // Apply transforms\n ctx.globalAlpha = eff.opacity;\n\n // Apply blend mode\n if (eff.blendMode !== \"normal\") {\n ctx.globalCompositeOperation = blendModeToComposite(eff.blendMode);\n }\n\n ctx.translate(eff.x, eff.y);\n\n // Apply anchor-relative transforms\n const anchorPixelX = eff.anchorX * eff.width;\n const anchorPixelY = eff.anchorY * eff.height;\n\n // Combine explicit rotation with motion path auto-rotation\n const totalRotation = eff.rotation + eff.motionPathAngle;\n\n if (totalRotation !== 0 || eff.scaleX !== 1 || eff.scaleY !== 1) {\n ctx.translate(anchorPixelX, anchorPixelY);\n if (totalRotation !== 0) {\n ctx.rotate((totalRotation * Math.PI) / 180);\n }\n if (eff.scaleX !== 1 || eff.scaleY !== 1) {\n ctx.scale(eff.scaleX, eff.scaleY);\n }\n ctx.translate(-anchorPixelX, -anchorPixelY);\n }\n\n // Apply shadow if present\n if (eff.shadow) {\n ctx.shadowColor = eff.shadow.color;\n ctx.shadowBlur = eff.shadow.blur;\n ctx.shadowOffsetX = eff.shadow.offsetX;\n ctx.shadowOffsetY = eff.shadow.offsetY;\n }\n\n // Apply clip path if present\n if (layer.clipPath) {\n applyClipPath(ctx, layer.clipPath, eff.width, eff.height);\n }\n\n // Tint requires offscreen compositing — draw to offscreen if tint is active\n const hasTint = eff.tint && eff.tint.amount > 0 && ctx.createOffscreen;\n let renderCtx = ctx;\n let offscreen: { ctx: RenderContext; canvas: unknown } | null = null;\n\n if (hasTint) {\n offscreen = ctx.createOffscreen!(eff.width, eff.height);\n renderCtx = offscreen.ctx;\n }\n\n // Ref rendering options (passed through for sub-doc composition)\n const refOpts = { documentResolver, maxRefDepth, imageCache };\n\n // Dispatch to type-specific renderer\n switch (layer.visual.type) {\n case \"shape\":\n renderShape(renderCtx, eff);\n break;\n case \"text\":\n renderText(renderCtx, eff);\n break;\n case \"image\":\n if (imageCache) renderImage(renderCtx, eff, imageCache);\n break;\n case \"video\":\n if (videoFrameProvider) {\n renderVideo(renderCtx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider);\n }\n break;\n case \"group\":\n // Groups are structural containers — no visual output\n break;\n case \"ref\":\n renderRef(renderCtx, eff, refOpts, doc);\n break;\n }\n\n // Apply tint via multiply composite on offscreen canvas\n if (hasTint && offscreen && eff.tint) {\n const offCtx = offscreen.ctx;\n // Draw tint color over the content using multiply\n offCtx.save();\n offCtx.globalCompositeOperation = \"multiply\";\n offCtx.fillStyle = eff.tint.color;\n offCtx.fillRect(0, 0, eff.width, eff.height);\n offCtx.restore();\n\n // Clip to original content shape using destination-in\n offCtx.save();\n offCtx.globalCompositeOperation = \"destination-in\";\n // Re-render the content to create the alpha mask\n switch (layer.visual.type) {\n case \"shape\": renderShape(offCtx, eff); break;\n case \"text\": renderText(offCtx, eff); break;\n case \"image\": if (imageCache) renderImage(offCtx, eff, imageCache); break;\n case \"video\": if (videoFrameProvider) renderVideo(offCtx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider); break;\n case \"ref\": renderRef(offCtx, eff, refOpts, doc); break;\n }\n offCtx.restore();\n\n // Blend tinted offscreen back with original at tint.amount alpha\n // First draw original content\n switch (layer.visual.type) {\n case \"shape\": renderShape(ctx, eff); break;\n case \"text\": renderText(ctx, eff); break;\n case \"image\": if (imageCache) renderImage(ctx, eff, imageCache); break;\n case \"video\": if (videoFrameProvider) renderVideo(ctx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider); break;\n case \"ref\": renderRef(ctx, eff, refOpts, doc); break;\n }\n // Then overlay tinted version at tint amount\n const prevAlpha = ctx.globalAlpha;\n ctx.globalAlpha = eff.tint.amount;\n ctx.drawImage(offscreen.canvas, 0, 0, eff.width, eff.height);\n ctx.globalAlpha = prevAlpha;\n }\n\n ctx.restore();\n }\n}\n\n/** Apply a shape as a clipping region */\nfunction applyClipPath(ctx: RenderContext, shape: Shape, width: number, height: number): void {\n ctx.beginPath();\n switch (shape.type) {\n case \"rect\":\n if (shape.cornerRadius && ctx.roundRect) {\n ctx.roundRect(0, 0, width, height, shape.cornerRadius);\n } else {\n // Manual rect path for clipping (fillRect doesn't create a path)\n ctx.moveTo(0, 0);\n ctx.lineTo(width, 0);\n ctx.lineTo(width, height);\n ctx.lineTo(0, height);\n ctx.closePath();\n }\n break;\n case \"ellipse\":\n ctx.ellipse(width / 2, height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n case \"path\":\n if (shape.points.length >= 2) {\n ctx.moveTo(shape.points[0].x, shape.points[0].y);\n for (let i = 1; i < shape.points.length; i++) {\n const prev = shape.points[i - 1];\n const curr = shape.points[i];\n if (prev.out && curr.in) {\n ctx.bezierCurveTo(\n prev.x + prev.out.x, prev.y + prev.out.y,\n curr.x + curr.in.x, curr.y + curr.in.y,\n curr.x, curr.y,\n );\n } else {\n ctx.lineTo(curr.x, curr.y);\n }\n }\n if (shape.closed) ctx.closePath();\n }\n break;\n }\n ctx.clip();\n}\n\n/** Map Atelier blend mode names to Canvas 2D globalCompositeOperation values */\nfunction blendModeToComposite(mode: string): string {\n const map: Record<string, string> = {\n \"multiply\": \"multiply\",\n \"screen\": \"screen\",\n \"overlay\": \"overlay\",\n \"darken\": \"darken\",\n \"lighten\": \"lighten\",\n \"color-dodge\": \"color-dodge\",\n \"color-burn\": \"color-burn\",\n \"hard-light\": \"hard-light\",\n \"soft-light\": \"soft-light\",\n \"difference\": \"difference\",\n \"exclusion\": \"exclusion\",\n \"hue\": \"hue\",\n \"saturation\": \"saturation\",\n \"color\": \"color\",\n \"luminosity\": \"luminosity\",\n };\n return map[mode] ?? \"source-over\";\n}\n\n/**\n * Walk the parentId chain and apply each ancestor's transforms.\n * This makes child layers inherit parent position/rotation/scale.\n */\nfunction applyAncestorTransforms(\n ctx: RenderContext,\n layerId: string,\n effMap: Map<string, EffectiveLayer>,\n doc: AtelierDocument,\n): void {\n // Collect ancestor chain (excluding self)\n const chain: EffectiveLayer[] = [];\n const layer = doc.layers.find((l) => l.id === layerId);\n let parentId = layer?.parentId;\n const visited = new Set<string>();\n\n while (parentId && !visited.has(parentId)) {\n visited.add(parentId);\n const parentEff = effMap.get(parentId);\n if (!parentEff) break;\n chain.push(parentEff);\n parentId = parentEff.layer.parentId;\n }\n\n // Apply from root ancestor down to direct parent\n for (let i = chain.length - 1; i >= 0; i--) {\n const p = chain[i];\n ctx.translate(p.x, p.y);\n\n const ax = p.anchorX * p.width;\n const ay = p.anchorY * p.height;\n\n if (p.rotation !== 0 || p.scaleX !== 1 || p.scaleY !== 1) {\n ctx.translate(ax, ay);\n if (p.rotation !== 0) ctx.rotate((p.rotation * Math.PI) / 180);\n if (p.scaleX !== 1 || p.scaleY !== 1) ctx.scale(p.scaleX, p.scaleY);\n ctx.translate(-ax, -ay);\n }\n }\n}\n","/**\n * A loaded image entry that can be drawn via RenderContext.drawImage.\n */\nexport interface CachedImage {\n complete: boolean;\n image: unknown;\n}\n\n/**\n * Simple image cache for loading and caching images.\n * Browser-agnostic — the actual Image constructor is injected via createImage.\n * Triggers an onLoad callback when an image finishes loading so the\n * renderer can re-render the current frame.\n */\nexport class ImageCache {\n private cache = new Map<string, CachedImage>();\n private loading = new Set<string>();\n private onLoad?: () => void;\n private createImage?: (src: string, onLoad: () => void, onError: () => void) => unknown;\n\n constructor(opts?: {\n onLoad?: () => void;\n createImage?: (src: string, onLoad: () => void, onError: () => void) => unknown;\n }) {\n this.onLoad = opts?.onLoad;\n this.createImage = opts?.createImage;\n }\n\n get(src: string): unknown | null {\n const entry = this.cache.get(src);\n return entry?.complete ? entry.image : null;\n }\n\n load(src: string): void {\n if (this.cache.has(src) || this.loading.has(src)) return;\n if (!this.createImage) return;\n this.loading.add(src);\n const image = this.createImage(\n src,\n () => {\n this.cache.set(src, { complete: true, image });\n this.loading.delete(src);\n this.onLoad?.();\n },\n () => {\n this.loading.delete(src);\n },\n );\n }\n}\n","// @a-company/atelier-cli — CLI tool: validate, preview, render, info commands\n\n// Command registration functions (for programmatic use)\nexport { validateCommand, validateFile } from \"./commands/validate.js\";\nexport { infoCommand, getInfo } from \"./commands/info.js\";\nexport type { DocumentInfo } from \"./commands/info.js\";\nexport { stillCommand, resolveStill } from \"./commands/still.js\";\nexport { renderCommand } from \"./commands/render.js\";\nexport { exportSvgCommand } from \"./commands/export-svg.js\";\nexport { exportLottieCommand } from \"./commands/export-lottie.js\";\nexport { exportImageCommand, resolveExportDimensions } from \"./commands/export-image.js\";\nexport {\n carouselCommand,\n composeCarouselFrameDoc,\n expandInputs,\n carouselFileName,\n} from \"./commands/carousel.js\";\nexport {\n renderDocumentToPng,\n fitImageToCanvas,\n loadCanvasModule,\n CanvasUnavailableError,\n} from \"./lib/render-image.js\";\nexport { assetsCommand, getAssets } from \"./commands/assets.js\";\nexport type { AssetInfo } from \"./commands/assets.js\";\nexport { variablesCommand, getVariables } from \"./commands/variables.js\";\nexport type { VariableInfo } from \"./commands/variables.js\";\nexport {\n checkFfmpeg,\n buildFfmpegArgs,\n renderDocument,\n} from \"./commands/render-pipeline.js\";\nexport type {\n RenderFormat,\n RenderOptions,\n RenderResult,\n ProgressInfo,\n} from \"./commands/render-pipeline.js\";\n\n// VideoProject — local-first video project folder structure\nexport {\n createVideoProject,\n loadVideoProject,\n readCutList,\n writeCutList,\n readTranscript,\n writeTranscript,\n readComposition,\n writeComposition,\n rewriteCutLayers,\n effectiveSpan,\n VIDEO_PROJECT_VERSION,\n VIDEO_CUTLIST_VERSION,\n} from \"./lib/video-project.js\";\nexport type { VideoProject } from \"./lib/video-project.js\";\n\n// Silence trim — parametric cuts + atelier trim pipeline\nexport { trimCommand, trimProject } from \"./commands/trim.js\";\nexport type { TrimOptions, TrimResult } from \"./commands/trim.js\";\n\n// Transcribe — Whisper + editable transcript + caption layers\nexport { transcribeCommand, transcribeProject } from \"./commands/transcribe.js\";\nexport type { TranscribeOptions, TranscribeResult } from \"./commands/transcribe.js\";\nexport { transcriptCommand } from \"./commands/transcript.js\";\nexport { captionsCommand } from \"./commands/captions.js\";\nexport {\n buildCaptionLayers,\n rewriteCaptionLayers,\n} from \"./lib/caption-builder.js\";\nexport type { CaptionStyle, BuildCaptionsOptions } from \"./lib/caption-builder.js\";\nexport {\n flattenWords,\n groupIntoPhrases,\n mergeTranscriptWithExisting,\n applyTextEdit,\n applyBatchReplace,\n applyHide,\n applyAdd,\n applyMerge,\n applySplit,\n} from \"./lib/transcript-model.js\";\nexport {\n probeWhisper,\n runWhisperCpp,\n parseWhisperCppJson,\n} from \"./lib/whisper.js\";\nexport type { WhisperBackend, WhisperModel, WhisperOptions } from \"./lib/whisper.js\";\nexport { VIDEO_TRANSCRIPT_VERSION } from \"./lib/video-project.js\";\n\n// Studio Recipe — Phase 1\nexport { recipeCommand } from \"./commands/recipe.js\";\nexport { applyRecipeCommand } from \"./commands/apply-recipe.js\";\nexport {\n loadRecipe,\n resolveRecipePath,\n scaffoldRecipeYaml,\n applyRecipeToTrimOptions,\n applyRecipeToTranscribeOptions,\n applyRecipeToCaptionOptions,\n renderRecipeWithDefaults,\n recipeToYaml,\n RECIPE_VERSION,\n} from \"./lib/recipe.js\";\nexport type { LoadedRecipe } from \"./lib/recipe.js\";\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { validateAllDeltas } from \"@a-company/atelier-core\";\n\n/**\n * Validate an .atelier file: parse YAML, check schema, check delta overlaps.\n * Returns { valid, errors } for programmatic use.\n */\nexport function validateFile(filePath: string): {\n valid: boolean;\n errors: string[];\n} {\n const absPath = resolve(filePath);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n return { valid: false, errors: [`Cannot read file: ${absPath}`] };\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n return {\n valid: false,\n errors: result.errors.map(\n (e) => `${e.path}: ${e.message}`,\n ),\n };\n }\n\n // Check all states for delta overlaps\n const overlapErrors: string[] = [];\n for (const [stateName, state] of Object.entries(result.data.states)) {\n const overlaps = validateAllDeltas(state.deltas);\n for (const overlap of overlaps) {\n overlapErrors.push(`State \"${stateName}\": ${overlap.message}`);\n }\n }\n\n if (overlapErrors.length > 0) {\n return { valid: false, errors: overlapErrors };\n }\n\n return { valid: true, errors: [] };\n}\n\n/**\n * Register the `validate` subcommand on the Commander program.\n */\nexport function validateCommand(program: Command): void {\n program\n .command(\"validate <file>\")\n .description(\"Validate an .atelier YAML file\")\n .action((file: string) => {\n const { valid, errors } = validateFile(file);\n if (valid) {\n console.log(\"Valid\");\n } else {\n console.error(\"Validation errors:\");\n for (const error of errors) {\n console.error(` - ${error}`);\n }\n process.exit(1);\n }\n });\n}\n","import { z } from \"zod\";\n\n/** Pixel value — any number */\nexport const PixelSchema = z.number();\n\n/** Percentage string like \"50%\" */\nexport const PercentageSchema = z.string().regex(/^-?\\d+(\\.\\d+)?%$/, {\n message: \"Percentage must be a number followed by %, e.g. \\\"50%\\\"\",\n});\n\n/** Either pixel or percentage */\nexport const UnitValueSchema = z.union([PixelSchema, PercentageSchema]);\n","import { z } from \"zod\";\nimport { UnitValueSchema } from \"./units.js\";\n\nexport const FrameSchema = z.object({\n x: UnitValueSchema,\n y: UnitValueSchema,\n});\n\nexport const BoundsSchema = z.object({\n width: UnitValueSchema,\n height: UnitValueSchema,\n});\n\nexport const AnchorPointSchema = z.object({\n x: z.number().min(0).max(1),\n y: z.number().min(0).max(1),\n});\n","import { z } from \"zod\";\n\nexport const RGBAColorSchema = z.object({\n r: z.number().min(0).max(255),\n g: z.number().min(0).max(255),\n b: z.number().min(0).max(255),\n a: z.number().min(0).max(1),\n});\n\nexport const HSLAColorSchema = z.object({\n h: z.number().min(0).max(360),\n s: z.number().min(0).max(100),\n l: z.number().min(0).max(100),\n a: z.number().min(0).max(1),\n});\n\nexport const HexColorSchema = z.string().regex(/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, {\n message: \"Color must be a hex string: #RGB, #RGBA, #RRGGBB, or #RRGGBBAA\",\n});\n\nexport const ColorSchema = z.union([RGBAColorSchema, HSLAColorSchema, HexColorSchema]);\n","import { z } from \"zod\";\nimport { ColorSchema } from \"./color.js\";\nimport { UnitValueSchema } from \"./units.js\";\n\nexport const PathPointSchema = z.object({\n x: z.number(),\n y: z.number(),\n in: z.object({ x: z.number(), y: z.number() }).optional(),\n out: z.object({ x: z.number(), y: z.number() }).optional(),\n});\n\nexport const RectShapeSchema = z.object({\n type: z.literal(\"rect\"),\n cornerRadius: z.union([\n z.number().min(0),\n z.tuple([z.number().min(0), z.number().min(0), z.number().min(0), z.number().min(0)]),\n ]).optional(),\n});\n\nexport const EllipseShapeSchema = z.object({\n type: z.literal(\"ellipse\"),\n});\n\nexport const PathShapeSchema = z.object({\n type: z.literal(\"path\"),\n points: z.array(PathPointSchema).min(2, \"Path must have at least 2 points\"),\n closed: z.boolean().optional(),\n});\n\nexport const ShapeSchema = z.discriminatedUnion(\"type\", [\n RectShapeSchema,\n EllipseShapeSchema,\n PathShapeSchema,\n]);\n\nexport const GradientStopSchema = z.object({\n offset: z.number().min(0).max(1),\n color: ColorSchema,\n});\n\nexport const SolidFillSchema = z.object({\n type: z.literal(\"solid\"),\n color: ColorSchema,\n});\n\nexport const LinearGradientFillSchema = z.object({\n type: z.literal(\"linear-gradient\"),\n angle: z.number(),\n stops: z.array(GradientStopSchema).min(2, \"Gradient needs at least 2 stops\"),\n});\n\nexport const RadialGradientFillSchema = z.object({\n type: z.literal(\"radial-gradient\"),\n center: z.object({ x: UnitValueSchema, y: UnitValueSchema }),\n radius: UnitValueSchema,\n stops: z.array(GradientStopSchema).min(2, \"Gradient needs at least 2 stops\"),\n});\n\nexport const FillSchema = z.discriminatedUnion(\"type\", [\n SolidFillSchema,\n LinearGradientFillSchema,\n RadialGradientFillSchema,\n]);\n\nexport const StrokeSchema = z.object({\n color: ColorSchema,\n width: z.number().min(0),\n dash: z.array(z.number().min(0)).optional(),\n lineCap: z.enum([\"butt\", \"round\", \"square\"]).optional(),\n lineJoin: z.enum([\"miter\", \"round\", \"bevel\"]).optional(),\n strokeStart: z.number().min(0).max(1).optional(),\n strokeEnd: z.number().min(0).max(1).optional(),\n});\n\nexport const TextStyleSchema = z.object({\n fontFamily: z.string().min(1, \"fontFamily is required\"),\n fontSize: z.number().positive(\"fontSize must be positive\"),\n fontWeight: z.union([z.number(), z.enum([\"normal\", \"bold\"])]).optional(),\n fontStyle: z.enum([\"normal\", \"italic\"]).optional(),\n textAlign: z.enum([\"left\", \"center\", \"right\"]).optional(),\n lineHeight: z.number().positive().optional(),\n letterSpacing: z.number().optional(),\n color: ColorSchema,\n});\n","import { z } from \"zod\";\n\nexport const LinearEasingSchema = z.object({ type: z.literal(\"linear\") });\n\nexport const CubicBezierEasingSchema = z.object({\n type: z.literal(\"cubic-bezier\"),\n x1: z.number().min(0).max(1),\n y1: z.number(),\n x2: z.number().min(0).max(1),\n y2: z.number(),\n});\n\nexport const SpringEasingSchema = z.object({\n type: z.literal(\"spring\"),\n mass: z.number().positive().optional(),\n stiffness: z.number().positive().optional(),\n damping: z.number().positive().optional(),\n velocity: z.number().optional(),\n});\n\nexport const StepEasingSchema = z.object({\n type: z.literal(\"step\"),\n steps: z.number().int().positive(),\n position: z.enum([\"start\", \"end\"]).optional(),\n});\n\nexport const EasingPresetSchema = z.enum([\"linear\", \"ease-in\", \"ease-out\", \"ease-in-out\"]);\n\nexport const EasingSchema = z.union([\n LinearEasingSchema,\n CubicBezierEasingSchema,\n SpringEasingSchema,\n StepEasingSchema,\n EasingPresetSchema,\n]);\n","import { z } from \"zod\";\nimport { ColorSchema } from \"./color.js\";\n\nexport const ShadowSchema = z.object({\n color: ColorSchema,\n blur: z.number().min(0),\n offsetX: z.number().optional(),\n offsetY: z.number().optional(),\n});\n","import { z } from \"zod\";\nimport { ShapeSchema, FillSchema, StrokeSchema, TextStyleSchema, PathPointSchema } from \"./shape.js\";\nimport { FrameSchema, BoundsSchema, AnchorPointSchema } from \"./coordinates.js\";\nimport { ShadowSchema } from \"./shadow.js\";\nimport { InteractionSchema } from \"./interaction.js\";\n\nexport const BlendModeSchema = z.enum([\n \"normal\", \"multiply\", \"screen\", \"overlay\",\n \"darken\", \"lighten\", \"color-dodge\", \"color-burn\",\n \"hard-light\", \"soft-light\", \"difference\", \"exclusion\",\n \"hue\", \"saturation\", \"color\", \"luminosity\",\n]);\n\nexport const MotionPathSchema = z.object({\n points: z.array(PathPointSchema).min(2, \"Motion path must have at least 2 points\"),\n closed: z.boolean().optional(),\n autoRotate: z.boolean().optional(),\n autoRotateOffset: z.number().optional(),\n});\n\nexport const ShapeVisualSchema = z.object({\n type: z.literal(\"shape\"),\n shape: ShapeSchema,\n fill: FillSchema.optional(),\n stroke: StrokeSchema.optional(),\n});\n\nexport const TextVisualSchema = z.object({\n type: z.literal(\"text\"),\n content: z.string(),\n style: TextStyleSchema,\n});\n\nexport const SpritesheetConfigSchema = z.object({\n columns: z.number().int().positive(),\n rows: z.number().int().positive(),\n frameCount: z.number().int().positive().optional(),\n frameWidth: z.number().positive(),\n frameHeight: z.number().positive(),\n});\n\nexport const SourceRectSchema = z.object({\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n});\n\nexport const ImageVisualSchema = z.object({\n type: z.literal(\"image\"),\n assetId: z.string().min(1, \"assetId is required\"),\n src: z.string().optional(),\n sourceRect: SourceRectSchema.optional(),\n spritesheet: SpritesheetConfigSchema.optional(),\n frameIndex: z.number().int().min(0).optional(),\n});\n\nexport const VideoVisualSchema = z.object({\n type: z.literal(\"video\"),\n assetId: z.string().min(1, \"assetId is required\"),\n src: z.string().optional(),\n startFrame: z.number().int().min(0).optional(),\n sourceOffset: z.number().min(0).optional(),\n sourceEnd: z.number().positive().optional(),\n playbackRate: z.number().positive().optional(),\n volume: z.number().min(0).max(1).optional(),\n muted: z.boolean().optional(),\n objectFit: z.enum([\"contain\", \"cover\", \"fill\"]).optional(),\n});\n\nexport const GroupVisualSchema = z.object({\n type: z.literal(\"group\"),\n});\n\nexport const RefVisualSchema = z.object({\n type: z.literal(\"ref\"),\n src: z.string().min(1, \"src is required\"),\n state: z.string().optional(),\n frame: z.number().int().min(0).optional(),\n});\n\nexport const VisualSchema = z.discriminatedUnion(\"type\", [\n ShapeVisualSchema,\n TextVisualSchema,\n ImageVisualSchema,\n VideoVisualSchema,\n GroupVisualSchema,\n RefVisualSchema,\n]);\n\nexport const LayerSchema = z.object({\n id: z.string().min(1, \"Layer id is required\"),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n visual: VisualSchema,\n frame: FrameSchema,\n bounds: BoundsSchema,\n anchorPoint: AnchorPointSchema.optional(),\n parentId: z.string().optional(),\n opacity: z.number().min(0).max(1).optional(),\n rotation: z.number().optional(),\n scale: z.object({ x: z.number(), y: z.number() }).optional(),\n visible: z.boolean().optional(),\n shadow: ShadowSchema.optional(),\n blendMode: BlendModeSchema.optional(),\n motionPath: MotionPathSchema.optional(),\n clipPath: ShapeSchema.optional(),\n tint: z.object({\n color: z.string(),\n amount: z.number().min(0).max(1),\n }).optional(),\n interactions: z.array(InteractionSchema).optional(),\n});\n","import { z } from \"zod\";\n\nexport const TriggerTypeSchema = z.enum([\n \"click\", \"hover\", \"pointerdown\", \"pointerup\", \"timer\", \"signal\",\n]);\n\nexport const TriggerSchema = z.object({\n type: TriggerTypeSchema,\n delay: z.number().nonnegative(\"Timer delay must be non-negative\").optional(),\n signal: z.string().optional(),\n}).refine(\n (t) => t.type !== \"timer\" || t.delay !== undefined,\n { message: \"Timer trigger requires a delay\" },\n).refine(\n (t) => t.type !== \"signal\" || t.signal !== undefined,\n { message: \"Signal trigger requires a signal name\" },\n);\n\nexport const ActionTypeSchema = z.enum([\n \"go-to-state\", \"emit-signal\", \"set-variable\", \"toggle-visibility\",\n]);\n\nexport const ActionSchema = z.object({\n type: ActionTypeSchema,\n state: z.string().optional(),\n signal: z.string().optional(),\n variable: z.string().optional(),\n value: z.unknown().optional(),\n targetLayer: z.string().optional(),\n}).refine(\n (a) => a.type !== \"go-to-state\" || a.state !== undefined,\n { message: \"go-to-state action requires a state name\" },\n).refine(\n (a) => a.type !== \"emit-signal\" || a.signal !== undefined,\n { message: \"emit-signal action requires a signal name\" },\n).refine(\n (a) => a.type !== \"set-variable\" || (a.variable !== undefined && a.value !== undefined),\n { message: \"set-variable action requires variable and value\" },\n);\n\nexport const InteractionSchema = z.object({\n id: z.string().min(1, \"Interaction id is required\"),\n trigger: TriggerSchema,\n action: ActionSchema,\n description: z.string().optional(),\n});\n","import { z } from \"zod\";\nimport { EasingSchema } from \"./easing.js\";\n\nexport const AnimatablePropertySchema = z.enum([\n \"frame.x\",\n \"frame.y\",\n \"bounds.width\",\n \"bounds.height\",\n \"opacity\",\n \"rotation\",\n \"scale.x\",\n \"scale.y\",\n \"anchorPoint.x\",\n \"anchorPoint.y\",\n \"visual.shape.cornerRadius\",\n \"visual.fill.color\",\n \"visual.stroke.color\",\n \"visual.stroke.width\",\n \"visual.stroke.start\",\n \"visual.stroke.end\",\n \"visual.style.fontSize\",\n \"visual.style.color\",\n \"shadow.color\",\n \"shadow.blur\",\n \"shadow.offsetX\",\n \"shadow.offsetY\",\n \"motionPath.progress\",\n \"visual.fill.angle\",\n \"visual.fill.center.x\",\n \"visual.fill.center.y\",\n \"visual.fill.radius\",\n \"visual.image.sourceRect.x\",\n \"visual.image.sourceRect.y\",\n \"visual.image.sourceRect.width\",\n \"visual.image.sourceRect.height\",\n \"visual.image.frameIndex\",\n \"visible\",\n \"tint.color\",\n \"tint.amount\",\n]);\n\nexport const FrameRangeSchema = z.tuple([\n z.number().int().min(0, \"Frame start must be >= 0\"),\n z.number().int().min(0, \"Frame end must be >= 0\"),\n]).refine(([start, end]) => end >= start, {\n message: \"Frame range end must be >= start\",\n});\n\nexport const DeltaSchema = z.object({\n id: z.string().optional(),\n name: z.string().optional(),\n layer: z.string().min(1, \"Delta must reference a layer id\"),\n property: AnimatablePropertySchema,\n range: FrameRangeSchema,\n from: z.unknown(),\n to: z.unknown(),\n easing: EasingSchema.optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n});\n","import { z } from \"zod\";\nimport { DeltaSchema } from \"./delta.js\";\nimport { EasingSchema } from \"./easing.js\";\n\nexport const AudioSchema = z.object({\n src: z.string().min(1, \"Audio src is required\"),\n offset: z.number().min(0, \"Audio offset must be non-negative\").optional(),\n volume: z.number().min(0).max(1, \"Audio volume must be 0–1\").optional(),\n loop: z.boolean().optional(),\n startFrame: z.number().int().min(0, \"Audio startFrame must be a non-negative integer\").optional(),\n});\n\nexport const StateTransitionConfigSchema = z.object({\n duration: z.number().int().positive(\"Transition duration must be a positive integer (frames)\"),\n easing: EasingSchema.optional(),\n});\n\nexport const StateSchema = z.object({\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n parent: z.string().optional(),\n duration: z.number().int().positive(\"State duration must be a positive integer (frames)\"),\n deltas: z.array(DeltaSchema),\n audio: AudioSchema.optional(),\n transitions: z.record(z.string(), StateTransitionConfigSchema).optional(),\n});\n","import { z } from \"zod\";\nimport { AnimatablePropertySchema } from \"./delta.js\";\nimport { EasingSchema } from \"./easing.js\";\n\nexport const PresetDeltaSchema = z.object({\n property: AnimatablePropertySchema,\n offset: z.tuple([z.number().int().min(0), z.number().int().min(0)]).optional(),\n from: z.unknown(),\n to: z.unknown(),\n easing: EasingSchema.optional(),\n});\n\nexport const PresetSchema = z.object({\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n deltas: z.array(PresetDeltaSchema).min(1, \"Preset must have at least one delta\"),\n});\n","import { z } from \"zod\";\n\nexport const VariableTypeSchema = z.enum([\"string\", \"number\", \"color\", \"asset\", \"boolean\"]);\n\nexport const VariableSchema = z.object({\n type: VariableTypeSchema,\n default: z.unknown().optional(),\n description: z.string().optional(),\n});\n","import { z } from \"zod\";\n\nexport const AssetTypeSchema = z.enum([\"image\", \"svg\", \"font\", \"animation\", \"audio\", \"video\"]);\n\nexport const AssetSchema = z.object({\n type: AssetTypeSchema,\n src: z.string().min(1, \"Asset src is required\"),\n description: z.string().optional(),\n spritesheet: z.object({\n columns: z.number().int().positive(),\n rows: z.number().int().positive(),\n frameCount: z.number().int().positive().optional(),\n frameWidth: z.number().positive(),\n frameHeight: z.number().positive(),\n }).optional(),\n videoMeta: z.object({\n duration: z.number().positive(\"videoMeta.duration must be positive\"),\n fps: z.number().positive(\"videoMeta.fps must be positive\"),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n }).optional(),\n});\n","import { z } from \"zod\";\nimport { LayerSchema } from \"./layer.js\";\nimport { StateSchema } from \"./state.js\";\nimport { PresetSchema } from \"./preset.js\";\nimport { VariableSchema } from \"./variable.js\";\nimport { AssetSchema } from \"./asset.js\";\n\nexport const CanvasSchema = z.object({\n width: z.number().int().positive(\"Canvas width must be a positive integer\"),\n height: z.number().int().positive(\"Canvas height must be a positive integer\"),\n fps: z.number().int().positive(\"FPS must be a positive integer\"),\n background: z.string().optional(),\n});\n\nexport const AtelierDocumentSchema = z.object({\n version: z.string().min(1, \"Version is required\"),\n name: z.string().min(1, \"Animation name is required\"),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n canvas: CanvasSchema,\n variables: z.record(z.string(), VariableSchema).optional(),\n assets: z.record(z.string(), AssetSchema).optional(),\n presets: z.record(z.string(), PresetSchema).optional(),\n layers: z.array(LayerSchema),\n states: z.record(z.string(), StateSchema),\n});\n","import { z } from \"zod\";\n\n/** Silence-trim policy block */\nexport const SilencePolicySchema = z.object({\n noise: z.string().optional(),\n min_silence: z.number().nonnegative().optional(),\n default_padding_pre: z.number().nonnegative().optional(),\n default_padding_post: z.number().nonnegative().optional(),\n match_tolerance: z.number().nonnegative().optional(),\n}).strict();\n\n/** Caption visual style block */\nexport const CaptionStyleSchema = z.object({\n font_family: z.string().optional(),\n font_size: z.number().positive().optional(),\n font_weight: z.union([z.literal(\"normal\"), z.literal(\"bold\"), z.number()]).optional(),\n text_align: z.enum([\"left\", \"center\", \"right\"]).optional(),\n color: z.string().optional(),\n y_ratio: z.number().min(0).max(1).optional(),\n width_ratio: z.number().min(0).max(1).optional(),\n fade_seconds: z.number().nonnegative().optional(),\n}).strict();\n\n/** Caption phrase grouping block */\nexport const CaptionGroupingSchema = z.object({\n max_words: z.number().int().positive().optional(),\n pause_gap: z.number().nonnegative().optional(),\n}).strict();\n\n/** Anchor enum shared by every overlay sub-rule */\nexport const OverlayAnchorSchema = z.enum([\n \"top-left\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-right\",\n]);\n\n/** Visual subset for overlay text — recipe snake_case convention */\nexport const OverlayTextStyleSchema = z.object({\n font_family: z.string().optional(),\n font_size: z.number().positive().optional(),\n font_weight: z.union([z.literal(\"normal\"), z.literal(\"bold\"), z.number()]).optional(),\n color: z.string().optional(),\n}).strict();\n\n/**\n * Validate a page-number format template:\n * - braces must balance\n * - every {…} group must match (current|total)(:0Nd)? (zero-pad form)\n * - at least one of {current} / {total} must appear\n *\n * Render-time substitution is a separate concern; this only validates syntax.\n */\nfunction validatePageNumberFormat(\n format: string,\n ctx: z.RefinementCtx,\n): void {\n if (format.length === 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"format must be a non-empty string\",\n });\n return;\n }\n\n const open = (format.match(/\\{/g) ?? []).length;\n const close = (format.match(/\\}/g) ?? []).length;\n if (open !== close) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `format has unbalanced braces (${open} '{' vs ${close} '}')`,\n });\n return;\n }\n\n const groupRe = /\\{([^{}]*)\\}/g;\n const groupRule = /^(current|total)(:0\\d+d)?$/;\n let m: RegExpExecArray | null;\n let sawCurrent = false;\n let sawTotal = false;\n while ((m = groupRe.exec(format)) !== null) {\n const inner = m[1];\n if (!groupRule.test(inner)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `format placeholder \"{${inner}}\" is not recognized — expected {current}, {total}, {current:0Nd}, or {total:0Nd}`,\n });\n return;\n }\n if (inner.startsWith(\"current\")) sawCurrent = true;\n if (inner.startsWith(\"total\")) sawTotal = true;\n }\n\n if (!sawCurrent && !sawTotal) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"format must contain at least one {current} or {total} placeholder\",\n });\n }\n}\n\n/** Handle overlay rule schema — anchored creator-handle text */\nexport const OverlayHandleRuleSchema = z.object({\n text: z.string().min(1),\n anchor: OverlayAnchorSchema,\n margin: z.number().nonnegative().optional(),\n style: OverlayTextStyleSchema.optional(),\n}).strict();\n\n/** Page-number overlay rule schema — anchored \"1/5\"-style indicator */\nexport const OverlayPageNumberRuleSchema = z.object({\n format: z.string().superRefine(validatePageNumberFormat),\n anchor: OverlayAnchorSchema,\n margin: z.number().nonnegative().optional(),\n style: OverlayTextStyleSchema.optional(),\n}).strict();\n\n/** Overlay rules block (Phase 1.5) — both sub-blocks optional */\nexport const OverlayRulesSchema = z.object({\n handle: OverlayHandleRuleSchema.optional(),\n page_number: OverlayPageNumberRuleSchema.optional(),\n}).strict();\n\n/**\n * StudioRecipe — top-level. Reserved fields (caption_highlight, transition_kit,\n * etc.) still accept any shape; Phase 3 will refine them. Validate-time warnings\n * surface reserved-fields-in-use to authors so they aren't caught off-guard\n * when those sections become load-bearing.\n *\n * overlay_rules was promoted from reserved Phase 3 to first-class Phase 1.5.\n */\nexport const StudioRecipeSchema = z.object({\n version: z.string(),\n name: z.string(),\n description: z.string().optional(),\n author: z.string().optional(),\n tags: z.array(z.string()).optional(),\n\n silence_policy: SilencePolicySchema.optional(),\n caption_style: CaptionStyleSchema.optional(),\n caption_grouping: CaptionGroupingSchema.optional(),\n\n // Phase 1.5 — first-class overlay rules\n overlay_rules: OverlayRulesSchema.optional(),\n\n // Reserved — Phase 3 (parse-opaque)\n caption_highlight: z.unknown().optional(),\n transition_kit: z.unknown().optional(),\n palette: z.unknown().optional(),\n audio_policy: z.unknown().optional(),\n aspect_targets: z.array(z.unknown()).optional(),\n}).strict();\n\n/** Names of still-reserved fields — used by validators to emit forward-compat warnings */\nexport const RESERVED_RECIPE_FIELDS = [\n \"caption_highlight\",\n \"transition_kit\",\n \"palette\",\n \"audio_policy\",\n \"aspect_targets\",\n] as const;\n","import type { AtelierDocument, Layer, Delta, VideoVisual, StudioRecipe } from \"@a-company/atelier-types\";\nimport { AtelierDocumentSchema } from \"./document.js\";\nimport { LayerSchema } from \"./layer.js\";\nimport { DeltaSchema } from \"./delta.js\";\nimport { StudioRecipeSchema, RESERVED_RECIPE_FIELDS } from \"./recipe.js\";\nimport type { z } from \"zod\";\n\n/** Validation result — either success with typed data or failure with readable errors */\nexport type ValidationResult<T> =\n | { success: true; data: T }\n | { success: false; errors: ValidationError[] };\n\nexport interface ValidationError {\n path: string;\n message: string;\n}\n\n/** Format Zod errors into flat, AI-readable error messages */\nfunction formatErrors(error: z.ZodError): ValidationError[] {\n return error.issues.map((issue) => ({\n path: issue.path.join(\".\") || \"(root)\",\n message: issue.message,\n }));\n}\n\n/** Validate a complete AtelierDocument */\nexport function validateDocument(input: unknown): ValidationResult<AtelierDocument> {\n const result = AtelierDocumentSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data as AtelierDocument };\n }\n return { success: false, errors: formatErrors(result.error) };\n}\n\n/** Validate a single Layer */\nexport function validateLayer(input: unknown): ValidationResult<Layer> {\n const result = LayerSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data as Layer };\n }\n return { success: false, errors: formatErrors(result.error) };\n}\n\n/** Validate a single Delta */\nexport function validateDelta(input: unknown): ValidationResult<Delta> {\n const result = DeltaSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data as Delta };\n }\n return { success: false, errors: formatErrors(result.error) };\n}\n\n/**\n * Validate a VideoVisual layer against semantic constraints (^valid-video-layer gate).\n * Checks beyond Zod: sourceEnd > sourceOffset, sourceEnd ≤ videoMeta.duration.\n */\nexport function validateVideoLayer(\n visual: VideoVisual,\n videoMetaDuration?: number,\n): ValidationResult<VideoVisual> {\n const errors: ValidationError[] = [];\n\n if (!visual.assetId) {\n errors.push({ path: \"assetId\", message: \"assetId is required\" });\n }\n\n const sourceOffset = visual.sourceOffset ?? 0;\n if (visual.sourceEnd !== undefined) {\n if (visual.sourceEnd <= sourceOffset) {\n errors.push({\n path: \"sourceEnd\",\n message: `sourceEnd (${visual.sourceEnd}) must be greater than sourceOffset (${sourceOffset})`,\n });\n }\n if (videoMetaDuration !== undefined && visual.sourceEnd > videoMetaDuration) {\n errors.push({\n path: \"sourceEnd\",\n message: `sourceEnd (${visual.sourceEnd}) exceeds asset duration (${videoMetaDuration})`,\n });\n }\n }\n\n if (videoMetaDuration !== undefined && sourceOffset >= videoMetaDuration) {\n errors.push({\n path: \"sourceOffset\",\n message: `sourceOffset (${sourceOffset}) is at or beyond asset duration (${videoMetaDuration})`,\n });\n }\n\n if (errors.length > 0) return { success: false, errors };\n return { success: true, data: visual };\n}\n\n/**\n * Validate a StudioRecipe against the schema (^valid-recipe gate).\n * Returns success with the parsed recipe and optional warnings about\n * reserved-but-unimplemented Phase 3 fields that are present.\n */\nexport function validateRecipe(\n recipe: unknown,\n): ValidationResult<StudioRecipe> & { warnings?: string[] } {\n const parsed = StudioRecipeSchema.safeParse(recipe);\n if (!parsed.success) {\n return { success: false, errors: formatErrors(parsed.error) };\n }\n\n const warnings: string[] = [];\n const data = parsed.data as StudioRecipe;\n for (const field of RESERVED_RECIPE_FIELDS) {\n if (data[field] !== undefined) {\n warnings.push(\n `${field} is reserved for Phase 3 and currently has no effect.`,\n );\n }\n }\n\n return { success: true, data, ...(warnings.length > 0 && { warnings }) };\n}\n","import { parse as yamlParse, stringify as yamlStringify } from \"yaml\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { validateDocument } from \"./validate.js\";\nimport type { ValidationResult } from \"./validate.js\";\n\n/**\n * Parse a YAML string into a validated AtelierDocument.\n * Returns validation errors if the YAML is invalid or doesn't match the schema.\n */\nexport function parseAtelier(yamlString: string): ValidationResult<AtelierDocument> {\n let parsed: unknown;\n try {\n parsed = yamlParse(yamlString);\n } catch (err) {\n return {\n success: false,\n errors: [{ path: \"(yaml)\", message: `YAML parse error: ${(err as Error).message}` }],\n };\n }\n return validateDocument(parsed);\n}\n\n/**\n * Serialize an AtelierDocument to YAML string.\n */\nexport function serializeAtelier(doc: AtelierDocument): string {\n return yamlStringify(doc, { indent: 2 });\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\n\n/**\n * Info summary for an AtelierDocument.\n */\nexport interface DocumentInfo {\n name: string;\n description?: string;\n canvas: {\n width: number;\n height: number;\n fps: number;\n background?: string;\n };\n layers: {\n count: number;\n items: { id: string; type: string }[];\n };\n states: {\n count: number;\n items: { name: string; duration: number; deltaCount: number }[];\n };\n presets: {\n count: number;\n };\n}\n\n/**\n * Extract summary info from a parsed AtelierDocument.\n */\nexport function getInfo(doc: AtelierDocument): DocumentInfo {\n return {\n name: doc.name,\n description: doc.description,\n canvas: {\n width: doc.canvas.width,\n height: doc.canvas.height,\n fps: doc.canvas.fps,\n background: doc.canvas.background,\n },\n layers: {\n count: doc.layers.length,\n items: doc.layers.map((layer) => ({\n id: layer.id,\n type: layer.visual.type,\n })),\n },\n states: {\n count: Object.keys(doc.states).length,\n items: Object.entries(doc.states).map(([name, state]) => ({\n name,\n duration: state.duration,\n deltaCount: state.deltas.length,\n })),\n },\n presets: {\n count: doc.presets ? Object.keys(doc.presets).length : 0,\n },\n };\n}\n\n/**\n * Format a DocumentInfo for terminal output.\n */\nfunction formatInfo(info: DocumentInfo): string {\n const lines: string[] = [];\n\n lines.push(`Name: ${info.name}`);\n if (info.description) {\n lines.push(`Description: ${info.description}`);\n }\n\n const bg = info.canvas.background\n ? `, background: ${info.canvas.background}`\n : \"\";\n lines.push(\n `Canvas: ${info.canvas.width}x${info.canvas.height} @ ${info.canvas.fps}fps${bg}`,\n );\n\n lines.push(`Layers: ${info.layers.count}`);\n for (const layer of info.layers.items) {\n lines.push(` - ${layer.id} (${layer.type})`);\n }\n\n lines.push(`States: ${info.states.count}`);\n for (const state of info.states.items) {\n lines.push(\n ` - ${state.name}: ${state.duration} frames, ${state.deltaCount} deltas`,\n );\n }\n\n if (info.presets.count > 0) {\n lines.push(`Presets: ${info.presets.count}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `info` subcommand on the Commander program.\n */\nexport function infoCommand(program: Command): void {\n program\n .command(\"info <file>\")\n .description(\"Display summary info for an .atelier file\")\n .action((file: string) => {\n const doc = readAndParse(file);\n const info = getInfo(doc);\n console.log(formatInfo(info));\n });\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { resolveFrame } from \"@a-company/atelier-core\";\nimport type { ResolvedFrame } from \"@a-company/atelier-core\";\n\n/**\n * Resolve a single frame from a document, returning the resolved frame data.\n * If stateName is not provided, uses the first state.\n * If frame is not provided, uses frame 0.\n */\nexport function resolveStill(\n doc: AtelierDocument,\n stateName?: string,\n frame?: number,\n): ResolvedFrame {\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) {\n throw new Error(\"Document has no states\");\n }\n\n const resolvedStateName = stateName ?? stateNames[0];\n if (!(resolvedStateName in doc.states)) {\n throw new Error(\n `State \"${resolvedStateName}\" not found. Available: ${stateNames.join(\", \")}`,\n );\n }\n\n const resolvedFrame = frame ?? 0;\n return resolveFrame(doc, resolvedStateName, resolvedFrame);\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `still` subcommand on the Commander program.\n */\nexport function stillCommand(program: Command): void {\n program\n .command(\"still <file>\")\n .description(\n \"Resolve a single frame and output as JSON or render as PNG\",\n )\n .option(\"-s, --state <name>\", \"State name (defaults to first state)\")\n .option(\n \"-f, --frame <number>\",\n \"Frame number (defaults to 0)\",\n \"0\",\n )\n .option(\n \"--format <type>\",\n \"Output format: json | png (default: json)\",\n \"json\",\n )\n .option(\"-o, --output <path>\", \"Output file path (default: stdout)\")\n .action(\n async (\n file: string,\n options: { state?: string; frame: string; format: string; output?: string },\n ) => {\n const doc = readAndParse(file);\n\n const frameNumber = parseInt(options.frame, 10);\n if (isNaN(frameNumber) || frameNumber < 0) {\n console.error(\n `Invalid frame number: ${options.frame}`,\n );\n process.exit(1);\n return;\n }\n\n if (options.format !== \"json\" && options.format !== \"png\") {\n console.error(`Unknown format: \"${options.format}\". Use json or png.`);\n process.exit(1);\n return;\n }\n\n try {\n const resolved = resolveStill(\n doc,\n options.state,\n frameNumber,\n );\n\n if (options.format === \"json\") {\n const json = JSON.stringify(resolved, null, 2);\n if (options.output) {\n writeFileSync(resolve(options.output), json, \"utf-8\");\n } else {\n console.log(json);\n }\n } else {\n // PNG format — rasterize via @napi-rs/canvas (prebuilt platform\n // binaries; no node-gyp / system libraries, so PNG output works on\n // a plain install).\n const { createCanvas } = await import(\"@napi-rs/canvas\");\n const { renderFrame } = await import(\"@a-company/atelier-canvas\");\n\n const cvs = createCanvas(doc.canvas.width, doc.canvas.height);\n const ctx = cvs.getContext(\"2d\");\n renderFrame(ctx as unknown as import(\"@a-company/atelier-canvas\").RenderContext, resolved, doc);\n\n const buffer = cvs.toBuffer(\"image/png\");\n if (options.output) {\n writeFileSync(resolve(options.output), buffer);\n } else {\n process.stdout.write(buffer);\n }\n }\n } catch (err) {\n console.error(\n (err as Error).message,\n );\n process.exit(1);\n }\n },\n );\n}\n","/**\n * `atelier render <file>` — render an animation to MP4 or GIF via FFmpeg.\n *\n * Usage:\n * atelier render animation.atelier → animation.mp4\n * atelier render animation.atelier -f gif → animation.gif\n * atelier render animation.atelier -o out/video.mp4 → custom path\n * atelier render animation.atelier -s intro outro → specific states\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { resolve, basename, extname } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport {\n checkFfmpeg,\n renderDocument,\n type RenderFormat,\n} from \"./render-pipeline.js\";\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\nfunction inferFormat(output: string | undefined): RenderFormat {\n if (!output) return \"mp4\";\n const ext = extname(output).toLowerCase();\n if (ext === \".gif\") return \"gif\";\n return \"mp4\";\n}\n\n/** Register the `render` subcommand on the Commander program. */\nexport function renderCommand(program: Command): void {\n program\n .command(\"render <file>\")\n .description(\"Render animation to MP4 or GIF via FFmpeg\")\n .option(\"-o, --output <path>\", \"Output file path\")\n .option(\"-f, --format <type>\", \"Output format: mp4 | gif\")\n .option(\n \"-s, --state <names...>\",\n \"State(s) to render (default: all in order)\",\n )\n .action(\n async (\n file: string,\n options: {\n output?: string;\n format?: string;\n state?: string[];\n },\n ) => {\n // Check FFmpeg availability\n const hasFfmpeg = await checkFfmpeg();\n if (!hasFfmpeg) {\n console.error(\"FFmpeg is not installed or not in PATH.\");\n console.error(\"Install it:\");\n console.error(\" macOS: brew install ffmpeg\");\n console.error(\" Ubuntu: sudo apt install ffmpeg\");\n console.error(\" Windows: https://ffmpeg.org/download.html\");\n process.exit(1);\n return;\n }\n\n const doc = readAndParse(file);\n\n // Resolve format\n let format: RenderFormat;\n if (options.format) {\n if (options.format !== \"mp4\" && options.format !== \"gif\") {\n console.error(\n `Unknown format: \"${options.format}\". Use mp4 or gif.`,\n );\n process.exit(1);\n return;\n }\n format = options.format;\n } else {\n format = inferFormat(options.output);\n }\n\n // Resolve output path\n const inputName = basename(file, extname(file));\n const output = options.output ?? `${inputName}.${format}`;\n\n const startTime = Date.now();\n\n try {\n const result = await renderDocument(doc, {\n output: resolve(output),\n format,\n states: options.state,\n onProgress: ({ frame, totalFrames, state, percent }) => {\n const elapsed = (Date.now() - startTime) / 1000;\n const rate = elapsed > 0 ? frame / elapsed : 0;\n const remaining =\n rate > 0 ? (totalFrames - frame) / rate : 0;\n process.stderr.write(\n `\\rRendering: frame ${frame}/${totalFrames} (${percent}%) - state \"${state}\" - ETA ${remaining.toFixed(1)}s`,\n );\n },\n });\n\n process.stderr.write(\"\\n\");\n console.log(\n `Done: ${result.totalFrames} frames \\u2192 ${result.output} (${(result.durationMs / 1000).toFixed(1)}s)`,\n );\n } catch (err) {\n process.stderr.write(\"\\n\");\n console.error((err as Error).message);\n process.exit(1);\n }\n },\n );\n}\n","/**\n * Core render pipeline — renders an Atelier document to MP4 or GIF via FFmpeg.\n * Pure pipeline with no Commander dependency; testable in isolation.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { resolveFrame } from \"@a-company/atelier-core\";\nimport { renderFrame, ImageCache } from \"@a-company/atelier-canvas\";\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport type RenderFormat = \"mp4\" | \"gif\";\n\nexport interface RenderOptions {\n output: string;\n format: RenderFormat;\n states?: string[];\n onProgress?: (info: ProgressInfo) => void;\n}\n\nexport interface ProgressInfo {\n frame: number;\n totalFrames: number;\n state: string;\n percent: number;\n}\n\nexport interface RenderResult {\n output: string;\n format: RenderFormat;\n totalFrames: number;\n states: string[];\n durationMs: number;\n}\n\n// ─── FFmpeg Helpers ──────────────────────────────────────────\n\n/** Check whether FFmpeg is available on the system PATH. */\nexport async function checkFfmpeg(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"ffmpeg\", [\"-version\"], { stdio: \"pipe\" });\n proc.on(\"error\", () => resolve(false));\n proc.on(\"close\", (code) => resolve(code === 0));\n });\n}\n\n/** Build the FFmpeg argument array for the given format. Pure function. */\nexport function buildFfmpegArgs(\n width: number,\n height: number,\n fps: number,\n format: RenderFormat,\n output: string,\n): string[] {\n const input = [\n \"-y\",\n \"-f\", \"rawvideo\",\n \"-pix_fmt\", \"bgra\",\n \"-s\", `${width}x${height}`,\n \"-r\", String(fps),\n \"-i\", \"pipe:0\",\n ];\n\n if (format === \"mp4\") {\n return [\n ...input,\n \"-c:v\", \"libx264\",\n \"-pix_fmt\", \"yuv420p\",\n \"-preset\", \"medium\",\n \"-crf\", \"18\",\n \"-movflags\", \"+faststart\",\n output,\n ];\n }\n\n // GIF — single-pass palette generation (stdin-compatible)\n return [\n ...input,\n \"-vf\", \"split[s0][s1];[s0]palettegen=stats_mode=single[p];[s1][p]paletteuse=dither=sierra2_4a\",\n \"-loop\", \"0\",\n output,\n ];\n}\n\n// ─── Image Pre-loading ───────────────────────────────────────\n\n/**\n * Scan document layers for image visuals, pre-load them with node-canvas\n * loadImage, and return a populated ImageCache ready for rendering.\n */\nasync function preloadImages(\n doc: AtelierDocument,\n loadImage: (src: string) => Promise<unknown>,\n): Promise<ImageCache> {\n const sources = new Set<string>();\n\n for (const layer of doc.layers) {\n if (layer.visual.type === \"image\") {\n const iv = layer.visual as { src?: string; assetId?: string };\n if (iv.src) {\n sources.add(iv.src);\n } else if (iv.assetId && doc.assets?.[iv.assetId]) {\n sources.add(doc.assets[iv.assetId].src);\n }\n }\n }\n\n if (sources.size === 0) {\n return new ImageCache();\n }\n\n // Load all images in parallel\n const preloaded = new Map<string, unknown>();\n await Promise.all(\n [...sources].map(async (src) => {\n try {\n preloaded.set(src, await loadImage(src));\n } catch {\n // Images that fail to load will render as blank\n }\n }),\n );\n\n // Create ImageCache pre-populated with loaded images.\n // createImage returns the pre-loaded image and fires onLoad on next tick\n // so that the ImageCache internal `image` variable is assigned first.\n const imageCache = new ImageCache({\n createImage: (src, onLoad, onError) => {\n const img = preloaded.get(src);\n if (img) {\n process.nextTick(onLoad);\n return img;\n }\n process.nextTick(onError);\n return {};\n },\n });\n\n for (const src of preloaded.keys()) {\n imageCache.load(src);\n }\n\n // Wait for nextTick callbacks to populate the cache\n await new Promise<void>((resolve) => process.nextTick(resolve));\n\n return imageCache;\n}\n\n// ─── Main Render Loop ────────────────────────────────────────\n\n/**\n * Render an Atelier document to a video/GIF file via FFmpeg.\n * Dynamically imports `canvas` (node-canvas) — fails with a helpful\n * message if the native dependency is not installed.\n */\nexport async function renderDocument(\n doc: AtelierDocument,\n opts: RenderOptions,\n): Promise<RenderResult> {\n // Dynamic import — canvas requires native compilation.\n // Use a variable to avoid TypeScript resolving the module at compile time.\n const canvasModuleName = \"canvas\";\n let createCanvas: (w: number, h: number) => unknown;\n let loadImage: (src: string) => Promise<unknown>;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const canvasModule = await import(/* webpackIgnore: true */ canvasModuleName);\n createCanvas = canvasModule.createCanvas;\n loadImage = canvasModule.loadImage;\n } catch {\n throw new Error(\n \"The 'canvas' package is not installed.\\n\" +\n \"Install it with:\\n\" +\n \" npm install canvas\\n\" +\n \"Prerequisites vary by OS:\\n\" +\n \" macOS: brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman\\n\" +\n \" Ubuntu: sudo apt install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev\\n\" +\n \"See: https://github.com/Automattic/node-canvas#compiling\",\n );\n }\n\n const { width, height, fps } = doc.canvas;\n const { output, format, states, onProgress } = opts;\n\n // H.264 requires even dimensions\n if (format === \"mp4\" && (width % 2 !== 0 || height % 2 !== 0)) {\n throw new Error(\n `H.264 requires even dimensions. Canvas is ${width}\\u00d7${height}. ` +\n `Try ${width + (width % 2)}\\u00d7${height + (height % 2)}.`,\n );\n }\n\n // Resolve which states to render\n const allStates = Object.keys(doc.states);\n const renderStates = states ?? allStates;\n for (const s of renderStates) {\n if (!(s in doc.states)) {\n throw new Error(\n `State \"${s}\" not found. Available: ${allStates.join(\", \")}`,\n );\n }\n }\n\n // Total frame count across all states\n let totalFrames = 0;\n for (const s of renderStates) {\n totalFrames += doc.states[s].duration;\n }\n\n if (totalFrames === 0) {\n throw new Error(\"Nothing to render \\u2014 all states have duration 0\");\n }\n\n // Pre-load images before the render loop\n const imageCache = await preloadImages(doc, loadImage);\n\n // Create node-canvas\n const canvas = createCanvas(width, height) as { getContext(id: \"2d\"): unknown; toBuffer(format: \"raw\"): Buffer };\n const ctx = canvas.getContext(\"2d\");\n\n // Spawn FFmpeg\n const ffmpegArgs = buildFfmpegArgs(width, height, fps, format, output);\n const ffmpeg = spawn(\"ffmpeg\", ffmpegArgs, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n let stderrOutput = \"\";\n ffmpeg.stderr?.on(\"data\", (chunk: Buffer) => {\n stderrOutput += chunk.toString();\n });\n\n const startTime = Date.now();\n let frameIndex = 0;\n\n for (const stateName of renderStates) {\n const duration = doc.states[stateName].duration;\n for (let f = 0; f < duration; f++) {\n const resolved = resolveFrame(doc, stateName, f);\n renderFrame(ctx as never, resolved, doc, imageCache);\n\n const raw = canvas.toBuffer(\"raw\");\n const canWrite = ffmpeg.stdin!.write(raw);\n if (!canWrite) {\n await new Promise<void>((resolve) =>\n ffmpeg.stdin!.once(\"drain\", resolve),\n );\n }\n\n frameIndex++;\n onProgress?.({\n frame: frameIndex,\n totalFrames,\n state: stateName,\n percent: Math.round((frameIndex / totalFrames) * 100),\n });\n }\n }\n\n // Close stdin and wait for FFmpeg to exit\n ffmpeg.stdin!.end();\n\n const exitCode = await new Promise<number | null>((resolve) => {\n ffmpeg.on(\"close\", resolve);\n });\n\n if (exitCode !== 0) {\n throw new Error(\n `FFmpeg exited with code ${exitCode}.\\n${stderrOutput.slice(-500)}`,\n );\n }\n\n return {\n output,\n format,\n totalFrames,\n states: renderStates,\n durationMs: Date.now() - startTime,\n };\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { renderFrameSVG } from \"@a-company/atelier-svg\";\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/** Register the `export-svg` subcommand on the Commander program. */\nexport function exportSvgCommand(program: Command): void {\n program\n .command(\"export-svg <file>\")\n .description(\"Export a frame as SVG\")\n .option(\"-s, --state <name>\", \"State name (defaults to first state)\")\n .option(\"-f, --frame <number>\", \"Frame number (defaults to 0)\", \"0\")\n .option(\"-o, --output <path>\", \"Output file path (default: stdout)\")\n .option(\"--xml-declaration\", \"Include XML declaration\")\n .action(\n (\n file: string,\n options: { state?: string; frame: string; output?: string; xmlDeclaration?: boolean },\n ) => {\n const doc = readAndParse(file);\n\n const frameNumber = parseInt(options.frame, 10);\n if (isNaN(frameNumber) || frameNumber < 0) {\n console.error(`Invalid frame number: ${options.frame}`);\n process.exit(1);\n return;\n }\n\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) {\n console.error(\"Document has no states\");\n process.exit(1);\n return;\n }\n\n const stateName = options.state ?? stateNames[0];\n if (!doc.states[stateName]) {\n console.error(`State \"${stateName}\" not found. Available: ${stateNames.join(\", \")}`);\n process.exit(1);\n return;\n }\n\n try {\n const svg = renderFrameSVG(doc, stateName, frameNumber, {\n xmlDeclaration: options.xmlDeclaration,\n });\n\n if (options.output) {\n writeFileSync(resolve(options.output), svg, \"utf-8\");\n } else {\n console.log(svg);\n }\n } catch (err) {\n console.error((err as Error).message);\n process.exit(1);\n }\n },\n );\n}\n","import type { AtelierDocument, ImageVisual, RefVisual } from \"@a-company/atelier-types\";\nimport { resolveFrame, type ResolvedFrame } from \"@a-company/atelier-core\";\nimport { buildEffectiveLayer, type EffectiveLayer, type DocumentResolver } from \"@a-company/atelier-canvas\";\nimport { buildTransform, buildStyleAttrs } from \"./svg-properties.js\";\nimport { renderShapeSVG } from \"./svg-shapes.js\";\nimport { renderTextSVG } from \"./svg-text.js\";\nimport { buildShadowFilter, buildTintFilter, resetFilterCounter } from \"./svg-filters.js\";\nimport { resetGradientCounter } from \"./svg-gradients.js\";\nimport { buildClipPathDef, resetClipCounter } from \"./svg-clip.js\";\nimport { escapeXml } from \"./svg-properties.js\";\n\nexport interface RenderSVGOptions {\n /** Include XML declaration (default: false) */\n xmlDeclaration?: boolean;\n /** Include viewBox attribute (default: true) */\n viewBox?: boolean;\n /** Indent size in spaces (default: 2) */\n indent?: number;\n /** Resolves ref layer src paths to loaded AtelierDocuments */\n documentResolver?: DocumentResolver;\n /** Maximum ref nesting depth (default: 4) */\n maxRefDepth?: number;\n}\n\n/**\n * Render a resolved frame as an SVG string.\n * If no resolved frame is provided, resolves the given state and frame.\n */\nexport function renderFrameSVG(\n doc: AtelierDocument,\n stateOrFrame: string | ResolvedFrame,\n frame?: number,\n opts?: RenderSVGOptions,\n): string {\n // Reset counters for deterministic IDs\n resetGradientCounter();\n resetFilterCounter();\n resetClipCounter();\n\n let resolved: ResolvedFrame;\n if (typeof stateOrFrame === \"string\") {\n resolved = resolveFrame(doc, stateOrFrame, frame ?? 0);\n } else {\n resolved = stateOrFrame;\n }\n\n const { width, height } = doc.canvas;\n const indent = opts?.indent ?? 2;\n const pad = \" \".repeat(indent);\n\n // Build effective layers\n const effLayers: EffectiveLayer[] = resolved.layers.map(rl =>\n buildEffectiveLayer(rl, width, height),\n );\n\n // Collect all defs and layer elements\n const allDefs: string[] = [];\n const layerElements: string[] = [];\n\n for (let i = 0; i < effLayers.length; i++) {\n const eff = effLayers[i];\n const layer = resolved.layers[i].layer;\n\n // Skip invisible or fully transparent\n if (!eff.visible) continue;\n if (eff.opacity <= 0) continue;\n\n // Resolve asset for images\n if (layer.visual.type === \"image\") {\n const iv = eff.visual as ImageVisual;\n if (!iv.src && iv.assetId && doc.assets?.[iv.assetId]) {\n (eff.visual as ImageVisual).src = doc.assets[iv.assetId].src;\n }\n }\n\n // Build transform\n const transform = buildTransform(eff);\n const styleAttrs = buildStyleAttrs(eff);\n\n // Build shadow filter\n const filterResult = buildShadowFilter(eff);\n if (filterResult) allDefs.push(filterResult.defs);\n\n // Build tint filter\n const tintResult = buildTintFilter(eff);\n if (tintResult) allDefs.push(tintResult.defs);\n\n // Build clip path\n let clipAttr = \"\";\n if (layer.clipPath) {\n const clipResult = buildClipPathDef(layer.clipPath, eff.width, eff.height);\n if (clipResult.defs) {\n allDefs.push(clipResult.defs);\n clipAttr = ` clip-path=\"${clipResult.clipRef}\"`;\n }\n }\n\n // Build group attributes\n const gAttrs: string[] = [];\n if (transform) gAttrs.push(`transform=\"${transform}\"`);\n if (styleAttrs) gAttrs.push(styleAttrs);\n // Apply combined or individual filters\n if (filterResult && tintResult) {\n // When both shadow and tint exist, we need a combined filter\n // For simplicity, apply shadow filter and tint separately via style\n gAttrs.push(`filter=\"${filterResult.filterRef}\"`);\n // Tint is a second filter — wrap content in nested group\n } else if (filterResult) {\n gAttrs.push(`filter=\"${filterResult.filterRef}\"`);\n } else if (tintResult) {\n gAttrs.push(`filter=\"${tintResult.filterRef}\"`);\n }\n if (clipAttr) gAttrs.push(clipAttr.trim());\n\n // Render visual content\n let content = \"\";\n let layerDefs = \"\";\n\n switch (layer.visual.type) {\n case \"shape\": {\n const result = renderShapeSVG(eff, eff.visual as import(\"@a-company/atelier-types\").ShapeVisual);\n content = result.elements;\n layerDefs = result.defs;\n break;\n }\n case \"text\":\n content = renderTextSVG(eff, eff.visual as import(\"@a-company/atelier-types\").TextVisual);\n break;\n case \"image\": {\n const iv = eff.visual as ImageVisual;\n if (iv.src) {\n if (iv.spritesheet) {\n // Spritesheet: compute source rect and use full sheet dimensions for inner image\n const { columns, rows, frameWidth, frameHeight, frameCount } = iv.spritesheet;\n const maxFrames = frameCount ?? (columns * rows);\n const idx = Math.max(0, Math.min(Math.floor(iv.frameIndex ?? 0), maxFrames - 1));\n const col = idx % columns;\n const row = Math.floor(idx / columns);\n const sx = col * frameWidth;\n const sy = row * frameHeight;\n const imgW = columns * frameWidth;\n const imgH = rows * frameHeight;\n content = `<svg viewBox=\"${sx} ${sy} ${frameWidth} ${frameHeight}\" width=\"${eff.width}\" height=\"${eff.height}\">` +\n `<image href=\"${escapeXml(iv.src)}\" width=\"${imgW}\" height=\"${imgH}\" />` +\n `</svg>`;\n } else if (iv.sourceRect) {\n // Manual sourceRect: viewBox crops from image coordinate space\n const sr = iv.sourceRect;\n content = `<svg viewBox=\"${sr.x} ${sr.y} ${sr.width} ${sr.height}\" width=\"${eff.width}\" height=\"${eff.height}\">` +\n `<image href=\"${escapeXml(iv.src)}\" width=\"${eff.width}\" height=\"${eff.height}\" />` +\n `</svg>`;\n } else {\n content = `<image href=\"${escapeXml(iv.src)}\" width=\"${eff.width}\" height=\"${eff.height}\" />`;\n }\n }\n break;\n }\n case \"group\":\n // Groups are structural — no visual content in SVG either\n break;\n case \"ref\": {\n const refVisual = eff.visual as RefVisual;\n const refContent = renderRefSVG(eff, refVisual, doc, opts);\n content = refContent;\n break;\n }\n }\n\n if (layerDefs) allDefs.push(layerDefs);\n\n if (content) {\n const gOpen = gAttrs.length > 0 ? `<g ${gAttrs.join(\" \")}>` : \"<g>\";\n layerElements.push(`${pad}${gOpen}${content}</g>`);\n }\n }\n\n // Build SVG\n const lines: string[] = [];\n\n if (opts?.xmlDeclaration) {\n lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n }\n\n const viewBox = opts?.viewBox !== false ? ` viewBox=\"0 0 ${width} ${height}\"` : \"\";\n const bg = doc.canvas.background;\n\n lines.push(`<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"${viewBox}>`);\n\n // Defs section\n if (allDefs.length > 0) {\n lines.push(`${pad}<defs>`);\n for (const def of allDefs) {\n lines.push(`${pad}${pad}${def}`);\n }\n lines.push(`${pad}</defs>`);\n }\n\n // Background\n if (bg && bg !== \"transparent\") {\n lines.push(`${pad}<rect width=\"${width}\" height=\"${height}\" fill=\"${bg}\" />`);\n }\n\n // Layers\n lines.push(...layerElements);\n\n lines.push(\"</svg>\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Render a ref layer as SVG. Uses documentResolver to inline sub-doc content,\n * or falls back to a dashed placeholder rectangle.\n */\nfunction renderRefSVG(\n eff: EffectiveLayer,\n visual: RefVisual,\n _parentDoc: AtelierDocument,\n opts?: RenderSVGOptions,\n _depth?: number,\n _visitedRefs?: Set<string>,\n): string {\n const resolver = opts?.documentResolver;\n\n if (!resolver) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" />`;\n }\n\n const depth = _depth ?? 0;\n const maxDepth = opts?.maxRefDepth ?? 4;\n if (depth >= maxDepth) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#c33\" stroke-dasharray=\"4 2\" /><text x=\"${eff.width / 2}\" y=\"${eff.height / 2}\" text-anchor=\"middle\" dominant-baseline=\"middle\" fill=\"#c33\" font-size=\"12\">MAX DEPTH</text>`;\n }\n\n const visitedRefs = _visitedRefs ?? new Set<string>();\n if (visitedRefs.has(visual.src)) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#c33\" stroke-dasharray=\"4 2\" /><text x=\"${eff.width / 2}\" y=\"${eff.height / 2}\" text-anchor=\"middle\" dominant-baseline=\"middle\" fill=\"#c33\" font-size=\"12\">CYCLE</text>`;\n }\n\n const subDoc = resolver(visual.src);\n if (!subDoc) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" /><text x=\"${eff.width / 2}\" y=\"${eff.height / 2}\" text-anchor=\"middle\" dominant-baseline=\"middle\" fill=\"#999\" font-size=\"12\">NOT FOUND</text>`;\n }\n\n const stateNames = Object.keys(subDoc.states);\n if (stateNames.length === 0) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" />`;\n }\n\n const stateName = visual.state ?? stateNames[0];\n const stateObj = subDoc.states[stateName];\n if (!stateObj) {\n return `<rect width=\"${eff.width}\" height=\"${eff.height}\" fill=\"none\" stroke=\"#999\" stroke-dasharray=\"4 2\" />`;\n }\n\n const maxFrame = Math.max(0, stateObj.duration - 1);\n const frame = Math.min(visual.frame ?? 0, maxFrame);\n\n visitedRefs.add(visual.src);\n\n // Render sub-doc as nested <svg> with viewBox for scaling\n const subW = subDoc.canvas.width;\n const subH = subDoc.canvas.height;\n const resolved = resolveFrame(subDoc, stateName, frame);\n\n const subParts: string[] = [];\n for (const rl of resolved.layers) {\n const subEff = buildEffectiveLayer(rl, subW, subH);\n if (!subEff.visible || subEff.opacity <= 0) continue;\n\n // Resolve asset\n if (rl.layer.visual.type === \"image\") {\n const iv = subEff.visual as ImageVisual;\n if (!iv.src && iv.assetId && subDoc.assets?.[iv.assetId]) {\n iv.src = subDoc.assets[iv.assetId].src;\n }\n }\n\n const transform = buildTransform(subEff);\n const styleAttrs = buildStyleAttrs(subEff);\n const gAttrs: string[] = [];\n if (transform) gAttrs.push(`transform=\"${transform}\"`);\n if (styleAttrs) gAttrs.push(styleAttrs);\n\n let childContent = \"\";\n switch (rl.layer.visual.type) {\n case \"shape\": {\n const result = renderShapeSVG(subEff, subEff.visual as import(\"@a-company/atelier-types\").ShapeVisual);\n childContent = result.elements;\n break;\n }\n case \"text\":\n childContent = renderTextSVG(subEff, subEff.visual as import(\"@a-company/atelier-types\").TextVisual);\n break;\n case \"image\": {\n const iv = subEff.visual as ImageVisual;\n if (iv.src) {\n childContent = `<image href=\"${escapeXml(iv.src)}\" width=\"${subEff.width}\" height=\"${subEff.height}\" />`;\n }\n break;\n }\n case \"ref\": {\n const refV = subEff.visual as RefVisual;\n childContent = renderRefSVG(subEff, refV, subDoc, opts, depth + 1, visitedRefs);\n break;\n }\n }\n\n if (childContent) {\n const gOpen = gAttrs.length > 0 ? `<g ${gAttrs.join(\" \")}>` : \"<g>\";\n subParts.push(`${gOpen}${childContent}</g>`);\n }\n }\n\n visitedRefs.delete(visual.src);\n\n return `<svg x=\"0\" y=\"0\" width=\"${eff.width}\" height=\"${eff.height}\" viewBox=\"0 0 ${subW} ${subH}\">${subParts.join(\"\")}</svg>`;\n}\n","import type { EffectiveLayer } from \"@a-company/atelier-canvas\";\n\n/** Build SVG transform attribute from effective layer values */\nexport function buildTransform(eff: EffectiveLayer): string {\n const parts: string[] = [];\n\n // Translate to position\n if (eff.x !== 0 || eff.y !== 0) {\n parts.push(`translate(${eff.x}, ${eff.y})`);\n }\n\n const totalRotation = eff.rotation + eff.motionPathAngle;\n if (totalRotation !== 0 || eff.scaleX !== 1 || eff.scaleY !== 1) {\n const ax = eff.anchorX * eff.width;\n const ay = eff.anchorY * eff.height;\n\n // Move to anchor, apply rotation/scale, move back\n if (ax !== 0 || ay !== 0) {\n parts.push(`translate(${ax}, ${ay})`);\n }\n if (totalRotation !== 0) {\n parts.push(`rotate(${totalRotation})`);\n }\n if (eff.scaleX !== 1 || eff.scaleY !== 1) {\n parts.push(`scale(${eff.scaleX}, ${eff.scaleY})`);\n }\n if (ax !== 0 || ay !== 0) {\n parts.push(`translate(${-ax}, ${-ay})`);\n }\n }\n\n return parts.length > 0 ? parts.join(\" \") : \"\";\n}\n\n/** Build common SVG style attributes */\nexport function buildStyleAttrs(eff: EffectiveLayer): string {\n const attrs: string[] = [];\n\n if (eff.opacity < 1) {\n attrs.push(`opacity=\"${eff.opacity}\"`);\n }\n\n if (eff.blendMode !== \"normal\") {\n attrs.push(`style=\"mix-blend-mode: ${eff.blendMode}\"`);\n }\n\n return attrs.join(\" \");\n}\n\n/** Escape XML special characters */\nexport function escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n","import type { Fill, LinearGradientFill, RadialGradientFill, Color, RGBAColor, HSLAColor } from \"@a-company/atelier-types\";\n\nlet gradientIdCounter = 0;\n\nexport function resetGradientCounter(): void {\n gradientIdCounter = 0;\n}\n\n/** Convert an Atelier Color to a CSS color string */\nexport function colorToCSS(color: Color): string {\n if (typeof color === \"string\") return color;\n if (\"r\" in color) {\n const c = color as RGBAColor;\n return `rgba(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)}, ${c.a})`;\n }\n if (\"h\" in color) {\n const c = color as HSLAColor;\n return `hsla(${c.h}, ${c.s}%, ${c.l}%, ${c.a})`;\n }\n return \"#000000\";\n}\n\n/** Generate SVG gradient defs and return the fill reference */\nexport function buildGradientDef(fill: Fill, width: number, height: number): { defs: string; fillRef: string } {\n if (fill.type === \"solid\") {\n return { defs: \"\", fillRef: colorToCSS(fill.color) };\n }\n\n if (fill.type === \"linear-gradient\") {\n return buildLinearGradient(fill, width, height);\n }\n\n if (fill.type === \"radial-gradient\") {\n return buildRadialGradient(fill, width, height);\n }\n\n return { defs: \"\", fillRef: \"none\" };\n}\n\nfunction buildLinearGradient(fill: LinearGradientFill, _width: number, _height: number): { defs: string; fillRef: string } {\n const id = `grad-${++gradientIdCounter}`;\n const rad = (fill.angle * Math.PI) / 180;\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n\n // Map angle to x1,y1,x2,y2 (0-1 percentages)\n const x1 = 0.5 - cos * 0.5;\n const y1 = 0.5 - sin * 0.5;\n const x2 = 0.5 + cos * 0.5;\n const y2 = 0.5 + sin * 0.5;\n\n const stops = fill.stops.map(s =>\n `<stop offset=\"${s.offset}\" stop-color=\"${colorToCSS(s.color)}\" />`\n ).join(\"\");\n\n const def = `<linearGradient id=\"${id}\" x1=\"${x1}\" y1=\"${y1}\" x2=\"${x2}\" y2=\"${y2}\">${stops}</linearGradient>`;\n return { defs: def, fillRef: `url(#${id})` };\n}\n\nfunction buildRadialGradient(fill: RadialGradientFill, width: number, height: number): { defs: string; fillRef: string } {\n const id = `grad-${++gradientIdCounter}`;\n\n const cx = typeof fill.center.x === \"number\" ? fill.center.x : (parseFloat(fill.center.x) / 100) * width;\n const cy = typeof fill.center.y === \"number\" ? fill.center.y : (parseFloat(fill.center.y) / 100) * height;\n const r = typeof fill.radius === \"number\" ? fill.radius : (parseFloat(fill.radius) / 100) * Math.max(width, height);\n\n const stops = fill.stops.map(s =>\n `<stop offset=\"${s.offset}\" stop-color=\"${colorToCSS(s.color)}\" />`\n ).join(\"\");\n\n const def = `<radialGradient id=\"${id}\" cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" gradientUnits=\"userSpaceOnUse\">${stops}</radialGradient>`;\n return { defs: def, fillRef: `url(#${id})` };\n}\n","import type { ShapeVisual, Shape, RectShape, PathShape, Stroke } from \"@a-company/atelier-types\";\nimport type { EffectiveLayer } from \"@a-company/atelier-canvas\";\nimport { buildGradientDef, colorToCSS } from \"./svg-gradients.js\";\n\n/** Render a shape visual as SVG elements */\nexport function renderShapeSVG(\n eff: EffectiveLayer,\n visual: ShapeVisual,\n): { elements: string; defs: string } {\n const { shape } = visual;\n const defs: string[] = [];\n\n let fillAttr = \"none\";\n if (visual.fill) {\n const gradResult = buildGradientDef(visual.fill, eff.width, eff.height);\n if (gradResult.defs) defs.push(gradResult.defs);\n fillAttr = gradResult.fillRef;\n }\n\n let strokeAttrs = \"\";\n if (visual.stroke) {\n strokeAttrs = buildStrokeAttrs(visual.stroke);\n }\n\n const element = buildShapeElement(shape, eff.width, eff.height, fillAttr, strokeAttrs);\n return { elements: element, defs: defs.join(\"\") };\n}\n\nfunction buildShapeElement(\n shape: Shape,\n width: number,\n height: number,\n fill: string,\n strokeAttrs: string,\n): string {\n switch (shape.type) {\n case \"rect\":\n return buildRectElement(shape, width, height, fill, strokeAttrs);\n case \"ellipse\":\n return buildEllipseElement(width, height, fill, strokeAttrs);\n case \"path\":\n return buildPathElement(shape, fill, strokeAttrs);\n }\n}\n\nfunction buildRectElement(\n shape: RectShape,\n width: number,\n height: number,\n fill: string,\n strokeAttrs: string,\n): string {\n let rx = \"\";\n if (shape.cornerRadius) {\n const r = typeof shape.cornerRadius === \"number\" ? shape.cornerRadius : shape.cornerRadius[0];\n rx = ` rx=\"${r}\" ry=\"${r}\"`;\n }\n return `<rect width=\"${width}\" height=\"${height}\" fill=\"${fill}\"${rx}${strokeAttrs ? \" \" + strokeAttrs : \"\"} />`;\n}\n\nfunction buildEllipseElement(\n width: number,\n height: number,\n fill: string,\n strokeAttrs: string,\n): string {\n const cx = width / 2;\n const cy = height / 2;\n const rx = width / 2;\n const ry = height / 2;\n return `<ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${rx}\" ry=\"${ry}\" fill=\"${fill}\"${strokeAttrs ? \" \" + strokeAttrs : \"\"} />`;\n}\n\nfunction buildPathElement(\n shape: PathShape,\n fill: string,\n strokeAttrs: string,\n): string {\n if (shape.points.length < 2) return \"\";\n\n const d: string[] = [];\n d.push(`M ${shape.points[0].x} ${shape.points[0].y}`);\n\n for (let i = 1; i < shape.points.length; i++) {\n const prev = shape.points[i - 1];\n const curr = shape.points[i];\n\n if (prev.out && curr.in) {\n d.push(`C ${prev.x + prev.out.x} ${prev.y + prev.out.y} ${curr.x + curr.in.x} ${curr.y + curr.in.y} ${curr.x} ${curr.y}`);\n } else {\n d.push(`L ${curr.x} ${curr.y}`);\n }\n }\n\n if (shape.closed) d.push(\"Z\");\n\n return `<path d=\"${d.join(\" \")}\" fill=\"${fill}\"${strokeAttrs ? \" \" + strokeAttrs : \"\"} />`;\n}\n\nfunction buildStrokeAttrs(stroke: Stroke): string {\n const parts: string[] = [];\n parts.push(`stroke=\"${colorToCSS(stroke.color)}\"`);\n parts.push(`stroke-width=\"${stroke.width}\"`);\n\n if (stroke.lineCap) parts.push(`stroke-linecap=\"${stroke.lineCap}\"`);\n if (stroke.lineJoin) parts.push(`stroke-linejoin=\"${stroke.lineJoin}\"`);\n if (stroke.dash) parts.push(`stroke-dasharray=\"${stroke.dash.join(\" \")}\"`);\n\n return parts.join(\" \");\n}\n","import type { TextVisual } from \"@a-company/atelier-types\";\nimport type { EffectiveLayer } from \"@a-company/atelier-canvas\";\nimport { colorToCSS } from \"./svg-gradients.js\";\nimport { escapeXml } from \"./svg-properties.js\";\n\n/** Render a text visual as SVG elements */\nexport function renderTextSVG(eff: EffectiveLayer, visual: TextVisual): string {\n const { style } = visual;\n\n const attrs: string[] = [];\n\n // Font attributes\n attrs.push(`font-family=\"${escapeXml(style.fontFamily)}\"`);\n attrs.push(`font-size=\"${style.fontSize}\"`);\n\n if (style.fontWeight && style.fontWeight !== \"normal\") {\n attrs.push(`font-weight=\"${style.fontWeight}\"`);\n }\n if (style.fontStyle && style.fontStyle !== \"normal\") {\n attrs.push(`font-style=\"${style.fontStyle}\"`);\n }\n\n // Color\n attrs.push(`fill=\"${colorToCSS(style.color)}\"`);\n\n // Text alignment\n const align = style.textAlign ?? \"left\";\n let textAnchor = \"start\";\n let x = 0;\n if (align === \"center\") {\n textAnchor = \"middle\";\n x = eff.width / 2;\n } else if (align === \"right\") {\n textAnchor = \"end\";\n x = eff.width;\n }\n attrs.push(`text-anchor=\"${textAnchor}\"`);\n\n // Letter spacing\n if (style.letterSpacing) {\n attrs.push(`letter-spacing=\"${style.letterSpacing}\"`);\n }\n\n // SVG text baseline: use dominant-baseline for top alignment\n attrs.push(`dominant-baseline=\"hanging\"`);\n\n return `<text x=\"${x}\" y=\"0\" ${attrs.join(\" \")}>${escapeXml(visual.content)}</text>`;\n}\n","import type { EffectiveLayer } from \"@a-company/atelier-canvas\";\n\nlet filterIdCounter = 0;\n\nexport function resetFilterCounter(): void {\n filterIdCounter = 0;\n}\n\n/** Build SVG filter definition for shadow effects */\nexport function buildShadowFilter(eff: EffectiveLayer): { defs: string; filterRef: string } | null {\n if (!eff.shadow) return null;\n\n const id = `filter-${++filterIdCounter}`;\n const { color, blur, offsetX, offsetY } = eff.shadow;\n\n const def = [\n `<filter id=\"${id}\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">`,\n `<feDropShadow dx=\"${offsetX}\" dy=\"${offsetY}\" stdDeviation=\"${blur / 2}\" flood-color=\"${color}\" />`,\n `</filter>`,\n ].join(\"\");\n\n return { defs: def, filterRef: `url(#${id})` };\n}\n\n/** Build SVG filter definition for tint effect (feFlood + feBlend multiply) */\nexport function buildTintFilter(eff: EffectiveLayer): { defs: string; filterRef: string } | null {\n if (!eff.tint || eff.tint.amount <= 0) return null;\n\n const id = `filter-${++filterIdCounter}`;\n const { color, amount } = eff.tint;\n\n const def = [\n `<filter id=\"${id}\" x=\"0%\" y=\"0%\" width=\"100%\" height=\"100%\">`,\n `<feFlood flood-color=\"${color}\" flood-opacity=\"${amount}\" result=\"tint\" />`,\n `<feBlend in=\"SourceGraphic\" in2=\"tint\" mode=\"multiply\" />`,\n `</filter>`,\n ].join(\"\");\n\n return { defs: def, filterRef: `url(#${id})` };\n}\n","import type { Shape } from \"@a-company/atelier-types\";\n\nlet clipIdCounter = 0;\n\nexport function resetClipCounter(): void {\n clipIdCounter = 0;\n}\n\n/** Build SVG clipPath definition */\nexport function buildClipPathDef(shape: Shape, width: number, height: number): { defs: string; clipRef: string } {\n const id = `clip-${++clipIdCounter}`;\n let pathContent = \"\";\n\n switch (shape.type) {\n case \"rect\":\n if (shape.cornerRadius) {\n const r = typeof shape.cornerRadius === \"number\" ? shape.cornerRadius : shape.cornerRadius[0];\n pathContent = `<rect width=\"${width}\" height=\"${height}\" rx=\"${r}\" ry=\"${r}\" />`;\n } else {\n pathContent = `<rect width=\"${width}\" height=\"${height}\" />`;\n }\n break;\n case \"ellipse\":\n pathContent = `<ellipse cx=\"${width / 2}\" cy=\"${height / 2}\" rx=\"${width / 2}\" ry=\"${height / 2}\" />`;\n break;\n case \"path\": {\n if (shape.points.length < 2) return { defs: \"\", clipRef: \"\" };\n const d: string[] = [];\n d.push(`M ${shape.points[0].x} ${shape.points[0].y}`);\n for (let i = 1; i < shape.points.length; i++) {\n const prev = shape.points[i - 1];\n const curr = shape.points[i];\n if (prev.out && curr.in) {\n d.push(`C ${prev.x + prev.out.x} ${prev.y + prev.out.y} ${curr.x + curr.in.x} ${curr.y + curr.in.y} ${curr.x} ${curr.y}`);\n } else {\n d.push(`L ${curr.x} ${curr.y}`);\n }\n }\n if (shape.closed) d.push(\"Z\");\n pathContent = `<path d=\"${d.join(\" \")}\" />`;\n break;\n }\n }\n\n const def = `<clipPath id=\"${id}\">${pathContent}</clipPath>`;\n return { defs: def, clipRef: `url(#${id})` };\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { exportToLottie } from \"@a-company/atelier-lottie\";\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/** Register the `export-lottie` subcommand on the Commander program. */\nexport function exportLottieCommand(program: Command): void {\n program\n .command(\"export-lottie <file>\")\n .description(\"Export a document to Lottie JSON format\")\n .option(\"-s, --state <name>\", \"State name (defaults to first state)\")\n .option(\"-o, --output <path>\", \"Output file path (default: stdout)\")\n .action(\n (\n file: string,\n options: { state?: string; output?: string },\n ) => {\n const doc = readAndParse(file);\n\n try {\n const { json, warnings } = exportToLottie(doc, {\n state: options.state,\n });\n\n // Print warnings to stderr\n for (const warning of warnings) {\n console.error(`Warning: ${warning}`);\n }\n\n const output = JSON.stringify(json, null, 2);\n if (options.output) {\n writeFileSync(resolve(options.output), output, \"utf-8\");\n } else {\n console.log(output);\n }\n } catch (err) {\n console.error((err as Error).message);\n process.exit(1);\n }\n },\n );\n}\n","import type { Color, RGBAColor, HSLAColor } from \"@a-company/atelier-types\";\n\n/** Convert an Atelier color to Lottie [r, g, b, a] format (0–1 range) */\nexport function colorToLottie(color: Color): number[] {\n if (typeof color === \"string\") {\n return hexToLottie(color);\n }\n\n if (\"r\" in color) {\n const c = color as RGBAColor;\n return [c.r / 255, c.g / 255, c.b / 255, c.a];\n }\n\n if (\"h\" in color) {\n const c = color as HSLAColor;\n const rgb = hslToRgb(c.h, c.s, c.l);\n return [rgb[0] / 255, rgb[1] / 255, rgb[2] / 255, c.a];\n }\n\n return [0, 0, 0, 1];\n}\n\nfunction hexToLottie(hex: string): number[] {\n const clean = hex.replace(\"#\", \"\");\n if (clean.length === 3 || clean.length === 4) {\n const r = parseInt(clean[0] + clean[0], 16) / 255;\n const g = parseInt(clean[1] + clean[1], 16) / 255;\n const b = parseInt(clean[2] + clean[2], 16) / 255;\n const a = clean.length === 4 ? parseInt(clean[3] + clean[3], 16) / 255 : 1;\n return [r, g, b, a];\n }\n const r = parseInt(clean.slice(0, 2), 16) / 255;\n const g = parseInt(clean.slice(2, 4), 16) / 255;\n const b = parseInt(clean.slice(4, 6), 16) / 255;\n const a = clean.length === 8 ? parseInt(clean.slice(6, 8), 16) / 255 : 1;\n return [r, g, b, a];\n}\n\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n s = s / 100;\n l = l / 100;\n const a = s * Math.min(l, 1 - l);\n const f = (n: number) => {\n const k = (n + h / 30) % 12;\n return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n };\n return [Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255)];\n}\n","import type { ShapeVisual, Fill, Stroke } from \"@a-company/atelier-types\";\nimport type { LottieShapeItem } from \"./lottie-types.js\";\nimport { colorToLottie } from \"./map-colors.js\";\n\n/** Map an Atelier shape visual to Lottie shape items */\nexport function mapShapeVisual(\n visual: ShapeVisual,\n width: number,\n height: number,\n): LottieShapeItem[] {\n const items: LottieShapeItem[] = [];\n\n // Shape geometry\n switch (visual.shape.type) {\n case \"rect\":\n items.push({\n ty: \"rc\",\n nm: \"Rectangle\",\n d: 1,\n s: { a: 0, k: [width, height] },\n p: { a: 0, k: [width / 2, height / 2] },\n r: { a: 0, k: typeof visual.shape.cornerRadius === \"number\" ? visual.shape.cornerRadius : 0 },\n });\n break;\n case \"ellipse\":\n items.push({\n ty: \"el\",\n nm: \"Ellipse\",\n d: 1,\n s: { a: 0, k: [width, height] },\n p: { a: 0, k: [width / 2, height / 2] },\n });\n break;\n case \"path\": {\n const vertices = visual.shape.points.map(p => [p.x, p.y]);\n const inTangents = visual.shape.points.map(p => p.in ? [p.in.x, p.in.y] : [0, 0]);\n const outTangents = visual.shape.points.map(p => p.out ? [p.out.x, p.out.y] : [0, 0]);\n items.push({\n ty: \"sh\",\n nm: \"Path\",\n ks: {\n a: 0,\n k: {\n c: visual.shape.closed ?? false,\n v: vertices,\n i: inTangents,\n o: outTangents,\n },\n },\n });\n break;\n }\n }\n\n // Fill\n if (visual.fill) {\n items.push(mapFill(visual.fill, width, height));\n }\n\n // Stroke\n if (visual.stroke) {\n items.push(mapStroke(visual.stroke));\n }\n\n return items;\n}\n\nfunction mapFill(fill: Fill, _width: number, _height: number): LottieShapeItem {\n if (fill.type === \"solid\") {\n const color = colorToLottie(fill.color);\n return {\n ty: \"fl\",\n nm: \"Fill\",\n c: { a: 0, k: color.slice(0, 3) },\n o: { a: 0, k: (color[3] ?? 1) * 100 },\n r: 1,\n };\n }\n\n if (fill.type === \"linear-gradient\") {\n const stops: number[] = [];\n for (const stop of fill.stops) {\n const c = colorToLottie(stop.color);\n stops.push(stop.offset, c[0], c[1], c[2]);\n }\n return {\n ty: \"gf\",\n nm: \"Gradient Fill\",\n t: 1, // linear\n s: { a: 0, k: [0, 0] },\n e: { a: 0, k: [100, 0] },\n g: { p: fill.stops.length, k: { a: 0, k: stops } },\n r: 1,\n o: { a: 0, k: 100 },\n };\n }\n\n if (fill.type === \"radial-gradient\") {\n const stops: number[] = [];\n for (const stop of fill.stops) {\n const c = colorToLottie(stop.color);\n stops.push(stop.offset, c[0], c[1], c[2]);\n }\n return {\n ty: \"gf\",\n nm: \"Gradient Fill\",\n t: 2, // radial\n s: { a: 0, k: [50, 50] },\n e: { a: 0, k: [100, 50] },\n g: { p: fill.stops.length, k: { a: 0, k: stops } },\n r: 1,\n o: { a: 0, k: 100 },\n };\n }\n\n return { ty: \"fl\", nm: \"Fill\", c: { a: 0, k: [0, 0, 0] }, o: { a: 0, k: 100 }, r: 1 };\n}\n\nfunction mapStroke(stroke: Stroke): LottieShapeItem {\n const color = colorToLottie(stroke.color);\n return {\n ty: \"st\",\n nm: \"Stroke\",\n c: { a: 0, k: color.slice(0, 3) },\n o: { a: 0, k: (color[3] ?? 1) * 100 },\n w: { a: 0, k: stroke.width },\n lc: stroke.lineCap === \"round\" ? 2 : stroke.lineCap === \"square\" ? 3 : 1,\n lj: stroke.lineJoin === \"round\" ? 2 : stroke.lineJoin === \"bevel\" ? 3 : 1,\n };\n}\n","import type { Easing } from \"@a-company/atelier-types\";\n\nexport interface LottieEasing {\n i: { x: number[]; y: number[] };\n o: { x: number[]; y: number[] };\n}\n\n/** Map an Atelier easing to Lottie bezier easing curves */\nexport function mapEasing(easing: Easing | undefined): LottieEasing | { h: 1 } {\n if (!easing) return linearEasing();\n\n if (typeof easing === \"string\") {\n switch (easing) {\n case \"ease-in\":\n return bezierEasing(0.42, 0, 1, 1);\n case \"ease-out\":\n return bezierEasing(0, 0, 0.58, 1);\n case \"ease-in-out\":\n return bezierEasing(0.42, 0, 0.58, 1);\n default:\n return linearEasing();\n }\n }\n\n switch (easing.type) {\n case \"linear\":\n return linearEasing();\n case \"cubic-bezier\":\n return bezierEasing(easing.x1, easing.y1, easing.x2, easing.y2);\n case \"spring\":\n // Approximate spring as a cubic-bezier (lossy)\n return bezierEasing(0.25, 0.1, 0.25, 1);\n case \"step\":\n // Steps map to hold keyframes\n return { h: 1 };\n default:\n return linearEasing();\n }\n}\n\nfunction linearEasing(): LottieEasing {\n return {\n i: { x: [0.833], y: [0.833] },\n o: { x: [0.167], y: [0.167] },\n };\n}\n\nfunction bezierEasing(x1: number, y1: number, x2: number, y2: number): LottieEasing {\n return {\n i: { x: [x2], y: [y2] },\n o: { x: [x1], y: [y1] },\n };\n}\n\n/** Check if an easing is lossy (spring/step → approximated) */\nexport function isLossyEasing(easing: Easing | undefined): string | null {\n if (!easing || typeof easing === \"string\") return null;\n if (easing.type === \"spring\") return \"Spring easing approximated as cubic-bezier\";\n if (easing.type === \"step\") return \"Step easing mapped to hold keyframes\";\n return null;\n}\n","import type { Delta, AnimatableProperty } from \"@a-company/atelier-types\";\nimport type { LottieAnimatedValue, LottieAnimatedMultiValue, LottieKeyframe, LottieMultiKeyframe } from \"./lottie-types.js\";\nimport { mapEasing, isLossyEasing } from \"./map-easing.js\";\n\n/** Map deltas for a single layer+property to Lottie animated value */\nexport function mapDeltasToAnimated(\n deltas: Delta[],\n property: AnimatableProperty,\n warnings: string[],\n): LottieAnimatedValue {\n if (deltas.length === 0) {\n return { a: 0, k: 0 };\n }\n\n // Check for lossy easings\n for (const d of deltas) {\n const lossyMsg = isLossyEasing(d.easing);\n if (lossyMsg) warnings.push(`${property}: ${lossyMsg}`);\n }\n\n // If expressions, warn and use static\n for (const d of deltas) {\n if (isExpression(d.from) || isExpression(d.to)) {\n warnings.push(`${property}: Expression values not supported in Lottie, using static values`);\n return { a: 0, k: typeof d.from === \"number\" ? d.from : 0 };\n }\n }\n\n // Single delta — simple animated value\n if (deltas.length === 1) {\n const d = deltas[0];\n const fromVal = resolveValue(d.from, property);\n const toVal = resolveValue(d.to, property);\n\n if (fromVal === toVal) {\n return { a: 0, k: fromVal };\n }\n\n const easing = mapEasing(d.easing);\n const kfs: LottieKeyframe[] = [];\n\n if (\"h\" in easing) {\n kfs.push({ t: d.range[0], s: [fromVal], h: 1 });\n kfs.push({ t: d.range[1], s: [toVal] });\n } else {\n kfs.push({ t: d.range[0], s: [fromVal], e: [toVal], i: easing.i, o: easing.o });\n kfs.push({ t: d.range[1], s: [toVal] });\n }\n\n return { a: 1, k: kfs };\n }\n\n // Multiple deltas — chain keyframes\n const sorted = [...deltas].sort((a, b) => a.range[0] - b.range[0]);\n const kfs: LottieKeyframe[] = [];\n\n for (const d of sorted) {\n const fromVal = resolveValue(d.from, property);\n const toVal = resolveValue(d.to, property);\n const easing = mapEasing(d.easing);\n\n if (\"h\" in easing) {\n kfs.push({ t: d.range[0], s: [fromVal], h: 1 });\n } else {\n kfs.push({ t: d.range[0], s: [fromVal], e: [toVal], i: easing.i, o: easing.o });\n }\n }\n\n // Final keyframe\n const last = sorted[sorted.length - 1];\n kfs.push({ t: last.range[1], s: [resolveValue(last.to, property)] });\n\n return { a: 1, k: kfs };\n}\n\n/** Map position deltas (frame.x, frame.y) to Lottie multi-dimensional animated value */\nexport function mapPositionDeltas(\n xDeltas: Delta[],\n yDeltas: Delta[],\n baseX: number,\n baseY: number,\n warnings: string[],\n): LottieAnimatedMultiValue {\n const hasXAnim = xDeltas.length > 0;\n const hasYAnim = yDeltas.length > 0;\n\n if (!hasXAnim && !hasYAnim) {\n return { a: 0, k: [baseX, baseY, 0] };\n }\n\n // Collect all unique frame points\n const frames = new Set<number>();\n for (const d of [...xDeltas, ...yDeltas]) {\n frames.add(d.range[0]);\n frames.add(d.range[1]);\n }\n const sortedFrames = [...frames].sort((a, b) => a - b);\n\n if (sortedFrames.length < 2) {\n return { a: 0, k: [baseX, baseY, 0] };\n }\n\n // Build multi-dimensional keyframes\n const kfs: LottieMultiKeyframe[] = [];\n for (let i = 0; i < sortedFrames.length; i++) {\n const f = sortedFrames[i];\n const x = resolveAtFrame(xDeltas, f, baseX);\n const y = resolveAtFrame(yDeltas, f, baseY);\n\n if (i < sortedFrames.length - 1) {\n const nextF = sortedFrames[i + 1];\n const nextX = resolveAtFrame(xDeltas, nextF, baseX);\n const nextY = resolveAtFrame(yDeltas, nextF, baseY);\n\n // Find the active delta's easing\n const activeX = xDeltas.find(d => d.range[0] <= f && d.range[1] >= f);\n const activeY = yDeltas.find(d => d.range[0] <= f && d.range[1] >= f);\n const easing = mapEasing(activeX?.easing ?? activeY?.easing);\n\n if (\"h\" in easing) {\n kfs.push({ t: f, s: [x, y, 0], h: 1 });\n } else {\n kfs.push({ t: f, s: [x, y, 0], e: [nextX, nextY, 0], i: easing.i, o: easing.o });\n }\n } else {\n kfs.push({ t: f, s: [x, y, 0] });\n }\n }\n\n // Check for lossy warnings\n for (const d of [...xDeltas, ...yDeltas]) {\n const msg = isLossyEasing(d.easing);\n if (msg) warnings.push(`position: ${msg}`);\n }\n\n return { a: 1, k: kfs };\n}\n\nfunction resolveAtFrame(deltas: Delta[], frame: number, base: number): number {\n for (const d of deltas) {\n if (frame >= d.range[0] && frame <= d.range[1]) {\n const from = typeof d.from === \"number\" ? d.from : base;\n const to = typeof d.to === \"number\" ? d.to : base;\n const progress = d.range[0] === d.range[1] ? 1 : (frame - d.range[0]) / (d.range[1] - d.range[0]);\n return from + (to - from) * progress;\n }\n }\n // Hold last completed value\n let lastCompleted: Delta | undefined;\n for (const d of deltas) {\n if (frame > d.range[1]) {\n if (!lastCompleted || d.range[1] > lastCompleted.range[1]) {\n lastCompleted = d;\n }\n }\n }\n if (lastCompleted) return typeof lastCompleted.to === \"number\" ? lastCompleted.to : base;\n return base;\n}\n\nfunction resolveValue(val: unknown, _property: AnimatableProperty): number {\n if (typeof val === \"number\") return val;\n if (typeof val === \"string\" && val.startsWith(\"#\")) {\n // Color — for Lottie, colors are handled separately\n return 0;\n }\n return 0;\n}\n\nfunction isExpression(val: unknown): boolean {\n return typeof val === \"object\" && val !== null && \"expr\" in val;\n}\n","import type { AtelierDocument, Layer, Delta, State, UnitValue } from \"@a-company/atelier-types\";\nimport type { LottieLayer, LottieTransform, LottieTextData } from \"./lottie-types.js\";\nimport { mapShapeVisual } from \"./map-shapes.js\";\nimport { mapDeltasToAnimated, mapPositionDeltas } from \"./map-keyframes.js\";\nimport { colorToLottie } from \"./map-colors.js\";\n\n/** Resolve a UnitValue to a plain number (percentages treated as 0 for Lottie) */\nfunction toNum(v: UnitValue): number {\n return typeof v === \"number\" ? v : 0;\n}\n\n/** Map all layers in a document+state to Lottie layers */\nexport function mapLayers(\n doc: AtelierDocument,\n state: State,\n warnings: string[],\n): LottieLayer[] {\n const layerIndexMap = new Map<string, number>();\n doc.layers.forEach((l, i) => layerIndexMap.set(l.id, i));\n\n return doc.layers.map((layer, index) => {\n const deltas = state.deltas.filter(d => d.layer === layer.id);\n return mapLayer(layer, index, deltas, layerIndexMap, doc, warnings);\n });\n}\n\nfunction mapLayer(\n layer: Layer,\n index: number,\n deltas: Delta[],\n layerIndexMap: Map<string, number>,\n doc: AtelierDocument,\n warnings: string[],\n): LottieLayer {\n const duration = getMaxFrame(deltas, doc);\n\n const base: LottieLayer = {\n ty: getLayerType(layer),\n nm: layer.id,\n ind: index,\n ip: 0,\n op: duration,\n st: 0,\n ks: buildTransform(layer, deltas, warnings),\n };\n\n // Parent\n if (layer.parentId) {\n const parentIdx = layerIndexMap.get(layer.parentId);\n if (parentIdx !== undefined) {\n base.parent = parentIdx;\n }\n }\n\n // Blend mode\n if (layer.blendMode) {\n base.bm = mapBlendMode(layer.blendMode);\n }\n\n // Shape layer\n if (layer.visual.type === \"shape\") {\n base.shapes = mapShapeVisual(layer.visual, toNum(layer.bounds.width), toNum(layer.bounds.height));\n }\n\n // Text layer\n if (layer.visual.type === \"text\") {\n const color = colorToLottie(layer.visual.style.color);\n base.t = {\n d: {\n k: [{\n s: {\n s: layer.visual.style.fontSize,\n f: layer.visual.style.fontFamily,\n t: layer.visual.content,\n fc: color.slice(0, 3),\n j: layer.visual.style.textAlign === \"center\" ? 1 :\n layer.visual.style.textAlign === \"right\" ? 2 : 0,\n },\n t: 0,\n }],\n },\n } as LottieTextData;\n }\n\n // Image layer\n if (layer.visual.type === \"image\") {\n base.refId = layer.visual.assetId;\n base.w = toNum(layer.bounds.width);\n base.h = toNum(layer.bounds.height);\n\n if (layer.visual.spritesheet) {\n warnings.push(`Layer \"${layer.id}\": Spritesheet animation not supported in Lottie export`);\n }\n if (layer.visual.sourceRect) {\n warnings.push(`Layer \"${layer.id}\": sourceRect cropping not supported in Lottie export`);\n }\n }\n\n // Tint warning\n if (layer.tint && layer.tint.amount > 0) {\n warnings.push(`Layer \"${layer.id}\": Tint effect not supported in Lottie export`);\n }\n\n return base;\n}\n\nfunction getLayerType(layer: Layer): number {\n switch (layer.visual.type) {\n case \"shape\": return 4;\n case \"text\": return 5;\n case \"image\": return 2;\n case \"group\": return 3; // null layer\n case \"ref\": return 0; // precomp\n default: return 4;\n }\n}\n\nfunction buildTransform(\n layer: Layer,\n deltas: Delta[],\n warnings: string[],\n): LottieTransform {\n // Group deltas by property\n const byProp = new Map<string, Delta[]>();\n for (const d of deltas) {\n if (!byProp.has(d.property)) byProp.set(d.property, []);\n byProp.get(d.property)!.push(d);\n }\n\n const xDeltas = byProp.get(\"frame.x\") ?? [];\n const yDeltas = byProp.get(\"frame.y\") ?? [];\n const opacityDeltas = byProp.get(\"opacity\") ?? [];\n const rotationDeltas = byProp.get(\"rotation\") ?? [];\n const scaleXDeltas = byProp.get(\"scale.x\") ?? [];\n const scaleYDeltas = byProp.get(\"scale.y\") ?? [];\n\n // Position\n const position = mapPositionDeltas(\n xDeltas, yDeltas,\n typeof layer.frame.x === \"number\" ? layer.frame.x : 0,\n typeof layer.frame.y === \"number\" ? layer.frame.y : 0,\n warnings,\n );\n\n // Opacity (Lottie uses 0–100)\n let opacity;\n if (opacityDeltas.length > 0) {\n const raw = mapDeltasToAnimated(opacityDeltas, \"opacity\", warnings);\n // Scale 0-1 to 0-100\n if (raw.a === 0) {\n opacity = { a: 0 as const, k: (raw.k as number) * 100 };\n } else {\n const kfs = (raw.k as Array<{ t: number; s: [number]; e?: [number]; [key: string]: unknown }>).map(kf => ({\n ...kf,\n s: [kf.s[0] * 100] as [number],\n e: kf.e ? [kf.e[0] * 100] as [number] : undefined,\n }));\n opacity = { a: 1 as const, k: kfs };\n }\n } else {\n opacity = { a: 0 as const, k: (layer.opacity ?? 1) * 100 };\n }\n\n // Rotation\n const rotation = rotationDeltas.length > 0\n ? mapDeltasToAnimated(rotationDeltas, \"rotation\", warnings)\n : { a: 0 as const, k: layer.rotation ?? 0 };\n\n // Scale (Lottie uses 0–100)\n const baseScaleX = (layer.scale?.x ?? 1) * 100;\n const baseScaleY = (layer.scale?.y ?? 1) * 100;\n let scale;\n if (scaleXDeltas.length > 0 || scaleYDeltas.length > 0) {\n // Simplified: use x deltas for now\n scale = { a: 0 as const, k: [baseScaleX, baseScaleY, 100] };\n if (scaleXDeltas.length > 0 || scaleYDeltas.length > 0) {\n warnings.push(\"Scale animation partially mapped to Lottie\");\n }\n } else {\n scale = { a: 0 as const, k: [baseScaleX, baseScaleY, 100] };\n }\n\n // Anchor point\n const ax = (layer.anchorPoint?.x ?? 0) * toNum(layer.bounds.width);\n const ay = (layer.anchorPoint?.y ?? 0) * toNum(layer.bounds.height);\n\n return {\n o: opacity,\n r: rotation,\n p: position,\n a: { a: 0, k: [ax, ay, 0] },\n s: scale,\n };\n}\n\nfunction getMaxFrame(deltas: Delta[], doc: AtelierDocument): number {\n let max = 0;\n for (const state of Object.values(doc.states)) {\n if (state.duration > max) max = state.duration;\n }\n for (const d of deltas) {\n if (d.range[1] > max) max = d.range[1];\n }\n return max || 60;\n}\n\nfunction mapBlendMode(mode: string): number {\n const map: Record<string, number> = {\n normal: 0, multiply: 1, screen: 2, overlay: 3,\n darken: 4, lighten: 5, \"color-dodge\": 6, \"color-burn\": 7,\n \"hard-light\": 8, \"soft-light\": 9, difference: 10, exclusion: 11,\n hue: 12, saturation: 13, color: 14, luminosity: 15,\n };\n return map[mode] ?? 0;\n}\n","import type { AtelierDocument, State } from \"@a-company/atelier-types\";\n\n/** Check for unsupported features and collect warnings */\nexport function collectUnsupportedWarnings(doc: AtelierDocument, state: State): string[] {\n const warnings: string[] = [];\n\n // Audio not supported\n if (state.audio) {\n warnings.push(\"Audio tracks are not supported in Lottie format and will be dropped\");\n }\n\n // Expressions not supported\n for (const delta of state.deltas) {\n if (isExpression(delta.from) || isExpression(delta.to)) {\n warnings.push(`Expression values on \"${delta.layer}.${delta.property}\" not supported in Lottie`);\n }\n }\n\n // Shadow not supported in base Lottie\n for (const layer of doc.layers) {\n if (layer.shadow) {\n warnings.push(`Shadow on layer \"${layer.id}\" is not supported in base Lottie format`);\n }\n }\n\n // Motion path not directly mapped\n for (const layer of doc.layers) {\n if (layer.motionPath) {\n warnings.push(`Motion path on layer \"${layer.id}\" is not directly mappable to Lottie`);\n }\n }\n\n // Clip paths have limited support\n for (const layer of doc.layers) {\n if (layer.clipPath) {\n warnings.push(`Clip path on layer \"${layer.id}\" mapped as Lottie mask (partial support)`);\n }\n }\n\n // States/transitions\n if (Object.keys(doc.states).length > 1) {\n warnings.push(\"Multiple states flattened to single timeline in Lottie export\");\n }\n\n return warnings;\n}\n\nfunction isExpression(val: unknown): boolean {\n return typeof val === \"object\" && val !== null && \"expr\" in val;\n}\n","import type { AtelierDocument } from \"@a-company/atelier-types\";\nimport type { LottieAnimation, LottieAsset } from \"./lottie-types.js\";\nimport { mapLayers } from \"./map-layers.js\";\nimport { collectUnsupportedWarnings } from \"./warnings.js\";\n\nexport interface ExportLottieOptions {\n /** State to export (defaults to first state) */\n state?: string;\n}\n\nexport interface ExportLottieResult {\n /** The Lottie JSON animation */\n json: LottieAnimation;\n /** Warnings about unsupported features */\n warnings: string[];\n}\n\n/**\n * Export an Atelier document to Lottie JSON format.\n * This is a lossy conversion — not all features are supported.\n */\nexport function exportToLottie(\n doc: AtelierDocument,\n opts?: ExportLottieOptions,\n): ExportLottieResult {\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) {\n throw new Error(\"Document has no states to export\");\n }\n\n const stateName = opts?.state ?? stateNames[0];\n const state = doc.states[stateName];\n if (!state) {\n throw new Error(`State \"${stateName}\" not found`);\n }\n\n const warnings: string[] = [];\n\n // Collect unsupported feature warnings\n warnings.push(...collectUnsupportedWarnings(doc, state));\n\n // Map layers\n const layers = mapLayers(doc, state, warnings);\n\n // Map assets\n const assets: LottieAsset[] = [];\n if (doc.assets) {\n for (const [id, asset] of Object.entries(doc.assets)) {\n if (asset.type === \"image\") {\n assets.push({\n id,\n w: 100,\n h: 100,\n p: asset.src,\n e: 0,\n });\n }\n }\n }\n\n const json: LottieAnimation = {\n v: \"5.7.4\",\n fr: doc.canvas.fps,\n ip: 0,\n op: state.duration,\n w: doc.canvas.width,\n h: doc.canvas.height,\n nm: doc.name,\n layers,\n ...(assets.length > 0 ? { assets } : {}),\n };\n\n // Deduplicate warnings\n const uniqueWarnings = [...new Set(warnings)];\n\n return { json, warnings: uniqueWarnings };\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport {\n renderDocumentToPng,\n resolveExportDimensions,\n CanvasUnavailableError,\n} from \"../lib/render-image.js\";\n\n// Re-export so existing import sites (index.ts, tests) keep resolving.\nexport { resolveExportDimensions };\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\ninterface ExportImageOptions {\n state?: string;\n frame: string;\n width?: string;\n height?: string;\n out: string;\n}\n\n/** Parse a positive integer CLI option, returning undefined if not set. */\nfunction parseDim(raw: string | undefined, name: string): number | undefined {\n if (raw === undefined) return undefined;\n const n = parseInt(raw, 10);\n if (isNaN(n) || n <= 0) {\n console.error(`Invalid --${name}: ${raw}`);\n process.exit(1);\n }\n return n;\n}\n\n/** Register the `export-image` subcommand on the Commander program. */\nexport function exportImageCommand(program: Command): void {\n program\n .command(\"export-image <file>\")\n .description(\n \"Export a single frame as a PNG image. \" +\n \"Aspect-preserving when only one of --width/--height is set; \" +\n \"if both are set the renderer uses both verbatim (may squash).\",\n )\n .requiredOption(\"-o, --out <path>\", \"Output PNG file path\")\n .option(\"-s, --state <name>\", \"State name (defaults to first state)\")\n .option(\"-f, --frame <number>\", \"Frame number (defaults to 0)\", \"0\")\n .option(\"--width <number>\", \"Override output width (px)\")\n .option(\"--height <number>\", \"Override output height (px)\")\n .action(async (file: string, options: ExportImageOptions) => {\n const doc = readAndParse(file);\n\n const frameNumber = parseInt(options.frame, 10);\n if (isNaN(frameNumber) || frameNumber < 0) {\n console.error(`Invalid frame number: ${options.frame}`);\n process.exit(1);\n return;\n }\n\n const width = parseDim(options.width, \"width\");\n const height = parseDim(options.height, \"height\");\n\n try {\n const buffer = await renderDocumentToPng(doc, {\n state: options.state,\n frame: frameNumber,\n width,\n height,\n });\n writeFileSync(resolve(options.out), buffer);\n } catch (err) {\n if (err instanceof CanvasUnavailableError) {\n console.error(err.message);\n process.exit(1);\n return;\n }\n console.error((err as Error).message);\n process.exit(1);\n }\n });\n}\n","/**\n * Shared single-frame render-to-PNG path.\n *\n * Extracted from `atelier export-image` so the carousel batch driver and the\n * single-frame export command render through one code path. Rasterizes via\n * `@napi-rs/canvas` — a Canvas2D implementation shipped as prebuilt platform\n * binaries, so PNG export works on a plain install with no node-gyp build and\n * no system libraries (cairo/pango/etc.). Pre-loads any ImageVisual layers via\n * its `loadImage` (file path / data-URL / buffer all work server-side, the same\n * mechanism the MP4 render-pipeline uses) and renders one resolved frame scaled\n * to the requested output dimensions.\n */\n\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { resolveFrame } from \"@a-company/atelier-core\";\nimport { createCanvas, loadImage } from \"@napi-rs/canvas\";\n\n/** @napi-rs/canvas surface — the subset this module touches. */\ninterface NodeCanvas {\n getContext(id: \"2d\"): unknown;\n toBuffer(format: \"image/png\"): Buffer;\n}\n\n/** A loaded image — width/height are the natural pixel dims. */\nexport interface LoadedImage {\n width: number;\n height: number;\n}\n\n/** Canvas module surface (createCanvas + loadImage). */\ninterface CanvasModule {\n createCanvas: (w: number, h: number) => NodeCanvas;\n loadImage: (src: string) => Promise<LoadedImage>;\n}\n\n/** Bounds + centered frame for fitting an image into a canvas. */\nexport interface ImageFitResult {\n bounds: { width: number; height: number };\n frame: { x: number; y: number };\n}\n\n/**\n * Fit a natural-sized image into a canvas while preserving aspect ratio,\n * centered. Adapted from studio's image-drop helper (kept local so the CLI's\n * server-side render path doesn't import the browser studio package).\n *\n * Landscape (wider than canvas) → fit to width; portrait (taller or equal) →\n * fit to height; both dims capped at the canvas extents. Degenerate natural\n * sizes fall back to canvas extents so callers always get valid bounds.\n */\nexport function fitImageToCanvas(\n canvas: { width: number; height: number },\n natural: { width: number; height: number },\n): ImageFitResult {\n const cw = canvas.width;\n const ch = canvas.height;\n const iw = natural.width;\n const ih = natural.height;\n\n if (!iw || !ih) {\n return { bounds: { width: cw, height: ch }, frame: { x: cw / 2, y: ch / 2 } };\n }\n\n const imageAspect = iw / ih;\n const canvasAspect = cw / ch;\n\n let width: number;\n let height: number;\n if (imageAspect > canvasAspect) {\n width = cw;\n height = cw / imageAspect;\n } else {\n height = ch;\n width = ch * imageAspect;\n }\n width = Math.min(width, cw);\n height = Math.min(height, ch);\n\n return { bounds: { width, height }, frame: { x: cw / 2, y: ch / 2 } };\n}\n\n/**\n * Raised when the `@napi-rs/canvas` rasterizer cannot be loaded. In practice\n * this never fires: `@napi-rs/canvas` is a hard dependency that ships prebuilt\n * platform binaries (no node-gyp, no system libraries). It can only happen if\n * the install is corrupt or running on an unsupported platform with no prebuilt\n * binary — in which case a reinstall is the fix. Kept as a typed seam so call\n * sites can still distinguish a missing-rasterizer failure from a bad document.\n */\nexport class CanvasUnavailableError extends Error {\n constructor() {\n super(\n \"The '@napi-rs/canvas' rasterizer could not be loaded.\\n\" +\n \"This package ships prebuilt platform binaries — no system libraries needed.\\n\" +\n \"Try reinstalling dependencies (e.g. `npm install`) to fetch the binary for this platform.\",\n );\n this.name = \"CanvasUnavailableError\";\n }\n}\n\n/**\n * Resolve the canvas module. `@napi-rs/canvas` is a hard, statically-imported\n * dependency, so this is a thin accessor that surfaces a typed\n * {@link CanvasUnavailableError} on the (essentially impossible) chance the\n * platform binary failed to load.\n */\nexport async function loadCanvasModule(): Promise<CanvasModule> {\n if (typeof createCanvas !== \"function\" || typeof loadImage !== \"function\") {\n throw new CanvasUnavailableError();\n }\n return {\n createCanvas: createCanvas as unknown as CanvasModule[\"createCanvas\"],\n loadImage: loadImage as unknown as CanvasModule[\"loadImage\"],\n };\n}\n\n/**\n * Compute final output dimensions from the document canvas and optional\n * width/height overrides. When only one of width/height is provided, the\n * other is derived to preserve the document's aspect ratio. When both are\n * provided, both are used verbatim (allows non-uniform scaling).\n */\nexport function resolveExportDimensions(\n docWidth: number,\n docHeight: number,\n width?: number,\n height?: number,\n): { width: number; height: number } {\n if (width !== undefined && height !== undefined) {\n return { width, height };\n }\n if (width !== undefined) {\n const h = Math.max(1, Math.round((width * docHeight) / docWidth));\n return { width, height: h };\n }\n if (height !== undefined) {\n const w = Math.max(1, Math.round((height * docWidth) / docHeight));\n return { width: w, height };\n }\n return { width: docWidth, height: docHeight };\n}\n\n/**\n * Build an {@link ImageCache} pre-populated with every ImageVisual source in\n * the document. Mirrors render-pipeline.ts: load each source with\n * `loadImage`, then wire a synchronous-from-cache `createImage` so the renderer\n * resolves images immediately. Returns the cache plus a map of src → loaded\n * image so callers can read natural dimensions.\n */\nasync function preloadImages(\n doc: AtelierDocument,\n loadImage: (src: string) => Promise<LoadedImage>,\n): Promise<{\n imageCache: import(\"@a-company/atelier-canvas\").ImageCache;\n loaded: Map<string, LoadedImage>;\n}> {\n const { ImageCache } = await import(\"@a-company/atelier-canvas\");\n\n const sources = new Set<string>();\n for (const layer of doc.layers) {\n if (layer.visual.type === \"image\") {\n const iv = layer.visual as { src?: string; assetId?: string };\n if (iv.src) sources.add(iv.src);\n else if (iv.assetId && doc.assets?.[iv.assetId]) sources.add(doc.assets[iv.assetId].src);\n }\n }\n\n if (sources.size === 0) {\n return { imageCache: new ImageCache(), loaded: new Map() };\n }\n\n const preloaded = new Map<string, LoadedImage>();\n await Promise.all(\n [...sources].map(async (src) => {\n try {\n preloaded.set(src, await loadImage(src));\n } catch {\n // Sources that fail to load render blank — same tolerance as render-pipeline.\n }\n }),\n );\n\n const imageCache = new ImageCache({\n createImage: (src, onLoad, onError) => {\n const img = preloaded.get(src);\n if (img) {\n process.nextTick(onLoad);\n return img;\n }\n process.nextTick(onError);\n return {};\n },\n });\n for (const src of preloaded.keys()) imageCache.load(src);\n await new Promise<void>((resolve) => process.nextTick(resolve));\n\n return { imageCache, loaded: preloaded };\n}\n\nexport interface RenderToPngOptions {\n /** State to resolve (defaults to the first state). */\n state?: string;\n /** Frame within the state (defaults to 0). */\n frame?: number;\n /** Output width override (px). */\n width?: number;\n /** Output height override (px). */\n height?: number;\n /**\n * Optional hook to adjust each image layer's bounds once natural dimensions\n * are known from the loaded image. Receives the layer src + natural dims and\n * the doc canvas; returns new bounds (and frame). Used by the carousel driver\n * to aspect-fit fit-to-canvas images that were composed with placeholder\n * bounds (natural dims are unknown until the rasterizer decodes the file).\n */\n refitImageBounds?: (args: {\n canvas: { width: number; height: number };\n natural: { width: number; height: number };\n }) => { bounds: { width: number; height: number }; frame: { x: number; y: number } };\n}\n\n/**\n * Render a single resolved frame of a document to a PNG buffer.\n *\n * Validates state/frame, pre-loads image layers, scales rendering to fit the\n * requested output dimensions, and returns the encoded PNG bytes. Throws\n * {@link CanvasUnavailableError} when the rasterizer is missing and a plain\n * Error for bad state/frame selection.\n */\nexport async function renderDocumentToPng(\n doc: AtelierDocument,\n opts: RenderToPngOptions = {},\n): Promise<Buffer> {\n const stateNames = Object.keys(doc.states);\n if (stateNames.length === 0) {\n throw new Error(\"Document has no states\");\n }\n const stateName = opts.state ?? stateNames[0];\n if (!doc.states[stateName]) {\n throw new Error(`State \"${stateName}\" not found. Available: ${stateNames.join(\", \")}`);\n }\n const frameNumber = opts.frame ?? 0;\n if (!Number.isInteger(frameNumber) || frameNumber < 0) {\n throw new Error(`Invalid frame number: ${frameNumber}`);\n }\n const duration = doc.states[stateName].duration;\n if (frameNumber >= duration) {\n throw new Error(\n `Frame ${frameNumber} is out of range for state \"${stateName}\" (duration ${duration})`,\n );\n }\n\n const { createCanvas, loadImage } = await loadCanvasModule();\n const { renderFrame } = await import(\"@a-company/atelier-canvas\");\n\n const { imageCache, loaded } = await preloadImages(doc, loadImage);\n\n // Re-fit image layers now that natural dims are known (carousel path).\n let renderDoc = doc;\n if (opts.refitImageBounds && loaded.size > 0) {\n renderDoc = {\n ...doc,\n layers: doc.layers.map((layer) => {\n if (layer.visual.type !== \"image\") return layer;\n const iv = layer.visual as { src?: string; assetId?: string };\n const src = iv.src ?? (iv.assetId ? doc.assets?.[iv.assetId]?.src : undefined);\n const natural = src ? loaded.get(src) : undefined;\n if (!natural || !natural.width || !natural.height) return layer;\n const fit = opts.refitImageBounds!({ canvas: doc.canvas, natural });\n return { ...layer, bounds: fit.bounds, frame: fit.frame };\n }),\n };\n }\n\n const { width: outW, height: outH } = resolveExportDimensions(\n renderDoc.canvas.width,\n renderDoc.canvas.height,\n opts.width,\n opts.height,\n );\n\n const resolved = resolveFrame(renderDoc, stateName, frameNumber);\n const cvs = createCanvas(outW, outH);\n const ctx = cvs.getContext(\"2d\") as unknown as import(\"@a-company/atelier-canvas\").RenderContext;\n\n const sx = outW / renderDoc.canvas.width;\n const sy = outH / renderDoc.canvas.height;\n if (sx !== 1 || sy !== 1) ctx.scale(sx, sy);\n\n renderFrame(ctx, resolved, renderDoc, imageCache);\n\n return cvs.toBuffer(\"image/png\");\n}\n","import { readdirSync, mkdirSync, writeFileSync, statSync } from \"node:fs\";\nimport { resolve, join, basename, extname, dirname, sep } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument, StudioRecipe } from \"@a-company/atelier-types\";\nimport { loadRecipe, applyRecipeToOverlay } from \"../lib/recipe.js\";\nimport {\n renderDocumentToPng,\n fitImageToCanvas,\n CanvasUnavailableError,\n} from \"../lib/render-image.js\";\n\n/** Image extensions the carousel driver accepts (lower-cased, with leading dot). */\nconst IMAGE_EXTS = new Set([\".png\", \".jpg\", \".jpeg\", \".webp\"]);\n\n/** Default canvas size when neither --width/--height nor a recipe aspect is set. */\nconst DEFAULT_CANVAS = 1080;\n\n/**\n * Expand an --inputs pattern into a sorted list of absolute image file paths.\n *\n * Deliberately minimal (no new glob dependency): supports a directory path\n * (lists all image files within), a single file path, or a single-segment\n * `*`-glob in the final path component (e.g. `shots/*.png`, `shots/img-*`).\n * Multi-segment / recursive globs are out of scope — point --inputs at a\n * directory instead. The returned list is filtered to image extensions and\n * sorted lexicographically so output ordering is stable.\n */\nexport function expandInputs(pattern: string): string[] {\n const abs = resolve(pattern);\n\n // Directory → every image file inside it.\n let isDir = false;\n try {\n isDir = statSync(abs).isDirectory();\n } catch {\n isDir = false;\n }\n if (isDir) {\n return listImages(abs);\n }\n\n const dir = dirname(abs);\n const base = basename(abs);\n\n // Single-segment `*` glob in the final component.\n if (base.includes(\"*\")) {\n const matcher = globToRegExp(base);\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n return entries\n .filter((name) => matcher.test(name) && isImageFile(name))\n .map((name) => join(dir, name))\n .sort();\n }\n\n // Literal file path — keep it only if it is an image file.\n return isImageFile(base) ? [abs] : [];\n}\n\n/** List image files directly within a directory, sorted, as absolute paths. */\nfunction listImages(dir: string): string[] {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n return entries\n .filter(isImageFile)\n .map((name) => join(dir, name))\n .sort();\n}\n\n/** True when a filename has an accepted image extension. */\nfunction isImageFile(name: string): boolean {\n return IMAGE_EXTS.has(extname(name).toLowerCase());\n}\n\n/**\n * Convert a single path-component glob (only `*` and `?` honored) into a\n * RegExp anchored to the whole name. `*` matches any run except the path\n * separator; `?` matches a single non-separator char.\n */\nfunction globToRegExp(glob: string): RegExp {\n const escaped = glob.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = escaped.replace(/\\*/g, `[^${sep === \"\\\\\" ? \"\\\\\\\\\" : sep}]*`).replace(/\\?/g, \".\");\n return new RegExp(`^${pattern}$`);\n}\n\n/**\n * Build a single-frame carousel document for one image: a canvas-sized doc with\n * a background and one fit-to-canvas ImageVisual layer, then the recipe's\n * overlay_rules applied with currentIndex/totalCount threaded so the page-number\n * overlay renders \"i/N\".\n *\n * Pure + synchronous (no node-canvas): image bounds use the canvas-extent\n * fallback because natural dimensions aren't known until node-canvas decodes\n * the file at render time. {@link renderDocumentToPng} re-fits the bounds via\n * `refitImageBounds` once the image is loaded.\n */\nexport function composeCarouselFrameDoc(args: {\n imagePath: string;\n index: number;\n total: number;\n width: number;\n height: number;\n recipe: StudioRecipe;\n background?: string;\n}): AtelierDocument {\n const { imagePath, index, total, width, height, recipe } = args;\n const canvas = { width, height };\n\n // Natural dims unknown here → fitImageToCanvas falls back to canvas extents.\n const fit = fitImageToCanvas(canvas, { width: 0, height: 0 });\n\n const assetId = \"carousel-image-asset\";\n const baseDoc: AtelierDocument = {\n version: \"1.0\",\n name: `carousel-${index}`,\n canvas: { width, height, fps: 30, background: args.background ?? \"#000000\" },\n assets: { [assetId]: { type: \"image\", src: imagePath } },\n layers: [\n {\n id: \"carousel-image\",\n visual: { type: \"image\", assetId, src: imagePath },\n frame: fit.frame,\n bounds: fit.bounds,\n anchorPoint: { x: 0.5, y: 0.5 },\n opacity: 1,\n },\n ],\n states: { default: { duration: 1, deltas: [] } },\n };\n\n // Thread the carousel position so page_number resolves \"i/N\"; handle (if any)\n // is anchored on top of the image.\n return applyRecipeToOverlay(baseDoc, recipe, { currentIndex: index, totalCount: total });\n}\n\n/** Zero-padded sortable filename prefix: width = max(2, digits in N). */\nexport function carouselFileName(index: number, total: number, imagePath: string): string {\n const padWidth = Math.max(2, String(total).length);\n const prefix = String(index).padStart(padWidth, \"0\");\n const ext = extname(imagePath);\n const stem = basename(imagePath, ext);\n return `${prefix}-${stem}.png`;\n}\n\ninterface CarouselOptions {\n inputs: string;\n outDir: string;\n width?: string;\n height?: string;\n frame: string;\n}\n\n/** Parse a positive-integer CLI option, exiting on bad input. */\nfunction parseDim(raw: string | undefined, name: string): number | undefined {\n if (raw === undefined) return undefined;\n const n = parseInt(raw, 10);\n if (isNaN(n) || n <= 0) {\n console.error(`Invalid --${name}: ${raw}`);\n process.exit(1);\n }\n return n;\n}\n\n/**\n * Register `atelier carousel <recipe> --inputs <glob> --out-dir <dir>` — batch\n * compose a folder of images into recipe-overlaid PNGs.\n *\n * For each image i of N: build a fit-to-canvas doc, apply the recipe's\n * overlay_rules with currentIndex=i / totalCount=N (handle + \"i/N\" page-number),\n * render via the shared export-image path, and write a zero-padded sortable\n * PNG into --out-dir.\n */\nexport function carouselCommand(program: Command): void {\n program\n .command(\"carousel <recipe>\")\n .description(\n \"Batch-compose a folder of images into recipe-overlaid PNGs. \" +\n \"Each image becomes a fit-to-canvas post with the recipe's handle + \" +\n \"page-number ('i/N') overlays, written to --out-dir as zero-padded PNGs.\",\n )\n .requiredOption(\"-i, --inputs <glob>\", \"Input images: a directory, file, or single-segment *-glob\")\n .requiredOption(\"-d, --out-dir <dir>\", \"Destination directory for composed PNGs\")\n .option(\"--width <number>\", \"Canvas width (px)\", String(DEFAULT_CANVAS))\n .option(\"--height <number>\", \"Canvas height (px)\", String(DEFAULT_CANVAS))\n .option(\"-f, --frame <number>\", \"Frame to render (defaults to 0)\", \"0\")\n .action(async (recipeRef: string, options: CarouselOptions) => {\n // Resolve the recipe (same chain as other recipe commands).\n let recipe: StudioRecipe;\n try {\n const loaded = loadRecipe(recipeRef);\n recipe = loaded.recipe;\n console.log(`Loaded recipe ${loaded.path}`);\n for (const w of loaded.warnings) console.log(` ⚠ ${w}`);\n } catch (err) {\n console.error(`atelier carousel: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n return;\n }\n\n // Expand inputs.\n const inputs = expandInputs(options.inputs);\n if (inputs.length === 0) {\n console.error(\n `atelier carousel: no image files matched --inputs \"${options.inputs}\" ` +\n `(accepted: ${[...IMAGE_EXTS].join(\", \")})`,\n );\n process.exit(1);\n return;\n }\n\n const width = parseDim(options.width, \"width\") ?? DEFAULT_CANVAS;\n const height = parseDim(options.height, \"height\") ?? DEFAULT_CANVAS;\n const frame = parseInt(options.frame, 10);\n if (isNaN(frame) || frame < 0) {\n console.error(`Invalid frame number: ${options.frame}`);\n process.exit(1);\n return;\n }\n\n // Ensure the destination exists / is writable.\n const outDir = resolve(options.outDir);\n try {\n mkdirSync(outDir, { recursive: true });\n } catch (err) {\n console.error(`atelier carousel: cannot create out-dir ${outDir}: ${(err as Error).message}`);\n process.exit(1);\n return;\n }\n\n const total = inputs.length;\n console.log(`Composing ${total} image${total === 1 ? \"\" : \"s\"} → ${outDir}`);\n\n try {\n for (let n = 0; n < total; n++) {\n const index = n + 1; // 1-based\n const imagePath = inputs[n];\n const doc = composeCarouselFrameDoc({\n imagePath,\n index,\n total,\n width,\n height,\n recipe,\n });\n\n const buffer = await renderDocumentToPng(doc, {\n frame,\n // Re-fit the image to the canvas using real natural dims once decoded.\n refitImageBounds: ({ canvas, natural }) => fitImageToCanvas(canvas, natural),\n });\n\n const outName = carouselFileName(index, total, imagePath);\n writeFileSync(join(outDir, outName), buffer);\n console.log(` [${index}/${total}] ${basename(imagePath)} → ${outName}`);\n }\n } catch (err) {\n if (err instanceof CanvasUnavailableError) {\n console.error(err.message);\n process.exit(1);\n return;\n }\n console.error(`atelier carousel: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n return;\n }\n\n console.log(`\\nDone. ${total} image${total === 1 ? \"\" : \"s\"} → ${outDir}`);\n });\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join, resolve, isAbsolute } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { validateRecipe } from \"@a-company/atelier-schema\";\nimport type {\n StudioRecipe,\n SilencePolicy,\n CaptionStyle,\n CaptionGrouping,\n AtelierDocument,\n Layer,\n OverlayAnchor,\n OverlayTextStyle,\n OverlayPageNumberRule,\n} from \"@a-company/atelier-types\";\nimport type { TrimOptions } from \"../commands/trim.js\";\nimport type { TranscribeOptions } from \"../commands/transcribe.js\";\nimport type { CaptionStyle as RuntimeCaptionStyle, BuildCaptionsOptions } from \"./caption-builder.js\";\n\nexport const RECIPE_VERSION = \"1.0\";\n\nexport interface LoadedRecipe {\n recipe: StudioRecipe;\n /** Absolute path the recipe was read from */\n path: string;\n /** Warnings from validateRecipe (e.g. reserved-field usage) */\n warnings: string[];\n}\n\n/**\n * Resolve a recipe reference to an absolute path.\n *\n * Resolution order (per studio-recipe.md §6.2):\n * 1. <projectDir>/.atelier/recipes/<name>.recipe.{yaml,json}\n * 2. ~/.atelier/recipes/<name>.recipe.{yaml,json}\n * 3. The literal path passed (absolute or relative to cwd)\n *\n * Absolute paths and paths containing slashes skip resolution and load directly.\n */\nexport function resolveRecipePath(pathOrName: string, projectDir?: string): string {\n // Absolute path or contains a path separator — treat as literal\n if (isAbsolute(pathOrName) || pathOrName.includes(\"/\") || pathOrName.includes(\"\\\\\")) {\n return resolve(pathOrName);\n }\n\n const candidates: string[] = [];\n const exts = [\".recipe.yaml\", \".recipe.json\", \".yaml\", \".yml\", \".json\"];\n\n if (projectDir) {\n const projectRecipesDir = join(resolve(projectDir), \".atelier\", \"recipes\");\n for (const ext of exts) candidates.push(join(projectRecipesDir, `${pathOrName}${ext}`));\n }\n const userRecipesDir = join(homedir(), \".atelier\", \"recipes\");\n for (const ext of exts) candidates.push(join(userRecipesDir, `${pathOrName}${ext}`));\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n\n throw new Error(\n `Recipe \"${pathOrName}\" not found. Looked in:\\n${candidates.map((c) => ` ${c}`).join(\"\\n\")}`,\n );\n}\n\n/**\n * Load and validate a recipe from a path or name.\n *\n * Sniffs YAML vs JSON by file extension; falls back to YAML parser when\n * unclear (YAML is a superset of JSON for objects).\n */\nexport function loadRecipe(pathOrName: string, projectDir?: string): LoadedRecipe {\n const path = resolveRecipePath(pathOrName, projectDir);\n const raw = readFileSync(path, \"utf-8\");\n\n let parsed: unknown;\n if (path.endsWith(\".json\")) {\n parsed = JSON.parse(raw);\n } else {\n parsed = parseYaml(raw);\n }\n\n const result = validateRecipe(parsed);\n if (!result.success) {\n const msg = result.errors.map((e) => ` ${e.path}: ${e.message}`).join(\"\\n\");\n throw new Error(`Invalid recipe at ${path}:\\n${msg}`);\n }\n\n return {\n recipe: result.data,\n path,\n warnings: result.warnings ?? [],\n };\n}\n\n/**\n * Generate a starter recipe YAML with every Phase 1 field present and\n * inline comments documenting it. Authors learn the shape by editing.\n */\nexport function scaffoldRecipeYaml(name: string): string {\n return `# Studio Recipe — ${name}\n# Phase 1 — manual authoring + apply\n# https://github.com/ascend42/a-atelier/blob/main/.paradigm/specs/studio-recipe.md\n\nversion: \"${RECIPE_VERSION}\"\nname: \"${name}\"\ndescription: \"\"\nauthor: \"\"\ntags: []\n\n# ── Silence-trim policy — consumed by \\`atelier trim\\` ───────────────────\nsilence_policy:\n # silencedetect noise threshold (default: -30dB)\n noise: \"-30dB\"\n # Minimum silence duration to register, in seconds (default: 0.35)\n min_silence: 0.35\n # Default leading padding for new cuts, in seconds (default: 0.08)\n default_padding_pre: 0.08\n # Default trailing padding for new cuts, in seconds (default: 0.12)\n default_padding_post: 0.12\n # Re-detect match tolerance for preserving user padding, in seconds (default: 0.5)\n match_tolerance: 0.5\n\n# ── Caption visual style — consumed by \\`atelier transcribe\\` ────────────\ncaption_style:\n font_family: \"Inter\"\n font_size: 84\n font_weight: \"bold\" # normal | bold | numeric (100..900)\n text_align: \"center\" # left | center | right\n color: \"#FFFFFF\"\n y_ratio: 0.85 # 0=top, 1=bottom\n width_ratio: 0.9\n fade_seconds: 0.05\n\n# ── Caption phrase grouping — consumed by \\`atelier transcribe\\` ─────────\ncaption_grouping:\n max_words: 5\n pause_gap: 0.4\n\n# ── Overlay rules (Phase 1.5) — anchored handle + page-number overlays ─\n# overlay_rules:\n# handle:\n# text: \"@username\"\n# anchor: \"bottom-left\" # top-left | top-right | bottom-left | bottom-right\n# margin: 24 # px from anchored edges\n# style:\n# font_family: \"Inter\"\n# font_size: 36\n# font_weight: \"bold\"\n# color: \"#FFFFFF\"\n# page_number:\n# format: \"{current}/{total}\" # supports {current:02d} / {total:02d} zero-pad\n# anchor: \"top-right\"\n# margin: 24\n# style:\n# font_family: \"Inter\"\n# font_size: 36\n# font_weight: \"normal\"\n# color: \"#FFFFFF\"\n\n# ── Phase 3 fields (reserved — Phase 1 ignores these) ──────────────────\n# caption_highlight: {}\n# transition_kit: {}\n# palette: {}\n# audio_policy: {}\n# aspect_targets: []\n`;\n}\n\n// ─── Recipe → CLI options translation ─────────────────────────────\n\n/**\n * Merge a recipe's silence_policy into TrimOptions.\n * CLI options take precedence (per studio-recipe.md §4.1).\n */\nexport function applyRecipeToTrimOptions(\n recipe: StudioRecipe | undefined,\n cliOptions: TrimOptions,\n): TrimOptions {\n const policy = recipe?.silence_policy;\n if (!policy) return cliOptions;\n\n // CLI options win — only fill in from recipe where CLI didn't specify\n return {\n ...cliOptions,\n noise: cliOptions.noise ?? policy.noise,\n minSilence: cliOptions.minSilence ?? policy.min_silence,\n padPre: cliOptions.padPre ?? policy.default_padding_pre,\n padPost: cliOptions.padPost ?? policy.default_padding_post,\n // matchTolerance is recipe-only at this layer (no CLI flag yet)\n matchTolerance: cliOptions.matchTolerance ?? policy.match_tolerance,\n };\n}\n\n/**\n * Translate a recipe's caption_style + caption_grouping into runtime\n * BuildCaptionsOptions for the caption builder.\n *\n * CLI doesn't currently expose per-invocation caption styling flags;\n * the recipe is the canonical source for now.\n */\nexport function applyRecipeToCaptionOptions(\n recipe: StudioRecipe | undefined,\n): BuildCaptionsOptions {\n if (!recipe) return {};\n const style = recipe.caption_style;\n const grouping = recipe.caption_grouping;\n\n const runtimeStyle: RuntimeCaptionStyle = {};\n if (style) {\n if (style.font_family !== undefined) runtimeStyle.fontFamily = style.font_family;\n if (style.font_size !== undefined) runtimeStyle.fontSize = style.font_size;\n if (style.font_weight !== undefined) runtimeStyle.fontWeight = style.font_weight;\n if (style.text_align !== undefined) runtimeStyle.textAlign = style.text_align;\n if (style.color !== undefined) runtimeStyle.color = style.color;\n if (style.y_ratio !== undefined) runtimeStyle.yRatio = style.y_ratio;\n if (style.width_ratio !== undefined) runtimeStyle.widthRatio = style.width_ratio;\n if (style.fade_seconds !== undefined) runtimeStyle.fadeSeconds = style.fade_seconds;\n }\n\n return {\n ...(Object.keys(runtimeStyle).length > 0 && { style: runtimeStyle }),\n ...(grouping?.max_words !== undefined && { maxWords: grouping.max_words }),\n ...(grouping?.pause_gap !== undefined && { pauseGap: grouping.pause_gap }),\n };\n}\n\n/**\n * Merge a recipe into TranscribeOptions. Caption-related recipe fields\n * are stashed on the transcribe options so the orchestrator can pass them\n * through to rewriteCaptionLayers.\n */\nexport function applyRecipeToTranscribeOptions(\n recipe: StudioRecipe | undefined,\n cliOptions: TranscribeOptions,\n): TranscribeOptions {\n if (!recipe) return cliOptions;\n const captionOptions = applyRecipeToCaptionOptions(recipe);\n return {\n ...cliOptions,\n captionOptions,\n };\n}\n\n/**\n * Render a recipe's effective values (recipe overlaid on code defaults).\n * Used by `atelier recipe show --with-defaults`.\n */\nexport function renderRecipeWithDefaults(recipe: StudioRecipe): StudioRecipe {\n const defaults: { silence_policy: SilencePolicy; caption_style: CaptionStyle; caption_grouping: CaptionGrouping } = {\n silence_policy: {\n noise: \"-30dB\",\n min_silence: 0.35,\n default_padding_pre: 0.08,\n default_padding_post: 0.12,\n match_tolerance: 0.5,\n },\n caption_style: {\n font_family: \"Inter\",\n font_size: 84,\n font_weight: \"bold\",\n text_align: \"center\",\n color: \"#FFFFFF\",\n y_ratio: 0.85,\n width_ratio: 0.9,\n fade_seconds: 0.05,\n },\n caption_grouping: {\n max_words: 5,\n pause_gap: 0.4,\n },\n };\n\n return {\n ...recipe,\n silence_policy: { ...defaults.silence_policy, ...recipe.silence_policy },\n caption_style: { ...defaults.caption_style, ...recipe.caption_style },\n caption_grouping: { ...defaults.caption_grouping, ...recipe.caption_grouping },\n };\n}\n\n/** Serialize a recipe back to YAML for `recipe show` output */\nexport function recipeToYaml(recipe: StudioRecipe): string {\n return stringifyYaml(recipe);\n}\n\n// ─── Overlay translator ──────────────────────────────────────────\n//\n// Translates recipe.overlay_rules → tag-isolated TextVisual layers\n// (handle + page_number). Mirrors rewriteCaptionLayers' tag-namespace\n// isolation invariant: only \"overlay\"-tagged layers are touched; all\n// user-authored / silence-trim / caption layers pass through untouched.\n// Re-applying is idempotent — the prior overlay set is dropped before\n// the fresh one is appended.\n\n/** Context for overlay translation — required for page_number rendering */\nexport interface ApplyOverlayContext {\n /** 1-based index in a carousel (substituted for {current}) */\n currentIndex?: number;\n /** Total carousel size (substituted for {total}) */\n totalCount?: number;\n}\n\n/** Default px from the anchored edges when a rule omits margin */\nconst DEFAULT_OVERLAY_MARGIN = 24;\n\n/** Default TextStyle baseline — overlay rule.style merges OVER these */\nconst DEFAULT_OVERLAY_TEXT_STYLE = {\n fontFamily: \"Inter\",\n fontSize: 24,\n fontWeight: 600 as const,\n color: \"#F5F5F7\",\n};\n\n/** Stable layer ids — re-apply replaces by id within the overlay drop+re-add */\nconst HANDLE_LAYER_ID = \"overlay-handle\";\nconst PAGE_NUMBER_LAYER_ID = \"overlay-page-number\";\n\n/**\n * Apply a Studio Recipe's overlay_rules to a document. Returns a NEW document;\n * input is never mutated. Drops every layer tagged \"overlay\" before appending\n * the freshly-derived overlay layers, so re-running is idempotent.\n *\n * page_number layers are only emitted when ctx.currentIndex + ctx.totalCount\n * are both present — single-frame application silently skips page_number\n * (with a one-shot console.warn) so apply-recipe pipelines stay safe outside\n * carousel batches.\n */\nexport function applyRecipeToOverlay(\n doc: AtelierDocument,\n recipe: StudioRecipe,\n ctx?: ApplyOverlayContext,\n): AtelierDocument {\n const preserved = doc.layers.filter((l) => !(l.tags ?? []).includes(\"overlay\"));\n const overlayLayers: Layer[] = [];\n\n const rules = recipe.overlay_rules;\n if (!rules) {\n return { ...doc, layers: preserved };\n }\n\n if (rules.handle) {\n overlayLayers.push(buildHandleLayer(rules.handle, doc.canvas));\n }\n\n if (rules.page_number) {\n if (ctx?.currentIndex != null && ctx?.totalCount != null) {\n overlayLayers.push(\n buildPageNumberLayer(rules.page_number, doc.canvas, ctx.currentIndex, ctx.totalCount),\n );\n } else {\n console.warn(\n `applyRecipeToOverlay: recipe.overlay_rules.page_number present but ` +\n `currentIndex/totalCount not provided — skipping page_number layer.`,\n );\n }\n }\n\n return {\n ...doc,\n layers: [...preserved, ...overlayLayers],\n };\n}\n\n/** Build the anchored handle TextVisual layer */\nfunction buildHandleLayer(\n rule: { text: string; anchor: OverlayAnchor; margin?: number; style?: OverlayTextStyle },\n canvas: AtelierDocument[\"canvas\"],\n): Layer {\n const margin = rule.margin ?? DEFAULT_OVERLAY_MARGIN;\n const { frame, anchorPoint } = anchorToFrame(rule.anchor, canvas, margin);\n return {\n id: HANDLE_LAYER_ID,\n tags: [\"overlay\"],\n visual: {\n type: \"text\",\n content: rule.text,\n style: mergeOverlayStyle(rule.style),\n },\n frame,\n bounds: { width: 600, height: 80 },\n anchorPoint,\n };\n}\n\n/** Build the anchored page-number TextVisual layer */\nfunction buildPageNumberLayer(\n rule: OverlayPageNumberRule,\n canvas: AtelierDocument[\"canvas\"],\n currentIndex: number,\n totalCount: number,\n): Layer {\n const margin = rule.margin ?? DEFAULT_OVERLAY_MARGIN;\n const { frame, anchorPoint } = anchorToFrame(rule.anchor, canvas, margin);\n return {\n id: PAGE_NUMBER_LAYER_ID,\n tags: [\"overlay\"],\n visual: {\n type: \"text\",\n content: renderPageNumberFormat(rule.format, currentIndex, totalCount),\n style: mergeOverlayStyle(rule.style),\n },\n frame,\n bounds: { width: 200, height: 80 },\n anchorPoint,\n };\n}\n\n/** Anchor enum → frame coords + 0/1 anchorPoint */\nfunction anchorToFrame(\n anchor: OverlayAnchor,\n canvas: AtelierDocument[\"canvas\"],\n margin: number,\n): { frame: { x: number; y: number }; anchorPoint: { x: number; y: number } } {\n switch (anchor) {\n case \"top-left\":\n return { frame: { x: margin, y: margin }, anchorPoint: { x: 0, y: 0 } };\n case \"top-right\":\n return { frame: { x: canvas.width - margin, y: margin }, anchorPoint: { x: 1, y: 0 } };\n case \"bottom-left\":\n return { frame: { x: margin, y: canvas.height - margin }, anchorPoint: { x: 0, y: 1 } };\n case \"bottom-right\":\n return {\n frame: { x: canvas.width - margin, y: canvas.height - margin },\n anchorPoint: { x: 1, y: 1 },\n };\n }\n}\n\n/** Merge a partial OverlayTextStyle over the runtime defaults (always returns a complete TextStyle) */\nfunction mergeOverlayStyle(\n style: OverlayTextStyle | undefined,\n): { fontFamily: string; fontSize: number; fontWeight: number | \"normal\" | \"bold\"; color: string } {\n return {\n fontFamily: style?.font_family ?? DEFAULT_OVERLAY_TEXT_STYLE.fontFamily,\n fontSize: style?.font_size ?? DEFAULT_OVERLAY_TEXT_STYLE.fontSize,\n fontWeight: style?.font_weight ?? DEFAULT_OVERLAY_TEXT_STYLE.fontWeight,\n color: style?.color ?? DEFAULT_OVERLAY_TEXT_STYLE.color,\n };\n}\n\n/**\n * Render a page_number format template by substituting {current} / {total}\n * placeholders (including zero-pad forms like {current:02d}, {total:02d}).\n *\n * The schema (^valid-recipe gate) already enforces that ≥1 placeholder is\n * present — this is render-time substitution only.\n */\nexport function renderPageNumberFormat(\n format: string,\n currentIndex: number,\n totalCount: number,\n): string {\n return format.replace(\n /\\{(current|total)(?::0(\\d+)d)?\\}/g,\n (_, name: string, padWidth?: string) => {\n const value = name === \"current\" ? currentIndex : totalCount;\n const str = String(value);\n if (padWidth) {\n const width = parseInt(padWidth, 10);\n return str.padStart(width, \"0\");\n }\n return str;\n },\n );\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument, ImageVisual } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\n\n/** Asset summary entry */\nexport interface AssetInfo {\n assetId: string;\n type: string;\n src: string;\n description?: string;\n usedByLayers: string[];\n usedByStates: string[];\n}\n\n/**\n * Extract asset info from a parsed AtelierDocument.\n */\nexport function getAssets(doc: AtelierDocument): AssetInfo[] {\n const assets = doc.assets ?? {};\n return Object.entries(assets).map(([assetId, asset]) => {\n const usedByLayers = doc.layers\n .filter(l => l.visual.type === \"image\" && (l.visual as ImageVisual).assetId === assetId)\n .map(l => l.id);\n\n const usedByStates = Object.entries(doc.states)\n .filter(([, state]) => state.audio?.src === assetId)\n .map(([name]) => name);\n\n return {\n assetId,\n type: asset.type,\n src: asset.src,\n description: asset.description,\n usedByLayers,\n usedByStates,\n };\n });\n}\n\n/**\n * Format asset info for terminal output.\n */\nfunction formatAssets(assets: AssetInfo[]): string {\n if (assets.length === 0) return \"No assets registered.\";\n\n const lines: string[] = [`Assets: ${assets.length}`];\n for (const a of assets) {\n const desc = a.description ? ` — ${a.description}` : \"\";\n lines.push(` - ${a.assetId} (${a.type}): ${a.src}${desc}`);\n if (a.usedByLayers.length > 0) {\n lines.push(` Layers: ${a.usedByLayers.join(\", \")}`);\n }\n if (a.usedByStates.length > 0) {\n lines.push(` States: ${a.usedByStates.join(\", \")}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `assets` subcommand on the Commander program.\n */\nexport function assetsCommand(program: Command): void {\n program\n .command(\"assets <file>\")\n .description(\"List all assets in an .atelier file with usage info\")\n .action((file: string) => {\n const doc = readAndParse(file);\n const assets = getAssets(doc);\n console.log(formatAssets(assets));\n });\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport type { AtelierDocument } from \"@a-company/atelier-types\";\nimport { parseAtelier } from \"@a-company/atelier-schema\";\nimport { findTemplateVariables } from \"@a-company/atelier-core\";\n\n/** Variable summary entry */\nexport interface VariableInfo {\n name: string;\n type: string;\n description?: string;\n default?: unknown;\n referenced: boolean;\n}\n\n/**\n * Extract variable info from a parsed AtelierDocument.\n */\nexport function getVariables(doc: AtelierDocument): { variables: VariableInfo[]; undeclared: string[] } {\n const variables = doc.variables ?? {};\n const referenced = findTemplateVariables(doc);\n\n const entries = Object.entries(variables).map(([name, variable]) => ({\n name,\n type: variable.type,\n description: variable.description,\n default: variable.default,\n referenced: referenced.includes(name),\n }));\n\n const undeclared = referenced.filter(r => !variables[r]);\n\n return { variables: entries, undeclared };\n}\n\n/**\n * Format variable info for terminal output.\n */\nfunction formatVariables(info: { variables: VariableInfo[]; undeclared: string[] }): string {\n if (info.variables.length === 0 && info.undeclared.length === 0) return \"No variables declared or referenced.\";\n\n const lines: string[] = [];\n\n if (info.variables.length > 0) {\n lines.push(`Variables: ${info.variables.length}`);\n for (const v of info.variables) {\n const desc = v.description ? ` — ${v.description}` : \"\";\n const def = v.default !== undefined ? ` [default: ${JSON.stringify(v.default)}]` : \"\";\n const ref = v.referenced ? \"\" : \" (unused)\";\n lines.push(` - {{${v.name}}} (${v.type})${def}${desc}${ref}`);\n }\n }\n\n if (info.undeclared.length > 0) {\n lines.push(`Undeclared references: ${info.undeclared.length}`);\n for (const name of info.undeclared) {\n lines.push(` - {{${name}}} (not declared in variables)`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Read and parse an .atelier file, exiting on failure. */\nfunction readAndParse(file: string): AtelierDocument {\n const absPath = resolve(file);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n console.error(`Cannot read file: ${absPath}`);\n return process.exit(1);\n }\n\n const result = parseAtelier(content);\n if (!result.success) {\n console.error(\"Parse errors:\");\n for (const error of result.errors) {\n console.error(` - ${error.path}: ${error.message}`);\n }\n return process.exit(1);\n }\n\n return result.data;\n}\n\n/**\n * Register the `variables` subcommand on the Commander program.\n */\nexport function variablesCommand(program: Command): void {\n program\n .command(\"variables <file>\")\n .description(\"List all variables in an .atelier file with usage info\")\n .action((file: string) => {\n const doc = readAndParse(file);\n const info = getVariables(doc);\n console.log(formatVariables(info));\n });\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from \"node:fs\";\nimport { join, basename, extname, resolve } from \"node:path\";\nimport type { AtelierDocument, Layer } from \"@a-company/atelier-types\";\nimport type {\n CutEntry,\n VideoCutList,\n VideoTranscript,\n VideoProjectManifest,\n} from \"@a-company/atelier-types\";\n\nexport const VIDEO_PROJECT_VERSION = \"1.0\";\nexport const VIDEO_CUTLIST_VERSION = \"1.1\";\nexport const VIDEO_TRANSCRIPT_VERSION = \"1.1\";\n\n/**\n * Compute the effective in/out span for a cut, clamped to source bounds.\n * `start = max(0, rawStart - paddingPre)`, `end = min(duration, rawEnd + paddingPost)`.\n */\nexport function effectiveSpan(\n cut: CutEntry,\n duration: number,\n): { start: number; end: number } {\n return {\n start: Math.max(0, cut.rawStart - cut.paddingPre),\n end: Math.min(duration, cut.rawEnd + cut.paddingPost),\n };\n}\n\n/** Resolved absolute paths for all files in a VideoProject folder */\nexport interface VideoProject {\n /** Absolute path to the project folder */\n dir: string;\n /** Absolute path to source video file */\n sourcePath: string;\n /** Absolute path to project.atelier composition */\n compositionPath: string;\n /** Absolute path to transcript.json */\n transcriptPath: string;\n /** Absolute path to cuts.json */\n cutsPath: string;\n /** Absolute path to export/ directory */\n exportDir: string;\n /** Manifest metadata */\n manifest: VideoProjectManifest;\n}\n\n/**\n * Scaffold a new VideoProject folder from a source video file.\n *\n * Creates the folder at `destDir` (defaults to same directory as source,\n * named after the video file without extension). Copies the source video\n * into the folder as \"source<ext>\". Writes an empty draft project.atelier,\n * an empty cuts.json, and creates the export/ directory.\n *\n * Does NOT run metadata extraction — the caller (`atelier edit`, T-005)\n * probes duration/fps via ffprobe and fills in videoMeta before saving.\n */\nexport async function createVideoProject(\n srcPath: string,\n destDir?: string,\n): Promise<VideoProject> {\n const absSrc = resolve(srcPath);\n const ext = extname(absSrc);\n const stem = basename(absSrc, ext);\n\n const projectDir = destDir ? resolve(destDir) : join(resolve(absSrc, \"..\"), stem);\n\n if (!existsSync(projectDir)) {\n mkdirSync(projectDir, { recursive: true });\n }\n\n const sourceFilename = `source${ext}`;\n const sourcePath = join(projectDir, sourceFilename);\n\n // Copy source only if not already in place (idempotent re-init)\n if (!existsSync(sourcePath)) {\n copyFileSync(absSrc, sourcePath);\n }\n\n const compositionPath = join(projectDir, \"project.atelier\");\n const transcriptPath = join(projectDir, \"transcript.json\");\n const cutsPath = join(projectDir, \"cuts.json\");\n const exportDir = join(projectDir, \"export\");\n\n if (!existsSync(exportDir)) {\n mkdirSync(exportDir, { recursive: true });\n }\n\n const manifest: VideoProjectManifest = {\n source: sourceFilename,\n composition: \"project.atelier\",\n transcript: \"transcript.json\",\n cuts: \"cuts.json\",\n exportDir: \"export/\",\n createdAt: new Date().toISOString(),\n version: VIDEO_PROJECT_VERSION,\n };\n\n // Draft composition — caller fills in canvas dimensions and videoMeta after probing\n const draft: AtelierDocument = {\n version: \"1.0\",\n name: stem,\n canvas: { width: 1920, height: 1080, fps: 30 },\n assets: {\n src: {\n type: \"video\",\n src: sourceFilename,\n description: `Source: ${basename(absSrc)}`,\n },\n },\n layers: [\n {\n id: \"clip-0\",\n visual: {\n type: \"video\",\n assetId: \"src\",\n src: sourceFilename,\n startFrame: 0,\n sourceOffset: 0,\n playbackRate: 1.0,\n objectFit: \"contain\",\n },\n frame: { x: 0, y: 0 },\n bounds: { width: 1920, height: 1080 },\n },\n ],\n states: {\n default: {\n duration: 0,\n deltas: [],\n },\n },\n };\n\n if (!existsSync(compositionPath)) {\n writeFileSync(compositionPath, JSON.stringify(draft, null, 2), \"utf-8\");\n }\n\n const initialCuts: VideoCutList = {\n version: VIDEO_CUTLIST_VERSION,\n source: sourceFilename,\n cuts: [],\n };\n\n if (!existsSync(cutsPath)) {\n writeFileSync(cutsPath, JSON.stringify(initialCuts, null, 2), \"utf-8\");\n }\n\n return {\n dir: projectDir,\n sourcePath,\n compositionPath,\n transcriptPath,\n cutsPath,\n exportDir,\n manifest,\n };\n}\n\n/**\n * Load an existing VideoProject from a folder path.\n * Does not validate that the composition or cut list are well-formed —\n * callers that need that should use lintFile() after loading.\n */\nexport function loadVideoProject(dir: string): VideoProject {\n const projectDir = resolve(dir);\n\n // Detect source file (source.mp4, source.mov, etc.)\n const possibleExts = [\".mp4\", \".mov\", \".webm\", \".mkv\", \".avi\"];\n let sourceFilename = \"source.mp4\";\n for (const ext of possibleExts) {\n if (existsSync(join(projectDir, `source${ext}`))) {\n sourceFilename = `source${ext}`;\n break;\n }\n }\n\n const manifest: VideoProjectManifest = {\n source: sourceFilename,\n composition: \"project.atelier\",\n transcript: \"transcript.json\",\n cuts: \"cuts.json\",\n exportDir: \"export/\",\n createdAt: new Date().toISOString(),\n version: VIDEO_PROJECT_VERSION,\n };\n\n return {\n dir: projectDir,\n sourcePath: join(projectDir, sourceFilename),\n compositionPath: join(projectDir, \"project.atelier\"),\n transcriptPath: join(projectDir, \"transcript.json\"),\n cutsPath: join(projectDir, \"cuts.json\"),\n exportDir: join(projectDir, \"export\"),\n manifest,\n };\n}\n\n/**\n * Read and parse cuts.json from a VideoProject.\n *\n * Migrates legacy 1.0 cuts (flat { start, end }) to 1.1 parametric form\n * (rawStart/rawEnd + zero padding) on the fly. Writers always emit 1.1.\n */\nexport function readCutList(project: VideoProject): VideoCutList {\n if (!existsSync(project.cutsPath)) {\n return { version: VIDEO_CUTLIST_VERSION, source: project.manifest.source, cuts: [] };\n }\n const raw = JSON.parse(readFileSync(project.cutsPath, \"utf-8\")) as {\n version?: string;\n source: string;\n cuts: Array<CutEntry | { start: number; end: number; label?: string }>;\n };\n\n const cuts: CutEntry[] = raw.cuts.map((entry) => {\n if (\"rawStart\" in entry) return entry;\n // Legacy 1.0 migration — stored start/end become rawStart/rawEnd with zero padding.\n return {\n rawStart: entry.start,\n rawEnd: entry.end,\n paddingPre: 0,\n paddingPost: 0,\n ...(entry.label !== undefined && { label: entry.label }),\n };\n });\n\n return {\n version: VIDEO_CUTLIST_VERSION,\n source: raw.source,\n cuts,\n };\n}\n\n/** Write cuts.json to a VideoProject (always at the current cut list version) */\nexport function writeCutList(project: VideoProject, cuts: VideoCutList): void {\n const payload: VideoCutList = { ...cuts, version: VIDEO_CUTLIST_VERSION };\n writeFileSync(project.cutsPath, JSON.stringify(payload, null, 2), \"utf-8\");\n}\n\n/**\n * Read and parse transcript.json from a VideoProject.\n *\n * Migrates legacy 1.0 transcripts (TranscriptWord had flat `word: string`)\n * to 1.1 (`detected` + `text` + flags) on the fly. Writers always emit 1.1.\n */\nexport function readTranscript(project: VideoProject): VideoTranscript | null {\n if (!existsSync(project.transcriptPath)) return null;\n const raw = JSON.parse(readFileSync(project.transcriptPath, \"utf-8\")) as {\n version?: string;\n language?: string;\n segments: Array<{\n text: string;\n start: number;\n end: number;\n words: Array<\n // 1.1 shape\n | { detected: string; text: string; start: number; end: number; confidence?: number; userEdited?: boolean; userAdded?: boolean; hidden?: boolean }\n // 1.0 legacy shape\n | { word: string; start: number; end: number; confidence?: number }\n >;\n }>;\n };\n\n const segments = raw.segments.map((seg) => ({\n text: seg.text,\n start: seg.start,\n end: seg.end,\n words: seg.words.map((w) => {\n if (\"detected\" in w) return w;\n // 1.0 migration — `word` becomes both detected and text\n return {\n detected: w.word,\n text: w.word,\n start: w.start,\n end: w.end,\n ...(w.confidence !== undefined && { confidence: w.confidence }),\n };\n }),\n }));\n\n return {\n version: VIDEO_TRANSCRIPT_VERSION,\n ...(raw.language !== undefined && { language: raw.language }),\n segments,\n };\n}\n\n/** Write transcript.json to a VideoProject (always at the current transcript version) */\nexport function writeTranscript(project: VideoProject, transcript: VideoTranscript): void {\n const payload: VideoTranscript = { ...transcript, version: VIDEO_TRANSCRIPT_VERSION };\n writeFileSync(project.transcriptPath, JSON.stringify(payload, null, 2), \"utf-8\");\n}\n\n/** Read and parse project.atelier from a VideoProject */\nexport function readComposition(project: VideoProject): AtelierDocument {\n return JSON.parse(readFileSync(project.compositionPath, \"utf-8\")) as AtelierDocument;\n}\n\n/** Write project.atelier to a VideoProject */\nexport function writeComposition(project: VideoProject, doc: AtelierDocument): void {\n writeFileSync(project.compositionPath, JSON.stringify(doc, null, 2), \"utf-8\");\n}\n\n/**\n * Rewrite the silence-trim layers in a composition from a current cut list.\n *\n * Drops every layer tagged \"silence-trim\" then appends one VideoVisual layer\n * per cut, in temporal order, with cumulative startFrame computed from prior\n * clip durations. All other layers (user-authored, captions, overlays) are\n * preserved untouched — this is the tag-namespace isolation invariant.\n */\nexport function rewriteCutLayers(\n doc: AtelierDocument,\n cuts: CutEntry[],\n sourceFilename: string,\n sourceDuration: number,\n assetId = \"src\",\n): AtelierDocument {\n const preserved = doc.layers.filter((l) => !(l.tags ?? []).includes(\"silence-trim\"));\n const fps = doc.canvas.fps;\n\n let cumulativeFrame = 0;\n const trimLayers: Layer[] = cuts.map((cut, idx) => {\n const span = effectiveSpan(cut, sourceDuration);\n const sourceOffsetFrames = Math.floor(span.start * fps) / fps;\n const sourceEndFrames = Math.ceil(span.end * fps) / fps;\n const durationFrames = Math.max(1, Math.round((sourceEndFrames - sourceOffsetFrames) * fps));\n\n const layer: Layer = {\n id: `clip-trim-${idx}`,\n tags: [\"silence-trim\"],\n visual: {\n type: \"video\",\n assetId,\n src: sourceFilename,\n startFrame: cumulativeFrame,\n sourceOffset: sourceOffsetFrames,\n sourceEnd: sourceEndFrames,\n playbackRate: 1.0,\n objectFit: \"contain\",\n },\n frame: { x: 0, y: 0 },\n bounds: { width: doc.canvas.width, height: doc.canvas.height },\n };\n cumulativeFrame += durationFrames;\n return layer;\n });\n\n return { ...doc, layers: [...preserved, ...trimLayers] };\n}\n","import { spawn } from \"node:child_process\";\n\n/** A detected silence interval, in seconds from source start */\nexport interface SilenceInterval {\n start: number;\n end: number;\n}\n\n/** Options for the ffmpeg silencedetect filter */\nexport interface SilenceDetectOptions {\n /** Threshold below which audio counts as silence (default: \"-30dB\") */\n noise?: string;\n /** Minimum silence duration in seconds to register (default: 0.35) */\n minSilence?: number;\n}\n\n/**\n * Verify the local ffmpeg build has the silencedetect filter compiled in.\n * Fails loud and early if missing — some minimal builds disable filters.\n */\nexport async function probeSilencedetect(): Promise<void> {\n const stdout = await runCapture(\"ffmpeg\", [\"-hide_banner\", \"-filters\"]);\n if (!/\\bsilencedetect\\b/.test(stdout)) {\n throw new Error(\n \"Your ffmpeg build lacks the silencedetect filter. \" +\n \"Install a standard ffmpeg ≥ 4.0 (brew install ffmpeg / apt install ffmpeg).\",\n );\n }\n}\n\n/**\n * Probe source video duration via ffprobe, in seconds.\n * Used for boundary clamping of the trailing cut.\n */\nexport async function probeDuration(sourcePath: string): Promise<number> {\n const stdout = await runCapture(\"ffprobe\", [\n \"-v\", \"error\",\n \"-show_entries\", \"format=duration\",\n \"-of\", \"csv=p=0\",\n sourcePath,\n ]);\n const n = parseFloat(stdout.trim());\n if (!Number.isFinite(n) || n <= 0) {\n throw new Error(`ffprobe returned invalid duration for ${sourcePath}: \"${stdout}\"`);\n }\n return n;\n}\n\n/**\n * Run ffmpeg silencedetect on a source file, return list of silence intervals.\n *\n * silencedetect writes paired lines to stderr:\n * [silencedetect @ 0x...] silence_start: 1.234\n * [silencedetect @ 0x...] silence_end: 5.678 | silence_duration: 4.444\n *\n * Output to null muxer — no decoded frames, just the filter walking the audio.\n */\nexport async function runSilenceDetect(\n sourcePath: string,\n options: SilenceDetectOptions = {},\n): Promise<SilenceInterval[]> {\n const noise = options.noise ?? \"-30dB\";\n const minSilence = options.minSilence ?? 0.35;\n const filter = `silencedetect=noise=${noise}:d=${minSilence}`;\n\n const stderr = await runCaptureStderr(\"ffmpeg\", [\n \"-hide_banner\",\n \"-nostats\",\n \"-i\", sourcePath,\n \"-af\", filter,\n \"-f\", \"null\",\n \"-\",\n ]);\n\n return parseSilenceDetectStderr(stderr);\n}\n\n/**\n * Parse ffmpeg's silencedetect stderr output into intervals.\n * Pairs start/end lines in order; tolerates other filter chatter interleaved.\n * Exported for unit testing.\n */\nexport function parseSilenceDetectStderr(stderr: string): SilenceInterval[] {\n const intervals: SilenceInterval[] = [];\n const startRe = /silence_start:\\s*(-?[\\d.]+)/;\n const endRe = /silence_end:\\s*(-?[\\d.]+)/;\n\n let pendingStart: number | null = null;\n for (const line of stderr.split(/\\r?\\n/)) {\n const sm = line.match(startRe);\n if (sm) {\n pendingStart = parseFloat(sm[1]);\n continue;\n }\n const em = line.match(endRe);\n if (em && pendingStart !== null) {\n const end = parseFloat(em[1]);\n // silencedetect can emit start <0 if audio starts in silence — clamp\n intervals.push({ start: Math.max(0, pendingStart), end });\n pendingStart = null;\n }\n }\n return intervals;\n}\n\n// ─── subprocess plumbing ─────────────────────────────────────────\n\nfunction runCapture(cmd: string, args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const proc = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n proc.stdout.on(\"data\", (b) => (stdout += b.toString()));\n proc.on(\"error\", (err) => {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\") {\n reject(new Error(`${cmd} not found on PATH. Install ffmpeg/ffprobe (brew install ffmpeg).`));\n } else {\n reject(err);\n }\n });\n proc.on(\"close\", (code) => {\n if (code !== 0) reject(new Error(`${cmd} exited ${code}`));\n else resolve(stdout);\n });\n });\n}\n\nfunction runCaptureStderr(cmd: string, args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const proc = spawn(cmd, args, { stdio: [\"ignore\", \"ignore\", \"pipe\"] });\n let stderr = \"\";\n proc.stderr.on(\"data\", (b) => (stderr += b.toString()));\n proc.on(\"error\", (err) => {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\") {\n reject(new Error(`${cmd} not found on PATH. Install ffmpeg (brew install ffmpeg).`));\n } else {\n reject(err);\n }\n });\n // null muxer always exits non-zero on EOF in some ffmpeg builds — accept any code\n proc.on(\"close\", () => resolve(stderr));\n });\n}\n","import type { CutEntry } from \"@a-company/atelier-types\";\nimport type { SilenceInterval } from \"./silence-detect.js\";\n\n/** A detected speech span (inverse of silence) — pre-padding */\nexport interface SpeechInterval {\n start: number;\n end: number;\n}\n\n/** Default leading/trailing padding around each detected speech segment */\nexport const DEFAULT_PADDING_PRE = 0.08;\nexport const DEFAULT_PADDING_POST = 0.12;\n\n/** Match tolerance (seconds) for preserving user padding on re-detect */\nexport const DEFAULT_MATCH_TOLERANCE = 0.5;\n\n/**\n * Invert silence intervals into the gaps between them — the speech intervals.\n * Handles leading and trailing silence (no speech before first silence /\n * after last silence respectively).\n */\nexport function invertToSpeechIntervals(\n silences: SilenceInterval[],\n duration: number,\n): SpeechInterval[] {\n if (silences.length === 0) {\n return duration > 0 ? [{ start: 0, end: duration }] : [];\n }\n\n const sorted = [...silences].sort((a, b) => a.start - b.start);\n const speech: SpeechInterval[] = [];\n\n // Leading speech (before first silence)\n if (sorted[0].start > 0) {\n speech.push({ start: 0, end: sorted[0].start });\n }\n\n // Speech between adjacent silences\n for (let i = 0; i < sorted.length - 1; i++) {\n const gapStart = sorted[i].end;\n const gapEnd = sorted[i + 1].start;\n if (gapEnd > gapStart) {\n speech.push({ start: gapStart, end: gapEnd });\n }\n }\n\n // Trailing speech (after last silence)\n const last = sorted[sorted.length - 1];\n if (last.end < duration) {\n speech.push({ start: last.end, end: duration });\n }\n\n return speech;\n}\n\n/** Build initial CutEntry[] from speech intervals using default padding */\nexport function buildInitialCuts(\n speech: SpeechInterval[],\n paddingPre = DEFAULT_PADDING_PRE,\n paddingPost = DEFAULT_PADDING_POST,\n): CutEntry[] {\n return speech.map((s) => ({\n rawStart: s.start,\n rawEnd: s.end,\n paddingPre,\n paddingPost,\n }));\n}\n\n/**\n * Resolve overlap between adjacent cuts (when paddingPost[i] + paddingPre[i+1]\n * exceeds the silence gap between them). Each cut gets equal share of the\n * silence — neither \"wins.\"\n *\n * Mutates cuts in place.\n */\nexport function resolveOverlaps(cuts: CutEntry[]): void {\n for (let i = 0; i < cuts.length - 1; i++) {\n const a = cuts[i];\n const b = cuts[i + 1];\n const aEnd = a.rawEnd + a.paddingPost;\n const bStart = b.rawStart - b.paddingPre;\n if (aEnd > bStart) {\n // Overlap — split at silence midpoint\n const mid = (a.rawEnd + b.rawStart) / 2;\n a.paddingPost = Math.max(0, mid - a.rawEnd);\n b.paddingPre = Math.max(0, b.rawStart - mid);\n }\n }\n}\n\n/**\n * Clamp first cut's paddingPre so effective start >= 0, and last cut's\n * paddingPost so effective end <= duration.\n *\n * Mutates cuts in place.\n */\nexport function clampBoundaries(cuts: CutEntry[], duration: number): void {\n if (cuts.length === 0) return;\n const first = cuts[0];\n if (first.rawStart - first.paddingPre < 0) {\n first.paddingPre = first.rawStart;\n }\n const last = cuts[cuts.length - 1];\n if (last.rawEnd + last.paddingPost > duration) {\n last.paddingPost = Math.max(0, duration - last.rawEnd);\n }\n}\n\n/**\n * Merge a freshly-detected cut list with an existing one, preserving user\n * padding overrides on any cut whose raw boundary still matches within\n * `tolerance` seconds (both start and end).\n *\n * For each fresh cut:\n * - if an existing cut matches: copy its padding and label, update raw values\n * - if no match: keep the fresh defaults\n *\n * Returns a new array; does not mutate inputs.\n */\nexport function mergeWithExisting(\n fresh: CutEntry[],\n existing: CutEntry[],\n tolerance = DEFAULT_MATCH_TOLERANCE,\n): CutEntry[] {\n return fresh.map((f) => {\n const match = existing.find(\n (e) =>\n Math.abs(e.rawStart - f.rawStart) < tolerance &&\n Math.abs(e.rawEnd - f.rawEnd) < tolerance,\n );\n if (!match) return f;\n return {\n rawStart: f.rawStart,\n rawEnd: f.rawEnd,\n paddingPre: match.paddingPre,\n paddingPost: match.paddingPost,\n ...(match.label !== undefined && { label: match.label }),\n };\n });\n}\n\n/**\n * Apply a global padding delta to every cut (positive = loosen, negative = tighten).\n * Floors padding at 0 — never goes negative.\n *\n * Mutates cuts in place.\n */\nexport function applyGlobalPadding(cuts: CutEntry[], deltaSeconds: number): void {\n for (const cut of cuts) {\n cut.paddingPre = Math.max(0, cut.paddingPre + deltaSeconds);\n cut.paddingPost = Math.max(0, cut.paddingPost + deltaSeconds);\n }\n}\n","import type { Command } from \"commander\";\nimport type { CutEntry } from \"@a-company/atelier-types\";\nimport {\n loadVideoProject,\n readCutList,\n writeCutList,\n readComposition,\n writeComposition,\n rewriteCutLayers,\n} from \"../lib/video-project.js\";\nimport {\n probeSilencedetect,\n probeDuration,\n runSilenceDetect,\n} from \"../lib/silence-detect.js\";\nimport {\n invertToSpeechIntervals,\n buildInitialCuts,\n resolveOverlaps,\n clampBoundaries,\n mergeWithExisting,\n applyGlobalPadding,\n DEFAULT_PADDING_PRE,\n DEFAULT_PADDING_POST,\n} from \"../lib/cut-model.js\";\nimport { loadRecipe, applyRecipeToTrimOptions } from \"../lib/recipe.js\";\n\nexport interface TrimOptions {\n /** silencedetect noise threshold, e.g. \"-30dB\" */\n noise?: string;\n /** Minimum silence duration to register, in seconds */\n minSilence?: number;\n /** Default leading padding for new cuts, in seconds */\n padPre?: number;\n /** Default trailing padding for new cuts, in seconds */\n padPost?: number;\n /** Re-detect match tolerance for preserving user padding, in seconds */\n matchTolerance?: number;\n /** Global tighten across all cuts, in milliseconds (positive number) */\n tightenMs?: number;\n /** Global loosen across all cuts, in milliseconds (positive number) */\n loosenMs?: number;\n /** Apply --pad-pre / --pad-post to one specific cut index only */\n cutIndex?: number;\n /** Discard existing padding; full fresh detect with default padding */\n reset?: boolean;\n /** Don't write files; return result */\n dryRun?: boolean;\n}\n\nexport interface TrimResult {\n projectDir: string;\n duration: number;\n cuts: CutEntry[];\n layerCount: number;\n}\n\n/**\n * Run the silence-trim pipeline on a VideoProject folder.\n *\n * Pipeline:\n * 1. Probe ffmpeg has silencedetect filter\n * 2. ffprobe source duration\n * 3. Run silencedetect → silence intervals\n * 4. Invert to speech intervals\n * 5. Build fresh CutEntry[] with default (or recipe) padding\n * 6. Merge with existing cuts (preserves user padding) unless --reset\n * 7. Apply --tighten / --loosen / --cut overrides\n * 8. Resolve overlaps at silence midpoints\n * 9. Clamp boundaries to [0, duration]\n * 10. Write cuts.json + rewrite silence-trim layers in project.atelier\n */\nexport async function trimProject(\n projectDir: string,\n options: TrimOptions = {},\n): Promise<TrimResult> {\n const project = loadVideoProject(projectDir);\n\n await probeSilencedetect();\n const duration = await probeDuration(project.sourcePath);\n\n const silences = await runSilenceDetect(project.sourcePath, {\n noise: options.noise,\n minSilence: options.minSilence,\n });\n const speech = invertToSpeechIntervals(silences, duration);\n\n const padPre = options.padPre ?? DEFAULT_PADDING_PRE;\n const padPost = options.padPost ?? DEFAULT_PADDING_POST;\n let cuts = buildInitialCuts(speech, padPre, padPost);\n\n // Re-run preservation — keep user padding on matching raw boundaries\n if (!options.reset) {\n const existing = readCutList(project);\n cuts = mergeWithExisting(cuts, existing.cuts, options.matchTolerance);\n }\n\n // Global tighten/loosen — applied to current padding (preserves overrides)\n if (typeof options.tightenMs === \"number\") {\n applyGlobalPadding(cuts, -options.tightenMs / 1000);\n }\n if (typeof options.loosenMs === \"number\") {\n applyGlobalPadding(cuts, options.loosenMs / 1000);\n }\n\n // Single-cut override\n if (typeof options.cutIndex === \"number\") {\n if (options.cutIndex < 0 || options.cutIndex >= cuts.length) {\n throw new Error(\n `--cut ${options.cutIndex} out of range (have ${cuts.length} cuts)`,\n );\n }\n if (options.padPre !== undefined) cuts[options.cutIndex].paddingPre = options.padPre;\n if (options.padPost !== undefined) cuts[options.cutIndex].paddingPost = options.padPost;\n }\n\n resolveOverlaps(cuts);\n clampBoundaries(cuts, duration);\n\n const result: TrimResult = {\n projectDir: project.dir,\n duration,\n cuts,\n layerCount: cuts.length,\n };\n\n if (options.dryRun) return result;\n\n writeCutList(project, {\n version: \"1.1\",\n source: project.manifest.source,\n cuts,\n });\n\n const doc = readComposition(project);\n const updated = rewriteCutLayers(doc, cuts, project.manifest.source, duration);\n writeComposition(project, updated);\n\n return result;\n}\n\n/** Format a TrimResult for human-readable terminal output */\nfunction formatResult(result: TrimResult): string {\n const lines: string[] = [];\n lines.push(`Trimmed ${result.projectDir}`);\n lines.push(` source duration: ${result.duration.toFixed(2)}s`);\n lines.push(` cuts: ${result.cuts.length}`);\n for (let i = 0; i < result.cuts.length; i++) {\n const c = result.cuts[i];\n const effStart = Math.max(0, c.rawStart - c.paddingPre);\n const effEnd = Math.min(result.duration, c.rawEnd + c.paddingPost);\n const dur = effEnd - effStart;\n lines.push(\n ` [${i}] ${effStart.toFixed(2)}s → ${effEnd.toFixed(2)}s ` +\n `(${dur.toFixed(2)}s, pad ${c.paddingPre.toFixed(2)}/${c.paddingPost.toFixed(2)})` +\n (c.label ? ` \"${c.label}\"` : \"\"),\n );\n }\n return lines.join(\"\\n\");\n}\n\n/** Register `atelier trim` on the Commander program */\nexport function trimCommand(program: Command): void {\n program\n .command(\"trim <project>\")\n .description(\n \"Detect silence and rewrite project.atelier with parametric cuts \" +\n \"(silence-trim tagged layers). Preserves user padding overrides on re-run.\",\n )\n .option(\"--noise <dB>\", \"Silence threshold (default: -30dB)\", \"-30dB\")\n .option(\n \"--min-silence <seconds>\",\n \"Minimum silence duration to register (default: 0.35)\",\n (v) => parseFloat(v),\n 0.35,\n )\n .option(\n \"--pad-pre <seconds>\",\n `Default leading padding (default: ${DEFAULT_PADDING_PRE})`,\n (v) => parseFloat(v),\n )\n .option(\n \"--pad-post <seconds>\",\n `Default trailing padding (default: ${DEFAULT_PADDING_POST})`,\n (v) => parseFloat(v),\n )\n .option(\"--tighten <ms>\", \"Reduce all current padding by N ms\", (v) => parseInt(v, 10))\n .option(\"--loosen <ms>\", \"Increase all current padding by N ms\", (v) => parseInt(v, 10))\n .option(\n \"--cut <index>\",\n \"Apply --pad-pre / --pad-post to one specific cut only\",\n (v) => parseInt(v, 10),\n )\n .option(\"--reset\", \"Discard existing padding; re-detect from scratch\")\n .option(\"--recipe <name>\", \"Apply a Studio Recipe's silence_policy as the baseline\")\n .option(\"--dry-run\", \"Print computed cuts; don't write files\")\n .option(\"--json\", \"Output result as JSON for piping\")\n .action(async (\n project: string,\n opts: {\n noise: string;\n minSilence: number;\n padPre?: number;\n padPost?: number;\n tighten?: number;\n loosen?: number;\n cut?: number;\n reset?: boolean;\n recipe?: string;\n dryRun?: boolean;\n json?: boolean;\n },\n ) => {\n try {\n let trimOpts: TrimOptions = {\n noise: opts.noise,\n minSilence: opts.minSilence,\n padPre: opts.padPre,\n padPost: opts.padPost,\n tightenMs: opts.tighten,\n loosenMs: opts.loosen,\n cutIndex: opts.cut,\n reset: opts.reset,\n dryRun: opts.dryRun,\n };\n if (opts.recipe) {\n const { recipe } = loadRecipe(opts.recipe, project);\n trimOpts = applyRecipeToTrimOptions(recipe, trimOpts);\n }\n const result = await trimProject(project, trimOpts);\n\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(formatResult(result));\n if (opts.dryRun) console.log(\"(dry-run — no files written)\");\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`atelier trim: ${msg}`);\n process.exit(1);\n }\n });\n}\n","import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport type { VideoTranscript } from \"@a-company/atelier-types\";\n\n/** Whisper model selection (size/quality tradeoff) */\nexport type WhisperModel =\n | \"tiny\" | \"tiny.en\"\n | \"base\" | \"base.en\"\n | \"small\" | \"small.en\"\n | \"medium\" | \"medium.en\"\n | \"large-v3\";\n\nexport interface WhisperOptions {\n /** Model size (default: \"base.en\") */\n model?: WhisperModel;\n /** BCP-47 language hint (omit for autodetect) */\n language?: string;\n /** Explicit path to the model file — overrides model lookup by name */\n modelPath?: string;\n}\n\n/** Backend that produced a transcript run */\nexport type WhisperBackend = \"whisper-cpp\" | \"openai-api\" | \"none\";\n\n/**\n * Probe which Whisper backend is available on this machine.\n * - \"whisper-cpp\" if `whisper-cli` is on PATH\n * - \"openai-api\" if OPENAI_API_KEY is set and --use-api requested\n * - \"none\" otherwise — caller throws with install guidance\n */\nexport async function probeWhisper(): Promise<WhisperBackend> {\n if (await commandExists(\"whisper-cli\")) return \"whisper-cpp\";\n if (process.env.OPENAI_API_KEY) return \"openai-api\";\n return \"none\";\n}\n\n/**\n * Run whisper.cpp on a source file and return the raw JSON stdout.\n * Caller passes to parseWhisperCppJson() to get a VideoTranscript.\n *\n * Note: whisper-cli writes JSON to stdout when given --output-json and \"-\"\n * as the output destination. Some builds always write to a file with the\n * `.json` suffix appended to the input path; we handle both.\n */\nexport async function runWhisperCpp(\n sourcePath: string,\n options: WhisperOptions = {},\n): Promise<string> {\n const model = options.modelPath ?? options.model ?? \"base.en\";\n\n const args = [\n sourcePath,\n \"--model\", model,\n \"--output-json\",\n \"--word-thold\", \"0.01\", // emit word-level timestamps\n \"--print-progress\", \"false\",\n ];\n if (options.language) {\n args.push(\"--language\", options.language);\n }\n\n return runCaptureStdout(\"whisper-cli\", args);\n}\n\n/**\n * Parse whisper.cpp --output-json output into a VideoTranscript.\n *\n * whisper.cpp emits a structure like:\n * {\n * \"result\": { \"language\": \"en\" },\n * \"transcription\": [\n * {\n * \"timestamps\": { \"from\": \"00:00:00,000\", \"to\": \"00:00:02,300\" },\n * \"offsets\": { \"from\": 0, \"to\": 2300 },\n * \"text\": \" Hello world\",\n * \"tokens\": [ ... ] // optional per-token detail\n * }\n * ]\n * }\n *\n * Token-level word timestamps come via the \"tokens\" array on each segment\n * when --output-json-full is used. With --output-json (lighter), only\n * segment-level boundaries are present and we synthesize word timing by\n * even split across the segment.\n *\n * Exported for unit testing.\n */\nexport function parseWhisperCppJson(jsonStr: string): VideoTranscript {\n const raw = JSON.parse(jsonStr) as {\n result?: { language?: string };\n transcription?: Array<{\n offsets?: { from: number; to: number };\n timestamps?: { from: string; to: string };\n text: string;\n tokens?: Array<{\n text: string;\n offsets?: { from: number; to: number };\n timestamps?: { from: string; to: string };\n p?: number; // probability/confidence\n }>;\n }>;\n };\n\n const segments = (raw.transcription ?? []).map((seg) => {\n const segStart = (seg.offsets?.from ?? 0) / 1000;\n const segEnd = (seg.offsets?.to ?? 0) / 1000;\n const segText = seg.text.trim();\n\n let words;\n if (seg.tokens && seg.tokens.length > 0) {\n // Token-level detail available — emit one word per non-special token\n words = seg.tokens\n .filter((t) => t.text.trim().length > 0 && !t.text.startsWith(\"[_\"))\n .map((t) => ({\n detected: t.text.trim(),\n text: t.text.trim(),\n start: (t.offsets?.from ?? segStart * 1000) / 1000,\n end: (t.offsets?.to ?? segEnd * 1000) / 1000,\n ...(t.p !== undefined && { confidence: t.p }),\n }));\n } else {\n // Fall back to even-split across segment\n const tokens = segText.split(/\\s+/).filter((t) => t.length > 0);\n const span = segEnd - segStart;\n const per = tokens.length > 0 ? span / tokens.length : 0;\n words = tokens.map((tok, i) => ({\n detected: tok,\n text: tok,\n start: segStart + i * per,\n end: segStart + (i + 1) * per,\n }));\n }\n\n return {\n text: segText,\n start: segStart,\n end: segEnd,\n words,\n };\n });\n\n return {\n version: \"1.1\",\n ...(raw.result?.language !== undefined && { language: raw.result.language }),\n segments,\n };\n}\n\n// ─── subprocess plumbing ─────────────────────────────────────────\n\n/** Check whether a binary is callable on PATH (cross-platform-ish via `which` / `where`) */\nexport async function commandExists(name: string): Promise<boolean> {\n // If user passed an absolute path, just check the file\n if (name.startsWith(\"/\") || name.match(/^[A-Z]:\\\\/)) {\n return existsSync(name);\n }\n return new Promise((resolve) => {\n const probe = spawn(process.platform === \"win32\" ? \"where\" : \"which\", [name], {\n stdio: [\"ignore\", \"ignore\", \"ignore\"],\n });\n probe.on(\"error\", () => resolve(false));\n probe.on(\"close\", (code) => resolve(code === 0));\n });\n}\n\nfunction runCaptureStdout(cmd: string, args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const proc = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n let stderr = \"\";\n proc.stdout.on(\"data\", (b) => (stdout += b.toString()));\n proc.stderr.on(\"data\", (b) => (stderr += b.toString()));\n proc.on(\"error\", (err) => {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\") {\n reject(new Error(\n `${cmd} not found on PATH. Install whisper.cpp (brew install whisper-cpp) ` +\n `or run \\`pnpm add @xenova/transformers\\` for the ONNX fallback.`,\n ));\n } else {\n reject(err);\n }\n });\n proc.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(`${cmd} exited ${code}\\n${stderr}`));\n } else {\n resolve(stdout);\n }\n });\n });\n}\n","import type { TranscriptWord, TranscriptSegment, VideoTranscript } from \"@a-company/atelier-types\";\n\n/** Default match tolerance for re-transcribe merge (seconds) */\nexport const DEFAULT_TRANSCRIPT_MATCH_TOLERANCE = 0.3;\n\n/** Default phrase grouping parameters */\nexport const DEFAULT_PHRASE_MAX_WORDS = 5;\nexport const DEFAULT_PHRASE_PAUSE_GAP_SECONDS = 0.4;\n\n/** End-of-phrase punctuation marks */\nconst END_PUNCT = /[.!?,;:]\\s*$/;\n\n/**\n * Flatten a VideoTranscript's segments into a single ordered word array.\n * Used by edit commands that take a global word index.\n */\nexport function flattenWords(transcript: VideoTranscript): TranscriptWord[] {\n return transcript.segments.flatMap((s) => s.words);\n}\n\n/**\n * Phrase block — one rendered caption layer's worth of words.\n */\nexport interface CaptionPhrase {\n start: number;\n end: number;\n text: string;\n words: TranscriptWord[];\n}\n\n/**\n * Group transcript words into caption-sized phrases.\n *\n * Emits a new phrase when ANY of:\n * - currentPhrase.length >= maxWords\n * - currentWord.text ends in . ! ? , ; :\n * - gap between currentWord and nextWord > pauseGap seconds\n *\n * Hidden words are skipped (do not appear in captions but still in transcript).\n */\nexport function groupIntoPhrases(\n transcript: VideoTranscript,\n options: { maxWords?: number; pauseGap?: number } = {},\n): CaptionPhrase[] {\n const maxWords = options.maxWords ?? DEFAULT_PHRASE_MAX_WORDS;\n const pauseGap = options.pauseGap ?? DEFAULT_PHRASE_PAUSE_GAP_SECONDS;\n\n const phrases: CaptionPhrase[] = [];\n const visibleWords = flattenWords(transcript).filter((w) => !w.hidden);\n\n let current: TranscriptWord[] = [];\n for (let i = 0; i < visibleWords.length; i++) {\n const w = visibleWords[i];\n current.push(w);\n\n const next = visibleWords[i + 1];\n const gap = next ? next.start - w.end : 0;\n const endsOnPunct = END_PUNCT.test(w.text);\n const atMax = current.length >= maxWords;\n\n if (!next || atMax || endsOnPunct || gap > pauseGap) {\n phrases.push({\n start: current[0].start,\n end: current[current.length - 1].end,\n text: current.map((c) => c.text).join(\" \"),\n words: current,\n });\n current = [];\n }\n }\n\n return phrases;\n}\n\n/**\n * Merge a freshly-detected transcript with an existing one, preserving user\n * edits (userEdited / userAdded / hidden + text override) on any word whose\n * raw boundary still matches within `tolerance` seconds AND whose `detected`\n * string is unchanged.\n *\n * userAdded words in the existing transcript have no matching fresh entry by\n * definition — they're preserved as orphans, inserted into the appropriate\n * segment by timing.\n */\nexport function mergeTranscriptWithExisting(\n fresh: VideoTranscript,\n existing: VideoTranscript,\n tolerance = DEFAULT_TRANSCRIPT_MATCH_TOLERANCE,\n): VideoTranscript {\n const existingWords = flattenWords(existing);\n\n const merged: VideoTranscript = {\n version: \"1.1\",\n ...(fresh.language !== undefined && { language: fresh.language }),\n segments: fresh.segments.map((seg) => ({\n text: seg.text,\n start: seg.start,\n end: seg.end,\n words: seg.words.map((freshWord) => {\n const match = existingWords.find(\n (e) =>\n !e.userAdded &&\n Math.abs(e.start - freshWord.start) < tolerance &&\n e.detected === freshWord.detected,\n );\n if (!match) return freshWord;\n return {\n detected: freshWord.detected,\n text: match.text,\n start: freshWord.start,\n end: freshWord.end,\n ...(freshWord.confidence !== undefined && { confidence: freshWord.confidence }),\n ...(match.userEdited && { userEdited: true }),\n ...(match.hidden && { hidden: true }),\n };\n }),\n })),\n };\n\n // Re-insert user-added orphan words into their original segment by timing\n const orphans = existingWords.filter((w) => w.userAdded);\n for (const orphan of orphans) {\n const segIdx = merged.segments.findIndex(\n (s) => orphan.start >= s.start && orphan.start <= s.end,\n );\n const targetSeg = segIdx >= 0\n ? merged.segments[segIdx]\n : merged.segments[merged.segments.length - 1];\n if (!targetSeg) continue;\n const insertIdx = targetSeg.words.findIndex((w) => w.start > orphan.start);\n if (insertIdx === -1) targetSeg.words.push(orphan);\n else targetSeg.words.splice(insertIdx, 0, orphan);\n }\n\n return merged;\n}\n\n/**\n * Replace the text of word at the given global index. Sets userEdited=true.\n * Returns a new VideoTranscript; does not mutate input.\n */\nexport function applyTextEdit(\n transcript: VideoTranscript,\n wordIndex: number,\n newText: string,\n): VideoTranscript {\n return mapWord(transcript, wordIndex, (w) => ({\n ...w,\n text: newText,\n userEdited: true,\n }));\n}\n\n/**\n * Apply a batch find/replace across all detected words.\n * Sets userEdited=true on every word whose detected text matches `find`.\n */\nexport function applyBatchReplace(\n transcript: VideoTranscript,\n find: string,\n replace: string,\n): VideoTranscript {\n return {\n ...transcript,\n segments: transcript.segments.map((seg) => ({\n ...seg,\n words: seg.words.map((w) =>\n w.detected === find\n ? { ...w, text: replace, userEdited: true }\n : w,\n ),\n })),\n };\n}\n\n/** Hide a word (excluded from caption render, kept in transcript). Sets hidden=true. */\nexport function applyHide(transcript: VideoTranscript, wordIndex: number): VideoTranscript {\n return mapWord(transcript, wordIndex, (w) => ({ ...w, hidden: true }));\n}\n\n/**\n * Insert a user-added word after the given global index.\n * Sets userAdded=true. Duration defaults to 0.15s if not specified.\n * Word is placed in the segment containing the anchor word.\n */\nexport function applyAdd(\n transcript: VideoTranscript,\n afterIndex: number,\n text: string,\n duration = 0.15,\n): VideoTranscript {\n const flat = flattenWords(transcript);\n if (afterIndex < 0 || afterIndex >= flat.length) {\n throw new Error(`afterIndex ${afterIndex} out of range (have ${flat.length} words)`);\n }\n const anchor = flat[afterIndex];\n const newWord: TranscriptWord = {\n detected: text,\n text,\n start: anchor.end,\n end: anchor.end + duration,\n userAdded: true,\n };\n\n // Find which segment contains the anchor word and insert there\n let cursor = 0;\n return {\n ...transcript,\n segments: transcript.segments.map((seg) => {\n const segStart = cursor;\n cursor += seg.words.length;\n if (afterIndex < segStart || afterIndex >= cursor) return seg;\n const localIdx = afterIndex - segStart;\n return {\n ...seg,\n words: [...seg.words.slice(0, localIdx + 1), newWord, ...seg.words.slice(localIdx + 1)],\n };\n }),\n };\n}\n\n/**\n * Merge adjacent words at indices i and i+1 into a single word.\n * The merged word's detected/text becomes the concatenation; timing spans both.\n * Sets userEdited=true.\n */\nexport function applyMerge(transcript: VideoTranscript, firstIndex: number): VideoTranscript {\n const flat = flattenWords(transcript);\n if (firstIndex < 0 || firstIndex >= flat.length - 1) {\n throw new Error(`firstIndex ${firstIndex} out of range for merge`);\n }\n const a = flat[firstIndex];\n const b = flat[firstIndex + 1];\n const mergedWord: TranscriptWord = {\n detected: a.detected + b.detected,\n text: a.text + b.text,\n start: a.start,\n end: b.end,\n userEdited: true,\n };\n\n let cursor = 0;\n return {\n ...transcript,\n segments: transcript.segments.map((seg) => {\n const segStart = cursor;\n cursor += seg.words.length;\n // Both words must fall in the same segment to merge cleanly\n if (firstIndex < segStart || firstIndex >= cursor - 1) return seg;\n const localIdx = firstIndex - segStart;\n return {\n ...seg,\n words: [...seg.words.slice(0, localIdx), mergedWord, ...seg.words.slice(localIdx + 2)],\n };\n }),\n };\n}\n\n/**\n * Split one word at the given fractional point (0–1). Timing prorates.\n * Sets userEdited=true on both halves. `firstText` and `secondText` default\n * to slicing the original text at its character midpoint.\n */\nexport function applySplit(\n transcript: VideoTranscript,\n wordIndex: number,\n fraction: number,\n firstText?: string,\n secondText?: string,\n): VideoTranscript {\n if (fraction <= 0 || fraction >= 1) {\n throw new Error(`split fraction must be in (0, 1), got ${fraction}`);\n }\n const flat = flattenWords(transcript);\n if (wordIndex < 0 || wordIndex >= flat.length) {\n throw new Error(`wordIndex ${wordIndex} out of range`);\n }\n const w = flat[wordIndex];\n const splitTime = w.start + (w.end - w.start) * fraction;\n const cutChar = Math.max(1, Math.floor(w.text.length * fraction));\n const first: TranscriptWord = {\n detected: w.detected,\n text: firstText ?? w.text.slice(0, cutChar),\n start: w.start,\n end: splitTime,\n userEdited: true,\n };\n const second: TranscriptWord = {\n detected: w.detected,\n text: secondText ?? w.text.slice(cutChar),\n start: splitTime,\n end: w.end,\n userEdited: true,\n };\n\n let cursor = 0;\n return {\n ...transcript,\n segments: transcript.segments.map((seg) => {\n const segStart = cursor;\n cursor += seg.words.length;\n if (wordIndex < segStart || wordIndex >= cursor) return seg;\n const localIdx = wordIndex - segStart;\n return {\n ...seg,\n words: [...seg.words.slice(0, localIdx), first, second, ...seg.words.slice(localIdx + 1)],\n };\n }),\n };\n}\n\n// ─── helpers ─────────────────────────────────────────────────────\n\nfunction mapWord(\n transcript: VideoTranscript,\n wordIndex: number,\n fn: (w: TranscriptWord) => TranscriptWord,\n): VideoTranscript {\n const flat = flattenWords(transcript);\n if (wordIndex < 0 || wordIndex >= flat.length) {\n throw new Error(`wordIndex ${wordIndex} out of range (have ${flat.length} words)`);\n }\n let cursor = 0;\n return {\n ...transcript,\n segments: transcript.segments.map((seg) => {\n const segStart = cursor;\n cursor += seg.words.length;\n if (wordIndex < segStart || wordIndex >= cursor) return seg;\n const localIdx = wordIndex - segStart;\n return {\n ...seg,\n words: seg.words.map((w, i) => (i === localIdx ? fn(w) : w)),\n };\n }),\n };\n}\n\n// Re-export for convenience\nexport type { TranscriptSegment };\n","import type {\n AtelierDocument,\n Layer,\n Delta,\n VideoTranscript,\n} from \"@a-company/atelier-types\";\nimport { groupIntoPhrases, type CaptionPhrase } from \"./transcript-model.js\";\n\n/** Default style for generated caption layers — overridable by Studio Recipe */\nexport interface CaptionStyle {\n fontFamily?: string;\n fontSize?: number;\n fontWeight?: number | \"normal\" | \"bold\";\n textAlign?: \"left\" | \"center\" | \"right\";\n color?: string;\n /** Relative vertical position 0–1 (0 = top, 1 = bottom). Default 0.85 — lower-third. */\n yRatio?: number;\n /** Horizontal width as ratio of canvas width. Default 0.9. */\n widthRatio?: number;\n /** Fade duration in seconds for opacity in/out. Default 0.05 (3 frames at 60fps). */\n fadeSeconds?: number;\n}\n\nconst DEFAULT_STYLE: Required<CaptionStyle> = {\n fontFamily: \"Inter\",\n fontSize: 84,\n fontWeight: \"bold\" as const,\n textAlign: \"center\" as const,\n color: \"#FFFFFF\",\n yRatio: 0.85,\n widthRatio: 0.9,\n fadeSeconds: 0.05,\n};\n\nexport interface BuildCaptionsOptions {\n style?: CaptionStyle;\n /** Phrase grouping — max words per caption phrase */\n maxWords?: number;\n /** Phrase grouping — pause gap in seconds that forces a phrase break */\n pauseGap?: number;\n}\n\n/**\n * Build caption-tagged TextVisual layers from a transcript + canvas dimensions.\n *\n * Each phrase becomes one Layer with:\n * - tags: [\"caption\"]\n * - TextVisual with merged style\n * - opacity: 0 (default; deltas animate to 1 during the phrase)\n * - positioned at canvas.width * 0.5, canvas.height * yRatio\n *\n * Caller is responsible for appending these to a state's deltas array\n * (returned alongside the layers as Delta[] keyed to layer id).\n */\nexport function buildCaptionLayers(\n transcript: VideoTranscript,\n canvas: AtelierDocument[\"canvas\"],\n options: BuildCaptionsOptions = {},\n): { layers: Layer[]; deltas: Delta[] } {\n const style = { ...DEFAULT_STYLE, ...options.style };\n const phrases = groupIntoPhrases(transcript, {\n maxWords: options.maxWords,\n pauseGap: options.pauseGap,\n });\n\n const layers: Layer[] = [];\n const deltas: Delta[] = [];\n const fps = canvas.fps;\n\n phrases.forEach((phrase, idx) => {\n const layerId = `caption-${idx}`;\n layers.push(buildPhraseLayer(layerId, phrase, canvas, style));\n deltas.push(...buildPhraseDeltas(layerId, phrase, style.fadeSeconds, fps));\n });\n\n return { layers, deltas };\n}\n\n/**\n * Drop caption-tagged layers + their deltas from a composition,\n * append fresh ones from the current transcript.\n *\n * Mirrors rewriteCutLayers' invariant: only caption-tagged layers touched;\n * all other layers (silence-trim, overlay, user-authored) preserved.\n *\n * Deltas are written into the default state (or first state if no \"default\").\n */\nexport function rewriteCaptionLayers(\n doc: AtelierDocument,\n transcript: VideoTranscript,\n options: BuildCaptionsOptions = {},\n): AtelierDocument {\n const preserved = doc.layers.filter((l) => !(l.tags ?? []).includes(\"caption\"));\n const { layers: captionLayers, deltas: captionDeltas } = buildCaptionLayers(\n transcript,\n doc.canvas,\n options,\n );\n const captionLayerIds = new Set(captionLayers.map((l) => l.id));\n\n // Pick the target state for caption deltas: prefer \"default\", else first\n const stateNames = Object.keys(doc.states);\n const targetStateName = stateNames.includes(\"default\") ? \"default\" : stateNames[0];\n const states = { ...doc.states };\n\n if (targetStateName && states[targetStateName]) {\n const existing = states[targetStateName];\n // Drop deltas on caption layers we're rewriting; keep all others\n const preservedDeltas = existing.deltas.filter(\n (d) => !captionLayerIds.has(d.layer),\n );\n states[targetStateName] = {\n ...existing,\n deltas: [...preservedDeltas, ...captionDeltas],\n };\n }\n\n return {\n ...doc,\n layers: [...preserved, ...captionLayers],\n states,\n };\n}\n\n// ─── internals ───────────────────────────────────────────────────\n\nfunction buildPhraseLayer(\n id: string,\n phrase: CaptionPhrase,\n canvas: AtelierDocument[\"canvas\"],\n style: Required<CaptionStyle>,\n): Layer {\n return {\n id,\n tags: [\"caption\"],\n visual: {\n type: \"text\",\n content: phrase.text,\n style: {\n fontFamily: style.fontFamily,\n fontSize: style.fontSize,\n fontWeight: style.fontWeight,\n textAlign: style.textAlign,\n color: style.color,\n },\n },\n frame: {\n x: canvas.width / 2,\n y: canvas.height * style.yRatio,\n },\n bounds: {\n width: canvas.width * style.widthRatio,\n height: Math.max(120, style.fontSize * 1.6),\n },\n anchorPoint: { x: 0.5, y: 0.5 },\n opacity: 0,\n };\n}\n\nfunction buildPhraseDeltas(\n layerId: string,\n phrase: CaptionPhrase,\n fadeSeconds: number,\n fps: number,\n): Delta[] {\n const fadeFrames = Math.max(1, Math.round(fadeSeconds * fps));\n const startFrame = Math.floor(phrase.start * fps);\n const endFrame = Math.ceil(phrase.end * fps);\n const fadeOutStart = Math.max(startFrame + 1, endFrame - fadeFrames);\n\n return [\n // Fade in to visible at phrase start\n {\n layer: layerId,\n property: \"opacity\",\n range: [Math.max(0, startFrame - fadeFrames), startFrame],\n from: 0,\n to: 1,\n easing: \"ease-out\",\n },\n // Hold visible through the phrase\n // (no explicit delta needed — value persists between deltas)\n // Fade out at phrase end\n {\n layer: layerId,\n property: \"opacity\",\n range: [fadeOutStart, endFrame],\n from: 1,\n to: 0,\n easing: \"ease-in\",\n },\n ];\n}\n","import type { Command } from \"commander\";\nimport type { VideoTranscript } from \"@a-company/atelier-types\";\nimport {\n loadVideoProject,\n readTranscript,\n writeTranscript,\n readComposition,\n writeComposition,\n} from \"../lib/video-project.js\";\nimport {\n probeWhisper,\n runWhisperCpp,\n parseWhisperCppJson,\n type WhisperModel,\n} from \"../lib/whisper.js\";\nimport { mergeTranscriptWithExisting } from \"../lib/transcript-model.js\";\nimport { rewriteCaptionLayers, type BuildCaptionsOptions } from \"../lib/caption-builder.js\";\nimport { loadRecipe, applyRecipeToTranscribeOptions } from \"../lib/recipe.js\";\n\nexport interface TranscribeOptions {\n /** Whisper model selection */\n model?: WhisperModel;\n /** BCP-47 language hint (omit for autodetect) */\n language?: string;\n /** Discard existing user edits; full fresh transcript */\n reset?: boolean;\n /** Skip caption layer generation; transcript.json only */\n noCaptions?: boolean;\n /** Don't write files; return result */\n dryRun?: boolean;\n /** Caption style + grouping overrides, typically supplied by a Studio Recipe */\n captionOptions?: BuildCaptionsOptions;\n}\n\nexport interface TranscribeResult {\n projectDir: string;\n backend: string;\n transcript: VideoTranscript;\n wordCount: number;\n captionsGenerated: boolean;\n}\n\n/**\n * Run the transcription pipeline on a VideoProject folder.\n *\n * Pipeline:\n * 1. Probe Whisper backend (whisper-cpp / openai-api / none)\n * 2. Run Whisper → raw transcript JSON\n * 3. Parse into VideoTranscript shape\n * 4. Merge with existing transcript (preserves user edits) unless --reset\n * 5. Write transcript.json\n * 6. Unless --no-captions: rewriteCaptionLayers in project.atelier\n */\nexport async function transcribeProject(\n projectDir: string,\n options: TranscribeOptions = {},\n): Promise<TranscribeResult> {\n const project = loadVideoProject(projectDir);\n\n const backend = await probeWhisper();\n if (backend === \"none\") {\n throw new Error(\n \"No Whisper backend available. Install whisper.cpp (brew install whisper-cpp) \" +\n \"or set OPENAI_API_KEY and pass --use-api.\",\n );\n }\n if (backend === \"openai-api\") {\n // Reserved for the --use-api opt-in path; not implemented in this milestone\n throw new Error(\n \"OpenAI API backend is not yet implemented. Install whisper.cpp for local transcription.\",\n );\n }\n\n const rawJson = await runWhisperCpp(project.sourcePath, {\n model: options.model,\n language: options.language,\n });\n let transcript = parseWhisperCppJson(rawJson);\n\n // Re-run preservation — keep user edits on matching detected words\n if (!options.reset) {\n const existing = readTranscript(project);\n if (existing) {\n transcript = mergeTranscriptWithExisting(transcript, existing);\n }\n }\n\n const wordCount = transcript.segments.reduce((n, s) => n + s.words.length, 0);\n\n const result: TranscribeResult = {\n projectDir: project.dir,\n backend,\n transcript,\n wordCount,\n captionsGenerated: false,\n };\n\n if (options.dryRun) return result;\n\n writeTranscript(project, transcript);\n\n if (!options.noCaptions) {\n const doc = readComposition(project);\n const updated = rewriteCaptionLayers(doc, transcript, options.captionOptions);\n writeComposition(project, updated);\n result.captionsGenerated = true;\n }\n\n return result;\n}\n\nfunction formatResult(result: TranscribeResult): string {\n const lines: string[] = [];\n lines.push(`Transcribed ${result.projectDir} via ${result.backend}`);\n if (result.transcript.language) {\n lines.push(` language: ${result.transcript.language}`);\n }\n lines.push(` segments: ${result.transcript.segments.length}`);\n lines.push(` words: ${result.wordCount}`);\n if (result.captionsGenerated) {\n lines.push(` captions: written to project.atelier`);\n } else {\n lines.push(` captions: skipped`);\n }\n return lines.join(\"\\n\");\n}\n\n/** Register `atelier transcribe` on the Commander program */\nexport function transcribeCommand(program: Command): void {\n program\n .command(\"transcribe <project>\")\n .description(\n \"Transcribe source video via Whisper, write transcript.json, and \" +\n \"rewrite caption-tagged TextVisual layers in project.atelier. \" +\n \"Preserves user transcript edits on re-run.\",\n )\n .option(\"--model <name>\", \"Whisper model: tiny|base|small|medium|large-v3\", \"base.en\")\n .option(\"--language <code>\", \"BCP-47 language hint (omit for autodetect)\")\n .option(\"--reset\", \"Discard existing user edits; full fresh transcript\")\n .option(\"--no-captions\", \"Write transcript.json only; skip caption layer generation\")\n .option(\"--recipe <name>\", \"Apply a Studio Recipe's caption_style + caption_grouping\")\n .option(\"--dry-run\", \"Print transcript; don't write files\")\n .option(\"--json\", \"Output result as JSON for piping\")\n .action(async (\n project: string,\n opts: {\n model: WhisperModel;\n language?: string;\n reset?: boolean;\n captions: boolean;\n recipe?: string;\n dryRun?: boolean;\n json?: boolean;\n },\n ) => {\n try {\n let transcribeOpts: TranscribeOptions = {\n model: opts.model,\n language: opts.language,\n reset: opts.reset,\n noCaptions: !opts.captions,\n dryRun: opts.dryRun,\n };\n if (opts.recipe) {\n const { recipe } = loadRecipe(opts.recipe, project);\n transcribeOpts = applyRecipeToTranscribeOptions(recipe, transcribeOpts);\n }\n const result = await transcribeProject(project, transcribeOpts);\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(formatResult(result));\n if (opts.dryRun) console.log(\"(dry-run — no files written)\");\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`atelier transcribe: ${msg}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from \"commander\";\nimport type { VideoTranscript } from \"@a-company/atelier-types\";\nimport {\n loadVideoProject,\n readTranscript,\n writeTranscript,\n readComposition,\n writeComposition,\n} from \"../lib/video-project.js\";\nimport {\n applyTextEdit,\n applyBatchReplace,\n applyHide,\n applyAdd,\n applyMerge,\n applySplit,\n flattenWords,\n} from \"../lib/transcript-model.js\";\nimport { rewriteCaptionLayers } from \"../lib/caption-builder.js\";\n\n/** Read the project's transcript; throws if none exists */\nfunction loadOrThrow(projectDir: string): { project: ReturnType<typeof loadVideoProject>; transcript: VideoTranscript } {\n const project = loadVideoProject(projectDir);\n const transcript = readTranscript(project);\n if (!transcript) {\n throw new Error(\n `No transcript.json in ${projectDir}. Run \\`atelier transcribe ${projectDir}\\` first.`,\n );\n }\n return { project, transcript };\n}\n\n/** Save the transcript and optionally regenerate caption layers */\nfunction save(\n project: ReturnType<typeof loadVideoProject>,\n transcript: VideoTranscript,\n noRegenerate: boolean,\n): void {\n writeTranscript(project, transcript);\n if (!noRegenerate) {\n const doc = readComposition(project);\n const updated = rewriteCaptionLayers(doc, transcript);\n writeComposition(project, updated);\n }\n}\n\n/** Register the `atelier transcript` family of edit subcommands */\nexport function transcriptCommand(program: Command): void {\n const transcript = program\n .command(\"transcript\")\n .description(\"Edit transcript.json — fix, add, delete, merge, split, list\");\n\n transcript\n .command(\"fix <project>\")\n .description(\"Apply text correction(s). Use --replace 'wrong=right' for batch, or --word <idx> --text '<correction>' for single edit.\")\n .option(\"--replace <pair...>\", \"Batch find/replace, format: 'detected=replacement' (repeatable)\")\n .option(\"--word <index>\", \"Single-word edit by index\", (v) => parseInt(v, 10))\n .option(\"--text <text>\", \"Correction text (paired with --word)\")\n .option(\"--no-regenerate\", \"Skip caption layer regeneration after edit\")\n .action(async (\n projectDir: string,\n opts: { replace?: string[]; word?: number; text?: string; regenerate: boolean },\n ) => {\n try {\n const { project, transcript } = loadOrThrow(projectDir);\n let updated = transcript;\n\n if (opts.replace?.length) {\n for (const pair of opts.replace) {\n const [find, repl] = pair.split(\"=\");\n if (!find || repl === undefined) {\n throw new Error(`Invalid --replace pair: \"${pair}\". Use 'detected=replacement'.`);\n }\n updated = applyBatchReplace(updated, find, repl);\n }\n }\n\n if (typeof opts.word === \"number\") {\n if (opts.text === undefined) {\n throw new Error(\"--word requires --text <correction>\");\n }\n updated = applyTextEdit(updated, opts.word, opts.text);\n }\n\n if (!opts.replace?.length && opts.word === undefined) {\n throw new Error(\"Provide --replace 'wrong=right' or --word <idx> --text '...'\");\n }\n\n save(project, updated, !opts.regenerate);\n console.log(`Updated transcript in ${project.dir}`);\n } catch (err) {\n console.error(`atelier transcript fix: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n\n transcript\n .command(\"add <project>\")\n .description(\"Insert a user-added word after the anchor word.\")\n .requiredOption(\"--after-word <index>\", \"Anchor word index\", (v) => parseInt(v, 10))\n .requiredOption(\"--text <text>\", \"Text of the new word\")\n .option(\"--duration <seconds>\", \"Word duration in seconds (default: 0.15)\", (v) => parseFloat(v), 0.15)\n .option(\"--no-regenerate\", \"Skip caption layer regeneration\")\n .action(async (\n projectDir: string,\n opts: { afterWord: number; text: string; duration: number; regenerate: boolean },\n ) => {\n try {\n const { project, transcript } = loadOrThrow(projectDir);\n const updated = applyAdd(transcript, opts.afterWord, opts.text, opts.duration);\n save(project, updated, !opts.regenerate);\n console.log(`Inserted \"${opts.text}\" after word ${opts.afterWord} in ${project.dir}`);\n } catch (err) {\n console.error(`atelier transcript add: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n\n transcript\n .command(\"delete <project>\")\n .description(\"Hide a word (excluded from captions, kept in transcript).\")\n .requiredOption(\"--word <index>\", \"Word index\", (v) => parseInt(v, 10))\n .option(\"--no-regenerate\", \"Skip caption layer regeneration\")\n .action(async (\n projectDir: string,\n opts: { word: number; regenerate: boolean },\n ) => {\n try {\n const { project, transcript } = loadOrThrow(projectDir);\n const updated = applyHide(transcript, opts.word);\n save(project, updated, !opts.regenerate);\n console.log(`Hidden word ${opts.word} in ${project.dir}`);\n } catch (err) {\n console.error(`atelier transcript delete: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n\n transcript\n .command(\"merge <project>\")\n .description(\"Merge two adjacent words at indices i and i+1.\")\n .requiredOption(\"--word <index>\", \"First of the two words to merge\", (v) => parseInt(v, 10))\n .option(\"--no-regenerate\", \"Skip caption layer regeneration\")\n .action(async (\n projectDir: string,\n opts: { word: number; regenerate: boolean },\n ) => {\n try {\n const { project, transcript } = loadOrThrow(projectDir);\n const updated = applyMerge(transcript, opts.word);\n save(project, updated, !opts.regenerate);\n console.log(`Merged words ${opts.word} and ${opts.word + 1} in ${project.dir}`);\n } catch (err) {\n console.error(`atelier transcript merge: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n\n transcript\n .command(\"split <project>\")\n .description(\"Split one word at a fractional point.\")\n .requiredOption(\"--word <index>\", \"Word to split\", (v) => parseInt(v, 10))\n .requiredOption(\"--at <fraction>\", \"Split point (0–1)\", (v) => parseFloat(v))\n .option(\"--first <text>\", \"Override text for first half\")\n .option(\"--second <text>\", \"Override text for second half\")\n .option(\"--no-regenerate\", \"Skip caption layer regeneration\")\n .action(async (\n projectDir: string,\n opts: { word: number; at: number; first?: string; second?: string; regenerate: boolean },\n ) => {\n try {\n const { project, transcript } = loadOrThrow(projectDir);\n const updated = applySplit(transcript, opts.word, opts.at, opts.first, opts.second);\n save(project, updated, !opts.regenerate);\n console.log(`Split word ${opts.word} at ${opts.at} in ${project.dir}`);\n } catch (err) {\n console.error(`atelier transcript split: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n\n transcript\n .command(\"list <project>\")\n .description(\"Print all words with their indices for reference.\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (projectDir: string, opts: { json?: boolean }) => {\n try {\n const { transcript } = loadOrThrow(projectDir);\n const words = flattenWords(transcript);\n if (opts.json) {\n console.log(JSON.stringify(words.map((w, i) => ({ index: i, ...w })), null, 2));\n } else {\n for (let i = 0; i < words.length; i++) {\n const w = words[i];\n const flags: string[] = [];\n if (w.userEdited) flags.push(\"edited\");\n if (w.userAdded) flags.push(\"added\");\n if (w.hidden) flags.push(\"hidden\");\n const flagStr = flags.length ? ` [${flags.join(\", \")}]` : \"\";\n const editedDisplay = w.text !== w.detected ? ` ← \"${w.detected}\"` : \"\";\n console.log(\n ` [${i.toString().padStart(4)}] ${w.start.toFixed(2).padStart(7)}s ` +\n `\"${w.text}\"${editedDisplay}${flagStr}`,\n );\n }\n }\n } catch (err) {\n console.error(`atelier transcript list: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from \"commander\";\nimport {\n loadVideoProject,\n readTranscript,\n readComposition,\n writeComposition,\n} from \"../lib/video-project.js\";\nimport { rewriteCaptionLayers } from \"../lib/caption-builder.js\";\nimport { loadRecipe, applyRecipeToCaptionOptions } from \"../lib/recipe.js\";\n\n/** Register `atelier captions regenerate <project>` */\nexport function captionsCommand(program: Command): void {\n const captions = program.command(\"captions\").description(\"Manage caption layers in a VideoProject\");\n\n captions\n .command(\"regenerate <project>\")\n .description(\n \"Re-derive caption-tagged TextVisual layers from the current transcript.json. \" +\n \"Used when caption styling changes without re-running Whisper.\",\n )\n .option(\"--recipe <name>\", \"Apply a Studio Recipe's caption_style + caption_grouping\")\n .action(async (projectDir: string, opts: { recipe?: string }) => {\n try {\n const project = loadVideoProject(projectDir);\n const transcript = readTranscript(project);\n if (!transcript) {\n throw new Error(\n `No transcript.json in ${projectDir}. Run \\`atelier transcribe ${projectDir}\\` first.`,\n );\n }\n const captionOptions = opts.recipe\n ? applyRecipeToCaptionOptions(loadRecipe(opts.recipe, projectDir).recipe)\n : {};\n const doc = readComposition(project);\n const updated = rewriteCaptionLayers(doc, transcript, captionOptions);\n writeComposition(project, updated);\n const captionLayers = updated.layers.filter((l) =>\n (l.tags ?? []).includes(\"caption\"),\n );\n console.log(\n `Regenerated ${captionLayers.length} caption layer${captionLayers.length === 1 ? \"\" : \"s\"} in ${project.dir}`,\n );\n } catch (err) {\n console.error(`atelier captions regenerate: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n","import { writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport type { Command } from \"commander\";\nimport {\n loadRecipe,\n scaffoldRecipeYaml,\n renderRecipeWithDefaults,\n recipeToYaml,\n} from \"../lib/recipe.js\";\n\n/** Register `atelier recipe new/validate/show` family */\nexport function recipeCommand(program: Command): void {\n const recipe = program.command(\"recipe\").description(\"Manage Studio Recipes — reusable style presets\");\n\n recipe\n .command(\"new <name>\")\n .description(\"Scaffold a starter recipe YAML with all current defaults filled in\")\n .option(\"--dir <path>\", \"Where to write the recipe (default: ./.atelier/recipes/)\")\n .action((name: string, opts: { dir?: string }) => {\n try {\n const baseDir = opts.dir ?? join(resolve(process.cwd()), \".atelier\", \"recipes\");\n if (!existsSync(baseDir)) {\n mkdirSync(baseDir, { recursive: true });\n }\n // Footgun guard: if the name already carries a recognized extension,\n // treat it as a filename so `recipe new foo.recipe.yaml` doesn't\n // produce `foo.recipe.yaml.recipe.yaml`. Otherwise append the canonical\n // extension. The bare-name stem (without ext) is what `recipe validate\n // <name>` resolves, so they stay in agreement.\n const hasKnownExt = /\\.(recipe\\.yaml|recipe\\.json|yaml|yml|json)$/i.test(name);\n const fileName = hasKnownExt ? name : `${name}.recipe.yaml`;\n const outPath = join(baseDir, fileName);\n if (existsSync(outPath)) {\n throw new Error(`Recipe already exists at ${outPath} — refusing to overwrite.`);\n }\n const recipeName = name.replace(/\\.(recipe\\.yaml|recipe\\.json|yaml|yml|json)$/i, \"\");\n const yaml = scaffoldRecipeYaml(recipeName);\n writeFileSync(outPath, yaml, \"utf-8\");\n console.log(`Created ${outPath}`);\n } catch (err) {\n console.error(`atelier recipe new: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n\n recipe\n .command(\"validate <path>\")\n .description(\"Validate a recipe against the schema (^valid-recipe gate). Warns on reserved Phase 3 fields.\")\n .option(\"--json\", \"Output result as JSON\")\n .action((path: string, opts: { json?: boolean }) => {\n try {\n // Resolve a bare name against the project-local recipes dir first\n // (where `recipe new` writes), then the user library — so new/validate\n // agree on where a bare name lives.\n const loaded = loadRecipe(path, process.cwd());\n if (opts.json) {\n console.log(JSON.stringify({\n valid: true,\n path: loaded.path,\n warnings: loaded.warnings,\n }, null, 2));\n } else {\n console.log(`PASS ${loaded.path}`);\n for (const w of loaded.warnings) {\n console.log(` ⚠ ${w}`);\n }\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (opts.json) {\n console.log(JSON.stringify({ valid: false, error: msg }, null, 2));\n } else {\n console.error(`FAIL ${path}`);\n console.error(` ${msg}`);\n }\n process.exit(1);\n }\n });\n\n recipe\n .command(\"show <path>\")\n .description(\"Print a recipe; --with-defaults fills in every omitted field with its code default.\")\n .option(\"--with-defaults\", \"Overlay code defaults onto omitted fields\")\n .action((path: string, opts: { withDefaults?: boolean }) => {\n try {\n // Same project-local-first resolution as `recipe validate`.\n const loaded = loadRecipe(path, process.cwd());\n const out = opts.withDefaults ? renderRecipeWithDefaults(loaded.recipe) : loaded.recipe;\n console.log(recipeToYaml(out));\n for (const w of loaded.warnings) {\n console.error(`# ⚠ ${w}`);\n }\n } catch (err) {\n console.error(`atelier recipe show: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from \"commander\";\nimport { trimProject } from \"./trim.js\";\nimport { transcribeProject } from \"./transcribe.js\";\nimport {\n loadRecipe,\n applyRecipeToTrimOptions,\n applyRecipeToTranscribeOptions,\n applyRecipeToOverlay,\n} from \"../lib/recipe.js\";\nimport {\n loadVideoProject,\n readComposition,\n writeComposition,\n} from \"../lib/video-project.js\";\n\n/**\n * Register `atelier apply-recipe <project> <recipe>` — convenience verb that\n * runs `atelier trim` and `atelier transcribe` against the same recipe in\n * one shot. Useful for fresh-project bootstrap.\n */\nexport function applyRecipeCommand(program: Command): void {\n program\n .command(\"apply-recipe <project> <recipe>\")\n .description(\n \"Apply a Studio Recipe by running atelier trim + atelier transcribe \" +\n \"with the same recipe, in that order.\",\n )\n .option(\"--reset\", \"Apply --reset to both pipelines (destructive — discards existing user padding and transcript edits)\")\n .option(\"--no-trim\", \"Skip the atelier trim step\")\n .option(\"--no-transcribe\", \"Skip the atelier transcribe step\")\n .action(async (\n project: string,\n recipeRef: string,\n opts: { reset?: boolean; trim: boolean; transcribe: boolean },\n ) => {\n try {\n const { recipe, path, warnings } = loadRecipe(recipeRef, project);\n console.log(`Loaded recipe ${path}`);\n for (const w of warnings) console.log(` ⚠ ${w}`);\n\n if (opts.trim) {\n const trimOpts = applyRecipeToTrimOptions(recipe, { reset: opts.reset });\n console.log(`\\nRunning atelier trim...`);\n const r = await trimProject(project, trimOpts);\n console.log(` ${r.cuts.length} cut${r.cuts.length === 1 ? \"\" : \"s\"} written`);\n }\n\n if (opts.transcribe) {\n const transcribeOpts = applyRecipeToTranscribeOptions(recipe, { reset: opts.reset });\n console.log(`\\nRunning atelier transcribe...`);\n const r = await transcribeProject(project, transcribeOpts);\n console.log(` ${r.wordCount} words, ${r.captionsGenerated ? \"captions written\" : \"captions skipped\"}`);\n }\n\n // Overlay translator — rewrites \"overlay\"-tagged layers in project.atelier\n // from recipe.overlay_rules. Single-frame apply: no carousel ctx, so\n // page_number is silently skipped (handle is always applied if present).\n if (recipe.overlay_rules) {\n const vp = loadVideoProject(project);\n const doc = readComposition(vp);\n const updated = applyRecipeToOverlay(doc, recipe);\n writeComposition(vp, updated);\n console.log(`\\nApplied overlay rules to ${vp.compositionPath}`);\n }\n\n console.log(`\\nDone.`);\n } catch (err) {\n console.error(`atelier apply-recipe: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":["init_dist","import_zod","z","yamlParse","init_dist","import_node_fs","import_node_path","import_node_fs","import_node_path","init_dist","readAndParse","createCanvas","renderFrame","import_node_fs","import_node_path","init_dist","resolve","loadImage","createCanvas","readAndParse","import_node_fs","import_node_path","init_dist","colorToCSS","readAndParse","import_node_fs","import_node_path","r","g","b","a","isExpression","kfs","buildTransform","readAndParse","import_node_fs","import_node_path","init_dist","preloadImages","loadImage","ImageCache","resolve","createCanvas","renderFrame","readAndParse","import_node_fs","import_node_path","import_node_fs","import_node_path","import_yaml","parseYaml","stringifyYaml","parseDim","import_node_fs","import_node_path","readAndParse","import_node_fs","import_node_path","init_dist","readAndParse","import_node_fs","import_node_path","import_node_child_process","resolve","import_node_child_process","import_node_fs","resolve","formatResult","transcript","import_node_fs","import_node_path"]}