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 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.-1.1s) starts the loop with the sign hanging straight down, so a paused sign hangs at rest in the middle of the frame instead of held up at one end of its swing.--u, tied to the canvas: the sign is 220 × 190 units, so it is the same share of a gallery card, the editor and a recording canvas, and its swing toward you still stays inside the frame.transform-origin: topanimation-direction: alternateease-in-out = pendulum<div class="scene">
<div class="sign">
<div class="board">OPEN</div>
</div>
</div>
.scene {
/* one base unit: every length below is a multiple of it, so the sign is the same share of a
gallery card, the editor, a full screen and a recording canvas */
--u: 0.3vmin;
display: grid;
place-items: center;
perspective: calc(800 * var(--u));
}
.sign {
position: relative;
width: calc(220 * var(--u));
height: calc(190 * var(--u));
transform-origin: top center;
animation: swing 2.2s ease-in-out -1.1s infinite alternate;
}
/* rail + two cords */
.sign::before {
content: '';
position: absolute;
inset: 0 calc(16 * var(--u)) auto;
height: calc(80 * var(--u));
border: solid #949bc0;
border-width: calc(4 * var(--u)) calc(2 * var(--u)) 0;
}
.board {
position: absolute;
inset: calc(80 * var(--u)) 0 0;
display: grid;
place-items: center;
border: calc(3 * var(--u)) solid #ffb547;
border-radius: calc(12 * var(--u));
background: #1b1408;
color: #ffb547;
font: 900 calc(45 * var(--u)) Inter, system-ui;
letter-spacing: 0.12em;
text-shadow: 0 0 calc(14 * var(--u)) #ffb547;
box-shadow: 0 0 calc(24 * var(--u)) rgb(255 181 71 / 0.45);
}
@keyframes swing {
from { transform: rotateY(-18deg) rotateX(-32deg); }
to { transform: rotateY(-18deg) rotateX(32deg); }
}