Synthwave floor
Pure CSSA gradient-drawn grid laid flat with rotateX, scrolling toward you forever.
Each layer is ONE element; its stars are box-shadows generated by Sass random().
Your edited version
box-shadow of it.random() at build time (see the SCSS tab); here it is written out.box-shadow as particlesSass random() at build timetranslateZ fly-through<div class="space">
<i></i><i></i><i></i>
</div>
.space {
position: fixed;
inset: 0;
display: grid;
place-items: center;
overflow: hidden;
perspective: 300px;
background: radial-gradient(circle, #0d1030, #02030a 75%);
}
.space i {
position: absolute;
width: 1px;
height: 1px;
border-radius: 50%;
animation: warp 3s linear infinite;
box-shadow:
-450px 379px 0 0.5px #fff, -261px 206px 0 1px #fff, -154px 227px 0 1px #fff, 39px 166px 0 1px #fff,
285px -232px 0 0.5px #fff, 187px 178px 0 0.5px #fff, 166px -29px 0 1px #fff, 277px -339px 0 1px #fff,
381px 170px 0 1px #fff, 70px 371px 0 1px #fff, -115px -148px 0 1px #fff, -151px -313px 0 0.5px #fff,
-64px -185px 0 1px #fff, 52px 206px 0 1px #fff, -397px -204px 0 1px #fff, 8px -71px 0 0.5px #fff,
368px -401px 0 0.5px #fff, -140px 148px 0 1px #fff, 13px -301px 0 0.5px #fff, -195px -122px 0 0.5px #fff,
-151px 28px 0 1px #fff, -240px 366px 0 0.5px #fff, 327px 122px 0 1px #fff, 15px 4px 0 1px #fff,
396px -93px 0 1px #fff, -224px 78px 0 0.5px #fff, -152px -98px 0 1px #fff, 340px -350px 0 1px #fff,
-380px -84px 0 0.5px #fff, -380px 447px 0 0.5px #fff, 119px -320px 0 0.5px #fff, 84px -326px 0 1px #fff,
346px 352px 0 1px #fff, 367px 235px 0 0.5px #fff, -441px -227px 0 0.5px #fff, -449px 105px 0 0.5px #fff,
217px -10px 0 1px #fff, -236px 344px 0 0.5px #fff, -113px 355px 0 0.5px #fff, -10px -447px 0 1px #fff;
}
.space i:nth-child(2) {
animation-delay: -1s;
box-shadow:
-449px -430px 0 1px #fff, -84px 220px 0 1px #fff, 142px -263px 0 0.5px #fff, 31px 420px 0 0.5px #fff,
-211px -70px 0 0.5px #fff, -54px -51px 0 1px #fff, 412px 106px 0 0.5px #fff, 441px -172px 0 0.5px #fff,
243px -301px 0 0.5px #fff, 214px -284px 0 0.5px #fff, -340px -38px 0 1px #fff, 179px 335px 0 0.5px #fff,
118px 346px 0 0.5px #fff, -298px -39px 0 0.5px #fff, 39px 74px 0 1px #fff, -274px 29px 0 1px #fff,
448px -266px 0 1px #fff, -184px 36px 0 0.5px #fff, 61px -14px 0 0.5px #fff, 331px -440px 0 1px #fff,
55px 403px 0 0.5px #fff, 76px 160px 0 1px #fff, -137px 434px 0 1px #fff, -179px 63px 0 0.5px #fff,
-62px -29px 0 0.5px #fff, 432px -309px 0 1px #fff, -99px -225px 0 1px #fff, -80px 64px 0 0.5px #fff,
411px -158px 0 1px #fff, 284px 402px 0 1px #fff, -372px -157px 0 1px #fff, 283px 18px 0 1px #fff,
266px -171px 0 1px #fff, -338px -276px 0 0.5px #fff, -59px 139px 0 0.5px #fff, 84px -56px 0 0.5px #fff,
369px -135px 0 1px #fff, -377px 363px 0 0.5px #fff, 324px -124px 0 1px #fff, -394px 231px 0 1px #fff;
}
.space i:nth-child(3) {
animation-delay: -2s;
box-shadow:
-436px -241px 0 0.5px #fff, -173px -161px 0 0.5px #fff, -254px -430px 0 1px #fff, 287px -263px 0 0.5px #fff,
336px 427px 0 0.5px #fff, -348px -84px 0 1px #fff, -420px -190px 0 1px #fff, -425px -370px 0 0.5px #fff,
128px 3px 0 0.5px #fff, 29px 434px 0 0.5px #fff, -10px 170px 0 0.5px #fff, -389px 297px 0 0.5px #fff,
-36px 427px 0 1px #fff, -49px -444px 0 1px #fff, 148px 263px 0 1px #fff, -345px -64px 0 1px #fff,
418px -183px 0 0.5px #fff, 386px -220px 0 0.5px #fff, -313px -440px 0 1px #fff, 321px -237px 0 1px #fff,
-434px -311px 0 1px #fff, 200px 417px 0 1px #fff, 159px 129px 0 0.5px #fff, -209px -62px 0 1px #fff,
282px 60px 0 0.5px #fff, -415px 39px 0 0.5px #fff, -176px 355px 0 1px #fff, 216px -345px 0 0.5px #fff,
-151px -274px 0 0.5px #fff, -240px 362px 0 0.5px #fff, 438px 446px 0 0.5px #fff, 329px -77px 0 0.5px #fff,
-404px -254px 0 0.5px #fff, 233px 3px 0 0.5px #fff, -164px 392px 0 0.5px #fff, -424px -388px 0 1px #fff,
204px 381px 0 1px #fff, 40px -20px 0 1px #fff, 175px -191px 0 0.5px #fff, 98px 66px 0 1px #fff;
}
/* stop at 2/3 of the perspective distance; at z = perspective the scale is infinite */
@keyframes warp {
from { opacity: 0; transform: translateZ(-600px); }
20%, 80% { opacity: 1; }
to { opacity: 0; transform: translateZ(200px); }
}
@use 'sass:list';
@use 'sass:math';
// $count random white dots inside a $size square, returned as one box-shadow list.
// random() runs at BUILD time: the browser just receives a long static value.
@function stars($count, $size) {
$shadows: ();
@for $i from 1 through $count {
$x: math.random($size) - math.div($size, 2);
$y: math.random($size) - math.div($size, 2);
$shadows: list.append($shadows, #{$x}px #{$y}px 0 #{math.random(2) * 0.5}px #fff, comma);
}
@return $shadows;
}
.d-starfield {
position: absolute;
inset: 0;
display: grid;
place-items: center;
overflow: hidden;
perspective: 300px;
background: radial-gradient(circle, #0d1030, #02030a 75%);
// One element per layer; every star is a shadow of this single 1px dot.
i {
position: absolute;
width: 1px;
height: 1px;
border-radius: 50%;
box-shadow: stars(70, 700);
animation: d-starfield-warp 3s linear infinite;
}
i:nth-child(2) {
box-shadow: stars(70, 700);
animation-delay: -1s;
}
i:nth-child(3) {
box-shadow: stars(70, 700);
animation-delay: -2s;
}
}
@keyframes d-starfield-warp {
from {
opacity: 0;
transform: translateZ(-600px);
}
20%,
80% {
opacity: 1;
}
// Stop at 2/3 of the perspective distance (3x magnification) and fade out.
// At z = perspective the scale would be infinite.
to {
opacity: 0;
transform: translateZ(200px);
}
}