Skip to content

stussysenik/v0-ipod

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

224 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

   ___      __   ____         ____  _       _ __        __
  / (_     / /  / __ \       / __ \(_)___ _(_) /_____ _/ /
 / / __ __/ /  / / / /_____/ / / / / __ `/ / __/ __ `/ /
/ / / // / /  / /_/ /_____/ /_/ / / /_/ / / /_/ /_/ / /
\_\ \_,_/_/  /_____/     /_____/_/\__, /_/\__/\__,_/_/
                                  /____/
                    iPod Classic Digital Clone

TypeScript React Next.js License

๐ŸŽต Live Demo โ€ข ๐Ÿ“– Docs โ€ข ๐Ÿค Contributing โ€ข ๐Ÿ—๏ธ Architecture

Drag & drop your song and create an iPod-like digital footprint

iPod Classic Digital Clone

โœจ Features

Demo

๐ŸŽต iPod Classic Simulation

  • Metadata Editing: Title, artist, album, artwork, rating (1-5 stars)
  • Click Wheel Navigation: Authentic iPod controls simulation
  • Progress Seeking: Scrub through your track with visual feedback
  • Track Numbers: Full album context with track X of Y
  • Authentic Battery Logic: Natural discharging cycle that drains slowly while the app is active

๐Ÿ•น๏ธ Interaction Modes

Control Menu Screen Now Playing Screen
Wheel rotation Scroll through menu items Seek through track
Center button Select highlighted item Toggle edit mode
Menu button โ€” Return to menu
Play/Pause Jump to Now Playing Visual feedback
Prev / Next Cycle menu items Seek -5s / +5s
  • iPod OS Mode (default): Full menu navigation with 9 items (Music, Videos, Photos, Podcasts, Extras, Settings, Shuffle Songs, Now Playing, About)
  • Center button on Now Playing: Toggles edit mode โ€” tap to make title, artist, album, rating, and time editable, tap again to lock

๐ŸŽจ View Modes

graph LR
    A[๐Ÿ“ฑ 2D Edit] --> B[๐ŸŽฎ 3D Experience]
    B --> C[๐ŸŽฌ Marquee Preview]
    C --> D[๐Ÿ’ป ASCII Mode]
    D --> E[๐Ÿ” Focus Mode]
    E --> A
Loading
  • 2D Edit Mode: Full metadata editing interface
  • 3D iPod Classic: Interactive 3D rendering with Three.js
  • Marquee Preview: Animated scrolling text simulation
  • ASCII Mode: Terminal-style text representation
  • Focus Mode: Minimal, distraction-free view

๐Ÿ“ค Export Capabilities

flowchart TD
    A[Export Request] --> B{Export Type}
    B -->|PNG| C[Create Detached Clone]
    B -->|GIF/MP4| D[Pipelined Capture Flow]
    C --> E[html-to-image]
    E -->|Success| F[Process Blob]
    E -->|Fail| G[html2canvas Fallback]
    G --> F
    D --> H[Main Thread Capture]
    H -->|ImageBitmap| I[Worker Encoding]
    I -->|Parallel| H
    I --> J[Finalize & Mux]
    J --> F
    F --> K{Platform}
    K -->|Mobile| L[Web Share API]
    K -->|Desktop| M[Blob Download]
    L -->|Fail| N[Fallback Download]
Loading
  • PNG Export: 4x resolution (1200ร—1600px) with dual fallback strategy
  • Animated GIF: 12 FPS marquee animation with gifenc encoding
  • MP4 Export: H.264 video with 12Mbps bitrate for high-quality motion capture
  • Pipelined Architecture: Concurrent capture and encoding using Web Workers and ImageBitmap for zero-jank UI during export
  • Real-time ETA: Live estimation of remaining export time based on frame capture velocity
  • Smart Animation Capture:
    • Marquee: Automatically scrolls for long titles (overflow-based)
    • Song Progress: Progress bar and timestamps are automatically animated to reflect the export duration
    • Consistency: The export preview dialog provides a 1:1 simulation of the final rendered file
  • Platform Detection: Web Share API for mobile, download for desktop
  • Automatic Fallback: Graceful degradation if primary method fails

๐ŸŽจ Customization

  • 138+ Grey Tones: 6 undertone families (Neutral, Warm, Cool, Greige, Sage, Lavender) ร— 23 perceptual lightness stops + OKLCH spectrum picker
  • 9 Apple Colors: Classic iPod finishes from graphite to starlight
  • Dual Theming: iPod case color + Background color independent control
  • Color History: Track and revisit recent color choices
  • Live Preview: Real-time updates across all view modes

๐Ÿ’พ Snapshot System

sequenceDiagram
    participant U as User
    participant C as Component
    participant S as Storage
    participant L as localStorage

    U->>C: Edit Metadata
    C->>S: saveMetadata()
    S->>L: Store JSON

    U->>C: Save Snapshot
    C->>S: saveSnapshot()
    S->>L: Full State

    U->>C: Reload Page
    L->>S: Restore Data
    S->>C: Hydrate State
    C->>U: Restored UI
Loading
  • Auto-save: Metadata and UI state persist automatically
  • Manual Snapshots: Save complete state snapshots
  • Quick Restore: One-click restoration of saved snapshots
  • localStorage: Client-side persistence, no backend required

๐Ÿ“ฑ PWA Support

  • Installable as Progressive Web App
  • Offline-capable with service worker caching
  • Mobile-optimized responsive design
  • Touch-friendly interface

๐Ÿš€ Quick Start

Prerequisites

  • pnpm 10+
  • Git for cloning the repository

Shell Productivity Tools

This project ships with shell helpers for faster git workflows:

Tool What It Does
forgit Interactive git (add, log, diff, checkoutโ€ฆ) via fzf
gh-repo-fzf Fuzzy-find and clone GitHub repos

To enable forgit aliases (ga, glo, gcb, gdโ€ฆ) in this directory:

Option A: direnv (recommended, auto-activates on cd)

brew install direnv          # one-time
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
direnv allow                 # inside this project

Option B: Manual

source /opt/homebrew/opt/forgit/share/forgit/forgit.plugin.zsh

To use gh-repo-fzf:

gh repo-fzf    # fuzzy-find repos from your GitHub

Both for forgit aliases and gh repo-fzf require fzf and gh to be installed: brew install fzf gh forgit && gh extension install kavinvalli/gh-repo-fzf

Installation

# Clone the repository
git clone https://github.com/stussysenik/v0-ipod.git
cd v0-ipod

# Install dependencies
pnpm install

# Start development server
pnpm dev

The app will be available at http://localhost:4001

Cursor Harness

This repo also includes a small local Cursor SDK harness based on the official cursor/cookbook quickstart example.

# add your Cursor API key to .env.local or export it in your shell
echo 'CURSOR_API_KEY="crsr_..."' >> .env.local

# ask Cursor to inspect this workspace
pnpm cursor:harness -- "Summarize the export pipeline in this repo"

Optional flags:

  • --model composer-2
  • --cwd /absolute/path/to/workspace
  • --force to allow local execution with uncommitted changes

๐Ÿ’ก Tip: Override the port if needed:

PORT=4010 pnpm dev
PORT=4010 pnpm start

Build for Production

pnpm build
pnpm start

๐Ÿงญ Design Workflow

This repository now uses Storybook as the default review surface for shared UI, tokens, and the physical iPod assembly.

Use the app page when you need full integration behavior:

  • metadata editing flow
  • persistence and snapshot behavior
  • export behavior
  • broader UX validation across the whole workbench

Use Storybook when you want to change a visual system input or a component and inspect it in isolation first.

What Is A Story?

A story is a small isolated example of a component or visual surface.

Examples:

  • an IconButton in default, hover, focus, and disabled states
  • the iPod status bar by itself
  • the full physical iPod assembly with real screen and click-wheel parts
  • a token manifest board that lets you inspect source values before changing component code

Stories are not the app. They are focused review fixtures for one component, one assembly, or one source-of-truth surface at a time.

Storybook Commands

# Run Storybook locally for day-to-day work
pnpm storybook

# Build the static Storybook site
pnpm build-storybook

# Run Storybook-linked tests
pnpm storybook:test

# Run build + Storybook tests together
pnpm storybook:validate

How to use them:

  • Use pnpm storybook while actively designing or refactoring.
  • Use pnpm build-storybook to make sure the Storybook site compiles cleanly.
  • Use pnpm storybook:test to verify story interactions and test coverage.
  • Use pnpm storybook:validate before landing larger Storybook-related changes.

pnpm build-storybook is not the main daily command. It is the static verification/build command. The main interactive command is pnpm storybook.

Source Of Truth Map

There are three main design ownership layers in this repo:

  1. tokens/* Shared reusable UI tokens. Today this is mainly tokens/shared-ui.json.

  2. scripts/*.json Product-owned iPod manifests. These are not shared design-system primitives. They hold iPod-specific color, finish, chrome, and surface data.

  3. components/* The actual implementation layer. components/ui/* is shared UI. components/ipod/* is product-owned iPod assembly code.

Practical Loop

If you want to change a shared primitive:

  1. Edit tokens/shared-ui.json if the styling change is semantic and reusable.
  2. Open tokens/shared-ui/Manifest in Storybook.
  3. Open the affected components/ui/* story, for example components/ui/IconButton.
  4. Adjust the component only if the token change is not enough.
  5. Run pnpm build-storybook when the change is ready to verify.

If you want to change the physical iPod finish, screen chrome, or wheel:

  1. Edit the owning product source: scripts/color-manifest.json, scripts/design-system.json, or a components/ipod/* file.
  2. Open the matching Storybook entry first: scripts/color-manifest/ProductFinishes, components/ipod/display/IpodStatusBar, components/ipod/display/IpodScreen, components/ipod/controls/IpodClickWheel, components/ipod/device/PhysicalIpod.
  3. Review the isolated element first, then the full physical assembly story.
  4. Open the app workbench only after the Storybook pass looks right.

Storybook Sidebar Shape

The Storybook tree mirrors repository ownership on purpose:

  • Foundations/*
  • tokens/*
  • components/ui/*
  • components/ipod/*
  • scripts/*

That means you should be able to move from a Storybook entry to the owning file without translation.

Recommended first-read order inside Storybook:

  1. Foundations/Start Here
  2. tokens/shared-ui/Manifest
  3. components/ipod/device/PhysicalIpod
  4. the relevant isolated component story
  5. scripts/color-manifest/ProductFinishes when tuning finish direction

Important:

  • changing Storybook controls does not persist anything globally
  • changing the real source file does

If you tweak a color in Storybook controls, you are only previewing a temporary runtime state for that story. If you edit tokens/shared-ui.json, scripts/color-manifest.json, scripts/design-system.json, or the owning components/* file, every consumer of that source updates globally.

Figma / Tokens Studio

If design work happens in Figma:

  • shared primitive changes still start in repository token files
  • Storybook is used to review the result in code
  • Tokens Studio syncs to the repository JSON

The repository stays authoritative. Figma sync is downstream collaboration, not a parallel source of truth.


๐Ÿ“ Design Fidelity: Click Wheel Label Positioning

The click wheel labels (MENU, โ–ถโธ, โฎ, โญ) are positioned using a source-truth proportion system derived from the official Wikipedia SVG diagram of the iPod click wheel.

Method

The Wikipedia SVG provides precise coordinate data:

Element Outer Circle Center Button Ring Width
Radius 245 units 90 units 155 units

Label positions were measured from raw SVG coordinates:

Label Distance from outer edge % of ring width
MENU 25 units 16.1%
Play/Pause 26 units 16.8%
Prev/Next 28 units 18.1%

The Inequality

The constraint that keeps labels true to the original hardware:

0.12 โ‰ค (inset_px / ring_width) โ‰ค 0.20

Where ring_width = (wheel_size - center_size) / 2 and inset_px = inset_% ร— wheel_size.

Applying to Presets

Each preset is checked against the inequality by solving for the percentage that places labels at ~15โ€“18% of the ring from the outer edge:

inset_% โ‰ˆ 0.15 ร— ring_width / wheel_size
Preset Old inset Ring position New inset Ring position
2007 10.5% 33% โŒ 5% 16% โœ“
2008 2% 6% โœ“ unchanged โ€”
2009 10% 30% โŒ 5% 15% โœ“

This ensures no preset places labels closer to the center button than to the outer edge โ€” matching the visual balance of the original hardware.


๐ŸŽฏ User Workflow

graph LR
    A[๐ŸŽต Upload Song] --> B[โœ๏ธ Edit Metadata]
    B --> C[๐ŸŽจ Customize Appearance]
    C --> D{Choose View}
    D -->|2D| E[๐Ÿ“ Edit Mode]
    D -->|3D| F[๐ŸŽฎ 3D Experience]
    D -->|Preview| G[๐ŸŽฌ Marquee Preview]
    D -->|ASCII| H[๐Ÿ’ป Terminal Mode]
    E --> I[๐Ÿ“ค Export PNG]
    G --> J[๐Ÿ“ค Export GIF]
    H --> J
Loading

๐Ÿ“ฆ Project Structure

v0-ipod/
โ”œโ”€โ”€ app/                      # Next.js 15 app directory
โ”‚   โ”œโ”€โ”€ layout.tsx           # Root layout with PWA manifest
โ”‚   โ””โ”€โ”€ page.tsx             # Main iPod component page
โ”œโ”€โ”€ components/
โ”‚   โ”œโ”€โ”€ ipod/
โ”‚   โ”‚   โ”œโ”€โ”€ ipod-classic.tsx        # Main iPod container
โ”‚   โ”‚   โ”œโ”€โ”€ ipod-screen.tsx         # Screen display logic
โ”‚   โ”‚   โ”œโ”€โ”€ ascii-ipod.tsx          # ASCII mode renderer
โ”‚   โ”‚   โ”œโ”€โ”€ grey-palette-picker.tsx # OKLCH grey palette picker
โ”‚   โ”‚   โ””โ”€โ”€ click-wheel.tsx         # Navigation controls
โ”‚   โ”œโ”€โ”€ three/
โ”‚   โ”‚   โ””โ”€โ”€ three-d-ipod.tsx        # 3D iPod with Three.js
โ”‚   โ””โ”€โ”€ ui/                          # Radix UI components
โ”œโ”€โ”€ lib/
โ”‚   โ”œโ”€โ”€ export-utils.ts              # PNG/GIF export pipeline
โ”‚   โ”œโ”€โ”€ storage.ts                   # localStorage persistence
โ”‚   โ””โ”€โ”€ utils.ts                     # Utility functions
โ””โ”€โ”€ public/
    โ””โ”€โ”€ manifest.json                # PWA manifest

๐Ÿ—๏ธ Component Architecture

graph TD
    A[IPodClassic] --> B[IPodScreen]
    A --> C[ClickWheel]
    A --> D[ThreeDIPod]
    B --> E[MarqueeText]
    B --> F[ProgressBar]
    B --> G[StarRating]
    B --> H[EditableText]
    A --> I[ExportUtils]
    I --> J[PNG Export]
    I --> K[GIF Export]

    style A fill:#3178C6,stroke:#fff,color:#fff
    style I fill:#61DAFB,stroke:#000,color:#000
Loading

๐Ÿ› ๏ธ Tech Stack

Layer Technology
Framework Next.js 15 (React 19)
Language TypeScript (strict mode)
3D Rendering Three.js + React Three Fiber
UI Components Radix UI + Tailwind CSS
Export Pipeline html-to-image + html2canvas + gifenc
State Management React useReducer + Context
Storage localStorage API
PWA @ducanh2912/next-pwa
Deployment Vercel

๐Ÿ”Ž Verification

This repository currently does not ship with a committed automated test suite. Use the existing quality gates plus focused manual checks while rebuilding test ownership:

pnpm lint
pnpm type-check
pnpm build

๐Ÿ“œ Available Scripts

Script Description
pnpm dev Start development server on port 4001
pnpm build Build production bundle
pnpm start Start production server
pnpm clean:next Remove .next if a stale local build causes runtime issues
pnpm lint Run OXC (oxlint)
pnpm lint:fix Auto-fix OXC lint issues
pnpm lint:eslint Run the legacy Next/ESLint ruleset
pnpm type-check Run TypeScript type checking
pnpm validate Run lint + type check
pnpm storybook Start Storybook locally on port 6006
pnpm build-storybook Build the static Storybook site
pnpm storybook:test Run Storybook-linked Vitest coverage
pnpm storybook:validate Run Storybook build + Storybook tests

๐ŸŽจ Color Palette

Apple Colors

graphite โ€ข silver โ€ข starlight โ€ข midnight โ€ข blue โ€ข pink โ€ข purple โ€ข red โ€ข green

OKLCH Grey Palette

6 undertone families โ€” Neutral, Warm, Cool, Greige, Sage, Lavender โ€” each with 23 perceptually-spaced lightness stops. Hex deduplication ensures unique swatches. Gradient preview bar, curated favorites, and undertone tab persistence via localStorage.

OKLCH Spectrum

Full spectrum color picker with infinite color possibilities

CIEDE2000 Color Proximity

Shades and palette matches are driven by perceptually uniform color math, not naive RGB interpolation:

hex โ†’ RGB โ†’ CIEXYZ โ†’ CIELAB โ†’ ฮ”E 2000
Step Formula Purpose
hex โ†’ RGB sRGB transfer Linearize gamma-compressed values
RGB โ†’ XYZ CIE 1931 matrix Device-independent tristimulus
XYZ โ†’ LAB CIE 1976 Perceptually uniform opponent space
LAB โ†’ ฮ”E CIEDE2000 Industry-standard color difference

ฮ”E 2000 corrects the remaining non-uniformities in CIELAB:

  • Hue weighting (t): blue region has smaller tolerance than yellow
  • Lightness compensation (sl): dark colors have smaller JND
  • Chroma compensation (sc): low-saturation colors behave differently
  • Hue-chroma rotation (rt): elliptical tolerance in blue region

Shades are displayed only when ฮ”E โ‰ค 15 โ€” beyond that a color is no longer meaningfully "a shade of" the target. A ฮ”E of ~2.3 is JND (just noticeable difference); ~1.0 is barely perceptible.

The same pipeline also derives the screen gasket color from the case skin, keeping the physical gap cohesive on every theme.


๐Ÿ“– Documentation

This README is the central starting point. Use the documents below for deeper detail:


๐Ÿค Contributing

We welcome contributions! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feat/your-feature
  3. Make your changes using semantic commits
  4. Run validation: pnpm validate
  5. Push and create a PR

See CONTRIBUTING.md for detailed guidelines including:

  • Semantic commit conventions
  • Code style guidelines
  • Testing requirements
  • PR review process

๐Ÿ› Troubleshooting

Port Already in Use

If pnpm dev fails because port 4001 is occupied:

PORT=4010 pnpm dev

Export Not Working on Mobile

The app uses the Web Share API on mobile devices. If your browser doesn't support it, the export will automatically fall back to direct download.

3D View Performance Issues

If you experience performance issues with the 3D view:

  • Try switching to 2D edit mode
  • Close other browser tabs
  • Update your graphics drivers
  • Use a modern browser (Chrome, Edge, Safari)

๐Ÿ“„ License

MIT License - see LICENSE for details


๐Ÿ™ Acknowledgments

  • Inspired by the iconic iPod Classic design
  • Built with modern web technologies
  • Export pipeline leverages multiple fallback strategies for reliability
  • Testing ensures cross-platform compatibility

Made with โค๏ธ for music lovers

โฌ†๏ธ Back to Top

About

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors