From a6e26a46d883a0287c4304b98420ccba731ee573 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Tue, 8 Sep 2026 00:04:07 -0400 Subject: [PATCH] =?UTF-8?q?npscore:=20the=20room=20learns=20to=20rest=20?= =?UTF-8?q?=E2=80=94=20envelopes=20on=20every=20cue,=20and=20level=20rides?= =?UTF-8?q?=20activity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sustained cues pulse e^-3 over their dur instead of holding a plateau, and the weighted average now only picks the color while min(1, sum of activity) sets the level — normalizing alone cancelled the envelopes (one dying pad rendered full-bright), which is why blackouts never landed. Rests and decays reach black; drops saturate; kicks still punch white on top. Claude-Session: https://claude.ai/code/session_01Xju7GpzP6o2JwxtqfKqFiG --- fedac/native/pieces/npscore.mjs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/fedac/native/pieces/npscore.mjs b/fedac/native/pieces/npscore.mjs index b88d7cf90d..3adddad66c 100644 --- a/fedac/native/pieces/npscore.mjs +++ b/fedac/native/pieces/npscore.mjs @@ -175,15 +175,23 @@ function paint({ wipe, ink, write, system }) { if (l.start > t) break; if (l.dur != null) { if (t < l.start + l.dur) { - r += l.rgb[0] * l.gain; g += l.rgb[1] * l.gain; b += l.rgb[2] * l.gain; - w += l.gain; + // Envelope, not a plateau: each note-on pulses bright then dies + // toward the cue's end (fade overrides the curve, default e^-3u) + // so the room carries the music's dynamic, not a held average. + const k = l.gain * Math.exp(-(l.fade ?? 3) * (t - l.start) / l.dur); + r += l.rgb[0] * k; g += l.rgb[1] * k; b += l.rgb[2] * k; + w += k; } } else { const k = Math.max(0, 1 - (t - l.start) / (l.decay ?? 0.12)) * l.gain; fr += l.rgb[0] * k; fg += l.rgb[1] * k; fb += l.rgb[2] * k; } } - if (w) { r /= w; g /= w; b /= w; } + // Weighted average picks the COLOR; summed activity sets the LEVEL. + // Normalizing alone would cancel the envelopes (one dying pad would + // still render full-bright) — scaling by min(1, w) is what lets rests + // and decays actually reach black. + if (w) { const lvl = Math.min(1, w); r = r / w * lvl; g = g / w * lvl; b = b / w * lvl; } const R = Math.min(255, Math.round(r + fr)); const G = Math.min(255, Math.round(g + fg)); const B = Math.min(255, Math.round(b + fb)); -- 2.51.2