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 crown of trapezoid facets leaning 45° above the girdle and a deep pavilion of triangles below, with a glint that walks from facet to facet.
Your edited version
--u, so the stone is the same share of a gallery card, the editor and a recording canvas. The numbers below are those units.rotateY(i × 45deg) translateZ(calc(60 * var(--u))).clip-path: 20% to 80%.transform-origin: top) and lean in by atan(60 / 72) ≈ 39.8°, so a 72-deep point forms where the tips meet.animation-delay grows with --i, so the sparkle walks around the stone. Only opacity animates.trapezoid + triangle clip-pathshinge on the girdle: transform-origin top / bottomlean = atan(radius / depth)staggered opacity glint<div class="scene">
<div class="gem">
<i class="crown" style="--i:0"></i>
<i class="crown" style="--i:1"></i>
<i class="crown" style="--i:2"></i>
<i class="crown" style="--i:3"></i>
<i class="crown" style="--i:4"></i>
<i class="crown" style="--i:5"></i>
<i class="crown" style="--i:6"></i>
<i class="crown" style="--i:7"></i>
<i class="pav" style="--i:0"></i>
<i class="pav" style="--i:1"></i>
<i class="pav" style="--i:2"></i>
<i class="pav" style="--i:3"></i>
<i class="pav" style="--i:4"></i>
<i class="pav" style="--i:5"></i>
<i class="pav" style="--i:6"></i>
<i class="pav" style="--i:7"></i>
<b></b>
</div>
</div>
.scene {
/* one base unit: every length below is a multiple of it, so the stone is the same share of a
card, the editor, a full screen and a recording canvas */
--u: 0.55vmin;
perspective: calc(800 * var(--u));
}
.gem {
position: relative;
width: calc(49.71 * var(--u)); /* one girdle edge = 2 × 60 × tan(180deg / 8) */
height: calc(96 * var(--u)); /* crown 24 + pavilion 72 */
transform-style: preserve-3d;
animation: spin 14s linear infinite;
}
.gem i {
--alpha: 0.2;
position: absolute;
left: 0;
width: 100%;
}
.gem i:nth-child(odd) {
--alpha: 0.4;
}
/* the glint: fades in and out, one facet after another */
.gem i::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(115deg, transparent 30%, rgb(255 255 255 / 0.8) 50%, transparent 70%);
opacity: 0;
animation: glint 3.2s ease-in-out infinite;
animation-delay: calc(var(--i) * -0.4s + var(--late, 0s));
}
/* crown: trapezoids standing on the girdle, leaning 45deg inward */
.gem .crown {
bottom: calc(72 * var(--u));
height: calc(33.94 * var(--u)); /* slant = √2 × 24 */
transform-origin: 50% 100%;
transform: rotateY(calc(var(--i) * 45deg)) translateZ(calc(60 * var(--u))) rotateX(45deg);
clip-path: polygon(20% 0, 80% 0, 100% 100%, 0 100%); /* top edge = 36 / 60 of the bottom */
background:
linear-gradient(rgb(46 230 214 / 0.8), rgb(46 230 214 / 0.8)) top / 100% calc(1.5 * var(--u)) no-repeat,
linear-gradient(rgb(46 230 214 / 0.8), rgb(46 230 214 / 0.8)) bottom / 100% calc(1.5 * var(--u)) no-repeat,
linear-gradient(to top, rgb(46 230 214 / var(--alpha)), rgb(46 230 214 / 0.12));
}
/* pavilion: triangles hanging from the girdle, leaning in by atan(60 / 72) */
.gem .pav {
--late: -1.7s;
top: calc(24 * var(--u));
height: calc(93.72 * var(--u)); /* slant = √(72² + 60²) */
transform-origin: 50% 0;
transform: rotateY(calc(var(--i) * 45deg)) translateZ(calc(60 * var(--u))) rotateX(-39.81deg);
clip-path: polygon(0 0, 100% 0, 50% 100%);
background:
linear-gradient(to top right, transparent 50%, rgb(139 108 255 / 0.8) 50% calc(50% + 1.2 * var(--u)), transparent calc(50% + 1.2 * var(--u))) left / 50% 100% no-repeat,
linear-gradient(to top left, transparent 50%, rgb(139 108 255 / 0.8) 50% calc(50% + 1.2 * var(--u)), transparent calc(50% + 1.2 * var(--u))) right / 50% 100% no-repeat,
linear-gradient(rgb(139 108 255 / var(--alpha)), rgb(255 77 157 / 0.14));
}
/* table: a flat octagon on top, 36 from the axis */
.gem b {
position: absolute;
left: calc(50% - 36 * var(--u));
top: calc(-36 * var(--u));
width: calc(72 * var(--u));
height: calc(72 * var(--u));
clip-path: polygon(29.29% 0, 70.71% 0, 100% 29.29%, 100% 70.71%, 70.71% 100%, 29.29% 100%, 0 70.71%, 0 29.29%);
background: linear-gradient(135deg, rgb(46 230 214 / 0.55), rgb(255 255 255 / 0.35), rgb(46 230 214 / 0.3));
transform: rotateX(90deg);
}
@keyframes spin {
from { transform: rotateX(-18deg) rotateY(0deg); }
to { transform: rotateX(-18deg) rotateY(360deg); }
}
@keyframes glint {
0%, 55%, 100% { opacity: 0; }
78% { opacity: 0.9; }
}