# CMusic 3D Frontend Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Build a supermodern 3D-animated music website frontend with React Three Fiber, Framer Motion, GSAP, and Tailwind CSS — cyberpunk-luxury aesthetic.
**Architecture:** Single-page React app with distinct section components each managing their own 3D canvas (via R3F) or animation layer (Framer Motion / GSAP). A global `useAudioPlayer` hook drives the persistent player bar state. Stitch MCP generates base UI screens; Context7 provides accurate library API docs.
**Tech Stack:** React 18, Vite 5, Tailwind CSS 3, @react-three/fiber, @react-three/drei, Framer Motion, GSAP (+ ScrollTrigger), Stitch MCP (UI generation)
---
## File Map
```
/srv/CMusic/
├── index.html
├── vite.config.js
├── tailwind.config.js
├── postcss.config.js
├── package.json
└── src/
├── main.jsx
├── App.jsx
├── index.css # global styles, CSS vars
├── data/
│ └── mockData.js # tracks, albums, artists
├── hooks/
│ └── useAudioPlayer.js # global player state
└── components/
├── Navbar/
│ └── Navbar.jsx
├── Hero/
│ ├── Hero.jsx
│ ├── AudioVisualizer3D.jsx # R3F bar visualizer
│ └── HeroParticles.jsx # R3F floating particles
├── FeaturedAlbums/
│ ├── FeaturedAlbums.jsx
│ └── AlbumCard3D.jsx # R3F card with flip
├── TrendingTracks/
│ ├── TrendingTracks.jsx
│ └── TrackRow.jsx
├── ArtistSpotlight/
│ ├── ArtistSpotlight.jsx
│ └── ArtistParticles.jsx # R3F particle field
└── Player/
├── PlayerBar.jsx
└── Waveform3D.jsx # R3F animated waveform
```
---
## Task 1: Scaffold Project
**Files:**
- Create: `package.json`, `vite.config.js`, `tailwind.config.js`, `postcss.config.js`, `index.html`, `src/main.jsx`
- [ ] **Step 1: Init Vite React project**
```bash
cd /srv/CMusic
npm create vite@latest . -- --template react
```
- [ ] **Step 2: Install all dependencies**
```bash
npm install
npm install three @react-three/fiber @react-three/drei
npm install framer-motion gsap
npm install tailwindcss@3 postcss autoprefixer
npm install @types/three
npx tailwindcss init -p
```
- [ ] **Step 3: Configure tailwind.config.js**
```js
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{js,jsx}'],
theme: {
extend: {
colors: {
'neon-purple': '#b829f5',
'neon-cyan': '#00f5ff',
'neon-pink': '#ff2d78',
'dark-base': '#050508',
'dark-card': '#0d0d18',
'dark-surface': '#12121f',
'glass': 'rgba(255,255,255,0.04)',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
display: ['Space Grotesk', 'system-ui', 'sans-serif'],
},
backgroundImage: {
'gradient-neon': 'linear-gradient(135deg, #b829f5 0%, #00f5ff 100%)',
'gradient-dark': 'linear-gradient(180deg, #050508 0%, #0d0d18 100%)',
},
boxShadow: {
'neon-purple': '0 0 20px rgba(184,41,245,0.5), 0 0 60px rgba(184,41,245,0.2)',
'neon-cyan': '0 0 20px rgba(0,245,255,0.5), 0 0 60px rgba(0,245,255,0.2)',
'glass': 'inset 0 1px 0 rgba(255,255,255,0.1)',
},
},
},
plugins: [],
}
```
- [ ] **Step 4: Configure vite.config.js**
```js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})
```
- [ ] **Step 5: Commit**
```bash
git init
git add .
git commit -m "feat: scaffold Vite+React+R3F+Tailwind project"
```
---
## Task 2: Fetch Docs via Context7
**Purpose:** Get accurate API signatures for React Three Fiber, Framer Motion, GSAP ScrollTrigger before writing 3D/animation code.
- [ ] **Step 1: Resolve Context7 library IDs**
Use `mcp__context7__resolve-library-id` with queries:
- `"react-three-fiber 3D scene"`
- `"framer-motion animation"`
- `"gsap scroll trigger"`
- [ ] **Step 2: Query R3F docs**
Use `mcp__context7__query-docs` with resolved ID and question:
`"How to create a Canvas with useFrame animation loop and mesh geometry in React Three Fiber?"`
- [ ] **Step 3: Query Framer Motion docs**
Use `mcp__context7__query-docs` with question:
`"How to use motion.div with variants, whileHover, and useInView scroll animations?"`
- [ ] **Step 4: Query GSAP ScrollTrigger docs**
Use `mcp__context7__query-docs` with question:
`"How to use GSAP ScrollTrigger with React useEffect for parallax and scrub animations?"`
---
## Task 3: Global Styles + Design System
**Files:**
- Modify: `src/index.css`
- Use Stitch MCP to generate design system
- [ ] **Step 1: Create Stitch design system**
Call `mcp__stitch__create_design_system` with:
```json
{
"name": "CMusic Design System",
"description": "Cyberpunk-luxury dark theme. Deep black backgrounds (#050508), electric purple (#b829f5) and cyan (#00f5ff) neon accents, glassmorphism cards with backdrop-blur, Space Grotesk display font, Inter body. Neon glow box-shadows. No white backgrounds anywhere."
}
```
- [ ] **Step 2: Write src/index.css**
```css
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Space+Grotesk:wght@400;500;600;700&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--neon-purple: #b829f5;
--neon-cyan: #00f5ff;
--neon-pink: #ff2d78;
--dark-base: #050508;
--dark-card: #0d0d18;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
background-color: var(--dark-base);
color: #e8e8f0;
font-family: 'Inter', sans-serif;
overflow-x: hidden;
}
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: var(--dark-base); }
::-webkit-scrollbar-thumb {
background: var(--neon-purple);
border-radius: 2px;
}
.glass {
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.08);
}
.neon-text-purple {
color: var(--neon-purple);
text-shadow: 0 0 10px rgba(184,41,245,0.8);
}
.neon-text-cyan {
color: var(--neon-cyan);
text-shadow: 0 0 10px rgba(0,245,255,0.8);
}
.neon-border {
border: 1px solid rgba(184,41,245,0.4);
box-shadow: 0 0 15px rgba(184,41,245,0.2), inset 0 0 15px rgba(184,41,245,0.05);
}
canvas { display: block; }
```
- [ ] **Step 3: Commit**
```bash
git add src/index.css tailwind.config.js
git commit -m "feat: global styles and cyberpunk design system"
```
---
## Task 4: Mock Data + useAudioPlayer Hook
**Files:**
- Create: `src/data/mockData.js`
- Create: `src/hooks/useAudioPlayer.js`
- [ ] **Step 1: Write mockData.js**
```js
export const tracks = [
{ id: 1, title: 'Neon Pulse', artist: 'Synthwave X', album: 'Electric Dreams', duration: '3:42', plays: '2.1M', cover: 'https://picsum.photos/seed/track1/400/400' },
{ id: 2, title: 'Void Walker', artist: 'Dark Matter', album: 'Singularity', duration: '4:15', plays: '1.8M', cover: 'https://picsum.photos/seed/track2/400/400' },
{ id: 3, title: 'Cyber Rain', artist: 'Neo Tokyo', album: 'Ghost Protocol', duration: '3:58', plays: '3.4M', cover: 'https://picsum.photos/seed/track3/400/400' },
{ id: 4, title: 'Quantum Drift', artist: 'Parallax', album: 'Infinite Loop', duration: '5:02', plays: '987K', cover: 'https://picsum.photos/seed/track4/400/400' },
{ id: 5, title: 'Aurora Blaze', artist: 'Synthwave X', album: 'Electric Dreams', duration: '4:33', plays: '1.2M', cover: 'https://picsum.photos/seed/track5/400/400' },
{ id: 6, title: 'Digital Soul', artist: 'Echo System', album: 'Phase Shift', duration: '3:21', plays: '756K', cover: 'https://picsum.photos/seed/track6/400/400' },
];
export const albums = [
{ id: 1, title: 'Electric Dreams', artist: 'Synthwave X', year: 2024, genre: 'Synthwave', cover: 'https://picsum.photos/seed/album1/600/600', tracks: 12, color: '#b829f5' },
{ id: 2, title: 'Singularity', artist: 'Dark Matter', year: 2024, genre: 'Dark Electro', cover: 'https://picsum.photos/seed/album2/600/600', tracks: 9, color: '#00f5ff' },
{ id: 3, title: 'Ghost Protocol', artist: 'Neo Tokyo', year: 2023, genre: 'Cyberpunk', cover: 'https://picsum.photos/seed/album3/600/600', tracks: 11, color: '#ff2d78' },
{ id: 4, title: 'Infinite Loop', artist: 'Parallax', year: 2024, genre: 'Ambient', cover: 'https://picsum.photos/seed/album4/600/600', tracks: 8, color: '#b829f5' },
];
export const artists = [
{ id: 1, name: 'Synthwave X', genre: 'Synthwave / Electro', followers: '4.2M', image: 'https://picsum.photos/seed/artist1/800/1000', bio: 'Pioneering the neon-drenched soundscapes of tomorrow.' },
{ id: 2, name: 'Dark Matter', genre: 'Dark Electro', followers: '2.8M', image: 'https://picsum.photos/seed/artist2/800/1000', bio: 'Where darkness meets digital frequency.' },
];
```
- [ ] **Step 2: Write useAudioPlayer.js**
```js
import { useState, useCallback } from 'react'
import { tracks } from '../data/mockData'
export function useAudioPlayer() {
const [currentTrack, setCurrentTrack] = useState(tracks[0])
const [isPlaying, setIsPlaying] = useState(false)
const [progress, setProgress] = useState(0)
const [volume, setVolume] = useState(0.8)
const play = useCallback((track) => {
setCurrentTrack(track)
setIsPlaying(true)
}, [])
const togglePlay = useCallback(() => {
setIsPlaying(p => !p)
}, [])
const next = useCallback(() => {
const idx = tracks.findIndex(t => t.id === currentTrack.id)
setCurrentTrack(tracks[(idx + 1) % tracks.length])
}, [currentTrack])
const prev = useCallback(() => {
const idx = tracks.findIndex(t => t.id === currentTrack.id)
setCurrentTrack(tracks[(idx - 1 + tracks.length) % tracks.length])
}, [currentTrack])
return { currentTrack, isPlaying, progress, volume, play, togglePlay, next, prev, setProgress, setVolume }
}
```
- [ ] **Step 3: Commit**
```bash
git add src/data/mockData.js src/hooks/useAudioPlayer.js
git commit -m "feat: mock data and audio player hook"
```
---
## Task 5: Navbar
**Files:**
- Create: `src/components/Navbar/Navbar.jsx`
- [ ] **Step 1: Generate Navbar screen via Stitch**
Call `mcp__stitch__create_project` then `mcp__stitch__generate_screen_from_text` with:
```
"Glassmorphism music app navbar. Dark background with backdrop-blur. Logo 'CMUSIC' in electric purple neon. Nav links: Discover, Artists, Albums, Charts. Right side: Search icon, notification bell, user avatar circle. Subtle purple neon bottom border that animates on scroll. Cyberpunk aesthetic."
```
- [ ] **Step 2: Write Navbar.jsx**
```jsx
import { useState, useEffect } from 'react'
import { motion } from 'framer-motion'
const navLinks = ['Discover', 'Artists', 'Albums', 'Charts']
export default function Navbar() {
const [scrolled, setScrolled] = useState(false)
useEffect(() => {
const handler = () => setScrolled(window.scrollY > 20)
window.addEventListener('scroll', handler)
return () => window.removeEventListener('scroll', handler)
}, [])
return (
Immerse yourself in a new dimension of music. Visualize every beat, every pulse, every frequency.
{album.artist} Collection {track.title} {track.artist} Hot Right Now Artist Spotlight {artist.genre} {artist.bio} {artist.followers} Followers 48 Tracks 6 Albums {currentTrack.title} {currentTrack.artist}
Feel The{' '}
Music
In 3D
{/* Play overlay */}
{album.title}
Featured Albums
Trending Tracks
{artist.name}
{isPlaying && (
)}