# Voronoi Cells

A cellular surface like soap foam, crackle glaze or raised stone tiles, drawn as a dither, with cells that slowly swell, shrink and trade edges.

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

> **This is an example, not the only option.** It is one component built on the dithercn engine. Install it when it is what you were asked for. For any other look, don't stretch its props to fit: write your own field on `DitherShader` ([Write your own dither](/docs/engine/write-your-own.md)), and read this example's source for technique. Its full source is in [https://dithercn.dev/r/voronoi.json](https://dithercn.dev/r/voronoi.json), under `files[].content`.

## Installation [#installation]

```bash
npx shadcn@latest add https://dithercn.dev/r/voronoi.json
```

## Usage [#usage]

```tsx
import { Voronoi } from "@/components/dithercn/voronoi";

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

Every grid square holds one seed, and every point belongs to the seed nearest to it. Each seed wanders inside its square on its own slow loop, so cells grow as their neighbours move away, and two cells that meet at a corner can pull apart while the other two close in.

The walls are measured as the exact distance to the nearest edge, in dither cells, so a wall is the same width along its whole length and at any box size. There are three variants:

* `"foam"`: bright thin walls that thicken where three meet, like the borders in a soap foam. Light gathers just inside each wall, and each cell has a faint glint.
* `"glaze"`: flat cells at four exact dither levels, split by open cracks, with a finer crackle running across them, like a crackle glaze or dried mud.
* `"stone"`: raised tiles with rounded corners. Each tile is bevelled towards its edges and lit from the top left, so the edges facing the light are denser.

## Examples [#examples]

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

`fade={1}` clears an oval in the middle of the box. In `"glaze"`, cells fade as a whole by where their seed sits, so every cell stays one flat level and the ones near the middle drop out first.

```tsx title="examples/voronoi-headline.tsx"
import { Voronoi } from "@/components/dithercn/voronoi";

export default function VoronoiHeadline() {
  return (
    <section className="relative isolate flex size-full flex-col items-center justify-center gap-3 px-6 text-center">
      <Voronoi
        variant="glaze"
        scale={1.2}
        fade={1}
        palette={["--dither-paper", "orange"]}
        className="absolute inset-0 -z-10"
      />
      <h3 className="max-w-sm text-3xl font-medium tracking-[-0.03em] text-balance">
        Every firing cracks its own way
      </h3>
      <p className="text-muted-foreground max-w-[18rem] text-sm text-pretty">
        Small-batch stoneware from a two-kiln studio. The spring glazes go on
        sale Thursday.
      </p>
    </section>
  );
}
```

### Coloured mosaic [#coloured-mosaic]

`colors` gives each cell one colour from a list. With `"stone"`, a wider `wall` for the grout and a slower `drift`, the tiles read as a mosaic that shifts very slowly.

```tsx title="examples/voronoi-mosaic.tsx"
import { Voronoi } from "@/components/dithercn/voronoi";

export default function VoronoiMosaic() {
  return (
    <Voronoi
      variant="stone"
      scale={1.6}
      wall={2}
      drift={0.6}
      colors={["blue", "purple", "green", "pink"]}
      className="absolute inset-0"
    />
  );
}
```

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `"foam" \| "glaze" \| "stone"` | `"foam"` | Bright walls around dark cells, flat cells split by cracks, or raised tiles lit from one side. |
| `scale` | `number` | `1` | How many cells fit in the box. 1 puts about five across its shorter side; 2 doubles that. |
| `wall` | `number` | `1.5` | Width of the walls, cracks or grout between cells, in dither cells. Capped at a fifth of a cell's size, so small cells never close up. |
| `drift` | `number` | `1` | How fast the seeds wander, so cells swell, shrink and trade edges. 0 holds them still. |
| `fade` | `number` | `0` | How far the cells fade out in the middle of the box, from 0 to 1, to clear room for text. |
| `colors` | `[DitherColor, ...DitherColor[]]` | `–` | One colour per cell, picked from this list. Foam walls keep the last palette colour. Palette names such as "blue", CSS variable names, or any CSS colour. |
| `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 stops the motion: a still frame if it starts off, the current frame if it was moving. |
| `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 the same kind of cells as an SVG, in the same colours.
* Each cell checks 34 seeds, and `"glaze"` twice that for its fine crackle, at one pixel per dither cell and 30 fps. With `colors`, the colour pass checks them again. See [Performance](/docs/engine/performance).