How every note of a mixtape toy is made in your browser

October 26, 2026

Small Beats is a mixtape toy: pick a sound, switch parts on and off, pick a buddy for the label, and send the link to someone. Every note they hear is synthesized in their browser as it plays. There are no audio files, no samples and no AI anywhere in it.

The music engine is one JavaScript file of about 47 KB, 17 KB gzipped, built on the Web Audio API. A whole song travels as a link of about 100 characters. This is how it works, and what was hard.

A song is a number

A tape link holds a short JSON array, base64url-encoded: the name, the cassette shell, the buddy, six settings (sound, drums, bass, keys, texture, speed), one integer seed and, if you played along on the keyboard, your two bars of notes (three characters a note: when, which step of the scale, how long).

[1, "GROCERY RUN", 0, 1, 1, 3, 0, 1, 1, 1422687053, 49]

The seed goes through a small hash (FNV-1a) into a seeded random number generator. Everything structural comes from that generator: the key, the mood, the two chord progressions, and the hook. So the same link gives everyone the same song's bones.

The six settings give 3,600 combinations of parts, and the seed has about 2.1 billion values. That is roughly 7.7 trillion possible tapes, though plenty of neighbours sound alike.

One honest caveat: the bones are fixed, but the small stuff is not. Timing jitter, velocities and the improvised riffs between hooks use the ordinary Math.random(). Two people hear the same key, chords and hook, played by a slightly different band each time. I like that: it's closer to a band than a recording.

Why any combination fits

Every part follows the same chord chart, so drums, bass, keys and tune can be switched on in any combination and still agree.

The seed picks one of three moods. Each mood is a scale plus a handful of four-chord progressions, written as root and chord quality per bar:

2m9 7dom9 0maj9 9m7      ii9 – V9 – Imaj9 – vi7, in whatever key the seed chose
0m9 5m7 8maj9 7dom7b9    a minor-key loop with a flat-nine pull back home

A tune uses two progressions: one for the first 16 bars of a 32-bar cycle, another for the second.

Three small rules keep it sounding played rather than generated:

The hook, and how a tune develops

Each tune has a two-bar hook built from a tiny cell: two or three notes, the same cell moved up or down a step, and a long note to land on. That shape (statement, answer, resolution) is most of what makes a melody feel intentional.

The hook comes back every eight bars and develops on a four-step cycle:

  1. As written.
  2. With a new ending.
  3. A rest, sometimes filled with a short riff improvised from pieces of the hook.
  4. Moved up a step.

The second half of the tune gets its own hook, and a fresh one every 64 bars, so a tape left on for an hour keeps moving. Late in each 32-bar cycle the drums drop out for a few bars, leaving only hats, and come back in. That breakdown is the cheapest trick in the engine, and the most effective.

The instruments, all in code

Every voice is built from oscillators, noise and filters at the moment it plays.

PartHow it's made
RhodesTwo-operator FM: a sine modulating a sine, with the modulation depth decaying fast for the bell-like attack, plus a slightly detuned sine for warmth
GuitarKarplus–Strong plucked string: a burst of filtered noise fed into a short delay loop that averages itself; a comb filter sets where the string is plucked. Each note is rendered once and cached, in three takes, so repeated strums aren't identical
PadDetuned saw pairs through a lowpass filter that opens and closes over the chord
8-bitPulse waves at 12.5% and 25% duty, built from Fourier series with createPeriodicWave
BassWarm (sine and triangle), deep (a tighter sub) and synth (saw and square through a plucky filter)
KickA sine swept from 110 Hz to 42 Hz in about 130 ms
Snare, clap, rimBand-passed noise bursts, the snare with a 190 Hz tone under it
Hats, shakers, brushesHigh-passed and band-passed noise with very short envelopes
KeyboardA two-oscillator synth with a sub, a filter envelope and a glide between quick notes, voiced per style (warm for lo-fi, a stab for house, glassy for ambient, a square lead for 8-bit, dark and echoing for dub). Every key is a note of the song's pentatonic scale, so nothing you play clashes, and it plays through the song's own tempo echo
Chip drumsNoise held for six samples at a time, which mimics the stepped noise of old sound chips

None of this is new. Most of it is textbook synthesis from the 1970s and 80s. What surprised me is how far plain Web Audio nodes go when the envelopes are right.

Feel

Perfect timing sounds like a machine, so three things loosen it up.

The cassette chain, and weather that never loops

Lo-fi tapes run the whole mix through a small model of a worn cassette:

The textures are generated too, never looped:

Because the timing is random rather than a recording, an hour of rain never repeats a pattern you could notice.

Scheduling on the audio clock

JavaScript timers are too jittery to play music, so nothing is played "now". A plain setInterval wakes every 400 ms and schedules whole bars up to 2.2 seconds ahead, against the audio context's own sample-accurate clock. This is the two-clock pattern from Chris Wilson's A Tale of Two Clocks. A busy main thread, or a tab in the background, never makes the beat stumble.

The same scheduler also reports every note as it's queued. That stream drives the visuals: the buddies on the screen hop on beats 1 and 3, the step lights chase the beat, and the player piano lights each note on the keyboard. Pause is AudioContext.suspend(), so a tune picks up exactly where it stopped.

What was hard, and how I built it

I'm a guy who likes mixtapes, 808s, retro games and dinosaurs. Small Beats is all four in one tab.

I'm old enough to remember trading cassette tapes in high school. Small Beats is sort of the digital version of that. It's hosted on GitHub, with AWS Amplify pointed at it.

I used Claude (Opus 5.5) to help with the procedural generation algorithms. The music itself is still made by plain code in your browser, with no AI involved when a tape plays.

Try it

It's free, with no account, and it works offline once loaded. Make a tape, roll the dice until the melody grabs you, and send the link to someone. If you make one you like, I'd love to hear it: hello@smallbeats.com.

▶ MAKE A TAPE