@hyperframes/inspector 0.0.0-stage → 0.8.152
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/LICENSE +190 -0
- package/README.md +104 -2
- package/dist/inspection.js +2007 -0
- package/dist/live.js +1288 -0
- package/dist/service.js +63122 -0
- package/dist/types/core/src/audioAutomation.d.ts +202 -0
- package/dist/types/core/src/audioFx.d.ts +181 -0
- package/dist/types/core/src/audioGain.d.ts +44 -0
- package/dist/types/core/src/colorGrading.d.ts +1959 -0
- package/dist/types/core/src/colorGradingCurves.d.ts +8 -0
- package/dist/types/core/src/colorLuts.d.ts +24 -0
- package/dist/types/core/src/compiler/assetPaths.d.ts +1 -0
- package/dist/types/core/src/compiler/compositionAssembly.d.ts +144 -0
- package/dist/types/core/src/compiler/compositionScoping.d.ts +28 -0
- package/dist/types/core/src/compiler/externalScripts.d.ts +8 -0
- package/dist/types/core/src/compiler/htmlBundler.d.ts +74 -0
- package/dist/types/core/src/compiler/htmlCompiler.d.ts +18 -0
- package/dist/types/core/src/compiler/htmlDocument.d.ts +23 -0
- package/dist/types/core/src/compiler/importMaps.d.ts +18 -0
- package/dist/types/core/src/compiler/inlineSubCompositions.d.ts +151 -0
- package/dist/types/core/src/compiler/rewriteSubCompPaths.d.ts +1 -0
- package/dist/types/core/src/compiler/scriptRuns.d.ts +31 -0
- package/dist/types/core/src/compiler/selectorIdTokens.d.ts +70 -0
- package/dist/types/core/src/compiler/standaloneEntry.d.ts +2 -0
- package/dist/types/core/src/compiler/staticGuard.d.ts +7 -0
- package/dist/types/core/src/compiler/svgIdNamespacing.d.ts +80 -0
- package/dist/types/core/src/compiler/svgSelectorAliases.d.ts +30 -0
- package/dist/types/core/src/compiler/timingCompiler.d.ts +89 -0
- package/dist/types/core/src/generated/runtime-inline.d.ts +6 -0
- package/dist/types/core/src/generated/svg-selector-aliases-inline.d.ts +2 -0
- package/dist/types/core/src/inline-scripts/pickerApi.d.ts +32 -0
- package/dist/types/core/src/inline-scripts/runtimeContract.d.ts +13 -0
- package/dist/types/core/src/mediaTiming.d.ts +41 -0
- package/dist/types/core/src/playbackRateBounds.d.ts +1 -0
- package/dist/types/core/src/runtime/analytics.d.ts +18 -0
- package/dist/types/core/src/runtime/applyVariableBindings.d.ts +47 -0
- package/dist/types/core/src/runtime/audioAutomationVolume.d.ts +19 -0
- package/dist/types/core/src/runtime/authoredTiming.d.ts +16 -0
- package/dist/types/core/src/runtime/compositionDimension.d.ts +5 -0
- package/dist/types/core/src/runtime/diagnostics.d.ts +3 -0
- package/dist/types/core/src/runtime/domRealm.d.ts +67 -0
- package/dist/types/core/src/runtime/flattenedRoot.d.ts +9 -0
- package/dist/types/core/src/runtime/getVariables.d.ts +42 -0
- package/dist/types/core/src/runtime/globals.d.ts +11 -0
- package/dist/types/core/src/runtime/inspectionTypes.d.ts +68 -0
- package/dist/types/core/src/runtime/playbackRate.d.ts +26 -0
- package/dist/types/core/src/runtime/protocol.d.ts +30 -0
- package/dist/types/core/src/runtime/proxySrc.d.ts +3 -0
- package/dist/types/core/src/runtime/startExpression.d.ts +14 -0
- package/dist/types/core/src/runtime/startResolver.d.ts +21 -0
- package/dist/types/core/src/runtime/timelineDuration.d.ts +3 -0
- package/dist/types/core/src/runtime/timelineInspection.d.ts +46 -0
- package/dist/types/core/src/runtime/timelineValues.d.ts +15 -0
- package/dist/types/core/src/runtime/types.d.ts +335 -0
- package/dist/types/core/src/runtime/variableScope.d.ts +8 -0
- package/dist/types/core/src/safePath.d.ts +49 -0
- package/dist/types/core/src/sceneParts.d.ts +9 -0
- package/dist/types/core/src/speedRamp.d.ts +59 -0
- package/dist/types/core/src/tokenSlug.d.ts +12 -0
- package/dist/types/inspector/src/elementMap.d.ts +33 -0
- package/dist/types/inspector/src/engine.d.ts +35 -0
- package/dist/types/inspector/src/live.d.ts +18 -0
- package/dist/types/inspector/src/mapInspection.d.ts +76 -0
- package/dist/types/inspector/src/outputSchemas.d.ts +12 -0
- package/dist/types/inspector/src/pageQueries.d.ts +21 -0
- package/dist/types/inspector/src/pageServer.d.ts +2 -0
- package/dist/types/inspector/src/requests.d.ts +5 -0
- package/dist/types/inspector/src/service.d.ts +98 -0
- package/dist/types/inspector/src/sourceDependencies.d.ts +5 -0
- package/dist/types/inspector/src/sources.d.ts +49 -0
- package/dist/types/inspector/src/timelineReport.d.ts +28 -0
- package/dist/types/inspector/src/tools.d.ts +18 -0
- package/dist/types/inspector/src/types.d.ts +1 -0
- package/package.json +54 -3
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const RUNTIME_PROTOCOL_VERSION: 1;
|
|
2
|
+
export declare const RUNTIME_FILLER = "hf-runtime-filler";
|
|
3
|
+
export declare const RUNTIME_PROTOCOL_CAPABILITIES: readonly ["seconds-time", "rational-fps", "seek-keep-playing", "composition-manifest-v1", "runtime-data", "play-range"];
|
|
4
|
+
export type RuntimeProtocolFps = {
|
|
5
|
+
numerator: number;
|
|
6
|
+
denominator: number;
|
|
7
|
+
};
|
|
8
|
+
export type RuntimeProtocolV1 = {
|
|
9
|
+
protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
10
|
+
capabilities: readonly string[];
|
|
11
|
+
fps: RuntimeProtocolFps;
|
|
12
|
+
};
|
|
13
|
+
export type RuntimeProtocolInspection = {
|
|
14
|
+
status: "legacy";
|
|
15
|
+
fps: number;
|
|
16
|
+
} | {
|
|
17
|
+
status: "supported";
|
|
18
|
+
fps: number;
|
|
19
|
+
metadata: RuntimeProtocolV1;
|
|
20
|
+
} | {
|
|
21
|
+
status: "unsupported";
|
|
22
|
+
code: "unsupported_protocol_version" | "invalid_protocol_metadata";
|
|
23
|
+
receivedVersion: unknown;
|
|
24
|
+
};
|
|
25
|
+
export declare function runtimeProtocolFpsFromNumber(value: number): RuntimeProtocolFps;
|
|
26
|
+
export declare function playRangeHoldTime(start: number, end: number, fps: number): number;
|
|
27
|
+
export declare function runtimeProtocolFpsToNumber(value: unknown): number | null;
|
|
28
|
+
export declare function runtimeProtocolMetadata(fps: number): RuntimeProtocolV1;
|
|
29
|
+
export declare function frameDisplayScale(frame: HTMLElement): number | null;
|
|
30
|
+
export declare function inspectRuntimeProtocol(value: unknown, legacyFps?: number): RuntimeProtocolInspection;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure parser for the `data-start` timing expression grammar, shared by the
|
|
3
|
+
* browser runtime resolver (`createRuntimeStartTimeResolver`) and the Node-side
|
|
4
|
+
* video-frame extractor (`parseVideoElements`) so both agree on exactly what a
|
|
5
|
+
* relative reference means. No DOM/browser dependencies — safe to import in
|
|
6
|
+
* Node.
|
|
7
|
+
*
|
|
8
|
+
* Grammar (matches the docs' "Relative Timing" section):
|
|
9
|
+
* - `"12.5"` -> absolute seconds
|
|
10
|
+
* - `"intro"` -> start when clip `intro` ends
|
|
11
|
+
* - `"intro + 2"` -> 2s after `intro` ends
|
|
12
|
+
* - `"intro - 0.5"` -> 0.5s before `intro` ends (overlap)
|
|
13
|
+
*/
|
|
14
|
+
export { parseNumeric, parseStartExpression, type ReferenceExpression, } from "@hyperframes/parsers/composition-contract";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RuntimeTimelineLike } from "./types.js";
|
|
2
|
+
import { type HostSlot } from "../mediaTiming.js";
|
|
3
|
+
export declare function createRuntimeStartTimeResolver(params: {
|
|
4
|
+
timelineRegistry?: Record<string, Pick<RuntimeTimelineLike, "duration"> | undefined>;
|
|
5
|
+
includeAuthoredTimingAttrs?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* The document that reference lookups (`data-start="intro + 2"`) resolve
|
|
8
|
+
* against. Defaults to the global `document` — the runtime bundle's own
|
|
9
|
+
* realm. Hosts driving a composition in an IFRAME must pass that iframe's
|
|
10
|
+
* document, or every reference silently resolves against the host page.
|
|
11
|
+
*/
|
|
12
|
+
documentRef?: Document;
|
|
13
|
+
}): {
|
|
14
|
+
resolveStartForElement: (element: Element, fallback?: number) => number;
|
|
15
|
+
resolveDurationForElement: (element: Element) => number | null;
|
|
16
|
+
resolveMediaStartForElement: (element: Element) => number;
|
|
17
|
+
resolveHostStartForElement: (element: Element) => number;
|
|
18
|
+
resolveHostSlotsForElement: (element: Element) => HostSlot[];
|
|
19
|
+
isRootGlobalMediaStartForElement: (element: Element) => boolean;
|
|
20
|
+
};
|
|
21
|
+
export type { RuntimeTimelineLike } from "./types.js";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RuntimeTimelineLike } from "./types.js";
|
|
2
|
+
/** A registered timeline's finite duration(); a partial, throwing or non-numeric entry reads as null. */
|
|
3
|
+
export declare function readTimelineDurationSeconds(timeline: Pick<RuntimeTimelineLike, "duration"> | null | undefined): number | null;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type AnimationValues } from "./timelineValues.js";
|
|
2
|
+
import type { ElementRef, Target } from "./inspectionTypes.js";
|
|
3
|
+
export interface TimelineRequest {
|
|
4
|
+
component?: Target;
|
|
5
|
+
at?: number;
|
|
6
|
+
range?: [number, number];
|
|
7
|
+
boundary?: number;
|
|
8
|
+
generation?: string;
|
|
9
|
+
offset?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface TimedAnimation {
|
|
12
|
+
parent?: TimedAnimation;
|
|
13
|
+
timeline?: TimedAnimation;
|
|
14
|
+
_ease?: (progress: number) => number;
|
|
15
|
+
vars?: Record<string, unknown>;
|
|
16
|
+
targets?: () => unknown[];
|
|
17
|
+
getChildren?: (nested: boolean, tweens: boolean, timelines: boolean) => TimedAnimation[];
|
|
18
|
+
startTime(): number;
|
|
19
|
+
duration(): number;
|
|
20
|
+
totalDuration?(): number;
|
|
21
|
+
timeScale?(): number;
|
|
22
|
+
repeat?(): number;
|
|
23
|
+
repeatDelay?(): number;
|
|
24
|
+
yoyo?(): boolean;
|
|
25
|
+
paused?(): boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface Interval {
|
|
28
|
+
start: number;
|
|
29
|
+
end: number;
|
|
30
|
+
}
|
|
31
|
+
export interface TimelineEvent extends Interval {
|
|
32
|
+
kind: "animation" | "item";
|
|
33
|
+
relation: string;
|
|
34
|
+
component: ElementRef | null;
|
|
35
|
+
targets: ElementRef[];
|
|
36
|
+
properties: string[];
|
|
37
|
+
values?: AnimationValues;
|
|
38
|
+
stack: string | null;
|
|
39
|
+
}
|
|
40
|
+
export interface TimelineRuntimeResult {
|
|
41
|
+
status: string;
|
|
42
|
+
candidates: ElementRef[];
|
|
43
|
+
events: TimelineEvent[];
|
|
44
|
+
warnings: string[];
|
|
45
|
+
}
|
|
46
|
+
export declare function inspectTimelineRuntime(q: TimelineRequest, roots: TimedAnimation[], scope: Element, describe: (el: Element) => ElementRef, origin: (a: TimedAnimation) => string | null, reserved: Set<string>, registry: Record<string, TimedAnimation>): TimelineRuntimeResult;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface DeclaredValue {
|
|
2
|
+
kind: "literal" | "relative" | "expression" | "unknown";
|
|
3
|
+
value: number | string | null;
|
|
4
|
+
}
|
|
5
|
+
export interface AnimationValues {
|
|
6
|
+
basis: "authored-tween";
|
|
7
|
+
properties: Array<{
|
|
8
|
+
property: string;
|
|
9
|
+
from: DeclaredValue;
|
|
10
|
+
to: DeclaredValue;
|
|
11
|
+
}>;
|
|
12
|
+
ease: DeclaredValue;
|
|
13
|
+
}
|
|
14
|
+
/** Authored endpoints, never sampled values or inferred previous-tween state. */
|
|
15
|
+
export declare function animationValues(vars: Record<string, unknown>, properties: string[]): AnimationValues;
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import type { HfColorGradingTarget } from "../colorGrading.js";
|
|
2
|
+
import type { RuntimeAnalyticsEvent } from "./analytics.js";
|
|
3
|
+
export type RuntimeJson = string | number | boolean | null | RuntimeJson[] | {
|
|
4
|
+
[key: string]: RuntimeJson;
|
|
5
|
+
};
|
|
6
|
+
import type { HyperframeControlAction } from "../inline-scripts/runtimeContract.js";
|
|
7
|
+
import type { HyperframePickerElementInfo } from "../inline-scripts/pickerApi.js";
|
|
8
|
+
import type { RuntimeProtocolV1 } from "./protocol.js";
|
|
9
|
+
type RuntimeBridgeControlActionBase = HyperframeControlAction | "tick" | "set-volume" | "set-media-output-muted" | "set-native-media-sync-disabled" | "set-web-audio-media-disabled" | "set-idle-heartbeat" | "set-display-scale" | "set-root-duration" | "set-play-range" | "stop-media" | "flash-elements";
|
|
10
|
+
type RuntimeBridgeControlMessageBase = {
|
|
11
|
+
source: "hf-parent";
|
|
12
|
+
type: "control";
|
|
13
|
+
action: RuntimeBridgeControlAction;
|
|
14
|
+
frame?: number;
|
|
15
|
+
timeSeconds?: number;
|
|
16
|
+
muted?: boolean;
|
|
17
|
+
volume?: number;
|
|
18
|
+
durationSeconds?: number;
|
|
19
|
+
startSeconds?: number | null;
|
|
20
|
+
endSeconds?: number | null;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
slow?: boolean;
|
|
23
|
+
scale?: number;
|
|
24
|
+
playbackRate?: number;
|
|
25
|
+
target?: HfColorGradingTarget | string | null;
|
|
26
|
+
grading?: RuntimeJson;
|
|
27
|
+
compare?: RuntimeJson;
|
|
28
|
+
seekMode?: "drag" | "commit";
|
|
29
|
+
};
|
|
30
|
+
export type RuntimeStateMessage = {
|
|
31
|
+
source: "hf-preview";
|
|
32
|
+
type: "state";
|
|
33
|
+
frame: number;
|
|
34
|
+
currentTime: number;
|
|
35
|
+
ended: boolean;
|
|
36
|
+
isPlaying: boolean;
|
|
37
|
+
muted: boolean;
|
|
38
|
+
playbackRate: number;
|
|
39
|
+
};
|
|
40
|
+
export type RuntimeTimelineClipIdentity = {
|
|
41
|
+
id: string | null;
|
|
42
|
+
label: string;
|
|
43
|
+
start: number;
|
|
44
|
+
duration: number;
|
|
45
|
+
track: number;
|
|
46
|
+
kind: "video" | "audio" | "image" | "element" | "composition";
|
|
47
|
+
tagName: string | null;
|
|
48
|
+
compositionId: string | null;
|
|
49
|
+
parentCompositionId: string | null;
|
|
50
|
+
compositionSrc: string | null;
|
|
51
|
+
assetUrl: string | null;
|
|
52
|
+
};
|
|
53
|
+
export type RuntimeTimelineClip = RuntimeTimelineClipIdentity & {
|
|
54
|
+
zIndex: number;
|
|
55
|
+
stackingContextId: string | null;
|
|
56
|
+
compositionAncestors: string[];
|
|
57
|
+
nodePath: string | null;
|
|
58
|
+
playbackStart: number;
|
|
59
|
+
playbackRate: number;
|
|
60
|
+
timelineRole: string | null;
|
|
61
|
+
timelineLabel: string | null;
|
|
62
|
+
timelineGroup: string | null;
|
|
63
|
+
timelinePriority: number | null;
|
|
64
|
+
};
|
|
65
|
+
export type RuntimeTimelineScene = {
|
|
66
|
+
id: string;
|
|
67
|
+
label: string;
|
|
68
|
+
start: number;
|
|
69
|
+
duration: number;
|
|
70
|
+
thumbnailUrl: string | null;
|
|
71
|
+
avatarName: string | null;
|
|
72
|
+
};
|
|
73
|
+
export type RuntimeTimelineMessage = RuntimeProtocolV1 & {
|
|
74
|
+
source: "hf-preview";
|
|
75
|
+
type: "timeline";
|
|
76
|
+
compositionContractVersion: 1;
|
|
77
|
+
durationSeconds: number;
|
|
78
|
+
durationInFrames: number;
|
|
79
|
+
clips: RuntimeTimelineClip[];
|
|
80
|
+
scenes: RuntimeTimelineScene[];
|
|
81
|
+
compositionWidth: number;
|
|
82
|
+
compositionHeight: number;
|
|
83
|
+
/** Present when this runtime will post `assets-ready`; the value is whether
|
|
84
|
+
* the composition's assets have settled yet. Absent on older runtimes, whose
|
|
85
|
+
* parents must not wait for a message that never comes. */
|
|
86
|
+
assetsReady?: boolean;
|
|
87
|
+
};
|
|
88
|
+
export type RuntimeDiagnosticMessage = {
|
|
89
|
+
source: "hf-preview";
|
|
90
|
+
type: "diagnostic";
|
|
91
|
+
code: string;
|
|
92
|
+
details: Record<string, RuntimeJson>;
|
|
93
|
+
};
|
|
94
|
+
export type RuntimePickerElementInfo = HyperframePickerElementInfo;
|
|
95
|
+
export type RuntimePickerHoveredMessage = {
|
|
96
|
+
source: "hf-preview";
|
|
97
|
+
type: "element-hovered";
|
|
98
|
+
elementInfo: RuntimePickerElementInfo;
|
|
99
|
+
};
|
|
100
|
+
export type RuntimePickerCandidatesMessage = {
|
|
101
|
+
source: "hf-preview";
|
|
102
|
+
type: "element-pick-candidates";
|
|
103
|
+
candidates: RuntimePickerElementInfo[];
|
|
104
|
+
selectedIndex: number;
|
|
105
|
+
point: {
|
|
106
|
+
x: number;
|
|
107
|
+
y: number;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
export type RuntimePickerPickedMessage = {
|
|
111
|
+
source: "hf-preview";
|
|
112
|
+
type: "element-picked";
|
|
113
|
+
elementInfo: RuntimePickerElementInfo;
|
|
114
|
+
};
|
|
115
|
+
export type RuntimePickerPickedManyMessage = {
|
|
116
|
+
source: "hf-preview";
|
|
117
|
+
type: "element-picked-many";
|
|
118
|
+
elementInfos: RuntimePickerElementInfo[];
|
|
119
|
+
};
|
|
120
|
+
export type RuntimePickerCancelledMessage = {
|
|
121
|
+
source: "hf-preview";
|
|
122
|
+
type: "pick-mode-cancelled";
|
|
123
|
+
};
|
|
124
|
+
export type RuntimeStageSizeMessage = {
|
|
125
|
+
source: "hf-preview";
|
|
126
|
+
type: "stage-size";
|
|
127
|
+
width: number;
|
|
128
|
+
height: number;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Fired once per session when the runtime's attempt to play a timed media
|
|
132
|
+
* element is rejected with `NotAllowedError`. The parent (web component / host
|
|
133
|
+
* app) uses this as the signal to promote to parent-frame audio proxies —
|
|
134
|
+
* iframes lose autoplay privileges when the user gesture originated in the
|
|
135
|
+
* parent frame, so the host has to take over audible playback there.
|
|
136
|
+
*/
|
|
137
|
+
export type RuntimeMediaAutoplayBlockedMessage = {
|
|
138
|
+
source: "hf-preview";
|
|
139
|
+
type: "media-autoplay-blocked";
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Posted by the runtime when `installRuntimeControlBridge` finishes registering
|
|
143
|
+
* its message listener — signals that subsequent control messages
|
|
144
|
+
* (`set-muted`, `set-volume`, `set-playback-rate`, etc.) will now be received
|
|
145
|
+
* and processed. The parent (web component / host app) listens for this and
|
|
146
|
+
* replays current playback state to repair any race where bridge messages
|
|
147
|
+
* were posted before the listener was installed. Emitted again on every iframe
|
|
148
|
+
* reload because the new runtime instance starts with no state.
|
|
149
|
+
*/
|
|
150
|
+
export type RuntimeReadyMessage = {
|
|
151
|
+
source: "hf-preview";
|
|
152
|
+
type: "ready";
|
|
153
|
+
};
|
|
154
|
+
/** Posted once per runtime instance, after the first timeline message, when
|
|
155
|
+
* the composition's media, images and fonts have settled (or timed out). It
|
|
156
|
+
* lets a parent that cannot read the iframe (opaque origin) gate playback. */
|
|
157
|
+
export type RuntimeAssetsReadyMessage = {
|
|
158
|
+
source: "hf-preview";
|
|
159
|
+
type: "assets-ready";
|
|
160
|
+
timedOut: boolean;
|
|
161
|
+
};
|
|
162
|
+
export type RuntimeDataErrorMessage = {
|
|
163
|
+
source: "hf-preview";
|
|
164
|
+
type: "runtime-data-error";
|
|
165
|
+
channel: string;
|
|
166
|
+
requestId: number;
|
|
167
|
+
message: string;
|
|
168
|
+
};
|
|
169
|
+
export type RuntimeDataAppliedMessage = {
|
|
170
|
+
source: "hf-preview";
|
|
171
|
+
type: "runtime-data-applied";
|
|
172
|
+
channel: string;
|
|
173
|
+
requestId: number;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Analytics events emitted by the runtime.
|
|
177
|
+
*
|
|
178
|
+
* The host app receives these via postMessage and forwards to its analytics
|
|
179
|
+
* provider (PostHog, Mixpanel, Amplitude, custom logging, etc.).
|
|
180
|
+
* No analytics SDK runs inside this iframe.
|
|
181
|
+
*/
|
|
182
|
+
export type RuntimeAnalyticsMessage = {
|
|
183
|
+
source: "hf-preview";
|
|
184
|
+
type: "analytics";
|
|
185
|
+
event: RuntimeAnalyticsEvent;
|
|
186
|
+
properties: Record<string, string | number | boolean | null>;
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Numeric performance metrics emitted by the runtime — scrub latency, sustained
|
|
190
|
+
* fps, dropped frames, decoder count, composition load time, media sync drift.
|
|
191
|
+
* The host aggregates per-session values (p50/p95) and forwards to its
|
|
192
|
+
* observability pipeline. Distinct from `analytics` events because perf data
|
|
193
|
+
* is continuous and numeric, not discrete.
|
|
194
|
+
*/
|
|
195
|
+
export type RuntimePerformanceMessage = {
|
|
196
|
+
source: "hf-preview";
|
|
197
|
+
type: "perf";
|
|
198
|
+
name: string;
|
|
199
|
+
value: number;
|
|
200
|
+
tags: Record<string, string | number | boolean | null>;
|
|
201
|
+
};
|
|
202
|
+
/** One audio group's live meter reading, polled from the transport each tick
|
|
203
|
+
* while playing. A group id absent from `levels` is idle/unknown (no active
|
|
204
|
+
* member) — the studio side treats that as "no reading", not zero. */
|
|
205
|
+
export type RuntimeGroupLevelsMessage = {
|
|
206
|
+
source: "hf-preview";
|
|
207
|
+
type: "group-levels";
|
|
208
|
+
levels: Array<{
|
|
209
|
+
groupId: string;
|
|
210
|
+
level: number;
|
|
211
|
+
clipped: boolean;
|
|
212
|
+
}>;
|
|
213
|
+
};
|
|
214
|
+
export type RuntimeOutboundMessage = RuntimeStateMessage | RuntimeTimelineMessage | RuntimeDiagnosticMessage | RuntimePickerHoveredMessage | RuntimePickerCandidatesMessage | RuntimePickerPickedMessage | RuntimePickerPickedManyMessage | RuntimePickerCancelledMessage | RuntimeStageSizeMessage | RuntimeMediaAutoplayBlockedMessage | RuntimeReadyMessage | RuntimeAssetsReadyMessage | RuntimeDataErrorMessage | RuntimeDataAppliedMessage | RuntimeAnalyticsMessage | RuntimePerformanceMessage | RuntimeGroupLevelsMessage;
|
|
215
|
+
export type HeldSeek = Promise<void> | void;
|
|
216
|
+
export type RuntimePlayer = {
|
|
217
|
+
_timeline: RuntimeTimelineLike | null;
|
|
218
|
+
play: () => void;
|
|
219
|
+
pause: () => void;
|
|
220
|
+
seek: (timeSeconds: number, options?: {
|
|
221
|
+
keepPlaying?: boolean;
|
|
222
|
+
}) => HeldSeek;
|
|
223
|
+
renderSeek: (timeSeconds: number, options?: RuntimeSeekOptions) => void;
|
|
224
|
+
getTime: () => number;
|
|
225
|
+
getDuration: () => number;
|
|
226
|
+
isPlaying: () => boolean;
|
|
227
|
+
setPlaybackRate: (rate: number) => void;
|
|
228
|
+
getPlaybackRate: () => number;
|
|
229
|
+
};
|
|
230
|
+
export type RuntimeSeekOptions = {
|
|
231
|
+
suppressEvents?: boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Subdivide the output frame grid this render seek quantizes onto. Integer >= 1;
|
|
234
|
+
* 1 (or absent) is the output frame grid. Motion-blur sub-frame sampling passes the
|
|
235
|
+
* engine's sub-frame tick count so a fractional sample time survives quantization.
|
|
236
|
+
*/
|
|
237
|
+
subFrameDivisions?: number;
|
|
238
|
+
exact?: boolean;
|
|
239
|
+
};
|
|
240
|
+
export type RuntimeTimelineChildLike = {
|
|
241
|
+
targets?: () => unknown[];
|
|
242
|
+
vars?: unknown;
|
|
243
|
+
startTime?: () => number;
|
|
244
|
+
duration?: () => number;
|
|
245
|
+
data?: unknown;
|
|
246
|
+
parent?: RuntimeTimelineChildLike;
|
|
247
|
+
getChildren?: RuntimeTimelineLike["getChildren"];
|
|
248
|
+
};
|
|
249
|
+
/** A timeline or tween a composition script started, as a scene swap stops it. */
|
|
250
|
+
export type SceneAnimation = {
|
|
251
|
+
targets?: () => unknown[];
|
|
252
|
+
duration?: () => number;
|
|
253
|
+
getChildren?: (nested?: boolean, tweens?: boolean, timelines?: boolean) => SceneAnimation[];
|
|
254
|
+
revert?: () => void;
|
|
255
|
+
kill?: () => void;
|
|
256
|
+
totalTime?: (timeSeconds?: number, suppressEvents?: boolean) => unknown;
|
|
257
|
+
};
|
|
258
|
+
export type RuntimeTimelineLike = {
|
|
259
|
+
play: () => void;
|
|
260
|
+
pause: () => void;
|
|
261
|
+
seek: (timeSeconds?: number, suppressEvents?: boolean) => unknown;
|
|
262
|
+
totalTime?: (timeSeconds?: number, suppressEvents?: boolean) => unknown;
|
|
263
|
+
totalDuration?: () => number;
|
|
264
|
+
progress?: (value?: number, suppressEvents?: boolean) => unknown;
|
|
265
|
+
time: () => number;
|
|
266
|
+
duration: () => number;
|
|
267
|
+
add: (timeline: RuntimeTimelineLike, startAtSeconds: number) => void;
|
|
268
|
+
paused: (paused?: boolean) => void;
|
|
269
|
+
timeScale?: (rate: number) => void;
|
|
270
|
+
set: (target: RuntimeGsapSetTarget, vars: RuntimeGsapSetVars, atSeconds?: number) => void;
|
|
271
|
+
getChildren?: (nested?: boolean, tweens?: boolean, timelines?: boolean, ignoreBeforeTime?: number) => RuntimeTimelineChildLike[];
|
|
272
|
+
};
|
|
273
|
+
export type RuntimeDeterministicAdapter = {
|
|
274
|
+
name: string;
|
|
275
|
+
discover: () => void;
|
|
276
|
+
seek: (ctx: {
|
|
277
|
+
time: number;
|
|
278
|
+
suppressEvents?: boolean;
|
|
279
|
+
pageAnimations?: () => Animation[];
|
|
280
|
+
}) => void;
|
|
281
|
+
pause: (ctx?: {
|
|
282
|
+
pageAnimations?: () => Animation[];
|
|
283
|
+
}) => void;
|
|
284
|
+
play?: () => void;
|
|
285
|
+
revert?: () => void;
|
|
286
|
+
/**
|
|
287
|
+
* Optional async readiness gate. If the adapter has outstanding async work
|
|
288
|
+
* (e.g. Three.js's `DefaultLoadingManager` still loading models/textures),
|
|
289
|
+
* return a promise that settles when the work is done. The runtime waits
|
|
290
|
+
* for the returned promise to settle before publishing
|
|
291
|
+
* `window.__renderReady = true`, so the engine doesn't capture empty
|
|
292
|
+
* frames while assets are still loading.
|
|
293
|
+
*
|
|
294
|
+
* Return `null` (or omit the method) when nothing is pending. The runtime
|
|
295
|
+
* calls this on every readiness-publish evaluation and tracks promise
|
|
296
|
+
* identity, so returning the same promise on repeated calls is the
|
|
297
|
+
* expected contract — return a fresh promise only when a new wait is
|
|
298
|
+
* actually needed (e.g. a new batch of items has been queued).
|
|
299
|
+
*
|
|
300
|
+
* Throwing or rejecting is safe: the runtime swallows the error and
|
|
301
|
+
* proceeds to publish (matching the existing failure-doesn't-block-render
|
|
302
|
+
* convention).
|
|
303
|
+
*/
|
|
304
|
+
getReadyPromise?: () => PromiseLike<unknown> | null;
|
|
305
|
+
/**
|
|
306
|
+
* Optional duration auto-inference. Non-GSAP runtimes (CSS, WAAPI, Lottie)
|
|
307
|
+
* have no `window.__timelines` entry, so the runtime has no authored source
|
|
308
|
+
* of truth for total composition length unless the author sets
|
|
309
|
+
* `data-duration` on the root element. This hook lets an adapter report the
|
|
310
|
+
* longest end time it can discover from its own animations, so the runtime
|
|
311
|
+
* can fold it into the duration floor (see `resolveAdapterDurationFloorSeconds`
|
|
312
|
+
* in `init.ts`) and treat `data-duration` as optional rather than required.
|
|
313
|
+
*
|
|
314
|
+
* Return the inferred duration in seconds, or `null` when nothing usable
|
|
315
|
+
* was discovered (e.g. no animations yet, or an animation with unbounded /
|
|
316
|
+
* infinite iteration count that can't be resolved to a finite end time —
|
|
317
|
+
* those compositions must keep declaring `data-duration` explicitly).
|
|
318
|
+
*
|
|
319
|
+
* Called on every adapter-discovery cycle (same cadence as `discover`), so
|
|
320
|
+
* it's safe — and expected — to return a growing value as async work
|
|
321
|
+
* (Lottie JSON fetch, etc.) resolves.
|
|
322
|
+
*/
|
|
323
|
+
getInferredDurationSeconds?: () => number | null;
|
|
324
|
+
getAnimationCycleEndSeconds?: () => number | null;
|
|
325
|
+
};
|
|
326
|
+
export type RuntimeGsapSetTarget = string | Element | Element[] | null;
|
|
327
|
+
export type RuntimeGsapSetVars = Record<string, string | number | boolean | null | undefined>;
|
|
328
|
+
type RuntimeDataControlFields = {
|
|
329
|
+
channel?: string;
|
|
330
|
+
payload?: unknown;
|
|
331
|
+
requestId?: number;
|
|
332
|
+
};
|
|
333
|
+
type RuntimeBridgeControlAction = RuntimeBridgeControlActionBase | "set-runtime-data" | "clear-runtime-data";
|
|
334
|
+
export type RuntimeBridgeControlMessage = RuntimeBridgeControlMessageBase & RuntimeDataControlFields;
|
|
335
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the composition-variable values an element should see: the scoped
|
|
3
|
+
* per-instance table for inlined sub-compositions, then the top-level merged
|
|
4
|
+
* getVariables(), then the raw render-injection global. Shared by every
|
|
5
|
+
* runtime consumer of variables (color grading, declarative bindings) so the
|
|
6
|
+
* scope chain can never diverge between channels.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readVariablesForElement(element: Element): Record<string, unknown>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export declare function realpath(path: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* Reject paths that escape the `base` directory — including via symlinks.
|
|
4
|
+
*
|
|
5
|
+
* `path.resolve()` collapses `.`/`..` but does NOT dereference symlinks, so a
|
|
6
|
+
* plain prefix check (`resolved.startsWith(base + sep)`) can be defeated by a
|
|
7
|
+
* symlink that lives *inside* `base` but points outside it (e.g.
|
|
8
|
+
* `base/link -> /etc`). A downstream `readFileSync`/`writeFileSync`/`statSync`
|
|
9
|
+
* then follows that link to a file outside `base`. To close this we canonicalize
|
|
10
|
+
* both sides with `realpathSync.native` (the on-disk letter case too) before comparing.
|
|
11
|
+
*
|
|
12
|
+
* The target may not exist yet (e.g. creating a new file), so we canonicalize the
|
|
13
|
+
* deepest *existing* ancestor and re-attach the trailing not-yet-existing
|
|
14
|
+
* segments. Segments that don't exist cannot be symlinks at check time, so they
|
|
15
|
+
* can't redirect the path outside `base` right now. (A symlink swapped in between
|
|
16
|
+
* this check and the subsequent fs call is an inherent TOCTOU race this helper
|
|
17
|
+
* does not, and cannot by itself, defend against.)
|
|
18
|
+
*
|
|
19
|
+
* Lives at the package root rather than under `studio-api/` because callers span
|
|
20
|
+
* layers — `studio-api` routes, the `compiler`, the CLI, and the engine — and
|
|
21
|
+
* `compiler` sits below `studio-api` in the dependency graph, so it cannot import
|
|
22
|
+
* from there without a backwards edge.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isSafePath(base: string, resolved: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve `relativePath` against `base` and return the absolute path only if it
|
|
27
|
+
* stays within `base` (after symlink resolution); otherwise return `null`.
|
|
28
|
+
*
|
|
29
|
+
* Prefer this over a bare `resolve()` followed by a separate `isSafePath()`
|
|
30
|
+
* check: collapsing the two into one call means a caller cannot resolve a
|
|
31
|
+
* project-relative path and then forget the containment guard — the gap that
|
|
32
|
+
* let the symlink-escape slip past several call sites historically.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveWithinProject(base: string, relativePath: string): string | null;
|
|
35
|
+
/** The project folder is gone, renamed or deleted while open; a write must not bring it back. */
|
|
36
|
+
export declare class ProjectRootMissingError extends Error {
|
|
37
|
+
readonly root: string;
|
|
38
|
+
constructor(root: string);
|
|
39
|
+
}
|
|
40
|
+
export declare const isProjectRootMissing: (error: unknown) => boolean;
|
|
41
|
+
/** True only when nothing is at `dir` any more; a folder that cannot be looked at (EACCES, EIO) is not gone. */
|
|
42
|
+
export declare function folderGone(dir: string): boolean;
|
|
43
|
+
/** The project folder's real path; ProjectRootMissingError when it is gone. */
|
|
44
|
+
export declare function realProjectRoot(root: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Creates `dir` below `root` one folder at a time, so a root moved away fails instead of reappearing.
|
|
47
|
+
* A `dir` outside `root` is created recursively, but only while `root` exists.
|
|
48
|
+
*/
|
|
49
|
+
export declare function mkdirWithinProject(root: string, dir: string): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const SCENE_PART_ATTR = "data-hf-scene";
|
|
2
|
+
export declare const SCENE_PARTS_META = "hf-scene-parts";
|
|
3
|
+
/** On a scene's top-level host: why the scene cannot be swapped in place, so edits to it reload. */
|
|
4
|
+
export declare const SCENE_NO_SWAP_ATTR = "data-hf-scene-no-swap";
|
|
5
|
+
/** Hashes of one preview document: everything outside the scene parts, and each scene's parts. */
|
|
6
|
+
export interface SceneParts {
|
|
7
|
+
shared: string;
|
|
8
|
+
scenes: Record<string, string>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** A ramp is a `rate` lane in `data-automation`; `sourceTimeAt` is the one rate-to-time mapping consumers share. */
|
|
2
|
+
import { type HfAutomationLane } from "./audioAutomation.js";
|
|
3
|
+
/** A constant multiplier, or a lane whose `v` is the multiplier over clip-local time. */
|
|
4
|
+
export type RateSpec = number | HfAutomationLane;
|
|
5
|
+
/**
|
|
6
|
+
* The lane as seen from `dt` seconds into the clip: what a renderer sees after it trims the clip's start.
|
|
7
|
+
* A shaped segment (`curve`, `viaX`) cut in the middle is resampled, since its shape belongs to its left point.
|
|
8
|
+
*/
|
|
9
|
+
export declare function shiftRateLane(spec: RateSpec, dt: number): RateSpec;
|
|
10
|
+
/** Speed multiplier at clip-local time `t`. */
|
|
11
|
+
export declare function rateAt(spec: RateSpec, t: number): number;
|
|
12
|
+
/** Source seconds consumed by clip-local time `t` (the integral of the rate). */
|
|
13
|
+
export declare function sourceTimeAt(spec: RateSpec, t: number): number;
|
|
14
|
+
/** Inverse of `sourceTimeAt`: the clip-local time at which `source` seconds have been consumed. */
|
|
15
|
+
export declare function timeAtSourceTime(spec: RateSpec, source: number): number;
|
|
16
|
+
/** The `rate` lane inside a `data-automation` attribute value, or null when absent or unreadable. */
|
|
17
|
+
export declare function parseRateLane(raw: string | null | undefined): HfAutomationLane | null;
|
|
18
|
+
/** A clip's rate: its `rate` lane when it has one, otherwise the constant. */
|
|
19
|
+
export declare function resolveRateSpec(automationAttr: string | null | undefined, constant: number): RateSpec;
|
|
20
|
+
/** The CapCut-style presets; `speedPresetLane` stretches one over a clip's duration. */
|
|
21
|
+
export declare const SPEED_PRESETS: readonly [{
|
|
22
|
+
readonly id: "montage";
|
|
23
|
+
readonly label: "Montage";
|
|
24
|
+
readonly points: readonly [readonly [0, 0.9], readonly [0.15, 0.3], readonly [0.5, 2.5], readonly [0.85, 0.3], readonly [1, 0.9]];
|
|
25
|
+
}, {
|
|
26
|
+
readonly id: "hero";
|
|
27
|
+
readonly label: "Hero";
|
|
28
|
+
readonly points: readonly [readonly [0, 1], readonly [0.25, 1.6], readonly [0.5, 0.25], readonly [0.75, 1.6], readonly [1, 1]];
|
|
29
|
+
}, {
|
|
30
|
+
readonly id: "bullet";
|
|
31
|
+
readonly label: "Bullet";
|
|
32
|
+
readonly points: readonly [readonly [0, 3], readonly [0.4, 3], readonly [0.5, 0.15], readonly [0.6, 3], readonly [1, 3]];
|
|
33
|
+
}, {
|
|
34
|
+
readonly id: "jump-cut";
|
|
35
|
+
readonly label: "Jump cut";
|
|
36
|
+
readonly points: readonly [readonly [0, 0.5], readonly [0.24, 0.5], readonly [0.26, 3], readonly [0.5, 3], readonly [0.52, 0.5], readonly [0.74, 0.5], readonly [0.76, 3], readonly [1, 3]];
|
|
37
|
+
}, {
|
|
38
|
+
readonly id: "flash-in";
|
|
39
|
+
readonly label: "Flash in";
|
|
40
|
+
readonly points: readonly [readonly [0, 0.3], readonly [0.6, 0.6], readonly [1, 5]];
|
|
41
|
+
}, {
|
|
42
|
+
readonly id: "flash-out";
|
|
43
|
+
readonly label: "Flash out";
|
|
44
|
+
readonly points: readonly [readonly [0, 5], readonly [0.4, 0.6], readonly [1, 0.3]];
|
|
45
|
+
}, {
|
|
46
|
+
readonly id: "ramp-in";
|
|
47
|
+
readonly label: "Ramp in";
|
|
48
|
+
readonly points: readonly [readonly [0, 0.5], readonly [1, 1]];
|
|
49
|
+
}, {
|
|
50
|
+
readonly id: "ramp-out";
|
|
51
|
+
readonly label: "Ramp out";
|
|
52
|
+
readonly points: readonly [readonly [0, 1], readonly [1, 0.5]];
|
|
53
|
+
}, {
|
|
54
|
+
readonly id: "slowmo-middle";
|
|
55
|
+
readonly label: "Slow-mo middle";
|
|
56
|
+
readonly points: readonly [readonly [0, 1], readonly [number, 0.35], readonly [number, 0.35], readonly [1, 1]];
|
|
57
|
+
}];
|
|
58
|
+
export type SpeedPresetId = (typeof SPEED_PRESETS)[number]["id"];
|
|
59
|
+
export declare function speedPresetLane(id: SpeedPresetId, clipDuration: number): HfAutomationLane;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE slug for composition-variable ids → CSS custom-property names. Shared
|
|
3
|
+
* by the figma importer (emits `var(--<slug>, literal)`) and the runtime
|
|
4
|
+
* (defines `--<slug>` from declared variables) — one function so the two
|
|
5
|
+
* sides can never drift. The slug is lossy (case-folded, symbol runs
|
|
6
|
+
* collapse to "-"), so distinct ids CAN collide; callers surface
|
|
7
|
+
* detectSlugCollisions() as a warning rather than silently merging.
|
|
8
|
+
*/
|
|
9
|
+
export declare function slugify(name: string): string;
|
|
10
|
+
export declare function cssVariableName(id: string): string;
|
|
11
|
+
/** Groups of distinct ids that collapse to the same CSS variable name. */
|
|
12
|
+
export declare function detectSlugCollisions(ids: Iterable<string>): string[][];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Page } from "puppeteer-core";
|
|
2
|
+
|
|
3
|
+
export interface ElementNode {
|
|
4
|
+
index: number;
|
|
5
|
+
parent: number | null;
|
|
6
|
+
selector: string;
|
|
7
|
+
tag: string;
|
|
8
|
+
id: string;
|
|
9
|
+
hfId: string | null;
|
|
10
|
+
classes: string[];
|
|
11
|
+
composition: string | null;
|
|
12
|
+
compositionSrc: string | null;
|
|
13
|
+
text: string;
|
|
14
|
+
media: string | null;
|
|
15
|
+
relative: string;
|
|
16
|
+
groupSelector: string;
|
|
17
|
+
siblingMatchCount: number;
|
|
18
|
+
children: number[];
|
|
19
|
+
}
|
|
20
|
+
export interface ElementDom {
|
|
21
|
+
generation: string | null;
|
|
22
|
+
nodes: ElementNode[];
|
|
23
|
+
limitations: { canvas: number; iframes: number; shadowRoots: number };
|
|
24
|
+
}
|
|
25
|
+
export interface ElementMap {
|
|
26
|
+
text: string;
|
|
27
|
+
entries: { line: number; selectors: string[]; nodeIndices: number[] }[];
|
|
28
|
+
elementCount: number;
|
|
29
|
+
coveredCount: number;
|
|
30
|
+
}
|
|
31
|
+
export function collectElementDom(): ElementDom;
|
|
32
|
+
export function formatElementMap(snapshot: ElementDom, options?: { file?: string }): ElementMap;
|
|
33
|
+
export function createElementMap(page: Page, options?: { file?: string }): Promise<ElementMap>;
|