Skip to content

feat(studio): make the FX rack speak the author's language - #3159

Closed
vanceingalls wants to merge 4 commits into
wa-20b-fx-followupsfrom
wa-20c-rack-copy
Closed

feat(studio): make the FX rack speak the author's language#3159
vanceingalls wants to merge 4 commits into
wa-20b-fx-followupsfrom
wa-20c-rack-copy

Conversation

@vanceingalls

@vanceingalls vanceingalls commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Wires the plain-language layer that landed in core into the FX rack, to three
UX decisions recorded in plans/audio-fx-ux/README.md §Decided.

What the rack says now

The plain name replaces the DSP name; the DSP name moves inside. A module
reads "Remove Rumble" with "Cutting everything below 80 Hz" under it, and
opening it shows "Details — High-pass" above the knobs. Every knob is renamed
too — plainDef writes the copy over the registry's labels and hints while
leaving range, step, unit and automatability alone, because those are facts and
only the words were ever the problem. A preset's own job name still wins where
it has one: it is the most specific truth available.

Presets read as the complaint they answer. "My voice sounds boomy", with
Boom Tame underneath in small type — which is also how the name gets learned.
The four shelves stay: eighteen sentences in a column is a wall, and
Voice/Fix/Character/Space is already the author's grouping rather than the
registry's. The effect list is untouched and stays in signal order.

da5403026 fixes what that first pass broke: the rack was renamed and the
add menu was not, so an author picked "High-pass" and a module called "Remove
Rumble" appeared — the exact confusion this layer exists to remove,
reintroduced one gesture upstream of it.

Hover-audition

Hovering a preset or an offered effect plays it through the same preview channel
a slider drag already uses, so it costs no new machinery and never touches the
document. Four things have to hold, and each has a test that fails without
it:

  1. Leaving puts the stored chain back — captured when the audition starts,
    because the preview channel does not persist and the prop never changes.
  2. Applying does not put it back. The audition was the preset, and
    reverting over the write that just landed is a race the author hears as it
    arriving and then leaving again.
  3. The panel going away mid-audition reverts — but the teardown must have
    empty deps.
  4. Moving between two entries in a shelf is not leaving it.

3 and 4 were bugs in the first commit here, both found by review rather than
by tests, and 8639f3076 fixes them.
The teardown was keyed on
onChainPreview, an inline arrow from a component that re-renders on every
playhead tick — so the audition reverted itself about thirty times a second,
during playback, which is the only time there is anything to audition. And
sliding from "Even Out Levels" to the effect beside it kept a measurement
running that then landed on top of the audition next to it. Both are the kind a
static mount cannot see.

Even Out Levels auditions by measuring first — it decodes the track and
analyses it before there is anything to play, so it says "measuring…" while it
works, caches the decode per src, and a run counter drops any result that
arrives after the pointer has left. Reverting puts back both the chain and
the automation, because levelling is a node AND the lane that drives it.

Tone deliberately does not audition: its bands arrive at 0 dB, so there is
nothing to hear, and a hover that changes nothing teaches that hovering does
nothing.

Tests

studio 3685 + 18 todo. Tests that addressed rows by their registry labels now
look them up through EFFECT_COPY, and preset buttons by preset id — those
tests are about which row carries the automate button, not about how it reads,
and hard-coding the words would make every copy edit a test edit.

🤖 Generated with Claude Code

@vanceingalls vanceingalls changed the title wa 20c rack copy feat(studio): make the FX rack speak the author's language Aug 10, 2026
Wires `audioFxCopy` into the panel, to the three decisions recorded in
`plans/audio-fx-ux/README.md` §Decided.

**The plain name replaces the DSP name, which moves inside.** A module
reads "Remove Rumble" with "Cutting everything below 80 Hz" under it, and
opening it shows "Details — High-pass" above the knobs. Every knob is
renamed too — `plainDef` writes the copy over the registry's labels and
hints while leaving range, step, unit and automatability alone, because
those are facts and only the words were ever the problem. A preset's own
job name still wins where it has one: it is the most specific truth
available.

**Presets read as the complaint they answer.** "My voice sounds boomy",
with `Boom Tame` underneath in small type — which is also how the name
gets learned. The four shelves stay: eighteen sentences in a column is a
wall, and Voice/Fix/Character/Space is already the author's grouping
rather than the registry's. The effect list is untouched and stays in
signal order, per the same decision.

**Everything auditions on hover, and on focus — the keyboard reaches it
too.** Hovering a preset or an offered effect plays it through the same
preview channel a slider drag already uses, so it costs no new machinery
and never touches the document. Three things this has to get right, each
with a test that fails without it:

- Leaving puts the stored chain back — captured when the audition starts,
  because the preview channel does not persist and the prop never changes.
- Applying does NOT put it back. The audition *was* the preset, and
  reverting over the write that just landed is a race the author hears as
  it arriving and then leaving again.
- The panel going away mid-audition reverts too. Deselecting a clip is
  not a decision, and a preview left playing is audible, absent from the
  document, and gone on the next reload.

Tone does not audition: its bands arrive at 0 dB, so there is nothing to
hear, and a hover that changes nothing teaches that hovering does nothing.

**Even Out Levels auditions by measuring first**, which is the expensive
answer of the three — it decodes the track and analyses it before there
is anything to play. So it says "measuring…" while it works, the decode
is cached per `src` (a hover that re-fetched a several-minute voiceover
would be slower than the thing it previews), and a run counter drops any
result that arrives after the pointer has left. Reverting puts both the
chain and the automation back, because levelling is a node AND the lane
that drives it — restoring only the chain leaves an envelope writing to a
gain stage that is no longer there.

Tests that addressed rows by their registry labels now look them up
through `EFFECT_COPY`, and the preset buttons by preset id. Those tests
are about which row carries the automate button, not about how it reads,
and hard-coding the words would make every copy edit a test edit.

Falsified: dropping the phase of each of the three audition invariants
fails its own test, and removing the stale-run guard fails the levelling
one.

studio 3683 passing, 18 todo (was 3674); section file 510 lines, under the
600 cap.
Two bugs in the hover-audition that shipped in the commit before this,
both invisible to its tests because a static mount never re-renders and
never moves the pointer between two entries.

**It reverted itself about thirty times a second.** The teardown that
puts the chain back was keyed on `onChainPreview`, which the group passes
as an inline arrow — and the group re-renders on every playhead tick to
move the automation readouts. So React tore the effect down and re-ran it
on every tick, and each teardown saw an audition in progress and undid
it. The preset was heard for one frame and then silently reverted with
the pointer still on the button, during playback, which is the only time
there is anything to audition at all. The handler moves into a ref and
the effect gets empty deps, so it runs on teardown and at no other time.

**Moving to the effect beside it left a measurement in flight.** The
levelling audition was only called off by leaving the whole shelf, so
sliding from Even Out Levels to Reverb kept the decode running — and when
it finished it wrote a levelled version of the chain as it had been, on
top of the reverb being auditioned, through the channel the document
never sees. Exactly the failure the run counter was added to prevent, one
gesture to its left. Every entry in the shelf now calls its neighbours'
auditions off: the effects cancel levelling, levelling cancels the chain
audition, and Tone cancels both despite having none of its own.

The keyboard path was already right — `focusout` bubbles, so a move
within the menu fires the shelf's own handler. Only the mouse leaked.

Falsified: restoring the dep array fails the re-render test, and dropping
the effect buttons' cancel fails the sideways-move one.

studio 3685 passing, 18 todo.
@vanceingalls

Copy link
Copy Markdown
Collaborator Author

Superseded — replaced by a slice on the new chain to keep the stack linear after the split.

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.

1 participant