@pixerate/flair 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +254 -2
  4. package/dist/catalog/index.d.ts +74 -0
  5. package/dist/catalog/index.js +47 -0
  6. package/dist/catalog/index.js.map +1 -0
  7. package/dist/chunk-36DTNSHU.js +160 -0
  8. package/dist/chunk-36DTNSHU.js.map +1 -0
  9. package/dist/chunk-3FAUZOGL.js +331 -0
  10. package/dist/chunk-3FAUZOGL.js.map +1 -0
  11. package/dist/chunk-CFCLT2XL.js +1 -0
  12. package/dist/chunk-CFCLT2XL.js.map +1 -0
  13. package/dist/chunk-EHDJ3CPJ.js +327 -0
  14. package/dist/chunk-EHDJ3CPJ.js.map +1 -0
  15. package/dist/chunk-G5FNZDTA.js +536 -0
  16. package/dist/chunk-G5FNZDTA.js.map +1 -0
  17. package/dist/chunk-HKXOHRCD.js +763 -0
  18. package/dist/chunk-HKXOHRCD.js.map +1 -0
  19. package/dist/chunk-J55UBNAT.js +164 -0
  20. package/dist/chunk-J55UBNAT.js.map +1 -0
  21. package/dist/chunk-JWZCPMFG.js +2074 -0
  22. package/dist/chunk-JWZCPMFG.js.map +1 -0
  23. package/dist/chunk-MWVTQFV5.js +1894 -0
  24. package/dist/chunk-MWVTQFV5.js.map +1 -0
  25. package/dist/chunk-UQQNZSYL.js +594 -0
  26. package/dist/chunk-UQQNZSYL.js.map +1 -0
  27. package/dist/chunk-WMZQCUFJ.js +73 -0
  28. package/dist/chunk-WMZQCUFJ.js.map +1 -0
  29. package/dist/cli.d.ts +1 -0
  30. package/dist/cli.js +331 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/clock-BhdXWH-n.d.ts +47 -0
  33. package/dist/controls-DdXMbovi.d.ts +97 -0
  34. package/dist/editor/index.d.ts +413 -0
  35. package/dist/editor/index.js +1009 -0
  36. package/dist/editor/index.js.map +1 -0
  37. package/dist/export-FEBPEEO7.js +22 -0
  38. package/dist/export-FEBPEEO7.js.map +1 -0
  39. package/dist/index.d.ts +1431 -0
  40. package/dist/index.js +1263 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/motion-D0TVv2CF.d.ts +148 -0
  43. package/dist/node.d.ts +24 -0
  44. package/dist/node.js +10 -0
  45. package/dist/node.js.map +1 -0
  46. package/dist/recorder-WJTWMEQN.js +10 -0
  47. package/dist/recorder-WJTWMEQN.js.map +1 -0
  48. package/dist/renderer-Oyynz-fs.d.ts +293 -0
  49. package/dist/types-CkKkavvB.d.ts +71 -0
  50. package/dist/vector/index.d.ts +83 -0
  51. package/dist/vector/index.js +39 -0
  52. package/dist/vector/index.js.map +1 -0
  53. package/package.json +96 -4
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/export/motn.ts","../src/export/lottie.ts","../src/export/interchange.ts"],"sourcesContent":["import type { Scene, Shot } from '../scene/types.js';\nimport { DEFAULT_STAGE, CAMERA_MS } from '../scene/camera.js';\nimport { isElementCommand } from '../scene/types.js';\n\nexport interface MotnExportOptions {\n frameRate?: number;\n}\n\nfunction escapeXml(unsafe: string): string {\n return unsafe\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Serializes a Flair Scene into Apple Motion ozml 4.0 XML document format (.motn).\n */\nexport function exportMotn(scene: Scene, options: MotnExportOptions = {}): string {\n const frameRate = options.frameRate ?? 30;\n const width = scene.stage?.width ?? DEFAULT_STAGE.width;\n const height = scene.stage?.height ?? DEFAULT_STAGE.height;\n\n // Calculate shot frame ranges\n let currentMs = 0;\n const shotTimings = scene.shots.map((shot, idx) => {\n const camMs = idx > 0 && shot.camera ? CAMERA_MS : 0;\n const holdMs = shot.hold ?? 800;\n const durationMs = camMs + holdMs;\n const startMs = currentMs;\n currentMs += durationMs;\n\n const startFrame = Math.round((startMs / 1000) * frameRate);\n const durationFrames = Math.max(1, Math.round((durationMs / 1000) * frameRate));\n const endFrame = startFrame + durationFrames - 1;\n\n return {\n shot,\n startFrame,\n durationFrames,\n endFrame,\n };\n });\n\n const totalFrames = Math.max(1, Math.round((currentMs / 1000) * frameRate));\n\n let nodeId = 10000;\n const lines: string[] = [];\n\n lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n lines.push('<!DOCTYPE ozxmlscene>');\n lines.push('<ozml version=\"4.0\">');\n if (scene.name) {\n lines.push(` <!-- Scene: ${escapeXml(scene.name)} -->`);\n }\n lines.push('');\n lines.push(' <displayversion>5.0</displayversion>');\n lines.push('');\n lines.push(' <factory id=\"1\" uuid=\"044beba5ad3211d7ac9b000393833f6a\">');\n lines.push(' <description>Style</description>');\n lines.push(' <manufacturer>Apple</manufacturer>');\n lines.push(' <version>1</version>');\n lines.push(' </factory>');\n lines.push(' <factory id=\"2\" uuid=\"babfc7777f4711d7aaa7000393833f6a\">');\n lines.push(' <description>Text</description>');\n lines.push(' <manufacturer>Apple</manufacturer>');\n lines.push(' <version>1</version>');\n lines.push(' </factory>');\n lines.push(' <factory id=\"3\" uuid=\"712462a4323911d78f8400039389b702\">');\n lines.push(' <description>Shape</description>');\n lines.push(' <manufacturer>Apple</manufacturer>');\n lines.push(' <version>1</version>');\n lines.push(' </factory>');\n lines.push(' <factory id=\"4\" uuid=\"65cb4dc9d4504fa281921f5f751fba06\">');\n lines.push(' <description>Widget</description>');\n lines.push(' <manufacturer>Apple</manufacturer>');\n lines.push(' <version>1</version>');\n lines.push(' </factory>');\n lines.push('');\n lines.push(' <scene>');\n lines.push(' <sceneSettings>');\n lines.push(` <width>${width}</width>`);\n lines.push(` <height>${height}</height>`);\n lines.push(` <duration>${totalFrames}</duration>`);\n lines.push(` <frameRate>${frameRate}</frameRate>`);\n lines.push(' <NTSC>0</NTSC>');\n lines.push(' <channels>4</channels>');\n lines.push(' <channelDepth>8</channelDepth>');\n lines.push(' <pixelAspectRatio>1</pixelAspectRatio>');\n lines.push(' <backgroundColor red=\"0\" green=\"0\" blue=\"0\" alpha=\"1\"/>');\n lines.push(' </sceneSettings>');\n lines.push(' <currentFrame>0</currentFrame>');\n lines.push(` <timeRange offset=\"0\" duration=\"${totalFrames}\"/>`);\n lines.push(` <playRange offset=\"0\" duration=\"${totalFrames}\"/>`);\n lines.push(' <flags>1</flags>');\n\n // Rig widget export if defined\n if (scene.rig && Object.keys(scene.rig.widgets).length > 0) {\n lines.push(` <scenenode name=\"Rigs\" id=\"${nodeId++}\" factoryID=\"4\" version=\"1\">`);\n for (const [widgetName, widget] of Object.entries(scene.rig.widgets)) {\n lines.push(` <scenenode name=\"${escapeXml(widgetName)}\" id=\"${nodeId++}\" factoryID=\"4\" version=\"1\">`);\n lines.push(' <parameter name=\"Object\" id=\"2\">');\n if (widget.type === 'slider') {\n lines.push(` <parameter name=\"Widget\" id=\"100\" default=\"0\" value=\"${widget.value}\"/>`);\n } else if (widget.type === 'toggle') {\n lines.push(` <parameter name=\"Widget\" id=\"100\" default=\"0\" value=\"${widget.enabled ? 1 : 0}\"/>`);\n } else if (widget.type === 'popup') {\n lines.push(` <parameter name=\"Widget\" id=\"100\" default=\"0\" value=\"${escapeXml(widget.selected)}\"/>`);\n }\n lines.push(' </parameter>');\n lines.push(' </scenenode>');\n }\n lines.push(' </scenenode>');\n }\n\n // Groups and element nodes per shot\n for (const [idx, item] of shotTimings.entries()) {\n const shotLabel = item.shot.title\n ? `Shot ${idx + 1}: ${escapeXml(item.shot.title)}`\n : `Shot ${idx + 1}`;\n lines.push(` <group name=\"${shotLabel}\" id=\"${nodeId++}\">`);\n lines.push(` <timing in=\"${item.startFrame}\" out=\"${item.endFrame}\" offset=\"${item.startFrame}\"/>`);\n\n if (item.shot.run) {\n for (const cmd of item.shot.run) {\n if (isElementCommand(cmd) && cmd.element) {\n const el = cmd.element;\n const isText = el.type === 'text';\n const factoryId = isText ? 2 : 3;\n lines.push(` <scenenode name=\"${escapeXml(el.id)}\" id=\"${nodeId++}\" factoryID=\"${factoryId}\" version=\"1\">`);\n lines.push(` <timing in=\"${item.startFrame}\" out=\"${item.endFrame}\" offset=\"${item.startFrame}\"/>`);\n lines.push(' <parameter name=\"Properties\" id=\"1\">');\n lines.push(' <parameter name=\"Transform\" id=\"100\">');\n lines.push(' <parameter name=\"Position\" id=\"101\">');\n lines.push(` <parameter name=\"X\" id=\"1\" value=\"${el.x}\"/>`);\n lines.push(` <parameter name=\"Y\" id=\"2\" value=\"${-el.y}\"/>`);\n lines.push(' </parameter>');\n if (!isText) {\n lines.push(' <parameter name=\"Scale\" id=\"102\">');\n lines.push(` <parameter name=\"X\" id=\"1\" value=\"${el.width}\"/>`);\n lines.push(` <parameter name=\"Y\" id=\"2\" value=\"${el.height}\"/>`);\n lines.push(' </parameter>');\n }\n lines.push(' </parameter>');\n lines.push(' </parameter>');\n\n if (isText && el.text) {\n lines.push(` <text>${escapeXml(el.text)}</text>`);\n }\n lines.push(' </scenenode>');\n }\n }\n }\n\n lines.push(' </group>');\n }\n\n lines.push(' </scene>');\n lines.push('</ozml>');\n lines.push('');\n\n return lines.join('\\n');\n}\n","/**\n * Lottie JSON Vector Animation Exporter.\n *\n * Converts Flair scenes, elements, shapes, transforms, and keyframes into\n * official Lottie JSON format (v5.5.2) compatible with Airbnb Lottie-Web,\n * iOS/Android Lottie, Figma, and Telegram.\n */\n\nimport type { Scene } from '../scene/types.js';\nimport { DEFAULT_STAGE, CAMERA_MS } from '../scene/camera.js';\nimport { isElementCommand, isUpdateCommand } from '../scene/types.js';\nimport type { KeyframeEase } from '../time/keyframe.js';\n\nexport interface LottieExportOptions {\n /** Target framerate in fps. Default: 30 */\n frameRate?: number;\n}\n\nexport interface LottieKeyframe<T> {\n t: number; // frame number\n s: T; // start value\n e?: T; // end value\n o?: { x: number | number[]; y: number | number[] }; // out tangent ease\n i?: { x: number | number[]; y: number | number[] }; // in tangent ease\n h?: number; // hold keyframe flag\n}\n\nexport interface LottieAnimatable<T, K = T> {\n a: 0 | 1; // 0 = static, 1 = animated\n k: T | LottieKeyframe<K>[];\n}\n\nexport interface LottieTransform {\n p: LottieAnimatable<[number, number, number], [number, number, number]>; // position\n a: LottieAnimatable<[number, number, number], [number, number, number]>; // anchor\n s: LottieAnimatable<[number, number, number], [number, number, number]>; // scale\n r: LottieAnimatable<number, [number]>; // rotation\n o: LottieAnimatable<number, [number]>; // opacity\n}\n\n\nexport interface LottieShapeItem {\n ty: string;\n nm?: string;\n [key: string]: unknown;\n}\n\nexport interface LottieLayer {\n ddd: 0 | 1;\n ind: number;\n ty: number; // 0 = precomp, 1 = solid, 2 = image, 3 = null, 4 = shape, 5 = text\n nm: string;\n sr: number;\n ks: LottieTransform;\n ao: 0 | 1;\n ip: number;\n op: number;\n st: number;\n bm: number;\n shapes?: LottieShapeItem[];\n sw?: number;\n sh?: number;\n sc?: string;\n}\n\nexport interface LottieAnimation {\n v: string;\n fr: number;\n ip: number;\n op: number;\n w: number;\n h: number;\n nm: string;\n ddd: 0;\n assets: unknown[];\n layers: LottieLayer[];\n}\n\n/**\n * Maps AE speed and influence into normalized Lottie Bezier ease control points (o.x, o.y, i.x, i.y).\n */\nexport function createLottieEase(\n durationFrames: number,\n deltaVal: number,\n outEase?: KeyframeEase,\n inEase?: KeyframeEase\n): { o: { x: number; y: number }; i: { x: number; y: number } } {\n const infOut = Math.max(0.001, Math.min(1.0, (outEase?.influence ?? 33.333) / 100));\n const infIn = Math.max(0.001, Math.min(1.0, (inEase?.influence ?? 33.333) / 100));\n\n const safeDelta = Math.abs(deltaVal) > 1e-6 ? deltaVal : 1;\n const speedOut = outEase?.speed ?? 0;\n const speedIn = inEase?.speed ?? 0;\n\n // Lottie normalized control points\n const ox = infOut;\n const oy = Math.max(0, Math.min(1, (speedOut * infOut * durationFrames) / safeDelta));\n\n const ix = 1.0 - infIn;\n const iy = Math.max(0, Math.min(1, 1.0 - (speedIn * infIn * durationFrames) / safeDelta));\n\n return {\n o: { x: Number(ox.toFixed(4)), y: Number(oy.toFixed(4)) },\n i: { x: Number(ix.toFixed(4)), y: Number(iy.toFixed(4)) },\n };\n}\n\n/**\n * Serializes a Flair Scene into standard Lottie JSON animation.\n */\nexport function exportLottie(scene: Scene, options: LottieExportOptions = {}): LottieAnimation {\n const fr = options.frameRate ?? 30;\n const width = scene.stage?.width ?? DEFAULT_STAGE.width;\n const height = scene.stage?.height ?? DEFAULT_STAGE.height;\n\n // Compute shot timeline frames\n let currentMs = 0;\n const shotTimings = scene.shots.map((shot, idx) => {\n const camMs = idx > 0 && shot.camera ? CAMERA_MS : 0;\n const holdMs = shot.hold ?? 800;\n const durationMs = camMs + holdMs;\n const startMs = currentMs;\n currentMs += durationMs;\n\n const startFrame = Math.round((startMs / 1000) * fr);\n const durationFrames = Math.max(1, Math.round((durationMs / 1000) * fr));\n const endFrame = startFrame + durationFrames;\n\n return {\n shot,\n startFrame,\n durationFrames,\n endFrame,\n };\n });\n\n const totalFrames = Math.max(1, Math.round((currentMs / 1000) * fr));\n\n // Collect elements and track property updates across shots\n interface ElementTrack {\n id: string;\n type: string;\n initialX: number;\n initialY: number;\n width: number;\n height: number;\n text?: string;\n opacity: number;\n inFrame: number;\n outFrame: number;\n posKeyframes: LottieKeyframe<[number, number, number]>[];\n opacityKeyframes: LottieKeyframe<[number]>[];\n }\n\n const tracks = new Map<string, ElementTrack>();\n\n for (const timing of shotTimings) {\n const shot = timing.shot;\n if (!shot.run) continue;\n\n for (const cmd of shot.run) {\n if (isElementCommand(cmd)) {\n const el = cmd.element;\n if (!tracks.has(el.id)) {\n tracks.set(el.id, {\n id: el.id,\n type: el.type,\n initialX: el.x,\n initialY: el.y,\n width: el.width,\n height: el.height,\n text: el.text,\n opacity: el.opacity ?? 1,\n inFrame: timing.startFrame,\n outFrame: totalFrames,\n posKeyframes: [\n {\n t: timing.startFrame,\n s: [el.x + el.width * 0.5, el.y + el.height * 0.5, 0],\n },\n ],\n opacityKeyframes: [\n {\n t: timing.startFrame,\n s: [(el.opacity ?? 1) * 100],\n },\n ],\n });\n }\n } else if (isUpdateCommand(cmd)) {\n const track = tracks.get(cmd.id);\n if (track) {\n const props = cmd.props;\n const prevPos = track.posKeyframes[track.posKeyframes.length - 1];\n const newX = props.x !== undefined ? props.x : prevPos.s[0] - track.width * 0.5;\n const newY = props.y !== undefined ? props.y : prevPos.s[1] - track.height * 0.5;\n\n const ease = createLottieEase(timing.durationFrames, 1);\n prevPos.o = ease.o;\n prevPos.i = ease.i;\n\n track.posKeyframes.push({\n t: timing.endFrame,\n s: [newX + track.width * 0.5, newY + track.height * 0.5, 0],\n });\n\n if (props.opacity !== undefined) {\n const prevOp = track.opacityKeyframes[track.opacityKeyframes.length - 1];\n prevOp.o = ease.o;\n prevOp.i = ease.i;\n track.opacityKeyframes.push({\n t: timing.endFrame,\n s: [props.opacity * 100],\n });\n }\n }\n }\n }\n }\n\n // Build Lottie layers\n const layers: LottieLayer[] = [];\n let layerIndex = 1;\n\n for (const track of tracks.values()) {\n const isPosAnimated = track.posKeyframes.length > 1;\n const isOpAnimated = track.opacityKeyframes.length > 1;\n\n const p: LottieAnimatable<[number, number, number], [number, number, number]> = isPosAnimated\n ? { a: 1, k: track.posKeyframes }\n : { a: 0, k: [track.initialX + track.width * 0.5, track.initialY + track.height * 0.5, 0] };\n\n const o: LottieAnimatable<number, [number]> = isOpAnimated\n ? { a: 1, k: track.opacityKeyframes }\n : { a: 0, k: track.opacity * 100 };\n\n const ks: LottieTransform = {\n p,\n a: { a: 0, k: [0, 0, 0] },\n s: { a: 0, k: [100, 100, 100] },\n r: { a: 0, k: 0 },\n o,\n };\n\n // Shape items for rectangle / visual element\n const shapes: LottieShapeItem[] = [\n {\n ty: 'gr',\n nm: track.id,\n it: [\n {\n ty: 'rc',\n nm: 'Rectangle Path',\n d: 1,\n s: { a: 0, k: [track.width, track.height] },\n p: { a: 0, k: [0, 0] },\n r: { a: 0, k: 8 },\n },\n {\n ty: 'fl',\n nm: 'Fill',\n c: { a: 0, k: [0.2, 0.4, 0.9, 1] },\n o: { a: 0, k: 100 },\n r: 1,\n },\n {\n ty: 'tr',\n nm: 'Transform',\n p: { a: 0, k: [0, 0] },\n a: { a: 0, k: [0, 0] },\n s: { a: 0, k: [100, 100] },\n r: { a: 0, k: 0 },\n o: { a: 0, k: 100 },\n },\n ],\n },\n ];\n\n layers.push({\n ddd: 0,\n ind: layerIndex++,\n ty: 4, // Shape layer\n nm: track.id,\n sr: 1,\n ks,\n ao: 0,\n ip: track.inFrame,\n op: track.outFrame,\n st: track.inFrame,\n bm: 0, // Normal blend mode\n shapes,\n });\n }\n\n return {\n v: '5.5.2',\n fr,\n ip: 0,\n op: totalFrames,\n w: width,\n h: height,\n nm: scene.name || 'Flair Animation',\n ddd: 0,\n assets: [],\n layers,\n };\n}\n","import type { Scene, Shot } from '../scene/types.js';\nimport { DEFAULT_STAGE, CAMERA_MS } from '../scene/camera.js';\n\nexport interface Fcp7ExportOptions {\n /** Timeline timebase / frame rate (default 30). */\n frameRate?: number;\n /** NTSC flag (default false, or true if 29.97 / 59.94). */\n ntsc?: boolean;\n /** Starting timecode (default \"00:00:00:00\"). */\n timecodeStart?: string;\n /** Sequence name override. */\n sequenceName?: string;\n /** Media path prefix or file base URL (default \"file://localhost/media/\"). */\n mediaPathPrefix?: string;\n /** Include text generator overlay track for titles/captions (default true). */\n includeTextTrack?: boolean;\n /** Include timeline sequence markers (default true). */\n includeMarkers?: boolean;\n}\n\nexport interface EdlExportOptions {\n /** Timeline timebase / frame rate (default 30). */\n frameRate?: number;\n /** Drop frame flag (default false). */\n dropFrame?: boolean;\n /** Starting timecode (default \"01:00:00:00\" as per standard broadcast EDL practice). */\n timecodeStart?: string;\n /** Reel name identifier (default \"AX\", max 8 chars). */\n reel?: string;\n}\n\nexport interface ShotTiming {\n shot: Shot;\n index: number;\n startFrame: number;\n endFrame: number;\n durationFrames: number;\n startMs: number;\n durationMs: number;\n}\n\nfunction escapeXml(unsafe: string): string {\n return unsafe\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Calculates start and duration frame boundaries for each shot in a scene.\n */\nexport function calculateShotTimings(scene: Scene, frameRate: number = 30): ShotTiming[] {\n let currentMs = 0;\n return scene.shots.map((shot, index) => {\n const camMs = index > 0 && shot.camera ? CAMERA_MS : 0;\n const holdMs = shot.hold ?? 800;\n const durationMs = camMs + holdMs;\n const startMs = currentMs;\n currentMs += durationMs;\n\n const startFrame = Math.round((startMs / 1000) * frameRate);\n const durationFrames = Math.max(1, Math.round((durationMs / 1000) * frameRate));\n const endFrame = startFrame + durationFrames;\n\n return {\n shot,\n index,\n startFrame,\n endFrame,\n durationFrames,\n startMs,\n durationMs,\n };\n });\n}\n\n/**\n * Converts frame count to standard SMPTE timecode HH:MM:SS:FF.\n */\nexport function framesToTimecode(\n frame: number,\n timebase: number = 30,\n dropFrame: boolean = false\n): string {\n const roundedFps = Math.round(timebase);\n let totalFrames = Math.max(0, Math.floor(frame));\n\n if (dropFrame && (roundedFps === 30 || roundedFps === 29)) {\n // 29.97 DF: drop frames 0 and 1 at the start of every minute except minutes 0, 10, 20, 30, 40, 50\n const dropFramesPer10Mins = 18;\n const framesPer10Mins = 17982; // 10 * 60 * 30 - 18\n const framesPerMinute = 1798; // 60 * 30 - 2\n\n const d = Math.floor(totalFrames / framesPer10Mins);\n const m = totalFrames % framesPer10Mins;\n\n if (m >= 2) {\n totalFrames += dropFramesPer10Mins * d + 2 * Math.floor((m - 2) / framesPerMinute);\n } else {\n totalFrames += dropFramesPer10Mins * d;\n }\n }\n\n const ff = totalFrames % roundedFps;\n const totalSeconds = Math.floor(totalFrames / roundedFps);\n const ss = totalSeconds % 60;\n const totalMinutes = Math.floor(totalSeconds / 60);\n const mm = totalMinutes % 60;\n const hh = Math.floor(totalMinutes / 60);\n\n const pad = (n: number) => n.toString().padStart(2, '0');\n const separator = dropFrame ? ';' : ':';\n return `${pad(hh)}:${pad(mm)}:${pad(ss)}${separator}${pad(ff)}`;\n}\n\n/**\n * Converts standard SMPTE timecode HH:MM:SS:FF to frame count.\n */\nexport function timecodeToFrames(\n timecode: string,\n timebase: number = 30,\n dropFrame: boolean = false\n): number {\n const parts = timecode.split(/[:;]/).map(Number);\n if (parts.length !== 4 || parts.some(isNaN)) {\n return 0;\n }\n const [hh, mm, ss, ff] = parts;\n const roundedFps = Math.round(timebase);\n\n if (dropFrame && (roundedFps === 30 || roundedFps === 29)) {\n const totalMinutes = hh * 60 + mm;\n const dropCount = (totalMinutes - Math.floor(totalMinutes / 10)) * 2;\n return ((hh * 3600 + mm * 60 + ss) * roundedFps + ff) - dropCount;\n }\n\n return (hh * 3600 + mm * 60 + ss) * roundedFps + ff;\n}\n\n/**\n * Serializes a Flair Scene into Apple Final Cut Pro 7 XML Interchange Format (xmeml v4).\n * Compatible with Premiere Pro, DaVinci Resolve, and Final Cut Pro.\n */\nexport function exportFcp7Xml(scene: Scene, options: Fcp7ExportOptions = {}): string {\n const frameRate = options.frameRate ?? 30;\n const timebase = Math.round(frameRate);\n const ntsc = options.ntsc ?? (Math.abs(frameRate - 29.97) < 0.05 || Math.abs(frameRate - 59.94) < 0.05);\n const ntscStr = ntsc ? 'TRUE' : 'FALSE';\n const width = scene.stage?.width ?? DEFAULT_STAGE.width;\n const height = scene.stage?.height ?? DEFAULT_STAGE.height;\n const sequenceName = options.sequenceName ?? scene.name ?? 'Flair Sequence';\n const timecodeStart = options.timecodeStart ?? '00:00:00:00';\n const mediaPrefix = options.mediaPathPrefix ?? 'file://localhost/media/';\n const includeTextTrack = options.includeTextTrack ?? true;\n const includeMarkers = options.includeMarkers ?? true;\n\n const timings = calculateShotTimings(scene, frameRate);\n const totalFrames = timings.length > 0 ? timings[timings.length - 1].endFrame : 0;\n const startFrameOffset = timecodeToFrames(timecodeStart, frameRate);\n\n const lines: string[] = [];\n\n lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n lines.push('<!DOCTYPE xmeml>');\n lines.push('<xmeml version=\"4\">');\n lines.push(` <sequence id=\"sequence-1\">`);\n lines.push(` <name>${escapeXml(sequenceName)}</name>`);\n lines.push(` <duration>${totalFrames}</duration>`);\n lines.push(' <rate>');\n lines.push(` <timebase>${timebase}</timebase>`);\n lines.push(` <ntsc>${ntscStr}</ntsc>`);\n lines.push(' </rate>');\n lines.push(' <timecode>');\n lines.push(' <rate>');\n lines.push(` <timebase>${timebase}</timebase>`);\n lines.push(` <ntsc>${ntscStr}</ntsc>`);\n lines.push(' </rate>');\n lines.push(` <string>${timecodeStart}</string>`);\n lines.push(` <frame>${startFrameOffset}</frame>`);\n lines.push(' <displayformat>NDF</displayformat>');\n lines.push(' </timecode>');\n\n // Sequence Timeline Markers\n if (includeMarkers) {\n timings.forEach(({ shot, index, startFrame, endFrame }) => {\n const name = shot.title || `Shot ${index + 1}`;\n const comment = shot.caption || '';\n lines.push(' <marker>');\n lines.push(` <name>${escapeXml(name)}</name>`);\n lines.push(` <comment>${escapeXml(comment)}</comment>`);\n lines.push(` <in>${startFrame}</in>`);\n lines.push(` <out>${endFrame}</out>`);\n lines.push(' </marker>');\n });\n }\n\n lines.push(' <media>');\n lines.push(' <video>');\n lines.push(' <format>');\n lines.push(' <samplecharacteristics>');\n lines.push(` <width>${width}</width>`);\n lines.push(` <height>${height}</height>`);\n lines.push(' <pixelaspectratio>square</pixelaspectratio>');\n lines.push(' <rate>');\n lines.push(` <timebase>${timebase}</timebase>`);\n lines.push(` <ntsc>${ntscStr}</ntsc>`);\n lines.push(' </rate>');\n lines.push(' </samplecharacteristics>');\n lines.push(' </format>');\n\n // Video Track 1: Base Shot Clips\n lines.push(' <track>');\n lines.push(' <enabled>TRUE</enabled>');\n lines.push(' <locked>FALSE</locked>');\n\n timings.forEach(({ shot, index, startFrame, endFrame, durationFrames }) => {\n const shotName = shot.title || `Shot_${index + 1}`;\n const fileId = `file-${index + 1}`;\n const clipId = `clipitem-${index + 1}`;\n const fileName = `${shotName.replace(/[^a-zA-Z0-9_-]/g, '_')}.mov`;\n const fileUrl = `${mediaPrefix.replace(/\\/+$/, '')}/${fileName}`;\n\n lines.push(` <clipitem id=\"${clipId}\">`);\n lines.push(` <name>${escapeXml(shotName)}</name>`);\n lines.push(` <duration>${durationFrames}</duration>`);\n lines.push(' <rate>');\n lines.push(` <timebase>${timebase}</timebase>`);\n lines.push(` <ntsc>${ntscStr}</ntsc>`);\n lines.push(' </rate>');\n lines.push(` <start>${startFrame}</start>`);\n lines.push(` <end>${endFrame}</end>`);\n lines.push(' <in>0</in>');\n lines.push(` <out>${durationFrames}</out>`);\n\n // File element\n lines.push(` <file id=\"${fileId}\">`);\n lines.push(` <name>${escapeXml(fileName)}</name>`);\n lines.push(` <pathurl>${escapeXml(fileUrl)}</pathurl>`);\n lines.push(' <rate>');\n lines.push(` <timebase>${timebase}</timebase>`);\n lines.push(` <ntsc>${ntscStr}</ntsc>`);\n lines.push(' </rate>');\n lines.push(` <duration>${durationFrames}</duration>`);\n lines.push(' <timecode>');\n lines.push(' <rate>');\n lines.push(` <timebase>${timebase}</timebase>`);\n lines.push(` <ntsc>${ntscStr}</ntsc>`);\n lines.push(' </rate>');\n lines.push(' <string>00:00:00:00</string>');\n lines.push(' <frame>0</frame>');\n lines.push(' <displayformat>NDF</displayformat>');\n lines.push(' </timecode>');\n lines.push(' <media>');\n lines.push(' <video>');\n lines.push(' <samplecharacteristics>');\n lines.push(` <width>${width}</width>`);\n lines.push(` <height>${height}</height>`);\n lines.push(' </samplecharacteristics>');\n lines.push(' </video>');\n lines.push(' </media>');\n lines.push(' </file>');\n\n // Clip marker if caption is present\n if (shot.caption) {\n lines.push(' <marker>');\n lines.push(` <name>${escapeXml(shotName)} Narration</name>`);\n lines.push(` <comment>${escapeXml(shot.caption)}</comment>`);\n lines.push(' <in>0</in>');\n lines.push(` <out>${durationFrames}</out>`);\n lines.push(' </marker>');\n }\n\n // Basic Motion Filter\n lines.push(' <filter>');\n lines.push(' <effect>');\n lines.push(' <name>Basic Motion</name>');\n lines.push(' <effectid>basic</effectid>');\n lines.push(' <effectcategory>motion</effectcategory>');\n lines.push(' <effecttype>motion</effecttype>');\n lines.push(' <mediatype>video</mediatype>');\n lines.push(' <parameter>');\n lines.push(' <parameterid>scale</parameterid>');\n lines.push(' <name>Scale</name>');\n lines.push(' <value>100</value>');\n lines.push(' </parameter>');\n lines.push(' </effect>');\n lines.push(' </filter>');\n lines.push(' </clipitem>');\n });\n\n lines.push(' </track>');\n\n // Video Track 2: Title / Narration Overlay Track (Generators)\n const hasTextOverlays = timings.some((t) => t.shot.title || t.shot.caption);\n if (includeTextTrack && hasTextOverlays) {\n lines.push(' <track>');\n lines.push(' <enabled>TRUE</enabled>');\n lines.push(' <locked>FALSE</locked>');\n\n timings.forEach(({ shot, index, startFrame, endFrame, durationFrames }) => {\n const text = shot.title ?? shot.caption;\n if (!text) return;\n\n const generatorId = `generator-title-${index + 1}`;\n lines.push(` <clipitem id=\"${generatorId}\">`);\n lines.push(` <name>${escapeXml(text)}</name>`);\n lines.push(` <duration>${durationFrames}</duration>`);\n lines.push(' <rate>');\n lines.push(` <timebase>${timebase}</timebase>`);\n lines.push(` <ntsc>${ntscStr}</ntsc>`);\n lines.push(' </rate>');\n lines.push(` <start>${startFrame}</start>`);\n lines.push(` <end>${endFrame}</end>`);\n lines.push(' <in>0</in>');\n lines.push(` <out>${durationFrames}</out>`);\n lines.push(' <effect>');\n lines.push(' <name>Text</name>');\n lines.push(' <effectid>Text</effectid>');\n lines.push(' <effectcategory>Text</effectcategory>');\n lines.push(' <effecttype>generator</effecttype>');\n lines.push(' <mediatype>video</mediatype>');\n lines.push(' <parameter>');\n lines.push(' <parameterid>str</parameterid>');\n lines.push(' <name>Text</name>');\n lines.push(` <value>${escapeXml(text)}</value>`);\n lines.push(' </parameter>');\n lines.push(' </effect>');\n lines.push(' </clipitem>');\n });\n\n lines.push(' </track>');\n }\n\n lines.push(' </video>');\n lines.push(' </media>');\n lines.push(' </sequence>');\n lines.push('</xmeml>');\n\n return lines.join('\\n');\n}\n\n/**\n * Serializes a Flair Scene into standard CMX 3600 Edit Decision List (EDL).\n * Fully readable by DaVinci Resolve, Premiere Pro, Avid, and Lightworks.\n */\nexport function exportCmx3600Edl(scene: Scene, options: EdlExportOptions = {}): string {\n const frameRate = options.frameRate ?? 30;\n const timebase = Math.round(frameRate);\n const dropFrame = options.dropFrame ?? false;\n const reel = (options.reel ?? 'AX').slice(0, 8).padEnd(8, ' ');\n const title = (scene.name ?? 'UNTITLED').toUpperCase().replace(/[^A-Z0-9_ -]/g, '');\n const startTc = options.timecodeStart ?? '01:00:00:00';\n\n const timings = calculateShotTimings(scene, frameRate);\n let recordFrame = timecodeToFrames(startTc, timebase, dropFrame);\n\n const lines: string[] = [];\n lines.push(`TITLE: ${title}`);\n lines.push(dropFrame ? 'FCM: DROP FRAME' : 'FCM: NON-DROP FRAME');\n lines.push('');\n\n timings.forEach(({ shot, index, durationFrames }) => {\n const eventNum = (index + 1).toString().padStart(3, '0');\n const srcInTc = '00:00:00:00';\n const srcOutTc = framesToTimecode(durationFrames, timebase, dropFrame);\n\n const recInTc = framesToTimecode(recordFrame, timebase, dropFrame);\n recordFrame += durationFrames;\n const recOutTc = framesToTimecode(recordFrame, timebase, dropFrame);\n\n // Standard CMX 3600 line format:\n // Event Reel Track Transition SourceIn SourceOut RecordIn RecordOut\n lines.push(`${eventNum} ${reel} V C ${srcInTc} ${srcOutTc} ${recInTc} ${recOutTc}`);\n\n const clipName = shot.title || `Shot ${index + 1}`;\n lines.push(`* FROM CLIP NAME: ${clipName}`);\n if (shot.caption) {\n lines.push(`* COMMENT: ${shot.caption}`);\n }\n lines.push('');\n });\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["escapeXml"]}
@@ -0,0 +1,73 @@
1
+ // src/time/clock.ts
2
+ var pageHidden = () => typeof document !== "undefined" && document.hidden;
3
+ var realClock = {
4
+ live: true,
5
+ now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
6
+ frame: () => new Promise(
7
+ (resolve) => typeof requestAnimationFrame === "function" && !pageHidden() ? requestAnimationFrame(() => resolve()) : setTimeout(resolve, 16)
8
+ ),
9
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms))
10
+ };
11
+ var settle = () => new Promise((resolve) => setTimeout(resolve, 0));
12
+ var ManualClock = class {
13
+ live = false;
14
+ time;
15
+ frames = [];
16
+ sleepers = [];
17
+ seq = 0;
18
+ constructor(start = 0) {
19
+ this.time = start;
20
+ }
21
+ now() {
22
+ return this.time;
23
+ }
24
+ frame() {
25
+ return new Promise((resolve) => this.frames.push(resolve));
26
+ }
27
+ sleep(ms) {
28
+ return new Promise(
29
+ (resolve) => this.sleepers.push({ at: this.time + Math.max(0, ms), seq: this.seq++, resolve })
30
+ );
31
+ }
32
+ get pending() {
33
+ return this.frames.length > 0 || this.sleepers.length > 0;
34
+ }
35
+ async advance(ms) {
36
+ const end = this.time + Math.max(0, ms);
37
+ await settle();
38
+ for (; ; ) {
39
+ let next;
40
+ for (const s of this.sleepers)
41
+ if (s.at <= end && (!next || s.at < next.at || s.at === next.at && s.seq < next.seq))
42
+ next = s;
43
+ if (!next) break;
44
+ this.sleepers.splice(this.sleepers.indexOf(next), 1);
45
+ this.time = Math.max(this.time, next.at);
46
+ next.resolve();
47
+ await settle();
48
+ }
49
+ this.time = end;
50
+ const frames = this.frames;
51
+ this.frames = [];
52
+ for (const resolve of frames) resolve();
53
+ await settle();
54
+ }
55
+ tick(fps = 60) {
56
+ return this.advance(1e3 / fps);
57
+ }
58
+ };
59
+ function jitter(key, n) {
60
+ let h = 2166136261 ^ n;
61
+ for (let i = 0; i < key.length; i++) h = Math.imul(h ^ key.charCodeAt(i), 16777619);
62
+ h = Math.imul(h ^ h >>> 15, 2246822507);
63
+ h = Math.imul(h ^ h >>> 13, 3266489909);
64
+ return ((h ^ h >>> 16) >>> 0) / 2 ** 32;
65
+ }
66
+
67
+ export {
68
+ pageHidden,
69
+ realClock,
70
+ ManualClock,
71
+ jitter
72
+ };
73
+ //# sourceMappingURL=chunk-WMZQCUFJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/time/clock.ts"],"sourcesContent":["/**\n * Time source for generative animations and playback.\n * By default that is real time (animation frames and timers).\n * A ManualClock instead moves only when told to, enabling frame-exact\n * rendering, video recording, scrubbing, or fast simulation without waiting.\n */\nexport interface Clock {\n /** Current time in milliseconds. */\n now(): number;\n /** Resolves on the next frame. */\n frame(): Promise<void>;\n /** Resolves after `ms` milliseconds of this clock's time. */\n sleep(ms: number): Promise<void>;\n /**\n * Whether the clock follows wall time. Live clocks stop when the tab is in\n * the background (browsers pause animation frames there).\n */\n readonly live: boolean;\n}\n\nexport const pageHidden = (): boolean =>\n typeof document !== 'undefined' && document.hidden;\n\nexport const realClock: Clock = {\n live: true,\n now: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\n frame: () =>\n new Promise<void>((resolve) =>\n typeof requestAnimationFrame === 'function' && !pageHidden()\n ? requestAnimationFrame(() => resolve())\n : setTimeout(resolve, 16),\n ),\n sleep: (ms) => new Promise<void>((resolve) => setTimeout(resolve, ms)),\n};\n\nconst settle = () => new Promise<void>((resolve) => setTimeout(resolve, 0));\n\n/**\n * A clock that only moves when {@link advance} or {@link tick} is called.\n * Each call fires the sleeps that fall due, in order, letting awaiting code\n * run before the next sleep fires, then resolves pending frames.\n */\nexport class ManualClock implements Clock {\n readonly live = false;\n private time: number;\n private frames: (() => void)[] = [];\n private sleepers: { at: number; seq: number; resolve: () => void }[] = [];\n private seq = 0;\n\n constructor(start = 0) {\n this.time = start;\n }\n\n now(): number {\n return this.time;\n }\n\n frame(): Promise<void> {\n return new Promise((resolve) => this.frames.push(resolve));\n }\n\n sleep(ms: number): Promise<void> {\n return new Promise((resolve) =>\n this.sleepers.push({ at: this.time + Math.max(0, ms), seq: this.seq++, resolve }),\n );\n }\n\n get pending(): boolean {\n return this.frames.length > 0 || this.sleepers.length > 0;\n }\n\n async advance(ms: number): Promise<void> {\n const end = this.time + Math.max(0, ms);\n await settle();\n for (;;) {\n let next: (typeof this.sleepers)[number] | undefined;\n for (const s of this.sleepers)\n if (s.at <= end && (!next || s.at < next.at || (s.at === next.at && s.seq < next.seq)))\n next = s;\n if (!next) break;\n this.sleepers.splice(this.sleepers.indexOf(next), 1);\n this.time = Math.max(this.time, next.at);\n next.resolve();\n await settle();\n }\n this.time = end;\n const frames = this.frames;\n this.frames = [];\n for (const resolve of frames) resolve();\n await settle();\n }\n\n tick(fps = 60): Promise<void> {\n return this.advance(1000 / fps);\n }\n}\n\n/**\n * A repeatable pseudo-random number in [0, 1) for a key and index.\n * Useful for deterministic, reproducible animations.\n */\nexport function jitter(key: string, n: number): number {\n let h = 2166136261 ^ n;\n for (let i = 0; i < key.length; i++) h = Math.imul(h ^ key.charCodeAt(i), 16777619);\n h = Math.imul(h ^ (h >>> 15), 2246822507);\n h = Math.imul(h ^ (h >>> 13), 3266489909);\n return ((h ^ (h >>> 16)) >>> 0) / 2 ** 32;\n}\n"],"mappings":";AAoBO,IAAM,aAAa,MACxB,OAAO,aAAa,eAAe,SAAS;AAEvC,IAAM,YAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,KAAK,MAAO,OAAO,gBAAgB,cAAc,YAAY,IAAI,IAAI,KAAK,IAAI;AAAA,EAC9E,OAAO,MACL,IAAI;AAAA,IAAc,CAAC,YACjB,OAAO,0BAA0B,cAAc,CAAC,WAAW,IACvD,sBAAsB,MAAM,QAAQ,CAAC,IACrC,WAAW,SAAS,EAAE;AAAA,EAC5B;AAAA,EACF,OAAO,CAAC,OAAO,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACvE;AAEA,IAAM,SAAS,MAAM,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,CAAC,CAAC;AAOnE,IAAM,cAAN,MAAmC;AAAA,EAC/B,OAAO;AAAA,EACR;AAAA,EACA,SAAyB,CAAC;AAAA,EAC1B,WAA+D,CAAC;AAAA,EAChE,MAAM;AAAA,EAEd,YAAY,QAAQ,GAAG;AACrB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAc;AACZ,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,QAAuB;AACrB,WAAO,IAAI,QAAQ,CAAC,YAAY,KAAK,OAAO,KAAK,OAAO,CAAC;AAAA,EAC3D;AAAA,EAEA,MAAM,IAA2B;AAC/B,WAAO,IAAI;AAAA,MAAQ,CAAC,YAClB,KAAK,SAAS,KAAK,EAAE,IAAI,KAAK,OAAO,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,KAAK,OAAO,QAAQ,CAAC;AAAA,IAClF;AAAA,EACF;AAAA,EAEA,IAAI,UAAmB;AACrB,WAAO,KAAK,OAAO,SAAS,KAAK,KAAK,SAAS,SAAS;AAAA,EAC1D;AAAA,EAEA,MAAM,QAAQ,IAA2B;AACvC,UAAM,MAAM,KAAK,OAAO,KAAK,IAAI,GAAG,EAAE;AACtC,UAAM,OAAO;AACb,eAAS;AACP,UAAI;AACJ,iBAAW,KAAK,KAAK;AACnB,YAAI,EAAE,MAAM,QAAQ,CAAC,QAAQ,EAAE,KAAK,KAAK,MAAO,EAAE,OAAO,KAAK,MAAM,EAAE,MAAM,KAAK;AAC/E,iBAAO;AACX,UAAI,CAAC,KAAM;AACX,WAAK,SAAS,OAAO,KAAK,SAAS,QAAQ,IAAI,GAAG,CAAC;AACnD,WAAK,OAAO,KAAK,IAAI,KAAK,MAAM,KAAK,EAAE;AACvC,WAAK,QAAQ;AACb,YAAM,OAAO;AAAA,IACf;AACA,SAAK,OAAO;AACZ,UAAM,SAAS,KAAK;AACpB,SAAK,SAAS,CAAC;AACf,eAAW,WAAW,OAAQ,SAAQ;AACtC,UAAM,OAAO;AAAA,EACf;AAAA,EAEA,KAAK,MAAM,IAAmB;AAC5B,WAAO,KAAK,QAAQ,MAAO,GAAG;AAAA,EAChC;AACF;AAMO,SAAS,OAAO,KAAa,GAAmB;AACrD,MAAI,IAAI,aAAa;AACrB,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,KAAI,KAAK,KAAK,IAAI,IAAI,WAAW,CAAC,GAAG,QAAQ;AAClF,MAAI,KAAK,KAAK,IAAK,MAAM,IAAK,UAAU;AACxC,MAAI,KAAK,KAAK,IAAK,MAAM,IAAK,UAAU;AACxC,WAAS,IAAK,MAAM,QAAS,KAAK,KAAK;AACzC;","names":[]}
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,331 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ simulateScene,
4
+ standaloneHtml,
5
+ standaloneSceneHtml,
6
+ validateScene
7
+ } from "./chunk-JWZCPMFG.js";
8
+ import "./chunk-HKXOHRCD.js";
9
+ import "./chunk-EHDJ3CPJ.js";
10
+ import "./chunk-WMZQCUFJ.js";
11
+ import "./chunk-36DTNSHU.js";
12
+ import {
13
+ parseControls
14
+ } from "./chunk-J55UBNAT.js";
15
+
16
+ // src/cli.ts
17
+ import { Command } from "commander";
18
+ import path from "path";
19
+ import fs from "fs";
20
+ import { exec } from "child_process";
21
+ var program = new Command();
22
+ program.name("flair").description("Generative motion graphics, animation directing & bespoke WebGL shader engine").version("2.0.0");
23
+ program.command("controls <shaderPath>").description("Inspect and parse @control declarations in a WebGL shader file").option("--json", "Output controls as JSON", false).action((shaderPath, options) => {
24
+ const fullPath = path.resolve(process.cwd(), shaderPath);
25
+ if (!fs.existsSync(fullPath)) {
26
+ console.error(`Error: Shader file not found at: ${fullPath}`);
27
+ process.exit(1);
28
+ }
29
+ const source = fs.readFileSync(fullPath, "utf-8");
30
+ const controls = parseControls(source);
31
+ if (options.json) {
32
+ console.log(JSON.stringify(controls, null, 2));
33
+ return;
34
+ }
35
+ if (controls.length === 0) {
36
+ console.log(`No @control annotations found in ${path.basename(shaderPath)}.`);
37
+ return;
38
+ }
39
+ console.log(`Controls in ${path.basename(shaderPath)} (${controls.length}):`);
40
+ for (const c of controls) {
41
+ const defVal = Array.isArray(c.default) ? `[${c.default.join(", ")}]` : String(c.default);
42
+ console.log(
43
+ ` \u2022 ${c.name} (${c.type}): "${c.label}" | default=${defVal} | range=[${c.min}, ${c.max}] (line ${c.line})`
44
+ );
45
+ }
46
+ });
47
+ program.command("html <shaderPath>").description("Generate a self-contained standalone HTML page running the shader").option("-t, --title <title>", "Page title").option("-o, --out <outputPath>", "Output HTML path").option("-v, --values <jsonOrFile>", "Control values as JSON string or path to JSON file").option("--open", "Open generated HTML page in default browser", false).action((shaderPath, options) => {
48
+ const fullPath = path.resolve(process.cwd(), shaderPath);
49
+ if (!fs.existsSync(fullPath)) {
50
+ console.error(`Error: Shader file not found at: ${fullPath}`);
51
+ process.exit(1);
52
+ }
53
+ const source = fs.readFileSync(fullPath, "utf-8");
54
+ const title = options.title || path.basename(shaderPath, path.extname(shaderPath));
55
+ let values = {};
56
+ if (options.values) {
57
+ try {
58
+ if (fs.existsSync(options.values)) {
59
+ values = JSON.parse(fs.readFileSync(options.values, "utf-8"));
60
+ } else {
61
+ values = JSON.parse(options.values);
62
+ }
63
+ } catch (err) {
64
+ console.error(`Error parsing values: ${err.message}`);
65
+ process.exit(1);
66
+ }
67
+ }
68
+ const htmlContent = standaloneHtml(title, source, values);
69
+ const outputPath = path.resolve(
70
+ process.cwd(),
71
+ options.out || `${path.basename(shaderPath, path.extname(shaderPath))}.html`
72
+ );
73
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
74
+ fs.writeFileSync(outputPath, htmlContent, "utf-8");
75
+ console.log(`Generated standalone shader page at: ${outputPath}`);
76
+ if (options.open) {
77
+ exec(`open "${outputPath}"`);
78
+ }
79
+ });
80
+ program.command("export <targetOrShader> [extraPath] [outputPath]").description("Export shader animation (GIF/MP4) or scene to Apple Motion ozml 4.0 (.motn)").option("-o, --out <outputPath>", "Output file path").option("-w, --width <width>", "Canvas width", "720").option("-h, --height <height>", "Canvas height", "720").option("--fps <fps>", "Frames per second", "30").option("-d, --duration <duration>", "Duration in seconds", "3").option("-v, --values <jsonOrFile>", "Control values as JSON string or file").action(async (targetOrShader, extraPath, outputPath, options) => {
81
+ if (targetOrShader === "motn" || targetOrShader === "lottie" || targetOrShader === "fcp7" || targetOrShader === "edl") {
82
+ const sceneFile = extraPath;
83
+ if (!sceneFile) {
84
+ console.error(`Error: Please provide a scene JSON file to export: flair export ${targetOrShader} <scene.json> [output]`);
85
+ process.exit(1);
86
+ }
87
+ const fullPath2 = path.resolve(process.cwd(), sceneFile);
88
+ if (!fs.existsSync(fullPath2)) {
89
+ console.error(`Error: Scene file not found at: ${fullPath2}`);
90
+ process.exit(1);
91
+ }
92
+ try {
93
+ const scene = JSON.parse(fs.readFileSync(fullPath2, "utf-8"));
94
+ const { exportMotn, exportLottie, exportFcp7Xml, exportCmx3600Edl } = await import("./export-FEBPEEO7.js");
95
+ const fps2 = parseInt(options.fps, 10);
96
+ let content;
97
+ let ext;
98
+ if (targetOrShader === "motn") {
99
+ content = exportMotn(scene, { frameRate: fps2 });
100
+ ext = "motn";
101
+ } else if (targetOrShader === "lottie") {
102
+ content = JSON.stringify(exportLottie(scene, { frameRate: fps2 }), null, 2);
103
+ ext = "json";
104
+ } else if (targetOrShader === "fcp7") {
105
+ content = exportFcp7Xml(scene, { frameRate: fps2 });
106
+ ext = "xml";
107
+ } else {
108
+ content = exportCmx3600Edl(scene, { frameRate: fps2 });
109
+ ext = "edl";
110
+ }
111
+ const destination = path.resolve(
112
+ process.cwd(),
113
+ options.out || outputPath || `${scene.name || "scene"}.${ext}`
114
+ );
115
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
116
+ fs.writeFileSync(destination, content, "utf-8");
117
+ console.log(`\u2705 Successfully exported ${targetOrShader.toUpperCase()} to: ${destination}`);
118
+ } catch (err) {
119
+ console.error(`Error exporting scene to ${targetOrShader}: ${err.message}`);
120
+ process.exit(1);
121
+ }
122
+ return;
123
+ }
124
+ const shaderPath = targetOrShader;
125
+ const fullPath = path.resolve(process.cwd(), shaderPath);
126
+ if (!fs.existsSync(fullPath)) {
127
+ console.error(`Error: Shader file not found at: ${fullPath}`);
128
+ process.exit(1);
129
+ }
130
+ if (!options.out) {
131
+ console.error("Error: Output file path required (-o, --out <outputPath>)");
132
+ process.exit(1);
133
+ }
134
+ const source = fs.readFileSync(fullPath, "utf-8");
135
+ let values = {};
136
+ if (options.values) {
137
+ try {
138
+ if (fs.existsSync(options.values)) {
139
+ values = JSON.parse(fs.readFileSync(options.values, "utf-8"));
140
+ } else {
141
+ values = JSON.parse(options.values);
142
+ }
143
+ } catch (err) {
144
+ console.error(`Error parsing values: ${err.message}`);
145
+ process.exit(1);
146
+ }
147
+ }
148
+ const width = parseInt(options.width, 10);
149
+ const height = parseInt(options.height, 10);
150
+ const fps = parseInt(options.fps, 10);
151
+ const duration = parseFloat(options.duration);
152
+ console.log(`Rendering ${duration}s (${duration * fps} frames at ${width}x${height}, ${fps}fps) to ${options.out}...`);
153
+ try {
154
+ const { exportMotionGraphic } = await import("./recorder-WJTWMEQN.js");
155
+ const savedPath = await exportMotionGraphic({
156
+ source,
157
+ values,
158
+ outputPath: options.out,
159
+ width,
160
+ height,
161
+ fps,
162
+ duration,
163
+ onProgress: (frame, total) => {
164
+ process.stdout.write(`\rRendering frame ${frame}/${total} (${Math.round(frame / total * 100)}%)`);
165
+ }
166
+ });
167
+ console.log(`
168
+ \u2705 Successfully exported motion graphic to: ${savedPath}`);
169
+ } catch (err) {
170
+ console.error(`
171
+ Export failed: ${err.message}`);
172
+ process.exit(1);
173
+ }
174
+ });
175
+ var sceneCmd = program.command("scene").description("Direct, validate, simulate, and render multi-shot animated scenes");
176
+ sceneCmd.command("validate <sceneFile>").description("Validate scene JSON structure, camera framing, and effect IDs").action((sceneFile) => {
177
+ const fullPath = path.resolve(process.cwd(), sceneFile);
178
+ if (!fs.existsSync(fullPath)) {
179
+ console.error(`Error: Scene file not found at: ${fullPath}`);
180
+ process.exit(1);
181
+ }
182
+ try {
183
+ const scene = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
184
+ const issues = validateScene(scene);
185
+ if (issues.length === 0) {
186
+ console.log(`\u2705 Scene "${scene.name}" is valid (${scene.shots.length} shots).`);
187
+ } else {
188
+ console.warn(`Found ${issues.length} issue(s) in "${scene.name}":`);
189
+ for (const iss of issues) {
190
+ const loc = iss.shot === 0 ? "Scene" : `Shot ${iss.shot}`;
191
+ console.warn(` \u2022 [${loc}] ${iss.message}`);
192
+ }
193
+ process.exit(1);
194
+ }
195
+ } catch (err) {
196
+ console.error(`Error reading scene: ${err.message}`);
197
+ process.exit(1);
198
+ }
199
+ });
200
+ sceneCmd.command("review <sceneFile>").alias("preview").description("Simulate scene off-screen and generate timing breakdown & diagnostic review").action(async (sceneFile) => {
201
+ const fullPath = path.resolve(process.cwd(), sceneFile);
202
+ if (!fs.existsSync(fullPath)) {
203
+ console.error(`Error: Scene file not found at: ${fullPath}`);
204
+ process.exit(1);
205
+ }
206
+ try {
207
+ const scene = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
208
+ const { review } = await simulateScene(scene);
209
+ console.log(review.markdown);
210
+ } catch (err) {
211
+ console.error(`Error reviewing scene: ${err.message}`);
212
+ process.exit(1);
213
+ }
214
+ });
215
+ sceneCmd.command("html <sceneFile>").description("Generate standalone interactive web player for the scene").option("-o, --out <outputPath>", "Output HTML path").option("--open", "Open generated HTML in browser", false).action((sceneFile, options) => {
216
+ const fullPath = path.resolve(process.cwd(), sceneFile);
217
+ if (!fs.existsSync(fullPath)) {
218
+ console.error(`Error: Scene file not found at: ${fullPath}`);
219
+ process.exit(1);
220
+ }
221
+ try {
222
+ const scene = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
223
+ const htmlContent = standaloneSceneHtml(scene);
224
+ const outputPath = path.resolve(
225
+ process.cwd(),
226
+ options.out || `${scene.name || "scene"}.html`
227
+ );
228
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
229
+ fs.writeFileSync(outputPath, htmlContent, "utf-8");
230
+ console.log(`Generated standalone scene player at: ${outputPath}`);
231
+ if (options.open) {
232
+ exec(`open "${outputPath}"`);
233
+ }
234
+ } catch (err) {
235
+ console.error(`Error generating scene HTML: ${err.message}`);
236
+ process.exit(1);
237
+ }
238
+ });
239
+ sceneCmd.command("motn <sceneFile> [outFile]").description("Export scene to Apple Motion ozml 4.0 XML (.motn) document").option("--fps <fps>", "Target frame rate", "30").action(async (sceneFile, outFile, options) => {
240
+ const fullPath = path.resolve(process.cwd(), sceneFile);
241
+ if (!fs.existsSync(fullPath)) {
242
+ console.error(`Error: Scene file not found at: ${fullPath}`);
243
+ process.exit(1);
244
+ }
245
+ try {
246
+ const scene = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
247
+ const { exportMotn } = await import("./export-FEBPEEO7.js");
248
+ const xml = exportMotn(scene, { frameRate: parseInt(options.fps, 10) });
249
+ const destination = path.resolve(
250
+ process.cwd(),
251
+ outFile || `${scene.name || "scene"}.motn`
252
+ );
253
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
254
+ fs.writeFileSync(destination, xml, "utf-8");
255
+ console.log(`\u2705 Successfully exported Apple Motion scene to: ${destination}`);
256
+ } catch (err) {
257
+ console.error(`Error exporting scene to .motn: ${err.message}`);
258
+ process.exit(1);
259
+ }
260
+ });
261
+ sceneCmd.command("lottie <sceneFile> [outFile]").description("Export scene vector shapes and animations to Lottie JSON").option("--fps <fps>", "Target frame rate", "30").action(async (sceneFile, outFile, options) => {
262
+ const fullPath = path.resolve(process.cwd(), sceneFile);
263
+ if (!fs.existsSync(fullPath)) {
264
+ console.error(`Error: Scene file not found at: ${fullPath}`);
265
+ process.exit(1);
266
+ }
267
+ try {
268
+ const scene = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
269
+ const { exportLottie } = await import("./export-FEBPEEO7.js");
270
+ const animation = exportLottie(scene, { frameRate: parseInt(options.fps, 10) });
271
+ const destination = path.resolve(
272
+ process.cwd(),
273
+ outFile || `${scene.name || "scene"}.json`
274
+ );
275
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
276
+ fs.writeFileSync(destination, JSON.stringify(animation, null, 2), "utf-8");
277
+ console.log(`\u2705 Successfully exported Lottie animation to: ${destination}`);
278
+ } catch (err) {
279
+ console.error(`Error exporting scene to Lottie: ${err.message}`);
280
+ process.exit(1);
281
+ }
282
+ });
283
+ sceneCmd.command("fcp7 <sceneFile> [outFile]").description("Export scene timeline and markers to Final Cut Pro 7 XML (xmeml v4)").option("--fps <fps>", "Target frame rate", "30").action(async (sceneFile, outFile, options) => {
284
+ const fullPath = path.resolve(process.cwd(), sceneFile);
285
+ if (!fs.existsSync(fullPath)) {
286
+ console.error(`Error: Scene file not found at: ${fullPath}`);
287
+ process.exit(1);
288
+ }
289
+ try {
290
+ const scene = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
291
+ const { exportFcp7Xml } = await import("./export-FEBPEEO7.js");
292
+ const xml = exportFcp7Xml(scene, { frameRate: parseInt(options.fps, 10) });
293
+ const destination = path.resolve(
294
+ process.cwd(),
295
+ outFile || `${scene.name || "scene"}.xml`
296
+ );
297
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
298
+ fs.writeFileSync(destination, xml, "utf-8");
299
+ console.log(`\u2705 Successfully exported FCP7 XML to: ${destination}`);
300
+ } catch (err) {
301
+ console.error(`Error exporting scene to FCP7 XML: ${err.message}`);
302
+ process.exit(1);
303
+ }
304
+ });
305
+ sceneCmd.command("edl <sceneFile> [outFile]").description("Export scene edit decision list to standard CMX 3600 EDL").option("--fps <fps>", "Target frame rate", "30").option("--reel <reel>", "Reel name identifier", "AX").action(async (sceneFile, outFile, options) => {
306
+ const fullPath = path.resolve(process.cwd(), sceneFile);
307
+ if (!fs.existsSync(fullPath)) {
308
+ console.error(`Error: Scene file not found at: ${fullPath}`);
309
+ process.exit(1);
310
+ }
311
+ try {
312
+ const scene = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
313
+ const { exportCmx3600Edl } = await import("./export-FEBPEEO7.js");
314
+ const edl = exportCmx3600Edl(scene, {
315
+ frameRate: parseInt(options.fps, 10),
316
+ reel: options.reel
317
+ });
318
+ const destination = path.resolve(
319
+ process.cwd(),
320
+ outFile || `${scene.name || "scene"}.edl`
321
+ );
322
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
323
+ fs.writeFileSync(destination, edl, "utf-8");
324
+ console.log(`\u2705 Successfully exported CMX 3600 EDL to: ${destination}`);
325
+ } catch (err) {
326
+ console.error(`Error exporting scene to CMX 3600 EDL: ${err.message}`);
327
+ process.exit(1);
328
+ }
329
+ });
330
+ program.parse(process.argv);
331
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport path from 'path';\nimport fs from 'fs';\nimport { exec } from 'child_process';\nimport { parseControls, standaloneHtml, type ControlValue } from './shader/index.js';\nimport { validateScene, simulateScene, standaloneSceneHtml, type Scene } from './scene/index.js';\n\nconst program = new Command();\n\nprogram\n .name('flair')\n .description('Generative motion graphics, animation directing & bespoke WebGL shader engine')\n .version('2.0.0');\n\n// ==========================================\n// Shader Commands\n// ==========================================\nprogram\n .command('controls <shaderPath>')\n .description('Inspect and parse @control declarations in a WebGL shader file')\n .option('--json', 'Output controls as JSON', false)\n .action((shaderPath, options) => {\n const fullPath = path.resolve(process.cwd(), shaderPath);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Shader file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n const source = fs.readFileSync(fullPath, 'utf-8');\n const controls = parseControls(source);\n\n if (options.json) {\n console.log(JSON.stringify(controls, null, 2));\n return;\n }\n\n if (controls.length === 0) {\n console.log(`No @control annotations found in ${path.basename(shaderPath)}.`);\n return;\n }\n\n console.log(`Controls in ${path.basename(shaderPath)} (${controls.length}):`);\n for (const c of controls) {\n const defVal = Array.isArray(c.default) ? `[${c.default.join(', ')}]` : String(c.default);\n console.log(\n ` • ${c.name} (${c.type}): \"${c.label}\" | default=${defVal} | range=[${c.min}, ${c.max}] (line ${c.line})`\n );\n }\n });\n\nprogram\n .command('html <shaderPath>')\n .description('Generate a self-contained standalone HTML page running the shader')\n .option('-t, --title <title>', 'Page title')\n .option('-o, --out <outputPath>', 'Output HTML path')\n .option('-v, --values <jsonOrFile>', 'Control values as JSON string or path to JSON file')\n .option('--open', 'Open generated HTML page in default browser', false)\n .action((shaderPath, options) => {\n const fullPath = path.resolve(process.cwd(), shaderPath);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Shader file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n const source = fs.readFileSync(fullPath, 'utf-8');\n const title = options.title || path.basename(shaderPath, path.extname(shaderPath));\n\n let values: Record<string, ControlValue> = {};\n if (options.values) {\n try {\n if (fs.existsSync(options.values)) {\n values = JSON.parse(fs.readFileSync(options.values, 'utf-8'));\n } else {\n values = JSON.parse(options.values);\n }\n } catch (err: any) {\n console.error(`Error parsing values: ${err.message}`);\n process.exit(1);\n }\n }\n\n const htmlContent = standaloneHtml(title, source, values);\n const outputPath = path.resolve(\n process.cwd(),\n options.out || `${path.basename(shaderPath, path.extname(shaderPath))}.html`\n );\n\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n fs.writeFileSync(outputPath, htmlContent, 'utf-8');\n console.log(`Generated standalone shader page at: ${outputPath}`);\n\n if (options.open) {\n exec(`open \"${outputPath}\"`);\n }\n });\n\nprogram\n .command('export <targetOrShader> [extraPath] [outputPath]')\n .description('Export shader animation (GIF/MP4) or scene to Apple Motion ozml 4.0 (.motn)')\n .option('-o, --out <outputPath>', 'Output file path')\n .option('-w, --width <width>', 'Canvas width', '720')\n .option('-h, --height <height>', 'Canvas height', '720')\n .option('--fps <fps>', 'Frames per second', '30')\n .option('-d, --duration <duration>', 'Duration in seconds', '3')\n .option('-v, --values <jsonOrFile>', 'Control values as JSON string or file')\n .action(async (targetOrShader, extraPath, outputPath, options) => {\n if (targetOrShader === 'motn' || targetOrShader === 'lottie' || targetOrShader === 'fcp7' || targetOrShader === 'edl') {\n const sceneFile = extraPath;\n if (!sceneFile) {\n console.error(`Error: Please provide a scene JSON file to export: flair export ${targetOrShader} <scene.json> [output]`);\n process.exit(1);\n }\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const { exportMotn, exportLottie, exportFcp7Xml, exportCmx3600Edl } = await import('./export/index.js');\n const fps = parseInt(options.fps, 10);\n\n let content: string;\n let ext: string;\n if (targetOrShader === 'motn') {\n content = exportMotn(scene, { frameRate: fps });\n ext = 'motn';\n } else if (targetOrShader === 'lottie') {\n content = JSON.stringify(exportLottie(scene, { frameRate: fps }), null, 2);\n ext = 'json';\n } else if (targetOrShader === 'fcp7') {\n content = exportFcp7Xml(scene, { frameRate: fps });\n ext = 'xml';\n } else {\n content = exportCmx3600Edl(scene, { frameRate: fps });\n ext = 'edl';\n }\n\n const destination = path.resolve(\n process.cwd(),\n options.out || outputPath || `${scene.name || 'scene'}.${ext}`\n );\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.writeFileSync(destination, content, 'utf-8');\n console.log(`✅ Successfully exported ${targetOrShader.toUpperCase()} to: ${destination}`);\n } catch (err: any) {\n console.error(`Error exporting scene to ${targetOrShader}: ${err.message}`);\n process.exit(1);\n }\n return;\n }\n\n const shaderPath = targetOrShader;\n const fullPath = path.resolve(process.cwd(), shaderPath);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Shader file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n if (!options.out) {\n console.error('Error: Output file path required (-o, --out <outputPath>)');\n process.exit(1);\n }\n\n const source = fs.readFileSync(fullPath, 'utf-8');\n\n let values: Record<string, ControlValue> = {};\n if (options.values) {\n try {\n if (fs.existsSync(options.values)) {\n values = JSON.parse(fs.readFileSync(options.values, 'utf-8'));\n } else {\n values = JSON.parse(options.values);\n }\n } catch (err: any) {\n console.error(`Error parsing values: ${err.message}`);\n process.exit(1);\n }\n }\n\n const width = parseInt(options.width, 10);\n const height = parseInt(options.height, 10);\n const fps = parseInt(options.fps, 10);\n const duration = parseFloat(options.duration);\n\n console.log(`Rendering ${duration}s (${duration * fps} frames at ${width}x${height}, ${fps}fps) to ${options.out}...`);\n\n try {\n const { exportMotionGraphic } = await import('./export/recorder.js');\n const savedPath = await exportMotionGraphic({\n source,\n values,\n outputPath: options.out,\n width,\n height,\n fps,\n duration,\n onProgress: (frame, total) => {\n process.stdout.write(`\\rRendering frame ${frame}/${total} (${Math.round((frame / total) * 100)}%)`);\n },\n });\n console.log(`\\n✅ Successfully exported motion graphic to: ${savedPath}`);\n } catch (err: any) {\n console.error(`\\nExport failed: ${err.message}`);\n process.exit(1);\n }\n });\n\n// ==========================================\n// Scene Directing Commands\n// ==========================================\nconst sceneCmd = program\n .command('scene')\n .description('Direct, validate, simulate, and render multi-shot animated scenes');\n\nsceneCmd\n .command('validate <sceneFile>')\n .description('Validate scene JSON structure, camera framing, and effect IDs')\n .action((sceneFile) => {\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const issues = validateScene(scene);\n if (issues.length === 0) {\n console.log(`✅ Scene \"${scene.name}\" is valid (${scene.shots.length} shots).`);\n } else {\n console.warn(`Found ${issues.length} issue(s) in \"${scene.name}\":`);\n for (const iss of issues) {\n const loc = iss.shot === 0 ? 'Scene' : `Shot ${iss.shot}`;\n console.warn(` • [${loc}] ${iss.message}`);\n }\n process.exit(1);\n }\n } catch (err: any) {\n console.error(`Error reading scene: ${err.message}`);\n process.exit(1);\n }\n });\n\nsceneCmd\n .command('review <sceneFile>')\n .alias('preview')\n .description('Simulate scene off-screen and generate timing breakdown & diagnostic review')\n .action(async (sceneFile) => {\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const { review } = await simulateScene(scene);\n console.log(review.markdown);\n } catch (err: any) {\n console.error(`Error reviewing scene: ${err.message}`);\n process.exit(1);\n }\n });\n\nsceneCmd\n .command('html <sceneFile>')\n .description('Generate standalone interactive web player for the scene')\n .option('-o, --out <outputPath>', 'Output HTML path')\n .option('--open', 'Open generated HTML in browser', false)\n .action((sceneFile, options) => {\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const htmlContent = standaloneSceneHtml(scene);\n const outputPath = path.resolve(\n process.cwd(),\n options.out || `${scene.name || 'scene'}.html`\n );\n\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n fs.writeFileSync(outputPath, htmlContent, 'utf-8');\n console.log(`Generated standalone scene player at: ${outputPath}`);\n\n if (options.open) {\n exec(`open \"${outputPath}\"`);\n }\n } catch (err: any) {\n console.error(`Error generating scene HTML: ${err.message}`);\n process.exit(1);\n }\n });\n\nsceneCmd\n .command('motn <sceneFile> [outFile]')\n .description('Export scene to Apple Motion ozml 4.0 XML (.motn) document')\n .option('--fps <fps>', 'Target frame rate', '30')\n .action(async (sceneFile, outFile, options) => {\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const { exportMotn } = await import('./export/index.js');\n const xml = exportMotn(scene, { frameRate: parseInt(options.fps, 10) });\n const destination = path.resolve(\n process.cwd(),\n outFile || `${scene.name || 'scene'}.motn`\n );\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.writeFileSync(destination, xml, 'utf-8');\n console.log(`✅ Successfully exported Apple Motion scene to: ${destination}`);\n } catch (err: any) {\n console.error(`Error exporting scene to .motn: ${err.message}`);\n process.exit(1);\n }\n });\n\nsceneCmd\n .command('lottie <sceneFile> [outFile]')\n .description('Export scene vector shapes and animations to Lottie JSON')\n .option('--fps <fps>', 'Target frame rate', '30')\n .action(async (sceneFile, outFile, options) => {\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const { exportLottie } = await import('./export/index.js');\n const animation = exportLottie(scene, { frameRate: parseInt(options.fps, 10) });\n const destination = path.resolve(\n process.cwd(),\n outFile || `${scene.name || 'scene'}.json`\n );\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.writeFileSync(destination, JSON.stringify(animation, null, 2), 'utf-8');\n console.log(`✅ Successfully exported Lottie animation to: ${destination}`);\n } catch (err: any) {\n console.error(`Error exporting scene to Lottie: ${err.message}`);\n process.exit(1);\n }\n });\n\nsceneCmd\n .command('fcp7 <sceneFile> [outFile]')\n .description('Export scene timeline and markers to Final Cut Pro 7 XML (xmeml v4)')\n .option('--fps <fps>', 'Target frame rate', '30')\n .action(async (sceneFile, outFile, options) => {\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const { exportFcp7Xml } = await import('./export/index.js');\n const xml = exportFcp7Xml(scene, { frameRate: parseInt(options.fps, 10) });\n const destination = path.resolve(\n process.cwd(),\n outFile || `${scene.name || 'scene'}.xml`\n );\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.writeFileSync(destination, xml, 'utf-8');\n console.log(`✅ Successfully exported FCP7 XML to: ${destination}`);\n } catch (err: any) {\n console.error(`Error exporting scene to FCP7 XML: ${err.message}`);\n process.exit(1);\n }\n });\n\nsceneCmd\n .command('edl <sceneFile> [outFile]')\n .description('Export scene edit decision list to standard CMX 3600 EDL')\n .option('--fps <fps>', 'Target frame rate', '30')\n .option('--reel <reel>', 'Reel name identifier', 'AX')\n .action(async (sceneFile, outFile, options) => {\n const fullPath = path.resolve(process.cwd(), sceneFile);\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Scene file not found at: ${fullPath}`);\n process.exit(1);\n }\n\n try {\n const scene: Scene = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n const { exportCmx3600Edl } = await import('./export/index.js');\n const edl = exportCmx3600Edl(scene, {\n frameRate: parseInt(options.fps, 10),\n reel: options.reel,\n });\n const destination = path.resolve(\n process.cwd(),\n outFile || `${scene.name || 'scene'}.edl`\n );\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.writeFileSync(destination, edl, 'utf-8');\n console.log(`✅ Successfully exported CMX 3600 EDL to: ${destination}`);\n } catch (err: any) {\n console.error(`Error exporting scene to CMX 3600 EDL: ${err.message}`);\n process.exit(1);\n }\n });\n\n\nprogram.parse(process.argv);\n"],"mappings":"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","names":["fullPath","fps"]}