# Dither text

A display headline whose letters are filled with a dithered gradient, noise, dots or hatching, in any palette colour, from hero size down to section headings.

> 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/dither-text-demo.tsx" size="lg" controls="ditherTextControls">
  <DitherTextDemo />
</ComponentPreview>

## Installation [#installation]

<InstallBlock name="dither-text" />

## Usage [#usage]

```tsx
import { DitherText } from "@/components/dithercn/dither-text";

export function Hero() {
  return (
    <DitherText
      as="h1"
      color="blue"
      className="text-8xl font-bold tracking-tight"
    >
      Your headline
    </DitherText>
  );
}
```

The text stays a real element: people can select and copy it, screen readers read it, and search engines index it. The dither is a small image drawn on the client and clipped to the letters with `background-clip: text`.

`fill` picks what goes inside the letters:

* `gradient` (the default) runs from solid ink on one side to a sparse dither on the other, with a slow drift that bends the bands. `direction` is the way it thins out: `"down"` is solid at the top.
* `noise` fills the letters with drifting blobs of density. `scale` sets their size and `direction` the way they drift.
* `dotted` and `hatched` use the same textures as the charts and buttons, drifting a cell at a time in `direction`. A faint `ghost` of the ink fills the gaps so the letters keep their shape.
* `solid` is flat colour, useful with `bloom` alone.

Set the size with your own classes. The cell size follows the font size, about 1/24 of it and never below 2px, so the same component reads well as a hero and as a section heading. Pass `cell` to fix it.

## Examples [#examples]

### Hatched and dotted [#hatched-and-dotted]

Two words in heavy type, one `hatched` in orange with a low bloom and one `dotted` in pink drifting left.

<ComponentPreview src="examples/dither-text-hatched.tsx" size="lg">
  <DitherTextHatched />
</ComponentPreview>

### Noise with a palette [#noise-with-a-palette]

`palette` takes over from `color` for a multi-tone fill. Here blue noise and a palette from transparent through blue to purple give a soft grain.

<ComponentPreview src="examples/dither-text-noise.tsx" size="lg">
  <DitherTextNoise />
</ComponentPreview>

### Section heading in the foreground colour [#section-heading-in-the-foreground-colour]

A smaller heading that thins out to the right, drawn in `--foreground` so it matches body text on light and dark themes. `to={0.55}` keeps the last word readable and `animate={false}` draws it once.

<ComponentPreview src="examples/dither-text-section.tsx">
  <DitherTextSection />
</ComponentPreview>

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` (required) | `ReactNode` |  | The text. It stays real, selectable text. |
| `as` | `"h1" \| "h2" \| "h3" \| "h4" \| "p" \| "span" \| "div" \| "strong"` | `"span"` | The element to render. |
| `fill` | `"gradient" \| "noise" \| "dotted" \| "hatched" \| "solid"` | `"gradient"` | What fills the letters. |
| `color` | `DitherColor` | `"ink"` | Ink colour: a palette name such as "green" or any CSS colour. |
| `direction` | `"down" \| "up" \| "left" \| "right" \| number` | `"down"` | Gradient: the way it thins out from its solid side. Noise, dotted and hatched: the way it drifts. A number is an angle in degrees, as in CSS. |
| `scale` | `number` | `3` | Noise only. Higher values give smaller blobs. |
| `from` | `number` | `1` | Gradient and noise: tone at the dense end, from 0 (no ink) to 1 (solid). |
| `to` | `number` | `0.4` | Gradient and noise: tone at the sparse end. Keep it above about 0.3 so the letters stay readable. |
| `ghost` | `number` | `0.2 for dotted and hatched, else 0` | Opacity of the ink in the gaps between dots, 0 to 1. |
| `bloom` | `"off" \| "low" \| "high"` | `"off"` | A soft glow in the ink colour that follows the dots. |
| `palette` | `[DitherColor, DitherColor, ...DitherColor[]]` |  | Colours from the lightest tone to the darkest, for a multi-tone fill. Overrides color and ghost. |
| `matrix` | `"bayer2" \| "bayer4" \| "bayer8" \| "blue-noise"` | `"bayer4"` | The threshold pattern for gradient and noise. See Dither engine. |
| `cell` | `number` | `Font size / 24, at least 2` | Size of one dither cell in CSS pixels. |
| `animate` | `boolean` | `true` | false draws the fill once and stops. |
| `speed` | `number` | `1` | How fast the fill drifts. 0 holds it still. |

## Notes [#notes]

* The text is the accessible content. The fill is a background image, so assistive technology ignores it.
* Before the client draws the fill, the letters show in the ink colour through a plain dither mask, so there is no flash of unstyled text. In forced-colours mode the fill is removed and the text uses the system colour.
* Selected text shows in the site's selection colours, solid, so it stays readable while highlighted.
* With reduced motion turned on, or `animate={false}`, it draws one frame. It redraws at 12 fps only while on screen, at one pixel per dither cell, and pauses in hidden tabs. `solid` never animates.