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.
Six side panels in a closed ring plus two hexagon caps cut with clip-path. The apothem, (side / 2) / tan(30°), is how far each panel steps out.
Your edited version
rotateY(i × 60deg), then translateZ by the apothem, the distance from the centre to the middle of a side.--u, so the prism is the same share of a gallery card, the editor and a recording canvas. The numbers below are those units.(side / 2) / tan(180° / 6). For 60-wide panels that is 51.96. Any less and the panels cross; any more and the corners open.2 × side by 2 × apothem box cut to a hexagon with clip-path. clip-path would flatten a 3D container, but the caps have no 3D children, so it is safe here.rotateX(90deg) lays a cap flat; translateZ(height / 2) then lifts it along its new normal to the top (and -90deg for the bottom).rotateY(i × 60°) + translateZ(apothem)clip-path: polygon() capsrotateX(90deg) to lay a cap flattwo-axis tumble<div class="scene">
<div class="prism">
<i style="--i:0"></i>
<i style="--i:1"></i>
<i style="--i:2"></i>
<i style="--i:3"></i>
<i style="--i:4"></i>
<i style="--i:5"></i>
<b></b>
<b></b>
</div>
</div>
.scene {
/* one base unit: every length below is a multiple of it, so the prism is the same share of a
card, the editor, a full screen and a recording canvas */
--u: 0.33vmin;
perspective: calc(800 * var(--u));
}
.prism {
--w: calc(60 * var(--u)); /* one side of the hexagon = one panel */
--h: calc(110 * var(--u));
--r: calc(51.96 * var(--u)); /* apothem = (w / 2) / tan(180deg / 6) */
position: relative;
width: var(--w);
height: var(--h);
transform-style: preserve-3d;
animation: tumble 18s linear infinite;
}
.prism i {
position: absolute;
inset: 0;
background: rgb(139 108 255 / 0.24);
border: calc(1 * var(--u)) solid rgb(139 108 255 / 0.75);
box-shadow: inset 0 0 calc(24 * var(--u)) rgb(139 108 255 / 0.3);
/* turn to face outward, THEN step out along that direction */
transform: rotateY(calc(var(--i) * 60deg)) translateZ(var(--r));
}
.prism i:nth-child(even) {
background: rgb(46 230 214 / 0.2);
border-color: rgb(46 230 214 / 0.75);
box-shadow: inset 0 0 calc(24 * var(--u)) rgb(46 230 214 / 0.3);
}
/* caps: a regular hexagon's corner radius equals its side, so the box is 2w by 2r */
.prism b {
position: absolute;
left: calc(50% - var(--w));
top: calc(50% - var(--r));
width: calc(var(--w) * 2);
height: calc(var(--r) * 2);
clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
background: radial-gradient(circle, rgb(255 77 157 / 0.12) 20%, rgb(255 77 157 / 0.55));
transform: rotateX(90deg) translateZ(calc(var(--h) / 2));
}
.prism b + b {
transform: rotateX(-90deg) translateZ(calc(var(--h) / 2));
}
/* -25deg + 360deg = 335deg: the end pose equals the start pose, so the loop is seamless */
@keyframes tumble {
from { transform: rotateX(-25deg) rotateY(0deg); }
to { transform: rotateX(335deg) rotateY(360deg); }
}