Commit Graph
1523 Commits
Author SHA1 Message Date
Miguel Ángel a30a520970 chore: release v0.8.219 (#6775) 2026-10-30 02:07:39 +00:00
James Russo f7db6ba40c chore: release v0.8.218 (#6758) 2026-10-29 23:31:55 +00:00
Miguel Ángel 4e2a1c215a chore: release v0.8.217 (#6751) 2026-10-29 15:13:36 +00:00
Miguel Ángel e1a8c7f173 fix(engine): long films show progress during the effect check and never wait minutes on it (#6697)
* fix(engine): long films start capturing at once instead of after a full effect scan

* fix(engine): give the effect scan two minutes, under the app's stall limit

* fix(engine): show effect scan progress so a long scan reads as preparing, not stalled
2026-10-29 10:35:12 +00:00
Miguel Ángel 0da46832ef fix(cli): a failed render's code comes only from the producer's list of safe codes (#6737) 2026-10-29 10:31:22 +00:00
Miguel Ángel 6df754fbf3 chore: release v0.8.216 (#6735) 2026-10-29 10:01:01 +00:00
Miguel Ángel be05c86932 perf(engine): encode high quality with the x264 fast preset (#6640)
* perf(engine): encode high quality with the x264 fast preset

* test(engine): name the NVENC p5 case by its preset, not the high tier
2026-10-29 06:40:21 +00:00
Miguel Ángel 17f5d67643 chore: release v0.8.215 (#6719) 2026-10-29 06:19:54 +00:00
Miguel Ángel a5496b1887 fix(producer): a BeginFrame capture that draws no first frame in 20 s switches to screenshot (#6701)
* fix(producer): a BeginFrame capture that draws no first frame in 20 s switches to screenshot

* test(cli): cover the Chrome launch failure messages a failed render prints
2026-10-29 00:49:04 +00:00
Miguel Ángel 0620067eb0 fix(cli): snapshot reads https video in the Desktop app instead of failing at ffprobe (#6699)
* fix(cli): snapshot reads https video in the Desktop app instead of failing at ffprobe

* fix(cli): give a remote clip download the same 30 s a stalled host had before
2026-10-28 22:52:28 +00:00
Miguel Ángel 9830059bdb fix(engine): downloads refuse hosts that resolve to private addresses (#6571)
* fix(engine): downloads refuse hosts that resolve to private addresses

* fix(core): shorten the env proxy doc comment

* test(producer): remote-media tests stub the download fetch seam
2026-10-28 20:08:50 +00:00
Miguel Ángel 3ca1005a81 feat(producer): report which element set the film length (#6689)
* feat(producer): report which element set the film length

* fix(core): keep the duration guard and comment share in step with the length helper
2026-10-28 19:05:59 +00:00
Miguel Ángel 067cbf7acf fix(producer): a capture that landed every frame is not failed for the work after its last frame (#6674)
* fix(producer): a capture that landed every frame is not failed for the work after its last frame

* chore(producer): drop a comment the ratchet counts
2026-10-28 17:48:50 +00:00
Miguel Ángel c2cde2fb62 perf(producer): the audio true-peak check seeks to each segment instead of decoding up to it (#6672)
* perf(producer): the audio true-peak check seeks to each segment instead of decoding up to it

Each parallel segment scan decoded the AAC from the start and trimmed after, so the last one decoded the whole file. It now seeks to a whole second one second before its segment and trims relative to it: the same peak, measured in about half the time.

* test(producer): the true-peak check's ffmpeg tests run in the integration lane
2026-10-28 17:48:36 +00:00
Vance Ingalls 4719543e97 chore: release v0.8.214 (#6684) 2026-10-28 10:17:04 -07:00
Miguel Ángel c6af88d2e6 chore: release v0.8.213 (#6673) 2026-10-28 16:40:44 +00:00
Miguel Ángel 67c7ec27d9 fix(core): bundled fonts in a linked stylesheet or a font shorthand are seen by the bundler (#6665)
* fix(core): a font declared in a linked stylesheet no longer trips the bundler's font warning

* fix(core): drop the guard's explanatory comment

* fix(core): bundled fonts named only in a CSS font shorthand load

* fix(core): a font shorthand loads faces but never fails the cloud system-font check

* test(producer): regenerate static-volume-future-set for the font shorthand face

* test(producer): regenerate two more fixtures for the font shorthand face
2026-10-28 14:08:07 +00:00
Miguel Ángel 6486d58021 test(producer): stall test no longer waits a real second for the progress flush (#6658) 2026-10-28 13:30:36 +00:00
Miguel Ángel 437784038b fix(engine): late-starting MP4 and WebM videos render every frame the preview shows (#6664)
* fix(engine): late-starting MP4 and WebM videos render every frame the preview shows

The browser counts an MP4 or WebM from timestamp 0, but FFmpeg seeks from the file's
earliest stream start. A file whose first frame comes after 0 (a fragment cut from a
longer stream, an edit-list offset, a WebM with a start offset) was extracted early and
short, so renders tripped the video coverage gate. Every video seek now maps media time
to FFmpeg's timeline, and the video begins where the browser shows it.

* fix(engine): audio from late-starting MP4 and WebM plays when the preview plays it

The mixer seeked and trimmed audio by FFmpeg's clock, which starts at the file's earliest
stream. In an MP4 or WebM whose streams all start after 0, the browser plays that audio
later, so the render heard it early by the same amount. The mixer now maps media time onto
FFmpeg's clock with the same offset frame extraction uses.

* fix(engine): a late-starting file's picture shows on the clock its audio plays on

* test(producer): vfr-screen-recording baseline shows each frame at its timestamp
2026-10-28 13:09:53 +00:00
Miguel Ángel eba596d026 chore: release v0.8.212 (#6660) 2026-10-28 12:29:35 +00:00
Miguel Ángel 5ed694264e chore: release v0.8.211 (#6623) 2026-10-28 09:30:08 +00:00
Miguel Ángel 6553b1f6ba perf(producer): --gpu renders encode while frames are captured (#6631) 2026-10-28 09:24:27 +00:00
Miguel Ángel e6476c2cd5 perf(engine): Macs with a hardware GPU render with more capture workers (#6636)
* perf(engine): Macs with a hardware GPU render with more capture workers

* perf(engine): Apple-GPU worker sizing skips layered renders; fewer comment lines

* test(producer): format
2026-10-28 08:42:31 +00:00
Miguel Ángel 2ddf41eb7d perf(producer): download a remote video once per render (#6637) 2026-10-28 08:04:05 +00:00
Miguel Ángel 6cf4b56697 fix(engine): a render on Windows opens no console windows (#6613)
* ci(windows): probe that a render opens no visible window

* ci(windows): the probe names what opened each window

* ci(windows): the probe spawns each binary alone, with and without detached

* ci(windows): the probe logs the processes started during the render

* ci(windows): the probe also spawns Chrome one consoleless hop down

* ci(windows): the probe logs each child started without windowsHide

* ci(windows): the probe logs every child process with its windowsHide and detached

* fix(engine): Chrome keeps the CLI's console on Windows, so a render opens no window

* fix(cli): every child the CLI starts on Windows is hidden unless it opts out

* ci(windows): the probe bisects Chrome's flags and keeps each command's output

* ci(windows): the probe names the Chrome process behind each window

* ci(windows): the probe loads a page in Chrome directly and one hidden hop down

* ci(windows): the probe prints the Chrome main command line and renders with the reporter's flags

* ci(windows): the probe narrows the CLI's Chrome arguments to the ones that open a window

* ci(windows): the probe launches the CLI's Chrome arguments one hidden hop down

* ci(windows): the probe launches Chrome through the engine's browser pool

* ci(windows): the probe varies what the engine passes to Puppeteer

* fix(engine): renders on Windows launch Chrome with a Puppeteer that keeps it attached

* refactor(cli): hideChildConsoles copies its arguments and keeps one comment line
2026-10-28 07:48:40 +00:00
Miguel Ángel 1d97ed24c6 perf(producer): the audio mix runs while capture starts its browsers (#6632)
* perf(producer): the audio mix runs while capture starts its browsers

* test(producer): master-bus test stops the render at capture setup
2026-10-28 07:36:32 +00:00
Miguel Ángel 7d83a3d219 perf(producer): drawElement films keep their parallel workers instead of dropping to one (#6633)
* perf(producer): drawElement films keep their parallel workers instead of dropping to one

* perf(producer): shorter inversion floor comment

* test(producer): inversion suites opt into the single-worker inversion
2026-10-28 07:24:46 +00:00
Miguel Ángel 2b6d176452 perf(producer): worker sizing measures screenshot capture, one browser launch fewer (#6630) 2026-10-28 07:24:34 +00:00
Miguel Ángel bf7ebe961e fix(cli): local servers never bind a port Chromium refuses to load from (#6620) 2026-10-28 05:16:42 +00:00
kevin c8052fbdae fix(producer): isPathInside accepts children whose names start with two dots (#5834) 2026-10-28 01:31:40 +00:00
Miguel Ángel e5b4f2bf78 chore: release v0.8.210 (#6600) 2026-10-28 00:49:27 +00:00
Miguel Ángel 313792408d fix(producer): HDR sources are tone-mapped for formats that cannot carry HDR (#6597)
* fix(producer): HDR sources are tone-mapped for formats that cannot carry HDR

* refactor(producer): one owner for which output formats can carry HDR

* refactor(producer): drop comments the helper names already carry

* fix(engine): SDR clips are not lifted to HDR when the render tone-maps to SDR
2026-10-27 23:09:15 +00:00
Miguel Ángel 957df5c268 feat(cli): render --prores-profile picks ProRes 4444, hq, 422, lt or proxy for MOV (#6581)
* feat(cli): render --prores-profile picks ProRes 4444, hq, 422, lt or proxy for MOV

* fix(cli): drop a comment line that raised the comment share

* fix(cli): the render plan args type carries --prores-profile
2026-10-27 19:28:49 +00:00
James RussoandClaude Opus 5.5 07b0f2cda1 fix(producer): stop HDR video windows after the first from repeating one frame (#6575)
* fix(producer): stop HDR video windows after the first from repeating one frame

A raw HDR window seeks to a whole second, then trims its lead-in frames.
trim keeps their timestamps, and the raw muxer writes none, so when the
input has an audio track FFmpeg's default CFR sync pads from pts 0 with
copies of the window's first frame and -frames:v cuts the real ones off.
Phone footage always has audio, so HLG clips rendered at ~half their frames.
Pass frames through as the filter graph emits them.

Fixes #6556

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

* fix(producer): hold the first frame until a delayed HDR video starts

Window slots counted from the first decoded frame, so a video stream that
starts after its audio played early by its lead. Slots now count from the
extraction start and show the first frame until the stream begins, as they
did before windowed extraction (#6304) and as Chrome does.

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

* test(producer): add an HDR fixture whose clips carry audio and span extraction windows

Neither HDR fixture had an audio track, which is how #6556 shipped. Window A
checks frames after the first extraction window are not repeats; window B
checks a video stream that starts 0.5 s after its audio holds its first frame
until the picture starts. The baseline was generated in Docker and the fixture
fails against 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-27 17:38:34 +00:00
Miguel Ángel 53c9759666 chore: release v0.8.209 (#6562) 2026-10-27 14:34:53 +00:00
Miguel Ángel 9d9bdd23ba fix(producer): a taken file-server port fails the render, and the late grading test runs in its lane (#6561)
* fix(producer): a taken file-server port fails the render, and the late grading test runs in its lane

* test(producer): run the taken-port file-server test under Node, where listen errors are events

* test(producer): every *.integration.test.ts must sit in the integration lane

* fix(producer): drop the explanatory comment on the file-server error handler
2026-10-27 14:31:17 +00:00
Miguel Ángel 7053aa90dd fix(core): text a script splits into letters shows once and carries the variable's value (#6543)
* fix(core): text a script splits into letters shows once and carries the variable's value

* fix(core): Studio's mounted and swapped scenes read bound text, and instance values load first

* test(core): the scoped variables table is emitted compact in head
2026-10-27 11:29:02 +00:00
Miguel Ángel f007882ca7 chore: release v0.8.208 (#6529) 2026-10-27 11:12:48 +00:00
Miguel Ángel 6989271600 perf(producer): a parallel chunk checks BeginFrame on its first worker, with no separate browser (#6500)
* perf(producer): a parallel chunk checks BeginFrame on its first worker, with no separate browser

* style(producer): format

* fix(producer): a chunk whose first worker dies before its check settles instead of hanging
2026-10-27 09:08:54 +00:00
Miguel Ángel 019b17b4b7 fix(engine): a failed video extraction says what ffmpeg reported, without paths or URLs (#6527) 2026-10-27 07:29:03 +00:00
Miguel Ángel 619b8bc4d7 chore: release v0.8.207 (#6510) 2026-10-27 04:33:06 +00:00
Miguel Ángel 202bed36c9 test(producer): the stall tests jump fake time to the next timer instead of a second at a time (#6508)
* test(producer): the stall tests jump fake time to the next timer instead of a second at a time

A 400 s scenario took 400 steps of 50 real event-loop turns plus file IO, which crept
past the unit timeout on a loaded runner. Idle windows now cost one step.

* test(producer): stub the memory sampler so the stall tests' timer jumps skip the idle windows

The sampler is a faked 250 ms interval, so it was the next timer on every jump and the
jump was never longer than 250 ms.
2026-10-27 03:51:58 +00:00
Miguel Ángel c618724a5f fix(producer): a clip bound by its mount's variable values plays the bound file (#6501)
* test(producer): probe a variable-bound clip under a host with values

* fix(producer): probe a variable-bound clip its mount or defaults rebind

* style(producer): variable media fixtures in small steps

* test(producer): list the real-render variable mount test in the integration lane

* style(producer): keep probeStage's comment share at the base
2026-10-27 03:09:31 +00:00
Miguel Ángel 312a8fd9c7 fix(engine): a stalled BeginFrame capture resumes from the first unwritten frame (#6490)
* fix(engine): a stalled BeginFrame capture resumes from the first unwritten frame

A wedged worker used to throw away every frame already written and restart the
whole render on a screenshot session. Fresh BeginFrame workers now continue from
the first unwritten frame (once; a second stall still takes the screenshot
fallback), and the stall message names each worker's in-flight frame and step.

Force-closing the wedged Chrome no longer crashes the CLI with an unhandled
pipe ECONNRESET.

* chore(engine): cut the stall-resume comments to the comment limit

The explanations live in the PR body.
2026-10-27 01:10:09 +00:00
Miguel Ángel 54d0af57eb feat(engine): render sets a keyframe interval and a peak bitrate cap (#6444)
* feat(engine): encoders cap peak bitrate and place keyframes on a set interval

* style(engine): shorten the rate-cap comment

* style(engine): drop the doc lines the comment ratchet flagged

* feat(producer): mp4 renders honour a keyframe interval and a peak bitrate cap on every encoder path

* style(producer): shorten the delivery encoder file headers

* style(producer): drop a comment line from the segment manifest

* style(producer): shorten the integration test header

* test: delivery encoder tests follow the ffprobe argv contract and run in the integration lane

* feat: the render request, server and Lambda plan carry the keyframe interval and peak bitrate cap

* fix(studio): the Studio render route passes the keyframe interval and bitrate cap to the encoder

* chore(studio-server): drop a comment the helper's name already says

* feat(cli): render and lambda render take --keyframe-interval, --max-bitrate and --buffer-size
2026-10-27 00:29:06 +00:00
Miguel Ángel dcec31b468 fix(engine): audio scratch files Windows refuses to delete no longer fail a render (#6474)
* fix(engine): a scratch folder Windows refuses to delete no longer fails a finished audio mix

* fix(engine): audio scratch files Windows refuses to delete no longer fail a render

* fix(engine): a rename Windows keeps refusing falls back to a copy so the audio mix finishes

* fix(engine): audio scratch left behind is counted in the render log

* style(engine): wrap the long rename fallback test call

* refactor(engine): split the rename fallback decision out of the retry loop

* fix(engine): the rename copy fallback is opt-in and scratch leftovers are counted per render

* style(engine): keep renameWithRetry's comment share at the base

* style(engine): drop the blank line left by the comment cut
2026-10-26 23:49:02 +00:00
Miguel Ángel 165744edc0 fix(producer): compile probes each unique media source once however many elements use it (#6441)
* fix(producer): compile probes each unique media source once however many elements use it

* test(producer): run the probe-count test in the integration lane
2026-10-26 23:28:57 +00:00
Vance IngallsandClaude Opus 5.5 08d3745391 fix(producer): retry segmented capture on a screenshot session after a drawElement failure (#6437)
The segmented route had no drawElement recovery: a suspect small frame, a
missing paint record, a renderer stall or a failed self-verification failed
the whole render, where the streaming and disk paths re-render via
screenshot. Catch those errors around the segmented stage, replan with
forceScreenshot (segmentation kept), close the probe and retry once.

The retry discards the segment directory and manifest, including segments
resumed from an earlier run: the plan hash does not cover the capture mode,
drawElement and screenshot segments are not byte-identical, and segmented
drawElement segments are never self-verified.

A screenshot retry whose first segment encoder cannot spawn now keeps
forceScreenshot when it drops to plain streaming.

— Via

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 21:07:21 +00:00
Vance IngallsandClaude Opus 5.5 e47fdad7d0 fix(producer): open a fresh segmented session when the probe has risk frames (#6434)
* fix(producer): open a fresh segmented session when the probe has risk frames

Since #6318 the gate-check probe is planned with deFrameFallback: true, so
it can carry deRiskFrames. The segmented stage reuses that probe for its
first session and captures every frame with captureFrameToBuffer, which
cannot hand a risk frame to a screenshot session: the first one throws
"frame needs screenshot capture, which this capture path cannot hand over"
and the segmented route has no drawElement catch, so the render fails.

Close such a probe and open a fresh segmented session instead; those are
created with deFrameFallback: false and keep the whole-render screenshot
fallback.

— Via

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

* refactor(producer): name the risk-frame probe condition instead of commenting it

The comment ratchet does not allow a file's comment share to rise.

— Via

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-26 21:07:19 +00:00
Miguel Ángel 9b339e37cb fix(ci): the producer integration test list is data, not part of the pinned selection logic (#6467) 2026-10-26 19:29:17 +00:00