shadcn.io is not affiliated with official shadcn/ui
Three-Tap Voronoi Shader draws a honeycomb of irregular cells. Each one is a cone: a dark pit in the middle rises through the color to a white-hot seam where it meets its neighbors, and a cool light from the top left catches one side of every seam, so the cells look pressed into the surface. A two-color field sweeps slowly across them, pink to amber by default, and every cell's center wobbles on a small circle, so the walls ripple in place. A WGSL fragment shader on WebGPU draws every pixel each frame, testing only three points per pixel, for about a third of a millisecond of GPU time.
Use it behind a warm hero, a launch page or a pricing card, in its own colors or in your brand's. For a monochrome, finer cell texture, use Worley Noise Shader; for flowing contour lines over a blended cell field, Smooth Voronoi Contours Shader; for lit glass cells in plain CSS, the Voronoi background. It runs only while it's on screen, holds a still frame with reduced motion, and shows a CSS gradient of the same two colors in browsers without WebGPU.
Installation
Usage
import {
ThreeTapVoronoiShader,
} from "@/components/ui/three-tap-voronoi-shader";<ThreeTapVoronoiShader className="flex min-h-[32rem] items-center justify-center">
<div className="rounded-xl bg-black/60 px-8 py-6">
<h1 className="text-5xl font-semibold text-white">Ship faster</h1>
</div>
</ThreeTapVoronoiShader>Three-Tap Voronoi Shader is a container: your content sits on top of the cells, 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". Every cell runs from a dark pit to a bright seam, so no text color reads on it bare: put copy on a panel, like the bg-black/60 one above, which keeps white text above 5.8:1 everywhere.
Demos
Ice
fromColor and toColor set the two ends of the sweeping color field, here royal blue and aqua, and highlight={1.6} strengthens the light on the seams for a glassier, frozen look. The pits always stay dark, so any pair of mid-to-bright colors works.
In a card
The cells are sized to the box's height, about 7 rows at the default scale, so the pattern keeps its proportions in any box. scale={0.7} fits about 5 rows instead, so the cells read as big, glossy tiles at card size.
Performance
About 0.3 ms of GPU time a frame at 1280×720 on an M2 Max laptop; slower GPUs take several times longer. Each pixel finds its cell twice (once more for the light), with three distance tests each time, whatever the scale. Keep quality at 1: the seams and highlights are crisp and the shader is cheap enough not to need less. 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 a CSS gradient of the same two colors with a darkened edge, 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 pattern is decoration: it's hidden from assistive tech and lets every click through to your content. With reduced motion it draws one still frame and stops. Nothing flashes: the cells wobble over 5 to 10 seconds, and the color field takes over a minute to sweep across. The contrast inside each cell is high, so never set text on it bare: a bg-black/60 panel keeps white text above 5.8:1, and bg-black/70 above 8.6:1.
FAQ
What does three-tap mean?
A classic Voronoi pattern checks 9 nearby points per pixel to find the nearest. This one lays the points on a triangle lattice, so a pixel only has to check the 3 corners of the triangle it sits in. That's a third of the work, at the cost of rare, tiny kinks in a wall where a point just outside the triangle would have been nearer. The points barely move from their corners, which keeps those kinks small.
How do I change the cell size?
scale sets how many cells fit: 1 is about 7 rows in the box's height, 0.5 half as many, and 2.5 about 18 small ones. The cells are sized to the box, so a card and a full-screen hero show the same pattern, scaled.
Where does the 3D look come from?
From a second lookup a small step toward the top left. Where the cone rises in that direction, the pixel faces the light and gets a cool highlight, so each seam is lit on one side and not the other. It's a cheap emboss: there's no lighting model and no normal map. highlight sets how strong it is, and 0 turns it off.
Can I change the colors?
Yes: fromColor and toColor are the two ends of the color field that sweeps across the cells. They take any CSS color, var(--primary) included, and follow a theme switch. The pits darken toward each color and the seams brighten toward white, so mid-to-bright colors work best.
Credits
Inspired by a three-tap Voronoi shader (opens in a new tab) by Shane on Shadertoy. This is a new shader written from the idea, not a port: its own lattice code, hash, cell shading, light, color field and colors.
API Reference
ThreeTapVoronoiShader
data-slot="three-tap-voronoi-shader"
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.
fromColor?string
One end of the colour field that sweeps across the cells. Any CSS colour. @default "#f0287a".
- Default
"#f0287a"
highlight?number
The embossed light on one side of every seam, from 0 (flat) to 2 (glassy). @default 1.
- Default
1
interactive?boolean
Whether u.pointer follows the pointer. @default false.
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.
scale?number
How many cells fit: 1 is about 7 rows in the box's height, from 0.5 (big cells) to 2.5 (small). @default 1.
- Default
1
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.
toColor?string
The other end of the colour field. Any CSS colour. @default "#ffab1f".
- Default
"#ffab1f"
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.
Related
- Pro


Worley Noise Shader
Patterns & tilingsA monochrome, finer cell texture
- Pro


Smooth Voronoi Contours Shader
Patterns & tilingsContour lines over a blended cell field
- Pro


Magma Shader
Ink, smoke & fireThe same glowing seams, as lava plates
- Pro


Perspex Web Lattice Shader
Tunnels & 3DCells cut into lit facets


Fluted Glass Shader
Light & glassWarm color for a pricing card, free
- Pro


Triangle Mesh Incircles Shader
Patterns & tilingsIts dual: a triangle mesh with discs