@editframe/elements 0.30.1-beta.0 → 0.30.2-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.
- package/dist/elements/EFAudio.d.ts +2 -2
- package/dist/elements/EFCaptions.d.ts +12 -12
- package/dist/elements/EFImage.d.ts +4 -4
- package/dist/elements/EFMedia.d.ts +2 -2
- package/dist/elements/EFTextSegment.js.map +1 -1
- package/dist/elements/EFTimegroup.js +3 -3
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/dist/elements/EFVideo.d.ts +4 -4
- package/dist/elements/EFWaveform.d.ts +4 -4
- package/dist/elements/updateAnimations.js +348 -108
- package/dist/elements/updateAnimations.js.map +1 -1
- package/dist/gui/EFFilmstrip.d.ts +3 -3
- package/dist/gui/EFPause.d.ts +4 -4
- package/dist/gui/EFPlay.d.ts +4 -4
- package/dist/gui/EFPreview.d.ts +4 -4
- package/dist/gui/EFScrubber.d.ts +4 -4
- package/dist/gui/EFTimeDisplay.d.ts +4 -4
- package/dist/gui/EFToggleLoop.d.ts +4 -4
- package/dist/gui/EFTogglePlay.d.ts +4 -4
- package/dist/gui/EFWorkbench.d.ts +4 -4
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/style.css +0 -4
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { MediaEngine } from "../transcoding/types/index.js";
|
|
|
2
2
|
import { EFMedia } from "./EFMedia.js";
|
|
3
3
|
import * as _lit_task8 from "@lit/task";
|
|
4
4
|
import { Task } from "@lit/task";
|
|
5
|
-
import * as
|
|
5
|
+
import * as lit_html6 from "lit-html";
|
|
6
6
|
import * as lit_html_directives_ref_js1 from "lit-html/directives/ref.js";
|
|
7
7
|
|
|
8
8
|
//#region src/elements/EFAudio.d.ts
|
|
@@ -10,7 +10,7 @@ declare const EFAudio_base: typeof EFMedia;
|
|
|
10
10
|
declare class EFAudio extends EFAudio_base {
|
|
11
11
|
private _propertyHack;
|
|
12
12
|
audioElementRef: lit_html_directives_ref_js1.Ref<HTMLAudioElement>;
|
|
13
|
-
render():
|
|
13
|
+
render(): lit_html6.TemplateResult<1>;
|
|
14
14
|
frameTask: Task<readonly [_lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus], void>;
|
|
15
15
|
/**
|
|
16
16
|
* Legacy getter for fragment index task (maps to audioSegmentIdTask)
|
|
@@ -4,9 +4,9 @@ import { FetchMixinInterface } from "./FetchMixin.js";
|
|
|
4
4
|
import { EFAudio } from "./EFAudio.js";
|
|
5
5
|
import { EFVideo } from "./EFVideo.js";
|
|
6
6
|
import { Task, TaskStatus } from "@lit/task";
|
|
7
|
-
import * as
|
|
7
|
+
import * as lit1 from "lit";
|
|
8
8
|
import { LitElement, PropertyValueMap } from "lit";
|
|
9
|
-
import * as
|
|
9
|
+
import * as lit_html1 from "lit-html";
|
|
10
10
|
|
|
11
11
|
//#region src/elements/EFCaptions.d.ts
|
|
12
12
|
interface WordSegment {
|
|
@@ -25,8 +25,8 @@ interface Caption {
|
|
|
25
25
|
}
|
|
26
26
|
declare const EFCaptionsActiveWord_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
|
|
27
27
|
declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
|
|
28
|
-
static styles:
|
|
29
|
-
render():
|
|
28
|
+
static styles: lit1.CSSResult[];
|
|
29
|
+
render(): lit_html1.TemplateResult<1> | undefined;
|
|
30
30
|
wordStartMs: number;
|
|
31
31
|
wordEndMs: number;
|
|
32
32
|
wordText: string;
|
|
@@ -38,8 +38,8 @@ declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
|
|
|
38
38
|
}
|
|
39
39
|
declare const EFCaptionsSegment_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
|
|
40
40
|
declare class EFCaptionsSegment extends EFCaptionsSegment_base {
|
|
41
|
-
static styles:
|
|
42
|
-
render():
|
|
41
|
+
static styles: lit1.CSSResult[];
|
|
42
|
+
render(): lit_html1.TemplateResult<1> | undefined;
|
|
43
43
|
segmentStartMs: number;
|
|
44
44
|
segmentEndMs: number;
|
|
45
45
|
segmentText: string;
|
|
@@ -49,8 +49,8 @@ declare class EFCaptionsSegment extends EFCaptionsSegment_base {
|
|
|
49
49
|
get durationMs(): number;
|
|
50
50
|
}
|
|
51
51
|
declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
|
|
52
|
-
static styles:
|
|
53
|
-
render():
|
|
52
|
+
static styles: lit1.CSSResult[];
|
|
53
|
+
render(): lit_html1.TemplateResult<1> | undefined;
|
|
54
54
|
hidden: boolean;
|
|
55
55
|
segmentText: string;
|
|
56
56
|
segmentStartMs: number;
|
|
@@ -60,8 +60,8 @@ declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
|
|
|
60
60
|
get durationMs(): number;
|
|
61
61
|
}
|
|
62
62
|
declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
|
|
63
|
-
static styles:
|
|
64
|
-
render():
|
|
63
|
+
static styles: lit1.CSSResult[];
|
|
64
|
+
render(): lit_html1.TemplateResult<1> | undefined;
|
|
65
65
|
hidden: boolean;
|
|
66
66
|
segmentText: string;
|
|
67
67
|
segmentStartMs: number;
|
|
@@ -72,7 +72,7 @@ declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
|
|
|
72
72
|
}
|
|
73
73
|
declare const EFCaptions_base: (new (...args: any[]) => EFSourceMixinInterface) & (new (...args: any[]) => TemporalMixinInterface) & (new (...args: any[]) => FetchMixinInterface) & typeof LitElement;
|
|
74
74
|
declare class EFCaptions extends EFCaptions_base {
|
|
75
|
-
static styles:
|
|
75
|
+
static styles: lit1.CSSResult[];
|
|
76
76
|
targetSelector: string;
|
|
77
77
|
set target(value: string);
|
|
78
78
|
wordStyle: string;
|
|
@@ -95,7 +95,7 @@ declare class EFCaptions extends EFCaptions_base {
|
|
|
95
95
|
segmentContainers: HTMLCollectionOf<EFCaptionsSegment>;
|
|
96
96
|
beforeActiveWordContainers: HTMLCollectionOf<EFCaptionsBeforeActiveWord>;
|
|
97
97
|
afterActiveWordContainers: HTMLCollectionOf<EFCaptionsAfterActiveWord>;
|
|
98
|
-
render():
|
|
98
|
+
render(): lit_html1.TemplateResult<1>;
|
|
99
99
|
transcriptionsPath(): string | null;
|
|
100
100
|
captionsPath(): string | null;
|
|
101
101
|
protected md5SumLoader: Task<readonly [string, typeof fetch], string | null | undefined>;
|
|
@@ -3,21 +3,21 @@ import { EFSourceMixinInterface } from "./EFSourceMixin.js";
|
|
|
3
3
|
import { FetchMixinInterface } from "./FetchMixin.js";
|
|
4
4
|
import * as _lit_task0 from "@lit/task";
|
|
5
5
|
import { Task } from "@lit/task";
|
|
6
|
-
import * as
|
|
6
|
+
import * as lit0 from "lit";
|
|
7
7
|
import { LitElement } from "lit";
|
|
8
|
-
import * as
|
|
8
|
+
import * as lit_html0 from "lit-html";
|
|
9
9
|
import * as lit_html_directives_ref_js0 from "lit-html/directives/ref.js";
|
|
10
10
|
|
|
11
11
|
//#region src/elements/EFImage.d.ts
|
|
12
12
|
declare const EFImage_base: (new (...args: any[]) => TemporalMixinInterface) & (new (...args: any[]) => EFSourceMixinInterface) & (new (...args: any[]) => FetchMixinInterface) & typeof LitElement;
|
|
13
13
|
declare class EFImage extends EFImage_base {
|
|
14
14
|
#private;
|
|
15
|
-
static styles:
|
|
15
|
+
static styles: lit0.CSSResult[];
|
|
16
16
|
imageRef: lit_html_directives_ref_js0.Ref<HTMLImageElement>;
|
|
17
17
|
canvasRef: lit_html_directives_ref_js0.Ref<HTMLCanvasElement>;
|
|
18
18
|
set assetId(value: string | null);
|
|
19
19
|
get assetId(): string | null;
|
|
20
|
-
render():
|
|
20
|
+
render(): lit_html0.TemplateResult<1>;
|
|
21
21
|
private isDirectUrl;
|
|
22
22
|
assetPath(): string;
|
|
23
23
|
get hasOwnDuration(): boolean;
|
|
@@ -9,7 +9,7 @@ import { AudioBufferState } from "./EFMedia/audioTasks/makeAudioBufferTask.js";
|
|
|
9
9
|
import { ControllableInterface } from "../gui/Controllable.js";
|
|
10
10
|
import { UrlGenerator } from "../transcoding/utils/UrlGenerator.js";
|
|
11
11
|
import * as _lit_task0 from "@lit/task";
|
|
12
|
-
import * as
|
|
12
|
+
import * as lit6 from "lit";
|
|
13
13
|
import { LitElement, PropertyValueMap } from "lit";
|
|
14
14
|
import * as mediabunny0 from "mediabunny";
|
|
15
15
|
|
|
@@ -23,7 +23,7 @@ declare class EFMedia extends EFMedia_base {
|
|
|
23
23
|
static readonly VIDEO_SAMPLE_BUFFER_SIZE = 30;
|
|
24
24
|
static readonly AUDIO_SAMPLE_BUFFER_SIZE = 120;
|
|
25
25
|
static get observedAttributes(): string[];
|
|
26
|
-
static styles:
|
|
26
|
+
static styles: lit6.CSSResult[];
|
|
27
27
|
/**
|
|
28
28
|
* Duration in milliseconds for audio buffering ahead of current time
|
|
29
29
|
* @domAttribute "audio-buffer-duration"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EFTextSegment.js","names":["EFTextSegment"],"sources":["../../src/elements/EFTextSegment.ts"],"sourcesContent":["import { css, html, LitElement } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { EFTemporal } from \"./EFTemporal.js\";\nimport type { EFText } from \"./EFText.js\";\n\n@customElement(\"ef-text-segment\")\nexport class EFTextSegment extends EFTemporal(LitElement) {\n static styles = [\n css`\n :host {\n display: inline-block;\n white-space: pre;\n line-height: 1;\n }\n :host([data-line-segment]) {\n display: block;\n white-space: normal;\n }\n :host([hidden]) {\n opacity: 0;\n pointer-events: none;\n }\n `,\n ];\n\n render() {\n // Set deterministic --ef-seed value based on segment index\n const seed = (this.segmentIndex * 9007) % 233; // Prime numbers for better distribution\n const seedValue = seed / 233; // Normalize to 0-1 range\n this.style.setProperty(\"--ef-seed\", seedValue.toString());\n\n // Set stagger offset CSS variable\n // staggerOffsetMs is always set (defaults to 0), so we can always set the CSS variable\n const offsetMs = this.staggerOffsetMs ?? 0;\n this.style.setProperty(\"--ef-stagger-offset\", `${offsetMs}ms`);\n\n // Set index CSS variable\n this.style.setProperty(\"--ef-index\", this.segmentIndex.toString());\n\n return html`${this.segmentText}`;\n }\n\n private _animationsPaused = false;\n\n connectedCallback() {\n super.connectedCallback();\n // CRITICAL: Pause all animations once when segment is first connected\n // CSS
|
|
1
|
+
{"version":3,"file":"EFTextSegment.js","names":["EFTextSegment"],"sources":["../../src/elements/EFTextSegment.ts"],"sourcesContent":["import { css, html, LitElement } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { EFTemporal } from \"./EFTemporal.js\";\nimport type { EFText } from \"./EFText.js\";\n\n@customElement(\"ef-text-segment\")\nexport class EFTextSegment extends EFTemporal(LitElement) {\n static styles = [\n css`\n :host {\n display: inline-block;\n white-space: pre;\n line-height: 1;\n }\n :host([data-line-segment]) {\n display: block;\n white-space: normal;\n }\n :host([hidden]) {\n opacity: 0;\n pointer-events: none;\n }\n `,\n ];\n\n render() {\n // Set deterministic --ef-seed value based on segment index\n const seed = (this.segmentIndex * 9007) % 233; // Prime numbers for better distribution\n const seedValue = seed / 233; // Normalize to 0-1 range\n this.style.setProperty(\"--ef-seed\", seedValue.toString());\n\n // Set stagger offset CSS variable\n // staggerOffsetMs is always set (defaults to 0), so we can always set the CSS variable\n const offsetMs = this.staggerOffsetMs ?? 0;\n this.style.setProperty(\"--ef-stagger-offset\", `${offsetMs}ms`);\n\n // Set index CSS variable\n this.style.setProperty(\"--ef-index\", this.segmentIndex.toString());\n\n return html`${this.segmentText}`;\n }\n\n private _animationsPaused = false;\n\n connectedCallback() {\n super.connectedCallback();\n // CRITICAL: Pause all animations once when segment is first connected\n // Animations (both CSS and WAAPI) start automatically and must be paused so updateAnimations can control them\n // Only do this once on initial load\n if (!this._animationsPaused) {\n // Wait for segment to be fully updated before pausing animations\n this.updateComplete.then(() => {\n requestAnimationFrame(() => {\n const animations = this.getAnimations();\n for (const animation of animations) {\n // Ensure animation is in a playable state\n // If it's finished, reset it\n if (animation.playState === \"finished\") {\n animation.cancel();\n animation.play();\n animation.pause();\n } else if (animation.playState === \"running\") {\n // Pause if running, preserving current visual state\n animation.pause();\n }\n // Don't reset currentTime here - let updateAnimations set it based on timeline\n // This preserves any visual state that was already applied\n }\n this._animationsPaused = true;\n // Note: updateAnimations is called from parent EFText after all segments are created\n // This avoids calling it multiple times (once per segment)\n });\n });\n }\n }\n\n @property({ type: String, attribute: false })\n segmentText = \"\";\n\n @property({ type: Number, attribute: false })\n segmentIndex = 0;\n\n @property({ type: Number, attribute: false })\n staggerOffsetMs?: number;\n\n @property({ type: Number, attribute: false })\n segmentStartMs = 0;\n\n @property({ type: Number, attribute: false })\n segmentEndMs = 0;\n\n @property({ type: Boolean, reflect: true })\n hidden = false;\n\n get startTimeMs() {\n // Get parent text element's absolute start time, then add our local offset\n const parentText = this.closest(\"ef-text\") as EFText;\n const parentStartTime = parentText?.startTimeMs || 0;\n return parentStartTime + (this.segmentStartMs || 0);\n }\n\n get endTimeMs() {\n const parentText = this.closest(\"ef-text\") as EFText;\n const parentStartTime = parentText?.startTimeMs || 0;\n return parentStartTime + (this.segmentEndMs || 0);\n }\n\n get durationMs(): number {\n return this.segmentEndMs - this.segmentStartMs;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-text-segment\": EFTextSegment;\n }\n}\n"],"mappings":";;;;;;AAMO,0BAAMA,wBAAsB,WAAW,WAAW,CAAC;;;2BAoC5B;qBAmCd;sBAGC;wBAME;sBAGF;gBAGN;;;gBArFO,CACd,GAAG;;;;;;;;;;;;;;MAeJ;;CAED,SAAS;EAGP,MAAM,YADQ,KAAK,eAAe,OAAQ,MACjB;AACzB,OAAK,MAAM,YAAY,aAAa,UAAU,UAAU,CAAC;EAIzD,MAAM,WAAW,KAAK,mBAAmB;AACzC,OAAK,MAAM,YAAY,uBAAuB,GAAG,SAAS,IAAI;AAG9D,OAAK,MAAM,YAAY,cAAc,KAAK,aAAa,UAAU,CAAC;AAElE,SAAO,IAAI,GAAG,KAAK;;CAKrB,oBAAoB;AAClB,QAAM,mBAAmB;AAIzB,MAAI,CAAC,KAAK,kBAER,MAAK,eAAe,WAAW;AAC7B,+BAA4B;IAC1B,MAAM,aAAa,KAAK,eAAe;AACvC,SAAK,MAAM,aAAa,WAGtB,KAAI,UAAU,cAAc,YAAY;AACtC,eAAU,QAAQ;AAClB,eAAU,MAAM;AAChB,eAAU,OAAO;eACR,UAAU,cAAc,UAEjC,WAAU,OAAO;AAKrB,SAAK,oBAAoB;KAGzB;IACF;;CAsBN,IAAI,cAAc;AAIhB,UAFmB,KAAK,QAAQ,UAAU,EACN,eAAe,MACzB,KAAK,kBAAkB;;CAGnD,IAAI,YAAY;AAGd,UAFmB,KAAK,QAAQ,UAAU,EACN,eAAe,MACzB,KAAK,gBAAgB;;CAGjD,IAAI,aAAqB;AACvB,SAAO,KAAK,eAAe,KAAK;;;YAhCjC,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAO,CAAC;YAG5C,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAO,CAAC;YAG5C,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAO,CAAC;YAG5C,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAO,CAAC;YAG5C,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAO,CAAC;YAG5C,SAAS;CAAE,MAAM;CAAS,SAAS;CAAM,CAAC;4BAtF5C,cAAc,kBAAkB"}
|
|
@@ -11,7 +11,7 @@ import { renderTemporalAudio } from "./renderTemporalAudio.js";
|
|
|
11
11
|
import { EFTargetable } from "./TargetController.js";
|
|
12
12
|
import { deepGetMediaElements } from "./EFMedia.js";
|
|
13
13
|
import { TimegroupController } from "./TimegroupController.js";
|
|
14
|
-
import {
|
|
14
|
+
import { evaluateAnimationVisibilityState, updateAnimations } from "./updateAnimations.js";
|
|
15
15
|
import { provide } from "@lit/context";
|
|
16
16
|
import { Task, TaskStatus } from "@lit/task";
|
|
17
17
|
import debug from "debug";
|
|
@@ -205,7 +205,7 @@ let EFTimegroup = class EFTimegroup$1 extends EFTargetable(EFTemporal(TWMixin(Li
|
|
|
205
205
|
if (this.playbackController) this.saveTimeToLocalStorage(this.currentTime);
|
|
206
206
|
await this.frameTask.taskComplete;
|
|
207
207
|
const visibleElements = deepGetElementsWithFrameTasks(this).filter((element) => {
|
|
208
|
-
return
|
|
208
|
+
return evaluateAnimationVisibilityState(element).isVisible;
|
|
209
209
|
});
|
|
210
210
|
await Promise.all(visibleElements.map(async (element) => {
|
|
211
211
|
if ("waitForFrameReady" in element && typeof element.waitForFrameReady === "function") await element.waitForFrameReady();
|
|
@@ -376,7 +376,7 @@ let EFTimegroup = class EFTimegroup$1 extends EFTargetable(EFTemporal(TWMixin(Li
|
|
|
376
376
|
const temporalElements = deepGetElementsWithFrameTasks(this);
|
|
377
377
|
if (isTracingEnabled()) span.setAttribute("temporalElementsCount", temporalElements.length);
|
|
378
378
|
const visibleElements = temporalElements.filter((element) => {
|
|
379
|
-
return
|
|
379
|
+
return evaluateAnimationVisibilityState(element).isVisible;
|
|
380
380
|
});
|
|
381
381
|
if (isTracingEnabled()) span.setAttribute("visibleElementsCount", visibleElements.length);
|
|
382
382
|
const promiseStart = performance.now();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EFTimegroup.js","names":["sequenceDurationCache: WeakMap<EFTimegroup, number>","EFTimegroup","#executeCustomFrameTasks","#pendingSeekTime","#currentTime","#seekInProgress","#processingPendingSeek","#customFrameTasks","#handleSlotChange","#previousDurationMs","#resizeObserver","#waitForMediaDurations","loaderTasks: Promise<any>[]"],"sources":["../../src/elements/EFTimegroup.ts"],"sourcesContent":["import { provide } from \"@lit/context\";\nimport { Task, TaskStatus } from \"@lit/task\";\nimport debug from \"debug\";\nimport { css, html, LitElement, type PropertyValues } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\n\nimport { EF_INTERACTIVE } from \"../EF_INTERACTIVE.js\";\nimport { EF_RENDERING } from \"../EF_RENDERING.js\";\nimport { isContextMixin } from \"../gui/ContextMixin.js\";\nimport { efContext } from \"../gui/efContext.js\";\nimport { TWMixin } from \"../gui/TWMixin.js\";\nimport { isTracingEnabled, withSpan } from \"../otel/tracingHelpers.js\";\nimport { deepGetMediaElements, type EFMedia } from \"./EFMedia.js\";\nimport {\n deepGetElementsWithFrameTasks,\n EFTemporal,\n flushStartTimeMsCache,\n resetTemporalCache,\n shallowGetTemporalElements,\n timegroupContext,\n} from \"./EFTemporal.js\";\nimport { parseTimeToMs } from \"./parseTimeToMs.js\";\nimport { renderTemporalAudio } from \"./renderTemporalAudio.js\";\nimport { EFTargetable } from \"./TargetController.js\";\nimport { TimegroupController } from \"./TimegroupController.js\";\nimport {\n evaluateTemporalStateForAnimation,\n updateAnimations,\n} from \"./updateAnimations.ts\";\n\ndeclare global {\n var EF_DEV_WORKBENCH: boolean | undefined;\n}\n\nconst log = debug(\"ef:elements:EFTimegroup\");\n\n// Custom frame task callback type\nexport type FrameTaskCallback = (info: {\n ownCurrentTimeMs: number;\n currentTimeMs: number;\n durationMs: number;\n percentComplete: number;\n element: EFTimegroup;\n}) => void | Promise<void>;\n\n// Cache for sequence mode duration calculations to avoid O(n) recalculation\nlet sequenceDurationCache: WeakMap<EFTimegroup, number> = new WeakMap();\n\nexport const flushSequenceDurationCache = () => {\n sequenceDurationCache = new WeakMap();\n};\n\nexport const shallowGetTimegroups = (\n element: Element,\n groups: EFTimegroup[] = [],\n) => {\n for (const child of Array.from(element.children)) {\n if (child instanceof EFTimegroup) {\n groups.push(child);\n } else {\n shallowGetTimegroups(child, groups);\n }\n }\n return groups;\n};\n\n@customElement(\"ef-timegroup\")\nexport class EFTimegroup extends EFTargetable(EFTemporal(TWMixin(LitElement))) {\n static get observedAttributes(): string[] {\n // biome-ignore lint/complexity/noThisInStatic: It's okay to use this here\n const parentAttributes = super.observedAttributes || [];\n return [\n ...parentAttributes,\n \"mode\",\n \"overlap\",\n \"currenttime\",\n \"fit\",\n \"fps\",\n ];\n }\n\n static styles = css`\n :host {\n display: block;\n position: relative;\n overflow: hidden;\n }\n\n ::slotted(ef-timegroup) {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n overflow: initial;\n }\n `;\n\n @provide({ context: timegroupContext })\n _timeGroupContext = this;\n\n @provide({ context: efContext })\n efContext = this;\n\n mode: \"fit\" | \"fixed\" | \"sequence\" | \"contain\" = \"contain\";\n overlapMs = 0;\n\n @property({ type: Number })\n fps = 30;\n\n attributeChangedCallback(\n name: string,\n old: string | null,\n value: string | null,\n ): void {\n if (name === \"mode\" && value) {\n this.mode = value as typeof this.mode;\n }\n if (name === \"overlap\" && value) {\n this.overlapMs = parseTimeToMs(value);\n }\n if (name === \"fps\" && value) {\n this.fps = Number.parseFloat(value);\n }\n super.attributeChangedCallback(name, old, value);\n }\n\n @property({ type: String })\n fit: \"none\" | \"contain\" | \"cover\" = \"none\";\n\n #resizeObserver?: ResizeObserver;\n\n #currentTime: number | undefined = undefined;\n #seekInProgress = false;\n #pendingSeekTime: number | undefined;\n #processingPendingSeek = false;\n #customFrameTasks: Set<FrameTaskCallback> = new Set();\n\n /**\n * Get the effective FPS for this timegroup.\n * During rendering, uses the render options FPS if available.\n * Otherwise uses the configured fps property.\n */\n get effectiveFps(): number {\n // During rendering, prefer the render options FPS\n if (typeof window !== \"undefined\" && window.EF_FRAMEGEN?.renderOptions) {\n return window.EF_FRAMEGEN.renderOptions.encoderOptions.video.framerate;\n }\n return this.fps;\n }\n\n /**\n * Quantize a time value to the nearest frame boundary based on effectiveFps.\n * @param timeSeconds - Time in seconds\n * @returns Time quantized to frame boundaries in seconds\n */\n private quantizeToFrameTime(timeSeconds: number): number {\n const fps = this.effectiveFps;\n if (!fps || fps <= 0) return timeSeconds;\n const frameDurationS = 1 / fps;\n return Math.round(timeSeconds / frameDurationS) * frameDurationS;\n }\n\n private async runThrottledFrameTask(): Promise<void> {\n if (this.playbackController) {\n return this.playbackController.runThrottledFrameTask();\n }\n await this.frameTask.run();\n }\n\n @property({ type: Number, attribute: \"currenttime\" })\n set currentTime(time: number) {\n // Quantize time to frame boundaries based on fps\n // Do this BEFORE delegating to playbackController to ensure consistency\n time = this.quantizeToFrameTime(time);\n\n if (this.playbackController) {\n this.playbackController.currentTime = time;\n return;\n }\n\n time = Math.max(0, Math.min(this.durationMs / 1000, time));\n if (!this.isRootTimegroup) {\n return;\n }\n if (Number.isNaN(time)) {\n return;\n }\n if (time === this.#currentTime && !this.#processingPendingSeek) {\n return;\n }\n if (this.#pendingSeekTime === time) {\n return;\n }\n\n if (this.#seekInProgress) {\n this.#pendingSeekTime = time;\n this.#currentTime = time;\n return;\n }\n\n this.#currentTime = time;\n this.#seekInProgress = true;\n\n this.seekTask.run().finally(() => {\n if (\n this.#pendingSeekTime !== undefined &&\n this.#pendingSeekTime !== time\n ) {\n const pendingTime = this.#pendingSeekTime;\n this.#pendingSeekTime = undefined;\n this.#processingPendingSeek = true;\n try {\n this.currentTime = pendingTime;\n } finally {\n this.#processingPendingSeek = false;\n }\n } else {\n this.#pendingSeekTime = undefined;\n }\n });\n }\n\n get currentTime() {\n if (this.playbackController) {\n return this.playbackController.currentTime;\n }\n return this.#currentTime ?? 0;\n }\n\n set currentTimeMs(ms: number) {\n this.currentTime = ms / 1000;\n }\n\n get currentTimeMs() {\n return this.currentTime * 1000;\n }\n\n /**\n * Seek to a specific time and wait for all frames to be ready.\n * This is the recommended way to seek in tests and programmatic control.\n *\n * @param timeMs - Time in milliseconds to seek to\n * @returns Promise that resolves when the seek is complete and all visible children are ready\n */\n async seek(timeMs: number): Promise<void> {\n this.currentTimeMs = timeMs;\n await this.seekTask.taskComplete;\n\n // Handle localStorage when playbackController delegates seek\n if (this.playbackController) {\n this.saveTimeToLocalStorage(this.currentTime);\n }\n\n await this.frameTask.taskComplete;\n\n // Ensure all visible elements have completed their reactive update cycles AND frame rendering\n // waitForFrameTasks() calls frameTask.run() on children, but this may happen before child\n // elements have processed property changes from requestUpdate(). To ensure frame data is\n // accurate, we wait for updateComplete first, then ensure the frameTask has run with the\n // updated properties. Elements like EFVideo provide waitForFrameReady() for this pattern.\n const temporalElements = deepGetElementsWithFrameTasks(this);\n const visibleElements = temporalElements.filter((element) => {\n const animationState = evaluateTemporalStateForAnimation(element);\n return animationState.isVisible;\n });\n\n await Promise.all(\n visibleElements.map(async (element) => {\n if (\n \"waitForFrameReady\" in element &&\n typeof element.waitForFrameReady === \"function\"\n ) {\n await (element as any).waitForFrameReady();\n } else {\n await element.updateComplete;\n }\n }),\n );\n }\n\n /**\n * Determines if this is a root timegroup (no parent timegroups)\n */\n get isRootTimegroup(): boolean {\n return !this.parentTimegroup;\n }\n\n /**\n * Register a custom frame task callback that will be executed during frame rendering.\n * The callback receives timing information and can be async or sync.\n * Multiple callbacks can be registered and will execute in parallel.\n *\n * @param callback - Function to execute on each frame\n * @returns A cleanup function that removes the callback when called\n */\n addFrameTask(callback: FrameTaskCallback): () => void {\n if (typeof callback !== \"function\") {\n throw new Error(\"Frame task callback must be a function\");\n }\n this.#customFrameTasks.add(callback);\n return () => {\n this.#customFrameTasks.delete(callback);\n };\n }\n\n /**\n * Remove a previously registered custom frame task callback.\n *\n * @param callback - The callback function to remove\n */\n removeFrameTask(callback: FrameTaskCallback): void {\n this.#customFrameTasks.delete(callback);\n }\n\n saveTimeToLocalStorage(time: number) {\n try {\n if (this.id && this.isConnected && !Number.isNaN(time)) {\n localStorage.setItem(this.storageKey, time.toString());\n }\n } catch (error) {\n log(\"Failed to save time to localStorage\", error);\n }\n }\n\n render() {\n return html`<slot @slotchange=${this.#handleSlotChange}></slot> `;\n }\n\n #handleSlotChange = () => {\n // Invalidate caches when slot content changes\n resetTemporalCache();\n flushSequenceDurationCache();\n flushStartTimeMsCache();\n\n // Request update to trigger recalculation of dependent properties\n this.requestUpdate();\n };\n\n loadTimeFromLocalStorage(): number | undefined {\n if (this.id) {\n try {\n const storedValue = localStorage.getItem(this.storageKey);\n if (storedValue === null) {\n return undefined;\n }\n return Number.parseFloat(storedValue);\n } catch (error) {\n log(\"Failed to load time from localStorage\", error);\n }\n }\n return undefined;\n }\n\n connectedCallback() {\n super.connectedCallback();\n\n if (!this.playbackController) {\n this.waitForMediaDurations().then(async () => {\n let didLoadFromStorage = false;\n if (this.id) {\n const maybeLoadedTime = this.loadTimeFromLocalStorage();\n if (maybeLoadedTime !== undefined) {\n this.currentTime = maybeLoadedTime;\n didLoadFromStorage = true;\n }\n }\n if (EF_INTERACTIVE && this.seekTask.status === TaskStatus.INITIAL) {\n this.seekTask.run();\n } else if (didLoadFromStorage) {\n await this.seekTask.run();\n }\n });\n }\n\n if (this.parentTimegroup) {\n new TimegroupController(this.parentTimegroup, this);\n }\n\n if (this.shouldWrapWithWorkbench()) {\n this.wrapWithWorkbench();\n }\n }\n\n #previousDurationMs = 0;\n\n protected updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n\n if (changedProperties.has(\"mode\") || changedProperties.has(\"overlapMs\")) {\n sequenceDurationCache.delete(this);\n }\n\n if (this.#previousDurationMs !== this.durationMs) {\n this.#previousDurationMs = this.durationMs;\n this.runThrottledFrameTask();\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.#resizeObserver?.disconnect();\n }\n\n get storageKey() {\n if (!this.id) {\n throw new Error(\"Timegroup must have an id to use localStorage.\");\n }\n return `ef-timegroup-${this.id}`;\n }\n\n get intrinsicDurationMs() {\n if (this.hasExplicitDuration) {\n return this.explicitDurationMs;\n }\n return undefined;\n }\n\n get hasOwnDuration() {\n return (\n this.mode === \"contain\" ||\n this.mode === \"sequence\" ||\n (this.mode === \"fixed\" && this.hasExplicitDuration)\n );\n }\n\n get durationMs(): number {\n switch (this.mode) {\n case \"fit\": {\n if (!this.parentTimegroup) {\n return 0;\n }\n return this.parentTimegroup.durationMs;\n }\n case \"fixed\":\n return super.durationMs;\n case \"sequence\": {\n // Check cache first to avoid expensive O(n) recalculation\n const cachedDuration = sequenceDurationCache.get(this);\n if (cachedDuration !== undefined) {\n return cachedDuration;\n }\n\n let duration = 0;\n this.childTemporals.forEach((child, index) => {\n if (child instanceof EFTimegroup && child.mode === \"fit\") {\n return;\n }\n if (index > 0) {\n duration -= this.overlapMs;\n }\n duration += child.durationMs;\n });\n\n // Cache the calculated duration\n sequenceDurationCache.set(this, duration);\n return duration;\n }\n case \"contain\": {\n let maxDuration = 0;\n for (const child of this.childTemporals) {\n // fit timegroups look \"up\" to their parent timegroup for their duration\n // so we need to skip them to avoid an infinite loop\n if (child instanceof EFTimegroup && child.mode === \"fit\") {\n continue;\n }\n if (!child.hasOwnDuration) {\n continue;\n }\n maxDuration = Math.max(maxDuration, child.durationMs);\n }\n return maxDuration;\n }\n default:\n throw new Error(`Invalid time mode: ${this.mode}`);\n }\n }\n\n async getPendingFrameTasks(signal?: AbortSignal) {\n await this.waitForNestedUpdates(signal);\n signal?.throwIfAborted();\n const temporals = deepGetElementsWithFrameTasks(this);\n\n // Filter to only include temporally visible elements for frame processing\n // (but keep all elements for duration calculations)\n // Use the target timeline time if we're in the middle of seeking\n const timelineTimeMs =\n (this.#pendingSeekTime ?? this.#currentTime ?? 0) * 1000;\n const activeTemporals = temporals.filter((temporal) => {\n // Skip timeline filtering if temporal doesn't have timeline position info\n if (!(\"startTimeMs\" in temporal) || !(\"endTimeMs\" in temporal)) {\n return true; // Keep non-temporal elements\n }\n\n // Only process frame tasks for elements that overlap the current timeline\n // Use same epsilon logic as seek task for consistency\n const epsilon = 0.001; // 1µs offset to break ties at boundaries\n const startTimeMs = (temporal as any).startTimeMs as number;\n const endTimeMs = (temporal as any).endTimeMs as number;\n const elementStartsBeforeEnd = startTimeMs <= timelineTimeMs + epsilon;\n // Root timegroups should remain visible at exact end time, but other elements use exclusive end for clean transitions\n const isRootTimegroup =\n temporal.tagName.toLowerCase() === \"ef-timegroup\" &&\n !(temporal as any).parentTimegroup;\n const useInclusiveEnd = isRootTimegroup;\n const elementEndsAfterStart = useInclusiveEnd\n ? endTimeMs >= timelineTimeMs\n : endTimeMs > timelineTimeMs;\n return elementStartsBeforeEnd && elementEndsAfterStart;\n });\n\n const frameTasks = activeTemporals.map((temporal) => temporal.frameTask);\n frameTasks.forEach((task) => {\n task.run();\n });\n\n return frameTasks.filter((task) => task.status < TaskStatus.COMPLETE);\n }\n\n async waitForNestedUpdates(signal?: AbortSignal) {\n const limit = 10;\n let steps = 0;\n let isComplete = true;\n while (true) {\n steps++;\n if (steps > limit) {\n throw new Error(\"Reached update depth limit.\");\n }\n isComplete = await this.updateComplete;\n signal?.throwIfAborted();\n if (isComplete) {\n break;\n }\n }\n }\n\n async waitForFrameTasks() {\n const result = await withSpan(\n \"timegroup.waitForFrameTasks\",\n {\n timegroupId: this.id || \"unknown\",\n mode: this.mode,\n },\n undefined,\n async (span) => {\n const innerStart = performance.now();\n\n const temporalElements = deepGetElementsWithFrameTasks(this);\n if (isTracingEnabled()) {\n span.setAttribute(\"temporalElementsCount\", temporalElements.length);\n }\n\n // Filter to only include temporally visible elements for frame processing\n // Use animation-friendly visibility to prevent animation jumps at exact boundaries\n const visibleElements = temporalElements.filter((element) => {\n const animationState = evaluateTemporalStateForAnimation(element);\n return animationState.isVisible;\n });\n if (isTracingEnabled()) {\n span.setAttribute(\"visibleElementsCount\", visibleElements.length);\n }\n\n const promiseStart = performance.now();\n\n await Promise.all(\n visibleElements.map((element) => element.frameTask.run()),\n );\n const promiseEnd = performance.now();\n\n const innerEnd = performance.now();\n if (isTracingEnabled()) {\n span.setAttribute(\"actualInnerMs\", innerEnd - innerStart);\n span.setAttribute(\"promiseAwaitMs\", promiseEnd - promiseStart);\n }\n },\n );\n\n return result;\n }\n\n mediaDurationsPromise: Promise<void> | undefined = undefined;\n\n async waitForMediaDurations() {\n if (!this.mediaDurationsPromise) {\n this.mediaDurationsPromise = this.#waitForMediaDurations();\n }\n return this.mediaDurationsPromise;\n }\n\n /**\n * Wait for all media elements to load their initial segments.\n * Ideally we would only need the extracted index json data, but\n * that caused issues with constructing audio data. We had negative durations\n * in calculations and it was not clear why.\n */\n async #waitForMediaDurations() {\n return withSpan(\n \"timegroup.waitForMediaDurations\",\n {\n timegroupId: this.id || \"unknown\",\n mode: this.mode,\n },\n undefined,\n async (span) => {\n // We must await updateComplete to ensure all media elements inside this are connected\n // and will match deepGetMediaElements\n await this.updateComplete;\n const mediaElements = deepGetMediaElements(this);\n if (isTracingEnabled()) {\n span.setAttribute(\"mediaElementsCount\", mediaElements.length);\n }\n\n // Then, we must await the fragmentIndexTask to ensure all media elements have their\n // fragment index loaded, which is where their duration is parsed from.\n await Promise.all(\n mediaElements.map((m) =>\n m.mediaEngineTask.value\n ? Promise.resolve()\n : m.mediaEngineTask.run(),\n ),\n );\n\n // After waiting for durations, we must force some updates to cascade and ensure all temporal elements\n // have correct durations and start times. It is not ideal that we have to do this inside here,\n // but it is the best current way to ensure that all temporal elements have correct durations and start times.\n\n // Next, we must flush the startTimeMs cache to ensure all media elements have their\n // startTimeMs parsed fresh, otherwise the startTimeMs is cached per animation frame.\n flushStartTimeMsCache();\n\n // Flush duration cache since child durations may have changed\n flushSequenceDurationCache();\n\n // Request an update to the currentTime of this group, ensuring that time updates will cascade\n // down to children, forcing sequence groups to arrange correctly.\n // This also makes the filmstrip update correctly.\n this.requestUpdate(\"currentTime\");\n // Finally, we must await updateComplete to ensure all temporal elements have their\n // currentTime updated and all animations have run.\n\n await this.updateComplete;\n },\n );\n }\n\n get childTemporals() {\n return shallowGetTemporalElements(this);\n }\n\n get contextProvider() {\n let parent = this.parentNode;\n while (parent) {\n if (isContextMixin(parent)) {\n return parent;\n }\n parent = parent.parentNode;\n }\n return null;\n }\n\n /**\n * Returns true if the timegroup should be wrapped with a workbench.\n *\n * A timegroup should be wrapped with a workbench if:\n * - It's being rendered (EF_RENDERING), OR\n * - It's in interactive mode (EF_INTERACTIVE) with the dev workbench flag set\n *\n * If the timegroup is already wrapped in a context provider like ef-preview,\n * it should NOT be wrapped in a workbench.\n */\n shouldWrapWithWorkbench() {\n const isRendering = EF_RENDERING?.() === true;\n\n // During rendering, always wrap with workbench (needed by EF_FRAMEGEN)\n if (isRendering) {\n return (\n this.closest(\"ef-timegroup\") === this &&\n this.closest(\"ef-preview\") === null &&\n this.closest(\"ef-workbench\") === null &&\n this.closest(\"test-context\") === null\n );\n }\n\n // During interactive mode, respect the dev workbench flag\n if (!globalThis.EF_DEV_WORKBENCH) {\n return false;\n }\n\n return (\n EF_INTERACTIVE &&\n this.closest(\"ef-timegroup\") === this &&\n this.closest(\"ef-preview\") === null &&\n this.closest(\"ef-workbench\") === null &&\n this.closest(\"test-context\") === null\n );\n }\n\n wrapWithWorkbench() {\n const workbench = document.createElement(\"ef-workbench\");\n this.parentElement?.append(workbench);\n if (!this.hasAttribute(\"id\")) {\n this.setAttribute(\"id\", \"root-this\");\n }\n this.setAttribute(\"slot\", \"canvas\");\n workbench.append(this as unknown as Element);\n\n const filmstrip = document.createElement(\"ef-filmstrip\");\n filmstrip.setAttribute(\"slot\", \"timeline\");\n filmstrip.setAttribute(\"target\", this.id);\n workbench.append(filmstrip);\n }\n\n get efElements() {\n return Array.from(\n this.querySelectorAll(\n \"ef-audio, ef-video, ef-image, ef-captions, ef-waveform\",\n ),\n );\n }\n\n /**\n * Returns media elements for playback audio rendering\n * For standalone media, returns [this]; for timegroups, returns all descendants\n * Used by PlaybackController for audio-driven playback\n */\n getMediaElements(): EFMedia[] {\n return deepGetMediaElements(this);\n }\n\n /**\n * Render audio buffer for playback\n * Called by PlaybackController during live playback\n * Delegates to shared renderTemporalAudio utility for consistent behavior\n */\n async renderAudio(fromMs: number, toMs: number): Promise<AudioBuffer> {\n return renderTemporalAudio(this, fromMs, toMs);\n }\n\n /**\n * TEMPORARY TEST METHOD: Renders audio and immediately plays it back\n * Usage: timegroup.testPlayAudio(0, 5000) // Play first 5 seconds\n */\n async testPlayAudio(fromMs: number, toMs: number) {\n // Render the audio using the existing renderAudio method\n const renderedBuffer = await this.renderAudio(fromMs, toMs);\n\n // Create a regular AudioContext for playback\n const playbackContext = new AudioContext();\n\n // Create a buffer source and connect it\n const bufferSource = playbackContext.createBufferSource();\n bufferSource.buffer = renderedBuffer;\n bufferSource.connect(playbackContext.destination);\n\n // Start playback immediately\n bufferSource.start(0);\n\n // Return a promise that resolves when playback ends\n return new Promise<void>((resolve) => {\n bufferSource.onended = () => {\n playbackContext.close();\n resolve();\n };\n });\n }\n\n async loadMd5Sums() {\n const efElements = this.efElements;\n const loaderTasks: Promise<any>[] = [];\n for (const el of efElements) {\n const md5SumLoader = (el as any).md5SumLoader;\n if (md5SumLoader instanceof Task) {\n md5SumLoader.run();\n loaderTasks.push(md5SumLoader.taskComplete);\n }\n }\n\n await Promise.all(loaderTasks);\n\n efElements.forEach((el) => {\n if (\"productionSrc\" in el && el.productionSrc instanceof Function) {\n el.setAttribute(\"src\", el.productionSrc());\n }\n });\n }\n\n frameTask = new Task(this, {\n // autoRun: EF_INTERACTIVE,\n autoRun: false,\n args: () => [this.ownCurrentTimeMs, this.currentTimeMs] as const,\n task: async ([ownCurrentTimeMs, currentTimeMs]) => {\n if (this.isRootTimegroup) {\n await withSpan(\n \"timegroup.frameTask\",\n {\n timegroupId: this.id || \"unknown\",\n ownCurrentTimeMs,\n currentTimeMs,\n },\n undefined,\n async () => {\n await this.waitForFrameTasks();\n await this.#executeCustomFrameTasks();\n updateAnimations(this);\n },\n );\n } else {\n // Non-root timegroups execute their custom frame tasks when called\n await this.#executeCustomFrameTasks();\n }\n },\n });\n\n async #executeCustomFrameTasks() {\n if (this.#customFrameTasks.size > 0) {\n const percentComplete =\n this.durationMs > 0 ? this.ownCurrentTimeMs / this.durationMs : 0;\n const frameInfo = {\n ownCurrentTimeMs: this.ownCurrentTimeMs,\n currentTimeMs: this.currentTimeMs,\n durationMs: this.durationMs,\n percentComplete,\n element: this,\n };\n\n await Promise.all(\n Array.from(this.#customFrameTasks).map((callback) =>\n Promise.resolve(callback(frameInfo)),\n ),\n );\n }\n }\n\n seekTask = new Task(this, {\n autoRun: false,\n args: () => [this.#pendingSeekTime ?? this.#currentTime] as const,\n onComplete: () => {},\n task: async ([targetTime]) => {\n if (this.playbackController) {\n await this.playbackController.seekTask.taskComplete;\n return this.currentTime;\n }\n\n if (!this.isRootTimegroup) {\n return;\n }\n return withSpan(\n \"timegroup.seekTask\",\n {\n timegroupId: this.id || \"unknown\",\n targetTime: targetTime ?? 0,\n durationMs: this.durationMs,\n },\n undefined,\n async (span) => {\n await this.waitForMediaDurations();\n const newTime = Math.max(\n 0,\n Math.min(targetTime ?? 0, this.durationMs / 1000),\n );\n if (isTracingEnabled()) {\n span.setAttribute(\"newTime\", newTime);\n }\n // Apply the clamped time back to currentTime\n\n this.#currentTime = newTime;\n this.requestUpdate(\"currentTime\");\n await this.runThrottledFrameTask();\n this.saveTimeToLocalStorage(this.#currentTime);\n this.#seekInProgress = false;\n return newTime;\n },\n );\n },\n });\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-timegroup\": EFTimegroup & Element;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EFTimegroup.js","names":["sequenceDurationCache: WeakMap<EFTimegroup, number>","EFTimegroup","#executeCustomFrameTasks","#pendingSeekTime","#currentTime","#seekInProgress","#processingPendingSeek","#customFrameTasks","#handleSlotChange","#previousDurationMs","#resizeObserver","#waitForMediaDurations","loaderTasks: Promise<any>[]"],"sources":["../../src/elements/EFTimegroup.ts"],"sourcesContent":["import { provide } from \"@lit/context\";\nimport { Task, TaskStatus } from \"@lit/task\";\nimport debug from \"debug\";\nimport { css, html, LitElement, type PropertyValues } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\n\nimport { EF_INTERACTIVE } from \"../EF_INTERACTIVE.js\";\nimport { EF_RENDERING } from \"../EF_RENDERING.js\";\nimport { isContextMixin } from \"../gui/ContextMixin.js\";\nimport { efContext } from \"../gui/efContext.js\";\nimport { TWMixin } from \"../gui/TWMixin.js\";\nimport { isTracingEnabled, withSpan } from \"../otel/tracingHelpers.js\";\nimport { deepGetMediaElements, type EFMedia } from \"./EFMedia.js\";\nimport {\n deepGetElementsWithFrameTasks,\n EFTemporal,\n flushStartTimeMsCache,\n resetTemporalCache,\n shallowGetTemporalElements,\n timegroupContext,\n} from \"./EFTemporal.js\";\nimport { parseTimeToMs } from \"./parseTimeToMs.js\";\nimport { renderTemporalAudio } from \"./renderTemporalAudio.js\";\nimport { EFTargetable } from \"./TargetController.js\";\nimport { TimegroupController } from \"./TimegroupController.js\";\nimport {\n evaluateAnimationVisibilityState,\n updateAnimations,\n} from \"./updateAnimations.ts\";\n\ndeclare global {\n var EF_DEV_WORKBENCH: boolean | undefined;\n}\n\nconst log = debug(\"ef:elements:EFTimegroup\");\n\n// Custom frame task callback type\nexport type FrameTaskCallback = (info: {\n ownCurrentTimeMs: number;\n currentTimeMs: number;\n durationMs: number;\n percentComplete: number;\n element: EFTimegroup;\n}) => void | Promise<void>;\n\n// Cache for sequence mode duration calculations to avoid O(n) recalculation\nlet sequenceDurationCache: WeakMap<EFTimegroup, number> = new WeakMap();\n\nexport const flushSequenceDurationCache = () => {\n sequenceDurationCache = new WeakMap();\n};\n\nexport const shallowGetTimegroups = (\n element: Element,\n groups: EFTimegroup[] = [],\n) => {\n for (const child of Array.from(element.children)) {\n if (child instanceof EFTimegroup) {\n groups.push(child);\n } else {\n shallowGetTimegroups(child, groups);\n }\n }\n return groups;\n};\n\n@customElement(\"ef-timegroup\")\nexport class EFTimegroup extends EFTargetable(EFTemporal(TWMixin(LitElement))) {\n static get observedAttributes(): string[] {\n // biome-ignore lint/complexity/noThisInStatic: It's okay to use this here\n const parentAttributes = super.observedAttributes || [];\n return [\n ...parentAttributes,\n \"mode\",\n \"overlap\",\n \"currenttime\",\n \"fit\",\n \"fps\",\n ];\n }\n\n static styles = css`\n :host {\n display: block;\n position: relative;\n overflow: hidden;\n }\n\n ::slotted(ef-timegroup) {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n overflow: initial;\n }\n `;\n\n @provide({ context: timegroupContext })\n _timeGroupContext = this;\n\n @provide({ context: efContext })\n efContext = this;\n\n mode: \"fit\" | \"fixed\" | \"sequence\" | \"contain\" = \"contain\";\n overlapMs = 0;\n\n @property({ type: Number })\n fps = 30;\n\n attributeChangedCallback(\n name: string,\n old: string | null,\n value: string | null,\n ): void {\n if (name === \"mode\" && value) {\n this.mode = value as typeof this.mode;\n }\n if (name === \"overlap\" && value) {\n this.overlapMs = parseTimeToMs(value);\n }\n if (name === \"fps\" && value) {\n this.fps = Number.parseFloat(value);\n }\n super.attributeChangedCallback(name, old, value);\n }\n\n @property({ type: String })\n fit: \"none\" | \"contain\" | \"cover\" = \"none\";\n\n #resizeObserver?: ResizeObserver;\n\n #currentTime: number | undefined = undefined;\n #seekInProgress = false;\n #pendingSeekTime: number | undefined;\n #processingPendingSeek = false;\n #customFrameTasks: Set<FrameTaskCallback> = new Set();\n\n /**\n * Get the effective FPS for this timegroup.\n * During rendering, uses the render options FPS if available.\n * Otherwise uses the configured fps property.\n */\n get effectiveFps(): number {\n // During rendering, prefer the render options FPS\n if (typeof window !== \"undefined\" && window.EF_FRAMEGEN?.renderOptions) {\n return window.EF_FRAMEGEN.renderOptions.encoderOptions.video.framerate;\n }\n return this.fps;\n }\n\n /**\n * Quantize a time value to the nearest frame boundary based on effectiveFps.\n * @param timeSeconds - Time in seconds\n * @returns Time quantized to frame boundaries in seconds\n */\n private quantizeToFrameTime(timeSeconds: number): number {\n const fps = this.effectiveFps;\n if (!fps || fps <= 0) return timeSeconds;\n const frameDurationS = 1 / fps;\n return Math.round(timeSeconds / frameDurationS) * frameDurationS;\n }\n\n private async runThrottledFrameTask(): Promise<void> {\n if (this.playbackController) {\n return this.playbackController.runThrottledFrameTask();\n }\n await this.frameTask.run();\n }\n\n @property({ type: Number, attribute: \"currenttime\" })\n set currentTime(time: number) {\n // Quantize time to frame boundaries based on fps\n // Do this BEFORE delegating to playbackController to ensure consistency\n time = this.quantizeToFrameTime(time);\n\n if (this.playbackController) {\n this.playbackController.currentTime = time;\n return;\n }\n\n time = Math.max(0, Math.min(this.durationMs / 1000, time));\n if (!this.isRootTimegroup) {\n return;\n }\n if (Number.isNaN(time)) {\n return;\n }\n if (time === this.#currentTime && !this.#processingPendingSeek) {\n return;\n }\n if (this.#pendingSeekTime === time) {\n return;\n }\n\n if (this.#seekInProgress) {\n this.#pendingSeekTime = time;\n this.#currentTime = time;\n return;\n }\n\n this.#currentTime = time;\n this.#seekInProgress = true;\n\n this.seekTask.run().finally(() => {\n if (\n this.#pendingSeekTime !== undefined &&\n this.#pendingSeekTime !== time\n ) {\n const pendingTime = this.#pendingSeekTime;\n this.#pendingSeekTime = undefined;\n this.#processingPendingSeek = true;\n try {\n this.currentTime = pendingTime;\n } finally {\n this.#processingPendingSeek = false;\n }\n } else {\n this.#pendingSeekTime = undefined;\n }\n });\n }\n\n get currentTime() {\n if (this.playbackController) {\n return this.playbackController.currentTime;\n }\n return this.#currentTime ?? 0;\n }\n\n set currentTimeMs(ms: number) {\n this.currentTime = ms / 1000;\n }\n\n get currentTimeMs() {\n return this.currentTime * 1000;\n }\n\n /**\n * Seek to a specific time and wait for all frames to be ready.\n * This is the recommended way to seek in tests and programmatic control.\n *\n * @param timeMs - Time in milliseconds to seek to\n * @returns Promise that resolves when the seek is complete and all visible children are ready\n */\n async seek(timeMs: number): Promise<void> {\n this.currentTimeMs = timeMs;\n await this.seekTask.taskComplete;\n\n // Handle localStorage when playbackController delegates seek\n if (this.playbackController) {\n this.saveTimeToLocalStorage(this.currentTime);\n }\n\n await this.frameTask.taskComplete;\n\n // Ensure all visible elements have completed their reactive update cycles AND frame rendering\n // waitForFrameTasks() calls frameTask.run() on children, but this may happen before child\n // elements have processed property changes from requestUpdate(). To ensure frame data is\n // accurate, we wait for updateComplete first, then ensure the frameTask has run with the\n // updated properties. Elements like EFVideo provide waitForFrameReady() for this pattern.\n const temporalElements = deepGetElementsWithFrameTasks(this);\n const visibleElements = temporalElements.filter((element) => {\n const animationState = evaluateAnimationVisibilityState(element);\n return animationState.isVisible;\n });\n\n await Promise.all(\n visibleElements.map(async (element) => {\n if (\n \"waitForFrameReady\" in element &&\n typeof element.waitForFrameReady === \"function\"\n ) {\n await (element as any).waitForFrameReady();\n } else {\n await element.updateComplete;\n }\n }),\n );\n }\n\n /**\n * Determines if this is a root timegroup (no parent timegroups)\n */\n get isRootTimegroup(): boolean {\n return !this.parentTimegroup;\n }\n\n /**\n * Register a custom frame task callback that will be executed during frame rendering.\n * The callback receives timing information and can be async or sync.\n * Multiple callbacks can be registered and will execute in parallel.\n *\n * @param callback - Function to execute on each frame\n * @returns A cleanup function that removes the callback when called\n */\n addFrameTask(callback: FrameTaskCallback): () => void {\n if (typeof callback !== \"function\") {\n throw new Error(\"Frame task callback must be a function\");\n }\n this.#customFrameTasks.add(callback);\n return () => {\n this.#customFrameTasks.delete(callback);\n };\n }\n\n /**\n * Remove a previously registered custom frame task callback.\n *\n * @param callback - The callback function to remove\n */\n removeFrameTask(callback: FrameTaskCallback): void {\n this.#customFrameTasks.delete(callback);\n }\n\n saveTimeToLocalStorage(time: number) {\n try {\n if (this.id && this.isConnected && !Number.isNaN(time)) {\n localStorage.setItem(this.storageKey, time.toString());\n }\n } catch (error) {\n log(\"Failed to save time to localStorage\", error);\n }\n }\n\n render() {\n return html`<slot @slotchange=${this.#handleSlotChange}></slot> `;\n }\n\n #handleSlotChange = () => {\n // Invalidate caches when slot content changes\n resetTemporalCache();\n flushSequenceDurationCache();\n flushStartTimeMsCache();\n\n // Request update to trigger recalculation of dependent properties\n this.requestUpdate();\n };\n\n loadTimeFromLocalStorage(): number | undefined {\n if (this.id) {\n try {\n const storedValue = localStorage.getItem(this.storageKey);\n if (storedValue === null) {\n return undefined;\n }\n return Number.parseFloat(storedValue);\n } catch (error) {\n log(\"Failed to load time from localStorage\", error);\n }\n }\n return undefined;\n }\n\n connectedCallback() {\n super.connectedCallback();\n\n if (!this.playbackController) {\n this.waitForMediaDurations().then(async () => {\n let didLoadFromStorage = false;\n if (this.id) {\n const maybeLoadedTime = this.loadTimeFromLocalStorage();\n if (maybeLoadedTime !== undefined) {\n this.currentTime = maybeLoadedTime;\n didLoadFromStorage = true;\n }\n }\n if (EF_INTERACTIVE && this.seekTask.status === TaskStatus.INITIAL) {\n this.seekTask.run();\n } else if (didLoadFromStorage) {\n await this.seekTask.run();\n }\n });\n }\n\n if (this.parentTimegroup) {\n new TimegroupController(this.parentTimegroup, this);\n }\n\n if (this.shouldWrapWithWorkbench()) {\n this.wrapWithWorkbench();\n }\n }\n\n #previousDurationMs = 0;\n\n protected updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n\n if (changedProperties.has(\"mode\") || changedProperties.has(\"overlapMs\")) {\n sequenceDurationCache.delete(this);\n }\n\n if (this.#previousDurationMs !== this.durationMs) {\n this.#previousDurationMs = this.durationMs;\n this.runThrottledFrameTask();\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.#resizeObserver?.disconnect();\n }\n\n get storageKey() {\n if (!this.id) {\n throw new Error(\"Timegroup must have an id to use localStorage.\");\n }\n return `ef-timegroup-${this.id}`;\n }\n\n get intrinsicDurationMs() {\n if (this.hasExplicitDuration) {\n return this.explicitDurationMs;\n }\n return undefined;\n }\n\n get hasOwnDuration() {\n return (\n this.mode === \"contain\" ||\n this.mode === \"sequence\" ||\n (this.mode === \"fixed\" && this.hasExplicitDuration)\n );\n }\n\n get durationMs(): number {\n switch (this.mode) {\n case \"fit\": {\n if (!this.parentTimegroup) {\n return 0;\n }\n return this.parentTimegroup.durationMs;\n }\n case \"fixed\":\n return super.durationMs;\n case \"sequence\": {\n // Check cache first to avoid expensive O(n) recalculation\n const cachedDuration = sequenceDurationCache.get(this);\n if (cachedDuration !== undefined) {\n return cachedDuration;\n }\n\n let duration = 0;\n this.childTemporals.forEach((child, index) => {\n if (child instanceof EFTimegroup && child.mode === \"fit\") {\n return;\n }\n if (index > 0) {\n duration -= this.overlapMs;\n }\n duration += child.durationMs;\n });\n\n // Cache the calculated duration\n sequenceDurationCache.set(this, duration);\n return duration;\n }\n case \"contain\": {\n let maxDuration = 0;\n for (const child of this.childTemporals) {\n // fit timegroups look \"up\" to their parent timegroup for their duration\n // so we need to skip them to avoid an infinite loop\n if (child instanceof EFTimegroup && child.mode === \"fit\") {\n continue;\n }\n if (!child.hasOwnDuration) {\n continue;\n }\n maxDuration = Math.max(maxDuration, child.durationMs);\n }\n return maxDuration;\n }\n default:\n throw new Error(`Invalid time mode: ${this.mode}`);\n }\n }\n\n async getPendingFrameTasks(signal?: AbortSignal) {\n await this.waitForNestedUpdates(signal);\n signal?.throwIfAborted();\n const temporals = deepGetElementsWithFrameTasks(this);\n\n // Filter to only include temporally visible elements for frame processing\n // (but keep all elements for duration calculations)\n // Use the target timeline time if we're in the middle of seeking\n const timelineTimeMs =\n (this.#pendingSeekTime ?? this.#currentTime ?? 0) * 1000;\n const activeTemporals = temporals.filter((temporal) => {\n // Skip timeline filtering if temporal doesn't have timeline position info\n if (!(\"startTimeMs\" in temporal) || !(\"endTimeMs\" in temporal)) {\n return true; // Keep non-temporal elements\n }\n\n // Only process frame tasks for elements that overlap the current timeline\n // Use same epsilon logic as seek task for consistency\n const epsilon = 0.001; // 1µs offset to break ties at boundaries\n const startTimeMs = (temporal as any).startTimeMs as number;\n const endTimeMs = (temporal as any).endTimeMs as number;\n const elementStartsBeforeEnd = startTimeMs <= timelineTimeMs + epsilon;\n // Root timegroups should remain visible at exact end time, but other elements use exclusive end for clean transitions\n const isRootTimegroup =\n temporal.tagName.toLowerCase() === \"ef-timegroup\" &&\n !(temporal as any).parentTimegroup;\n const useInclusiveEnd = isRootTimegroup;\n const elementEndsAfterStart = useInclusiveEnd\n ? endTimeMs >= timelineTimeMs\n : endTimeMs > timelineTimeMs;\n return elementStartsBeforeEnd && elementEndsAfterStart;\n });\n\n const frameTasks = activeTemporals.map((temporal) => temporal.frameTask);\n frameTasks.forEach((task) => {\n task.run();\n });\n\n return frameTasks.filter((task) => task.status < TaskStatus.COMPLETE);\n }\n\n async waitForNestedUpdates(signal?: AbortSignal) {\n const limit = 10;\n let steps = 0;\n let isComplete = true;\n while (true) {\n steps++;\n if (steps > limit) {\n throw new Error(\"Reached update depth limit.\");\n }\n isComplete = await this.updateComplete;\n signal?.throwIfAborted();\n if (isComplete) {\n break;\n }\n }\n }\n\n async waitForFrameTasks() {\n const result = await withSpan(\n \"timegroup.waitForFrameTasks\",\n {\n timegroupId: this.id || \"unknown\",\n mode: this.mode,\n },\n undefined,\n async (span) => {\n const innerStart = performance.now();\n\n const temporalElements = deepGetElementsWithFrameTasks(this);\n if (isTracingEnabled()) {\n span.setAttribute(\"temporalElementsCount\", temporalElements.length);\n }\n\n // Filter to only include temporally visible elements for frame processing\n // Use animation-friendly visibility to prevent animation jumps at exact boundaries\n const visibleElements = temporalElements.filter((element) => {\n const animationState = evaluateAnimationVisibilityState(element);\n return animationState.isVisible;\n });\n if (isTracingEnabled()) {\n span.setAttribute(\"visibleElementsCount\", visibleElements.length);\n }\n\n const promiseStart = performance.now();\n\n await Promise.all(\n visibleElements.map((element) => element.frameTask.run()),\n );\n const promiseEnd = performance.now();\n\n const innerEnd = performance.now();\n if (isTracingEnabled()) {\n span.setAttribute(\"actualInnerMs\", innerEnd - innerStart);\n span.setAttribute(\"promiseAwaitMs\", promiseEnd - promiseStart);\n }\n },\n );\n\n return result;\n }\n\n mediaDurationsPromise: Promise<void> | undefined = undefined;\n\n async waitForMediaDurations() {\n if (!this.mediaDurationsPromise) {\n this.mediaDurationsPromise = this.#waitForMediaDurations();\n }\n return this.mediaDurationsPromise;\n }\n\n /**\n * Wait for all media elements to load their initial segments.\n * Ideally we would only need the extracted index json data, but\n * that caused issues with constructing audio data. We had negative durations\n * in calculations and it was not clear why.\n */\n async #waitForMediaDurations() {\n return withSpan(\n \"timegroup.waitForMediaDurations\",\n {\n timegroupId: this.id || \"unknown\",\n mode: this.mode,\n },\n undefined,\n async (span) => {\n // We must await updateComplete to ensure all media elements inside this are connected\n // and will match deepGetMediaElements\n await this.updateComplete;\n const mediaElements = deepGetMediaElements(this);\n if (isTracingEnabled()) {\n span.setAttribute(\"mediaElementsCount\", mediaElements.length);\n }\n\n // Then, we must await the fragmentIndexTask to ensure all media elements have their\n // fragment index loaded, which is where their duration is parsed from.\n await Promise.all(\n mediaElements.map((m) =>\n m.mediaEngineTask.value\n ? Promise.resolve()\n : m.mediaEngineTask.run(),\n ),\n );\n\n // After waiting for durations, we must force some updates to cascade and ensure all temporal elements\n // have correct durations and start times. It is not ideal that we have to do this inside here,\n // but it is the best current way to ensure that all temporal elements have correct durations and start times.\n\n // Next, we must flush the startTimeMs cache to ensure all media elements have their\n // startTimeMs parsed fresh, otherwise the startTimeMs is cached per animation frame.\n flushStartTimeMsCache();\n\n // Flush duration cache since child durations may have changed\n flushSequenceDurationCache();\n\n // Request an update to the currentTime of this group, ensuring that time updates will cascade\n // down to children, forcing sequence groups to arrange correctly.\n // This also makes the filmstrip update correctly.\n this.requestUpdate(\"currentTime\");\n // Finally, we must await updateComplete to ensure all temporal elements have their\n // currentTime updated and all animations have run.\n\n await this.updateComplete;\n },\n );\n }\n\n get childTemporals() {\n return shallowGetTemporalElements(this);\n }\n\n get contextProvider() {\n let parent = this.parentNode;\n while (parent) {\n if (isContextMixin(parent)) {\n return parent;\n }\n parent = parent.parentNode;\n }\n return null;\n }\n\n /**\n * Returns true if the timegroup should be wrapped with a workbench.\n *\n * A timegroup should be wrapped with a workbench if:\n * - It's being rendered (EF_RENDERING), OR\n * - It's in interactive mode (EF_INTERACTIVE) with the dev workbench flag set\n *\n * If the timegroup is already wrapped in a context provider like ef-preview,\n * it should NOT be wrapped in a workbench.\n */\n shouldWrapWithWorkbench() {\n const isRendering = EF_RENDERING?.() === true;\n\n // During rendering, always wrap with workbench (needed by EF_FRAMEGEN)\n if (isRendering) {\n return (\n this.closest(\"ef-timegroup\") === this &&\n this.closest(\"ef-preview\") === null &&\n this.closest(\"ef-workbench\") === null &&\n this.closest(\"test-context\") === null\n );\n }\n\n // During interactive mode, respect the dev workbench flag\n if (!globalThis.EF_DEV_WORKBENCH) {\n return false;\n }\n\n return (\n EF_INTERACTIVE &&\n this.closest(\"ef-timegroup\") === this &&\n this.closest(\"ef-preview\") === null &&\n this.closest(\"ef-workbench\") === null &&\n this.closest(\"test-context\") === null\n );\n }\n\n wrapWithWorkbench() {\n const workbench = document.createElement(\"ef-workbench\");\n this.parentElement?.append(workbench);\n if (!this.hasAttribute(\"id\")) {\n this.setAttribute(\"id\", \"root-this\");\n }\n this.setAttribute(\"slot\", \"canvas\");\n workbench.append(this as unknown as Element);\n\n const filmstrip = document.createElement(\"ef-filmstrip\");\n filmstrip.setAttribute(\"slot\", \"timeline\");\n filmstrip.setAttribute(\"target\", this.id);\n workbench.append(filmstrip);\n }\n\n get efElements() {\n return Array.from(\n this.querySelectorAll(\n \"ef-audio, ef-video, ef-image, ef-captions, ef-waveform\",\n ),\n );\n }\n\n /**\n * Returns media elements for playback audio rendering\n * For standalone media, returns [this]; for timegroups, returns all descendants\n * Used by PlaybackController for audio-driven playback\n */\n getMediaElements(): EFMedia[] {\n return deepGetMediaElements(this);\n }\n\n /**\n * Render audio buffer for playback\n * Called by PlaybackController during live playback\n * Delegates to shared renderTemporalAudio utility for consistent behavior\n */\n async renderAudio(fromMs: number, toMs: number): Promise<AudioBuffer> {\n return renderTemporalAudio(this, fromMs, toMs);\n }\n\n /**\n * TEMPORARY TEST METHOD: Renders audio and immediately plays it back\n * Usage: timegroup.testPlayAudio(0, 5000) // Play first 5 seconds\n */\n async testPlayAudio(fromMs: number, toMs: number) {\n // Render the audio using the existing renderAudio method\n const renderedBuffer = await this.renderAudio(fromMs, toMs);\n\n // Create a regular AudioContext for playback\n const playbackContext = new AudioContext();\n\n // Create a buffer source and connect it\n const bufferSource = playbackContext.createBufferSource();\n bufferSource.buffer = renderedBuffer;\n bufferSource.connect(playbackContext.destination);\n\n // Start playback immediately\n bufferSource.start(0);\n\n // Return a promise that resolves when playback ends\n return new Promise<void>((resolve) => {\n bufferSource.onended = () => {\n playbackContext.close();\n resolve();\n };\n });\n }\n\n async loadMd5Sums() {\n const efElements = this.efElements;\n const loaderTasks: Promise<any>[] = [];\n for (const el of efElements) {\n const md5SumLoader = (el as any).md5SumLoader;\n if (md5SumLoader instanceof Task) {\n md5SumLoader.run();\n loaderTasks.push(md5SumLoader.taskComplete);\n }\n }\n\n await Promise.all(loaderTasks);\n\n efElements.forEach((el) => {\n if (\"productionSrc\" in el && el.productionSrc instanceof Function) {\n el.setAttribute(\"src\", el.productionSrc());\n }\n });\n }\n\n frameTask = new Task(this, {\n // autoRun: EF_INTERACTIVE,\n autoRun: false,\n args: () => [this.ownCurrentTimeMs, this.currentTimeMs] as const,\n task: async ([ownCurrentTimeMs, currentTimeMs]) => {\n if (this.isRootTimegroup) {\n await withSpan(\n \"timegroup.frameTask\",\n {\n timegroupId: this.id || \"unknown\",\n ownCurrentTimeMs,\n currentTimeMs,\n },\n undefined,\n async () => {\n await this.waitForFrameTasks();\n await this.#executeCustomFrameTasks();\n updateAnimations(this);\n },\n );\n } else {\n // Non-root timegroups execute their custom frame tasks when called\n await this.#executeCustomFrameTasks();\n }\n },\n });\n\n async #executeCustomFrameTasks() {\n if (this.#customFrameTasks.size > 0) {\n const percentComplete =\n this.durationMs > 0 ? this.ownCurrentTimeMs / this.durationMs : 0;\n const frameInfo = {\n ownCurrentTimeMs: this.ownCurrentTimeMs,\n currentTimeMs: this.currentTimeMs,\n durationMs: this.durationMs,\n percentComplete,\n element: this,\n };\n\n await Promise.all(\n Array.from(this.#customFrameTasks).map((callback) =>\n Promise.resolve(callback(frameInfo)),\n ),\n );\n }\n }\n\n seekTask = new Task(this, {\n autoRun: false,\n args: () => [this.#pendingSeekTime ?? this.#currentTime] as const,\n onComplete: () => {},\n task: async ([targetTime]) => {\n if (this.playbackController) {\n await this.playbackController.seekTask.taskComplete;\n return this.currentTime;\n }\n\n if (!this.isRootTimegroup) {\n return;\n }\n return withSpan(\n \"timegroup.seekTask\",\n {\n timegroupId: this.id || \"unknown\",\n targetTime: targetTime ?? 0,\n durationMs: this.durationMs,\n },\n undefined,\n async (span) => {\n await this.waitForMediaDurations();\n const newTime = Math.max(\n 0,\n Math.min(targetTime ?? 0, this.durationMs / 1000),\n );\n if (isTracingEnabled()) {\n span.setAttribute(\"newTime\", newTime);\n }\n // Apply the clamped time back to currentTime\n\n this.#currentTime = newTime;\n this.requestUpdate(\"currentTime\");\n await this.runThrottledFrameTask();\n this.saveTimeToLocalStorage(this.#currentTime);\n this.#seekInProgress = false;\n return newTime;\n },\n );\n },\n });\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-timegroup\": EFTimegroup & Element;\n }\n}\n"],"mappings":"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"}
|
|
@@ -4,10 +4,10 @@ import { MediaEngine } from "../transcoding/types/index.js";
|
|
|
4
4
|
import { EFMedia } from "./EFMedia.js";
|
|
5
5
|
import { VideoBufferState } from "./EFMedia/videoTasks/makeVideoBufferTask.js";
|
|
6
6
|
import { Task } from "@lit/task";
|
|
7
|
-
import * as
|
|
7
|
+
import * as lit7 from "lit";
|
|
8
8
|
import { PropertyValueMap } from "lit";
|
|
9
9
|
import * as mediabunny0 from "mediabunny";
|
|
10
|
-
import * as
|
|
10
|
+
import * as lit_html7 from "lit-html";
|
|
11
11
|
import * as lit_html_directives_ref0 from "lit-html/directives/ref";
|
|
12
12
|
|
|
13
13
|
//#region src/elements/EFVideo.d.ts
|
|
@@ -21,7 +21,7 @@ interface LoadingState {
|
|
|
21
21
|
}
|
|
22
22
|
declare const EFVideo_base: typeof EFMedia;
|
|
23
23
|
declare class EFVideo extends EFVideo_base {
|
|
24
|
-
static styles:
|
|
24
|
+
static styles: lit7.CSSResult[];
|
|
25
25
|
canvasRef: lit_html_directives_ref0.Ref<HTMLCanvasElement>;
|
|
26
26
|
/**
|
|
27
27
|
* Duration in milliseconds for video buffering ahead of current time
|
|
@@ -60,7 +60,7 @@ declare class EFVideo extends EFVideo_base {
|
|
|
60
60
|
};
|
|
61
61
|
constructor();
|
|
62
62
|
protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
|
|
63
|
-
render():
|
|
63
|
+
render(): lit_html7.TemplateResult<1>;
|
|
64
64
|
get canvasElement(): HTMLCanvasElement | undefined;
|
|
65
65
|
frameTask: Task<readonly [number], void>;
|
|
66
66
|
/**
|
|
@@ -3,21 +3,21 @@ import { EFAudio } from "./EFAudio.js";
|
|
|
3
3
|
import { EFVideo } from "./EFVideo.js";
|
|
4
4
|
import { TargetController } from "./TargetController.js";
|
|
5
5
|
import { Task } from "@lit/task";
|
|
6
|
-
import * as
|
|
6
|
+
import * as lit8 from "lit";
|
|
7
7
|
import { LitElement, PropertyValueMap } from "lit";
|
|
8
8
|
import { Ref } from "lit/directives/ref.js";
|
|
9
|
-
import * as
|
|
9
|
+
import * as lit_html8 from "lit-html";
|
|
10
10
|
|
|
11
11
|
//#region src/elements/EFWaveform.d.ts
|
|
12
12
|
declare const EFWaveform_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
|
|
13
13
|
declare class EFWaveform extends EFWaveform_base {
|
|
14
|
-
static styles:
|
|
14
|
+
static styles: lit8.CSSResult;
|
|
15
15
|
canvasRef: Ref<HTMLCanvasElement>;
|
|
16
16
|
private ctx;
|
|
17
17
|
private styleObserver;
|
|
18
18
|
private resizeObserver?;
|
|
19
19
|
private mutationObserver?;
|
|
20
|
-
render():
|
|
20
|
+
render(): lit_html8.TemplateResult<1>;
|
|
21
21
|
mode: "roundBars" | "bars" | "bricks" | "line" | "curve" | "pixel" | "wave" | "spikes";
|
|
22
22
|
color: string;
|
|
23
23
|
target: string;
|