An analog-hardware-styled web DAW built with TypeScript and the Web Audio
API. No backend, no dependencies: patterns, samples, effects, the playlist
and the wall layout all live in the browser and persist to localStorage.
The interface is a canvas-style studio room — drag hardware modules (step
sequencer, piano roll, playlist, mixer, transport) around a 3400×2800 wall,
zoom with Ctrl+wheel, and arrange a full track: 16-step sequencing,
piano-roll notes, per-track reverb/delay/EQ, a synth editor (waveform +
ADSR), sample trimming and pitch, loop regions, swing/groove, a master bus
with limiter, WAV + stem export, computer-keyboard / Web MIDI live input,
a MODULES dock for arranging the studio wall, sample trim/reverse/pitch,
and gesture-based undo/redo.
The old UI is archived in git tag legacy-vscode-ui.
npm install
npm run build # compiles src/**/*.ts → dist/
python3 -m http.server 8000Then visit http://localhost:8000.
The main interface is a canvas-style "studio room": a large world
(3400×2800) with absolutely-positioned hardware modules you can drag by
their brushed-metal headers. Pan with native scroll, zoom with
Ctrl+wheel (or the HUD — / % / + / ⌂ buttons).
Every module is also listed in the MODULES dock — a slide-out sidebar on
the left edge (MODULES tab or the HUD ▤ button). Drag a chip onto the
wall to place its module, drag an on-wall chip to relocate it, click a chip
to auto-pan to it, and use the ⏏ button in a header to put a unit away.
Double-clicking a header collapses/expands the body; docked/collapsed state
persists with the wall layout (voidstation-wall-v1).
Modules (one feature = one file in src/ui/):
| Module | Description |
|---|---|
| Transport | play/stop, REC, BPM, swing, loop toggle, pattern name, SAVE / OPEN / NEW / EXPORT / EXPORT STEMS / EXPORT PROJ / IMPORT PROJ, status readout; shortcuts Space, R, Ctrl+S/O/N, Ctrl+Z/Y (Ctrl+Shift+Z = redo) |
| Step sequencer | 16 steps × 5 tracks, rubber MPC pads, playing-column highlight, per-step velocity accents (right-click or Shift+click an active pad), row tools: clear / shift left / shift right / re-roll accents |
| Piano roll | 24 pitch rows (B4..C3) × 16 steps, key strip with preview, draw / resize / erase, playing-cell highlight |
| Playlist | 20 bar cells, pattern switching, clip drag & drop, loop region with draggable handles |
| Mixer | 5 analog channels: pan knob, LED meter, mute/solo, volume fader, channel click selects the piano-roll track |
| Synth editor | per-track waveform (sine/tri/sqr/saw/noise) + ADSR envelope sliders with note preview |
| Master section | master volume, brickwall limiter (toggle + threshold), real-time output LED meter |
| Live controller | play the selected track from the computer keyboard (Z S X D C V G B H N J M…, -/= octave) or a Web MIDI device, with held-note voices |
Module positions persist across reloads (voidstation-wall-v1).
- Audio engine (
src/audio/engine.ts): lazyAudioContext, per-track insert chain (voice → effects → gain → pan → master), 16-step Web Audio scheduling, BPM, offline render to WAV export. - Effects: reverb (ConvolverNode + procedural stereo IR, Room/Hall/Plate), delay (feedback loop), 3-band EQ (lowshelf 250 Hz / peaking 1 kHz / highshelf 4 kHz) — per-track, live and in export. Reorder the insert chain by dragging an effect's name; the ▲▼ buttons still work.
- Samples: load a sample per track, canvas waveform with draggable start/end trim handles, preview by clicking the wave, tape-style pitch (-24..+12 semitones) and a REVERSE toggle.
- Velocity accents: each sequencer step carries a velocity (1.0 / 0.7 /
0.45). Right-click (or
Shift+click) an active pad to cycle its accent; dimmer pads play softer. Applied to both sample triggers and synth notes, live and in the WAV export, and included in save/export. Row tools clear, rotate (shift left/right) or humanize (re-roll accents) a whole track row. - Swing/groove: odd 16th steps play up to 1/3 step later (SWING slider in the transport bar; 100% = full triplet feel). Applied live and in the WAV export; the metronome stays straight so it remains a timing reference.
- Synth editor: per-track waveform (sine/triangle/square/saw/noise) and ADSR envelope with sliders and a preview note; part of save/export.
- Master bus: master volume plus an optional brickwall limiter
(
DynamicsCompressor, toggle + threshold). A real-time output LED meter is fed by anAnalyserNodetapped after the limiter. All audible live and in the WAV export. - Live controller: held-note synth voices (attack → decay → sustain until release) from the computer keyboard or any Web MIDI input device; octave shift, on-screen keys, device hot-plug.
- Note recording: arm REC (button or
R) while the transport plays and anything played on the live controller is quantized into the current pattern's piano roll — nearest-step start, note-off defines the length, velocity is kept. The whole take is a single undo entry; an empty take leaves the history untouched. - Pattern copy/paste: COPY grabs every track of the current pattern into an in-memory clipboard, PASTE overwrites the active pattern (single undo entry).
- Sample pitch: per-track tape-style playback rate in semitones (-24..+12), applied live and in exports; a fresh sample load resets it.
- Stem export:
EXPORT STEMSrenders every track that plays anything in the export region to its own WAV file (voidstation-stem-01-kick.wav, …), fx chains and master bus included. - Piano roll: draw / resize / erase notes, real-time playback preview.
- Playlist: patterns, clip drag & drop (move/swap), loop region rendered into the WAV export.
- Mixer: pan, mute/solo, volume fader — all audible live and in export.
- Undo/redo: snapshot history (limit 20), transaction per gesture,
Ctrl+Z/Ctrl+Y/Ctrl+Shift+Z. - Persistence: project save/load to
localStorage(voidstation-project-v1), wall layout separately, plus project export/import as a JSON file (EXPORT PROJ/IMPORT PROJ); imported projects load in memory until you hit SAVE.
index.html — shell, links src/styles/*.css, loads dist/main.js
src/main.ts — bootstrap: build UI, auto-load project
src/audio/engine.ts — Web Audio context, scheduling, effects, offline render
src/audio/wav.ts — WAV encode for export
src/types.ts — shared types
src/ui/theme.ts — track names/colors, storage keys, clamp
src/ui/hardwareWall.ts — the canvas wall: pan/zoom/drag modules
src/ui/rack.ts — chassis primitives (panel, LED, button, readout, group)
src/ui/topbar.ts — fixed header (brand, transport, sampler toggle)
src/ui/drawer.ts — slide-out sampler panel
src/ui/transport.ts — transport: bar controls + file-ops wall module
src/ui/stepSequencer.ts — 16×5 pad sequencer module
src/ui/pianoRoll.ts — piano roll module
src/ui/playlist.ts — playlist module
src/ui/mixer.ts — mixer module
src/ui/fx.ts — per-track reverb/delay/EQ rack
src/ui/sampler.ts — sample load/trim/preview
src/ui/instrument.ts — per-track synth editor (waveform + ADSR)
src/ui/master.ts — master bus: volume, limiter, output meter
src/ui/keys.ts — live controller: computer keyboard + Web MIDI
src/ui/app.ts — assembly: engine + wall + modules + wiring
tests/ — node:test suites (headless engine + WAV encoder)
run via `npm test` against the compiled dist/
src/styles/ — theme/base/racks/topbar/transport/drawer/sequencer/pianoroll/playlist/mixer/fx/sampler/instrument/master/keys/dock
dist/ (compiled JS) and node_modules/ are git-ignored; the engine
sources live in TS, the build runs via tsc into dist/.
Muted cold-dark base (#0F3040), brushed-metal panels and headers with
screws, VFD/CRT readouts with amber glow, rubber MPC pads, analog knobs and
faders — inspired by image_5. Palette tokens live in
src/styles/theme.css.
