ichor
A collaborative, hackable, browser-native synthesizer that grows with you.
ichor is a browser-native synthesizer built in Svelte 5 + SvelteKit. Two oscillators with swappable engines (subtractive, FM, AM, Karplus-Strong), a multi-mode filter, draggable LFOs, an effects rack, an arpeggiator, live coding via Strudel, and real-time collaborative sessions over Cloudflare Durable Objects. Nothing to install. Bring headphones.
Synthesis
- Two oscillators with swappable engines: BASIC (subtractive), FM, AM, and PLUCK (Karplus-Strong)
- Waveforms: sine / square / saw / triangle / pulse (with adjustable width)
- Per-osc octave / semi / fine detune, level, pan, enable
- Unison (1–7 voices) with stereo spread for fat supersaws (BASIC engine)
- Sub oscillator (1 or 2 octaves below) for added low-end weight
- Noise generator (white / pink / brown) with level + pan
- AHDSR envelope with a draggable visual editor and matching knobs
- Multi-mode filter (lowpass / highpass / bandpass / notch) with cutoff + resonance
- LFO → cutoff with rate, depth, shape (sine / square / saw), enable
- Voice modes: poly / mono / legato / scale, with glide time
- Glide implemented via parallel mono
Tone.Synthinstances (PolySynth doesn't support portamento) - Pluck voicing uses a per-note
PluckSynthMap (PluckSynth isn'tMonophonic)
- Glide implemented via parallel mono
Effects rack (right drawer)
- Distortion, Bitcrusher, Chorus, Ping-Pong Delay, Reverb
- Each with wet/dry mix and individual enable; chained left-to-right
- All effect params are addressable from Strudel patterns
Performance & I/O
- Multi-octave keyboard (3 octaves) with mouse glissando, two rows of keybinds (
a–j/k–'),z/xto shift octave - Pitch bend wheel (±2 semitones, springs back) and mod wheel (boosts LFO depth)
- Web MIDI input support
UI
- Live oscilloscope + spectrum analyser as the page header background
- 300+ built-in presets in a floating, physics-based picker (drag, hover, click to load)
- Live JSON patch editor on the left, Strudel + Effects drawers on the right — all built on CodeMirror 6 with custom Catppuccin highlighting
- Three Catppuccin themes: latte, mocha, sky
- Beginner's guide modal: 15 lessons with embedded interactive visualizers (knob, waveform, envelope, filter)
- Lucide icons throughout
Networking & live coding
- Live multiplayer sessions via Cloudflare Durable Objects: click "share" → get a URL → anyone who opens it edits the same patch in real time, with presence count
- Live coding via a custom Strudel lookahead scheduler (bypassing broken
@kabelsalatinternals): write patterns likenote("c3 eb3 g3 bb3").s("ichor").cutoff(sine.range(0.1, 0.9))in the side drawer; every synth + effect param is a Strudel-addressable channel.
Stack
- Svelte 5 (runes) + SvelteKit
- TypeScript + Zod (canonical patch schema, validated at every write)
- Tailwind CSS v4 (Catppuccin tokens via
@theme inline) - Tone.js on top of the Web Audio API
- Cloudflare Workers (adapter:
sveltekit-adapter cloudflare+cfTarget:workers) - Vite for dev & build
- ESLint + Prettier
Getting started
pnpm install
pnpm dev # http://localhost:5173
pnpm dev -- --open
Build
pnpm build
pnpm preview
Run locally only
It's a static-friendly SvelteKit app; pnpm preview is enough for local-only usage. No external services are required for layers 0–3.
Project layout
src/
lib/
audio/
patch.ts # Zod schema, types, defaults, validators
engine.svelte.ts # AudioEngine: Tone graph, validated setters,
# subscribe API, write-source tagging
presets.ts # Built-in presets grouped by category
server/
PatchSession.ts # Durable Object: holds canonical patch, fans out updates
audio/
session.svelte.ts # Client-side websocket sync, coalesced per-frame
audio/
strudel.svelte.ts # Custom lookahead scheduler + param routing
ui/
Keyboard.svelte # Multi-octave keyboard, glissando, octave shift
SoundDesign.svelte # Two-row grid: osc1 / osc2 / filter then env / lfo
OscCard.svelte # Per-osc swappable engine UI (BASIC/FM/AM/Pluck)
Envelope.svelte # Draggable AHDSR + knob row, ResizeObserver-sized SVG
LFOWave.svelte # Inline LFO shape preview
Knob.svelte # Circular knob (drag, wheel, dblclick, exponential curves)
Visualizer.svelte # Canvas oscilloscope + spectrum, theme-aware
ThemeToggle.svelte # latte / mocha / sky picker
PatchEditor.svelte # CodeMirror 6 JSON editor in a sliding drawer
StrudelDrawer.svelte # CodeMirror 6 live coding drawer
EffectsDrawer.svelte # Distortion / bitcrusher / chorus / delay / reverb
PitchModWheels.svelte # Pitch bend (sprung) + mod wheel
PresetCloud.svelte # Verlet-physics preset picker
Guide.svelte # 15-lesson beginner modal w/ live visualizers
guide/ # GuideKnob, GuideWave, GuideEnvelope, GuideFilter
routes/
+page.svelte # Layout: full-bleed visualizer header → controls → keys
layout.css # Catppuccin tokens (latte / mocha / sky)
Roadmap
Built in public, in small increments. The rough direction, loosest to firmest:
- next: patch persistence (save your own presets to localStorage / cloud)
- sampling (mic, file, tab capture)
- export (WAV / MP3 / stems / MIDI)
- granular / FM / wavetable synths
- AI helpers (vibe → arrangement, "more space", etc.)
- accessibility, gamepad / Pi controllers
- guided exploration & genre templates, Synplant-style sound exploration
Nothing here is committed to. It's a list of things that would be cool, in roughly the order they make sense to build. Sequencing is intentionally out of scope — that lane belongs to Strudel.
Why "ichor"
The fluid in the veins of the gods. Short, looks good in lowercase, and the domain was free.
License
MIT.
Built With
- cloudflare
- svelte
- sveltekit
- tailwindcss
- tone.js
- typescript
- vite
- zod
Log in or sign up for Devpost to join the conversation.