shadcn.io is not affiliated with official shadcn/ui
Cellular Tiled Tunnel Shader flies a camera fast down a winding tunnel on the GPU. A WGSL fragment shader on WebGPU ray marches a tube whose wall is broken into cellular plates, a Voronoi pattern wrapped around it: each plate rises in flat facets from its seams to a flat top, so the wall looks hammered from angular sheets of metal. The plates carry a blocky mosaic of greys, a third of them are tinted bronze, each block of the mosaic is a facet tilted at random so the metal glints pale blue as you pass, and the far end fades into a dark hole.
Use it behind an industrial, engineering or gaming hero, or a feature card that wants texture and motion. For a lit tunnel of colorful glossy tiles, use Advanced Tunnel Shader; for a metal tube seen from a slow, swinging camera, Oldschool Tube Shader; for a grid tunnel in plain CSS, with no GPU, the Warp background. It runs only while it's on screen, holds a still frame with reduced motion, and shows a CSS gradient of the same greys and bronze in browsers without WebGPU.
Installation
Usage
import {
CellularTiledTunnelShader,
} from "@/components/ui/cellular-tiled-tunnel-shader";<CellularTiledTunnelShader className="flex min-h-[32rem] items-end">
<div className="m-8 rounded-xl bg-black/60 px-8 py-6 backdrop-blur-sm">
<h1 className="text-5xl font-semibold text-white">Go deeper</h1>
</div>
</CellularTiledTunnelShader>Cellular Tiled Tunnel Shader is a container: your content sits on top of the tunnel, 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 plates are light and busy in both color schemes, so set text on a dark panel, as above.
Demos
Brass
width={1.4} widens the tunnel, cellSize={1.6} makes fewer, larger plates, and tintColor="#c7a26b" turns the warm plates a paler brass.
In a card
The tunnel scales with its box, and speed={0.5} halves the flight, which is calmer next to text.
Performance
About 3.5 ms of GPU time a frame at 1280×720 on an M2 Max laptop at its default quality of 0.75, which renders three quarters of the resolution, about half the pixels; at quality={1} it takes about 4.5 ms. Slower GPUs take several times longer. It's a medium-weight shader: the march takes up to 90 steps, and each step near the wall works out the plate pattern, though it skips the pattern while it's far from the wall. At quality={0.5} the mosaic blurs, so keep that for very slow GPUs. The props don't change the cost. 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, a dark hole ringed with bronze fading out to greys, 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 tunnel is decoration: it's hidden from assistive tech and lets every click through to your content. With reduced motion it draws one still frame, the dark hole framed by plates, and stops. Nothing flashes: the plates stream past steadily and the glints are small. Text needs a dark panel: bare white text reaches 6.6:1 on a typical pixel but drops to about 2:1 on the lightest 5% of the frame. On a bg-black/60 panel, as in Usage, it stays above 5.9:1 everywhere, and on bg-black/70 above 8.7:1.
FAQ
How is a tunnel drawn with no geometry?
With sphere tracing: for each pixel, the shader asks how far the nearest wall is and steps the ray that far, again and again, until it lands. The wall is a tube that winds along two slow sine curves, minus the height of the plates where the ray is.
What makes the plates?
A Voronoi pattern: random points scattered around the tube, each claiming the wall nearest to it. The shader measures how far each spot is from its plate's nearest edge and raises the wall by that, up to a cap, so every plate rises in flat facets to a flat top, with sharp seams between them. A whole number of plates fits around, so there's no seam where the pattern meets itself.
How do I make it wider, or the plates bigger?
width sets how wide the tunnel is, from 0.6 to 1.6, and the plates keep their size, so a wider tunnel has more of them around. cellSize sets the plate size, from 0.5 (many small plates) to 2 (a few large ones). shadcn.io's version had a tunnelRadius that narrowed the tunnel as it grew; width widens it.
How do I recolor the bronze?
tintColor is the warm metal on about a third of the plates and highlightColor the glints. They take any CSS color, var(--primary) included, and follow a theme switch. The rest of the mosaic stays grey, so a tint reads as one metal among steel.
Why does it look pixelated?
That's the design: the mosaic is made of small cubes in space, each a grey level and a slightly tilted facet, and they cross the plates as blocks. grain sets how strong it is, from 0 (smooth, even metal) to 2 (deep contrast and strong glints).
Will it slow my page down?
It costs about 3.5 ms of GPU time a frame at 1280×720 on a laptop at its default quality of 0.75, and the CPU only sets a few numbers each frame. It stops when it's off screen. The props don't change the cost; on a slow GPU, lower quality a little, but at 0.5 the mosaic blurs.
Credits
Inspired by a cellular tiled tunnel (opens in a new tab) by Shane on Shadertoy. This is a new shader written from a description of the look, not a port: the wrapped plate pattern and its facets, the mosaic and its glints, the path, the lighting and the code are ours. The Voronoi edge distance follows Inigo Quilez's article (MIT), and the hash is lowbias32 by Chris Wellons, in the public domain; both keep their credit lines in the WGSL.
API Reference
CellularTiledTunnelShader
data-slot="cellular-tiled-tunnel-shader"
cellSize?number
How big the plates are, from 0.5 (many small ones) to 2 (a few large ones). @default 1.
- Default
1
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.
grain?number
How strong the blocky mosaic on the plates is, from 0 (smooth metal) to 2. @default 1.
- Default
1
highlightColor?string
The glints of light on the metal. Any CSS colour. @default "#b3e6ff".
- Default
"#b3e6ff"
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.
- Default
0.75
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.
tintColor?string
The warm metal on about a third of the plates. Any CSS colour. @default "#cc9966".
- Default
"#cc9966"
width?number
How wide the tunnel is, from 0.6 (narrow) to 1.6 (wide). @default 1.
- Default
1
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


Advanced Tunnel Shader
Tunnels & 3DColorful glossy tiles
- Pro


Oldschool Tube Shader
Tunnels & 3DA metal tube from a slow, swinging camera
- Pro


Biomine Shader
Tunnels & 3DA cavern of glossy tubes
- Pro


Pyramid Pattern Shader
Patterns & tilingsBrushed metal, flat and calm
- Pro


Perspex Web Lattice Shader
Tunnels & 3DCells cut into facets, on a wall
- Pro


Abstract Mod Shader
Tunnels & 3DAnother dark flight, with neon pulses