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

Line chart

Crisp lines with dithered range bands and point markers, for latency, conversion and period-over-period comparisons.

Controls
Band fill
Colour
Bloom
Markers
Curve
Interactive

Installation

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

Usage

import { LineChart } from "@/components/dithercn/line-chart";
 
const data = [
  { time: "12:00", p10: 160, p50: 188, p90: 238 },
  { time: "12:30", p10: 164, p50: 184, p90: 230 },
  { time: "13:00", p10: 167, p50: 191, p90: 245 },
];
 
export function Latency() {
  return (
    <LineChart
      data={data}
      x="time"
      series={[
        { label: "p50", value: "p50", range: { low: "p10", high: "p90" } },
      ]}
    />
  );
}

Each series is a 2px line. Give it a range and the space between low and high fills with a light dither, which suits percentiles, forecasts and min/max envelopes. The readout lists the value with its range.

Examples

This week against last week

A dashed series reads as a reference: a previous period or a target. The legend repeats the dash, so the two lines never rely on colour alone. Here this week's range runs from last week's value to its own, so the dither fills exactly the gap between the two.

Few points, every one marked

With sparse data, markers="all" puts a dot on each point and curve="linear" keeps straight segments between them, so nobody reads a curve the data does not have. The band is a sector benchmark in its own color, and zero starts the axis at 0 because a score's distance from zero matters here.

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?, range?: { low, high, color? }, dashed? }. value, low and high are numeric fields of T or functions.

Type: [LineSeries<T>, ...LineSeries<T>[]]Default –
markers

Which points get a dot.

Type: "all" | "last" | "none"Default "last"
zero

Start the value axis at zero. By default it fits the data, so small changes stay visible.

Type: booleanDefault false
height

Height in px, axes included.

Type: numberDefault 240
curve

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

Type: "smooth" | "linear"Default "smooth"
fill

Texture of the range bands. gradient is one even dither level, set by level; solid draws a translucent band.

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 range bands, from 0 to 1.

Type: numberDefault 0.25
matrix

Gradient only: the dither texture of the bands.

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.

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, or color on one series, with a palette name or any CSS colour.

Notes

  • The chart is a focusable group with a short summary, and every value, including ranges, is in a visually hidden table. The arrow keys, Home and End move the readout without easing, a polite live region reads out each stop, and Escape clears the readout and any locked series. With bloom, each line gets a soft glow in its colour.
  • On entrance solid lines draw from left to right, dashed lines fade in, and bands step up through the dither levels. With reduced motion the finished chart appears at once.
  • Markers carry a 2px ring in --dither-paper so they stay legible where lines cross. Set --dither-paper to your card's background if it differs from the page.