|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +"Everything Is Remixed" (EVR) is a web-based interactive music album and stem mixer. Users can remix tracks by manipulating individual audio stems (drums, vocals, synths, etc.) directly in the browser using the Web Audio API. Released under CC0 1.0 (public domain). |
| 6 | + |
| 7 | +## Architecture |
| 8 | + |
| 9 | +- **Platform**: Cloudflare Workers |
| 10 | +- **Storage**: Cloudflare R2 (buckets named by element: `HYDROGEN`, `LITHIUM`, etc.) |
| 11 | +- **Frontend**: Modular ES6 JavaScript served via Workers Assets |
| 12 | +- **Audio Engine**: Web Audio API (client-side) |
| 13 | + |
| 14 | +## File Structure |
| 15 | + |
| 16 | +``` |
| 17 | +src/ |
| 18 | +├── standalone-mixer/ |
| 19 | +│ └── index.html # Standalone mixer (drag-and-drop, no dependencies) |
| 20 | +└── workers/ |
| 21 | + ├── everything-is-remixed-worker.js # Worker entry point (~309 lines) |
| 22 | + ├── stems.json # Stem metadata for all tracks |
| 23 | + ├── {trackId}_peaks.json # Pre-generated waveform peaks |
| 24 | + └── app/ # Frontend/UI (served as assets) |
| 25 | + ├── mixer-app.js # Client orchestrator (~565 lines) |
| 26 | + ├── mix-style.css # Application styles |
| 27 | + └── modules/ # ES6 modules (13 total) |
| 28 | + ├── mixer-constants.js # Config, defaults |
| 29 | + ├── mixer-audio.js # AudioEngine class |
| 30 | + ├── mixer-state.js # MixerState class |
| 31 | + ├── mixer-transport.js # TransportController class |
| 32 | + ├── mixer-ui.js # UIBuilder class |
| 33 | + ├── mixer-fx.js # FXController class |
| 34 | + ├── mixer-help.js # HelpController class |
| 35 | + ├── mixer-loader.js # StemLoader class |
| 36 | + ├── mixer-loop.js # AnimationManager class |
| 37 | + ├── mixer-waveform.js # WaveformRenderer class |
| 38 | + ├── mixer-templates.js # HTML generation functions |
| 39 | + ├── mixer-visualizer.js # Holograph class (main thread) |
| 40 | + └── mixer-holographic-worker.js # 3D visualizer (Web Worker) |
| 41 | +``` |
| 42 | + |
| 43 | +## Standalone Mixer (standalone-mixer/index.html) |
| 44 | + |
| 45 | +Self-contained stem mixer for user-provided audio files. No external dependencies, no share URL functionality (not applicable for local files). |
| 46 | + |
| 47 | +**Features:** |
| 48 | +- Drag-and-drop audio files (M4A, MP3, MP4, WAV, FLAC, OGG) |
| 49 | +- Full FX chain with filter rolloff (-12/-24 dB/oct) |
| 50 | +- Holograph visualizer |
| 51 | +- Help system |
| 52 | +- Performance optimizations (visibility tracking, time slicing, dirty checks) |
| 53 | + |
| 54 | +## Key Concepts |
| 55 | + |
| 56 | +- **Tracks**: Named after alkali metals (Hydrogen, Lithium, Sodium, Potassium, Rubidium, Caesium, Francium) |
| 57 | +- **Stems**: Individual audio tracks that make up a song (9-38 per track) |
| 58 | +- **FX Chain**: EQ → Filter (-12/-24 dB/oct) → Delay → Panner → Gain → Master (+ Reverb Send) |
| 59 | +- **FX Modal**: Tabbed modal interface (EQ/FILTER tab with Slope dropdown, REVERB/DELAY tab) |
| 60 | +- **Progress Bar**: Display-only, no seeking (use skip buttons ±10s) |
| 61 | +- **Share URLs**: Mix state encoded in URL parameters for sharing |
| 62 | +- **Holograph**: 3D "City Landscape" visualizer using OffscreenCanvas + Web Worker |
| 63 | +- **Signal LED**: Per-channel LED that lights up when audio detected (>5% level) |
| 64 | +- **Sync**: Leader-based playback with rate nudging (desktop only, ~1Hz) |
| 65 | +- **Theme**: Light/dark mode via `data-theme` attribute, persisted in localStorage |
| 66 | +- **Listing**: Swiss Lab periodic table design (4-column grid, element symbols) |
| 67 | + |
| 68 | +## Module Responsibilities |
| 69 | + |
| 70 | +| Module | Class | Purpose | |
| 71 | +|--------|-------|---------| |
| 72 | +| `mixer-constants.js` | - | Configuration, defaults | |
| 73 | +| `mixer-audio.js` | `AudioEngine` | Web Audio API setup, effects chain, filter rolloff, master output | |
| 74 | +| `mixer-state.js` | `MixerState` | Stem volume, mute/solo, FX state, URL encoding | |
| 75 | +| `mixer-transport.js` | `TransportController` | Play, pause, seek, skip, sync, leader election | |
| 76 | +| `mixer-ui.js` | `UIBuilder` | Channel strips, faders, meters, visibility tracking | |
| 77 | +| `mixer-fx.js` | `FXController` | FX modal, tabbed UI, parameter control, rolloff | |
| 78 | +| `mixer-help.js` | `HelpController` | Help modal/bottom sheet, keyboard shortcuts | |
| 79 | +| `mixer-loader.js` | `StemLoader` | Batch loading, audio graph construction | |
| 80 | +| `mixer-loop.js` | `AnimationManager` | Throttled loop tasks, drift correction | |
| 81 | +| `mixer-waveform.js` | `WaveformRenderer` | Canvas waveform drawing & caching | |
| 82 | +| `mixer-templates.js` | - | Pure HTML string generation functions | |
| 83 | +| `mixer-visualizer.js` | `Holograph` | Main thread bridge to visualizer worker | |
| 84 | +| `mixer-holographic-worker.js` | - | 3D "City Landscape" rendering (Web Worker) | |
| 85 | + |
| 86 | +## Development Guidelines |
| 87 | + |
| 88 | +- **Worker**: Serves HTML shell, routes audio/asset requests, handles R2 proxying |
| 89 | +- **Client**: ES6 modules loaded via `type="module"` script tag |
| 90 | +- **Audio**: Processing done in browser (gain, EQ, filter, reverb, delay, pan) |
| 91 | +- **State**: Mix state shareable via URL parameters (`?mix=...&master=80`) |
| 92 | +- **Style**: Light/dark theme via `data-theme` attribute, track-specific accent colors (`--track-color`) |
| 93 | + |
| 94 | +## Performance Considerations |
| 95 | + |
| 96 | +- **Pre-allocate buffers**: Reuse `Float32Array` for meters/waveforms (avoid GC) |
| 97 | +- **Cache DOM refs**: Store meter/channel element references after building UI |
| 98 | +- **GPU animation**: Use `transform: scaleY()` not `height` for meters |
| 99 | +- **Throttle updates**: Progress bar at 10fps, meters at 30fps, holograph at 30fps |
| 100 | +- **Time slicing**: Update half the meters per frame (30fps → 15fps effective per channel) |
| 101 | +- **Dirty check**: Only update meter DOM if value changed by >1% |
| 102 | +- **Cache computations**: Pass `hasSolo` result to `isStemActive()` calls |
| 103 | +- **Visibility tracking**: Skip meter updates for off-screen channels (IntersectionObserver) |
| 104 | +- **Memory cleanup**: Release blob objects early, URLs on page unload |
| 105 | +- **Event delegation**: Single container listener instead of per-channel listeners |
| 106 | +- **Event cleanup**: Call `uiBuilder.dispose()` to remove global listeners |
| 107 | +- **Visualizer**: OffscreenCanvas + Web Worker, fake glow (2-pass), pre-allocated arrays |
| 108 | + |
| 109 | +## Route Order (Critical) |
| 110 | + |
| 111 | +1. Audio files: `/{trackId}/{filename}.m4a` (must be before assets) |
| 112 | +2. Peaks JSON: `/*_peaks.json` (must be before assets) |
| 113 | +3. Assets: `/assets/*` (JS, CSS, JSON, modules) |
| 114 | +4. App: `/` (home) or `/{trackId}` (mixer) |
| 115 | + |
| 116 | +## Documentation |
| 117 | + |
| 118 | +Detailed documentation in `docs/`: |
| 119 | +- `ARCHITECTURE.md` - Modular architecture, classes |
| 120 | +- `CLIENT_APP.md` - Audio, state, transport, UI |
| 121 | +- `SERVER_WORKER.md` - Routing, R2, caching |
| 122 | +- `GUIDES.md` - Adding tracks, FX, deployment |
| 123 | +- `MIXER_SYSTEM.md` - Effects, state encoding |
| 124 | +- `PERFORMANCE.md` - Animation loop, memory, rendering optimizations |
| 125 | +- `STEM_COLOR_PALETTES.md` - Color generation |
| 126 | +- `TRACK_COLORS.md` - Track primary colors |
| 127 | +- `PEAK_GENERATOR.md` - Waveform peaks tool |
| 128 | + |
| 129 | +## Filter Rolloff |
| 130 | + |
| 131 | +The filter supports two rolloff slopes selectable via the FX modal "Slope" dropdown: |
| 132 | + |
| 133 | +| Rolloff | Implementation | Use Case | |
| 134 | +|---------|----------------|----------| |
| 135 | +| **-12 dB/oct** | Single BiquadFilterNode | Gentle slope, default | |
| 136 | +| **-24 dB/oct** | 2 cascaded BiquadFilterNodes | Steeper, more surgical | |
| 137 | + |
| 138 | +Hot-swapping rolloff requires reconnecting the audio graph (disconnect old filter, create new, reconnect EQ → Filter → Delay). |
| 139 | + |
| 140 | +## Persona |
| 141 | + |
| 142 | +The project embodies the philosophy that "Everything is free" and "Music should circulate like electricity." Code should reflect high engineering standards while respecting the artistic intent of radical accessibility. |
0 commit comments