This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
There's a file modification bug in Claude Code. The workaround is: always use complete absolute Windows paths with drive letters and backslashes for ALL file operations. Apply this rule going forward, not just for this file.
When using Edit or MultiEdit tools on Windows, you MUST use backslashes (\) in file paths, NOT forward slashes (/).
WRONG: Edit(file_path: "D:/repos/project/file.tsx", ...)
RIGHT: Edit(file_path: "D:\repos\project\file.tsx", ...)
MusicBox is a plugin-based local music player built with Electron. It supports multiple audio formats (flac, mp3, wav, ogg, m4a, aac, wma) and features a plugin system inspired by VSCode's extension architecture.
- Main Process: Electron (v41.2.1) with TypeScript, Node.js (>=24.15.0)
- Renderer Process: Vite + TypeScript/vanilla JS hybrid (migrating to TypeScript)
- Native Audio: Rust (v1.94.1) with WASAPI exclusive mode support, built via napi-rs
- Python: Used for metadata editing utilities (>=3.8), compiled to
.exevia PyInstaller - Styling: SCSS
# Install all dependencies
npm install && npm run install:renderer && npm run install:rs
pip install -r requirements.txt
# Development (builds renderer + Rust + TypeScript, then launches Electron with --expose-gc)
npm run dev
# Build renderer only (for UI iteration)
npm run dev:renderer # Vite dev server on port 8080
# Build TypeScript (main process) only
npm run build:ts # Compiles src/main/**/*.ts to dist/main/
npm run watch:ts # Watch mode for TypeScript compilation
# Build Rust native module only
npm run build:rs
# Build Python metadata editor only
npm run build:python # Compiles metadata_editor.py to .exe via PyInstaller
# Type-check renderer (separate from build)
npm run typecheck:renderer
# Full application build
npm run build
# Platform-specific builds
npm run build:win # Windows (NSIS + portable)
npm run build:mac # macOS (DMG + ZIP)
npm run build:linux # Linux (AppImage + deb + rpm)
# Lint renderer code
cd src/renderer && npm run lint
# Clean build artifacts
npm run cleanNote: npm run dev is NOT hot-reload -- it runs a full build:renderer + build:rs + build:ts before launching Electron. For fast UI iteration, use dev:renderer separately.
Main Process (Node.js + TypeScript) <-> IPC <-> Renderer Process (Chromium)
├── Application class (core/Application.ts) ├── Vite + TS/JS hybrid
├── Controllers (IPC handlers via decorators) ├── Plugin system (TypeScript)
├── Services (library, network, extensions) ├── Feature modules
├── WindowManager & ConfigManager ├── UI layer (base/dialogs/modals/pages/widgets)
├── Native audio engine (Rust N-API) ├── API layer (MusicBoxAPI)
├── Tray, HTTP server, global shortcuts ├── Infrastructure & shared utilities
└── Python metadata editor (subprocess) └── Desktop lyrics window (separate HTML entry)
Architecture Pattern: Controller-based with dependency injection
main.ts: Entry point -- createsApplicationinstance and manages app lifecyclecore/Application.ts: Central orchestrator -- initializes services, registers controllers, manages startup. All 22 controllers are instantiated and registered inregisterStartupControllers().core/ServiceContainer.ts: Dependency injection container for servicescore/WindowManager.ts: Window creation and management (main window, mini mode, etc.)core/ConfigManager.ts: Configuration file managementpreload.ts: Preload script bridging main/renderer via contextBridge. Exposes namespaced APIs: audio, nativeAudio, library, settings, lyrics, covers, networkDrive, window, desktopLyrics, tray, globalShortcuts, extensions, userdata, memory, benchmark, httpServer, app, hardwareAcceleration, and file operations.controllers/: 22 IPC handler classes using@IpcHandlerdecorator pattern. Key controllers: AudioController, NativeAudioController, LibraryController, NetworkController, LyricsController, CoversController, DesktopLyricsController, WindowController, TrayController, HttpServerController, GlobalShortcutsController, ExtensionsController, SettingsController, HardwareAccelerationController, BenchmarkController, MemoryController, UserDataController, AppController, DialogController, FileController, SystemController.services/: Business logiclibrary/: LibraryCacheManager, MetadataHandler, AutoScanSchedulernetwork/: NetworkDriveManager, NetworkFileAdapter, DriveRegistryextensions/: ExtensionInstaller
decorators/IpcHandler.ts: Decorator for automatic IPC handler registrationutils/: Utility functions (metadata parsing, path security, file search)types/: TypeScript type definitions
The renderer uses a feature-based modular architecture (recently refactored from a monolithic app.js). Layers:
app/: Application bootstrap, composition root, lifecycle management, and app shell.core/: Core app entry point --app.tsre-exports fromapp/bootstrap/app.ts.features/: Domain feature modules -- each is a self-contained vertical slice:playback/-- Playback controls, progress, volume, mini modeaudioDriver/-- Audio engine driver (WASAPI/fallback)desktopLyrics/-- Desktop lyrics window logicequalizer/-- Graphic and parametric EQ controlslibrary/-- Music library browsing and managementplaylists/-- Playlist managementmedia/-- Media file handlingmediaAssets/-- Cover art, embedded medianetworkDrive/-- SMB/WebDAV network drive UIsettings/-- Application settingsextensions/-- Extension management UIevents/-- Application event systemappShell/-- App shell, window behavioruserData/-- User mood/diary data
ui/: Presentation layer --base/,dialogs/,modals/,pages/,widgets/api/: Renderer-side API layer.MusicBoxAPI.tsis the central orchestrator (~33KB) -- it bridges main process events to the app event system, manages playback state synchronization, and provides typed API access to all main process functionality.services/: Cross-feature shared services (audio, covers, lyrics, navigation, plugins, preferences, settings, update)shared/: Shared utilities -- caching, network helpers, typesinfrastructure/: Infrastructure layer (currentlyelectron/for Electron-specific adapters)extensions/: Plugin system (TypeScript) -- core infrastructure, namespaced API, built-in plugins. API docs atextensions/api/README.md.utils/: General utilities (md5, URL validation, shortcuts)styles/: SCSS stylesheets (main.scss,DesktopLyrics.scss)- Two HTML entry points:
index.html(main app) andDesktopLyrics.html(separate window)
- Rust-based audio engine: decoding (rodio/symphonia), WASAPI exclusive output, resampling (rubato), EQ (biquad)
- Built as
NativeAudio.nodeN-API addon, loaded by main process - Release profile: LTO enabled, opt-level=3, stripped
- Root:
src/, output:public/ - Target: Chrome 138
- Two HTML entry points:
index.htmlandDesktopLyrics.html - Manual chunks: vendor, extensions, components, shared-utils
- Path aliases:
@->src/,@utils,@api,@ui,@extensions,@styles,@assets
To add main process functionality accessible from renderer:
-
Create a Controller in
src/main/controllers/(or update existing one)import { BaseController, IpcHandler } from '../decorators/IpcHandler'; export class MyController extends BaseController { @IpcHandler('my-domain:action') async handleAction(event: any, arg: any) { // Implementation return result; } }
-
Register Controller in
Application.registerStartupControllers()(core/Application.ts) -
Expose in preload.ts via
contextBridge.exposeInMainWorld -
Use from Renderer via
window.electronAPI.*const result = await window.electronAPI.invoke('my-domain:action', arg);
Channel naming convention: domain:action (e.g., audio:loadTrack, library:scan)
Each feature in features/ follows a controller-based pattern where domain logic is split into focused controllers (e.g., playback feature has separate controllers for controls, progress, volume, mini mode, lyrics). Features register with the app's composition root in app/.
The MusicBoxAPI class in api/MusicBoxAPI.ts is the central renderer-side API orchestrator. It:
- Bridges main process
EventEmitterto the app event service - Exposes typed wrappers for all IPC channels
- Synchronizes playback state between main and renderer
- Manages playback queue, persistence, and desktop lyrics sync
Located in src/renderer/src/extensions/:
- Core (
core/): TypeScript -- lifecycle, events, DI, registry, activation, permissions, host management - API (
api/): Exposes namespaced API (player, library, ui, storage, settings, navigation, etc.). Seeapi/README.mdfor API documentation. - Built-in plugins:
builtin/-- serve as reference implementations - Each plugin needs:
manifest.json+ entry file exportingactivate(context)/deactivate() - Activation events:
onStartUp,onCommand:*,onView:*,*
- LibraryCacheManager (
src/main/services/library/LibraryCacheManager.ts): Central music library cache with incremental updates, file watching, and query interface - AutoScanScheduler (
src/main/services/library/AutoScanScheduler.ts): Automatic library scanning - MetadataHandler (
src/main/services/library/MetadataHandler.ts): Metadata parsing and editing (usesmusic-metadata@11.12.3) - Library search uses Fuse.js for fuzzy matching
- NetworkDriveManager (
src/main/services/network/NetworkDriveManager.ts): Manages SMB (vianode-smb2) and WebDAV (viawebdav) connections - NetworkFileAdapter (
src/main/services/network/NetworkFileAdapter.ts): Unified interface for local and network files - DriveRegistry (
src/main/services/network/DriveRegistry.ts): Registry for mounted network drives - Metadata parsing and audio playback work transparently with network files
- Electron Builder:
electron-builder.yml-- targets Windows (NSIS + portable), macOS (DMG + ZIP), Linux (AppImage + deb + rpm), all with x64 + arm64 NativeAudio.nodeandmetadata_editor.exeare unpacked from ASAR and placed in extraResources- Python module: Built via
scripts/build-python-module.jsusing PyInstaller (fallback to Nuitka) - Rust module: Built via napi-rs with
cargo-cp-artifact, outputs todist/main/NativeAudio.node - TypeScript: Main process compiled to
dist/main/viatsc -p src/main/tsconfig.json(target ES2022, CommonJS) - Benchmark infrastructure:
scripts/benchmarks/contains benchmark scripts for performance testing
.github/workflows/deploy-docs.yml: Deploys docs to GitHub Pages on pushes todevtouchingdocs/**.github/workflows/release.yml: Manual workflow dispatch for building and releasing the application across platforms
- Main process (
src/main/tsconfig.json): Target ES2022, module CommonJS, strict mode, experimental decorators enabled - Renderer (
src/renderer/tsconfig.json): Target ES2022, module ESNext, strict mode, path aliases configured
- Source:
src/main/metadata_editor.py - Dependencies: mutagen (defined in
requirements.txt) - Build process automatically tries PyInstaller first, falls back to Nuitka
- Built with Rust 1.94.1 (specific version required)
- Uses WASAPI for Windows exclusive audio mode
- Release build uses LTO and opt-level=3 for performance
- Main process changes: Run
npm run build:ts(ornpm run watch:ts), then restartnpm run dev - Renderer UI changes: Use
npm run dev:rendererfor faster iteration (Vite HMR) - Rust changes: Run
npm run build:rsthen restart main process - Python changes: Run
npm run build:pythonthen restart main process
- TypeScript: Main process uses TypeScript with strict mode, 4-space indentation, semicolons; renderer is hybrid TS/JS (migrating toward full TypeScript)
- JavaScript: ES6+ with
async/awaitfor async operations - Naming:
PascalCasefor classes (e.g.,AppController.ts),camelCasefor methods and helpers - Resource cleanup: Disposable pattern in extension system
- Log outputs: Must start with relevant emoji icons for quick identification (project convention)
- 🔧 Configuration/setup, ✅ Success, ❌ Errors, 🔄 Loading/processing, 🎵 Audio, 📦 Build/packaging,
⚠️ Warnings
- 🔧 Configuration/setup, ✅ Success, ❌ Errors, 🔄 Loading/processing, 🎵 Audio, 📦 Build/packaging,
- IPC naming: Use
domain:actionpattern (e.g.,audio:init,library:scan) - File organization: Controllers in
src/main/controllers/, services insrc/main/services/, features insrc/renderer/src/features/ - Decorators: Use
@IpcHandler('channel:name')for IPC handler methods in controllers - Windows:
npm run dev:mainuseschcp 65001to set UTF-8 console encoding (required for proper emoji/log output on Windows)
No automated test framework configured. For all changes, smoke-test manually with npm run dev:
- Library scan and browse
- Audio playback (local and network files)
- Lyrics display (synced and desktop lyrics)
- Settings changes and persistence
- Plugin loading and activation
Put reusable media fixtures in test-files/. Run cd src/renderer && npm run lint before opening a PR (this also runs an architecture-boundary check via check:architecture).
- Commit prefixes:
feature:,fix:,refactor:,docs:(lowercase) - Commit subjects: short, imperative mood, scoped to one change
- PRs must: explain user-visible impact, list manual checks performed, link related issues, include screenshots for UI changes
- Call out changes in
native/, packaging, or preload/API boundaries explicitly (they affect release builds and security review)
- Never bypass the preload boundary -- no direct renderer access to Node.js APIs. All main-process access goes through
contextBridgeviapreload.ts. - Reuse existing utilities like
src/main/utils/pathSecurity.tsfor filesystem-facing work. - Keep native (Rust) and Python changes isolated to their build paths.