Rotating cube
Pure CSSSix faces placed with rotate + translateZ, spun by a single keyframe animation.
Three rings tilted into different planes, each spinning inside its own plane.
Your edited version
transform, so a ring cannot both hold a tilt and animate a spin.rotateZ.preserve-3dstatic tilt wrapper + spinning childSass @each<div class="scene">
<div class="atom">
<b></b>
<div class="plane"><div class="orbit"><i></i></div></div>
<div class="plane"><div class="orbit"><i></i></div></div>
<div class="plane"><div class="orbit"><i></i></div></div>
</div>
</div>
.scene {
perspective: 800px;
}
.atom {
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
}
.atom b {
position: absolute;
inset: 40%;
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, #fff, #8b6cff 60%);
box-shadow: 0 0 24px #8b6cff;
}
.plane {
position: absolute;
inset: 0;
transform-style: preserve-3d;
}
.plane:nth-of-type(1) { transform: rotateX(72deg); color: #2ee6d6; }
.plane:nth-of-type(2) { transform: rotateZ(60deg) rotateX(72deg); color: #ff4d9d; }
.plane:nth-of-type(3) { transform: rotateZ(-60deg) rotateX(72deg); color: #ffb547; }
.orbit {
position: absolute;
inset: 0;
border: 2px solid currentColor;
border-radius: 50%;
animation: orbit-spin 3s linear infinite;
}
.plane:nth-of-type(2) .orbit { animation-duration: 3.7s; }
.plane:nth-of-type(3) .orbit { animation-duration: 4.4s; }
.orbit i {
position: absolute;
top: -7px;
left: calc(50% - 6px);
width: 12px;
height: 12px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 12px currentColor;
}
@keyframes orbit-spin {
to { transform: rotateZ(360deg); }
}
@use 'sass:list';
$planes: (
1: (rotateX(72deg), var(--accent-2), 2.4s),
2: (rotateZ(60deg) rotateX(72deg), var(--hot), 3.1s),
3: (rotateZ(-60deg) rotateX(72deg), var(--warm), 3.8s),
);
.d-orbit {
position: relative;
width: 170px;
height: 170px;
transform-style: preserve-3d;
// nucleus
b {
position: absolute;
inset: 40%;
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, #fff, var(--accent) 60%);
box-shadow: 0 0 24px var(--accent);
}
// The plane holds the static tilt…
&__plane {
position: absolute;
inset: 0;
transform-style: preserve-3d;
}
// …and the ring spins inside it, so the two transforms never fight.
&__ring {
position: absolute;
inset: 0;
border: 2px solid currentColor;
border-radius: 50%;
animation: d-orbit-spin 3s linear infinite;
i {
position: absolute;
top: -7px;
left: calc(50% - 6px);
width: 12px;
height: 12px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 12px currentColor;
}
}
@each $n, $plane in $planes {
&__plane:nth-of-type(#{$n}) {
transform: #{list.nth($plane, 1)};
color: list.nth($plane, 2);
.d-orbit__ring {
animation-duration: list.nth($plane, 3);
}
}
}
}
@keyframes d-orbit-spin {
to {
transform: rotateZ(360deg);
}
}