Commit Graph
6001 Commits
Author SHA1 Message Date
Miguel Ángel 490ecafbc4 chore: release v0.8.163 (#5676) v0.8.163 2026-10-16 01:52:29 +00:00
Miguel Ángel c03532b285 fix(producer): an ffmpeg failure names how ffmpeg ended and keeps its last line (#5678)
* test: ffmpeg failures name how ffmpeg ended and keep its last line

* fix(producer): an ffmpeg failure names how ffmpeg ended and keeps its last line

* refactor(producer): say why in names, not comments
2026-10-16 01:38:20 +00:00
Miguel Ángel 8e17ee9300 fix(engine): preserve authored audio mix order (#5672) 2026-10-16 00:13:04 +00:00
Miguel Ángel 917ee5d313 fix(cli): ask to log in when publishing needs an account (#5670) 2026-10-15 23:43:46 +00:00
Miguel Ángel 1ee6754f71 fix(core): timed svg clips hide outside their window (#5661)
* fix(core): timed svg clips hide outside their window

* fix(core): type the clip visibility path for SVG as well as HTML elements

* chore(core): regenerate the position edits render script
2026-10-15 23:22:42 +00:00
Miguel Ángel 0d6bdd453b fix(cli): capture writes inline SVG logos whole and parakeet takes long audio (#5662)
* fix(cli): capture writes inline SVG logos whole and parakeet takes long audio

* fix(cli): keep the decode timeout comment under the line limit
2026-10-15 21:16:20 +00:00
WaterrrForeverandClaude Opus 5.5 cea8aa8a7d feat(cli): judge text behind a transparent video by its decoded alpha in check (#5657)
* feat(cli): judge text behind a transparent video by its decoded alpha in check

The layout audit treated every <video> as opaque over its whole box, so a
caption between footage and a remove-background cutout always failed
text_occluded and needed data-layout-allow-occlusion, which also hid a word
the subject's head fully covered.

check now draws the video's current (seeked) frame into one reused,
downscaled scratch canvas, once per sample and only for a video a text probe
lands under. A fully opaque frame keeps today's behaviour. A frame with
transparency is judged per rendered word against its alpha: partial cover is
an info finding carrying the most covered word's share, and a word 80% hidden
or two neighbouring words each half hidden is an error. A frame that cannot
be read falls back to opaque with a video_alpha_unread info note.

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

* test(cli): serve the video-alpha fixtures from memory, not request paths

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

* fix(cli): check finds words under narrow, mirrored or backed cutouts

Review follow-ups on #5657:
- A matte the probe walk passes over, even at clear-alpha points, now triggers
  the per-word check, so a feature between two probe columns (an arm, a mic
  stand) still fails the word it hides.
- Mirrored videos and images map viewport points through the flip; a rotated,
  skewed or 3D-transformed video falls back to opaque with video_alpha_unread.
- A video with an opaque CSS background keeps its whole box occluding.
- cli.mdx lists every unread cause and why a fully transparent frame is one.

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-15 18:53:16 +00:00
WaterrrForeverandClaude Opus 5.5 08ee1bd5ad fix(cli): skip runtime by-products when fingerprinting a skill bundle (#5654)
The skill hash walked every file in a skill directory, so Python
__pycache__/*.pyc left by running a skill script (or node_modules, editor
swap files) changed it. Locally gen-skills-manifest then wrote a hash CI's
clean checkout could not reproduce, and an installed skill that had run a
script read as outdated forever. Skip those by-products on both the source
and the installed side so the hash stays a function of authored content.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 18:24:12 +00:00
Miguel Ángel a403ea1e8b ci(studio): re-run an edit accuracy shard on a fresh runner when its runner is too slow (#5659) 2026-10-15 17:43:09 +00:00
Miguel Ángel 0e9f380c2e feat(cli): render telemetry reports how busy the machine's CPU was (#5646)
* feat(cli): render telemetry reports how busy the machine's CPU was

render_complete and render_error now carry system-wide CPU busy share (average
and busiest 2 s window), cores busy in that window, and the one-minute load
average at start and end, for CLI and Studio renders. Nothing is sampled when
telemetry is off.

* test(cli): render tests use a private project folder instead of /tmp/project
2026-10-15 16:08:52 +00:00
Miguel Ángel 76222e41d7 chore: release v0.8.162 (#5649) v0.8.162 2026-10-15 11:54:09 +00:00
Xuanru Li 34776f3def fix(cli): analyze finalized audio assets after direct upload (#5647) 2026-10-15 09:23:10 +00:00
Xuanru Li ce060c7acc chore: release v0.8.161 (#5643) v0.8.161 2026-10-15 08:49:20 +00:00
Miguel Ángel 49c49504a4 fix(studio-server): an edit aimed at a clip never lands on an audio group sharing its id (#5645)
* fix(studio-server): an edit aimed at a clip never lands on an audio group sharing its id

* refactor(studio-server): one comment line, the rest in names
2026-10-15 08:19:28 +00:00
Xuanru Li 695110e46b feat(core): signal rhythm is rate-independent, refuses grids in the tracker, follows chords (#5644)
* fix(core): signal beats read the same at any decode rate and refuse a grid in the tracker

The tracker resamples every channel to 22.05 kHz and averages their band power, so the
CLI's native-rate decode and Studio's AudioContext decode get the same beats, and a mono
file and the same sound on two channels get identical ones.

The no-steady-beat floor moves from analyzeMusicFromSignal into the tracker, so
hyperframes audio, grep_audio and beats share one floor. It is 0.15: above every one of
66 synthetic ambient, speech, scattered-effect and noise clips (max 0.122), where the
wrapper's 0.2 also refused a third of GTZAN's produced music.

* feat(core): signal downbeats follow chord changes, and sections hear harmony

The tracker now keeps a 10 fps chroma beside its band energies. Downbeats weigh where the
chords change, over one beat and over two, with the low-end hit, instead of the low end
alone. Sections compare timbre and harmony equally.

Tuned on GTZAN's dev half: the tempo prior narrows to 0.8 octave, the local tempo stays
within 10% of the global one, and beats sit 15 ms after the onset peak, where annotators
put them.

* chore(core): trim redundant audio analysis comments

* refactor(core): keep the rhythm files under their comment share

Drops doc comments whose function or field name already says the same thing.
2026-10-15 07:31:04 +00:00
Xuanru Li 124492e427 feat(cli): the api provider speaks the HeyGen audio analysis contract (#5641)
* feat(cli): the api provider speaks the HeyGen audio analysis contract

The api rung now sends its key as x-api-key, a new Idempotency-Key on each
request, and 16 kHz mono 16-bit WAV: the channels are averaged and resampled
with a windowed sinc whose cutoff sits under 8 kHz, so nothing folds back in.
It reads the answer from a { "data": ... } envelope, or bare. Times stay in
seconds, and the answered times still snap onto beats measured on the signal
as decoded. The response type gains time_resolution_seconds.

* fix(cli): reject redirects from audio analysis requests

* fix(cli): preserve audio when stereo downmix cancels
2026-10-15 06:54:29 +00:00
Xuanru Li 1544b519a9 feat(cli): beats tracks the music with the TypeScript beat tracker, without Chrome (#5634)
* feat(cli): audio answers beats, downbeats, bpm, sections and describe through a provider ladder

Beats and downbeats try api, apple-mu, beat-this, then signal; sections try api, apple-mu,
then signal; describe tries api, then apple-sound. bpm is read off whichever provider placed
the beats. Each provider says whether it can run here and why not, and the ladder warns
when it passes one over.

The signal rung is a TypeScript tracker: log-band spectral flux, autocorrelation tempo with
a log-normal prior, Ellis dynamic-programming beats with a windowed local tempo, a low-band
bar phase, and Foote novelty sections snapped to beats. It reports no steady beat when the
onsets do not repeat.

The api rung posts the audio to HYPERFRAMES_AUDIO_API_URL with HYPERFRAMES_AUDIO_API_KEY and
moves each answered time onto the nearest signal beat within a quarter beat, reporting what
moved and what did not. beat-this runs Beat This! from a configured Python and local weights
and never downloads. apple-sound runs macOS's sound classifier through a Swift helper.
apple-mu reports that Music Understanding needs macOS 27.

words are no longer accepted: they come from hyperframes transcribe.

* docs(cli): audio's beats, downbeats, bpm, sections, describe and their provider ladder

* feat(cli): beats tracks the music with the TypeScript beat tracker, without Chrome

hyperframes beats and Studio's beat detection now share analyzeMusicFromSignal: band energies,
then the spectral-flux tracker in audioRhythm.ts, then each beat's loudness for its strength.
The CLI decodes with the same ffmpeg path as hyperframes audio, so beats no longer launches
headless Chrome. Studio still decodes in the browser and passes every channel.

The old analyzer averaged bpm-detective's tempo with an energy-peak tempo it had only compared
after folding both into one octave, and phased a rigid grid from noisy peaks. On 22 real tracks
with exact script grids it found the tempo 18% of the time with beat F 0.437; this finds it
91% of the time with F 0.887, and refuses the other two rather than guess.

Below a tracker confidence of 0.2 no beats are reported, so ambient or rubato music gets no
invented grid and the CLI still writes nothing. bpm-detective, the energy-peak grid, the
headless analyzer and its prebuilt bundle are gone.

* fix(core): tempo reads 96 BPM off beats on 10 ms frames, not 95.2

The tracker places beats on 10 ms frames, so a 625 ms beat lands 620 or 630 ms apart and the
median interval reported 95.2 or 96.8 BPM. Tempo now averages the intervals within 10% of the
median: as robust to a skipped or doubled beat, without the frame-sized step. Both
hyperframes audio and hyperframes beats read it.

* fix(cli): remove redundant audio context comment

* fix(core): remove redundant tempo interval comment

* fix(ci): record beat analyzer removals and browser evidence

* fix(core): keep flat audio novelty in one section

* chore: keep PR capture evidence out of the source tree

* fix(cli): honor BPM provider pins before analysis
2026-10-15 06:23:03 +00:00
James RussoandClaude Opus 5.5 f55b366175 fix(build): ship NodeNext-resolvable declarations from every package (#5532)
* fix(build): ship NodeNext-resolvable declarations from every package

tsc copies relative specifiers verbatim, so packages whose sources use
bundler-style extensionless imports (core, inspector) published .d.ts files
that a module/moduleResolution nodenext consumer cannot resolve. Core already
rewrote its emitted JavaScript for this, but not its declarations.

Move that rewrite to scripts/rewrite-relative-import-extensions.mjs, make it
cover .d.ts too (adding .js or /index.js, and failing the build when a
declaration import has no declaration), and run it after every tsc emit:
core, engine, sdk, producer, aws-lambda, gcp-cloud-run and inspector.

verify:packed-manifests now typechecks the clean packed consumer with
skipLibCheck false and type-only imports of every typed subpath, so an
unresolvable import inside a published declaration fails the gate and is
attributed to its package.

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

* chore(ci): allow the moved core rewrite-esm-extensions script deletion

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

* ci: rebuild the edit-accuracy bench when the import-extension rewriter changes

The package builds now run scripts/rewrite-relative-import-extensions.mjs, so main's
edit_accuracy paths filter has to include it (check-edit-accuracy-filter test).

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-15 05:59:41 +00:00
Xuanru Li ec97816a92 chore: release v0.8.160 (#5636) v0.8.160 2026-10-15 05:43:55 +00:00
Miguel Ángel d4c8d76fff fix(lint): warn on unbounded cosine powers in shaders (#5640) 2026-10-15 05:40:38 +00:00
Xuanru Li 8e340d220e feat(cli): audio answers beats, downbeats, bpm, sections and describe through a provider ladder (#5632)
* feat(cli): audio answers beats, downbeats, bpm, sections and describe through a provider ladder

Beats and downbeats try api, apple-mu, beat-this, then signal; sections try api, apple-mu,
then signal; describe tries api, then apple-sound. bpm is read off whichever provider placed
the beats. Each provider says whether it can run here and why not, and the ladder warns
when it passes one over.

The signal rung is a TypeScript tracker: log-band spectral flux, autocorrelation tempo with
a log-normal prior, Ellis dynamic-programming beats with a windowed local tempo, a low-band
bar phase, and Foote novelty sections snapped to beats. It reports no steady beat when the
onsets do not repeat.

The api rung posts the audio to HYPERFRAMES_AUDIO_API_URL with HYPERFRAMES_AUDIO_API_KEY and
moves each answered time onto the nearest signal beat within a quarter beat, reporting what
moved and what did not. beat-this runs Beat This! from a configured Python and local weights
and never downloads. apple-sound runs macOS's sound classifier through a Swift helper.
apple-mu reports that Music Understanding needs macOS 27.

words are no longer accepted: they come from hyperframes transcribe.

* docs(cli): audio's beats, downbeats, bpm, sections, describe and their provider ladder

* fix(cli): remove redundant audio context comment

* fix(core): keep flat audio novelty in one section

* fix(cli): honor BPM provider pins before analysis
2026-10-15 05:16:55 +00:00
Miguel Ángel db845d9409 fix(cli): retire old snapshot run folders (#5635)
* fix(cli): retire old snapshot run folders

* chore: satisfy snapshot comment limit

* fix(history): read and release snapshot leases through verified handles

* test(history): run lease races in Node and check released markers

* fix(studio): verify snapshot leases from open descriptors
2026-10-15 04:59:59 +00:00
Xuanru Li c694785df5 fix(core): faint SVG grain is not a click target, and a page reset is not an element's CSS (#5628)
* fix(core): a faint SVG grain is not the click target, and a page reset is not an element's CSS

A filter rect under an svg at opacity 0.07 was still picked. The veil check
required that element's own opacity and a background-image. A `*` rule matched
every element, so a rect was given the page reset as its CSS.

fails without the fix: clicking the grain selects the rect, and inspection attaches `*`.

* fix(core): keep picker comments within the source ratchet

* fix(core): preserve selector literals and SVG veil boundaries
2026-10-15 04:04:13 +00:00
Miguel Ángel 8f8f91c9de fix(runtime): prepare trimmed video frames before preview cuts (#5633) 2026-10-15 03:31:39 +00:00
Miguel Ángel 916ec37755 fix(studio-server): history copies a changing file without stalling its sweep (#5627)
* fix(studio-server): history copies a changing file without stalling its sweep

* fix(studio-server): a failed history copy leaves no partial file and keeps the mode

* style(studio-server): name the history copy for what it does
2026-10-15 03:16:32 +00:00
Xuanru Li bb49858b8a feat(cli): hyperframes audio measures where sounds land, in film time (#5602)
* feat(cli): hyperframes audio measures where sounds land, in film time

Adds @hyperframes/core/audio-analysis: an energy envelope, spectral-flux
and energy onsets, the moments a sound lands (onset, steepest rise, peak,
tail end), BS.1770 loudness with true peak, silence spans and a first
guess at sfx/voice/music, all pure functions of PCM. Each capability runs
through a provider ladder so model or service providers can join later.
The radix-2 FFT moves out of audioCarve so both share it.

`hyperframes audio` decodes with FFmpeg and analyzes files, or the film's
own audio and video clips by element, second, range or boundary, reading
only the part of each file that plays. Timeline rows now carry
`mediaStart`, moved by an in-point host's cut, so file time maps to film
time.

* feat(cli): audio placements carry the element's own data-start, local to its composition

* feat(cli): audio placements carry the element's own data-start, local to its composition

* feat(cli): audio places a file with --place-at, drops --boundary

--start becomes --place-at and --media-start becomes --skip-file-seconds,
which only goes with --place-at, refuses to skip the whole file, and warns
when the skipped part held the file's loudest moment. --boundary is gone:
--at and --range cover the sounds a cut touches.

* fix(cli): pass a sound file to ffprobe as a file, on every platform

ffprobe treated a name starting with a dash as an option because the argument
list never ended the flags. The path check compared a Windows drive path to a
POSIX string, and a new timeline comment raised that file's comment share.

* fix(cli): hear a reversed stereo channel, and warn when its peak was skipped

Averaging the channels cancelled a reversed one, so a real hit was reported
as silence. The skip warning also compared against the decode margin, so a
peak just before the kept window produced no warning.
2026-10-15 02:32:10 +00:00
Xuanru LiandClaude Opus 5.5 150e1c94d0 fix(cli): report spend usage for Claude plans without rate windows (#5629)
* fix(cli): report spend usage for Claude plans without rate windows

Spend-metered Claude plans (for example Enterprise) return null five_hour
and seven_day windows from the OAuth usage endpoint and put their allowance
in spend / extra_usage instead. The parser rejected every such response as
invalid_usage_response, so `hyperframes usage` always reported unknown.

- Read spend.percent (falling back to extra_usage.utilization) into a new
  `spend` window on known results; over-limit spend caps at fully used.
- Report `no_usage_windows` instead of `invalid_usage_response` when a
  well-formed response simply has no window.
- Document the `spend` field in the hyperframes-cli skill.

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

* fix(cli): satisfy usage budget comment ratchet

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 02:04:55 +00:00
Miguel Ángel 03a9fab9a7 fix(cli): first render on Windows no longer fails while a new browser or ffmpeg is scanned (#5625) 2026-10-15 00:56:06 +00:00
Miguel Ángel f35b05fba0 chore: release v0.8.159 (#5621)
* chore: release v0.8.159

* chore: v0.8.159 notes list the first-frame fix

* chore: v0.8.159 notes list the sandboxed GPU check fix

* chore: v0.8.159 notes list the hidden-scene fix and the offline font test
v0.8.159
2026-10-15 00:27:52 +00:00
Miguel Ángel 8f0bcadcd3 test(core): the var() font fallback test no longer waits on Google Fonts (#5623) 2026-10-14 22:19:20 +00:00
Miguel Ángel 24a9b78171 fix(core): a hidden scene's contents stay hidden when a child is set visible (#5619)
* fix(core): a hidden scene's contents stay hidden when a child is set visible

* fix(core): keep the hidden-clip rule's file within its comment share

* fix(core): hide a hidden scene's contents by the visibility pass's own mark

* fix(core): keep a scene's video across a swap when the hidden mark is on it

* test(core): pin that a mask-hidden container's contents are left to the mask

* test(producer): a nested scene stays hidden before its host starts in the static-volume baseline

* fix(core): a scene copy a shader transition forces visible shows its contents
2026-10-14 22:19:15 +00:00
James Russo 9c11715971 fix(audio): preserve subprocess causes through CLI diagnostics (#5620)
* fix(audio): preserve subprocess evidence through CLI diagnostics

* test(producer): retain real engine exports in assembly mock

* fix(audio): retain triggering interruption within diagnostic cap

* fix(producer): sanitize audio evidence before encoder error construction

* test(cli): isolate diagnostic render temporary project
2026-10-14 20:26:59 +00:00
Miguel Ángel 6c89decb0d fix(cli): the GPU probe uses the pipe too, so a sandboxed check doesn't wait 120 s (#5622)
* fix(cli): the GPU probe uses the pipe too, so a sandboxed check doesn't wait 120 s

* fix(cli): name, not comment, says the probe can't listen
2026-10-14 20:26:09 +00:00
Miguel Ángel 8c00ebad80 fix(core): show a scene's starting state on a render's first frame (#5614)
* fix(core): show a scene's starting state on a render's first frame

A seek to the time a GSAP timeline already sits at renders nothing, so a
sub-composition timeline at 0 never applied its t=0 steps before frame 0
was captured. Every runtime seek now goes through seekGsapTimeline, which
redraws the timeline silently when the seek did not move it.

* test(producer): share the frame-level reader across render tests

* fix(core): name the in-place render skip instead of commenting it

* perf(core): redraw a parked scene timeline once instead of every frame

* fix(core): redraw only a scene timeline GSAP has never drawn
2026-10-14 19:50:07 +00:00
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 71595dd820 fix(cli): check and snapshot run where a sandbox refuses to listen on localhost (#5618) 2026-10-14 19:19:37 +00:00
Miguel Ángel b14a456471 fix(cli): a long video conversion in init never stalls on ffmpeg's own log (#5616)
init's transcodeToMp4 piped ffmpeg's stdout and stderr and never read them.
ffmpeg's progress log filled the pipe buffer and ffmpeg blocked in write(),
so init hung with its spinner running. Both streams are now ignored.

render --docker --quiet piped the container's stdout without reading it; it
is now ignored. stderr is still read and kept as a bounded tail.
2026-10-14 19:19:31 +00:00
Miguel Ángel cd87cf1110 ci: a stalled history fetch in change detection is retried instead of failing the run (#5615) 2026-10-14 19:19:25 +00:00
Miguel Ángel fa99eec9d0 chore: release v0.8.158 (#5617) v0.8.158 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 14e2ccf3bb test(engine): the warm extraction cache test checks ffmpeg did not run, not the clock (#5613) 2026-10-14 17:51:02 +00:00
Miguel Ángel 4957bf6939 fix(cli): capture keeps fonts a page declares in its own style block (#5609) 2026-10-14 17:01:29 +00:00
Miguel Ángel fe29f157f9 fix(cli): a killed browser on a busy Windows machine no longer fails check (#5607) 2026-10-14 16:59:25 +00:00
Miguel Ángel 7744692a46 test(engine): audio effect tests that start Chrome get the same time as the others (#5608) 2026-10-14 16:49:13 +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) v0.8.157 2026-10-14 09:19:15 +00:00
Xuanru Li 45825faa5d fix(inspector): grep timeline windows, continuation, candidates and timeline text from the Canary dogfood (#5595)
* fix(inspector): report nested hosts' authored window, one location per source line

The runtime strips data-duration/data-end from nested composition hosts after
boot and keeps them as data-hf-authored-*. Timeline inspection built its
resolver without authored attrs, so a host with data-duration="4" reported
its GSAP timeline length (3.72s) instead.

Timeline text and events[].sources listed the same file:line once per mapped
snippet (creation, caller, dependency), so a one-line script printed one
location up to nine times.

* refactor(inspector): carry the dedupe reason in the helper's name

* fix(inspector): end continuation on a page that fits no snippet; fill budget with candidates

* fix(inspector): timeline groups by component, names attr values, eases, film end

* fix(studio-server): stamp hf ids into a file without reformatting it

* fix(inspector): find an element's tag before its served hf id reaches the source

* fix(inspector): live element map shows authored classes and text, not the playhead's

* fix(inspector): collapse script-built text so the element map ignores the playhead

Class names stay in source order, a runtime-stripped id is shown as id="…"
rather than a selector, and a grouped row names which children it covers.

* fix(inspector): keep paging, stamping, and the live map still on the reported edges

A snippet larger than the page ended the walk, so later snippets could not
be reached. Raw text ended at a longer tag name, which could stamp an id
inside a script. An empty or mixed source element showed live text, and an
unknown duration read as a film that ends at 0s.

* fix(inspector): mint ids for an empty hf id and keep an unquoted class

An empty data-hf-id was treated as already assigned, so stamping left it
blank while the older stamper minted one. An unquoted class was read as no
class, so the live map dropped it.

* fix(inspector): narrow markup before reading a child tag

skipMarkup returns a boolean, so the build still sees Markup where a tag
is required. Narrow on the kind first so the inspector typechecks.

* fix: quiet check false positives and name the ancestor of an id-less target

Endpoint contact, disjoint fromTo pairs, and a negative z-index under a
stacking-context parent were warnings with bad advice. Layout and contrast
blamed a dot grid, a circular avatar's panel, and a visibility override.
A faint texture veil is no longer the click target.

* fix(lint): drop a history sentence and six gsap comments

The comments check treats "load-bearing" as history, and gsap.ts added six
comment lines. The names already carry what those lines said.

* fix(parsers): ignore an empty id written inside another attribute

The empty-id scan matched the first data-hf-id="" in the tag, including one
inside a quoted title. It now skips quoted text, so the real attribute is minted.

* fix(lint): keep real covers and a negative z-index under a card

A gradient scale-down treated every fill like a radial dot, so a panel
that starts transparent stopped counting as a cover. A stacking context
on any ancestor cleared a negative z-index, and a faint wrapper made
images inside it unpickable.

* fix: keep an emoji from shifting a stamped id

The quote mask replaced one emoji with one space, so the id landed before
the closing quote. A radial cover that turns opaque after a clear stop
stays fully painted.

* fix(lint): score a letter-only dot as a dot, not a color name

namesAColor saw #fff and rgba as words, so those dot grids counted as a
full cover. Hex and rgb colors are stripped before that word check.
2026-10-14 09:16:20 +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 d9edffa3a4 perf(studio): settle the edit accuracy bench on frames and network, and reuse the producer Chrome (#5571)
* perf(studio): settle the edit accuracy bench on frames and network, not a fixed window

settled() waited for the box and the preview frames to hold still for 500 ms,
7 to 15 times a case. It now resolves once they read the same on 3 animation
frames in a row while the Studio page has no request in flight (the event
stream and server-rendered timeline thumbnails excepted) and the server has
announced every project file written since its last file-change event, so a
save, a preview reload or a reload the event starts still holds it open.
EDIT_ACCURACY_STILL_MS restores the fixed window with no network signal.

Also polls studio_seek every 50 ms instead of 250 ms while Studio opens.

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

* perf(studio): keep one producer Chrome open across edit accuracy renders

Every render launched and closed its own producer Chrome. The run now holds a
lease on the engine's pooled browser (a capture session with the renders'
launch settings and its page closed), so each render opens a page in that
browser instead. Each render still gets its own page and file server, and
clears the browser cache first. A held browser that failed to launch or whose
Chrome died is dropped and held again, never reused.

Studio's server stays per case: it serves one project folder, stamps it on
start and keeps that folder's undo history open, so switching folders under it
would leak history between cases. Its start is polled every 50 ms instead of
200 ms.

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

* test(studio): import render.mjs at the top of the edit accuracy render test

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

* fix(studio): restart the settle window when a busy request's frame goes away

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

* style(studio): format the edit accuracy settle test

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

* fix(studio): seek the edit bench only after Studio binds the timeline

openStudio now polls every 50 ms, so after a reload its first studio_seek
often lands before the runtime binds the timeline (Studio still reports
duration 0, but the playhead moves). The bind then replays the playhead from
near 0 (core init.ts progress(0.0001) then totalTime). A tween that starts on
the playhead was already initialised by the early seek, so GSAP skips its
first keyframe. The preview then holds a box no fresh seek or render shows.
In resize-fromto-px-r0-nested-z100-on that box is 90 px off, and it persists
until the next seek.

Wait for studio_look to report a duration before seeking.

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-14 05:52:14 +00:00
James RussoandClaude Opus 5.5 692b89b6e5 chore(docker): pin FFmpeg 8.0.1 in the Docker images and host CI (#5576)
* chore(docker): pin FFmpeg 8.0.1 in the Docker images and host CI

Install one pinned static BtbN build (n8.0.1-66, month-end release) in
Dockerfile.test, the CLI render image, the Cloud Run image and the k8s
example, and bump the host CI install-ffmpeg-linux action from 7.1.3 to
the same build. Regression baselines and the shipped images now use the
same FFmpeg version instead of Debian's apt ffmpeg 5.1.

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

* test(producer): regenerate six regression baselines on FFmpeg 8.0.1

The Docker test image now renders with FFmpeg 8.0.1 instead of Debian's
5.1. Six fixtures fail against the 5.1 baselines; everything else passes
unchanged, including vfr-screen-recording.

- style-2-prod, style-10-prod: FFmpeg 8 honors the MP3 gapless header,
  so the probed SFX duration is 1.0s instead of 1.044898s. Regenerate
  output.mp4 and compiled.html.
- vignelli-stacking: one checkpoint (8.06s) now shows source frame 201
  of the 25fps a-roll, which is the right frame for that time; the old
  baseline showed frame 202.
- missing-host-comp-id, variables-prod, speed-ramp: AAC encoder output
  differs enough to drop the RMS-envelope correlation on flat signals
  below 0.9. Sample correlation against the source stays at 0.9999.

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

* fix(cli): read the ffmpeg version from n-prefixed release builds

Release-branch ffmpeg builds, including the BtbN build now pinned in CI,
print "ffmpeg version n8.0.1-66-...". extractMajorVersion skipped the
"n8" token and returned 0 (and 1 for n7.1.3), so the CLI telemetry
smoke check failed. parseToolVersion fell back to the whole banner line.
Accept an optional "n" before the version number in both.

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

* fix(cli): keep the preflight comment share flat

Fold the n-prefix note into the existing doc line instead of adding new
comment lines, which the comment ratchet rejects.

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

* fix(docker): pick the FFmpeg build per arch and fail on a bad binary

Dockerfile.test, the k8s example and the Cloud Run image always extracted the
amd64 archive on multiarch bases, and the piped version check passed even when
the binary could not run. All four images now pick linux64 or linuxarm64 by
TARGETARCH, fail on any other arch, and grep both ffmpeg and ffprobe for the
pinned version.

style-2-prod and style-10-prod compiled.html go back to the previous golden
with only the SFX data-duration/data-end changed, instead of a full
recompile that also picked up unrelated compiler output.

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-14 05:37:15 +00:00