.track — a tiny language for making music

.track is a small, readable text language for writing beats and songs. You type a few lines, press play, and hear it — and when you edit the text, the sound changes live. It runs in the browser on the Web Audio API (no install, no plugins), and it’s MIT-licensed.

This guide teaches the whole language from scratch. Almost every example is a complete, paste-able song — copy any block, hit play, and it makes a sound. The few that aren’t are marked.

bpm 120
steps 16

kick  x...x...x...x...
hat   ..x...x...x...x.

↑ That’s a real song: a four-on-the-floor kick with off-beat hats.

When you’ve finished here, language-reference.md is the exact, exhaustive spec for everything the language accepts.


Running it

If you’re running the project locally:

npm install
npm run dev      # opens a local URL — edit the text, hit ▶ Play
npm test         # run the test suite
npm run build    # build everything in the workspace

1. Your first beat

A song is made of rows. Every row has a name and a pattern:

kick  x...x...x...x...
  │       └─ the pattern: when this instrument plays
  └─ the name: which instrument

The name picks the sound (kick is a kick drum), and the pattern is a grid you read left to right, one cell per step:

Paste this and hit play:

# my first beat
bpm   120
steps 16

kick  x...x...x...x...
hat   x.x.x.x.x.x.x.x.
clap  ....x.......x...

Now the two settings at the top. bpm is the tempo (beats per minute — bigger is faster), and steps is how many cells make one bar (16 = sixteenth notes, the usual choice). Lines that start with # are comments. The row’s length has to match steps — count the cells, there are 16. Built-in drum names: kick, hat (also hihat / hh), clap, snare.

Try this: change 120 to 160 and hear it sprint.


2. Loud and soft

A real drummer doesn’t hit everything equally hard. The grid has three loudness marks, not just one:

Same kick-and-hat beat twice. First flat, every hat identical:

steps 16

kick  x...x...x...x...
hat   x.x.x.x.x.x.x.x.

Now the same beat, breathing — ghosts on the in-between hats, accents landing on the beat:

steps 16

kick  x...x...x...x...
hat   X.o.X.o.X.o.X.o.

Play them back to back. The notes are identical; only the loudness changed, and the second one grooves.


3. A melody

Paste this and hear a melody:

steps 16

lead  C4 . E4 . G4 . E4 . C4 . E4 . G4 . C5 .

For pitched instruments you write a note per step, separated by spaces. Each one is a note name like C4 or E4: a letter AG, an optional # (sharp) or b (flat), then an octave number. A4 is 440 Hz; a bigger octave number means a higher pitch. Examples: C4, A1, F#3, Eb2, G#5.

Between notes you’ll see two marks that shape how long a note rings: . (rest) and _ (hold). They sound different, and the difference is the whole feel of a melody:

Hear it. First, every note held long and connected (legato) — the line breathes as one phrase:

steps 16

lead  C4 _ _ _ G4 _ _ _ A4 _ _ _ E4 _ _ _

Now the same notes chopped short with . — each one a quick, detached stab (staccato):

steps 16

lead  C4 . . . G4 . . . A4 . . . E4 . . .

Play them back to back. Same pitches, completely different mood: the first flows, the second pokes. Mixing _ and . in one line is how you phrase a melody.

Built-in pitched names: bass, lead, pad (any other name gets a plain saw synth).


4. Stay in key

Hitting a “wrong” note is the easiest way to make a melody sound off. The fix is a scale line. Pick a key once, then write degree numbers1 is the first note of the scale, 2 the next, and so on, walking up. The magic: with degrees, every number is in key, so you literally can’t hit a wrong note.

Here’s a melody written with note names:

scale A minor

lead  A3 . C4 . E4 . C4 . A3 . D4 . E4 . A4 .

And the exact same melody written as degrees in A minor (1=A3, 3=C4, 5=E4, 8=A4):

scale A minor

lead  1 . 3 . 5 . 3 . 1 . 4 . 5 . 8 .

A scale line is scale ROOT FLAVOUR — the flavours are major, minor, dorian, and penta. Once you’re using degrees, you can shuffle the numbers around all day and it always stays musical.

Try this: swap minor for major — one word, new mood.


5. Chords

To play several notes at once, join them with + — no spaces. With note names:

steps 16

pad  A3+C4+E4 . . . . . . . D4+F4+A4 . . . . . . .

And the same idea with degrees (a 1+3+5 chord is the classic “stack every other note of the scale”):

scale A minor
steps 16

pad  1+3+5 . . . . . . . 4+6+8 . . . . . . .

Chords work everywhere a single note does, and you can even mix names and degrees inside one (C4+5).


6. Less typing

Repeating the same mark gets old. A count is a number stuck to a mark: 4x is four hits, 7_ is seven holds, 8. is eight rests. A whole bar of sixteenth-note hits is just 16x:

steps 16

kick  4x 4. 4x 4.
hat   8. 8x
clap  4. 4x 4. 4x

One spacing trap, worth burning into memory:

clap  3.        ← three rests   (number glued to the mark)
clap  3 .       ← degree-3, then one rest   (a SPACE changes everything)

Counts only work on the five marks (. _ o x X). 4C4 is not four C4 notes — it’s an error.


7. Your own sounds

inst defines what a name sounds like. It makes no sound by itself — it’s a recipe the matching row uses. The easiest win is to start from a preset — a ready-made sound:

inst lead = preset pluck

lead  C4 . E4 . G4 . E4 . C4 . E4 . G4 . C5 .

Presets: pluck, reese, sub, stab, softpad, brightlead, bell, organ, plus the fat ones — supersaw, wobblebass, epiano, choir (see “Fatter, weirder, wilder” below).

Try this: swap in preset bell instead and listen.

You can tweak a preset by adding parameters after it. Three handy ones:

inst lead = preset pluck cutoff 3000

lead  C4 . E4 . G4 . E4 . C4 . E4 . G4 . C5 .

When you want full control, build from a raw wave instead of a preset — same parameters apply. The waves are saw (sawtooth), square, sine, and triangle (tri):

inst lead = saw cutoff 1800 attack 0.01 release 0.25

lead  C4 . E4 . G4 . E4 . C4 . E4 . G4 . C5 .

A sample plays a recorded clip instead of a synth — perfect for real-sounding drums:

inst kick = sample 808kick

kick  x...x...x...x...

And a kit sets up several instruments in one line:

use kit 808

kick  x...x...x...x...
clap  ....x.......x...

Kits: synthwave, house, chip, and 808 (real sampled drums).

Real recorded instruments (sample packs)

A single sample 808kick plays one recorded clip. A sample pack is a whole recorded instrument — say a real violin, with a separate recording for each note, soft and loud takes, and a few slightly different versions of each so repeated notes don’t sound like a robot. Put the pack name in quotes and you can play it like any other instrument:

steps 4

inst vln = sample "violin"
vln  A4 C5 E5 _

The quoted name ("violin") tells the app to load that pack. Play softly and you hear the soft recordings; play harder (with accents) and the loud ones kick in — that’s a velocity layer. Hit the same note twice and it quietly rotates between takes — that’s round-robin, and it’s why it sounds alive instead of copy-pasted. Some packs even let you switch playing styles (plucked vs. bowed) by hitting a special keyswitch note. You don’t have to build packs to use them — just sample "name" and play.

Slides (glide)

Add glide to an instrument and its notes slide into each other instead of jumping — the pitch swoops from the previous note up or down to the next, like a singer or a slide whistle. The number is how long the slide takes, in seconds. It’s the secret behind the classic acid-bass portamento:

scale A minor
steps 16

inst bass = saw glide 0.08 cutoff 700 sustain 0.7

bass  1 _ _ _ 5 _ _ _ 4 _ _ _ 8 _ _ _

Each new note glides from the one before it. Turn glide up to 0.2 for a slow, drunken swoop, or down to 0 to switch the slide off and hear the notes snap.

Want a slide on one note only? Write it inline with ->: E4->G4 is a single note that starts on E4 and swoops up to G4 across its own step — no glide parameter needed.

steps 16

lead  C4 _ _ _ E4->G4 . . . A4 _ _ _ E4->C4 . . .

Fatter, weirder, wilder

A handful of parameters take a thin synth and make it huge. The fastest one is the supersaw preset — five detuned saws stacked into one wide wall of sound:

scale A minor
steps 16

inst lead = preset supersaw reverb 0.3

lead  1 . 5 . 8 . 5 . 1 . 5 . 8 . 5 .

Want to dial it yourself? unison N stacks N copies (up to 7) and detune (in cents) sets how far apart they spread. Add sub for a sine an octave down, drive to make it growl, and wobble to sweep the filter open and shut — that’s the dubstep wobble bass:

scale A minor
steps 16

inst bass = saw octave -1 cutoff 800 wobble 4 drive 0.3 sustain 0.8

bass  1 _ _ _ 1 _ _ _ 5 _ _ _ 4 _ _ _

wobble 4 sweeps four times a second; bump it to 8 for a faster gurgle. Other knobs in the same family: fm (bell/electric-piano tones — try preset epiano), crush (lo-fi bit-crush, 116 bits), and chorus (shimmery and wide — preset choir).

Samples can be mangled too. reverse 1 plays a sample backwards, and speed repitches it (0.5 = half speed and an octave down, 2 = double speed up an octave):

inst riser = sample 808clap reverse 1 speed 0.5

riser . . . . . . . . . . . . x . . .

New presets to start from: supersaw, wobblebass, epiano, choir.


8. Space

Three settings spread your sound out so it doesn’t all pile up in the middle:

One little song using all three, tastefully — bass dead-center, lead nudged right with a touch of room, plucky echoes off to the left:

scale A minor
steps 16

inst bass = preset sub
inst lead = preset pluck reverb 0.3 pan 0.3
inst echo = preset bell delay 0.4 pan -0.4

kick  x...x...x...x...
bass  1 . . . 1 . . . 5 . . . 5 . . .
lead  8 . 7 . 5 . 3 . 5 . 7 . 8 . 5 .
echo  . . 3 . . . 5 . . . 8 . . . 5 .

Tune the echo and the room

delay and reverb on an instrument are just send levels — how much of that voice goes into the one shared echo and the one shared room. You tune the buses themselves with fx lines (they can go anywhere in the file):

bpm   124
steps 16
scale A minor

fx delay  sync 3 feedback 0.4 wet 0.4
fx reverb room 0.9 wet 0.4

inst lead = preset pluck delay 0.4 reverb 0.3
lead 1 . . . 5 . . . 8 . . . 5 . . .

Make the pad breathe with the kick (duck)

In a lot of dance music the whole track briefly “pumps” in time with the kick — everything ducks out of the kick’s way, then swells back. Add duck to a voice (01) and it dips every time the kick row fires, recovering over about 120 ms. Hold a pad under a four-on-the-floor kick and you’ll hear it breathe:

steps 16
scale A minor

inst pad = preset choir duck 0.7

kick x...x...x...x...
pad  1+3+5 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

Turn duck up toward 1 for a hard pump, down toward 0 to switch it off. The duck always follows the row literally named kick.


9. Build a song

Group rows into named sections with [name xN] — play this section for N bars — then set the play order with arrange:

bpm   120
steps 16
scale A minor

[intro x2]
kick  x...x...x...x...
hat   ..x...x...x...x.

[drop x4]
kick  x...x...x...x...
clap  ....x.......x...
bass  1 . 1 . 5 . 5 . 6 . 6 . 4 . 4 .
lead  1 . . . 5 . . . 6 . . . 5 . . .

arrange intro drop drop intro

The intro is drums alone; arriving at the drop adds a bass line and a lead, so the change of section is something you actually hear.

Sections play in that order; live, the whole thing loops. With no arrange line, sections play in the order written.

Fade in, fade out

A section can fade in from silence or fade out to nothing — add fade in or fade out to its header (after the xN). The loudness ramps across the whole section: a fade in intro swells up, a fade out outro drifts away:

bpm   120
steps 16
scale A minor

[intro x2 fade in]
kick  x...x...x...x...
hat   ..x...x...x...x.

[drop x2]
kick  x...x...x...x...
clap  ....x.......x...
bass  1 . 1 . 5 . 5 . 6 . 6 . 4 . 4 .

[outro x2 fade out]
kick  x...x...x...x...
hat   ..x...x...x...x.

arrange intro drop outro

The fade scales each hit by where it lands in the section, so parts that keep re-triggering (drums, repeated stabs) fade most smoothly — a single long held chord only reflects the fade at the moment it’s struck.

A part can also evolve if its row is longer than one bar. A row that’s a multiple of steps is a multi-bar row — it keeps advancing instead of repeating every bar. Here the bass is 32 steps = two bars in a 16-step grid, so it walks a longer line:

scale A minor
steps 16

[drop x4]
kick  x...x...x...x...
bass  1 . . . 5 . . . 6 . . . 4 . . . 1 . . . 5 . . . 3 . . . 7 . . .

10. Make it human

Three settings take the stiffness out — and keep it reproducible:

Want a lead that actually sings? Add vibrato 0.3 to a synth instrument — a gentle 5.5 Hz pitch wobble that blooms in after the note settles (push it toward 0.6 for something more operatic).

inst lead = saw vibrato 0.3 cutoff 2000 release 0.3
bpm      120
steps    16
swing    0.12
humanize 0.4
seed     7

kick  x...x...x...x...
hat   o.x.o.X.o.x.o.X.
clap  ....X.......X...

Change seed to a different number and the wobble rearranges; change it back and your exact song returns.


11. Patterns that play themselves

Up to now you placed every hit. The language can also fill in patterns for you — grooves, rolls, and little surprises — so you type less and the music does more. The best part: the random bits are tied to seed, so “surprising” still means “the same every time you play.”

Instant grooves with spread

spread N sprinkles N hits as evenly as it can across the bar. It’s a famous trick — a lot of world-music and dance rhythms are exactly this. Type a number, get a groove:

bpm 124
steps 16

kick spread 4
hat  spread 11
clap spread 2 rotate 4

That’s a full groove: spread 4 is four-on-the-floor, spread 11 a busy off-kilter hat, and spread 2 rotate 4 nudges two claps onto the backbeat. Change one number — spread 5, spread 7 — and the whole feel shifts. rotate slides the pattern sideways without changing how many hits there are.

Builds with rolls *N

Stick *N on a hit and that one step bursts into N fast hits — a drum roll on a single beat. Great for fills and risers. Here a snare rolls harder and harder toward bar’s end:

bpm 128
steps 16

kick x . . . x . . . x . . . x . . .
hat  spread 11
snare . . . . x . . . . . . . x*2 x*4 x*3 .

N goes from 2 to 9. Put it on a held chord later and add arp to make it sparkle (below).

Basslines that evolve with <cycle>

Write a few notes inside < > and the row picks the next one each bar, looping around. One short line becomes a bassline that walks somewhere new every bar:

bpm 120
steps 16
scale A minor

kick spread 4
bass <1 5 6 4> . . . <1 5 6 4> . . . <1 5 6 4> . . . <1 5 6 4> . . .

Bar 1 plays 1, bar 2 plays 5, bar 3 6, bar 4 4, then it wraps. (Notice every spot in a single bar shows the same number — the cycle steps once per bar, not per step.)

Controlled surprise with [choice] and ?

[a|b|c] rolls a die each time it plays and picks one. ? after a hit means “maybe” — play it about half the time (?75 = 75% of the time). Both are tied to seed, so the surprise is reproducible: same seed, same song.

bpm 120
steps 16
scale A minor
seed 7

kick spread 4
hat  x? x? x? x? x? x? x? x? x? x? x? x? x? x? x? x?
lead [1|5|8] . . . [3|5|8] . . . [1|5|8] . . . [3|5|8] . . .

Change seed 7 to seed 8 for a different-but-fixed take; change it back and the first one returns exactly.

Chords that sparkle with arp

A chord normally hits all its notes at once. Add arp up (or arp down) and the chord spells its notes out as a quick run instead — an arpeggio:

bpm 120
steps 16
scale A minor

pad 1+3+5 . . . . . . . 4+6+8 . . . . . . . arp up

Put it together — a song that mostly writes itself

Almost every part here is generated. Drums from spread, an evolving <cycle> bass, a [choice] lead, a rolled snare build, and arped chords — pinned with a seed so it sounds the same every play:

bpm   124
steps 16
scale A minor
seed  7

inst bass = preset reese cutoff 520
inst lead = preset pluck cutoff 3000 reverb 0.2 pan 0.2
inst pad  = preset softpad reverb 0.3

[groove x4]
kick  spread 4
hat   spread 11
snare . . . . x . . . . . . . x . x*3 .
bass  <1 5 6 4> . . . <1 5 6 4> . . . <1 5 6 4> . . . <1 5 6 4> . . .
lead  [1|5|8] . . . [3|5|8] . . . [1|5|8] . . . [8|5|3] . . .
pad   1+3+5 . . . . . . . . . . . . . . . arp up

arrange groove groove groove groove

Tweak any single number — a different seed, spread 5, a new note in the <cycle> — and listen to how much changes for how little typing.


12. Split your work

Once a song grows, keep your sounds in one place and your song in another. In the app each file is a tab; a quoted use imports the instruments defined in another file:

inst lead = preset brightlead cutoff 3200
inst bass = preset reese
inst pad  = preset softpad

↑ a “synths” file — just sound definitions, so it makes no sound on its own (no rows to play).

use kit 808
use "synths"

[drop x4]
kick  x...x...x...x...
bass  A1 . A1 . C2 . C2 . G1 . G1 . A1 . A1 .
lead  A3 . E3 . A3 C4 . E4 . A3 . G3 . E3 . .

↑ a song file that borrows those sounds.

The rule that keeps you out of trouble: local definitions win. If you write your own inst lead in the song, it overrides the imported one (a calm note tells you it happened — it’s not an error).


13. What’s next

You now know the heart of the language. A few directions:

Now go make something. The fastest way to learn is to change one number and listen.


Quick reference

# comment            whole line only — NO end-of-line comments

bpm 120  steps 16  swing 0–1  master 0–1  seed N  humanize 0–1   header settings
beats 4               beats per bar (default 4); stepDuration = 60/bpm × beats / steps

name  x...x...        drum row    o ghost · x hit · X accent · . rest(cuts) · _ hold(sustains)
name  C4 . E4 _ …     note row    one entry per step
                        notes:   A–G, optional #/b, octave  (A4 = 440 Hz)
                        degrees: 1 2 3 …  (need a scale line; walk up the key)
                        chords:  C4+E4+G4   1+3+5   (join with +, no spaces)
                        counts:  4x 7_ 8.   GOTCHA: 3. = 3 rests, 3 . = degree 3 + rest
  row length = steps, or a multiple (a multi-bar row evolves across bars)

self-playing (token form):
  x*N      roll — N quick hits in one step (N 2–9)      x?  x?75  maybe (seeded)
  <a b c>  cycle — next element per bar    [a|b|c]  choice — random per event (seeded)
  ... rev | fast N | slow N | arp up|down  transforms after the pattern (left→right)
  name spread K [rotate R]                 Euclidean groove, K hits across the bar

scale ROOT FLAVOUR    major · minor · dorian · penta   (e.g. scale A minor)

[name xN]             section "name", N bars
[name xN fade in|out] fade the section up from / down to silence
arrange a b a …       play order (loops live); omit = file order

inst NAME = WAVE   [k v …]   saw/square/sine/triangle
inst NAME = preset P [k v …] start from a preset, optionally override
inst NAME = sample S [k v …] play a recorded sample
   params: cutoff resonance attack decay sustain release octave delay reverb pan glide vibrato duck
           unison detune sub fm hp bp hpf wobble drive crush chorus   (synth)
           reverse start speed                                        (sample only)
           glide = portamento seconds; vibrato 0–1 = 5.5 Hz pitch wobble; wobble Hz = filter LFO
           unison 1–7 + detune cents = fat
           duck 0–1 = sidechain pump, ducks when the `kick` row fires

fx delay  time S | sync N (tempo-synced steps, wins over time) | feedback 0–1 | wet 0–1
fx reverb room 0–1 | damp 0–1 | wet 0–1
fx master compress 0–1        master glue (0 = off)   — fx lines go anywhere, last wins per key

use kit NAME          synthwave · house · chip · 808
use "file"            import sounds from another file (local wins)

presets: pluck reese sub stab softpad brightlead bell organ supersaw wobblebass epiano choir
samples: 808kick 808snare 808hat 808clap

Made with the Web Audio API. License: MIT.