@motionscript/browser 0.1.0 → 0.1.1-alpha.1

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 (102) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/asset-bytes.d.ts +12 -50
  3. package/dist/asset-bytes.d.ts.map +1 -1
  4. package/dist/asset-bytes.js +20 -52
  5. package/dist/asset-bytes.js.map +1 -1
  6. package/dist/audio/bus-graph.d.ts +4 -39
  7. package/dist/audio/bus-graph.d.ts.map +1 -1
  8. package/dist/audio/bus-graph.js +4 -38
  9. package/dist/audio/bus-graph.js.map +1 -1
  10. package/dist/audio/effect-graph.d.ts +4 -29
  11. package/dist/audio/effect-graph.d.ts.map +1 -1
  12. package/dist/audio/effect-graph.js +4 -31
  13. package/dist/audio/effect-graph.js.map +1 -1
  14. package/dist/audio/loop-region.d.ts +3 -21
  15. package/dist/audio/loop-region.d.ts.map +1 -1
  16. package/dist/audio/loop-region.js +3 -21
  17. package/dist/audio/loop-region.js.map +1 -1
  18. package/dist/audio/mixer.d.ts +9 -41
  19. package/dist/audio/mixer.d.ts.map +1 -1
  20. package/dist/audio/mixer.js +11 -44
  21. package/dist/audio/mixer.js.map +1 -1
  22. package/dist/audio/player.d.ts +3 -17
  23. package/dist/audio/player.d.ts.map +1 -1
  24. package/dist/audio/player.js +4 -23
  25. package/dist/audio/player.js.map +1 -1
  26. package/dist/browser/audio.js +1 -1
  27. package/dist/browser/chunks/chunk-NDJYMKIV.js +2 -0
  28. package/dist/browser/chunks/chunk-NDJYMKIV.js.map +7 -0
  29. package/dist/browser/index.js +19 -19
  30. package/dist/browser/index.js.map +4 -4
  31. package/dist/browser/manifest.json +1 -1
  32. package/dist/browser/ms_renderer_bg.wasm +0 -0
  33. package/dist/concat.d.ts +25 -84
  34. package/dist/concat.d.ts.map +1 -1
  35. package/dist/concat.js +19 -69
  36. package/dist/concat.js.map +1 -1
  37. package/dist/dynamic-nodes.d.ts +1 -6
  38. package/dist/dynamic-nodes.d.ts.map +1 -1
  39. package/dist/dynamic-nodes.js +3 -24
  40. package/dist/dynamic-nodes.js.map +1 -1
  41. package/dist/engine.d.ts +9 -42
  42. package/dist/engine.d.ts.map +1 -1
  43. package/dist/engine.js +10 -44
  44. package/dist/engine.js.map +1 -1
  45. package/dist/export-audio.d.ts +1 -6
  46. package/dist/export-audio.d.ts.map +1 -1
  47. package/dist/export-audio.js +1 -6
  48. package/dist/export-audio.js.map +1 -1
  49. package/dist/exporter.d.ts +28 -141
  50. package/dist/exporter.d.ts.map +1 -1
  51. package/dist/exporter.js +15 -90
  52. package/dist/exporter.js.map +1 -1
  53. package/dist/frame-loop.d.ts +19 -105
  54. package/dist/frame-loop.d.ts.map +1 -1
  55. package/dist/frame-loop.js +20 -82
  56. package/dist/frame-loop.js.map +1 -1
  57. package/dist/index.d.ts +1 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +7 -15
  60. package/dist/index.js.map +1 -1
  61. package/dist/mix-timeline-audio.d.ts +7 -24
  62. package/dist/mix-timeline-audio.d.ts.map +1 -1
  63. package/dist/mix-timeline-audio.js +7 -23
  64. package/dist/mix-timeline-audio.js.map +1 -1
  65. package/dist/native-export.d.ts +29 -0
  66. package/dist/native-export.d.ts.map +1 -0
  67. package/dist/native-export.js +99 -0
  68. package/dist/native-export.js.map +1 -0
  69. package/dist/parallel/export-parallel.d.ts +2 -16
  70. package/dist/parallel/export-parallel.d.ts.map +1 -1
  71. package/dist/parallel/export-parallel.js +1 -11
  72. package/dist/parallel/export-parallel.js.map +1 -1
  73. package/dist/parallel/governor.d.ts +2 -15
  74. package/dist/parallel/governor.d.ts.map +1 -1
  75. package/dist/parallel/governor.js +1 -5
  76. package/dist/parallel/governor.js.map +1 -1
  77. package/dist/parallel/lane.d.ts +1 -5
  78. package/dist/parallel/lane.d.ts.map +1 -1
  79. package/dist/parallel/lane.js.map +1 -1
  80. package/dist/parallel/plan.d.ts +3 -7
  81. package/dist/parallel/plan.d.ts.map +1 -1
  82. package/dist/parallel/plan.js +1 -6
  83. package/dist/parallel/plan.js.map +1 -1
  84. package/dist/parallel/run-lanes.d.ts +4 -18
  85. package/dist/parallel/run-lanes.d.ts.map +1 -1
  86. package/dist/parallel/run-lanes.js +1 -12
  87. package/dist/parallel/run-lanes.js.map +1 -1
  88. package/dist/screenshot.d.ts +1 -12
  89. package/dist/screenshot.d.ts.map +1 -1
  90. package/dist/screenshot.js +1 -12
  91. package/dist/screenshot.js.map +1 -1
  92. package/dist/still.d.ts +17 -74
  93. package/dist/still.d.ts.map +1 -1
  94. package/dist/still.js +13 -50
  95. package/dist/still.js.map +1 -1
  96. package/dist/ticker.d.ts +10 -39
  97. package/dist/ticker.d.ts.map +1 -1
  98. package/dist/ticker.js +13 -45
  99. package/dist/ticker.js.map +1 -1
  100. package/package.json +4 -4
  101. package/dist/browser/chunks/chunk-F3AZKPHU.js +0 -2
  102. package/dist/browser/chunks/chunk-F3AZKPHU.js.map +0 -7
package/dist/engine.js CHANGED
@@ -7,23 +7,12 @@ import { exportVideo as exportVideoFile } from "./exporter";
7
7
  import { exportAudio } from "./export-audio";
8
8
  import { isAudioFormat } from "./formats";
9
9
  import { StillRenderer } from "./still";
10
- /**
11
- * The browser's {@link Exporter}: WebCodecs + mediabunny for video, the
12
- * browser's own image codecs for a still.
13
- *
14
- * **It does not reuse a session's storage adapter, and that is deliberate.** An
15
- * adapter's viewport clamps the resolution images decode at — `StorageAdapter`
16
- * documents that it has no setter for exactly this reason — so handing an export
17
- * the preview's adapter would paint a 2× render from decodes sized for 1×, and
18
- * the result would be soft in a way nothing reports. What is shared is the
19
- * engine's renderer backend, the same one its sessions draw with.
20
- */
10
+ /** The browser's {@link Exporter}: WebCodecs + mediabunny for video, the browser's image codecs for a still. **It deliberately does not reuse a session's storage adapter**: its viewport clamps decode resolution, so a 2× export from the preview's adapter would be soft in a way nothing reports. What is shared is the engine's renderer backend. */
21
11
  class WebExporter {
22
12
  backend;
23
13
  defaults;
24
14
  still = null;
25
15
  stillRegistry = null;
26
- /** Settles once every still asked for so far has been encoded. */
27
16
  stillQueue = Promise.resolve();
28
17
  constructor(backend, defaults) {
29
18
  this.backend = backend;
@@ -66,11 +55,7 @@ class WebExporter {
66
55
  rendererWasmUrl: this.defaults.rendererWasmUrl,
67
56
  });
68
57
  }
69
- /**
70
- * Queued, rather than a renderer per call: the one renderer is what keeps a
71
- * GPU surface and the decode cache warm between stills, and its draw and the
72
- * encode of it are two steps another call's draw would land between.
73
- */
58
+ /** Queued rather than a renderer per call: the one renderer keeps the GPU surface and decode cache warm, and another call's draw would land between a draw and its encode. */
74
59
  exportStill(request) {
75
60
  const still = this.stillQueue.then(() => this.drawStill(request));
76
61
  this.stillQueue = still.catch(() => undefined);
@@ -93,11 +78,7 @@ class WebExporter {
93
78
  });
94
79
  return { bytes, frame: drawn.frame, totalFrames: drawn.totalFrames };
95
80
  }
96
- /**
97
- * One `StillRenderer`, reused across calls and re-viewported when the ask
98
- * changes — `setViewport` is a no-op when the size already matches, and a
99
- * full reset when it does not, which is the same trade the class documents.
100
- */
81
+ /** One `StillRenderer`, reused and re-viewported when the ask changes (`setViewport` is a no-op at the same size, a full reset otherwise). */
101
82
  renderer(request) {
102
83
  const { project, registry } = request;
103
84
  if (project.viewport === undefined || project.fps === undefined) {
@@ -119,20 +100,15 @@ class WebExporter {
119
100
  return this.still;
120
101
  }
121
102
  }
122
- /** `ExportStillRequest.frame` in the shape `StillRenderer.render` accepts. */
123
103
  function frameOption(frame) {
124
104
  if (frame.kind === "frame")
125
105
  return { frame: frame.frame };
126
106
  return { frame: frame.kind };
127
107
  }
128
108
  /**
129
- * An engine backed by the browser: WebGPU surfaces, Web Audio, WebCodecs.
130
- * Rejects with `WebGpuUnavailableError` where this browser has no WebGPU adapter.
131
- *
132
- * Async because the renderer is a wasm module and every seam below needs it. Await
133
- * once, at app start, and share the result — the caches underneath (registered
134
- * fonts, decoded images, shaped paragraphs) are the point of keeping one engine
135
- * rather than one per canvas.
109
+ * An engine backed by the browser: WebGPU surfaces, Web Audio, WebCodecs. Rejects with `WebGpuUnavailableError` where
110
+ * there is no WebGPU adapter. Async because the renderer is a wasm module; await once at app start and share the
111
+ * result, since the caches underneath (fonts, decoded images, shaped paragraphs) are the point of one engine.
136
112
  *
137
113
  * ```ts
138
114
  * const engine = await createBrowserEngine({ nodes: { pulseRing: PulseRing } });
@@ -142,20 +118,14 @@ function frameOption(frame) {
142
118
  */
143
119
  export async function createBrowserEngine(options = {}) {
144
120
  const rawNodes = options.nodes;
145
- // `Array.isArray` doesn't narrow a `readonly T[] | U` union cleanly against
146
- // its `arg is any[]` (mutable) predicate — the `.filter` predicate below
147
- // already guarantees no string survives, so the cast is just recovering
148
- // what the runtime check already proved.
121
+ // `Array.isArray` doesn't narrow the readonly union against its mutable predicate; the `.filter` below already excludes strings.
149
122
  const classNodes = (Array.isArray(rawNodes)
150
123
  ? rawNodes.filter((n) => typeof n !== "string")
151
124
  : rawNodes);
152
125
  const sourceNodes = Array.isArray(rawNodes)
153
126
  ? rawNodes.filter((n) => typeof n === "string")
154
127
  : [];
155
- // Cheap — see dynamic-nodes.ts: no WASM import happens here, only on
156
- // `compile`'s first actual call. Attached unconditionally so a later
157
- // `engine.registerNode(source)` works even when `nodes` carried no
158
- // string at boot.
128
+ // Cheap: no WASM import until `compile`'s first call. Attached unconditionally so a later `engine.registerNode(source)` works even when `nodes` held no string.
159
129
  const dynamicNodes = resolveDynamicNodes(options.dynamicNodes, options.compilerWasmUrl);
160
130
  const renderer = await loadRenderer(options);
161
131
  const exporter = new WebExporter(renderer, { video: options.video, audio: options.audio, rendererWasmUrl: options.rendererWasmUrl });
@@ -167,10 +137,7 @@ export async function createBrowserEngine(options = {}) {
167
137
  return new WebAudioSink();
168
138
  },
169
139
  createTicker(fps, audioDevice) {
170
- // Shares the device's own `AudioContext`: two independent timebases
171
- // in one session drift against each other, and sound is the one that
172
- // cannot be nudged back. A getter, so neither creates it before it
173
- // is needed (the first play, or the first sound to decode).
140
+ // Shares the device's own `AudioContext` (two timebases in one session drift, and sound cannot be nudged back). A getter, so neither creates it before needed.
174
141
  const sink = audioDevice;
175
142
  return new WebTicker({ context: () => sink.getContext(), fps });
176
143
  },
@@ -184,8 +151,7 @@ export async function createBrowserEngine(options = {}) {
184
151
  };
185
152
  const engine = new Engine(platform, { ...options, nodes: classNodes, dynamicNodes });
186
153
  for (const source of sourceNodes) {
187
- // Sequential — one script's error shouldn't mask another's, and
188
- // registration order should match array order for determinism.
154
+ // Sequential: one script's error shouldn't mask another's, and registration order should match array order.
189
155
  await engine.registerNode(source);
190
156
  }
191
157
  return engine;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AudioSink,\n Engine,\n EngineOptions,\n EnginePlatform,\n EngineRenderContext,\n Exporter,\n ExportStillRequest,\n ExportVideoRequest,\n ExportedStill,\n Registry,\n Ticker,\n MeasureContext2D,\n PlatformDeps,\n StorageAdapter,\n type DynamicNodeConfig,\n type NodeConstructor,\n type NodeTypeMap,\n} from \"@motionscript/core\";\n\nimport type { WgpuStorageAdapter } from \"@motionscript/renderer\";\nimport { loadRenderer, type RendererWasmOption } from \"./renderer\";\nimport { resolveDynamicNodes } from \"./dynamic-nodes\";\nimport { WebAudioSink } from \"./audio/player\";\nimport { WebTicker } from \"./ticker\";\nimport { exportVideo as exportVideoFile, type AudioEncoderOptions, type VideoEncoderOptions } from \"./exporter\";\nimport { exportAudio } from \"./export-audio\";\nimport { isAudioFormat, type ExportFormat } from \"./formats\";\nimport { StillRenderer } from \"./still\";\n\nexport interface BrowserEngineOptions extends Omit<EngineOptions, \"nodes\" | \"dynamicNodes\">, RendererWasmOption {\n /**\n * Node types any document opened here may name — components as an array\n * or a record naming each key outright, same as `EngineOptions`, plus a\n * TS source string in the **array** form only. A string default-exports a\n * component, whose `key` is its key — the record form takes no string, so\n * there is exactly one place a dynamic node's key comes from, not two that\n * could disagree.\n */\n nodes?: readonly (NodeConstructor | string)[] | NodeTypeMap;\n /**\n * Enables a source string in `nodes`, and `engine.registerNode(source)`\n * at any point afterward. Any field left unset falls back to `browser`'s\n * own default — `@motionscript/core/sdk` for `sdk`, a lazily-loaded\n * `esbuild-wasm` for `compile` — so this never needs to be passed at all\n * for the common case. `modules` has no default: only the host knows\n * which loaded packages a script it compiles may reach.\n */\n dynamicNodes?: Partial<DynamicNodeConfig>;\n /**\n * Where `esbuild-wasm`'s own `.wasm` binary is served — only read if the\n * default compiler is actually used.\n */\n compilerWasmUrl?: string;\n /** Default video encoder settings for `session.export()`. Overridable per call. */\n video?: VideoEncoderOptions;\n /** Default audio encoder settings for `session.export()`. Overridable per call. */\n audio?: AudioEncoderOptions;\n}\n\n/** What a session's frames are drawn with, and the storage and measurement it reads from. */\nexport interface BrowserRenderer<TStorage extends StorageAdapter = StorageAdapter> {\n createStorageAdapter(deps: PlatformDeps): TStorage;\n createRenderContext(storage: TStorage): BrowserRenderContext;\n createMeasureContext(storage: TStorage): MeasureContext2D;\n dispose?(): void;\n}\n\n/** A render context as this package drives it: an engine one, plus what exports and stills ask of it. */\nexport type BrowserRenderContext = EngineRenderContext & {\n /**\n * Settles once the surface `mount` began can draw. A backend whose surface\n * comes up asynchronously (a GPU device) must have it, or the first frame\n * draws onto nothing.\n */\n whenMounted?(): Promise<void>;\n /**\n * The frame last drawn, copied into a fresh 2D canvas, or `undefined` before\n * one was. What a still encodes; a WebGPU canvas is readable only in the task\n * that drew it, so a backend may draw it again here.\n */\n snapshotCanvas?(): HTMLCanvasElement | undefined;\n};\n\n/** What `session.export({ encode })` accepts in this environment. */\nexport interface BrowserEncodeOptions {\n /**\n * Defaults to `'mp4'`. An audio format (`'wav'`, `'mp3'`, `'m4a'`) renders no\n * frames and ignores `scale`, `frames`, `includeAudio`, `video` and `supersample`.\n */\n format?: ExportFormat;\n video?: VideoEncoderOptions;\n audio?: AudioEncoderOptions;\n supersample?: number;\n /** Set false to get the bytes back instead of triggering a browser download. */\n download?: boolean;\n filename?: string;\n}\n\n/**\n * The browser's {@link Exporter}: WebCodecs + mediabunny for video, the\n * browser's own image codecs for a still.\n *\n * **It does not reuse a session's storage adapter, and that is deliberate.** An\n * adapter's viewport clamps the resolution images decode at — `StorageAdapter`\n * documents that it has no setter for exactly this reason — so handing an export\n * the preview's adapter would paint a 2× render from decodes sized for 1×, and\n * the result would be soft in a way nothing reports. What is shared is the\n * engine's renderer backend, the same one its sessions draw with.\n */\nclass WebExporter implements Exporter {\n private still: StillRenderer | null = null;\n private stillRegistry: Registry | null = null;\n /** Settles once every still asked for so far has been encoded. */\n private stillQueue: Promise<unknown> = Promise.resolve();\n\n constructor(\n private readonly backend: BrowserRenderer,\n private readonly defaults: { video?: VideoEncoderOptions; audio?: AudioEncoderOptions } & RendererWasmOption,\n ) { }\n\n async exportVideo(request: ExportVideoRequest): Promise<Uint8Array | void> {\n const encode = (request.encode ?? {}) as BrowserEncodeOptions;\n if (encode.format && isAudioFormat(encode.format)) {\n return exportAudio({\n document: request.project,\n registry: request.registry,\n manifest: request.manifest,\n format: encode.format,\n audio: encode.audio ?? this.defaults.audio,\n filename: encode.filename,\n returnBytes: encode.download !== true,\n onProgress: request.onProgress,\n signal: request.signal,\n rendererWasmUrl: this.defaults.rendererWasmUrl,\n });\n }\n return exportVideoFile({\n document: request.project,\n registry: request.registry,\n scale: request.scale,\n manifest: request.manifest,\n includeAudio: request.includeAudio,\n frames: request.frames,\n format: encode.format,\n video: encode.video ?? this.defaults.video,\n audio: encode.audio ?? this.defaults.audio,\n supersample: encode.supersample,\n filename: encode.filename,\n // A `Session` asks for bytes; only an explicit `download: true` takes\n // the DOM anchor path this function offers a page.\n returnBytes: encode.download !== true,\n onProgress: request.onProgress,\n onIssue: request.onIssue,\n signal: request.signal,\n rendererWasmUrl: this.defaults.rendererWasmUrl,\n });\n }\n\n /**\n * Queued, rather than a renderer per call: the one renderer is what keeps a\n * GPU surface and the decode cache warm between stills, and its draw and the\n * encode of it are two steps another call's draw would land between.\n */\n exportStill(request: ExportStillRequest): Promise<ExportedStill> {\n const still = this.stillQueue.then(() => this.drawStill(request));\n this.stillQueue = still.catch(() => undefined);\n return still;\n }\n\n dispose(): void {\n this.still?.dispose();\n this.still = null;\n }\n\n private async drawStill(request: ExportStillRequest): Promise<ExportedStill> {\n const renderer = this.renderer(request);\n const drawn = await renderer.render(request.project, {\n scale: request.scale,\n onIssue: request.onIssue,\n ...frameOption(request.frame),\n });\n const bytes = await renderer.toBytes({\n format: request.format,\n quality: request.quality,\n });\n return { bytes, frame: drawn.frame, totalFrames: drawn.totalFrames };\n }\n\n /**\n * One `StillRenderer`, reused across calls and re-viewported when the ask\n * changes — `setViewport` is a no-op when the size already matches, and a\n * full reset when it does not, which is the same trade the class documents.\n */\n private renderer(request: ExportStillRequest): StillRenderer {\n const { project, registry } = request;\n if (project.viewport === undefined || project.fps === undefined) {\n throw new Error(\"exportStill takes a project whose fps and viewport are resolved — see Session.\");\n }\n // A renderer compiles against the registry it was built with.\n if (this.still && this.stillRegistry !== registry) this.dispose();\n this.still ??= new StillRenderer(this.backend, {\n viewport: project.viewport,\n fps: project.fps,\n manifest: request.manifest,\n registry,\n });\n this.stillRegistry = registry;\n this.still.setViewport(project.viewport);\n if (request.manifest) this.still.setManifest(request.manifest);\n return this.still;\n }\n}\n\n/** `ExportStillRequest.frame` in the shape `StillRenderer.render` accepts. */\nfunction frameOption(frame: ExportStillRequest[\"frame\"]): { frame?: number | \"first\" | \"last\" } {\n if (frame.kind === \"frame\") return { frame: frame.frame };\n return { frame: frame.kind };\n}\n\n/**\n * An engine backed by the browser: WebGPU surfaces, Web Audio, WebCodecs.\n * Rejects with `WebGpuUnavailableError` where this browser has no WebGPU adapter.\n *\n * Async because the renderer is a wasm module and every seam below needs it. Await\n * once, at app start, and share the result — the caches underneath (registered\n * fonts, decoded images, shaped paragraphs) are the point of keeping one engine\n * rather than one per canvas.\n *\n * ```ts\n * const engine = await createBrowserEngine({ nodes: { pulseRing: PulseRing } });\n * const session = engine.open({ document, target: canvasEl });\n * session.playback!.play();\n * ```\n */\nexport async function createBrowserEngine(\n options: BrowserEngineOptions = {},\n): Promise<Engine<WgpuStorageAdapter>> {\n const rawNodes = options.nodes;\n // `Array.isArray` doesn't narrow a `readonly T[] | U` union cleanly against\n // its `arg is any[]` (mutable) predicate — the `.filter` predicate below\n // already guarantees no string survives, so the cast is just recovering\n // what the runtime check already proved.\n const classNodes = (\n Array.isArray(rawNodes)\n ? rawNodes.filter((n): n is NodeConstructor => typeof n !== \"string\")\n : rawNodes\n ) as NodeTypeMap | readonly NodeConstructor[] | undefined;\n const sourceNodes = Array.isArray(rawNodes)\n ? rawNodes.filter((n): n is string => typeof n === \"string\")\n : [];\n // Cheap — see dynamic-nodes.ts: no WASM import happens here, only on\n // `compile`'s first actual call. Attached unconditionally so a later\n // `engine.registerNode(source)` works even when `nodes` carried no\n // string at boot.\n const dynamicNodes = resolveDynamicNodes(options.dynamicNodes, options.compilerWasmUrl);\n\n const renderer: BrowserRenderer<WgpuStorageAdapter> = await loadRenderer(options);\n const exporter = new WebExporter(renderer, { video: options.video, audio: options.audio, rendererWasmUrl: options.rendererWasmUrl });\n\n const platform: EnginePlatform<WgpuStorageAdapter> = {\n createStorageAdapter: (deps) => renderer.createStorageAdapter(deps),\n createRenderContext: (storage) => renderer.createRenderContext(storage),\n createMeasureContext: (storage) => renderer.createMeasureContext(storage),\n createAudioSink(): AudioSink {\n return new WebAudioSink();\n },\n createTicker(fps: number, audioDevice: AudioSink): Ticker {\n // Shares the device's own `AudioContext`: two independent timebases\n // in one session drift against each other, and sound is the one that\n // cannot be nudged back. A getter, so neither creates it before it\n // is needed (the first play, or the first sound to decode).\n const sink = audioDevice as WebAudioSink;\n return new WebTicker({ context: () => sink.getContext(), fps });\n },\n createExporter(): Exporter {\n return exporter;\n },\n dispose(): void {\n exporter.dispose();\n renderer.dispose?.();\n },\n };\n\n const engine = new Engine<WgpuStorageAdapter>(platform, { ...options, nodes: classNodes, dynamicNodes });\n for (const source of sourceNodes) {\n // Sequential — one script's error shouldn't mask another's, and\n // registration order should match array order for determinism.\n await engine.registerNode(source);\n }\n return engine;\n}\n"]}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AudioSink,\n Engine,\n EngineOptions,\n EnginePlatform,\n EngineRenderContext,\n Exporter,\n ExportStillRequest,\n ExportVideoRequest,\n ExportedStill,\n Registry,\n Ticker,\n MeasureContext2D,\n PlatformDeps,\n StorageAdapter,\n type DynamicNodeConfig,\n type NodeConstructor,\n type NodeTypeMap,\n} from \"@motionscript/core\";\n\nimport type { WgpuStorageAdapter } from \"@motionscript/renderer\";\nimport { loadRenderer, type RendererWasmOption } from \"./renderer\";\nimport { resolveDynamicNodes } from \"./dynamic-nodes\";\nimport { WebAudioSink } from \"./audio/player\";\nimport { WebTicker } from \"./ticker\";\nimport { exportVideo as exportVideoFile, type AudioEncoderOptions, type VideoEncoderOptions } from \"./exporter\";\nimport { exportAudio } from \"./export-audio\";\nimport { isAudioFormat, type ExportFormat } from \"./formats\";\nimport { StillRenderer } from \"./still\";\n\nexport interface BrowserEngineOptions extends Omit<EngineOptions, \"nodes\" | \"dynamicNodes\">, RendererWasmOption {\n /** Node types any document opened here may name: components as an array or a record, plus a TS source string in the **array** form only (a string default-exports a component whose `key` is its key, so a dynamic node's key has one source). */\n nodes?: readonly (NodeConstructor | string)[] | NodeTypeMap;\n /** Enables a source string in `nodes` and `engine.registerNode(source)`. Unset fields fall back to `browser`'s defaults (`@motionscript/core/sdk`, a lazy `esbuild-wasm`); `modules` has none, since only the host knows which packages a script may reach. */\n dynamicNodes?: Partial<DynamicNodeConfig>;\n /** Where `esbuild-wasm`'s `.wasm` is served; only read if the default compiler is used. */\n compilerWasmUrl?: string;\n /** Default video encoder settings for `session.export()`. Overridable per call. */\n video?: VideoEncoderOptions;\n /** Default audio encoder settings for `session.export()`. Overridable per call. */\n audio?: AudioEncoderOptions;\n}\n\n/** What a session's frames are drawn with, and the storage and measurement it reads from. */\nexport interface BrowserRenderer<TStorage extends StorageAdapter = StorageAdapter> {\n createStorageAdapter(deps: PlatformDeps): TStorage;\n createRenderContext(storage: TStorage): BrowserRenderContext;\n createMeasureContext(storage: TStorage): MeasureContext2D;\n dispose?(): void;\n}\n\n/** A render context as this package drives it: an engine one, plus what exports and stills ask of it. */\nexport type BrowserRenderContext = EngineRenderContext & {\n /** Settles once the surface `mount` began can draw; a backend with an asynchronous surface (a GPU device) must have it or the first frame draws onto nothing. */\n whenMounted?(): Promise<void>;\n /** The frame last drawn, copied into a fresh 2D canvas (what a still encodes), or `undefined` before one was. A WebGPU canvas is readable only in the task that drew it, so a backend may draw again here. */\n snapshotCanvas?(): HTMLCanvasElement | undefined;\n};\n\nexport interface BrowserEncodeOptions {\n /** Defaults to `'mp4'`. An audio format (`'wav'`, `'mp3'`, `'m4a'`) renders no frames and ignores `scale`, `frames`, `includeAudio`, `video` and `supersample`. */\n format?: ExportFormat;\n video?: VideoEncoderOptions;\n audio?: AudioEncoderOptions;\n supersample?: number;\n /** Set false to get the bytes back instead of triggering a browser download. */\n download?: boolean;\n filename?: string;\n}\n\n/** The browser's {@link Exporter}: WebCodecs + mediabunny for video, the browser's image codecs for a still. **It deliberately does not reuse a session's storage adapter**: its viewport clamps decode resolution, so a 2× export from the preview's adapter would be soft in a way nothing reports. What is shared is the engine's renderer backend. */\nclass WebExporter implements Exporter {\n private still: StillRenderer | null = null;\n private stillRegistry: Registry | null = null;\n private stillQueue: Promise<unknown> = Promise.resolve();\n\n constructor(\n private readonly backend: BrowserRenderer,\n private readonly defaults: { video?: VideoEncoderOptions; audio?: AudioEncoderOptions } & RendererWasmOption,\n ) { }\n\n async exportVideo(request: ExportVideoRequest): Promise<Uint8Array | void> {\n const encode = (request.encode ?? {}) as BrowserEncodeOptions;\n if (encode.format && isAudioFormat(encode.format)) {\n return exportAudio({\n document: request.project,\n registry: request.registry,\n manifest: request.manifest,\n format: encode.format,\n audio: encode.audio ?? this.defaults.audio,\n filename: encode.filename,\n returnBytes: encode.download !== true,\n onProgress: request.onProgress,\n signal: request.signal,\n rendererWasmUrl: this.defaults.rendererWasmUrl,\n });\n }\n return exportVideoFile({\n document: request.project,\n registry: request.registry,\n scale: request.scale,\n manifest: request.manifest,\n includeAudio: request.includeAudio,\n frames: request.frames,\n format: encode.format,\n video: encode.video ?? this.defaults.video,\n audio: encode.audio ?? this.defaults.audio,\n supersample: encode.supersample,\n filename: encode.filename,\n // A `Session` asks for bytes; only an explicit `download: true` takes\n // the DOM anchor path this function offers a page.\n returnBytes: encode.download !== true,\n onProgress: request.onProgress,\n onIssue: request.onIssue,\n signal: request.signal,\n rendererWasmUrl: this.defaults.rendererWasmUrl,\n });\n }\n\n /** Queued rather than a renderer per call: the one renderer keeps the GPU surface and decode cache warm, and another call's draw would land between a draw and its encode. */\n exportStill(request: ExportStillRequest): Promise<ExportedStill> {\n const still = this.stillQueue.then(() => this.drawStill(request));\n this.stillQueue = still.catch(() => undefined);\n return still;\n }\n\n dispose(): void {\n this.still?.dispose();\n this.still = null;\n }\n\n private async drawStill(request: ExportStillRequest): Promise<ExportedStill> {\n const renderer = this.renderer(request);\n const drawn = await renderer.render(request.project, {\n scale: request.scale,\n onIssue: request.onIssue,\n ...frameOption(request.frame),\n });\n const bytes = await renderer.toBytes({\n format: request.format,\n quality: request.quality,\n });\n return { bytes, frame: drawn.frame, totalFrames: drawn.totalFrames };\n }\n\n /** One `StillRenderer`, reused and re-viewported when the ask changes (`setViewport` is a no-op at the same size, a full reset otherwise). */\n private renderer(request: ExportStillRequest): StillRenderer {\n const { project, registry } = request;\n if (project.viewport === undefined || project.fps === undefined) {\n throw new Error(\"exportStill takes a project whose fps and viewport are resolved — see Session.\");\n }\n // A renderer compiles against the registry it was built with.\n if (this.still && this.stillRegistry !== registry) this.dispose();\n this.still ??= new StillRenderer(this.backend, {\n viewport: project.viewport,\n fps: project.fps,\n manifest: request.manifest,\n registry,\n });\n this.stillRegistry = registry;\n this.still.setViewport(project.viewport);\n if (request.manifest) this.still.setManifest(request.manifest);\n return this.still;\n }\n}\n\nfunction frameOption(frame: ExportStillRequest[\"frame\"]): { frame?: number | \"first\" | \"last\" } {\n if (frame.kind === \"frame\") return { frame: frame.frame };\n return { frame: frame.kind };\n}\n\n/**\n * An engine backed by the browser: WebGPU surfaces, Web Audio, WebCodecs. Rejects with `WebGpuUnavailableError` where\n * there is no WebGPU adapter. Async because the renderer is a wasm module; await once at app start and share the\n * result, since the caches underneath (fonts, decoded images, shaped paragraphs) are the point of one engine.\n *\n * ```ts\n * const engine = await createBrowserEngine({ nodes: { pulseRing: PulseRing } });\n * const session = engine.open({ document, target: canvasEl });\n * session.playback!.play();\n * ```\n */\nexport async function createBrowserEngine(\n options: BrowserEngineOptions = {},\n): Promise<Engine<WgpuStorageAdapter>> {\n const rawNodes = options.nodes;\n // `Array.isArray` doesn't narrow the readonly union against its mutable predicate; the `.filter` below already excludes strings.\n const classNodes = (\n Array.isArray(rawNodes)\n ? rawNodes.filter((n): n is NodeConstructor => typeof n !== \"string\")\n : rawNodes\n ) as NodeTypeMap | readonly NodeConstructor[] | undefined;\n const sourceNodes = Array.isArray(rawNodes)\n ? rawNodes.filter((n): n is string => typeof n === \"string\")\n : [];\n // Cheap: no WASM import until `compile`'s first call. Attached unconditionally so a later `engine.registerNode(source)` works even when `nodes` held no string.\n const dynamicNodes = resolveDynamicNodes(options.dynamicNodes, options.compilerWasmUrl);\n\n const renderer: BrowserRenderer<WgpuStorageAdapter> = await loadRenderer(options);\n const exporter = new WebExporter(renderer, { video: options.video, audio: options.audio, rendererWasmUrl: options.rendererWasmUrl });\n\n const platform: EnginePlatform<WgpuStorageAdapter> = {\n createStorageAdapter: (deps) => renderer.createStorageAdapter(deps),\n createRenderContext: (storage) => renderer.createRenderContext(storage),\n createMeasureContext: (storage) => renderer.createMeasureContext(storage),\n createAudioSink(): AudioSink {\n return new WebAudioSink();\n },\n createTicker(fps: number, audioDevice: AudioSink): Ticker {\n // Shares the device's own `AudioContext` (two timebases in one session drift, and sound cannot be nudged back). A getter, so neither creates it before needed.\n const sink = audioDevice as WebAudioSink;\n return new WebTicker({ context: () => sink.getContext(), fps });\n },\n createExporter(): Exporter {\n return exporter;\n },\n dispose(): void {\n exporter.dispose();\n renderer.dispose?.();\n },\n };\n\n const engine = new Engine<WgpuStorageAdapter>(platform, { ...options, nodes: classNodes, dynamicNodes });\n for (const source of sourceNodes) {\n // Sequential: one script's error shouldn't mask another's, and registration order should match array order.\n await engine.registerNode(source);\n }\n return engine;\n}\n"]}
@@ -26,11 +26,6 @@ export declare class NoAudioError extends Error {
26
26
  readonly name = "NoAudioError";
27
27
  constructor();
28
28
  }
29
- /**
30
- * Mix the timeline's audio and encode it alone: WAV, MP3 or M4A (AAC). Nothing
31
- * is drawn, so no frame is rendered and no GPU surface is made.
32
- *
33
- * @throws {NoAudioError} when nothing on the timeline plays, rather than writing a silent file.
34
- */
29
+ /** Mixes the timeline's audio and encodes it alone (WAV, MP3 or M4A/AAC); nothing is drawn, so no frame is rendered and no GPU surface made. @throws {NoAudioError} when nothing plays, rather than writing a silent file. */
35
30
  export declare function exportAudio(params: ExportAudioParams): Promise<Uint8Array | void>;
36
31
  //# sourceMappingURL=export-audio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"export-audio.d.ts","sourceRoot":"","sources":["../src/export-audio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAI3G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAoD,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG/F,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG;IACjD,yEAAyE;IACzE,QAAQ,EAAE,eAAe,GAAG,cAAc,CAAC;IAC3C,oFAAoF;IACpF,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mHAAmH;IACnH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,mDAAmD;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,qFAAqF;AACrF,qBAAa,YAAa,SAAQ,KAAK;IACnC,SAAkB,IAAI,kBAAkB;;CAK3C;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAqCvF"}
1
+ {"version":3,"file":"export-audio.d.ts","sourceRoot":"","sources":["../src/export-audio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAI3G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAoD,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG/F,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG;IACjD,yEAAyE;IACzE,QAAQ,EAAE,eAAe,GAAG,cAAc,CAAC;IAC3C,oFAAoF;IACpF,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mHAAmH;IACnH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,mDAAmD;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,qFAAqF;AACrF,qBAAa,YAAa,SAAQ,KAAK;IACnC,SAAkB,IAAI,kBAAkB;;CAK3C;AAED,8NAA8N;AAC9N,wBAAsB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAqCvF"}
@@ -9,12 +9,7 @@ export class NoAudioError extends Error {
9
9
  super("The timeline has no audio to export.");
10
10
  }
11
11
  }
12
- /**
13
- * Mix the timeline's audio and encode it alone: WAV, MP3 or M4A (AAC). Nothing
14
- * is drawn, so no frame is rendered and no GPU surface is made.
15
- *
16
- * @throws {NoAudioError} when nothing on the timeline plays, rather than writing a silent file.
17
- */
12
+ /** Mixes the timeline's audio and encodes it alone (WAV, MP3 or M4A/AAC); nothing is drawn, so no frame is rendered and no GPU surface made. @throws {NoAudioError} when nothing plays, rather than writing a silent file. */
18
13
  export async function exportAudio(params) {
19
14
  const { format = "wav", audio = {}, onProgress, signal, returnBytes = false } = params;
20
15
  const spec = formatSpec(format);
@@ -1 +1 @@
1
- {"version":3,"file":"export-audio.js","sourceRoot":"","sources":["../src/export-audio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,UAAU,EAAoB,MAAM,WAAW,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAsBxD,qFAAqF;AACrF,MAAM,OAAO,YAAa,SAAQ,KAAK;IACjB,IAAI,GAAG,cAAc,CAAC;IAExC;QACI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAClD,CAAC;CACJ;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAyB;IACvD,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,KAAK,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC;IACvF,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QAAE,MAAM,IAAI,UAAU,CAAC,8BAA8B,MAAM,uCAAuC,CAAC,CAAC;IAC7H,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,yEAAyE;IACzE,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAEjC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC;QACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,eAAe,EAAE,MAAM,CAAC,eAAe;KAC1C,CAAC,CAAC;IACH,IAAI,KAAK,KAAK,IAAI;QAAE,MAAM,IAAI,YAAY,EAAE,CAAC;IAC7C,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;IACxB,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/D,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAEhB,OAAO,OAAO,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QAC1C,WAAW;QACX,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,UAAU,IAAI,CAAC,SAAS,EAAE;QACvD,QAAQ,EAAE,IAAI,CAAC,QAAQ;KAC1B,CAAC,CAAC;AACP,CAAC","sourcesContent":["import type { AssetManifest, ProjectDocument, Registry, Size2D, VisualDocument } from \"@motionscript/core\";\nimport { BufferTarget, Output } from \"mediabunny\";\n\nimport { deliver } from \"./deliver\";\nimport type { RendererWasmOption } from \"./renderer\";\nimport type { AudioEncoderOptions, ExportProgressCallback } from \"./exporter\";\nimport { audioTrackSource, ensureAudioEncoder, formatSpec, type AudioFormat } from \"./formats\";\nimport { mixTimelineAudio } from \"./mix-timeline-audio\";\n\nexport type ExportAudioParams = RendererWasmOption & {\n /** A project, or a lone still or composition as the one track of one. */\n document: ProjectDocument | VisualDocument;\n /** The vocabulary its clips compile against. Defaults to what the library ships. */\n registry?: Registry;\n /** Discovery lays clips out at this size and rate; 1920×1080 at 60 fps when neither the document nor this says. */\n viewport?: Size2D;\n fps?: number;\n manifest?: AssetManifest;\n /** Defaults to `'wav'`, which needs no encoder. */\n format?: AudioFormat;\n audio?: AudioEncoderOptions;\n /** Defaults to `export.<extension>`. */\n filename?: string;\n onProgress?: ExportProgressCallback;\n signal?: AbortSignal;\n /** When true, the encoded bytes are returned instead of triggering a browser download. */\n returnBytes?: boolean;\n};\n\n/** The timeline schedules no sound, so an audio-only export has nothing to write. */\nexport class NoAudioError extends Error {\n override readonly name = \"NoAudioError\";\n\n constructor() {\n super(\"The timeline has no audio to export.\");\n }\n}\n\n/**\n * Mix the timeline's audio and encode it alone: WAV, MP3 or M4A (AAC). Nothing\n * is drawn, so no frame is rendered and no GPU surface is made.\n *\n * @throws {NoAudioError} when nothing on the timeline plays, rather than writing a silent file.\n */\nexport async function exportAudio(params: ExportAudioParams): Promise<Uint8Array | void> {\n const { format = \"wav\", audio = {}, onProgress, signal, returnBytes = false } = params;\n const spec = formatSpec(format);\n if (spec.kind !== \"audio\") throw new RangeError(`exportAudio writes audio; \"${format}\" is video, which exportVideo writes.`);\n signal?.throwIfAborted();\n // Before the mix, so a browser that cannot encode the format fails fast.\n await ensureAudioEncoder(format);\n\n const mixed = await mixTimelineAudio({\n document: params.document,\n registry: params.registry,\n viewport: params.viewport,\n fps: params.fps,\n manifest: params.manifest,\n sampleRate: audio.sampleRate,\n rendererWasmUrl: params.rendererWasmUrl,\n });\n if (mixed === null) throw new NoAudioError();\n signal?.throwIfAborted();\n onProgress?.(0.5);\n\n const target = new BufferTarget();\n const output = new Output({ format: spec.container(), target });\n const source = audioTrackSource(format, audio.bitrate);\n output.addAudioTrack(source);\n await output.start();\n await source.add(mixed);\n source.close();\n await output.finalize();\n if (!target.buffer) throw new Error(\"Export produced no data\");\n onProgress?.(1);\n\n return deliver(new Uint8Array(target.buffer), {\n returnBytes,\n filename: params.filename ?? `export.${spec.extension}`,\n mimeType: spec.mimeType,\n });\n}\n"]}
1
+ {"version":3,"file":"export-audio.js","sourceRoot":"","sources":["../src/export-audio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,UAAU,EAAoB,MAAM,WAAW,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAsBxD,qFAAqF;AACrF,MAAM,OAAO,YAAa,SAAQ,KAAK;IACjB,IAAI,GAAG,cAAc,CAAC;IAExC;QACI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAClD,CAAC;CACJ;AAED,8NAA8N;AAC9N,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAyB;IACvD,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,KAAK,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC;IACvF,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QAAE,MAAM,IAAI,UAAU,CAAC,8BAA8B,MAAM,uCAAuC,CAAC,CAAC;IAC7H,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,yEAAyE;IACzE,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAEjC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC;QACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,eAAe,EAAE,MAAM,CAAC,eAAe;KAC1C,CAAC,CAAC;IACH,IAAI,KAAK,KAAK,IAAI;QAAE,MAAM,IAAI,YAAY,EAAE,CAAC;IAC7C,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;IACxB,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/D,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAEhB,OAAO,OAAO,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QAC1C,WAAW;QACX,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,UAAU,IAAI,CAAC,SAAS,EAAE;QACvD,QAAQ,EAAE,IAAI,CAAC,QAAQ;KAC1B,CAAC,CAAC;AACP,CAAC","sourcesContent":["import type { AssetManifest, ProjectDocument, Registry, Size2D, VisualDocument } from \"@motionscript/core\";\nimport { BufferTarget, Output } from \"mediabunny\";\n\nimport { deliver } from \"./deliver\";\nimport type { RendererWasmOption } from \"./renderer\";\nimport type { AudioEncoderOptions, ExportProgressCallback } from \"./exporter\";\nimport { audioTrackSource, ensureAudioEncoder, formatSpec, type AudioFormat } from \"./formats\";\nimport { mixTimelineAudio } from \"./mix-timeline-audio\";\n\nexport type ExportAudioParams = RendererWasmOption & {\n /** A project, or a lone still or composition as the one track of one. */\n document: ProjectDocument | VisualDocument;\n /** The vocabulary its clips compile against. Defaults to what the library ships. */\n registry?: Registry;\n /** Discovery lays clips out at this size and rate; 1920×1080 at 60 fps when neither the document nor this says. */\n viewport?: Size2D;\n fps?: number;\n manifest?: AssetManifest;\n /** Defaults to `'wav'`, which needs no encoder. */\n format?: AudioFormat;\n audio?: AudioEncoderOptions;\n /** Defaults to `export.<extension>`. */\n filename?: string;\n onProgress?: ExportProgressCallback;\n signal?: AbortSignal;\n /** When true, the encoded bytes are returned instead of triggering a browser download. */\n returnBytes?: boolean;\n};\n\n/** The timeline schedules no sound, so an audio-only export has nothing to write. */\nexport class NoAudioError extends Error {\n override readonly name = \"NoAudioError\";\n\n constructor() {\n super(\"The timeline has no audio to export.\");\n }\n}\n\n/** Mixes the timeline's audio and encodes it alone (WAV, MP3 or M4A/AAC); nothing is drawn, so no frame is rendered and no GPU surface made. @throws {NoAudioError} when nothing plays, rather than writing a silent file. */\nexport async function exportAudio(params: ExportAudioParams): Promise<Uint8Array | void> {\n const { format = \"wav\", audio = {}, onProgress, signal, returnBytes = false } = params;\n const spec = formatSpec(format);\n if (spec.kind !== \"audio\") throw new RangeError(`exportAudio writes audio; \"${format}\" is video, which exportVideo writes.`);\n signal?.throwIfAborted();\n // Before the mix, so a browser that cannot encode the format fails fast.\n await ensureAudioEncoder(format);\n\n const mixed = await mixTimelineAudio({\n document: params.document,\n registry: params.registry,\n viewport: params.viewport,\n fps: params.fps,\n manifest: params.manifest,\n sampleRate: audio.sampleRate,\n rendererWasmUrl: params.rendererWasmUrl,\n });\n if (mixed === null) throw new NoAudioError();\n signal?.throwIfAborted();\n onProgress?.(0.5);\n\n const target = new BufferTarget();\n const output = new Output({ format: spec.container(), target });\n const source = audioTrackSource(format, audio.bitrate);\n output.addAudioTrack(source);\n await output.start();\n await source.add(mixed);\n source.close();\n await output.finalize();\n if (!target.buffer) throw new Error(\"Export produced no data\");\n onProgress?.(1);\n\n return deliver(new Uint8Array(target.buffer), {\n returnBytes,\n filename: params.filename ?? `export.${spec.extension}`,\n mimeType: spec.mimeType,\n });\n}\n"]}
@@ -6,91 +6,32 @@ import { type RendererWasmOption } from "./renderer";
6
6
  import { type VideoFormat } from "./formats";
7
7
  /** Reports export progress in [0, 1]; video encoding occupies most of the range, audio mixing/finalize the tail. */
8
8
  export type ExportProgressCallback = (progress: number) => void;
9
- /**
10
- * How the video track is encoded.
11
- *
12
- * Every field is a straight pass-through to mediabunny's `VideoEncodingConfig`,
13
- * defaulted here rather than there so an export has one obvious place to look.
14
- */
9
+ /** How the video track is encoded; fields pass through to mediabunny's `VideoEncodingConfig`, defaulted here. */
15
10
  export type VideoEncoderOptions = {
16
11
  /**
17
- * Which codec the video track is encoded with. Defaults to the format's own:
18
- * `'avc'` (H.264) for MP4, which every player, editor and upload target
19
- * accepts, and `'vp9'` for WebM.
20
- *
21
- * `'hevc'` and `'av1'` reconstruct sharp edges far better at the same
22
- * bitrate, which is what a listing of syntax-highlighted code or a hairline
23
- * stroke is made of — worth reaching for when the file is going somewhere
24
- * that decodes them. Both are still 4:2:0, so they narrow the gap rather
25
- * than close it. Availability depends on the platform's encoders; an
26
- * unsupported choice, or one the container cannot hold (`'avc'` in WebM),
27
- * falls back to the format's default rather than failing the export.
12
+ * Defaults to the format's own: `'avc'` for MP4, `'vp9'` for WebM. `'hevc'`/`'av1'` keep hairline strokes and
13
+ * code listings sharper at the same bitrate (still 4:2:0). An unsupported choice, or one the container cannot
14
+ * hold, falls back to the default.
28
15
  */
29
16
  codec?: 'avc' | 'hevc' | 'av1' | 'vp9' | 'vp8';
30
17
  /**
31
- * Which encoder implementation WebCodecs should prefer.
32
- *
33
- * Defaults to `'no-preference'`, which lets each platform use its own
34
- * hardware encoder (VideoToolbox on macOS, Media Foundation/NVENC on
35
- * Windows, VA-API on Linux). That is typically several times faster than the
36
- * software path *and* it is the only configuration in which this sink's
37
- * zero-readback design actually holds: a software encoder needs the pixels
38
- * on the CPU, so it forces a full GPU→CPU copy of every frame that a
39
- * hardware encoder reads directly off the canvas.
40
- *
41
- * Pass `'prefer-software'` when byte-identical output across machines
42
- * matters more than speed — different hardware encoders tune quality and
43
- * colour differently at the same nominal bitrate, so the same settings do
44
- * not produce the same file.
18
+ * Defaults to `'no-preference'` (the platform's hardware encoder): several times faster, and the only setup where
19
+ * this sink's zero-readback design holds, since a software encoder forces a GPU->CPU copy of every frame.
20
+ * `'prefer-software'` when byte-identical output across machines matters more than speed.
45
21
  */
46
22
  hardwareAcceleration?: 'no-preference' | 'prefer-hardware' | 'prefer-software';
47
- /**
48
- * Target bitrate in bits per second, or one of mediabunny's subjective
49
- * `Quality` levels.
50
- *
51
- * Defaults to {@link motionGraphicsBitrate}, which is deliberately *not*
52
- * mediabunny's `QUALITY_VERY_HIGH`: that level is frame-rate blind, so a
53
- * 60 fps export got the same ~12 Mbps at 1080p as a 30 fps one and paid for
54
- * it with ringing along every glyph edge and banding across every gradient.
55
- * See that function for the reasoning.
56
- */
23
+ /** Bits per second or a mediabunny `Quality`. Defaults to {@link motionGraphicsBitrate}, not `QUALITY_VERY_HIGH`, which is frame-rate blind (ringing on glyph edges at 60 fps). */
57
24
  bitrate?: number | Quality;
58
25
  /** Defaults to mediabunny's `'variable'`. `'constant'` is the reproducible-output choice. */
59
26
  bitrateMode?: 'constant' | 'variable';
60
- /**
61
- * Seconds between key frames. Defaults to 1.
62
- *
63
- * Shorter than mediabunny's 2, because a frame's error is carried by every
64
- * inter frame that references it: on synthetic content, where a flat
65
- * background makes a shimmer obvious, a keyframe twice as often visibly
66
- * resets the drift. It also halves the seek granularity, which matters for a
67
- * clip an editor is going to scrub.
68
- */
27
+ /** Seconds between key frames (default 1). Shorter than mediabunny's 2 because inter frames carry a frame's error, so flat synthetic backgrounds shimmer less; it also halves seek granularity. */
69
28
  keyFrameInterval?: number;
70
- /**
71
- * WebCodecs performance/quality trade-off. Defaults to `'quality'`, which
72
- * also guarantees no frame is dropped — the only correct setting for a file
73
- * being written rather than streamed.
74
- */
29
+ /** Defaults to `'quality'`, which also guarantees no frame is dropped: the only correct setting for a file being written. */
75
30
  latencyMode?: 'quality' | 'realtime';
76
- /**
77
- * A hint about what the frames contain, per
78
- * [mst-content-hint](https://w3c.github.io/mst-content-hint/#video-content-hints).
79
- *
80
- * Defaults to `'detail'`: encoders that honour it bias towards preserving
81
- * sharp edges and fine texture over smoothing motion, which is what motion
82
- * graphics are. Ignored where it is not implemented.
83
- */
31
+ /** A [content hint](https://w3c.github.io/mst-content-hint/#video-content-hints). Defaults to `'detail'`: bias towards sharp edges and fine texture over smoothing motion. Ignored where unimplemented. */
84
32
  contentHint?: string;
85
33
  };
86
- /**
87
- * The default video bitrate for an export of this size and frame rate.
88
- *
89
- * Scaling with **both** axes is the point. mediabunny's `Quality` levels scale
90
- * with resolution only, so doubling the frame rate halved the bits available per
91
- * frame while leaving the number unchanged — which is exactly the configuration
92
- * that produced clean stills and a mushy video from the very same renderer.
93
- */
34
+ /** Default video bitrate scaled by **both** axes: mediabunny's `Quality` levels scale with resolution only, so doubling the frame rate halved the bits per frame (clean stills, mushy video). */
94
35
  export declare function motionGraphicsBitrate(width: number, height: number, fps: number): number;
95
36
  /** How the mixed audio track is encoded. */
96
37
  export type AudioEncoderOptions = {
@@ -115,10 +56,7 @@ export type ExportParams = RendererWasmOption & {
115
56
  manifest?: AssetManifest;
116
57
  /** Theme for a document that carries none of its own. */
117
58
  theme?: Theme;
118
- /**
119
- * Set false to produce a silent file — no audio track is added to the
120
- * container and the mix is skipped entirely. Defaults to true.
121
- */
59
+ /** Set false to produce a silent file: no audio track, mix skipped. Defaults to true. */
122
60
  includeAudio?: boolean;
123
61
  /** Video encoder settings; see {@link VideoEncoderOptions} for the defaults. */
124
62
  video?: VideoEncoderOptions;
@@ -139,50 +77,20 @@ export type ExportParams = RendererWasmOption & {
139
77
  */
140
78
  onIssue?: (issue: RenderIssue) => void;
141
79
  /**
142
- * Render each frame at this multiple of the output resolution and downsample
143
- * it before encoding. **Defaults to 2**; pass 1 to turn it off.
144
- *
145
- * The one lever that improves an export at a *fixed* output size. Every
146
- * codec a browser can encode is 4:2:0 — colour is stored at half resolution
147
- * on both axes, and no bitrate buys that back — so the colour fringing along
148
- * a saturated glyph or a hard edge is a property of the format, not of the
149
- * settings. Handing the encoder an already-downsampled frame does not undo
150
- * the subsampling, but it does mean every chroma sample averages four real
151
- * pixels instead of one, which is what removes most of the crawl on fine
152
- * detail and much of the banding on gradients.
153
- *
154
- * Measured against a correctly-sampled reference frame of a syntax-highlighted
155
- * listing, `2` lands 2.7 dB closer than a 1× encode — and 1.3 dB closer than
156
- * an *unencoded* 1× still, which is why it is the default despite costing
157
- * `supersample²` times the render work per frame plus a rescale. Pass 1 when
158
- * turnaround matters more than the file, and note that exporting at
159
- * `scale: 2` is cheaper than supersampling *and* better whenever the extra
160
- * resolution is wanted in the file itself.
161
- *
162
- * Clamped so the render surface stays inside {@link MAX_RENDER_AXIS}, since a
163
- * supersampled 4K export is already drawing 8K frames.
80
+ * Render each frame at this multiple of the output resolution and downsample before encoding (default 2; 1 turns
81
+ * it off). Every browser-encodable codec is 4:2:0, so chroma fringing on saturated edges is a property of the
82
+ * format; downsampling first makes each chroma sample average four real pixels (2 measured 2.7 dB closer to a
83
+ * reference than a 1x encode). Costs `supersample²` render work; `scale: 2` is cheaper and better when the
84
+ * resolution is wanted in the file. Clamped to {@link MAX_RENDER_AXIS}.
164
85
  */
165
86
  supersample?: number;
166
- /**
167
- * When true, the encoded bytes are returned instead of triggering a
168
- * browser download. Used by headless drivers (e.g. the CLI) that capture
169
- * the output themselves and write it to disk; leave unset for the
170
- * interactive player, which downloads via an `<a>` element.
171
- */
87
+ /** Return the encoded bytes instead of triggering a browser download (for headless drivers that write to disk). */
172
88
  returnBytes?: boolean;
173
89
  };
174
90
  /**
175
- * mediabunny/WebCodecs implementation of the frame sink, writing whichever
176
- * container `format` names.
177
- *
178
- * Wraps the very `<canvas>` the renderer draws into, so `addFrame` costs nothing but
179
- * a timestamp — WebCodecs pulls the pixels from the canvas itself, with no
180
- * GPU→CPU readback. That is why the seam signals a frame rather than passing one.
181
- *
182
- * The readback claim holds only while the encoder is a hardware one, which is
183
- * why {@link VideoEncoderOptions.hardwareAcceleration} defaults to letting the
184
- * platform choose: a software encoder has to be handed CPU pixels, so it drags
185
- * a full-frame copy off the GPU on every single frame.
91
+ * mediabunny/WebCodecs frame sink wrapping the very canvas the renderer draws into: `addFrame` costs only a timestamp
92
+ * because WebCodecs pulls pixels from the canvas with no GPU->CPU readback (hence the seam signals a frame rather
93
+ * than passing one). Holds only for a hardware encoder; a software one forces a full-frame copy every frame.
186
94
  */
187
95
  export declare class MediabunnyVideoSink implements VideoFrameSink<AudioBuffer> {
188
96
  private readonly format;
@@ -205,12 +113,7 @@ export declare class MediabunnyVideoSink implements VideoFrameSink<AudioBuffer>
205
113
  addAudio(mixed: AudioBuffer): Promise<void>;
206
114
  finalize(): Promise<Uint8Array>;
207
115
  }
208
- /**
209
- * Every encoder setting, decided. A split export pins one of these across its
210
- * segments, since `concatVideoSegments` refuses parts encoded differently. With
211
- * a numeric `bitrate` (see {@link plainVideoEncoding}) it is plain data and
212
- * crosses a process boundary.
213
- */
116
+ /** Every encoder setting, decided; a split export pins one across segments since `concatVideoSegments` refuses parts encoded differently. Plain data with a numeric `bitrate` (see {@link plainVideoEncoding}). */
214
117
  export interface ResolvedVideoEncoding {
215
118
  codec: VideoCodec;
216
119
  /** A `Quality` is left for the encoder to size, as an export always has. */
@@ -226,10 +129,7 @@ export declare function resolveVideoEncoding(video: VideoEncoderOptions | undefi
226
129
  width: number;
227
130
  height: number;
228
131
  }, fps: number): Promise<ResolvedVideoEncoding>;
229
- /**
230
- * The encoding with a `Quality` turned into the bits per second mediabunny would
231
- * give it at this size, since a class instance cannot cross a `MessagePort`.
232
- */
132
+ /** Turns a `Quality` into bits per second at this size, since a class instance cannot cross a `MessagePort`. */
233
133
  export declare function plainVideoEncoding(encoding: ResolvedVideoEncoding, output: {
234
134
  width: number;
235
135
  height: number;
@@ -246,19 +146,14 @@ export declare function exportGeometry(viewport: Size2D, scale: number, supersam
246
146
  renderScale: number;
247
147
  };
248
148
  /** A hidden canvas with a mounted render context, reusable across renders of one project. */
249
- export interface ExportSurface {
149
+ interface ExportSurface {
250
150
  canvas: HTMLCanvasElement;
251
151
  renderContext: BrowserRenderContext;
252
152
  storageAdapter: StorageAdapter;
253
153
  assetCatalog: ManifestAssetCatalog;
254
154
  dispose(): void;
255
155
  }
256
- /**
257
- * Open the canvas, renderer, storage and render context an export draws with,
258
- * resolving once the surface can draw (a frame drawn before an asynchronously
259
- * started surface is ready encodes blank). The canvas is a whole multiple of the
260
- * output, so the downsample is exact.
261
- */
156
+ /** Opens the canvas, renderer, storage and render context an export draws with, resolving once the surface can draw (a frame drawn earlier encodes blank). The canvas is a whole multiple of the output, so the downsample is exact. */
262
157
  export declare function openExportSurface(params: {
263
158
  canvasSize: {
264
159
  width: number;
@@ -268,15 +163,7 @@ export declare function openExportSurface(params: {
268
163
  fps: number;
269
164
  manifest: AssetManifest;
270
165
  } & RendererWasmOption): Promise<ExportSurface>;
271
- /**
272
- * Renders a document frame-by-frame to an offscreen canvas and muxes the result
273
- * into an MP4 or WebM via mediabunny.
274
- *
275
- * The frame loop itself — discovery, state evaluation, the warm-and-re-render retry
276
- * that keeps every frame accurate, audio scheduling, progress and cancellation —
277
- * lives in `renderTimeline` (frame-loop.ts). What this function
278
- * supplies is the browser-specific half: a canvas to draw into, a WebCodecs sink,
279
- * a Web Audio mixer, and the `<a download>` delivery.
280
- */
166
+ /** Renders a document frame by frame to an offscreen canvas and muxes it into MP4/WebM via mediabunny. The frame loop lives in `renderTimeline` (frame-loop.ts); this supplies the browser half: canvas, WebCodecs sink, Web Audio mixer, download. */
281
167
  export declare function exportVideo(params: ExportParams): Promise<Uint8Array | void>;
168
+ export {};
282
169
  //# sourceMappingURL=exporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"exporter.d.ts","sourceRoot":"","sources":["../src/exporter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exporter.d.ts","sourceRoot":"","sources":["../src/exporter.ts"],"names":[],"mappings":"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"}