@editframe/elements 0.33.0-beta → 0.34.5-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/dist/EF_FRAMEGEN.js +5 -3
  2. package/dist/EF_FRAMEGEN.js.map +1 -1
  3. package/dist/_virtual/{_@oxc-project_runtime@0.94.0 → _@oxc-project_runtime@0.95.0}/helpers/decorate.js +1 -1
  4. package/dist/canvas/EFCanvas.d.ts +7 -4
  5. package/dist/canvas/EFCanvas.js +1 -1
  6. package/dist/canvas/EFCanvasItem.d.ts +4 -4
  7. package/dist/canvas/EFCanvasItem.js +1 -1
  8. package/dist/canvas/overlays/SelectionOverlay.d.ts +95 -0
  9. package/dist/canvas/overlays/SelectionOverlay.js +1 -1
  10. package/dist/canvas/selection/SelectionController.js +7 -11
  11. package/dist/canvas/selection/SelectionController.js.map +1 -1
  12. package/dist/elements/EFAudio.d.ts +25 -7
  13. package/dist/elements/EFAudio.js +31 -61
  14. package/dist/elements/EFAudio.js.map +1 -1
  15. package/dist/elements/EFCaptions.d.ts +65 -52
  16. package/dist/elements/EFCaptions.js +186 -400
  17. package/dist/elements/EFCaptions.js.map +1 -1
  18. package/dist/elements/EFImage.d.ts +34 -6
  19. package/dist/elements/EFImage.js +114 -79
  20. package/dist/elements/EFImage.js.map +1 -1
  21. package/dist/elements/EFMedia/AssetIdMediaEngine.js +17 -17
  22. package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
  23. package/dist/elements/EFMedia/AssetMediaEngine.js +41 -25
  24. package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
  25. package/dist/elements/EFMedia/BaseMediaEngine.js +4 -4
  26. package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
  27. package/dist/elements/EFMedia/BufferedSeekingInput.js +1 -1
  28. package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
  29. package/dist/elements/EFMedia/JitMediaEngine.js +31 -17
  30. package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
  31. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
  32. package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
  33. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +17 -9
  34. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
  35. package/dist/elements/EFMedia.d.ts +66 -20
  36. package/dist/elements/EFMedia.js +412 -30
  37. package/dist/elements/EFMedia.js.map +1 -1
  38. package/dist/elements/EFPanZoom.d.ts +4 -4
  39. package/dist/elements/EFPanZoom.js +1 -1
  40. package/dist/elements/EFSourceMixin.js +43 -15
  41. package/dist/elements/EFSourceMixin.js.map +1 -1
  42. package/dist/elements/EFSurface.d.ts +23 -10
  43. package/dist/elements/EFSurface.js +64 -22
  44. package/dist/elements/EFSurface.js.map +1 -1
  45. package/dist/elements/EFTemporal.d.ts +8 -2
  46. package/dist/elements/EFTemporal.js +42 -31
  47. package/dist/elements/EFTemporal.js.map +1 -1
  48. package/dist/elements/EFText.d.ts +5 -4
  49. package/dist/elements/EFText.js +11 -2
  50. package/dist/elements/EFText.js.map +1 -1
  51. package/dist/elements/EFTextSegment.d.ts +4 -4
  52. package/dist/elements/EFTextSegment.js +1 -1
  53. package/dist/elements/EFThumbnailStrip.d.ts +4 -4
  54. package/dist/elements/EFThumbnailStrip.js +1 -1
  55. package/dist/elements/EFTimegroup.d.ts +22 -8
  56. package/dist/elements/EFTimegroup.js +203 -115
  57. package/dist/elements/EFTimegroup.js.map +1 -1
  58. package/dist/elements/EFVideo.d.ts +57 -20
  59. package/dist/elements/EFVideo.js +324 -72
  60. package/dist/elements/EFVideo.js.map +1 -1
  61. package/dist/elements/EFWaveform.d.ts +33 -7
  62. package/dist/elements/EFWaveform.js +103 -59
  63. package/dist/elements/EFWaveform.js.map +1 -1
  64. package/dist/elements/renderTemporalAudio.js +14 -3
  65. package/dist/elements/renderTemporalAudio.js.map +1 -1
  66. package/dist/getRenderInfo.d.ts +2 -2
  67. package/dist/gui/ContextMixin.js +1 -1
  68. package/dist/gui/Controllable.d.ts +2 -0
  69. package/dist/gui/EFActiveRootTemporal.d.ts +4 -4
  70. package/dist/gui/EFActiveRootTemporal.js +1 -1
  71. package/dist/gui/EFConfiguration.d.ts +4 -4
  72. package/dist/gui/EFConfiguration.js +1 -1
  73. package/dist/gui/EFControls.d.ts +2 -2
  74. package/dist/gui/EFControls.js +1 -1
  75. package/dist/gui/EFDial.d.ts +4 -4
  76. package/dist/gui/EFDial.js +1 -1
  77. package/dist/gui/EFFilmstrip.d.ts +3 -2
  78. package/dist/gui/EFFilmstrip.js +1 -1
  79. package/dist/gui/EFFitScale.js +1 -1
  80. package/dist/gui/EFFocusOverlay.d.ts +4 -4
  81. package/dist/gui/EFFocusOverlay.js +1 -1
  82. package/dist/gui/EFOverlayItem.d.ts +4 -4
  83. package/dist/gui/EFOverlayItem.js +1 -1
  84. package/dist/gui/EFOverlayLayer.d.ts +4 -4
  85. package/dist/gui/EFOverlayLayer.js +1 -1
  86. package/dist/gui/EFPause.d.ts +4 -4
  87. package/dist/gui/EFPause.js +1 -1
  88. package/dist/gui/EFPlay.d.ts +4 -4
  89. package/dist/gui/EFPlay.js +1 -1
  90. package/dist/gui/EFPreview.d.ts +4 -4
  91. package/dist/gui/EFPreview.js +1 -1
  92. package/dist/gui/EFResizableBox.d.ts +4 -4
  93. package/dist/gui/EFResizableBox.js +1 -1
  94. package/dist/gui/EFScrubber.d.ts +4 -4
  95. package/dist/gui/EFScrubber.js +1 -1
  96. package/dist/gui/EFTimeDisplay.d.ts +4 -4
  97. package/dist/gui/EFTimeDisplay.js +1 -1
  98. package/dist/gui/EFTimelineRuler.d.ts +4 -4
  99. package/dist/gui/EFTimelineRuler.js +1 -1
  100. package/dist/gui/EFToggleLoop.d.ts +4 -4
  101. package/dist/gui/EFToggleLoop.js +1 -1
  102. package/dist/gui/EFTogglePlay.d.ts +4 -4
  103. package/dist/gui/EFTogglePlay.js +1 -1
  104. package/dist/gui/EFTransformHandles.d.ts +4 -4
  105. package/dist/gui/EFTransformHandles.js +1 -1
  106. package/dist/gui/EFWorkbench.d.ts +5 -4
  107. package/dist/gui/EFWorkbench.js +1 -1
  108. package/dist/gui/PlaybackController.d.ts +10 -2
  109. package/dist/gui/PlaybackController.js +52 -30
  110. package/dist/gui/PlaybackController.js.map +1 -1
  111. package/dist/gui/TWMixin.js +1 -1
  112. package/dist/gui/TWMixin.js.map +1 -1
  113. package/dist/gui/TargetOrContextMixin.js +1 -1
  114. package/dist/gui/hierarchy/EFHierarchy.d.ts +4 -4
  115. package/dist/gui/hierarchy/EFHierarchy.js +1 -1
  116. package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
  117. package/dist/gui/hierarchy/EFHierarchyItem.js +1 -1
  118. package/dist/gui/timeline/EFTimeline.d.ts +6 -2
  119. package/dist/gui/timeline/EFTimeline.js +1 -1
  120. package/dist/gui/timeline/EFTimelineRow.d.ts +57 -0
  121. package/dist/gui/timeline/EFTimelineRow.js +1 -1
  122. package/dist/gui/timeline/TrimHandles.d.ts +4 -4
  123. package/dist/gui/timeline/TrimHandles.js +1 -1
  124. package/dist/gui/timeline/tracks/AudioTrack.d.ts +2 -0
  125. package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
  126. package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +58 -0
  127. package/dist/gui/timeline/tracks/CaptionsTrack.js +1 -1
  128. package/dist/gui/timeline/tracks/HTMLTrack.d.ts +13 -0
  129. package/dist/gui/timeline/tracks/HTMLTrack.js +1 -1
  130. package/dist/gui/timeline/tracks/ImageTrack.d.ts +14 -0
  131. package/dist/gui/timeline/tracks/ImageTrack.js +1 -1
  132. package/dist/gui/timeline/tracks/TextTrack.d.ts +26 -0
  133. package/dist/gui/timeline/tracks/TextTrack.js +1 -1
  134. package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +47 -0
  135. package/dist/gui/timeline/tracks/TimegroupTrack.js +4 -12
  136. package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
  137. package/dist/gui/timeline/tracks/TrackItem.d.ts +81 -0
  138. package/dist/gui/timeline/tracks/TrackItem.js +1 -1
  139. package/dist/gui/timeline/tracks/VideoTrack.d.ts +25 -0
  140. package/dist/gui/timeline/tracks/VideoTrack.js +1 -1
  141. package/dist/gui/timeline/tracks/WaveformTrack.d.ts +14 -0
  142. package/dist/gui/timeline/tracks/WaveformTrack.js +1 -1
  143. package/dist/gui/timeline/tracks/ensureTrackItemInit.d.ts +1 -0
  144. package/dist/gui/timeline/tracks/preloadTracks.d.ts +9 -0
  145. package/dist/gui/tree/EFTree.d.ts +5 -4
  146. package/dist/gui/tree/EFTree.js +1 -1
  147. package/dist/gui/tree/EFTreeItem.d.ts +4 -4
  148. package/dist/gui/tree/EFTreeItem.js +1 -1
  149. package/dist/index.d.ts +4 -1
  150. package/dist/preview/AdaptiveResolutionTracker.js +6 -14
  151. package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
  152. package/dist/preview/FrameController.d.ts +123 -0
  153. package/dist/preview/FrameController.js +216 -0
  154. package/dist/preview/FrameController.js.map +1 -0
  155. package/dist/preview/RenderContext.d.ts +1 -0
  156. package/dist/preview/RenderContext.js +193 -0
  157. package/dist/preview/RenderContext.js.map +1 -0
  158. package/dist/preview/encoding/canvasEncoder.js +166 -0
  159. package/dist/preview/encoding/canvasEncoder.js.map +1 -0
  160. package/dist/preview/encoding/mainThreadEncoder.js +39 -0
  161. package/dist/preview/encoding/mainThreadEncoder.js.map +1 -0
  162. package/dist/preview/encoding/types.d.ts +1 -0
  163. package/dist/preview/encoding/workerEncoder.js +58 -0
  164. package/dist/preview/encoding/workerEncoder.js.map +1 -0
  165. package/dist/preview/logger.js +41 -0
  166. package/dist/preview/logger.js.map +1 -0
  167. package/dist/preview/previewTypes.js +11 -10
  168. package/dist/preview/previewTypes.js.map +1 -1
  169. package/dist/preview/renderTimegroupPreview.js +259 -236
  170. package/dist/preview/renderTimegroupPreview.js.map +1 -1
  171. package/dist/preview/renderTimegroupToCanvas.d.ts +5 -0
  172. package/dist/preview/renderTimegroupToCanvas.js +99 -489
  173. package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
  174. package/dist/preview/renderTimegroupToVideo.d.ts +1 -0
  175. package/dist/preview/renderTimegroupToVideo.js +80 -22
  176. package/dist/preview/renderTimegroupToVideo.js.map +1 -1
  177. package/dist/preview/renderers.js.map +1 -1
  178. package/dist/preview/rendering/inlineImages.js +56 -0
  179. package/dist/preview/rendering/inlineImages.js.map +1 -0
  180. package/dist/preview/rendering/renderToImage.d.ts +1 -0
  181. package/dist/preview/rendering/renderToImage.js +120 -0
  182. package/dist/preview/rendering/renderToImage.js.map +1 -0
  183. package/dist/preview/rendering/renderToImageForeignObject.js +135 -0
  184. package/dist/preview/rendering/renderToImageForeignObject.js.map +1 -0
  185. package/dist/preview/rendering/renderToImageNative.d.ts +1 -0
  186. package/dist/preview/rendering/renderToImageNative.js +129 -0
  187. package/dist/preview/rendering/renderToImageNative.js.map +1 -0
  188. package/dist/preview/rendering/svgSerializer.js +43 -0
  189. package/dist/preview/rendering/svgSerializer.js.map +1 -0
  190. package/dist/preview/rendering/types.d.ts +2 -0
  191. package/dist/preview/statsTrackingStrategy.js +3 -1
  192. package/dist/preview/statsTrackingStrategy.js.map +1 -1
  193. package/dist/preview/workers/WorkerPool.js +8 -57
  194. package/dist/preview/workers/WorkerPool.js.map +1 -1
  195. package/dist/render/EFRenderAPI.d.ts +35 -0
  196. package/dist/render/EFRenderAPI.js +1 -0
  197. package/dist/render/EFRenderAPI.js.map +1 -1
  198. package/dist/sandbox/PlaybackControls.d.ts +1 -0
  199. package/dist/sandbox/ScenarioRunner.d.ts +1 -0
  200. package/dist/sandbox/defineSandbox.d.ts +1 -0
  201. package/dist/sandbox/index.d.ts +3 -0
  202. package/dist/style.css +3 -0
  203. package/dist/transcoding/types/index.d.ts +6 -3
  204. package/package.json +2 -3
  205. package/test/EFVideo.framegen.browsertest.ts +8 -1
  206. package/test/profilingPlugin.ts +1 -3
  207. package/test/setup.ts +23 -1
  208. package/dist/EF_INTERACTIVE.js +0 -7
  209. package/dist/EF_INTERACTIVE.js.map +0 -1
  210. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +0 -50
  211. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +0 -12
  212. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +0 -104
  213. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +0 -1
  214. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +0 -168
  215. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +0 -1
  216. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +0 -46
  217. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +0 -1
  218. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +0 -49
  219. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +0 -1
  220. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +0 -30
  221. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +0 -1
  222. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +0 -49
  223. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +0 -1
  224. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +0 -47
  225. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +0 -1
  226. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +0 -140
  227. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +0 -1
  228. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +0 -13
  229. package/dist/elements/EFMedia/shared/BufferUtils.js +0 -86
  230. package/dist/elements/EFMedia/shared/BufferUtils.js.map +0 -1
  231. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +0 -17
  232. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +0 -90
  233. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +0 -1
  234. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +0 -80
  235. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +0 -1
  236. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +0 -49
  237. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +0 -1
  238. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +0 -58
  239. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +0 -1
  240. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +0 -71
  241. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +0 -1
  242. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +0 -52
  243. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +0 -1
  244. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +0 -50
  245. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +0 -1
  246. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +0 -109
  247. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +0 -1
  248. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +0 -12
  249. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +0 -97
  250. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +0 -1
  251. package/dist/elements/SampleBuffer.d.ts +0 -19
@@ -1 +1 @@
1
- {"version":3,"file":"TimegroupTrack.js","names":["EFTimegroupTrack"],"sources":["../../../../src/gui/timeline/tracks/TimegroupTrack.ts"],"sourcesContent":["import { css, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\n// TrackItem must be pre-loaded before this module is imported\n// See preloadTracks.ts for the initialization sequence\nimport { TrackItem } from \"./TrackItem.js\";\nimport { renderTrackChildren } from \"./renderTrackChildren.js\";\nimport { EFTimegroup } from \"../../../elements/EFTimegroup.js\";\nimport \"../../../elements/EFThumbnailStrip.js\";\n\n/**\n * Check if a timegroup is a root timegroup (has no parent timegroup)\n * Uses the timegroup's own isRootTimegroup property for reliability\n */\nfunction isRootTimegroup(element: Element | null | undefined): boolean {\n // Handle null/undefined\n if (!element) {\n return false;\n }\n \n // Check if element has the isRootTimegroup property (most reliable)\n // EFTimegroup instances have this property that checks parentTimegroup\n const elem = element as any;\n if (typeof elem.isRootTimegroup === 'boolean') {\n return elem.isRootTimegroup;\n }\n \n // Alternative: check parentTimegroup property directly (EFTimegroup has this)\n if (elem.parentTimegroup !== undefined) {\n return !elem.parentTimegroup; // Root if no parent timegroup\n }\n \n // Fallback: check DOM parent tree (less reliable after DOM moves)\n let parent = element.parentElement;\n while (parent) {\n if (parent.tagName.toLowerCase() === \"ef-timegroup\") {\n return false;\n }\n parent = parent.parentElement;\n }\n return true;\n}\n\n/** Height for root timegroup filmstrip row */\nconst FILMSTRIP_ROW_HEIGHT = 48;\n\n@customElement(\"ef-timegroup-track\")\nexport class EFTimegroupTrack extends TrackItem {\n static styles = [\n ...TrackItem.styles,\n css`\n .trim-container {\n background: linear-gradient(\n 135deg,\n rgba(148, 163, 184, 0.1) 0%,\n rgba(148, 163, 184, 0.05) 100%\n ) !important;\n }\n \n :host(:hover) .trim-container {\n background: linear-gradient(\n 135deg,\n rgba(148, 163, 184, 0.15) 0%,\n rgba(148, 163, 184, 0.08) 100%\n ) !important;\n }\n `,\n ];\n\n /**\n * When true, children are not rendered (used in unified row architecture\n * where children get their own rows).\n */\n @property({ type: Boolean, attribute: \"skip-children\" })\n skipChildren = false;\n\n /**\n * When true, show filmstrip thumbnails for root timegroups\n * TODO: Re-enable when thumbnail strip performance is improved\n */\n @property({ type: Boolean, attribute: \"show-filmstrip\" })\n showFilmstrip = false;\n\n /**\n * Check if this track should show a filmstrip\n */\n private get shouldShowFilmstrip(): boolean {\n const skipChildren = this.skipChildren;\n const showFilmstrip = this.showFilmstrip;\n const hasId = !!this.element?.id;\n const isRoot = isRootTimegroup(this.element);\n \n return skipChildren && showFilmstrip && hasId && isRoot;\n }\n\n /**\n * Override trimPortionStyles to use taller height for filmstrip rows\n */\n override get trimPortionStyles() {\n const baseStyles = super.trimPortionStyles;\n if (this.shouldShowFilmstrip) {\n // Ensure minimum width for filmstrip tracks so thumbnail strip can render\n // even when duration is 0 (e.g., sequence mode timegroups before children load)\n const durationMs = this.element.durationMs ?? 0;\n const calculatedWidth = this.pixelsPerMs * durationMs;\n const minWidth = Math.max(calculatedWidth, 500); // Minimum 500px for thumbnail strip visibility\n \n return {\n ...baseStyles,\n height: `${FILMSTRIP_ROW_HEIGHT}px`,\n width: `${minWidth}px`,\n minWidth: `${minWidth}px`, // Ensure minimum width is enforced\n };\n }\n return baseStyles;\n }\n\n contents() {\n // Show filmstrip only for ROOT timegroups (no parent timegroup)\n const shouldShow = this.shouldShowFilmstrip;\n \n if (shouldShow) {\n // Don't set end-time-ms if duration is 0 - let thumbnail strip use target's duration directly\n // This allows the thumbnail strip to watch for duration changes and update automatically\n const durationMs = this.element.durationMs ?? 0;\n const elementId = this.element.id;\n \n if (!elementId) {\n return nothing;\n }\n \n return html`\n <ef-thumbnail-strip\n target=\"${elementId}\"\n start-time-ms=\"0\"\n ${durationMs > 0 ? html`end-time-ms=\"${durationMs}\"` : nothing}\n pixels-per-ms=\"${this.pixelsPerMs}\"\n ></ef-thumbnail-strip>\n `;\n }\n\n // Mode info is now shown in the label, track is empty for non-root timegroups\n if (this.skipChildren) {\n return nothing;\n }\n // Wrap children in a fragment for consistent return type\n return html`${renderTrackChildren(\n Array.from(this.element.children || []),\n this.pixelsPerMs,\n this.hideSelectors,\n this.showSelectors,\n false,\n this.enableTrim,\n )}`;\n }\n\n /**\n * Override render to use taller height for filmstrip rows\n */\n override render() {\n // Use custom height for filmstrip, standard height otherwise\n const trackHeight = this.shouldShowFilmstrip \n ? `${FILMSTRIP_ROW_HEIGHT}px` \n : \"var(--timeline-track-height, 22px)\";\n\n return html`<div style=${styleMap(this.gutterStyles)}>\n <div\n style=\"background-color: var(--filmstrip-bg);\"\n ?data-focused=${this.isFocused}\n @mouseenter=${() => {\n if (this.focusContext) {\n this.focusContext.focusedElement = this.element;\n }\n }}\n @mouseleave=${() => {\n if (this.focusContext) {\n this.focusContext.focusedElement = null;\n }\n }}\n >\n <div\n ?data-focused=${this.isFocused}\n class=\"trim-container relative mb-0 block text-nowrap border text-sm\"\n style=${styleMap({\n ...this.trimPortionStyles,\n height: trackHeight,\n backgroundColor: this.isFocused\n ? \"var(--filmstrip-item-focused)\"\n : \"var(--filmstrip-item-bg)\",\n borderColor: this.shouldShowFilmstrip ? \"transparent\" : \"var(--filmstrip-border)\",\n })}\n >\n ${this.animations()}\n ${this.contents()}\n </div>\n </div>\n ${this.renderChildren()}\n </div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-timegroup-track\": EFTimegroupTrack;\n }\n}\n\n"],"mappings":";;;;;;;;;;;;;AAcA,SAAS,gBAAgB,SAA8C;AAErE,KAAI,CAAC,QACH,QAAO;CAKT,MAAM,OAAO;AACb,KAAI,OAAO,KAAK,oBAAoB,UAClC,QAAO,KAAK;AAId,KAAI,KAAK,oBAAoB,OAC3B,QAAO,CAAC,KAAK;CAIf,IAAI,SAAS,QAAQ;AACrB,QAAO,QAAQ;AACb,MAAI,OAAO,QAAQ,aAAa,KAAK,eACnC,QAAO;AAET,WAAS,OAAO;;AAElB,QAAO;;;AAIT,MAAM,uBAAuB;AAGtB,6BAAMA,2BAAyB,UAAU;;;sBA2B/B;uBAOC;;;gBAjCA,CACd,GAAG,UAAU,QACb,GAAG;;;;;;;;;;;;;;;;MAiBJ;;;;;CAmBD,IAAY,sBAA+B;EACzC,MAAM,eAAe,KAAK;EAC1B,MAAM,gBAAgB,KAAK;EAC3B,MAAM,QAAQ,CAAC,CAAC,KAAK,SAAS;EAC9B,MAAM,SAAS,gBAAgB,KAAK,QAAQ;AAE5C,SAAO,gBAAgB,iBAAiB,SAAS;;;;;CAMnD,IAAa,oBAAoB;EAC/B,MAAM,aAAa,MAAM;AACzB,MAAI,KAAK,qBAAqB;GAG5B,MAAM,aAAa,KAAK,QAAQ,cAAc;GAC9C,MAAM,kBAAkB,KAAK,cAAc;GAC3C,MAAM,WAAW,KAAK,IAAI,iBAAiB,IAAI;AAE/C,UAAO;IACL,GAAG;IACH,QAAQ,GAAG,qBAAqB;IAChC,OAAO,GAAG,SAAS;IACnB,UAAU,GAAG,SAAS;IACvB;;AAEH,SAAO;;CAGT,WAAW;AAIT,MAFmB,KAAK,qBAER;GAGd,MAAM,aAAa,KAAK,QAAQ,cAAc;GAC9C,MAAM,YAAY,KAAK,QAAQ;AAE/B,OAAI,CAAC,UACH,QAAO;AAGT,UAAO,IAAI;;oBAEG,UAAU;;YAElB,aAAa,IAAI,IAAI,gBAAgB,WAAW,KAAK,QAAQ;2BAC9C,KAAK,YAAY;;;;AAMxC,MAAI,KAAK,aACP,QAAO;AAGT,SAAO,IAAI,GAAG,oBACZ,MAAM,KAAK,KAAK,QAAQ,YAAY,EAAE,CAAC,EACvC,KAAK,aACL,KAAK,eACL,KAAK,eACL,OACA,KAAK,WACN;;;;;CAMH,AAAS,SAAS;EAEhB,MAAM,cAAc,KAAK,sBACrB,GAAG,qBAAqB,MACxB;AAEJ,SAAO,IAAI,cAAc,SAAS,KAAK,aAAa,CAAC;;;wBAGjC,KAAK,UAAU;4BACX;AAClB,OAAI,KAAK,aACP,MAAK,aAAa,iBAAiB,KAAK;IAE1C;4BACkB;AAClB,OAAI,KAAK,aACP,MAAK,aAAa,iBAAiB;IAErC;;;0BAGgB,KAAK,UAAU;;kBAEvB,SAAS;GACf,GAAG,KAAK;GACR,QAAQ;GACR,iBAAiB,KAAK,YAClB,kCACA;GACJ,aAAa,KAAK,sBAAsB,gBAAgB;GACzD,CAAC,CAAC;;YAED,KAAK,YAAY,CAAC;YAClB,KAAK,UAAU,CAAC;;;QAGpB,KAAK,gBAAgB,CAAC;;;;YA3H3B,SAAS;CAAE,MAAM;CAAS,WAAW;CAAiB,CAAC;YAOvD,SAAS;CAAE,MAAM;CAAS,WAAW;CAAkB,CAAC;+BAlC1D,cAAc,qBAAqB"}
1
+ {"version":3,"file":"TimegroupTrack.js","names":["EFTimegroupTrack"],"sources":["../../../../src/gui/timeline/tracks/TimegroupTrack.ts"],"sourcesContent":["import { css, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\n// TrackItem must be pre-loaded before this module is imported\n// See preloadTracks.ts for the initialization sequence\nimport { TrackItem } from \"./TrackItem.js\";\nimport { renderTrackChildren } from \"./renderTrackChildren.js\";\nimport \"../../../elements/EFThumbnailStrip.js\";\n\n/**\n * Check if a timegroup is a root timegroup (has no parent timegroup)\n * Uses the timegroup's own isRootTimegroup property for reliability\n */\nfunction isRootTimegroup(element: Element | null | undefined): boolean {\n // Handle null/undefined\n if (!element) {\n return false;\n }\n \n // Check if element has the isRootTimegroup property (most reliable)\n // EFTimegroup instances have this property that checks parentTimegroup\n const elem = element as any;\n if (typeof elem.isRootTimegroup === 'boolean') {\n return elem.isRootTimegroup;\n }\n \n // Alternative: check parentTimegroup property directly (EFTimegroup has this)\n if (elem.parentTimegroup !== undefined) {\n return !elem.parentTimegroup; // Root if no parent timegroup\n }\n \n // Fallback: check DOM parent tree (less reliable after DOM moves)\n let parent = element.parentElement;\n while (parent) {\n if (parent.tagName.toLowerCase() === \"ef-timegroup\") {\n return false;\n }\n parent = parent.parentElement;\n }\n return true;\n}\n\n/** Height for root timegroup filmstrip row */\nconst FILMSTRIP_ROW_HEIGHT = 48;\n\n@customElement(\"ef-timegroup-track\")\nexport class EFTimegroupTrack extends TrackItem {\n static styles = [\n ...TrackItem.styles,\n css`\n .trim-container {\n background: linear-gradient(\n 135deg,\n rgba(148, 163, 184, 0.1) 0%,\n rgba(148, 163, 184, 0.05) 100%\n ) !important;\n }\n \n :host(:hover) .trim-container {\n background: linear-gradient(\n 135deg,\n rgba(148, 163, 184, 0.15) 0%,\n rgba(148, 163, 184, 0.08) 100%\n ) !important;\n }\n `,\n ];\n\n /**\n * When true, children are not rendered (used in unified row architecture\n * where children get their own rows).\n */\n @property({ type: Boolean, attribute: \"skip-children\" })\n skipChildren = false;\n\n /**\n * When true, show filmstrip thumbnails for root timegroups\n * TODO: Re-enable when thumbnail strip performance is improved\n */\n @property({ type: Boolean, attribute: \"show-filmstrip\" })\n showFilmstrip = false;\n\n /**\n * Check if this track should show a filmstrip\n */\n private get shouldShowFilmstrip(): boolean {\n const skipChildren = this.skipChildren;\n const showFilmstrip = this.showFilmstrip;\n const hasId = !!this.element?.id;\n const isRoot = isRootTimegroup(this.element);\n \n return skipChildren && showFilmstrip && hasId && isRoot;\n }\n\n /**\n * Override trimPortionStyles to use taller height for filmstrip rows\n */\n override get trimPortionStyles() {\n const baseStyles = super.trimPortionStyles;\n if (this.shouldShowFilmstrip) {\n // Ensure minimum width for filmstrip tracks so thumbnail strip can render\n // even when duration is 0 (e.g., sequence mode timegroups before children load)\n const durationMs = this.element.durationMs ?? 0;\n const calculatedWidth = this.pixelsPerMs * durationMs;\n const minWidth = Math.max(calculatedWidth, 500); // Minimum 500px for thumbnail strip visibility\n \n return {\n ...baseStyles,\n height: `${FILMSTRIP_ROW_HEIGHT}px`,\n width: `${minWidth}px`,\n minWidth: `${minWidth}px`, // Ensure minimum width is enforced\n };\n }\n return baseStyles;\n }\n\n contents() {\n // Show filmstrip only for ROOT timegroups (no parent timegroup)\n const shouldShow = this.shouldShowFilmstrip;\n \n if (shouldShow) {\n // Don't set end-time-ms if duration is 0 - let thumbnail strip use target's duration directly\n // This allows the thumbnail strip to watch for duration changes and update automatically\n const durationMs = this.element.durationMs ?? 0;\n const elementId = this.element.id;\n \n if (!elementId) {\n return nothing;\n }\n \n return nothing;\n return html`\n <ef-thumbnail-strip\n target=\"${elementId}\"\n start-time-ms=\"0\"\n ${durationMs > 0 ? html`end-time-ms=\"${durationMs}\"` : nothing}\n pixels-per-ms=\"${this.pixelsPerMs}\"\n ></ef-thumbnail-strip>\n `;\n }\n\n // Mode info is now shown in the label, track is empty for non-root timegroups\n if (this.skipChildren) {\n return nothing;\n }\n // Wrap children in a fragment for consistent return type\n return html`${renderTrackChildren(\n Array.from(this.element.children || []),\n this.pixelsPerMs,\n this.hideSelectors,\n this.showSelectors,\n false,\n this.enableTrim,\n )}`;\n }\n\n /**\n * Override render to use taller height for filmstrip rows\n */\n override render() {\n // Use custom height for filmstrip, standard height otherwise\n const trackHeight = this.shouldShowFilmstrip \n ? `${FILMSTRIP_ROW_HEIGHT}px` \n : \"var(--timeline-track-height, 22px)\";\n\n return html`<div style=${styleMap(this.gutterStyles)}>\n <div\n style=\"background-color: var(--filmstrip-bg);\"\n ?data-focused=${this.isFocused}\n @mouseenter=${() => {\n if (this.focusContext) {\n this.focusContext.focusedElement = this.element;\n }\n }}\n @mouseleave=${() => {\n if (this.focusContext) {\n this.focusContext.focusedElement = null;\n }\n }}\n >\n <div\n ?data-focused=${this.isFocused}\n class=\"trim-container relative mb-0 block text-nowrap border text-sm\"\n style=${styleMap({\n ...this.trimPortionStyles,\n height: trackHeight,\n backgroundColor: this.isFocused\n ? \"var(--filmstrip-item-focused)\"\n : \"var(--filmstrip-item-bg)\",\n borderColor: this.shouldShowFilmstrip ? \"transparent\" : \"var(--filmstrip-border)\",\n })}\n >\n ${this.animations()}\n ${this.contents()}\n </div>\n </div>\n ${this.renderChildren()}\n </div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-timegroup-track\": EFTimegroupTrack;\n }\n}\n\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAS,gBAAgB,SAA8C;AAErE,KAAI,CAAC,QACH,QAAO;CAKT,MAAM,OAAO;AACb,KAAI,OAAO,KAAK,oBAAoB,UAClC,QAAO,KAAK;AAId,KAAI,KAAK,oBAAoB,OAC3B,QAAO,CAAC,KAAK;CAIf,IAAI,SAAS,QAAQ;AACrB,QAAO,QAAQ;AACb,MAAI,OAAO,QAAQ,aAAa,KAAK,eACnC,QAAO;AAET,WAAS,OAAO;;AAElB,QAAO;;;AAIT,MAAM,uBAAuB;AAGtB,6BAAMA,2BAAyB,UAAU;;;sBA2B/B;uBAOC;;;gBAjCA,CACd,GAAG,UAAU,QACb,GAAG;;;;;;;;;;;;;;;;MAiBJ;;;;;CAmBD,IAAY,sBAA+B;EACzC,MAAM,eAAe,KAAK;EAC1B,MAAM,gBAAgB,KAAK;EAC3B,MAAM,QAAQ,CAAC,CAAC,KAAK,SAAS;EAC9B,MAAM,SAAS,gBAAgB,KAAK,QAAQ;AAE5C,SAAO,gBAAgB,iBAAiB,SAAS;;;;;CAMnD,IAAa,oBAAoB;EAC/B,MAAM,aAAa,MAAM;AACzB,MAAI,KAAK,qBAAqB;GAG5B,MAAM,aAAa,KAAK,QAAQ,cAAc;GAC9C,MAAM,kBAAkB,KAAK,cAAc;GAC3C,MAAM,WAAW,KAAK,IAAI,iBAAiB,IAAI;AAE/C,UAAO;IACL,GAAG;IACH,QAAQ,GAAG,qBAAqB;IAChC,OAAO,GAAG,SAAS;IACnB,UAAU,GAAG,SAAS;IACvB;;AAEH,SAAO;;CAGT,WAAW;AAIT,MAFmB,KAAK,qBAER;AAGK,QAAK,QAAQ;AAGhC,OAAI,CAFc,KAAK,QAAQ,GAG7B,QAAO;AAGT,UAAO;;AAYT,MAAI,KAAK,aACP,QAAO;AAGT,SAAO,IAAI,GAAG,oBACZ,MAAM,KAAK,KAAK,QAAQ,YAAY,EAAE,CAAC,EACvC,KAAK,aACL,KAAK,eACL,KAAK,eACL,OACA,KAAK,WACN;;;;;CAMH,AAAS,SAAS;EAEhB,MAAM,cAAc,KAAK,sBACrB,GAAG,qBAAqB,MACxB;AAEJ,SAAO,IAAI,cAAc,SAAS,KAAK,aAAa,CAAC;;;wBAGjC,KAAK,UAAU;4BACX;AAClB,OAAI,KAAK,aACP,MAAK,aAAa,iBAAiB,KAAK;IAE1C;4BACkB;AAClB,OAAI,KAAK,aACP,MAAK,aAAa,iBAAiB;IAErC;;;0BAGgB,KAAK,UAAU;;kBAEvB,SAAS;GACf,GAAG,KAAK;GACR,QAAQ;GACR,iBAAiB,KAAK,YAClB,kCACA;GACJ,aAAa,KAAK,sBAAsB,gBAAgB;GACzD,CAAC,CAAC;;YAED,KAAK,YAAY,CAAC;YAClB,KAAK,UAAU,CAAC;;;QAGpB,KAAK,gBAAgB,CAAC;;;;YA5H3B,SAAS;CAAE,MAAM;CAAS,WAAW;CAAiB,CAAC;YAOvD,SAAS;CAAE,MAAM;CAAS,WAAW;CAAkB,CAAC;+BAlC1D,cAAc,qBAAqB"}
@@ -0,0 +1,81 @@
1
+ import { TemporalMixinInterface } from "../../../elements/EFTemporal.js";
2
+ import { FocusContext } from "../../focusContext.js";
3
+ import { TrimChangeDetail } from "../TrimHandles.js";
4
+ import * as lit43 from "lit";
5
+ import { LitElement, PropertyValueMap, ReactiveController, TemplateResult, nothing } from "lit";
6
+
7
+ //#region src/gui/timeline/tracks/TrackItem.d.ts
8
+ declare class ElementTrackController implements ReactiveController {
9
+ private host;
10
+ private track;
11
+ private lastDuration;
12
+ private durationCheckFrame?;
13
+ constructor(host: LitElement, track: TrackItem);
14
+ remove(): void;
15
+ hostDisconnected(): void;
16
+ hostConnected(): void;
17
+ private checkDuration;
18
+ hostUpdated(): void;
19
+ }
20
+ declare const TrackItem_base: typeof LitElement;
21
+ declare class TrackItem extends TrackItem_base {
22
+ static styles: lit43.CSSResult[];
23
+ focusContext?: FocusContext;
24
+ focusedElement?: HTMLElement | null;
25
+ get isFocused(): boolean;
26
+ /**
27
+ * Get element type for styling and icons
28
+ */
29
+ protected getElementType(): "video" | "audio" | "image" | "text" | "timegroup" | "captions" | "unknown";
30
+ /**
31
+ * Get color for element type
32
+ */
33
+ protected getElementTypeColor(): string;
34
+ /**
35
+ * Get icon for element type
36
+ */
37
+ protected getElementIcon(): TemplateResult | typeof nothing;
38
+ /**
39
+ * Format duration for display
40
+ */
41
+ protected formatDuration(ms: number): string;
42
+ /**
43
+ * Get tooltip text with element info
44
+ */
45
+ protected getTooltipText(): string;
46
+ element: TemporalMixinInterface & LitElement;
47
+ pixelsPerMs: number;
48
+ enableTrim: boolean;
49
+ hideSelectors?: string[];
50
+ showSelectors?: string[];
51
+ /**
52
+ * When true, positions the track at the element's absolute start time
53
+ * (startTimeMs) rather than relative to parent (startTimeWithinParentMs).
54
+ * Used for flat row architectures where each element gets its own row.
55
+ */
56
+ useAbsolutePosition: boolean;
57
+ get gutterStyles(): {
58
+ position: string;
59
+ left: string;
60
+ width: string;
61
+ };
62
+ get trimPortionStyles(): {
63
+ width: string;
64
+ left: string;
65
+ };
66
+ protected handleTrimChange(e: CustomEvent<TrimChangeDetail>): void;
67
+ contents(): TemplateResult | typeof nothing;
68
+ animations(): never[];
69
+ renderChildren(): Array<TemplateResult<1> | typeof nothing> | typeof nothing;
70
+ render(): TemplateResult<1>;
71
+ protected trackController?: ElementTrackController;
72
+ update(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
73
+ }
74
+ declare global {
75
+ interface HTMLElementTagNameMap {
76
+ "ef-track-item": TrackItem;
77
+ }
78
+ }
79
+ //#endregion
80
+ export { TrackItem };
81
+ //# sourceMappingURL=TrackItem.d.ts.map
@@ -1,4 +1,4 @@
1
- import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
+ import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
2
2
  import { focusContext } from "../../focusContext.js";
3
3
  import { focusedElementContext } from "../../focusedElementContext.js";
4
4
  import { TWMixin } from "../../TWMixin2.js";
@@ -0,0 +1,25 @@
1
+ import { TrackItem } from "./TrackItem.js";
2
+ import "../../../elements/EFThumbnailStrip.js";
3
+ import * as lit39 from "lit";
4
+ import * as lit_html36 from "lit-html";
5
+ import * as lit_html_directives_ref_js5 from "lit-html/directives/ref.js";
6
+
7
+ //#region src/gui/timeline/tracks/VideoTrack.d.ts
8
+ declare class EFVideoTrack extends TrackItem {
9
+ #private;
10
+ static styles: lit39.CSSResult[];
11
+ audioCanvasRef: lit_html_directives_ref_js5.Ref<HTMLCanvasElement>;
12
+ private _timelineState?;
13
+ private _waveformData;
14
+ private _hasAudio;
15
+ connectedCallback(): void;
16
+ disconnectedCallback(): void;
17
+ updated(changedProperties: Map<string | number | symbol, unknown>): void;
18
+ render(): lit_html36.TemplateResult<1>;
19
+ }
20
+ declare global {
21
+ interface HTMLElementTagNameMap {
22
+ "ef-video-track": EFVideoTrack;
23
+ }
24
+ }
25
+ //# sourceMappingURL=VideoTrack.d.ts.map
@@ -1,4 +1,4 @@
1
- import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
+ import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
2
2
  import { EFVideo } from "../../../elements/EFVideo.js";
3
3
  import { TrackItem } from "./TrackItem.js";
4
4
  import { extractWaveformData } from "./waveformUtils.js";
@@ -0,0 +1,14 @@
1
+ import { TrackItem } from "./TrackItem.js";
2
+ import { TemplateResult, nothing } from "lit";
3
+
4
+ //#region src/gui/timeline/tracks/WaveformTrack.d.ts
5
+ declare class EFWaveformTrack extends TrackItem {
6
+ contents(): TemplateResult<1>;
7
+ renderChildren(): Array<TemplateResult<1> | typeof nothing> | typeof nothing;
8
+ }
9
+ declare global {
10
+ interface HTMLElementTagNameMap {
11
+ "ef-waveform-track": EFWaveformTrack;
12
+ }
13
+ }
14
+ //# sourceMappingURL=WaveformTrack.d.ts.map
@@ -1,4 +1,4 @@
1
- import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
+ import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
2
2
  import { ICONS, phosphorIcon } from "../../icons.js";
3
3
  import { TrackItem } from "./TrackItem.js";
4
4
  import { nothing } from "lit";
@@ -0,0 +1 @@
1
+ import { TrackItem } from "./TrackItem.js";
@@ -0,0 +1,9 @@
1
+ import "./ensureTrackItemInit.js";
2
+ import "./AudioTrack.js";
3
+ import "./VideoTrack.js";
4
+ import "./ImageTrack.js";
5
+ import "./TimegroupTrack.js";
6
+ import "./TextTrack.js";
7
+ import "./HTMLTrack.js";
8
+ import "./CaptionsTrack.js";
9
+ import "./WaveformTrack.js";
@@ -1,7 +1,8 @@
1
1
  import { TreeItem } from "./treeContext.js";
2
- import * as lit16 from "lit";
2
+ import "./EFTreeItem.js";
3
+ import * as lit12 from "lit";
3
4
  import { LitElement, PropertyValues } from "lit";
4
- import * as lit_html16 from "lit-html";
5
+ import * as lit_html12 from "lit-html";
5
6
 
6
7
  //#region src/gui/tree/EFTree.d.ts
7
8
 
@@ -28,7 +29,7 @@ import * as lit_html16 from "lit-html";
28
29
  * ```
29
30
  */
30
31
  declare class EFTree extends LitElement {
31
- static styles: lit16.CSSResult;
32
+ static styles: lit12.CSSResult;
32
33
  /** Tree items to display */
33
34
  items: TreeItem[];
34
35
  /** Optional header text */
@@ -47,7 +48,7 @@ declare class EFTree extends LitElement {
47
48
  protected willUpdate(changedProperties: PropertyValues): void;
48
49
  protected updated(changedProperties: PropertyValues): void;
49
50
  connectedCallback(): void;
50
- render(): lit_html16.TemplateResult<1>;
51
+ render(): lit_html12.TemplateResult<1>;
51
52
  }
52
53
  declare global {
53
54
  interface HTMLElementTagNameMap {
@@ -1,4 +1,4 @@
1
- import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
+ import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
2
2
  import { collectAllIds, treeContext } from "./treeContext.js";
3
3
  import "./EFTreeItem.js";
4
4
  import { provide } from "@lit/context";
@@ -1,7 +1,7 @@
1
1
  import { TreeContext, TreeItem } from "./treeContext.js";
2
- import * as lit17 from "lit";
2
+ import * as lit13 from "lit";
3
3
  import { LitElement, nothing } from "lit";
4
- import * as lit_html17 from "lit-html";
4
+ import * as lit_html13 from "lit-html";
5
5
 
6
6
  //#region src/gui/tree/EFTreeItem.d.ts
7
7
 
@@ -17,7 +17,7 @@ import * as lit_html17 from "lit-html";
17
17
  * @fires tree-item-click - When item is clicked (for selection)
18
18
  */
19
19
  declare class EFTreeItem extends LitElement {
20
- static styles: lit17.CSSResult;
20
+ static styles: lit13.CSSResult;
21
21
  treeContext?: TreeContext;
22
22
  item: TreeItem;
23
23
  private localExpanded;
@@ -26,7 +26,7 @@ declare class EFTreeItem extends LitElement {
26
26
  get hasChildren(): boolean;
27
27
  private handleClick;
28
28
  private handleExpandClick;
29
- render(): lit_html17.TemplateResult<1> | typeof nothing;
29
+ render(): lit_html13.TemplateResult<1> | typeof nothing;
30
30
  }
31
31
  declare global {
32
32
  interface HTMLElementTagNameMap {
@@ -1,4 +1,4 @@
1
- import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
+ import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
2
2
  import { treeContext } from "./treeContext.js";
3
3
  import { consume } from "@lit/context";
4
4
  import { LitElement, css, html, nothing } from "lit";
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { TraceContext } from "./otel/tracingHelpers.js";
2
+ import "./EF_FRAMEGEN.js";
2
3
  import { TemporalMixinInterface, isEFTemporal } from "./elements/EFTemporal.js";
3
4
  import { EFMedia } from "./elements/EFMedia.js";
4
5
  import { ContainerInfo, getContainerInfoFromElement } from "./elements/ContainerInfo.js";
5
6
  import { ElementPositionInfo, PositionInfoMixin, getPositionInfoFromElement } from "./elements/ElementPositionInfo.js";
7
+ import { EFVideo } from "./elements/EFVideo.js";
6
8
  import { RenderProgress, RenderToVideoOptions } from "./preview/renderTimegroupToVideo.js";
7
9
  import { CanvasElementBounds, CanvasElementData, SelectionState } from "./canvas/api/types.js";
8
10
  import { EFPanZoom, PanZoomTransform } from "./elements/EFPanZoom.js";
@@ -12,7 +14,6 @@ import { EFTransformHandles, TransformBounds } from "./gui/EFTransformHandles.js
12
14
  import { EFCanvas } from "./canvas/EFCanvas.js";
13
15
  import { EFHierarchy } from "./gui/hierarchy/EFHierarchy.js";
14
16
  import { EFTrimHandles, TrimChangeDetail } from "./gui/timeline/TrimHandles.js";
15
- import { EFVideo } from "./elements/EFVideo.js";
16
17
  import { EFThumbnailStrip } from "./elements/EFThumbnailStrip.js";
17
18
  import { EFAudio } from "./elements/EFAudio.js";
18
19
  import { EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment } from "./elements/EFCaptions.js";
@@ -22,6 +23,7 @@ import { EFFilmstrip } from "./gui/EFFilmstrip.js";
22
23
  import { EFFitScale } from "./gui/EFFitScale.js";
23
24
  import { EFWorkbench } from "./gui/EFWorkbench.js";
24
25
  import { EFTimegroup } from "./elements/EFTimegroup.js";
26
+ import "./sandbox/index.js";
25
27
  import { elementNeedsFitScale, needsFitScale } from "./gui/FitScaleHelpers.js";
26
28
  import { EFImage } from "./elements/EFImage.js";
27
29
  import { EFTextSegment } from "./elements/EFTextSegment.js";
@@ -50,6 +52,7 @@ import { EFSurface } from "./elements/EFSurface.js";
50
52
  import { EFCanvasItem } from "./canvas/EFCanvasItem.js";
51
53
  import { CanvasAPI } from "./canvas/api/CanvasAPI.js";
52
54
  import { SelectionModel } from "./canvas/selection/SelectionModel.js";
55
+ import "./render/EFRenderAPI.js";
53
56
  import { RenderInfo, getRenderInfo } from "./getRenderInfo.js";
54
57
  import { getRenderData } from "./render/getRenderData.js";
55
58
  export { type BoxBounds, CanvasAPI, type CanvasElementBounds, type CanvasElementData, type ContainerInfo, type DialChangeDetail, EFActiveRootTemporal, EFAudio, EFAudioHierarchyItem, EFCanvas, EFCanvasItem, EFCaptions, EFCaptionsActiveWord, EFCaptionsActiveWordHierarchyItem, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsHierarchyItem, EFCaptionsSegment, EFConfiguration, EFControls, EFDial, EFFilmstrip, EFFitScale, EFFocusOverlay, EFHTMLHierarchyItem, EFHierarchy, EFHierarchyItem, EFImage, EFImageHierarchyItem, type EFMedia, EFOverlayItem, EFOverlayLayer, EFPanZoom, EFPause, EFPlay, EFPreview, EFResizableBox, EFScrubber, EFSurface, EFText, EFTextHierarchyItem, EFTextSegment, EFTextSegmentHierarchyItem, EFThumbnailStrip, EFTimeDisplay, EFTimegroup, EFTimegroupHierarchyItem, EFTimeline, EFTimelineRuler, EFToggleLoop, EFTogglePlay, EFTransformHandles, EFTree, EFTreeItem, EFTrimHandles, EFVideo, EFVideoHierarchyItem, EFWaveform, EFWaveformHierarchyItem, EFWorkbench, type ElementPositionInfo, type HierarchyActions, type HierarchyContext, type HierarchyState, type OverlayItemPosition, type PanZoomTransform, PositionInfoMixin, RenderInfo, type RenderProgress, type RenderToVideoOptions, SelectionModel, type SelectionState, type TemporalMixinInterface, type TraceContext, type TransformBounds, type TreeActions, type TreeContext, type TreeItem, type TreeState, type TrimChangeDetail, calculateFrameIntervalMs, calculatePixelsPerFrame, collectAllIds, elementNeedsFitScale, getContainerInfoFromElement, getCornerPoint, getOppositeCorner, getPositionInfoFromElement, getRenderData, getRenderInfo, hierarchyContext, isEFTemporal, needsFitScale, quantizeToFrameTimeMs, rotatePoint, shouldShowFrameMarkers, treeContext };
@@ -1,15 +1,7 @@
1
+ import { logger } from "./logger.js";
2
+
1
3
  //#region src/preview/AdaptiveResolutionTracker.ts
2
4
  /**
3
- * Adaptive Resolution Tracker
4
- *
5
- * Monitors actual render time to dynamically adjust preview resolution
6
- * for smooth playback without dropped frames.
7
- *
8
- * Key insight: We measure how long each render() takes, not rAF timing.
9
- * If renders consistently take longer than our frame budget, scale down.
10
- * If renders consistently have headroom, scale up.
11
- */
12
- /**
13
5
  * Available resolution scale steps for adaptive scaling.
14
6
  * Finer-grained steps (5% increments) for smoother adaptation.
15
7
  * Ordered from highest to lowest quality.
@@ -83,7 +75,7 @@ var AdaptiveResolutionTracker = class {
83
75
  });
84
76
  this.pressureObserver.observe("cpu", { sampleInterval: 500 });
85
77
  } catch (e) {
86
- console.warn("[AdaptiveResolutionTracker] Failed to initialize PressureObserver:", e);
78
+ logger.warn("[AdaptiveResolutionTracker] Failed to initialize PressureObserver:", e);
87
79
  this.pressureObserver = null;
88
80
  }
89
81
  }
@@ -134,7 +126,7 @@ var AdaptiveResolutionTracker = class {
134
126
  this.samplesAtCurrentScale = 0;
135
127
  this.renderTimes = [];
136
128
  const newScale = SCALE_STEPS[this.currentScaleIndex];
137
- console.log(`[AdaptiveResolutionTracker] Scaling DOWN to ${(newScale * 100).toFixed(0)}% (reason: ${reason})`);
129
+ logger.debug(`[AdaptiveResolutionTracker] Scaling DOWN to ${(newScale * 100).toFixed(0)}% (reason: ${reason})`);
138
130
  this.onScaleChange?.(newScale);
139
131
  }
140
132
  }
@@ -148,7 +140,7 @@ var AdaptiveResolutionTracker = class {
148
140
  this.samplesAtCurrentScale = 0;
149
141
  this.renderTimes = [];
150
142
  const newScale = SCALE_STEPS[this.currentScaleIndex];
151
- console.log(`[AdaptiveResolutionTracker] Scaling UP to ${(newScale * 100).toFixed(0)}% (reason: stable performance)`);
143
+ logger.debug(`[AdaptiveResolutionTracker] Scaling UP to ${(newScale * 100).toFixed(0)}% (reason: stable performance)`);
152
144
  this.onScaleChange?.(newScale);
153
145
  }
154
146
  }
@@ -208,7 +200,7 @@ var AdaptiveResolutionTracker = class {
208
200
  this.renderTimes = [];
209
201
  this.lastScaleChangeTime = 0;
210
202
  this.samplesAtCurrentScale = 0;
211
- console.log(`[AdaptiveResolutionTracker] Initialized at scale ${(SCALE_STEPS[bestIndex] * 100).toFixed(0)}%`);
203
+ logger.debug(`[AdaptiveResolutionTracker] Initialized at scale ${(SCALE_STEPS[bestIndex] * 100).toFixed(0)}%`);
212
204
  }
213
205
  /**
214
206
  * Clean up resources.
@@ -1 +1 @@
1
- {"version":3,"file":"AdaptiveResolutionTracker.js","names":[],"sources":["../../src/preview/AdaptiveResolutionTracker.ts"],"sourcesContent":["/**\n * Adaptive Resolution Tracker\n * \n * Monitors actual render time to dynamically adjust preview resolution\n * for smooth playback without dropped frames.\n * \n * Key insight: We measure how long each render() takes, not rAF timing.\n * If renders consistently take longer than our frame budget, scale down.\n * If renders consistently have headroom, scale up.\n */\n\n/**\n * Available resolution scale steps for adaptive scaling.\n * Finer-grained steps (5% increments) for smoother adaptation.\n * Ordered from highest to lowest quality.\n */\nconst SCALE_STEPS = [\n 1.0, 0.95, 0.90, 0.85, 0.80, \n 0.75, 0.70, 0.65, 0.60, 0.55,\n 0.50, 0.45, 0.40, 0.35, 0.30,\n 0.25, 0.20, 0.15, 0.10\n] as const;\ntype ScaleStep = typeof SCALE_STEPS[number];\n\n/**\n * Compute Pressure API types (not yet in TypeScript lib)\n */\ntype PressureState = \"nominal\" | \"fair\" | \"serious\" | \"critical\";\n\ninterface PressureRecord {\n state: PressureState;\n time: number;\n}\n\ninterface PressureObserverCallback {\n (records: PressureRecord[]): void;\n}\n\ninterface PressureObserverOptions {\n sampleInterval?: number;\n}\n\ndeclare class PressureObserver {\n constructor(callback: PressureObserverCallback);\n observe(source: \"cpu\", options?: PressureObserverOptions): Promise<void>;\n unobserve(source: \"cpu\"): void;\n disconnect(): void;\n}\n\n/**\n * Timing thresholds\n * \n * Target: 30fps = 33.33ms per frame\n * Tolerate down to 15fps (half target) before scaling down.\n * Scale up when we have plenty of headroom.\n */\nconst TARGET_FRAME_TIME_MS = 33.33; // 30fps target\nconst SCALE_DOWN_THRESHOLD_MS = 66.67; // 15fps (half target) - only scale down if really struggling\nconst SCALE_UP_THRESHOLD_MS = 25; // If avg render time is well below target, consider scaling up\nconst ROLLING_WINDOW_SIZE = 30; // ~1 second of samples at 30fps\nconst MIN_SCALE_CHANGE_INTERVAL_MS = 2000; // Wait 2s between any scale changes\nconst SCALE_UP_STABILITY_SAMPLES = 60; // Need 60 samples (~2s) of good performance to scale up\n\n/** Size of the pressure history for histogram display */\nconst PRESSURE_HISTORY_SIZE = 60;\n\n/**\n * Tracks render time to recommend optimal preview resolution.\n */\nexport class AdaptiveResolutionTracker {\n private renderTimes: number[] = []; // Rolling window of render times (ms)\n private currentScaleIndex = 0; // Index into SCALE_STEPS (0 = highest quality)\n private lastScaleChangeTime = 0;\n private samplesAtCurrentScale = 0; // How many samples we've collected at current scale\n \n // Compute Pressure API\n private pressureObserver: PressureObserver | null = null;\n private pressureState: PressureState = \"nominal\";\n private pressureHistory: PressureState[] = [];\n \n // For display - track frame intervals separately from render times\n private lastFrameTime = 0;\n private frameIntervals: number[] = [];\n \n // Callbacks\n private onScaleChange?: (scale: ScaleStep) => void;\n \n constructor(options?: { onScaleChange?: (scale: ScaleStep) => void }) {\n this.onScaleChange = options?.onScaleChange;\n this.initPressureObserver();\n }\n \n /**\n * Initialize Compute Pressure API observer if available.\n */\n private initPressureObserver(): void {\n if (!(\"PressureObserver\" in globalThis)) {\n return;\n }\n \n try {\n this.pressureObserver = new PressureObserver((records) => {\n if (records.length > 0) {\n const latest = records[records.length - 1]!;\n this.pressureState = latest.state;\n \n this.pressureHistory.push(latest.state);\n if (this.pressureHistory.length > PRESSURE_HISTORY_SIZE) {\n this.pressureHistory.shift();\n }\n }\n });\n \n this.pressureObserver.observe(\"cpu\", { sampleInterval: 500 });\n } catch (e) {\n console.warn(\"[AdaptiveResolutionTracker] Failed to initialize PressureObserver:\", e);\n this.pressureObserver = null;\n }\n }\n \n /**\n * Record a frame's render time.\n * Call this AFTER each render completes with how long the render took.\n * \n * @param renderTimeMs - How long the render() call took in milliseconds\n * @param timestamp - Optional rAF timestamp for frame interval tracking (display only)\n */\n recordFrame(renderTimeMs: number, timestamp?: number): void {\n // Track render times for adaptive decisions\n this.renderTimes.push(renderTimeMs);\n if (this.renderTimes.length > ROLLING_WINDOW_SIZE) {\n this.renderTimes.shift();\n }\n this.samplesAtCurrentScale++;\n \n // Track frame intervals for FPS display (separate from render time)\n if (timestamp !== undefined && this.lastFrameTime > 0) {\n const interval = timestamp - this.lastFrameTime;\n this.frameIntervals.push(interval);\n if (this.frameIntervals.length > ROLLING_WINDOW_SIZE) {\n this.frameIntervals.shift();\n }\n }\n if (timestamp !== undefined) {\n this.lastFrameTime = timestamp;\n }\n \n // Check if we should adjust scale\n this.checkForScaleAdjustment();\n }\n \n /**\n * Check if we should scale up or down based on render time trends.\n */\n private checkForScaleAdjustment(): void {\n if (this.renderTimes.length < 10) return; // Need some samples\n \n const now = performance.now();\n if (now - this.lastScaleChangeTime < MIN_SCALE_CHANGE_INTERVAL_MS) {\n return; // Rate limit changes\n }\n \n const avgRenderTime = this.renderTimes.reduce((a, b) => a + b, 0) / this.renderTimes.length;\n \n // Scale DOWN if we're consistently slow\n if (avgRenderTime > SCALE_DOWN_THRESHOLD_MS) {\n this.scaleDown(\"slow\");\n return;\n }\n \n // Scale DOWN if CPU pressure is high (proactive)\n if (this.pressureState === \"critical\" || this.pressureState === \"serious\") {\n this.scaleDown(\"pressure\");\n return;\n }\n \n // Scale UP if we have sustained headroom and CPU isn't under pressure\n // (we already returned above if pressure is serious/critical, but check again for clarity)\n const pressureOk = this.pressureState === \"nominal\" || this.pressureState === \"fair\";\n if (avgRenderTime < SCALE_UP_THRESHOLD_MS && \n this.samplesAtCurrentScale >= SCALE_UP_STABILITY_SAMPLES &&\n pressureOk) {\n this.scaleUp();\n }\n }\n \n /**\n * Decrease resolution (increase scale index).\n */\n private scaleDown(reason: \"slow\" | \"pressure\"): void {\n if (this.currentScaleIndex < SCALE_STEPS.length - 1) {\n this.currentScaleIndex++;\n this.lastScaleChangeTime = performance.now();\n this.samplesAtCurrentScale = 0;\n this.renderTimes = []; // Clear history at new scale\n \n const newScale = SCALE_STEPS[this.currentScaleIndex]!;\n console.log(`[AdaptiveResolutionTracker] Scaling DOWN to ${(newScale * 100).toFixed(0)}% (reason: ${reason})`);\n this.onScaleChange?.(newScale);\n }\n }\n \n /**\n * Increase resolution (decrease scale index).\n */\n private scaleUp(): void {\n if (this.currentScaleIndex > 0) {\n this.currentScaleIndex--;\n this.lastScaleChangeTime = performance.now();\n this.samplesAtCurrentScale = 0;\n this.renderTimes = []; // Clear history at new scale\n \n const newScale = SCALE_STEPS[this.currentScaleIndex]!;\n console.log(`[AdaptiveResolutionTracker] Scaling UP to ${(newScale * 100).toFixed(0)}% (reason: stable performance)`);\n this.onScaleChange?.(newScale);\n }\n }\n \n /**\n * Get the current recommended scale factor.\n */\n getRecommendedScale(): ScaleStep {\n return SCALE_STEPS[this.currentScaleIndex]!;\n }\n \n /**\n * Get current statistics for display.\n */\n getStats(): {\n currentScale: ScaleStep;\n avgRenderTime: number;\n fps: number;\n pressureState: PressureState;\n pressureHistory: PressureState[];\n samplesAtCurrentScale: number;\n canScaleUp: boolean;\n canScaleDown: boolean;\n headroom: number; // How much faster than target we're rendering (negative = behind)\n } {\n const avgRenderTime = this.renderTimes.length > 0\n ? this.renderTimes.reduce((a, b) => a + b, 0) / this.renderTimes.length\n : 0;\n \n // FPS based on frame intervals (how often we're called), not render time\n const avgFrameInterval = this.frameIntervals.length > 0\n ? this.frameIntervals.reduce((a, b) => a + b, 0) / this.frameIntervals.length\n : 16.67;\n const fps = avgFrameInterval > 0 ? 1000 / avgFrameInterval : 0;\n \n const now = performance.now();\n const timeSinceLastChange = now - this.lastScaleChangeTime;\n const canChange = timeSinceLastChange >= MIN_SCALE_CHANGE_INTERVAL_MS;\n \n const pressureOk = this.pressureState === \"nominal\" || this.pressureState === \"fair\";\n const canScaleUp = canChange && \n this.currentScaleIndex > 0 && \n avgRenderTime < SCALE_UP_THRESHOLD_MS &&\n this.samplesAtCurrentScale >= SCALE_UP_STABILITY_SAMPLES &&\n pressureOk;\n \n const canScaleDown = canChange && \n this.currentScaleIndex < SCALE_STEPS.length - 1;\n \n // Headroom: positive = we're faster than needed, negative = we're behind\n const headroom = TARGET_FRAME_TIME_MS - avgRenderTime;\n \n return {\n currentScale: this.getRecommendedScale(),\n avgRenderTime,\n fps,\n pressureState: this.pressureState,\n pressureHistory: [...this.pressureHistory],\n samplesAtCurrentScale: this.samplesAtCurrentScale,\n canScaleUp,\n canScaleDown,\n headroom,\n };\n }\n \n /**\n * Reset the tracker state.\n */\n reset(): void {\n this.lastFrameTime = 0;\n this.frameIntervals = [];\n this.renderTimes = [];\n this.currentScaleIndex = 0;\n this.lastScaleChangeTime = 0;\n this.samplesAtCurrentScale = 0;\n }\n \n /**\n * Initialize the tracker to start at a specific scale.\n */\n initializeAtScale(targetScale: number): void {\n let bestIndex = 0;\n for (let i = 0; i < SCALE_STEPS.length; i++) {\n if (SCALE_STEPS[i]! <= targetScale) {\n bestIndex = i;\n break;\n }\n }\n \n this.currentScaleIndex = bestIndex;\n this.lastFrameTime = 0;\n this.frameIntervals = [];\n this.renderTimes = [];\n this.lastScaleChangeTime = 0;\n this.samplesAtCurrentScale = 0;\n \n console.log(`[AdaptiveResolutionTracker] Initialized at scale ${(SCALE_STEPS[bestIndex]! * 100).toFixed(0)}%`);\n }\n \n /**\n * Clean up resources.\n */\n dispose(): void {\n if (this.pressureObserver) {\n try {\n this.pressureObserver.disconnect();\n } catch {\n // Ignore cleanup errors\n }\n this.pressureObserver = null;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAM,cAAc;CAClB;CAAK;CAAM;CAAM;CAAM;CACvB;CAAM;CAAM;CAAM;CAAM;CACxB;CAAM;CAAM;CAAM;CAAM;CACxB;CAAM;CAAM;CAAM;CACnB;;;;;;;;AAmCD,MAAM,uBAAuB;AAC7B,MAAM,0BAA0B;AAChC,MAAM,wBAAwB;AAC9B,MAAM,sBAAsB;AAC5B,MAAM,+BAA+B;AACrC,MAAM,6BAA6B;;AAGnC,MAAM,wBAAwB;;;;AAK9B,IAAa,4BAAb,MAAuC;CAkBrC,YAAY,SAA0D;qBAjBtC,EAAE;2BACN;6BACE;+BACE;0BAGoB;uBACb;yBACI,EAAE;uBAGrB;wBACW,EAAE;AAMnC,OAAK,gBAAgB,SAAS;AAC9B,OAAK,sBAAsB;;;;;CAM7B,AAAQ,uBAA6B;AACnC,MAAI,EAAE,sBAAsB,YAC1B;AAGF,MAAI;AACF,QAAK,mBAAmB,IAAI,kBAAkB,YAAY;AACxD,QAAI,QAAQ,SAAS,GAAG;KACtB,MAAM,SAAS,QAAQ,QAAQ,SAAS;AACxC,UAAK,gBAAgB,OAAO;AAE5B,UAAK,gBAAgB,KAAK,OAAO,MAAM;AACvC,SAAI,KAAK,gBAAgB,SAAS,sBAChC,MAAK,gBAAgB,OAAO;;KAGhC;AAEF,QAAK,iBAAiB,QAAQ,OAAO,EAAE,gBAAgB,KAAK,CAAC;WACtD,GAAG;AACV,WAAQ,KAAK,sEAAsE,EAAE;AACrF,QAAK,mBAAmB;;;;;;;;;;CAW5B,YAAY,cAAsB,WAA0B;AAE1D,OAAK,YAAY,KAAK,aAAa;AACnC,MAAI,KAAK,YAAY,SAAS,oBAC5B,MAAK,YAAY,OAAO;AAE1B,OAAK;AAGL,MAAI,cAAc,UAAa,KAAK,gBAAgB,GAAG;GACrD,MAAM,WAAW,YAAY,KAAK;AAClC,QAAK,eAAe,KAAK,SAAS;AAClC,OAAI,KAAK,eAAe,SAAS,oBAC/B,MAAK,eAAe,OAAO;;AAG/B,MAAI,cAAc,OAChB,MAAK,gBAAgB;AAIvB,OAAK,yBAAyB;;;;;CAMhC,AAAQ,0BAAgC;AACtC,MAAI,KAAK,YAAY,SAAS,GAAI;AAGlC,MADY,YAAY,KAAK,GACnB,KAAK,sBAAsB,6BACnC;EAGF,MAAM,gBAAgB,KAAK,YAAY,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,YAAY;AAGrF,MAAI,gBAAgB,yBAAyB;AAC3C,QAAK,UAAU,OAAO;AACtB;;AAIF,MAAI,KAAK,kBAAkB,cAAc,KAAK,kBAAkB,WAAW;AACzE,QAAK,UAAU,WAAW;AAC1B;;EAKF,MAAM,aAAa,KAAK,kBAAkB,aAAa,KAAK,kBAAkB;AAC9E,MAAI,gBAAgB,yBAChB,KAAK,yBAAyB,8BAC9B,WACF,MAAK,SAAS;;;;;CAOlB,AAAQ,UAAU,QAAmC;AACnD,MAAI,KAAK,oBAAoB,YAAY,SAAS,GAAG;AACnD,QAAK;AACL,QAAK,sBAAsB,YAAY,KAAK;AAC5C,QAAK,wBAAwB;AAC7B,QAAK,cAAc,EAAE;GAErB,MAAM,WAAW,YAAY,KAAK;AAClC,WAAQ,IAAI,gDAAgD,WAAW,KAAK,QAAQ,EAAE,CAAC,aAAa,OAAO,GAAG;AAC9G,QAAK,gBAAgB,SAAS;;;;;;CAOlC,AAAQ,UAAgB;AACtB,MAAI,KAAK,oBAAoB,GAAG;AAC9B,QAAK;AACL,QAAK,sBAAsB,YAAY,KAAK;AAC5C,QAAK,wBAAwB;AAC7B,QAAK,cAAc,EAAE;GAErB,MAAM,WAAW,YAAY,KAAK;AAClC,WAAQ,IAAI,8CAA8C,WAAW,KAAK,QAAQ,EAAE,CAAC,gCAAgC;AACrH,QAAK,gBAAgB,SAAS;;;;;;CAOlC,sBAAiC;AAC/B,SAAO,YAAY,KAAK;;;;;CAM1B,WAUE;EACA,MAAM,gBAAgB,KAAK,YAAY,SAAS,IAC5C,KAAK,YAAY,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,YAAY,SAC/D;EAGJ,MAAM,mBAAmB,KAAK,eAAe,SAAS,IAClD,KAAK,eAAe,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,eAAe,SACrE;EACJ,MAAM,MAAM,mBAAmB,IAAI,MAAO,mBAAmB;EAI7D,MAAM,YAFM,YAAY,KAAK,GACK,KAAK,uBACE;EAEzC,MAAM,aAAa,KAAK,kBAAkB,aAAa,KAAK,kBAAkB;EAC9E,MAAM,aAAa,aACjB,KAAK,oBAAoB,KACzB,gBAAgB,yBAChB,KAAK,yBAAyB,8BAC9B;EAEF,MAAM,eAAe,aACnB,KAAK,oBAAoB,YAAY,SAAS;EAGhD,MAAM,WAAW,uBAAuB;AAExC,SAAO;GACL,cAAc,KAAK,qBAAqB;GACxC;GACA;GACA,eAAe,KAAK;GACpB,iBAAiB,CAAC,GAAG,KAAK,gBAAgB;GAC1C,uBAAuB,KAAK;GAC5B;GACA;GACA;GACD;;;;;CAMH,QAAc;AACZ,OAAK,gBAAgB;AACrB,OAAK,iBAAiB,EAAE;AACxB,OAAK,cAAc,EAAE;AACrB,OAAK,oBAAoB;AACzB,OAAK,sBAAsB;AAC3B,OAAK,wBAAwB;;;;;CAM/B,kBAAkB,aAA2B;EAC3C,IAAI,YAAY;AAChB,OAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,IACtC,KAAI,YAAY,MAAO,aAAa;AAClC,eAAY;AACZ;;AAIJ,OAAK,oBAAoB;AACzB,OAAK,gBAAgB;AACrB,OAAK,iBAAiB,EAAE;AACxB,OAAK,cAAc,EAAE;AACrB,OAAK,sBAAsB;AAC3B,OAAK,wBAAwB;AAE7B,UAAQ,IAAI,qDAAqD,YAAY,aAAc,KAAK,QAAQ,EAAE,CAAC,GAAG;;;;;CAMhH,UAAgB;AACd,MAAI,KAAK,kBAAkB;AACzB,OAAI;AACF,SAAK,iBAAiB,YAAY;WAC5B;AAGR,QAAK,mBAAmB"}
1
+ {"version":3,"file":"AdaptiveResolutionTracker.js","names":[],"sources":["../../src/preview/AdaptiveResolutionTracker.ts"],"sourcesContent":["/**\n * Adaptive Resolution Tracker\n * \n * Monitors actual render time to dynamically adjust preview resolution\n * for smooth playback without dropped frames.\n * \n * Key insight: We measure how long each render() takes, not rAF timing.\n * If renders consistently take longer than our frame budget, scale down.\n * If renders consistently have headroom, scale up.\n */\n\nimport { logger } from \"./logger.js\";\n\n/**\n * Available resolution scale steps for adaptive scaling.\n * Finer-grained steps (5% increments) for smoother adaptation.\n * Ordered from highest to lowest quality.\n */\nconst SCALE_STEPS = [\n 1.0, 0.95, 0.90, 0.85, 0.80, \n 0.75, 0.70, 0.65, 0.60, 0.55,\n 0.50, 0.45, 0.40, 0.35, 0.30,\n 0.25, 0.20, 0.15, 0.10\n] as const;\ntype ScaleStep = typeof SCALE_STEPS[number];\n\n/**\n * Compute Pressure API types (not yet in TypeScript lib)\n */\ntype PressureState = \"nominal\" | \"fair\" | \"serious\" | \"critical\";\n\ninterface PressureRecord {\n state: PressureState;\n time: number;\n}\n\ninterface PressureObserverCallback {\n (records: PressureRecord[]): void;\n}\n\ninterface PressureObserverOptions {\n sampleInterval?: number;\n}\n\ndeclare class PressureObserver {\n constructor(callback: PressureObserverCallback);\n observe(source: \"cpu\", options?: PressureObserverOptions): Promise<void>;\n unobserve(source: \"cpu\"): void;\n disconnect(): void;\n}\n\n/**\n * Timing thresholds\n * \n * Target: 30fps = 33.33ms per frame\n * Tolerate down to 15fps (half target) before scaling down.\n * Scale up when we have plenty of headroom.\n */\nconst TARGET_FRAME_TIME_MS = 33.33; // 30fps target\nconst SCALE_DOWN_THRESHOLD_MS = 66.67; // 15fps (half target) - only scale down if really struggling\nconst SCALE_UP_THRESHOLD_MS = 25; // If avg render time is well below target, consider scaling up\nconst ROLLING_WINDOW_SIZE = 30; // ~1 second of samples at 30fps\nconst MIN_SCALE_CHANGE_INTERVAL_MS = 2000; // Wait 2s between any scale changes\nconst SCALE_UP_STABILITY_SAMPLES = 60; // Need 60 samples (~2s) of good performance to scale up\n\n/** Size of the pressure history for histogram display */\nconst PRESSURE_HISTORY_SIZE = 60;\n\n/**\n * Tracks render time to recommend optimal preview resolution.\n */\nexport class AdaptiveResolutionTracker {\n private renderTimes: number[] = []; // Rolling window of render times (ms)\n private currentScaleIndex = 0; // Index into SCALE_STEPS (0 = highest quality)\n private lastScaleChangeTime = 0;\n private samplesAtCurrentScale = 0; // How many samples we've collected at current scale\n \n // Compute Pressure API\n private pressureObserver: PressureObserver | null = null;\n private pressureState: PressureState = \"nominal\";\n private pressureHistory: PressureState[] = [];\n \n // For display - track frame intervals separately from render times\n private lastFrameTime = 0;\n private frameIntervals: number[] = [];\n \n // Callbacks\n private onScaleChange?: (scale: ScaleStep) => void;\n \n constructor(options?: { onScaleChange?: (scale: ScaleStep) => void }) {\n this.onScaleChange = options?.onScaleChange;\n this.initPressureObserver();\n }\n \n /**\n * Initialize Compute Pressure API observer if available.\n */\n private initPressureObserver(): void {\n if (!(\"PressureObserver\" in globalThis)) {\n return;\n }\n \n try {\n this.pressureObserver = new PressureObserver((records) => {\n if (records.length > 0) {\n const latest = records[records.length - 1]!;\n this.pressureState = latest.state;\n \n this.pressureHistory.push(latest.state);\n if (this.pressureHistory.length > PRESSURE_HISTORY_SIZE) {\n this.pressureHistory.shift();\n }\n }\n });\n \n this.pressureObserver.observe(\"cpu\", { sampleInterval: 500 });\n } catch (e) {\n logger.warn(\"[AdaptiveResolutionTracker] Failed to initialize PressureObserver:\", e);\n this.pressureObserver = null;\n }\n }\n \n /**\n * Record a frame's render time.\n * Call this AFTER each render completes with how long the render took.\n * \n * @param renderTimeMs - How long the render() call took in milliseconds\n * @param timestamp - Optional rAF timestamp for frame interval tracking (display only)\n */\n recordFrame(renderTimeMs: number, timestamp?: number): void {\n // Track render times for adaptive decisions\n this.renderTimes.push(renderTimeMs);\n if (this.renderTimes.length > ROLLING_WINDOW_SIZE) {\n this.renderTimes.shift();\n }\n this.samplesAtCurrentScale++;\n \n // Track frame intervals for FPS display (separate from render time)\n if (timestamp !== undefined && this.lastFrameTime > 0) {\n const interval = timestamp - this.lastFrameTime;\n this.frameIntervals.push(interval);\n if (this.frameIntervals.length > ROLLING_WINDOW_SIZE) {\n this.frameIntervals.shift();\n }\n }\n if (timestamp !== undefined) {\n this.lastFrameTime = timestamp;\n }\n \n // Check if we should adjust scale\n this.checkForScaleAdjustment();\n }\n \n /**\n * Check if we should scale up or down based on render time trends.\n */\n private checkForScaleAdjustment(): void {\n if (this.renderTimes.length < 10) return; // Need some samples\n \n const now = performance.now();\n if (now - this.lastScaleChangeTime < MIN_SCALE_CHANGE_INTERVAL_MS) {\n return; // Rate limit changes\n }\n \n const avgRenderTime = this.renderTimes.reduce((a, b) => a + b, 0) / this.renderTimes.length;\n \n // Scale DOWN if we're consistently slow\n if (avgRenderTime > SCALE_DOWN_THRESHOLD_MS) {\n this.scaleDown(\"slow\");\n return;\n }\n \n // Scale DOWN if CPU pressure is high (proactive)\n if (this.pressureState === \"critical\" || this.pressureState === \"serious\") {\n this.scaleDown(\"pressure\");\n return;\n }\n \n // Scale UP if we have sustained headroom and CPU isn't under pressure\n // (we already returned above if pressure is serious/critical, but check again for clarity)\n const pressureOk = this.pressureState === \"nominal\" || this.pressureState === \"fair\";\n if (avgRenderTime < SCALE_UP_THRESHOLD_MS && \n this.samplesAtCurrentScale >= SCALE_UP_STABILITY_SAMPLES &&\n pressureOk) {\n this.scaleUp();\n }\n }\n \n /**\n * Decrease resolution (increase scale index).\n */\n private scaleDown(reason: \"slow\" | \"pressure\"): void {\n if (this.currentScaleIndex < SCALE_STEPS.length - 1) {\n this.currentScaleIndex++;\n this.lastScaleChangeTime = performance.now();\n this.samplesAtCurrentScale = 0;\n this.renderTimes = []; // Clear history at new scale\n \n const newScale = SCALE_STEPS[this.currentScaleIndex]!;\n logger.debug(`[AdaptiveResolutionTracker] Scaling DOWN to ${(newScale * 100).toFixed(0)}% (reason: ${reason})`);\n this.onScaleChange?.(newScale);\n }\n }\n \n /**\n * Increase resolution (decrease scale index).\n */\n private scaleUp(): void {\n if (this.currentScaleIndex > 0) {\n this.currentScaleIndex--;\n this.lastScaleChangeTime = performance.now();\n this.samplesAtCurrentScale = 0;\n this.renderTimes = []; // Clear history at new scale\n \n const newScale = SCALE_STEPS[this.currentScaleIndex]!;\n logger.debug(`[AdaptiveResolutionTracker] Scaling UP to ${(newScale * 100).toFixed(0)}% (reason: stable performance)`);\n this.onScaleChange?.(newScale);\n }\n }\n \n /**\n * Get the current recommended scale factor.\n */\n getRecommendedScale(): ScaleStep {\n return SCALE_STEPS[this.currentScaleIndex]!;\n }\n \n /**\n * Get current statistics for display.\n */\n getStats(): {\n currentScale: ScaleStep;\n avgRenderTime: number;\n fps: number;\n pressureState: PressureState;\n pressureHistory: PressureState[];\n samplesAtCurrentScale: number;\n canScaleUp: boolean;\n canScaleDown: boolean;\n headroom: number; // How much faster than target we're rendering (negative = behind)\n } {\n const avgRenderTime = this.renderTimes.length > 0\n ? this.renderTimes.reduce((a, b) => a + b, 0) / this.renderTimes.length\n : 0;\n \n // FPS based on frame intervals (how often we're called), not render time\n const avgFrameInterval = this.frameIntervals.length > 0\n ? this.frameIntervals.reduce((a, b) => a + b, 0) / this.frameIntervals.length\n : 16.67;\n const fps = avgFrameInterval > 0 ? 1000 / avgFrameInterval : 0;\n \n const now = performance.now();\n const timeSinceLastChange = now - this.lastScaleChangeTime;\n const canChange = timeSinceLastChange >= MIN_SCALE_CHANGE_INTERVAL_MS;\n \n const pressureOk = this.pressureState === \"nominal\" || this.pressureState === \"fair\";\n const canScaleUp = canChange && \n this.currentScaleIndex > 0 && \n avgRenderTime < SCALE_UP_THRESHOLD_MS &&\n this.samplesAtCurrentScale >= SCALE_UP_STABILITY_SAMPLES &&\n pressureOk;\n \n const canScaleDown = canChange && \n this.currentScaleIndex < SCALE_STEPS.length - 1;\n \n // Headroom: positive = we're faster than needed, negative = we're behind\n const headroom = TARGET_FRAME_TIME_MS - avgRenderTime;\n \n return {\n currentScale: this.getRecommendedScale(),\n avgRenderTime,\n fps,\n pressureState: this.pressureState,\n pressureHistory: [...this.pressureHistory],\n samplesAtCurrentScale: this.samplesAtCurrentScale,\n canScaleUp,\n canScaleDown,\n headroom,\n };\n }\n \n /**\n * Reset the tracker state.\n */\n reset(): void {\n this.lastFrameTime = 0;\n this.frameIntervals = [];\n this.renderTimes = [];\n this.currentScaleIndex = 0;\n this.lastScaleChangeTime = 0;\n this.samplesAtCurrentScale = 0;\n }\n \n /**\n * Initialize the tracker to start at a specific scale.\n */\n initializeAtScale(targetScale: number): void {\n let bestIndex = 0;\n for (let i = 0; i < SCALE_STEPS.length; i++) {\n if (SCALE_STEPS[i]! <= targetScale) {\n bestIndex = i;\n break;\n }\n }\n \n this.currentScaleIndex = bestIndex;\n this.lastFrameTime = 0;\n this.frameIntervals = [];\n this.renderTimes = [];\n this.lastScaleChangeTime = 0;\n this.samplesAtCurrentScale = 0;\n \n logger.debug(`[AdaptiveResolutionTracker] Initialized at scale ${(SCALE_STEPS[bestIndex]! * 100).toFixed(0)}%`);\n }\n \n /**\n * Clean up resources.\n */\n dispose(): void {\n if (this.pressureObserver) {\n try {\n this.pressureObserver.disconnect();\n } catch {\n // Ignore cleanup errors\n }\n this.pressureObserver = null;\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import { LitElement } from "lit";
2
+
3
+ //#region src/preview/FrameController.d.ts
4
+
5
+ /**
6
+ * State returned by elements describing their readiness for a given time.
7
+ */
8
+ interface FrameState {
9
+ /**
10
+ * Whether async preparation is needed before rendering.
11
+ * Examples: video needs to seek, captions need to load data.
12
+ */
13
+ needsPreparation: boolean;
14
+ /**
15
+ * Whether the element is ready to render synchronously.
16
+ * True when all async work is complete and renderFrame() can be called.
17
+ */
18
+ isReady: boolean;
19
+ /**
20
+ * Rendering priority hint. Lower numbers render first.
21
+ * Used to order render calls for elements with dependencies.
22
+ *
23
+ * Standard priorities:
24
+ * - PRIORITY_VIDEO (1): Video elements
25
+ * - PRIORITY_CAPTIONS (2): Caption overlays
26
+ * - PRIORITY_AUDIO (3): Audio elements
27
+ * - PRIORITY_WAVEFORM (4): Audio visualizers (depend on audio)
28
+ * - PRIORITY_IMAGE (5): Static images
29
+ * - PRIORITY_DEFAULT (100): Fallback for custom elements
30
+ */
31
+ priority: number;
32
+ }
33
+ /**
34
+ * Interface that elements implement to participate in centralized frame rendering.
35
+ * Elements keep their rendering logic local but expose a standardized interface.
36
+ */
37
+ interface FrameRenderable {
38
+ /**
39
+ * Query the element's readiness state for a given time.
40
+ * Must be synchronous and cheap to call.
41
+ */
42
+ getFrameState(timeMs: number): FrameState;
43
+ /**
44
+ * Async preparation phase. Called when getFrameState().needsPreparation is true.
45
+ * Performs any async work needed before rendering (seeking, loading, etc.).
46
+ *
47
+ * @param timeMs - The time to prepare for
48
+ * @param signal - Abort signal for cancellation
49
+ */
50
+ prepareFrame(timeMs: number, signal: AbortSignal): Promise<void>;
51
+ /**
52
+ * Synchronous render phase. Called after all preparation is complete.
53
+ * Performs the actual rendering (paint to canvas, update DOM, etc.).
54
+ *
55
+ * @param timeMs - The time to render
56
+ */
57
+ renderFrame(timeMs: number): void;
58
+ }
59
+ /**
60
+ * Options for FrameController.renderFrame()
61
+ */
62
+ interface RenderFrameOptions {
63
+ /**
64
+ * Whether to wait for Lit updateComplete before querying elements.
65
+ * Default: true
66
+ */
67
+ waitForLitUpdate?: boolean;
68
+ /**
69
+ * Callback to update CSS animations after frame rendering completes.
70
+ * Called with the root element after all elements have rendered.
71
+ * This centralizes animation synchronization in one place.
72
+ */
73
+ onAnimationsUpdate?: (rootElement: Element) => void;
74
+ }
75
+ /**
76
+ * Central controller for frame rendering.
77
+ * Lives at the root timegroup and orchestrates all element rendering.
78
+ */
79
+ declare class FrameController {
80
+ #private;
81
+ constructor(rootElement: LitElement & {
82
+ currentTimeMs: number;
83
+ });
84
+ /**
85
+ * Cancel any in-progress render operation.
86
+ */
87
+ abort(): void;
88
+ /**
89
+ * Render a frame at the specified time.
90
+ *
91
+ * This is the main entry point for frame rendering. It:
92
+ * 1. Cancels any previous in-progress render
93
+ * 2. Queries all visible FrameRenderable elements
94
+ * 3. Runs preparation in parallel for elements that need it
95
+ * 4. Runs render in priority order
96
+ *
97
+ * @param timeMs - The time in milliseconds to render
98
+ * @param options - Optional configuration
99
+ */
100
+ renderFrame(timeMs: number, options?: RenderFrameOptions): Promise<void>;
101
+ /**
102
+ * Check if a render is currently in progress.
103
+ */
104
+ get isRendering(): boolean;
105
+ }
106
+ /**
107
+ * Interface for the legacy frameTask object.
108
+ * Used for backwards compatibility with code expecting the old Task-like API.
109
+ */
110
+ interface FrameTask {
111
+ /**
112
+ * Run the frame task (prepare + render).
113
+ * @returns Promise that resolves when the task completes
114
+ */
115
+ run(): Promise<void>;
116
+ /**
117
+ * Promise that resolves when the current task completes.
118
+ */
119
+ taskComplete: Promise<void>;
120
+ }
121
+ //#endregion
122
+ export { FrameController, FrameRenderable, FrameState, FrameTask, RenderFrameOptions };
123
+ //# sourceMappingURL=FrameController.d.ts.map