@editframe/elements 0.45.2 → 0.45.4

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 (165) hide show
  1. package/dist/DelayedLoadingState.js.map +1 -1
  2. package/dist/EF_FRAMEGEN.js.map +1 -1
  3. package/dist/EF_RENDERING.js.map +1 -1
  4. package/dist/canvas/EFCanvas.js +3 -3
  5. package/dist/canvas/EFCanvas.js.map +1 -1
  6. package/dist/canvas/EFCanvasItem.js.map +1 -1
  7. package/dist/canvas/api/CanvasAPI.js.map +1 -1
  8. package/dist/canvas/getElementBounds.js.map +1 -1
  9. package/dist/canvas/overlays/SelectionOverlay.js.map +1 -1
  10. package/dist/canvas/overlays/overlayState.js.map +1 -1
  11. package/dist/canvas/selection/SelectionController.js +25 -23
  12. package/dist/canvas/selection/SelectionController.js.map +1 -1
  13. package/dist/canvas/selection/SelectionModel.js.map +1 -1
  14. package/dist/canvas/selection/selectionContext.js.map +1 -1
  15. package/dist/elements/ContainerInfo.js.map +1 -1
  16. package/dist/elements/CrossUpdateController.js.map +1 -1
  17. package/dist/elements/EFAudio.js.map +1 -1
  18. package/dist/elements/EFCaptions.js.map +1 -1
  19. package/dist/elements/EFImage.js +1 -1
  20. package/dist/elements/EFImage.js.map +1 -1
  21. package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
  22. package/dist/elements/EFMedia/CachedFetcher.js.map +1 -1
  23. package/dist/elements/EFMedia/MediaEngine.js.map +1 -1
  24. package/dist/elements/EFMedia/SegmentIndex.js.map +1 -1
  25. package/dist/elements/EFMedia/SegmentTransport.js.map +1 -1
  26. package/dist/elements/EFMedia/TimingModel.js.map +1 -1
  27. package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
  28. package/dist/elements/EFMedia/shared/GlobalInputCache.js.map +1 -1
  29. package/dist/elements/EFMedia/shared/PrecisionUtils.js.map +1 -1
  30. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
  31. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
  32. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
  33. package/dist/elements/EFMedia.js.map +1 -1
  34. package/dist/elements/EFPanZoom.js +9 -8
  35. package/dist/elements/EFPanZoom.js.map +1 -1
  36. package/dist/elements/EFSourceMixin.js +1 -1
  37. package/dist/elements/EFSourceMixin.js.map +1 -1
  38. package/dist/elements/EFSurface.js.map +1 -1
  39. package/dist/elements/EFTemporal.js.map +1 -1
  40. package/dist/elements/EFText.d.ts +4 -4
  41. package/dist/elements/EFText.js.map +1 -1
  42. package/dist/elements/EFTextSegment.d.ts +4 -4
  43. package/dist/elements/EFTimegroup.js +7 -8
  44. package/dist/elements/EFTimegroup.js.map +1 -1
  45. package/dist/elements/EFVideo.d.ts +4 -4
  46. package/dist/elements/EFVideo.js.map +1 -1
  47. package/dist/elements/EFWaveform.d.ts +4 -4
  48. package/dist/elements/EFWaveform.js.map +1 -1
  49. package/dist/elements/ElementPositionInfo.js.map +1 -1
  50. package/dist/elements/FetchMixin.js.map +1 -1
  51. package/dist/elements/SampleBuffer.js.map +1 -1
  52. package/dist/elements/TargetController.js.map +1 -1
  53. package/dist/elements/TimegroupController.js.map +1 -1
  54. package/dist/elements/cloneFactoryRegistry.js.map +1 -1
  55. package/dist/elements/durationConverter.js.map +1 -1
  56. package/dist/elements/easingUtils.js.map +1 -1
  57. package/dist/elements/renderTemporalAudio.js.map +1 -1
  58. package/dist/elements/setupTemporalHierarchy.js.map +1 -1
  59. package/dist/elements/updateAnimations.js +1 -1
  60. package/dist/elements/updateAnimations.js.map +1 -1
  61. package/dist/getRenderInfo.js.map +1 -1
  62. package/dist/gui/ContextMixin.js.map +1 -1
  63. package/dist/gui/Controllable.js.map +1 -1
  64. package/dist/gui/EFActiveRootTemporal.d.ts +4 -4
  65. package/dist/gui/EFActiveRootTemporal.js.map +1 -1
  66. package/dist/gui/EFConfiguration.d.ts +4 -4
  67. package/dist/gui/EFControls.js.map +1 -1
  68. package/dist/gui/EFDial.d.ts +4 -4
  69. package/dist/gui/EFFilmstrip.d.ts +4 -4
  70. package/dist/gui/EFFilmstrip.js.map +1 -1
  71. package/dist/gui/EFFitScale.js.map +1 -1
  72. package/dist/gui/EFOverlayItem.d.ts +4 -4
  73. package/dist/gui/EFOverlayItem.js.map +1 -1
  74. package/dist/gui/EFOverlayLayer.d.ts +4 -4
  75. package/dist/gui/EFOverlayLayer.js.map +1 -1
  76. package/dist/gui/EFPause.d.ts +4 -4
  77. package/dist/gui/EFPlay.d.ts +4 -4
  78. package/dist/gui/EFPreview.d.ts +4 -4
  79. package/dist/gui/EFPreview.js.map +1 -1
  80. package/dist/gui/EFResizableBox.js.map +1 -1
  81. package/dist/gui/EFScrubber.d.ts +4 -4
  82. package/dist/gui/EFScrubber.js.map +1 -1
  83. package/dist/gui/EFTimeDisplay.d.ts +4 -4
  84. package/dist/gui/EFTimeDisplay.js.map +1 -1
  85. package/dist/gui/EFTimelineRuler.d.ts +4 -4
  86. package/dist/gui/EFTimelineRuler.js.map +1 -1
  87. package/dist/gui/EFToggleLoop.d.ts +4 -4
  88. package/dist/gui/EFTogglePlay.d.ts +4 -4
  89. package/dist/gui/EFTogglePlay.js.map +1 -1
  90. package/dist/gui/EFTransformHandles.js.map +1 -1
  91. package/dist/gui/EFWorkbench.d.ts +4 -4
  92. package/dist/gui/EFWorkbench.js.map +1 -1
  93. package/dist/gui/FitScaleHelpers.js.map +1 -1
  94. package/dist/gui/PlaybackController.js.map +1 -1
  95. package/dist/gui/TWMixin2.js.map +1 -1
  96. package/dist/gui/TargetOrContextMixin.js.map +1 -1
  97. package/dist/gui/currentTimeContext.js.map +1 -1
  98. package/dist/gui/efContext.js.map +1 -1
  99. package/dist/gui/fetchContext.js.map +1 -1
  100. package/dist/gui/hierarchy/EFHierarchy.d.ts +4 -4
  101. package/dist/gui/hierarchy/EFHierarchy.js.map +1 -1
  102. package/dist/gui/hierarchy/EFHierarchyItem.d.ts +2 -2
  103. package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -1
  104. package/dist/gui/hierarchy/hierarchyContext.js.map +1 -1
  105. package/dist/gui/panZoomTransformContext.js.map +1 -1
  106. package/dist/gui/previewSettingsContext.js.map +1 -1
  107. package/dist/gui/theme.js.map +1 -1
  108. package/dist/gui/timeline/EFTimeline.d.ts +2 -2
  109. package/dist/gui/timeline/EFTimeline.js +0 -1
  110. package/dist/gui/timeline/EFTimeline.js.map +1 -1
  111. package/dist/gui/timeline/EFTimelineRow.js.map +1 -1
  112. package/dist/gui/timeline/TrimHandles.d.ts +4 -4
  113. package/dist/gui/timeline/TrimHandles.js.map +1 -1
  114. package/dist/gui/timeline/flattenHierarchy.js.map +1 -1
  115. package/dist/gui/timeline/timelineStateContext.js.map +1 -1
  116. package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -1
  117. package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -1
  118. package/dist/gui/timeline/tracks/EFThumbnailStrip.js.map +1 -1
  119. package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -1
  120. package/dist/gui/timeline/tracks/TextTrack.js.map +1 -1
  121. package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
  122. package/dist/gui/timeline/tracks/TrackItem.js.map +1 -1
  123. package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -1
  124. package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -1
  125. package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -1
  126. package/dist/gui/transformCalculations.js.map +1 -1
  127. package/dist/gui/transformUtils.js.map +1 -1
  128. package/dist/gui/tree/EFTree.d.ts +4 -4
  129. package/dist/gui/tree/EFTree.js.map +1 -1
  130. package/dist/gui/tree/EFTreeItem.d.ts +4 -4
  131. package/dist/gui/tree/EFTreeItem.js.map +1 -1
  132. package/dist/index.js.map +1 -1
  133. package/dist/otel/BridgeSpanExporter.js.map +1 -1
  134. package/dist/otel/setupBrowserTracing.js.map +1 -1
  135. package/dist/otel/tracingHelpers.js.map +1 -1
  136. package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
  137. package/dist/preview/FrameController.js.map +1 -1
  138. package/dist/preview/QualityUpgradeScheduler.js.map +1 -1
  139. package/dist/preview/RenderContext.js.map +1 -1
  140. package/dist/preview/RenderProfiler.js.map +1 -1
  141. package/dist/preview/RenderStats.js.map +1 -1
  142. package/dist/preview/encoding/canvasEncoder.js.map +1 -1
  143. package/dist/preview/encoding/mainThreadEncoder.js +1 -1
  144. package/dist/preview/encoding/mainThreadEncoder.js.map +1 -1
  145. package/dist/preview/previewSettings.js.map +1 -1
  146. package/dist/preview/previewTypes.js.map +1 -1
  147. package/dist/preview/renderElementToCanvas.js.map +1 -1
  148. package/dist/preview/renderTimegroupToCanvas.js +2 -44
  149. package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
  150. package/dist/preview/renderTimegroupToVideo.js +2 -2
  151. package/dist/preview/renderTimegroupToVideo.js.map +1 -1
  152. package/dist/preview/renderVideoToVideo.js +2 -2
  153. package/dist/preview/renderVideoToVideo.js.map +1 -1
  154. package/dist/preview/renderers.js.map +1 -1
  155. package/dist/preview/rendering/ScaleConfig.js.map +1 -1
  156. package/dist/preview/rendering/loadImage.js.map +1 -1
  157. package/dist/preview/rendering/renderToImageNative.js.map +1 -1
  158. package/dist/preview/rendering/serializeTimelineDirect.js +1 -1
  159. package/dist/preview/rendering/serializeTimelineDirect.js.map +1 -1
  160. package/dist/preview/statsTrackingStrategy.js.map +1 -1
  161. package/dist/preview/workers/WorkerPool.js.map +1 -1
  162. package/dist/render/EFRenderAPI.js.map +1 -1
  163. package/dist/transcoding/cache/RequestDeduplicator.js.map +1 -1
  164. package/dist/utils/LRUCache.js.map +1 -1
  165. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DelayedLoadingState.js","names":[],"sources":["../src/DelayedLoadingState.ts"],"sourcesContent":["interface LoadingOperation {\n id: string;\n message: string;\n startTime: number;\n timeout?: NodeJS.Timeout;\n isBackground: boolean;\n}\n\ninterface LoadingOptions {\n background?: boolean;\n}\n\nexport class DelayedLoadingState {\n private operations = new Map<string, LoadingOperation>();\n private loadingDelayMs: number;\n private isCurrentlyLoading = false;\n private currentMessage = \"\";\n private onStateChange?: (isLoading: boolean, message: string) => void;\n\n constructor(\n delayMs = 250,\n onStateChange?: (isLoading: boolean, message: string) => void,\n ) {\n this.loadingDelayMs = delayMs;\n this.onStateChange = onStateChange;\n }\n\n /**\n * Start a delayed loading operation\n */\n startLoading(\n operationId: string,\n message: string,\n options: LoadingOptions = {},\n ): void {\n const isBackground = options.background || false;\n\n // Clear existing timeout for this operation if it exists\n const existingOp = this.operations.get(operationId);\n if (existingOp?.timeout) {\n clearTimeout(existingOp.timeout);\n }\n\n // Don't create timeout for background operations\n if (isBackground) {\n this.operations.set(operationId, {\n id: operationId,\n message,\n startTime: Date.now(),\n isBackground: true,\n });\n return;\n }\n\n // Create timeout to show loading after delay\n const timeout = setTimeout(() => {\n // Only trigger if operation still exists and is not background\n const operation = this.operations.get(operationId);\n if (operation && !operation.isBackground) {\n this.triggerLoadingState();\n }\n }, this.loadingDelayMs);\n\n this.operations.set(operationId, {\n id: operationId,\n message,\n startTime: Date.now(),\n timeout,\n isBackground: false,\n });\n }\n\n /**\n * Clear a loading operation\n */\n clearLoading(operationId: string): void {\n const operation = this.operations.get(operationId);\n if (!operation) return;\n\n // Clear timeout if it exists\n if (operation.timeout) {\n clearTimeout(operation.timeout);\n }\n\n this.operations.delete(operationId);\n\n // Update loading state\n this.updateLoadingState();\n }\n\n /**\n * Clear all loading operations\n */\n clearAllLoading(): void {\n for (const operation of this.operations.values()) {\n if (operation.timeout) {\n clearTimeout(operation.timeout);\n }\n }\n this.operations.clear();\n this.updateLoadingState();\n }\n\n /**\n * Get current loading state\n */\n get isLoading(): boolean {\n return this.isCurrentlyLoading;\n }\n\n /**\n * Get current loading message\n */\n get message(): string {\n return this.currentMessage;\n }\n\n /**\n * Check if any non-background operations are active\n */\n private hasActiveOperations(): boolean {\n for (const operation of this.operations.values()) {\n if (!operation.isBackground) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the message for the most recent non-background operation\n */\n private getCurrentMessage(): string {\n let latestTime = 0;\n let latestMessage = \"\";\n\n for (const operation of this.operations.values()) {\n if (!operation.isBackground && operation.startTime > latestTime) {\n latestTime = operation.startTime;\n latestMessage = operation.message;\n }\n }\n\n return latestMessage;\n }\n\n /**\n * Trigger loading state (called by timeout)\n */\n private triggerLoadingState(): void {\n if (this.hasActiveOperations() && !this.isCurrentlyLoading) {\n this.isCurrentlyLoading = true;\n this.currentMessage = this.getCurrentMessage();\n this.onStateChange?.(true, this.currentMessage);\n }\n }\n\n /**\n * Update loading state based on current operations\n */\n private updateLoadingState(): void {\n const shouldBeLoading = this.hasActiveOperations();\n\n if (shouldBeLoading !== this.isCurrentlyLoading) {\n this.isCurrentlyLoading = shouldBeLoading;\n\n if (shouldBeLoading) {\n this.currentMessage = this.getCurrentMessage();\n this.onStateChange?.(true, this.currentMessage);\n } else {\n this.currentMessage = \"\";\n this.onStateChange?.(false, \"\");\n }\n }\n }\n}\n"],"mappings":";AAYA,IAAa,sBAAb,MAAiC;CAO/B,YACE,UAAU,KACV,eACA;oCATmB,IAAI,KAA+B;4BAE3B;wBACJ;AAOvB,OAAK,iBAAiB;AACtB,OAAK,gBAAgB;;;;;CAMvB,aACE,aACA,SACA,UAA0B,EAAE,EACtB;EACN,MAAM,eAAe,QAAQ,cAAc;EAG3C,MAAM,aAAa,KAAK,WAAW,IAAI,YAAY;AACnD,MAAI,YAAY,QACd,cAAa,WAAW,QAAQ;AAIlC,MAAI,cAAc;AAChB,QAAK,WAAW,IAAI,aAAa;IAC/B,IAAI;IACJ;IACA,WAAW,KAAK,KAAK;IACrB,cAAc;IACf,CAAC;AACF;;EAIF,MAAM,UAAU,iBAAiB;GAE/B,MAAM,YAAY,KAAK,WAAW,IAAI,YAAY;AAClD,OAAI,aAAa,CAAC,UAAU,aAC1B,MAAK,qBAAqB;KAE3B,KAAK,eAAe;AAEvB,OAAK,WAAW,IAAI,aAAa;GAC/B,IAAI;GACJ;GACA,WAAW,KAAK,KAAK;GACrB;GACA,cAAc;GACf,CAAC;;;;;CAMJ,aAAa,aAA2B;EACtC,MAAM,YAAY,KAAK,WAAW,IAAI,YAAY;AAClD,MAAI,CAAC,UAAW;AAGhB,MAAI,UAAU,QACZ,cAAa,UAAU,QAAQ;AAGjC,OAAK,WAAW,OAAO,YAAY;AAGnC,OAAK,oBAAoB;;;;;CAM3B,kBAAwB;AACtB,OAAK,MAAM,aAAa,KAAK,WAAW,QAAQ,CAC9C,KAAI,UAAU,QACZ,cAAa,UAAU,QAAQ;AAGnC,OAAK,WAAW,OAAO;AACvB,OAAK,oBAAoB;;;;;CAM3B,IAAI,YAAqB;AACvB,SAAO,KAAK;;;;;CAMd,IAAI,UAAkB;AACpB,SAAO,KAAK;;;;;CAMd,AAAQ,sBAA+B;AACrC,OAAK,MAAM,aAAa,KAAK,WAAW,QAAQ,CAC9C,KAAI,CAAC,UAAU,aACb,QAAO;AAGX,SAAO;;;;;CAMT,AAAQ,oBAA4B;EAClC,IAAI,aAAa;EACjB,IAAI,gBAAgB;AAEpB,OAAK,MAAM,aAAa,KAAK,WAAW,QAAQ,CAC9C,KAAI,CAAC,UAAU,gBAAgB,UAAU,YAAY,YAAY;AAC/D,gBAAa,UAAU;AACvB,mBAAgB,UAAU;;AAI9B,SAAO;;;;;CAMT,AAAQ,sBAA4B;AAClC,MAAI,KAAK,qBAAqB,IAAI,CAAC,KAAK,oBAAoB;AAC1D,QAAK,qBAAqB;AAC1B,QAAK,iBAAiB,KAAK,mBAAmB;AAC9C,QAAK,gBAAgB,MAAM,KAAK,eAAe;;;;;;CAOnD,AAAQ,qBAA2B;EACjC,MAAM,kBAAkB,KAAK,qBAAqB;AAElD,MAAI,oBAAoB,KAAK,oBAAoB;AAC/C,QAAK,qBAAqB;AAE1B,OAAI,iBAAiB;AACnB,SAAK,iBAAiB,KAAK,mBAAmB;AAC9C,SAAK,gBAAgB,MAAM,KAAK,eAAe;UAC1C;AACL,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,OAAO,GAAG"}
1
+ {"version":3,"file":"DelayedLoadingState.js","names":[],"sources":["../src/DelayedLoadingState.ts"],"sourcesContent":["interface LoadingOperation {\n id: string;\n message: string;\n startTime: number;\n timeout?: NodeJS.Timeout;\n isBackground: boolean;\n}\n\ninterface LoadingOptions {\n background?: boolean;\n}\n\nexport class DelayedLoadingState {\n private operations = new Map<string, LoadingOperation>();\n private loadingDelayMs: number;\n private isCurrentlyLoading = false;\n private currentMessage = \"\";\n private onStateChange?: (isLoading: boolean, message: string) => void;\n\n constructor(delayMs = 250, onStateChange?: (isLoading: boolean, message: string) => void) {\n this.loadingDelayMs = delayMs;\n this.onStateChange = onStateChange;\n }\n\n /**\n * Start a delayed loading operation\n */\n startLoading(operationId: string, message: string, options: LoadingOptions = {}): void {\n const isBackground = options.background || false;\n\n // Clear existing timeout for this operation if it exists\n const existingOp = this.operations.get(operationId);\n if (existingOp?.timeout) {\n clearTimeout(existingOp.timeout);\n }\n\n // Don't create timeout for background operations\n if (isBackground) {\n this.operations.set(operationId, {\n id: operationId,\n message,\n startTime: Date.now(),\n isBackground: true,\n });\n return;\n }\n\n // Create timeout to show loading after delay\n const timeout = setTimeout(() => {\n // Only trigger if operation still exists and is not background\n const operation = this.operations.get(operationId);\n if (operation && !operation.isBackground) {\n this.triggerLoadingState();\n }\n }, this.loadingDelayMs);\n\n this.operations.set(operationId, {\n id: operationId,\n message,\n startTime: Date.now(),\n timeout,\n isBackground: false,\n });\n }\n\n /**\n * Clear a loading operation\n */\n clearLoading(operationId: string): void {\n const operation = this.operations.get(operationId);\n if (!operation) return;\n\n // Clear timeout if it exists\n if (operation.timeout) {\n clearTimeout(operation.timeout);\n }\n\n this.operations.delete(operationId);\n\n // Update loading state\n this.updateLoadingState();\n }\n\n /**\n * Clear all loading operations\n */\n clearAllLoading(): void {\n for (const operation of this.operations.values()) {\n if (operation.timeout) {\n clearTimeout(operation.timeout);\n }\n }\n this.operations.clear();\n this.updateLoadingState();\n }\n\n /**\n * Get current loading state\n */\n get isLoading(): boolean {\n return this.isCurrentlyLoading;\n }\n\n /**\n * Get current loading message\n */\n get message(): string {\n return this.currentMessage;\n }\n\n /**\n * Check if any non-background operations are active\n */\n private hasActiveOperations(): boolean {\n for (const operation of this.operations.values()) {\n if (!operation.isBackground) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the message for the most recent non-background operation\n */\n private getCurrentMessage(): string {\n let latestTime = 0;\n let latestMessage = \"\";\n\n for (const operation of this.operations.values()) {\n if (!operation.isBackground && operation.startTime > latestTime) {\n latestTime = operation.startTime;\n latestMessage = operation.message;\n }\n }\n\n return latestMessage;\n }\n\n /**\n * Trigger loading state (called by timeout)\n */\n private triggerLoadingState(): void {\n if (this.hasActiveOperations() && !this.isCurrentlyLoading) {\n this.isCurrentlyLoading = true;\n this.currentMessage = this.getCurrentMessage();\n this.onStateChange?.(true, this.currentMessage);\n }\n }\n\n /**\n * Update loading state based on current operations\n */\n private updateLoadingState(): void {\n const shouldBeLoading = this.hasActiveOperations();\n\n if (shouldBeLoading !== this.isCurrentlyLoading) {\n this.isCurrentlyLoading = shouldBeLoading;\n\n if (shouldBeLoading) {\n this.currentMessage = this.getCurrentMessage();\n this.onStateChange?.(true, this.currentMessage);\n } else {\n this.currentMessage = \"\";\n this.onStateChange?.(false, \"\");\n }\n }\n }\n}\n"],"mappings":";AAYA,IAAa,sBAAb,MAAiC;CAO/B,YAAY,UAAU,KAAK,eAA+D;oCANrE,IAAI,KAA+B;4BAE3B;wBACJ;AAIvB,OAAK,iBAAiB;AACtB,OAAK,gBAAgB;;;;;CAMvB,aAAa,aAAqB,SAAiB,UAA0B,EAAE,EAAQ;EACrF,MAAM,eAAe,QAAQ,cAAc;EAG3C,MAAM,aAAa,KAAK,WAAW,IAAI,YAAY;AACnD,MAAI,YAAY,QACd,cAAa,WAAW,QAAQ;AAIlC,MAAI,cAAc;AAChB,QAAK,WAAW,IAAI,aAAa;IAC/B,IAAI;IACJ;IACA,WAAW,KAAK,KAAK;IACrB,cAAc;IACf,CAAC;AACF;;EAIF,MAAM,UAAU,iBAAiB;GAE/B,MAAM,YAAY,KAAK,WAAW,IAAI,YAAY;AAClD,OAAI,aAAa,CAAC,UAAU,aAC1B,MAAK,qBAAqB;KAE3B,KAAK,eAAe;AAEvB,OAAK,WAAW,IAAI,aAAa;GAC/B,IAAI;GACJ;GACA,WAAW,KAAK,KAAK;GACrB;GACA,cAAc;GACf,CAAC;;;;;CAMJ,aAAa,aAA2B;EACtC,MAAM,YAAY,KAAK,WAAW,IAAI,YAAY;AAClD,MAAI,CAAC,UAAW;AAGhB,MAAI,UAAU,QACZ,cAAa,UAAU,QAAQ;AAGjC,OAAK,WAAW,OAAO,YAAY;AAGnC,OAAK,oBAAoB;;;;;CAM3B,kBAAwB;AACtB,OAAK,MAAM,aAAa,KAAK,WAAW,QAAQ,CAC9C,KAAI,UAAU,QACZ,cAAa,UAAU,QAAQ;AAGnC,OAAK,WAAW,OAAO;AACvB,OAAK,oBAAoB;;;;;CAM3B,IAAI,YAAqB;AACvB,SAAO,KAAK;;;;;CAMd,IAAI,UAAkB;AACpB,SAAO,KAAK;;;;;CAMd,AAAQ,sBAA+B;AACrC,OAAK,MAAM,aAAa,KAAK,WAAW,QAAQ,CAC9C,KAAI,CAAC,UAAU,aACb,QAAO;AAGX,SAAO;;;;;CAMT,AAAQ,oBAA4B;EAClC,IAAI,aAAa;EACjB,IAAI,gBAAgB;AAEpB,OAAK,MAAM,aAAa,KAAK,WAAW,QAAQ,CAC9C,KAAI,CAAC,UAAU,gBAAgB,UAAU,YAAY,YAAY;AAC/D,gBAAa,UAAU;AACvB,mBAAgB,UAAU;;AAI9B,SAAO;;;;;CAMT,AAAQ,sBAA4B;AAClC,MAAI,KAAK,qBAAqB,IAAI,CAAC,KAAK,oBAAoB;AAC1D,QAAK,qBAAqB;AAC1B,QAAK,iBAAiB,KAAK,mBAAmB;AAC9C,QAAK,gBAAgB,MAAM,KAAK,eAAe;;;;;;CAOnD,AAAQ,qBAA2B;EACjC,MAAM,kBAAkB,KAAK,qBAAqB;AAElD,MAAI,oBAAoB,KAAK,oBAAoB;AAC/C,QAAK,qBAAqB;AAE1B,OAAI,iBAAiB;AACnB,SAAK,iBAAiB,KAAK,mBAAmB;AAC9C,SAAK,gBAAgB,MAAM,KAAK,eAAe;UAC1C;AACL,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,OAAO,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"EF_FRAMEGEN.js","names":[],"sources":["../src/EF_FRAMEGEN.ts"],"sourcesContent":["import type { VideoRenderOptions } from \"@editframe/assets\";\n\nimport {\n shallowGetTimegroups,\n type SeekForRenderTiming,\n} from \"./elements/EFTimegroup.js\";\nimport { setupTemporalHierarchy } from \"./elements/setupTemporalHierarchy.js\";\n\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 // Per-phase timing accumulators (reset every 30 frames)\n private timingFrameCount = 0;\n private timingAccum: SeekForRenderTiming = {\n updateComplete1Ms: 0,\n updateComplete2Ms: 0,\n updateComplete3Ms: 0,\n textSegmentsMs: 0,\n renderFrameMs: 0,\n renderFrameQueryMs: 0,\n renderFramePrepareMs: 0,\n renderFrameDrawMs: 0,\n renderFrameAnimsMs: 0,\n frameTasksMs: 0,\n totalMs: 0,\n };\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, or fall back to renderOptions dimensions.\n // Without ef-workbench (e.g. API renders), the canvas was never sized or appended,\n // causing frame verification to fail on every frame.\n const workbench = document.querySelector(\"ef-workbench\") as HTMLElement;\n const canvasWidth = workbench\n ? workbench.clientWidth\n : (this.renderOptions?.encoderOptions.video.width ?? 0);\n\n if (canvasWidth > 0) {\n this.verificationCanvas.width = canvasWidth;\n this.verificationCanvas.height = 1;\n\n Object.assign(this.verificationCanvas.style, {\n position: \"fixed\",\n left: \"0px\",\n bottom: \"0px\",\n width: `${canvasWidth}px`,\n height: \"1px\",\n zIndex: \"99999\",\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 // Workbench is optional - look for it but don't require it\n const workbench = document.querySelector(\"ef-workbench\");\n if (workbench) {\n this.setWorkbenchRendering(true);\n workbench.playing = false;\n }\n\n // Find timegroups either in workbench or directly in document\n const searchRoot = workbench || document.body;\n const timegroups = shallowGetTimegroups(searchRoot);\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\n // CRITICAL: Manually wire up temporal hierarchy since Lit Context fails with our connection order\n // When loading via loadURL(), elements connect depth-first (children before parents), causing\n // children to miss the context-request event since parents aren't listening yet.\n // See setupTemporalHierarchy.ts for detailed explanation.\n setupTemporalHierarchy(searchRoot, firstGroup);\n\n // Suppress autonomous re-renders (EFTemporal/EFTimegroup.updated) while\n // seekForRender is in progress — same protection applied to render clones.\n firstGroup.setAttribute(\"data-no-playback-controller\", \"\");\n\n // Use seekForRender for proper time seeking during rendering\n await firstGroup.seekForRender(startingTimeMs);\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 // Suppress unhandled rejection while the promise sits in storage before being awaited.\n this.audioBufferPromise.catch(() => {});\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 this.setWorkbenchRendering(true);\n }\n const searchRoot = workbench || document.body;\n const timegroups = shallowGetTimegroups(searchRoot);\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 const frameTimeMs = Number(Number(frameTime).toFixed(5));\n\n // Use seekForRender for proper time seeking during rendering\n const timing = await firstGroup.seekForRender(frameTimeMs);\n this.timingFrameCount++;\n for (const key of Object.keys(\n this.timingAccum,\n ) as (keyof SeekForRenderTiming)[]) {\n this.timingAccum[key] += timing[key];\n }\n if (this.timingFrameCount >= 30) {\n const n = this.timingFrameCount;\n console.log(\n `[EF_FRAMEGEN] seekForRender phase avg (${n} frames):`,\n `total=${(this.timingAccum.totalMs / n).toFixed(1)}ms`,\n `uc1=${(this.timingAccum.updateComplete1Ms / n).toFixed(1)}ms`,\n `uc2=${(this.timingAccum.updateComplete2Ms / n).toFixed(1)}ms`,\n `uc3=${(this.timingAccum.updateComplete3Ms / n).toFixed(1)}ms`,\n `text=${(this.timingAccum.textSegmentsMs / n).toFixed(1)}ms`,\n `renderFrame=${(this.timingAccum.renderFrameMs / n).toFixed(1)}ms`,\n `rf.query=${(this.timingAccum.renderFrameQueryMs / n).toFixed(1)}ms`,\n `rf.prepare=${(this.timingAccum.renderFramePrepareMs / n).toFixed(1)}ms`,\n `rf.draw=${(this.timingAccum.renderFrameDrawMs / n).toFixed(1)}ms`,\n `rf.anims=${(this.timingAccum.renderFrameAnimsMs / n).toFixed(1)}ms`,\n `frameTasks=${(this.timingAccum.frameTasksMs / n).toFixed(1)}ms`,\n );\n this.timingFrameCount = 0;\n for (const key of Object.keys(\n this.timingAccum,\n ) as (keyof SeekForRenderTiming)[]) {\n this.timingAccum[key] = 0;\n }\n }\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":";;;;;;AA2DA,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;CAgCtB,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;EAKvB,MAAM,YAAY,SAAS,cAAc,eAAe;EACxD,MAAM,cAAc,YAChB,UAAU,cACT,KAAK,eAAe,eAAe,MAAM,SAAS;AAEvD,MAAI,cAAc,GAAG;AACnB,QAAK,mBAAmB,QAAQ;AAChC,QAAK,mBAAmB,SAAS;AAEjC,UAAO,OAAO,KAAK,mBAAmB,OAAO;IAC3C,UAAU;IACV,MAAM;IACN,QAAQ;IACR,OAAO,GAAG,YAAY;IACtB,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;cApHP;yBACW;kBAGP,SAAS,cAAc,MAAM;uBAExB,IAAI,eAAe;qBAGb;8BAGQ;4BACF;0BAGD;qBACgB;GACzC,mBAAmB;GACnB,mBAAmB;GACnB,mBAAmB;GACnB,gBAAgB;GAChB,eAAe;GACf,oBAAoB;GACpB,sBAAsB;GACtB,mBAAmB;GACnB,oBAAoB;GACpB,cAAc;GACd,SAAS;GACV;AAwFC,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;EAGrB,MAAM,YAAY,SAAS,cAAc,eAAe;AACxD,MAAI,WAAW;AACb,QAAK,sBAAsB,KAAK;AAChC,aAAU,UAAU;;EAItB,MAAM,aAAa,aAAa,SAAS;EAEzC,MAAM,aADa,qBAAqB,WAAW,CACrB;AAC9B,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,6BAA6B;EAE/C,MAAM,iBAAiB,cAAc,eAAe;AACpD,QAAM,WAAW,uBAAuB;AAMxC,yBAAuB,YAAY,WAAW;AAI9C,aAAW,aAAa,+BAA+B,GAAG;AAG1D,QAAM,WAAW,cAAc,eAAe;AAE9C,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;AAED,OAAK,mBAAmB,YAAY,GAAG;;CAGzC,MAAM,WAAW,aAAqB,QAAiB;AACrD,MAAI,KAAK,kBAAkB,OACzB,OAAM,IAAI,MAAM,mBAAmB;EAErC,MAAM,YAAY,SAAS,cAAc,eAAe;AACxD,MAAI,UACF,MAAK,sBAAsB,KAAK;EAIlC,MAAM,aADa,qBADA,aAAa,SAAS,KACU,CACrB;AAC9B,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,6BAA6B;EAI/C,MAAM,YACJ,KAAK,cAAc,eAAe,SAClC,cAAc,KAAK;EACrB,MAAM,cAAc,OAAO,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAC;EAGxD,MAAM,SAAS,MAAM,WAAW,cAAc,YAAY;AAC1D,OAAK;AACL,OAAK,MAAM,OAAO,OAAO,KACvB,KAAK,YACN,CACC,MAAK,YAAY,QAAQ,OAAO;AAElC,MAAI,KAAK,oBAAoB,IAAI;GAC/B,MAAM,IAAI,KAAK;AACf,WAAQ,IACN,0CAA0C,EAAE,YAC5C,UAAU,KAAK,YAAY,UAAU,GAAG,QAAQ,EAAE,CAAC,KACnD,QAAQ,KAAK,YAAY,oBAAoB,GAAG,QAAQ,EAAE,CAAC,KAC3D,QAAQ,KAAK,YAAY,oBAAoB,GAAG,QAAQ,EAAE,CAAC,KAC3D,QAAQ,KAAK,YAAY,oBAAoB,GAAG,QAAQ,EAAE,CAAC,KAC3D,SAAS,KAAK,YAAY,iBAAiB,GAAG,QAAQ,EAAE,CAAC,KACzD,gBAAgB,KAAK,YAAY,gBAAgB,GAAG,QAAQ,EAAE,CAAC,KAC/D,aAAa,KAAK,YAAY,qBAAqB,GAAG,QAAQ,EAAE,CAAC,KACjE,eAAe,KAAK,YAAY,uBAAuB,GAAG,QAAQ,EAAE,CAAC,KACrE,YAAY,KAAK,YAAY,oBAAoB,GAAG,QAAQ,EAAE,CAAC,KAC/D,aAAa,KAAK,YAAY,qBAAqB,GAAG,QAAQ,EAAE,CAAC,KACjE,eAAe,KAAK,YAAY,eAAe,GAAG,QAAQ,EAAE,CAAC,IAC9D;AACD,QAAK,mBAAmB;AACxB,QAAK,MAAM,OAAO,OAAO,KACvB,KAAK,YACN,CACC,MAAK,YAAY,OAAO;;AAG5B,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
+ {"version":3,"file":"EF_FRAMEGEN.js","names":[],"sources":["../src/EF_FRAMEGEN.ts"],"sourcesContent":["import type { VideoRenderOptions } from \"@editframe/assets\";\n\nimport { shallowGetTimegroups, type SeekForRenderTiming } from \"./elements/EFTimegroup.js\";\nimport { setupTemporalHierarchy } from \"./elements/setupTemporalHierarchy.js\";\n\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: (frameNumber: number, isLast: boolean, traceContext?: TraceContext) => 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 // Per-phase timing accumulators (reset every 30 frames)\n private timingFrameCount = 0;\n private timingAccum: SeekForRenderTiming = {\n updateComplete1Ms: 0,\n updateComplete2Ms: 0,\n updateComplete3Ms: 0,\n textSegmentsMs: 0,\n renderFrameMs: 0,\n renderFrameQueryMs: 0,\n renderFramePrepareMs: 0,\n renderFrameDrawMs: 0,\n renderFrameAnimsMs: 0,\n frameTasksMs: 0,\n totalMs: 0,\n };\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) => (typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)))\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, or fall back to renderOptions dimensions.\n // Without ef-workbench (e.g. API renders), the canvas was never sized or appended,\n // causing frame verification to fail on every frame.\n const workbench = document.querySelector(\"ef-workbench\") as HTMLElement;\n const canvasWidth = workbench\n ? workbench.clientWidth\n : (this.renderOptions?.encoderOptions.video.width ?? 0);\n\n if (canvasWidth > 0) {\n this.verificationCanvas.width = canvasWidth;\n this.verificationCanvas.height = 1;\n\n Object.assign(this.verificationCanvas.style, {\n position: \"fixed\",\n left: \"0px\",\n bottom: \"0px\",\n width: `${canvasWidth}px`,\n height: \"1px\",\n zIndex: \"99999\",\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: renderOptions.encoderOptions.toMs - 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(\"[EF_FRAMEGEN.connectToBridge] error initializing\", error);\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 // Workbench is optional - look for it but don't require it\n const workbench = document.querySelector(\"ef-workbench\");\n if (workbench) {\n this.setWorkbenchRendering(true);\n workbench.playing = false;\n }\n\n // Find timegroups either in workbench or directly in document\n const searchRoot = workbench || document.body;\n const timegroups = shallowGetTimegroups(searchRoot);\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\n // CRITICAL: Manually wire up temporal hierarchy since Lit Context fails with our connection order\n // When loading via loadURL(), elements connect depth-first (children before parents), causing\n // children to miss the context-request event since parents aren't listening yet.\n // See setupTemporalHierarchy.ts for detailed explanation.\n setupTemporalHierarchy(searchRoot, firstGroup);\n\n // Suppress autonomous re-renders (EFTemporal/EFTimegroup.updated) while\n // seekForRender is in progress — same protection applied to render clones.\n firstGroup.setAttribute(\"data-no-playback-controller\", \"\");\n\n // Use seekForRender for proper time seeking during rendering\n await firstGroup.seekForRender(startingTimeMs);\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 // Suppress unhandled rejection while the promise sits in storage before being awaited.\n this.audioBufferPromise.catch(() => {});\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 this.setWorkbenchRendering(true);\n }\n const searchRoot = workbench || document.body;\n const timegroups = shallowGetTimegroups(searchRoot);\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 = this.renderOptions.encoderOptions.fromMs + frameNumber * this.frameDurationMs;\n const frameTimeMs = Number(Number(frameTime).toFixed(5));\n\n // Use seekForRender for proper time seeking during rendering\n const timing = await firstGroup.seekForRender(frameTimeMs);\n this.timingFrameCount++;\n for (const key of Object.keys(this.timingAccum) as (keyof SeekForRenderTiming)[]) {\n this.timingAccum[key] += timing[key];\n }\n if (this.timingFrameCount >= 30) {\n const n = this.timingFrameCount;\n console.log(\n `[EF_FRAMEGEN] seekForRender phase avg (${n} frames):`,\n `total=${(this.timingAccum.totalMs / n).toFixed(1)}ms`,\n `uc1=${(this.timingAccum.updateComplete1Ms / n).toFixed(1)}ms`,\n `uc2=${(this.timingAccum.updateComplete2Ms / n).toFixed(1)}ms`,\n `uc3=${(this.timingAccum.updateComplete3Ms / n).toFixed(1)}ms`,\n `text=${(this.timingAccum.textSegmentsMs / n).toFixed(1)}ms`,\n `renderFrame=${(this.timingAccum.renderFrameMs / n).toFixed(1)}ms`,\n `rf.query=${(this.timingAccum.renderFrameQueryMs / n).toFixed(1)}ms`,\n `rf.prepare=${(this.timingAccum.renderFramePrepareMs / n).toFixed(1)}ms`,\n `rf.draw=${(this.timingAccum.renderFrameDrawMs / n).toFixed(1)}ms`,\n `rf.anims=${(this.timingAccum.renderFrameAnimsMs / n).toFixed(1)}ms`,\n `frameTasks=${(this.timingAccum.frameTasksMs / n).toFixed(1)}ms`,\n );\n this.timingFrameCount = 0;\n for (const key of Object.keys(this.timingAccum) as (keyof SeekForRenderTiming)[]) {\n this.timingAccum[key] = 0;\n }\n }\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(channelCount * renderedAudio.length);\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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EF_RENDERING.js","names":[],"sources":["../src/EF_RENDERING.ts"],"sourcesContent":["export const EF_RENDERING = () =>\n typeof window !== \"undefined\" && \"FRAMEGEN_BRIDGE\" in window;\n\nexport const EF_NO_WORKBENCH = () => {\n if (typeof window === \"undefined\") return false;\n const params = new URLSearchParams(window.location.search);\n return (\n params.get(\"noWorkbench\") === \"true\" ||\n params.get(\"no-workbench\") === \"true\"\n );\n};\n"],"mappings":";AAAA,MAAa,qBACX,OAAO,WAAW,eAAe,qBAAqB"}
1
+ {"version":3,"file":"EF_RENDERING.js","names":[],"sources":["../src/EF_RENDERING.ts"],"sourcesContent":["export const EF_RENDERING = () => typeof window !== \"undefined\" && \"FRAMEGEN_BRIDGE\" in window;\n\nexport const EF_NO_WORKBENCH = () => {\n if (typeof window === \"undefined\") return false;\n const params = new URLSearchParams(window.location.search);\n return params.get(\"noWorkbench\") === \"true\" || params.get(\"no-workbench\") === \"true\";\n};\n"],"mappings":";AAAA,MAAa,qBAAqB,OAAO,WAAW,eAAe,qBAAqB"}
@@ -149,7 +149,7 @@ let EFCanvas = class EFCanvas$1 extends EFTargetable(TWMixin(LitElement)) {
149
149
  if (this.capturedPointerId !== null) {
150
150
  try {
151
151
  this.releasePointerCapture(e.pointerId);
152
- } catch (err) {}
152
+ } catch (_err) {}
153
153
  this.capturedPointerId = null;
154
154
  }
155
155
  if (this.isDragging || this.dragStarted || this.draggedElementId !== null) {
@@ -194,7 +194,7 @@ let EFCanvas = class EFCanvas$1 extends EFTargetable(TWMixin(LitElement)) {
194
194
  if (this.capturedPointerId !== null) {
195
195
  try {
196
196
  this.releasePointerCapture(e.pointerId);
197
- } catch (err) {}
197
+ } catch (_err) {}
198
198
  this.capturedPointerId = null;
199
199
  }
200
200
  if (this.draggedElementId !== null || this.dragStartPos !== null) {
@@ -284,7 +284,7 @@ let EFCanvas = class EFCanvas$1 extends EFTargetable(TWMixin(LitElement)) {
284
284
  if (!element.id || element.id.trim() === "") element.id = elementId;
285
285
  if (!element.getAttribute(this.elementIdAttribute)) element.setAttribute(this.elementIdAttribute, elementId);
286
286
  this.registerElement(element, elementId);
287
- } catch (error) {}
287
+ } catch (_error) {}
288
288
  }
289
289
  /**
290
290
  * Register an element for canvas management.