Synthwave floor
Pure CSSA gradient-drawn grid laid flat with rotateX, scrolling toward you forever.
A pendulum is just rotateX around the top edge with an ease-in-out alternate.
Your edited version
transform-origin: top center.rotateX from −32° to +32° with animation-direction: alternate.ease-in-out is what makes it physical — slow at the ends of the swing, fast through the middle.rotateY in both keyframes turns the sign slightly so you can see the swing.transform-origin: topanimation-direction: alternateease-in-out = pendulum<div class="scene">
<div class="sign">
<div class="board">OPEN</div>
</div>
</div>
.scene {
perspective: 800px;
}
.sign {
position: relative;
width: 220px;
height: 190px;
transform-origin: top center;
animation: swing 2.2s ease-in-out infinite alternate;
}
/* rail + two cords */
.sign::before {
content: '';
position: absolute;
inset: 0 16px auto;
height: 80px;
border: solid #949bc0;
border-width: 4px 2px 0;
}
.board {
position: absolute;
inset: 80px 0 0;
display: grid;
place-items: center;
border: 3px solid #ffb547;
border-radius: 12px;
background: #1b1408;
color: #ffb547;
font: 900 2.8rem system-ui;
letter-spacing: 0.12em;
text-shadow: 0 0 14px #ffb547;
box-shadow: 0 0 24px rgb(255 181 71 / 0.45);
}
@keyframes swing {
from { transform: rotateY(-18deg) rotateX(-32deg); }
to { transform: rotateY(-18deg) rotateX(32deg); }
}
.d-sign {
position: relative;
width: 170px;
height: 150px;
transform-style: preserve-3d;
transform-origin: top center;
animation: d-sign-swing 2.2s ease-in-out infinite alternate;
// the rail it hangs from + two cords
&::before {
content: '';
position: absolute;
inset: 0 12px auto;
height: 62px;
border: solid var(--muted);
border-width: 4px 2px 0;
}
&__board {
position: absolute;
inset: 62px 0 0;
display: grid;
place-items: center;
border: 3px solid var(--warm);
border-radius: 12px;
background: #1b1408;
color: var(--warm);
font-size: 36px;
font-weight: 900;
letter-spacing: 0.12em;
text-shadow: 0 0 14px var(--warm);
box-shadow:
0 0 24px color-mix(in srgb, var(--warm) 45%, transparent),
inset 0 0 18px color-mix(in srgb, var(--warm) 25%, transparent);
}
}
@keyframes d-sign-swing {
from {
transform: translateY(-20px) rotateY(-18deg) rotateX(-32deg);
}
to {
transform: translateY(-20px) rotateY(-18deg) rotateX(32deg);
}
}