@editframe/elements 0.33.0-beta → 0.34.6-beta

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 (251) hide show
  1. package/dist/EF_FRAMEGEN.js +5 -3
  2. package/dist/EF_FRAMEGEN.js.map +1 -1
  3. package/dist/_virtual/{_@oxc-project_runtime@0.94.0 → _@oxc-project_runtime@0.95.0}/helpers/decorate.js +1 -1
  4. package/dist/canvas/EFCanvas.d.ts +7 -4
  5. package/dist/canvas/EFCanvas.js +1 -1
  6. package/dist/canvas/EFCanvasItem.d.ts +4 -4
  7. package/dist/canvas/EFCanvasItem.js +1 -1
  8. package/dist/canvas/overlays/SelectionOverlay.d.ts +95 -0
  9. package/dist/canvas/overlays/SelectionOverlay.js +1 -1
  10. package/dist/canvas/selection/SelectionController.js +7 -11
  11. package/dist/canvas/selection/SelectionController.js.map +1 -1
  12. package/dist/elements/EFAudio.d.ts +25 -7
  13. package/dist/elements/EFAudio.js +31 -61
  14. package/dist/elements/EFAudio.js.map +1 -1
  15. package/dist/elements/EFCaptions.d.ts +65 -52
  16. package/dist/elements/EFCaptions.js +186 -400
  17. package/dist/elements/EFCaptions.js.map +1 -1
  18. package/dist/elements/EFImage.d.ts +34 -6
  19. package/dist/elements/EFImage.js +114 -79
  20. package/dist/elements/EFImage.js.map +1 -1
  21. package/dist/elements/EFMedia/AssetIdMediaEngine.js +17 -17
  22. package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
  23. package/dist/elements/EFMedia/AssetMediaEngine.js +41 -25
  24. package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
  25. package/dist/elements/EFMedia/BaseMediaEngine.js +4 -4
  26. package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
  27. package/dist/elements/EFMedia/BufferedSeekingInput.js +1 -1
  28. package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
  29. package/dist/elements/EFMedia/JitMediaEngine.js +31 -17
  30. package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
  31. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
  32. package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
  33. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +17 -9
  34. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
  35. package/dist/elements/EFMedia.d.ts +66 -20
  36. package/dist/elements/EFMedia.js +412 -30
  37. package/dist/elements/EFMedia.js.map +1 -1
  38. package/dist/elements/EFPanZoom.d.ts +4 -4
  39. package/dist/elements/EFPanZoom.js +1 -1
  40. package/dist/elements/EFSourceMixin.js +43 -15
  41. package/dist/elements/EFSourceMixin.js.map +1 -1
  42. package/dist/elements/EFSurface.d.ts +23 -10
  43. package/dist/elements/EFSurface.js +64 -22
  44. package/dist/elements/EFSurface.js.map +1 -1
  45. package/dist/elements/EFTemporal.d.ts +8 -2
  46. package/dist/elements/EFTemporal.js +42 -31
  47. package/dist/elements/EFTemporal.js.map +1 -1
  48. package/dist/elements/EFText.d.ts +5 -4
  49. package/dist/elements/EFText.js +11 -2
  50. package/dist/elements/EFText.js.map +1 -1
  51. package/dist/elements/EFTextSegment.d.ts +4 -4
  52. package/dist/elements/EFTextSegment.js +1 -1
  53. package/dist/elements/EFThumbnailStrip.d.ts +4 -4
  54. package/dist/elements/EFThumbnailStrip.js +1 -1
  55. package/dist/elements/EFTimegroup.d.ts +22 -8
  56. package/dist/elements/EFTimegroup.js +203 -115
  57. package/dist/elements/EFTimegroup.js.map +1 -1
  58. package/dist/elements/EFVideo.d.ts +57 -20
  59. package/dist/elements/EFVideo.js +324 -72
  60. package/dist/elements/EFVideo.js.map +1 -1
  61. package/dist/elements/EFWaveform.d.ts +33 -7
  62. package/dist/elements/EFWaveform.js +103 -59
  63. package/dist/elements/EFWaveform.js.map +1 -1
  64. package/dist/elements/renderTemporalAudio.js +14 -3
  65. package/dist/elements/renderTemporalAudio.js.map +1 -1
  66. package/dist/getRenderInfo.d.ts +2 -2
  67. package/dist/gui/ContextMixin.js +1 -1
  68. package/dist/gui/Controllable.d.ts +2 -0
  69. package/dist/gui/EFActiveRootTemporal.d.ts +4 -4
  70. package/dist/gui/EFActiveRootTemporal.js +1 -1
  71. package/dist/gui/EFConfiguration.d.ts +4 -4
  72. package/dist/gui/EFConfiguration.js +1 -1
  73. package/dist/gui/EFControls.d.ts +2 -2
  74. package/dist/gui/EFControls.js +1 -1
  75. package/dist/gui/EFDial.d.ts +4 -4
  76. package/dist/gui/EFDial.js +1 -1
  77. package/dist/gui/EFFilmstrip.d.ts +3 -2
  78. package/dist/gui/EFFilmstrip.js +1 -1
  79. package/dist/gui/EFFitScale.js +1 -1
  80. package/dist/gui/EFFocusOverlay.d.ts +4 -4
  81. package/dist/gui/EFFocusOverlay.js +1 -1
  82. package/dist/gui/EFOverlayItem.d.ts +4 -4
  83. package/dist/gui/EFOverlayItem.js +1 -1
  84. package/dist/gui/EFOverlayLayer.d.ts +4 -4
  85. package/dist/gui/EFOverlayLayer.js +1 -1
  86. package/dist/gui/EFPause.d.ts +4 -4
  87. package/dist/gui/EFPause.js +1 -1
  88. package/dist/gui/EFPlay.d.ts +4 -4
  89. package/dist/gui/EFPlay.js +1 -1
  90. package/dist/gui/EFPreview.d.ts +4 -4
  91. package/dist/gui/EFPreview.js +1 -1
  92. package/dist/gui/EFResizableBox.d.ts +4 -4
  93. package/dist/gui/EFResizableBox.js +1 -1
  94. package/dist/gui/EFScrubber.d.ts +4 -4
  95. package/dist/gui/EFScrubber.js +1 -1
  96. package/dist/gui/EFTimeDisplay.d.ts +4 -4
  97. package/dist/gui/EFTimeDisplay.js +1 -1
  98. package/dist/gui/EFTimelineRuler.d.ts +4 -4
  99. package/dist/gui/EFTimelineRuler.js +1 -1
  100. package/dist/gui/EFToggleLoop.d.ts +4 -4
  101. package/dist/gui/EFToggleLoop.js +1 -1
  102. package/dist/gui/EFTogglePlay.d.ts +4 -4
  103. package/dist/gui/EFTogglePlay.js +1 -1
  104. package/dist/gui/EFTransformHandles.d.ts +4 -4
  105. package/dist/gui/EFTransformHandles.js +1 -1
  106. package/dist/gui/EFWorkbench.d.ts +5 -4
  107. package/dist/gui/EFWorkbench.js +1 -1
  108. package/dist/gui/PlaybackController.d.ts +10 -2
  109. package/dist/gui/PlaybackController.js +52 -30
  110. package/dist/gui/PlaybackController.js.map +1 -1
  111. package/dist/gui/TWMixin.js +1 -1
  112. package/dist/gui/TWMixin.js.map +1 -1
  113. package/dist/gui/TargetOrContextMixin.js +1 -1
  114. package/dist/gui/hierarchy/EFHierarchy.d.ts +4 -4
  115. package/dist/gui/hierarchy/EFHierarchy.js +1 -1
  116. package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
  117. package/dist/gui/hierarchy/EFHierarchyItem.js +1 -1
  118. package/dist/gui/timeline/EFTimeline.d.ts +6 -2
  119. package/dist/gui/timeline/EFTimeline.js +1 -1
  120. package/dist/gui/timeline/EFTimelineRow.d.ts +57 -0
  121. package/dist/gui/timeline/EFTimelineRow.js +1 -1
  122. package/dist/gui/timeline/TrimHandles.d.ts +4 -4
  123. package/dist/gui/timeline/TrimHandles.js +1 -1
  124. package/dist/gui/timeline/tracks/AudioTrack.d.ts +2 -0
  125. package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
  126. package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +58 -0
  127. package/dist/gui/timeline/tracks/CaptionsTrack.js +1 -1
  128. package/dist/gui/timeline/tracks/HTMLTrack.d.ts +13 -0
  129. package/dist/gui/timeline/tracks/HTMLTrack.js +1 -1
  130. package/dist/gui/timeline/tracks/ImageTrack.d.ts +14 -0
  131. package/dist/gui/timeline/tracks/ImageTrack.js +1 -1
  132. package/dist/gui/timeline/tracks/TextTrack.d.ts +26 -0
  133. package/dist/gui/timeline/tracks/TextTrack.js +1 -1
  134. package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +47 -0
  135. package/dist/gui/timeline/tracks/TimegroupTrack.js +4 -12
  136. package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
  137. package/dist/gui/timeline/tracks/TrackItem.d.ts +81 -0
  138. package/dist/gui/timeline/tracks/TrackItem.js +1 -1
  139. package/dist/gui/timeline/tracks/VideoTrack.d.ts +25 -0
  140. package/dist/gui/timeline/tracks/VideoTrack.js +1 -1
  141. package/dist/gui/timeline/tracks/WaveformTrack.d.ts +14 -0
  142. package/dist/gui/timeline/tracks/WaveformTrack.js +1 -1
  143. package/dist/gui/timeline/tracks/ensureTrackItemInit.d.ts +1 -0
  144. package/dist/gui/timeline/tracks/preloadTracks.d.ts +9 -0
  145. package/dist/gui/tree/EFTree.d.ts +5 -4
  146. package/dist/gui/tree/EFTree.js +1 -1
  147. package/dist/gui/tree/EFTreeItem.d.ts +4 -4
  148. package/dist/gui/tree/EFTreeItem.js +1 -1
  149. package/dist/index.d.ts +4 -1
  150. package/dist/preview/AdaptiveResolutionTracker.js +6 -14
  151. package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
  152. package/dist/preview/FrameController.d.ts +123 -0
  153. package/dist/preview/FrameController.js +216 -0
  154. package/dist/preview/FrameController.js.map +1 -0
  155. package/dist/preview/RenderContext.d.ts +1 -0
  156. package/dist/preview/RenderContext.js +193 -0
  157. package/dist/preview/RenderContext.js.map +1 -0
  158. package/dist/preview/encoding/canvasEncoder.js +166 -0
  159. package/dist/preview/encoding/canvasEncoder.js.map +1 -0
  160. package/dist/preview/encoding/mainThreadEncoder.js +39 -0
  161. package/dist/preview/encoding/mainThreadEncoder.js.map +1 -0
  162. package/dist/preview/encoding/types.d.ts +1 -0
  163. package/dist/preview/encoding/workerEncoder.js +58 -0
  164. package/dist/preview/encoding/workerEncoder.js.map +1 -0
  165. package/dist/preview/logger.js +41 -0
  166. package/dist/preview/logger.js.map +1 -0
  167. package/dist/preview/previewTypes.js +11 -10
  168. package/dist/preview/previewTypes.js.map +1 -1
  169. package/dist/preview/renderTimegroupPreview.js +259 -236
  170. package/dist/preview/renderTimegroupPreview.js.map +1 -1
  171. package/dist/preview/renderTimegroupToCanvas.d.ts +5 -0
  172. package/dist/preview/renderTimegroupToCanvas.js +100 -489
  173. package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
  174. package/dist/preview/renderTimegroupToVideo.d.ts +1 -0
  175. package/dist/preview/renderTimegroupToVideo.js +80 -22
  176. package/dist/preview/renderTimegroupToVideo.js.map +1 -1
  177. package/dist/preview/renderers.js.map +1 -1
  178. package/dist/preview/rendering/inlineImages.js +56 -0
  179. package/dist/preview/rendering/inlineImages.js.map +1 -0
  180. package/dist/preview/rendering/renderToImage.d.ts +1 -0
  181. package/dist/preview/rendering/renderToImage.js +120 -0
  182. package/dist/preview/rendering/renderToImage.js.map +1 -0
  183. package/dist/preview/rendering/renderToImageForeignObject.js +135 -0
  184. package/dist/preview/rendering/renderToImageForeignObject.js.map +1 -0
  185. package/dist/preview/rendering/renderToImageNative.d.ts +1 -0
  186. package/dist/preview/rendering/renderToImageNative.js +129 -0
  187. package/dist/preview/rendering/renderToImageNative.js.map +1 -0
  188. package/dist/preview/rendering/svgSerializer.js +43 -0
  189. package/dist/preview/rendering/svgSerializer.js.map +1 -0
  190. package/dist/preview/rendering/types.d.ts +2 -0
  191. package/dist/preview/statsTrackingStrategy.js +3 -1
  192. package/dist/preview/statsTrackingStrategy.js.map +1 -1
  193. package/dist/preview/workers/WorkerPool.js +8 -57
  194. package/dist/preview/workers/WorkerPool.js.map +1 -1
  195. package/dist/render/EFRenderAPI.d.ts +35 -0
  196. package/dist/render/EFRenderAPI.js +1 -0
  197. package/dist/render/EFRenderAPI.js.map +1 -1
  198. package/dist/sandbox/PlaybackControls.d.ts +1 -0
  199. package/dist/sandbox/ScenarioRunner.d.ts +1 -0
  200. package/dist/sandbox/defineSandbox.d.ts +1 -0
  201. package/dist/sandbox/index.d.ts +3 -0
  202. package/dist/style.css +3 -0
  203. package/dist/transcoding/types/index.d.ts +6 -3
  204. package/package.json +2 -3
  205. package/test/EFVideo.framegen.browsertest.ts +8 -1
  206. package/test/profilingPlugin.ts +1 -3
  207. package/test/setup.ts +23 -1
  208. package/dist/EF_INTERACTIVE.js +0 -7
  209. package/dist/EF_INTERACTIVE.js.map +0 -1
  210. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +0 -50
  211. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +0 -12
  212. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +0 -104
  213. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +0 -1
  214. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +0 -168
  215. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +0 -1
  216. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +0 -46
  217. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +0 -1
  218. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +0 -49
  219. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +0 -1
  220. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +0 -30
  221. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +0 -1
  222. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +0 -49
  223. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +0 -1
  224. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +0 -47
  225. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +0 -1
  226. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +0 -140
  227. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +0 -1
  228. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +0 -13
  229. package/dist/elements/EFMedia/shared/BufferUtils.js +0 -86
  230. package/dist/elements/EFMedia/shared/BufferUtils.js.map +0 -1
  231. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +0 -17
  232. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +0 -90
  233. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +0 -1
  234. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +0 -80
  235. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +0 -1
  236. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +0 -49
  237. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +0 -1
  238. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +0 -58
  239. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +0 -1
  240. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +0 -71
  241. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +0 -1
  242. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +0 -52
  243. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +0 -1
  244. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +0 -50
  245. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +0 -1
  246. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +0 -109
  247. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +0 -1
  248. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +0 -12
  249. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +0 -97
  250. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +0 -1
  251. package/dist/elements/SampleBuffer.d.ts +0 -19
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvasEncoder.js","names":["_workerPool: WorkerPool | null","dataUrl: string"],"sources":["../../../src/preview/encoding/canvasEncoder.ts"],"sourcesContent":["/**\n * Canvas encoding orchestration with worker pool support.\n * \n * Supports caching via RenderContext:\n * - For ef-image/ef-waveform: caches by element + renderVersion\n * - For ef-video: uses direct capture API with source timestamp caching\n */\n\nimport { logger } from \"../logger.js\";\nimport { WorkerPool } from \"../workers/WorkerPool.js\";\nimport { getEncoderWorkerUrl } from \"../workers/encoderWorkerInline.js\";\nimport { encodeCanvasOnMainThread } from \"./mainThreadEncoder.js\";\nimport { encodeCanvasInWorker } from \"./workerEncoder.js\";\nimport type { CanvasEncodeResult, CanvasEncodeOptions } from \"./types.js\";\nimport type { EFVideo } from \"../../elements/EFVideo.js\";\nimport type { EFSurface } from \"../../elements/EFSurface.js\";\n\n// Module-level worker pool state\nlet _workerPool: WorkerPool | null = null;\nlet _workerPoolWarningLogged = false;\n\n/**\n * Get or create the worker pool for canvas encoding.\n * Returns null if workers are not available.\n */\nfunction getWorkerPool(): WorkerPool | null {\n if (_workerPool) {\n return _workerPool;\n }\n\n // Check if workers are available\n if (\n typeof Worker === \"undefined\" ||\n typeof OffscreenCanvas === \"undefined\" ||\n typeof createImageBitmap === \"undefined\"\n ) {\n if (!_workerPoolWarningLogged) {\n _workerPoolWarningLogged = true;\n logger.warn(\n \"[canvasEncoder] Web Workers or OffscreenCanvas not available, using main thread fallback\",\n );\n }\n return null;\n }\n\n try {\n // Use inline worker URL - this works in any bundler environment\n // because the worker code is embedded in the bundle as a blob URL\n const workerUrl = getEncoderWorkerUrl();\n \n _workerPool = new WorkerPool(workerUrl);\n \n // Check if workers were actually created\n if (!_workerPool.isAvailable()) {\n const reason = _workerPool.workerCount === 0 \n ? \"no workers created (check console for errors)\" \n : \"workers not available\";\n _workerPool = null;\n if (!_workerPoolWarningLogged) {\n _workerPoolWarningLogged = true;\n logger.warn(\n `[canvasEncoder] Worker pool initialization failed (${reason}), using main thread fallback`,\n );\n }\n }\n } catch (error) {\n _workerPool = null;\n if (!_workerPoolWarningLogged) {\n _workerPoolWarningLogged = true;\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.warn(\n `[canvasEncoder] Failed to create worker pool: ${errorMessage} - using main thread fallback`,\n );\n }\n }\n\n return _workerPool;\n}\n\n/**\n * Check if an element is an EFVideo.\n */\nfunction isEFVideo(element: Element): element is EFVideo {\n return element.tagName === \"EF-VIDEO\";\n}\n\n/**\n * Check if an element is an EFSurface.\n */\nfunction isEFSurface(element: Element): element is EFSurface {\n return element.tagName === \"EF-SURFACE\";\n}\n\n/**\n * Encode canvases to data URLs in parallel using worker pool.\n * Falls back to main thread encoding if workers are unavailable.\n * \n * When RenderContext and sourceMap are provided:\n * - Checks cache for static elements (ef-image, ef-waveform)\n * - Uses direct capture API for ef-video elements\n * - Shares cached frames for ef-surface elements targeting ef-video\n * \n * @param canvases - Array of canvases to encode\n * @param options - Encoding options including optional renderContext and sourceMap\n * @returns Promise resolving to array of encoded results\n */\nexport async function encodeCanvasesInParallel(\n canvases: HTMLCanvasElement[],\n options: CanvasEncodeOptions = {},\n): Promise<CanvasEncodeResult[]> {\n const { scale: canvasScale = 1, renderContext, sourceMap } = options;\n const workerPool = getWorkerPool();\n\n // Helper to encode a single canvas (with caching)\n const encodeCanvas = async (canvas: HTMLCanvasElement): Promise<CanvasEncodeResult | null> => {\n try {\n if (canvas.width === 0 || canvas.height === 0) {\n return null;\n }\n\n const preserveAlpha = canvas.dataset.preserveAlpha === \"true\";\n const sourceElement = sourceMap?.get(canvas);\n\n // OPTIMIZATION: Check RenderContext cache for static elements\n if (renderContext && sourceElement) {\n // For ef-video, use direct capture API\n if (isEFVideo(sourceElement)) {\n const sourceTimeMs = sourceElement.currentSourceTimeMs;\n \n // Use direct capture API (bypasses frameTask)\n // Always use \"main\" quality for export - scrub track is only for preview scrubbing\n try {\n const frame = await sourceElement.captureFrameAtSourceTime(sourceTimeMs, { quality: \"main\" });\n return { canvas, dataUrl: frame.dataUrl, preserveAlpha: false };\n } catch (e) {\n // Fall back to normal encoding if direct capture fails\n logger.warn(\"[canvasEncoder] Direct capture failed, falling back to canvas encoding:\", e);\n }\n }\n \n // For ef-surface targeting ef-video, share the video's cached frame\n if (isEFSurface(sourceElement)) {\n const target = sourceElement.targetElement;\n if (target && isEFVideo(target as Element)) {\n const videoTarget = target as unknown as EFVideo;\n const sourceTimeMs = videoTarget.currentSourceTimeMs;\n const cached = renderContext.getCachedVideoFrame(videoTarget, sourceTimeMs);\n if (cached) {\n return { canvas, dataUrl: cached.dataUrl, preserveAlpha: false };\n }\n \n // Capture from the target video\n // Always use \"main\" quality for export\n try {\n const frame = await videoTarget.captureFrameAtSourceTime(sourceTimeMs, { quality: \"main\" });\n renderContext.setCachedVideoFrame(videoTarget, sourceTimeMs, frame);\n return { canvas, dataUrl: frame.dataUrl, preserveAlpha: false };\n } catch (e) {\n logger.warn(\"[canvasEncoder] Direct capture for surface target failed:\", e);\n }\n }\n }\n \n // For static elements (ef-image, ef-waveform), check version-based cache\n const cachedDataUrl = renderContext.getCachedCanvasDataUrl(sourceElement);\n if (cachedDataUrl) {\n return { canvas, dataUrl: cachedDataUrl, preserveAlpha };\n }\n }\n\n // Standard encoding path (fallback when no RenderContext cache)\n let sourceCanvas = canvas;\n\n // Handle canvas scaling on main thread before encoding\n if (canvasScale < 1) {\n const scaledWidth = Math.floor(canvas.width * canvasScale);\n const scaledHeight = Math.floor(canvas.height * canvasScale);\n const scaledCanvas = document.createElement(\"canvas\");\n scaledCanvas.width = scaledWidth;\n scaledCanvas.height = scaledHeight;\n const scaledCtx = scaledCanvas.getContext(\"2d\");\n if (scaledCtx) {\n scaledCtx.drawImage(canvas, 0, 0, scaledWidth, scaledHeight);\n sourceCanvas = scaledCanvas;\n }\n }\n\n let dataUrl: string;\n \n if (workerPool) {\n // Encode in worker\n dataUrl = await workerPool.execute((worker) =>\n encodeCanvasInWorker(worker, sourceCanvas, preserveAlpha),\n );\n } else {\n // Main thread fallback - warning already logged once in getWorkerPool()\n const encoded = encodeCanvasOnMainThread(sourceCanvas, canvasScale);\n if (!encoded) return null;\n dataUrl = encoded.dataUrl;\n }\n\n // Cache the result for static elements\n if (renderContext && sourceElement) {\n renderContext.setCachedCanvasDataUrl(sourceElement, dataUrl);\n }\n\n return { canvas, dataUrl, preserveAlpha };\n } catch (error) {\n // Fallback to main thread if worker encoding fails\n logger.warn(\"[canvasEncoder] Worker encoding failed, using main thread fallback:\", error);\n const encoded = encodeCanvasOnMainThread(canvas, canvasScale);\n if (encoded) {\n logger.warn(\"[canvasEncoder] Main thread fallback succeeded\");\n return { canvas, ...encoded };\n }\n \n // Cross-origin canvas or other error - skip\n logger.warn(\"[canvasEncoder] Main thread encoding also failed, skipping canvas:\", error);\n return null;\n }\n };\n\n // Encode all canvases in parallel\n const encodingTasks = canvases.map(encodeCanvas);\n const encodedResults = await Promise.all(encodingTasks);\n const validResults = encodedResults.filter(\n (r): r is CanvasEncodeResult => r !== null,\n );\n return validResults;\n}\n\n/**\n * Reset the worker pool state (for testing).\n */\nexport function resetWorkerPool(): void {\n if (_workerPool) {\n _workerPool.terminate();\n _workerPool = null;\n }\n _workerPoolWarningLogged = false;\n}\n"],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ //#region src/preview/encoding/mainThreadEncoder.ts
2
+ const JPEG_QUALITY_HIGH = .92;
3
+ const JPEG_QUALITY_MEDIUM = .85;
4
+ /**
5
+ * Encode a single canvas to a data URL on the main thread (fallback).
6
+ * @param canvas - The canvas to encode
7
+ * @param canvasScale - Scale factor for encoding (default: 1)
8
+ * @returns Encoded result or null if encoding fails
9
+ */
10
+ function encodeCanvasOnMainThread(canvas, canvasScale) {
11
+ try {
12
+ if (canvas.width === 0 || canvas.height === 0) return null;
13
+ const preserveAlpha = canvas.dataset.preserveAlpha === "true";
14
+ let dataUrl;
15
+ if (canvasScale < 1) {
16
+ const scaledWidth = Math.floor(canvas.width * canvasScale);
17
+ const scaledHeight = Math.floor(canvas.height * canvasScale);
18
+ const scaledCanvas = document.createElement("canvas");
19
+ scaledCanvas.width = scaledWidth;
20
+ scaledCanvas.height = scaledHeight;
21
+ const scaledCtx = scaledCanvas.getContext("2d");
22
+ if (scaledCtx) {
23
+ scaledCtx.drawImage(canvas, 0, 0, scaledWidth, scaledHeight);
24
+ const quality = canvasScale < .5 ? JPEG_QUALITY_MEDIUM : JPEG_QUALITY_HIGH;
25
+ dataUrl = preserveAlpha ? scaledCanvas.toDataURL("image/png") : scaledCanvas.toDataURL("image/jpeg", quality);
26
+ } else dataUrl = preserveAlpha ? canvas.toDataURL("image/png") : canvas.toDataURL("image/jpeg", JPEG_QUALITY_HIGH);
27
+ } else dataUrl = preserveAlpha ? canvas.toDataURL("image/png") : canvas.toDataURL("image/jpeg", JPEG_QUALITY_HIGH);
28
+ return {
29
+ dataUrl,
30
+ preserveAlpha
31
+ };
32
+ } catch (e) {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ //#endregion
38
+ export { encodeCanvasOnMainThread };
39
+ //# sourceMappingURL=mainThreadEncoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mainThreadEncoder.js","names":["dataUrl: string"],"sources":["../../../src/preview/encoding/mainThreadEncoder.ts"],"sourcesContent":["/**\n * Main thread canvas encoding (fallback implementation).\n */\n\nimport type { CanvasEncodeResult } from \"./types.js\";\n\n// JPEG quality constants\nexport const JPEG_QUALITY_HIGH = 0.92;\nexport const JPEG_QUALITY_MEDIUM = 0.85;\n\n/**\n * Encode a single canvas to a data URL on the main thread (fallback).\n * @param canvas - The canvas to encode\n * @param canvasScale - Scale factor for encoding (default: 1)\n * @returns Encoded result or null if encoding fails\n */\nexport function encodeCanvasOnMainThread(\n canvas: HTMLCanvasElement,\n canvasScale: number,\n): { dataUrl: string; preserveAlpha: boolean } | null {\n try {\n if (canvas.width === 0 || canvas.height === 0) {\n return null;\n }\n\n const preserveAlpha = canvas.dataset.preserveAlpha === \"true\";\n let dataUrl: string;\n\n if (canvasScale < 1) {\n // Scale down canvas before encoding\n const scaledWidth = Math.floor(canvas.width * canvasScale);\n const scaledHeight = Math.floor(canvas.height * canvasScale);\n const scaledCanvas = document.createElement(\"canvas\");\n scaledCanvas.width = scaledWidth;\n scaledCanvas.height = scaledHeight;\n const scaledCtx = scaledCanvas.getContext(\"2d\");\n if (scaledCtx) {\n scaledCtx.drawImage(canvas, 0, 0, scaledWidth, scaledHeight);\n const quality = canvasScale < 0.5 ? JPEG_QUALITY_MEDIUM : JPEG_QUALITY_HIGH;\n dataUrl = preserveAlpha\n ? scaledCanvas.toDataURL(\"image/png\")\n : scaledCanvas.toDataURL(\"image/jpeg\", quality);\n } else {\n dataUrl = preserveAlpha\n ? canvas.toDataURL(\"image/png\")\n : canvas.toDataURL(\"image/jpeg\", JPEG_QUALITY_HIGH);\n }\n } else {\n dataUrl = preserveAlpha\n ? canvas.toDataURL(\"image/png\")\n : canvas.toDataURL(\"image/jpeg\", JPEG_QUALITY_HIGH);\n }\n\n return { dataUrl, preserveAlpha };\n } catch (e) {\n // Cross-origin canvas or other error - skip\n return null;\n }\n}\n"],"mappings":";AAOA,MAAa,oBAAoB;AACjC,MAAa,sBAAsB;;;;;;;AAQnC,SAAgB,yBACd,QACA,aACoD;AACpD,KAAI;AACF,MAAI,OAAO,UAAU,KAAK,OAAO,WAAW,EAC1C,QAAO;EAGT,MAAM,gBAAgB,OAAO,QAAQ,kBAAkB;EACvD,IAAIA;AAEJ,MAAI,cAAc,GAAG;GAEnB,MAAM,cAAc,KAAK,MAAM,OAAO,QAAQ,YAAY;GAC1D,MAAM,eAAe,KAAK,MAAM,OAAO,SAAS,YAAY;GAC5D,MAAM,eAAe,SAAS,cAAc,SAAS;AACrD,gBAAa,QAAQ;AACrB,gBAAa,SAAS;GACtB,MAAM,YAAY,aAAa,WAAW,KAAK;AAC/C,OAAI,WAAW;AACb,cAAU,UAAU,QAAQ,GAAG,GAAG,aAAa,aAAa;IAC5D,MAAM,UAAU,cAAc,KAAM,sBAAsB;AAC1D,cAAU,gBACN,aAAa,UAAU,YAAY,GACnC,aAAa,UAAU,cAAc,QAAQ;SAEjD,WAAU,gBACN,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,cAAc,kBAAkB;QAGvD,WAAU,gBACN,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,cAAc,kBAAkB;AAGvD,SAAO;GAAE;GAAS;GAAe;UAC1B,GAAG;AAEV,SAAO"}
@@ -0,0 +1 @@
1
+ import "../RenderContext.js";
@@ -0,0 +1,58 @@
1
+ //#region src/preview/encoding/workerEncoder.ts
2
+ /**
3
+ * Worker-based canvas encoding.
4
+ */
5
+ const WORKER_TASK_TIMEOUT_MS = 3e4;
6
+ /**
7
+ * Encode a canvas using a worker.
8
+ * @param worker - The worker to use for encoding
9
+ * @param canvas - The canvas to encode
10
+ * @param preserveAlpha - Whether to preserve alpha channel (PNG vs JPEG)
11
+ * @returns Promise resolving to the encoded data URL
12
+ */
13
+ async function encodeCanvasInWorker(worker, canvas, preserveAlpha) {
14
+ return new Promise((resolve, reject) => {
15
+ const taskId = `task-${Date.now()}-${Math.random()}-${performance.now()}`;
16
+ let timeoutId = null;
17
+ const cleanup = () => {
18
+ if (timeoutId !== null) {
19
+ clearTimeout(timeoutId);
20
+ timeoutId = null;
21
+ }
22
+ worker.removeEventListener("message", messageHandler);
23
+ worker.removeEventListener("messageerror", messageErrorHandler);
24
+ };
25
+ const messageHandler = (event) => {
26
+ const result = event.data;
27
+ if (result.taskId === taskId) {
28
+ cleanup();
29
+ if (result.error) reject(/* @__PURE__ */ new Error(`Worker encoding failed: ${result.error}`));
30
+ else resolve(result.dataUrl);
31
+ }
32
+ };
33
+ const messageErrorHandler = () => {
34
+ cleanup();
35
+ reject(/* @__PURE__ */ new Error("Worker message error"));
36
+ };
37
+ worker.addEventListener("message", messageHandler);
38
+ worker.addEventListener("messageerror", messageErrorHandler);
39
+ timeoutId = window.setTimeout(() => {
40
+ cleanup();
41
+ reject(/* @__PURE__ */ new Error("Worker task timed out"));
42
+ }, WORKER_TASK_TIMEOUT_MS);
43
+ createImageBitmap(canvas).then((bitmap) => {
44
+ worker.postMessage({
45
+ taskId,
46
+ bitmap,
47
+ preserveAlpha
48
+ }, [bitmap]);
49
+ }).catch((error) => {
50
+ cleanup();
51
+ reject(error instanceof Error ? error : new Error(String(error)));
52
+ });
53
+ });
54
+ }
55
+
56
+ //#endregion
57
+ export { encodeCanvasInWorker };
58
+ //# sourceMappingURL=workerEncoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workerEncoder.js","names":["timeoutId: number | null"],"sources":["../../../src/preview/encoding/workerEncoder.ts"],"sourcesContent":["/**\n * Worker-based canvas encoding.\n */\n\nconst WORKER_TASK_TIMEOUT_MS = 30000;\n\n/**\n * Encode a canvas using a worker.\n * @param worker - The worker to use for encoding\n * @param canvas - The canvas to encode\n * @param preserveAlpha - Whether to preserve alpha channel (PNG vs JPEG)\n * @returns Promise resolving to the encoded data URL\n */\nexport async function encodeCanvasInWorker(\n worker: Worker,\n canvas: HTMLCanvasElement,\n preserveAlpha: boolean,\n): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const taskId = `task-${Date.now()}-${Math.random()}-${performance.now()}`;\n let timeoutId: number | null = null;\n\n const cleanup = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n worker.removeEventListener(\"message\", messageHandler);\n worker.removeEventListener(\"messageerror\", messageErrorHandler);\n };\n\n const messageHandler = (event: MessageEvent) => {\n const result = event.data as { taskId: string; dataUrl: string; error?: string };\n if (result.taskId === taskId) {\n cleanup();\n if (result.error) {\n reject(new Error(`Worker encoding failed: ${result.error}`));\n } else {\n resolve(result.dataUrl);\n }\n }\n };\n\n const messageErrorHandler = () => {\n cleanup();\n reject(new Error(\"Worker message error\"));\n };\n\n worker.addEventListener(\"message\", messageHandler);\n worker.addEventListener(\"messageerror\", messageErrorHandler);\n\n // Set timeout to detect if worker never responds\n timeoutId = window.setTimeout(() => {\n cleanup();\n reject(new Error(\"Worker task timed out\"));\n }, WORKER_TASK_TIMEOUT_MS);\n\n // Create ImageBitmap from canvas\n createImageBitmap(canvas)\n .then((bitmap) => {\n // Transfer bitmap to worker (zero-copy)\n worker.postMessage(\n {\n taskId,\n bitmap,\n preserveAlpha,\n },\n [bitmap],\n );\n })\n .catch((error) => {\n cleanup();\n reject(error instanceof Error ? error : new Error(String(error)));\n });\n });\n}\n"],"mappings":";;;;AAIA,MAAM,yBAAyB;;;;;;;;AAS/B,eAAsB,qBACpB,QACA,QACA,eACiB;AACjB,QAAO,IAAI,SAAiB,SAAS,WAAW;EAC9C,MAAM,SAAS,QAAQ,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,GAAG,YAAY,KAAK;EACvE,IAAIA,YAA2B;EAE/B,MAAM,gBAAgB;AACpB,OAAI,cAAc,MAAM;AACtB,iBAAa,UAAU;AACvB,gBAAY;;AAEd,UAAO,oBAAoB,WAAW,eAAe;AACrD,UAAO,oBAAoB,gBAAgB,oBAAoB;;EAGjE,MAAM,kBAAkB,UAAwB;GAC9C,MAAM,SAAS,MAAM;AACrB,OAAI,OAAO,WAAW,QAAQ;AAC5B,aAAS;AACT,QAAI,OAAO,MACT,wBAAO,IAAI,MAAM,2BAA2B,OAAO,QAAQ,CAAC;QAE5D,SAAQ,OAAO,QAAQ;;;EAK7B,MAAM,4BAA4B;AAChC,YAAS;AACT,0BAAO,IAAI,MAAM,uBAAuB,CAAC;;AAG3C,SAAO,iBAAiB,WAAW,eAAe;AAClD,SAAO,iBAAiB,gBAAgB,oBAAoB;AAG5D,cAAY,OAAO,iBAAiB;AAClC,YAAS;AACT,0BAAO,IAAI,MAAM,wBAAwB,CAAC;KACzC,uBAAuB;AAG1B,oBAAkB,OAAO,CACtB,MAAM,WAAW;AAEhB,UAAO,YACL;IACE;IACA;IACA;IACD,EACD,CAAC,OAAO,CACT;IACD,CACD,OAAO,UAAU;AAChB,YAAS;AACT,UAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;IACjE;GACJ"}
@@ -0,0 +1,41 @@
1
+ //#region src/preview/logger.ts
2
+ const LOG_LEVELS = {
3
+ debug: 0,
4
+ info: 1,
5
+ warn: 2,
6
+ error: 3,
7
+ silent: 4
8
+ };
9
+ function getLogLevel() {
10
+ if (typeof globalThis !== "undefined" && "EF_LOG_LEVEL" in globalThis) {
11
+ const level = globalThis.EF_LOG_LEVEL;
12
+ if (level && level in LOG_LEVELS) return level;
13
+ }
14
+ if (typeof process !== "undefined" && process.env?.EF_LOG_LEVEL) {
15
+ const level = process.env.EF_LOG_LEVEL;
16
+ if (level in LOG_LEVELS) return level;
17
+ }
18
+ return "silent";
19
+ }
20
+ function shouldLog(level) {
21
+ const currentLevel = getLogLevel();
22
+ return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
23
+ }
24
+ const logger = {
25
+ debug: (...args) => {
26
+ if (shouldLog("debug")) console.log(...args);
27
+ },
28
+ info: (...args) => {
29
+ if (shouldLog("info")) console.log(...args);
30
+ },
31
+ warn: (...args) => {
32
+ if (shouldLog("warn")) console.warn(...args);
33
+ },
34
+ error: (...args) => {
35
+ if (shouldLog("error")) console.error(...args);
36
+ }
37
+ };
38
+
39
+ //#endregion
40
+ export { logger };
41
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","names":["LOG_LEVELS: Record<LogLevel, number>"],"sources":["../../src/preview/logger.ts"],"sourcesContent":["/**\n * Centralized logging utility for the preview module.\n * \n * Logging is disabled by default. To enable logging, set:\n * - Environment variable: EF_LOG_LEVEL=debug (or info, warn, error)\n * - Global flag: globalThis.EF_LOG_LEVEL = 'debug'\n * \n * Log levels (in order of verbosity):\n * - debug: All logs including performance metrics\n * - info: Informational messages\n * - warn: Warnings\n * - error: Errors only\n * - silent: No logging (default)\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\nfunction getLogLevel(): LogLevel {\n // Check global flag first\n if (typeof globalThis !== 'undefined' && 'EF_LOG_LEVEL' in globalThis) {\n const level = (globalThis as { EF_LOG_LEVEL?: string }).EF_LOG_LEVEL;\n if (level && level in LOG_LEVELS) {\n return level as LogLevel;\n }\n }\n \n // Check environment variable (works in Node.js and some bundlers)\n if (typeof process !== 'undefined' && process.env?.EF_LOG_LEVEL) {\n const level = process.env.EF_LOG_LEVEL;\n if (level in LOG_LEVELS) {\n return level as LogLevel;\n }\n }\n \n // Default to silent\n return 'silent';\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n const currentLevel = getLogLevel();\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\n}\n\nexport const logger = {\n debug: (...args: unknown[]): void => {\n if (shouldLog('debug')) {\n console.log(...args);\n }\n },\n \n info: (...args: unknown[]): void => {\n if (shouldLog('info')) {\n console.log(...args);\n }\n },\n \n warn: (...args: unknown[]): void => {\n if (shouldLog('warn')) {\n console.warn(...args);\n }\n },\n \n error: (...args: unknown[]): void => {\n if (shouldLog('error')) {\n console.error(...args);\n }\n },\n};\n"],"mappings":";AAiBA,MAAMA,aAAuC;CAC3C,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,QAAQ;CACT;AAED,SAAS,cAAwB;AAE/B,KAAI,OAAO,eAAe,eAAe,kBAAkB,YAAY;EACrE,MAAM,QAAS,WAAyC;AACxD,MAAI,SAAS,SAAS,WACpB,QAAO;;AAKX,KAAI,OAAO,YAAY,eAAe,QAAQ,KAAK,cAAc;EAC/D,MAAM,QAAQ,QAAQ,IAAI;AAC1B,MAAI,SAAS,WACX,QAAO;;AAKX,QAAO;;AAGT,SAAS,UAAU,OAA0B;CAC3C,MAAM,eAAe,aAAa;AAClC,QAAO,WAAW,UAAU,WAAW;;AAGzC,MAAa,SAAS;CACpB,QAAQ,GAAG,SAA0B;AACnC,MAAI,UAAU,QAAQ,CACpB,SAAQ,IAAI,GAAG,KAAK;;CAIxB,OAAO,GAAG,SAA0B;AAClC,MAAI,UAAU,OAAO,CACnB,SAAQ,IAAI,GAAG,KAAK;;CAIxB,OAAO,GAAG,SAA0B;AAClC,MAAI,UAAU,OAAO,CACnB,SAAQ,KAAK,GAAG,KAAK;;CAIzB,QAAQ,GAAG,SAA0B;AACnC,MAAI,UAAU,QAAQ,CACpB,SAAQ,MAAM,GAAG,KAAK;;CAG3B"}
@@ -8,18 +8,22 @@ function isTemporal(el) {
8
8
  /**
9
9
  * Get temporal bounds for an element, treating invalid ranges as unbounded.
10
10
  * Invalid range (end <= start) means element hasn't computed its duration yet.
11
+ *
12
+ * NOTE: No caching - bounds are computed dynamically by timegroups based on
13
+ * composition mode (sequence/contain/fit) and may change between frames.
11
14
  */
12
15
  function getTemporalBounds(el) {
13
16
  if (!isTemporal(el)) return {
14
17
  startMs: -Infinity,
15
18
  endMs: Infinity
16
19
  };
17
- const startMs = el.startTimeMs ?? -Infinity;
18
- const endMs = el.endTimeMs ?? Infinity;
19
- if (endMs <= startMs) return {
20
- startMs: -Infinity,
21
- endMs: Infinity
22
- };
20
+ const temporal = el;
21
+ let startMs = temporal.startTimeMs ?? -Infinity;
22
+ let endMs = temporal.endTimeMs ?? Infinity;
23
+ if (endMs <= startMs) {
24
+ startMs = -Infinity;
25
+ endMs = Infinity;
26
+ }
23
27
  return {
24
28
  startMs,
25
29
  endMs
@@ -39,9 +43,6 @@ const DEFAULT_HEIGHT = 1080;
39
43
  const DEFAULT_THUMBNAIL_SCALE = .25;
40
44
  /** Default timeout for blocking content readiness mode (ms) */
41
45
  const DEFAULT_BLOCKING_TIMEOUT_MS = 5e3;
42
- /** JPEG quality settings for different canvas scales */
43
- const JPEG_QUALITY_HIGH = .95;
44
- const JPEG_QUALITY_MEDIUM = .85;
45
46
  /**
46
47
  * Create a preview container with standard styling.
47
48
  * Consolidates the repeated container creation pattern across preview functions.
@@ -60,5 +61,5 @@ function createPreviewContainer(options) {
60
61
  }
61
62
 
62
63
  //#endregion
63
- export { DEFAULT_BLOCKING_TIMEOUT_MS, DEFAULT_HEIGHT, DEFAULT_THUMBNAIL_SCALE, DEFAULT_WIDTH, JPEG_QUALITY_HIGH, JPEG_QUALITY_MEDIUM, createPreviewContainer, getTemporalBounds, isTemporal, isVisibleAtTime };
64
+ export { DEFAULT_BLOCKING_TIMEOUT_MS, DEFAULT_HEIGHT, DEFAULT_THUMBNAIL_SCALE, DEFAULT_WIDTH, createPreviewContainer, getTemporalBounds, isTemporal, isVisibleAtTime };
64
65
  //# sourceMappingURL=previewTypes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"previewTypes.js","names":[],"sources":["../../src/preview/previewTypes.ts"],"sourcesContent":["/**\n * Shared types and constants for preview rendering.\n * \n * Consolidates duplicate definitions from renderTimegroupToCanvas.ts and\n * renderTimegroupPreview.ts into a single source of truth.\n */\n\n// ============================================================================\n// Temporal Types\n// ============================================================================\n\n/**\n * Element with temporal properties (startTimeMs, endTimeMs).\n * Used for temporal visibility checks during preview rendering.\n */\nexport interface TemporalElement extends Element {\n startTimeMs?: number;\n endTimeMs?: number;\n src?: string;\n}\n\n/**\n * Type guard to check if an element has temporal properties.\n */\nexport function isTemporal(el: Element): el is TemporalElement {\n return \"startTimeMs\" in el && \"endTimeMs\" in el;\n}\n\n/**\n * Get temporal bounds for an element, treating invalid ranges as unbounded.\n * Invalid range (end <= start) means element hasn't computed its duration yet.\n */\nexport function getTemporalBounds(el: Element): { startMs: number; endMs: number } {\n if (!isTemporal(el)) return { startMs: -Infinity, endMs: Infinity };\n\n const startMs = el.startTimeMs ?? -Infinity;\n const endMs = el.endTimeMs ?? Infinity;\n\n // Invalid range (end <= start) means element hasn't computed its duration yet\n if (endMs <= startMs) return { startMs: -Infinity, endMs: Infinity };\n\n return { startMs, endMs };\n}\n\n/**\n * Check if an element is temporally visible at the given time.\n */\nexport function isVisibleAtTime(element: Element, timeMs: number): boolean {\n const { startMs, endMs } = getTemporalBounds(element);\n return timeMs >= startMs && timeMs <= endMs;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Default timegroup dimensions when not measurable */\nexport const DEFAULT_WIDTH = 1920;\nexport const DEFAULT_HEIGHT = 1080;\n\n/** Default scale for thumbnail captures */\nexport const DEFAULT_THUMBNAIL_SCALE = 0.25;\n\n/** Default timeout for blocking content readiness mode (ms) */\nexport const DEFAULT_BLOCKING_TIMEOUT_MS = 5000;\n\n/** JPEG quality settings for different canvas scales */\nexport const JPEG_QUALITY_HIGH = 0.95;\nexport const JPEG_QUALITY_MEDIUM = 0.85;\n\n// ============================================================================\n// Container Creation\n// ============================================================================\n\n/**\n * Options for creating a preview container.\n */\nexport interface PreviewContainerOptions {\n width: number;\n height: number;\n background?: string;\n position?: \"relative\" | \"absolute\" | \"fixed\";\n}\n\n/**\n * Create a preview container with standard styling.\n * Consolidates the repeated container creation pattern across preview functions.\n */\nexport function createPreviewContainer(options: PreviewContainerOptions): HTMLDivElement {\n const { width, height, background = \"#000\", position = \"relative\" } = options;\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n width: ${width}px;\n height: ${height}px;\n position: ${position};\n overflow: hidden;\n background: ${background};\n `;\n return container;\n}\n\n// ============================================================================\n// Style Injection\n// ============================================================================\n\n/**\n * Inject document styles into a container for foreignObject rendering.\n * SVG foreignObject needs all CSS rules inlined since it can't access\n * the document's stylesheets.\n */\nexport function injectDocumentStyles(\n container: HTMLElement,\n collectStyles: () => string,\n): HTMLStyleElement {\n const styleEl = document.createElement(\"style\");\n styleEl.textContent = collectStyles();\n container.appendChild(styleEl);\n return styleEl;\n}\n"],"mappings":";;;;AAwBA,SAAgB,WAAW,IAAoC;AAC7D,QAAO,iBAAiB,MAAM,eAAe;;;;;;AAO/C,SAAgB,kBAAkB,IAAiD;AACjF,KAAI,CAAC,WAAW,GAAG,CAAE,QAAO;EAAE,SAAS;EAAW,OAAO;EAAU;CAEnE,MAAM,UAAU,GAAG,eAAe;CAClC,MAAM,QAAQ,GAAG,aAAa;AAG9B,KAAI,SAAS,QAAS,QAAO;EAAE,SAAS;EAAW,OAAO;EAAU;AAEpE,QAAO;EAAE;EAAS;EAAO;;;;;AAM3B,SAAgB,gBAAgB,SAAkB,QAAyB;CACzE,MAAM,EAAE,SAAS,UAAU,kBAAkB,QAAQ;AACrD,QAAO,UAAU,WAAW,UAAU;;;AAQxC,MAAa,gBAAgB;AAC7B,MAAa,iBAAiB;;AAG9B,MAAa,0BAA0B;;AAGvC,MAAa,8BAA8B;;AAG3C,MAAa,oBAAoB;AACjC,MAAa,sBAAsB;;;;;AAoBnC,SAAgB,uBAAuB,SAAkD;CACvF,MAAM,EAAE,OAAO,QAAQ,aAAa,QAAQ,WAAW,eAAe;CAEtE,MAAM,YAAY,SAAS,cAAc,MAAM;AAC/C,WAAU,MAAM,UAAU;aACf,MAAM;cACL,OAAO;gBACL,SAAS;;kBAEP,WAAW;;AAE3B,QAAO"}
1
+ {"version":3,"file":"previewTypes.js","names":[],"sources":["../../src/preview/previewTypes.ts"],"sourcesContent":["/**\n * Shared types and constants for preview rendering.\n * \n * Consolidates duplicate definitions from renderTimegroupToCanvas.ts and\n * renderTimegroupPreview.ts into a single source of truth.\n */\n\n// ============================================================================\n// Temporal Types\n// ============================================================================\n\n/**\n * Element with temporal properties (startTimeMs, endTimeMs).\n * Used for temporal visibility checks during preview rendering.\n */\nexport interface TemporalElement extends Element {\n startTimeMs?: number;\n endTimeMs?: number;\n src?: string;\n}\n\n/**\n * Type guard to check if an element has temporal properties.\n */\nexport function isTemporal(el: Element): el is TemporalElement {\n return \"startTimeMs\" in el && \"endTimeMs\" in el;\n}\n\n/**\n * Get temporal bounds for an element, treating invalid ranges as unbounded.\n * Invalid range (end <= start) means element hasn't computed its duration yet.\n * \n * NOTE: No caching - bounds are computed dynamically by timegroups based on\n * composition mode (sequence/contain/fit) and may change between frames.\n */\nexport function getTemporalBounds(el: Element): { startMs: number; endMs: number } {\n // Non-temporal elements are always visible\n if (!isTemporal(el)) {\n return { startMs: -Infinity, endMs: Infinity };\n }\n\n // Compute bounds fresh each time\n const temporal = el as TemporalElement;\n let startMs = temporal.startTimeMs ?? -Infinity;\n let endMs = temporal.endTimeMs ?? Infinity;\n\n // If end <= start, treat as always visible (element hasn't computed duration yet)\n if (endMs <= startMs) {\n startMs = -Infinity;\n endMs = Infinity;\n }\n\n return { startMs, endMs };\n}\n\n/**\n * Check if an element is temporally visible at the given time.\n */\nexport function isVisibleAtTime(element: Element, timeMs: number): boolean {\n const { startMs, endMs } = getTemporalBounds(element);\n return timeMs >= startMs && timeMs <= endMs;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Default timegroup dimensions when not measurable */\nexport const DEFAULT_WIDTH = 1920;\nexport const DEFAULT_HEIGHT = 1080;\n\n/** Default scale for thumbnail captures */\nexport const DEFAULT_THUMBNAIL_SCALE = 0.25;\n\n/** Default timeout for blocking content readiness mode (ms) */\nexport const DEFAULT_BLOCKING_TIMEOUT_MS = 5000;\n\n// ============================================================================\n// Container Creation\n// ============================================================================\n\n/**\n * Options for creating a preview container.\n */\nexport interface PreviewContainerOptions {\n width: number;\n height: number;\n background?: string;\n position?: \"relative\" | \"absolute\" | \"fixed\";\n}\n\n/**\n * Create a preview container with standard styling.\n * Consolidates the repeated container creation pattern across preview functions.\n */\nexport function createPreviewContainer(options: PreviewContainerOptions): HTMLDivElement {\n const { width, height, background = \"#000\", position = \"relative\" } = options;\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n width: ${width}px;\n height: ${height}px;\n position: ${position};\n overflow: hidden;\n background: ${background};\n `;\n return container;\n}\n\n// ============================================================================\n// Style Injection\n// ============================================================================\n\n/**\n * Inject document styles into a container for foreignObject rendering.\n * SVG foreignObject needs all CSS rules inlined since it can't access\n * the document's stylesheets.\n */\nexport function injectDocumentStyles(\n container: HTMLElement,\n collectStyles: () => string,\n): HTMLStyleElement {\n const styleEl = document.createElement(\"style\");\n styleEl.textContent = collectStyles();\n container.appendChild(styleEl);\n return styleEl;\n}\n"],"mappings":";;;;AAwBA,SAAgB,WAAW,IAAoC;AAC7D,QAAO,iBAAiB,MAAM,eAAe;;;;;;;;;AAU/C,SAAgB,kBAAkB,IAAiD;AAEjF,KAAI,CAAC,WAAW,GAAG,CACjB,QAAO;EAAE,SAAS;EAAW,OAAO;EAAU;CAIhD,MAAM,WAAW;CACjB,IAAI,UAAU,SAAS,eAAe;CACtC,IAAI,QAAQ,SAAS,aAAa;AAGlC,KAAI,SAAS,SAAS;AACpB,YAAU;AACV,UAAQ;;AAGV,QAAO;EAAE;EAAS;EAAO;;;;;AAM3B,SAAgB,gBAAgB,SAAkB,QAAyB;CACzE,MAAM,EAAE,SAAS,UAAU,kBAAkB,QAAQ;AACrD,QAAO,UAAU,WAAW,UAAU;;;AAQxC,MAAa,gBAAgB;AAC7B,MAAa,iBAAiB;;AAG9B,MAAa,0BAA0B;;AAGvC,MAAa,8BAA8B;;;;;AAoB3C,SAAgB,uBAAuB,SAAkD;CACvF,MAAM,EAAE,OAAO,QAAQ,aAAa,QAAQ,WAAW,eAAe;CAEtE,MAAM,YAAY,SAAS,cAAc,MAAM;AAC/C,WAAU,MAAM,UAAU;aACf,MAAM;cACL,OAAO;gBACL,SAAS;;kBAEP,WAAW;;AAE3B,QAAO"}