@hyperframes/core 0.8.193 → 0.8.194
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/browserMarker.d.ts +3 -0
- package/dist/browserMarker.js +7 -0
- package/dist/compiler/compositionScoping.js +10 -4
- package/dist/compiler/htmlDocument.d.ts +1 -0
- package/dist/compiler/htmlDocument.js +3 -0
- package/dist/compiler/standaloneEntry.d.ts +1 -1
- package/dist/compiler/standaloneEntry.js +1 -3
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/gsapCdn.d.ts +5 -2
- package/dist/gsapCdn.js +20 -4
- package/dist/hyperframe.runtime.iife.js +69 -63
- package/dist/runtime/media.js +8 -1
- package/dist/runtime/preloadMedia.d.ts +1 -0
- package/dist/runtime/preloadMedia.js +43 -1
- package/dist/runtime/startResolver.js +10 -2
- package/package.json +8 -4
package/dist/runtime/media.js
CHANGED
|
@@ -233,6 +233,11 @@ const MIN_NATIVE_PLAYBACK_RATE = 1 / 16;
|
|
|
233
233
|
// A playing video is steered back by rate, not seeked (a seek resets its decoder).
|
|
234
234
|
// Its rate is written only when steering starts or stops: every write costs a frame.
|
|
235
235
|
const VIDEO_STEER = 0.03;
|
|
236
|
+
// A video that starts a cut late closes its lag over one clip at 3%; a bigger lag steers harder, in steps so the rate is written rarely.
|
|
237
|
+
const VIDEO_STEER_STEPS = [
|
|
238
|
+
[0.3, 0.25],
|
|
239
|
+
[0.1, 0.1],
|
|
240
|
+
];
|
|
236
241
|
const VIDEO_STEER_RELEASE_SECONDS = 0.01;
|
|
237
242
|
/** Direction (+1 fast, -1 slow) a video is being steered in; absent when it plays at its authored rate. */
|
|
238
243
|
const videoSteering = new WeakMap();
|
|
@@ -246,7 +251,9 @@ function steeredVideoRate(el, offset, baseRate) {
|
|
|
246
251
|
videoSteering.delete(el);
|
|
247
252
|
return baseRate;
|
|
248
253
|
}
|
|
249
|
-
|
|
254
|
+
const lag = Math.abs(offset);
|
|
255
|
+
const steer = VIDEO_STEER_STEPS.find(([from]) => lag > from)?.[1] ?? VIDEO_STEER;
|
|
256
|
+
return baseRate * (1 + direction * steer);
|
|
250
257
|
}
|
|
251
258
|
// fallow-ignore-next-line complexity
|
|
252
259
|
export function syncRuntimeMedia(params) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
type PreloadableMedia = Pick<HTMLMediaElement, "id" | "tagName" | "getAttribute" | "preload" | "readyState" | "networkState" | "load">;
|
|
2
2
|
export declare function isRenderFrameVideo(media: Pick<Element, "getAttribute" | "id" | "tagName">): boolean;
|
|
3
3
|
export declare function preloadMedia(media: PreloadableMedia): void;
|
|
4
|
+
export declare function prepareUpcomingMedia(media: HTMLMediaElement, isUpcoming: () => boolean): void;
|
|
4
5
|
/** Ends a fetch in flight for good, which preload none alone does not. */
|
|
5
6
|
export declare function stopMediaDownload(media: HTMLMediaElement): void;
|
|
6
7
|
export declare function releaseMedia(media: HTMLMediaElement): void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { parseStrictFiniteTimingNumber } from "./playbackRate.js";
|
|
1
|
+
import { parseStrictFiniteTimingNumber, readMediaStart } from "./playbackRate.js";
|
|
2
2
|
import { createRuntimeStartTimeResolver } from "./startResolver.js";
|
|
3
3
|
import { readMediaRenderId } from "./renderFrameSibling.js";
|
|
4
4
|
import { defersMedia } from "./timedClipHide.js";
|
|
5
|
+
import { swallow } from "./diagnostics.js";
|
|
5
6
|
export function isRenderFrameVideo(media) {
|
|
6
7
|
const ids = window
|
|
7
8
|
.__HF_RENDER_FRAME_VIDEO_IDS;
|
|
@@ -17,8 +18,49 @@ export function preloadMedia(media) {
|
|
|
17
18
|
if (media.readyState < 3 && !videoAlreadyLoading)
|
|
18
19
|
media.load();
|
|
19
20
|
}
|
|
21
|
+
const pendingPlaybackStart = new WeakMap();
|
|
22
|
+
function cancelPlaybackStart(media) {
|
|
23
|
+
pendingPlaybackStart.get(media)?.();
|
|
24
|
+
}
|
|
25
|
+
export function prepareUpcomingMedia(media, isUpcoming) {
|
|
26
|
+
cancelPlaybackStart(media);
|
|
27
|
+
if (media.tagName !== "VIDEO" || isRenderFrameVideo(media))
|
|
28
|
+
return;
|
|
29
|
+
const prepare = () => {
|
|
30
|
+
if (!media.isConnected || !media.paused || media.seeking || !isUpcoming())
|
|
31
|
+
return;
|
|
32
|
+
const start = readMediaStart(media);
|
|
33
|
+
if (Math.abs(media.currentTime - start) <= 0.02)
|
|
34
|
+
return;
|
|
35
|
+
try {
|
|
36
|
+
media.currentTime = start;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
swallow("runtime.preload.playbackStart", error);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
if (media.readyState > 0) {
|
|
43
|
+
prepare();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const cancel = () => {
|
|
47
|
+
media.removeEventListener("loadedmetadata", loaded);
|
|
48
|
+
media.removeEventListener("error", cancel);
|
|
49
|
+
media.removeEventListener("abort", cancel);
|
|
50
|
+
pendingPlaybackStart.delete(media);
|
|
51
|
+
};
|
|
52
|
+
const loaded = () => {
|
|
53
|
+
cancel();
|
|
54
|
+
prepare();
|
|
55
|
+
};
|
|
56
|
+
pendingPlaybackStart.set(media, cancel);
|
|
57
|
+
media.addEventListener("loadedmetadata", loaded);
|
|
58
|
+
media.addEventListener("error", cancel);
|
|
59
|
+
media.addEventListener("abort", cancel);
|
|
60
|
+
}
|
|
20
61
|
/** Ends a fetch in flight for good, which preload none alone does not. */
|
|
21
62
|
export function stopMediaDownload(media) {
|
|
63
|
+
cancelPlaybackStart(media);
|
|
22
64
|
for (const source of media.querySelectorAll("source"))
|
|
23
65
|
source.remove();
|
|
24
66
|
media.removeAttribute("src");
|
|
@@ -14,7 +14,15 @@ export function createRuntimeStartTimeResolver(params) {
|
|
|
14
14
|
const startCache = new WeakMap();
|
|
15
15
|
const durationCache = new WeakMap();
|
|
16
16
|
const visiting = new Set();
|
|
17
|
-
const
|
|
17
|
+
const compositionScopeOf = (element) => (element.hasAttribute("data-composition-id") ? element.parentElement : element)?.closest("[data-composition-id]") ?? null;
|
|
18
|
+
const findReferenceTarget = (refId, from) => {
|
|
19
|
+
const scope = compositionScopeOf(from);
|
|
20
|
+
if (scope) {
|
|
21
|
+
for (const candidate of scope.querySelectorAll(`[id="${refId}"]`)) {
|
|
22
|
+
if (compositionScopeOf(candidate) === scope)
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
18
26
|
const byId = doc.getElementById(refId);
|
|
19
27
|
if (byId)
|
|
20
28
|
return byId;
|
|
@@ -82,7 +90,7 @@ export function createRuntimeStartTimeResolver(params) {
|
|
|
82
90
|
// Negative when a host's in-point is past its start; the host's slot cuts that part.
|
|
83
91
|
return resolveHostOffsetForElement(element, fallback) + Math.max(0, expression.value);
|
|
84
92
|
}
|
|
85
|
-
const target = findReferenceTarget(expression.refId);
|
|
93
|
+
const target = findReferenceTarget(expression.refId, element);
|
|
86
94
|
if (!target)
|
|
87
95
|
return fallback;
|
|
88
96
|
const targetStart = resolveStartForElementInternal(target, 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.194",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
"import": "./dist/safePath.js",
|
|
53
53
|
"types": "./dist/safePath.d.ts"
|
|
54
54
|
},
|
|
55
|
+
"./browser-marker": {
|
|
56
|
+
"import": "./dist/browserMarker.js",
|
|
57
|
+
"types": "./dist/browserMarker.d.ts"
|
|
58
|
+
},
|
|
55
59
|
"./atomic-file": {
|
|
56
60
|
"import": "./dist/atomicFile.js",
|
|
57
61
|
"types": "./dist/atomicFile.d.ts"
|
|
@@ -389,9 +393,9 @@
|
|
|
389
393
|
"linkedom": "^0.18.12",
|
|
390
394
|
"postcss": "^8.5.8",
|
|
391
395
|
"wawoff2": "^2.0.1",
|
|
392
|
-
"@hyperframes/lint": "0.8.
|
|
393
|
-
"@hyperframes/
|
|
394
|
-
"@hyperframes/
|
|
396
|
+
"@hyperframes/lint": "0.8.194",
|
|
397
|
+
"@hyperframes/parsers": "0.8.194",
|
|
398
|
+
"@hyperframes/studio-server": "0.8.194"
|
|
395
399
|
},
|
|
396
400
|
"devDependencies": {
|
|
397
401
|
"@fontsource/archivo-black": "^5.2.8",
|