# Noise field

A slow, folding noise texture drawn as a dither, in four styles, with a mask that clears space for the text on top.

> 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/noise-field.json](https://dithercn.dev/r/noise-field.json), under `files[].content`.

## Installation [#installation]

```bash
npx shadcn@latest add https://dithercn.dev/r/noise-field.json
```

## Usage [#usage]

```tsx
import { NoiseField } from "@/components/dithercn/noise-field";

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

The field is fractal noise folded back on itself, so it flows like smoke rather than scrolling. `variant` changes what the noise draws:

* `smoke`, the default: soft folds that dither into smooth gradients.
* `ridges`: sharp creases, like veins or lightning.
* `contours`: topographic lines, spaced by `bands`.
* `marble`: warped stripes, also set by `bands`.

`warp`, `detail` and `scale` shape the noise itself. `contrast`, `coverage` and `intensity` decide how much of it turns to ink. `angle` and `flow` set where it drifts, and `mask` with `maskSize` clears room for your text.

## Examples [#examples]

### Cleared under a headline [#cleared-under-a-headline]

`mask="center"` fades the field to paper in the middle of the box. Use `"top"` or `"bottom"` when the text sits at one end, and `maskSize` to clear more or less.

```tsx title="examples/noise-field-masked.tsx"
import { NoiseField } from "@/components/dithercn/noise-field";

export default function NoiseFieldMasked() {
  return (
    <section className="relative isolate flex size-full flex-col items-center justify-center gap-3 px-6 text-center">
      <NoiseField mask="center" className="absolute inset-0 -z-10" />
      <h3 className="max-w-md text-3xl font-medium tracking-[-0.03em] text-balance sm:text-4xl">
        Infrastructure you can forget about
      </h3>
      <p className="text-muted-foreground max-w-sm text-sm text-pretty">
        The texture thins out under the copy and keeps moving at the edges.
      </p>
    </section>
  );
}
```

### Fine grain in a dashboard card [#fine-grain-in-a-dashboard-card]

A high `scale`, a low `intensity` and 2px cells turn it into a texture you notice only when it moves.

```tsx title="examples/noise-field-card.tsx"
import { NoiseField } from "@/components/dithercn/noise-field";

export default function NoiseFieldCard() {
  return (
    <div className="bg-background border-border relative isolate flex w-full max-w-sm [--dither-paper:var(--background)] flex-col gap-6 overflow-hidden rounded-2xl border p-5">
      <NoiseField
        scale={5}
        intensity={0.45}
        mask="top"
        cell={2}
        className="absolute inset-0 -z-10"
      />
      <div className="flex items-center justify-between text-sm">
        <span className="text-muted-foreground">Requests / min</span>
        <span className="text-muted-foreground font-mono text-xs">live</span>
      </div>
      <span className="text-4xl font-semibold tracking-tight tabular-nums">
        48.2k
      </span>
      <span className="text-muted-foreground mt-6 text-xs">
        p95 latency 112 ms
      </span>
    </div>
  );
}
```

### Topographic lines [#topographic-lines]

`variant="contours"` draws the noise as height lines, a good fit for maps and region stats. A bottom `mask` keeps the numbers on clean paper, and a low `flow` lets the terrain shift slowly.

```tsx title="examples/noise-field-topography.tsx"
import { NoiseField } from "@/components/dithercn/noise-field";

const regions = [
  { name: "eu-west", share: "41%" },
  { name: "us-east", share: "37%" },
  { name: "ap-south", share: "22%" },
];

export default function NoiseFieldTopography() {
  return (
    <div className="bg-background border-border relative isolate flex w-full max-w-md [--dither-paper:var(--background)] flex-col gap-4 overflow-hidden rounded-2xl border p-5 pt-36">
      <NoiseField
        variant="contours"
        bands={5}
        scale={1.1}
        intensity={1}
        mask="bottom"
        maskSize={0.42}
        flow={0.5}
        cell={2}
        className="absolute inset-0 -z-10"
      />
      <div className="flex items-center justify-between text-sm">
        <span className="font-medium">Traffic by region</span>
        <span className="text-muted-foreground font-mono text-xs">24h</span>
      </div>
      <dl className="grid grid-cols-3 gap-3">
        {regions.map((region) => (
          <div key={region.name} className="flex flex-col gap-1">
            <dt className="text-muted-foreground font-mono text-xs">
              {region.name}
            </dt>
            <dd className="text-xl font-semibold tabular-nums">
              {region.share}
            </dd>
          </div>
        ))}
      </dl>
    </div>
  );
}
```

### Marble with a highlight [#marble-with-a-highlight]

`variant="marble"` with more `warp` bends the stripes into veins. `highlight` adds a third colour for the brightest peaks, here the foreground, so the stripes catch the light.

```tsx title="examples/noise-field-marble.tsx"
import { NoiseField } from "@/components/dithercn/noise-field";

export default function NoiseFieldMarble() {
  return (
    <section className="relative isolate flex size-full flex-col justify-end gap-2 p-8 sm:p-10">
      <NoiseField
        variant="marble"
        color="blue"
        highlight="--foreground"
        bands={5}
        warp={2.4}
        intensity={0.85}
        angle={20}
        mask="bottom"
        maskSize={0.55}
        className="absolute inset-0 -z-10"
      />
      <span className="text-muted-foreground font-mono text-xs tracking-[0.08em] uppercase">
        Changelog
      </span>
      <h3 className="max-w-sm text-3xl font-medium tracking-[-0.03em] text-balance">
        Faster builds, quieter logs
      </h3>
    </section>
  );
}
```

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `DitherColor` | `"--dither-ink"` | The ink of the texture. |
| `highlight` | `DitherColor` | `u2013` | A third colour for the brightest peaks. Leave it out for two tones. |
| `background` | `DitherColor` | `"--dither-paper"` | The paper behind. |
| `variant` | `"smoke" \| "ridges" \| "contours" \| "marble"` | `"smoke"` | The shape of the texture: soft folds, sharp creases, topographic lines or warped stripes. |
| `scale` | `number` | `1.3` | Size of the features. Higher values give smaller, busier noise. |
| `warp` | `number` | `1.7` | How far the noise folds back on itself, from 0 (plain noise) to 4. |
| `detail` | `number` | `4` | Octaves of noise, from 1 (smooth blobs) to 6 (fine grain on top). |
| `contrast` | `number` | `1.2` | 1 is soft. 2 and up give hard-edged islands. |
| `coverage` | `number` | `0` | How much of the box is inked, from -0.5 (sparse) to 0.5 (dense). |
| `intensity` | `number` | `0.9` | Brightest tone the field reaches, from 0 to 1. |
| `bands` | `number` | `8` | Lines for "contours" and stripes for "marble", from 2 to 24. |
| `angle` | `number` | `90` | Direction it drifts in, in degrees. 0 is right, 90 is up. |
| `flow` | `number` | `1` | How fast it drifts along angle, from 0 to 4. |
| `invert` | `boolean` | `false` | Swaps paper and ink. |
| `mask` | `"none" \| "center" \| "top" \| "bottom" \| "edges"` | `"none"` | Fades the field out where your text sits. "edges" keeps only the middle. |
| `maskSize` | `number` | `0.5` | How much of the box the mask clears, from 0 to 1. |
| `palette` | `[DitherColor, DitherColor, ...DitherColor[]]` | `Built from the colour props` | Takes over the colours: paper first, brightest last. Palette names, CSS variable names or any CSS colour. |
| `matrix` | `"bayer2" \| "bayer4" \| "bayer8" \| "blue-noise"` | `"bayer8"` | The threshold pattern. See Dither engine. |
| `levels` | `number` | `All the matrix can draw` | Tones the field snaps to before dithering. Low values give hard steps. |
| `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. |
| `stillTime` | `number` | `0` | The moment drawn when motion is off or reduced, in seconds. |
| `className` | `string` | `u2013` | 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 a CSS approximation in the same colours.
* It costs one small draw per frame at 30 fps, at one pixel per dither cell. Each step of `detail` adds a layer of noise, so lower it on large, busy pages. See [Performance](/docs/engine/performance).