mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-14 18:01:20 +08:00
485c037dcf
* feat(core): route grouped audio through a group bus in preview An audio element carrying `data-audio-group` no longer lands its gain on the master bus directly — it feeds a per-group `GainNode` (built lazily on first use, one per group id) which itself feeds master, so members of the same group sum before the ear, ready for a group-level FX chain and volume/mute in later steps. An id with no matching `<hf-audio-group>` element still gets a plain, unprocessed bus rather than losing the track. The group's own chain and volume lane are wired through the same `attachElementFxChain`/`scheduleVolumeLane` every element already uses, against the group's clock — composition time (design doc §1.3), since a group has no `data-start` and a missing one parses as 0. The bus persists across `stopAll()` (mirroring `_masterGain`'s own lifecycle) so replaying a group does not rebuild its chain; only `destroy()` disposes it. Render is untouched — stays flat until B4; `audio-groups` is still a 0% canary so nothing ships this to a real composition without hand-authoring `data-audio-group`. Also: `audioGroupOf` (B1) crashed on any element lacking a real `tagName`/ `getAttribute` — exactly the shape of most `HTMLMediaElement` test doubles in this suite, including this file's own `mockEl`. Made it tolerant, same style as `readChain`'s existing guard in `runtime/audioFx.ts`. `schedulePlayback` was already 110 lines pre-existing before this diff; extracted `resolveDestination` and `handleSourceEnded` to shrink it to 92, then suppressed the remainder (inherently sequential graph wiring, not a decision tree) per the same precedent B2 used on `TimelineLogicalRow`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * feat(studio,lint): carve targets voiceover groups — always, when plural Plural voiceover carve now targets a group instead of naming each clip: `resolveCarveSourceIds` (core `audioGroups.ts`) expands a group id to its current members at analysis time, so a clip added to the group later is covered without touching `sources`. The picker (`useFxCarve.ts`) offers a grouped voice as one option instead of one row per member, tests overlap as a union of member spans (a group overlaps the bed if ANY member does), and prefers a qualifying group over its individual members in `autoSourceIds`. Picking two or more ungrouped voice clips in the carve flow now mints a group behind them (`mintGroupId`, de-duped against every id in the document) and writes `data-audio-group` on each picked clip atomically, one undo entry — `createAudioGroupAndAssignMembers` in `timelineTrackVisibility.ts` copies `setElementsHidden`'s multi-target write shape. The DSP is untouched: `mixCarveSources` already sums multiple sources correctly (verified in the design doc's own investigation) — this only fixes the picker. New lint rule `audio_carve_ungrouped_sources` (`packages/lint/src/rules/ media.ts`, alongside `audio_volume_double_automation`) warns when a `data-fx-carve`'s `sources` names two or more plain clip ids instead of a group — the shape that silently rots when a clip is added. `/hyperframes- audio` states the same rule as an invariant, not a tip, with the grouped- narration HTML example from the design doc. The group-matching and auto-group logic (`withAutoGroupedSources`, `collectCarveCandidates`) is split into `useFxCarveGrouping.ts` — `useFxCarve.ts` was pushing past the 600-line cap. `resolveNextCarveSettings` is deliberately NOT an `async function`: wrapping it in one would force a microtask on every call, including the synchronous branch — the exact bug `withAutoGroupedSources`'s own sync-when-possible contract exists to avoid, and one caught via `propertyPanelAudioFxGroup.test.tsx` (10 failures) before fixing it back to a plain function the caller conditionally awaits. Also extracted `useEffectiveTimelineDuration` out of `App.tsx` and `useRemoveBackground` out of `StudioRightPanel.tsx` (both pushed past 600 lines from an added prop wire), and decomposed `useFxCarve.ts`'s picker IIFE to clear fallow's complexity gate. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
86 lines
1.7 KiB
JSON
86 lines
1.7 KiB
JSON
{
|
|
"source": "heygen-com/hyperframes",
|
|
"skills": {
|
|
"embedded-captions": {
|
|
"hash": "ab099eb22321e865",
|
|
"files": 138
|
|
},
|
|
"faceless-explainer": {
|
|
"hash": "5de02925f2431645",
|
|
"files": 24
|
|
},
|
|
"figma": {
|
|
"hash": "642cce1b5e211182",
|
|
"files": 2
|
|
},
|
|
"general-video": {
|
|
"hash": "16898c02677d09bc",
|
|
"files": 4
|
|
},
|
|
"hyperframes": {
|
|
"hash": "d64583e4aa8011f7",
|
|
"files": 17
|
|
},
|
|
"hyperframes-animation": {
|
|
"hash": "67d23c9507ebb1e8",
|
|
"files": 121
|
|
},
|
|
"hyperframes-audio": {
|
|
"hash": "819ab4e70d0f1cc9",
|
|
"files": 6
|
|
},
|
|
"hyperframes-cli": {
|
|
"hash": "3fa884269c43d7df",
|
|
"files": 11
|
|
},
|
|
"hyperframes-core": {
|
|
"hash": "74b9841f63c8f405",
|
|
"files": 20
|
|
},
|
|
"hyperframes-creative": {
|
|
"hash": "87bc09ec744313c8",
|
|
"files": 78
|
|
},
|
|
"hyperframes-keyframes": {
|
|
"hash": "6bc62531ecea9a52",
|
|
"files": 3
|
|
},
|
|
"hyperframes-registry": {
|
|
"hash": "d6dfcc8ceb7c8178",
|
|
"files": 12
|
|
},
|
|
"media-use": {
|
|
"hash": "1b0ce647f5c7df95",
|
|
"files": 152
|
|
},
|
|
"motion-graphics": {
|
|
"hash": "853ac75cbab69036",
|
|
"files": 23
|
|
},
|
|
"music-to-video": {
|
|
"hash": "39282be90a90f89f",
|
|
"files": 132
|
|
},
|
|
"pr-to-video": {
|
|
"hash": "337d781bd7517d2c",
|
|
"files": 30
|
|
},
|
|
"product-launch-video": {
|
|
"hash": "6d691b3db92e2c39",
|
|
"files": 29
|
|
},
|
|
"remotion-to-hyperframes": {
|
|
"hash": "79fcf8e9641d126e",
|
|
"files": 70
|
|
},
|
|
"slideshow": {
|
|
"hash": "c68fb51d48b80802",
|
|
"files": 2
|
|
},
|
|
"talking-head-recut": {
|
|
"hash": "2eaa83d6889537a5",
|
|
"files": 28
|
|
}
|
|
}
|
|
}
|