ksynth web is a browser-based live-coding environment for the ksynth synthesis language. It compiles ksynth scripts in WebAssembly and plays audio directly through the Web Audio API.
The interface has three functional areas:
0–F. Holds audio buffers ready to
trigger.A pad panel overlay turns the 16 slots into a
playable instrument. A patches button fetches
.ks files directly from the octetta/k-synth
GitHub repo.
The toolbar has save and load
buttons for persisting sessions as .json files, a
theme toggle (retro / dark / light), and
guide / readme buttons.
After building with build.sh, serve the directory with
any static file server:
python3 -m http.server 8080
Open http://localhost:8080. The status indicator reads
wasm ready in green when the engine is available. Audio
initialises on the first user gesture.
Type the following into the editor and press
Ctrl+Enter:
N: 4410
T: !N
W: w s +\(N#(440*(6.28318%44100)))
You should hear a 100ms sine wave at 440 Hz. A cell appears in the notebook showing the waveform. What each line does:
N: 4410 — 4410 samples = 100ms at 44100 HzT: !N — time index: a ramp from 0 to N−1W: ... — the output buffer. w s writes
samples. +\(N#...) is a phase accumulator.
440*(6.28318%44100) is the per-sample phase increment for
440 HzW is always the output. Every script must set it.
FM synthesis produces bell tones naturally. A carrier oscillator is
phase-modulated by a modulator: the modulation index starts high —
bright and complex at the attack — then decays fast. ksynth’s
right-associative parse makes FM natural: s P + Q parses as
s(P + s(Q)).
N: 88200
T: !N
A: e(T*(0-3%N))
I: 3.5*e(T*(0-40%N))
C: 440*(6.28318%44100)
M: 440*(6.28318%44100)
P: +\(N#C)
Q: +\(N#M)
W: w A*(s P+(I*s Q))
A — amplitude envelope, decays over ~2 secondsI — modulation index: starts at 3.5, decays to near
zero in ~50msP, Q — carrier and modulator phase
accumulatorsW — A × sin(P + I×sin(Q)), the FM
formulaExperiment: change 40 to
80 for a drier attack, 3.5 to 5
for something harsher, or the modulator to 616 Hz (ratio
1.4:1) for a tubular bell quality.
After running the bell script, find its cell in the notebook. Click
→0 to bank the buffer to slot 0. Click the slot card to
play it. Right-click for the context menu.
The playback rate for each pad is 2^(semitones/12).
Right-click the slot card and use set base rate to
transpose the whole instrument.
Bank a second sound to slot 1, then right-click pads to assign them to slot 1 with their own offsets. You now have two independent pitched voices across the grid.
Write ksynth code one assignment per line. Comments use
/.
Ctrl+Enter or Cmd+Enter to run. Variables
A–Z reset before each run — each script is
self-contained.
↑ at the first line loads the previous run.
↓ at the last line moves forward through history.
Ctrl+L clears the editor.
The single-line input at the bottom of the editor is a persistent calculator. Type any ksynth expression and press Enter:
2+2 => 4
440*6.28318 => 2763.8
N => 44100 (if N was set in the last run)
!8 => [0 1 2 3 4 5 ...] len=8
Variables persist between REPL entries and are shared with the main editor — run a script then inspect intermediate values here.
Type these directly in the editor or REPL and press Enter (or they fire as you type the third character in the editor):
| Command | Action |
|---|---|
\pV |
Play variable V scaled to audio levels |
\vV |
Open a graph window showing variable V |
The graph window shows the waveform, min/max values, zero line,
sample count and duration. V is any single letter
a–z.
Each run appends a cell. Click the header to toggle
between collapsed (first line only) and expanded (full code). Click
→ edit in the header to copy the code back
to the editor. Click the waveform to audition without
banking.
When a patch is loaded from the browser, the filename appears in the cell header.
16 slots in a 2×8 grid, indexed 0–F. Each
holds a buffer, a label, and a base pitch offset.
Right-click any slot for the context menu:
| Item | Action |
|---|---|
| Play | Trigger the slot |
| Set base rate | Pitch offset in semitones (±24). Affects all pads on this slot. |
| Download WAV | Export as 16-bit mono WAV |
| Rename | Set a custom label |
| Clear slot | Empty the slot |
Click pads to open. Escape
to close.
4×4 grid of 16 trigger pads. Each pad shows its slot, key shortcut, label, and semitone offset.
Keyboard triggers (editor must not have focus):
| Keys | Pads |
|---|---|
1–9 |
pads 0–8 |
0 |
pad 9 |
a–f |
pads 10–15 |
Right-click any pad to configure its slot and semitone offset. Scroll wheel adjusts semitone offset.
Presets: drum assigns pad N → slot N at 0 semitones. melodic assigns all pads to slot 0 at offsets −7 through +8.
save downloads the session as a .json
file containing all slot buffers, pad assignments, notebook history, and
editor text. load restores it completely — no scripts
are re-run.
Session files are compatible with ksynth-desktop.
patches fetches the file tree from
octetta/k-synth on GitHub. Type to filter. Click any file
to load it into the editor. Press Ctrl+Enter to run when
ready.
Variable isolation — A–Z
reset before each main editor run. The REPL preserves state between
entries.
W is the output — every script must set
W. No W → error cell.
Wavetable oscillator —
T t [freq n_samples] plays vector T as a DDS
oscillator. See readme for examples.
Literal arrays — every number after the first must
start with a digit 0–9. Use 0.5
not .5.
Sample rate — fixed at 44100 Hz.