Skip to content

Gate audio controls to desktop only via DesktopAudioControl - #45

Merged
MrZoller merged 2 commits into
mainfrom
claude/sleepy-cannon-87wml8
Jun 21, 2026
Merged

MrZoller merged 2 commits into
mainfrom
claude/sleepy-cannon-87wml8

Conversation

@MrZoller

Copy link
Copy Markdown
Owner

Summary

Audio playback is a desktop-only enrichment in Wavefront — mobile browsers' autoplay and gesture rules make a single "hear it" tap unreliable, leaving users with a dead button that reads as broken. This PR introduces a <DesktopAudioControl> wrapper that suppresses audio controls below the lg breakpoint, ensuring the affordance only appears where it can deliver.

Changes

  • New component: src/audio/DesktopAudioControl.tsx — A simple gate that renders its children on lg+ and returns null below lg, keyed off the same breakpoint as the overlay-drawer layout (useIsCompactViewport). On desktop, it wraps the control in a Fragment, leaving layout and behavior untouched. Audio hooks build their AudioContext lazily on button press, so a hidden button never initializes audio — nothing audio-related runs on mobile.

  • New test: src/audio/DesktopAudioControl.test.tsx — Verifies the component renders on desktop and suppresses on mobile. Includes a structural guard that scans all modules in src/modules/ to enforce that every module using a Web Audio playback hook (@/audio/use*) also gates it through <DesktopAudioControl>. This prevents future audio modules from reintroducing a dead mobile button by forgetting the gate.

  • Updated three modules to wrap their audio controls:

    • src/modules/signal-chain-sdr/quantization/QuantizationModule.tsx
    • src/modules/direction-finding/rotating-phasor/PhasorModule.tsx
    • src/modules/modulations-and-waveforms/analog/AnalogModule.tsx

Implementation notes

  • The gate is visibility-only: suppression happens at render time, not via CSS display: none, so the control is never mounted on mobile and audio initialization never runs.
  • The test enforces the pattern by construction — any new audio module that forgets the gate will fail CI, making the rule unignorable.
  • Desktop layout and behavior are completely unchanged; the wrapper is transparent on lg+.

https://claude.ai/code/session_01H3H6X9cPYBPSp7pVFQMNca

Audio is a desktop-only enrichment. Mobile browsers gate the Web Audio API
behind autoplay/gesture rules (and a suspended AudioContext) that a single
"hear it" tap can't reliably satisfy, so on a phone the control taps to silence
— a dead button that reads as broken. Rather than chase per-device resume hacks,
don't offer the affordance where it can't deliver: the visuals carry each module
on mobile, and audio stays a desktop feature.

Add one shared gate, <DesktopAudioControl>, keyed off the same `lg` breakpoint
the overlay-drawer layout uses (useIsCompactViewport), and route the three audio
buttons (rotating phasor, analog modulation, quantization) through it. On desktop
the gate renders a Fragment, leaving the button a direct child of its flex row
exactly as before — desktop layout and behavior are untouched. Below `lg` it
renders nothing, and the flex gap collapses cleanly (no orphaned spacing). The
audio hooks build their AudioContext lazily on the button press, so a hidden
button never initializes audio — nothing audio-related runs on mobile.

A guard test scans the modules and fails if one triggers Web Audio without
routing through the gate, the way <Slider> guards against raw range inputs — so a
new audio module can't reintroduce a dead mobile button by forgetting to.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3H6X9cPYBPSp7pVFQMNca

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 26d6683ea0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/audio/DesktopAudioControl.tsx
Hiding the trigger wasn't enough. If a listener starts audio on desktop and then
crosses below `lg` — dragging the window narrow, rotating a tablet, split-screen
— the gate unmounted only the button, while the audio hook lives on in the parent
module and keeps the oscillator/buffer running. The result: sound with no visible
way to stop it until the viewport grows again or the module unmounts.

Keep "no control" and "no sound" in lockstep. <DesktopAudioControl> gains an
optional onSuppress callback and fires it as it crosses into compact; each module
passes its audio stop (the rotating phasor also clears its local playing flag so
the button reads correctly if the viewport grows back). Desktop is still
untouched — onSuppress only fires on the transition into compact, never at `lg+`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3H6X9cPYBPSp7pVFQMNca
@MrZoller
MrZoller merged commit 1c3e0cd into main Jun 21, 2026
2 checks passed
@MrZoller
MrZoller deleted the claude/sleepy-cannon-87wml8 branch June 21, 2026 19:03
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.

2 participants