Skip to content

Play soundtrack tracks and Sound picker previews through a scrubbable waveform - #31

Merged
davior merged 1 commit into
mainfrom
claude/sweet-newton-gqcfag
Oct 29, 2026
Merged

davior merged 1 commit into
mainfrom
claude/sweet-newton-gqcfag

Conversation

@davior

@davior davior commented Oct 29, 2026

Copy link
Copy Markdown
Owner

What

The two places GVC plays audio now use a waveform you can click or drag to seek, with a play/pause button and a time readout, instead of the plain <audio controls>:

  • each card on the Soundtrack tab, as a compact 32 px strip;
  • the preview of a picked hit in the Sound picker.

How

Frontend. WaveformPlayer is GAM's player from davior/gam#54, ported without the clip window and outside control that only GAM needs.

  • The <audio> element is still the player, minus its native controls, and wavesurfer.js draws over it.
  • wavesurfer always gets peaks: GAM's, or a flat placeholder until they arrive. It is never left to download and decode the file itself.
  • Colours follow the light/dark theme and redraw when it changes. GAM's player always sits on a dark well; GVC's sit in cards.
  • Soundtrack cards keep preload="none". GAM's measured duration fills the readout and makes the waveform scrubbable before the audio has loaded.
  • Keyboard: the waveform is a slider. ←/→ seek ±5 s and Space plays or pauses.

Backend. GET /api/gam/assets/{id}/peaks proxies GAM's cached waveform as the signed-in user, like every other GAM read, so CORS and GAM-5 aren't involved.

  • The call gets a 120 s timeout rather than the default 30 s, because GAM decodes a long recording on its first view (about 21 s for an hour in testing).
  • A GAM with no waveform for the asset gives a 422 waveform_unavailable, and the player keeps a flat line that still scrubs. This includes a GAM older than gam#54, which answers 404.
  • GAM's own failures still come through as gam_unavailable / gam_rejected_session.

Recorded as GAM-9 (done) in docs/plan-of-attack.md.

Testing

  • pytest -q: 758 passed. New tests in test_gam_api.py cover peaks passed through with the caller's token, a GAM 422 or 404 giving waveform_unavailable, and a GAM 5xx giving gam_unavailable.
  • npm test: 199 passed. The new WaveformPlayer.test.tsx covers:
    • GAM's peaks drawn over the page's <audio>;
    • the flat placeholder, then the swap, and the fallback when there are no peaks;
    • the duration taken from the waveform before the audio loads;
    • play/pause, arrow keys, and the theme redraw.
      The existing Soundtrack and picker tests stub the peaks call. lint, Prettier and build are clean.
  • Driven in Chromium against GAM on :8001 and GVC on :8002/:5175:
    • a soundtrack card, in light and in dark, shows 0:00 / 0:40 before any audio has loaded;
    • a click at 75% seeks to 30 s, and Play carries on from there;
    • the picker preview seeks to the midpoint on a click;
    • the <audio> src is never reset, and wavesurfer makes no media fetches.

Generated by Claude Code

… waveform

The two places GVC plays audio, each soundtrack card and the Sound
picker's preview, now use a waveform you can click or drag to seek, with
a play/pause button and a time readout, in place of <audio controls>.
WaveformPlayer is GAM's player (davior/gam#54), ported without what only
GAM needs, with colours that follow the light/dark theme, and with a
compact size for the soundtrack cards.

The peaks come from GAM, which already computes and caches them, through
a new GET /api/gam/assets/{id}/peaks proxy as the signed-in user, like
every other GAM read. That call gets a 120 s timeout, because GAM decodes
a long recording on its first view. A GAM that has no waveform (including
one older than gam#54) gives a 422, and the player scrubs on a flat line.

Soundtrack cards still don't load their audio until played. GAM's
measured duration fills the readout and makes the waveform scrubbable
before then. Recorded as GAM-9 in the plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1geD3VLg4aqTvHVuRLA53
@davior
davior marked this pull request as ready for review October 29, 2026 01:50
@davior
davior merged commit d74b2a0 into main Oct 29, 2026
3 checks passed
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