@editframe/elements 0.20.4-beta.0 → 0.21.0-beta.0

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 (92) hide show
  1. package/dist/DelayedLoadingState.js +0 -27
  2. package/dist/EF_FRAMEGEN.d.ts +5 -3
  3. package/dist/EF_FRAMEGEN.js +50 -11
  4. package/dist/_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js +7 -0
  5. package/dist/elements/ContextProxiesController.js +2 -22
  6. package/dist/elements/EFAudio.js +4 -8
  7. package/dist/elements/EFCaptions.js +59 -84
  8. package/dist/elements/EFImage.js +5 -6
  9. package/dist/elements/EFMedia/AssetIdMediaEngine.js +2 -4
  10. package/dist/elements/EFMedia/AssetMediaEngine.js +35 -30
  11. package/dist/elements/EFMedia/BaseMediaEngine.js +57 -73
  12. package/dist/elements/EFMedia/BufferedSeekingInput.js +134 -76
  13. package/dist/elements/EFMedia/JitMediaEngine.js +9 -19
  14. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +3 -6
  15. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +1 -1
  16. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +1 -1
  17. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +6 -5
  18. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +1 -3
  19. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +1 -1
  20. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +1 -1
  21. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +1 -1
  22. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +4 -16
  23. package/dist/elements/EFMedia/shared/BufferUtils.js +2 -15
  24. package/dist/elements/EFMedia/shared/GlobalInputCache.js +0 -24
  25. package/dist/elements/EFMedia/shared/PrecisionUtils.js +0 -21
  26. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +0 -17
  27. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -10
  28. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.d.ts +29 -0
  29. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +32 -0
  30. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +1 -15
  31. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +1 -7
  32. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +8 -5
  33. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +12 -13
  34. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +1 -1
  35. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +134 -70
  36. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +7 -11
  37. package/dist/elements/EFMedia.js +26 -24
  38. package/dist/elements/EFSourceMixin.js +5 -7
  39. package/dist/elements/EFSurface.js +6 -9
  40. package/dist/elements/EFTemporal.js +19 -37
  41. package/dist/elements/EFThumbnailStrip.js +16 -59
  42. package/dist/elements/EFTimegroup.js +95 -90
  43. package/dist/elements/EFVideo.d.ts +6 -2
  44. package/dist/elements/EFVideo.js +142 -107
  45. package/dist/elements/EFWaveform.js +18 -27
  46. package/dist/elements/SampleBuffer.js +2 -5
  47. package/dist/elements/TargetController.js +3 -3
  48. package/dist/elements/durationConverter.js +4 -4
  49. package/dist/elements/updateAnimations.js +14 -35
  50. package/dist/gui/ContextMixin.js +23 -52
  51. package/dist/gui/EFConfiguration.js +7 -7
  52. package/dist/gui/EFControls.js +5 -5
  53. package/dist/gui/EFFilmstrip.js +77 -98
  54. package/dist/gui/EFFitScale.js +5 -6
  55. package/dist/gui/EFFocusOverlay.js +4 -4
  56. package/dist/gui/EFPreview.js +4 -4
  57. package/dist/gui/EFScrubber.js +9 -9
  58. package/dist/gui/EFTimeDisplay.js +5 -5
  59. package/dist/gui/EFToggleLoop.js +4 -4
  60. package/dist/gui/EFTogglePlay.js +5 -5
  61. package/dist/gui/EFWorkbench.js +5 -5
  62. package/dist/gui/TWMixin2.js +1 -1
  63. package/dist/index.d.ts +1 -0
  64. package/dist/otel/BridgeSpanExporter.d.ts +13 -0
  65. package/dist/otel/BridgeSpanExporter.js +87 -0
  66. package/dist/otel/setupBrowserTracing.d.ts +12 -0
  67. package/dist/otel/setupBrowserTracing.js +30 -0
  68. package/dist/otel/tracingHelpers.d.ts +34 -0
  69. package/dist/otel/tracingHelpers.js +113 -0
  70. package/dist/transcoding/cache/RequestDeduplicator.js +0 -21
  71. package/dist/transcoding/cache/URLTokenDeduplicator.js +1 -21
  72. package/dist/transcoding/utils/UrlGenerator.js +2 -19
  73. package/dist/utils/LRUCache.js +6 -53
  74. package/package.json +10 -2
  75. package/src/elements/EFCaptions.browsertest.ts +2 -0
  76. package/src/elements/EFMedia/AssetMediaEngine.ts +65 -37
  77. package/src/elements/EFMedia/BaseMediaEngine.ts +110 -52
  78. package/src/elements/EFMedia/BufferedSeekingInput.ts +218 -101
  79. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +7 -3
  80. package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +76 -0
  81. package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +16 -10
  82. package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +7 -1
  83. package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +222 -116
  84. package/src/elements/EFMedia.ts +16 -1
  85. package/src/elements/EFTimegroup.browsertest.ts +10 -8
  86. package/src/elements/EFTimegroup.ts +164 -76
  87. package/src/elements/EFVideo.browsertest.ts +19 -27
  88. package/src/elements/EFVideo.ts +203 -101
  89. package/src/otel/BridgeSpanExporter.ts +150 -0
  90. package/src/otel/setupBrowserTracing.ts +68 -0
  91. package/src/otel/tracingHelpers.ts +251 -0
  92. package/types.json +1 -1
@@ -1,3 +1,5 @@
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
2
+ import { withSpan, withSpanSync } from "../otel/tracingHelpers.js";
1
3
  import { EFMedia } from "./EFMedia.js";
2
4
  import { TWMixin } from "../gui/TWMixin2.js";
3
5
  import { DelayedLoadingState } from "../DelayedLoadingState.js";
@@ -13,10 +15,10 @@ import { Task } from "@lit/task";
13
15
  import debug from "debug";
14
16
  import { css, html } from "lit";
15
17
  import { customElement, property, state } from "lit/decorators.js";
16
- import _decorate from "@oxc-project/runtime/helpers/decorate";
18
+ import { context, trace } from "@opentelemetry/api";
17
19
  import { createRef, ref } from "lit/directives/ref.js";
18
- const log = debug("ef:elements:EFVideo");
19
- let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
20
+ var log = debug("ef:elements:EFVideo");
21
+ var EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
20
22
  static {
21
23
  this.styles = [css`
22
24
  :host {
@@ -104,43 +106,31 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
104
106
  console.error("frameTask error", error);
105
107
  },
106
108
  onComplete: () => {},
107
- task: async ([_desiredSeekTimeMs]) => {
108
- this.unifiedVideoSeekTask.run();
109
- await this.unifiedVideoSeekTask.taskComplete;
110
- this.paintTask.run();
111
- await this.paintTask.taskComplete;
112
- }
113
- });
114
- this.paintTask = new Task(this, {
115
- autoRun: false,
116
- args: () => [this.desiredSeekTimeMs],
117
- onError: (error) => {
118
- console.error("paintTask error", error);
119
- },
120
- onComplete: () => {},
121
- task: async ([_seekToMs], { signal }) => {
122
- const isProductionRendering = this.isInProductionRenderingMode();
123
- try {
109
+ task: async ([_desiredSeekTimeMs], { signal }) => {
110
+ const t0 = performance.now();
111
+ await withSpan("video.frameTask", {
112
+ elementId: this.id || "unknown",
113
+ desiredSeekTimeMs: _desiredSeekTimeMs,
114
+ src: this.src || "none"
115
+ }, void 0, async (span) => {
116
+ const t1 = performance.now();
117
+ span.setAttribute("preworkMs", t1 - t0);
118
+ this.unifiedVideoSeekTask.run();
119
+ const t2 = performance.now();
120
+ span.setAttribute("seekRunMs", t2 - t1);
124
121
  await this.unifiedVideoSeekTask.taskComplete;
125
- const videoSample = this.unifiedVideoSeekTask.value;
126
- if (videoSample) {
127
- const videoFrame = videoSample.toVideoFrame();
128
- try {
129
- this.displayFrame(videoFrame, _seekToMs);
130
- } finally {
131
- videoFrame.close();
132
- }
122
+ const t3 = performance.now();
123
+ span.setAttribute("seekAwaitMs", t3 - t2);
124
+ if (signal.aborted) {
125
+ span.setAttribute("aborted", true);
126
+ return;
133
127
  }
134
- } catch (error) {
135
- console.warn("Unified video pipeline error:", error);
136
- }
137
- if (!isProductionRendering) {
138
- if (!this.rootTimegroup || this.rootTimegroup.currentTimeMs === 0 && this.desiredSeekTimeMs === 0) return;
139
- } else {
140
- if (!this.rootTimegroup) return;
141
- if (!this.isFrameRenderingActive()) return;
142
- }
143
- if (signal.aborted) return;
128
+ const t4 = performance.now();
129
+ this.paint(_desiredSeekTimeMs, span);
130
+ const t5 = performance.now();
131
+ span.setAttribute("paintMs", t5 - t4);
132
+ span.setAttribute("totalFrameMs", t5 - t0);
133
+ });
144
134
  }
145
135
  });
146
136
  this.delayedLoadingState = new DelayedLoadingState(250, (isLoading, message) => {
@@ -171,23 +161,13 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
171
161
  if (referencedCanvas) return referencedCanvas;
172
162
  const shadowCanvas = this.shadowRoot?.querySelector("canvas");
173
163
  if (shadowCanvas) return shadowCanvas;
174
- return void 0;
175
164
  }
176
- /**
177
- * Start a delayed loading operation for testing
178
- */
179
165
  startDelayedLoading(operationId, message, options = {}) {
180
166
  this.delayedLoadingState.startLoading(operationId, message, options);
181
167
  }
182
- /**
183
- * Clear a delayed loading operation for testing
184
- */
185
168
  clearDelayedLoading(operationId) {
186
169
  this.delayedLoadingState.clearLoading(operationId);
187
170
  }
188
- /**
189
- * Set loading state for user feedback
190
- */
191
171
  setLoadingState(isLoading, operation = null, message = "") {
192
172
  this.loadingState = {
193
173
  isLoading,
@@ -195,96 +175,151 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
195
175
  message
196
176
  };
197
177
  }
198
- /**
199
- * Clear the canvas when element becomes inactive
200
- */
178
+ paint(seekToMs, parentSpan) {
179
+ const parentContext = parentSpan ? trace.setSpan(context.active(), parentSpan) : void 0;
180
+ withSpanSync("video.paint", {
181
+ elementId: this.id || "unknown",
182
+ seekToMs,
183
+ src: this.src || "none"
184
+ }, parentContext, (span) => {
185
+ const t0 = performance.now();
186
+ const isProductionRendering = this.isInProductionRenderingMode();
187
+ const t1 = performance.now();
188
+ span.setAttribute("isProductionRendering", isProductionRendering);
189
+ span.setAttribute("modeCheckMs", t1 - t0);
190
+ try {
191
+ const t2 = performance.now();
192
+ const videoSample = this.unifiedVideoSeekTask.value;
193
+ span.setAttribute("hasVideoSample", !!videoSample);
194
+ span.setAttribute("valueAccessMs", t2 - t1);
195
+ if (videoSample) {
196
+ const t3 = performance.now();
197
+ const videoFrame = videoSample.toVideoFrame();
198
+ const t4 = performance.now();
199
+ span.setAttribute("toVideoFrameMs", t4 - t3);
200
+ try {
201
+ const t5 = performance.now();
202
+ this.displayFrame(videoFrame, seekToMs, span);
203
+ const t6 = performance.now();
204
+ span.setAttribute("displayFrameMs", t6 - t5);
205
+ } finally {
206
+ videoFrame.close();
207
+ }
208
+ }
209
+ } catch (error) {
210
+ console.warn("Unified video pipeline error:", error);
211
+ }
212
+ if (!isProductionRendering) {
213
+ if (!this.rootTimegroup || this.rootTimegroup.currentTimeMs === 0 && this.desiredSeekTimeMs === 0) {
214
+ span.setAttribute("skipped", "preview-initialization");
215
+ return;
216
+ }
217
+ } else {
218
+ if (!this.rootTimegroup) {
219
+ span.setAttribute("skipped", "no-root-timegroup");
220
+ return;
221
+ }
222
+ if (!this.isFrameRenderingActive()) {
223
+ span.setAttribute("skipped", "frame-rendering-not-active");
224
+ return;
225
+ }
226
+ }
227
+ const tEnd = performance.now();
228
+ span.setAttribute("totalPaintMs", tEnd - t0);
229
+ });
230
+ }
201
231
  clearCanvas() {
202
232
  if (!this.canvasElement) return;
203
233
  const ctx = this.canvasElement.getContext("2d");
204
234
  if (ctx) ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
205
235
  }
206
- /**
207
- * Display a video frame on the canvas
208
- */
209
- displayFrame(frame, seekToMs) {
210
- log("trace: displayFrame start", {
236
+ displayFrame(frame, seekToMs, parentSpan) {
237
+ const parentContext = parentSpan ? trace.setSpan(context.active(), parentSpan) : void 0;
238
+ withSpanSync("video.displayFrame", {
239
+ elementId: this.id || "unknown",
211
240
  seekToMs,
212
- frameFormat: frame.format
213
- });
214
- if (!this.canvasElement) {
215
- log("trace: displayFrame aborted - no canvas element");
216
- throw new Error(`Frame display failed: Canvas element is not available at time ${seekToMs}ms. The video component may not be properly initialized.`);
217
- }
218
- const ctx = this.canvasElement.getContext("2d");
219
- if (!ctx) {
220
- log("trace: displayFrame aborted - no canvas context");
221
- throw new Error(`Frame display failed: Unable to get 2D canvas context at time ${seekToMs}ms. This may indicate a browser compatibility issue or canvas corruption.`);
222
- }
223
- if (frame?.codedWidth && frame?.codedHeight) {
224
- if (this.canvasElement.width !== frame.codedWidth || this.canvasElement.height !== frame.codedHeight) {
225
- log("trace: updating canvas dimensions", {
226
- width: frame.codedWidth,
227
- height: frame.codedHeight
228
- });
229
- this.canvasElement.width = frame.codedWidth;
230
- this.canvasElement.height = frame.codedHeight;
241
+ format: frame.format || "unknown",
242
+ width: frame.codedWidth,
243
+ height: frame.codedHeight
244
+ }, parentContext, (span) => {
245
+ const t0 = performance.now();
246
+ log("trace: displayFrame start", {
247
+ seekToMs,
248
+ frameFormat: frame.format
249
+ });
250
+ if (!this.canvasElement) {
251
+ log("trace: displayFrame aborted - no canvas element");
252
+ throw new Error(`Frame display failed: Canvas element is not available at time ${seekToMs}ms. The video component may not be properly initialized.`);
231
253
  }
232
- }
233
- if (frame.format === null) {
234
- log("trace: displayFrame aborted - null frame format");
235
- throw new Error(`Frame display failed: Video frame has null format at time ${seekToMs}ms. This indicates corrupted or incompatible video data.`);
236
- }
237
- ctx.drawImage(frame, 0, 0, this.canvasElement.width, this.canvasElement.height);
238
- log("trace: frame drawn to canvas", { seekToMs });
239
- return seekToMs;
254
+ const t1 = performance.now();
255
+ span.setAttribute("getCanvasMs", Math.round((t1 - t0) * 100) / 100);
256
+ const ctx = this.canvasElement.getContext("2d");
257
+ const t2 = performance.now();
258
+ span.setAttribute("getCtxMs", Math.round((t2 - t1) * 100) / 100);
259
+ if (!ctx) {
260
+ log("trace: displayFrame aborted - no canvas context");
261
+ throw new Error(`Frame display failed: Unable to get 2D canvas context at time ${seekToMs}ms. This may indicate a browser compatibility issue or canvas corruption.`);
262
+ }
263
+ let resized = false;
264
+ if (frame?.codedWidth && frame?.codedHeight) {
265
+ if (this.canvasElement.width !== frame.codedWidth || this.canvasElement.height !== frame.codedHeight) {
266
+ log("trace: updating canvas dimensions", {
267
+ width: frame.codedWidth,
268
+ height: frame.codedHeight
269
+ });
270
+ this.canvasElement.width = frame.codedWidth;
271
+ this.canvasElement.height = frame.codedHeight;
272
+ resized = true;
273
+ const t3 = performance.now();
274
+ span.setAttribute("resizeMs", Math.round((t3 - t2) * 100) / 100);
275
+ }
276
+ }
277
+ span.setAttribute("canvasResized", resized);
278
+ if (frame.format === null) {
279
+ log("trace: displayFrame aborted - null frame format");
280
+ throw new Error(`Frame display failed: Video frame has null format at time ${seekToMs}ms. This indicates corrupted or incompatible video data.`);
281
+ }
282
+ const tDrawStart = performance.now();
283
+ ctx.drawImage(frame, 0, 0, this.canvasElement.width, this.canvasElement.height);
284
+ const tDrawEnd = performance.now();
285
+ span.setAttribute("drawImageMs", Math.round((tDrawEnd - tDrawStart) * 100) / 100);
286
+ span.setAttribute("totalDisplayMs", Math.round((tDrawEnd - t0) * 100) / 100);
287
+ span.setAttribute("canvasWidth", this.canvasElement.width);
288
+ span.setAttribute("canvasHeight", this.canvasElement.height);
289
+ log("trace: frame drawn to canvas", { seekToMs });
290
+ });
240
291
  }
241
- /**
242
- * Check if we're in production rendering mode (EF_FRAMEGEN active) vs preview mode
243
- */
244
292
  isInProductionRenderingMode() {
245
293
  if (typeof window.EF_RENDERING === "function") return window.EF_RENDERING();
246
- const workbench = document.querySelector("ef-workbench");
247
- if (workbench?.rendering) return true;
294
+ if (document.querySelector("ef-workbench")?.rendering) return true;
248
295
  if (window.EF_FRAMEGEN?.renderOptions) return true;
249
296
  return false;
250
297
  }
251
- /**
252
- * Check if EF_FRAMEGEN has explicitly started frame rendering (not just initialization)
253
- */
254
298
  isFrameRenderingActive() {
255
299
  if (!window.EF_FRAMEGEN?.renderOptions) return false;
256
- const renderOptions = window.EF_FRAMEGEN.renderOptions;
257
- const renderStartTime = renderOptions.encoderOptions.fromMs;
258
- const currentTime = this.rootTimegroup?.currentTimeMs || 0;
259
- return currentTime >= renderStartTime;
300
+ const renderStartTime = window.EF_FRAMEGEN.renderOptions.encoderOptions.fromMs;
301
+ return (this.rootTimegroup?.currentTimeMs || 0) >= renderStartTime;
260
302
  }
261
- /**
262
- * Legacy getter for fragment index task
263
- * Still used by EFCaptions - maps to unified video seek task
264
- */
265
303
  get fragmentIndexTask() {
266
304
  return this.unifiedVideoSeekTask;
267
305
  }
268
- /**
269
- * Clean up resources when component is disconnected
270
- */
271
306
  disconnectedCallback() {
272
307
  super.disconnectedCallback();
273
308
  this.delayedLoadingState.clearAllLoading();
274
309
  }
275
310
  };
276
- _decorate([property({
311
+ __decorate([property({
277
312
  type: Number,
278
313
  attribute: "video-buffer-duration"
279
314
  })], EFVideo.prototype, "videoBufferDurationMs", void 0);
280
- _decorate([property({
315
+ __decorate([property({
281
316
  type: Number,
282
317
  attribute: "max-video-buffer-fetches"
283
318
  })], EFVideo.prototype, "maxVideoBufferFetches", void 0);
284
- _decorate([property({
319
+ __decorate([property({
285
320
  type: Boolean,
286
321
  attribute: "enable-video-buffering"
287
322
  })], EFVideo.prototype, "enableVideoBuffering", void 0);
288
- _decorate([state()], EFVideo.prototype, "loadingState", void 0);
289
- EFVideo = _decorate([customElement("ef-video")], EFVideo);
323
+ __decorate([state()], EFVideo.prototype, "loadingState", void 0);
324
+ EFVideo = __decorate([customElement("ef-video")], EFVideo);
290
325
  export { EFVideo };
@@ -1,4 +1,5 @@
1
1
  import { EF_RENDERING } from "../EF_RENDERING.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
2
3
  import { EFTemporal } from "./EFTemporal.js";
3
4
  import { TargetController } from "./TargetController.js";
4
5
  import { TWMixin } from "../gui/TWMixin2.js";
@@ -6,10 +7,9 @@ import { CrossUpdateController } from "./CrossUpdateController.js";
6
7
  import { Task } from "@lit/task";
7
8
  import { LitElement, css, html } from "lit";
8
9
  import { customElement, property, state } from "lit/decorators.js";
9
- import _decorate from "@oxc-project/runtime/helpers/decorate";
10
10
  import { createRef, ref } from "lit/directives/ref.js";
11
11
  import { CSSStyleObserver } from "@bramus/style-observer";
12
- let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
12
+ var EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
13
13
  constructor(..._args) {
14
14
  super(..._args);
15
15
  this.canvasRef = createRef();
@@ -38,8 +38,7 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
38
38
  if (!frequencyData || !byteTimeData) return;
39
39
  ctx.save();
40
40
  if (this.color === "currentColor") {
41
- const computedStyle = getComputedStyle(this);
42
- const currentColor = computedStyle.color;
41
+ const currentColor = getComputedStyle(this).color;
43
42
  ctx.strokeStyle = currentColor;
44
43
  ctx.fillStyle = currentColor;
45
44
  } else {
@@ -150,13 +149,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
150
149
  const totalBars = frequencyData.length;
151
150
  const paddingInner = this.barSpacing;
152
151
  const paddingOuter = .01;
153
- const availableWidth = waveWidth;
154
- const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
152
+ const barWidth = waveWidth / (totalBars + (totalBars - 1) * paddingInner);
155
153
  ctx.clearRect(0, 0, waveWidth, waveHeight);
156
154
  const path = new Path2D();
157
155
  frequencyData.forEach((value, i) => {
158
- const normalizedValue = value / 255;
159
- const barHeight = normalizedValue * waveHeight;
156
+ const barHeight = value / 255 * waveHeight;
160
157
  const y = (waveHeight - barHeight) / 2;
161
158
  const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
162
159
  path.rect(x, y, barWidth, barHeight);
@@ -191,13 +188,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
191
188
  const totalBars = frequencyData.length;
192
189
  const paddingInner = this.barSpacing;
193
190
  const paddingOuter = .01;
194
- const availableWidth = waveWidth;
195
- const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
191
+ const barWidth = waveWidth / (totalBars + (totalBars - 1) * paddingInner);
196
192
  ctx.clearRect(0, 0, waveWidth, waveHeight);
197
193
  const path = new Path2D();
198
194
  frequencyData.forEach((value, i) => {
199
- const normalizedValue = value / 255;
200
- const height = normalizedValue * waveHeight;
195
+ const height = value / 255 * waveHeight;
201
196
  const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
202
197
  const y = (waveHeight - height) / 2;
203
198
  path.roundRect(x, y, barWidth, height, barWidth / 2);
@@ -281,8 +276,7 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
281
276
  if (i === 0) path.moveTo(x, y);
282
277
  else {
283
278
  const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
284
- const prevValue = Math.min((frequencyData[i - 1] ?? 0) / 255 * 2, 1);
285
- const prevBarHeight = prevValue * waveHeight;
279
+ const prevBarHeight = Math.min((frequencyData[i - 1] ?? 0) / 255 * 2, 1) * waveHeight;
286
280
  const prevY = (waveHeight - prevBarHeight) / 2;
287
281
  const xc = (prevX + x) / 2;
288
282
  const yc = (prevY + y) / 2;
@@ -297,8 +291,7 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
297
291
  if (i === frequencyData.length - 1) path.lineTo(x, y);
298
292
  else {
299
293
  const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
300
- const nextValue = Math.min((frequencyData[i + 1] ?? 0) / 255 * 2, 1);
301
- const nextBarHeight = nextValue * waveHeight;
294
+ const nextBarHeight = Math.min((frequencyData[i + 1] ?? 0) / 255 * 2, 1) * waveHeight;
302
295
  const nextY = (waveHeight + nextBarHeight) / 2;
303
296
  const xc = (nextX + x) / 2;
304
297
  const yc = (nextY + y) / 2;
@@ -331,8 +324,7 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
331
324
  if (i === 0) path.moveTo(x, y);
332
325
  else {
333
326
  const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
334
- const prevValue = (frequencyData[i - 1] ?? 0) / 255;
335
- const prevBarHeight = prevValue * (waveHeight / 2);
327
+ const prevBarHeight = (frequencyData[i - 1] ?? 0) / 255 * (waveHeight / 2);
336
328
  const prevY = (waveHeight - prevBarHeight * 2) / 2;
337
329
  const xc = (prevX + x) / 2;
338
330
  const yc = (prevY + y) / 2;
@@ -347,8 +339,7 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
347
339
  if (i === frequencyData.length - 1) path.lineTo(x, y);
348
340
  else {
349
341
  const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
350
- const nextValue = (frequencyData[i + 1] ?? 0) / 255;
351
- const nextBarHeight = nextValue * (waveHeight / 2);
342
+ const nextBarHeight = (frequencyData[i + 1] ?? 0) / 255 * (waveHeight / 2);
352
343
  const nextY = (waveHeight + nextBarHeight * 2) / 2;
353
344
  const xc = (nextX + x) / 2;
354
345
  const yc = (nextY + y) / 2;
@@ -370,23 +361,23 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
370
361
  if (changedProperties.size > 0) this.frameTask.run();
371
362
  }
372
363
  };
373
- _decorate([property({
364
+ __decorate([property({
374
365
  type: String,
375
366
  attribute: "mode"
376
367
  })], EFWaveform.prototype, "mode", void 0);
377
- _decorate([property({ type: String })], EFWaveform.prototype, "color", void 0);
378
- _decorate([property({
368
+ __decorate([property({ type: String })], EFWaveform.prototype, "color", void 0);
369
+ __decorate([property({
379
370
  type: String,
380
371
  reflect: true
381
372
  })], EFWaveform.prototype, "target", void 0);
382
- _decorate([property({
373
+ __decorate([property({
383
374
  type: Number,
384
375
  attribute: "bar-spacing"
385
376
  })], EFWaveform.prototype, "barSpacing", void 0);
386
- _decorate([state()], EFWaveform.prototype, "targetElement", void 0);
387
- _decorate([property({
377
+ __decorate([state()], EFWaveform.prototype, "targetElement", void 0);
378
+ __decorate([property({
388
379
  type: Number,
389
380
  attribute: "line-width"
390
381
  })], EFWaveform.prototype, "lineWidth", void 0);
391
- EFWaveform = _decorate([customElement("ef-waveform")], EFWaveform);
382
+ EFWaveform = __decorate([customElement("ef-waveform")], EFWaveform);
392
383
  export { EFWaveform };
@@ -23,8 +23,7 @@ var SampleBuffer = class {
23
23
  } catch (_error) {}
24
24
  }
25
25
  peek() {
26
- const currentBuffer = this.buffer;
27
- return currentBuffer[0];
26
+ return this.buffer[0];
28
27
  }
29
28
  find(desiredSeekTimeMs) {
30
29
  const currentBuffer = [...this.buffer];
@@ -36,14 +35,12 @@ var SampleBuffer = class {
36
35
  const sampleEndMs = roundToMilliseconds(sampleStartMs + sampleDurationMs);
37
36
  if (targetTimeMs >= sampleStartMs && targetTimeMs < sampleEndMs) return sample;
38
37
  }
39
- return void 0;
40
38
  }
41
39
  get length() {
42
40
  return this.buffer.length;
43
41
  }
44
42
  get firstTimestamp() {
45
- const currentBuffer = this.buffer;
46
- return currentBuffer[0]?.timestamp || 0;
43
+ return this.buffer[0]?.timestamp || 0;
47
44
  }
48
45
  getContents() {
49
46
  return [...this.buffer];
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from "lit";
2
- const EF_TARGETABLE = Symbol("EF_TARGETABLE");
2
+ var EF_TARGETABLE = Symbol("EF_TARGETABLE");
3
3
  var TargetRegistry = class {
4
4
  constructor() {
5
5
  this.idMap = /* @__PURE__ */ new Map();
@@ -28,8 +28,8 @@ var TargetRegistry = class {
28
28
  this.callbacks.delete(id);
29
29
  }
30
30
  };
31
- const documentRegistries = /* @__PURE__ */ new WeakMap();
32
- const getRegistry = (root) => {
31
+ var documentRegistries = /* @__PURE__ */ new WeakMap();
32
+ var getRegistry = (root) => {
33
33
  let registry = documentRegistries.get(root);
34
34
  if (!registry) {
35
35
  registry = new TargetRegistry();
@@ -3,7 +3,7 @@ const durationConverter = {
3
3
  fromAttribute: (value) => value === null ? null : parseTimeToMs(value),
4
4
  toAttribute: (value) => value === null ? null : `${value}s`
5
5
  };
6
- const positiveDurationConverter = (error) => {
6
+ var positiveDurationConverter = (error) => {
7
7
  return {
8
8
  fromAttribute: (value) => {
9
9
  if (value === null) return null;
@@ -13,7 +13,7 @@ const positiveDurationConverter = (error) => {
13
13
  toAttribute: (value) => value === null ? null : `${value}s`
14
14
  };
15
15
  };
16
- const trimDurationConverter = positiveDurationConverter("Trimstart & trimend must be a positive value in milliseconds or seconds (1s, 1000ms)");
17
- const imageDurationConverter = positiveDurationConverter("Image duration must be a positive value in milliseconds or seconds (1s, 1000ms)");
18
- const sourceDurationConverter = positiveDurationConverter("Sourcein & sourceout must be a positive value in milliseconds or seconds (1s, 1000ms)");
16
+ positiveDurationConverter("Trimstart & trimend must be a positive value in milliseconds or seconds (1s, 1000ms)");
17
+ positiveDurationConverter("Image duration must be a positive value in milliseconds or seconds (1s, 1000ms)");
18
+ positiveDurationConverter("Sourcein & sourceout must be a positive value in milliseconds or seconds (1s, 1000ms)");
19
19
  export { durationConverter };
@@ -1,19 +1,15 @@
1
1
  import { deepGetTemporalElements } from "./EFTemporal.js";
2
- const ANIMATION_PRECISION_OFFSET = .1;
3
- const DEFAULT_ANIMATION_ITERATIONS = 1;
4
- const PROGRESS_PROPERTY = "--ef-progress";
5
- const DURATION_PROPERTY = "--ef-duration";
6
- const TRANSITION_DURATION_PROPERTY = "--ef-transition-duration";
7
- const TRANSITION_OUT_START_PROPERTY = "--ef-transition-out-start";
8
- const TIMEGROUP_TAGNAME = "ef-timegroup";
9
- /**
10
- * Evaluates what the element's state should be based on the timeline
11
- */
2
+ var ANIMATION_PRECISION_OFFSET = .1;
3
+ var DEFAULT_ANIMATION_ITERATIONS = 1;
4
+ var PROGRESS_PROPERTY = "--ef-progress";
5
+ var DURATION_PROPERTY = "--ef-duration";
6
+ var TRANSITION_DURATION_PROPERTY = "--ef-transition-duration";
7
+ var TRANSITION_OUT_START_PROPERTY = "--ef-transition-out-start";
8
+ var TIMEGROUP_TAGNAME = "ef-timegroup";
12
9
  const evaluateTemporalState = (element) => {
13
10
  const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
14
11
  const progress = element.durationMs <= 0 ? 1 : Math.max(0, Math.min(1, element.currentTimeMs / element.durationMs));
15
- const isRootTimegroup = element.tagName.toLowerCase() === TIMEGROUP_TAGNAME && !element.parentTimegroup;
16
- const useInclusiveEnd = isRootTimegroup;
12
+ const useInclusiveEnd = element.tagName.toLowerCase() === TIMEGROUP_TAGNAME && !element.parentTimegroup;
17
13
  const isVisible = element.startTimeMs <= timelineTimeMs && (useInclusiveEnd ? element.endTimeMs >= timelineTimeMs : element.endTimeMs > timelineTimeMs);
18
14
  return {
19
15
  progress,
@@ -21,10 +17,6 @@ const evaluateTemporalState = (element) => {
21
17
  timelineTimeMs
22
18
  };
23
19
  };
24
- /**
25
- * Evaluates element visibility specifically for animation coordination
26
- * Uses inclusive end boundaries to prevent animation jumps at exact boundaries
27
- */
28
20
  const evaluateTemporalStateForAnimation = (element) => {
29
21
  const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
30
22
  const progress = element.durationMs <= 0 ? 1 : Math.max(0, Math.min(1, element.currentTimeMs / element.durationMs));
@@ -35,10 +27,7 @@ const evaluateTemporalStateForAnimation = (element) => {
35
27
  timelineTimeMs
36
28
  };
37
29
  };
38
- /**
39
- * Updates the visual state (CSS + display) to match temporal state
40
- */
41
- const updateVisualState = (element, state) => {
30
+ var updateVisualState = (element, state) => {
42
31
  element.style.setProperty(PROGRESS_PROPERTY, `${state.progress * 100}%`);
43
32
  if (!state.isVisible) {
44
33
  if (element.style.display !== "none") element.style.display = "none";
@@ -49,17 +38,13 @@ const updateVisualState = (element, state) => {
49
38
  element.style.setProperty(TRANSITION_DURATION_PROPERTY, `${element.parentTimegroup?.overlapMs ?? 0}ms`);
50
39
  element.style.setProperty(TRANSITION_OUT_START_PROPERTY, `${element.durationMs - (element.parentTimegroup?.overlapMs ?? 0)}ms`);
51
40
  };
52
- /**
53
- * Coordinates animations for a single element and its subtree, using the element as the time source
54
- */
55
- const coordinateAnimationsForSingleElement = (element) => {
41
+ var coordinateAnimationsForSingleElement = (element) => {
56
42
  const animations = element.getAnimations({ subtree: true });
57
43
  for (const animation of animations) {
58
44
  if (animation.playState === "running") animation.pause();
59
45
  const effect = animation.effect;
60
46
  if (!(effect && effect instanceof KeyframeEffect)) continue;
61
- const target = effect.target;
62
- if (!target) continue;
47
+ if (!effect.target) continue;
63
48
  const timing = effect.getTiming();
64
49
  const duration = Number(timing.duration) || 0;
65
50
  const delay = Number(timing.delay) || 0;
@@ -76,8 +61,7 @@ const coordinateAnimationsForSingleElement = (element) => {
76
61
  const adjustedTime = currentTime - delay;
77
62
  const currentIteration = Math.floor(adjustedTime / duration);
78
63
  const currentIterationTime = adjustedTime % duration;
79
- const totalAnimationLength = delay + duration * iterations;
80
- const maxSafeCurrentTime = totalAnimationLength - ANIMATION_PRECISION_OFFSET;
64
+ const maxSafeCurrentTime = delay + duration * iterations - ANIMATION_PRECISION_OFFSET;
81
65
  if (currentIteration >= iterations) animation.currentTime = maxSafeCurrentTime;
82
66
  else {
83
67
  const proposedCurrentTime = Math.min(currentIterationTime, duration - ANIMATION_PRECISION_OFFSET) + delay;
@@ -85,9 +69,6 @@ const coordinateAnimationsForSingleElement = (element) => {
85
69
  }
86
70
  }
87
71
  };
88
- /**
89
- * Main function: synchronizes DOM element with timeline
90
- */
91
72
  const updateAnimations = (element) => {
92
73
  const temporalState = evaluateTemporalState(element);
93
74
  deepGetTemporalElements(element).forEach((temporalElement) => {
@@ -95,11 +76,9 @@ const updateAnimations = (element) => {
95
76
  updateVisualState(temporalElement, temporalState$1);
96
77
  });
97
78
  updateVisualState(element, temporalState);
98
- const animationState = evaluateTemporalStateForAnimation(element);
99
- if (animationState.isVisible) coordinateAnimationsForSingleElement(element);
79
+ if (evaluateTemporalStateForAnimation(element).isVisible) coordinateAnimationsForSingleElement(element);
100
80
  deepGetTemporalElements(element).forEach((temporalElement) => {
101
- const childAnimationState = evaluateTemporalStateForAnimation(temporalElement);
102
- if (childAnimationState.isVisible) coordinateAnimationsForSingleElement(temporalElement);
81
+ if (evaluateTemporalStateForAnimation(temporalElement).isVisible) coordinateAnimationsForSingleElement(temporalElement);
103
82
  });
104
83
  };
105
84
  export { evaluateTemporalStateForAnimation, updateAnimations };