Devlog: Building a React Music Player in a Day
Development Log

Devlog: Building a React Music Player in a Day

By Bill W.
2025-09-23
5 min read
React
TypeScript
UI/UX
Web Audio
State Management

Kickoff: Planning, Research, and Asset Preparation

Every feature begins with a plan. The day started by laying the groundwork for the new music player. Before writing a single line of component code, I focused on two key areas: creating the content and understanding the technical constraints. The first commit of the day wasn't code for the player itself, but a script to process the metadata for our debut album, 'Endless Drifting'. This ensured we had content ready to go.

commit 2141c8c
Author: Bill <bill@gameology.com>
Date:   Tue Sep 23 2025 15:00:00 GMT-0700 (PDT)

    Add "Endless Drifting" album metadata and duration calculation script

Next, I moved to the production environment, working within a Digital Audio Workstation (DAW) to mix and prepare the tracks. This hands-on work with the audio assets was crucial for understanding the data I'd need to manage in the application state.

With assets in hand, I researched the best practices for web audio. A major concern was browser autoplay policies, which are notoriously strict. I used Google Gemini to investigate the latest standards and compare the pros and cons of different audio formats, settling on a strategy of using M4A for modern browsers with an MP3 fallback.

Core Architecture: Building the Foundation with React Context and Hooks

With the planning phase complete, I formalized the architecture in a development plan document. This plan, captured in commit `15bf98d`, outlined the phased implementation, starting with core infrastructure and UI components.

The foundation of the player was built using modern React state management. I opted for React Context combined with custom hooks (`useMusicPlayer`) to create a centralized, easy-to-access state for the currently playing track, volume, and playback status. This avoids prop-drilling and keeps the component logic clean. This core implementation was landed in commit `5bbfe88`.

// A glimpse into the type definitions from the development process
interface MusicState {
  currentAlbumId: string | null;
  currentTrackId: string | null;
  playbackState: 'playing' | 'paused' | 'stopped';
  volume: number;
}

// Abstracting logic into a custom hook
const useMusicPlayer = () => {
  const context = useContext(MusicPlayerContext);
  // ... logic to handle play, pause, skip ...
  return context;
};

UI Implementation and User Experience

With the backend logic in place, I focused on the user-facing components. I developed a `MusicDrawer` and `MusicToggleButton` to give users intuitive control over the player. A key component was the `MusicDiscoveryToast`, which elegantly handles the browser's autoplay restrictions by prompting users for interaction first. This was a direct result of the earlier research phase.

Of course, development is never without its hurdles. While testing the autoplay flow, I ran into the classic `AudioContext.resume() failed` error, which happens when you try to play audio before a user has clicked or tapped anywhere on the page. This confirmed the necessity of the toast component for a good user experience.

After several iterations and enhancements to the UI and the underlying `MusicService`, the player was looking and feeling great. The final UI is minimalist, focusing on the essential controls and letting the music take center stage.

Mission Complete: Merging the 'secretsauce' Branch

After a full day of planning, asset creation, implementation, and debugging, the feature was complete. All the work, which had been developed on the `secretsauce` feature branch, was ready for integration. The final action of the day was merging Pull Request #4, officially bringing the new music player into the main codebase.

This was a great example of a feature development cycle from start to finish. It's rewarding to see an idea go from a development plan and a DAW session to a fully functional and integrated part of the application in a single day.

Discussion

0 comments