"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).
- Platform: Cloudflare Workers
- Storage: Cloudflare R2 (buckets named by element:
HYDROGEN,LITHIUM, etc.) - Frontend: Modular ES6 JavaScript served via Workers Assets
- Audio Engine: Web Audio API (client-side)
src/
├── standalone-mixer/
│ └── index.html # Standalone mixer (drag-and-drop, no dependencies)
└── workers/
├── everything-is-remixed-worker.js # Worker entry point (~309 lines)
├── stems.json # Stem metadata for all tracks
├── {trackId}_peaks.json # Pre-generated waveform peaks
└── app/ # Frontend/UI (served as assets)
├── mixer-app.js # Client orchestrator (~565 lines)
├── mixer-style.css # Application styles
└── modules/ # ES6 modules (13 total)
├── mixer-constants.js # Config, defaults
├── mixer-audio.js # AudioEngine class
├── mixer-state.js # MixerState class
├── mixer-transport.js # TransportController class
├── mixer-ui.js # UIBuilder class
├── mixer-fx.js # FXController class
├── mixer-help.js # HelpController class
├── mixer-loader.js # StemLoader class
├── mixer-loop.js # AnimationManager class
├── mixer-waveform.js # WaveformRenderer class
├── mixer-templates.js # HTML generation functions
├── mixer-visualizer.js # Holograph class (main thread)
└── mixer-holographic-worker.js # 3D visualizer (Web Worker)
Self-contained stem mixer for user-provided audio files. No external dependencies, no share URL functionality (not applicable for local files).
Features:
- Drag-and-drop audio files (M4A, MP3, MP4, WAV, FLAC, OGG)
- Full FX chain: EQ, Filter (rolloff -12/-24 dB/oct), Tremolo, Ring Modulator, Delay, Reverb
- 3-tab FX modal (EQ/FILTER, MOD/FX, REVERB/DELAY)
- Holograph visualizer
- Help system
- Performance optimizations (visibility tracking, time slicing, dirty checks)
- Tracks: Named after alkali metals (Hydrogen, Lithium, Sodium, Potassium, Rubidium, Caesium, Francium)
- Stems: Individual audio tracks that make up a song (9-38 per track)
- FX Chain: EQ → [Compressor] → [Distortion] → Filter (-12/-24 dB/oct) → [Ring Mod] → Delay → [Tremolo] → Panner → Gain → Master (+ Reverb Send)
- FX Modal: Tabbed modal interface (EQ/FILTER, DYNAMICS, MOD/FX, SEND/DELAY)
- Progress Bar: Display-only, no seeking (use skip buttons ±10s)
- Share URLs: Mix state encoded in URL parameters for sharing
- Holograph: 3D "City Landscape" visualizer using OffscreenCanvas + Web Worker
- Signal LED: Per-channel LED that lights up when audio detected (>5% level)
- Sync: Leader-based playback with rate nudging (desktop only, ~1Hz)
- Theme: Light/dark mode via
data-themeattribute, persisted in localStorage - Listing: Swiss Lab periodic table design (4-column grid, element symbols)
| Module | Class | Purpose |
|---|---|---|
mixer-constants.js |
- | Configuration, defaults |
mixer-audio.js |
AudioEngine |
Web Audio API setup, effects chain, filter rolloff, master output |
mixer-state.js |
MixerState |
Stem volume, mute/solo, FX state, URL encoding |
mixer-transport.js |
TransportController |
Play, pause, seek, skip, sync, leader election |
mixer-ui.js |
UIBuilder |
Channel strips, faders, meters, visibility tracking |
mixer-fx.js |
FXController |
FX modal, tabbed UI, parameter control, rolloff |
mixer-help.js |
HelpController |
Help modal/bottom sheet, keyboard shortcuts |
mixer-loader.js |
StemLoader |
Batch loading, audio graph construction |
mixer-loop.js |
AnimationManager |
Throttled loop tasks, drift correction |
mixer-waveform.js |
WaveformRenderer |
Canvas waveform drawing & caching |
mixer-templates.js |
- | Pure HTML string generation functions |
mixer-visualizer.js |
Holograph |
Main thread bridge to visualizer worker |
mixer-holographic-worker.js |
- | 3D "City Landscape" rendering (Web Worker) |
- Worker: Serves HTML shell, routes audio/asset requests, handles R2 proxying
- Client: ES6 modules loaded via
type="module"script tag - Audio: Processing done in browser (gain, EQ, compressor, distortion, filter, ring mod, delay, tremolo, reverb, pan)
- State: Mix state shareable via URL parameters (
?mix=...&master=80) - Style: Light/dark theme via
data-themeattribute, track-specific accent colors (--track-color)
- Pre-allocate buffers: Reuse
Float32Arrayfor meters/waveforms (avoid GC) - Cache DOM refs: Store meter/channel element references after building UI
- GPU animation: Use
transform: scaleY()notheightfor meters - Throttle updates: Progress bar at 10fps, meters at 30fps, holograph at 30fps
- Time slicing: Update half the meters per frame (30fps → 15fps effective per channel)
- Dirty check: Only update meter DOM if value changed by >1%
- Cache computations: Pass
hasSoloresult toisStemActive()calls - Visibility tracking: Skip meter updates for off-screen channels (IntersectionObserver)
- Memory cleanup: Release blob objects early, URLs on page unload
- Event delegation: Single container listener instead of per-channel listeners
- Event cleanup: Call
uiBuilder.dispose()to remove global listeners - Visualizer: OffscreenCanvas + Web Worker, fake glow (2-pass), pre-allocated arrays
- Audio files:
/{trackId}/{filename}.m4a(must be before assets) - Peaks JSON:
/*_peaks.json(must be before assets) - Assets:
/assets/*(JS, CSS, JSON, modules) - App:
/(home) or/{trackId}(mixer)
Detailed documentation in docs/:
ARCHITECTURE.md- Modular architecture, classesCLIENT_APP.md- Audio, state, transport, UISERVER_WORKER.md- Routing, R2, cachingGUIDES.md- Adding tracks, FX, deploymentMIXER_SYSTEM.md- Effects, state encodingPERFORMANCE.md- Animation loop, memory, rendering optimizationsSTEM_COLOR_PALETTES.md- Color generationTRACK_COLORS.md- Track primary colorsPEAK_GENERATOR.md- Waveform peaks tool
The filter supports two rolloff slopes selectable via the FX modal "Slope" dropdown:
| Rolloff | Implementation | Use Case |
|---|---|---|
| -12 dB/oct | Single BiquadFilterNode | Gentle slope, default |
| -24 dB/oct | 2 cascaded BiquadFilterNodes | Steeper, more surgical |
Hot-swapping rolloff requires reconnecting the audio graph (disconnect old filter, create new, reconnect prev → Filter → next node).
Compressor, Distortion, Ring Modulator, and Tremolo use lazy instantiation — nodes are only created when the user first interacts with them. Each _ensure*() method splices the new node into the existing audio chain by disconnecting adjacent nodes and reconnecting through the new effect. This avoids unnecessary CPU overhead for unused effects.
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.