shadcn.io is not affiliated with official shadcn/ui
A grid tunnel recedes to a vanishing point lost in a soft haze while thin beams of light streak along its walls toward you. The tunnel's grid is drawn once, flat, in perspective, so its lines stay crisp at any size; the beams run on four invisible walls turned into the screen with CSS 3D transforms under the same perspective, and each slides along its wall with a CSS keyframe, so nothing runs in JavaScript while it moves. Each beam is a bright core in a soft glow that fades along its tail, in cyan or violet.
Use it for a launch, a performance claim or a sci-fi hero. For a flat perspective floor, use Retro Grid; for flying through stars, Starfield; for rings receding to a point, Portal; for diagonal light, Beams.
Installation
Usage
import { Warp } from "@/components/ui/warp";Warp is a container: give it a size and put your content inside. The vanishing point is the centre of the box, hidden in a soft haze, so a short headline in the middle sits at the end of the tunnel.
<Warp className="flex min-h-[420px] items-center justify-center">
<h1 className="text-5xl font-semibold">Jump to lightspeed</h1>
</Warp>For a backdrop behind the whole page, leave it empty and fix it under everything else:
<Warp className="fixed inset-0 -z-10" />Demos
Monochrome
colors={["var(--primary)"]} draws every beam in your theme's primary colour, and gridColor takes the border colour at under half strength for a quieter tunnel.
Dense
count={8} puts eight beams on each wall, cellSize={2.5} halves the grid cell and the beams' width, perspective={160} makes the tunnel a little shallower, and speed={1.5} makes each pass take 2 seconds.
Accessibility
The tunnel is decorative: it's hidden from screen readers and never takes the pointer, and your content stays on top in normal flow. With reduced motion the beams stop where they are and the tunnel stays, a still picture of the effect. The beams are thin and the middle of the box is a soft haze, so a centred headline in your foreground colour stays readable. Nothing flashes.
FAQ
How is the tunnel built?
The grid is one still SVG: a rail from every cell line on each edge toward the vanishing point, and rings that bunch up with depth, stretched to the box with 1px lines. The beams ride four walls 600 pixels deep, turned 90° into the screen under a perspective of 100 pixels by default, so the far end is a seventh of the box, lost in the haze.
How do the beams move?
Each slides along its wall from the far end past the viewer, 3 seconds a pass at speed={1}. Their places, lengths, colours and delays come from a fixed hash, so the server and the browser render the same thing, and only the beams' position changes, which the browser animates without repainting.
How do I control density?
count sets the beams on each wall (4 by default, up to 10), and cellSize sets the grid cell as a percentage of a wall; beams are half a cell wide, run along its lines, and are 10 to 40% of the tunnel's depth long.
How do I change the colours?
colors takes up to two CSS colours, cyan and violet by default; pass one for a monochrome tunnel. gridColor sets the lines, your border colour at 75% by default.
API Reference
Warp
<div> data-slot="warp"
cellSize?number
The grid's cell, as a percentage of a wall's width; beams run along its lines.
- Default
5
colors?string[]
The beams' colours, up to two CSS colours; each beam takes one. By default cyan and violet; pass one colour for a monochrome tunnel.
count?number
How many beams run along each of the four walls, from 1 to 10.
- Default
4
gridColor?string
The grid lines' colour, any CSS colour.
- Default
"color-mix(in oklab, var(--border) 75%, transparent)"
perspective?number
The tunnel's perspective in pixels: lower is deeper and more dramatic, higher is flatter. At 100 the far end is a seventh of the box.
- Default
100
speed?number
How fast the beams travel, as a multiplier: a pass takes 3 seconds at 1, half as long at 2.
- 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
Merged with the part's classes.
--warp-color-1string
The first beam colour (cyan); --warp-color-2 the second (violet).
--warp-grid-colorstring
The grid lines' colour (the border colour at 75%).
--warp-perspectivestring--warp-speedstring
The beams' speed, a multiplier (1).
--warp-xstringRelated
- Pro


The same perspective trick as a floor


Starfield Background
SpaceFlying through stars
- Pro


Portal Background
LightRings receding to a point
- Pro


Neon pulses on a grid


Beams Background
LightDiagonal light
- Pro


Meteors Background
SpaceStreaks with tails