# Dither orb

A lit, dithered orb that breathes slowly and leans towards the pointer, for AI and assistant surfaces.

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

## Installation [#installation]

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

## Usage [#usage]

```tsx
import { DitherOrb } from "@/components/dithercn/dither-orb";

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

The orb is a sphere shaded by one light, with a soft terminator, a thin rim light on the shadow side and a dithered glow that falls off around it. Its outline breathes with two slow harmonics and a little noise (`morph`). When the pointer moves anywhere on the page, the orb and its light ease towards it, then drift back to the centre when the pointer leaves.

Pass `highlight` for a third, brighter tone on the specular spot, such as `"#fff"` or a pale mix of the orb colour. Pick a colour that is light in both themes: `"--foreground"` turns black in light mode.

## Examples [#examples]

### Assistant hero [#assistant-hero]

A purple orb with a pale highlight above a prompt.

```tsx title="examples/dither-orb-assistant.tsx"
import { DitherOrb } from "@/components/dithercn/dither-orb";

export default function DitherOrbAssistant() {
  return (
    <section className="relative isolate flex size-full flex-col items-center justify-end gap-5 overflow-hidden px-6 pb-10 text-center">
      <DitherOrb
        color="purple"
        highlight="color-mix(in oklch, var(--dither-color-purple) 30%, #fff)"
        size={0.3}
        className="absolute inset-x-0 top-0 bottom-[45%] -z-10 sm:bottom-1/4"
      />
      <div className="flex max-w-sm flex-col items-center gap-2">
        <h3 className="text-2xl font-medium tracking-[-0.03em] text-balance">
          Ask anything about your workspace
        </h3>
        <p className="text-muted-foreground text-sm">
          Answers cite the docs and tickets they came from.
        </p>
      </div>
      <div className="bg-background flex w-full max-w-sm items-center gap-2 rounded-xl border px-3 py-2 text-left">
        <span className="text-muted-foreground flex-1 truncate text-sm">
          Why did the deploy on Friday fail?
        </span>
        <kbd className="bg-muted text-muted-foreground rounded-sm px-1.5 py-0.5 font-mono text-[10px]">
          ⏎
        </kbd>
      </div>
    </section>
  );
}
```

### Voice status [#voice-status]

A 64px orb on a transparent background, with more `morph` and no lean, as a listening indicator.

```tsx title="examples/dither-orb-voice.tsx"
import { DitherOrb } from "@/components/dithercn/dither-orb";

export default function DitherOrbVoice() {
  return (
    <div className="bg-background flex w-full max-w-xs items-center gap-4 rounded-2xl border p-4">
      <DitherOrb
        color="green"
        background="transparent"
        size={0.36}
        morph={1.5}
        lean={0}
        cell={1}
        className="size-16 shrink-0"
      />
      <div className="flex min-w-0 flex-col gap-0.5">
        <span className="text-sm font-medium">Listening</span>
        <span className="text-muted-foreground truncate text-xs">
          “Book the usual table for Thursday”
        </span>
      </div>
    </div>
  );
}
```

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `DitherColor` | `"ink"` | Colour of the orb and its glow. |
| `highlight` | `DitherColor` | `–` | A third, brighter tone for the specular highlight. |
| `background` | `DitherColor` | `"--dither-paper"` | Colour behind the orb. "transparent" floats it over the page. |
| `size` | `number` | `0.26` | Radius as a share of the box's shorter side, 0.1 to 0.5. |
| `morph` | `number` | `1` | How much the outline wobbles. 0 is a perfect sphere. |
| `lean` | `number` | `1` | How far the orb and its light lean towards the pointer. 0 turns it off. |
| `glow` | `number` | `0.5` | Strength of the dithered glow around the orb, 0 to 1. |
| `matrix` | `"bayer2" \| "bayer4" \| "bayer8" \| "blue-noise"` | `"bayer4"` | Threshold matrix. |
| `cell` | `number` | `--dither-cell` | Size of one dither cell in CSS pixels. |
| `speed` | `number` | `1` | How fast the outline breathes. |
| `animate` | `boolean` | `true` | false draws one still frame and stops following the pointer. |

## Notes [#notes]

* The orb is decorative and hidden from assistive technology.
* With reduced motion turned on, it draws one still, centred frame and ignores the pointer.
* One WebGL context per orb. It pauses offscreen and in hidden tabs, and the pointer listener is passive and eased in one animation frame loop that stops once the orb settles.