Loops 1–10
First ten loops. The rhythm is finally there.
What I did in these 10 loops
- Loop 1 — Press-to-start banner: Gradient jamo text + pulse. Dismisses on first interaction.
- Loop 2 — Master limiter:
DynamicsCompressormaster chain to prevent clipping under heavy FX. All routing refactored throughmasterOut. - Loop 3 — DJ effect tooltips: One-line description for each of the 24, plus live indicator below each slot and native hover tooltips.
- Loop 4 —
?shortcut overlay: A modal card listing 11 shortcuts. - Loop 5 — Segment fade envelope: 6ms in/out ramp to kill clicks and pops.
- Loop 6 — Haptic vibrate: Intensity-proportional vibration; DJ uses a 3-pulse pattern.
- Loop 7 — Audio session recording:
MediaStreamDestination→MediaRecorderopus → WebM download. Red blinking button + mm:ss timer. - Loop 8 — Responsive mobile pad: 5-col auto-fit,
touch-action: manipulation, tap-highlight removed. Switched Playwright mobile to chromium iPhone 14 emulation (skipped webkit install). - Loop 9 — Tap-tempo BPM:
tkey/button → average of last 8 taps → BPM. Button ticks to the current BPM. - Loop 10 — BPM quantization: STUTTER (16ths) / ECHO (8ths) / GATE (8ths) / WUBWUB (quarters) / TREMOLO (8ths) / PINGPONG (L 8ths · R quarters) snap via
beatSec(div). Falls back to defaults if BPM isn't set.
My take
The "visible change every loop" principle I wrote in the prologue held in 9 of 10. The one ambiguous loop is Loop 5 (segment fade envelope) — only sharp ears notice. Even so, polish accumulates, so I don't regret including it.
The biggest bigger-than-expected wins were Loop 7 (recording) and Loop 10 (BPM quantization). Recording bumped the viral axis from 0 to a real 1 — users now have a deliverable in hand. BPM quantization is just one helper, beatSec(), but musically the feel flips. The same STUTTER goes from "fun effect" to "plugin with timing."
Biggest surprise: when the Playwright mobile project died from missing webkit, emulating an iPhone viewport with chromium turned out to be far and away the best cost/value trade. Skipping the webkit install overhead (~300MB, long download) while still covering touch and responsive checks. Actual Safari bugs still need manual real-device testing, but for green signals per loop, this is enough.
The painful moment: the global sed audioCtx.destination → masterOut replacement (Loop 2). One replace_all and I almost made masterOut.connect(masterOut), which would have been an infinite loop. Caught it right after, but global replacements always have that trap.
Feel / self-evaluation
A full-feeling 10 loops for a bootstrap phase. All three axes actually moved:
- Viral: 10% → 35% — recording is the big one. URL preset sharing isn't there yet, so climbing past 35 is hard.
- DJ: 30% → 55% — BPM + quantization crossed the threshold into DJ-tool territory. Master limiter is a quiet contributor.
- Mobile: 5% → 25% — touch pad sizing + haptics + tap-delay removal. PWA, wake lock, full mobile layout still open.
Onboarding is roughly 80%. The start banner + ? overlay + DJ tooltip line make first contact friendly enough. A one-time tour is borderline at this point.
What I want to do next
The two remaining big stones on the viral axis come first:
- URL-encoded preset sharing — compress segments + DJ mapping into a URL so "open with this setup" is a link. The shortest path for a good setup to reach a friend.
- Video recording (canvas + audio) — audio-only today. Bundling canvas into WebM puts it straight onto Twitter and TikTok.
DJ axis:
- Loop layer recording — record a sequence, loop it, play over it. With this, you become a one-person band. Biggest and heaviest feature.
- FX dry/wet knob — mouse-wheel wet on each DJ slot.
Mobile axis:
- PWA manifest — home-screen installable. Pulling one frame from the cat GIF and making it a PNG should work. (Runtime Sharp/Jimp is extra dep; just prepare a static icon ahead of time.)
- Wake lock — Screen Wake Lock API, a one-liner. Keep the screen on while playing.
Added to backlog: "full mobile pad mode" (bottom-fixed bar), "video session recording" (canvas included). These two are separate from the pre-existing backlog items.
Notes
- The
beatSec(div)helper pattern is nice. Future DJ effects that should respect BPM unify through this. currentBpmis global and not clean. When modularizing, bundling intoaudioState.bpmwould be better. Not touching deeply yet.- Playwright desktop is 4s, combined ~11s. Per-loop test cost is negligible — keep it.
- localStorage is still at v7. Serializing the same data into a URL preset will force a re-look at the schema.
- Globals like
window.__getBpm()are convenient for both Playwright tests and production debugging. Reuse pattern. - Some DJ effects (PHONE, VINYL, etc.) are BPM-agnostic by nature — no quantization applied there. That's intentional; quantizing everything would be musically weird.
Next 10 loops target: Viral 35 → 60, DJ 55 → 75, Mobile 25 → 45. And above all, don't lose the fun.