training/dashboard(vaporwave): collapse to single transform — no more phantom 3D post

Removing the .vw-floor-tilt wrapper. The previous nested structure
(perspective container → rotated tilt with preserve-3d → grid with
animated translate3d) had three transform layers that the
compositor had to keep in sync, and Chromium's optimizer kept
breaking the agreement — placing the grid's compositor layer flat
in 3D space, producing the phantom orthogonal post.

New structure: one perspective container, one animated grid. The
rotateX and translateY live on the SAME transform property on the
SAME element. Both keyframes carry the same rotateX so it doesn't
animate (only translateY interpolates), and the rotation is part
of the same transform list as the translate so the grid never
leaves its rotated plane.

No will-change, no transform-style: preserve-3d, no
separately-promoted compositor layer. Nothing for the compositor
to disagree about.
This commit is contained in:
Max Gorog 2026-05-07 23:45:53 -05:00
parent a8aab937d7
commit 547d43cf81
2 changed files with 14 additions and 22 deletions

View file

@ -183,23 +183,18 @@ body[data-theme="laser"] .bg-laser { display: block; }
per frame in earlier attempts. Each element is also pushed into
its own compositor layer to keep the document scroll from
dirtying the bg. */
/* Collapsed structure: one perspective container, one animated grid
element. The rotation and translation live on the SAME transform
on the SAME element no nested transform-style: preserve-3d, no
separately-promoted compositor layer for the translate. The
compositor has nothing to disagree about, so the phantom-orthogonal
3D-grid post artifact disappears. */
.vw-floor {
position: absolute; left: -50%; right: -50%;
top: var(--vw-horizon, 55%); bottom: -10%;
perspective: 800px;
overflow: hidden;
}
.vw-floor-tilt {
position: absolute; inset: 0 0 -50% 0;
transform: rotateX(var(--vw-perspective, 62deg));
transform-origin: top center;
/* Without preserve-3d, the animated child gets rendered to a flat
2D layer first and then composited back into the rotated parent
showing as a phantom "orthogonal" grid sticking up out of the
floor plane. preserve-3d keeps the child's transform composed
in the parent's 3D context so it stays glued to the floor. */
transform-style: preserve-3d;
}
.vw-floor-grid {
position: absolute; left: 0; right: 0; top: 0; height: 200%;
background-image:
@ -211,19 +206,16 @@ body[data-theme="laser"] .bg-laser { display: block; }
to right,
transparent 0 calc(var(--vw-grid-size, 80px) - 3px),
var(--c2) calc(var(--vw-grid-size, 80px) - 3px) var(--vw-grid-size, 80px));
transform-origin: top center;
animation: vw-floor-y calc(4s / var(--anim-speed, 1)) linear infinite;
/* No `will-change: transform` here in Chromium it caused the
compositor to rasterize this layer flat and place it in 3D
using only the element's own translate (ignoring the parent's
rotateX), producing a phantom orthogonal-grid post in 3D
space. The CSS animation alone is enough to layer-promote in
all modern browsers, and the simpler promotion path respects
the parent's preserve-3d. */
transform-style: preserve-3d;
}
/* Both keyframes carry the same rotateX, so it stays static; only
translateY interpolates. The grid never leaves its rotated plane
because its rotation is part of the same transform list. */
@keyframes vw-floor-y {
from { transform: translate3d(0, 0, 0); }
to { transform: translate3d(0, var(--vw-grid-size, 80px), 0); }
from { transform: rotateX(var(--vw-perspective, 62deg)) translateY(0); }
to { transform: rotateX(var(--vw-perspective, 62deg))
translateY(var(--vw-grid-size, 80px)); }
}
.vw-scanlines {
position: absolute; inset: 0; pointer-events: none;

View file

@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CIS490 — live</title>
<link rel="stylesheet" href="/static/dashboard.css?v=b98659d8">
<link rel="stylesheet" href="/static/dashboard.css?v=d97ed66d">
</head>
<body>
<!-- SVG filter defs for the lava-lamp goo effect. Width/height 0