@hyperframes/core 0.8.166 → 0.8.168
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/audioGroups.js +2 -5
- package/dist/compiler/compositionAssembly.d.ts +2 -0
- package/dist/compiler/compositionAssembly.js +8 -0
- package/dist/compiler/compositionScoping.js +10 -8
- package/dist/compiler/htmlBundler.js +13 -12
- package/dist/core.types.d.ts +4 -0
- package/dist/core.types.js +5 -0
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/hyperframe.runtime.iife.js +72 -70
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/runtime/adapters/seek-dispatch.d.ts +5 -2
- package/dist/runtime/adapters/seek-dispatch.js +10 -4
- package/dist/runtime/media.js +1 -1
- package/dist/runtime/mediaVolumeEnvelope.d.ts +7 -0
- package/dist/runtime/mediaVolumeEnvelope.js +19 -13
- package/dist/runtime/stackingContext.d.ts +1 -1
- package/dist/runtime/stackingContext.js +9 -1
- package/dist/runtime/timeline.js +4 -3
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export type { RuntimeTimelineClipIdentity } from "./runtime/types.js";
|
|
2
|
-
export type { ExecutionMode, Orientation, Asset, TimelineElement, TimelineElementBase, TimelineMediaElement, TimelineTextElement, TimelineCompositionElement, TimelineElementType, MediaElementType, CanvasResolution, Fps, FpsInput, FpsParseResult, MediaFile, CompositionAPI, PlayerAPI, AddElementData, ValidationResult, CompositionAsset, Keyframe, KeyframeProperties, ElementKeyframes, StageZoom, StageZoomKeyframe, CompositionVariableType, CompositionVariableBase, StringVariable, NumberVariable, ColorVariable, BooleanVariable, EnumVariable, CompositionVariable, CompositionSpec, WaveformData, OutputResolutionCompatibility, OutputResolutionIssueKind, } from "./core.types.js";
|
|
2
|
+
export type { ExecutionMode, Orientation, Asset, TimelineElement, TimelineElementBase, TimelineMediaElement, TimelineTextElement, TimelineCompositionElement, TimelineElementType, MediaElementType, CanvasResolution, Fps, FpsInput, DistributedFps, FpsParseResult, MediaFile, CompositionAPI, PlayerAPI, AddElementData, ValidationResult, CompositionAsset, Keyframe, KeyframeProperties, ElementKeyframes, StageZoom, StageZoomKeyframe, CompositionVariableType, CompositionVariableBase, StringVariable, NumberVariable, ColorVariable, BooleanVariable, EnumVariable, CompositionVariable, CompositionSpec, WaveformData, OutputResolutionCompatibility, OutputResolutionIssueKind, } from "./core.types.js";
|
|
3
3
|
export type { SlideshowManifest, SlideRef, SlideHotspot, SlideSequence, ResolvedSlide, ResolvedSlideSequence, ResolvedSlideshow, } from "./slideshow/index.js";
|
|
4
4
|
export { parseSlideshowManifest, resolveSlideshow } from "./slideshow/index.js";
|
|
5
5
|
export type { AuthoredTimingValue, RawAuthoredTiming, AuthoredTimingWindow, } from "./runtime/authoredTiming.js";
|
|
6
6
|
export { resolveAuthoredTimingWindow } from "./runtime/authoredTiming.js";
|
|
7
|
-
export { CANVAS_DIMENSIONS, VALID_CANVAS_RESOLUTIONS, normalizeResolutionFlag, isAspectAgnosticResolutionAlias, resolveResolutionFlagPair, checkOutputResolutionCompatibility, suggestMatchingPreset, parseFps, parseFpsWithDefault, toFps, fpsToNumber, fpsToFfmpegArg, TIMELINE_COLORS, DEFAULT_DURATIONS, COMPOSITION_VARIABLE_TYPES, isTextElement, isMediaElement, isCompositionElement, getDefaultStageZoom, } from "./core.types.js";
|
|
7
|
+
export { CANVAS_DIMENSIONS, VALID_CANVAS_RESOLUTIONS, normalizeResolutionFlag, isAspectAgnosticResolutionAlias, resolveResolutionFlagPair, checkOutputResolutionCompatibility, suggestMatchingPreset, parseFps, parseFpsWithDefault, toFps, fpsToNumber, fpsToFfmpegArg, DISTRIBUTED_FPS, isDistributedFps, TIMELINE_COLORS, DEFAULT_DURATIONS, COMPOSITION_VARIABLE_TYPES, isTextElement, isMediaElement, isCompositionElement, getDefaultStageZoom, } from "./core.types.js";
|
|
8
8
|
export { generateBaseHtml, getStageStyles } from "./templates/base.js";
|
|
9
9
|
export { GSAP_CDN, BASE_STYLES, ELEMENT_BASE_STYLES, MEDIA_STYLES, TEXT_STYLES, ZOOM_CONTAINER_STYLES, } from "./templates/constants.js";
|
|
10
10
|
export type { GsapAnimation, GsapMethod, ParsedGsap } from "@hyperframes/parsers";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { parseSlideshowManifest, resolveSlideshow } from "./slideshow/index.js";
|
|
2
2
|
export { resolveAuthoredTimingWindow } from "./runtime/authoredTiming.js";
|
|
3
|
-
export { CANVAS_DIMENSIONS, VALID_CANVAS_RESOLUTIONS, normalizeResolutionFlag, isAspectAgnosticResolutionAlias, resolveResolutionFlagPair, checkOutputResolutionCompatibility, suggestMatchingPreset, parseFps, parseFpsWithDefault, toFps, fpsToNumber, fpsToFfmpegArg, TIMELINE_COLORS, DEFAULT_DURATIONS, COMPOSITION_VARIABLE_TYPES, isTextElement, isMediaElement, isCompositionElement, getDefaultStageZoom, } from "./core.types.js";
|
|
3
|
+
export { CANVAS_DIMENSIONS, VALID_CANVAS_RESOLUTIONS, normalizeResolutionFlag, isAspectAgnosticResolutionAlias, resolveResolutionFlagPair, checkOutputResolutionCompatibility, suggestMatchingPreset, parseFps, parseFpsWithDefault, toFps, fpsToNumber, fpsToFfmpegArg, DISTRIBUTED_FPS, isDistributedFps, TIMELINE_COLORS, DEFAULT_DURATIONS, COMPOSITION_VARIABLE_TYPES, isTextElement, isMediaElement, isCompositionElement, getDefaultStageZoom, } from "./core.types.js";
|
|
4
4
|
// Templates
|
|
5
5
|
export { generateBaseHtml, getStageStyles } from "./templates/base.js";
|
|
6
6
|
export { GSAP_CDN, BASE_STYLES, ELEMENT_BASE_STYLES, MEDIA_STYLES, TEXT_STYLES, ZOOM_CONTAINER_STYLES, } from "./templates/constants.js";
|
|
@@ -12,7 +12,7 @@ export interface HfSeekEventDetail {
|
|
|
12
12
|
* its preview-side capture here, so the CLI seek paths that already await this
|
|
13
13
|
* barrier wait for a `self` chain's paint instead of racing it.
|
|
14
14
|
*/
|
|
15
|
-
export declare function registerSeekCompletion(promise: Promise<unknown
|
|
15
|
+
export declare function registerSeekCompletion(promise: Promise<unknown>, kind?: "video-frame"): void;
|
|
16
16
|
export declare function dispatchSeekEvent(time: number): void;
|
|
17
17
|
/**
|
|
18
18
|
* Force-dispatch a `"hf-seek"` event even if `time` equals the last dispatched
|
|
@@ -26,6 +26,9 @@ export declare function dispatchSeekEvent(time: number): void;
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function forceDispatchSeekEvent(time: number): void;
|
|
28
28
|
export declare function isSeekCompletionBarrierActive(): boolean;
|
|
29
|
-
|
|
29
|
+
/** `videoFrames: false` skips only the video-frame holds: a geometry read needs every other completion. */
|
|
30
|
+
export declare function waitForSeekCompletion(options?: {
|
|
31
|
+
videoFrames?: boolean;
|
|
32
|
+
}): Promise<void>;
|
|
30
33
|
/** Reset internal state — used in tests to prevent cross-test contamination. */
|
|
31
34
|
export declare function resetSeekDispatchState(): void;
|
|
@@ -18,6 +18,7 @@ import { swallow } from "../diagnostics.js";
|
|
|
18
18
|
*/
|
|
19
19
|
let _lastDispatchedTime = -1;
|
|
20
20
|
let _pendingCompletions = new Set();
|
|
21
|
+
let _videoFrameCompletions = new WeakSet();
|
|
21
22
|
let _pendingFailure;
|
|
22
23
|
let _activeCompletionBarriers = 0;
|
|
23
24
|
function dispatch(time) {
|
|
@@ -55,11 +56,13 @@ function dispatch(time) {
|
|
|
55
56
|
* its preview-side capture here, so the CLI seek paths that already await this
|
|
56
57
|
* barrier wait for a `self` chain's paint instead of racing it.
|
|
57
58
|
*/
|
|
58
|
-
export function registerSeekCompletion(promise) {
|
|
59
|
+
export function registerSeekCompletion(promise, kind) {
|
|
59
60
|
const completion = promise
|
|
60
61
|
.then(() => ({ status: "fulfilled" }))
|
|
61
62
|
.catch((reason) => ({ status: "rejected", reason }));
|
|
62
63
|
_pendingCompletions.add(completion);
|
|
64
|
+
if (kind === "video-frame")
|
|
65
|
+
_videoFrameCompletions.add(completion);
|
|
63
66
|
void completion.then((result) => {
|
|
64
67
|
if (!_pendingCompletions.delete(completion))
|
|
65
68
|
return;
|
|
@@ -91,15 +94,17 @@ export function forceDispatchSeekEvent(time) {
|
|
|
91
94
|
export function isSeekCompletionBarrierActive() {
|
|
92
95
|
return _activeCompletionBarriers > 0;
|
|
93
96
|
}
|
|
94
|
-
|
|
97
|
+
/** `videoFrames: false` skips only the video-frame holds: a geometry read needs every other completion. */
|
|
98
|
+
export async function waitForSeekCompletion(options) {
|
|
99
|
+
const awaited = () => [..._pendingCompletions].filter((completion) => options?.videoFrames !== false || !_videoFrameCompletions.has(completion));
|
|
95
100
|
_activeCompletionBarriers += 1;
|
|
96
101
|
let failed = _pendingFailure;
|
|
97
102
|
try {
|
|
98
103
|
// Let concurrently started barriers snapshot the same retained failure
|
|
99
104
|
// before either one consumes it.
|
|
100
105
|
await Promise.resolve();
|
|
101
|
-
|
|
102
|
-
const results = await Promise.all(
|
|
106
|
+
for (let pending = awaited(); pending.length > 0; pending = awaited()) {
|
|
107
|
+
const results = await Promise.all(pending);
|
|
103
108
|
const rejected = results.find((result) => result.status === "rejected");
|
|
104
109
|
if (failed === undefined && rejected?.status === "rejected") {
|
|
105
110
|
failed = { reason: rejected.reason };
|
|
@@ -123,6 +128,7 @@ export async function waitForSeekCompletion() {
|
|
|
123
128
|
export function resetSeekDispatchState() {
|
|
124
129
|
_lastDispatchedTime = -1;
|
|
125
130
|
_pendingCompletions = new Set();
|
|
131
|
+
_videoFrameCompletions = new WeakSet();
|
|
126
132
|
_pendingFailure = undefined;
|
|
127
133
|
_activeCompletionBarriers = 0;
|
|
128
134
|
}
|
package/dist/runtime/media.js
CHANGED
|
@@ -43,7 +43,7 @@ function holdSeekBarrierUntilVideoLands(el) {
|
|
|
43
43
|
for (const type of HOLD_END_EVENTS)
|
|
44
44
|
el.addEventListener(type, done, true);
|
|
45
45
|
releaseHeldVideo.set(el, done);
|
|
46
|
-
}));
|
|
46
|
+
}), "video-frame");
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
49
|
* Resolve a media element's timeline window without conflating a video's
|
|
@@ -48,7 +48,14 @@ export interface VolumeProbeOptions {
|
|
|
48
48
|
* Preview callers omit this option and retain live automation discovery.
|
|
49
49
|
*/
|
|
50
50
|
allowLiveTimelineSeek?: boolean;
|
|
51
|
+
movers?: () => VolumeMovers;
|
|
51
52
|
}
|
|
53
|
+
export interface VolumeMovers {
|
|
54
|
+
elements: Set<unknown>;
|
|
55
|
+
anySetter: boolean;
|
|
56
|
+
unknown: boolean;
|
|
57
|
+
}
|
|
58
|
+
export declare function volumeMoversOf(timeline: RuntimeTimelineRef): VolumeMovers;
|
|
52
59
|
/**
|
|
53
60
|
* Probe a media element and, if volume automation is detected, store a
|
|
54
61
|
* NORMALISED envelope in `cache`. Safe to call with a null timeline — returns
|
|
@@ -161,25 +161,31 @@ function hasSetter(target, key) {
|
|
|
161
161
|
}
|
|
162
162
|
return false;
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
* on a non-DOM object whose tweened property is a setter (a gain proxy). Spacers, calls and counters skip.
|
|
167
|
-
*/
|
|
168
|
-
function timelineCanMoveVolume(timeline, el) {
|
|
164
|
+
export function volumeMoversOf(timeline) {
|
|
165
|
+
const unknown = { elements: new Set(), anySetter: false, unknown: true };
|
|
169
166
|
if (typeof timeline.getChildren !== "function")
|
|
170
|
-
return
|
|
167
|
+
return unknown;
|
|
171
168
|
try {
|
|
172
|
-
|
|
169
|
+
const movers = { elements: new Set(), anySetter: false, unknown: false };
|
|
170
|
+
for (const tween of timeline.getChildren(true, true, false)) {
|
|
173
171
|
const targets = tween.targets?.() ?? [];
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
for (const target of targets) {
|
|
173
|
+
if (isDomNode(target)) {
|
|
174
|
+
if (namesKey(tween.vars, (key) => key === "volume"))
|
|
175
|
+
movers.elements.add(target);
|
|
176
|
+
}
|
|
177
|
+
else if (!movers.anySetter && namesKey(tween.vars, (key) => hasSetter(target, key))) {
|
|
178
|
+
movers.anySetter = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return movers;
|
|
178
183
|
}
|
|
179
184
|
catch {
|
|
180
|
-
return
|
|
185
|
+
return unknown;
|
|
181
186
|
}
|
|
182
187
|
}
|
|
188
|
+
const canMoveVolume = (movers, el) => movers.unknown || movers.anySetter || movers.elements.has(el);
|
|
183
189
|
/**
|
|
184
190
|
* Probe a media element and, if volume automation is detected, store a
|
|
185
191
|
* NORMALISED envelope in `cache`. Safe to call with a null timeline — returns
|
|
@@ -201,7 +207,7 @@ export function probeAndCacheElementVolume(mediaEl, timeline, compositionDuratio
|
|
|
201
207
|
if (compositionDuration <= 0)
|
|
202
208
|
return;
|
|
203
209
|
// Sampling is ~60 whole-timeline seeks per second of clip, paid again on every rebind.
|
|
204
|
-
if (!
|
|
210
|
+
if (!canMoveVolume(options.movers?.() ?? volumeMoversOf(timeline), mediaEl))
|
|
205
211
|
return;
|
|
206
212
|
const seekFn = (t) => {
|
|
207
213
|
try {
|
|
@@ -4,4 +4,4 @@ export declare const ROOT_CSS_STACKING_CONTEXT_ID = "css:root";
|
|
|
4
4
|
* the leaf itself: an element that establishes a context still compares its own
|
|
5
5
|
* z-index with siblings in its parent's context.
|
|
6
6
|
*/
|
|
7
|
-
export declare function resolveCssStackingContextId(node: Element): string;
|
|
7
|
+
export declare function resolveCssStackingContextId(node: Element, byParent?: Map<Element | null, string>): string;
|
|
@@ -94,7 +94,15 @@ function cssStackingContextPath(element) {
|
|
|
94
94
|
* the leaf itself: an element that establishes a context still compares its own
|
|
95
95
|
* z-index with siblings in its parent's context.
|
|
96
96
|
*/
|
|
97
|
-
export function resolveCssStackingContextId(node) {
|
|
97
|
+
export function resolveCssStackingContextId(node, byParent) {
|
|
98
|
+
const known = byParent?.get(node.parentElement);
|
|
99
|
+
if (known !== undefined)
|
|
100
|
+
return known;
|
|
101
|
+
const id = nearestCssStackingContextId(node);
|
|
102
|
+
byParent?.set(node.parentElement, id);
|
|
103
|
+
return id;
|
|
104
|
+
}
|
|
105
|
+
function nearestCssStackingContextId(node) {
|
|
98
106
|
const win = node.ownerDocument.defaultView;
|
|
99
107
|
if (!win)
|
|
100
108
|
return ROOT_CSS_STACKING_CONTEXT_ID;
|
package/dist/runtime/timeline.js
CHANGED
|
@@ -207,6 +207,7 @@ function buildTimelineClipLabel(node, kind, ordinal) {
|
|
|
207
207
|
return `${humanizeTimelineToken(kind)} ${ordinal + 1}`;
|
|
208
208
|
}
|
|
209
209
|
export function collectRuntimeTimelinePayload(params) {
|
|
210
|
+
const stackingByParent = new Map();
|
|
210
211
|
const runtimeWindow = window;
|
|
211
212
|
const timelineRegistry = runtimeWindow.__timelines ?? {};
|
|
212
213
|
const startResolver = createRuntimeStartTimeResolver({
|
|
@@ -409,7 +410,7 @@ export function collectRuntimeTimelinePayload(params) {
|
|
|
409
410
|
duration,
|
|
410
411
|
track: parseAuthoredTrack(node, i),
|
|
411
412
|
zIndex: readInlineZIndex(node),
|
|
412
|
-
stackingContextId: resolveCssStackingContextId(node),
|
|
413
|
+
stackingContextId: resolveCssStackingContextId(node, stackingByParent),
|
|
413
414
|
kind,
|
|
414
415
|
tagName: tag,
|
|
415
416
|
compositionId: node.getAttribute("data-composition-id"),
|
|
@@ -524,7 +525,7 @@ export function collectRuntimeTimelinePayload(params) {
|
|
|
524
525
|
duration: clampedDuration,
|
|
525
526
|
track: parseAuthoredTrack(el, gsapTrack),
|
|
526
527
|
zIndex: readInlineZIndex(el),
|
|
527
|
-
stackingContextId: resolveCssStackingContextId(el),
|
|
528
|
+
stackingContextId: resolveCssStackingContextId(el, stackingByParent),
|
|
528
529
|
kind: "element",
|
|
529
530
|
tagName: el.tagName.toLowerCase(),
|
|
530
531
|
compositionId: el.getAttribute("data-composition-id"),
|
|
@@ -586,7 +587,7 @@ export function collectRuntimeTimelinePayload(params) {
|
|
|
586
587
|
duration: clampedDuration,
|
|
587
588
|
track: parseAuthoredTrack(el, overlayTrack),
|
|
588
589
|
zIndex: readInlineZIndex(el),
|
|
589
|
-
stackingContextId: resolveCssStackingContextId(el),
|
|
590
|
+
stackingContextId: resolveCssStackingContextId(el, stackingByParent),
|
|
590
591
|
kind: "element",
|
|
591
592
|
tagName: tag,
|
|
592
593
|
compositionId: el.getAttribute("data-composition-id"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.168",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -377,9 +377,9 @@
|
|
|
377
377
|
"linkedom": "^0.18.12",
|
|
378
378
|
"postcss": "^8.5.8",
|
|
379
379
|
"wawoff2": "^2.0.1",
|
|
380
|
-
"@hyperframes/lint": "0.8.
|
|
381
|
-
"@hyperframes/parsers": "0.8.
|
|
382
|
-
"@hyperframes/studio-server": "0.8.
|
|
380
|
+
"@hyperframes/lint": "0.8.168",
|
|
381
|
+
"@hyperframes/parsers": "0.8.168",
|
|
382
|
+
"@hyperframes/studio-server": "0.8.168"
|
|
383
383
|
},
|
|
384
384
|
"devDependencies": {
|
|
385
385
|
"@fontsource/archivo-black": "^5.2.8",
|