# Tunnel

A slow flight down a tunnel of round or square rings, drawn as a dither.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available by appending `.md` to any URL or sending an `Accept: text/markdown` header. The dithercn agent skill, for building any dither on the engine, is at [/.well-known/agent-skills/dithercn/SKILL.md](/.well-known/agent-skills/dithercn/SKILL.md).

<ComponentPreview src="examples/tunnel-demo.tsx" size="full" align="stretch" controls="tunnelControls">
  <TunnelDemo />
</ComponentPreview>

## Installation [#installation]

<InstallBlock name="tunnel" />

## Usage [#usage]

```tsx
import { Tunnel } from "@/components/dithercn/tunnel";

export function Hero() {
  return (
    <section className="relative isolate min-h-[480px]">
      <Tunnel className="absolute inset-0 -z-10" />
      <h1>Your headline</h1>
    </section>
  );
}
```

Rings come out of the fog at the vanishing point and grow as they pass you. Spokes run along the walls, and every other panel between them is lit, like tiles. The middle stays empty, so a headline fits there.

## Examples [#examples]

### Behind a headline [#behind-a-headline]

`spokes={0}` leaves only the rings, and fewer `rings` spread them out. A larger `fog` widens the empty middle so the text sits clear of the rings.

<ComponentPreview src="examples/tunnel-headline.tsx" size="lg" align="stretch">
  <TunnelHeadline />
</ComponentPreview>

### Square corridor [#square-corridor]

`shape="square"` turns the rings into frames. Moving the `center` up a little and lowering the `sway` gives a steadier corridor, and a three-colour palette lights the near walls.

<ComponentPreview src="examples/tunnel-square.tsx" size="lg" align="stretch">
  <TunnelSquare />
</ComponentPreview>

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `shape` | `"circle" \| "square"` | `"circle"` | The cross-section of the tunnel. |
| `rings` | `number` | `1` | How close together the rings are. 2 packs twice as many in. |
| `spokes` | `number` | `12` | Lines along the walls, from 0 to 32. 0 leaves only the rings and drops the tiles. |
| `center` | `[number, number]` | `[0.5, 0.5]` | The vanishing point, as fractions of the box from the top left. |
| `sway` | `number` | `1` | How far the vanishing point wanders. 0 holds it still. |
| `fog` | `number` | `1` | Size of the empty fog in the middle. 2 doubles it to clear room for text. |
| `palette` | `[DitherColor, DitherColor, ...DitherColor[]]` | `["--dither-paper", "--dither-ink"]` | Colours from paper to ink: palette names such as "blue", CSS variable names, or any CSS colour. |
| `matrix` | `"bayer2" \| "bayer4" \| "bayer8" \| "blue-noise"` | `"bayer4"` | The threshold pattern. See Dither engine. |
| `cell` | `number` | `--dither-cell` | Size of one dither cell in CSS pixels. |
| `speed` | `number` | `1` | How fast it moves. |
| `animate` | `boolean` | `true` | false draws one still frame. |
| `className` | `string` | `–` | Size and position. The background fills this box. |

## Notes [#notes]

* It is decorative and hidden from assistive technology. Put real text on top of it, not inside it.
* With reduced motion turned on, it draws one still frame and stops.
* It pauses when scrolled out of view or when the tab is hidden, and releases its WebGL context when far offscreen. Without WebGL it shows concentric CSS rings in the same colours.
* It costs one small draw per frame at 30 fps, at one pixel per dither cell. See [Performance](/docs/engine/performance).