Skip to content

feat(studio): fold a preset shut, and give each one its own title design - #3191

Merged
vanceingalls merged 960 commits into
mainfrom
wa-20d6-preset-design
Aug 13, 2026
Merged

feat(studio): fold a preset shut, and give each one its own title design#3191
vanceingalls merged 960 commits into
mainfrom
wa-20d6-preset-design

Conversation

@vanceingalls

Copy link
Copy Markdown
Collaborator

Collapse. A preset is one thing the author added; once set, the modules inside are detail. The title is the disclosure, and folded it carries the node count — which is what keeps a collapsed preset reading as a chain rather than one opaque effect.

A title treatment per preset. The rack already letters by family, which says what kind of thing it is; this says which character. Eight named faces with documented fallback chains — the studio has no webfont pipeline, so these are system faces and a test enforces every stack ends in a generic keyword.

Colour. Saturation roughly doubles. Two hues moved rather than brightened: the voice presets sat on the accent's hue (#3CE6AC is hue 160), and saturating them there would have made "Clean Voice" read as automated. A test keeps every title ≥20° clear of the accent. Backgrounds are derived from each title hue rather than picked — nineteen hand-chosen pairs is nineteen chances for one to clash.

Also two preset fixes: Megaphone and AM Radio sounded the same. A log sweep showed both flattened to a dead −19 dB line — the saturation thresholds were low enough that clipping erased the resonances. Every character preset's clipper is backed off, and the ones still alike were separated by what physically distinguishes them. Every pair in the family is now positive where telephone/AM was −5.9 dB.

🤖 Generated with Claude Code

@vanceingalls
vanceingalls force-pushed the wa-20d5b-audition-fixes branch from 83f09a3 to 7eb2dcb Compare August 11, 2026 08:35
@vanceingalls
vanceingalls force-pushed the wa-20d6-preset-design branch from 1164623 to 0b032ca Compare August 11, 2026 08:35

@terencecho terencecho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: LGTM_WITH_NITS — CI: Preflight (oxfmt --check) is the only real failure; player-perf/preview-regression/regression are its transitive dependents (per repo GHA pattern where perf-shards="skipped" cascades to workflow FAIL). Drift list is 10 files; ~6 match the standing stack-wide docs drift on master, but 4 are files this PR touches or adds — plans/audio-fx-ux/README.md, skills/hyperframes-audio/SKILL.md, references/attributes.md, and the newly added references/presets.md. A bun run format on those before merge resolves it. TS/TSX code is clean.

Empirical claim verification (at 7443ac2):

  • "Collapse, view-local": propertyPanelFxSection.tsx:697 useState<ReadonlySet<string>>(new Set()) — not on chain, no parse/serialize impact. Key is ${run.preset}-${firstIndex} so a reorder survives.
  • "Open by default": data-collapsed={collapsed ? "" : undefined} at :727 + aria-expanded={!collapsed} at :746, initial empty Set → verified.
  • "Node count when folded": .hf-fx-preset-run-count at :767, {run.items.length}.
  • "Whole-preset controls stay reachable while folded": {collapsed ? null : rows} gates only the inner rows; the toggle+×+FxParamRow sit outside → asserted by test :1770.
  • "Every stack ends in a generic keyword, at least two fallbacks": test :1293-1305 — pattern /(sans-serif|serif|monospace|fantasy|cursive|ui-monospace)\s*$/ + .split(",").length > 2.
  • "Every hue ≥20° clear of the accent (160)": test :1334-1342, min circular distance.
  • "Backgrounds derived, not picked": fxTintWash at propertyPanelFxPresetStyle.ts:1605-1615 — preserves hue, snaps to 22%, 11%. Character-family bg uniqueness test :1362-1364.
  • "Decimal HSL support (fxFamilyTint emits 62.0%)": regex \d+(?:\.\d+)? at :1609 + explicit test :1385. Real bug this fix caught.

OLD-assumption counterfactuals (per new test):

  • audioFxGraph.test.ts "rebuilds…across preset boundary" — OLD shapeOf lacked %${fromPreset}, so type-identical reorder took update path → .update()===true where new expects false.
  • "gives every run its own blend" — OLD presetTargets[p.id] = mixTargets(...) overwrote; split preset yielded 2 params where new (??= []; push) yields 4.
  • "amount into each run of a split preset" — OLD presets.find(p => p.id === run.preset) returned first wrap only; second leg stays full-strength → wets≠0 or drys≠1.
  • audioFxCopy.test.ts 4× SPEECH audits — fail under old "Thins the voice out", "Some words are much louder", "Cuts quiet words too", "chest", "the body of a voice", "consonants, intelligibility". Non-vacuity guard at :198.
  • audioFxJobs.test.ts — fails under "Too much chest" / "Words are hard to make out".
  • audioFxProfiles.test.ts piecewise round-trip — OLD linear inverse: 0.5 in → size 0.55 stored → 0.46 back. New tolerance 0.01 (was toBeCloseTo(s, 1) = 0.05) catches it; explicit params.size === 0.55 pin at :501.
  • media.test.ts — OLD [^;)] stopped at ) closing fadeTime(2); new depth-counted scan crosses it. Test asserts finding IS raised for { duration: fadeTime(2), volume: 0.2 }.
  • propertyPanelAudioFxGroup.test.tsx "levels the clip window" — OLD levellingResult(chain, audio.samples, …) measured file 0-8s (mostly loud); new slices via media-start=2, duration=6 and t=0.5 sits in quiet zone. OLD → v < 4.
  • "removes every lane a preset owned" — OLD per-node loop, last-write-wins; n1.frequency would survive. Also the fx.preset.telephone lane test — OLD never touched it.
  • propertyPanelFxSection.test.tsx "drops voice shelf on music/sfx" — OLD had no trackKind prop wired; Voice family always present.
  • Fold tests — OLD had no .hf-fx-preset-run-caret/count/toggle structure; label was a <span>, not a button with aria-expanded.
  • Title-treatment test — OLD .hf-fx-preset-run-label had font-mono text-[9px] uniformly.

Cross-PR coupling:

  • vs #3184 audioFxCopy: doofus-worble entry added to PRESET_PROBLEM (audioFxCopy.ts:328); coverage test at audioFxCopy.test.ts:41 (!PRESET_PROBLEM[p.id]) would catch a missing entry. Wired cleanly.
  • vs #3187 family lettering: preset title design is orthogonal — family tint is unchanged; carve module imports the shared fxTintWash (new) alongside fxFamilyTint. Nests cleanly.
  • vs #3189 preset off/ramp: removeRun(items, presetId) now clears the fx.preset.<id> lane in the same batched write — direct improvement to #3189's amount-lane hygiene (test at group.test.tsx:731). Fold state does NOT hide the on/off toggle or the amount FxParamRow — verified by test at section.test.tsx:1770.
  • Scope-contained: yes. The +1433/-130 breaks down as fold+title (studio ~500), Doofus Worble preset (core ~15), character-preset resonance rebalance (~50), seven-defects fix (core ~50 + studio ~50), copy audit (core ~30), voice-hide-on-music (~30), WCAG panel-text-4→2 (~40 across 6 files), docs (~250). Each commit has an isolated falsifying test.

Nits:

  • runKey = ${preset}-${firstIndex}: index is stable across a reorder that preserves the split's first slot, but a preset split→remerge→resplit sequence could reuse a key across topologically different runs. Not a bug for the reachable UI paths, but worth noting if fold-state ever gains persistence.
  • The new SPEECH audit tests overlap in shape across audioFxCopy/Jobs/Profiles (nearly identical regex/loop). A shared helper would cut duplication.
  • fxTintWash returns hsl(H, 22%, 11%) with literal 22/11; if the wash ever needs tuning per-family, the two magic numbers become the extension seam.

— Review by tai (pr-review)

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: feat(studio): fold a preset shut, and give each one its own title design — #3191

Verdict: LGTM

The biggest PR in the batch at 1433 lines, bundling ~10 concerns (fold/title, graph boundary fix, copy de-voicing, profile inverse fix, lint paren-depth fix, leveller clip-window fix, preset removal orphan fix, shelf hiding, new preset, preset retuning, skill doc). Each is well-done individually.

Fold state is clean. useState<ReadonlySet<string>> in FxSection, keyed by preset id + first node index. Functional updater avoids stale closures. Rendering skips children via conditional null (not CSS hiding). Controls remain reachable while folded (tested).

Title design per preset is excellent. propertyPanelFxPresetStyle.ts maps each preset id to {type, color, family} with a FX_PRESET_STYLE_DEFAULT fallback. fxTintWash derives background from title color (same hue, 22% sat, 11% lightness) — eliminates the class of bug where hand-picked pairs clash. Test coverage is genuinely impressive: catalog completeness (bidirectional), character uniqueness, font stack validity, size bounds, color vibrancy/contrast, hue distance from accent, background derivation consistency.

Two findings worth noting:

  1. presets.md skill doc ships stale copy. Lines 2267-2269 say "Weight": "chest, body, warmth" but audioFxCopy.ts in this same PR changed those to "body, warmth, low end". The doc contradicts the de-voicing it sits next to.

  2. wrapIndex walk in audioFxGraph.ts introduces an implicit contract: the presets array and preset runs from enabledAudioFxNodes(next) must be in the same order. If they ever diverge, all subsequent wraps silently apply to the wrong runs. The architecture enforces this today, but a comment naming the invariant would make the coupling visible.

PR scope observation: the graph boundary fix is a subtle correctness change to shapeOf()/buildFxChain() that deserves its own review focus. Mixing it with copy changes, retuning, a new preset, a lint fix, AND the fold/title feature makes bisection harder if any regresses.


Review by Miga

🤖 Generated with Claude Code

@vanceingalls
vanceingalls force-pushed the wa-20d6-preset-design branch from 7443ac2 to 86d8d5d Compare August 12, 2026 02:57
@vanceingalls
vanceingalls force-pushed the wa-20d5b-audition-fixes branch from 7eb2dcb to 3972215 Compare August 12, 2026 02:57
@vanceingalls
vanceingalls force-pushed the wa-20d6-preset-design branch from 86d8d5d to eca1927 Compare August 12, 2026 04:49
@vanceingalls
vanceingalls force-pushed the wa-20d5b-audition-fixes branch from 3972215 to 0a6bf88 Compare August 12, 2026 04:49
@vanceingalls
vanceingalls force-pushed the wa-20d6-preset-design branch from eca1927 to f33ed99 Compare August 12, 2026 07:26
@vanceingalls
vanceingalls force-pushed the wa-20d5b-audition-fixes branch from 0a6bf88 to 788bf68 Compare August 12, 2026 07:27
@vanceingalls
vanceingalls force-pushed the wa-20d6-preset-design branch from f33ed99 to 9d69919 Compare August 12, 2026 07:50
@vanceingalls
vanceingalls force-pushed the wa-20d5b-audition-fixes branch from 788bf68 to 890c0fd Compare August 12, 2026 07:50
# Conflicts:
#	packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx
#	packages/studio/src/components/editor/propertyPanelAudioFxGroup.tsx
#	packages/studio/src/components/editor/propertyPanelFxSection.tsx
#	skills-manifest.json
#	skills/hyperframes-audio/SKILL.md
#	skills/hyperframes-audio/references/attributes.md
#	skills/hyperframes-audio/scripts/carve.mjs
Base automatically changed from wa-20d5b-audition-fixes to main August 13, 2026 20:07
@github-actions

Copy link
Copy Markdown

Fallow audit report

Found 29 findings.

Duplication (20)
Severity Rule Location Description
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:160 Code clone group 1 (10 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:204 Code clone group 1 (10 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:368 Code clone group 2 (6 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:372 Code clone group 3 (12 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:394 Code clone group 2 (6 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:452 Code clone group 3 (12 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:689 Code clone group 4 (8 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:729 Code clone group 4 (8 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:780 Code clone group 5 (6 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:850 Code clone group 5 (6 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:967 Code clone group 6 (15 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:980 Code clone group 7 (15 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:997 Code clone group 6 (15 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:1010 Code clone group 7 (15 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:1178 Code clone group 8 (7 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:1186 Code clone group 8 (7 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:1359 Code clone group 9 (6 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:1517 Code clone group 9 (6 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:1661 Code clone group 10 (11 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/components/editor/propertyPanelAudioFxGroup.test.tsx:1716 Code clone group 10 (11 lines, 2 instances)
Health (9)
Severity Rule Location Description
major fallow/high-crap-score packages/studio/src/components/editor/propertyPanelAudioFxGroup.tsx:234 'setCarve' has CRAP score 97.0 (threshold: 30.0, cyclomatic 19)
minor fallow/high-crap-score packages/studio/src/components/editor/propertyPanelAudioFxGroup.tsx:323 'carvedAgainstBy' has CRAP score 37.1 (threshold: 30.0, cyclomatic 11)
minor fallow/high-crap-score packages/studio/src/components/editor/propertyPanelAudioFxGroup.tsx:580 'clipWindow' has CRAP score 37.1 (threshold: 30.0, cyclomatic 11)
minor fallow/high-crap-score packages/studio/src/components/editor/propertyPanelAudioFxGroup.tsx:676 'auditionLevel' has CRAP score 43.1 (threshold: 30.0, cyclomatic 12)
critical fallow/high-crap-score packages/studio/src/components/editor/propertyPanelAudioFxGroup.tsx:723 'analyse' has CRAP score 148.4 (threshold: 30.0, cyclomatic 24)
critical fallow/high-complexity packages/studio/src/components/editor/propertyPanelFxCarveModule.tsx:142 'FxCarveModule' has cyclomatic complexity 25 (threshold: 20) and cognitive complexity 45 (threshold: 15)
major fallow/high-crap-score packages/studio/src/components/editor/propertyPanelFxNodeRow.tsx:305 'FxNodeRow' has CRAP score 36.7 (threshold: 30.0, cyclomatic 33)
major fallow/high-complexity packages/studio/src/components/editor/propertyPanelFxSection.tsx:160 'FxSection' has cyclomatic complexity 21 (threshold: 20) and cognitive complexity 31 (threshold: 15)
critical fallow/high-crap-score packages/studio/src/components/editor/propertyPanelFxSection.tsx:640 '<arrow>' has CRAP score 184.5 (threshold: 30.0, cyclomatic 27)

Generated by fallow.

@vanceingalls
vanceingalls merged commit e3ec48a into main Aug 13, 2026
56 of 58 checks passed
@vanceingalls
vanceingalls deleted the wa-20d6-preset-design branch August 13, 2026 20:53
vanceingalls added a commit that referenced this pull request Aug 13, 2026
# Conflicts:
#	packages/core/src/audio/audioFxGraph.ts
#	packages/studio/src/components/editor/propertyPanelAudioFxGroup.tsx
#	packages/studio/src/components/editor/propertyPanelFxNodeRow.tsx
#	packages/studio/src/components/editor/propertyPanelFxPresetMenu.tsx
#	packages/studio/src/components/editor/propertyPanelFxSection.tsx
#	packages/studio/src/player/components/TimelineTrackRow.tsx
#	plans/audio-automation-lanes/SPEC.md
#	plans/audio-fx-presets.md
#	plans/audio-fx-ux/README.md
#	skills-manifest.json
#	skills/hyperframes-audio/SKILL.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants