@editframe/elements 0.37.3-beta → 0.38.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 (327) hide show
  1. package/dist/EF_FRAMEGEN.js +17 -14
  2. package/dist/EF_FRAMEGEN.js.map +1 -1
  3. package/dist/EF_RENDERING.js.map +1 -1
  4. package/dist/canvas/EFCanvas.d.ts +9 -2
  5. package/dist/canvas/EFCanvas.js +14 -4
  6. package/dist/canvas/EFCanvas.js.map +1 -1
  7. package/dist/canvas/EFCanvasItem.d.ts +2 -2
  8. package/dist/canvas/overlays/SelectionOverlay.d.ts +10 -2
  9. package/dist/canvas/overlays/SelectionOverlay.js +5 -12
  10. package/dist/canvas/overlays/SelectionOverlay.js.map +1 -1
  11. package/dist/canvas/overlays/overlayState.js.map +1 -1
  12. package/dist/canvas/selection/SelectionController.js.map +1 -1
  13. package/dist/elements/EFAudio.d.ts +1 -11
  14. package/dist/elements/EFAudio.js +2 -10
  15. package/dist/elements/EFAudio.js.map +1 -1
  16. package/dist/elements/EFCaptions.d.ts +5 -9
  17. package/dist/elements/EFCaptions.js +34 -11
  18. package/dist/elements/EFCaptions.js.map +1 -1
  19. package/dist/elements/EFImage.d.ts +10 -8
  20. package/dist/elements/EFImage.js +117 -32
  21. package/dist/elements/EFImage.js.map +1 -1
  22. package/dist/elements/EFMedia/AssetMediaEngine.js +2 -2
  23. package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
  24. package/dist/elements/EFMedia/BaseMediaEngine.js +15 -92
  25. package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
  26. package/dist/elements/EFMedia/BufferedSeekingInput.js +10 -11
  27. package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
  28. package/dist/elements/EFMedia/{AssetIdMediaEngine.js → FileMediaEngine.js} +44 -24
  29. package/dist/elements/EFMedia/FileMediaEngine.js.map +1 -0
  30. package/dist/elements/EFMedia/JitMediaEngine.js +14 -13
  31. package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
  32. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
  33. package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
  34. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +12 -7
  35. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
  36. package/dist/elements/EFMedia/shared/timeoutUtils.js +44 -0
  37. package/dist/elements/EFMedia/shared/timeoutUtils.js.map +1 -0
  38. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +1 -1
  39. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
  40. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +4 -4
  41. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
  42. package/dist/elements/EFMedia.d.ts +14 -8
  43. package/dist/elements/EFMedia.js +52 -19
  44. package/dist/elements/EFMedia.js.map +1 -1
  45. package/dist/elements/EFPanZoom.d.ts +2 -2
  46. package/dist/elements/EFPanZoom.js +1 -1
  47. package/dist/elements/EFPanZoom.js.map +1 -1
  48. package/dist/elements/EFSourceMixin.js +16 -8
  49. package/dist/elements/EFSourceMixin.js.map +1 -1
  50. package/dist/elements/EFSurface.d.ts +5 -8
  51. package/dist/elements/EFSurface.js +4 -43
  52. package/dist/elements/EFSurface.js.map +1 -1
  53. package/dist/elements/EFTemporal.d.ts +33 -8
  54. package/dist/elements/EFTemporal.js +92 -40
  55. package/dist/elements/EFTemporal.js.map +1 -1
  56. package/dist/elements/EFText.d.ts +3 -0
  57. package/dist/elements/EFText.js +54 -21
  58. package/dist/elements/EFText.js.map +1 -1
  59. package/dist/elements/EFTextSegment.js +8 -4
  60. package/dist/elements/EFTextSegment.js.map +1 -1
  61. package/dist/elements/EFTimegroup.d.ts +26 -43
  62. package/dist/elements/EFTimegroup.js +295 -314
  63. package/dist/elements/EFTimegroup.js.map +1 -1
  64. package/dist/elements/EFVideo.d.ts +44 -42
  65. package/dist/elements/EFVideo.js +259 -172
  66. package/dist/elements/EFVideo.js.map +1 -1
  67. package/dist/elements/EFWaveform.d.ts +3 -8
  68. package/dist/elements/EFWaveform.js +18 -13
  69. package/dist/elements/EFWaveform.js.map +1 -1
  70. package/dist/elements/ElementPositionInfo.js.map +1 -1
  71. package/dist/elements/FetchMixin.js.map +1 -1
  72. package/dist/elements/TargetController.d.ts +0 -3
  73. package/dist/elements/TargetController.js +12 -35
  74. package/dist/elements/TargetController.js.map +1 -1
  75. package/dist/elements/TimegroupController.js.map +1 -1
  76. package/dist/elements/cloneFactoryRegistry.d.ts +14 -0
  77. package/dist/elements/cloneFactoryRegistry.js +15 -0
  78. package/dist/elements/cloneFactoryRegistry.js.map +1 -0
  79. package/dist/elements/renderTemporalAudio.js +8 -6
  80. package/dist/elements/renderTemporalAudio.js.map +1 -1
  81. package/dist/elements/setupTemporalHierarchy.js +62 -0
  82. package/dist/elements/setupTemporalHierarchy.js.map +1 -0
  83. package/dist/elements/updateAnimations.js +62 -87
  84. package/dist/elements/updateAnimations.js.map +1 -1
  85. package/dist/getRenderInfo.d.ts +3 -2
  86. package/dist/getRenderInfo.js +20 -4
  87. package/dist/getRenderInfo.js.map +1 -1
  88. package/dist/gui/ContextMixin.js +68 -12
  89. package/dist/gui/ContextMixin.js.map +1 -1
  90. package/dist/gui/Controllable.js +1 -1
  91. package/dist/gui/Controllable.js.map +1 -1
  92. package/dist/gui/EFActiveRootTemporal.d.ts +2 -2
  93. package/dist/gui/EFActiveRootTemporal.js.map +1 -1
  94. package/dist/gui/EFControls.d.ts +2 -2
  95. package/dist/gui/EFControls.js +2 -2
  96. package/dist/gui/EFControls.js.map +1 -1
  97. package/dist/gui/EFDial.d.ts +2 -2
  98. package/dist/gui/EFDial.js +12 -9
  99. package/dist/gui/EFDial.js.map +1 -1
  100. package/dist/gui/EFFilmstrip.d.ts +2 -0
  101. package/dist/gui/EFFilmstrip.js +18 -10
  102. package/dist/gui/EFFilmstrip.js.map +1 -1
  103. package/dist/gui/EFFitScale.d.ts +28 -4
  104. package/dist/gui/EFFitScale.js +88 -26
  105. package/dist/gui/EFFitScale.js.map +1 -1
  106. package/dist/gui/EFFocusOverlay.d.ts +2 -2
  107. package/dist/gui/EFFocusOverlay.js +3 -3
  108. package/dist/gui/EFFocusOverlay.js.map +1 -1
  109. package/dist/gui/EFOverlayItem.d.ts +2 -2
  110. package/dist/gui/EFOverlayLayer.d.ts +2 -2
  111. package/dist/gui/EFPause.d.ts +2 -2
  112. package/dist/gui/EFPause.js +1 -1
  113. package/dist/gui/EFPlay.d.ts +2 -2
  114. package/dist/gui/EFPlay.js +1 -1
  115. package/dist/gui/EFPreview.js +1 -1
  116. package/dist/gui/EFResizableBox.d.ts +2 -2
  117. package/dist/gui/EFResizableBox.js +5 -5
  118. package/dist/gui/EFResizableBox.js.map +1 -1
  119. package/dist/gui/EFScrubber.d.ts +2 -2
  120. package/dist/gui/EFScrubber.js +8 -13
  121. package/dist/gui/EFScrubber.js.map +1 -1
  122. package/dist/gui/EFTimeDisplay.d.ts +6 -2
  123. package/dist/gui/EFTimeDisplay.js +25 -7
  124. package/dist/gui/EFTimeDisplay.js.map +1 -1
  125. package/dist/gui/EFTimelineRuler.d.ts +2 -2
  126. package/dist/gui/EFTimelineRuler.js +3 -3
  127. package/dist/gui/EFTimelineRuler.js.map +1 -1
  128. package/dist/gui/EFToggleLoop.d.ts +2 -2
  129. package/dist/gui/EFToggleLoop.js +1 -1
  130. package/dist/gui/EFTogglePlay.d.ts +2 -2
  131. package/dist/gui/EFTogglePlay.js +1 -1
  132. package/dist/gui/EFTransformHandles.d.ts +2 -2
  133. package/dist/gui/EFTransformHandles.js +6 -6
  134. package/dist/gui/EFTransformHandles.js.map +1 -1
  135. package/dist/gui/EFWorkbench.d.ts +40 -36
  136. package/dist/gui/EFWorkbench.js +436 -822
  137. package/dist/gui/EFWorkbench.js.map +1 -1
  138. package/dist/gui/FitScaleHelpers.js.map +1 -1
  139. package/dist/gui/PlaybackController.d.ts +3 -8
  140. package/dist/gui/PlaybackController.js +59 -56
  141. package/dist/gui/PlaybackController.js.map +1 -1
  142. package/dist/gui/TWMixin.js +1 -1
  143. package/dist/gui/TWMixin.js.map +1 -1
  144. package/dist/gui/TargetOrContextMixin.js +43 -6
  145. package/dist/gui/TargetOrContextMixin.js.map +1 -1
  146. package/dist/gui/ef-theme.css +136 -0
  147. package/dist/gui/hierarchy/EFHierarchy.d.ts +2 -2
  148. package/dist/gui/hierarchy/EFHierarchy.js +14 -24
  149. package/dist/gui/hierarchy/EFHierarchy.js.map +1 -1
  150. package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
  151. package/dist/gui/hierarchy/EFHierarchyItem.js +22 -10
  152. package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -1
  153. package/dist/gui/icons.js.map +1 -1
  154. package/dist/gui/previewSettingsContext.d.ts +18 -0
  155. package/dist/gui/previewSettingsContext.js.map +1 -1
  156. package/dist/gui/theme.js +34 -0
  157. package/dist/gui/theme.js.map +1 -0
  158. package/dist/gui/timeline/EFTimeline.d.ts +2 -2
  159. package/dist/gui/timeline/EFTimeline.js +70 -52
  160. package/dist/gui/timeline/EFTimeline.js.map +1 -1
  161. package/dist/gui/timeline/EFTimelineRow.d.ts +5 -3
  162. package/dist/gui/timeline/EFTimelineRow.js +55 -32
  163. package/dist/gui/timeline/EFTimelineRow.js.map +1 -1
  164. package/dist/gui/timeline/TrimHandles.d.ts +23 -9
  165. package/dist/gui/timeline/TrimHandles.js +224 -51
  166. package/dist/gui/timeline/TrimHandles.js.map +1 -1
  167. package/dist/gui/timeline/flattenHierarchy.js.map +1 -1
  168. package/dist/gui/timeline/timelineEditingContext.d.ts +34 -0
  169. package/dist/gui/timeline/timelineEditingContext.js +24 -0
  170. package/dist/gui/timeline/timelineEditingContext.js.map +1 -0
  171. package/dist/gui/timeline/timelineStateContext.js.map +1 -1
  172. package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
  173. package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -1
  174. package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +2 -3
  175. package/dist/gui/timeline/tracks/CaptionsTrack.js +17 -75
  176. package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -1
  177. package/dist/gui/timeline/tracks/EFThumbnailStrip.d.ts +52 -0
  178. package/dist/gui/timeline/tracks/EFThumbnailStrip.js +596 -0
  179. package/dist/gui/timeline/tracks/EFThumbnailStrip.js.map +1 -0
  180. package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -1
  181. package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -1
  182. package/dist/gui/timeline/tracks/TextTrack.d.ts +3 -2
  183. package/dist/gui/timeline/tracks/TextTrack.js +17 -43
  184. package/dist/gui/timeline/tracks/TextTrack.js.map +1 -1
  185. package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +3 -4
  186. package/dist/gui/timeline/tracks/TimegroupTrack.js +33 -23
  187. package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
  188. package/dist/gui/timeline/tracks/TrackItem.d.ts +7 -9
  189. package/dist/gui/timeline/tracks/TrackItem.js +18 -17
  190. package/dist/gui/timeline/tracks/TrackItem.js.map +1 -1
  191. package/dist/gui/timeline/tracks/VideoTrack.d.ts +3 -3
  192. package/dist/gui/timeline/tracks/VideoTrack.js +11 -14
  193. package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -1
  194. package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -1
  195. package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -1
  196. package/dist/gui/timeline/tracks/waveformUtils.js +1 -1
  197. package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -1
  198. package/dist/gui/tree/EFTree.d.ts +2 -2
  199. package/dist/gui/tree/EFTree.js +8 -14
  200. package/dist/gui/tree/EFTree.js.map +1 -1
  201. package/dist/gui/tree/EFTreeItem.d.ts +2 -2
  202. package/dist/gui/tree/EFTreeItem.js +3 -3
  203. package/dist/gui/tree/EFTreeItem.js.map +1 -1
  204. package/dist/gui/tree/treeContext.js.map +1 -1
  205. package/dist/index.d.ts +10 -8
  206. package/dist/index.js +6 -5
  207. package/dist/index.js.map +1 -1
  208. package/dist/node.d.ts +2 -2
  209. package/dist/node.js +2 -2
  210. package/dist/preview/AdaptiveResolutionTracker.js +3 -3
  211. package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
  212. package/dist/preview/FrameController.d.ts +2 -17
  213. package/dist/preview/FrameController.js +40 -63
  214. package/dist/preview/FrameController.js.map +1 -1
  215. package/dist/preview/QualityUpgradeScheduler.d.ts +76 -0
  216. package/dist/preview/QualityUpgradeScheduler.js +158 -0
  217. package/dist/preview/QualityUpgradeScheduler.js.map +1 -0
  218. package/dist/preview/RenderContext.d.ts +119 -1
  219. package/dist/preview/RenderContext.js +21 -3
  220. package/dist/preview/RenderContext.js.map +1 -1
  221. package/dist/preview/RenderProfiler.js.map +1 -1
  222. package/dist/preview/RenderStats.js +85 -0
  223. package/dist/preview/RenderStats.js.map +1 -0
  224. package/dist/preview/encoding/canvasEncoder.js +2 -52
  225. package/dist/preview/encoding/canvasEncoder.js.map +1 -1
  226. package/dist/preview/encoding/mainThreadEncoder.js.map +1 -1
  227. package/dist/preview/encoding/workerEncoder.js.map +1 -1
  228. package/dist/preview/logger.js.map +1 -1
  229. package/dist/preview/previewSettings.d.ts +34 -0
  230. package/dist/preview/previewSettings.js +29 -17
  231. package/dist/preview/previewSettings.js.map +1 -1
  232. package/dist/preview/previewTypes.js +4 -4
  233. package/dist/preview/previewTypes.js.map +1 -1
  234. package/dist/preview/renderElementToCanvas.d.ts +44 -0
  235. package/dist/preview/renderElementToCanvas.js +72 -0
  236. package/dist/preview/renderElementToCanvas.js.map +1 -0
  237. package/dist/preview/renderTimegroupToCanvas.d.ts +134 -32
  238. package/dist/preview/renderTimegroupToCanvas.js +321 -146
  239. package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
  240. package/dist/preview/renderTimegroupToCanvas.types.d.ts +51 -0
  241. package/dist/preview/renderTimegroupToVideo.d.ts +20 -35
  242. package/dist/preview/renderTimegroupToVideo.js +94 -106
  243. package/dist/preview/renderTimegroupToVideo.js.map +1 -1
  244. package/dist/preview/renderTimegroupToVideo.types.d.ts +42 -0
  245. package/dist/preview/renderVideoToVideo.js +286 -0
  246. package/dist/preview/renderVideoToVideo.js.map +1 -0
  247. package/dist/preview/renderers.d.ts +56 -0
  248. package/dist/preview/renderers.js +13 -1
  249. package/dist/preview/renderers.js.map +1 -1
  250. package/dist/preview/rendering/ScaleConfig.js +74 -0
  251. package/dist/preview/rendering/ScaleConfig.js.map +1 -0
  252. package/dist/preview/rendering/inlineImages.d.ts +13 -0
  253. package/dist/preview/rendering/inlineImages.js +7 -44
  254. package/dist/preview/rendering/inlineImages.js.map +1 -1
  255. package/dist/preview/rendering/loadImage.d.ts +8 -0
  256. package/dist/preview/rendering/loadImage.js +22 -0
  257. package/dist/preview/rendering/loadImage.js.map +1 -0
  258. package/dist/preview/rendering/renderToImageNative.js +3 -3
  259. package/dist/preview/rendering/renderToImageNative.js.map +1 -1
  260. package/dist/preview/rendering/serializeTimelineDirect.js +224 -68
  261. package/dist/preview/rendering/serializeTimelineDirect.js.map +1 -1
  262. package/dist/preview/statsTrackingStrategy.js +1 -101
  263. package/dist/preview/statsTrackingStrategy.js.map +1 -1
  264. package/dist/preview/workers/WorkerPool.js +0 -1
  265. package/dist/preview/workers/WorkerPool.js.map +1 -1
  266. package/dist/preview/workers/encoderWorkerInline.js +21 -54
  267. package/dist/preview/workers/encoderWorkerInline.js.map +1 -1
  268. package/dist/render/EFRenderAPI.d.ts +2 -1
  269. package/dist/render/EFRenderAPI.js +12 -36
  270. package/dist/render/EFRenderAPI.js.map +1 -1
  271. package/dist/render/getRenderData.js +4 -4
  272. package/dist/render/getRenderData.js.map +1 -1
  273. package/dist/style.css +114 -163
  274. package/dist/transcoding/cache/RequestDeduplicator.js +1 -0
  275. package/dist/transcoding/cache/RequestDeduplicator.js.map +1 -1
  276. package/dist/transcoding/types/index.d.ts +1 -1
  277. package/dist/transcoding/utils/UrlGenerator.js +10 -3
  278. package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
  279. package/dist/utils/LRUCache.js +1 -0
  280. package/dist/utils/LRUCache.js.map +1 -1
  281. package/dist/utils/frameTime.js +23 -1
  282. package/dist/utils/frameTime.js.map +1 -1
  283. package/package.json +45 -8
  284. package/scripts/build-css.js +8 -1
  285. package/test/setup.ts +0 -1
  286. package/test/useAssetMSW.ts +50 -0
  287. package/test/visualRegressionUtils.ts +23 -9
  288. package/tsdown.config.ts +6 -1
  289. package/dist/_virtual/rolldown_runtime.js +0 -27
  290. package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +0 -1
  291. package/dist/elements/EFThumbnailStrip.d.ts +0 -167
  292. package/dist/elements/EFThumbnailStrip.js +0 -731
  293. package/dist/elements/EFThumbnailStrip.js.map +0 -1
  294. package/dist/elements/SessionThumbnailCache.js +0 -154
  295. package/dist/elements/SessionThumbnailCache.js.map +0 -1
  296. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +0 -688
  297. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +0 -1
  298. package/dist/node_modules/react/cjs/react.development.js +0 -1521
  299. package/dist/node_modules/react/cjs/react.development.js.map +0 -1
  300. package/dist/node_modules/react/index.js +0 -13
  301. package/dist/node_modules/react/index.js.map +0 -1
  302. package/dist/node_modules/react/jsx-runtime.js +0 -13
  303. package/dist/node_modules/react/jsx-runtime.js.map +0 -1
  304. package/dist/preview/encoding/types.d.ts +0 -1
  305. package/dist/preview/renderTimegroupPreview.js +0 -686
  306. package/dist/preview/renderTimegroupPreview.js.map +0 -1
  307. package/dist/preview/rendering/renderToImage.d.ts +0 -2
  308. package/dist/preview/rendering/renderToImage.js +0 -95
  309. package/dist/preview/rendering/renderToImage.js.map +0 -1
  310. package/dist/preview/rendering/renderToImageForeignObject.js +0 -163
  311. package/dist/preview/rendering/renderToImageForeignObject.js.map +0 -1
  312. package/dist/preview/rendering/renderToImageNative.d.ts +0 -1
  313. package/dist/preview/rendering/svgSerializer.js +0 -43
  314. package/dist/preview/rendering/svgSerializer.js.map +0 -1
  315. package/dist/preview/rendering/types.d.ts +0 -2
  316. package/dist/preview/thumbnailCacheSettings.js +0 -52
  317. package/dist/preview/thumbnailCacheSettings.js.map +0 -1
  318. package/dist/sandbox/PlaybackControls.d.ts +0 -1
  319. package/dist/sandbox/PlaybackControls.js +0 -10
  320. package/dist/sandbox/PlaybackControls.js.map +0 -1
  321. package/dist/sandbox/ScenarioRunner.d.ts +0 -1
  322. package/dist/sandbox/ScenarioRunner.js +0 -1
  323. package/dist/sandbox/defineSandbox.d.ts +0 -1
  324. package/dist/sandbox/index.d.ts +0 -3
  325. package/dist/sandbox/index.js +0 -2
  326. package/test/EFVideo.framegen.browsertest.ts +0 -80
  327. package/test/thumbnail-performance-test.html +0 -116
@@ -1,5 +1,27 @@
1
1
  //#region src/utils/frameTime.ts
2
2
  /**
3
+ * Frame timing utilities for quantizing time values to frame boundaries.
4
+ * These utilities ensure consistent frame-aligned timing across the codebase.
5
+ */
6
+ /** Default FPS when none is specified */
7
+ const DEFAULT_FPS = 30;
8
+ /**
9
+ * Calculate the duration of a single frame in milliseconds.
10
+ */
11
+ function calculateFrameIntervalMs(fps) {
12
+ if (fps <= 0) return 1e3 / DEFAULT_FPS;
13
+ return 1e3 / fps;
14
+ }
15
+ /**
16
+ * Quantize a time value (in milliseconds) to the nearest frame boundary.
17
+ * This ensures frame markers align perfectly with playhead position.
18
+ */
19
+ function quantizeToFrameTimeMs(timeMs, fps) {
20
+ if (!fps || fps <= 0) return timeMs;
21
+ const frameDurationMs = calculateFrameIntervalMs(fps);
22
+ return Math.round(timeMs / frameDurationMs) * frameDurationMs;
23
+ }
24
+ /**
3
25
  * Quantize a time value (in seconds) to the nearest frame boundary.
4
26
  * This ensures time values align with frame boundaries for consistent rendering.
5
27
  */
@@ -10,5 +32,5 @@ function quantizeToFrameTimeS(timeSeconds, fps) {
10
32
  }
11
33
 
12
34
  //#endregion
13
- export { quantizeToFrameTimeS };
35
+ export { quantizeToFrameTimeMs, quantizeToFrameTimeS };
14
36
  //# sourceMappingURL=frameTime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frameTime.js","names":[],"sources":["../../src/utils/frameTime.ts"],"sourcesContent":["/**\n * Frame timing utilities for quantizing time values to frame boundaries.\n * These utilities ensure consistent frame-aligned timing across the codebase.\n */\n\n/** Default FPS when none is specified */\nexport const DEFAULT_FPS = 30;\n\n/**\n * Calculate the duration of a single frame in milliseconds.\n */\nexport function calculateFrameIntervalMs(fps: number): number {\n if (fps <= 0) return 1000 / DEFAULT_FPS;\n return 1000 / fps;\n}\n\n/**\n * Quantize a time value (in milliseconds) to the nearest frame boundary.\n * This ensures frame markers align perfectly with playhead position.\n */\nexport function quantizeToFrameTimeMs(timeMs: number, fps: number): number {\n if (!fps || fps <= 0) return timeMs;\n const frameDurationMs = calculateFrameIntervalMs(fps);\n return Math.round(timeMs / frameDurationMs) * frameDurationMs;\n}\n\n/**\n * Quantize a time value (in seconds) to the nearest frame boundary.\n * This ensures time values align with frame boundaries for consistent rendering.\n */\nexport function quantizeToFrameTimeS(timeSeconds: number, fps: number): number {\n if (!fps || fps <= 0) return timeSeconds;\n const frameDurationS = 1 / fps;\n return Math.round(timeSeconds / frameDurationS) * frameDurationS;\n}\n\n/**\n * Clamp and quantize a seek time to valid range.\n * Prevents \"Sample not found\" errors at video boundaries.\n * \n * @param desiredSeekTimeMs - The desired seek time in milliseconds\n * @param durationMs - The total duration in milliseconds\n * @param fps - Frames per second (defaults to 30)\n * @returns Clamped and quantized time in milliseconds\n */\nexport function clampAndQuantizeSeekTimeMs(\n desiredSeekTimeMs: number,\n durationMs: number,\n fps: number = DEFAULT_FPS,\n): number {\n if (durationMs <= 0) return 0;\n\n // Quantize to frame boundaries\n const quantizedMs = quantizeToFrameTimeMs(desiredSeekTimeMs, fps);\n\n // Clamp to valid range [0, lastFrameTime]\n // The last valid frame is at durationMs - frameDurationMs to ensure we don't\n // seek past the last decodable frame\n const frameDurationMs = calculateFrameIntervalMs(fps);\n const maxValidTime = Math.max(0, durationMs - frameDurationMs);\n return Math.max(0, Math.min(quantizedMs, maxValidTime));\n}\n\n\n\n\n"],"mappings":";;;;;AA8BA,SAAgB,qBAAqB,aAAqB,KAAqB;AAC7E,KAAI,CAAC,OAAO,OAAO,EAAG,QAAO;CAC7B,MAAM,iBAAiB,IAAI;AAC3B,QAAO,KAAK,MAAM,cAAc,eAAe,GAAG"}
1
+ {"version":3,"file":"frameTime.js","names":[],"sources":["../../src/utils/frameTime.ts"],"sourcesContent":["/**\n * Frame timing utilities for quantizing time values to frame boundaries.\n * These utilities ensure consistent frame-aligned timing across the codebase.\n */\n\n/** Default FPS when none is specified */\nexport const DEFAULT_FPS = 30;\n\n/**\n * Calculate the duration of a single frame in milliseconds.\n */\nexport function calculateFrameIntervalMs(fps: number): number {\n if (fps <= 0) return 1000 / DEFAULT_FPS;\n return 1000 / fps;\n}\n\n/**\n * Quantize a time value (in milliseconds) to the nearest frame boundary.\n * This ensures frame markers align perfectly with playhead position.\n */\nexport function quantizeToFrameTimeMs(timeMs: number, fps: number): number {\n if (!fps || fps <= 0) return timeMs;\n const frameDurationMs = calculateFrameIntervalMs(fps);\n return Math.round(timeMs / frameDurationMs) * frameDurationMs;\n}\n\n/**\n * Quantize a time value (in seconds) to the nearest frame boundary.\n * This ensures time values align with frame boundaries for consistent rendering.\n */\nexport function quantizeToFrameTimeS(timeSeconds: number, fps: number): number {\n if (!fps || fps <= 0) return timeSeconds;\n const frameDurationS = 1 / fps;\n return Math.round(timeSeconds / frameDurationS) * frameDurationS;\n}\n\n/**\n * Clamp and quantize a seek time to valid range.\n * Prevents \"Sample not found\" errors at video boundaries.\n *\n * @param desiredSeekTimeMs - The desired seek time in milliseconds\n * @param durationMs - The total duration in milliseconds\n * @param fps - Frames per second (defaults to 30)\n * @returns Clamped and quantized time in milliseconds\n */\nexport function clampAndQuantizeSeekTimeMs(\n desiredSeekTimeMs: number,\n durationMs: number,\n fps: number = DEFAULT_FPS,\n): number {\n if (durationMs <= 0) return 0;\n\n // Quantize to frame boundaries\n const quantizedMs = quantizeToFrameTimeMs(desiredSeekTimeMs, fps);\n\n // Clamp to valid range [0, lastFrameTime]\n // The last valid frame is at durationMs - frameDurationMs to ensure we don't\n // seek past the last decodable frame\n const frameDurationMs = calculateFrameIntervalMs(fps);\n const maxValidTime = Math.max(0, durationMs - frameDurationMs);\n return Math.max(0, Math.min(quantizedMs, maxValidTime));\n}\n"],"mappings":";;;;;;AAMA,MAAa,cAAc;;;;AAK3B,SAAgB,yBAAyB,KAAqB;AAC5D,KAAI,OAAO,EAAG,QAAO,MAAO;AAC5B,QAAO,MAAO;;;;;;AAOhB,SAAgB,sBAAsB,QAAgB,KAAqB;AACzE,KAAI,CAAC,OAAO,OAAO,EAAG,QAAO;CAC7B,MAAM,kBAAkB,yBAAyB,IAAI;AACrD,QAAO,KAAK,MAAM,SAAS,gBAAgB,GAAG;;;;;;AAOhD,SAAgB,qBAAqB,aAAqB,KAAqB;AAC7E,KAAI,CAAC,OAAO,OAAO,EAAG,QAAO;CAC7B,MAAM,iBAAiB,IAAI;AAC3B,QAAO,KAAK,MAAM,cAAc,eAAe,GAAG"}
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "@editframe/elements",
3
- "version": "0.37.3-beta",
3
+ "version": "0.38.1",
4
4
  "description": "",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/editframe/elements.git",
8
+ "directory": "packages/elements"
9
+ },
5
10
  "type": "module",
6
11
  "scripts": {
7
- "typecheck": "tsc --noEmit --emitDeclarationOnly false",
12
+ "typecheck": "tsc --noEmit",
8
13
  "build": "tsdown && node scripts/build-css.js",
9
14
  "build:watch": "tsdown --watch",
10
15
  "typedoc": "(typedoc --json ./types.json --plugin typedoc-plugin-zod --excludeExternals ./src || true) && ([ -f ./types.json ] && jq -c . ./types.json > ./types.tmp.json && mv ./types.tmp.json ./types.json || true)"
@@ -13,7 +18,7 @@
13
18
  "license": "UNLICENSED",
14
19
  "dependencies": {
15
20
  "@bramus/style-observer": "^1.3.0",
16
- "@editframe/assets": "0.37.3-beta",
21
+ "@editframe/assets": "0.38.1",
17
22
  "@lit/context": "^1.1.6",
18
23
  "@opentelemetry/api": "^1.9.0",
19
24
  "@opentelemetry/context-zone": "^1.26.0",
@@ -28,15 +33,14 @@
28
33
  "zod": "^3.24.1"
29
34
  },
30
35
  "devDependencies": {
36
+ "@jridgewell/trace-mapping": "^0.3.28",
31
37
  "@types/dom-webcodecs": "^0.1.11",
32
- "@types/node": "^20.14.13",
38
+ "@types/node": "^22.0.0",
33
39
  "autoprefixer": "^10.4.19",
34
40
  "postcss": "^8.4.38",
35
41
  "tailwindcss": "^3.4.3",
36
- "typescript": "^5.5.4"
42
+ "typescript": "^5.9.3"
37
43
  },
38
- "main": "./dist/index.js",
39
- "module": "./dist/index.js",
40
44
  "types": "./dist/index.d.ts",
41
45
  "exports": {
42
46
  ".": {
@@ -51,6 +55,18 @@
51
55
  "default": "./dist/node.js"
52
56
  }
53
57
  },
58
+ "./preview/renderTimegroupToCanvas": {
59
+ "import": {
60
+ "types": "./dist/preview/renderTimegroupToCanvas.d.ts",
61
+ "default": "./dist/preview/renderTimegroupToCanvas.js"
62
+ }
63
+ },
64
+ "./preview/renderTimegroupToVideo": {
65
+ "import": {
66
+ "types": "./dist/preview/renderTimegroupToVideo.d.ts",
67
+ "default": "./dist/preview/renderTimegroupToVideo.js"
68
+ }
69
+ },
54
70
  "./package.json": "./package.json",
55
71
  "./styles.css": "./dist/style.css",
56
72
  "./types.json": "./types.json"
@@ -63,15 +79,36 @@
63
79
  "default": "./dist/index.js"
64
80
  }
65
81
  },
82
+ "./server": {
83
+ "import": {
84
+ "types": "./dist/server.d.ts",
85
+ "default": "./dist/server.js"
86
+ }
87
+ },
66
88
  "./node": {
67
89
  "import": {
68
90
  "types": "./dist/node.d.ts",
69
91
  "default": "./dist/node.js"
70
92
  }
71
93
  },
94
+ "./preview/renderTimegroupToVideo": {
95
+ "import": {
96
+ "types": "./dist/preview/renderTimegroupToVideo.d.ts",
97
+ "default": "./dist/preview/renderTimegroupToVideo.js"
98
+ }
99
+ },
100
+ "./preview/renderTimegroupToCanvas": {
101
+ "import": {
102
+ "types": "./dist/preview/renderTimegroupToCanvas.d.ts",
103
+ "default": "./dist/preview/renderTimegroupToCanvas.js"
104
+ }
105
+ },
72
106
  "./package.json": "./package.json",
73
107
  "./styles.css": "./dist/style.css",
108
+ "./theme.css": "./dist/gui/ef-theme.css",
74
109
  "./types.json": "./types.json"
75
110
  }
76
- }
111
+ },
112
+ "main": "./dist/index.js",
113
+ "module": "./dist/index.js"
77
114
  }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { mkdirSync, readFileSync, writeFileSync, cpSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import autoprefixer from "autoprefixer";
@@ -14,6 +14,7 @@ const configPath = join(__dirname, "..", "tailwind.config.ts");
14
14
 
15
15
  // Ensure dist directory exists
16
16
  mkdirSync(distDir, { recursive: true });
17
+ mkdirSync(join(distDir, "gui"), { recursive: true });
17
18
 
18
19
  // Read source CSS
19
20
  const cssPath = join(srcDir, "elements.css");
@@ -30,6 +31,12 @@ postcss([tailwindcss({ config: configPath }), autoprefixer()])
30
31
  writeFileSync(join(distDir, "style.css.map"), result.map.toString());
31
32
  }
32
33
  console.log("✅ CSS processed and written to dist/style.css");
34
+
35
+ // Copy theme CSS file
36
+ const themeCssPath = join(srcDir, "gui", "ef-theme.css");
37
+ const themeDistPath = join(distDir, "gui", "ef-theme.css");
38
+ cpSync(themeCssPath, themeDistPath);
39
+ console.log("✅ Theme CSS copied to dist/gui/ef-theme.css");
33
40
  })
34
41
  .catch((error) => {
35
42
  console.error("❌ CSS processing failed:", error);
package/test/setup.ts CHANGED
@@ -62,7 +62,6 @@ afterAll(() => {
62
62
  if (typeof window !== "undefined") {
63
63
  // Always set the flag, creating it if it doesn't exist
64
64
  // This handles both profiled and non-profiled test runs
65
- console.log("[Profiler] Signaling stop...");
66
65
  (window as any).__PROFILER_STOP_REQUESTED__ = true;
67
66
 
68
67
  // Give profiler time to detect the signal and retrieve profile data
@@ -100,4 +100,54 @@ export const assetMSWHandlers = [
100
100
  },
101
101
  });
102
102
  }),
103
+
104
+ http.get("/api/v1/files/:id/index", async () => {
105
+ const mockIndex = {
106
+ 0: {
107
+ duration: 10000,
108
+ timescale: 1000,
109
+ fragments: [
110
+ {
111
+ offset: 0,
112
+ size: 1024,
113
+ timestamp: 0,
114
+ duration: 10000,
115
+ },
116
+ ],
117
+ },
118
+ };
119
+
120
+ return HttpResponse.json(mockIndex, {
121
+ headers: {
122
+ "Content-Type": "application/json",
123
+ },
124
+ });
125
+ }),
126
+
127
+ http.get("/api/v1/files/:id/tracks/:trackId", async ({ request }) => {
128
+ const rangeHeader = request.headers.get("range");
129
+
130
+ if (rangeHeader) {
131
+ const mockData = new ArrayBuffer(1024);
132
+ return new HttpResponse(mockData, {
133
+ status: 206,
134
+ headers: {
135
+ "Content-Type": "video/mp4",
136
+ "Accept-Ranges": "bytes",
137
+ "Content-Range": rangeHeader,
138
+ "Content-Length": "1024",
139
+ },
140
+ });
141
+ }
142
+
143
+ const mockData = new ArrayBuffer(1024);
144
+ return new HttpResponse(mockData, {
145
+ status: 200,
146
+ headers: {
147
+ "Content-Type": "video/mp4",
148
+ "Accept-Ranges": "bytes",
149
+ "Content-Length": "1024",
150
+ },
151
+ });
152
+ }),
103
153
  ];
@@ -15,14 +15,28 @@ export interface SnapshotComparisonResult {
15
15
  }
16
16
 
17
17
  /**
18
- * Capture a canvas element as a data URL.
18
+ * Capture a canvas or image as a data URL.
19
19
  * Uses JPEG format with configurable quality for smaller file sizes.
20
20
  */
21
21
  export function captureCanvasAsDataUrl(
22
- canvas: HTMLCanvasElement,
22
+ source: CanvasImageSource | HTMLCanvasElement,
23
23
  format: "image/png" | "image/jpeg" = "image/jpeg",
24
24
  quality: number = 0.85,
25
25
  ): string {
26
+ // If it's already a canvas, use toDataURL directly
27
+ if (source instanceof HTMLCanvasElement) {
28
+ return source.toDataURL(format, quality);
29
+ }
30
+
31
+ // Otherwise, draw to temp canvas first
32
+ const canvas = document.createElement("canvas");
33
+ canvas.width = (source as any).width as number;
34
+ canvas.height = (source as any).height as number;
35
+ const ctx = canvas.getContext("2d");
36
+ if (!ctx) {
37
+ throw new Error("Failed to get canvas 2d context");
38
+ }
39
+ ctx.drawImage(source, 0, 0);
26
40
  return canvas.toDataURL(format, quality);
27
41
  }
28
42
 
@@ -178,7 +192,7 @@ export async function assertCanvasSnapshot(
178
192
  * Throws an assertion error if the diff exceeds the acceptable threshold.
179
193
  */
180
194
  export async function expectCanvasToMatchSnapshot(
181
- canvas: HTMLCanvasElement,
195
+ source: CanvasImageSource | HTMLCanvasElement,
182
196
  testName: string,
183
197
  snapshotName: string,
184
198
  options: {
@@ -187,7 +201,7 @@ export async function expectCanvasToMatchSnapshot(
187
201
  } = {},
188
202
  ): Promise<void> {
189
203
  const result = await assertCanvasSnapshot(
190
- canvas,
204
+ source as unknown as HTMLCanvasElement,
191
205
  testName,
192
206
  snapshotName,
193
207
  options,
@@ -210,12 +224,12 @@ export async function expectCanvasToMatchSnapshot(
210
224
  }
211
225
 
212
226
  /**
213
- * Compare two canvases directly against each other.
227
+ * Compare two canvases or images directly against each other.
214
228
  * Returns comparison results including diff percentage.
215
229
  */
216
230
  export async function compareTwoCanvases(
217
- canvas1: HTMLCanvasElement,
218
- canvas2: HTMLCanvasElement,
231
+ source1: CanvasImageSource | HTMLCanvasElement,
232
+ source2: CanvasImageSource | HTMLCanvasElement,
219
233
  testName: string,
220
234
  comparisonName: string,
221
235
  options: {
@@ -226,8 +240,8 @@ export async function compareTwoCanvases(
226
240
  const { threshold = 0.1, acceptableDiffPercentage = 1.0 } = options;
227
241
 
228
242
  // Use PNG format for consistent comparison (odiff works best with PNG)
229
- const dataUrl1 = captureCanvasAsDataUrl(canvas1, "image/png");
230
- const dataUrl2 = captureCanvasAsDataUrl(canvas2, "image/png");
243
+ const dataUrl1 = captureCanvasAsDataUrl(source1, "image/png");
244
+ const dataUrl2 = captureCanvasAsDataUrl(source2, "image/png");
231
245
 
232
246
  const response = await fetch("/@ef-compare-two-images", {
233
247
  method: "POST",
package/tsdown.config.ts CHANGED
@@ -48,7 +48,12 @@ const inlineCssPlugin = (): Plugin => ({
48
48
 
49
49
  export default defineConfig(
50
50
  createTsdownConfig({
51
- entry: ["src/index.ts", "src/node.ts"],
51
+ entry: [
52
+ "src/index.ts",
53
+ "src/node.ts",
54
+ "src/preview/renderTimegroupToVideo.ts",
55
+ "src/preview/renderTimegroupToCanvas.ts",
56
+ ],
52
57
  plugins: [inlineCssPlugin()],
53
58
  external: [/@editframe\/assets/],
54
59
  publint: false, // Disabled because CSS is built after tsdown
@@ -1,27 +0,0 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __commonJS = (cb, mod) => function() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
13
- key = keys[i];
14
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
15
- get: ((k) => from[k]).bind(null, key),
16
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
- });
18
- }
19
- return to;
20
- };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
22
- value: mod,
23
- enumerable: true
24
- }) : target, mod));
25
-
26
- //#endregion
27
- export { __commonJS, __toESM };
@@ -1 +0,0 @@
1
- {"version":3,"file":"AssetIdMediaEngine.js","names":["data: Record<number, TrackFragmentIndex>","assetId: string","apiHost: string","paths: InitSegmentPaths"],"sources":["../../../src/elements/EFMedia/AssetIdMediaEngine.ts"],"sourcesContent":["import type { TrackFragmentIndex } from \"@editframe/assets\";\nimport type {\n InitSegmentPaths,\n MediaEngine,\n VideoRendition,\n} from \"../../transcoding/types\";\nimport type { UrlGenerator } from \"../../transcoding/utils/UrlGenerator\";\nimport type { EFMedia } from \"../EFMedia\";\nimport { AssetMediaEngine } from \"./AssetMediaEngine\";\n\nexport class AssetIdMediaEngine\n extends AssetMediaEngine\n implements MediaEngine\n{\n static async fetchByAssetId(\n host: EFMedia,\n _urlGenerator: UrlGenerator,\n assetId: string,\n apiHost: string,\n requiredTracks: \"audio\" | \"video\" | \"both\" = \"both\",\n signal?: AbortSignal,\n ) {\n const url = `${apiHost}/api/v1/isobmff_files/${assetId}/index`;\n const response = await host.fetch(url, { signal });\n \n // Check for abort after potentially slow network operation\n signal?.throwIfAborted();\n \n // Check if response is ok before parsing JSON\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Failed to fetch asset index: ${response.status} ${text}`);\n }\n \n // Check content type to avoid parsing non-JSON responses\n const contentType = response.headers.get(\"content-type\");\n if (contentType && !contentType.includes(\"application/json\")) {\n const text = await response.text();\n throw new Error(`Expected JSON but got ${contentType}: ${text.substring(0, 100)}`);\n }\n \n let data: Record<number, TrackFragmentIndex>;\n try {\n data = (await response.json()) as Record<number, TrackFragmentIndex>;\n \n // Check for abort after potentially slow JSON parsing\n signal?.throwIfAborted();\n } catch (error) {\n // If aborted during JSON parsing, re-throw to propagate cancellation\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw error;\n }\n // If JSON parse fails, the response might be \"File not found\" or similar text\n const text = await response.text();\n throw new Error(`Failed to parse JSON response: ${text.substring(0, 100)}`);\n }\n \n const engine = new AssetIdMediaEngine(host, assetId, data, apiHost, _urlGenerator);\n \n // Check for abort after engine construction\n signal?.throwIfAborted();\n \n // Validate that segments are accessible by trying to fetch the first init segment\n // This prevents creating a media engine that will fail on all subsequent segment fetches\n // If segments require authentication that's not available, fail early\n // Only validate tracks that are actually required by the consumer (e.g., EFAudio only needs audio)\n // Skip validation if no signal provided (backwards compatibility) - validation is optional\n if (signal) {\n const videoTrack = engine.getVideoTrackIndex();\n const audioTrack = engine.getAudioTrackIndex();\n const needsVideo = requiredTracks === \"video\" || requiredTracks === \"both\";\n const needsAudio = requiredTracks === \"audio\" || requiredTracks === \"both\";\n \n // Validate video track if required and available\n if (needsVideo && videoTrack && videoTrack.track !== undefined) {\n try {\n await engine.fetchInitSegment(\n { trackId: videoTrack.track, src: engine.src },\n signal,\n );\n } catch (error) {\n // If aborted, re-throw to propagate cancellation\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw error;\n }\n // If fetch fails with 401, segments require authentication that's not available\n // Fail media engine creation early to avoid all subsequent fetch calls\n if (\n error instanceof Error &&\n (error.message.includes(\"401\") ||\n error.message.includes(\"UNAUTHORIZED\") ||\n (error.message.includes(\"Failed to fetch\") && error.message.includes(\"401\")))\n ) {\n throw new Error(`Video segments require authentication: ${error.message}`);\n }\n // For other errors (404, network errors, etc.), allow media engine creation\n // These might be transient or expected in some test scenarios\n }\n }\n \n // Check for abort between validations\n signal?.throwIfAborted();\n \n // Validate audio track if required and available\n if (needsAudio && audioTrack && audioTrack.track !== undefined) {\n try {\n await engine.fetchInitSegment(\n { trackId: audioTrack.track, src: engine.src },\n signal,\n );\n } catch (error) {\n // If aborted, re-throw to propagate cancellation\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw error;\n }\n // If fetch fails with 401, segments require authentication that's not available\n // Fail media engine creation early to avoid all subsequent fetch calls\n if (\n error instanceof Error &&\n (error.message.includes(\"401\") ||\n error.message.includes(\"UNAUTHORIZED\") ||\n (error.message.includes(\"Failed to fetch\") && error.message.includes(\"401\")))\n ) {\n throw new Error(`Audio segments require authentication: ${error.message}`);\n }\n // For other errors (404, network errors, etc.), allow media engine creation\n // These might be transient or expected in some test scenarios\n }\n }\n }\n \n return engine;\n }\n\n constructor(\n host: EFMedia,\n public assetId: string,\n data: Record<number, TrackFragmentIndex>,\n private apiHost: string,\n urlGenerator: UrlGenerator,\n ) {\n // Pass assetId as src to parent constructor for compatibility\n super(host, assetId, urlGenerator);\n // Initialize data after parent constructor\n this.data = data;\n\n // Calculate duration from the data\n const longestFragment = Object.values(this.data).reduce(\n (max, fragment) => Math.max(max, fragment.duration / fragment.timescale),\n 0,\n );\n this.durationMs = longestFragment * 1000;\n \n // Initialize MediaEngine interface properties\n this.templates = {\n initSegment: `${apiHost}/api/v1/isobmff_tracks/${assetId}/{trackId}`,\n mediaSegment: `${apiHost}/api/v1/isobmff_tracks/${assetId}/{trackId}`,\n };\n }\n\n // Override URL-building methods to use API endpoints instead of file paths\n getInitSegmentPaths(): InitSegmentPaths {\n const paths: InitSegmentPaths = {};\n const audioTrack = this.getAudioTrackIndex();\n const videoTrack = this.getVideoTrackIndex();\n\n if (audioTrack !== undefined) {\n paths.audio = {\n path: `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${audioTrack.track}`,\n pos: audioTrack.initSegment.offset,\n size: audioTrack.initSegment.size,\n };\n }\n\n if (videoTrack !== undefined) {\n paths.video = {\n path: `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${videoTrack.track}`,\n pos: videoTrack.initSegment.offset,\n size: videoTrack.initSegment.size,\n };\n }\n\n return paths;\n }\n\n // MediaEngine interface property - initialized in constructor/static fetch\n templates!: { initSegment: string; mediaSegment: string };\n\n buildInitSegmentUrl(trackId: number) {\n return `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${trackId}`;\n }\n\n buildMediaSegmentUrl(trackId: number, _segmentId: number) {\n return `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${trackId}`;\n }\n\n convertToSegmentRelativeTimestamps(\n globalTimestamps: number[],\n segmentId: number,\n rendition: VideoRendition,\n ): number[] {\n if (!rendition.trackId) {\n throw new Error(\n \"[convertToSegmentRelativeTimestamps] Track ID is required for asset metadata\",\n );\n }\n // For AssetMediaEngine, we need to calculate the actual segment start time\n // using the precise segment boundaries from the track fragment index\n const trackData = this.data[rendition.trackId];\n if (!trackData) {\n throw new Error(\"Track not found\");\n }\n const segment = trackData.segments?.[segmentId];\n if (!segment) {\n throw new Error(\"Segment not found\");\n }\n const segmentStartMs = (segment.cts / trackData.timescale) * 1000;\n\n return globalTimestamps.map(\n (globalMs) => (globalMs - segmentStartMs) / 1000,\n );\n }\n}\n"],"mappings":"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"}
@@ -1,167 +0,0 @@
1
- import { EFVideo } from "./EFVideo.js";
2
- import { EFTimegroup } from "./EFTimegroup.js";
3
- import * as lit27 from "lit";
4
- import { LitElement } from "lit";
5
- import * as lit_html26 from "lit-html";
6
- import * as lit_html_directives_ref4 from "lit-html/directives/ref";
7
-
8
- //#region src/elements/EFThumbnailStrip.d.ts
9
- declare class EFThumbnailStrip extends LitElement {
10
- static styles: lit27.CSSResult[];
11
- canvasRef: lit_html_directives_ref4.Ref<HTMLCanvasElement>;
12
- target: string;
13
- thumbnailWidth: number;
14
- gap: number;
15
- startTimeMs?: number;
16
- endTimeMs?: number;
17
- useIntrinsicDuration: boolean;
18
- pixelsPerMs: number;
19
- /** Timeline state context for viewport info */
20
- private _timelineState?;
21
- /** Target element controller */
22
- private _targetController;
23
- private _targetElement;
24
- get targetElement(): EFVideo | EFTimegroup | null;
25
- set targetElement(value: EFVideo | EFTimegroup | null);
26
- /** Host element dimensions */
27
- private _width;
28
- private _height;
29
- /** Scroll container reference */
30
- private _scrollContainer;
31
- private _currentScrollLeft;
32
- /**
33
- * Offset from scroll container's left edge to this element's track.
34
- * Used for sticky positioning when track doesn't start at x=0 (e.g., labels column).
35
- */
36
- private _trackLeftOffset;
37
- /** Current thumbnail slots */
38
- private _thumbnailSlots;
39
- /** Capture in progress flag */
40
- private _captureInProgress;
41
- /** Resize observer */
42
- private _resizeObserver?;
43
- /** Mutation observer for target element changes */
44
- private _mutationObserver?;
45
- /** Animation frame for scroll updates */
46
- private _scrollFrame?;
47
- /** Render request tracking */
48
- private _renderRequested;
49
- /** Track if any thumbnails have been loaded (for ready event) */
50
- private _hasLoadedThumbnails;
51
- /** Track the last epoch we loaded thumbnails for */
52
- private _lastLoadedEpoch;
53
- /** Track layout parameters to avoid unnecessary slot recreation */
54
- private _lastLayoutParams;
55
- connectedCallback(): void;
56
- disconnectedCallback(): void;
57
- updated(changedProperties: Map<string | number | symbol, unknown>): void;
58
- private _findScrollContainer;
59
- /**
60
- * Calculate the horizontal offset from scroll container's left edge to this element's track.
61
- * This accounts for sticky labels or other elements that precede the track area.
62
- *
63
- * We look for our specific timeline elements (ef-timeline-row) and measure their label width.
64
- */
65
- private _calculateTrackOffset;
66
- /**
67
- * Find the ef-timeline-row ancestor by walking up through shadow DOM boundaries.
68
- */
69
- private _findTimelineRow;
70
- /**
71
- * Get the label width from an ef-timeline-row element.
72
- * Queries the shadow root for .row-label and returns its width.
73
- */
74
- private _getTimelineRowLabelWidth;
75
- /**
76
- * Get this strip's absolute position in the timeline (pixels from timeline origin).
77
- * Uses the target element's startTimeMs to determine position.
78
- */
79
- private _getStripTimelinePosition;
80
- private _attachScrollListener;
81
- private _detachScrollListener;
82
- private _onScroll;
83
- private _onContextScroll;
84
- private get _viewportWidth();
85
- /**
86
- * Watch for async content loading from child media elements.
87
- * When media finishes loading, increment the epoch to invalidate cached thumbnails.
88
- */
89
- private _watchChildContentLoading;
90
- private _setupTargetObserver;
91
- private _scheduleRender;
92
- /**
93
- * Check if thumbnails are ready and dispatch event if not already done.
94
- */
95
- private _checkAndDispatchReady;
96
- /**
97
- * Calculate thumbnail layout based on current dimensions and time range.
98
- * Only recreates slots if layout parameters have actually changed.
99
- */
100
- private _calculateLayout;
101
- /**
102
- * Get effective time range for thumbnails.
103
- */
104
- private _getTimeRange;
105
- /**
106
- * Calculate effective thumbnail width (auto or specified).
107
- */
108
- private _getEffectiveThumbnailWidth;
109
- /**
110
- * Check cache for existing thumbnails.
111
- */
112
- private _checkCache;
113
- /**
114
- * Draw the canvas with current thumbnail state.
115
- * Canvas is absolutely positioned at the visible portion of the strip.
116
- * Uses virtual rendering - only draws thumbnails in the visible region.
117
- */
118
- private _drawCanvas;
119
- /**
120
- * Draw a thumbnail image with cover mode scaling.
121
- */
122
- private _drawThumbnailImage;
123
- /**
124
- * Load thumbnails that are visible in the current viewport.
125
- * Skips loading if the epoch hasn't changed since last load.
126
- */
127
- private _loadVisibleThumbnails;
128
- /**
129
- * Capture thumbnails from a timegroup target.
130
- */
131
- private _captureTimegroupThumbnails;
132
- /**
133
- * Capture thumbnails from a video target using MediaEngine.
134
- */
135
- private _captureVideoThumbnails;
136
- /**
137
- * Convert canvas to ImageData.
138
- */
139
- private _canvasToImageData;
140
- /**
141
- * Returns a promise that resolves when thumbnails are ready.
142
- * Resolves immediately if thumbnails are already loaded.
143
- */
144
- whenReady(): Promise<void>;
145
- /**
146
- * Check if thumbnails have been loaded.
147
- */
148
- get isReady(): boolean;
149
- /**
150
- * Invalidate cached thumbnails for this element within a time range.
151
- * Call this when content changes at specific times.
152
- */
153
- invalidateTimeRange(startTimeMs: number, endTimeMs: number): void;
154
- /**
155
- * Invalidate all cached thumbnails for this element.
156
- */
157
- invalidateAll(): void;
158
- render(): lit_html26.TemplateResult<1>;
159
- }
160
- declare global {
161
- interface HTMLElementTagNameMap {
162
- "ef-thumbnail-strip": EFThumbnailStrip;
163
- }
164
- }
165
- //#endregion
166
- export { EFThumbnailStrip };
167
- //# sourceMappingURL=EFThumbnailStrip.d.ts.map