Synthwave floor
Pure CSSA gradient-drawn grid laid flat with rotateX, scrolling toward you forever.
Identical frames fly from far away to past the camera on staggered negative delays.
Your edited version
translateZ(-1400px) → translateZ(320px).animation-delay of i × (duration / count) spreads them evenly along the tunnel.animated translateZnegative animation-delayopacity fade-in at distance<div class="tunnel">
<i style="--i:0"></i>
<i style="--i:1"></i>
<i style="--i:2"></i>
<i style="--i:3"></i>
<i style="--i:4"></i>
<i style="--i:5"></i>
<i style="--i:6"></i>
<i style="--i:7"></i>
<i style="--i:8"></i>
<i style="--i:9"></i>
</div>
.tunnel {
position: fixed;
inset: 0;
display: grid;
place-items: center;
overflow: hidden;
perspective: 320px;
background: radial-gradient(circle, #1b0f3a, #05030d 70%);
}
.tunnel i {
position: absolute;
width: 260px;
height: 260px;
border: 3px solid hsl(calc(260 + var(--i) * 14) 90% 65%);
border-radius: 18px;
box-shadow: 0 0 18px hsl(calc(260 + var(--i) * 14) 90% 65% / 0.7);
animation: fly 4s linear infinite;
animation-delay: calc(var(--i) * -0.4s); /* 4s / 10 frames */
}
/* stop well before z = perspective (320px): the scale there is infinite */
@keyframes fly {
from { opacity: 0; transform: translateZ(-1400px) rotateZ(0deg); }
25%, 85% { opacity: 1; }
to { opacity: 0; transform: translateZ(200px) rotateZ(90deg); }
}
@use 'sass:math';
$frames: 10;
$duration: 4s;
.d-tunnel {
position: absolute;
inset: 0;
display: grid;
place-items: center;
overflow: hidden;
perspective: 320px;
background: radial-gradient(circle, #1b0f3a, #05030d 70%);
i {
position: absolute;
width: 200px;
height: 200px;
border: 3px solid hsl(calc(260 + var(--i) * 14) 90% 65%);
border-radius: 18px;
box-shadow: 0 0 18px hsl(calc(260 + var(--i) * 14) 90% 65% / 0.7);
animation: d-tunnel-fly $duration linear infinite;
// Spread the frames evenly across one loop. --i is 0…9 from the markup.
animation-delay: calc(var(--i) * #{math.div(-$duration, $frames)});
}
}
@keyframes d-tunnel-fly {
from {
opacity: 0;
transform: translateZ(-1400px) rotateZ(0deg);
}
25%,
85% {
opacity: 1;
}
// Perspective is 320px, so z = 200px already magnifies 2.7x (the frame is off-screen).
// Never animate up to z = perspective: the scale there is infinite.
to {
opacity: 0;
transform: translateZ(200px) rotateZ(90deg);
}
}