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.
A donut made of 24 circles. Each one turns to its angle and walks out with translateX, so it stands edge-on around the hole like a slice of the tube.
Your edited version
border-radius: 50%).rotateY(i × 15deg) and then translateX, not translateZ. That keeps it in the plane through the axis, edge-on to the path, like a slice of the tube. (translateZ would lay it tangent, like a carousel panel.)translateX distance is the radius from the hole's centre to the tube's centre; the ring size is the tube's thickness. Both are multiples of one base unit, --u, so the torus is the same share of a gallery card, the editor and a recording canvas.cos(i × 15deg): teal at ring 0, violet halfway round, teal again at the end, so there is no seam.rotateY + translateX (not translateZ)border-radius: 50% cross-sectionscolour from cos(i × 15deg): no seamtwo-axis spin<div class="scene">
<div class="torus">
<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>
<i style="--i:6"></i>
<i style="--i:7"></i>
<i style="--i:8"></i>
<i style="--i:9"></i>
<i style="--i:10"></i>
<i style="--i:11"></i>
<i style="--i:12"></i>
<i style="--i:13"></i>
<i style="--i:14"></i>
<i style="--i:15"></i>
<i style="--i:16"></i>
<i style="--i:17"></i>
<i style="--i:18"></i>
<i style="--i:19"></i>
<i style="--i:20"></i>
<i style="--i:21"></i>
<i style="--i:22"></i>
<i style="--i:23"></i>
</div>
</div>
.scene {
/* one base unit: every length below is a multiple of it, so the ring is the same share of a
card, the editor, a full screen and a recording canvas */
--u: 0.4vmin;
perspective: calc(800 * var(--u));
}
.torus {
position: relative;
width: calc(40 * var(--u)); /* tube thickness */
height: calc(40 * var(--u));
transform-style: preserve-3d;
animation: tumble 16s linear infinite;
}
.torus i {
--hue: calc(214 - 39 * cos(var(--i) * 15deg)); /* 175 teal ... 253 violet ... 175 */
position: absolute;
inset: 0;
border: calc(2 * var(--u)) solid hsl(var(--hue) 85% 64%);
border-radius: 50%;
background: hsl(var(--hue) 85% 64% / 0.14);
box-shadow: inset 0 0 calc(10 * var(--u)) hsl(var(--hue) 85% 64% / 0.45);
/* 24 × 15deg = 360deg; translateX keeps each ring edge-on to the circle */
transform: rotateY(calc(var(--i) * 15deg)) translateX(calc(56 * var(--u)));
}
/* Every ring stands in a plane through the axis, so looked at straight down the axis they are
all edge-on at once and the torus draws nothing. So it never tumbles through that view: it is
held 50deg off it (rotateX), spins on its own axis (the inner rotateY) and swings round the
vertical (the outer rotateY), which keeps the axis at least 40deg from the line of sight.
Both spins end 360deg after they start, so the loop is seamless. */
@keyframes tumble {
from { transform: rotateZ(16deg) rotateY(0deg) rotateX(-50deg) rotateY(0deg); }
to { transform: rotateZ(16deg) rotateY(360deg) rotateX(-50deg) rotateY(360deg); }
}