The spring panorama has winter underneath it: audio-driven temporal layering

The compositor has two background images loaded. Spring is on top — bg-city.jpg, cherry-blossom petal light-trails over neon Tokyo, 3904×1088. Winter is behind it — bg-winter.jpg, same dimensions, snow and icicles and kids with snowballs. Spring hides winter entirely until bass opens a hole in it.

That’s not an analogy. That’s the implementation.

The layer architecture

Both panoramas live in public/. Both are 3904×1088. The spring image was swapped in at the start of this build cycle — the old city background (a static PNG) replaced with bg-city.jpg: swirling cherry-blossom petal light-trails over a neon Tokyo skyline, 3.4 MB. It runs edge-to-edge as the primary background.

Winter sits behind it. The front layer (spring) carries a radial clip region. At rest the clip radius is zero — spring covers the whole frame and winter is invisible. When bass hits, the radius grows and winter shows through the resulting hole.

No masking pipeline. No sprite system. Two stacked images and a variable-radius clip.

Bass as the reveal signal

The bass envelope was already computed and driving other elements before this feature existed. The radial cutout is another consumer of the same value. Making it drive holeR required connecting an existing signal to a new variable, not building new signal infrastructure.

The choice of bass over treble or overall amplitude is load-bearing. Bass correlates with weight and impact. When the low end hits, winter shows. When it drops, spring covers it again. The mapping follows the emotional register of the music rather than cutting against it. A background change triggered by treble would feel arbitrary; one triggered by bass reads as structural.

The background is the largest surface in the frame. When it changes, the whole visual field changes. Anchoring that change to bass keeps it from feeling random.

The midpoint swap

At swapFrame = round(durationInFrames * 0.5) — the exact halfway point of the track — the two panoramas exchange roles. A smooth bell curve swapOpen runs from 0 to 1 to 0 over ±50 frames centred on swapFrame. During the bell, holeR += swapOpen * 1500. The radial cutout blooms open wide enough to make the swap legible, then closes on whichever layer is now in front.

After the swap: winter is the primary layer, spring is the hidden one. The same bass-driven mechanism now reveals spring through winter rather than the other way around. No new code. The swap is a role reversal, not a feature addition.

The first half and second half are now visually distinct states. The midpoint event — the portal blooming open, the layers exchanging, the portal closing — reads as a scene turn rather than a cut.

Out of scope: syncing the swap to a musical cue rather than the structural midpoint. Cue-based triggering requires beat detection or manual frame-marking. The midpoint is a reliable structural approximation.

The glow problem and what fixed it

The centre of the cutout had a screen-blend spotlight applied over it. The intention: make the hole read as lit, as if something luminous behind the spring layer was glowing through.

It didn’t achieve that. The overlay added brightness without adding information. The result was a brightened circle, not a glowing window into another scene.

The fix: remove the overlay and let winter carry its own light. The winter panorama — neon skyline at sunset, snow-laden blossoms catching light, reflected glow off the snow in the foreground — has ambient light built into the image content. When bass opens the cutout and winter shows through, the image glows by itself. The overlay was competing with that, flattening it under a screen-blend coat.

An image with real light sources doesn’t need a simulated glow layer. The simulation competes with the source material and loses.

Replacing the winter scene

The original bg-winter.jpg was adequate: snow, icicles, kids with snowballs, 3.4 MB. The replacement (same filename, same 3904×1088) is richer: a snowball fight in the foreground, snow-laden blossoms catching the light, a neon skyline at sunset in the distance. 3.3 MB — slightly smaller in file size, more compositional complexity in content.

The swap was a pure content change. No code changed. Same file path, same dimensions, same format — all downstream references to the image were unaffected. The meaningful difference is that the new scene has stronger ambient light at the centre, which made the glow-removal fix more effective: there was better source light to reveal.

What makes it a temporal device

A clock is a temporal device because its state is indexed to time. The background here is indexed to bass amplitude. The mechanism is the same; the signal is different.

What makes it read as temporal is the content, not the code. Spring and winter are far enough apart in the seasonal register that the transition between them implies time passing — not just a change in mood or lighting, but a shift in era. The bass opens a window into a different time of year. That interpretation isn’t in the compositor. It’s in the choice of images.

The midpoint swap extends the device. Before the halfway mark, spring is the present and winter breaks through on bass hits — the past (or the future) showing through the surface. After the swap, winter is the present and spring is what’s underneath. The temporal relationship has inverted. Which one is past and which is present is genuinely ambiguous after the swap. That ambiguity is deliberate; it keeps the device from resolving too cleanly.

None of that required additional code. It required two panoramas with the right seasonal relationship, stacked the right way, with the swap direction chosen deliberately.

What this is and isn’t

The technique isn’t specific to audio-reactive work. A canvas with two stacked images and a variable-radius clip works with a scroll offset, a mouse position, or a manual timeline. Bass is the signal here because of how it correlates with energy and impact in this specific track. The content is spring-over-winter because of how that seasonal pairing reads temporally. Both choices were deliberate; neither is intrinsic to the mechanism.

The device works or it doesn’t based on whether the bass-driven reveals land where the music needs them to — whether the cutout opens at moments of weight, whether the midpoint swap reads as a scene turn rather than a glitch. That’s a question the full playback will answer. The build log will have the next entry when it does.

All writing