# Dither gradient (goodtabs UI)

A slow soft gradient printed through a 4 by 4 Bayer dither, drawn in raw WebGL.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/dither-gradient.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/dither-gradient`

## Usage

```tsx
import { DitherGradient } from "@/components/ui/dither-gradient"

<DitherGradient className="flex h-96 justify-center pt-20">
  <h2>One ink, sixteen tones</h2>
</DitherGradient>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| pixel | `number` | `4` | Size of one printed dot in CSS pixels. Multiples of 4 stay on the grid. |
| speed | `number` | `1` | Multiplies how fast the gradient moves. |

## When to use

- A hero or footer that should feel printed, not rendered
- A section divider with character and no colour
- With a heading at the top, where the gradient leaves the frame empty

## When not to use

- Behind text in the lower half: the dots run close to solid there
- On a page that already has a gradient or a photograph as its hero
- More than two or three times on a page: browsers cap live WebGL contexts near 16

## Notes for agents

- The element needs a height. It fills its box and does nothing to set one
- It installs components/ui/shader-canvas.tsx, which pauses off screen, follows the theme and handles reduced motion
- Under reduced motion it draws one frame, and without WebGL a CSS dot grid shows through
- The gradient sits low in the frame by design, so put content at the top. No GSAP is involved here

## The maths

- The dot size rounds to whole device pixels, floor(pixel × scale + 0.5), so a 4px dot at 1.5x is 6 even pixels.
- A 4 by 4 Bayer matrix is the 2 by 2 matrix plus itself at half frequency over 4, which gives 16 thresholds and 17 tones.
- Tone is 0.84 × (1 - e^(-1.9 t)), a soft ceiling that keeps the ink open so the dots never close up into a solid.

Docs: https://ui.goodtabs.co/components/dither-gradient