Files
element-call-Github/FEATURES_SPEC/2026-09_Audio_Quick_Menu.notes.md
T
fkwpandClaude Opus 5 17ff9b1343 Add the audio quick menu feature spec
The spec, its product sidecar and its notes, as of the exploration branch
fkwp/feature/audio_quick_menu_exploration at 39d2ffbf where it reached status
implement, plus the drift log this implementation appended: the drift check
against a fresh main, the re-derived slicing plan, the owner's decision to
land the feature as one PR, and the findings from building it.

The commits that follow are its slices, in the order the plan gives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 23:53:36 +02:00

4.1 KiB

Audio quick menu — exploration notes

Not load-bearing. Nothing here constrains the implementation; constraints live in the feature spec.

Findings from the spike

  • The shared slider names itself after its tooltip. Slider wraps its thumb in a compound Tooltip, which sets aria-labelledby on the thumb and so overrides the label prop's aria-label. A screen reader announced the volume control as "50%". Worked around at the call site by putting the control's name into the tooltip text. The same defect exists in Settings → Audio today and would be better fixed in Slider itself.
  • Arrow keys inside the menu. The radix menu treats arrow keys as navigation between items, so a slider placed inside it never receives them. The slider row stops propagation for arrow/Home/End. Without this the slider is mouse-only, which would have failed AC20 silently.
  • jsdom gaps. The radix slider needs ResizeObserver and the meter needs AudioContext; neither exists in jsdom, so both are stubbed per test file rather than globally.
  • Snapshot churn. LobbyView and InCallView snapshots changed because the mic button is now wrapped in the chevron container in cases that previously rendered a bare button. Reviewed before updating; the change is the intended one.

Findings from design review

  • An invented design token fails silently. The meter's bars were written with --cpd-radius-pill-effective; the token is --cpd-radius-pill-effect. An unknown custom property makes the whole border-radius declaration invalid, so the bars rendered square with no error anywhere. Worth grepping for the token name before using one.

  • A sticky child paints over the menu's border. FloatingMenu draws its border as an outline inset by one border width rather than as a real border. A position: sticky child is positioned, so it paints above that outline and its opaque background covered the border at the left and right edges. Fixed with a matching inline margin on the sticky row.

  • The bar geometry has two coupled knobs. The bars share the row, so their width is whatever the gaps leave over: raising the gap thins them and raising the count thins them too. Moving both at once cancels out, which cost two review rounds. Across the inset row (~248px at the menu's 340px maximum):

    bars gap bar width bar:gap
    20 8px 4.8px 0.60
    18 8px 6.2px 0.78
    17 8px 7.1px 0.88
    16 8px 8.0px 1.00

    The design sits near 0.8, hence 18 bars at an 8px gap.

  • The bars line up with the label column, not the menu edge. A menu item keeps a 4x margin after its label plus a 2x column reserved for the chevron, on top of the menu's own 4x padding, so the meter's inline-end inset is 2 * 4x + 2x.

Still open with design

  • The mockup marks the active device with a radio circle; the menu marks it with a device icon and a checkmark, which is the existing pattern shared with the camera chevron. Changing it would either change the camera menu too or make the two inconsistent. Left as-is pending design sign-off.

Not done

  • Storybook interaction tests were not run; that project drives a real browser. AudioLevelMeter.stories.tsx covers the five meter states for visual review.
  • Sticky positioning, the focus border and the bar geometry are all unverified by tests: jsdom has no layout. The tests assert the DOM structure that makes them possible, and the rest was checked by eye in a browser.
  • No measurement of what the meter's second capture costs while a call is running. This is the main thing left before sign-off, and it is the decision most likely to be revisited: if the cost is material, D1 gets narrower.
  • oxfmt covers markdown, and AGENTS.md, _TEMPLATE.product.md and the product spec do not match its style, so pnpm format:check fails on them. Left alone: the product spec is not editable after draft and the other two are process documents. Either format them in a separate commit or exclude the folder from oxfmt.