@hyperframes/core 0.8.198 → 0.8.200

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/index.d.ts CHANGED
@@ -49,6 +49,7 @@ export { fitTextFontSize } from "./text/index.js";
49
49
  export type { FitTextOptions, FitTextResult } from "./text/index.js";
50
50
  export { formatRenderOutputTimestamp } from "./utils/renderOutputTimestamp.js";
51
51
  export { getVariables } from "./runtime/getVariables.js";
52
+ export { SCENE_CALLBACK_ERROR_PREFIX } from "./runtime/diagnostics.js";
52
53
  export { parseStartExpression, parseNumeric, type ReferenceExpression, } from "./runtime/startExpression.js";
53
54
  export { COMPOSITION_CONTRACT_VERSION, COMPOSITION_ATTRIBUTES, CANONICAL_AUTHORED_TIMING_ATTRIBUTES, DERIVED_TIMING_ATTRIBUTES, LEGACY_TIMING_ATTRIBUTES, readClipTiming, writeClipTiming, ClipTimingWriteError, type ClipTiming, type ClipTimingDiagnostic, type ClipTimingDiagnosticCode, type ClipTimingUpdate, } from "./compositionContract.js";
54
55
  export { createRuntimeStartTimeResolver } from "./runtime/startResolver.js";
package/dist/index.js CHANGED
@@ -44,6 +44,7 @@ export { fitTextFontSize } from "./text/index.js";
44
44
  export { formatRenderOutputTimestamp } from "./utils/renderOutputTimestamp.js";
45
45
  // Runtime helpers (composition-side)
46
46
  export { getVariables } from "./runtime/getVariables.js";
47
+ export { SCENE_CALLBACK_ERROR_PREFIX } from "./runtime/diagnostics.js";
47
48
  export { parseStartExpression, parseNumeric, } from "./runtime/startExpression.js";
48
49
  export { COMPOSITION_CONTRACT_VERSION, COMPOSITION_ATTRIBUTES, CANONICAL_AUTHORED_TIMING_ATTRIBUTES, DERIVED_TIMING_ATTRIBUTES, LEGACY_TIMING_ATTRIBUTES, readClipTiming, writeClipTiming, ClipTimingWriteError, } from "./compositionContract.js";
49
50
  // Also exposed via the ./runtime/start-resolver subpath. This root re-export
@@ -1,7 +1,10 @@
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
- // 256 * 2^(k/2), even: nearby boxes share one cached copy, and a rung overshoots by at most ~41%.
4
- const RUNGS = [256, 362, 512, 724, 1024, 1448, 2048, 2896, 4096, 5792, 8192];
3
+ // 256 * 2^(k/4), even: nearby boxes share one cached copy, and a rung overshoots by at most ~19%.
4
+ const RUNGS = [
5
+ 256, 304, 362, 430, 512, 608, 724, 862, 1024, 1218, 1448, 1722, 2048, 2436, 2896, 3444, 4096,
6
+ 4870, 5792, 6888, 8192,
7
+ ];
5
8
  function rungAtLeast(pixels) {
6
9
  if (!(pixels > 0))
7
10
  return null;
@@ -1,7 +1,7 @@
1
1
  /** The visibility pass's mark on a timed clip it hides; the runtime's rules hide the clip's contents by it. */
2
2
  export declare const CLIP_HIDDEN_ATTR = "data-hf-clip-hidden";
3
3
  /** Shows a clip the visibility pass hid, contents included; returns a function that puts the mark back. */
4
- export declare function revealClip(el: HTMLElement, priority?: string): () => void;
4
+ export declare function revealClip(el: Element & ElementCSSInlineStyle, priority?: string): () => void;
5
5
  /** Called by shader-transitions builds on load: their revealers go through revealClip. */
6
6
  export declare function declareClipRevealAware(): void;
7
7
  /** A shader-transitions build is on the page whose revealers predate revealClip. */
@@ -1,3 +1,5 @@
1
1
  /** The named error readiness waits fail with once start-up or the render-ready publish throws; it stays set. */
2
2
  export declare function recordStartupError(error: unknown): void;
3
+ /** Starts the warning for a scene callback that threw; the render log shows it once per render. */
4
+ export declare const SCENE_CALLBACK_ERROR_PREFIX = "[hyperframes] scene timeline callback threw:";
3
5
  export declare function swallow(label: string, error?: unknown): void;
@@ -41,6 +41,8 @@ export function recordStartupError(error) {
41
41
  `HyperFrames runtime failed: ${detail}. Check the composition's scripts and window.__timelines ` +
42
42
  `entries; if they look right, report this as a HyperFrames bug.`;
43
43
  }
44
+ /** Starts the warning for a scene callback that threw; the render log shows it once per render. */
45
+ export const SCENE_CALLBACK_ERROR_PREFIX = "[hyperframes] scene timeline callback threw:";
44
46
  export function swallow(label, error) {
45
47
  if (typeof window === "undefined")
46
48
  return;
@@ -1,7 +1,8 @@
1
1
  import { CLIP_HIDDEN_ATTR } from "./clipReveal.js";
2
2
  export { CLIP_HIDDEN_ATTR };
3
3
  export declare const SKIPPED_CLIP = "[data-start]:not(video, audio, img, [data-hf-upcoming], [data-hf-autostamped])[data-hf-clip-hidden]";
4
- export declare function showHiddenClips(): () => void;
4
+ export declare function showHiddenClips(only?: (el: HTMLElement) => boolean): () => void;
5
+ export declare function showClips(hidden: Array<Element & ElementCSSInlineStyle>): () => void;
5
6
  export declare function defersMedia(): boolean;
6
7
  /** True in Studio's preview, where hidden clips' images are neither fetched nor decoded until due. */
7
8
  export declare function skipsHiddenImages(): boolean;
@@ -21,8 +21,10 @@ const hideHiddenClipContents = (clip) => {
21
21
  .join(", ");
22
22
  return `${clip} * { visibility: hidden !important; } ${filterOutputLayers} { filter: none !important; }`;
23
23
  };
24
- export function showHiddenClips() {
25
- const hidden = Array.from(document.querySelectorAll(`[${CLIP_HIDDEN_ATTR}]`));
24
+ export function showHiddenClips(only = () => true) {
25
+ return showClips(Array.from(document.querySelectorAll(`[${CLIP_HIDDEN_ATTR}]`)).filter(only));
26
+ }
27
+ export function showClips(hidden) {
26
28
  const putMarksBack = hidden.map((el) => revealClip(el));
27
29
  return () => {
28
30
  for (const el of hidden)
@@ -1,4 +1,4 @@
1
- import type { RuntimeTimelineMessage, RuntimeTimelineLike } from "./types.js";
1
+ import type { RuntimeTimelineClip, RuntimeTimelineMessage, RuntimeTimelineLike } from "./types.js";
2
2
  import { createRuntimeStartTimeResolver } from "./startResolver.js";
3
3
  export declare function runtimeElementWindow(rawNode: Element, options: {
4
4
  timelineRegistry: Record<string, RuntimeTimelineLike | undefined>;
@@ -15,12 +15,19 @@ export declare function isRuntimeElementVisibleAt(rawNode: Element, options: {
15
15
  timelineRegistry: Record<string, RuntimeTimelineLike | undefined>;
16
16
  resolver: ReturnType<typeof createRuntimeStartTimeResolver>;
17
17
  }): boolean;
18
+ export declare function parseElementDurationAttr(element: Element): number | null;
18
19
  /**
19
20
  * Parse an authored track attribute, honoring 0 (a valid top-lane index).
20
21
  * `parseInt(...) || fallback` silently replaced authored track 0 with the
21
22
  * synthetic fallback, so track-0 clips drifted to the bottom of the timeline.
22
23
  */
23
24
  export declare function parseAuthoredTrack(el: Element, fallback: number): number;
25
+ export type ParkedTimelineScene = {
26
+ name: string;
27
+ host: () => Element;
28
+ };
24
29
  export declare function collectRuntimeTimelinePayload(params: {
25
30
  canonicalFps: number;
31
+ parked?: ParkedTimelineScene[];
32
+ parkedClips?: Map<string, RuntimeTimelineClip[]>;
26
33
  }): RuntimeTimelineMessage;
@@ -58,7 +58,7 @@ export function isRuntimeElementVisibleAt(rawNode, options) {
58
58
  function parseNum(value) {
59
59
  return parseStrictFiniteTimingNumber(value);
60
60
  }
61
- function parseElementDurationAttr(element) {
61
+ export function parseElementDurationAttr(element) {
62
62
  const publicDuration = element.getAttribute("data-duration");
63
63
  const authoredDuration = element.getAttribute(AUTHORED_DURATION_ATTR);
64
64
  const resolved = resolveAuthoredTimingWindow({
@@ -353,13 +353,14 @@ export function collectRuntimeTimelinePayload(params) {
353
353
  // as clips — they have no declared timing so the timeline can't show their
354
354
  // actual visibility window. They can still appear as scenes via the separate
355
355
  // scene collection below.
356
- const nodes = Array.from(document.querySelectorAll("[data-start], [data-track-index], [data-composition-id], video, audio, img"));
356
+ const CLIP_NODES = "[data-start], [data-track-index], [data-composition-id], video, audio, img";
357
+ const nodes = Array.from(document.querySelectorAll(CLIP_NODES));
357
358
  let maxEnd = 0;
358
- for (const [i, node] of nodes.entries()) {
359
+ const clipOf = (node, i) => {
359
360
  if (node === root)
360
- continue;
361
+ return null;
361
362
  if (["SCRIPT", "STYLE", "LINK", "META", "TEMPLATE", "NOSCRIPT"].includes(node.tagName))
362
- continue;
363
+ return null;
363
364
  const compositionContext = resolveNearestCompositionContext(node, root);
364
365
  const tag = node.tagName.toLowerCase();
365
366
  let start = tag === "video" || tag === "audio"
@@ -387,21 +388,19 @@ export function collectRuntimeTimelinePayload(params) {
387
388
  }
388
389
  }
389
390
  if (duration == null || duration <= 0)
390
- continue;
391
+ return null;
391
392
  duration = clampDurationToRootWindow(start, duration);
392
393
  if (duration <= 0)
393
- continue;
394
+ return null;
394
395
  const slots = startResolver.resolveHostSlotsForElement(node);
395
396
  if (slots.length > 0) {
396
397
  const played = cutToHostSlots({ start, end: start + duration }, slots);
397
398
  const keepZeroLengthSoStudioNestsChildren = isNestedHost;
398
399
  if (played.end <= played.start && !keepZeroLengthSoStudioNestsChildren)
399
- continue;
400
+ return null;
400
401
  start = played.start;
401
402
  duration = played.end - played.start;
402
403
  }
403
- const end = start + duration;
404
- maxEnd = Math.max(maxEnd, end);
405
404
  const kind = nodeCompositionId && nodeCompositionId !== rootCompositionId
406
405
  ? "composition"
407
406
  : tag === "video"
@@ -411,7 +410,7 @@ export function collectRuntimeTimelinePayload(params) {
411
410
  : tag === "img"
412
411
  ? "image"
413
412
  : "element";
414
- clips.push({
413
+ return {
415
414
  id: stableClipId(node) ?? nodeCompositionId ?? null,
416
415
  label: buildTimelineClipLabel(node, kind, clips.length),
417
416
  start,
@@ -433,7 +432,26 @@ export function collectRuntimeTimelinePayload(params) {
433
432
  timelineLabel: node.getAttribute("data-timeline-label"),
434
433
  timelineGroup: node.getAttribute("data-timeline-group"),
435
434
  timelinePriority: parseNum(node.getAttribute("data-timeline-priority")),
436
- });
435
+ };
436
+ };
437
+ const addClip = (clip) => {
438
+ clips.push(clip);
439
+ maxEnd = Math.max(maxEnd, clip.start + clip.duration);
440
+ };
441
+ for (const [i, node] of nodes.entries()) {
442
+ const clip = clipOf(node, i);
443
+ if (clip)
444
+ addClip(clip);
445
+ }
446
+ for (const scene of params.parked ?? []) {
447
+ let parkedClips = params.parkedClips?.get(scene.name);
448
+ if (!parkedClips) {
449
+ const offset = nodes.length;
450
+ parkedClips = Array.from(scene.host().querySelectorAll(CLIP_NODES)).flatMap((node, j) => clipOf(node, offset + j) ?? []);
451
+ params.parkedClips?.set(scene.name, parkedClips);
452
+ }
453
+ for (const clip of parkedClips)
454
+ addClip(clip);
437
455
  }
438
456
  // ── GSAP introspection ──────────────────────────────────────────────────
439
457
  // Discover elements animated by GSAP that weren't picked up by the DOM query
@@ -5,5 +5,7 @@ export declare const STUDIO_PREVIEW_LAZY_ATTR = "data-hf-preview-lazy";
5
5
  export declare const STUDIO_PREVIEW_ERRORS = "__hfPreviewErrors";
6
6
  export declare const PREVIEW_RASTER_ATTR = "data-hf-preview-raster";
7
7
  export declare const RUNTIME_STAMPED_ATTR = "data-hf-autostamped";
8
- export declare const PREVIEW_ONLY_ATTRS: readonly ["data-hf-upcoming", "data-hf-preview-lazy", "data-hf-preview-raster", "data-hf-autostamped"];
8
+ export declare const STUDIO_PREVIEW_FAR_SCENE_ATTR = "data-hf-far-scene";
9
+ export declare const STUDIO_PREVIEW_PARKED_SCENE_ATTR = "data-hf-parked-scene";
10
+ export declare const PREVIEW_ONLY_ATTRS: readonly ["data-hf-upcoming", "data-hf-far-scene", "data-hf-parked-scene", "data-hf-preview-lazy", "data-hf-preview-raster", "data-hf-autostamped"];
9
11
  export declare function applyAuthoredTiming(el: Element, attrs: ReadonlyArray<readonly [name: string, value: string]>): void;
@@ -5,8 +5,12 @@ export const STUDIO_PREVIEW_LAZY_ATTR = "data-hf-preview-lazy";
5
5
  export const STUDIO_PREVIEW_ERRORS = "__hfPreviewErrors";
6
6
  export const PREVIEW_RASTER_ATTR = "data-hf-preview-raster";
7
7
  export const RUNTIME_STAMPED_ATTR = "data-hf-autostamped";
8
+ export const STUDIO_PREVIEW_FAR_SCENE_ATTR = "data-hf-far-scene";
9
+ export const STUDIO_PREVIEW_PARKED_SCENE_ATTR = "data-hf-parked-scene";
8
10
  export const PREVIEW_ONLY_ATTRS = [
9
11
  STUDIO_PREVIEW_UPCOMING_ATTR,
12
+ STUDIO_PREVIEW_FAR_SCENE_ATTR,
13
+ STUDIO_PREVIEW_PARKED_SCENE_ATTR,
10
14
  STUDIO_PREVIEW_LAZY_ATTR,
11
15
  PREVIEW_RASTER_ATTR,
12
16
  RUNTIME_STAMPED_ATTR,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/core",
3
- "version": "0.8.198",
3
+ "version": "0.8.200",
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/parsers": "0.8.198",
401
- "@hyperframes/studio-server": "0.8.198",
402
- "@hyperframes/lint": "0.8.198"
400
+ "@hyperframes/studio-server": "0.8.200",
401
+ "@hyperframes/parsers": "0.8.200",
402
+ "@hyperframes/lint": "0.8.200"
403
403
  },
404
404
  "devDependencies": {
405
405
  "@fontsource/archivo-black": "^5.2.8",