Cube Auto-Rotation
A translucent 100 px indigo cube, faces numbered 1 to 6, tumbles endlessly on two axes at once: one full turn in 8 s, at constant speed, with no interaction at all. Pure CSS, zero JavaScript, held at a three-quarter view when the user reduces motion.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. 3D has 50 effects, including 8 free. Explore the category →
3 usage examples



How it works
The .fx-0011-root root (#0a0a0f background, at least 300 px tall) centers a 100 × 100 px .cube-auto-container that carries the camera: perspective: 600px. Inside it, .cube-auto keeps its children in 3D space (transform-style: preserve-3d), and six 100 × 100 px .cube-auto-face elements are stacked in the same spot, then each pushed 50 px (half the side) in its own direction: translateZ(50px) for the front, rotateY(180deg) translateZ(50px) for the back, rotateY(±90deg) for the sides, rotateX(±90deg) for the top and bottom. All six faces share the same color, rgba(99, 102, 241, .8), with a solid 2 px #6366f1 border: the cube reads through its edges and its transparency, which lets you make out the faces behind.
The rotateCube animation runs from rotateX(0) rotateY(0) to rotateX(360deg) rotateY(360deg) over 8 s, linear, forever. Both angles grow together: the cube does not spin around a fixed axis, it tumbles, and no face comes back to the front at a steady pace. After 8 s both angles equal 360°, that is 0°: the loop restarts without a jolt, all the more since the speed is constant. Measured in Chromium 151 and Firefox 153: same tumble, about 3% of the block's pixels change every 0.8 s, 0 errors. Only transform is animated: the browser hands it to the compositor, with no layout recalculation.
Three choices hold the effect together. The perspective sits on the container, not on the cube: the camera stays put while the object turns in front of it. At 600 px for a 100 px cube, distortion stays moderate, near edges barely larger than far ones. Finally, nothing may "flatten" .cube-auto: overflow: hidden, a filter or an opacity below 1 on that element itself brings the six faces back into a single plane. Two copies on one page each turn on their own (nothing is shared, no JavaScript). Playwright's WebKit flattens all CSS 3D, even a minimal reference cube: rendering on a real Safari could not be verified.
Accessibility
- Reduced motion: under
prefers-reduced-motion: reduce, a block scoped to.fx-0011-rootstops the animation and sets the cube torotateX(-25deg) rotateY(-35deg): a fixed three-quarter view, three faces visible. Measured in Chromium and Firefox: 0 running animations and 0% of pixels changing over 0.8 s (3.2% without the preference). - Continuous motion: an animation lasting more than 5 s next to other content must be stoppable (WCAG 2.2.2). Reduced motion stops it; if the cube sits in the middle of a reading page, add a button that sets
animation-play-state: pausedon.cube-auto. - Decorative content: the cube only carries numbers. In a banner, put
aria-hidden="true"on the root, as in the examples. Text written on the faces is mirrored half the time: never leave useful information to the faces alone, write it next to the cube too. - Pace: one turn in 8 s, constant speed, no flashing and no sudden change in brightness; the motion stays inside a square of about 170 px (the cube's diagonal).
Browser compatibility
CSS (3D transform, transform-style: preserve-3d, perspective, @keyframes), zero JavaScript, no dependencies. Measured in Chromium 151 and Firefox 153: same tumble (0.13% difference between the two on the reduced-motion still frame), two independent copies, stops under reduced motion, 0 errors. Playwright's WebKit 26.5 flattens all CSS 3D, even a reference cube: it says nothing about the real Safari, which was not verified.
If preserve-3d is not applied (old browser, or overflow, filter, opacity < 1 set on .cube-auto), the six faces collapse into one plane: you see a square that warps as it turns. The content stays visible.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0011-root">
<div class="demo-3d">
<div class="cube-auto-container">
<div class="cube-auto">
<div class="cube-auto-face front">1</div> … (6 faces: front, back, right, left, top, bottom)
</div>
</div>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Speed (CSS — 8s in the animation of .cube-auto) |
8 s | 12 s for an object floating behind a heading, 4 s for a waiting indicator. Keep linear: with ease-in-out, the cube would pause at the end of every turn. |
Tumble axes (CSS — @keyframes rotateCube) |
rotateX(360deg) rotateY(360deg) | rotateY(360deg) alone: the cube spins as on a turntable, each side face coming to the front in turn. rotateX(360deg) rotateY(720deg): two horizontal turns for one vertical, a more irregular tumble. Keep multiples of 360° so the loop stays seamless. |
Size (CSS — 100px on the container and faces, translateZ(50px)) |
100 px, faces pushed out 50 px | The push is always half the side. For a 160 px cube: container and faces at 160 px, translateZ(80px) in all six face rules. |
Color and transparency (CSS — background and border of .cube-auto-face) |
rgba(99, 102, 241, .8), 2 px #6366f1 border | Below 0.5 opacity, the back faces read clearly through (glass, ice); at 1 the cube becomes a solid block (sugar, die). A thin light border draws the edges when faces are almost transparent. |
Perspective (CSS — perspective on .cube-auto-container) |
600px | 300 px exaggerates the distortion (huge near corners); 1,200 px almost flattens it into an isometric view. Keep it between 4 and 10 times the cube's size. |
Face content (HTML — the six .cube-auto-face) |
numbers 1 to 6 | Empty the faces for an object (ice, sugar) or keep a single engraving on the front face. Text on several faces reads mirrored half the time. |
FAQ
rotateX and rotateY grow together: at any moment, the actual rotation axis is a diagonal that keeps changing. After 8 s both angles equal 360° and the cube is back exactly where it started, so the loop repeats identically, but within one turn no face comes back to the front at a regular interval..cube-auto-container:hover .cube-auto { animation-play-state: paused }. Add tabindex="0" to the container and :focus-visible to the same rule so the keyboard can stop it too. The cube freezes where it was and resumes from there.