# Dither globe

A rotating dithered globe with a lit terminator, pulsing markers and arcs, for global sections of a landing page.

> 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-globe-demo.tsx" size="full" align="stretch" controls="globeControls">
  <DitherGlobeDemo />
</ComponentPreview>

## Installation [#installation]

<InstallBlock name="dither-globe" />

## Usage [#usage]

```tsx
import { DitherGlobe } from "@/components/dithercn/dither-globe";

const LONDON = [51.51, -0.13] as const;
const TOKYO = [35.68, 139.69] as const;

export function Global() {
  return (
    <DitherGlobe
      markers={[{ at: LONDON }, { at: TOKYO }]}
      arcs={[{ from: LONDON, to: TOKYO }]}
      className="aspect-square w-full max-w-md"
    />
  );
}
```

The globe is drawn on a 2D canvas at dither-cell resolution: every cell on the sphere gets a tone from the land mask and the light, then an ordered threshold decides whether it's inked. Land is bright on the day side and fades to a sparse grid past the terminator; the sea is a faint dither that thickens towards the rim. It uses no WebGL context, so it doesn't count against the page's shader budget.

The globe stays round and centred in its box and takes 84% of the shorter side. Make the box larger than its section and offset it to show only the top of the globe, as in the first example.

Visitors can turn the globe. Dragging sideways spins it and dragging up or down tilts it, with the land staying under the pointer. Let go mid-drag and it coasts to a stop, then picks its idle spin back up. On phones, a horizontal swipe turns it and a vertical swipe still scrolls the page. When it has keyboard focus, the arrow keys turn it. Set `draggable={false}` for a globe that should only spin on its own.

Land comes from the shared `world-land` mask (Natural Earth, public domain), installed with the component. Nothing is fetched at runtime.

## Examples [#examples]

### Horizon behind a headline [#horizon-behind-a-headline]

A globe 150% of the section's width, pushed below the bottom edge so only its lit top shows.

<ComponentPreview src="examples/dither-globe-hero.tsx" size="full" align="stretch">
  <DitherGlobeHero />
</ComponentPreview>

### Beside copy [#beside-copy]

A square globe in a two-column section. Drag it to spin.

<ComponentPreview src="examples/dither-globe-split.tsx" size="lg" align="stretch">
  <DitherGlobeSplit />
</ComponentPreview>

### Turned to one place, in a card [#turned-to-one-place-in-a-card]

`speed={0}` and `start` at the marker's longitude hold one region in view while the marker keeps pulsing.

<ComponentPreview src="examples/dither-globe-card.tsx">
  <DitherGlobeCard />
</ComponentPreview>

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `DitherColor` | `"ink"` | Colour of the land, sea and atmosphere. |
| `accent` | `DitherColor` | `"orange"` | Colour of markers and arcs that don't set their own. |
| `markers` | `{ at: [lat, lon]; color?: DitherColor }[]` | `[]` | Pulsing locations. Markers on the far side are hidden. |
| `arcs` | `{ from: [lat, lon]; to: [lat, lon]; color?: DitherColor }[]` | `[]` | Great-circle arcs lifted off the surface, with a stretch of light running along them. |
| `speed` | `number` | `6` | Degrees of rotation per second. Negative spins the other way. |
| `start` | `number` | `10` | Longitude facing the viewer at the start, in degrees. |
| `tilt` | `number` | `18` | How far the north pole leans towards the viewer, in degrees. |
| `light` | `number` | `300` | Where the light comes from, in degrees clockwise from the top. |
| `ocean` | `number` | `0.18` | Brightness of the sea on the lit side, 0 to 1. |
| `atmosphere` | `boolean` | `true` | A thin dithered glow around the lit rim. |
| `draggable` | `boolean` | `true` | Drag or use the arrow keys to turn and tilt the globe. It coasts after a drag, then eases back into its idle spin. |
| `cell` | `number` | `2` | Size of one dither cell in CSS pixels. |
| `matrix` | `"bayer2" \| "bayer4" \| "bayer8" \| "blue-noise"` | `"bayer4"` | Threshold matrix. |
| `animate` | `boolean` | `true` | Spin and pulse. false draws one still frame. |

## Notes [#notes]

* A draggable globe is focusable and announced as an image labelled "Globe. Drag it or use the arrow keys to turn it." Pass your own `aria-label` to say what it shows. With `draggable={false}` it's decorative and hidden from assistive technology, so say what it shows in the copy next to it.
* With reduced motion turned on, it draws one still frame. Dragging and the arrow keys still turn it, without the coasting.
* It pauses when scrolled out of view or when the tab is hidden. A 600px globe at 2px cells is about 70,000 cells per frame at 30 fps, well within budget on a phone; raise `cell` for very large globes.