mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
* feat(studio): make presets the primary path into the FX rack
Presets button becomes the stacked primary control (bold, filled outline);
Add-effect demoted to a small trailing link ("+ effect"). Button onClick
bodies and audition-revert logic are unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix(core,studio): silence hidden audio in preview, and call it mute
Preview scheduled every audio[data-start] regardless of data-hidden, so a
hidden audio track was silent in the export but audible in preview — render
was already correct, this was a preview-only parity bug. Web Audio scheduling
now skips (and re-syncs on toggle) any audio clip under a data-hidden
ancestor; the HTMLMedia per-tick volume path folds the same check into
effectiveVolume without touching el.muted (transport-owned). Ships unflagged
since it's a bugfix restoring parity.
Also relabels the eye as Mute/Muted on audio-only track rows (icon,
strikethrough label, undo-history copy), gated behind the new
audio-track-mute canary — the relabel is a copy/UX change, kept separate from
the behavior fix above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* test(core): assert hidden-audio exclusion on the scheduling entry point, not the decode fallback
CI was red on `Test`, `Test: runtime contract` and `Tests on windows-latest` — all three on the
same two tests, both reporting `decodeAudioElement` called 0 times.
Not a bug in this branch. The tests pass on the branch tip and fail on the MERGE with main, which
is what CI actually builds. Main had moved 66 commits ahead, and #3322 ("make creator media edits
render-safe") added `WebAudioTransport.scheduleMediaElementPlayback`: media-element clips now route
straight through the Web Audio graph instead of being decoded into an AudioBuffer.
`decodeAudioElement` survives only as the fallback for the rate-shifted case
(`Math.abs(effectiveRate - 1) > 1e-9`), so on the ordinary path it is correctly never called:
void webAudio.scheduleMediaElementPlayback(...).then((scheduled) => {
if (scheduled || !clock.isPlaying()) return; // <- returns here now
...
void webAudio.decodeAudioElement(rawEl) // <- fallback only
Both tests used `decodeAudioElement` as a proxy for "this clip reached Web Audio scheduling",
which was accurate before #3322 and is not any more. Retargeted to
`scheduleMediaElementPlayback`, which is that signal now and takes the element as its first
argument, so the assertions keep their exact shape and meaning.
Confirmed by instrumenting the run rather than inferring: on the merged tree the scheduler is
called exactly once, with the audible element — the feature under test works, only the probe was
pointed at the wrong method.
Still non-vacuous: deleting the `rawEl.closest("[data-hidden]")` guard from
`scheduleWebAudioForActiveClips` fails the first test with "expected 1 times, but got 2 times", so
it genuinely catches a hidden clip being scheduled.
`init.test.ts` 77/77, and 1259 passed across packages/core `src/runtime` + `src/audio` on the
merged tree.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>