Shapes & solids · 30 models

Every solid in CSS is made of paper

CSS 3D Lab has 30 shapes and solids, and not one of them is solid. Four of them show the tricks that make flat elements pass for a coin, a puzzle cube, a donut and a pair of gears.

Dark cover with a dotted grid. On the left, the CSS 3D Lab cube logo, the label CSS 3D Lab · Shapes & solids, the title “Every solid in CSS is made of paper” and the line “30 shapes, and the tricks that keep flat elements from vanishing edge-on.” On the right, four tiles: a gold coin turned almost edge-on, a puzzle cube mid-twist, a torus built from blue and teal circles, and two meshing gears, violet and teal.

Four of CSS 3D Lab’s 30 shapes and solids: a coin, a puzzle cube, a torus and a pair of gears. Image and models: Edgaras Neverdauskas.

Download
Alt text · 414 characters

Dark cover with a dotted grid. On the left, the CSS 3D Lab cube logo, the label CSS 3D Lab · Shapes & solids, the title “Every solid in CSS is made of paper” and the line “30 shapes, and the tricks that keep flat elements from vanishing edge-on.” On the right, four tiles: a gold coin turned almost edge-on, a puzzle cube mid-twist, a torus built from blue and teal circles, and two meshing gears, violet and teal.

How these get made

I don't write the CSS in CSS 3D Lab. Claude does. My part is asking for things, often fairly random ones, and looking hard at what comes back: does it hold up when it turns, from every side, at every size? I'm less a developer here than someone curious about what a web page is actually able to draw, and a bit of a tester.

The Shapes & solids group is where that curiosity runs into CSS's biggest limit.

Paper in a 3D room

CSS can turn an element in three dimensions, push it towards you and look at it through a perspective. What it can't do is give anything thickness. Every element stays a flat rectangle. There is no sphere in CSS, no box and no volume, only flat pieces arranged so your eye fills in the rest.

That works until you look from the side. A flat element seen exactly edge-on is zero pixels thick, and the browser draws nothing at all. Most of the work in this group went into what happens at that moment.

The coin: give the edge something to be

The obvious coin is two discs, a front and a back, pushed a little apart. It looks right until it turns edge-on, and then it's gone. Filling the gap with a stack of discs doesn't help: every disc in the stack is flat too, and vanishes with the others.

Two dark panels side by side, both showing the same coin at the same moment, exactly edge-on. The left panel, labelled “Two discs: nothing is drawn”, is empty. The right panel, labelled “With a rim: a solid edge”, shows a thin gold vertical bar with ridges, the rim of 24 slats.

The same coin at the same moment, exactly edge-on: without its rim it draws nothing; with it, a solid ridged edge.

Download
Alt text · 278 characters

Two dark panels side by side, both showing the same coin at the same moment, exactly edge-on. The left panel, labelled “Two discs: nothing is drawn”, is empty. The right panel, labelled “With a rim: a solid edge”, shows a thin gold vertical bar with ridges, the rim of 24 slats.

So the coin has a real rim: 24 thin slats stood around the edge. Each one is turned to its place on the circle, walked out to the edge and stood up facing outwards:

CSS
.coin i {
  transform: rotateZ(calc(var(--i) * 15deg)) translateY(calc(-74.5 * var(--u))) rotateX(90deg);
}

Edge-on, the slats facing you become a solid, ridged edge, like a real coin's.

A gold coin with a dollar sign, turned almost edge-on against a dark background, so its ridged rim of thin slats shows as a solid edge beside the face.

Almost edge-on, the 24 slats round the rim read as a solid, ridged edge.

Download
Alt text · 151 characters

A gold coin with a dollar sign, turned almost edge-on against a dark background, so its ridged rim of thin slats shows as a solid edge beside the face.

It's 59 lines of CSS and no JavaScript. Try the coin and pause it edge-on.

The puzzle cube: don't build what never moves on its own

A 3×3×3 puzzle cube is 27 small cubes, which is 162 faces. But in this animation a horizontal layer only ever turns as one piece, so it doesn't need to be nine cubes. Each layer is one flat box with the nine stickers painted on with gradients: three boxes instead of 27 cubes.

The layers take turns with one line each. All three run the same 12-second loop, started a second apart:

CSS
.layer { animation: twist 12s cubic-bezier(0.65, 0, 0.35, 1) infinite; }
.layer:nth-child(2) { animation-delay: -11s; } /* one second later */
.layer:nth-child(3) { animation-delay: -10s; } /* two seconds later */

After four quarter turns every layer is back where it began, so the cube solves itself on every loop.

A 3×3×3 puzzle cube with white, orange and violet stickers, its bottom layer turned partway against the two layers above it.

Each layer is one flat box with its nine stickers painted on, and the layers take turns twisting.

Download
Alt text · 124 characters

A 3×3×3 puzzle cube with white, orange and violet stickers, its bottom layer turned partway against the two layers above it.

Watch the cube twist.

The torus: build round things from slices

A donut is a circle swept around an axis, so it can be built from its cross-sections: 24 identical circles, each turned to its own angle and moved out from the centre.

CSS
.torus i {
  /* 24 × 15deg = 360deg; translateX keeps each ring edge-on to the circle */
  transform: rotateY(calc(var(--i) * 15deg)) translateX(calc(56 * var(--u)));
}

The detail that matters is the last step of that transform. Moved forwards (translateZ), each circle would lie flat against the path, like a panel on a carousel. Moved sideways (translateX), it stays edge-on to the path, like a slice through the tube, and the slices together read as a ring.

A ring made of 24 thin circles, each standing edge-on around the hole, shading from violet to teal and back.

Twenty-four circles, each turned to its angle and moved sideways, read together as a ring.

Download
Alt text · 108 characters

A ring made of 24 thin circles, each standing edge-on around the hole, shading from violet to teal and back.

See the torus.

The gears: the coin's trick, on every edge

A gear face is one element cut to the outline of eight teeth, with a copy behind it for the back. Edge-on it has the coin's problem, so it gets the coin's answer: a standing strip on every straight edge of the outline. The tip of each tooth is placed exactly like a slat on the coin's rim: turned to its place, walked out to the edge, stood up.

The two gears really mesh. While the big one turns once, the small one turns 576° the other way, exactly eight of its teeth going past, so the loop ends in the pose it started from.

A large violet gear with eight teeth meshing with a smaller teal gear with five teeth, both seen from above at an angle, with visible thickness on every edge.

Every straight edge of the outline has a standing strip, so the gears stay solid edge-on.

Download
Alt text · 158 characters

A large violet gear with eight teeth meshing with a smaller teal gear with five teeth, both seen from above at an angle, with visible thickness on every edge.

Turn the gears.

Three rules from 30 shapes

Across the whole group, the same three ideas keep coming back:

  • Give every edge something to be. A flat piece vanishes edge-on, so anything that can face you sideways needs a real surface there.
  • Merge what moves together. If parts never move on their own, make them one piece and paint the detail on.
  • Build round things from slices. Turn identical pieces around an axis and let the eye join them.

The other 26, from a sphere and an hourglass to a crystal and a tetrahedron, are on the Shapes & solids page, each with a live preview and the code to copy.