The winter panorama arrived as bg-winter.jpg: 3.4 MB, 3904×1088 pixels, same scene as the spring layer already sitting in public/ — same camera angle, same rooftops and city stretch — but with snow covering everything. Icicles on the eaves. Kids in the background with snowballs. Dropped it into the stack behind the spring canvas and nothing happened. Two layers. Nothing connecting them. Spring sat in front; winter sat behind. They didn’t know about each other.
That was the state of things before the radial alpha.
What the visualiser already knew about bass
By the time the winter layer went in, the visualiser had already been taught to treat bass as a brightness signal. The neon bloom behind the city ran its opacity through min(1, 0.14 + kickEnv*0.7 + bass*0.22) — pink to gold to transparent, pulsing with the low end. On a kick drum, the glow surged. Between beats it settled. Bass was the dial you turned to make things brighter or darker.
That’s a reasonable mapping. The low end is physically large; it moves air. Visual equivalents tend toward scale and luminosity — bigger, brighter, more saturated. The neon bloom was doing exactly that.
The particle life-arc was working a different register. Onset particles launched at max energy and bled it off as they aged: energy = 0.9^age scaling a perpendicular wobble of sin(age·freq + phase) · amp · energy. Wide and fast at launch, settling as they travelled. The effect was kinetic: energy as motion, decay as stillness. Not brightness. Movement.
Adding a second image layer didn’t fit either of those models. A static panorama in the background isn’t bright and doesn’t move. If bass drove its opacity globally, you’d get a cross-dissolve — spring fading out, winter fading in — which is just a slow wipe. Not related to what the music was doing.
The radial alpha as the missing piece
The change was structural rather than parametric. Instead of fading between the two layers globally, the spring canvas got a hole: a radial alpha mask, circular, centred in the frame. Within that radius, the spring layer is transparent. Outside it, opaque. The winter panorama shows through wherever the spring canvas has been made transparent.
That’s the basic geometry. The bass connection turns it into something else.
When bass frequency output drives the size of that radial hole, the low end isn’t adjusting brightness anymore. It’s adjusting how much of winter is visible through spring. On a bass drop, the hole opens — a wider circle of transparency punched through the spring layer, revealing the snow and icicles underneath. Between drops, the spring closes back in.
The conceptual shift is more significant than the implementation difference. Bass was a scalar: turn this thing up. Now bass is a mask boundary: reveal this thing beneath. One is additive; the other is subtractive and spatial.
Why “window” is the right word
The word is load-bearing. A window has a fixed location in a wall. You look through it; the wall doesn’t go away. The spring panorama doesn’t dissolve when the bass hits — it stays present everywhere outside the radial alpha. The winter scene isn’t replacing spring; it’s visible through a specific aperture in it.
That relationship — coexistent rather than alternating — is what the commit message calls “peek into a different time.” The visualiser isn’t cutting between seasons. It’s running both simultaneously and deciding, in real time, how much of one you can see through the other. Bass controls the aperture.
The track driving this is “Tasogare”: public/tasogare.wav, 3:16 at 48kHz 24-bit stereo. “Tasogare” is Japanese for dusk or twilight — the transition time, neither day nor night. The temporal ambiguity in the title and the spatial ambiguity in the layer stack share the same structure. Two states simultaneously present, with variable amounts of each visible depending on where you are in the signal.
That alignment wasn’t engineered. The track name predates the portal feature. But it’s there.
What this changes about the low end
The neon bloom is still in the frame. Bass is still doing min(1, 0.14 + kickEnv*0.7 + bass*0.22) on the glow. The brightness signal didn’t disappear; it was joined by the spatial one. Bass now does two things from the same frequency data: it brightens the neon behind the city and it opens the winter window in the foreground.
Those are parallel outputs from the same signal. They reinforce each other — the low end as physical presence, moving both light and aperture — without duplicating effort. The bloom and the portal are on different visual planes. They don’t compete.
What changed is the range of what bass can mean in this context. Before the radial alpha, every bass-to-visual mapping in this project was scalar: opacity, amplitude, size. The portal introduces a categorical mapping: bass determines whether a thing is visible at all, not just how prominently. That’s a different grammatical role.
The stack at this point
The visualiser has several independent layers by this commit:
- Spring panorama (foreground, with radial alpha hole driven by bass)
- Winter panorama (background, visible through the hole)
- Neon bloom (city glow, opacity driven by bass + kick envelope)
- Onset particles (life-arc: energy-decay wobble, perpendicular to travel direction)
- Waveform, beat flash, now-playing card, and RGB-split from the Claude Design handover
Each layer reads from the same Web Audio frequency data but maps it differently. Particles respond to onsets. Neon responds to bass amplitude. The portal responds to bass as a mask boundary. The waveform is continuous. The beat flash is binary.
That variety of mappings is not accidental. If every element scaled in the same direction on the same signal, the result would be rhythmically legible but spatially incoherent — everything pumping simultaneously, fighting for the same visual register. Distributing the bass signal across different mapping types (scalar, spatial, binary) spreads the load across the frame.
What I’d have done differently
One thing: the two-layer approach requires the panoramas to be compositionally compatible at every aperture size the radial alpha can produce. bg-winter.jpg is 3.4 MB at 3904×1088 — the same dimensions as the spring source. They line up precisely. That alignment was a prerequisite for the portal to work without visible seams at the hole edge.
If the winter image had been shot from a different angle or cropped differently, the radial reveal would expose mismatched geometry at the portal boundary. The effect would read as a compositing error rather than a window. The visual trick depends entirely on the two layers being spatially consistent. That’s a sourcing constraint, not an implementation one. It belongs in the brief, not the code.
The actual result
On a bass hit in “Tasogare,” the spring panorama opens. Snow and icicles appear through the circle of transparency. The neon bloom brightens simultaneously. The onset particles launch with maximum wobble and decay toward stillness. Then the bass drops off, the spring closes back in, the neon settles, and the particles reach the end of their life-arc and disappear.
The sequence runs in seconds on a typical low-end hit. What it produces is a visualiser that responds to the same signal at multiple timescales and through multiple visual grammars: the bloom as immediate presence, the particles as kinetic aftermath, the portal as momentary revelation.
The goal at the start of the session was to make bass do something more interesting than glow. The portal is what that led to.



