@a-company/atelier 0.28.2 → 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.
package/dist/cli.cjs.map CHANGED
@@ -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/ref-renderer.ts","../../canvas/src/render-frame.ts","../../canvas/src/image-cache.ts","../src/cli.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","../src/commands/studio.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}\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 return { id: layer.id, layer, computedProperties };\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 { 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, Shape } from \"@a-company/atelier-types\";\nimport type { ResolvedFrame } from \"@a-company/atelier-core\";\nimport type { RenderContext, DocumentResolver } 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 { 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}\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 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 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\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 }\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 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 \"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 \"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 \"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","#!/usr/bin/env node\n// @a-company/atelier-cli — Entry point for the `atelier` command\n\nimport { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { validateCommand } from \"./commands/validate.js\";\nimport { infoCommand } from \"./commands/info.js\";\nimport { stillCommand } from \"./commands/still.js\";\nimport { renderCommand } from \"./commands/render.js\";\nimport { exportSvgCommand } from \"./commands/export-svg.js\";\nimport { exportLottieCommand } from \"./commands/export-lottie.js\";\nimport { assetsCommand } from \"./commands/assets.js\";\nimport { variablesCommand } from \"./commands/variables.js\";\nimport { studioCommand } from \"./commands/studio.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"atelier\")\n .description(\"Atelier animation CLI\")\n .version(createRequire(import.meta.url)(\"../package.json\").version);\n\n// Register commands\nvalidateCommand(program);\ninfoCommand(program);\nstillCommand(program);\nrenderCommand(program);\nexportSvgCommand(program);\nexportLottieCommand(program);\nassetsCommand(program);\nvariablesCommand(program);\nstudioCommand(program);\n\nprogram.parse();\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 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 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\"]);\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});\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 } 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","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","/**\n * `atelier studio [file]` — launch the browser-based Atelier editor.\n *\n * Spins up a Vite dev server with a temporary app that imports AtelierStudio,\n * provides a file API for reading/writing .atelier files from CWD, and opens\n * the browser.\n *\n * Usage:\n * atelier studio → browse all .atelier files in CWD\n * atelier studio my-animation.atelier → open specific file\n * atelier studio --port 8080 → custom port\n * atelier studio --no-open → don't auto-open browser\n */\n\nimport { resolve, join, relative, dirname } from \"node:path\";\nimport { mkdirSync, writeFileSync, rmSync, readFileSync, readdirSync, statSync, realpathSync, symlinkSync, existsSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { randomBytes } from \"node:crypto\";\nimport { exec } from \"node:child_process\";\nimport type { Command } from \"commander\";\n\n/** Recursively glob for .atelier files under a directory. */\nfunction findAtelierFiles(dir: string, base: string = dir): string[] {\n const results: string[] = [];\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return results;\n }\n for (const entry of entries) {\n if (entry === \"node_modules\" || entry === \"dist\" || entry === \".git\") continue;\n const full = join(dir, entry);\n let stat;\n try {\n stat = statSync(full);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n results.push(...findAtelierFiles(full, base));\n } else if (entry.endsWith(\".atelier\")) {\n results.push(relative(base, full));\n }\n }\n return results.sort();\n}\n\n/** Validate that a file path is safe (relative, no traversal). */\nfunction isSafePath(filePath: string): boolean {\n if (!filePath || filePath.includes(\"..\") || filePath.startsWith(\"/\")) return false;\n const resolved = resolve(process.cwd(), filePath);\n return resolved.startsWith(process.cwd());\n}\n\nfunction getInlineHTML(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Atelier Studio</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&display=swap\" rel=\"stylesheet\">\n </head>\n <body>\n <div id=\"studio\"></div>\n <script type=\"module\" src=\"/main.ts\"></script>\n </body>\n</html>`;\n}\n\nfunction getInlineApp(initialFile: string | null): string {\n const initialFileStr = initialFile ? JSON.stringify(initialFile) : \"null\";\n return `import { AtelierStudio, exportDocument, ImageCache } from \"@a-company/atelier-studio\";\nimport \"@a-company/atelier-studio/styles.css\";\nimport { parseAtelier, serializeAtelier } from \"@a-company/atelier-schema\";\n\n// ── Types ──\ninterface FileEntry {\n path: string;\n name: string;\n folder: string;\n}\n\n// ── State ──\nlet studio: AtelierStudio | null = null;\nlet currentFile: string | null = null;\nlet files: FileEntry[] = [];\nlet saveTimeout: ReturnType<typeof setTimeout> | null = null;\n\n// ── API helpers ──\nasync function fetchFiles(): Promise<FileEntry[]> {\n const res = await fetch(\"/api/files\");\n return res.json();\n}\n\nasync function fetchFileContent(path: string): Promise<string> {\n const res = await fetch(\"/api/file?path=\" + encodeURIComponent(path));\n return res.text();\n}\n\nasync function saveFileContent(path: string, content: string): Promise<void> {\n await fetch(\"/api/file?path=\" + encodeURIComponent(path), {\n method: \"POST\",\n headers: { \"Content-Type\": \"text/plain\" },\n body: content,\n });\n}\n\nasync function saveExportBlob(path: string, blob: Blob): Promise<void> {\n const buf = await blob.arrayBuffer();\n await fetch(\"/api/export?path=\" + encodeURIComponent(path), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/octet-stream\" },\n body: buf,\n });\n}\n\nasync function exportAll(format: \"gif\" | \"mp4\" | \"webm\"): Promise<void> {\n if (files.length === 0) return;\n\n // Create progress overlay\n const overlay = document.createElement(\"div\");\n overlay.style.cssText = \"position:fixed;inset:0;background:rgba(0,0,0,0.75);display:flex;align-items:center;justify-content:center;z-index:10000\";\n const card = document.createElement(\"div\");\n card.style.cssText = \"background:#333;border:1px solid #4A4A4A;border-radius:8px;padding:32px 40px;min-width:360px;color:#F5F0EB;font-family:'Cormorant Garamond',Georgia,serif\";\n overlay.appendChild(card);\n document.body.appendChild(overlay);\n\n const title = document.createElement(\"div\");\n title.style.cssText = \"font-size:18px;margin-bottom:16px;font-weight:600\";\n title.textContent = \"Exporting All Files…\";\n card.appendChild(title);\n\n const fileLabel = document.createElement(\"div\");\n fileLabel.style.cssText = \"font-size:13px;color:#A89F95;margin-bottom:8px;font-family:'SF Mono','Fira Code',monospace\";\n card.appendChild(fileLabel);\n\n const progress = document.createElement(\"progress\");\n progress.style.cssText = \"width:100%;height:6px;appearance:none;-webkit-appearance:none\";\n progress.max = files.length;\n progress.value = 0;\n card.appendChild(progress);\n\n const statusText = document.createElement(\"div\");\n statusText.style.cssText = \"font-size:12px;color:#A89F95;margin-top:8px\";\n card.appendChild(statusText);\n\n let exported = 0;\n let errors = 0;\n\n for (const file of files) {\n fileLabel.textContent = file.path;\n statusText.textContent = (exported + errors + 1) + \" / \" + files.length;\n\n try {\n const content = await fetchFileContent(file.path);\n const result = parseAtelier(content);\n if (!result.success) {\n errors++;\n progress.value = exported + errors;\n continue;\n }\n\n const doc = result.data;\n const w = doc.canvas.width;\n const h = doc.canvas.height;\n const canvas = document.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const imageCache = new ImageCache();\n\n const exportResult = await exportDocument(doc, canvas, imageCache, {\n format,\n onProgress: ({ percent }) => {\n statusText.textContent = (exported + errors + 1) + \" / \" + files.length + \" — \" + percent + \"%\";\n },\n });\n\n // Save alongside the source file: e.g. \"dir/my-anim.atelier\" → \"dir/my-anim.gif\"\n const outPath = file.path.replace(/\\\\.atelier$/, \".\" + format);\n await saveExportBlob(outPath, exportResult.blob);\n exported++;\n } catch (e) {\n console.error(\"Export failed:\", file.path, e);\n errors++;\n }\n progress.value = exported + errors;\n }\n\n // Done\n title.textContent = \"Export Complete\";\n fileLabel.textContent = \"\";\n statusText.textContent = exported + \" exported\" + (errors > 0 ? \", \" + errors + \" failed\" : \"\");\n if (errors > 0) console.warn(\"Export All finished with \" + errors + \" error(s). Check console for details.\");\n\n const closeBtn = document.createElement(\"button\");\n closeBtn.style.cssText = \"margin-top:16px;padding:6px 20px;background:#3D3D3D;color:#F5F0EB;border:1px solid #4A4A4A;border-radius:4px;cursor:pointer;font-family:inherit;font-size:13px\";\n closeBtn.textContent = \"Close\";\n closeBtn.addEventListener(\"click\", () => document.body.removeChild(overlay));\n card.appendChild(closeBtn);\n}\n\n// ── Theme (matches branded theme from showcase) ──\nconst theme = {\n bg: \"#2C2C2C\",\n bgSecondary: \"#333333\",\n bgTertiary: \"#3D3D3D\",\n text: \"#F5F0EB\",\n textMuted: \"#A89F95\",\n textAccent: \"#F5F0EB\",\n border: \"#4A4A4A\",\n buttonBg: \"#3D3D3D\",\n buttonHover: \"#4A4A4A\",\n buttonActive: \"#555555\",\n accent: \"#C75B39\",\n accentHover: \"#D4724E\",\n sliderTrack: \"#4A4A4A\",\n sliderThumb: \"#C75B39\",\n fontFamily: \"'Cormorant Garamond', Georgia, serif\",\n fontMono: \"'SF Mono', 'Fira Code', monospace\",\n canvasShadow: \"0 4px 60px rgba(199, 91, 57, 0.12), 0 0 40px rgba(0,0,0,0.4)\",\n};\n\n// ── Styles ──\nconst style = document.createElement(\"style\");\nstyle.textContent = \\`\n * { margin: 0; padding: 0; box-sizing: border-box; }\n html, body { height: 100%; overflow: hidden; background: #2C2C2C; color: #F5F0EB; }\n body { font-family: 'Cormorant Garamond', Georgia, serif; }\n #studio { display: flex; height: 100vh; width: 100vw; }\n\n .sidebar {\n width: 260px;\n min-width: 260px;\n background: #333333;\n border-right: 1px solid #4A4A4A;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .sidebar__header {\n padding: 16px 20px;\n border-bottom: 1px solid #4A4A4A;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 2px;\n text-transform: uppercase;\n color: #A89F95;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .sidebar__header span {\n color: #C75B39;\n font-size: 13px;\n }\n .sidebar__list {\n flex: 1;\n overflow-y: auto;\n padding: 8px 0;\n }\n .sidebar__list::-webkit-scrollbar { width: 6px; }\n .sidebar__list::-webkit-scrollbar-track { background: transparent; }\n .sidebar__list::-webkit-scrollbar-thumb { background: #4A4A4A; border-radius: 3px; }\n\n .sidebar__folder {\n padding: 10px 20px 4px;\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 1.5px;\n text-transform: uppercase;\n color: #A89F95;\n }\n .sidebar__item {\n padding: 8px 20px 8px 28px;\n font-size: 13px;\n cursor: pointer;\n color: #A89F95;\n transition: background 0.15s, color 0.15s;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 11.5px;\n }\n .sidebar__item:hover { background: #363636; color: #F5F0EB; }\n .sidebar__item--active {\n background: rgba(199, 91, 57, 0.12) !important;\n color: #C75B39 !important;\n }\n\n .main {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .main__status {\n height: 32px;\n min-height: 32px;\n display: flex;\n align-items: center;\n padding: 0 16px;\n background: #333333;\n border-bottom: 1px solid #4A4A4A;\n font-size: 11px;\n color: #A89F95;\n font-family: 'SF Mono', 'Fira Code', monospace;\n gap: 12px;\n }\n .main__status .save-indicator {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-left: auto;\n transition: opacity 0.3s;\n }\n .main__status .save-indicator--saving { color: #C75B39; }\n .main__status .save-indicator--saved { color: #6B8E6B; }\n .main__editor {\n flex: 1;\n overflow: hidden;\n }\n .main__empty {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #A89F95;\n font-size: 18px;\n }\n\\`;\ndocument.head.appendChild(style);\n\n// ── Build UI ──\nconst root = document.getElementById(\"studio\")!;\nconst sidebar = document.createElement(\"div\");\nsidebar.className = \"sidebar\";\n\nconst sidebarHeader = document.createElement(\"div\");\nsidebarHeader.className = \"sidebar__header\";\nsidebarHeader.innerHTML = '<span>&#9670;</span> ATELIER STUDIO';\nsidebar.appendChild(sidebarHeader);\n\nconst sidebarList = document.createElement(\"div\");\nsidebarList.className = \"sidebar__list\";\nsidebar.appendChild(sidebarList);\n\nconst sidebarFooter = document.createElement(\"div\");\nsidebarFooter.style.cssText = \"padding:12px 16px;border-top:1px solid #4A4A4A;display:flex;gap:8px;align-items:center\";\nconst exportAllSelect = document.createElement(\"select\");\nexportAllSelect.style.cssText = \"flex:1;background:#3D3D3D;color:#F5F0EB;border:1px solid #4A4A4A;border-radius:4px;padding:4px 8px;font-size:11px;font-family:'SF Mono','Fira Code',monospace;cursor:pointer\";\nfor (const [val, label] of [[\"gif\",\"GIF\"],[\"mp4\",\"MP4\"],[\"webm\",\"WebM\"]] as const) {\n const o = document.createElement(\"option\");\n o.value = val;\n o.textContent = label;\n exportAllSelect.appendChild(o);\n}\nsidebarFooter.appendChild(exportAllSelect);\nconst exportAllBtn = document.createElement(\"button\");\nexportAllBtn.style.cssText = \"background:#C75B39;color:#F5F0EB;border:none;border-radius:4px;padding:5px 12px;font-size:11px;font-family:inherit;cursor:pointer;white-space:nowrap\";\nexportAllBtn.textContent = \"Export All\";\nexportAllBtn.addEventListener(\"click\", () => {\n exportAll(exportAllSelect.value as \"gif\" | \"mp4\" | \"webm\");\n});\nsidebarFooter.appendChild(exportAllBtn);\nsidebar.appendChild(sidebarFooter);\n\nconst main = document.createElement(\"div\");\nmain.className = \"main\";\n\nconst statusBar = document.createElement(\"div\");\nstatusBar.className = \"main__status\";\nmain.appendChild(statusBar);\n\nconst editorContainer = document.createElement(\"div\");\neditorContainer.className = \"main__editor\";\nmain.appendChild(editorContainer);\n\nroot.appendChild(sidebar);\nroot.appendChild(main);\n\n// ── File list rendering ──\nfunction renderFileList(): void {\n sidebarList.innerHTML = \"\";\n let lastFolder = \"\";\n\n for (const file of files) {\n if (file.folder && file.folder !== lastFolder) {\n lastFolder = file.folder;\n const folder = document.createElement(\"div\");\n folder.className = \"sidebar__folder\";\n folder.textContent = file.folder;\n sidebarList.appendChild(folder);\n }\n\n const item = document.createElement(\"div\");\n item.className = \"sidebar__item\" + (file.path === currentFile ? \" sidebar__item--active\" : \"\");\n item.textContent = file.name;\n item.title = file.path;\n item.addEventListener(\"click\", () => loadFile(file.path));\n sidebarList.appendChild(item);\n }\n}\n\n// ── Load a file into the studio ──\nasync function loadFile(path: string): Promise<void> {\n currentFile = path;\n renderFileList();\n\n const content = await fetchFileContent(path);\n const result = parseAtelier(content);\n\n if (!result.success) {\n editorContainer.innerHTML = \"\";\n const err = document.createElement(\"div\");\n err.className = \"main__empty\";\n err.style.flexDirection = \"column\";\n err.style.gap = \"8px\";\n err.innerHTML = '<div style=\"color:#C75B39\">Parse Error</div><div style=\"font-size:13px;font-family:monospace\">' +\n result.errors.map(e => e.path + \": \" + e.message).join(\"<br>\") + \"</div>\";\n editorContainer.appendChild(err);\n return;\n }\n\n statusBar.innerHTML = '<span>' + path + '</span><span class=\"save-indicator save-indicator--saved\">&#10003; saved</span>';\n\n if (studio) {\n studio.destroy();\n studio = null;\n }\n\n // Set filename for export downloads (strip path and .atelier extension)\n const baseName = path.split(\"/\").pop()?.replace(/\\\\.atelier$/, \"\") || null;\n\n studio = new AtelierStudio(editorContainer, {\n mode: \"full\",\n initialTab: \"yaml\",\n allowSave: true,\n onDocumentChange: (doc) => {\n // Auto-save with debounce\n const indicator = statusBar.querySelector(\".save-indicator\");\n if (indicator) {\n indicator.className = \"save-indicator save-indicator--saving\";\n indicator.innerHTML = \"&#9679; saving...\";\n }\n\n if (saveTimeout) clearTimeout(saveTimeout);\n saveTimeout = setTimeout(async () => {\n if (!currentFile) return;\n const yaml = serializeAtelier(doc);\n await saveFileContent(currentFile, yaml);\n const ind = statusBar.querySelector(\".save-indicator\");\n if (ind) {\n ind.className = \"save-indicator save-indicator--saved\";\n ind.innerHTML = \"&#10003; saved\";\n }\n }, 800);\n },\n });\n studio.setTheme(theme);\n studio.setFilename(baseName);\n studio.loadDocument(result.data);\n}\n\n// ── Boot ──\nasync function boot(): Promise<void> {\n files = await fetchFiles();\n\n if (files.length === 0) {\n editorContainer.innerHTML = \"\";\n const empty = document.createElement(\"div\");\n empty.className = \"main__empty\";\n empty.textContent = \"No .atelier files found in this directory\";\n editorContainer.appendChild(empty);\n statusBar.textContent = \"No files\";\n renderFileList();\n return;\n }\n\n renderFileList();\n\n const initialFile = ${initialFileStr};\n const target = initialFile\n ? files.find(f => f.path === initialFile || f.path.endsWith(initialFile))\n : files[0];\n\n if (target) {\n await loadFile(target.path);\n }\n}\n\nboot();\n`;\n}\n\n/** Register the `studio` subcommand on the Commander program. */\nexport function studioCommand(program: Command): void {\n program\n .command(\"studio [file]\")\n .description(\"Launch the browser-based Atelier editor\")\n .option(\"-p, --port <number>\", \"Port to serve on\", \"4321\")\n .option(\"--no-open\", \"Don't auto-open browser\")\n .action(\n async (\n file: string | undefined,\n options: { port: string; open: boolean },\n ) => {\n const port = parseInt(options.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n console.error(`Invalid port: ${options.port}`);\n process.exit(1);\n }\n\n const cwd = process.cwd();\n\n // Find the CLI package directory (where node_modules lives).\n // This file is at packages/cli/dist/cli.js (or src/commands/studio.ts in dev).\n const cliPackageDir = resolve(dirname(new URL(import.meta.url).pathname), \"..\");\n\n // Create temp directory with inline app.\n // Use realpathSync to resolve macOS /var -> /private/var symlink,\n // which Vite normalizes internally when resolving file paths.\n const tmpId = randomBytes(4).toString(\"hex\");\n const tmpDirRaw = join(tmpdir(), `atelier-studio-${tmpId}`);\n mkdirSync(tmpDirRaw, { recursive: true });\n const tmpDir = realpathSync(tmpDirRaw);\n\n writeFileSync(join(tmpDir, \"index.html\"), getInlineHTML());\n writeFileSync(join(tmpDir, \"main.ts\"), getInlineApp(file ?? null));\n\n // Symlink node_modules into temp dir so Vite can resolve @a-company/* packages.\n // Works for both monorepo (pnpm workspace links) and npm global install.\n const cliNodeModules = join(cliPackageDir, \"node_modules\");\n if (existsSync(cliNodeModules)) {\n try {\n symlinkSync(cliNodeModules, join(tmpDir, \"node_modules\"), \"dir\");\n } catch {\n // Non-fatal: aliases will handle resolution if symlink fails\n }\n }\n\n console.log(`Starting Atelier Studio...`);\n console.log(` Working directory: ${cwd}`);\n\n // Dynamically import Vite (it's a peer/optional dep)\n let vite: typeof import(\"vite\");\n try {\n vite = await import(\"vite\");\n } catch {\n console.error(\"Vite is required for `atelier studio`.\");\n console.error(\"Install it: pnpm add -D vite\");\n process.exit(1);\n return;\n }\n\n const server = await vite.createServer({\n root: tmpDir,\n server: {\n port,\n strictPort: false,\n fs: {\n strict: false,\n },\n },\n plugins: [\n {\n name: \"atelier-api\",\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const url = new URL(req.url ?? \"/\", `http://localhost:${port}`);\n\n if (url.pathname === \"/api/files\") {\n const atelierFiles = findAtelierFiles(cwd);\n const entries = atelierFiles.map((p) => {\n const parts = p.split(\"/\");\n return {\n path: p,\n name: parts[parts.length - 1].replace(\".atelier\", \"\"),\n folder: parts.length > 1 ? parts.slice(0, -1).join(\"/\") : \"\",\n };\n });\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify(entries));\n return;\n }\n\n if (url.pathname === \"/api/file\") {\n const filePath = url.searchParams.get(\"path\");\n if (!filePath || !isSafePath(filePath)) {\n res.statusCode = 400;\n res.end(\"Invalid path\");\n return;\n }\n\n const absPath = resolve(cwd, filePath);\n\n if (req.method === \"GET\") {\n try {\n const content = readFileSync(absPath, \"utf-8\");\n res.setHeader(\"Content-Type\", \"text/plain\");\n res.end(content);\n } catch {\n res.statusCode = 404;\n res.end(\"File not found\");\n }\n return;\n }\n\n if (req.method === \"POST\") {\n let body = \"\";\n req.on(\"data\", (chunk: Buffer) => { body += chunk.toString(); });\n req.on(\"end\", () => {\n try {\n writeFileSync(absPath, body, \"utf-8\");\n res.end(\"OK\");\n } catch {\n res.statusCode = 500;\n res.end(\"Write failed\");\n }\n });\n return;\n }\n }\n\n if (url.pathname === \"/api/export\" && req.method === \"POST\") {\n const filePath = url.searchParams.get(\"path\");\n if (!filePath || !isSafePath(filePath)) {\n res.statusCode = 400;\n res.end(\"Invalid path\");\n return;\n }\n\n const absPath = resolve(cwd, filePath);\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => { chunks.push(chunk); });\n req.on(\"end\", () => {\n try {\n mkdirSync(dirname(absPath), { recursive: true });\n writeFileSync(absPath, Buffer.concat(chunks));\n res.end(\"OK\");\n } catch {\n res.statusCode = 500;\n res.end(\"Write failed\");\n }\n });\n return;\n }\n\n if (url.pathname === \"/api/cwd\") {\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify({ cwd }));\n return;\n }\n\n next();\n });\n },\n },\n ],\n logLevel: \"warn\",\n });\n\n await server.listen();\n\n const resolvedUrl = server.resolvedUrls?.local[0] ?? `http://localhost:${port}`;\n const url = resolvedUrl;\n\n console.log(` Server running at: ${url}`);\n\n const atelierFiles = findAtelierFiles(cwd);\n console.log(` Found ${atelierFiles.length} .atelier file(s)`);\n\n if (file) {\n console.log(` Opening: ${file}`);\n }\n\n console.log(` Press Ctrl+C to stop\\n`);\n\n if (options.open) {\n exec(`open \"${url}\"`);\n }\n\n // Keep alive and handle cleanup\n const cleanup = () => {\n console.log(\"\\nShutting down...\");\n server.close();\n try {\n rmSync(tmpDir, { recursive: true, force: true });\n } catch {\n // ignore cleanup errors\n }\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n },\n );\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA0Ze,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYtC;AAGO,SAAS,cAAcC,UAAwB;AACpD,EAAAA,SACG,QAAQ,eAAe,EACvB,YAAY,yCAAyC,EACrD,OAAO,uBAAuB,oBAAoB,MAAM,EACxD,OAAO,aAAa,yBAAyB,EAC7C;AAAA,IACC,OACE,MACA,YACG;AACH,YAAM,OAAO,SAAS,QAAQ,MAAM,EAAE;AACtC,UAAI,MAAM,IAAI,KAAK,OAAO,KAAK,OAAO,OAAO;AAC3C,gBAAQ,MAAM,iBAAiB,QAAQ,IAAI,EAAE;AAC7C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,MAAM,QAAQ,IAAI;AAIxB,YAAM,oBAAgB,+BAAQ,2BAAQ,IAAI,IAAI,YAAY,GAAG,EAAE,QAAQ,GAAG,IAAI;AAK9E,YAAM,YAAQ,gCAAY,CAAC,EAAE,SAAS,KAAK;AAC3C,YAAM,gBAAY,4BAAK,uBAAO,GAAG,kBAAkB,KAAK,EAAE;AAC1D,qCAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AACxC,YAAM,aAAS,8BAAa,SAAS;AAErC,6CAAc,wBAAK,QAAQ,YAAY,GAAG,cAAc,CAAC;AACzD,6CAAc,wBAAK,QAAQ,SAAS,GAAG,aAAa,QAAQ,IAAI,CAAC;AAIjE,YAAM,qBAAiB,wBAAK,eAAe,cAAc;AACzD,cAAI,4BAAW,cAAc,GAAG;AAC9B,YAAI;AACF,2CAAY,oBAAgB,wBAAK,QAAQ,cAAc,GAAG,KAAK;AAAA,QACjE,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,cAAQ,IAAI,4BAA4B;AACxC,cAAQ,IAAI,wBAAwB,GAAG,EAAE;AAGzC,UAAI;AACJ,UAAI;AACF,eAAO,MAAM,OAAO,MAAM;AAAA,MAC5B,QAAQ;AACN,gBAAQ,MAAM,wCAAwC;AACtD,gBAAQ,MAAM,8BAA8B;AAC5C,gBAAQ,KAAK,CAAC;AACd;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,KAAK,aAAa;AAAA,QACrC,MAAM;AAAA,QACN,QAAQ;AAAA,UACN;AAAA,UACA,YAAY;AAAA,UACZ,IAAI;AAAA,YACF,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,gBAAgBC,SAAQ;AACtB,cAAAA,QAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AACzC,sBAAMC,OAAM,IAAI,IAAI,IAAI,OAAO,KAAK,oBAAoB,IAAI,EAAE;AAE9D,oBAAIA,KAAI,aAAa,cAAc;AACjC,wBAAMC,gBAAe,iBAAiB,GAAG;AACzC,wBAAM,UAAUA,cAAa,IAAI,CAAC,MAAM;AACtC,0BAAM,QAAQ,EAAE,MAAM,GAAG;AACzB,2BAAO;AAAA,sBACL,MAAM;AAAA,sBACN,MAAM,MAAM,MAAM,SAAS,CAAC,EAAE,QAAQ,YAAY,EAAE;AAAA,sBACpD,QAAQ,MAAM,SAAS,IAAI,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAAI;AAAA,oBAC5D;AAAA,kBACF,CAAC;AACD,sBAAI,UAAU,gBAAgB,kBAAkB;AAChD,sBAAI,IAAI,KAAK,UAAU,OAAO,CAAC;AAC/B;AAAA,gBACF;AAEA,oBAAID,KAAI,aAAa,aAAa;AAChC,wBAAM,WAAWA,KAAI,aAAa,IAAI,MAAM;AAC5C,sBAAI,CAAC,YAAY,CAAC,WAAW,QAAQ,GAAG;AACtC,wBAAI,aAAa;AACjB,wBAAI,IAAI,cAAc;AACtB;AAAA,kBACF;AAEA,wBAAM,cAAU,2BAAQ,KAAK,QAAQ;AAErC,sBAAI,IAAI,WAAW,OAAO;AACxB,wBAAI;AACF,4BAAM,cAAU,8BAAa,SAAS,OAAO;AAC7C,0BAAI,UAAU,gBAAgB,YAAY;AAC1C,0BAAI,IAAI,OAAO;AAAA,oBACjB,QAAQ;AACN,0BAAI,aAAa;AACjB,0BAAI,IAAI,gBAAgB;AAAA,oBAC1B;AACA;AAAA,kBACF;AAEA,sBAAI,IAAI,WAAW,QAAQ;AACzB,wBAAI,OAAO;AACX,wBAAI,GAAG,QAAQ,CAAC,UAAkB;AAAE,8BAAQ,MAAM,SAAS;AAAA,oBAAG,CAAC;AAC/D,wBAAI,GAAG,OAAO,MAAM;AAClB,0BAAI;AACF,2DAAc,SAAS,MAAM,OAAO;AACpC,4BAAI,IAAI,IAAI;AAAA,sBACd,QAAQ;AACN,4BAAI,aAAa;AACjB,4BAAI,IAAI,cAAc;AAAA,sBACxB;AAAA,oBACF,CAAC;AACD;AAAA,kBACF;AAAA,gBACF;AAEA,oBAAIA,KAAI,aAAa,iBAAiB,IAAI,WAAW,QAAQ;AAC3D,wBAAM,WAAWA,KAAI,aAAa,IAAI,MAAM;AAC5C,sBAAI,CAAC,YAAY,CAAC,WAAW,QAAQ,GAAG;AACtC,wBAAI,aAAa;AACjB,wBAAI,IAAI,cAAc;AACtB;AAAA,kBACF;AAEA,wBAAM,cAAU,2BAAQ,KAAK,QAAQ;AACrC,wBAAM,SAAmB,CAAC;AAC1B,sBAAI,GAAG,QAAQ,CAAC,UAAkB;AAAE,2BAAO,KAAK,KAAK;AAAA,kBAAG,CAAC;AACzD,sBAAI,GAAG,OAAO,MAAM;AAClB,wBAAI;AACF,yDAAU,2BAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C,yDAAc,SAAS,OAAO,OAAO,MAAM,CAAC;AAC5C,0BAAI,IAAI,IAAI;AAAA,oBACd,QAAQ;AACN,0BAAI,aAAa;AACjB,0BAAI,IAAI,cAAc;AAAA,oBACxB;AAAA,kBACF,CAAC;AACD;AAAA,gBACF;AAEA,oBAAIA,KAAI,aAAa,YAAY;AAC/B,sBAAI,UAAU,gBAAgB,kBAAkB;AAChD,sBAAI,IAAI,KAAK,UAAU,EAAE,IAAI,CAAC,CAAC;AAC/B;AAAA,gBACF;AAEA,qBAAK;AAAA,cACP,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,QACA,UAAU;AAAA,MACZ,CAAC;AAED,YAAM,OAAO,OAAO;AAEpB,YAAM,cAAc,OAAO,cAAc,MAAM,CAAC,KAAK,oBAAoB,IAAI;AAC7E,YAAM,MAAM;AAEZ,cAAQ,IAAI,wBAAwB,GAAG,EAAE;AAEzC,YAAM,eAAe,iBAAiB,GAAG;AACzC,cAAQ,IAAI,WAAW,aAAa,MAAM,mBAAmB;AAE7D,UAAI,MAAM;AACR,gBAAQ,IAAI,cAAc,IAAI,EAAE;AAAA,MAClC;AAEA,cAAQ,IAAI;AAAA,CAA0B;AAEtC,UAAI,QAAQ,MAAM;AAChB,6CAAK,SAAS,GAAG,GAAG;AAAA,MACtB;AAGA,YAAM,UAAU,MAAM;AACpB,gBAAQ,IAAI,oBAAoB;AAChC,eAAO,MAAM;AACb,YAAI;AACF,sCAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QACjD,QAAQ;AAAA,QAER;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,cAAQ,GAAG,UAAU,OAAO;AAC5B,cAAQ,GAAG,WAAW,OAAO;AAAA,IAC/B;AAAA,EACF;AACJ;;;AxC9rBA,IAAAE,eAAA;AAeA,IAAM,UAAU,IAAI,yBAAQ;AAE5B,QACG,KAAK,SAAS,EACd,YAAY,uBAAuB,EACnC,YAAQ,kCAAcA,aAAY,GAAG,EAAE,iBAAiB,EAAE,OAAO;AAGpE,gBAAgB,OAAO;AACvB,YAAY,OAAO;AACnB,aAAa,OAAO;AACpB,cAAc,OAAO;AACrB,iBAAiB,OAAO;AACxB,oBAAoB,OAAO;AAC3B,cAAc,OAAO;AACrB,iBAAiB,OAAO;AACxB,cAAc,OAAO;AAErB,QAAQ,MAAM;","names":["init_dist","import_zod","z","yamlParse","init_dist","program","import_node_fs","import_node_path","program","import_node_fs","import_node_path","init_dist","readAndParse","program","renderFrame","import_node_fs","import_node_path","init_dist","resolve","readAndParse","program","import_node_fs","import_node_path","init_dist","colorToCSS","readAndParse","program","import_node_fs","import_node_path","r","g","b","a","isExpression","kfs","buildTransform","readAndParse","program","import_node_fs","import_node_path","readAndParse","program","import_node_fs","import_node_path","init_dist","readAndParse","program","import_node_path","import_node_fs","import_node_child_process","program","server","url","atelierFiles","import_meta"]}
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/cli.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/lint.ts","../src/lib/video-project.ts","../src/lib/silence-detect.ts","../src/lib/cut-model.ts","../src/lib/recipe.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","../src/commands/carousel.ts","../src/lib/render-image.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/commands/assets.ts","../src/commands/variables.ts","../src/commands/studio.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","#!/usr/bin/env node\n// @a-company/atelier-cli — Entry point for the `atelier` command\n\nimport { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { validateCommand } from \"./commands/validate.js\";\nimport { lintCommand } from \"./commands/lint.js\";\nimport { trimCommand } from \"./commands/trim.js\";\nimport { transcribeCommand } from \"./commands/transcribe.js\";\nimport { transcriptCommand } from \"./commands/transcript.js\";\nimport { captionsCommand } from \"./commands/captions.js\";\nimport { recipeCommand } from \"./commands/recipe.js\";\nimport { applyRecipeCommand } from \"./commands/apply-recipe.js\";\nimport { carouselCommand } from \"./commands/carousel.js\";\nimport { infoCommand } from \"./commands/info.js\";\nimport { stillCommand } from \"./commands/still.js\";\nimport { renderCommand } from \"./commands/render.js\";\nimport { exportSvgCommand } from \"./commands/export-svg.js\";\nimport { exportLottieCommand } from \"./commands/export-lottie.js\";\nimport { exportImageCommand } from \"./commands/export-image.js\";\nimport { assetsCommand } from \"./commands/assets.js\";\nimport { variablesCommand } from \"./commands/variables.js\";\nimport { studioCommand } from \"./commands/studio.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"atelier\")\n .description(\"Atelier animation CLI\")\n .version(createRequire(import.meta.url)(\"../package.json\").version);\n\n// Register commands\nvalidateCommand(program);\nlintCommand(program);\ntrimCommand(program);\ntranscribeCommand(program);\ntranscriptCommand(program);\ncaptionsCommand(program);\nrecipeCommand(program);\napplyRecipeCommand(program);\ncarouselCommand(program);\ninfoCommand(program);\nstillCommand(program);\nrenderCommand(program);\nexportSvgCommand(program);\nexportLottieCommand(program);\nexportImageCommand(program);\nassetsCommand(program);\nvariablesCommand(program);\nstudioCommand(program);\n\nprogram.parse();\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 { VideoVisual } from \"@a-company/atelier-types\";\nimport { parseAtelier, validateVideoLayer } from \"@a-company/atelier-schema\";\nimport { validateAllDeltas } from \"@a-company/atelier-core\";\n\nexport interface GateResult {\n gate: string;\n pass: boolean;\n errors: string[];\n}\n\nexport interface LintResult {\n file: string;\n valid: boolean;\n gates: GateResult[];\n}\n\n/**\n * Run all gates against a single .atelier file.\n * Gates checked:\n * ^valid-document — Zod schema conformance\n * ^valid-delta — no overlapping deltas on same layer+property\n * ^valid-video-layer — semantic video layer constraints\n */\nexport function lintFile(filePath: string): LintResult {\n const absPath = resolve(filePath);\n\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n return {\n file: absPath,\n valid: false,\n gates: [\n {\n gate: \"^valid-document\",\n pass: false,\n errors: [`Cannot read file: ${absPath}`],\n },\n ],\n };\n }\n\n const gates: GateResult[] = [];\n\n // ── Gate 1: ^valid-document ──────────────────────────────────\n const parseResult = parseAtelier(content);\n if (!parseResult.success) {\n gates.push({\n gate: \"^valid-document\",\n pass: false,\n errors: parseResult.errors.map((e) => `${e.path}: ${e.message}`),\n });\n // Can't run further gates without a valid document\n return { file: absPath, valid: false, gates };\n }\n\n gates.push({ gate: \"^valid-document\", pass: true, errors: [] });\n const doc = parseResult.data;\n\n // ── Gate 2: ^valid-delta ─────────────────────────────────────\n const deltaErrors: string[] = [];\n for (const [stateName, state] of Object.entries(doc.states)) {\n const overlaps = validateAllDeltas(state.deltas);\n for (const overlap of overlaps) {\n deltaErrors.push(`State \"${stateName}\": ${overlap.message}`);\n }\n }\n gates.push({\n gate: \"^valid-delta\",\n pass: deltaErrors.length === 0,\n errors: deltaErrors,\n });\n\n // ── Gate 3: ^valid-video-layer ───────────────────────────────\n const videoErrors: string[] = [];\n for (const layer of doc.layers) {\n if (layer.visual.type !== \"video\") continue;\n const visual = layer.visual as VideoVisual;\n const duration = doc.assets?.[visual.assetId]?.videoMeta?.duration;\n const result = validateVideoLayer(visual, duration);\n if (!result.success) {\n for (const err of result.errors) {\n videoErrors.push(`Layer \"${layer.id}\" (${err.path}): ${err.message}`);\n }\n }\n }\n gates.push({\n gate: \"^valid-video-layer\",\n pass: videoErrors.length === 0,\n errors: videoErrors,\n });\n\n const valid = gates.every((g) => g.pass);\n return { file: absPath, valid, gates };\n}\n\n/** Format a LintResult for terminal output */\nfunction formatResult(result: LintResult): string {\n const lines: string[] = [];\n const status = result.valid ? \"PASS\" : \"FAIL\";\n lines.push(`${status} ${result.file}`);\n\n for (const gate of result.gates) {\n const gateStatus = gate.pass ? \" ✓\" : \" ✗\";\n lines.push(`${gateStatus} ${gate.gate}`);\n for (const err of gate.errors) {\n lines.push(` ${err}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Register the `lint` subcommand on the Commander program.\n */\nexport function lintCommand(program: Command): void {\n program\n .command(\"lint <files...>\")\n .description(\n \"Lint .atelier files against all gates (^valid-document, ^valid-delta, ^valid-video-layer)\",\n )\n .option(\"--json\", \"Output results as JSON array\")\n .action((files: string[], opts: { json?: boolean }) => {\n const results = files.map(lintFile);\n\n if (opts.json) {\n console.log(JSON.stringify(results, null, 2));\n } else {\n for (const result of results) {\n console.log(formatResult(result));\n }\n }\n\n const allValid = results.every((r) => r.valid);\n if (!allValid) process.exit(1);\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 { 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 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","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","/**\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 { 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","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","/**\n * `atelier studio [file]` — launch the browser-based Atelier editor.\n *\n * Spins up a Vite dev server with a temporary app that imports AtelierStudio,\n * provides a file API for reading/writing .atelier files from CWD, and opens\n * the browser.\n *\n * Usage:\n * atelier studio → browse all .atelier files in CWD\n * atelier studio my-animation.atelier → open specific file\n * atelier studio --port 8080 → custom port\n * atelier studio --no-open → don't auto-open browser\n */\n\nimport { resolve, join, relative, dirname, sep } from \"node:path\";\nimport { mkdirSync, writeFileSync, rmSync, readFileSync, readdirSync, statSync, realpathSync, symlinkSync, existsSync, copyFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { randomBytes } from \"node:crypto\";\nimport { exec } from \"node:child_process\";\nimport type { Command } from \"commander\";\nimport {\n DocumentStore,\n WebSocketServerTransport,\n createServer as createMcpServer,\n BRIDGE_PROTOCOL_VERSION,\n isBridgeEnvelope,\n type BridgeEnvelope,\n} from \"@a-company/atelier-mcp\";\nimport { parseAtelier, serializeAtelier } from \"@a-company/atelier-schema\";\nimport { WebSocketServer, type WebSocket as WsWebSocket } from \"ws\";\n\n/** Recursively glob for .atelier files under a directory. */\nfunction findAtelierFiles(dir: string, base: string = dir): string[] {\n const results: string[] = [];\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return results;\n }\n for (const entry of entries) {\n if (entry === \"node_modules\" || entry === \"dist\" || entry === \".git\") continue;\n const full = join(dir, entry);\n let stat;\n try {\n stat = statSync(full);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n results.push(...findAtelierFiles(full, base));\n } else if (entry.endsWith(\".atelier\")) {\n results.push(relative(base, full));\n }\n }\n return results.sort();\n}\n\n/**\n * Validate that a file path is safe (relative, contained within cwd).\n *\n * Rejects absolute inputs and any path that resolves outside the current\n * working directory. The containment test uses an exact-or-trailing-separator\n * prefix match so a sibling directory whose name merely starts with cwd\n * (e.g. cwd `/a/proj` vs resolved `/a/project-x`) is NOT treated as inside.\n * We intentionally do NOT reject a literal \"..\" substring — that blocks legit\n * names like `my..backup.atelier` while adding no real security (the resolved\n * containment check is the actual guard).\n */\nexport function isSafePath(filePath: string): boolean {\n if (!filePath || filePath.startsWith(\"/\")) return false;\n const cwd = process.cwd();\n const resolved = resolve(cwd, filePath);\n return resolved === cwd || resolved.startsWith(cwd + sep);\n}\n\n/**\n * Write a file, creating any missing parent directories first. Used by the\n * POST /api/file handler so creating e.g. `notes/foo.atelier` in a subfolder\n * doesn't ENOENT (mirrors what the /api/export handler already did).\n */\nexport function writeFileEnsuringDir(absPath: string, body: string): void {\n mkdirSync(dirname(absPath), { recursive: true });\n writeFileSync(absPath, body, \"utf-8\");\n}\n\n/**\n * Shared origin-check used by both REST middleware and WS upgrade handler.\n * ^localhost-only: WebSocket upgrade requests bypass connect middleware\n * entirely, so the bridge MUST re-run this check before accepting the\n * upgrade — otherwise an arbitrary cross-origin browser tab could connect\n * to /bridge or /mcp and drive the studio.\n */\nexport function isAllowedOrigin(origin: string | undefined, port: number): boolean {\n if (!origin) return false;\n return (\n origin === `http://localhost:${port}` ||\n origin === `http://127.0.0.1:${port}`\n );\n}\n\n/**\n * Origin check for the /mcp WS upgrade. Unlike /bridge (a real browser origin),\n * non-browser MCP clients (Claude Desktop, etc.) send NO Origin header — under\n * the strict isAllowedOrigin check they'd all 403 and the MCP-over-WS feature\n * would be unreachable. So we tolerate a MISSING Origin here but still reject a\n * PRESENT-but-foreign one (a browser tab on evil.com still can't reach /mcp).\n * The loopback bind remains the primary protection.\n */\nexport function isAllowedMcpOrigin(origin: string | undefined, port: number): boolean {\n return origin === undefined || isAllowedOrigin(origin, port);\n}\n\n/**\n * Decide whether a store change should be broadcast to the browser (as an\n * `llm:mutation` envelope) AND re-persisted to disk. Only LLM/agent edits\n * qualify: \"system\" (GET-hydration of a file the user just opened) and \"human\"\n * (the browser is already current) must stay silent — otherwise a plain\n * file-open would fire a phantom \"agent edited document\" toast + bogus undo\n * entry and needlessly rewrite the just-read bytes back to disk.\n */\nexport function shouldBroadcastMutation(source: string): boolean {\n return source === \"llm\";\n}\n\n// ─── Bridge & MCP-over-WS wiring ────────────────────────────────────────────\n//\n// The bridge connects an external MCP client (e.g. Claude Desktop running\n// `atelier-mcp` over WS) to the in-browser AtelierStudio. The full loop:\n//\n// external LLM tool ──► McpServer (per WS conn) ──► shared DocumentStore\n// │\n// onChange (source≠\"human\")\n// ▼\n// broadcast `llm:mutation` envelope\n// ▼\n// browser applies via studio.applyMutation\n//\n// browser human edit ──► fetch /api/file (POST) ──► writeFileSync ──► store.set(source:\"human\")\n// │\n// onChange (filtered: human)\n// ▼\n// NOT broadcast (skip echo)\n//\n// browser doc:patch (WS) ──► store.set(source:\"human\") + writeFileSync │\n// ▼\n// NOT broadcast (skip echo)\n//\n// Single-doc invariant for v1: the studio session tracks one currentDocId\n// (the most-recently-loaded file path). When a new bridge client connects\n// mid-session it receives `doc:loaded` for whatever's currently active.\n\n/** State held across the studio session — exported so tests can drive it. */\nexport interface BridgeSessionState {\n store: DocumentStore;\n /** Most-recently-loaded file path; null until first load. */\n currentDocId: string | null;\n}\n\n/**\n * Wrap a `ws.WebSocket` (already accepted as a /bridge connection) so it\n * receives the `hello` + initial `doc:loaded` handshake and joins the\n * broadcast set.\n *\n * Returned `dispose` removes the client from the set and unhooks listeners.\n */\nexport function attachBridgeClient(\n ws: WsWebSocket,\n state: BridgeSessionState,\n clients: Set<WsWebSocket>,\n loadDocFromDisk: (docId: string) => string | null,\n /** Persist a human-sourced inbound doc:patch envelope to disk. */\n persistHumanPatch: (docId: string, doc: import(\"@a-company/atelier-types\").AtelierDocument) => void,\n): () => void {\n clients.add(ws);\n\n const clientId = randomBytes(6).toString(\"hex\");\n const send = (env: BridgeEnvelope): void => {\n if (ws.readyState !== ws.OPEN) return;\n ws.send(JSON.stringify(env));\n };\n\n send({ type: \"hello\", clientId, protocolVersion: BRIDGE_PROTOCOL_VERSION });\n\n if (state.currentDocId) {\n const existing = state.store.get(state.currentDocId);\n if (existing) {\n send({ type: \"doc:loaded\", documentId: state.currentDocId, doc: existing });\n } else {\n // Re-hydrate from disk if the store hasn't seen it yet (e.g. bridge\n // client connected before the browser loaded any file).\n const raw = loadDocFromDisk(state.currentDocId);\n if (raw) {\n const parsed = parseAtelier(raw);\n if (parsed.success) {\n state.store.set(state.currentDocId, parsed.data, \"system\");\n send({ type: \"doc:loaded\", documentId: state.currentDocId, doc: parsed.data });\n }\n }\n }\n }\n\n const onMessage = (data: unknown): void => {\n let text: string;\n if (typeof data === \"string\") text = data;\n else if (data instanceof Buffer) text = data.toString(\"utf-8\");\n else if (Array.isArray(data)) text = Buffer.concat(data as Buffer[]).toString(\"utf-8\");\n else text = String(data);\n\n let env: unknown;\n try {\n env = JSON.parse(text);\n } catch {\n send({ type: \"error\", code: \"parse_error\", message: \"invalid JSON\" });\n return;\n }\n\n if (!isBridgeEnvelope(env)) {\n send({ type: \"error\", code: \"invalid_envelope\", message: \"unknown envelope shape\" });\n return;\n }\n\n if (env.type === \"doc:patch\") {\n // Browser-originated edit. Persist + mirror into the store with\n // source:\"human\" so the onChange filter skips re-broadcasting it\n // (which would echo back to the same browser that just emitted it).\n try {\n state.store.set(env.documentId, env.doc, \"human\");\n state.currentDocId = env.documentId;\n persistHumanPatch(env.documentId, env.doc);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n send({ type: \"error\", code: \"persist_failed\", message: msg, opId: env.opId });\n }\n return;\n }\n\n if (env.type === \"doc:load\") {\n const existing = state.store.get(env.documentId);\n if (existing) {\n send({ type: \"doc:loaded\", documentId: env.documentId, doc: existing });\n return;\n }\n const raw = loadDocFromDisk(env.documentId);\n if (raw) {\n const parsed = parseAtelier(raw);\n if (parsed.success) {\n state.store.set(env.documentId, parsed.data, \"system\");\n send({ type: \"doc:loaded\", documentId: env.documentId, doc: parsed.data });\n return;\n }\n }\n send({ type: \"error\", code: \"not_found\", message: `document ${env.documentId} not found` });\n return;\n }\n\n // hello / doc:loaded / llm:mutation / error are server-→client only.\n // Ignore silently; a future protocol revision may use them bidirectionally.\n };\n\n const onClose = (): void => {\n clients.delete(ws);\n };\n\n ws.on(\"message\", onMessage);\n ws.on(\"close\", onClose);\n ws.on(\"error\", onClose);\n\n return () => {\n clients.delete(ws);\n try {\n ws.close();\n } catch {\n // ignore\n }\n };\n}\n\n/**\n * Broadcast a single envelope to all connected bridge clients.\n * Silently skips clients that are not OPEN — the close handler removes\n * them on the next tick.\n */\nexport function broadcastToBridge(\n clients: Set<WsWebSocket>,\n envelope: BridgeEnvelope,\n): void {\n const payload = JSON.stringify(envelope);\n for (const ws of clients) {\n if (ws.readyState === ws.OPEN) {\n try {\n ws.send(payload);\n } catch {\n // Drop on send-failure; the close handler cleans up.\n }\n }\n }\n}\n\nfunction getInlineHTML(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Atelier Studio</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&display=swap\" rel=\"stylesheet\">\n </head>\n <body>\n <div id=\"studio\"></div>\n <script type=\"module\" src=\"/main.ts\"></script>\n </body>\n</html>`;\n}\n\n/**\n * Generate the tiny `main.ts` entry shim that Vite serves from the temp dir.\n *\n * The ~700-LOC studio client used to live here as a template-literal STRING\n * (no typecheck, no lint, no tests — which is exactly why the autosave\n * save-race and slider-flood bugs hid in it). It now lives as a real,\n * typechecked module at `src/web/inline-app.ts` (see #studio-inline-app),\n * exported as `bootStudioApp(config)`.\n *\n * This shim imports that module by ABSOLUTE path under the CLI package and\n * calls it with the injected `{ initialFile }`. The CLI ships `src/web/**` as\n * raw source (package `files` glob), so the path resolves identically in dev\n * (`packages/cli`) and prod (`dist/cli.js` → package root) — both via\n * `resolveCliPackageDir()`. Vite's dev server transpiles + serves the TS\n * module at request time (`server.fs.strict: false` lets it read source\n * outside the temp root).\n *\n * Resolution choice: a direct absolute-path import is the lowest-risk option —\n * no virtual-module plugin, no extra build step. Do NOT reintroduce a string.\n */\nfunction getInlineApp(initialFile: string | null, cliPackageDir: string): string {\n const initialFileStr = initialFile ? JSON.stringify(initialFile) : \"null\";\n // Absolute, POSIX-style path so the generated import specifier is valid on\n // all platforms (Vite/ESM specifiers use forward slashes even on Windows).\n const appModulePath = join(cliPackageDir, \"src\", \"web\", \"inline-app.ts\").split(sep).join(\"/\");\n return `import { bootStudioApp } from ${JSON.stringify(appModulePath)};\nbootStudioApp({ initialFile: ${initialFileStr} });\n`;\n}\n\n/**\n * Locate the CLI package directory regardless of whether this module is\n * running from `dist/cli.js` (production) or `src/commands/studio.ts` (dev).\n *\n * In production: this file is `dist/cli.js`, so `..` from its dirname\n * resolves to the package root.\n * In dev (vitest, ts-node): this file is `src/commands/studio.ts`, so\n * we need to climb two levels.\n *\n * We probe for a recognisable file (package.json) at each candidate.\n */\nfunction resolveCliPackageDir(): string {\n const here = dirname(new URL(import.meta.url).pathname);\n const candidates = [\n resolve(here, \"..\"),\n resolve(here, \"..\", \"..\"),\n ];\n for (const c of candidates) {\n if (existsSync(join(c, \"package.json\"))) {\n return c;\n }\n }\n // Fall back to first candidate; downstream callers handle missing files.\n return candidates[0];\n}\n\n/**\n * If `cwd` contains zero `.atelier` files, copy the bundled welcome template\n * (and any sibling assets) into `cwd`. Skips files that already exist so a\n * user re-running the command never overwrites their work.\n *\n * Returns the basename of the scaffolded file (or null if nothing was done).\n */\nfunction scaffoldWelcomeIfEmpty(cwd: string, cliPackageDir: string): string | null {\n const existing = findAtelierFiles(cwd);\n if (existing.length > 0) return null;\n\n const templatesDir = join(cliPackageDir, \"templates\");\n const welcomeSrc = join(templatesDir, \"welcome.atelier\");\n if (!existsSync(welcomeSrc)) return null;\n\n const welcomeDest = join(cwd, \"welcome.atelier\");\n if (existsSync(welcomeDest)) return null;\n\n try {\n copyFileSync(welcomeSrc, welcomeDest);\n } catch {\n // Non-fatal: studio still launches with empty-state UI.\n return null;\n }\n\n // Also copy welcome-bg.png if shipped alongside (currently we ship a\n // ShapeVisual placeholder, so this is a no-op; future-proofs the path).\n const bgSrc = join(templatesDir, \"welcome-bg.png\");\n if (existsSync(bgSrc)) {\n const bgDest = join(cwd, \"welcome-bg.png\");\n if (!existsSync(bgDest)) {\n try {\n copyFileSync(bgSrc, bgDest);\n } catch {\n // Non-fatal.\n }\n }\n }\n\n return \"welcome.atelier\";\n}\n\n/** Read the CLI package version for display in the splash banner. */\nfunction readCliVersion(cliPackageDir: string): string {\n try {\n const pkg = JSON.parse(readFileSync(join(cliPackageDir, \"package.json\"), \"utf-8\"));\n return typeof pkg.version === \"string\" ? pkg.version : \"unknown\";\n } catch {\n return \"unknown\";\n }\n}\n\n/** Register the `studio` subcommand on the Commander program. */\nexport function studioCommand(program: Command): void {\n program\n .command(\"studio [file]\")\n .description(\"Launch the browser-based Atelier editor\")\n .option(\"-p, --port <number>\", \"Port to serve on\", \"4321\")\n .option(\"--no-open\", \"Don't auto-open browser\")\n .action(\n async (\n file: string | undefined,\n options: { port: string; open: boolean },\n ) => {\n const port = parseInt(options.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n console.error(`Invalid port: ${options.port}`);\n process.exit(1);\n }\n\n const cwd = process.cwd();\n\n // Find the CLI package directory (where node_modules + templates live).\n const cliPackageDir = resolveCliPackageDir();\n const version = readCliVersion(cliPackageDir);\n\n // First-run scaffold: if CWD has zero .atelier files, drop in welcome.atelier\n // so the user lands on something real instead of an empty-state dead-end.\n const scaffolded = scaffoldWelcomeIfEmpty(cwd, cliPackageDir);\n\n console.log(\"\");\n console.log(` Atelier Studio · v${version}`);\n if (scaffolded) {\n console.log(` Scaffolded ${scaffolded} — opening…`);\n }\n\n // Create temp directory with inline app.\n // Use realpathSync to resolve macOS /var -> /private/var symlink,\n // which Vite normalizes internally when resolving file paths.\n const tmpId = randomBytes(4).toString(\"hex\");\n const tmpDirRaw = join(tmpdir(), `atelier-studio-${tmpId}`);\n mkdirSync(tmpDirRaw, { recursive: true });\n const tmpDir = realpathSync(tmpDirRaw);\n\n writeFileSync(join(tmpDir, \"index.html\"), getInlineHTML());\n writeFileSync(join(tmpDir, \"main.ts\"), getInlineApp(file ?? null, cliPackageDir));\n\n // Symlink node_modules into temp dir so Vite can resolve @a-company/* packages.\n // Works for both monorepo (pnpm workspace links) and npm global install.\n const cliNodeModules = join(cliPackageDir, \"node_modules\");\n if (existsSync(cliNodeModules)) {\n try {\n symlinkSync(cliNodeModules, join(tmpDir, \"node_modules\"), \"dir\");\n } catch {\n // Non-fatal: aliases will handle resolution if symlink fails\n }\n }\n\n console.log(` Working directory: ${cwd}`);\n\n // Dynamically import Vite (it's a peer/optional dep)\n let vite: typeof import(\"vite\");\n try {\n vite = await import(\"vite\");\n } catch {\n console.error(\"Vite is required for `atelier studio`.\");\n console.error(\"Install it: pnpm add -D vite\");\n process.exit(1);\n return;\n }\n\n // ^localhost-only: bind explicitly to the loopback interface so the\n // dev server cannot be reached from other machines on the network.\n // Vite's default is \"localhost\" which already resolves to loopback,\n // but we pin 127.0.0.1 to make the invariant intentional + auditable\n // and to defeat any future change in Vite defaults.\n const HOSTNAME = \"127.0.0.1\";\n\n // Shared session state for the bridge + MCP-over-WS endpoints.\n // The same DocumentStore is fed by:\n // - File reads via /api/file (source:\"system\" — hydrates the cache)\n // - File writes via /api/file POST (source:\"human\" — no broadcast)\n // - Bridge doc:patch (source:\"human\" — no broadcast; also persists)\n // - Per-connection MCP servers over /mcp (source:\"llm\" by default\n // for tools that don't tag — broadcasts to the bridge)\n const bridgeState: BridgeSessionState = {\n store: new DocumentStore(),\n currentDocId: null,\n };\n const bridgeClients = new Set<WsWebSocket>();\n\n const loadDocFromDisk = (docId: string): string | null => {\n if (!isSafePath(docId)) return null;\n try {\n return readFileSync(resolve(cwd, docId), \"utf-8\");\n } catch {\n return null;\n }\n };\n\n const persistHumanPatch = (\n docId: string,\n doc: import(\"@a-company/atelier-types\").AtelierDocument,\n ): void => {\n if (!isSafePath(docId)) return;\n // Create parent dirs first so a doc:patch over the WS bridge for a\n // subfolder doc (e.g. `notes/x.atelier`) doesn't ENOENT and lose the\n // edit — mirrors what the POST /api/file handler already does.\n writeFileEnsuringDir(resolve(cwd, docId), serializeAtelier(doc));\n };\n\n // Persist LLM/system mutations to disk so the on-disk .atelier file\n // stays in lock-step with what the browser shows. Without this, a\n // refresh would lose the LLM's edits.\n bridgeState.store.onChange((id, doc, source) => {\n // Only LLM/agent edits get persisted + broadcast. \"human\" is already\n // persisted by /api/file POST and the browser is current; \"system\" is\n // GET-hydration of a file the user just opened (the bytes are already\n // on disk and in the browser) — broadcasting it would fire a phantom\n // \"agent edited document\" toast on a plain file-open.\n if (!shouldBroadcastMutation(source)) return;\n if (doc === null) return; // deletions don't touch disk in v1\n try {\n persistHumanPatch(id, doc);\n } catch {\n // Non-fatal: in-memory state is authoritative for the browser session.\n }\n broadcastToBridge(bridgeClients, {\n type: \"llm:mutation\",\n documentId: id,\n doc,\n source,\n });\n });\n\n const server = await vite.createServer({\n root: tmpDir,\n server: {\n host: HOSTNAME,\n port,\n strictPort: false,\n fs: {\n strict: false,\n },\n },\n plugins: [\n {\n name: \"atelier-api\",\n configureServer(server) {\n // ^localhost-only: Origin check on mutating endpoints.\n // Without this, any browser tab on any site can fire\n // fetch('http://localhost:4321/api/file', { method: 'POST', ... })\n // and write .atelier files into the user's CWD.\n // Only allow Origins that match this server's own loopback host.\n const allowedOrigins = new Set([\n `http://localhost:${port}`,\n `http://127.0.0.1:${port}`,\n ]);\n const MUTATING = new Set([\"POST\", \"PUT\", \"DELETE\", \"PATCH\"]);\n\n server.middlewares.use((req, res, next) => {\n const url = new URL(req.url ?? \"/\", `http://${HOSTNAME}:${port}`);\n\n if (req.method && MUTATING.has(req.method) && url.pathname.startsWith(\"/api/\")) {\n const origin = req.headers.origin;\n if (!origin || !allowedOrigins.has(origin)) {\n res.statusCode = 403;\n res.end(\"Forbidden: cross-origin mutating request rejected\");\n return;\n }\n }\n\n if (url.pathname === \"/api/files\") {\n const atelierFiles = findAtelierFiles(cwd);\n const entries = atelierFiles.map((p) => {\n const parts = p.split(\"/\");\n return {\n path: p,\n name: parts[parts.length - 1].replace(\".atelier\", \"\"),\n folder: parts.length > 1 ? parts.slice(0, -1).join(\"/\") : \"\",\n };\n });\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify(entries));\n return;\n }\n\n if (url.pathname === \"/api/file\") {\n const filePath = url.searchParams.get(\"path\");\n if (!filePath || !isSafePath(filePath)) {\n res.statusCode = 400;\n res.end(\"Invalid path\");\n return;\n }\n\n const absPath = resolve(cwd, filePath);\n\n if (req.method === \"GET\") {\n try {\n const content = readFileSync(absPath, \"utf-8\");\n // Mirror into the shared store so MCP clients connecting\n // over /mcp see the same active document and the bridge\n // can broadcast it to late-joining browser clients.\n const parsed = parseAtelier(content);\n if (parsed.success) {\n bridgeState.store.set(filePath, parsed.data, \"system\");\n bridgeState.currentDocId = filePath;\n }\n res.setHeader(\"Content-Type\", \"text/plain\");\n res.end(content);\n } catch {\n res.statusCode = 404;\n res.end(\"File not found\");\n }\n return;\n }\n\n if (req.method === \"POST\") {\n let body = \"\";\n req.on(\"data\", (chunk: Buffer) => { body += chunk.toString(); });\n req.on(\"end\", () => {\n try {\n // Creates parent dirs first so a new file in a\n // subfolder (e.g. `notes/foo.atelier`) doesn't ENOENT.\n writeFileEnsuringDir(absPath, body);\n // Mirror human writes into the store with source:\"human\"\n // so onChange skips re-broadcasting (the browser already\n // has the latest — no echo needed).\n const parsed = parseAtelier(body);\n if (parsed.success) {\n bridgeState.store.set(filePath, parsed.data, \"human\");\n bridgeState.currentDocId = filePath;\n }\n res.end(\"OK\");\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n res.statusCode = 500;\n res.end(msg);\n }\n });\n return;\n }\n }\n\n if (url.pathname === \"/api/export\" && req.method === \"POST\") {\n const filePath = url.searchParams.get(\"path\");\n if (!filePath || !isSafePath(filePath)) {\n res.statusCode = 400;\n res.end(\"Invalid path\");\n return;\n }\n\n const absPath = resolve(cwd, filePath);\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => { chunks.push(chunk); });\n req.on(\"end\", () => {\n try {\n mkdirSync(dirname(absPath), { recursive: true });\n writeFileSync(absPath, Buffer.concat(chunks));\n res.end(\"OK\");\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n res.statusCode = 500;\n res.end(msg);\n }\n });\n return;\n }\n\n if (url.pathname === \"/api/cwd\") {\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify({ cwd }));\n return;\n }\n\n next();\n });\n },\n },\n ],\n logLevel: \"warn\",\n });\n\n await server.listen();\n\n // Mount WebSocket bridge + MCP transport on Vite's HTTP server.\n // ^localhost-only: the connect middleware does NOT run on WS upgrades\n // (Node fires 'upgrade' before connect), so we re-run the Origin\n // check here. Without this the bridge would be cross-origin-reachable\n // from any browser tab.\n const httpServer = server.httpServer;\n if (httpServer) {\n const wssBridge = new WebSocketServer({ noServer: true });\n const wssMcp = new WebSocketServer({ noServer: true });\n\n httpServer.on(\"upgrade\", (req, socket, head) => {\n const url = new URL(req.url ?? \"/\", `http://${HOSTNAME}:${port}`);\n if (url.pathname !== \"/bridge\" && url.pathname !== \"/mcp\") return;\n\n // ^localhost-only Origin check for WS upgrades. /bridge is a real\n // browser origin (strict same-origin), but /mcp serves non-browser\n // MCP clients that send NO Origin header — so /mcp tolerates a\n // missing Origin while still rejecting a present-but-foreign one.\n const origin = req.headers.origin;\n const originOk =\n url.pathname === \"/mcp\"\n ? isAllowedMcpOrigin(origin, port)\n : isAllowedOrigin(origin, port);\n if (!originOk) {\n socket.write(\"HTTP/1.1 403 Forbidden\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n if (url.pathname === \"/bridge\") {\n wssBridge.handleUpgrade(req, socket, head, (ws) => {\n wssBridge.emit(\"connection\", ws, req);\n });\n return;\n }\n\n // url.pathname === \"/mcp\"\n wssMcp.handleUpgrade(req, socket, head, (ws) => {\n wssMcp.emit(\"connection\", ws, req);\n });\n });\n\n wssBridge.on(\"connection\", (ws) => {\n attachBridgeClient(\n ws,\n bridgeState,\n bridgeClients,\n loadDocFromDisk,\n persistHumanPatch,\n );\n });\n\n wssMcp.on(\"connection\", (ws) => {\n // Per-connection MCP server, shared store. Each external client\n // gets its own handler context but writes flow through the same\n // emitter the bridge subscribes to.\n const { server: mcpServer } = createMcpServer(bridgeState.store);\n const transport = new WebSocketServerTransport(ws);\n mcpServer.connect(transport).catch((err) => {\n // Connection-time failures: log and close. Per-call failures\n // surface as JSON-RPC errors via the SDK.\n console.error(\"MCP-over-WS connect failed:\", err);\n try { ws.close(); } catch { /* ignore */ }\n });\n });\n }\n\n const resolvedUrl = server.resolvedUrls?.local[0] ?? `http://localhost:${port}`;\n const url = resolvedUrl;\n\n console.log(` Server running at: ${url}`);\n\n const atelierFiles = findAtelierFiles(cwd);\n console.log(` Found ${atelierFiles.length} .atelier file(s)`);\n\n if (file) {\n console.log(` Opening: ${file}`);\n }\n\n console.log(` Press Ctrl+C to stop\\n`);\n\n if (options.open) {\n exec(`open \"${url}\"`);\n }\n\n // Keep alive and handle cleanup\n const cleanup = () => {\n console.log(\"\\nShutting down...\");\n server.close();\n try {\n rmSync(tmpDir, { recursive: true, force: true });\n } catch {\n // ignore cleanup errors\n }\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n },\n );\n}\n"],"mappings":"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","names":["init_dist","import_zod","z","yamlParse","yamlStringify","init_dist","program","import_node_fs","import_node_path","init_dist","program","import_node_fs","import_node_path","resolve","import_node_fs","import_node_path","import_yaml","parseYaml","stringifyYaml","formatResult","program","import_node_child_process","import_node_fs","resolve","formatResult","program","program","transcript","program","import_node_fs","import_node_path","program","program","import_node_fs","import_node_path","init_dist","loadImage","ImageCache","resolve","createCanvas","renderFrame","program","import_node_fs","import_node_path","program","import_node_fs","import_node_path","init_dist","readAndParse","program","createCanvas","renderFrame","import_node_fs","import_node_path","import_node_child_process","init_dist","resolve","preloadImages","loadImage","createCanvas","readAndParse","program","import_node_fs","import_node_path","init_dist","colorToCSS","readAndParse","program","import_node_fs","import_node_path","r","g","b","a","isExpression","kfs","buildTransform","readAndParse","program","import_node_fs","import_node_path","readAndParse","parseDim","program","import_node_fs","import_node_path","readAndParse","program","import_node_fs","import_node_path","init_dist","readAndParse","program","import_node_path","import_node_fs","import_node_os","import_node_child_process","program","server","url","atelierFiles","createMcpServer","import_meta"]}