A browser-based drum pad and metronome built with React. Play eight drum sounds via keyboard or mouse, record your performance, and replay it with accurate timing.
https://Gpiero19.github.io/Music-player/
- 8 drum pad keys mapped to keyboard shortcuts (A S D F H J K L)
- Metronome with adjustable BPM (40–240), visual running indicator
- Record a performance and replay it with the original timing
- Stores up to 5 recent recordings — persisted across page refreshes via localStorage
- Responsive layout — works on desktop and mobile
- Accessible: ARIA labels on all interactive controls, respects
prefers-reduced-motion
- React 19 — functional components with custom hooks (
useAudioPool,useRecording,useRecordingHistory,usePlayback,useMetronome) - TypeScript — strict mode, shared types across hooks and components
- Vite 7 — build tooling and dev server
- Web Audio API — per-key pools of 3
HTMLAudioElementobjects (round-robin) so rapid repeated hits on the same pad overlap correctly - localStorage — lightweight persistence for recordings and session counter
- Vitest + Testing Library — unit tests for hooks and components
- gh-pages — deployment to GitHub Pages
git clone https://github.com/Gpiero19/Music-player.git
cd Music-player
npm install
npm run devOpen http://localhost:5173 in your browser.
| Script | Description |
|---|---|
npm run dev |
Start the development server |
npm run build |
Build for production |
npm run type-check |
Run TypeScript type checking |
npm test |
Run the test suite |
npm run lint |
Run ESLint |
npm run deploy |
Build and deploy to GitHub Pages |
- Custom hooks — extracting
useAudioPool,useRecording,useRecordingHistory,usePlayback, anduseMetronomefrom a monolithic component to keep each hook focused on one concern and independently testable. - React hooks in practice — managing audio state, recording timers, and playback with
useRef,useCallback, anduseMemowithout unnecessary re-renders. - Audio performance — pre-creating a pool of 3
HTMLAudioElementobjects per pad at mount time, cycling through them round-robin so rapid repeated hits on the same pad play concurrently without audio cutting out. - Async playback with cancellation — driving a timed playback loop with
setTimeoutpromises and a ref-based abort flag so playback can be stopped mid-sequence. - localStorage persistence — serializing and restoring structured state (recording history) across sessions with safe JSON parsing.
- Accessibility — adding ARIA labels to non-descriptive controls and respecting the
prefers-reduced-motionmedia query for animations.
