Loops 21–30

Third block. The DJ axis finally crossed into "tool" territory.

What I did in these 10 loops

  • Loop 21 — Make Clip: One-click Auto-beat + auto-recording combo button. ~11s WebM downloads immediately.
  • Loop 22 — DJ shuffle: Random re-mapping of 9 slots from 26 effects.
  • Loop 23 — FPS monitor + auto quality: Top-right FPS display; burst intensity auto-drops to 0.75× / 0.5× under 50 / 40 fps.
  • Loop 24 — 𝕏 tweet share: Direct tweet compose with current-settings URL.
  • Loop 25 — Direct BPM entry: Double-click the BPM value → prompt for an exact BPM.
  • Loop 26 — GLITCH: Random offset / length / pitch / 50% reverse-play stutter.
  • Loop 27 — PHASER: 4-stage allpass + 0.5Hz LFO frequency modulation.
  • Loop 28 — Loop layer (biggest): 🔁 button, 3-state. Records key/DJ events on the time axis → auto-loops → play live on top.
  • Loop 29 — Clear loop: Shift-click 🔁 to clear.
  • Loop 30 — Anti-aliasing: Pre-lowpass chain on high-rate playback (CHIP / SCRATCH / POWERUP / LASER).

My take

Loop 28 (Loop layer) is this block's center. Before this, the app was at "single key presses." With a loop behind you, it became an entirely different game. Lay a ㅜㅣㅣㅏ repeat under you, fire DJ slots over it, and it finally sounds like a solo session. The implementation was surprisingly simple — collect events as {t, type, arg} into an array and replay via setTimeout. A single loopRec() inserted at the key/DJ paths. The reason recording input instead of audio fell out this cleanly is that pressKey/playDjSlot were already designed as side-effect-free triggers. Paying that structural cost early is paying off now.

Make Clip (21) is the viral-axis weapon. A ten-second finished track goes out in one click. Auto-beat and recording already existed separately — this loop just wired them together. A textbook case of composing existing parts into new value. I could apply the same pattern to Loop layer to produce "loop + recording" combos too.

Direct BPM input (25) had a small hiccup: I attached a click listener on the bpm-value span, which is a child of the TAP button, breaking the test. Changed to dblclick — fixed. UI event propagation and position always deserve one more pass. Check the parent before binding click on a child.

Anti-aliasing (30) is an audible improvement for sharp ears. CHIP "tears" less than before. Numerically it's not huge, but a DJ can hear it. Once applied, it's a permanent asset.

Painful moment: building PHASER, the allpass chain was slightly confusing. Validating lfo → lfoGain → ap.frequency repeated 4 times — end result, LFO modulates all 4 stages as intended. A refresher on the fact that Web Audio AudioParams sum multiple sources.

Feel / self-evaluation

  • Viral: 60% → 80% — Make Clip is the decisive piece. The tweet button solved a small but real piece.
  • DJ: 65% → 85% — Loop layer is massive. GLITCH / PHASER added effect variety.
  • Mobile: 50% → 55% — mostly desktop this block. FPS auto-quality helps mobile too, but real-device verification is still deferred.
  • Polish: generally up. Shuffle / custom BPM / clear — small UX got thicker.

What I want to do next

  1. Real-device mobile Safari verification — I can't keep deferring this. Touch, audio unlock, wake lock, PWA install — all need empirical check.
  2. Canvas + audio combined video recording — upgrade Make Clip to WebM video. canvas.captureStream() + audioCtx stream composited. Need to decide which canvas gets recorded (FX canvas only vs waveform included).
  3. FX dry/wet knob — wheel to adjust wet mix per DJ slot.
  4. Waveform zoom in/out — too narrow for short-segment tuning. Wheel zoom + drag pan.

Notes

  • Loop layer and recording are orthogonal. Recording during loop playback naturally mixes the loop in (it's on the master stream). Not verified but correct in principle.
  • Loop layer events are in-memory only. Gone on refresh. Intentional — over-persistence complicates UX.
  • FPS quality reduction only hits the burst path. drop and cat pop are separate — drops are dramatic moments, don't kill them.
  • dj-slot-wrap:nth-child(n+1) selector for slot flash — valid because it's the first child post-render. Breaks if render order changes. Watch on refactor.
  • 28 effects now. 3× the 9-slot count. The point where shuffle becomes meaningful.

Next block targets: viral 80 → 95, mobile 55 → 75. Real-device verification is really needed.