Commit Graph
1511 Commits
Author SHA1 Message Date
Miguel Angel Simon Sierra 21bfd241f2 chore(core): shorten a comment 2026-10-25 20:05:33 -04:00
Miguel Angel Simon Sierra 18814202f3 fix(core): text the parser appends to a bound title is replaced, not kept 2026-10-25 20:04:51 -04:00
Miguel Angel Simon Sierra a1ace97ce5 chore: merge main into the variable text split fix 2026-10-25 19:15:43 -04:00
Abdullah M. Nazif 707c150cbd fix(cli): include external srcset images in project archives (#6335) 2026-10-25 22:55:35 +00:00
Miguel Ángel 553f2c5880 fix(core): a timeline set that hides a timed clip hides it in preview and render (#6351)
* fix(core): a timeline set that hides a timed clip hides it in preview and render

* fix(core): tell a script's hidden clip from the runtime's by the declaration's priority

* fix(core): a scene a script hides takes its timed children with it
2026-10-25 22:53:10 +00:00
Miguel Ángel 0ae48c9f33 fix(core): a root without data-duration stays on screen after its GSAP timeline ends (#6354)
A root composition with no data-duration took its own GSAP timeline's length as its visibility
window, so when media made the composition longer, the whole frame went black from the end of
that timeline in preview and render. The root's window is now open-ended, bounded by the
composition's length. In a framed preview, the duration the runtime stamps on GSAP targets for
Studio's timeline no longer hides the clips inside them either: the ancestor chain check now
skips discovery stamps, as the clip's own visibility pass already does.
2026-10-25 22:12:42 +00:00
Miguel Ángel 33685ef2be fix(core): a self-closed audio group no longer hides the clips after it (#6344)
* fix(core): a self-closed audio group no longer hides the clips after it

HTML does not close a custom element on `/>`, so `<hf-audio-group id="sfx" />` takes in every
later sibling, and the runtime's inert style (`display:none`) hid them in preview, snapshot and
render. The style is now `display:contents`: an empty group still makes no box, and anything
inside one renders as written. A lint warning names the elements a group holds, and the docs and
mixing reference show the group closed.

* style(core): cut the audio group comments to the comment length limits

* fix(core): a muted audio group still hides what sits inside it

A muted bus (`data-hidden`) is hidden by an inline display:none that the bus rule outranked, so
clips inside a muted self-closed bus kept painting while their audio and video frames dropped.
2026-10-25 21:44:32 +00:00
Miguel Ángel 2c10eb0a33 chore: release v0.8.200 (#6337) 2026-10-25 20:50:21 +00:00
Miguel Ángel a6121faa72 fix(core): a scene callback that throws no longer stops the main timeline in render (#6322)
* fix(core): a scene callback that throws no longer stops the main timeline in render

Render seeks now leave each scene paused in the root's pass and seek it on its own clock first,
as preview does, so a throwing onUpdate cannot cut the root's tweens short. The error is logged
once per scene as a composition script error, and the render log shows it once per render.

* fix(core): a scene registered without a timeline is not reported as a script error

A placeholder registration ({}) has nothing to seek. seekGsapTimeline now only calls seek()
when the object has one, as player.ts already does, so the new scene-error report stays for
real callback errors.

* fix(core): report a scene callback error as a warning, keeping render failure classes

Logged as a composition script error, a scene callback that threw became a page error, which
turns a timed-out timeline wait into a script failure and cuts the wait short. It is now a
runtime warning the engine forwards to the render log once per render, outside page errors.

* chore(core): regenerate the position-edits render bundle for the new diagnostics export
2026-10-25 20:48:03 +00:00
Miguel Ángel 70187a13b5 perf(core): the preview mounts and draws only the scenes near the playhead (#6189)
* perf(core): skip rendering preview scenes far from the playhead

* refactor(core): split the far-scene pass into small helpers

* perf(core): a first render reveals only the clips it reaches

* fix(core): reveal the clips holding first-rendered tweens, wherever their window is

* feat(core): a scene may load a project helper and wait for fonts and still swap

* perf(core): the preview mounts only the scenes near the playhead

* perf(core): a seek waits only for the scene it lands in; neighbours mount one per turn

* feat(studio): selecting a clip in an unmounted scene mounts that scene first

* fix(core): a source a play and a seek both need is fetched and decoded once

* fix(core): a scene mounting during play joins the mix without restarting what plays

* fix(studio): selecting a clip waits on a scene mount only in a preview that unmounts scenes

* fix(core): far scenes still mount after an edit, and an edit to a parked scene keeps its styles

* perf(core): web audio schedules a clip only as the playhead comes near it

* chore(studio): trim the scene hold helper's comments to its package's share

* fix(core): a scene the preview unmounts is freed, not kept by audio, caches or old roots

* fix(studio): an unmounted scene's rows and their state come from the markup it mounts with

* perf(core): the preview mounts scenes ahead of play and keeps recent ones mounted

* refactor(core): keep the far-scene neighbour rule private to its module

* style(core): format the far-scene neighbour rule

* perf(core): the preview unmounts scenes the playhead leaves, as kept ones slowed each mount

* fix(core): scenes that measure text, call their own animate or wait on font loads can unmount

* fix(core): each preview scene carries the helpers it loads, so it mounts on its own

* fix(core): a mounted scene shows though its stand-in was hidden by display

* fix(core): a helper scenes share runs once for the film, and a remounted scene keeps showing

* fix(core): a scene that also publishes its timeline under another id stays mounted

* feat(core): scenes that draw in 2D or chain the timeline they register can unmount

* perf(core): a play frame that draws nothing new skips the hidden-clip lookup

* fix(core): a GSAP file copied into a project counts as the library for scene unmounting

* style(core): drop an unneeded escape in the registered-chain pattern

* chore: core and producer size budgets make room for the preview scene window

* fix(core): a scene that draws on a 2D canvas stays mounted

* fix(core): a scene the preview unmounts lets go of timelines it built after a font wait

* perf(core): a scene leaving the playhead keeps its last rendered size, no forced layout at the cut

* refactor(core): the far-scene skip keeps last-render boxes in their own helper

* fix(core): a mounting scene never records the runtime's root timeline as its own

* chore(producer): raise the size budget to the measured size with the preview runtime inlined

* docs(core): keep the far-scene and scene-memory comments within the comment limits

* perf(core): style each hidden clip visible once ahead of its cut, so the cut frame does not

* fix(core): a seek into a scene still mounting as a neighbour waits for that mount

* chore(core): keep comment share and size budgets to main plus the measured core growth
2026-10-25 19:39:14 +00:00
Miguel Ángel 42b84632a8 chore: release v0.8.199 (#6328) 2026-10-25 18:13:20 +00:00
Miguel Ángel 80ba3f59ec fix(core): the decoded-audio cache keys a clip the same way everywhere (#6306)
* fix(core): the preview keeps a voiceover's decoded audio across an in-place reload

The decode cache and the release pass keyed the same asset two ways, so a clip the release pass was handed as live could lose its buffer and be re-fetched mid-playback.

* refactor(core): resolve the decode key through the runtime's own assetUrl

Smaller than the inline URL resolution it replaces, which tipped the producer package-size budget, and one owner for "resolve against the document".

* refactor(core): drop the decode-key comment the comment ratchet rejects

* fix(core): an unreadable clip src no longer stops the preview from playing

Resolving the decode key threw on a src that is not a URL, out of the release pass and through play(), so one bad clip silenced the whole preview instead of just failing its own fetch.
2026-10-25 14:52:35 +00:00
Miguel Ángel ada9932d4e fix(cli): a long video copy reports progress, resumes in 15 s pieces and stops only when stalled (#6307)
* fix(cli): a long video copy reports progress, resumes in 15 s pieces and stops only when stalled

* perf(core): a video copy's size box follows the stage within a fifth, not a half

* docs(cli): shorten two comments to the line limit

* fix(cli): the copy heartbeat drops a finished copy; size budgets follow the stall and progress code

* chore: size budgets rise by this change's measured bytes
2026-10-25 13:53:03 +00:00
Miguel Ángel 89af290808 perf(core): mounting a scene no longer restyles it to look for raster hints (#6300)
* perf(core): mounting a scene no longer restyles it to look for raster hints

* perf(core): raster hints read inline hints directly instead of matching every style

* perf(core): raster hints read the stylesheets once per page check, not per batch

* perf(core): raster hints watch no attributes while nothing is marked or hinted

* fix(core): a copied or re-attached marked layer keeps being followed

* chore(producer): raise the packed size budget by the 336 bytes the raster-hint fix adds

The producer bundles the runtime. On main (aae32e43ed) it packs at 773560 bytes
(2821768 unpacked) and this branch at 773896 (2822665): packed rises by 336, unpacked by 897.
2026-10-25 12:52:45 +00:00
Miguel Ángel d7f323d319 chore: release v0.8.198 (#6305) 2026-10-25 12:42:50 +00:00
Miguel Ángel 36b2c3c2b9 fix(core): hide static data-hidden elements in render as preview does (#6296)
* fix(core): hide a static data-hidden element in render as preview does

* fix(core): name the static-hidden skip instead of commenting it
2026-10-25 10:33:10 +00:00
Miguel Ángel f51650d8a7 chore: release v0.8.197 (#6298) 2026-10-25 09:17:12 +00:00
Miguel Ángel 751ca755f2 perf(core): text edits stop rebuilding the preview's caches every frame (#6276)
* perf(core): text edits no longer rebuild the preview's timing caches

* perf(core): color grading stops rescanning the page on text edits
2026-10-25 07:13:01 +00:00
Miguel Ángel 45167743a6 chore: release v0.8.196 (#6288) 2026-10-25 06:52:05 +00:00
Miguel Ángel 38afc0b013 fix(deps): update esbuild for the security advisory (#6277) 2026-10-25 04:52:58 +00:00
Akshar Patel 32d2d3cba0 fix(core): keep cache-busted images visible in bundles (#6264) 2026-10-25 04:15:02 +00:00
Miguel Ángel 1776b42736 chore: release v0.8.195 (#6273) 2026-10-25 03:18:09 +00:00
Miguel Ángel 3eb1aeb0de perf(core): Safari stops re-serializing inline styles on every GSAP write (#5974)
* perf(core): Safari stops re-serializing inline styles on every GSAP write in a playing film

* perf(core): declare the clip-reveal subpath in its descriptor and cut added comment lines

* fix(shader-transitions): shader transitions across a scene boundary keep the scene's contents

Every revealer now goes through one core helper that shows the clip and
lifts the runtime's hidden mark together; the page-side compositor's scene
copies were still carrying the mark. The contents rule keeps its old weight.

* fix(core): films on an older shader-transitions build keep their transition scenes

Published shader builds reveal scenes by inline style without lifting the
hidden mark. When one is on the page, the runtime keeps the inline-style
rules; builds that lift the mark declare it on load and keep the fast rules.

* test(core): pin the hidden-clip contents rule's weight on its selector

* style(core): format the reveal test and move hidden-clip rule notes into names

* test(producer): pin hidden-clip behaviours in real Chrome under the mark-keyed rules

* test(producer): read the forced restyle's result so lint accepts the restyle test
2026-10-25 03:17:39 +00:00
James RussoandClaude Opus 5.5 7f19f2335a feat(studio): load GSAP from the CLI's bundled copy by default (#6256)
* feat(studio): load GSAP from the CLI's bundled copy by default

Studio preview now loads the GSAP, CustomEase and MotionPathPlugin scripts
it adds from files the CLI ships and serves same-origin at /api/vendor/npm,
instead of jsDelivr. HYPERFRAMES_GSAP_BASE_URL still wins when set, and a
composition on another GSAP version gets its plugin from jsDelivr.

Renders now honor HYPERFRAMES_GSAP_BASE_URL when they replace a missing
local GSAP script, and the setting accepts plain http only for loopback
hosts.

Closes #6205

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(studio): keep comment share flat for the GSAP local root

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cli): find the installed gsap with node resolution when run from source

The Windows CI lane installs with the hoisted linker, so gsap is not under
packages/core/node_modules there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(producer): load a nested composition's missing GSAP from the mirror

A sub-composition's missing local gsap/dist script was hoisted into the
render unchanged, so HYPERFRAMES_GSAP_BASE_URL (and the jsDelivr fallback)
only reached the entry document. Run the same rewrite on every
sub-composition before it is compiled, resolving its path the way the
inliner will hoist it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 03:08:42 +00:00
Akshar Patel d44f67ac1d fix(core): preserve repeated stylesheet imports (#6250)
* fix(core): preserve repeated stylesheet imports

* docs(core): note repeated import bundle growth
2026-10-25 01:53:03 +00:00
Miguel Ángel 2e397dba59 chore: release v0.8.194 (#6269) 2026-10-24 22:17:19 -04:00
Akshar Patel 6e77d783c7 fix(core): scene shots keep their shell after leading comments (#6239) 2026-10-25 00:29:36 +00:00
Abdullah M. Nazif abcbde0b97 fix(core): prepare split-video offsets during preview preload (#5356)
* fix(core): prepare split-video offsets during preview preload

* chore: prepare conflict resolution against current main

* fix(core): retain scene-local deferral with split-video preparation

* chore: prepare conflict resolution against current main

* fix(core): preserve split preparation with queued media prefetch
2026-10-25 00:24:17 +00:00
Jay Hemnani c2a6b15f6f fix(core): resolve a relative data-start inside the clip's own composition (#5336)
* fix(core): resolve a relative data-start inside the clip's own composition

* fix(engine): render-side data-start references resolve in the clip's own composition

The engine's reference resolver still looked an id up document-wide, so
with two different compositions sharing an id the producer placed media
from the first one while the runtime used the clip's own. Scope it the
same way as the runtime's startResolver, with the same document-wide
fallback, and correct the SDK comments that called the runtime lookup global.

* fix(parsers): keep getAttribute-only reference adapters working

The scoped lookup needs parentElement, closest and querySelectorAll, but
RefResolverEl is exported from @hyperframes/parsers and @hyperframes/engine.
Make them optional and fall back to the document-wide lookup when an adapter
lacks them.

* refactor: look up a scoped reference with one id query
2026-10-25 00:23:39 +00:00
James RussoandClaude Opus 5.5 f180ffca64 fix(cli): reap only orphaned browsers HyperFrames launched (#6251)
* fix(cli): reap only orphaned browsers HyperFrames launched

Orphan cleanup on preview and render killed every PPID-1 process of the
current user whose args named chrome-headless-shell or a Puppeteer temp
profile, which included detached browsers started by other tools.

Every HyperFrames Chrome launch now passes an inert
--hyperframes-owned-browser switch, and the reaper only kills PPID-1
processes that carry it as a whole argument.

Fixes #6203

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(core): serve the browser marker from its own subpath

The GCP image's BeginFrame contract step imports the engine's
browserManager straight from source before core's generated runtime
exists, so pulling the marker from the core root entry broke it.
A dependency-free @hyperframes/core/browser-marker subpath keeps that
import chain as light as it was.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(cli): expect the browser marker in the capture fallback launches

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* docs(cli): say orphan cleanup runs before preview and render

The cleanup only stops browsers HyperFrames launched, so the opt-out is
no longer needed to protect other tools' browsers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 23:09:57 +00:00
Miguel Ángel b97de59c84 fix(core): motion blur no longer blacks out videos inside sub-compositions (#6252)
* fix(core): motion blur no longer blacks out videos inside sub-compositions

* chore(core): drop the explanatory comment from the motion blur isolate move
2026-10-24 22:35:57 +00:00
Vance IngallsandClaude Sonnet 5.5 e586922cd1 fix(core): a video that starts a cut far behind the playhead catches up in steps, not at a flat 3% (#6198)
A playing video is steered back by rate, not seeked, at a flat 3%. A talking-head clip
that waits on data at a cut starts 100-350 ms behind and takes 3-10 s to close, longer
than a short clip plays, so the picture trails the voice for the whole clip.

Measured in Desktop on a Riverside two-camera episode: clips 2-4 started up to 100 ms
behind and closed at 35 ms per second. The steer now steps with the lag (3% up to
100 ms, 10% to 300 ms, 25% beyond), so the rate is still written only when a step
changes.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 22:27:36 +00:00
Abdullah M. Nazif 1c14fbb542 fix(studio): allow a local GSAP dependency mirror (#6247) 2026-10-24 22:13:28 +00:00
serdarucelandserdarucel e26d330887 fix(core): name the selector when a scoped GSAP target matches nothing (#5839)
A sub-composition resolves GSAP selectors to a list of in-scope elements.
When that list is empty, GSAP's "target not found" warning stringified it
as an empty name, so check reported `GSAP target  not found` with no hint
of which selector missed. Keep the empty list but give it the authored
selector as its text, matching what GSAP prints in a root composition.

Refs #5687

Co-authored-by: serdarucel <196021214+serdarucel@users.noreply.github.com>
2026-10-24 21:11:36 +00:00
Miguel Ángel 89081b9197 chore: release v0.8.193 (#6229) 2026-10-24 12:39:08 -04:00
Miguel Ángel 700187b855 fix(core): color grading builds a new WebGL context when a lost one is never restored (#6211)
* fix(core): color grading builds a new WebGL context when a lost one is never restored

A context the browser evicts and does not restore left every graded clip hidden for good.
After a grace period the runtime now creates a new shared context and moves each clip onto it.

* refactor(core): split the lost-context rebuild into smaller steps and test its retry
2026-10-24 10:34:16 +00:00
Miguel Ángel c16b783f5e chore: release v0.8.192 (#6206) 2026-10-24 08:51:29 +00:00
Akshar Patel 73dda7191c fix(core): preserve images with commas in srcset URLs (#6192) 2026-10-24 08:16:02 +00:00
Abdullah M. Nazif 94a265e486 fix(core): sample hue curves across their periodic seam (#5287) 2026-10-24 07:31:49 +00:00
Miguel Ángel b47d745c05 fix(core): color grading rebuilds the graded clips when a lost WebGL context is restored (#6177)
* fix(core): color grading rebuilds the graded clips when a lost WebGL context is restored

A clip shown while the context was lost never got an entry.

* fix(core): drop the added comment line from the color grading restore fix
2026-10-24 07:21:33 +00:00
Xinyu YANG 879d735ee0 fix(core): keep bundled HTML under V8's max string length (#6134) 2026-10-24 07:19:00 +00:00
Miguel Ángel 09d7f1c646 fix(core): release decoded preview audio once no clip uses its source (#6178)
* fix(core): release decoded preview audio once no clip uses its source

The preview transport cached every decoded audio buffer by source until the player was destroyed. Each scheduling pass now drops cached buffers whose source no clip in the document still uses (scene edits, swapped sources), and keeps the rest so playback never re-decodes a clip still in the film.

* fix(core): drop the comment the comment-share ratchet rejects
2026-10-24 04:29:31 +00:00
Abdullah M. Nazif 14c9eb4487 test(core): isolate local font fallback from system discovery (#5360) 2026-10-24 04:11:27 +00:00
Abdullah M. Nazif ecf5db7070 fix(core): preserve blocked addresses in mounted import maps (#5277) 2026-10-24 04:11:18 +00:00
Abdullah M. Nazif 234b87a4bb fix(core): preserve literal percent in beat source paths (#5327)
* fix(core): preserve literal percent in beat source paths

* chore: prepare conflict resolution against current main

* fix(core): retain beat path handling with current main
2026-10-24 04:10:43 +00:00
Miguel Ángel cf7266d815 chore: release v0.8.191 (#6170) 2026-10-24 01:40:50 +00:00
Vance IngallsandClaude Sonnet 5.5 1c463a2fec fix(core): refuse nested vfx capture canvases and scope host lookups (#4804)
A `<canvas layoutsubtree class="hf-vfx-src">` nested inside another capture
canvas blocks the renderer main thread in drawElementImage, so `check` and
`snapshot` time out with no output. Refuse either direction of the nest with a
reportVfxError and leave the chain unregistered.

Also scope the two host lookups to immediate children (`:scope >`) so a nested
host's src/out canvas is never bound to the outer host, and read the
`data-vfx-ref-visible` flag in resolveCaptureSource so a canvas reached as both
a host's own source and as a ref gets one consistent `visible`/keepBitmap.

Refs #4405

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 01:30:58 +00:00
Miguel Ángel 179098936f fix(core): preview fetches only the clips due next, and drops passed clips still downloading (#6160)
* fix(core): preview fetches only the clips due next, and drops passed clips still downloading

A fast-cut film started a fetch per clip inside the look-ahead and let passed clips finish.

* fix(core): a passed clip stays released for the rest of the play

It was refetched each pass inside the look-back window.
2026-10-24 00:15:24 +00:00
Vance IngallsandClaude Sonnet 5.5 e077d9dc74 fix(core): a hidden child of a mover stays out of the blur trail (#6155)
The isolation CSS re-showed every descendant of a mover, so a child the
author hid with visibility:hidden was cropped and smeared into the trail
(240 green px in the repro; 0 in the sharp frame). The hide rule now skips
the mover subtree and the mover alone is made visible, so its descendants
inherit and keep their own visibility.

Found by review of #6106.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 17:37:41 -07:00
Vance IngallsandClaude Sonnet 5.5 ffc327b44c feat(studio): motion blur panel with Off / Subtle / Strong (#6112)
* feat(studio): motion blur panel with Off / Subtle / Strong

One three-way control in the right dock. Subtle is the default blur
(240 deg shutter, samples sized to the smear); Strong is 720 deg and 64
samples. Writes the root data-motion-blur attributes through the SDK so
renders match and undo works; reads live attributes from the preview.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(studio): motion blur panel edits the file's own root

The edits were worked out against the preview DOM but written to the file,
so a stale preview (undo inside the hold, a slow reload) could save a level
other than the one picked. They are now computed inside the mutation from
the candidate's root. While locked to a sub-composition no level is shown.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(studio): shorten the motion blur tab so the dock strip fits

Five tabs overflowed the default dock width by 10px and clipped a label
(Studio: load smoke). The tab is now titled Blur.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 17:29:42 -07:00