Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Shaders

Pro

Platonic Solids Shader for React

The five Platonic solids nested inside each other like an astrolabe, turning in fine brass lines on navy. For React with Base UI, when a research, education or protocol page wants quiet, precise geometry behind its copy.

Framework

Platonic Solids Shader nests the five Platonic solids inside each other, from an icosahedron on the outside through a dodecahedron, a cube and an octahedron to a tetrahedron at the heart. Each shell turns on its own axis at its own speed, drawn in fine brass lines on deep navy with mild perspective: front edges are solid, back edges dimmer and dashed, and every corner carries a dot. Thin orbit rings with a bead each run between the shells, inside a ticked outer ring, like an astrolabe. A WGSL fragment shader on WebGPU measures the distance from every pixel to all 90 edges each frame, so the lines stay crisp and anti-aliased at any size.

Use it behind a research, education, science or protocol page that wants geometry with some ceremony. For a single four-dimensional cube in plain CSS, use the Tesseract background; for engraved, banknote-style line art, Guilloche Shader. It runs only while it's on screen, holds a still frame with reduced motion, and shows CSS rings on a navy glow in browsers without WebGPU.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import {
  PlatonicSolidsShader,
} from "@/components/ui/platonic-solids-shader";
<PlatonicSolidsShader className="flex min-h-[32rem] items-center justify-center">
  <h1 className="text-5xl font-semibold text-white">Ship faster</h1>
</PlatonicSolidsShader>

Platonic Solids Shader is a container: your content sits on top of the stack, in normal flow. It fills its own box, so give it a height or content. For a backdrop behind the whole page, render it empty with className="fixed inset-0 -z-10". The stack and its outer ring fill about 90% of the box's shorter side, centered; align="right" moves it right of center, so copy on the left sits on bare navy. The background is dark in both color schemes, so put white or light text on it.

Demos

Offset

align="right" moves the stack to the right and enlarges it a little, for a hero with copy on the left. solids={3} keeps only the three outer shells, and lineColor with backgroundColor turn the brass and navy into silver on near-black.

Preview width

In a card

solids={1} draws the icosahedron alone, and align="right" lets it run off the card's edge, a quiet corner piece. lineWidth={1.25} thickens the lines a little for a small surface.

Preview width

Performance

About 1.5 ms of GPU time a frame at 1280×720 on an M2 Max laptop with all five solids, and less with fewer: the cost grows with the number of edges each pixel checks, and pixels outside a shell skip its edges. It keeps full quality, because the lines are a pixel wide and blur at half resolution; on a slow GPU, lower solids first. The animation stops when the shader scrolls out of view, and the browser pauses it in a hidden tab. Every shader on a page shares one GPU device and one frame loop, and vgpu (about 50 KB gzipped) loads only when the first one mounts.

Browser support

The shader needs WebGPU: Chrome and Edge, Safari 26 and later, and Firefox on Windows and macOS. Elsewhere, and until the first frame, the box shows faint brass rings on a navy glow, so the layout never jumps. data-state on the root reads unsupported there, if you want to style around it. See Shader Canvas.

Accessibility

The stack is decoration: it's hidden from assistive tech and lets every click through to your content. With interactive, the tilt follows a mouse or pen, never touch. With reduced motion it draws one still frame and stops. Nothing flashes: the fastest shell takes about 20 seconds to turn once. White text reads well on it: across the renders it keeps above 8.8:1 contrast on 90% of the middle of the box, and drops to about 2.6:1 only where it crosses a line, so headlines read bare; keep small body text on a panel or beside the stack with align="right".

FAQ

Which solids are drawn, and in what order?

From the outside in: the icosahedron (20 triangles), the dodecahedron (12 pentagons), the cube, the octahedron (8 triangles) and the tetrahedron (4 triangles). solids sets how many shells you see, from the outside: solids={1} is the icosahedron alone, and 5 is all of them.

Why are some edges dashed?

They're the back edges, behind the middle of their solid. Drawing them dimmer and dashed, as in a technical drawing, keeps the depth readable without hiding them, and they fade from solid to dashed as a shell turns.

Can the pointer move it?

With interactive, the pointer tilts the whole stack toward it, easing as it moves, and the stack settles back when the pointer leaves. It's off by default, so the stack turns on its own.

Can I change the colors?

Yes: lineColor colors the lines, dots and rings, and backgroundColor the page, which the shader lifts a little behind the stack. They take any CSS color, var(--primary) included, and follow a theme switch. Keep the background dark and the lines light: the back edges are dimmer versions of the line color.

Will it slow my page down?

It costs about 1.5 ms of GPU time a frame at 1280×720 on a laptop with all five solids, and the CPU only sets a few numbers each frame. It stops when it's off screen. Fewer solids cost less; half quality does too, but it blurs the hairlines.

How do I make the lines crisper or more luminous?

intensity sets the glow around the lines, from 0 (clean lines only) to 2 (a soft halo where they gather). lineWidth sets their width in CSS pixels, from 0.5 to 3.

API Reference

PlatonicSolidsShader

data-slot="platonic-solids-shader"

PropType
align?"center" | "right"

Where the stack sits: in the middle, or right of centre to leave room for copy on the left. @default "center".

Type
"center" | "right"
Default
"center"
backgroundColor?string

The background, lifted a little behind the stack. Any CSS colour; keep it dark. @default "#0b1430".

Default
"#0b1430"
fallback?string

What shows until the first frame and in browsers without WebGPU: a CSS background value (gradients, sizes, a colour) that looks like the shader. It can use the colour props' --shader-<field> variables.

intensity?number

How much the lines glow, from 0 (crisp lines only) to 2. @default 1.

Default
1
interactive?boolean

Whether u.pointer follows the pointer. @default false.

lineColor?string

The lines, dots and rings. Any CSS colour. @default "#d8b56a".

Default
"#d8b56a"
lineWidth?number

The line width in CSS pixels, from 0.5 to 3. @default 1.

Default
1
paused?boolean

Holds the current frame. @default false.

quality?number

Render scale, from 0.25 to 1, of the screen's pixels (capped at 2×). @default 1.

solids?number

How many shells, from 1 (the icosahedron alone) to 5 (all five solids). @default 5.

Default
5
speed?number

Animation speed: 1 is normal, 0 holds the frame. @default 1.

time?number

A fixed moment, in seconds: draws it and doesn't animate.

render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Forwarded to the part.

All 101 shaders