@hyperframes/core 0.8.200 → 0.8.201
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/audioAnalysis.d.ts +2 -0
- package/dist/audioAnalysis.js +14 -5
- package/dist/audioGroups.d.ts +3 -7
- package/dist/audioGroups.js +4 -8
- package/dist/audioResample.d.ts +2 -0
- package/dist/audioResample.js +7 -0
- package/dist/audioRhythm.d.ts +3 -0
- package/dist/audioRhythm.js +37 -20
- package/dist/audioSteps.d.ts +3 -0
- package/dist/audioSteps.js +7 -0
- package/dist/beats/beatDetection.js +22 -7
- package/dist/compiler/htmlBundler.js +1 -37
- package/dist/compiler/srcset.d.ts +1 -0
- package/dist/compiler/srcset.js +46 -0
- package/dist/generated/position-edits-render-inline.js +1 -1
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/hyperframe.runtime.iife.js +65 -64
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/mediaGradeAnalyzer.d.ts +1 -0
- package/dist/mediaGradeAnalyzer.js +32 -20
- package/dist/previewProxyBox.d.ts +14 -0
- package/dist/previewProxyBox.js +15 -0
- package/dist/runtime/bridge.d.ts +1 -0
- package/dist/runtime/bridge.js +1 -0
- package/dist/runtime/diagnostics.js +38 -1
- package/dist/runtime/media.d.ts +1 -0
- package/dist/runtime/media.js +15 -21
- package/dist/runtime/timedClipHide.js +4 -2
- package/dist/runtime/timeline.js +2 -1
- package/dist/runtime/types.d.ts +2 -1
- package/dist/runtime/validateVariables.js +6 -7
- package/dist/variables.d.ts +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export { AUDIO_GROUP_RENDER_ID_ATTR, MEDIA_RENDER_ID_ATTR, assignMediaRenderIds,
|
|
|
22
22
|
export { RENDER_FRAME_ID_PREFIX, RENDER_FRAME_ID_SUFFIX, renderFrameIdForRenderId, } from "./runtime/renderFrameSibling.js";
|
|
23
23
|
export { rewriteAssetPaths, rewriteAssetPath, rewriteCssAssetUrls, rewriteInlineStyleAssetUrls, } from "./compiler/rewriteSubCompPaths.js";
|
|
24
24
|
export { CSS_URL_RE, isNonRelativeUrl, isPathInside } from "./compiler/assetPaths.js";
|
|
25
|
+
export { rewriteSrcsetUrls } from "./compiler/srcset.js";
|
|
25
26
|
export { checkSubCompositionUsability, type ParsableDocumentLike, type SubCompositionValidity, type SubCompositionValidityReason, } from "./compiler/subCompositionValidity.js";
|
|
26
27
|
export { RUNTIME_BOOTSTRAP_ATTR, stripEmbeddedRuntimeScripts } from "./compiler/htmlDocument.js";
|
|
27
28
|
export { COMPOSITION_SOURCE_URL } from "./compiler/scriptRuns.js";
|
|
@@ -32,7 +33,7 @@ export { clearGifFramesBeforeNext, gifClearsAfterLeavingFrameInPlace, parseAnima
|
|
|
32
33
|
export { HF_COLOR_GRADING_ATTR, HF_COLOR_GRADING_ADJUST_KEYS, HF_COLOR_GRADING_ACTIVE_EFFECT_KEYS, HF_COLOR_GRADING_ANIMATABLE_PROPERTIES, HF_COLOR_GRADING_CANVAS_ID_PREFIX, HF_COLOR_GRADING_COLOR_SPACE, HF_COLOR_GRADING_CURVE_KEYS, HF_COLOR_GRADING_DETAIL_KEYS, HF_COLOR_GRADING_EFFECT_APPLY_DEFAULTS, HF_COLOR_GRADING_EFFECT_KEYS, HF_COLOR_GRADING_EFFECT_PRESETS, HF_COLOR_GRADING_GRADE_PRESETS, HF_COLOR_GRADING_HUE_CURVE_KEYS, HF_COLOR_GRADING_LUT_KEYS, HF_COLOR_GRADING_PALETTES, HF_COLOR_GRADING_PRESETS, HF_COLOR_GRADING_TOP_LEVEL_KEYS, HF_COLOR_GRADING_WHEEL_KEYS, getHfColorGradingCapabilities, hasHfColorGradingAuthoredValues, isHfColorGradingActive, normalizeHfColorGrading, normalizeHfColorGradingWithVariables, resolveHfColorGradingVariables, serializeHfColorGrading, type HfColorGrading, type HfColorGradingAdjust, type HfColorGradingAdjustKey, type HfColorGradingAnimatablePath, type HfColorGradingActiveEffectKey, type HfColorGradingDetailKey, type HfColorGradingDetails, type HfColorGradingEffectKey, type HfColorGradingEffects, type HfColorGradingLutRef, type HfColorGradingPreset, type HfColorGradingPresetId, type HfColorGradingTarget, type HfColorGradingVariableMap, type HfColorGradingCapabilities, type HfColorGradingCurveKey, type HfColorGradingCurves, type HfColorGradingHueCurveKey, type HfColorGradingHueCurves, type HfColorGradingHueRange, type HfColorGradingSecondary, type HfColorGradingSecondaryCorrection, type HfColorGradingSoftRange, type HfColorGradingTonalWheel, type HfColorGradingWheelKey, type HfColorGradingWheels, type HfColorCurvePoint, type HfHueCurvePoint, type NormalizedHfColorGrading, type NormalizedHfColorGradingCurves, type NormalizedHfColorGradingHueCurves, type NormalizedHfColorGradingSecondary, type NormalizedHfColorGradingWheels, type ResolvedHfColorGrading, } from "./colorGrading.js";
|
|
33
34
|
export { parseCubeLut, CubeLutParseError, type ParseCubeLutOptions } from "./colorLuts.js";
|
|
34
35
|
export { firstFrameColourArgs, hdrToSdrToneMapFilter, parseFirstFrameColour, type ToneMapSourceColour, } from "./hdrToneMap.js";
|
|
35
|
-
export { PREVIEW_PROXY_BOX_PARAM, formatPreviewProxyBox, parsePreviewProxyBox, quantizePreviewProxyBox, type PreviewProxyBox, } from "./previewProxyBox.js";
|
|
36
|
+
export { HEAVY_BITRATE, HEAVY_PIXEL_SHARE, PREVIEW_PROXY_BOX_PARAM, PREVIEW_PROXY_LIGHT_PARAM, PREVIEW_QUALITY_LEVELS, formatPreviewProxyBox, isHeavyForPreview, isPreviewQuality, parsePreviewProxyBox, quantizePreviewProxyBox, scalePreviewProxyBox, type PreviewProxyBox, type PreviewQuality, type PreviewSourceFacts, } from "./previewProxyBox.js";
|
|
36
37
|
export { HYPERFRAME_RUNTIME_ARTIFACTS, HYPERFRAME_RUNTIME_CONTRACT, loadHyperframeRuntimeSource, type HyperframeRuntimeContract, } from "./inline-scripts/hyperframe.js";
|
|
37
38
|
export { HYPERFRAME_RUNTIME_GLOBALS, HYPERFRAME_BRIDGE_SOURCES, HYPERFRAME_CONTROL_ACTIONS, type HyperframeControlAction, } from "./inline-scripts/runtimeContract.js";
|
|
38
39
|
export { getHyperframeRuntimeScript } from "./generated/runtime-inline.js";
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export { RENDER_FRAME_ID_PREFIX, RENDER_FRAME_ID_SUFFIX, renderFrameIdForRenderI
|
|
|
18
18
|
// package (which imports core utilities back).
|
|
19
19
|
export { rewriteAssetPaths, rewriteAssetPath, rewriteCssAssetUrls, rewriteInlineStyleAssetUrls, } from "./compiler/rewriteSubCompPaths.js";
|
|
20
20
|
export { CSS_URL_RE, isNonRelativeUrl, isPathInside } from "./compiler/assetPaths.js";
|
|
21
|
+
export { rewriteSrcsetUrls } from "./compiler/srcset.js";
|
|
21
22
|
export { checkSubCompositionUsability, } from "./compiler/subCompositionValidity.js";
|
|
22
23
|
export { RUNTIME_BOOTSTRAP_ATTR, stripEmbeddedRuntimeScripts } from "./compiler/htmlDocument.js";
|
|
23
24
|
export { COMPOSITION_SOURCE_URL } from "./compiler/scriptRuns.js";
|
|
@@ -28,7 +29,7 @@ export { clearGifFramesBeforeNext, gifClearsAfterLeavingFrameInPlace, parseAnima
|
|
|
28
29
|
export { HF_COLOR_GRADING_ATTR, HF_COLOR_GRADING_ADJUST_KEYS, HF_COLOR_GRADING_ACTIVE_EFFECT_KEYS, HF_COLOR_GRADING_ANIMATABLE_PROPERTIES, HF_COLOR_GRADING_CANVAS_ID_PREFIX, HF_COLOR_GRADING_COLOR_SPACE, HF_COLOR_GRADING_CURVE_KEYS, HF_COLOR_GRADING_DETAIL_KEYS, HF_COLOR_GRADING_EFFECT_APPLY_DEFAULTS, HF_COLOR_GRADING_EFFECT_KEYS, HF_COLOR_GRADING_EFFECT_PRESETS, HF_COLOR_GRADING_GRADE_PRESETS, HF_COLOR_GRADING_HUE_CURVE_KEYS, HF_COLOR_GRADING_LUT_KEYS, HF_COLOR_GRADING_PALETTES, HF_COLOR_GRADING_PRESETS, HF_COLOR_GRADING_TOP_LEVEL_KEYS, HF_COLOR_GRADING_WHEEL_KEYS, getHfColorGradingCapabilities, hasHfColorGradingAuthoredValues, isHfColorGradingActive, normalizeHfColorGrading, normalizeHfColorGradingWithVariables, resolveHfColorGradingVariables, serializeHfColorGrading, } from "./colorGrading.js";
|
|
29
30
|
export { parseCubeLut, CubeLutParseError } from "./colorLuts.js";
|
|
30
31
|
export { firstFrameColourArgs, hdrToSdrToneMapFilter, parseFirstFrameColour, } from "./hdrToneMap.js";
|
|
31
|
-
export { PREVIEW_PROXY_BOX_PARAM, formatPreviewProxyBox, parsePreviewProxyBox, quantizePreviewProxyBox, } from "./previewProxyBox.js";
|
|
32
|
+
export { HEAVY_BITRATE, HEAVY_PIXEL_SHARE, PREVIEW_PROXY_BOX_PARAM, PREVIEW_PROXY_LIGHT_PARAM, PREVIEW_QUALITY_LEVELS, formatPreviewProxyBox, isHeavyForPreview, isPreviewQuality, parsePreviewProxyBox, quantizePreviewProxyBox, scalePreviewProxyBox, } from "./previewProxyBox.js";
|
|
32
33
|
// Inline scripts
|
|
33
34
|
export { HYPERFRAME_RUNTIME_ARTIFACTS, HYPERFRAME_RUNTIME_CONTRACT, loadHyperframeRuntimeSource, } from "./inline-scripts/hyperframe.js";
|
|
34
35
|
export { HYPERFRAME_RUNTIME_GLOBALS, HYPERFRAME_BRIDGE_SOURCES, HYPERFRAME_CONTROL_ACTIONS, } from "./inline-scripts/runtimeContract.js";
|
|
@@ -56,6 +56,7 @@ type NumericStats = Readonly<Record<string, number | undefined>>;
|
|
|
56
56
|
export declare function parseMediaTreatmentSignalStats(raw: string): GradeSignalFrame[];
|
|
57
57
|
export declare function statsToAdjust(stats: NumericStats): Pick<MediaTreatmentAnalysis, "adjust" | "measured">;
|
|
58
58
|
export declare function summarizeMediaTreatmentAnalysis(probe: GradeMediaProbe, frames: readonly GradeSignalFrame[]): MediaTreatmentAnalysis;
|
|
59
|
+
export declare function gradeSampleTimes(duration: number): number[];
|
|
59
60
|
export declare function analyzeMediaGrade(mediaPath: string, options?: {
|
|
60
61
|
ffmpegPath?: string;
|
|
61
62
|
ffprobePath?: string;
|
|
@@ -212,43 +212,55 @@ export function summarizeMediaTreatmentAnalysis(probe, frames) {
|
|
|
212
212
|
warnings,
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
|
-
export function
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
export function gradeSampleTimes(duration) {
|
|
216
|
+
return Array.from({ length: SAMPLE_FRAMES }, (_, i) => (duration * (i + 0.5)) / SAMPLE_FRAMES);
|
|
217
|
+
}
|
|
218
|
+
function readSignalStats(ffmpegPath, mediaPath, seekSeconds, frames) {
|
|
219
|
+
const timeoutMs = Number(process.env.HYPERFRAMES_ANALYZE_TIMEOUT_MS) || DEFAULT_TIMEOUT_MS;
|
|
220
|
+
const keyframeSeek = seekSeconds === null ? [] : ["-noaccurate_seek", "-ss", seekSeconds.toFixed(3)];
|
|
218
221
|
try {
|
|
219
|
-
|
|
220
|
-
const isImage = IMAGE_EXTENSIONS.has(extname(mediaPath).toLowerCase());
|
|
221
|
-
const fps = !isImage && probe.duration
|
|
222
|
-
? Math.max(0.1, Math.min(2, SAMPLE_FRAMES / probe.duration))
|
|
223
|
-
: null;
|
|
224
|
-
const filters = [
|
|
225
|
-
fps ? `fps=${fps.toFixed(4)}` : null,
|
|
226
|
-
"format=yuv444p",
|
|
227
|
-
"signalstats",
|
|
228
|
-
"metadata=print:file=-",
|
|
229
|
-
]
|
|
230
|
-
.filter(Boolean)
|
|
231
|
-
.join(",");
|
|
232
|
-
const raw = execFileSync(ffmpegPath, [
|
|
222
|
+
return execFileSync(ffmpegPath, [
|
|
233
223
|
"-hide_banner",
|
|
234
224
|
"-nostdin",
|
|
235
225
|
"-v",
|
|
236
226
|
"error",
|
|
227
|
+
...keyframeSeek,
|
|
237
228
|
"-i",
|
|
238
229
|
mediaPath,
|
|
239
230
|
"-vf",
|
|
240
|
-
|
|
231
|
+
`trim=end_frame=${frames},format=yuv444p,signalstats,metadata=print:file=-`,
|
|
241
232
|
"-frames:v",
|
|
242
|
-
String(
|
|
233
|
+
String(frames),
|
|
243
234
|
"-f",
|
|
244
235
|
"null",
|
|
245
236
|
"-",
|
|
246
237
|
], {
|
|
247
238
|
encoding: "utf8",
|
|
248
|
-
timeout:
|
|
239
|
+
timeout: timeoutMs,
|
|
249
240
|
stdio: ["ignore", "pipe", "pipe"],
|
|
250
241
|
windowsHide: true,
|
|
251
242
|
});
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
if (error.code !== "ETIMEDOUT")
|
|
246
|
+
throw error;
|
|
247
|
+
const target = seekSeconds === null
|
|
248
|
+
? `the first ${frames} frames`
|
|
249
|
+
: `the frame at ${seekSeconds.toFixed(1)}s`;
|
|
250
|
+
throw new Error(`FFmpeg took longer than ${timeoutMs / 1000}s to measure ${target}; set HYPERFRAMES_ANALYZE_TIMEOUT_MS to allow more`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
export function analyzeMediaGrade(mediaPath, options = {}) {
|
|
254
|
+
const ffmpegPath = options.ffmpegPath ?? "ffmpeg";
|
|
255
|
+
const ffprobePath = options.ffprobePath ?? "ffprobe";
|
|
256
|
+
try {
|
|
257
|
+
const probe = probeMedia(mediaPath, ffprobePath);
|
|
258
|
+
const isImage = IMAGE_EXTENSIONS.has(extname(mediaPath).toLowerCase());
|
|
259
|
+
const raw = !isImage && probe.duration
|
|
260
|
+
? gradeSampleTimes(probe.duration)
|
|
261
|
+
.map((time) => readSignalStats(ffmpegPath, mediaPath, time, 1))
|
|
262
|
+
.join("\n")
|
|
263
|
+
: readSignalStats(ffmpegPath, mediaPath, null, SAMPLE_FRAMES);
|
|
252
264
|
return summarizeMediaTreatmentAnalysis(probe, parseMediaTreatmentSignalStats(raw));
|
|
253
265
|
}
|
|
254
266
|
catch (error) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Query parameter carrying the largest box, in device pixels, a preview shows a proxied video at. */
|
|
2
2
|
export declare const PREVIEW_PROXY_BOX_PARAM = "hf-proxy-box";
|
|
3
|
+
export declare const PREVIEW_PROXY_LIGHT_PARAM = "hf-proxy-light";
|
|
3
4
|
export type PreviewProxyBox = {
|
|
4
5
|
width: number;
|
|
5
6
|
height: number;
|
|
@@ -9,3 +10,16 @@ export declare function quantizePreviewProxyBox(width: number, height: number):
|
|
|
9
10
|
export declare function formatPreviewProxyBox(box: PreviewProxyBox): string;
|
|
10
11
|
/** Accepts only ladder rungs, so a client cannot make one cached copy per pixel. */
|
|
11
12
|
export declare function parsePreviewProxyBox(raw: string): PreviewProxyBox | null;
|
|
13
|
+
export declare const PREVIEW_QUALITY_LEVELS: readonly [1, 0.5, 0.25, 0.125];
|
|
14
|
+
export type PreviewQuality = (typeof PREVIEW_QUALITY_LEVELS)[number];
|
|
15
|
+
export declare function isPreviewQuality(value: unknown): value is PreviewQuality;
|
|
16
|
+
export type PreviewSourceFacts = {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
bitDepth: number;
|
|
20
|
+
bitrate: number;
|
|
21
|
+
};
|
|
22
|
+
export declare const HEAVY_PIXEL_SHARE = 0.5;
|
|
23
|
+
export declare const HEAVY_BITRATE = 40000000;
|
|
24
|
+
export declare function scalePreviewProxyBox(box: PreviewProxyBox, level: PreviewQuality): PreviewProxyBox;
|
|
25
|
+
export declare function isHeavyForPreview(facts: PreviewSourceFacts, copyBox: PreviewProxyBox): boolean;
|
package/dist/previewProxyBox.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Query parameter carrying the largest box, in device pixels, a preview shows a proxied video at. */
|
|
2
2
|
export const PREVIEW_PROXY_BOX_PARAM = "hf-proxy-box";
|
|
3
|
+
export const PREVIEW_PROXY_LIGHT_PARAM = "hf-proxy-light";
|
|
3
4
|
// 256 * 2^(k/4), even: nearby boxes share one cached copy, and a rung overshoots by at most ~19%.
|
|
4
5
|
const RUNGS = [
|
|
5
6
|
256, 304, 362, 430, 512, 608, 724, 862, 1024, 1218, 1448, 1722, 2048, 2436, 2896, 3444, 4096,
|
|
@@ -28,3 +29,17 @@ export function parsePreviewProxyBox(raw) {
|
|
|
28
29
|
const height = Number(match[2]);
|
|
29
30
|
return RUNGS.includes(width) && RUNGS.includes(height) ? { width, height } : null;
|
|
30
31
|
}
|
|
32
|
+
export const PREVIEW_QUALITY_LEVELS = [1, 0.5, 0.25, 0.125];
|
|
33
|
+
export function isPreviewQuality(value) {
|
|
34
|
+
return PREVIEW_QUALITY_LEVELS.some((level) => level === value);
|
|
35
|
+
}
|
|
36
|
+
export const HEAVY_PIXEL_SHARE = 0.5;
|
|
37
|
+
export const HEAVY_BITRATE = 40_000_000;
|
|
38
|
+
export function scalePreviewProxyBox(box, level) {
|
|
39
|
+
return quantizePreviewProxyBox(box.width * level, box.height * level) ?? box;
|
|
40
|
+
}
|
|
41
|
+
export function isHeavyForPreview(facts, copyBox) {
|
|
42
|
+
return (copyBox.width * copyBox.height <= HEAVY_PIXEL_SHARE * facts.width * facts.height ||
|
|
43
|
+
facts.bitDepth > 8 ||
|
|
44
|
+
facts.bitrate >= HEAVY_BITRATE);
|
|
45
|
+
}
|
package/dist/runtime/bridge.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ type BridgeDeps = {
|
|
|
22
22
|
onSetRuntimeData?: (channel: string, payload: unknown, requestId?: number) => void;
|
|
23
23
|
onClearRuntimeData?: (channel: string, requestId?: number) => void;
|
|
24
24
|
onSetDisplayScale?: (scale: number) => void;
|
|
25
|
+
onSetPreviewQuality?: (level: number) => void;
|
|
25
26
|
getCanonicalFps: () => number;
|
|
26
27
|
};
|
|
27
28
|
export declare function setRuntimeProtocolFps(fps: number): void;
|
package/dist/runtime/bridge.js
CHANGED
|
@@ -30,6 +30,7 @@ const CONTROL_HANDLERS = new Map(Object.entries({
|
|
|
30
30
|
"set-playback-rate": (data, deps) => deps.onSetPlaybackRate(Number(data.playbackRate ?? 1)),
|
|
31
31
|
"set-idle-heartbeat": (data, deps) => deps.onSetIdleHeartbeat(Boolean(data.slow)),
|
|
32
32
|
"set-display-scale": (data, deps) => deps.onSetDisplayScale?.(Number(data.scale)),
|
|
33
|
+
"set-preview-quality": (data, deps) => deps.onSetPreviewQuality?.(Number(data.level)),
|
|
33
34
|
"set-root-duration": (data, deps) => deps.onSetRootDuration(Number(data.durationSeconds ?? 0)),
|
|
34
35
|
"set-play-range": (data, deps) => deps.onSetPlayRange(Number(data.startSeconds ?? 0), data.endSeconds == null ? null : Number(data.endSeconds)),
|
|
35
36
|
"set-color-grading": (data, deps) => deps.onSetColorGrading(data.target ?? null, data.grading ?? null),
|
|
@@ -32,11 +32,18 @@ import { getDebugSurface } from "./globals.js";
|
|
|
32
32
|
export function recordStartupError(error) {
|
|
33
33
|
let detail = "unknown error";
|
|
34
34
|
try {
|
|
35
|
-
|
|
35
|
+
if (error instanceof Error) {
|
|
36
|
+
detail = `${error.name}: ${error.message}`;
|
|
37
|
+
detail += startupErrorStack(error, detail);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
detail = String(error);
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
catch (err) {
|
|
38
44
|
swallow("runtime.startupError", err);
|
|
39
45
|
}
|
|
46
|
+
detail = detail.replace(/\s+/g, " ").trim();
|
|
40
47
|
window.__hfStartupError =
|
|
41
48
|
`HyperFrames runtime failed: ${detail}. Check the composition's scripts and window.__timelines ` +
|
|
42
49
|
`entries; if they look right, report this as a HyperFrames bug.`;
|
|
@@ -65,3 +72,33 @@ export function swallow(label, error) {
|
|
|
65
72
|
console.debug(`[hyperframes] ${label} swallowed:`, error);
|
|
66
73
|
}
|
|
67
74
|
}
|
|
75
|
+
function isCompositionFrame(frame) {
|
|
76
|
+
const location = /(?:\(|@|\bat )(\S+?):\d+(?::\d+)?\)?$/.exec(frame)?.[1];
|
|
77
|
+
if (!location || location.startsWith("hyperframes://"))
|
|
78
|
+
return false;
|
|
79
|
+
return (location.startsWith("hyperframes-composition://") ||
|
|
80
|
+
/\.html?(?:[?#]|$)/i.test(location) ||
|
|
81
|
+
(typeof document !== "undefined" && location === document.URL));
|
|
82
|
+
}
|
|
83
|
+
function startupErrorStack(error, header) {
|
|
84
|
+
try {
|
|
85
|
+
const stack = error.stack;
|
|
86
|
+
if (typeof stack !== "string")
|
|
87
|
+
return "";
|
|
88
|
+
const hasHeader = stack === header || stack.startsWith(`${header}\n`) || stack.startsWith(`${header}\r`);
|
|
89
|
+
const body = hasHeader ? stack.slice(header.length) : stack;
|
|
90
|
+
const frames = body
|
|
91
|
+
.split(/[\r\n]+/)
|
|
92
|
+
.map((line) => line.trim().replace(/\s+/g, " "))
|
|
93
|
+
.filter((line) => /^at\s+\S/.test(line) || /^[^@]*@.+:\d+(?::\d+)?$/.test(line));
|
|
94
|
+
const selected = frames.slice(0, 3);
|
|
95
|
+
const composition = frames.find(isCompositionFrame);
|
|
96
|
+
if (composition && !selected.includes(composition))
|
|
97
|
+
selected.push(composition);
|
|
98
|
+
return selected.length ? ` [thrown at: ${selected.join(" <- ")}]` : "";
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
swallow("runtime.startupError.stack", err);
|
|
102
|
+
return "";
|
|
103
|
+
}
|
|
104
|
+
}
|
package/dist/runtime/media.d.ts
CHANGED
|
@@ -81,6 +81,7 @@ export declare function evictMediaSyncState(el: HTMLMediaElement): void;
|
|
|
81
81
|
export declare function hasMediaSyncStateForTest(el: HTMLMediaElement): boolean;
|
|
82
82
|
export declare const MEDIA_HARD_SYNC_SECONDS = 0.5;
|
|
83
83
|
export declare const VIDEO_PRESEEK_SECONDS = 1.5;
|
|
84
|
+
export declare function mediaSourceTimeAt(clip: RuntimeMediaClip, timeSeconds: number): number;
|
|
84
85
|
/** Drift a playing audio element may carry before sync pulls it back onto the playhead. */
|
|
85
86
|
export declare const MEDIA_SYNC_TOLERANCE_SECONDS = 0.04;
|
|
86
87
|
export declare function syncRuntimeMedia(params: {
|
package/dist/runtime/media.js
CHANGED
|
@@ -193,6 +193,19 @@ export function hasMediaSyncStateForTest(el) {
|
|
|
193
193
|
}
|
|
194
194
|
export const MEDIA_HARD_SYNC_SECONDS = 0.5;
|
|
195
195
|
export const VIDEO_PRESEEK_SECONDS = 1.5;
|
|
196
|
+
export function mediaSourceTimeAt(clip, timeSeconds) {
|
|
197
|
+
const elapsed = Math.max(0, Math.min(timeSeconds, clip.end) - (clip.origin ?? clip.start));
|
|
198
|
+
const target = clip.mediaStart + sourceTimeAt(clip.rate ?? clip.playbackRate, elapsed);
|
|
199
|
+
if (clip.sourceDuration == null)
|
|
200
|
+
return target;
|
|
201
|
+
const loopLength = clip.sourceDuration - clip.mediaStart;
|
|
202
|
+
if (clip.loop && loopLength > 0 && target >= clip.sourceDuration)
|
|
203
|
+
return clip.mediaStart + ((target - clip.mediaStart) % loopLength);
|
|
204
|
+
// A non-loop video past its source holds the last frame.
|
|
205
|
+
if (!clip.loop && clip.el.tagName === "VIDEO")
|
|
206
|
+
return Math.min(target, clip.sourceDuration);
|
|
207
|
+
return target;
|
|
208
|
+
}
|
|
196
209
|
function prepareUpcomingVideo(clip, time, playing, rate) {
|
|
197
210
|
const { el } = clip;
|
|
198
211
|
const dueIn = clip.start - time;
|
|
@@ -206,15 +219,7 @@ function prepareUpcomingVideo(clip, time, playing, rate) {
|
|
|
206
219
|
findInjectedRenderFrame(el) ||
|
|
207
220
|
("__HF_EXPORT_RENDER_SEEK_CONFIG" in window && window.__HF_EXPORT_RENDER_SEEK_CONFIG))
|
|
208
221
|
return;
|
|
209
|
-
|
|
210
|
-
sourceTimeAt(clip.rate ?? clip.playbackRate, clip.start - (clip.origin ?? clip.start));
|
|
211
|
-
if (clip.sourceDuration != null) {
|
|
212
|
-
const loopLength = clip.sourceDuration - clip.mediaStart;
|
|
213
|
-
if (clip.loop && loopLength > 0 && target >= clip.sourceDuration)
|
|
214
|
-
target = clip.mediaStart + ((target - clip.mediaStart) % loopLength);
|
|
215
|
-
else if (!clip.loop)
|
|
216
|
-
target = Math.min(target, clip.sourceDuration);
|
|
217
|
-
}
|
|
222
|
+
const target = mediaSourceTimeAt(clip, clip.start);
|
|
218
223
|
if (!Number.isFinite(target) || target < 0 || Math.abs(el.currentTime - target) <= 0.001)
|
|
219
224
|
return;
|
|
220
225
|
try {
|
|
@@ -282,13 +287,9 @@ export function syncRuntimeMedia(params) {
|
|
|
282
287
|
!inWindow &&
|
|
283
288
|
(params.timeSeconds >= clip.end || sameInstant(params.timeSeconds, clip.end)) &&
|
|
284
289
|
isClipVisibleAt(params.timeSeconds, clip.start, clip.end, params.getCompositionDuration());
|
|
285
|
-
|
|
286
|
-
clip.mediaStart;
|
|
290
|
+
const relTime = mediaSourceTimeAt(clip, params.timeSeconds);
|
|
287
291
|
const isHeldVideoTail = isTerminalVideo ||
|
|
288
292
|
(isNonLoopVideo && clip.sourceDuration != null && relTime >= clip.sourceDuration && inWindow);
|
|
289
|
-
if (isHeldVideoTail && clip.sourceDuration != null) {
|
|
290
|
-
relTime = Math.min(relTime, clip.sourceDuration);
|
|
291
|
-
}
|
|
292
293
|
const previousRelativeTime = lastRelativeTime.get(el);
|
|
293
294
|
const audioReenteredAfterBackwardSeek = el.tagName === "AUDIO" &&
|
|
294
295
|
(previousRelativeTime === undefined || relTime < previousRelativeTime - 0.04);
|
|
@@ -308,13 +309,6 @@ export function syncRuntimeMedia(params) {
|
|
|
308
309
|
(!el.ended || clip.loop || isHeldVideoTail || canSeekEndedMediaBackward);
|
|
309
310
|
if (isActive) {
|
|
310
311
|
lastRelativeTime.set(el, relTime);
|
|
311
|
-
// Loop wrapping: when media reaches end, restart from mediaStart
|
|
312
|
-
if (clip.loop && clip.sourceDuration != null && clip.sourceDuration > 0) {
|
|
313
|
-
const loopLength = clip.sourceDuration - clip.mediaStart;
|
|
314
|
-
if (loopLength > 0 && relTime >= clip.sourceDuration) {
|
|
315
|
-
relTime = clip.mediaStart + ((relTime - clip.mediaStart) % loopLength);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
312
|
const userVol = clampVolume(params.userVolume ?? 1);
|
|
319
313
|
const fallbackAuthorVolume = clampAudioGain(clip.volume ?? 1);
|
|
320
314
|
const previousRuntimeVolume = lastRuntimeAppliedVolume.get(el);
|
|
@@ -27,8 +27,10 @@ export function showHiddenClips(only = () => true) {
|
|
|
27
27
|
export function showClips(hidden) {
|
|
28
28
|
const putMarksBack = hidden.map((el) => revealClip(el));
|
|
29
29
|
return () => {
|
|
30
|
-
for (const el of hidden)
|
|
31
|
-
el.style.visibility
|
|
30
|
+
for (const el of hidden) {
|
|
31
|
+
if (el.style.getPropertyValue("visibility") !== "hidden")
|
|
32
|
+
el.style.setProperty("visibility", "hidden", "important");
|
|
33
|
+
}
|
|
32
34
|
for (const putMarkBack of putMarksBack)
|
|
33
35
|
putMarkBack();
|
|
34
36
|
};
|
package/dist/runtime/timeline.js
CHANGED
|
@@ -40,9 +40,10 @@ export function runtimeElementWindow(rawNode, options) {
|
|
|
40
40
|
duration = liveDuration;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
const isRoot = compId !== null && rawNode === findRootCompositionElement(rawNode.ownerDocument);
|
|
43
44
|
return {
|
|
44
45
|
start,
|
|
45
|
-
end: duration != null && duration > 0 ? start + duration : Number.POSITIVE_INFINITY,
|
|
46
|
+
end: !isRoot && duration != null && duration > 0 ? start + duration : Number.POSITIVE_INFINITY,
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
49
|
export function isRuntimeElementVisibleAt(rawNode, options) {
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type RuntimeJson = string | number | boolean | null | RuntimeJson[] | {
|
|
|
6
6
|
import type { HyperframeControlAction } from "../inline-scripts/runtimeContract.js";
|
|
7
7
|
import type { HyperframePickerElementInfo } from "../inline-scripts/pickerApi.js";
|
|
8
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";
|
|
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-preview-quality" | "set-root-duration" | "set-play-range" | "stop-media" | "flash-elements";
|
|
10
10
|
type RuntimeBridgeControlMessageBase = {
|
|
11
11
|
source: "hf-parent";
|
|
12
12
|
type: "control";
|
|
@@ -21,6 +21,7 @@ type RuntimeBridgeControlMessageBase = {
|
|
|
21
21
|
disabled?: boolean;
|
|
22
22
|
slow?: boolean;
|
|
23
23
|
scale?: number;
|
|
24
|
+
level?: number;
|
|
24
25
|
playbackRate?: number;
|
|
25
26
|
target?: HfColorGradingTarget | string | null;
|
|
26
27
|
grading?: RuntimeJson;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isFontValue, isImageValue } from "@hyperframes/parsers/composition";
|
|
1
2
|
/**
|
|
2
3
|
* Compare a flat values map (from `--variables` / `data-variable-values`) to
|
|
3
4
|
* the declared schema (`data-composition-variables`). Returns issues for keys
|
|
@@ -86,10 +87,7 @@ function checkType(value, decl) {
|
|
|
86
87
|
actual: jsTypeOf(value),
|
|
87
88
|
};
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
-
// value ({name: 42} / {}) is caught here rather than surfacing as a bogus
|
|
91
|
-
// font-family at render time.
|
|
92
|
-
if (typeof value.name !== "string" || typeof value.source !== "string") {
|
|
90
|
+
if (!isFontValue(value)) {
|
|
93
91
|
return {
|
|
94
92
|
kind: "type-mismatch",
|
|
95
93
|
variableId: decl.id,
|
|
@@ -111,13 +109,14 @@ function checkType(value, decl) {
|
|
|
111
109
|
actual: jsTypeOf(value),
|
|
112
110
|
};
|
|
113
111
|
}
|
|
114
|
-
|
|
115
|
-
if (typeof value.url !== "string") {
|
|
112
|
+
if (!isImageValue(value)) {
|
|
116
113
|
return {
|
|
117
114
|
kind: "type-mismatch",
|
|
118
115
|
variableId: decl.id,
|
|
119
116
|
expected: "image object {url: string}",
|
|
120
|
-
actual:
|
|
117
|
+
actual: typeof value.url !== "string"
|
|
118
|
+
? "object missing string url"
|
|
119
|
+
: "object with invalid alt/fit",
|
|
121
120
|
};
|
|
122
121
|
}
|
|
123
122
|
return null;
|
package/dist/variables.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the Node-only modules reachable from the core/parsers root entries, so
|
|
6
6
|
* browser consumers (SDK, Studio, embedders) can bundle it.
|
|
7
7
|
*/
|
|
8
|
-
export type { CompositionVariable, CompositionVariableType, CompositionVariableBase, StringVariable, NumberVariable, ColorVariable, BooleanVariable, EnumVariable, FontVariable, ImageVariable, } from "@hyperframes/parsers/composition";
|
|
8
|
+
export type { CompositionVariable, CompositionVariableType, CompositionVariableBase, StringVariable, NumberVariable, ColorVariable, BooleanVariable, EnumVariable, FontVariable, FontValue, ImageVariable, ImageValue, } from "@hyperframes/parsers/composition";
|
|
9
9
|
export { COMPOSITION_VARIABLE_TYPES, parseCompositionVariables, isCompositionVariable, isScalarVariableValue, scanVariableUsage, } from "@hyperframes/parsers/composition";
|
|
10
10
|
export type { VariableUsageScan } from "@hyperframes/parsers/composition";
|
|
11
11
|
export { getVariables, readDeclaredDefaults } from "./runtime/getVariables.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.201",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -397,9 +397,9 @@
|
|
|
397
397
|
"linkedom": "^0.18.12",
|
|
398
398
|
"postcss": "^8.5.8",
|
|
399
399
|
"wawoff2": "^2.0.1",
|
|
400
|
-
"@hyperframes/
|
|
401
|
-
"@hyperframes/
|
|
402
|
-
"@hyperframes/
|
|
400
|
+
"@hyperframes/lint": "0.8.201",
|
|
401
|
+
"@hyperframes/studio-server": "0.8.201",
|
|
402
|
+
"@hyperframes/parsers": "0.8.201"
|
|
403
403
|
},
|
|
404
404
|
"devDependencies": {
|
|
405
405
|
"@fontsource/archivo-black": "^5.2.8",
|