Sora UI
Media

Skeuomorphic Music Player

A skeuomorphic CD player featuring an animated rotating vinyl/CD, custom audio seeking, animated sound waves, and a morphing fullscreen track-transition animation.

Mavka
Forest Song
0:00/0:00

Playground Config

This playground passes values directly as props to the player, making the component pure, clean, and copy-paste friendly for v0.app.
Get a temporary token from the Spotify Web Console.
Timeline Color
#5e6ad2
Component BG
#0f1011
Volume
80%
Speed
Loop Playlist

Installation

Option A: Via Sora UI CLI (Recommended)

If your project uses `shadcn/ui`, you can install this component and its dependencies automatically:

npx soraui-cli add music-player

Option B: Manual Copy-Paste

1. Copy the code from the Code > Component tab above.
2. Paste it in your project at components/music-player.tsx.
3. Install the dependencies:
npm install framer-motion lucide-react clsx tailwind-merge

API Reference

All customization is done through standard React props. No internal state management, no context providers — just pass the props you need and the component handles the rest.

PropTypeDefaultDescription
spotifyTokenstringSpotify Web API Bearer Token. Used to fetch track metadata and album art. Get one from the Spotify Developer Dashboard.
trackIdsstring[]Array of Spotify Track IDs. Each track's name, artist, cover art, and 30s audio preview will be fetched. Falls back to built-in demo tracks when omitted.
timelineColorstring"#5e6ad2"Hex color for the progress bar fill. Changes the seek timeline accent to match your brand.
componentColorstring"#0f1011"Hex color for the player card background. Controls the overall body color of the skeuomorphic shell.
titleOverridestringOverride the displayed song title. When set, this text replaces the track name fetched from Spotify.
artistOverridestringOverride the displayed artist name. When set, this text replaces the artist fetched from Spotify.
defaultVolumenumber80Initial audio volume from 0 to 100. Maps directly to HTMLAudioElement.volume.
playbackSpeednumber1.0Audio playback rate multiplier. Supports 0.5, 1.0, 1.5, and 2.0.
loopbooleantrueWhen true, the playlist loops back to the first track after the last one ends. When false, playback stops after the final track.

🎵 Spotify Integration

The player fetches track names, artist names, album cover art (used as the spinning CD banner), and 30-second audio previews directly from the Spotify Web API.

1

Create a Spotify App

Go to developer.spotify.com/dashboard → Create App → Copy your Client ID and Client Secret.

2

Get an Access Token

Exchange your credentials for a Bearer token using the included server-side API route /api/spotify/token or your own backend. See the code example below.

3

Pass the token and track IDs

Pass the token as spotifyToken and your chosen track IDs as trackIds. The component will auto-fetch all metadata.

Token Exchange Route
// app/api/spotify/token/route.ts  (included in Sora UI)
//
// POST { clientId, clientSecret }
// Returns { access_token, expires_in }

async function getSpotifyToken() {
  const res = await fetch("/api/spotify/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      clientId: "YOUR_CLIENT_ID",
      clientSecret: "YOUR_CLIENT_SECRET",
    }),
  });
  const { access_token } = await res.json();
  return access_token;
}
Spotify Usage
import { MusicPlayer } from "@/components/ui/music-player";

// 1. Get your Spotify credentials:
//    → https://developer.spotify.com/dashboard
//    → Create an app → Copy Client ID & Secret
//
// 2. Exchange credentials for an Access Token
//    (use our included API route or your own backend):

const SPOTIFY_TOKEN = "BQDj7g0...your_token_here";

const MY_TRACKS = [
  "0V3wPSX3ygHQwZ21K47gOO",   // Shape of You
  "7qiZRhU7tZ2XG6xBvDUz6r",   // Blinding Lights
  "5PjdY0CKDHMDzPyvl44df6",    // Levitating
];

export default function SpotifyPlayer() {
  return (
    <MusicPlayer
      spotifyToken={SPOTIFY_TOKEN}
      trackIds={MY_TRACKS}
    />
  );
}
⚠️ Note:Spotify's free API tier only provides 30-second audio previews. Full-length playback requires Spotify Premium + OAuth user authorization. The CD banner (album art) is always available.

Customization Examples

Progress Timeline Color

Change the seek bar accent with any hex color value. Great for matching your app's brand palette.

// Pink progress bar
<MusicPlayer timelineColor="#ec4899" />

// Green neon progress bar
<MusicPlayer timelineColor="#22c55e" />

// Orange warm progress bar
<MusicPlayer timelineColor="#f97316" />

Component Background Color

Customize the skeuomorphic card body. Supports hex and rgba for glass-like transparency effects.

// Deep navy shell
<MusicPlayer componentColor="#0a1628" />

// Warm charcoal
<MusicPlayer componentColor="#1c1917" />

// Transparent glass (pair with backdrop-blur)
<MusicPlayer componentColor="rgba(15, 16, 17, 0.6)" />

🔁 Playlist: Loop vs Static

Control whether the playlist loops continuously or stops after the last track. Perfect for background music vs. curated listening.

// Loop mode — restarts playlist after last track
<MusicPlayer
  spotifyToken={token}
  trackIds={["id1", "id2", "id3"]}
  loop={true}
/>

// Static mode — stops after the last track finishes
<MusicPlayer
  spotifyToken={token}
  trackIds={["id1", "id2", "id3"]}
  loop={false}
/>

🔊 Volume & Playback Speed

Set the initial volume (0–100) and speed multiplier (0.5x, 1.0x, 1.5x, 2.0x). Both map directly to the HTML Audio API.

// Quiet background music at half speed
<MusicPlayer
  defaultVolume={30}
  playbackSpeed={0.5}
/>

// Full volume, double speed
<MusicPlayer
  defaultVolume={100}
  playbackSpeed={2.0}
/>

✏️ Song Name & Artist Override

Override the displayed track title and artist name. Useful for custom branding or when you want a fixed label regardless of which track is playing.

// Display a custom title and artist
<MusicPlayer
  titleOverride="My Custom Mix"
  artistOverride="DJ Sora"
/>

Full Kitchen Sink Example

Here's a complete example combining Spotify integration with every customization option:

Full Customization
import { MusicPlayer } from "@/components/ui/music-player";

const TOKEN = "BQDj7g0...";

export default function FullCustom() {
  return (
    <MusicPlayer
      spotifyToken={TOKEN}
      trackIds={[
        "0V3wPSX3ygHQwZ21K47gOO",
        "7qiZRhU7tZ2XG6xBvDUz6r",
        "5PjdY0CKDHMDzPyvl44df6",
      ]}
      timelineColor="#a855f7"
      componentColor="#0c0a12"
      defaultVolume={60}
      playbackSpeed={1.0}
      loop={true}
    />
  );
}

Dependencies

PackagePurpose
framer-motionCD spin animation, cover morph transitions, sound wave bars
clsx + tailwind-mergeConditional class name merging via the cn() utility
tailwindcssUtility-first CSS framework for all layout and styling
Install
npm install framer-motion clsx tailwind-merge