Overview
Beat App provides a full-featured music player with intuitive controls for managing your listening experience. The player bar is always accessible at the bottom of the app, giving you instant control over your music.
Player Controls
The player component (src/components/Player.jsx:23) provides comprehensive playback controls:
Play/Pause
Click the center play button to start or pause playback. The button shows a loading indicator while tracks are buffering. < IconButton
className = "play-btn-gradient"
aria-label = { isPlaying ? "pause" : "play" }
onClick = { playerActions . togglePause }
>
{ isLoading ? (
< CircularProgress size = { 24 } />
) : isPlaying ? (
< PauseRounded />
) : (
< PlayArrowRounded />
) }
</ IconButton >
Skip Tracks
Use the previous and next buttons to navigate through your queue: < IconButton onClick = { playerActions . playPrevious } >
< SkipPreviousRounded />
</ IconButton >
< IconButton onClick = { playerActions . playNext } >
< SkipNextRounded />
</ IconButton >
Seek Through Track
Drag the progress slider to jump to any position in the current track: < Slider
value = { parseInt ( currentTime * 5 ) }
max = { parseInt ( duration * 5 ) }
onChange = { ( _ , value ) => playerActions . seekTo ( value / 5 ) }
/>
Volume Control
Adjust playback volume using the volume slider on the right side of the player bar:
// Volume is synchronized with the audio element
useEffect (() => {
audioEl . volume = volume / 100 ;
}, [ volume ]);
// Mute/unmute functionality
useEffect (() => {
audioEl . muted = muted ;
}, [ muted ]);
Volume settings persist during your session. The mute button provides quick audio toggling without losing your volume level.
The player displays current track information including:
Album artwork thumbnail
Track title
Artist name
Like/unlike button
Current playback time
Total track duration
< div className = "track-info" >
< Box sx = { { width: 56 , height: 56 } } >
< img src = { ` ${ PROXY_URL }${ currentTrack . thumbnailUrl } ` } />
</ Box >
< Box >
< p > { currentTrack ?. title ?? "" } </ p >
< p > { currentTrack ?. artists [ 0 ]?. name ?? "" } </ p >
</ Box >
< IconButton onClick = { handleToggleLike } >
{ liked ? < FavoriteRounded /> : < FavoriteBorderRounded /> }
</ IconButton >
</ div >
Player State Management
The player uses a centralized store (src/stores/playerStore.js:33) to manage playback state:
const initialState = {
isPlaying: false ,
currentTrackIndex: - 1 ,
currentTrack: null ,
queue: [],
isLoading: false ,
currentTime: 0 ,
duration: 0 ,
isQueueOpen: false ,
};
Playing a Track
Tracks are played using the playTrack action which handles:
Setting the current track
Updating the queue (if provided)
Fetching the audio stream URL
Loading and playing the audio
playTrack : async ( track , newQueue = null ) => {
playerStore . setKey ( "currentTrack" , track );
playerStore . setKey ( "isLoading" , true );
if ( newQueue ) {
playerStore . setKey ( "queue" , newQueue );
}
const audioUrl = await getAudioUrl ( track . trackId );
audioEl . src = audioUrl ;
audioEl . play ();
}
Audio Event Handling
The player automatically responds to audio events:
Play/Pause
Loading States
Track Ended
Time Updates
audioEl . onplay = () => {
playerStore . setKey ( "isPlaying" , true );
};
audioEl . onpause = () => {
playerStore . setKey ( "isPlaying" , false );
};
audioEl . onplaying = () => {
playerStore . setKey ( "isLoading" , false );
};
audioEl . onwaiting = () => {
playerStore . setKey ( "isLoading" , true );
};
audioEl . onended = () => {
playerActions . playNext ();
};
audioEl . onloadedmetadata = () => {
playerStore . setKey ( "duration" , audioEl . duration );
};
audioEl . ontimeupdate = () => {
playerStore . setKey ( "currentTime" , audioEl . currentTime );
};
Recent Plays Tracking
Every track you play is automatically saved to your recent plays history:
// Automatically track when track changes
useEffect (() => {
if ( currentTrack ?. trackId ) {
addRecentPlay ( currentTrack ). catch (() => {});
}
}, [ currentTrack ?. trackId ]);
Recent plays are stored locally using IndexedDB and are available in your Library page under “Recently Played”.
Time Display
Track duration and current position are formatted for readability:
const secondsToTime = ( seconds ) => {
const totalSeconds = Math . floor ( seconds );
const hours = Math . floor ( totalSeconds / 3600 );
const minutes = Math . floor (( totalSeconds % 3600 ) / 60 );
const secs = totalSeconds % 60 ;
if ( hours > 0 ) {
return ` ${ hours } : ${ minutes . toString (). padStart ( 2 , "0" ) } : ${ secs . toString (). padStart ( 2 , "0" ) } ` ;
}
return ` ${ minutes } : ${ secs . toString (). padStart ( 2 , "0" ) } ` ;
};
Next Steps
Queue Management Learn how to manage your playback queue
Media Controls Control playback from your device’s media controls