Commit Graph
1042 Commits
Author SHA1 Message Date
Miguel Ángel c0636d017f feat(cli): snapshot --keep redoes one still and leaves the others (#5605)
* feat(cli): snapshot --keep redoes one board still and leaves the others

* fix(skills): the board recipe waits for a released snapshot --keep

* fix(cli): snapshot --keep refuses two times with one name and replaces linked stills
2026-10-14 19:25:31 +00:00
Miguel Ángel fa99eec9d0 chore: release v0.8.158 (#5617) 2026-10-14 19:19:18 +00:00
Miguel Ángel d65eefad5e feat(cli): init --keep-original copies a clip as is, without transcoding (#5612)
* feat(cli): init --keep-original copies a clip as is, without transcoding

`hyperframes init --keep-original` copies the --video file under its own
name and wires it into the project the way a web-safe clip is wired today:
no transcode and no prompt, interactive or not. Default behaviour is unchanged.

Theora leaves init's web-safe codecs and joins the preview proxy's
browser-hostile codecs, so init converts it and the preview proxy serves an
H.264 copy instead of a blank picture.

* fix(studio-server): keep the codec table's comment share at its base level
2026-10-14 18:19:17 +00:00
Miguel Ángel 6f90ca15a7 chore(skills): storyboards are a board of stills with one page format (#5599)
* chore(skills): storyboards are a board of stills with one page format

* chore(skills): count audio_meta.json as a project file in comment citations

* chore(skills): point every board mention at the storyboard recipe

* chore(skills): board redos replace only their own stills, from the mounted composition

* chore(skills): board stills come from the host's snapshot tool when one is offered
2026-10-14 13:56:58 +00:00
Miguel Ángel b72c3fb25d chore: release v0.8.157 (#5596) 2026-10-14 09:19:15 +00:00
Miguel Ángel 38cfcdd56c fix(engine): renders under WSL reach the GPU on Chrome 150 and later (#5591)
* fix(engine): renders under WSL reach the GPU on Chrome 150 and later

Part of #5548.

* fix(engine): shorten the WSL browser env comment

* fix(engine): cite the Chromium bug in one line and allow the fallback test's removal

* fix(engine): drop WAYLAND_DISPLAY under WSL only when that is what reaches the GPU

* fix(engine): restore the WSL note from before the full-Chrome fallback

* test(engine): give the second worker's page load room on a busy Windows runner

* fix(engine): keep the Chromium bug comment under the line limit
2026-10-14 06:22:39 +00:00
James RussoandClaude Opus 5.5 74e17fa9cf chore: release v0.8.156 (#5577)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 04:11:14 +00:00
Miguel Ángel 9b996059af fix(engine): renders under WSL use the GPU through full Chrome when the headless shell cannot (#5574)
* fix(engine): renders under WSL use the GPU through full Chrome when the headless shell cannot

Part of #5548.

* fix(engine): a missing or unreadable full Chrome cache never stops a WSL render
2026-10-14 02:49:08 +00:00
James Russo 5a6c0575f8 chore: release v0.8.155 (#5567) 2026-10-13 23:07:51 +00:00
Miguel Ángel 96e2154d7c fix(engine): say why WSL renders fall back to software and how to get the GPU (#5560)
* fix(engine): say why WSL renders fall back to software and how to get the GPU

Under WSL the GPU check often falls back to SwiftShader and the only output
was the probe line, with Docker passthrough advice for --browser-gpu. Print
one note that says what was checked (can this user open the render node),
the exact fix, and the native Windows alternative. The CLI's WSL detector
moves to the engine so both use one.

Part of #5548

* fix(engine): keep WSL GPU notes true to the probe result and render mode

The WSL note now prints only when auto mode really selects software, and
says whether the GPU check found no GPU or could not finish. Explicit
--browser-gpu keeps its unverified and Chrome-install advice and adds the
WSL checks. The render-node check verifies group membership before
suggesting usermod.
2026-10-13 22:18:59 +00:00
Xuanru Li 8147f7b940 chore: release v0.8.154 (#5545)
* chore: release v0.8.154

* ci: give the studio test job fifteen minutes

The queue run installs and builds inside the same ten minute cap.
It was still inside the studio tests when that cap cancelled the job.
2026-10-13 19:23:45 +00:00
Miguel Ángel 05786f5558 chore: release v0.8.153 (#5541) 2026-10-13 15:19:09 +00:00
Xuanru Li e8eb358fe2 chore: release v0.8.152 (#5534)
* chore: release v0.8.152

* docs(changelog): correct the v0.8.152 release notes

The summary overstated snapshot retention, history turns, and video state.
It also left out the new artifact paths and nullable keyframe times.
2026-10-13 07:37:26 +00:00
Xuanru Li 23d1fe5b42 feat(cli): save check, snapshot and render artifacts per revision (#5522)
* feat(cli): save check, snapshot and render artifacts per revision

* fix(cli): keep clean --snapshots inside the project

A symlinked .hyperframes or artifacts folder was followed, so the command
deleted snapshot and check files outside the project.

* test(cli): keep check, snapshot, and render successful when recording fails

A held history or a corrupt output registry warns and leaves the command result alone.

* fix(cli): drop snapshot records when a replaced run is not recorded

A reused --output rewrites the files even when history is busy.
Those records are removed so the old revision does not keep the new pixels.
The preview checkpoint stops waiting after five seconds.
A bad PNG header no longer fails the snapshot.

* fix(studio-server): keep the video-state comment share from rising

The forget helper's doc comment pushed the file above its base share.

* fix(cli): post the preview checkpoint and keep cleanup inside artifacts

A preview checkpoint with no body was sent as GET, so Studio never ran it.
Cleanup now requires the real path to stay under the artifacts folder.
A failed follow-up drop does not warn twice.
The studio-server unpacked budget covers the record-dropping helper.

* docs(cli): shorten the snapshot skill notes

The command examples already show range and composition.
The prose only keeps the output path and the flags that are easy to misuse.

* chore: leave package headroom for artifact cleanup

* test(cli): compare artifact paths portably

* style(cli): format portable artifact assertion
2026-10-13 06:20:31 +00:00
Miguel Ángel fb4189ca72 fix(catalog): match preview length to authored compositions (#5533)
* fix(catalog): match preview length to authored compositions

* fix(catalog): derive undeclared preview duration from motion
2026-10-13 05:51:02 +00:00
Xuanru Li 7c73b3caee feat(cli): guard history turns with --exclusive, --who and --if-open (#5518)
* feat(cli): guard history turns with --exclusive, --who and --if-open

* fix(cli): make exclusive history turns atomic

Re-read the open turn only after acquiring history ownership so
concurrent exclusive begins cannot both claim the same project.
Cover the race with a deterministic two-process regression test.

* fix(cli): refuse a second exclusive turn while a preview is open

The preview's begin window now rejects another agent's live turn, and an
idle turn no longer blocks exclusive begin. The two-process test waits on
pids collected from claim drafts instead of seeing both files at once.
2026-10-13 04:22:41 +00:00
Miguel Ángel 945c61ebb6 chore: release v0.8.151 (#5529) 2026-10-13 04:13:03 +00:00
Xuanru Li 1b60a40eff feat(cli): HF_TOOL_CONTEXT artifact events and project lock for agent harnesses (#5520)
* feat(cli): HF_TOOL_CONTEXT artifact events and project lock for agent harnesses

* fix(cli): serialize stale project lock takeover

Use a short-lived break lock so only one waiter can remove a dead
holder's lock. Cover the contention path with six real processes.

* fix(cli): hold snapshot lock through finalization

Keep the project lock while contact sheets, artifact events, and frame
descriptions read captured files so another snapshot cannot replace them.

* fix(cli): recover a project lock after the breaker crashes

A killed takeover left project.lock.break in place, so later commands
waited out the timeout even though both holders were dead. Reclaim that
file only when its recorded process is dead, and compare artifact paths
after the platform resolves them.

* fix(cli): accept a killed breaker process with no signal name

Windows ends the process without reporting SIGKILL, so the regression
was failing before it checked that the leftover breaker can be reclaimed.

* fix(cli): leave a killed project-lock breaker in place

Reclaiming a dead breaker unlinks a name another process may just have
created, so two commands can hold the lock. The timeout names that file
and its pid and says to delete it to continue.
2026-10-13 03:55:36 +00:00
Xuanru Li 36526bf1a6 feat(cli): scope check to a time range or a set of components (#5516)
* feat(cli): scope check to a time range or a set of components

* fix(cli): keep ranged check gates truthful

Refuse ranged caption and frame gates when none of their seek times
falls inside the requested range. Make ranged motion reporting,
overlap timestamps, filtering tests, and scope documentation match.
2026-10-13 03:13:26 +00:00
Xuanru Li 1cd086f7e3 feat(cli): snapshot a time range or one composition (#5519) 2026-10-13 02:12:54 +00:00
c3816a121b docs(lint): add a reference page for every lint finding code (#5493)
* docs(lint): add a reference page for every lint finding code

docs/reference/lint-rules.mdx lists every code emitted by the linter
(132: the 121 rule codes in packages/lint/src/rules/*.ts plus the 11
project-level probes that run as part of a project lint) with its
severity, what it catches, and how to fix it, grouped by the rule file
the code comes from. Conditional severities (Studio-host structure
checks, GSAP seek-order hazards) say when they escalate.

Link it from docs/packages/lint.mdx and add it to the Composition
reference group in docs.json.

Issue: #5385

* docs(lint): document the color grading codes and correct four entries

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

---------

Co-authored-by: James <james.russo@heygen.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 00:17:35 +01:00
Meghna VasudevaandClaude Opus 5.5 2973b3c8e4 docs(cli): document open, catch-up, timeline and history (#5442)
Add the four commands that `hyperframes --help` lists but the CLI reference
page left out, with their options taken from each command's args and
examples checked against a sample project.

Closes #5386

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:57:32 +00:00
github-actions[bot] ab06445439 chore(catalog): publish generated catalog (#5500)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-12 14:35:56 -07:00
James RussoandClaude Opus 5.5 86ff462d21 docs(changelog): weekly digest 2026-10-05–2026-10-12 (#5497)
* docs(changelog): weekly digest 2026-10-05–2026-10-12

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

* docs(changelog): add the Oct 5-12 weekly video

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-12 20:52:13 +00:00
github-actions[bot] 4f941de0da chore(catalog): publish generated catalog (#5498)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-12 12:00:31 -07:00
James RussoandClaude Opus 5.5 0e535ac6ab docs(changelog): weekly digest 2026-09-28-2026-10-05 (#5076)
* docs(changelog): weekly digest 2026-09-28-2026-10-05

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

* docs(changelog): embed the Sep 28 - Oct 5 weekly video

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-12 16:52:15 +00:00
Miguel Ángel 8b27935e8c chore: release v0.8.150 (#5495) 2026-10-12 13:51:49 +00:00
Jerrai e1925d4317 feat(audio): composition master bus (data-fx-chain on the root) (#5420)
* feat(audio): composition master bus (data-fx-chain on the root)

A clip can belong to only one audio group, so there was no way to put one
effect, such as a limiter, across the whole mix. The data-fx-chain on the
top-level composition root now runs once over the sum of every clip and every
group, after each group's own chain and fader. No new attribute: a sub-composition
root's data-fx-chain was never applied to anything and still is not.

Render: when a master chain exists, mixAudioTracks writes a float WAV instead
of AAC, applyAudioFxChain runs the chain over it, and ffmpeg encodes AAC last,
so the chain reads unclipped samples. An unreadable chain is a mix failure, as
for a group. Preview: the transport splices the chain between the clips' sum and
the monitor, re-anchored per play generation and watched for edits.

Only the top-level root is read. No master automation: the root's data-automation
is not read as the bus's. No lint rule: data-fx-chain is valid on clips, groups
and roots, and the one place it does nothing (a sub-composition root) has always
been silent.

— Jerrai

* fix(core): preview routes every audible video through the master bus

A root data-fx-chain is attached only inside the Web Audio graph, but a plainly
audible <video> joined that graph only for its own chain, group, automation or a
volume over 1. So preview limited the music and left the talking head dry, and a
composition whose only audio is video got no master chain at all, while export
sums every audible element into the master. A master chain on the top-level
composition root is now a reason to join, the same as a video's own chain.
Elements under a root with no chain keep native output. Sub-composition roots
are still ignored.

— Jerrai

* fix(audio): master bus review round 2 (temp dir, tests, docs, Studio meter)

- audioMixer: a fatal FX error in the master pass or a group bus left the
  work directory (the full float sum, about 1.4 GB an hour) on disk. The
  final mix now runs in try/finally and the group rethrow removes it first.
- Tests: the "once over the sum" case now uses a limiter then a gain, so a
  per-clip chain (-10.4) and a doubled one (-18) both fail it; a new case
  proves the sum stays float until the chain reads it; the fader case uses
  a group volume of 0.5 so the fader's position is exercised; the work-dir
  removal is covered for both paths.
- Docs: "Three rules exist" (the master-bus lint rule is gone), a bad master
  chain stops the render with audio_processing_failed, a sub-composition
  file opened on its own has its root chain as the master bus, and a seek
  clears a group or master limiter.
- Studio: TimelineElement.masterChain carries the root's data-fx-chain, so
  the program meter shows for a video-only composition whose only audio
  routing is the master chain, as preview now plays it.
- Comment blocks over four lines cut; webAudioTransport.setRate split so
  its CRAP score is under the Fallow threshold.

— Jerrai

* fix(audio): master chain reaches tracks the render adds; honest plain-limiter copy

- Master chain: it was carried on each parsed AudioElement, so a track the
  producer adds itself (appendAutoDetectedVideoAudio, the browser-discovered
  audio in probeStage) never had it, and a composition whose only audio was
  such a track exported with no master chain, no ceiling and no warning. It is
  now a composition property: parseMasterFxChain(html) at compile, carried on
  CompiledComposition and CompositionMetadata, passed to processCompositionAudio
  by runAudioStage (in-process and distributed plan). AudioElement.masterFxChain
  is removed so there is one source. Each forward (compile stage, local
  orchestrator, distributed plan) has a test that fails when it is dropped.
- Plain limiter: it follows the level with no lookahead and Level after is
  applied past the ceiling, so it cannot promise "nothing gets past" or "never
  clips". Studio copy (description, panel text, knob label, summary) and the
  hyperframes-audio skill now say a fast or inter-sample peak can pass it and
  point to the true-peak limiter for a delivery limit. A copy test guards it.

— Jerrai

* fix(producer): keep master bus comments within the ratchet; run the plan test with the ffmpeg tests

Drop three one-line field comments that raised their files' comment share,
and list plan.masterBus.test.ts with the integration tests because plan()
reads the ffmpeg version.

— Jerrai

* chore(ci): repin the producer test-classification source in the reachability map

The reachability map pins the hash of test-classification.mjs, which now
lists one more integration test. The map's producer lane command already
covers every test under src, in both the unit and integration matrix lanes.

— Jerrai
2026-10-11 19:07:00 +00:00
James RussoandClaude Opus 5.5 bf881bf79d chore: release v0.8.149 (#5472)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 18:52:16 +00:00
Miguel Ángel 43be84d82c chore: release v0.8.148 (#5470) 2026-10-11 17:34:38 +00:00
Miguel Ángel d4dd6c097d chore: release v0.8.147 (#5456) 2026-10-11 08:55:42 +00:00
Miguel Ángel 8bca7c4417 chore: release v0.8.146 (#5448) 2026-10-11 04:25:16 +00:00
Miguel Ángel 44e5a47e09 fix(cli): media-treatment applies one treatment to every matched image or video (#5443)
* fix(cli): media-treatment applies one treatment to every matched image or video

* fix(cli): media-treatment reports its action from every target and documents the per-element merge

* fix(cli): media-treatment patches each match by its stable id so one write cannot redirect another

* fix(cli): media-treatment sets every match in one parse instead of re-finding elements

* fix(cli): media-treatment refuses media that is not an HTML element, as before

* chore(skills): refresh the media-use manifest hash for the treatment reference edit
2026-10-11 03:45:37 +00:00
github-actions[bot] faa4913c9e chore(catalog): publish generated catalog (#4340)
* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-10 19:13:01 +00:00
Miguel Ángel 9825614d91 fix(studio): Studio's own text reads without em or en dashes (#5414)
* fix(studio): text in Studio reads without em or en dashes

* fix(studio): the dash check also catches HTML entities, and peak reads Unavailable

* test(studio): the dash check test covers every entity form

* fix(studio): messages Studio shows from lint, sdk, core and the renderer drop dashes too

* fix(producer): the gate check stops early on the engine's new fallback wording
2026-10-10 19:08:30 +00:00
Jerrai 3746703ea7 feat(core): truepeak, a lookahead true-peak limiter FX (#5419)
* feat(core): add a lookahead true-peak limiter FX (truepeak)

The existing limiter is an envelope follower with no lookahead and no
inter-sample detection, so a -14 dB ceiling can leave the true peak several dB
over. truepeak estimates the true peak on a 4x polyphase interpolator, takes the
minimum required gain over a lookahead window and smooths it with a boxcar of
the same length, so the gain is already down when the peak leaves the delay
line. Release is exponential and can only lower the gain further; channels
share one gain.

The offline render lengthens the OfflineAudioContext by the chain's latency and
drops the lead-in, so a limited clip stays sample-aligned with its source.
Preview plays the lookahead (about 3.3 ms at the default).

— Jerrai

* docs(audio): truepeak ceiling is a 4x estimate; measure it with an ideal interpolator

The unit test's meter was a 96-tap Kaiser sinc, which rolls off near Nyquist and
reads full-band noise about 0.5 dB low, so the PR reported a 0.3 dB broadband
overshoot. Against an ideal 16x interpolation (zero-padded FFT, cross-checked with
a 16x soxr resample) hot full-band white noise ends 1.2 to 1.7 dB over the ceiling
(median 1.4 over 28 runs of 10 to 30 s). ffmpeg's ebur128 true peak is also a 4x
meter and reads the same files 0.1 dB over.

- The test meter is now the FFT interpolation. Tolerances are what it measures on
  each fixed signal: tones 0.01 dB (they land on the ceiling), the dense program
  0.5 dB (reads 0.445, the old 0.4 passed only because the meter read low), and a
  new full-band noise case at -1, -6 and -14 dBTP with 1.35 dB (reads 1.09 to 1.31).
- audio-effects.mdx and the hyperframes-audio skill say the ceiling is a 4x
  estimate, give the measured overshoot and recommend a 2 dB margin under a hard
  delivery limit.
- skills-manifest.json regenerated.

— Jerrai

* fix(core): truepeak UI copy no longer promises a hard ceiling

The registry description and the rack summary said the true peak is never above
the ceiling. The limiter holds a 4x estimate, and full-band noise can land up to
about 1.7 dB above it, as the docs now say. The summary reads "held near", the
description names the estimate and the overshoot, and the rack blurb says "holds
... to a ceiling". No skill file changed, so the skills manifest is unchanged.

— Jerrai

* fix(core): Studio truepeak copy states the 4x-estimate margin

The ceiling control was labelled "Never exceed" and the module said the mix
"must not clip", so a Studio user never saw that dense full-band content can end
up to about 1.7 dB above the ceiling. The label is now "Target ceiling" with a
hint that names the 4x estimate and the headroom to leave, the blurb says
"toward a target ceiling", the rack summary says peaks are pulled down toward the
value, and the registry hint no longer says "highest true peak allowed". The
audio skill's "hard dBTP ceiling" wording is gone and the skills manifest is
regenerated. A copy test keeps the promise out.

— Jerrai

* fix(core): truepeak clears on a seek, and the review nits (fallow, comments)

- Unexport TRUE_PEAK_OVERSAMPLE, TRUE_PEAK_DETECTOR_DELAY and
  truePeakLookaheadSamples: nothing imports them (Fallow audit).
- A persistent group bus keeps its chain across a seek, so the limiter's
  delay line and held gain carried over. The worklet takes __hfReset, the
  graph exposes FxChainHandle.reset(), and reanchor() calls it.
- The processor-loading harness is shared by the truepeak and worklet tests
  (it was a 12-line clone); the test FFT no longer repeats audioCarve's
  bit-reversal; two test bodies are under the CRAP threshold.
- Comment blocks cut to four lines or fewer (Comments check).
- Docs state the preview delay in ms.

— Jerrai
2026-10-10 18:28:21 +00:00
Miguel Ángel 76f8a567a5 chore: release v0.8.145 (#5412) 2026-10-10 08:04:19 +00:00
Miguel Ángel f8ee010c65 chore: release v0.8.144 (#5384) 2026-10-10 00:45:48 +00:00
Miguel Ángel b20f3f7ad9 fix(cli): check warns instead of failing on a still title card (#5369)
* fix(cli): check passes a still title card whose timeline follows the seek

* fix(cli): check warns on a still frame and fails only when an animation is stuck

* fix(cli): count a seek clock once per sample and point the error at the registered timeline

* fix(cli): judge a finished animation by its own completion state, not its end time

* test(cli): pin a Web Animation paused at its end as finished

* fix(cli): judge a reversed animation's end in its own direction, and read plain timelines

* test(cli): pin a plain timeline held at its end as finished

* test(cli): keep an unfinished plain timeline beside the finished one

* fix(cli): skip a timeline whose time cannot be read instead of calling it stuck

* fix(cli): skip an animation whose time is not a plain number, such as a scroll-driven one

* fix(cli): a partial timeline with plain values no longer stops the browser checks
2026-10-10 00:38:09 +00:00
Miguel Ángel 908f4395b4 feat(cli): let transcribe --to write srt or vtt straight from a media file (#5215)
* feat(cli): let transcribe --to write srt or vtt straight from a media file

* fix(cli): fail a missing transcribe --output folder before decoding

* fix(cli): reject a transcribe --output that names a folder

* test(cli): check CJK caption grouping on the parsed cues

* fix(cli): keep transcribe --output from overwriting the media or its transcript

- Refuse an --output that resolves to the input file or the transcript.json the run writes,
  before the engine starts.
- When the caption file cannot be written after transcribing, say the transcript was saved
  and name the caption path and reason, instead of reporting a failed transcription.
- Docs: a one-run export groups cues for languages without spaces; exporting the saved
  transcript later may split them differently.

* fix(cli): refuse caption paths that alias the media or transcript

- The overwrite check compares files, not path text: an existing target is matched by device
  and inode, a new one by its real folder and its name ignoring letter case. Links, folder
  aliases such as /var and /private/var, and other letter case are all refused.
- The check also covers the default caption path, so exporting transcript.srt to srt no
  longer rewrites its own input.
- A trailing -o with no path fails before transcribing.
- One constant names transcript.json for the engines, the import and the check.

* fix(cli): refuse caption links to the transcript before it exists

- A caption path that is a link is followed to where the write would land, so a link to the
  transcript.json the run is about to create is refused before transcribing.
- A test pins the folder letter-case check on a case-insensitive disk, and says which branch ran.

* fix(cli): check the caption file against the transcript right before writing it

- Right before the caption write, by when the transcript exists, a destination that is the
  same file as the input or transcript.json is refused. The OS resolves every link, relative
  link and alias, so the hand-written link following is gone.
- The run keeps the transcript and says the caption file could not be written and why.
  An export whose caption write fails now says so too, instead of crashing.
- The check before transcribing stays as an early refusal for the common cases.

* fix(cli): compare caption paths by name when the disk reports no inode

- Some network shares report inode 0 for every file; such a pair is compared by folder and
  name instead of being called the same file. The check before transcribing and the one at
  write time now share one comparison.
- The link-through-a-file tests accept ENOENT as well as ENOTDIR, the code Windows reports.

* fix(cli): resolve both caption paths fully when the disk reports inode 0

- When either file reports inode 0 and both exist, compare their fully resolved real paths,
  so a link to the media or the transcript is still refused. The folder and name compare
  stays for a path that does not exist yet.
- Tests zero the inode on every path, on the caption path only, or on the protected file only.

* test(cli): say plainly why the caption-write test accepts two error codes
2026-10-09 22:54:36 +00:00
Abdullah M. Nazif 9e69821b8b docs: clarify async font measurement and timeline registration (#5203)
* docs: clarify async font measurement and timeline registration

* chore: align skill manifest with main before regeneration

* chore: regenerate animation skill manifest
2026-10-09 17:56:30 +00:00
Abdullah M. Nazif a03d709a52 fix(sdk): correct animation calls in examples and docs (#5247)
* fix(sdk): correct animation calls in editor examples

* docs(sdk): align entrance snippets with tween properties
2026-10-09 09:15:02 +00:00
Miguel Ángel 0576b24c75 feat(cli): models list shows which speech models transcribe can use (#5323)
* feat(cli): models list shows which speech models transcribe can use

* refactor(cli): models list and transcribe share one Parakeet runner check

* fix(cli): models list skips whisper links transcribe would download again

* style(cli): keep models list comments under the package share
2026-10-09 07:21:54 +00:00
James RussoandClaude Opus 5.5 3aa68869f7 chore: release v0.8.143 (#5302)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 23:28:49 +00:00
James RussoandClaude Opus 5.5 04f2bcd67a perf(producer): extract distributed video frames in each chunk (#5290)
* perf(producer): extract distributed video frames in each chunk

Plan v2 no longer extracts long constant-frame-rate videos. It ships
each source once and every chunk extracts only the frames it shows, so
Plan time stops growing with video length (#5260).

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

* docs(aws-lambda): plan no longer bounds video length

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

* test(producer): pin deferred compiled sources to every chunk

Each chunk's page loads every <video> src during session init and a
missing file fails the chunk, so a deferred source under compiled/ must
keep reaching every chunk, as it does on main.

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-08 21:50:01 +00:00
Abdullah M. Nazif 8efd9ca523 fix(sdk): drain pending saves and adapter storage on flush (#5285) 2026-10-08 19:51:25 +00:00
Abdullah M. Nazif e529fbb015 docs: explain negative z-index stacking contexts (#5201) 2026-10-08 19:31:12 +00:00
James RussoandClaude Opus 5.5 de1ef5a05a fix(engine): extract long video ranges in segments and keep plan uploads flowing (#5280)
* fix(engine): extract long video ranges in segments and keep plan uploads flowing

A distributed render's plan step extracted a whole video in one ffmpeg process,
so a long clip hit ffmpegProcessTimeout (300 s) however much of Lambda's
15-minute limit was left, and every frame then uploaded in batches of 16 that
each waited for their slowest blob.

Ranges longer than two minutes now extract as two-minute segments that run side
by side, each numbered after the last. They sample the same absolute times as a
single pass, so the frames are byte-identical (checked on a 26-minute, 37,440
frame clip). Plan v2 publishing keeps 32 uploads in flight instead of batching.
On a 10 GB Lambda the 26-minute clip's plan step fell from 395 s to 200 s.

The Lambda docs now state the plan-step length bound.

Fixes #5260

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

* fix(engine): split extraction on an integer frame count

The split compared and subtracted float seconds, so 200.3 - 80.3 became
120.00000000000001 s: a second segment got `-t 1.42e-14`, which ffmpeg
rejects, failing an ordinary two-minute range. The frame count now comes from
extractionFrameCountForDuration, the rule a single pass follows, and every
segment takes an exact frame count.

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-08 19:07:46 +00:00
Miguel Ángel 0b21016905 chore: release v0.8.142 (#5257) 2026-10-08 16:34:18 +00:00
Miguel Ángel c7d41dee5a fix(cli): enforce capture screenshot limits and report interruptions (#5171)
* fix(cli): enforce capture screenshot limits and report interruptions

* refactor(cli): split screenshot step out of capture animation phase

Keeps the screenshot limit outside the mirrored core-extraction argument
list and moves scroll screenshots into their own step, so both stay under
the audit's duplication and complexity gates with no behaviour change.
2026-10-08 15:41:50 +00:00