Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Shaders

Pro

Digital Tunnel Shader for React

A neon tunnel drawn on the GPU: tight rings that cycle cyan, magenta and blue as they flow out of the center, over a dark screen with scanlines and faint sparkles. For React with Base UI, when a tech, gaming or AI hero should feel like a dive into the network.

Framework

Digital Tunnel Shader draws a neon tunnel on the GPU. A WGSL fragment shader on WebGPU ray marches a wavy cylinder from inside it, every pixel, every frame, and colors the wall by depth through three neon colors, so tight rings cycle cyan, magenta and electric blue as they flow out of the center. The base drifts from teal to indigo, a soft blue haze spreads from the core, faint sparkles twinkle along the walls, and fine scanlines and a vignette finish the screen.

Use it behind a tech, gaming or AI launch, a sign-in screen or a full-screen intro. For glowing rings in plain CSS, with no GPU, use the Portal background; for a bright, colorful flight through star-cut planes, Starry Planes Shader; for a lit tunnel of glossy tiles, Advanced Tunnel Shader. It runs only while it's on screen, holds a still frame with reduced motion, and shows a CSS ring gradient of the same colors 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 {
  DigitalTunnelShader,
} from "@/components/ui/digital-tunnel-shader";
<DigitalTunnelShader className="flex min-h-[32rem] items-center justify-center">
  <h1 className="text-5xl font-semibold text-white">Enter the network</h1>
</DigitalTunnelShader>

Digital 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 screen is dark in both color schemes, so put white or light text over it, and keep small text off the bright rings at the center.

Demos

Custom colors

The rings cycle through fromColor, viaColor and toColor, then back to fromColor. Here they run orange, pink and violet, with a violet hazeColor at the core and peach particleColor sparkles. Every color prop takes any CSS color, var(--primary) included.

Preview width

In a card

The tunnel scales with its box. particles={0} hides the sparkles and scanlines={false} turns off the lines, for a cleaner surface under a form or a stat.

Preview width

Performance

About 0.3 ms of GPU time a frame at 1280×720 on an M2 Max laptop, so it renders at full resolution; slower GPUs take several times longer. quality={0.5} renders a quarter of the pixels, and the scanlines keep their size, but the rings at the center go soft. 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 rings and scanlines, 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 teal screen with the rings at the center, and stops. Nothing flashes: the colors flow over seconds and each sparkle fades in and out over about two seconds. White text has at least 6:1 contrast over 95% of the frame and 15:1 on a typical pixel, but the rings at the center drop to about 3.7:1, so keep small body text off them.

FAQ

Can I use my brand colors?

Yes. fromColor, viaColor and toColor are the three neon colors the rings cycle through, hazeColor the glow at the center and particleColor the sparkles. They take any CSS color, var(--primary) included, and follow a theme switch. Bright, saturated colors read best on the dark screen.

How do I turn off the scanlines?

Set scanlines={false}. The lines are sized in CSS pixels, so they look the same on any screen and at any quality.

How do the sparkles work?

The tunnel is divided into a fine 3D grid, and a hash lights about 15% of its cells with a soft dot that twinkles. The grid drifts down the tunnel. particles sets both their brightness and how fast they drift, from 0, which hides them, to 2.

Is it really 3D?

Yes: the shader marches each pixel's ray through a distance field, up to 64 steps, with no geometry. The camera sits inside the tunnel wall's field, so the march runs backward onto the wall behind it, and the rings line up by distance from the center of the screen. That quirk is the look, so it stays.

What changed from shadcn.io's version?

The look is the same, pixel for pixel apart from where the sparkles fall. depth and ringCount are gone: neither changed the picture, because the ring shapes never won against the walls and the backward march made depth only scale the brightness; use glow for brighter rims. The sparkles use an integer hash and the scene is drawn around the camera, so the tunnel stays as crisp after hours open as in its first second. The scanlines keep their CSS size on any screen and at any quality, and the vignette no longer turns negative in very wide boxes. The colors are props now.

Will it slow my page down?

It costs about 0.3 ms of GPU time a frame at 1280×720 on a laptop, and the CPU only sets a few numbers each frame. It stops when it's off screen. None of the props change the cost; on a slow GPU or a large screen, quality={0.75} renders fewer pixels and keeps the rings fairly crisp.

API Reference

DigitalTunnelShader

data-slot="digital-tunnel-shader"

PropType
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

The first neon colour of the cycle the rings flow through. Any CSS colour. @default "#00ffff".

Default
"#00ffff"
glow?number

How bright the neon rims of the rings glow, from 0 (flat) to 2 (vivid). @default 1.

Default
1
hazeColor?string

The soft haze that spreads from the centre. Any CSS colour. @default "#1a4dcc".

Default
"#1a4dcc"
interactive?boolean

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

particleColor?string

The twinkling sparkles. Any CSS colour. @default "#33ccff".

Default
"#33ccff"
particles?number

How bright the sparkles are and how fast they drift, from 0 (none) to 2. @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.

scanlines?boolean

Fine horizontal scanlines over the whole picture. @default true.

Default
true
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 last neon colour of the cycle, which leads back to fromColor. Any CSS colour. @default "#0080ff".

Default
"#0080ff"
viaColor?string

The middle neon colour of the cycle. Any CSS colour. @default "#ff00ff".

Default
"#ff00ff"
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