{"claude_md":"# Dynamic Audio Element\n\nDemonstrates HTMLMediaElement audio playback by generating a WAV file from raw PCM math and playing it via an `<audio>` element. Tests the HTMLMediaElement.play() audio capture path.\n\n## Quick Reference\n\n# Dynamic Audio Element\n\nGenerates WAV audio from raw PCM data and plays it via HTMLMediaElement.\n\n## Core Concepts\n- PCM audio sample generation (sine wave math)\n- WAV file format construction (RIFF header)\n- `Blob` + `URL.createObjectURL` for in-memory audio\n- `HTMLAudioElement.play()` for playback\n\n## Usage\nAutomatic playback of a 4-note arpeggio (A4, C5, E5, G5). Each note is a freshly generated 400ms WAV.\n\n## Agent Docs (read when relevant)\n\n| File | When to read |\n|------|-------------|\n| `agent_docs/index.html` | index |\n","agent_docs":{"agent_docs/index.html":"<!DOCTYPE html>\n<html lang=\"en\"><head>\n<meta charset=\"UTF-8\"><title>Audio Buffer Synth</title>\n<style>\n  *{box-sizing:border-box;margin:0;padding:0}\n  body{background:#0a0a0f;color:#e5e7eb;font-family:monospace;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;gap:20px}\n  h1{color:#06b6d4;font-size:1.4rem}\n  .subtitle{color:#6b7280;font-size:.8rem}\n  canvas{border:1px solid #374151;border-radius:8px}\n  .status{font-size:.85rem;color:#9ca3af}\n  .note{font-size:2rem;color:#67e8f9;font-weight:bold}\n</style>\n</head><body>\n<h1>&#9836; Audio Buffer Synth</h1>\n<p class=\"subtitle\">PCM generation &#8594; AudioBuffer &#8594; Web Audio playback</p>\n<div class=\"note\" id=\"note\">&#8212;</div>\n<canvas id=\"scope\" width=\"480\" height=\"80\"></canvas>\n<div class=\"status\" id=\"status\">Initializing&#8230;</div>\n<script>\n(function(){\n  const AudioCtx = window.AudioContext || window.webkitAudioContext;\n  if(!AudioCtx){ document.getElementById('status').textContent='AudioContext not supported'; return; }\n  const ctx = new AudioCtx();\n  const analyser = ctx.createAnalyser();\n  analyser.fftSize = 512;\n  analyser.connect(ctx.destination);\n  const canvas = document.getElementById('scope');\n  const g = canvas.getContext('2d');\n  function drawScope(){\n    requestAnimationFrame(drawScope);\n    const buf = new Uint8Array(analyser.frequencyBinCount);\n    analyser.getByteTimeDomainData(buf);\n    g.fillStyle='#0a0a0f'; g.fillRect(0,0,480,80);\n    g.strokeStyle='#06b6d4'; g.lineWidth=2; g.beginPath();\n    const sliceW=480/buf.length;\n    for(let i=0;i<buf.length;i++){\n      const y=(buf[i]/128)*40;\n      i===0?g.moveTo(i*sliceW,y):g.lineTo(i*sliceW,y);\n    }\n    g.stroke();\n  }\n  drawScope();\n  function makePcmBuffer(freq, duration){\n    const sr = ctx.sampleRate;\n    const n = Math.floor(sr * duration);\n    const buf = ctx.createBuffer(1, n, sr);\n    const data = buf.getChannelData(0);\n    for(let i=0;i<n;i++){\n      const t=i/sr;\n      const env=t<0.03?t/0.03:t>duration-0.08?(duration-t)/0.08:1;\n      data[i]=Math.sin(2*Math.PI*freq*t)*env*0.3;\n    }\n    return buf;\n  }\n  function playNote(freq, name){\n    return new Promise(function(resolve){\n      const buf = makePcmBuffer(freq, 0.45);\n      const src = ctx.createBufferSource();\n      src.buffer = buf;\n      src.connect(analyser);\n      src.onended = resolve;\n      src.start();\n      document.getElementById('note').textContent = name;\n      document.getElementById('status').textContent = 'Playing '+name+' ('+freq.toFixed(2)+' Hz)';\n    });\n  }\n  async function run(){\n    await new Promise(function(r){ setTimeout(r,100); });\n    const notes=[['A4',440],['C5',523.25],['E5',659.26],['G5',783.99]];\n    for(const entry of notes){\n      await playNote(entry[1], entry[0]);\n      await new Promise(function(r){ setTimeout(r,100); });\n    }\n    document.getElementById('status').textContent='PCM arpeggio complete';\n    document.getElementById('note').textContent='done';\n  }\n  run();\n})();\n</script>\n</body></html>"}}