* fix(core): a preview video short of data holds the film instead of looping snippets
* fix(core): keep the comment share of the runtime files where it was
* fix: cache paths follow HYPERFRAMES_CACHE_DIR
Every place HyperFrames keeps downloaded or built files now takes its
folder from one helper, hyperframesCacheDir() in @hyperframes/core. The
default stays ~/.cache/hyperframes; HYPERFRAMES_CACHE_DIR moves it.
* fix: register the cache-dir subpath for bun and node, and build inspector from core source
* test: the cache-dir override test uses a folder that is absolute on every platform
* fix: the opencv cache follows HYPERFRAMES_CACHE_DIR
* fix(cli): npm installs run in their staging dir, so no cache path reaches a command line
* fix(cli): whisper.cpp is cloned inside its build dir, so no cache path is a git argument
* test(cli): the whisper clone test finds no system whisper on Windows either
* fix(core): accept 65-point .cube LUTs, the size grading apps export
* fix(core): shrink LUTs wider than the GPU texture limit instead of rendering black
* fix(cli): check and snapshot free video clips the playhead left, halving memory on cut films
* fix(core): drop the releaseMedia doc comment that raised the file's comment share
* fix(core): a resized preview video keeps its picture while its new copy loads
Swapping a video to a copy made for its new size emptied it until the copy
decoded, so the preview showed black for a moment. The swap now shows a still
of the frame it had, as the video's poster, until the new copy can draw.
* fix(core): a held preview still is let go when no file loads back
* chore(core): raise the packed size budget for the held preview still
* feat(core): WebKit plays bare audio from a decoded buffer on the audio clock
* fix(core): a handed-over WebKit track goes back to its element when the speed changes
* test(player): play the WebKit audio edits in real Safari on a macOS runner
* fix(core): Safari keeps playing edits' audio without seeks or rate changes
* fix(core): keep the 0.1 s audio sync bound outside WebKit
* fix(core): restore main's audio steering outside WebKit
* fix(core): tell WebKit from the test DOM's user agent
* fix(core): name WebKit's audio start lag instead of commenting it
* fix(core): count embedded WKWebViews as WebKit for audio sync
* feat(core): the playback health reading says which clock the film followed
* style(core): format the clock's new reading
* refactor(core): let the clock's names say what the comments said
* fix(core): a seek that never settles ends after 30 s and names what it waits on
* fix(core): keep the seek-wait comments within the comment limits
* fix(core): only a caller's limit ends a seek wait; check and snapshot end it before their timeout
* fix(core): style a sub-composition root written as #root[data-composition-id]
* fix(core): keep an anonymous host's root styled when #root[data-composition-id] is scoped
* fix(core): scope a compounded authored root as a selector list so pseudo-elements stay valid
* fix(core): Safari stops chopping audio by seeking it over and over during playback
* test(player): the WebKit playbench also counts audio seeks and frozen audio
* fix(core): audio still catching up is seeked once its lag passes hard sync
* fix(core): motion blur preview no longer slows down later in the timeline
With data-motion-blur-events="on", which Studio's Subtle and Strong write,
both blur tiers ran timeline callbacks at every per-frame pose read. Each
frame's reads step back from half a shutter ahead to the frame, so a
callback that keeps state and replays from zero on a backward seek (a
ripple simulation, for example) redid its whole history most frames, and
the cost grew with the playhead.
The mover scan still runs callbacks, so motion set from a render(t)
callback is still found. With events on, it also scans once without them,
and the per-frame reads run callbacks only when the two scans disagree.
The eventful scan runs first, so tweens take their start values after the
callbacks before them and a one-off call fires as often as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(core): keep the motion blur comments to the invariant
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(core): motion blur reads run callbacks when a callback moves any box
Comparing which elements each scan finds missed a callback that pans a
mover's ancestor while a tween also changes that ancestor: both scans
found the same movers and the same changing elements, so the reads left
the pan out. The scans now compare every changing element's box at each
step, and the reads run callbacks when any step differs.
Raises @hyperframes/core's unpacked size budget to the measured size plus
the usual 5%: main already sat 0.98% over the old budget, and this change
adds 1,232 bytes, which tipped it past the 1% tolerance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(core): silent motion blur reads land back on the frame as its own seek left it
After silent pose reads, the restore seek back to the frame left GSAP in a
different state than the frame's own eventful seek did:
- A step exactly on the frame (a .call() or set) was re-armed, so the next
frame fired it again. Calls fired 2-5 times per crossing, and a toggle
could end inverted.
- In renders, which keep no GSAP structure, landing back on the frame from
later skipped same-time steps' authored order, so the frame showed the
first of two sets instead of the last.
Events-off blur always read silently and had both. This PR moves events-on
roots without callback-driven motion (the Studio default) onto that path,
so both are fixed here.
The host's new holdFrame snapshots every landing mark on the root and scene
timelines before the reads, and its restore seeks back silently, redraws in
authored order where there is no structure, and puts the marks back. Each
call now fires once per frame crossing, as without blur, and same-time sets
land as authored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(core): a held render frame draws its scenes first, so the root lands last
holdFrame redrew the root and then the scenes, the reverse of the frame's
own seek. When a scene and the root tween one property, the frame landed
on the scene's value instead of the root's.
The hold and landing move into the GSAP adapter as holdFrameMarks, which
takes the scenes and the root separately, so the order lives in one place
a real-GSAP test can pin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(core): audio that decodes short plays from its element in preview
* fix(core): keep the decoded copy when the element's duration is unknown
* fix(player): preview pauses with Buffering until every track due can play
* fix(core): keep the transport awake while it buffers
* fix(core): wait only for tracks the clock would also treat as playable
* test(core): buffering fixture pauses like a browser, with a pause event
* fix(core): hold for a clip only after media sync has asked it to play
* test(core): hold lands on the frame a slow tick skips into a clip with no data
* fix(core): a held clip counts as ready once it has data buffered ahead
* feat(core): playback health reports how long a video on screen showed no moving picture
* fix(core): a frozen picture is judged by the clip's own timing, not the film's
* style(core): shorten a test comment under the line limit
* fix(core): the frozen-picture check reads a video from any realm
* refactor(core): cut the frozen-picture comments the comment ratchet counts
* fix(core): the first cut after Play starts on time instead of running ahead
* fix(core): learn half the start delay from Play so the first cut keeps its last frame
* perf(studio): films with thousands of timed clips stop re-reading every clip each frame
* perf(studio): drop the added comment lines the ratchet counts
* fix(core): a video plays to the last frame before its out-point instead of stopping a frame early
* fix(core): a dropped frame before an out-point no longer lets the out-point's frame show
* perf(core): a video edit with no animation timeline stops rewriting every clip each frame
* refactor(core): drop the comments the comment ratchet counts
* fix(core): a clip that has fully downloaded stays loaded and plays on time
* refactor(core): drop the comments the comment ratchet counts
* fix(core): the playhead keeps moving at a cut while the incoming take has not started
* fix(core): shorten a comment in the clock
* fix(player): keep the WebKit stops script out of the type check
* fix(core): cut two comments from the clock
* fix(core): a still sub-composition's data-no-timeline on its template root skips the timeline wait
* chore(core): drop a comment the copy already says
* fix(core): the preview's scene window settles when a scene can't unmount instead of hanging the page
* refactor(core): name the scene window's stuck step instead of commenting it
* fix(core): telemetry redaction covers folders with spaces in any script
* style(core): shorten the redaction folder note
* fix(core): spaced folders without a root redact only before a file name
* style(core): drop the redaction note that described the leak as intended
* style(core): two fewer comment lines in the redactor
* fix(core): bound the spaced-folder match so long lines stay linear