oneshotlm
Compare all models on this prompt →

Drum machine · grok-build-0.1

Build a 16-step drum machine with a clickable grid for kick, snare, hi-hat, and clap, all sounds synthesized with the Web Audio API, plus play/stop and an adjustable BPM.

⛨ sandboxed Open in new tab ↗
transcript · 10 messages
user

Build a 16-step drum machine with a clickable grid for kick, snare, hi-hat, and clap, all sounds synthesized with the Web Audio API, plus play/stop and an adjustable BPM.

assistant
thinking
The task is: Build a 16-step drum machine with a clickable grid for kick, snare, hi-hat, and clap, all sounds synthesized with the Web Audio API, plus play/stop and an adjustable BPM.
bash {"command":"ls -la /tmp/ws"}
toolResult

total 0 drwxr-sr-x. 2 node node 6 Aug 1 19:55 . drwxrwsrwx. 3 root node 16 Aug 1 19:55 ..

assistant
thinking
The task is to build a single-page web app into one self-contained file named index.html in the current directory. It must be a 16-step drum machine with:
The task is to build a 16-step drum machine in a single HTML file using Web Audio API for sounds, clickable grid, play/stop, adjustable BPM. Everything in one file, no externals.

I need to create index.html in /tmp/ws.

I have a write tool to write the file.

First, I need to write the code for index.html.

Let me sketch the code.

<!DOCTYPE html>
<html>
<head>
<title>Drum Machine</title>
<style>
/* CSS here */
body { background: #222; color: white; font-family: Arial; }
#container { max-width: 800 }
#bpm { width: 100px; }
.grid { display: grid; grid-template-columns: 100px repeat(16, 50px); grid-template-rows: repeat(4, 50px); }
.instrument { background: #333; }
.kick { background: #f00; }
.snare { background: #00f; }
.hihat { background: #ff0; }
.clap { background: #0f0; }
.active { background: #fff; }
.playing { background: #ff0; }
button { padding: 10px; }
</style>
</head wait, fix.

Better define rows properly.

Use table or divs.

Let's use divs with grid.

For instruments: Kick, Snare, HiHat, Clap.

Labels on left.

Step numbers on top.

Cells clickable.

For sounds: define functions.

function playKick(time) {

  let osc = audio ctx.createOscillator();

  osc.type = 'sine';

  osc.frequency.value = 80;

  let gain = audioCtx.createGain();

  gain.gain.setValueAtTime(0, time);

  gain.gain.linearRampToValueAtTime(1, time + 0.01);

  gain.gain.exponentialRampToValueAtTime(0.001, time + 0.2);

  osc.connect(gain);

  gain.connect(audioCtx.destination);

  osc.start(time);

  osc.stop(time + 0.2);

}

Simple kick.

For snare:

function playSnare(time) {

 let noise = audioCtx.createBufferSource();

  noise.buffer = noiseBuffer;

  let filter = audioCtx.createBiquadFilter();

  filter.type = 'bandpass';

  filter.frequency.value = 1200;

  filter.Q.value = 0.5;

  let gain = audioCtx.createGain();

 gain.gain.value = 0.5;

  gain.gain.linearRampToValueAtTime(0.001, time + 0.2);

  noise.connect(filter);

  filter.connect(gain);

  gain.connect(audioCtx.destination);

  noise.start(time);

  // add tone

  let osc = audioCtx.createOscillator();

  osc.type = 'square';

  osc.frequency.value = 150;

  let oscGain = audioCtx.createGain();

  oscGain.gain.value = 0.3;

  oscGain.gain.linearRampToValueAtTime(0.001, time + 0. 1);

  osc.connect(oscGain);

  oscGain.connect(audioCtx.destination);

  osc.start(time);

  osc.stop(time + 0.1);

}

Yes.

For hi-hat:

function playHiHat(time) {

  let noise = audioCtx.createBufferSource();

  noise.buffer = noiseBuffer;

  let filter = audioCtx.createBiquadFilter();

  filter.type = 'highpass';

  filter.frequency.value = 7000;

  let gain = audioCtx.createGain();

  gain.gain.value = 0.5;

  gain.gain.linearRampToValueAtTime(0.001, time + 0.05);

  noise.connect(filter);

  filter.connect(gain);

  gain.connect(audioCtx.destination);

  noise.start(time);

  noise.stop(time + 0.1);

}

For clap:

function playClap(time) {

  let noise = audioCtx.createBufferSource();

  noise.buffer = noiseBuffer;

  let filter = audioCtx.createBiquadFilter();

  filter.type = 'bandpass';

  filter.frequency.value = 1500;

  filter.Q.value = 1;

  let gain = audioCtx.createGain();

  gain.gain.value = 0.4;

  gain.gain linearRampToValueAtTime(0.001, time + 0.1);

  noise.connect(filter);

  filter.connect(gain);

  gain.connect(audioCtx.destination);

  noise.start(time);

  noise.stop(time + 0.1);

  // add second for body

  // or use loop for 2-3

  // for simplicity one, but to make better, loop.

}

To make clap better, use loop.

function playClap(time) {

  for (let i = 0; i < 3; i++) {

    let t = time + i * 0.02;

    // same as above with gain adjusted

  }

}

Yes.

For noiseBuffer:

function createNoiseBuffer() {

  const length = audioCtx.sampleRate * 2;

  const buffer = audioCtx.createBuffer(1, length, audioCtx.sampleRate);

  const data = buffer.getChannelData(0);

 for (let i = 0; i < length; i++) {

    data[i] = Math.random() * 2 - 1;

  }

  return buffer;

}

Yes.

For grid: use JS to create the grid divs.

In script:

window.onload = function() {

  audioCtx = new AudioContext();

  noiseBuffer = createNoiseBuffer();

  // create pattern

  // create grid

  const sequencer = document.getElementById('sequencer');

  // add header

  const header = document.createElement('div');

  header.style.display = 'grid';

  header.style.gridTemplateColumns = '100px repeat(16, 50px)';

  header.style.gridTemplateRows = '1fr';

  header.style.gap = '2px';

  // label for header

  const empty = document.createElement('div');

  empty.textContent = 'Step';

  header.appendChild(empty);

 for(let i=0; i<16; i++) {

    const h = document.createElement('div');

    h.textContent = i+1;

    h.style.background = '#333';

    header.appendChild(h);

  }

  sequencer.appendChild(header);

  // rows

  const rows = [];

  for(let r=0; r<4; r++) {

    const row = document.createElement('div');

    row.style.display = 'grid';

    row.style.gridTemplateColumns = '100px repeat(16, 50px)';

    row.style.gap = '2px';

    const label = document.createElement('div');

    label.textContent = ['Kick', 'Snare', 'HiHat', 'Clap'][r];

    label.style.background = '#444';

    row.
write /tmp/ws/index.html (17906 bytes)
toolResult

Successfully wrote 17906 bytes to /tmp/ws/index.html

assistant
thinking
The user asked to build a 16-step drum machine as a single self-contained index.html file. I've done that. Now I need to verify it's present and works as expected.
bash {"command":"ls -la /tmp/ws/index.html && head -c 200 /tmp/ws/index.html && echo \"...\" && tail -c 100 /tmp/ws/index.html"}
toolResult

-rw-r--r--. 1 node node 17918 Aug 1 19:56 /tmp/ws/index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>16-Step Drum Machine</title> <style> :root { --bg: #0... dEventListener('DOMContentLoaded', init); } else { init(); } })(); </script> </body> </html>

assistant
thinking
The file has been created successfully. It's a single self-contained index.html with everything inline. 
bash {"command":"wc -l /tmp/ws/index.html && echo \"---\" && grep -c \"playKick\\|playSnare\\|playHiHat\\|playClap\" /tmp/ws/index.html && echo \
toolResult

698 /tmp/ws/index.html --- 12 sounds: 4 21

assistant
thinking
The file is complete and self-contained. It has:

Done. Created `/tmp/ws/index.html` — a fully self-contained 16-step drum machine with: - 4-track clickable grid (kick, snare, hi-hat, clap) - Pure Web Audio API synthesis (no samples or external files) - Play / Stop controls - Live BPM slider (40–240) - Pre-loaded demo pattern - Keyboard support (spacebar toggles playback) - Step preview by clicking column headers - Clear button - Zero external resources — runs completely offline Open `index.html` in any modern browser.

TAKE IT TO CODE

A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.

RUN

modelgrok-build-0.1
vendorxAI · Grok
harnesspi-agent
generated2026-08-01

EVALUATION

4/5 working

16-step drum machine with kick/snare/hi-hat/clap grid, BPM slider, and playback step indicator advancing across the grid.

Vision grade · anthropic/claude-sonnet-5

MEASUREMENTS

Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.

idle motion0.0%
on click0.0%
on drag0.3%
on wheel0.2%
on enter + space1.4%
on arrow keys2.0%
on w/a/s/d2.0%
frame spread25.7 / 255
console errors0
js errors none

METRICS

runtime82.6s
tokens in7.2k
tokens out14k
cached17k
cost / run$0.0382