Twisting puzzle cube
Pure CSSA 3×3×3 cube built as three layers that take turns twisting a quarter turn. Each layer is one flat box with the stickers painted on by gradients.
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);
}
}