how to build

Project · ★★ · Intermediate

Beat Lab

A drum machine in your browser. Sixteen steps, four drums, and every sound is made from scratch out of oscillators and noise, with no sample files. Drag the swing slider and a stiff beat starts to groove. The whole beat lives in the link, so you can send a beat to a friend in a chat message. Then flip it into a rhythm game: notes scroll towards a line and you tap in time for a score.

You need

What you'll learn

What this shows the agent can do

The brief

Make a new folder for the project. Copy the brief below into a file called BRIEF.md in that folder, or download BRIEF.md. Open the agent in the folder and say:

Read BRIEF.md and start with milestone 1. Stop after each milestone so I can check it.
# Beat Lab — a drum machine and rhythm game (★★)

Build a 16-step drum machine in the browser. Four rows (kick, snare, closed hat, clap), sixteen buttons each. Press play and the pattern loops. Every sound is made from scratch with the Web Audio API, from oscillators and noise, with no sample files. Tempo and swing sliders change the groove. The whole beat is saved in the page address, so sending the link sends the beat. Then add a rhythm game mode: the beat plays, notes from one row scroll towards a line, and you tap in time and get an accuracy score.

## Done looks like

- A 4 by 16 grid of step buttons, a play/stop button, tempo (60 to 180 BPM) and swing (0 to 50 percent) controls, and a volume and mute per row.
- Kick, snare, closed hat and clap are all synthesized. No audio files in the project.
- Timing stays tight: at 120 BPM the loop does not drift or stutter, even while you move the sliders or switch tabs briefly.
- A playhead highlights the current step, in time with what you hear.
- Add-on: the address bar holds the pattern, tempo and swing (for example `#v1-t120-s20-` then hex). Opening that link in another browser plays the same beat.
- Rhythm mode: pick a row, notes scroll to a hit line, tap (Space, or a big pad on a phone). Each tap is judged Perfect, Good or Miss. A results screen shows accuracy percent and best combo.
- A calibration screen measures your device's delay so taps are judged fairly.
- Works on a phone. No console errors.

## Constraints

- Static files, no build step: `index.html`, `style.css`, `audio.js`, `app.js`. No frameworks, no audio libraries.
- Sounds: kick is a sine oscillator whose pitch drops from about 150 Hz to 50 Hz in 0.1 s with a fast gain envelope. Snare is white noise through a high-pass filter mixed with a short triangle tone. Closed hat is noise through a high-pass filter around 7 kHz with a 50 ms decay. Clap is three quick noise bursts through a band-pass filter.
- Scheduling: never play sounds straight from `setInterval` or `setTimeout`. Use a lookahead scheduler: a timer every 25 ms schedules every step due in the next 100 ms at exact `AudioContext.currentTime` values. The drawing loop (`requestAnimationFrame`) reads a queue of scheduled steps to move the playhead.
- Swing: every second sixteenth note is delayed by `swing × step length`, with swing from 0 to 0.5.
- The `AudioContext` is created or resumed on the first tap or click, because phones block sound until then.
- Pattern in the URL hash, updated with `history.replaceState` as you edit (no new history entry per click). Each row is 16 bits written as 4 hex characters.
- Rhythm judging uses the audio clock, not `Date.now()`. Perfect within 40 ms, Good within 90 ms, otherwise Miss. The calibration offset is saved in localStorage.
- No server, no tracking, no accounts.
- Phone works: buttons at least 40 px, the grid scrolls inside its own box if it must, never the whole page sideways.

## Milestones

1. **One sound.** A button that plays a synthesized kick. Create the `AudioContext` on first tap.
   Check: tapping the button on a phone plays a punchy kick every time, with no delay you can hear.
2. **Four drums.** Add snare, closed hat and clap as functions that take a start time. A test row of four buttons plays each.
   Check: each button plays a sound that is clearly a snare, a hat or a clap, not just a beep.
3. **Grid and scheduler.** The 4 by 16 grid and the lookahead scheduler at a fixed 120 BPM. Clicking a step toggles it while playing.
   Check: a four-on-the-floor kick with snares on steps 5 and 13 loops for two minutes without drifting, while you click other steps.
4. **Tempo, swing, playhead, mix.** Tempo and swing sliders that change the groove on the next step. A playhead synced from the scheduled-steps queue. Volume and mute per row.
   Check: dragging swing to 50 percent turns straight hats into a shuffle, and the playhead stays exactly on the beat you hear.
5. **Rhythm mode.** Pick a row. Its notes scroll down to a hit line, timed from the audio clock. Tap to hit. Judge Perfect, Good, Miss. Show combo and a results screen with accuracy.
   Check: tapping exactly on the notes gives mostly Perfect; tapping randomly gives mostly Miss.
6. **Calibration and phone pass.** A calibration screen: a click plays 8 times, you tap along, the average offset is saved and used in judging. Check layout on a real phone.
   Check: after calibrating, your accuracy on a simple pattern goes up; the whole app works on a phone with sound on.
> That is the whole instrument and the game. Sharing comes last, once you have a beat worth sending.
7. **Share by link.** Encode pattern, tempo and swing in the hash. Load from the hash on open. A "Copy link" button.
   Check: build a beat, copy the link, open it in a different browser: the same beat, tempo and swing play.

## Stretch

- Two more rows: low and high toms with adjustable pitch.
- Pattern A and B with a chain button, so you get a 32-step loop.
- Accent per step (louder hit) with a long press.
- Export a WAV of four loops using `OfflineAudioContext`.
- A daily rhythm challenge pattern, seeded by the date.
- Play the pads from a MIDI keyboard with Web MIDI, where the browser supports it.

## Leave out

- Sample files, Tone.js or any audio library.
- A server, accounts, saving beats online.
- A full music editor: no piano roll, no song mode beyond A and B.

Start by reading WRITING.md and the guide chapter on data if you need storage.

Milestones

The same milestones as the brief. Tick each one off when its check passes. Do one per sitting if you like. The dot in the list marks the point where you have something that works on its own. Everything after it makes it remember things or work for more than one person. Stop at the dot and use what you built before you go on.

  1. One sound. A button that plays a synthesized kick. Create the AudioContext on first tap.

    Check: tapping the button on a phone plays a punchy kick every time, with no delay you can hear.

  2. Four drums. Add snare, closed hat and clap as functions that take a start time. A test row of four buttons plays each.

    Check: each button plays a sound that is clearly a snare, a hat or a clap, not just a beep.

  3. Grid and scheduler. The 4 by 16 grid and the lookahead scheduler at a fixed 120 BPM. Clicking a step toggles it while playing.

    Check: a four-on-the-floor kick with snares on steps 5 and 13 loops for two minutes without drifting, while you click other steps.

  4. Tempo, swing, playhead, mix. Tempo and swing sliders that change the groove on the next step. A playhead synced from the scheduled-steps queue. Volume and mute per row.

    Check: dragging swing to 50 percent turns straight hats into a shuffle, and the playhead stays exactly on the beat you hear.

  5. Rhythm mode. Pick a row. Its notes scroll down to a hit line, timed from the audio clock. Tap to hit. Judge Perfect, Good, Miss. Show combo and a results screen with accuracy.

    Check: tapping exactly on the notes gives mostly Perfect; tapping randomly gives mostly Miss.

  6. Calibration and phone pass. A calibration screen: a click plays 8 times, you tap along, the average offset is saved and used in judging. Check layout on a real phone.

    Check: after calibrating, your accuracy on a simple pattern goes up; the whole app works on a phone with sound on.

  7. That is the whole instrument and the game. Sharing comes last, once you have a beat worth sending.
  8. Share by link. Encode pattern, tempo and swing in the hash. Load from the hash on open. A "Copy link" button.

    Check: build a beat, copy the link, open it in a different browser: the same beat, tempo and swing play.

Make it yours

Once it works, pick one of these and ask for it as a new milestone.

If it goes wrong

No sound at all on the phone.

Phones block audio until the first tap. On an iPhone, the silent switch can also mute web audio. Say this to the agent:

There is no sound on my phone. Make sure the AudioContext is created or resumed inside the first tap handler, and show a "Tap to start" screen.

The beat drifts or stutters, worse when you move a slider.

Sounds are being triggered straight from setInterval, which the browser delays when it is busy. Say this to the agent:

The loop drifts and stutters. Switch to a lookahead scheduler: a 25 ms timer that schedules every step due in the next 100 ms at exact AudioContext times.

Rhythm mode says Miss when you know you hit it.

Every device has some output delay. Without calibration the judging is unfair. Say this to the agent:

Rhythm mode judges my hits late. Use the audio clock for tap times, subtract the saved calibration offset, and show me the offset in milliseconds after each tap.