@editframe/elements 0.30.2-beta.0 → 0.31.0-beta.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 (326) hide show
  1. package/dist/EF_FRAMEGEN.d.ts +5 -0
  2. package/dist/EF_FRAMEGEN.js +20 -4
  3. package/dist/EF_FRAMEGEN.js.map +1 -1
  4. package/dist/EF_INTERACTIVE.js.map +1 -1
  5. package/dist/_virtual/rolldown_runtime.js +27 -0
  6. package/dist/canvas/EFCanvas.d.ts +311 -0
  7. package/dist/canvas/EFCanvas.js +1089 -0
  8. package/dist/canvas/EFCanvas.js.map +1 -0
  9. package/dist/canvas/EFCanvasItem.d.ts +55 -0
  10. package/dist/canvas/EFCanvasItem.js +72 -0
  11. package/dist/canvas/EFCanvasItem.js.map +1 -0
  12. package/dist/canvas/api/CanvasAPI.d.ts +115 -0
  13. package/dist/canvas/api/CanvasAPI.js +182 -0
  14. package/dist/canvas/api/CanvasAPI.js.map +1 -0
  15. package/dist/canvas/api/types.d.ts +42 -0
  16. package/dist/canvas/coordinateTransform.js +90 -0
  17. package/dist/canvas/coordinateTransform.js.map +1 -0
  18. package/dist/canvas/getElementBounds.js +40 -0
  19. package/dist/canvas/getElementBounds.js.map +1 -0
  20. package/dist/canvas/overlays/SelectionOverlay.js +265 -0
  21. package/dist/canvas/overlays/SelectionOverlay.js.map +1 -0
  22. package/dist/canvas/overlays/overlayState.js +153 -0
  23. package/dist/canvas/overlays/overlayState.js.map +1 -0
  24. package/dist/canvas/selection/SelectionController.js +105 -0
  25. package/dist/canvas/selection/SelectionController.js.map +1 -0
  26. package/dist/canvas/selection/SelectionModel.d.ts +98 -0
  27. package/dist/canvas/selection/SelectionModel.js +229 -0
  28. package/dist/canvas/selection/SelectionModel.js.map +1 -0
  29. package/dist/canvas/selection/selectionContext.d.ts +31 -0
  30. package/dist/canvas/selection/selectionContext.js +12 -0
  31. package/dist/canvas/selection/selectionContext.js.map +1 -0
  32. package/dist/elements/ContainerInfo.d.ts +29 -0
  33. package/dist/elements/ContainerInfo.js +30 -0
  34. package/dist/elements/ContainerInfo.js.map +1 -0
  35. package/dist/elements/EFAudio.d.ts +13 -3
  36. package/dist/elements/EFAudio.js +64 -10
  37. package/dist/elements/EFAudio.js.map +1 -1
  38. package/dist/elements/EFCaptions.d.ts +18 -16
  39. package/dist/elements/EFCaptions.js +110 -19
  40. package/dist/elements/EFCaptions.js.map +1 -1
  41. package/dist/elements/EFImage.d.ts +16 -6
  42. package/dist/elements/EFImage.js +79 -9
  43. package/dist/elements/EFImage.js.map +1 -1
  44. package/dist/elements/EFMedia/AssetIdMediaEngine.js +51 -4
  45. package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
  46. package/dist/elements/EFMedia/AssetMediaEngine.js +125 -52
  47. package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
  48. package/dist/elements/EFMedia/BaseMediaEngine.js +24 -6
  49. package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
  50. package/dist/elements/EFMedia/JitMediaEngine.js +12 -8
  51. package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
  52. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +46 -7
  53. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +1 -1
  54. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +98 -73
  55. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +1 -1
  56. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +28 -5
  57. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +1 -1
  58. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +18 -6
  59. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +1 -1
  60. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +8 -2
  61. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +1 -1
  62. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +31 -6
  63. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +1 -1
  64. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +28 -5
  65. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +1 -1
  66. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +97 -72
  67. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +1 -1
  68. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -1
  69. package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
  70. package/dist/elements/EFMedia/shared/BufferUtils.js +1 -1
  71. package/dist/elements/EFMedia/shared/BufferUtils.js.map +1 -1
  72. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +25 -14
  73. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
  74. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +47 -16
  75. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +1 -1
  76. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +37 -19
  77. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
  78. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +65 -21
  79. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
  80. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +8 -3
  81. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +1 -1
  82. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +32 -9
  83. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +1 -1
  84. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +33 -10
  85. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +1 -1
  86. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +23 -8
  87. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +1 -1
  88. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +34 -10
  89. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +1 -1
  90. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +31 -8
  91. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +1 -1
  92. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +31 -114
  93. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +1 -1
  94. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +44 -8
  95. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +1 -1
  96. package/dist/elements/EFMedia.d.ts +18 -7
  97. package/dist/elements/EFMedia.js +23 -3
  98. package/dist/elements/EFMedia.js.map +1 -1
  99. package/dist/elements/EFPanZoom.d.ts +96 -0
  100. package/dist/elements/EFPanZoom.js +290 -0
  101. package/dist/elements/EFPanZoom.js.map +1 -0
  102. package/dist/elements/EFSourceMixin.js +7 -6
  103. package/dist/elements/EFSourceMixin.js.map +1 -1
  104. package/dist/elements/EFSurface.d.ts +6 -6
  105. package/dist/elements/EFSurface.js +7 -2
  106. package/dist/elements/EFSurface.js.map +1 -1
  107. package/dist/elements/EFTemporal.d.ts +2 -1
  108. package/dist/elements/EFTemporal.js +192 -71
  109. package/dist/elements/EFTemporal.js.map +1 -1
  110. package/dist/elements/EFText.d.ts +5 -4
  111. package/dist/elements/EFText.js +102 -13
  112. package/dist/elements/EFText.js.map +1 -1
  113. package/dist/elements/EFTextSegment.d.ts +32 -6
  114. package/dist/elements/EFTextSegment.js +53 -15
  115. package/dist/elements/EFTextSegment.js.map +1 -1
  116. package/dist/elements/EFThumbnailStrip.d.ts +129 -56
  117. package/dist/elements/EFThumbnailStrip.js +605 -359
  118. package/dist/elements/EFThumbnailStrip.js.map +1 -1
  119. package/dist/elements/EFTimegroup.d.ts +233 -25
  120. package/dist/elements/EFTimegroup.js +865 -144
  121. package/dist/elements/EFTimegroup.js.map +1 -1
  122. package/dist/elements/EFVideo.d.ts +42 -5
  123. package/dist/elements/EFVideo.js +165 -11
  124. package/dist/elements/EFVideo.js.map +1 -1
  125. package/dist/elements/EFWaveform.d.ts +6 -6
  126. package/dist/elements/EFWaveform.js +2 -1
  127. package/dist/elements/EFWaveform.js.map +1 -1
  128. package/dist/elements/ElementPositionInfo.d.ts +35 -0
  129. package/dist/elements/ElementPositionInfo.js +49 -0
  130. package/dist/elements/ElementPositionInfo.js.map +1 -0
  131. package/dist/elements/FetchMixin.js +16 -1
  132. package/dist/elements/FetchMixin.js.map +1 -1
  133. package/dist/elements/SessionThumbnailCache.js +154 -0
  134. package/dist/elements/SessionThumbnailCache.js.map +1 -0
  135. package/dist/elements/TargetController.js +3 -1
  136. package/dist/elements/TargetController.js.map +1 -1
  137. package/dist/elements/TimegroupController.js +9 -3
  138. package/dist/elements/TimegroupController.js.map +1 -1
  139. package/dist/elements/findRootTemporal.js +30 -0
  140. package/dist/elements/findRootTemporal.js.map +1 -0
  141. package/dist/elements/renderTemporalAudio.js +18 -5
  142. package/dist/elements/renderTemporalAudio.js.map +1 -1
  143. package/dist/elements/updateAnimations.js +171 -28
  144. package/dist/elements/updateAnimations.js.map +1 -1
  145. package/dist/getRenderInfo.d.ts +2 -2
  146. package/dist/gui/ContextMixin.js +4 -2
  147. package/dist/gui/ContextMixin.js.map +1 -1
  148. package/dist/gui/Controllable.js +74 -1
  149. package/dist/gui/Controllable.js.map +1 -1
  150. package/dist/gui/EFActiveRootTemporal.d.ts +50 -0
  151. package/dist/gui/EFActiveRootTemporal.js +94 -0
  152. package/dist/gui/EFActiveRootTemporal.js.map +1 -0
  153. package/dist/gui/EFConfiguration.d.ts +7 -1
  154. package/dist/gui/EFConfiguration.js.map +1 -1
  155. package/dist/gui/EFControls.d.ts +2 -2
  156. package/dist/gui/EFControls.js +109 -13
  157. package/dist/gui/EFControls.js.map +1 -1
  158. package/dist/gui/EFDial.d.ts +4 -4
  159. package/dist/gui/EFFilmstrip.d.ts +11 -214
  160. package/dist/gui/EFFilmstrip.js +53 -1152
  161. package/dist/gui/EFFilmstrip.js.map +1 -1
  162. package/dist/gui/EFFitScale.d.ts +3 -3
  163. package/dist/gui/EFFitScale.js +39 -12
  164. package/dist/gui/EFFitScale.js.map +1 -1
  165. package/dist/gui/EFFocusOverlay.d.ts +4 -4
  166. package/dist/gui/EFOverlayItem.d.ts +48 -0
  167. package/dist/gui/EFOverlayItem.js +97 -0
  168. package/dist/gui/EFOverlayItem.js.map +1 -0
  169. package/dist/gui/EFOverlayLayer.d.ts +70 -0
  170. package/dist/gui/EFOverlayLayer.js +104 -0
  171. package/dist/gui/EFOverlayLayer.js.map +1 -0
  172. package/dist/gui/EFPause.d.ts +4 -4
  173. package/dist/gui/EFPlay.d.ts +4 -4
  174. package/dist/gui/EFResizableBox.d.ts +12 -16
  175. package/dist/gui/EFResizableBox.js +109 -451
  176. package/dist/gui/EFResizableBox.js.map +1 -1
  177. package/dist/gui/EFScrubber.d.ts +30 -5
  178. package/dist/gui/EFScrubber.js +224 -31
  179. package/dist/gui/EFScrubber.js.map +1 -1
  180. package/dist/gui/EFTimeDisplay.d.ts +4 -4
  181. package/dist/gui/EFTimeDisplay.js +4 -1
  182. package/dist/gui/EFTimeDisplay.js.map +1 -1
  183. package/dist/gui/EFTimelineRuler.d.ts +71 -0
  184. package/dist/gui/EFTimelineRuler.js +320 -0
  185. package/dist/gui/EFTimelineRuler.js.map +1 -0
  186. package/dist/gui/EFToggleLoop.d.ts +4 -4
  187. package/dist/gui/EFTogglePlay.d.ts +4 -4
  188. package/dist/gui/EFTransformHandles.d.ts +91 -0
  189. package/dist/gui/EFTransformHandles.js +393 -0
  190. package/dist/gui/EFTransformHandles.js.map +1 -0
  191. package/dist/gui/EFWorkbench.d.ts +178 -0
  192. package/dist/gui/EFWorkbench.js +2067 -22
  193. package/dist/gui/EFWorkbench.js.map +1 -1
  194. package/dist/gui/FitScaleHelpers.d.ts +31 -0
  195. package/dist/gui/FitScaleHelpers.js +41 -0
  196. package/dist/gui/FitScaleHelpers.js.map +1 -0
  197. package/dist/gui/PlaybackController.d.ts +2 -1
  198. package/dist/gui/PlaybackController.js +46 -15
  199. package/dist/gui/PlaybackController.js.map +1 -1
  200. package/dist/gui/TWMixin.js +1 -1
  201. package/dist/gui/TWMixin.js.map +1 -1
  202. package/dist/gui/hierarchy/EFHierarchy.d.ts +65 -0
  203. package/dist/gui/hierarchy/EFHierarchy.js +338 -0
  204. package/dist/gui/hierarchy/EFHierarchy.js.map +1 -0
  205. package/dist/gui/hierarchy/EFHierarchyItem.d.ts +118 -0
  206. package/dist/gui/hierarchy/EFHierarchyItem.js +551 -0
  207. package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -0
  208. package/dist/gui/hierarchy/hierarchyContext.d.ts +38 -0
  209. package/dist/gui/hierarchy/hierarchyContext.js +8 -0
  210. package/dist/gui/hierarchy/hierarchyContext.js.map +1 -0
  211. package/dist/gui/icons.js +34 -0
  212. package/dist/gui/icons.js.map +1 -0
  213. package/dist/gui/panZoomTransformContext.js +12 -0
  214. package/dist/gui/panZoomTransformContext.js.map +1 -0
  215. package/dist/gui/previewSettingsContext.js +12 -0
  216. package/dist/gui/previewSettingsContext.js.map +1 -0
  217. package/dist/gui/timeline/EFTimeline.d.ts +270 -0
  218. package/dist/gui/timeline/EFTimeline.js +1369 -0
  219. package/dist/gui/timeline/EFTimeline.js.map +1 -0
  220. package/dist/gui/timeline/EFTimelineRow.js +374 -0
  221. package/dist/gui/timeline/EFTimelineRow.js.map +1 -0
  222. package/dist/gui/timeline/TrimHandles.d.ts +36 -0
  223. package/dist/gui/timeline/TrimHandles.js +204 -0
  224. package/dist/gui/timeline/TrimHandles.js.map +1 -0
  225. package/dist/gui/timeline/flattenHierarchy.js +31 -0
  226. package/dist/gui/timeline/flattenHierarchy.js.map +1 -0
  227. package/dist/gui/timeline/timelineStateContext.d.ts +26 -0
  228. package/dist/gui/timeline/timelineStateContext.js +42 -0
  229. package/dist/gui/timeline/timelineStateContext.js.map +1 -0
  230. package/dist/gui/timeline/tracks/AudioTrack.js +264 -0
  231. package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -0
  232. package/dist/gui/timeline/tracks/CaptionsTrack.js +595 -0
  233. package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -0
  234. package/dist/gui/timeline/tracks/HTMLTrack.js +19 -0
  235. package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -0
  236. package/dist/gui/timeline/tracks/ImageTrack.js +53 -0
  237. package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -0
  238. package/dist/gui/timeline/tracks/TextTrack.js +250 -0
  239. package/dist/gui/timeline/tracks/TextTrack.js.map +1 -0
  240. package/dist/gui/timeline/tracks/TimegroupTrack.js +143 -0
  241. package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -0
  242. package/dist/gui/timeline/tracks/TrackItem.js +269 -0
  243. package/dist/gui/timeline/tracks/TrackItem.js.map +1 -0
  244. package/dist/gui/timeline/tracks/VideoTrack.js +265 -0
  245. package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -0
  246. package/dist/gui/timeline/tracks/WaveformTrack.js +19 -0
  247. package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -0
  248. package/dist/gui/timeline/tracks/ensureTrackItemInit.js +1 -0
  249. package/dist/gui/timeline/tracks/preloadTracks.js +9 -0
  250. package/dist/gui/timeline/tracks/renderTrackChildren.js +119 -0
  251. package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -0
  252. package/dist/gui/timeline/tracks/waveformUtils.js +80 -0
  253. package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -0
  254. package/dist/gui/transformCalculations.js +217 -0
  255. package/dist/gui/transformCalculations.js.map +1 -0
  256. package/dist/gui/transformUtils.d.ts +37 -0
  257. package/dist/gui/transformUtils.js +77 -0
  258. package/dist/gui/transformUtils.js.map +1 -0
  259. package/dist/gui/tree/EFTree.d.ts +59 -0
  260. package/dist/gui/tree/EFTree.js +174 -0
  261. package/dist/gui/tree/EFTree.js.map +1 -0
  262. package/dist/gui/tree/EFTreeItem.d.ts +38 -0
  263. package/dist/gui/tree/EFTreeItem.js +146 -0
  264. package/dist/gui/tree/EFTreeItem.js.map +1 -0
  265. package/dist/gui/tree/treeContext.d.ts +60 -0
  266. package/dist/gui/tree/treeContext.js +23 -0
  267. package/dist/gui/tree/treeContext.js.map +1 -0
  268. package/dist/index.d.ts +32 -8
  269. package/dist/index.js +30 -6
  270. package/dist/index.js.map +1 -1
  271. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +688 -0
  272. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +1 -0
  273. package/dist/node_modules/react/cjs/react.development.js +1521 -0
  274. package/dist/node_modules/react/cjs/react.development.js.map +1 -0
  275. package/dist/node_modules/react/index.js +13 -0
  276. package/dist/node_modules/react/index.js.map +1 -0
  277. package/dist/node_modules/react/jsx-runtime.js +13 -0
  278. package/dist/node_modules/react/jsx-runtime.js.map +1 -0
  279. package/dist/preview/AdaptiveResolutionTracker.js +228 -0
  280. package/dist/preview/AdaptiveResolutionTracker.js.map +1 -0
  281. package/dist/preview/RenderProfiler.js +135 -0
  282. package/dist/preview/RenderProfiler.js.map +1 -0
  283. package/dist/preview/previewSettings.js +131 -0
  284. package/dist/preview/previewSettings.js.map +1 -0
  285. package/dist/preview/previewTypes.js +64 -0
  286. package/dist/preview/previewTypes.js.map +1 -0
  287. package/dist/preview/renderTimegroupPreview.js +656 -0
  288. package/dist/preview/renderTimegroupPreview.js.map +1 -0
  289. package/dist/preview/renderTimegroupToCanvas.d.ts +37 -0
  290. package/dist/preview/renderTimegroupToCanvas.js +833 -0
  291. package/dist/preview/renderTimegroupToCanvas.js.map +1 -0
  292. package/dist/preview/renderTimegroupToVideo.d.ts +39 -0
  293. package/dist/preview/renderTimegroupToVideo.js +274 -0
  294. package/dist/preview/renderTimegroupToVideo.js.map +1 -0
  295. package/dist/preview/renderers.js +16 -0
  296. package/dist/preview/renderers.js.map +1 -0
  297. package/dist/preview/statsTrackingStrategy.js +201 -0
  298. package/dist/preview/statsTrackingStrategy.js.map +1 -0
  299. package/dist/preview/thumbnailCacheSettings.js +52 -0
  300. package/dist/preview/thumbnailCacheSettings.js.map +1 -0
  301. package/dist/preview/workers/WorkerPool.js +178 -0
  302. package/dist/preview/workers/WorkerPool.js.map +1 -0
  303. package/dist/preview/workers/encoderWorkerInline.js +103 -0
  304. package/dist/preview/workers/encoderWorkerInline.js.map +1 -0
  305. package/dist/sandbox/PlaybackControls.js +10 -0
  306. package/dist/sandbox/PlaybackControls.js.map +1 -0
  307. package/dist/sandbox/ScenarioRunner.js +1 -0
  308. package/dist/sandbox/index.js +2 -0
  309. package/dist/style.css +71 -67
  310. package/dist/transcoding/types/index.d.ts +2 -1
  311. package/dist/transcoding/utils/UrlGenerator.d.ts +6 -1
  312. package/dist/transcoding/utils/UrlGenerator.js +12 -3
  313. package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
  314. package/dist/utils/LRUCache.js +1 -375
  315. package/dist/utils/LRUCache.js.map +1 -1
  316. package/dist/utils/frameTime.js +14 -0
  317. package/dist/utils/frameTime.js.map +1 -0
  318. package/package.json +3 -3
  319. package/test/profilingPlugin.ts +223 -0
  320. package/test/recordReplayProxyPlugin.js +22 -27
  321. package/test/thumbnail-performance-test.html +116 -0
  322. package/test/visualRegressionUtils.ts +286 -0
  323. package/types.json +1 -1
  324. package/dist/elements/TimegroupController.d.ts +0 -18
  325. package/dist/msToTimeCode.js +0 -17
  326. package/dist/msToTimeCode.js.map +0 -1
@@ -47,6 +47,11 @@ declare class EFFramegen {
47
47
  private initializeVerificationCanvas;
48
48
  private drawVerificationStrip;
49
49
  constructor();
50
+ /**
51
+ * Helper method to get the workbench and set its rendering state.
52
+ * This ensures consistent state management across the framegen lifecycle.
53
+ */
54
+ private setWorkbenchRendering;
50
55
  connectToBridge(): void;
51
56
  get showFrameBox(): boolean;
52
57
  initialize(renderOptions: VideoRenderOptions): Promise<void>;
@@ -92,6 +92,14 @@ var EFFramegen = class {
92
92
  this.BRIDGE = window.FRAMEGEN_BRIDGE;
93
93
  if (this.BRIDGE) this.connectToBridge();
94
94
  }
95
+ /**
96
+ * Helper method to get the workbench and set its rendering state.
97
+ * This ensures consistent state management across the framegen lifecycle.
98
+ */
99
+ setWorkbenchRendering(isRendering) {
100
+ const workbench = document.querySelector("ef-workbench");
101
+ if (workbench) workbench.rendering = isRendering;
102
+ }
95
103
  connectToBridge() {
96
104
  const BRIDGE = this.BRIDGE;
97
105
  if (!BRIDGE) throw new Error("No BRIDGE when attempting to connect to bridge");
@@ -112,10 +120,13 @@ var EFFramegen = class {
112
120
  fps: renderOptions.encoderOptions.video.framerate,
113
121
  durationMs: renderOptions.encoderOptions.toMs - renderOptions.encoderOptions.fromMs
114
122
  }, parentContext, async () => {
115
- await this.initialize(renderOptions).catch((error) => {
123
+ try {
124
+ await this.initialize(renderOptions);
125
+ } catch (error) {
126
+ this.setWorkbenchRendering(false);
116
127
  console.error("[EF_FRAMEGEN.connectToBridge] error initializing", error);
117
128
  throw error;
118
- });
129
+ }
119
130
  });
120
131
  BRIDGE.initialized();
121
132
  });
@@ -128,11 +139,15 @@ var EFFramegen = class {
128
139
  setCurrentFrameSpan(span);
129
140
  try {
130
141
  await this.beginFrame(frameNumber, isLast);
142
+ } catch (error) {
143
+ this.setWorkbenchRendering(false);
144
+ throw error;
131
145
  } finally {
132
146
  clearCurrentFrameSpan();
133
147
  }
134
148
  }).catch((error) => {
135
149
  console.error("[EF_FRAMEGEN.beginFrame] error:", error);
150
+ this.setWorkbenchRendering(false);
136
151
  clearCurrentFrameSpan();
137
152
  throw error;
138
153
  });
@@ -152,7 +167,7 @@ var EFFramegen = class {
152
167
  this.renderOptions = renderOptions;
153
168
  const workbench = document.querySelector("ef-workbench");
154
169
  if (!workbench) throw new Error("No workbench found");
155
- workbench.rendering = true;
170
+ this.setWorkbenchRendering(true);
156
171
  workbench.playing = false;
157
172
  const firstGroup = shallowGetTimegroups(workbench)[0];
158
173
  if (!firstGroup) throw new Error("No temporal elements found");
@@ -181,7 +196,7 @@ var EFFramegen = class {
181
196
  if (this.renderOptions === void 0) throw new Error("No renderOptions");
182
197
  const workbench = document.querySelector("ef-workbench");
183
198
  if (!workbench) throw new Error("No workbench found");
184
- workbench.rendering = true;
199
+ this.setWorkbenchRendering(true);
185
200
  const firstGroup = shallowGetTimegroups(workbench)[0];
186
201
  if (!firstGroup) throw new Error("No temporal elements found");
187
202
  const frameTime = this.renderOptions.encoderOptions.fromMs + frameNumber * this.frameDurationMs;
@@ -209,6 +224,7 @@ var EFFramegen = class {
209
224
  });
210
225
  return fileReader.result;
211
226
  }
227
+ this.setWorkbenchRendering(false);
212
228
  } else if (this.BRIDGE) this.BRIDGE.frameReady(frameNumber, /* @__PURE__ */ new ArrayBuffer(0));
213
229
  else {
214
230
  const fileReader = new FileReader();
@@ -1 +1 @@
1
- {"version":3,"file":"EF_FRAMEGEN.js","names":[],"sources":["../src/EF_FRAMEGEN.ts"],"sourcesContent":["import type { VideoRenderOptions } from \"@editframe/assets\";\n\nimport { shallowGetTimegroups } from \"./elements/EFTimegroup.js\";\nimport { setupBrowserTracing } from \"./otel/setupBrowserTracing.js\";\nimport {\n clearCurrentFrameSpan,\n enableTracing,\n extractParentContext,\n setCurrentFrameSpan,\n type TraceContext,\n withSpan,\n withSpanAndContext,\n} from \"./otel/tracingHelpers.js\";\n\ninterface Bridge {\n onInitialize: (\n callback: (\n renderOptions: VideoRenderOptions,\n traceContext?: TraceContext,\n otelEndpoint?: string,\n ) => void,\n ) => void;\n\n initialized(): void;\n\n onBeginFrame(\n callback: (\n frameNumber: number,\n isLast: boolean,\n traceContext?: TraceContext,\n ) => void,\n ): void;\n\n onTriggerCanvas(callback: (traceContext?: TraceContext) => void): void;\n\n frameReady(frameNumber: number, audioSamples: ArrayBuffer): void;\n\n error(error: Error): void;\n\n syncLog(sequence: number, message: string, callback: () => void): void;\n\n exportSpans?: (endpoint: string, payload: string) => void;\n}\n\ndeclare global {\n interface Window {\n EF_FRAMEGEN?: EFFramegen;\n FRAMEGEN_BRIDGE?: Bridge;\n FRAMEGEN_BINDING?: any;\n FRAMEGEN_BINDING_error?: (error: Error) => void;\n EF_RENDERING?: () => boolean;\n }\n}\n\nclass TriggerCanvas {\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n\n private canvasInitialized = false;\n\n constructor() {\n this.canvas = document.createElement(\"canvas\");\n const ctx = this.canvas.getContext(\"2d\", { willReadFrequently: true });\n if (!ctx) throw new Error(\"Canvas 2d context not ready\");\n this.ctx = ctx;\n this.ctx.fillStyle = \"transparent\";\n }\n\n initialize() {\n if (this.canvasInitialized) return;\n this.canvasInitialized = true;\n this.canvas.width = 1;\n this.canvas.height = 1;\n Object.assign(this.canvas.style, {\n position: \"fixed\",\n top: \"0px\",\n left: \"0px\",\n width: \"100%\",\n height: \"100%\",\n zIndex: \"100000\",\n });\n document.body.appendChild(this.canvas);\n }\n\n trigger() {\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n}\n\nexport class EFFramegen {\n time = 0;\n frameDurationMs = 0;\n audioBufferPromise?: Promise<AudioBuffer>;\n renderOptions?: VideoRenderOptions;\n frameBox = document.createElement(\"div\");\n BRIDGE: typeof window.FRAMEGEN_BRIDGE;\n triggerCanvas = new TriggerCanvas();\n verificationCanvas?: HTMLCanvasElement;\n verificationCtx?: CanvasRenderingContext2D;\n private logSequence = 0;\n\n // Frame sequence coordination\n public frameTasksInProgress = false;\n public currentFrameNumber = 0;\n\n trace(...args: any[]) {\n console.trace(\"[EF_FRAMEGEN]\", ...args);\n }\n\n async syncLog(...args: any[]): Promise<void> {\n if (!this.BRIDGE) {\n // Fallback to regular console.log if no bridge\n console.log(\"[EF_FRAMEGEN]\", ...args);\n return;\n }\n\n const sequence = ++this.logSequence;\n const message = args\n .map((arg) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg),\n )\n .join(\" \");\n\n return new Promise<void>((resolve) => {\n // biome-ignore lint/style/noNonNullAssertion: We know BRIDGE is set due to the guard above\n this.BRIDGE!.syncLog(sequence, message, () => {\n resolve();\n });\n });\n }\n\n private initializeVerificationCanvas() {\n if (this.verificationCanvas) {\n return;\n }\n\n this.verificationCanvas = document.createElement(\"canvas\");\n const ctx = this.verificationCanvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"Verification canvas 2d context not ready\");\n this.verificationCtx = ctx;\n\n // Size to match the workbench width, 1 pixel height for verification strip\n const workbench = document.querySelector(\"ef-workbench\") as HTMLElement;\n if (workbench) {\n this.verificationCanvas.width = workbench.clientWidth;\n this.verificationCanvas.height = 1;\n\n // Position at the bottom of the workbench (beyond content height)\n Object.assign(this.verificationCanvas.style, {\n position: \"fixed\",\n left: \"0px\",\n bottom: \"0px\",\n width: `${workbench.clientWidth}px`,\n height: \"1px\",\n zIndex: \"99999\", // Above trigger canvas\n });\n\n document.body.appendChild(this.verificationCanvas);\n }\n }\n\n private drawVerificationStrip(frameNumber: number) {\n this.initializeVerificationCanvas();\n\n if (!this.verificationCanvas || !this.verificationCtx) {\n return;\n }\n\n const width = this.verificationCanvas.width;\n const height = this.verificationCanvas.height;\n\n // Clear the strip\n this.verificationCtx.clearRect(0, 0, width, height);\n\n // Encode frame number into RGB (24-bit)\n // R=high byte, G=middle byte, B=low byte\n const red = Math.floor(frameNumber / (256 * 256)) % 256;\n const green = Math.floor(frameNumber / 256) % 256;\n const blue = frameNumber % 256;\n\n // Fill the entire strip with the encoded frame number\n this.verificationCtx.fillStyle = `rgb(${red}, ${green}, ${blue})`;\n this.verificationCtx.fillRect(0, 0, width, height);\n }\n\n constructor() {\n this.BRIDGE = window.FRAMEGEN_BRIDGE;\n if (this.BRIDGE) {\n this.connectToBridge();\n }\n }\n\n connectToBridge() {\n const BRIDGE = this.BRIDGE;\n if (!BRIDGE) {\n throw new Error(\"No BRIDGE when attempting to connect to bridge\");\n }\n\n BRIDGE.onInitialize(async (renderOptions, traceContext, otelEndpoint) => {\n // Only enable tracing if explicitly requested in renderOptions\n if (renderOptions.enableTracing && otelEndpoint) {\n enableTracing();\n await setupBrowserTracing({\n otelEndpoint,\n serviceName: \"telecine-browser\",\n bridge: BRIDGE,\n useBatching: true, // Batch spans to reduce overhead during rendering\n });\n }\n\n const parentContext = extractParentContext(traceContext);\n\n await withSpan(\n \"browser.initialize\",\n {\n width: renderOptions.encoderOptions.video.width,\n height: renderOptions.encoderOptions.video.height,\n fps: renderOptions.encoderOptions.video.framerate,\n durationMs:\n renderOptions.encoderOptions.toMs -\n renderOptions.encoderOptions.fromMs,\n },\n parentContext,\n async () => {\n await this.initialize(renderOptions).catch((error) => {\n console.error(\n \"[EF_FRAMEGEN.connectToBridge] error initializing\",\n error,\n );\n throw error;\n });\n },\n );\n\n BRIDGE.initialized();\n });\n\n BRIDGE.onBeginFrame((frameNumber, isLast, traceContext) => {\n const parentContext = extractParentContext(traceContext);\n withSpanAndContext(\n \"browser.frame.render\",\n {\n frameNumber,\n isLast,\n },\n parentContext,\n async (span, _spanContext) => {\n // Store the span itself for child operations\n // This allows spans created in Lit Tasks to use it as their parent\n setCurrentFrameSpan(span);\n\n try {\n await this.beginFrame(frameNumber, isLast);\n } finally {\n clearCurrentFrameSpan();\n }\n },\n ).catch((error) => {\n console.error(\"[EF_FRAMEGEN.beginFrame] error:\", error);\n clearCurrentFrameSpan();\n throw error;\n });\n });\n\n BRIDGE.onTriggerCanvas((traceContext) => {\n const parentContext = extractParentContext(traceContext);\n\n withSpan(\"browser.canvas.trigger\", {}, parentContext, async () => {\n this.triggerCanvas.trigger();\n }).catch((error) => {\n console.error(\"[EF_FRAMEGEN.triggerCanvas] error:\", error);\n });\n });\n }\n\n get showFrameBox() {\n return this.renderOptions?.showFrameBox ?? false;\n }\n\n async initialize(renderOptions: VideoRenderOptions) {\n this.renderOptions = renderOptions;\n\n const workbench = document.querySelector(\"ef-workbench\");\n if (!workbench) {\n throw new Error(\"No workbench found\");\n }\n workbench.rendering = true;\n workbench.playing = false;\n const timegroups = shallowGetTimegroups(workbench);\n const firstGroup = timegroups[0];\n if (!firstGroup) {\n throw new Error(\"No temporal elements found\");\n }\n const startingTimeMs = renderOptions.encoderOptions.fromMs;\n await firstGroup.waitForMediaDurations();\n await firstGroup.waitForFrameTasks();\n\n this.frameDurationMs = 1000 / renderOptions.encoderOptions.video.framerate;\n\n this.time = startingTimeMs;\n if (this.showFrameBox) {\n Object.assign(this.frameBox.style, {\n width: \"200px\",\n height: \"100px\",\n font: \"10px Arial\",\n backgroundColor: \"white\",\n position: \"absolute\",\n top: \"0px\",\n right: \"0px\",\n zIndex: \"100000\",\n });\n document.body.prepend(this.frameBox);\n }\n\n this.triggerCanvas.initialize();\n\n // These times are aligned to the audio frame boundaries\n // And they include padding if any.\n this.audioBufferPromise = firstGroup.renderAudio(\n renderOptions.encoderOptions.alignedFromUs / 1000,\n renderOptions.encoderOptions.alignedToUs / 1000,\n );\n }\n\n async beginFrame(frameNumber: number, isLast: boolean) {\n if (this.renderOptions === undefined) {\n throw new Error(\"No renderOptions\");\n }\n const workbench = document.querySelector(\"ef-workbench\");\n if (!workbench) {\n throw new Error(\"No workbench found\");\n }\n workbench.rendering = true;\n const timegroups = shallowGetTimegroups(workbench);\n const firstGroup = timegroups[0];\n if (!firstGroup) {\n throw new Error(\"No temporal elements found\");\n }\n\n // Calculate base frame time using normal progression\n const frameTime =\n this.renderOptions.encoderOptions.fromMs +\n frameNumber * this.frameDurationMs;\n firstGroup.currentTimeMs = Number(Number(frameTime).toFixed(5));\n await firstGroup.waitForFrameTasks();\n if (this.showFrameBox) {\n this.frameBox.innerHTML = `\n <div>🖼️ Frame: ${frameNumber}</div>\n <div>🕛 Segment: ${this.time.toFixed(4)}</div>\n <div>🕛 Frame: ${firstGroup.currentTimeMs.toFixed(4)}</div>\n <div> from-to: ${this.renderOptions.encoderOptions.fromMs.toFixed(4)} - ${this.renderOptions.encoderOptions.toMs.toFixed(4)}</div>\n `;\n }\n\n // Draw verification pixel strip for frame verification\n this.drawVerificationStrip(frameNumber);\n\n if (isLast && this.audioBufferPromise) {\n // Currently we emit the audio in one belch at the end of the render.\n // This is not ideal, but it's the simplest thing that could possibly work.\n // We could either emit it slices, or in parallel with the video.\n // But in any case, it's fine for now.\n const renderedAudio = await this.audioBufferPromise;\n\n const channelCount = renderedAudio.numberOfChannels;\n\n const interleavedSamples = new Float32Array(\n channelCount * renderedAudio.length,\n );\n\n for (let i = 0; i < renderedAudio.length; i++) {\n for (let j = 0; j < channelCount; j++) {\n interleavedSamples.set(\n renderedAudio.getChannelData(j).slice(i, i + 1),\n i * channelCount + j,\n );\n }\n }\n\n if (this.BRIDGE) {\n this.BRIDGE.frameReady(frameNumber, interleavedSamples.buffer);\n } else {\n const fileReader = new FileReader();\n fileReader.readAsDataURL(new Blob([interleavedSamples.buffer]));\n await new Promise((resolve, reject) => {\n fileReader.onload = resolve;\n fileReader.onerror = reject;\n });\n return fileReader.result;\n }\n } else {\n if (this.BRIDGE) {\n this.BRIDGE.frameReady(frameNumber, new ArrayBuffer(0));\n } else {\n const fileReader = new FileReader();\n fileReader.readAsDataURL(new Blob([]));\n await new Promise((resolve, reject) => {\n fileReader.onload = resolve;\n fileReader.onerror = reject;\n });\n return fileReader.result;\n }\n }\n }\n}\n\nif (typeof window !== \"undefined\") {\n window.EF_FRAMEGEN = new EFFramegen();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EF_FRAMEGEN.js","names":[],"sources":["../src/EF_FRAMEGEN.ts"],"sourcesContent":["import type { VideoRenderOptions } from \"@editframe/assets\";\n\nimport { shallowGetTimegroups } from \"./elements/EFTimegroup.js\";\nimport { setupBrowserTracing } from \"./otel/setupBrowserTracing.js\";\nimport {\n clearCurrentFrameSpan,\n enableTracing,\n extractParentContext,\n setCurrentFrameSpan,\n type TraceContext,\n withSpan,\n withSpanAndContext,\n} from \"./otel/tracingHelpers.js\";\n\ninterface Bridge {\n onInitialize: (\n callback: (\n renderOptions: VideoRenderOptions,\n traceContext?: TraceContext,\n otelEndpoint?: string,\n ) => void,\n ) => void;\n\n initialized(): void;\n\n onBeginFrame(\n callback: (\n frameNumber: number,\n isLast: boolean,\n traceContext?: TraceContext,\n ) => void,\n ): void;\n\n onTriggerCanvas(callback: (traceContext?: TraceContext) => void): void;\n\n frameReady(frameNumber: number, audioSamples: ArrayBuffer): void;\n\n error(error: Error): void;\n\n syncLog(sequence: number, message: string, callback: () => void): void;\n\n exportSpans?: (endpoint: string, payload: string) => void;\n}\n\ndeclare global {\n interface Window {\n EF_FRAMEGEN?: EFFramegen;\n FRAMEGEN_BRIDGE?: Bridge;\n FRAMEGEN_BINDING?: any;\n FRAMEGEN_BINDING_error?: (error: Error) => void;\n EF_RENDERING?: () => boolean;\n }\n}\n\nclass TriggerCanvas {\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n\n private canvasInitialized = false;\n\n constructor() {\n this.canvas = document.createElement(\"canvas\");\n const ctx = this.canvas.getContext(\"2d\", { willReadFrequently: true });\n if (!ctx) throw new Error(\"Canvas 2d context not ready\");\n this.ctx = ctx;\n this.ctx.fillStyle = \"transparent\";\n }\n\n initialize() {\n if (this.canvasInitialized) return;\n this.canvasInitialized = true;\n this.canvas.width = 1;\n this.canvas.height = 1;\n Object.assign(this.canvas.style, {\n position: \"fixed\",\n top: \"0px\",\n left: \"0px\",\n width: \"100%\",\n height: \"100%\",\n zIndex: \"100000\",\n });\n document.body.appendChild(this.canvas);\n }\n\n trigger() {\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n}\n\nexport class EFFramegen {\n time = 0;\n frameDurationMs = 0;\n audioBufferPromise?: Promise<AudioBuffer>;\n renderOptions?: VideoRenderOptions;\n frameBox = document.createElement(\"div\");\n BRIDGE: typeof window.FRAMEGEN_BRIDGE;\n triggerCanvas = new TriggerCanvas();\n verificationCanvas?: HTMLCanvasElement;\n verificationCtx?: CanvasRenderingContext2D;\n private logSequence = 0;\n\n // Frame sequence coordination\n public frameTasksInProgress = false;\n public currentFrameNumber = 0;\n\n trace(...args: any[]) {\n console.trace(\"[EF_FRAMEGEN]\", ...args);\n }\n\n async syncLog(...args: any[]): Promise<void> {\n if (!this.BRIDGE) {\n // Fallback to regular console.log if no bridge\n console.log(\"[EF_FRAMEGEN]\", ...args);\n return;\n }\n\n const sequence = ++this.logSequence;\n const message = args\n .map((arg) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg),\n )\n .join(\" \");\n\n return new Promise<void>((resolve) => {\n // biome-ignore lint/style/noNonNullAssertion: We know BRIDGE is set due to the guard above\n this.BRIDGE!.syncLog(sequence, message, () => {\n resolve();\n });\n });\n }\n\n private initializeVerificationCanvas() {\n if (this.verificationCanvas) {\n return;\n }\n\n this.verificationCanvas = document.createElement(\"canvas\");\n const ctx = this.verificationCanvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"Verification canvas 2d context not ready\");\n this.verificationCtx = ctx;\n\n // Size to match the workbench width, 1 pixel height for verification strip\n const workbench = document.querySelector(\"ef-workbench\") as HTMLElement;\n if (workbench) {\n this.verificationCanvas.width = workbench.clientWidth;\n this.verificationCanvas.height = 1;\n\n // Position at the bottom of the workbench (beyond content height)\n Object.assign(this.verificationCanvas.style, {\n position: \"fixed\",\n left: \"0px\",\n bottom: \"0px\",\n width: `${workbench.clientWidth}px`,\n height: \"1px\",\n zIndex: \"99999\", // Above trigger canvas\n });\n\n document.body.appendChild(this.verificationCanvas);\n }\n }\n\n private drawVerificationStrip(frameNumber: number) {\n this.initializeVerificationCanvas();\n\n if (!this.verificationCanvas || !this.verificationCtx) {\n return;\n }\n\n const width = this.verificationCanvas.width;\n const height = this.verificationCanvas.height;\n\n // Clear the strip\n this.verificationCtx.clearRect(0, 0, width, height);\n\n // Encode frame number into RGB (24-bit)\n // R=high byte, G=middle byte, B=low byte\n const red = Math.floor(frameNumber / (256 * 256)) % 256;\n const green = Math.floor(frameNumber / 256) % 256;\n const blue = frameNumber % 256;\n\n // Fill the entire strip with the encoded frame number\n this.verificationCtx.fillStyle = `rgb(${red}, ${green}, ${blue})`;\n this.verificationCtx.fillRect(0, 0, width, height);\n }\n\n constructor() {\n this.BRIDGE = window.FRAMEGEN_BRIDGE;\n if (this.BRIDGE) {\n this.connectToBridge();\n }\n }\n\n /**\n * Helper method to get the workbench and set its rendering state.\n * This ensures consistent state management across the framegen lifecycle.\n */\n private setWorkbenchRendering(isRendering: boolean) {\n const workbench = document.querySelector(\"ef-workbench\");\n if (workbench) {\n workbench.rendering = isRendering;\n }\n }\n\n connectToBridge() {\n const BRIDGE = this.BRIDGE;\n if (!BRIDGE) {\n throw new Error(\"No BRIDGE when attempting to connect to bridge\");\n }\n\n BRIDGE.onInitialize(async (renderOptions, traceContext, otelEndpoint) => {\n // Only enable tracing if explicitly requested in renderOptions\n if (renderOptions.enableTracing && otelEndpoint) {\n enableTracing();\n await setupBrowserTracing({\n otelEndpoint,\n serviceName: \"telecine-browser\",\n bridge: BRIDGE,\n useBatching: true, // Batch spans to reduce overhead during rendering\n });\n }\n\n const parentContext = extractParentContext(traceContext);\n\n await withSpan(\n \"browser.initialize\",\n {\n width: renderOptions.encoderOptions.video.width,\n height: renderOptions.encoderOptions.video.height,\n fps: renderOptions.encoderOptions.video.framerate,\n durationMs:\n renderOptions.encoderOptions.toMs -\n renderOptions.encoderOptions.fromMs,\n },\n parentContext,\n async () => {\n try {\n await this.initialize(renderOptions);\n } catch (error) {\n // If initialization fails, ensure rendering state is cleared\n this.setWorkbenchRendering(false);\n console.error(\n \"[EF_FRAMEGEN.connectToBridge] error initializing\",\n error,\n );\n throw error;\n }\n },\n );\n\n BRIDGE.initialized();\n });\n\n BRIDGE.onBeginFrame((frameNumber, isLast, traceContext) => {\n const parentContext = extractParentContext(traceContext);\n withSpanAndContext(\n \"browser.frame.render\",\n {\n frameNumber,\n isLast,\n },\n parentContext,\n async (span, _spanContext) => {\n // Store the span itself for child operations\n // This allows spans created in Lit Tasks to use it as their parent\n setCurrentFrameSpan(span);\n\n try {\n await this.beginFrame(frameNumber, isLast);\n } catch (error) {\n // If an error occurs during rendering, ensure rendering state is cleared\n this.setWorkbenchRendering(false);\n throw error;\n } finally {\n clearCurrentFrameSpan();\n }\n },\n ).catch((error) => {\n console.error(\"[EF_FRAMEGEN.beginFrame] error:\", error);\n // Ensure rendering state is cleared on error\n this.setWorkbenchRendering(false);\n clearCurrentFrameSpan();\n throw error;\n });\n });\n\n BRIDGE.onTriggerCanvas((traceContext) => {\n const parentContext = extractParentContext(traceContext);\n\n withSpan(\"browser.canvas.trigger\", {}, parentContext, async () => {\n this.triggerCanvas.trigger();\n }).catch((error) => {\n console.error(\"[EF_FRAMEGEN.triggerCanvas] error:\", error);\n });\n });\n }\n\n get showFrameBox() {\n return this.renderOptions?.showFrameBox ?? false;\n }\n\n async initialize(renderOptions: VideoRenderOptions) {\n this.renderOptions = renderOptions;\n\n const workbench = document.querySelector(\"ef-workbench\");\n if (!workbench) {\n throw new Error(\"No workbench found\");\n }\n this.setWorkbenchRendering(true);\n workbench.playing = false;\n const timegroups = shallowGetTimegroups(workbench);\n const firstGroup = timegroups[0];\n if (!firstGroup) {\n throw new Error(\"No temporal elements found\");\n }\n const startingTimeMs = renderOptions.encoderOptions.fromMs;\n await firstGroup.waitForMediaDurations();\n await firstGroup.waitForFrameTasks();\n\n this.frameDurationMs = 1000 / renderOptions.encoderOptions.video.framerate;\n\n this.time = startingTimeMs;\n if (this.showFrameBox) {\n Object.assign(this.frameBox.style, {\n width: \"200px\",\n height: \"100px\",\n font: \"10px Arial\",\n backgroundColor: \"white\",\n position: \"absolute\",\n top: \"0px\",\n right: \"0px\",\n zIndex: \"100000\",\n });\n document.body.prepend(this.frameBox);\n }\n\n this.triggerCanvas.initialize();\n\n // These times are aligned to the audio frame boundaries\n // And they include padding if any.\n this.audioBufferPromise = firstGroup.renderAudio(\n renderOptions.encoderOptions.alignedFromUs / 1000,\n renderOptions.encoderOptions.alignedToUs / 1000,\n );\n }\n\n async beginFrame(frameNumber: number, isLast: boolean) {\n if (this.renderOptions === undefined) {\n throw new Error(\"No renderOptions\");\n }\n const workbench = document.querySelector(\"ef-workbench\");\n if (!workbench) {\n throw new Error(\"No workbench found\");\n }\n this.setWorkbenchRendering(true);\n const timegroups = shallowGetTimegroups(workbench);\n const firstGroup = timegroups[0];\n if (!firstGroup) {\n throw new Error(\"No temporal elements found\");\n }\n\n // Calculate base frame time using normal progression\n const frameTime =\n this.renderOptions.encoderOptions.fromMs +\n frameNumber * this.frameDurationMs;\n firstGroup.currentTimeMs = Number(Number(frameTime).toFixed(5));\n await firstGroup.waitForFrameTasks();\n if (this.showFrameBox) {\n this.frameBox.innerHTML = `\n <div>🖼️ Frame: ${frameNumber}</div>\n <div>🕛 Segment: ${this.time.toFixed(4)}</div>\n <div>🕛 Frame: ${firstGroup.currentTimeMs.toFixed(4)}</div>\n <div> from-to: ${this.renderOptions.encoderOptions.fromMs.toFixed(4)} - ${this.renderOptions.encoderOptions.toMs.toFixed(4)}</div>\n `;\n }\n\n // Draw verification pixel strip for frame verification\n this.drawVerificationStrip(frameNumber);\n\n if (isLast && this.audioBufferPromise) {\n // Currently we emit the audio in one belch at the end of the render.\n // This is not ideal, but it's the simplest thing that could possibly work.\n // We could either emit it slices, or in parallel with the video.\n // But in any case, it's fine for now.\n const renderedAudio = await this.audioBufferPromise;\n\n const channelCount = renderedAudio.numberOfChannels;\n\n const interleavedSamples = new Float32Array(\n channelCount * renderedAudio.length,\n );\n\n for (let i = 0; i < renderedAudio.length; i++) {\n for (let j = 0; j < channelCount; j++) {\n interleavedSamples.set(\n renderedAudio.getChannelData(j).slice(i, i + 1),\n i * channelCount + j,\n );\n }\n }\n\n if (this.BRIDGE) {\n this.BRIDGE.frameReady(frameNumber, interleavedSamples.buffer);\n } else {\n const fileReader = new FileReader();\n fileReader.readAsDataURL(new Blob([interleavedSamples.buffer]));\n await new Promise((resolve, reject) => {\n fileReader.onload = resolve;\n fileReader.onerror = reject;\n });\n return fileReader.result;\n }\n \n // Rendering is complete after the last frame\n this.setWorkbenchRendering(false);\n } else {\n if (this.BRIDGE) {\n this.BRIDGE.frameReady(frameNumber, new ArrayBuffer(0));\n } else {\n const fileReader = new FileReader();\n fileReader.readAsDataURL(new Blob([]));\n await new Promise((resolve, reject) => {\n fileReader.onload = resolve;\n fileReader.onerror = reject;\n });\n return fileReader.result;\n }\n }\n }\n}\n\nif (typeof window !== \"undefined\") {\n window.EF_FRAMEGEN = new EFFramegen();\n}\n"],"mappings":";;;;;AAsDA,IAAM,gBAAN,MAAoB;CAMlB,cAAc;2BAFc;AAG1B,OAAK,SAAS,SAAS,cAAc,SAAS;EAC9C,MAAM,MAAM,KAAK,OAAO,WAAW,MAAM,EAAE,oBAAoB,MAAM,CAAC;AACtE,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,8BAA8B;AACxD,OAAK,MAAM;AACX,OAAK,IAAI,YAAY;;CAGvB,aAAa;AACX,MAAI,KAAK,kBAAmB;AAC5B,OAAK,oBAAoB;AACzB,OAAK,OAAO,QAAQ;AACpB,OAAK,OAAO,SAAS;AACrB,SAAO,OAAO,KAAK,OAAO,OAAO;GAC/B,UAAU;GACV,KAAK;GACL,MAAM;GACN,OAAO;GACP,QAAQ;GACR,QAAQ;GACT,CAAC;AACF,WAAS,KAAK,YAAY,KAAK,OAAO;;CAGxC,UAAU;AACR,OAAK,IAAI,UAAU,GAAG,GAAG,KAAK,OAAO,OAAO,KAAK,OAAO,OAAO;;;AAInE,IAAa,aAAb,MAAwB;CAgBtB,MAAM,GAAG,MAAa;AACpB,UAAQ,MAAM,iBAAiB,GAAG,KAAK;;CAGzC,MAAM,QAAQ,GAAG,MAA4B;AAC3C,MAAI,CAAC,KAAK,QAAQ;AAEhB,WAAQ,IAAI,iBAAiB,GAAG,KAAK;AACrC;;EAGF,MAAM,WAAW,EAAE,KAAK;EACxB,MAAM,UAAU,KACb,KAAK,QACJ,OAAO,QAAQ,WAAW,KAAK,UAAU,IAAI,GAAG,OAAO,IAAI,CAC5D,CACA,KAAK,IAAI;AAEZ,SAAO,IAAI,SAAe,YAAY;AAEpC,QAAK,OAAQ,QAAQ,UAAU,eAAe;AAC5C,aAAS;KACT;IACF;;CAGJ,AAAQ,+BAA+B;AACrC,MAAI,KAAK,mBACP;AAGF,OAAK,qBAAqB,SAAS,cAAc,SAAS;EAC1D,MAAM,MAAM,KAAK,mBAAmB,WAAW,KAAK;AACpD,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,2CAA2C;AACrE,OAAK,kBAAkB;EAGvB,MAAM,YAAY,SAAS,cAAc,eAAe;AACxD,MAAI,WAAW;AACb,QAAK,mBAAmB,QAAQ,UAAU;AAC1C,QAAK,mBAAmB,SAAS;AAGjC,UAAO,OAAO,KAAK,mBAAmB,OAAO;IAC3C,UAAU;IACV,MAAM;IACN,QAAQ;IACR,OAAO,GAAG,UAAU,YAAY;IAChC,QAAQ;IACR,QAAQ;IACT,CAAC;AAEF,YAAS,KAAK,YAAY,KAAK,mBAAmB;;;CAItD,AAAQ,sBAAsB,aAAqB;AACjD,OAAK,8BAA8B;AAEnC,MAAI,CAAC,KAAK,sBAAsB,CAAC,KAAK,gBACpC;EAGF,MAAM,QAAQ,KAAK,mBAAmB;EACtC,MAAM,SAAS,KAAK,mBAAmB;AAGvC,OAAK,gBAAgB,UAAU,GAAG,GAAG,OAAO,OAAO;EAInD,MAAM,MAAM,KAAK,MAAM,eAAe,MAAM,KAAK,GAAG;EACpD,MAAM,QAAQ,KAAK,MAAM,cAAc,IAAI,GAAG;EAC9C,MAAM,OAAO,cAAc;AAG3B,OAAK,gBAAgB,YAAY,OAAO,IAAI,IAAI,MAAM,IAAI,KAAK;AAC/D,OAAK,gBAAgB,SAAS,GAAG,GAAG,OAAO,OAAO;;CAGpD,cAAc;cA/FP;yBACW;kBAGP,SAAS,cAAc,MAAM;uBAExB,IAAI,eAAe;qBAGb;8BAGQ;4BACF;AAmF1B,OAAK,SAAS,OAAO;AACrB,MAAI,KAAK,OACP,MAAK,iBAAiB;;;;;;CAQ1B,AAAQ,sBAAsB,aAAsB;EAClD,MAAM,YAAY,SAAS,cAAc,eAAe;AACxD,MAAI,UACF,WAAU,YAAY;;CAI1B,kBAAkB;EAChB,MAAM,SAAS,KAAK;AACpB,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,iDAAiD;AAGnE,SAAO,aAAa,OAAO,eAAe,cAAc,iBAAiB;AAEvE,OAAI,cAAc,iBAAiB,cAAc;AAC/C,mBAAe;AACf,UAAM,oBAAoB;KACxB;KACA,aAAa;KACb,QAAQ;KACR,aAAa;KACd,CAAC;;GAGJ,MAAM,gBAAgB,qBAAqB,aAAa;AAExD,SAAM,SACJ,sBACA;IACE,OAAO,cAAc,eAAe,MAAM;IAC1C,QAAQ,cAAc,eAAe,MAAM;IAC3C,KAAK,cAAc,eAAe,MAAM;IACxC,YACE,cAAc,eAAe,OAC7B,cAAc,eAAe;IAChC,EACD,eACA,YAAY;AACV,QAAI;AACF,WAAM,KAAK,WAAW,cAAc;aAC7B,OAAO;AAEd,UAAK,sBAAsB,MAAM;AACjC,aAAQ,MACN,oDACA,MACD;AACD,WAAM;;KAGX;AAED,UAAO,aAAa;IACpB;AAEF,SAAO,cAAc,aAAa,QAAQ,iBAAiB;GACzD,MAAM,gBAAgB,qBAAqB,aAAa;AACxD,sBACE,wBACA;IACE;IACA;IACD,EACD,eACA,OAAO,MAAM,iBAAiB;AAG5B,wBAAoB,KAAK;AAEzB,QAAI;AACF,WAAM,KAAK,WAAW,aAAa,OAAO;aACnC,OAAO;AAEd,UAAK,sBAAsB,MAAM;AACjC,WAAM;cACE;AACR,4BAAuB;;KAG5B,CAAC,OAAO,UAAU;AACjB,YAAQ,MAAM,mCAAmC,MAAM;AAEvD,SAAK,sBAAsB,MAAM;AACjC,2BAAuB;AACvB,UAAM;KACN;IACF;AAEF,SAAO,iBAAiB,iBAAiB;AAGvC,YAAS,0BAA0B,EAAE,EAFf,qBAAqB,aAAa,EAEF,YAAY;AAChE,SAAK,cAAc,SAAS;KAC5B,CAAC,OAAO,UAAU;AAClB,YAAQ,MAAM,sCAAsC,MAAM;KAC1D;IACF;;CAGJ,IAAI,eAAe;AACjB,SAAO,KAAK,eAAe,gBAAgB;;CAG7C,MAAM,WAAW,eAAmC;AAClD,OAAK,gBAAgB;EAErB,MAAM,YAAY,SAAS,cAAc,eAAe;AACxD,MAAI,CAAC,UACH,OAAM,IAAI,MAAM,qBAAqB;AAEvC,OAAK,sBAAsB,KAAK;AAChC,YAAU,UAAU;EAEpB,MAAM,aADa,qBAAqB,UAAU,CACpB;AAC9B,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,6BAA6B;EAE/C,MAAM,iBAAiB,cAAc,eAAe;AACpD,QAAM,WAAW,uBAAuB;AACxC,QAAM,WAAW,mBAAmB;AAEpC,OAAK,kBAAkB,MAAO,cAAc,eAAe,MAAM;AAEjE,OAAK,OAAO;AACZ,MAAI,KAAK,cAAc;AACrB,UAAO,OAAO,KAAK,SAAS,OAAO;IACjC,OAAO;IACP,QAAQ;IACR,MAAM;IACN,iBAAiB;IACjB,UAAU;IACV,KAAK;IACL,OAAO;IACP,QAAQ;IACT,CAAC;AACF,YAAS,KAAK,QAAQ,KAAK,SAAS;;AAGtC,OAAK,cAAc,YAAY;AAI/B,OAAK,qBAAqB,WAAW,YACnC,cAAc,eAAe,gBAAgB,KAC7C,cAAc,eAAe,cAAc,IAC5C;;CAGH,MAAM,WAAW,aAAqB,QAAiB;AACrD,MAAI,KAAK,kBAAkB,OACzB,OAAM,IAAI,MAAM,mBAAmB;EAErC,MAAM,YAAY,SAAS,cAAc,eAAe;AACxD,MAAI,CAAC,UACH,OAAM,IAAI,MAAM,qBAAqB;AAEvC,OAAK,sBAAsB,KAAK;EAEhC,MAAM,aADa,qBAAqB,UAAU,CACpB;AAC9B,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,6BAA6B;EAI/C,MAAM,YACJ,KAAK,cAAc,eAAe,SAClC,cAAc,KAAK;AACrB,aAAW,gBAAgB,OAAO,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAC;AAC/D,QAAM,WAAW,mBAAmB;AACpC,MAAI,KAAK,aACP,MAAK,SAAS,YAAY;4BACJ,YAAY;2BACb,KAAK,KAAK,QAAQ,EAAE,CAAC;2BACrB,WAAW,cAAc,QAAQ,EAAE,CAAC;0BACrC,KAAK,cAAc,eAAe,OAAO,QAAQ,EAAE,CAAC,KAAK,KAAK,cAAc,eAAe,KAAK,QAAQ,EAAE,CAAC;;AAKjI,OAAK,sBAAsB,YAAY;AAEvC,MAAI,UAAU,KAAK,oBAAoB;GAKrC,MAAM,gBAAgB,MAAM,KAAK;GAEjC,MAAM,eAAe,cAAc;GAEnC,MAAM,qBAAqB,IAAI,aAC7B,eAAe,cAAc,OAC9B;AAED,QAAK,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,IACxC,MAAK,IAAI,IAAI,GAAG,IAAI,cAAc,IAChC,oBAAmB,IACjB,cAAc,eAAe,EAAE,CAAC,MAAM,GAAG,IAAI,EAAE,EAC/C,IAAI,eAAe,EACpB;AAIL,OAAI,KAAK,OACP,MAAK,OAAO,WAAW,aAAa,mBAAmB,OAAO;QACzD;IACL,MAAM,aAAa,IAAI,YAAY;AACnC,eAAW,cAAc,IAAI,KAAK,CAAC,mBAAmB,OAAO,CAAC,CAAC;AAC/D,UAAM,IAAI,SAAS,SAAS,WAAW;AACrC,gBAAW,SAAS;AACpB,gBAAW,UAAU;MACrB;AACF,WAAO,WAAW;;AAIpB,QAAK,sBAAsB,MAAM;aAE7B,KAAK,OACP,MAAK,OAAO,WAAW,6BAAa,IAAI,YAAY,EAAE,CAAC;OAClD;GACL,MAAM,aAAa,IAAI,YAAY;AACnC,cAAW,cAAc,IAAI,KAAK,EAAE,CAAC,CAAC;AACtC,SAAM,IAAI,SAAS,SAAS,WAAW;AACrC,eAAW,SAAS;AACpB,eAAW,UAAU;KACrB;AACF,UAAO,WAAW;;;;AAM1B,IAAI,OAAO,WAAW,YACpB,QAAO,cAAc,IAAI,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"EF_INTERACTIVE.js","names":[],"sources":["../src/EF_INTERACTIVE.ts"],"sourcesContent":["export let EF_INTERACTIVE = false;\n\nif (typeof window !== \"undefined\") {\n EF_INTERACTIVE = !window.location?.search.includes(\"EF_NONINTERACTIVE\");\n}\n"],"mappings":";AAAA,IAAW,iBAAiB;AAE5B,IAAI,OAAO,WAAW,YACpB,kBAAiB,CAAC,OAAO,UAAU,OAAO,SAAS,oBAAoB"}
1
+ {"version":3,"file":"EF_INTERACTIVE.js","names":[],"sources":["../src/EF_INTERACTIVE.ts"],"sourcesContent":["export let EF_INTERACTIVE = false;\n\nif (typeof window !== \"undefined\") {\n EF_INTERACTIVE = !window.location?.search.includes(\"EF_NONINTERACTIVE\");\n}\n\n/**\n * Set EF_INTERACTIVE value for testing purposes.\n * @internal\n */\nexport const setEFInteractive = (value: boolean) => {\n EF_INTERACTIVE = value;\n};\n"],"mappings":";AAAA,IAAW,iBAAiB;AAE5B,IAAI,OAAO,WAAW,YACpB,kBAAiB,CAAC,OAAO,UAAU,OAAO,SAAS,oBAAoB"}
@@ -0,0 +1,27 @@
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 };
@@ -0,0 +1,311 @@
1
+ import { TemporalMixinInterface } from "../elements/EFTemporal.js";
2
+ import { CanvasElementData } from "./api/types.js";
3
+ import { SelectionContext } from "./selection/selectionContext.js";
4
+ import { PanZoomTransform } from "../elements/EFPanZoom.js";
5
+ import * as lit33 from "lit";
6
+ import { LitElement } from "lit";
7
+ import * as lit_html32 from "lit-html";
8
+
9
+ //#region src/canvas/EFCanvas.d.ts
10
+ declare const EFCanvas_base: typeof LitElement;
11
+ /**
12
+ * =============================================================================
13
+ * COORDINATE SYSTEM AND DIMENSION CALCULATION PRINCIPLES
14
+ * =============================================================================
15
+ *
16
+ * This canvas system uses a unified approach for calculating element positions
17
+ * and dimensions that works correctly regardless of CSS transforms (rotation,
18
+ * scale, etc.), zoom level, or nesting depth.
19
+ *
20
+ * TWO KEY DOM APIS WITH DIFFERENT BEHAVIORS:
21
+ *
22
+ * 1. offsetWidth / offsetHeight
23
+ * - Returns the element's LAYOUT dimensions (CSS box model)
24
+ * - These are the dimensions BEFORE any CSS transforms are applied
25
+ * - UNAFFECTED by: rotation, scale, skew, or any other transform
26
+ * - UNAFFECTED by: parent transforms (including zoom scale)
27
+ * - AFFECTED by: CSS width/height properties, padding, border
28
+ * - Units: CSS pixels in the element's own coordinate space
29
+ *
30
+ * Example: A 200x100px element rotated 45° still has offsetWidth=200, offsetHeight=100
31
+ * Example: A 200x100px element in a 2x zoomed canvas still has offsetWidth=200, offsetHeight=100
32
+ *
33
+ * USE FOR: Getting the actual dimensions of an element in canvas coordinates
34
+ *
35
+ * 2. getBoundingClientRect()
36
+ * - Returns the element's visual BOUNDING BOX on screen
37
+ * - This is the axis-aligned rectangle that fully contains the transformed element
38
+ * - AFFECTED by: rotation (bounding box grows), scale, all transforms
39
+ * - AFFECTED by: parent transforms (including zoom scale)
40
+ * - Units: Screen pixels (viewport coordinates)
41
+ *
42
+ * Example: A 200x100px element rotated 45° has bounding box ~212x212px
43
+ * Example: A 200x100px element in a 2x zoomed canvas has bounding rect 400x200px
44
+ *
45
+ * USE FOR: Getting the visual center position (center of bounding box = element center)
46
+ * NOT FOR: Getting actual dimensions (bounding box ≠ actual size when rotated)
47
+ *
48
+ * THE UNIFIED CALCULATION METHOD:
49
+ *
50
+ * For ANY element (rotated, scaled, nested, etc.):
51
+ *
52
+ * 1. DIMENSIONS: Use offsetWidth/offsetHeight
53
+ * - These give us the true dimensions in canvas coordinates
54
+ * - No division by scale needed - they're already in canvas space
55
+ *
56
+ * 2. CENTER POSITION: Use getBoundingClientRect() center
57
+ * - screenCenterX = rect.left + rect.width / 2
58
+ * - screenCenterY = rect.top + rect.height / 2
59
+ * - The center of the bounding box IS the element's center
60
+ * - This is true for ANY rotation (rotation around center keeps center fixed)
61
+ *
62
+ * 3. TOP-LEFT POSITION: Calculate from center and dimensions
63
+ * - canvasX = canvasCenter.x - width / 2
64
+ * - canvasY = canvasCenter.y - height / 2
65
+ *
66
+ * WHY THIS WORKS UNIVERSALLY:
67
+ *
68
+ * - offsetWidth/Height are defined by CSS spec to be unaffected by transforms
69
+ * - The center of any shape is preserved under rotation around that center
70
+ * - This mathematical relationship holds for ALL transform combinations
71
+ * - No special cases needed for rotation, scale, or nesting
72
+ *
73
+ * COMMON MISTAKES TO AVOID:
74
+ *
75
+ * ❌ Using getBoundingClientRect().width for dimensions (wrong when rotated)
76
+ * ❌ Dividing offsetWidth by scale (offsetWidth is already in canvas coords)
77
+ * ❌ Using getBoundingClientRect().left/top for position (wrong when rotated)
78
+ * ❌ Having different code paths for rotated vs non-rotated elements
79
+ *
80
+ * =============================================================================
81
+ */
82
+ /**
83
+ * Main canvas container element.
84
+ * Manages existing elements (EF* elements, divs, etc.) and provides selection functionality.
85
+ */
86
+ declare class EFCanvas extends EFCanvas_base {
87
+ static styles: lit33.CSSResult[];
88
+ panZoomTransform?: PanZoomTransform;
89
+ elementIdAttribute: string;
90
+ enableTransformHandles: boolean;
91
+ private elementRegistry;
92
+ private elementMetadata;
93
+ private selectionController;
94
+ private overlayLayer;
95
+ private selectionOverlay;
96
+ private transformHandlesMap;
97
+ private overlayRafId;
98
+ private isDragging;
99
+ private dragStarted;
100
+ private dragStartPos;
101
+ private dragStartCanvasPos;
102
+ private dragStartElementPositions;
103
+ private draggedElementId;
104
+ private capturedPointerId;
105
+ private readonly DRAG_THRESHOLD;
106
+ private isBoxSelecting;
107
+ private boxSelectStart;
108
+ private boxSelectModifierKeys;
109
+ private emptySpaceClickPos;
110
+ private selectionChangeHandler?;
111
+ private elementHoverHandlers;
112
+ private _activeRootTemporal;
113
+ selectionContext: SelectionContext;
114
+ /**
115
+ * The currently highlighted (hovered) element.
116
+ * This is the source of truth for highlight state across all panels
117
+ * (canvas, hierarchy, timeline).
118
+ */
119
+ highlightedElement: HTMLElement | null;
120
+ constructor();
121
+ connectedCallback(): void;
122
+ disconnectedCallback(): void;
123
+ /**
124
+ * Setup mutation observer to track element additions/removals.
125
+ */
126
+ private setupElementTracking;
127
+ /**
128
+ * Try to register an element, auto-generating an ID if needed.
129
+ * Public method for external use (e.g., hierarchy selection).
130
+ */
131
+ tryRegisterElement(element: HTMLElement): void;
132
+ /**
133
+ * Register an element for canvas management.
134
+ * @throws Error if element does not have an ID
135
+ */
136
+ registerElement(element: HTMLElement, id?: string): string;
137
+ /**
138
+ * Unregister an element.
139
+ */
140
+ unregisterElement(element: HTMLElement | string): void;
141
+ /**
142
+ * Setup hover event listeners for an element to update highlightedElement.
143
+ * The canvas is the source of truth for highlight state.
144
+ */
145
+ private setupElementHoverListeners;
146
+ /**
147
+ * Set the highlighted element. Called by canvas hover handlers
148
+ * and by external panels (hierarchy, timeline) when user hovers items.
149
+ */
150
+ setHighlightedElement(element: HTMLElement | null): void;
151
+ /**
152
+ * Remove hover event listeners for an element.
153
+ */
154
+ private removeElementHoverListeners;
155
+ /**
156
+ * Update element metadata from DOM.
157
+ *
158
+ * UNIFIED APPROACH - works for ALL elements regardless of rotation, scale, or nesting:
159
+ *
160
+ * 1. DIMENSIONS: Always use offsetWidth/offsetHeight
161
+ * - These are layout dimensions in the element's coordinate space
162
+ * - Unaffected by CSS transforms (rotation, scale, etc.)
163
+ * - Already in canvas coordinates (no scale division needed)
164
+ *
165
+ * 2. CENTER POSITION: Always use getBoundingClientRect() center
166
+ * - The center of the bounding box IS the element's center (transform-origin: center)
167
+ * - Works correctly for rotated elements (center is rotation-invariant)
168
+ * - Convert to canvas coordinates using screenToCanvas()
169
+ *
170
+ * 3. TOP-LEFT POSITION: Calculate from center and dimensions
171
+ * - x = centerX - width/2
172
+ * - y = centerY - height/2
173
+ */
174
+ private updateElementMetadata;
175
+ /**
176
+ * Hit test - find elements intersecting with bounds.
177
+ * @param bounds - DOMRect in canvas coordinate space (from SelectionModel.boxSelectBounds)
178
+ */
179
+ private hitTest;
180
+ /**
181
+ * Handle pointer down events.
182
+ * Only handles events when clicking on elements. Otherwise, lets panzoom handle it.
183
+ */
184
+ private handlePointerDown;
185
+ /**
186
+ * Handle pointer move events.
187
+ */
188
+ private handlePointerMove;
189
+ /**
190
+ * Handle pointer up events.
191
+ */
192
+ private handlePointerUp;
193
+ /**
194
+ * Setup listener for selection changes to update data-selected attributes.
195
+ */
196
+ private setupSelectionListener;
197
+ /**
198
+ * Remove selection change listener.
199
+ */
200
+ private removeSelectionListener;
201
+ /**
202
+ * Get the root temporal element containing the current selection.
203
+ * Returns null if no element is selected or the selected element has no root temporal.
204
+ */
205
+ get activeRootTemporal(): (TemporalMixinInterface & HTMLElement) | null;
206
+ /**
207
+ * Update data-selected attributes on elements based on current selection.
208
+ * This enables pure CSS styling of selected elements.
209
+ */
210
+ private updateSelectionAttributes;
211
+ /**
212
+ * Update element position in canvas coordinates.
213
+ * Unified approach: Always calculate relative to parent (or .canvas-content for direct children).
214
+ * For direct children, parent position is (0, 0), so relative = absolute (no-op).
215
+ *
216
+ * For nested elements, we read parent's current position from DOM (not metadata) to ensure
217
+ * we're always calculating relative to the actual current position.
218
+ */
219
+ updateElementPosition(elementId: string, x: number, y: number): void;
220
+ /**
221
+ * Get element metadata.
222
+ */
223
+ getElementData(elementId: string): CanvasElementData | null;
224
+ /**
225
+ * Get all element data.
226
+ */
227
+ getAllElementsData(): CanvasElementData[];
228
+ /**
229
+ * Convert screen coordinates to canvas coordinates (for API).
230
+ */
231
+ screenToCanvasCoords(screenX: number, screenY: number): {
232
+ x: number;
233
+ y: number;
234
+ };
235
+ /**
236
+ * Convert canvas coordinates to screen coordinates (for API).
237
+ */
238
+ canvasToScreenCoords(canvasX: number, canvasY: number): {
239
+ x: number;
240
+ y: number;
241
+ };
242
+ /**
243
+ * Setup overlay layer as sibling of panzoom (outside panzoom, same level as panzoom).
244
+ */
245
+ private setupOverlayLayer;
246
+ /**
247
+ * Cleanup overlay layer if we created it.
248
+ */
249
+ private cleanupOverlayLayer;
250
+ /**
251
+ * Setup selection overlay as sibling of panzoom (outside panzoom, same level as panzoom).
252
+ * This ensures the overlay maintains 1:1 pixel ratio regardless of zoom level.
253
+ */
254
+ private setupSelectionOverlay;
255
+ /**
256
+ * Cleanup selection overlay if we created it.
257
+ */
258
+ private cleanupSelectionOverlay;
259
+ /**
260
+ * Start RAF loop for overlay layer sync and transform handles updates.
261
+ */
262
+ private startOverlayRafLoop;
263
+ /**
264
+ * Stop RAF loop.
265
+ */
266
+ private stopOverlayRafLoop;
267
+ /**
268
+ * Update transform handles for selected elements.
269
+ * For multiple selections, shows a single set of handles for the bounding box.
270
+ */
271
+ private updateTransformHandles;
272
+ /**
273
+ * Update transform handles bounds for an element.
274
+ */
275
+ private updateTransformHandlesBounds;
276
+ /**
277
+ * Handle transform handles bounds-change event for multi-selection.
278
+ * Updates all selected elements proportionally.
279
+ */
280
+ private handleMultiSelectionTransformHandlesBoundsChange;
281
+ private lastMultiSelectionRotation;
282
+ private multiSelectionRotationCenter;
283
+ private multiSelectionResizeInitial;
284
+ /**
285
+ * Handle transform handles rotation-change event for multiple selected elements.
286
+ * Rotates all elements around the center of the bounding box.
287
+ */
288
+ private handleMultiSelectionTransformHandlesRotationChange;
289
+ /**
290
+ * Handle transform handles bounds-change event for single element.
291
+ * Converts bounds from overlay-relative screen coordinates to canvas coordinates.
292
+ */
293
+ private handleTransformHandlesBoundsChange;
294
+ /**
295
+ * Handle transform handles rotation-change event for single element.
296
+ */
297
+ private handleTransformHandlesRotationChange;
298
+ /**
299
+ * Cleanup transform handles.
300
+ */
301
+ private cleanupTransformHandles;
302
+ render(): lit_html32.TemplateResult<1>;
303
+ }
304
+ declare global {
305
+ interface HTMLElementTagNameMap {
306
+ "ef-canvas": EFCanvas;
307
+ }
308
+ }
309
+ //#endregion
310
+ export { EFCanvas };
311
+ //# sourceMappingURL=EFCanvas.d.ts.map