feat(percussion): drums pulse full-screen background in drum colors
Tones have always painted the whole background from their note colors
while held — a kick drum, being a one-shot, never got the same visual
response. Drums now get a transient flash layer that merges with the
tone layer in paint(), so every hit pulses the screen in its kit color.
Design:
- PERCUSSION_COLORS (existing drum-pad palette) is reused as the flash
palette: kick = deep orange, snare = tan, clap = pale yellow, hats =
cyan/mint, ride = silver-blue, crash = lavender, splash = pink,
cowbell = brass, block = wood brown, tambourine = sandy, etc.
- New `drumFlashes` queue (module-level) holds up to 8 concurrent
fading entries. Each entry = { color, frame, life }. Life = 14
frames (~230ms at 60fps) so rolls overlap into a color wash.
- `flashDrum(letter)` pushes a new entry with max alpha; paint() prunes
expired entries and blends them into the bg compute.
Alpha curve per entry: hold full 1.0 for the first 2 frames (so the
hit reads as a punchy blink), then linear decay to 0 over the rest of
the life. This matches how real drum transients feel.
Blend in paint():
- Tone layer and drum layer are computed separately, then weighted-
summed (drums get 1.2× weight so a single hit still reads even
against multiple held tones).
- If any tone is held, the combined color snaps instantly (matches
previous "blink" behavior for tones).
- If drum-only (no held tones), the color smooth-blends at 0.55/frame
so rapid hits stack nicely and single hits fade out over ~230ms.
- With neither tone nor drum, background fades to dark/light theme.
Wired into all 4 drum trigger paths:
- Keyboard act() drum branch (notepat.mjs:~1450)
- Touch-tap drum pad (notepat.mjs:~1820)
- Drag-rollover drum pad (notepat.mjs:~1975)
- Reverse-playback replay (playReverseEvent, notepat.mjs:~467)