For agents, on top of README.md, which they read first.
Notes for agents
Stop playback before playing song.js. Its section masks count from cycle 0.
The chord cycle is rotated on purpose. It starts on Dm7 so the verses (cycles 4 and 20) open on Fmaj7; each vocoded line is rendered on one chord (samples/README.md lists which). The verse patterns are rotated to match: <…> indexes by cycle mod 8, so line 1 sits at index 4. Move a section and both rotations must move with it, or the lines must be re-rendered.
ffhum is one bar at 80 bpm, eight 8th-note slices. It is exactly 3.0 s: the hum's thumps cut on their transients and placed on the 8th grid, each tuned to a note (slice 0 A, 1 E, 2 D, 3 a short thump, then again; samples/README.md has how). slice(8, …) assumes that; change the tempo and it must be re-cut.
Don't use .delay() for the vocal echo. Superdough makes its delay line with the Web Audio default one-second maximum, so any delaytime over 1 s plays at 1 s (measured in Chromium, 2026-09-25). The echo is a second copy of each line, .late(3/4).
The mix is set by its peaks. Nothing limits the master, so up front (energy rung 3, postgain 1.1) must peak at or under −1 dBFS. The page's meter samples a fraction of the time and reads peaks low; check a capture of the output, not the meter. The vocal lines are peak-limited to −4.5 dBFS at −17.3 LUFS so they can sit forward.
The play-once mask stays .mask("<1!48 0!952>"). The card's length and tools/measure parse that exact shape; the early stop after "This is fine" is a second mask (ending).
The fade is velocity on the inner stack. Every layer except "This is fine" and the crackle sits inside it; don't put a .gain() on that stack, which would override each layer's own gain instead of scaling it.