Rotating cube
Pure CSSSix faces placed with rotate + translateZ, spun by a single keyframe animation.
CSS has no curves in 3D, so a cylinder is 24 flat strips. Sass computes the strip width.
Your edited version
2 × r × tan(180° / n). For r = 80px and n = 24 that is ≈ 21px; add 1px so no seams show.rotateY(i × 15deg) translateZ(r).strip width = 2r × tan(180° / n)rotateY + translateZper-strip shading<div class="scene">
<div class="cylinder">
<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>
<b></b>
</div>
</div>
.scene {
perspective: 800px;
}
.cylinder {
--r: 80px;
position: relative;
width: 22px; /* 2 × 80 × tan(7.5deg) + 1px */
height: 170px;
transform-style: preserve-3d;
animation: cylinder-spin 9s linear infinite;
}
.cylinder i {
position: absolute;
inset: 0;
background: hsl(calc(170 + var(--i) * 15) 80% 58%);
transform: rotateY(calc(var(--i) * 15deg)) translateZ(var(--r));
}
/* lid */
.cylinder b {
position: absolute;
top: calc(var(--r) * -1);
left: calc(50% - var(--r));
width: calc(var(--r) * 2);
height: calc(var(--r) * 2);
border-radius: 50%;
background: #17506e;
transform: rotateX(90deg);
}
@keyframes cylinder-spin {
from { transform: rotateX(-22deg) rotateY(0deg); }
to { transform: rotateX(-22deg) rotateY(360deg); }
}
@use 'sass:math';
$n: 24;
$r: 62px;
// Width of one flat strip so that $n of them close the circle (+1px overlap against seams).
$strip: 2 * $r * math.tan(math.div(180deg, $n)) + 1px;
.d-cylinder {
position: relative;
width: $strip;
height: 130px;
transform-style: preserve-3d;
animation: d-cylinder-spin 9s linear infinite;
// --i (0…23) comes from the markup
i {
position: absolute;
inset: 0;
background: hsl(calc(170 + var(--i) * 15) 80% 58%);
transform: rotateY(calc(var(--i) * #{math.div(360deg, $n)})) translateZ($r);
}
// lid
b {
position: absolute;
top: -$r;
left: calc(50% - #{$r});
width: $r * 2;
height: $r * 2;
border-radius: 50%;
background: radial-gradient(circle, #fff3, transparent 70%), #17506e;
transform: rotateX(90deg);
}
}
@keyframes d-cylinder-spin {
from {
transform: rotateX(-22deg) rotateY(0deg);
}
to {
transform: rotateX(-22deg) rotateY(360deg);
}
}