* fix(skills): paid-plan cloud final keeps the composition fps and high quality
Follow-up to #6884 from its review: the cloud command agents copy had
no --fps, so a 24 or 60 fps composition rendered at 30, and cloud's
default `standard` is below the local `delivery` final. Step 5 and
cloud.md now spell out `cloud render --fps <data-fps> --quality high
-o <path>`; the render table uses `-o` to stay within the entry's byte
budget and restores the "Hosted, no local Chrome or FFmpeg" row.
— wanbi
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(skills): pin --fps and --quality high on the paid-plan cloud final
Review on #6886: a later byte-budget trim of hyperframes-cli/SKILL.md or
cloud.md could drop the flags silently. The test asserts both files'
paid-plan command reads `cloud render --fps <data-fps> --quality high -o …`.
— wanbi
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
When `auth status` shows a paid HyperFrames plan, the render the person
receives goes through `hyperframes cloud render -o <path>`; authoring
checks stay local, Free keeps local renders unless the person asks, and
a refused or failed cloud render falls back to a local one with the
reason. reverse-any-video, which already requires a paid plan, now
renders and diffs the cloud output; the detach guidance stays for the
local fallback.
— wanbi
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): stopping remove-background on a Mac no longer aborts the process
* fix(cli): a quit after background removal released its session exits at once
* Revert "fix(cli): a quit after background removal released its session exits at once"
This reverts commit 3b9d6ffc24.
* 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(producer): auto renders with color-graded media stay SDR instead of promoting to HDR
* fix(producer): keep auto renders SDR when a graded canvas is present
* 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(cli,skills): say a step's credits are its total, and keep cost out of retries
An out-of-credits refusal named what the step needs, and an agent read
that as the shortfall. It now says the number is the step's total.
After its last try, an agent told the person what was spent and what
another try would cost. The HeyGen reference now says not to.
* fix(cli): plan avatar credits from the HyperFrames price rows
An avatar's credits came from its old API price, about five times what
the plan charges, so --max-credits refused calls that fit and a top-up
asked for too much. They now use the Avatar IV photo row plus the
general avatar video row, 950 credits a minute.
* fix(cli): pin the avatar price test and keep pricing under the comment share
* fix(cli): plan avatar seconds on the Avatar IV row alone
The general avatar row is only checked at admission and billed on
seconds left after Avatar IV, so adding it to every second made a 15 s
script plan at 238 instead of 200 and a 220 limit refuse a call that fits.
* fix(cli): the credits link opens the web plan page, which is live
* test(cli): pin the production credits link too
* chore(skills): regenerate the skills manifest after merging main
* docs(cli): keep the person measure's doc comments to four lines
* docs(cli): keep the measure doc comments to four lines
* docs(cli): keep the measure comment lines to 120 characters
---------
Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com>
* fix(lint): the podcast-lanes.html page Desktop writes is not a second root composition
HyperFrames Desktop's podcast edit writes its camera lanes page, podcast-lanes.html,
at the project root beside index.html: Studio reads no composition inside a dot
folder, and Desktop opens the page directly as its own view. index.html never mounts
it and no render plays it, but multiple_root_compositions fails lint and check on
every podcast project, and its fix hint tells an agent to remove the file. Exempt it
the way caption-skin.html already is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(lint): name the pages opened beside index.html instead of commenting them
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
Make a video, Studio app and Developers move into a Docs menu (each keeps its
own sidebar), with Free lessons, Community and the app changelog under them;
Catalog stays a tab. The top-bar copy of Ask Assistant goes (Ask stays in
search and the page's bottom bar); the logo opens the homepage; the button
reads Download.
* 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
* perf(studio): a long timeline no longer lays itself out on every render while it settles
* perf(studio): compare row data with sameData and drop the added comments
* fix(lint): a timeline registered in a local script file counts as registered
* fix(lint): a module script file is read as a module
* style(lint): format the module script check
* fix(cli): exit-time telemetry no longer loses a render's events on Windows
* fix(cli): telemetry smoke stand-in reads the batch file; format the warning
* fix(cli): read BOM-prefixed JSON files for timeline plans, grades and motion specs
* fix(cli): read BOM-prefixed files for render --batch, lambda policy and transcripts
* test(cli): drop the batch BOM test #6605 already covers
* fix(cli): decodeJsonText is only used inside jsonFlag.ts
* fix(cli): drop a fallow suppression the export no longer needs
* fix(cli): capture's public-address check uses the engine's list; 192.0/16 is not all reserved
Only 192.0.0.0/24 and 192.0.2.0/24 are special-use. The capture proxy blocked all of
192.0.0.0/16, so sites on WordPress VIP (192.0.64.0/18, e.g. nasa.gov at 192.0.66.108)
failed every capture with net::ERR_TUNNEL_CONNECTION_FAILED. isPublicIPv4 now reads the
engine's isBlockedNetworkHost, so capture and asset downloads share one list.
— Jerrai (cutroom-debug)
* refactor(engine): one special-use network list, in a light subpath capture imports
Importing all of @hyperframes/engine into capture's publicNetwork slowed the lookup child's
start-up past publicNetwork.process.test's 6 s mid-lookup exit. The list and
isBlockedNetworkHost move to engine/src/utils/networkPolicy.ts, exported as
@hyperframes/engine/network-policy; urlDownloader and the engine index read it there.
— Jerrai (cutroom-debug)
* test(engine): pin 192.0.0.0/24 and 192.0.2.0/24 blocked, the rest of 192.0/16 public
— Jerrai (cutroom-debug)
* fix(cli): alias the engine's network-policy subpath in the CLI bundle
esbuild's root alias rewrote @hyperframes/engine/network-policy to src/index.ts/network-policy;
the exact-subpath list now carries it. The publicNetwork docstring is cut to keep the file's
comment share under its base.
— Jerrai (cutroom-debug)
* docs(catalog): put each item page's title, description and Docs text in the server HTML
Mintlify renders snippet components in the browser only, so everything inside
CatalogDetail (title, standfirst, the Docs tab) was missing from the HTML search
engines read: 448 catalog pages served Googlebot no body text. The generator now
writes the H1 and standfirst as page markup above the component and the Docs tab
as page markup after it, shown with that tab (docs/custom.css). The component no
longer draws its own title. Pages patched structurally only; registry drift on 14
pages is left for a regeneration of its own.
* docs(catalog): keep the title's top spacing the component gave it
* fix(docs): catalog titles and descriptions keep markdown markers literal
MDX reads text inside the static <h1> and <p> as inline markdown, so @_blue_sweater_
rendered as italic blue_sweater. mdxText now writes backslash, backtick, * _ [ ] ~ as
character references too, with a unit test; the four affected pages are re-escaped.
* feat(lint): warn when a url() in a linked stylesheet does not resolve beside it
* fix(lint): a percent-encoded url() in a linked stylesheet resolves like the browser does