Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Shaders

Pro

Cellular Tiled Tunnel Shader for React

A fast flight down a winding tunnel drawn on the GPU, walled with faceted metal plates in a blocky grey mosaic, some in warm bronze, toward a dark hole. For React with Base UI, when an industrial, gaming or engineering hero wants texture and speed.

Framework

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.

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 {
  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.

Preview width

In a card

The tunnel scales with its box, and speed={0.5} halves the flight, which is calmer next to text.

Preview width

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"

PropType
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.

All 101 shaders