For the complete documentation index, see 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.
dithercn

Donut chart

A donut or pie chart drawn in dither cells, with a colour and texture per slice and a centre that follows the pointer.

Controls
Mode
Fill
Bloom
First slice
Gap (cells)1
Sweep in

Installation

pnpm dlx shadcn@latest add https://dithercn.dev/r/donut-chart.json

Usage

import { DonutChart } from "@/components/dithercn/donut-chart";
 
const data = [
  { label: "North America", value: 48210 },
  { label: "Europe", value: 31870 },
  { label: "Asia Pacific", value: 17430 },
];
 
export function Regions() {
  return <DonutChart data={data} label="Requests today" />;
}

Slices run clockwise from 12 o'clock in the order you pass them. Each one draws in the next palette colour (ink, orange, green, pink, purple, blue, red, grey) unless you set colors for the chart or color on the slice.

Every slice is a block of whole dither cells with a solid rim along the outside. fill="gradient" thins out from that rim toward the centre; dotted, hatched and solid fill evenly. The gaps between slices are a constant width in cells, so they stay crisp in both modes.

Hover a slice or its legend row to spotlight it: the others fade, the slice steps out by two cells, and the centre switches from the total to that slice's value and share. Click to keep it lit and press Escape to let go. Focus the chart with Tab and the arrow keys step through the slices.

Examples

Storage card

A smaller ring with fill="hatched". The free space is its own slice with color: "grey" and fill: "dotted", so it reads as empty without a second chart.

Pie in a landing section

mode="pie" drops the hole. The spotlit slice gets a readout card that glides between slices. bloom="high" adds a soft glow in each slice's colour.

Props

PropTypeDefault
data*

{ label: string; value: number; color?: DitherColor; fill?: FillVariant }, drawn clockwise from the top.

Type: DonutSlice[]Default –
label*

What the total counts. Shown in the centre and used in the chart's summary.

Type: stringDefault –
mode

A ring with the total in the middle, or full wedges with a readout over the active slice.

Type: "donut" | "pie"Default "donut"
fill

Texture of every slice. A slice's own fill wins.

Type: "gradient" | "dotted" | "hatched" | "solid"Default "gradient"
bloom

Soft glow in each slice's colour behind it.

Type: "off" | "low" | "high"Default "off"
colors

Colours by slice position, as palette names or CSS colours. A slice's own color wins.

Type: DitherColor[]Default –
size

Diameter in CSS pixels.

Type: numberDefault 220
thickness

Donut only: ring thickness as a share of the radius.

Type: numberDefault 0.36
gap

Gap between slices, in dither cells.

Type: numberDefault 1
unit

Shown after every value, such as " GB".

Type: stringDefault ""
format

How values and the total are written.

Type: Intl.NumberFormatOptions | ((value: number) => string)Default { maximumFractionDigits: 0 }
legend

Show the legend. When false it stays available to screen readers.

Type: booleanDefault true
interactive

Hover, keyboard focus and the legend spotlight. false draws a static image.

Type: booleanDefault true
animate

Sweep the slices in clockwise the first time the chart is seen.

Type: booleanDefault true
matrix

Threshold pattern of the gradient fill.

Type: "bayer2" | "bayer4" | "bayer8" | "blue-noise"Default "bayer4"
cell

Size of one dither cell in CSS pixels.

Type: numberDefault --dither-cell

Notes

  • The chart is a focusable group with a summary label. Arrow keys, Home and End move between slices, Enter keeps one lit, and a live region reads the active slice. A hidden table lists every value and share.
  • The sweep plays once when the chart scrolls into view. With reduced motion turned on, slices appear at once and the spotlight has no transition.
  • The drawing is one SVG path per slice, built from whole cells snapped to device pixels. Hovering only changes opacity and a transform.