@maravilla-labs/frames 0.3.2 → 0.4.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 +14 -4
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +111 -2
- package/dist/index.js.map +1 -1
- package/package.json +6 -7
- package/src/index.ts +122 -2
package/README.md
CHANGED
|
@@ -115,15 +115,25 @@ a WAAPI `Animation` object via `Element.getAnimations()`, and drives
|
|
|
115
115
|
its `currentTime` exactly like every other slot. The visual is the
|
|
116
116
|
class's native CSS animation; the timing is yours to control.
|
|
117
117
|
|
|
118
|
-
The stylesheet that defines the keyframes must be loaded before
|
|
119
|
-
|
|
120
|
-
`
|
|
118
|
+
The stylesheet that defines the keyframes must be loaded before the
|
|
119
|
+
animations are materialised — but **you don't need to do anything for
|
|
120
|
+
that**. `defineTimeline` waits internally for render-blocking
|
|
121
|
+
stylesheets and fonts to be ready before it reads the keyframes, so you
|
|
122
|
+
can just call it as soon as your module runs:
|
|
121
123
|
|
|
122
124
|
```ts
|
|
123
|
-
await new Promise(r => addEventListener("load", r, { once: true }));
|
|
124
125
|
defineTimeline({ /* ... */ });
|
|
125
126
|
```
|
|
126
127
|
|
|
128
|
+
> **Do not** gate `defineTimeline` behind the window `load` event
|
|
129
|
+
> (`await new Promise(r => addEventListener("load", r))`). `load` is also
|
|
130
|
+
> held open by `<video preload>` and `<img>`, which on a media-heavy page
|
|
131
|
+
> can take long enough to blow past the Maravilla renderer's readiness
|
|
132
|
+
> budget and fail the render with "timeline never became available."
|
|
133
|
+
> `defineTimeline` already waits for exactly what it needs (stylesheets +
|
|
134
|
+
> fonts) and nothing it doesn't (media). If you need that signal yourself,
|
|
135
|
+
> import `stylesheetsReady()`.
|
|
136
|
+
|
|
127
137
|
This works for any library that exposes its motion as CSS classes
|
|
128
138
|
plus shipped `@keyframes` — Animate.css, Magic, your own custom
|
|
129
139
|
keyframes — not just Animate.css specifically.
|
package/dist/index.d.ts
CHANGED
|
@@ -67,5 +67,26 @@ declare global {
|
|
|
67
67
|
__mvFramesRendererPresent?: boolean;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Declare the page's timeline. **Safe to call as soon as your module runs** —
|
|
72
|
+
* it internally waits for render-blocking stylesheets and fonts to be ready
|
|
73
|
+
* (so CSS keyframes, e.g. Animate.css, are present before animations are
|
|
74
|
+
* materialised) and only then registers `window.__mvFrames`.
|
|
75
|
+
*
|
|
76
|
+
* It deliberately does **NOT** wait for the window `load` event or for media
|
|
77
|
+
* (`<video preload>`, `<img>`). Those can take a long time — long enough to
|
|
78
|
+
* blow past the Maravilla renderer's readiness budget — and aren't needed to
|
|
79
|
+
* build the timeline. **Do not** gate this behind
|
|
80
|
+
* `window.addEventListener('load', …)`; that was an old recommendation and is
|
|
81
|
+
* the classic cause of "renderer timed out waiting for the timeline" on pages
|
|
82
|
+
* with video. `defineTimeline` now owns that readiness so every app gets it
|
|
83
|
+
* right by default.
|
|
84
|
+
*/
|
|
70
85
|
export declare function defineTimeline(schema: TimelineSchema): void;
|
|
86
|
+
/**
|
|
87
|
+
* Resolve once the document's render-blocking stylesheets are applied and web
|
|
88
|
+
* fonts are ready — **without** waiting on the window `load` event or media.
|
|
89
|
+
* Exposed for advanced callers; [`defineTimeline`] already awaits it.
|
|
90
|
+
*/
|
|
91
|
+
export declare function stylesheetsReady(): Promise<void>;
|
|
71
92
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,cAAc,GAAG;IAC3B,yDAAyD;IACzD,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,uDAAuD;IACvD,IAAI,EAAE,OAAO,CAAC;IACd,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,gCAAgC;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,cAAc,GAAG,UAAU,GAAG,aAAa,CAAC;AAChE,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC;AAEzE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,EAAE;YAAE,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;SAAE,CAAC;QACrD,yBAAyB,CAAC,EAAE,OAAO,CAAC;KACrC;CACF;AAaD,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,cAAc,GAAG;IAC3B,yDAAyD;IACzD,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,uDAAuD;IACvD,IAAI,EAAE,OAAO,CAAC;IACd,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,gCAAgC;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,cAAc,GAAG,UAAU,GAAG,aAAa,CAAC;AAChE,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC;AAEzE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,EAAE;YAAE,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;SAAE,CAAC;QACrD,yBAAyB,CAAC,EAAE,OAAO,CAAC;KACrC;CACF;AAaD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAW3D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CA2BhD"}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,60 @@
|
|
|
7
7
|
* - Inside the Maravilla renderer, the timeline is stepped frame by
|
|
8
8
|
* frame to produce deterministic video output.
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* Declare the page's timeline. **Safe to call as soon as your module runs** —
|
|
12
|
+
* it internally waits for render-blocking stylesheets and fonts to be ready
|
|
13
|
+
* (so CSS keyframes, e.g. Animate.css, are present before animations are
|
|
14
|
+
* materialised) and only then registers `window.__mvFrames`.
|
|
15
|
+
*
|
|
16
|
+
* It deliberately does **NOT** wait for the window `load` event or for media
|
|
17
|
+
* (`<video preload>`, `<img>`). Those can take a long time — long enough to
|
|
18
|
+
* blow past the Maravilla renderer's readiness budget — and aren't needed to
|
|
19
|
+
* build the timeline. **Do not** gate this behind
|
|
20
|
+
* `window.addEventListener('load', …)`; that was an old recommendation and is
|
|
21
|
+
* the classic cause of "renderer timed out waiting for the timeline" on pages
|
|
22
|
+
* with video. `defineTimeline` now owns that readiness so every app gets it
|
|
23
|
+
* right by default.
|
|
24
|
+
*/
|
|
10
25
|
export function defineTimeline(schema) {
|
|
26
|
+
stylesheetsReady()
|
|
27
|
+
.then(() => installTimeline(schema))
|
|
28
|
+
.catch((err) => {
|
|
29
|
+
// Surface in the page console (the renderer captures console output) so
|
|
30
|
+
// a bad selector / missing keyframes is debuggable. On failure
|
|
31
|
+
// `__mvFrames` simply never registers and the renderer reports a clean
|
|
32
|
+
// readiness timeout rather than hanging.
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.error("[@maravilla-labs/frames] defineTimeline failed:", err);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Resolve once the document's render-blocking stylesheets are applied and web
|
|
39
|
+
* fonts are ready — **without** waiting on the window `load` event or media.
|
|
40
|
+
* Exposed for advanced callers; [`defineTimeline`] already awaits it.
|
|
41
|
+
*/
|
|
42
|
+
export function stylesheetsReady() {
|
|
43
|
+
if (typeof document === "undefined")
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
const domReady = document.readyState === "loading"
|
|
46
|
+
? new Promise((resolve) => document.addEventListener("DOMContentLoaded", () => resolve(), { once: true }))
|
|
47
|
+
: Promise.resolve();
|
|
48
|
+
return domReady
|
|
49
|
+
.then(() => {
|
|
50
|
+
// A <link rel="stylesheet"> has a null `.sheet` until it has loaded +
|
|
51
|
+
// parsed. Wait for any still-pending ones; `error` resolves too so a
|
|
52
|
+
// missing/broken stylesheet can't hang the timeline.
|
|
53
|
+
const pending = Array.from(document.querySelectorAll('link[rel="stylesheet"]'))
|
|
54
|
+
.filter((link) => !link.sheet)
|
|
55
|
+
.map((link) => new Promise((resolve) => {
|
|
56
|
+
link.addEventListener("load", () => resolve(), { once: true });
|
|
57
|
+
link.addEventListener("error", () => resolve(), { once: true });
|
|
58
|
+
}));
|
|
59
|
+
return Promise.all(pending);
|
|
60
|
+
})
|
|
61
|
+
.then(() => (document.fonts ? document.fonts.ready.then(() => undefined) : undefined));
|
|
62
|
+
}
|
|
63
|
+
function installTimeline(schema) {
|
|
11
64
|
const rendererPresent = typeof window !== "undefined" && window.__mvFramesRendererPresent === true;
|
|
12
65
|
const slots = schema.instructions.flatMap((i) => {
|
|
13
66
|
const el = document.querySelector(i.selector);
|
|
@@ -80,19 +133,28 @@ export function defineTimeline(schema) {
|
|
|
80
133
|
});
|
|
81
134
|
window.__mvFrames = {
|
|
82
135
|
async applyState(t) {
|
|
136
|
+
const videoWaits = [];
|
|
83
137
|
for (const s of slots) {
|
|
84
138
|
if (s.kind === "css-pending")
|
|
85
139
|
continue; // only relevant in browser preview
|
|
86
140
|
const local = clamp(t - s.at, 0, s.duration);
|
|
87
141
|
if (s.kind === "video") {
|
|
88
142
|
s.el.pause();
|
|
89
|
-
|
|
143
|
+
const target = (s.seek + local) / 1000;
|
|
144
|
+
// Seeking is async: the decoded frame for `target` is NOT ready the
|
|
145
|
+
// instant we assign `currentTime`. The renderer captures each frame
|
|
146
|
+
// with a synchronous CDP `beginFrame` right after `applyState`
|
|
147
|
+
// resolves, so we MUST wait for the seek to land and the frame to
|
|
148
|
+
// decode — otherwise we capture a stale/blank frame, or (under
|
|
149
|
+
// deterministic `--enable-begin-frame-control`) race the media
|
|
150
|
+
// pipeline and wedge/crash the headless tab.
|
|
151
|
+
videoWaits.push(seekVideo(s.el, target));
|
|
90
152
|
}
|
|
91
153
|
else {
|
|
92
154
|
s.anim.currentTime = local;
|
|
93
155
|
}
|
|
94
156
|
}
|
|
95
|
-
await document.fonts.ready;
|
|
157
|
+
await Promise.all([document.fonts.ready, ...videoWaits]);
|
|
96
158
|
},
|
|
97
159
|
};
|
|
98
160
|
if (!rendererPresent) {
|
|
@@ -132,4 +194,51 @@ export function defineTimeline(schema) {
|
|
|
132
194
|
function clamp(v, lo, hi) {
|
|
133
195
|
return v < lo ? lo : v > hi ? hi : v;
|
|
134
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Seek `el` to `targetSec` and resolve only once the seeked frame has
|
|
199
|
+
* actually decoded — so a subsequent capture grabs the right frame instead
|
|
200
|
+
* of racing an in-flight seek.
|
|
201
|
+
*
|
|
202
|
+
* Resolution waits for the `seeked` event, then for one decoded video frame
|
|
203
|
+
* via `requestVideoFrameCallback` where available (fallback: a microtask, so
|
|
204
|
+
* we still yield to the decode). A timeout guards against `seeked` never
|
|
205
|
+
* firing (e.g. seeking to the exact current position, or an unsupported
|
|
206
|
+
* codec) so `applyState` can't hang the whole render. Already-satisfied
|
|
207
|
+
* seeks (`readyState` high enough and time already at target) resolve fast.
|
|
208
|
+
*/
|
|
209
|
+
function seekVideo(el, targetSec) {
|
|
210
|
+
const HAVE_CURRENT_DATA = 2;
|
|
211
|
+
// If we're already at (or within a frame of) the target with data ready,
|
|
212
|
+
// there's nothing to wait for — assigning currentTime won't fire `seeked`.
|
|
213
|
+
const alreadyThere = Math.abs(el.currentTime - targetSec) < 1e-3 && el.readyState >= HAVE_CURRENT_DATA;
|
|
214
|
+
el.currentTime = targetSec;
|
|
215
|
+
if (alreadyThere)
|
|
216
|
+
return Promise.resolve();
|
|
217
|
+
return new Promise((resolve) => {
|
|
218
|
+
let done = false;
|
|
219
|
+
const finish = () => {
|
|
220
|
+
if (done)
|
|
221
|
+
return;
|
|
222
|
+
done = true;
|
|
223
|
+
el.removeEventListener("seeked", onSeeked);
|
|
224
|
+
clearTimeout(timer);
|
|
225
|
+
resolve();
|
|
226
|
+
};
|
|
227
|
+
const afterSeeked = () => {
|
|
228
|
+
// Wait for one decoded frame to be presented when the API exists.
|
|
229
|
+
const rvfc = el.requestVideoFrameCallback;
|
|
230
|
+
if (typeof rvfc === "function") {
|
|
231
|
+
rvfc.call(el, () => finish());
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// No rVFC: yield a microtask so the decode can settle, then finish.
|
|
235
|
+
Promise.resolve().then(finish);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const onSeeked = () => afterSeeked();
|
|
239
|
+
el.addEventListener("seeked", onSeeked, { once: true });
|
|
240
|
+
// Guard: never let a missing `seeked` stall the render.
|
|
241
|
+
const timer = setTimeout(finish, 2000);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
135
244
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maravilla-labs/frames",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Tiny vanilla helper for declaring Web Animations API timelines that the Maravilla runtime renderer drives frame-accurately.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,11 +18,6 @@
|
|
|
18
18
|
"README.md",
|
|
19
19
|
"LICENSE"
|
|
20
20
|
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "tsc",
|
|
23
|
-
"typecheck": "tsc --noEmit",
|
|
24
|
-
"prepublishOnly": "tsc"
|
|
25
|
-
},
|
|
26
21
|
"keywords": [
|
|
27
22
|
"maravilla",
|
|
28
23
|
"frames",
|
|
@@ -37,5 +32,9 @@
|
|
|
37
32
|
},
|
|
38
33
|
"publishConfig": {
|
|
39
34
|
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"typecheck": "tsc --noEmit"
|
|
40
39
|
}
|
|
41
|
-
}
|
|
40
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -79,7 +79,69 @@ type CssPendingSlot = {
|
|
|
79
79
|
};
|
|
80
80
|
type Slot = AnimSlot | VideoSlot | CssPendingSlot;
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Declare the page's timeline. **Safe to call as soon as your module runs** —
|
|
84
|
+
* it internally waits for render-blocking stylesheets and fonts to be ready
|
|
85
|
+
* (so CSS keyframes, e.g. Animate.css, are present before animations are
|
|
86
|
+
* materialised) and only then registers `window.__mvFrames`.
|
|
87
|
+
*
|
|
88
|
+
* It deliberately does **NOT** wait for the window `load` event or for media
|
|
89
|
+
* (`<video preload>`, `<img>`). Those can take a long time — long enough to
|
|
90
|
+
* blow past the Maravilla renderer's readiness budget — and aren't needed to
|
|
91
|
+
* build the timeline. **Do not** gate this behind
|
|
92
|
+
* `window.addEventListener('load', …)`; that was an old recommendation and is
|
|
93
|
+
* the classic cause of "renderer timed out waiting for the timeline" on pages
|
|
94
|
+
* with video. `defineTimeline` now owns that readiness so every app gets it
|
|
95
|
+
* right by default.
|
|
96
|
+
*/
|
|
82
97
|
export function defineTimeline(schema: TimelineSchema): void {
|
|
98
|
+
stylesheetsReady()
|
|
99
|
+
.then(() => installTimeline(schema))
|
|
100
|
+
.catch((err) => {
|
|
101
|
+
// Surface in the page console (the renderer captures console output) so
|
|
102
|
+
// a bad selector / missing keyframes is debuggable. On failure
|
|
103
|
+
// `__mvFrames` simply never registers and the renderer reports a clean
|
|
104
|
+
// readiness timeout rather than hanging.
|
|
105
|
+
// eslint-disable-next-line no-console
|
|
106
|
+
console.error("[@maravilla-labs/frames] defineTimeline failed:", err);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Resolve once the document's render-blocking stylesheets are applied and web
|
|
112
|
+
* fonts are ready — **without** waiting on the window `load` event or media.
|
|
113
|
+
* Exposed for advanced callers; [`defineTimeline`] already awaits it.
|
|
114
|
+
*/
|
|
115
|
+
export function stylesheetsReady(): Promise<void> {
|
|
116
|
+
if (typeof document === "undefined") return Promise.resolve();
|
|
117
|
+
const domReady =
|
|
118
|
+
document.readyState === "loading"
|
|
119
|
+
? new Promise<void>((resolve) =>
|
|
120
|
+
document.addEventListener("DOMContentLoaded", () => resolve(), { once: true }),
|
|
121
|
+
)
|
|
122
|
+
: Promise.resolve();
|
|
123
|
+
return domReady
|
|
124
|
+
.then(() => {
|
|
125
|
+
// A <link rel="stylesheet"> has a null `.sheet` until it has loaded +
|
|
126
|
+
// parsed. Wait for any still-pending ones; `error` resolves too so a
|
|
127
|
+
// missing/broken stylesheet can't hang the timeline.
|
|
128
|
+
const pending = Array.from(
|
|
129
|
+
document.querySelectorAll<HTMLLinkElement>('link[rel="stylesheet"]'),
|
|
130
|
+
)
|
|
131
|
+
.filter((link) => !link.sheet)
|
|
132
|
+
.map(
|
|
133
|
+
(link) =>
|
|
134
|
+
new Promise<void>((resolve) => {
|
|
135
|
+
link.addEventListener("load", () => resolve(), { once: true });
|
|
136
|
+
link.addEventListener("error", () => resolve(), { once: true });
|
|
137
|
+
}),
|
|
138
|
+
);
|
|
139
|
+
return Promise.all(pending);
|
|
140
|
+
})
|
|
141
|
+
.then(() => (document.fonts ? document.fonts.ready.then(() => undefined) : undefined));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function installTimeline(schema: TimelineSchema): void {
|
|
83
145
|
const rendererPresent =
|
|
84
146
|
typeof window !== "undefined" && window.__mvFramesRendererPresent === true;
|
|
85
147
|
|
|
@@ -159,17 +221,26 @@ export function defineTimeline(schema: TimelineSchema): void {
|
|
|
159
221
|
|
|
160
222
|
window.__mvFrames = {
|
|
161
223
|
async applyState(t: number) {
|
|
224
|
+
const videoWaits: Promise<void>[] = [];
|
|
162
225
|
for (const s of slots) {
|
|
163
226
|
if (s.kind === "css-pending") continue; // only relevant in browser preview
|
|
164
227
|
const local = clamp(t - s.at, 0, s.duration);
|
|
165
228
|
if (s.kind === "video") {
|
|
166
229
|
s.el.pause();
|
|
167
|
-
|
|
230
|
+
const target = (s.seek + local) / 1000;
|
|
231
|
+
// Seeking is async: the decoded frame for `target` is NOT ready the
|
|
232
|
+
// instant we assign `currentTime`. The renderer captures each frame
|
|
233
|
+
// with a synchronous CDP `beginFrame` right after `applyState`
|
|
234
|
+
// resolves, so we MUST wait for the seek to land and the frame to
|
|
235
|
+
// decode — otherwise we capture a stale/blank frame, or (under
|
|
236
|
+
// deterministic `--enable-begin-frame-control`) race the media
|
|
237
|
+
// pipeline and wedge/crash the headless tab.
|
|
238
|
+
videoWaits.push(seekVideo(s.el, target));
|
|
168
239
|
} else {
|
|
169
240
|
s.anim.currentTime = local;
|
|
170
241
|
}
|
|
171
242
|
}
|
|
172
|
-
await document.fonts.ready;
|
|
243
|
+
await Promise.all([document.fonts.ready, ...videoWaits]);
|
|
173
244
|
},
|
|
174
245
|
};
|
|
175
246
|
|
|
@@ -209,3 +280,52 @@ export function defineTimeline(schema: TimelineSchema): void {
|
|
|
209
280
|
function clamp(v: number, lo: number, hi: number): number {
|
|
210
281
|
return v < lo ? lo : v > hi ? hi : v;
|
|
211
282
|
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Seek `el` to `targetSec` and resolve only once the seeked frame has
|
|
286
|
+
* actually decoded — so a subsequent capture grabs the right frame instead
|
|
287
|
+
* of racing an in-flight seek.
|
|
288
|
+
*
|
|
289
|
+
* Resolution waits for the `seeked` event, then for one decoded video frame
|
|
290
|
+
* via `requestVideoFrameCallback` where available (fallback: a microtask, so
|
|
291
|
+
* we still yield to the decode). A timeout guards against `seeked` never
|
|
292
|
+
* firing (e.g. seeking to the exact current position, or an unsupported
|
|
293
|
+
* codec) so `applyState` can't hang the whole render. Already-satisfied
|
|
294
|
+
* seeks (`readyState` high enough and time already at target) resolve fast.
|
|
295
|
+
*/
|
|
296
|
+
function seekVideo(el: HTMLVideoElement, targetSec: number): Promise<void> {
|
|
297
|
+
const HAVE_CURRENT_DATA = 2;
|
|
298
|
+
// If we're already at (or within a frame of) the target with data ready,
|
|
299
|
+
// there's nothing to wait for — assigning currentTime won't fire `seeked`.
|
|
300
|
+
const alreadyThere =
|
|
301
|
+
Math.abs(el.currentTime - targetSec) < 1e-3 && el.readyState >= HAVE_CURRENT_DATA;
|
|
302
|
+
el.currentTime = targetSec;
|
|
303
|
+
if (alreadyThere) return Promise.resolve();
|
|
304
|
+
|
|
305
|
+
return new Promise<void>((resolve) => {
|
|
306
|
+
let done = false;
|
|
307
|
+
const finish = () => {
|
|
308
|
+
if (done) return;
|
|
309
|
+
done = true;
|
|
310
|
+
el.removeEventListener("seeked", onSeeked);
|
|
311
|
+
clearTimeout(timer);
|
|
312
|
+
resolve();
|
|
313
|
+
};
|
|
314
|
+
const afterSeeked = () => {
|
|
315
|
+
// Wait for one decoded frame to be presented when the API exists.
|
|
316
|
+
const rvfc = (el as unknown as {
|
|
317
|
+
requestVideoFrameCallback?: (cb: () => void) => number;
|
|
318
|
+
}).requestVideoFrameCallback;
|
|
319
|
+
if (typeof rvfc === "function") {
|
|
320
|
+
rvfc.call(el, () => finish());
|
|
321
|
+
} else {
|
|
322
|
+
// No rVFC: yield a microtask so the decode can settle, then finish.
|
|
323
|
+
Promise.resolve().then(finish);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
const onSeeked = () => afterSeeked();
|
|
327
|
+
el.addEventListener("seeked", onSeeked, { once: true });
|
|
328
|
+
// Guard: never let a missing `seeked` stall the render.
|
|
329
|
+
const timer = setTimeout(finish, 2000);
|
|
330
|
+
});
|
|
331
|
+
}
|