Solar system
Pure CSSOrbits are rings on a tilted plane, each spinning at its own speed. Every planet undoes both rotations, so it always faces the camera.
A road plane laid flat with rotateX(90deg). The centre line slides by exactly one dash period, and posts travel the whole road with staggered delays, so the loop never shows a seam.
Your edited version
transform-origin: bottom; rotateX(90deg). Put perspective-origin on the horizon line, and the far end vanishes exactly there.rotateX(-90deg) around their foot and all run the same trip along the road, spread out by negative delays. Speed matches the dashes: 1400 units in 7s = 100 in 0.5s.mask on the road would flatten its 3D posts. Instead a flat band of haze sits on top of the horizon and hides where things appear. The ground lines are a repeating-conic-gradient from the vanishing point.inset: 0 and laid out in percentages, so it fills the canvas edge to edge whatever its shape. Its lengths are multiples of one base unit, --u, tied to the canvas, so the road reads the same on a gallery card and on a full screen.rotateX(90deg) floor + perspective-origin = horizontranslate by one pattern periodupright posts: rotateX(-90deg), origin bottomflat haze overlay instead of a mask<div class="drive">
<div class="sun"></div>
<div class="ground"></div>
<div class="road">
<div class="dashes"></div>
<i class="left" style="--i:0"></i>
<i class="right" style="--i:0"></i>
<i class="left" style="--i:1"></i>
<i class="right" style="--i:1"></i>
<i class="left" style="--i:2"></i>
<i class="right" style="--i:2"></i>
<i class="left" style="--i:3"></i>
<i class="right" style="--i:3"></i>
<i class="left" style="--i:4"></i>
<i class="right" style="--i:4"></i>
<i class="left" style="--i:5"></i>
<i class="right" style="--i:5"></i>
</div>
<div class="haze"></div>
</div>
.drive {
/* one base unit, tied to the canvas; the scene itself fills the canvas edge to edge, its
layout in percentages of it and its lengths in units */
--u: 0.33vmin;
position: fixed;
inset: 0;
overflow: hidden;
perspective: calc(300 * var(--u));
perspective-origin: 50% 44%; /* the horizon */
background: linear-gradient(#07051a, #3a2580 24%, #8c2a6c 44%);
}
.sun {
position: absolute;
top: calc(44% - calc(78 * var(--u)));
left: calc(50% - calc(60 * var(--u)));
width: calc(120 * var(--u));
height: calc(120 * var(--u));
border-radius: 50%;
background: linear-gradient(#ffb547 20%, #ff4d9d 75%);
box-shadow: 0 0 calc(40 * var(--u)) rgb(255 77 157 / 0.6);
mask: linear-gradient(#000 30%, transparent 0 33%, #000 0 41%, transparent 0 45%, #000 0 52%, transparent 0 57%, #000 0);
}
/* lines from the vanishing point: parallel to the road, so they stay still */
.ground {
position: absolute;
inset: 44% 0 0;
background:
repeating-conic-gradient(from 90deg at 50% 0%, rgb(255 77 157 / 0.5) 0 0.5deg, transparent 0.5deg 9deg),
linear-gradient(#3b1a6e, #06030f 70%);
}
.road {
position: absolute;
left: 29%;
right: 29%;
bottom: 0;
height: calc(1400 * var(--u));
background: linear-gradient(90deg, #ff4d9d 0 calc(3 * var(--u)), #1c1438 calc(3 * var(--u)) calc(100% - calc(3 * var(--u))), #ff4d9d calc(100% - calc(3 * var(--u))));
transform-style: preserve-3d;
transform-origin: bottom;
/* the near end starts 120 units in front of the screen (well below the 300-unit perspective) */
transform: translateZ(calc(120 * var(--u))) rotateX(90deg);
}
.dashes {
position: absolute;
top: calc(-100 * var(--u)); /* one period taller than the road */
bottom: 0;
left: calc(50% - calc(3 * var(--u)));
width: calc(6 * var(--u));
background: repeating-linear-gradient(#ffb547 0 calc(50 * var(--u)), transparent calc(50 * var(--u)) calc(100 * var(--u)));
animation: dash 0.5s linear infinite;
}
.road i {
position: absolute;
bottom: 0;
width: calc(5 * var(--u));
height: calc(46 * var(--u));
border-radius: calc(3 * var(--u));
background: linear-gradient(#2ee6d6, rgb(46 230 214 / 0.15));
box-shadow: 0 0 calc(8 * var(--u)) rgb(46 230 214 / 0.7);
transform-origin: bottom;
animation: post 7s linear infinite;
animation-delay: calc(var(--i) * -7s / 6);
}
.road i::before {
content: '';
position: absolute;
top: calc(-4 * var(--u));
left: calc(-3 * var(--u));
width: calc(11 * var(--u));
height: calc(11 * var(--u));
border-radius: 50%;
background: radial-gradient(circle, #fff 0 25%, #2ee6d6 60%);
}
.road .left {
left: calc(-22 * var(--u));
}
.road .right {
right: calc(-22 * var(--u));
animation-delay: calc(var(--i) * -7s / 6 - 7s / 12); /* half a step later */
}
.haze {
position: absolute;
inset: calc(44% - 7%) 0 auto;
height: 22%;
background: linear-gradient(transparent, #8c2a6c 30% 50%, transparent);
}
/* one unit of translateZ: paint just above the road surface */
@keyframes dash {
from { transform: translateZ(calc(1 * var(--u))) translateY(0); }
to { transform: translateZ(calc(1 * var(--u))) translateY(calc(100 * var(--u))); }
}
@keyframes post {
from { opacity: 0; transform: translateY(calc(-1400 * var(--u))) rotateX(-90deg); }
12% { opacity: 1; }
to { opacity: 1; transform: translateY(0) rotateX(-90deg); }
}