fix(decnet_web/Layout): theme swap animation no longer flashes opposite mode

Growing the NEW theme layer from circle(0) outward leaves a
one-frame gap where the new pseudo is fully opaque at full size
(the default state) before the clip-path animation registers.
Result: a flash of the destination theme right before the
reveal starts.

Inverted the layering and animation direction:
 - NEW theme snapshot sits on the bottom (z-index 0), static
 - OLD theme snapshot sits on top (z-index 1), shrinks via
   clip-path from circle(N) at click point down to circle(0)

The new layer is now hidden behind the old one until the old
shrinks away — no flash possible because the new layer was
never visible before the animation. Same 520ms duration, same
ease curve, same direction-of-travel from the user's POV
(circle expanding from cursor).
This commit is contained in:
2026-05-09 04:14:54 -04:00
parent 438a6e3e45
commit a81ea3f973
2 changed files with 20 additions and 7 deletions

View File

@@ -70,17 +70,22 @@ function animateSwap(next: Theme, x: number, y: number): void {
Math.max(x, window.innerWidth - x),
Math.max(y, window.innerHeight - y),
);
/* Shrink the OLD layer (on top per index.css z-index rules)
* away from the click point, uncovering the NEW layer that
* sits behind. Going outside-in instead of inside-out avoids
* the one-frame flash where the default-opaque new pseudo
* would otherwise be visible before the clip-path registers. */
document.documentElement.animate(
{
clipPath: [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,
`circle(0px at ${x}px ${y}px)`,
],
},
{
duration: 520,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
pseudoElement: '::view-transition-new(root)',
pseudoElement: '::view-transition-old(root)',
},
);
}).catch(() => { /* user-cancelled or unsupported pseudo, ignore */ });