Port the web sound-wave recording bar to the mobile composer - #2034
Conversation
The mobile voice bar showed a red dot, a label, and a timer. The web VoiceRecordingBar shows live scrolling sound-wave bars. This ports that waveform to React Native (expo-audio metering → an SVG path) and matches the web layout: cancel · waveform · confirm, with the bars frozen and breathing while transcribing. Co-Authored-By: Claude <noreply@anthropic.com>
| opacity.set(withTiming(1, { duration: 150 })); | ||
| return; | ||
| } | ||
| opacity.set( |
There was a problem hiding this comment.
🚨 slopcop/review — Respect the system Reduce Motion setting.
The waveform stops under Reduce Motion, but this infinite opacity loop still runs during transcription.
The web source also disables its shine animation under prefers-reduced-motion.
Use useReducedMotion() here, and keep opacity at 1 when the setting is active.
There was a problem hiding this comment.
🚨 SLOP COP 🚨 · review
Plain English summary: This pull request replaces the mobile recording timer with a live sound-wave display. The display freezes during transcription.
I found one medium issue. The transcription breath animation ignores the user's Reduce Motion setting. I left an inline comment on the animation.
I found no security or privacy issue. Microphone permission, audio upload, cancellation, data storage, and SVG input stay within existing boundaries.
The 33 ms sample loop has bounded work and correct cleanup. I found no other performance or resource problem.
The mobile model repeats waveform constants and RMS shaping code from the web app. A future refactor can move that neutral math into @bb/core-ui.
The canvas, SVG, Expo metering, and audio-source code must stay in their platform apps. I do not consider the duplication a merge blocker.
Validation passed:
- The mobile typecheck passed.
- The mobile lint task passed.
- All 821 mobile tests passed across 120 files.
- The iOS Expo bundle completed with 8,777 modules.
- All current GitHub checks passed. GitHub skipped the iOS simulator flow.
I could not run a native end-to-end flow. The simulator had no BB app, and Maestro was not installed.
Doobie controls browser documents and cannot control this React Native view. The new showcase exists only in the native UI gallery.
What was wrong
The mobile composer's voice bar (
apps/mobile/src/composer/VoiceBar.tsx) showed a red dot, a "Listening…" label, and an elapsed timer. It gave no live audio feedback and did not look like the webVoiceRecordingBar, which draws scrolling sound-wave bars from the microphone level.What changed
apps/mobile/src/composer/voice-waveform-model.ts(new): pure port of the webWaveformVisualizermath.meteringToAmplitudeconverts expo-audio metering (dBFS) to a bar amplitude with the same noise floor, gain, and gamma as the web RMS path; plus the scrolling bar buffer and the SVG path builder.apps/mobile/src/composer/VoiceWaveform.tsx(new): draws the bars as onereact-native-svgpath (3px bars, 2px gaps, round caps, newest at the right, oldest fading on the left via a gradient stroke). SamplesreadLevel()at ~30 Hz while active, freezes when inactive, shows flat idle bars under reduce-motion.apps/mobile/src/composer/VoiceBar.tsx: web layout — round ghost cancel · waveform · round primary confirm. While transcribing the bars freeze and breathe (theanimate-shine-iconstand-in) and the confirm button shows a spinner.apps/mobile/src/composer/useComposerVoice.ts: records withisMeteringEnabled: trueand exposesreadLevel(); the elapsed-seconds ticker is removed.apps/mobile/app/dev/ui.tsx: a "Voice bar (synthetic levels)" gallery section so the bar can be exercised without a mic.No wire changes.
How you verified
voice-waveform-model.test.ts(dB mapping floor/clamp/monotonic, scroll buffer, path geometry).pnpm exec turbo run test typecheck lint --filter=@bb/mobilepass.Fixes #