* feat(core): support deterministic async frame sources * feat(core): bridge preserved film HTML to native capture * feat(core): bound imported scene timing to source intervals * test(producer): verify film bridge pixels in real browser * fix(runtime): retain queued draws and disable unsafe dedup * fix(runtime): fail promptly on runner reloads and send errors * fix(runtime): align film draws with export windows * docs(core): mark frame-source hosts with data-no-timeline A composition that follows the frame-source contract registers no GSAP timeline, so lint reported missing_timeline_registry and every render waited 45 s for timeline registration (17.6 s -> 1 min 47.9 s for the 14 s imported film sample). Document the existing data-no-timeline opt-out for the host and a timeline-less root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(core): require data-no-timeline on imported film hosts Imported film wrappers have no GSAP timeline. Without data-no-timeline on the scene hosts and root, lint fails with missing_timeline_registry and each render waits 45 s for timeline registration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runtime): avoid transport redraws after render seeks * test: set explicit film fixture canvas background * test: diagnose film capture timeout phase * test: foreground film pages before screenshot capture --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2.7 KiB
title, description
| title | description |
|---|---|
| Frame sources | Run deterministic scene code on the HyperFrames timeline. |
HyperFrames can drive scene code that exposes a function of time without converting it to GSAP. Register that function against a timed host using window.__hyperframes.registerFrameSource before runtime initialization completes.
const unregister = window.__hyperframes.registerFrameSource({
element: document.getElementById("scene"),
ready: initializeScene(),
render: (sourceTime, signal) => drawScene(sourceTime, signal),
dispose: () => releaseScene(),
});
The host uses the usual composition attributes: data-composition-id, data-start, data-duration, and data-track-index. Declare the root's dimensions, FPS, and duration. A frame source does not need a dummy GSAP timeline. Add data-no-timeline to the host, and to a root that registers no timeline; otherwise hyperframes lint reports missing_timeline_registry and each render waits 45 seconds for timeline registration.
The callback receives seconds in source time: playback inpoint (data-playback-start) plus the rate-adjusted time since the host's resolved start. Optional sourceRange: { start, duration, fps } adds an original source offset and clamps this time to the last source frame within that interval. Existing playback rate and speed-ramp semantics apply. Timing is read again on every seek, so move, trim and rate edits do not require rewriting the animation code. Each overlapping scene needs its own source instance.
ready holds initialization and export capture. Return a promise from render when drawing is asynchronous: capture waits for it before taking pixels. Repeated and out-of-order times must produce the same frame. HyperFrames owns playback; do not start a second clock.
Draws are serialized per source. Rapid preview seeks coalesce while a draw is in flight; sequential export seeks draw every requested frame. Setup and draw failures are delivered to the capture completion barrier. A later successful seek can recover from a frame failure.
Call unregister() when replacing a source. Removal of its host or runtime teardown also unregisters it. The callback's AbortSignal is aborted, queued work is cancelled, capture waiters are released, and dispose runs once. Stop any underlying work in response to the signal or in dispose; cancellation cannot forcibly interrupt synchronous JavaScript.
Registration does not expose arbitrary scene code as editable keyframes. Manual element edits need stable identities and persistent parameters or overrides. Imported iframe sources also need screenshot capture and an explicit message bridge; this API does not grant access to sandboxed DOM.