Files
GMW/.hermes/plans/2026-08-22_voice-audio-playback-polish.md
T
asepharyana 4e0c21d86c feat(frontend): perbagus voice & audio playback UX
- Recordings: custom RecordingAudioPlayer (play/pause, buffering spinner,
  click-to-seek, time label, eq bars, single-playback antar kartu) +
  highlight kartu now-playing
- Media: thumbnail di disc hero + queue row, equalizer saat playing,
  badge 'up next', label Paused vs Now playing
- MiniPlayer global di AppFrame (fixed bottom-right, hidden on /media)
  menggantikan use-media-player.tsx dead provider (dihapus)
- Voice: mic level meter live (AnalyserNode RMS) + slider mic/listen volume
2026-08-22 12:53:18 +07:00

3.3 KiB

Spec: Perbagus fitur Voice + Audio Playback (GMW frontend)

Tanggal: 2026-08-22 · Scope: frontend only (backend/gateway API sudah cukup)

Masalah (audit)

  1. Recordings: semua kartu pakai <audio controls> native — tampilan identik, tidak ada indikasi which-clip-playing / loading / paused, dan N audio bisa play bareng (overlap).
  2. Media view: thumbnailUrl dari gateway tidak dipakai; tidak ada visual "sedang playing" selain disc spin; queue item semua sama tanpa badge up-next.
  3. Mini-player (lib/hooks/use-media-player.tsx) ada tapi TIDAK PERNAH dimount → dead code, user tidak lihat status musik di halaman lain.
  4. Voice page: useMicTransmit.setVolume + useVoiceListen.setVolume tersedia tapi tak ada UI-nya; mic live tidak punya level feedback.

Desain

A. RecordingAudioPlayer (baru, components/voice/recording-audio-player.tsx)

Custom player menggantikan <audio controls>:

  • Play/pause button (ikon berubah), spinner saat buffering (waiting event).
  • Progress bar seekable (click-to-seek) + time label m:ss / m:ss.
  • Waveform-ish equalizer bars saat playing (CSS animation, reduced-motion safe).
  • Single-playback: module-level registry activePlayers — memainkan satu clip otomatis pause yang lain.
  • Kartu pemilik player aktif dapat highlight border signal + "Now playing" chip.

B. Recordings view — pasang player baru

  • Ganti <audio><RecordingAudioPlayer src download_url>.
  • Highlight kartu via state lifted: playingId di view, callback onPlay.

C. Media view polish

  • Hero: thumbnail (jika current.thumbnailUrl) sebagai disc center image; fallback ListMusic icon. Equalizer bars animasi CSS saat playing.
  • Queue row pertama: badge "up next"; baris current track diberi ring signal.
  • Volume read-only tetap.

D. MiniPlayer global

  • Hapus lib/hooks/use-media-player.tsx (dead) — ganti dengan komponen components/media/mini-player.tsx yang subscribe useMediaState + useMediaWsSync langsung (SWR cache shared antar route), mounted di AppFrame bawah layar (fixed bottom, hidden di route /media).
  • Menampilkan: thumbnail kecil/judul, tombol skip/stop, link ke /media.

E. Voice UI

  • Mic live: level meter (Equalizer bars) — mic-transmitter sudah punya worklet; tambah getLevel() via AnalyserNode pada stream (simple RMS) di hook.
  • Listen: volume slider (input range) wired ke listen.setVolume.
  • Mic volume slider wired ke mic.setVolume.

File touched

File Aksi
services/frontend/src/components/voice/recording-audio-player.tsx new
services/frontend/src/app/(dashboard)/recordings/view.tsx edit
services/frontend/src/app/(dashboard)/media/view.tsx edit
services/frontend/src/components/media/mini-player.tsx new
services/frontend/src/components/shell/ambient-app.tsx mount MiniPlayer
services/frontend/src/lib/hooks/use-media-player.tsx delete
services/frontend/src/hooks/use-voice.ts tambah micLevel
services/frontend/src/lib/audio/mic-transmit.ts expose analyser level
services/frontend/src/app/(dashboard)/voice/view.tsx sliders + meter

Verifikasi

  1. pnpm lint (biome) + pnpm build clean.
  2. Smoke di port 4024 (BUKAN 4017) → curl 200 semua route.
  3. Commit (tanpa trailer) → push → gh run watch → live check https://imphnen.asepharyana.my.id/{media,recordings,voice}/ = 200.