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

Area chart

A line over a dithered fill that is densest at the line, for revenue, traffic and other totals over time.

Controls
Fill
Stack
Bloom
First series
Cell3px
Interactive

Installation

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

Usage

import { AreaChart } from "@/components/dithercn/area-chart";
 
const data = [
  { month: "Jan", revenue: 18400 },
  { month: "Feb", revenue: 21900 },
  { month: "Mar", revenue: 26300 },
];
 
export function Revenue() {
  return (
    <AreaChart
      data={data}
      x="month"
      series={[{ label: "Revenue", value: "revenue" }]}
    />
  );
}

data can hold any objects. x names the field with each point's label and every series names the field with its value. Both also accept a function, such as (datum) => datum.total / 100, when you render the chart from a Client Component. The chart fills its container's width and redraws when the container resizes.

Examples

Two layered series

With two or more series the chart adds a legend, and every series after the first draws in the next palette colour. Each fill knocks out the ones behind it, so overlapping areas never mix and the lines always sit on top. Scrub with the pointer, or focus the chart and use the arrow keys: a crosshair and readout glide between points. Hover a legend entry to spotlight that series, click it to keep it lit, and press Escape to let go.

Compact, inside a stat card

axes={false} drops the axes and the padding around the plot, so the fill can run to the edges of a card. fill="dotted" swaps the gradient for a sparse, even lattice of dots.

Props

PropTypeDefault
data*

One entry per point along the x axis, in order.

Type: readonly T[]Default –
x*

The field (or function) holding each point's x axis label.

Type: keyof T | ((datum: T) => string | number)Default –
series*

Each series is { label, value, color? }, where value is a numeric field of T or a function. Later series draw on top.

Type: [ChartSeries<T>, ...ChartSeries<T>[]]Default –
stack

none overlaps the series from the baseline. stacked sits each on the ones before it. percent stacks and scales every point to 100%; the readout adds each share.

Type: "none" | "stacked" | "percent"Default "none"
height

Height in px, axes included.

Type: numberDefault 240
fill

gradient is densest just under the line and thins toward the axis. dotted is a sparse lattice, hatched diagonal lines, solid flat colour.

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

A soft glow in each series' colour behind its fill. Its strength follows --dither-bloom, lower in light mode.

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

Colours by series position: palette names such as "green" or any CSS colour. A series' own color wins.

Type: readonly DitherColor[]Default ink, orange, green, pink, …
interactive

Scrubbing, the readout and the legend spotlight. false makes a decorative chart: no focus stop, no readout, just an image with a summary.

Type: booleanDefault true
animate

Entrance motion. Always off under reduced motion.

Type: booleanDefault true
level

Gradient only: coverage of the densest band, just under the line, from 0 to 1.

Type: numberDefault 0.625
curve

smooth is a monotone curve that never overshoots a data point.

Type: "smooth" | "linear"Default "smooth"
matrix

Gradient only: the dither texture.

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

Size of one dither cell in px, rounded to whole device pixels.

Type: numberDefault --dither-cell
axes

Show the value and category axes.

Type: booleanDefault true
tooltip

Show the readout while scrubbing.

Type: booleanDefault true
legend

Show the legend under the chart. Its entries spotlight a series on hover and lock it on click.

Type: booleanDefault Two or more series
format

How values are written on the axis, in the readout and in the table. Options work from Server Components.

Type: Intl.NumberFormatOptions | ((value: number) => string)Default Compact, as in 1.2K

Series colours follow the palette: ink, then orange, green, pink, purple, blue, red and grey. Pass colors for the whole chart, or color on one series, using a palette name or any CSS colour.

Notes

  • The chart is a focusable group labelled with a short summary, and the full data sits in a visually hidden table, so screen readers get every value. The arrow keys, Page Up, Page Down, Home and End move the readout without easing, a polite live region reads out the values at each stop, and Escape clears the readout and any locked series. Legend entries are toggle buttons.
  • On entrance the line draws in and the fill steps up through the dither levels. With reduced motion the finished chart appears at once.
  • Cells are snapped to whole device pixels, so the dither stays sharp on any screen. Markers use a ring in --dither-paper; set it to your card's background if the card is not the page colour.
  • It is plain SVG with no chart library. The entrance re-renders the chart about 16 times. Scrubbing updates at most once a frame and only moves the crosshair, markers and readout, by transform, so a year of daily points in three series stays smooth.