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: DynamicsCompressor master chain to prevent clipping under heavy FX. All routing refactored through masterOut.
  • 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: MediaStreamDestinationMediaRecorder opus → 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: t key/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.destinationmasterOut 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:

  1. 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.
  2. Video recording (canvas + audio) — audio-only today. Bundling canvas into WebM puts it straight onto Twitter and TikTok.

DJ axis:

  1. Loop layer recording — record a sequence, loop it, play over it. With this, you become a one-person band. Biggest and heaviest feature.
  2. FX dry/wet knob — mouse-wheel wet on each DJ slot.

Mobile axis:

  1. 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.)
  2. 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.
  • currentBpm is global and not clean. When modularizing, bundling into audioState.bpm would 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.