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.
Isometric plates that rest spread apart along the Z axis and close up together, each placed by one custom property.
Your edited version
rotateX(58deg) rotateZ(-45deg) on the parent gives the classic isometric viewing angle.translateZ separates them.--i, and its resting offset is calc((var(--i) - 1.5) * 40 * var(--u)) — one line, four different results.to { translateZ(0) }. An alternate animation starts from the element’s own transform, so the pose a paused card shows is the open one.--u, so the deck is the same share of a gallery card, the editor and a recording canvas. A plate is 140 of those units square.rotateX + rotateZ isometric viewtranslateZvar() in the resting pose, one keyframe to close<div class="scene">
<div class="layers">
<i style="--i:0"></i>
<i style="--i:1"></i>
<i style="--i:2"></i>
<i style="--i:3"></i>
</div>
</div>
.scene {
/* one base unit: every length below is a multiple of it, so the deck is the same share of a
card, the editor, a full screen and a recording canvas */
--u: 0.32vmin;
perspective: calc(900 * var(--u));
}
.layers {
position: relative;
width: calc(140 * var(--u));
height: calc(140 * var(--u));
transform-style: preserve-3d;
transform: rotateX(58deg) rotateZ(-45deg);
}
/* the deck rests open, 40 units between plates, measured from the MIDDLE of the four: it grows
both ways at once, so what is drawn stays centred on the model box at every moment */
.layers i {
position: absolute;
inset: 0;
border-radius: calc(16 * var(--u));
border: calc(1 * var(--u)) solid rgb(255 255 255 / 0.35);
background: hsl(calc(255 + var(--i) * 32) 85% 62% / 0.78);
transform: translateZ(calc((var(--i) - 1.5) * 40 * var(--u)));
animation: close 2.6s ease-in-out infinite alternate;
}
@keyframes close {
to { transform: translateZ(0); }
}