One face is just a square div. To turn six of them into a cube: point each one straight at the camera, then push it out along z by half the cube's edge length. translateZ(h) alone is the front face; rotateY(180deg) translateZ(h) is the back; rotateY(±90deg) translateZ(h) are the sides; rotateX(±90deg) translateZ(h) are top and bottom.
The key is transform-style: preserve-3d on the parent (the cube group) — without it the children's 3D placement collapses into one flat plane and it just looks like stacked squares. Perspective on some ancestor still needs to be present for the result to actually read as three-dimensional.
preserve-3d breaks the moment it passes through an ancestor with overflow: hidden, opacity < 1, or a filter — each of those forces its own flat rendering group. If a cube suddenly looks flat, suspect one of those three sitting somewhere in between.
When to use
For product showcases, loaders, or a setting switcher that reads as a physical rotating object. Filling all six faces with rich content gets heavy — only populate the faces you need.