@editframe/elements 0.16.7-beta.0 → 0.17.6-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/README.md +30 -0
- package/dist/DecoderResetFrequency.test.d.ts +1 -0
- package/dist/DecoderResetRecovery.test.d.ts +1 -0
- package/dist/DelayedLoadingState.d.ts +48 -0
- package/dist/DelayedLoadingState.integration.test.d.ts +1 -0
- package/dist/DelayedLoadingState.js +113 -0
- package/dist/DelayedLoadingState.test.d.ts +1 -0
- package/dist/EF_FRAMEGEN.d.ts +10 -1
- package/dist/EF_FRAMEGEN.js +199 -179
- package/dist/EF_INTERACTIVE.js +2 -6
- package/dist/EF_RENDERING.js +1 -3
- package/dist/JitTranscodingClient.browsertest.d.ts +1 -0
- package/dist/JitTranscodingClient.d.ts +167 -0
- package/dist/JitTranscodingClient.js +373 -0
- package/dist/JitTranscodingClient.test.d.ts +1 -0
- package/dist/LoadingDebounce.test.d.ts +1 -0
- package/dist/LoadingIndicator.browsertest.d.ts +0 -0
- package/dist/ManualScrubTest.test.d.ts +1 -0
- package/dist/ScrubResolvedFlashing.test.d.ts +1 -0
- package/dist/ScrubTrackIntegration.test.d.ts +1 -0
- package/dist/ScrubTrackManager.d.ts +96 -0
- package/dist/ScrubTrackManager.js +216 -0
- package/dist/ScrubTrackManager.test.d.ts +1 -0
- package/dist/SegmentSwitchLoading.test.d.ts +1 -0
- package/dist/VideoSeekFlashing.browsertest.d.ts +0 -0
- package/dist/VideoStuckDiagnostic.test.d.ts +1 -0
- package/dist/elements/CrossUpdateController.js +13 -15
- package/dist/elements/EFAudio.browsertest.d.ts +0 -0
- package/dist/elements/EFAudio.d.ts +1 -1
- package/dist/elements/EFAudio.js +30 -43
- package/dist/elements/EFCaptions.js +337 -373
- package/dist/elements/EFImage.js +64 -90
- package/dist/elements/EFMedia.d.ts +98 -33
- package/dist/elements/EFMedia.js +1169 -678
- package/dist/elements/EFSourceMixin.js +31 -48
- package/dist/elements/EFTemporal.d.ts +1 -0
- package/dist/elements/EFTemporal.js +266 -360
- package/dist/elements/EFTimegroup.d.ts +3 -1
- package/dist/elements/EFTimegroup.js +262 -323
- package/dist/elements/EFVideo.browsertest.d.ts +0 -0
- package/dist/elements/EFVideo.d.ts +90 -2
- package/dist/elements/EFVideo.js +408 -111
- package/dist/elements/EFWaveform.js +375 -411
- package/dist/elements/FetchMixin.js +14 -24
- package/dist/elements/MediaController.d.ts +30 -0
- package/dist/elements/TargetController.js +130 -156
- package/dist/elements/TimegroupController.js +17 -19
- package/dist/elements/durationConverter.js +15 -4
- package/dist/elements/parseTimeToMs.js +4 -10
- package/dist/elements/printTaskStatus.d.ts +2 -0
- package/dist/elements/printTaskStatus.js +11 -0
- package/dist/elements/updateAnimations.js +39 -59
- package/dist/getRenderInfo.js +58 -67
- package/dist/gui/ContextMixin.js +203 -288
- package/dist/gui/EFConfiguration.js +27 -43
- package/dist/gui/EFFilmstrip.js +440 -620
- package/dist/gui/EFFitScale.js +112 -135
- package/dist/gui/EFFocusOverlay.js +45 -61
- package/dist/gui/EFPreview.js +30 -49
- package/dist/gui/EFScrubber.js +78 -99
- package/dist/gui/EFTimeDisplay.js +49 -70
- package/dist/gui/EFToggleLoop.js +17 -34
- package/dist/gui/EFTogglePlay.js +37 -58
- package/dist/gui/EFWorkbench.js +66 -88
- package/dist/gui/TWMixin.js +2 -48
- package/dist/gui/TWMixin2.js +31 -0
- package/dist/gui/efContext.js +2 -6
- package/dist/gui/fetchContext.js +1 -3
- package/dist/gui/focusContext.js +1 -3
- package/dist/gui/focusedElementContext.js +2 -6
- package/dist/gui/playingContext.js +1 -4
- package/dist/index.js +5 -30
- package/dist/msToTimeCode.js +11 -13
- package/dist/style.css +2 -1
- package/package.json +3 -3
- package/src/elements/EFAudio.browsertest.ts +569 -0
- package/src/elements/EFAudio.ts +4 -6
- package/src/elements/EFCaptions.browsertest.ts +0 -1
- package/src/elements/EFImage.browsertest.ts +0 -1
- package/src/elements/EFMedia.browsertest.ts +147 -115
- package/src/elements/EFMedia.ts +1339 -307
- package/src/elements/EFTemporal.browsertest.ts +0 -1
- package/src/elements/EFTemporal.ts +11 -0
- package/src/elements/EFTimegroup.ts +73 -10
- package/src/elements/EFVideo.browsertest.ts +680 -0
- package/src/elements/EFVideo.ts +729 -50
- package/src/elements/EFWaveform.ts +4 -4
- package/src/elements/MediaController.ts +108 -0
- package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
- package/src/elements/printTaskStatus.ts +16 -0
- package/src/elements/updateAnimations.ts +6 -0
- package/src/gui/TWMixin.ts +10 -3
- package/test/EFVideo.frame-tasks.browsertest.ts +524 -0
- package/test/EFVideo.framegen.browsertest.ts +118 -0
- package/test/createJitTestClips.ts +293 -0
- package/test/useAssetMSW.ts +49 -0
- package/test/useMSW.ts +31 -0
- package/types.json +1 -1
- package/dist/gui/TWMixin.css.js +0 -4
- /package/dist/elements/{TargetController.test.d.ts → TargetController.browsertest.d.ts} +0 -0
- /package/src/elements/{TargetController.test.ts → TargetController.browsertest.ts} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Tasks: Hierarchical Async Task System for lit-html
|
|
2
|
+
|
|
3
|
+
## Relevant Files
|
|
4
|
+
|
|
5
|
+
- `src/task-system/types.ts` - Complete TypeScript interfaces and types for the task system
|
|
6
|
+
- `src/task-system/Task.ts` - Core Task class with lifecycle management, hierarchy, and event handling
|
|
7
|
+
- `src/task-system/Task.test.ts` - Comprehensive unit tests for Task class
|
|
8
|
+
- `src/task-system/TaskManager.ts` - Core task orchestration with dependency tracking, resolution, and priority scheduling
|
|
9
|
+
- `src/task-system/TaskManager.test.ts` - Comprehensive unit tests for TaskManager with dependency scenarios
|
|
10
|
+
- `src/task-system/TaskRegistry.ts` - Global registry with automatic cleanup, memory management, and monitoring
|
|
11
|
+
- `src/task-system/TaskRegistry.test.ts` - Comprehensive unit tests for TaskRegistry covering all cleanup scenarios
|
|
12
|
+
- `src/task-system/index.ts` - Public API exports with convenience functions for common task patterns
|
|
13
|
+
- `src/integrations/lit-html-task-mixin.ts` - Lit-html component integration mixin
|
|
14
|
+
- `src/integrations/lit-html-task-mixin.test.ts` - Unit tests for lit-html integration
|
|
15
|
+
- `src/utils/task-debug.ts` - Developer debugging utilities and task graph visualization
|
|
16
|
+
- `src/utils/task-debug.test.ts` - Unit tests for debugging utilities
|
|
17
|
+
|
|
18
|
+
### Notes
|
|
19
|
+
|
|
20
|
+
- Unit tests should be placed alongside the code files they are testing
|
|
21
|
+
- Use `npx tsx` to execute TypeScript files for testing
|
|
22
|
+
- The system should be domain-agnostic and reusable across different use cases
|
|
23
|
+
|
|
24
|
+
## Tasks
|
|
25
|
+
|
|
26
|
+
- [x] 1.0 Design and implement core task abstraction and lifecycle management
|
|
27
|
+
- [x] 2.0 Build hierarchical dependency tracking and resolution system
|
|
28
|
+
- [x] 3.0 Create task registry and cleanup mechanisms
|
|
29
|
+
- [ ] 4.0 Implement lit-html component integration layer
|
|
30
|
+
- [ ] 5.0 Add debugging and observability features
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
interface LoadingOptions {
|
|
2
|
+
background?: boolean;
|
|
3
|
+
}
|
|
4
|
+
export declare class DelayedLoadingState {
|
|
5
|
+
private operations;
|
|
6
|
+
private loadingDelayMs;
|
|
7
|
+
private isCurrentlyLoading;
|
|
8
|
+
private currentMessage;
|
|
9
|
+
private onStateChange?;
|
|
10
|
+
constructor(delayMs?: number, onStateChange?: (isLoading: boolean, message: string) => void);
|
|
11
|
+
/**
|
|
12
|
+
* Start a delayed loading operation
|
|
13
|
+
*/
|
|
14
|
+
startLoading(operationId: string, message: string, options?: LoadingOptions): void;
|
|
15
|
+
/**
|
|
16
|
+
* Clear a loading operation
|
|
17
|
+
*/
|
|
18
|
+
clearLoading(operationId: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Clear all loading operations
|
|
21
|
+
*/
|
|
22
|
+
clearAllLoading(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Get current loading state
|
|
25
|
+
*/
|
|
26
|
+
get isLoading(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Get current loading message
|
|
29
|
+
*/
|
|
30
|
+
get message(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Check if any non-background operations are active
|
|
33
|
+
*/
|
|
34
|
+
private hasActiveOperations;
|
|
35
|
+
/**
|
|
36
|
+
* Get the message for the most recent non-background operation
|
|
37
|
+
*/
|
|
38
|
+
private getCurrentMessage;
|
|
39
|
+
/**
|
|
40
|
+
* Trigger loading state (called by timeout)
|
|
41
|
+
*/
|
|
42
|
+
private triggerLoadingState;
|
|
43
|
+
/**
|
|
44
|
+
* Update loading state based on current operations
|
|
45
|
+
*/
|
|
46
|
+
private updateLoadingState;
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
var DelayedLoadingState = class {
|
|
2
|
+
constructor(delayMs = 250, onStateChange) {
|
|
3
|
+
this.operations = /* @__PURE__ */ new Map();
|
|
4
|
+
this.isCurrentlyLoading = false;
|
|
5
|
+
this.currentMessage = "";
|
|
6
|
+
this.loadingDelayMs = delayMs;
|
|
7
|
+
this.onStateChange = onStateChange;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Start a delayed loading operation
|
|
11
|
+
*/
|
|
12
|
+
startLoading(operationId, message, options = {}) {
|
|
13
|
+
const isBackground = options.background || false;
|
|
14
|
+
const existingOp = this.operations.get(operationId);
|
|
15
|
+
if (existingOp?.timeout) clearTimeout(existingOp.timeout);
|
|
16
|
+
if (isBackground) {
|
|
17
|
+
this.operations.set(operationId, {
|
|
18
|
+
id: operationId,
|
|
19
|
+
message,
|
|
20
|
+
startTime: Date.now(),
|
|
21
|
+
isBackground: true
|
|
22
|
+
});
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const timeout = setTimeout(() => {
|
|
26
|
+
const operation = this.operations.get(operationId);
|
|
27
|
+
if (operation && !operation.isBackground) this.triggerLoadingState();
|
|
28
|
+
}, this.loadingDelayMs);
|
|
29
|
+
this.operations.set(operationId, {
|
|
30
|
+
id: operationId,
|
|
31
|
+
message,
|
|
32
|
+
startTime: Date.now(),
|
|
33
|
+
timeout,
|
|
34
|
+
isBackground: false
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Clear a loading operation
|
|
39
|
+
*/
|
|
40
|
+
clearLoading(operationId) {
|
|
41
|
+
const operation = this.operations.get(operationId);
|
|
42
|
+
if (!operation) return;
|
|
43
|
+
if (operation.timeout) clearTimeout(operation.timeout);
|
|
44
|
+
this.operations.delete(operationId);
|
|
45
|
+
this.updateLoadingState();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Clear all loading operations
|
|
49
|
+
*/
|
|
50
|
+
clearAllLoading() {
|
|
51
|
+
for (const operation of this.operations.values()) if (operation.timeout) clearTimeout(operation.timeout);
|
|
52
|
+
this.operations.clear();
|
|
53
|
+
this.updateLoadingState();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get current loading state
|
|
57
|
+
*/
|
|
58
|
+
get isLoading() {
|
|
59
|
+
return this.isCurrentlyLoading;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get current loading message
|
|
63
|
+
*/
|
|
64
|
+
get message() {
|
|
65
|
+
return this.currentMessage;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if any non-background operations are active
|
|
69
|
+
*/
|
|
70
|
+
hasActiveOperations() {
|
|
71
|
+
for (const operation of this.operations.values()) if (!operation.isBackground) return true;
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the message for the most recent non-background operation
|
|
76
|
+
*/
|
|
77
|
+
getCurrentMessage() {
|
|
78
|
+
let latestTime = 0;
|
|
79
|
+
let latestMessage = "";
|
|
80
|
+
for (const operation of this.operations.values()) if (!operation.isBackground && operation.startTime > latestTime) {
|
|
81
|
+
latestTime = operation.startTime;
|
|
82
|
+
latestMessage = operation.message;
|
|
83
|
+
}
|
|
84
|
+
return latestMessage;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Trigger loading state (called by timeout)
|
|
88
|
+
*/
|
|
89
|
+
triggerLoadingState() {
|
|
90
|
+
if (this.hasActiveOperations() && !this.isCurrentlyLoading) {
|
|
91
|
+
this.isCurrentlyLoading = true;
|
|
92
|
+
this.currentMessage = this.getCurrentMessage();
|
|
93
|
+
this.onStateChange?.(true, this.currentMessage);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Update loading state based on current operations
|
|
98
|
+
*/
|
|
99
|
+
updateLoadingState() {
|
|
100
|
+
const shouldBeLoading = this.hasActiveOperations();
|
|
101
|
+
if (shouldBeLoading !== this.isCurrentlyLoading) {
|
|
102
|
+
this.isCurrentlyLoading = shouldBeLoading;
|
|
103
|
+
if (shouldBeLoading) {
|
|
104
|
+
this.currentMessage = this.getCurrentMessage();
|
|
105
|
+
this.onStateChange?.(true, this.currentMessage);
|
|
106
|
+
} else {
|
|
107
|
+
this.currentMessage = "";
|
|
108
|
+
this.onStateChange?.(false, "");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
export { DelayedLoadingState };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/EF_FRAMEGEN.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ interface Bridge {
|
|
|
6
6
|
onTriggerCanvas(callback: () => void): void;
|
|
7
7
|
frameReady(frameNumber: number, audioSamples: ArrayBuffer): void;
|
|
8
8
|
error(error: Error): void;
|
|
9
|
+
syncLog(sequence: number, message: string, callback: () => void): void;
|
|
9
10
|
}
|
|
10
11
|
declare global {
|
|
11
12
|
interface Window {
|
|
@@ -27,15 +28,23 @@ declare class TriggerCanvas {
|
|
|
27
28
|
export declare class EFFramegen {
|
|
28
29
|
time: number;
|
|
29
30
|
frameDurationMs: number;
|
|
30
|
-
initialBusyTasks: Promise<unknown[]>;
|
|
31
31
|
audioBufferPromise?: Promise<AudioBuffer>;
|
|
32
32
|
renderOptions?: VideoRenderOptions;
|
|
33
33
|
frameBox: HTMLDivElement;
|
|
34
34
|
BRIDGE: typeof window.FRAMEGEN_BRIDGE;
|
|
35
35
|
triggerCanvas: TriggerCanvas;
|
|
36
|
+
verificationCanvas?: HTMLCanvasElement;
|
|
37
|
+
verificationCtx?: CanvasRenderingContext2D;
|
|
38
|
+
private logSequence;
|
|
39
|
+
frameTasksInProgress: boolean;
|
|
40
|
+
currentFrameNumber: number;
|
|
36
41
|
trace(...args: any[]): void;
|
|
42
|
+
syncLog(...args: any[]): Promise<void>;
|
|
43
|
+
private initializeVerificationCanvas;
|
|
44
|
+
private drawVerificationStrip;
|
|
37
45
|
constructor();
|
|
38
46
|
connectToBridge(): void;
|
|
47
|
+
get showFrameBox(): boolean;
|
|
39
48
|
initialize(renderOptions: VideoRenderOptions): Promise<void>;
|
|
40
49
|
beginFrame(frameNumber: number, isLast: boolean): Promise<string | ArrayBuffer | null | undefined>;
|
|
41
50
|
}
|
package/dist/EF_FRAMEGEN.js
CHANGED
|
@@ -1,182 +1,202 @@
|
|
|
1
|
-
import { TaskStatus } from "@lit/task";
|
|
2
|
-
import { deepGetElementsWithFrameTasks } from "./elements/EFTemporal.js";
|
|
3
1
|
import { shallowGetTimegroups } from "./elements/EFTimegroup.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
2
|
+
var TriggerCanvas = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.canvasInitialized = false;
|
|
5
|
+
this.canvas = document.createElement("canvas");
|
|
6
|
+
const ctx = this.canvas.getContext("2d", { willReadFrequently: true });
|
|
7
|
+
if (!ctx) throw new Error("Canvas 2d context not ready");
|
|
8
|
+
this.ctx = ctx;
|
|
9
|
+
this.ctx.fillStyle = "transparent";
|
|
10
|
+
}
|
|
11
|
+
initialize() {
|
|
12
|
+
if (this.canvasInitialized) return;
|
|
13
|
+
this.canvasInitialized = true;
|
|
14
|
+
this.canvas.width = 1;
|
|
15
|
+
this.canvas.height = 1;
|
|
16
|
+
Object.assign(this.canvas.style, {
|
|
17
|
+
position: "fixed",
|
|
18
|
+
top: "0px",
|
|
19
|
+
left: "0px",
|
|
20
|
+
width: "100%",
|
|
21
|
+
height: "100%",
|
|
22
|
+
zIndex: "100000"
|
|
23
|
+
});
|
|
24
|
+
document.body.appendChild(this.canvas);
|
|
25
|
+
}
|
|
26
|
+
trigger() {
|
|
27
|
+
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var EFFramegen = class {
|
|
31
|
+
trace(...args) {
|
|
32
|
+
console.trace("[EF_FRAMEGEN]", ...args);
|
|
33
|
+
}
|
|
34
|
+
async syncLog(...args) {
|
|
35
|
+
if (!this.BRIDGE) {
|
|
36
|
+
console.log("[EF_FRAMEGEN]", ...args);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const sequence = ++this.logSequence;
|
|
40
|
+
const message = args.map((arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)).join(" ");
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
this.BRIDGE.syncLog(sequence, message, () => {
|
|
43
|
+
resolve();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
initializeVerificationCanvas() {
|
|
48
|
+
if (this.verificationCanvas) return;
|
|
49
|
+
this.verificationCanvas = document.createElement("canvas");
|
|
50
|
+
const ctx = this.verificationCanvas.getContext("2d");
|
|
51
|
+
if (!ctx) throw new Error("Verification canvas 2d context not ready");
|
|
52
|
+
this.verificationCtx = ctx;
|
|
53
|
+
const workbench = document.querySelector("ef-workbench");
|
|
54
|
+
if (workbench) {
|
|
55
|
+
this.verificationCanvas.width = workbench.clientWidth;
|
|
56
|
+
this.verificationCanvas.height = 1;
|
|
57
|
+
Object.assign(this.verificationCanvas.style, {
|
|
58
|
+
position: "fixed",
|
|
59
|
+
left: "0px",
|
|
60
|
+
bottom: "0px",
|
|
61
|
+
width: `${workbench.clientWidth}px`,
|
|
62
|
+
height: "1px",
|
|
63
|
+
zIndex: "99999"
|
|
64
|
+
});
|
|
65
|
+
document.body.appendChild(this.verificationCanvas);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
drawVerificationStrip(frameNumber) {
|
|
69
|
+
this.initializeVerificationCanvas();
|
|
70
|
+
if (!this.verificationCanvas || !this.verificationCtx) return;
|
|
71
|
+
const width = this.verificationCanvas.width;
|
|
72
|
+
const height = this.verificationCanvas.height;
|
|
73
|
+
this.verificationCtx.clearRect(0, 0, width, height);
|
|
74
|
+
const red = Math.floor(frameNumber / (256 * 256)) % 256;
|
|
75
|
+
const green = Math.floor(frameNumber / 256) % 256;
|
|
76
|
+
const blue = frameNumber % 256;
|
|
77
|
+
this.verificationCtx.fillStyle = `rgb(${red}, ${green}, ${blue})`;
|
|
78
|
+
this.verificationCtx.fillRect(0, 0, width, height);
|
|
79
|
+
}
|
|
80
|
+
constructor() {
|
|
81
|
+
this.time = 0;
|
|
82
|
+
this.frameDurationMs = 0;
|
|
83
|
+
this.frameBox = document.createElement("div");
|
|
84
|
+
this.triggerCanvas = new TriggerCanvas();
|
|
85
|
+
this.logSequence = 0;
|
|
86
|
+
this.frameTasksInProgress = false;
|
|
87
|
+
this.currentFrameNumber = 0;
|
|
88
|
+
this.BRIDGE = window.FRAMEGEN_BRIDGE;
|
|
89
|
+
if (this.BRIDGE) this.connectToBridge();
|
|
90
|
+
}
|
|
91
|
+
connectToBridge() {
|
|
92
|
+
const BRIDGE = this.BRIDGE;
|
|
93
|
+
if (!BRIDGE) throw new Error("No BRIDGE when attempting to connect to bridge");
|
|
94
|
+
BRIDGE.onInitialize(async (renderOptions) => {
|
|
95
|
+
await this.initialize(renderOptions);
|
|
96
|
+
BRIDGE.initialized();
|
|
97
|
+
});
|
|
98
|
+
BRIDGE.onBeginFrame((frameNumber, isLast) => {
|
|
99
|
+
this.beginFrame(frameNumber, isLast);
|
|
100
|
+
});
|
|
101
|
+
BRIDGE.onTriggerCanvas(() => {
|
|
102
|
+
this.triggerCanvas.trigger();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
get showFrameBox() {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
async initialize(renderOptions) {
|
|
109
|
+
this.renderOptions = renderOptions;
|
|
110
|
+
const alignedFromMs = renderOptions.encoderOptions.alignedFromUs / 1e3;
|
|
111
|
+
const alignedToMs = renderOptions.encoderOptions.alignedToUs / 1e3;
|
|
112
|
+
const alignedDurationMs = alignedToMs - alignedFromMs;
|
|
113
|
+
await this.syncLog("[EF_FRAMEGEN.initialize] Aligned boundary parameters:", {
|
|
114
|
+
alignedFromUs: renderOptions.encoderOptions.alignedFromUs,
|
|
115
|
+
alignedToUs: renderOptions.encoderOptions.alignedToUs,
|
|
116
|
+
alignedFromMs: alignedFromMs.toFixed(3),
|
|
117
|
+
alignedToMs: alignedToMs.toFixed(3),
|
|
118
|
+
alignedDurationMs: alignedDurationMs.toFixed(3),
|
|
119
|
+
sequenceNumber: renderOptions.encoderOptions.sequenceNumber,
|
|
120
|
+
originalFromMs: renderOptions.encoderOptions.fromMs,
|
|
121
|
+
originalToMs: renderOptions.encoderOptions.toMs,
|
|
122
|
+
originalDurationMs: (renderOptions.encoderOptions.toMs - renderOptions.encoderOptions.fromMs).toFixed(3)
|
|
123
|
+
});
|
|
124
|
+
const workbench = document.querySelector("ef-workbench");
|
|
125
|
+
if (!workbench) throw new Error("No workbench found");
|
|
126
|
+
workbench.rendering = true;
|
|
127
|
+
workbench.playing = false;
|
|
128
|
+
const timegroups = shallowGetTimegroups(workbench);
|
|
129
|
+
const firstGroup = timegroups[0];
|
|
130
|
+
if (!firstGroup) throw new Error("No temporal elements found");
|
|
131
|
+
const startingTimeMs = renderOptions.encoderOptions.fromMs;
|
|
132
|
+
await firstGroup.waitForMediaDurations();
|
|
133
|
+
await firstGroup.waitForFrameTasks();
|
|
134
|
+
this.frameDurationMs = 1e3 / renderOptions.encoderOptions.video.framerate;
|
|
135
|
+
this.time = startingTimeMs;
|
|
136
|
+
if (this.showFrameBox) {
|
|
137
|
+
Object.assign(this.frameBox.style, {
|
|
138
|
+
width: "200px",
|
|
139
|
+
height: "100px",
|
|
140
|
+
font: "10px Arial",
|
|
141
|
+
backgroundColor: "white",
|
|
142
|
+
position: "absolute",
|
|
143
|
+
top: "0px",
|
|
144
|
+
right: "0px",
|
|
145
|
+
zIndex: "100000"
|
|
146
|
+
});
|
|
147
|
+
document.body.prepend(this.frameBox);
|
|
148
|
+
}
|
|
149
|
+
this.triggerCanvas.initialize();
|
|
150
|
+
await this.syncLog("[EF_FRAMEGEN.initialize] About to call renderAudio with:", {
|
|
151
|
+
fromMs: alignedFromMs.toFixed(3),
|
|
152
|
+
toMs: alignedToMs.toFixed(3),
|
|
153
|
+
durationMs: alignedDurationMs.toFixed(3)
|
|
154
|
+
});
|
|
155
|
+
this.audioBufferPromise = firstGroup.renderAudio(renderOptions.encoderOptions.alignedFromUs / 1e3, renderOptions.encoderOptions.alignedToUs / 1e3);
|
|
156
|
+
}
|
|
157
|
+
async beginFrame(frameNumber, isLast) {
|
|
158
|
+
if (this.renderOptions === void 0) throw new Error("No renderOptions");
|
|
159
|
+
const workbench = document.querySelector("ef-workbench");
|
|
160
|
+
if (!workbench) throw new Error("No workbench found");
|
|
161
|
+
workbench.rendering = true;
|
|
162
|
+
const timegroups = shallowGetTimegroups(workbench);
|
|
163
|
+
const firstGroup = timegroups[0];
|
|
164
|
+
if (!firstGroup) throw new Error("No temporal elements found");
|
|
165
|
+
const frameTime = this.renderOptions.encoderOptions.fromMs + frameNumber * this.frameDurationMs;
|
|
166
|
+
firstGroup.currentTimeMs = Number(Number(frameTime).toFixed(5));
|
|
167
|
+
await firstGroup.waitForFrameTasks();
|
|
168
|
+
if (this.showFrameBox) this.frameBox.innerHTML = `
|
|
169
|
+
<div>🖼️ Frame: ${frameNumber}</div>
|
|
170
|
+
<div>🕛 Segment: ${this.time.toFixed(4)}</div>
|
|
171
|
+
<div>🕛 Frame: ${firstGroup.currentTimeMs.toFixed(4)}</div>
|
|
172
|
+
<div> from-to: ${this.renderOptions.encoderOptions.fromMs.toFixed(4)} - ${this.renderOptions.encoderOptions.toMs.toFixed(4)}</div>
|
|
110
173
|
`;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const renderedAudio = await this.audioBufferPromise;
|
|
139
|
-
const channelCount = renderedAudio.numberOfChannels;
|
|
140
|
-
const interleavedSamples = new Float32Array(
|
|
141
|
-
channelCount * renderedAudio.length
|
|
142
|
-
);
|
|
143
|
-
for (let i = 0; i < renderedAudio.length; i++) {
|
|
144
|
-
for (let j = 0; j < channelCount; j++) {
|
|
145
|
-
interleavedSamples.set(
|
|
146
|
-
renderedAudio.getChannelData(j).slice(i, i + 1),
|
|
147
|
-
i * channelCount + j
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (this.BRIDGE) {
|
|
152
|
-
this.BRIDGE.frameReady(frameNumber, interleavedSamples.buffer);
|
|
153
|
-
} else {
|
|
154
|
-
const fileReader = new FileReader();
|
|
155
|
-
fileReader.readAsDataURL(new Blob([interleavedSamples.buffer]));
|
|
156
|
-
await new Promise((resolve, reject) => {
|
|
157
|
-
fileReader.onload = resolve;
|
|
158
|
-
fileReader.onerror = reject;
|
|
159
|
-
});
|
|
160
|
-
return fileReader.result;
|
|
161
|
-
}
|
|
162
|
-
} else {
|
|
163
|
-
if (this.BRIDGE) {
|
|
164
|
-
this.BRIDGE.frameReady(frameNumber, new ArrayBuffer(0));
|
|
165
|
-
} else {
|
|
166
|
-
const fileReader = new FileReader();
|
|
167
|
-
fileReader.readAsDataURL(new Blob([]));
|
|
168
|
-
await new Promise((resolve, reject) => {
|
|
169
|
-
fileReader.onload = resolve;
|
|
170
|
-
fileReader.onerror = reject;
|
|
171
|
-
});
|
|
172
|
-
return fileReader.result;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (typeof window !== "undefined") {
|
|
178
|
-
window.EF_FRAMEGEN = new EFFramegen();
|
|
179
|
-
}
|
|
180
|
-
export {
|
|
181
|
-
EFFramegen
|
|
174
|
+
this.drawVerificationStrip(frameNumber);
|
|
175
|
+
if (isLast && this.audioBufferPromise) {
|
|
176
|
+
const renderedAudio = await this.audioBufferPromise;
|
|
177
|
+
const channelCount = renderedAudio.numberOfChannels;
|
|
178
|
+
const interleavedSamples = new Float32Array(channelCount * renderedAudio.length);
|
|
179
|
+
for (let i = 0; i < renderedAudio.length; i++) for (let j = 0; j < channelCount; j++) interleavedSamples.set(renderedAudio.getChannelData(j).slice(i, i + 1), i * channelCount + j);
|
|
180
|
+
if (this.BRIDGE) this.BRIDGE.frameReady(frameNumber, interleavedSamples.buffer);
|
|
181
|
+
else {
|
|
182
|
+
const fileReader = new FileReader();
|
|
183
|
+
fileReader.readAsDataURL(new Blob([interleavedSamples.buffer]));
|
|
184
|
+
await new Promise((resolve, reject) => {
|
|
185
|
+
fileReader.onload = resolve;
|
|
186
|
+
fileReader.onerror = reject;
|
|
187
|
+
});
|
|
188
|
+
return fileReader.result;
|
|
189
|
+
}
|
|
190
|
+
} else if (this.BRIDGE) this.BRIDGE.frameReady(frameNumber, /* @__PURE__ */ new ArrayBuffer(0));
|
|
191
|
+
else {
|
|
192
|
+
const fileReader = new FileReader();
|
|
193
|
+
fileReader.readAsDataURL(new Blob([]));
|
|
194
|
+
await new Promise((resolve, reject) => {
|
|
195
|
+
fileReader.onload = resolve;
|
|
196
|
+
fileReader.onerror = reject;
|
|
197
|
+
});
|
|
198
|
+
return fileReader.result;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
182
201
|
};
|
|
202
|
+
if (typeof window !== "undefined") window.EF_FRAMEGEN = new EFFramegen();
|
package/dist/EF_INTERACTIVE.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
let EF_INTERACTIVE = false;
|
|
2
|
-
if (typeof window !== "undefined")
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
export {
|
|
6
|
-
EF_INTERACTIVE
|
|
7
|
-
};
|
|
2
|
+
if (typeof window !== "undefined") EF_INTERACTIVE = !window.location?.search.includes("EF_NONINTERACTIVE");
|
|
3
|
+
export { EF_INTERACTIVE };
|
package/dist/EF_RENDERING.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|