Graphs

Thirty components that draw a chart as characters on the cell — mdx-graphs, rendered on buena mono’s 618-unit grid. Every one of them is text: no canvas, no SVG, no runtime. Select a graph and you select its characters.

Each is shown with the code that drew it, generated from the same props the page passes the component — so what you copy is what you are looking at, not a sample of it that has drifted. 21 of the thirty are drawn from measured data: this repository’s own commit history, or figures the specimen publishes and sources elsewhere. The rest are marked as sample data, because no honest reading of a typeface produces an invoice.

All thirty

The frame

Everything below is drawn inside this. It is worth seeing on its own, because it is the part you compose against when none of the twenty-nine fit.

Frame

Graph sample data

Not a graph — the dashed figure the other twenty-nine are drawn inside. Compose it with GraphBody, GraphTitle, GraphRule, GraphTrack and GraphTick to draw one of your own.

[ frame ]

a track, a rule, and eleven ticks

import { Graph, GraphBody, GraphTrack, GraphTick, GraphRule } from "@buenalabs/buena-graphs";

<Graph title="frame">
  <GraphBody className="flex flex-col gap-3">
    <GraphTrack>
      {"▁▂▃▅▇█▇▅▃▂▁".split("").map((glyph, i) => (
        <GraphTick key={i}>{glyph}</GraphTick>
      ))}
    </GraphTrack>
    <GraphRule />
    <p className="text-graph-muted">a track, a rule, and eleven ticks</p>
  </GraphBody>
</Graph>

Density

Many small cells, where the reading is in the pattern rather than in any one value. These are the graphs that put the most characters on the grid at once.

Activity

GraphActivity measured

A contribution grid. Dated counts in, weeks and intensity derived.

[ commits ]
MarAprMayJunJulAug
MWF

243 commits

LessMore

243 contributions across 197 days. 243 commits
import { GraphActivity } from "@buenalabs/buena-graphs";

<GraphActivity
  title="commits"
  days={[
    { date: "2026-02-14", count: 7 },
    { date: "2026-02-15", count: 20 },
    { date: "2026-02-16", count: 2 },
    { date: "2026-02-17", count: 0 },
    { date: "2026-02-18", count: 1 },
    { date: "2026-02-19", count: 2 },
    { date: "2026-02-20", count: 0 },
    { date: "2026-02-21", count: 0 },
    { date: "2026-02-22", count: 0 },
    { date: "2026-02-23", count: 0 },
    { date: "2026-02-24", count: 0 },
    { date: "2026-02-25", count: 0 },
    { date: "2026-02-26", count: 0 },
    { date: "2026-02-27", count: 0 },
    { date: "2026-02-28", count: 0 },
    { date: "2026-03-01", count: 0 },
    { date: "2026-03-02", count: 0 },
    { date: "2026-03-03", count: 0 },
    { date: "2026-03-04", count: 0 },
    { date: "2026-03-05", count: 0 },
    { date: "2026-03-06", count: 0 },
    { date: "2026-03-07", count: 0 },
    { date: "2026-03-08", count: 0 },
    { date: "2026-03-09", count: 0 },
    { date: "2026-03-10", count: 0 },
    { date: "2026-03-11", count: 0 },
    { date: "2026-03-12", count: 0 },
    { date: "2026-03-13", count: 0 },
    { date: "2026-03-14", count: 0 },
    { date: "2026-03-15", count: 0 },
    { date: "2026-03-16", count: 0 },
    { date: "2026-03-17", count: 0 },
    { date: "2026-03-18", count: 0 },
    { date: "2026-03-19", count: 0 },
    { date: "2026-03-20", count: 0 },
    { date: "2026-03-21", count: 0 },
    { date: "2026-03-22", count: 0 },
    { date: "2026-03-23", count: 0 },
    { date: "2026-03-24", count: 0 },
    { date: "2026-03-25", count: 0 },
    { date: "2026-03-26", count: 0 },
    { date: "2026-03-27", count: 0 },
    { date: "2026-03-28", count: 0 },
    { date: "2026-03-29", count: 0 },
    { date: "2026-03-30", count: 0 },
    { date: "2026-03-31", count: 0 },
    { date: "2026-04-01", count: 0 },
    { date: "2026-04-02", count: 0 },
    { date: "2026-04-03", count: 0 },
    { date: "2026-04-04", count: 0 },
    { date: "2026-04-05", count: 0 },
    { date: "2026-04-06", count: 0 },
    { date: "2026-04-07", count: 0 },
    { date: "2026-04-08", count: 0 },
    { date: "2026-04-09", count: 0 },
    { date: "2026-04-10", count: 0 },
    { date: "2026-04-11", count: 0 },
    { date: "2026-04-12", count: 0 },
    { date: "2026-04-13", count: 0 },
    { date: "2026-04-14", count: 0 },
    { date: "2026-04-15", count: 0 },
    { date: "2026-04-16", count: 0 },
    { date: "2026-04-17", count: 0 },
    { date: "2026-04-18", count: 0 },
    { date: "2026-04-19", count: 0 },
    { date: "2026-04-20", count: 0 },
    { date: "2026-04-21", count: 0 },
    { date: "2026-04-22", count: 0 },
    { date: "2026-04-23", count: 0 },
    { date: "2026-04-24", count: 0 },
    { date: "2026-04-25", count: 0 },
    { date: "2026-04-26", count: 0 },
    { date: "2026-04-27", count: 0 },
    { date: "2026-04-28", count: 0 },
    { date: "2026-04-29", count: 0 },
    { date: "2026-04-30", count: 0 },
    { date: "2026-05-01", count: 0 },
    { date: "2026-05-02", count: 0 },
    { date: "2026-05-03", count: 0 },
    { date: "2026-05-04", count: 0 },
    { date: "2026-05-05", count: 0 },
    { date: "2026-05-06", count: 0 },
    { date: "2026-05-07", count: 0 },
    { date: "2026-05-08", count: 0 },
    { date: "2026-05-09", count: 0 },
    { date: "2026-05-10", count: 0 },
    { date: "2026-05-11", count: 0 },
    { date: "2026-05-12", count: 0 },
    { date: "2026-05-13", count: 0 },
    { date: "2026-05-14", count: 0 },
    { date: "2026-05-15", count: 0 },
    { date: "2026-05-16", count: 0 },
    { date: "2026-05-17", count: 0 },
    { date: "2026-05-18", count: 0 },
    { date: "2026-05-19", count: 0 },
    { date: "2026-05-20", count: 0 },
    { date: "2026-05-21", count: 0 },
    { date: "2026-05-22", count: 0 },
    { date: "2026-05-23", count: 0 },
    { date: "2026-05-24", count: 0 },
    { date: "2026-05-25", count: 0 },
    { date: "2026-05-26", count: 0 },
    { date: "2026-05-27", count: 0 },
    { date: "2026-05-28", count: 0 },
    { date: "2026-05-29", count: 0 },
    { date: "2026-05-30", count: 0 },
    { date: "2026-05-31", count: 0 },
    { date: "2026-06-01", count: 0 },
    { date: "2026-06-02", count: 0 },
    { date: "2026-06-03", count: 0 },
    { date: "2026-06-04", count: 0 },
    { date: "2026-06-05", count: 0 },
    { date: "2026-06-06", count: 0 },
    { date: "2026-06-07", count: 0 },
    { date: "2026-06-08", count: 0 },
    { date: "2026-06-09", count: 0 },
    { date: "2026-06-10", count: 0 },
    { date: "2026-06-11", count: 0 },
    { date: "2026-06-12", count: 0 },
    { date: "2026-06-13", count: 0 },
    { date: "2026-06-14", count: 0 },
    { date: "2026-06-15", count: 0 },
    { date: "2026-06-16", count: 0 },
    { date: "2026-06-17", count: 0 },
    { date: "2026-06-18", count: 0 },
    { date: "2026-06-19", count: 0 },
    { date: "2026-06-20", count: 0 },
    { date: "2026-06-21", count: 0 },
    { date: "2026-06-22", count: 0 },
    { date: "2026-06-23", count: 0 },
    { date: "2026-06-24", count: 0 },
    { date: "2026-06-25", count: 0 },
    { date: "2026-06-26", count: 0 },
    { date: "2026-06-27", count: 0 },
    { date: "2026-06-28", count: 0 },
    { date: "2026-06-29", count: 0 },
    { date: "2026-06-30", count: 1 },
    { date: "2026-07-01", count: 0 },
    { date: "2026-07-02", count: 0 },
    { date: "2026-07-03", count: 4 },
    { date: "2026-07-04", count: 49 },
    { date: "2026-07-05", count: 27 },
    { date: "2026-07-06", count: 0 },
    { date: "2026-07-07", count: 6 },
    { date: "2026-07-08", count: 14 },
    { date: "2026-07-09", count: 0 },
    { date: "2026-07-10", count: 0 },
    { date: "2026-07-11", count: 0 },
    { date: "2026-07-12", count: 0 },
    { date: "2026-07-13", count: 0 },
    { date: "2026-07-14", count: 0 },
    { date: "2026-07-15", count: 1 },
    { date: "2026-07-16", count: 2 },
    { date: "2026-07-17", count: 0 },
    { date: "2026-07-18", count: 1 },
    { date: "2026-07-19", count: 3 },
    { date: "2026-07-20", count: 0 },
    { date: "2026-07-21", count: 1 },
    { date: "2026-07-22", count: 3 },
    { date: "2026-07-23", count: 0 },
    { date: "2026-07-24", count: 0 },
    { date: "2026-07-25", count: 4 },
    { date: "2026-07-26", count: 10 },
    { date: "2026-07-27", count: 1 },
    { date: "2026-07-28", count: 20 },
    { date: "2026-07-29", count: 18 },
    { date: "2026-07-30", count: 1 },
    { date: "2026-07-31", count: 4 },
    { date: "2026-08-01", count: 0 },
    { date: "2026-08-02", count: 0 },
    { date: "2026-08-03", count: 0 },
    { date: "2026-08-04", count: 4 },
    { date: "2026-08-05", count: 0 },
    { date: "2026-08-06", count: 0 },
    { date: "2026-08-07", count: 0 },
    { date: "2026-08-08", count: 0 },
    { date: "2026-08-09", count: 0 },
    { date: "2026-08-10", count: 0 },
    { date: "2026-08-11", count: 0 },
    { date: "2026-08-12", count: 0 },
    { date: "2026-08-13", count: 0 },
    { date: "2026-08-14", count: 7 },
    { date: "2026-08-15", count: 6 },
    { date: "2026-08-16", count: 0 },
    { date: "2026-08-17", count: 0 },
    { date: "2026-08-18", count: 0 },
    { date: "2026-08-19", count: 0 },
    { date: "2026-08-20", count: 18 },
    { date: "2026-08-21", count: 1 },
    { date: "2026-08-22", count: 0 },
    { date: "2026-08-23", count: 0 },
    { date: "2026-08-24", count: 1 },
    { date: "2026-08-25", count: 0 },
    { date: "2026-08-26", count: 2 },
    { date: "2026-08-27", count: 0 },
    { date: "2026-08-28", count: 0 },
    { date: "2026-08-29", count: 2 },
  ]}
  weekStartsOn={1}
  caption="243 commits"
/>

Calendar

GraphCalendar measured

One month on a seven-column grid, with days marked and one picked out.

[ july ]
July 2026, marked 3, 4, 5, 7, 8, 15, 16, 18, 19, 21, 22, 25, 26, 27, 28, 29, 30, 31
import { GraphCalendar } from "@buenalabs/buena-graphs";

<GraphCalendar
  title="july"
  year={2026}
  month={7}
  weekStartsOn={1}
  marks={[
    { day: 3 },
    { day: 4, accent: true },
    { day: 5 },
    { day: 7 },
    { day: 8 },
    { day: 15 },
    { day: 16 },
    { day: 18 },
    { day: 19 },
    { day: 21 },
    { day: 22 },
    { day: 25 },
    { day: 26 },
    { day: 27 },
    { day: 28 },
    { day: 29 },
    { day: 30 },
    { day: 31 },
  ]}
/>

Uptime

GraphUptime sample data

A status strip — one cell a day, three states and a gap.

[ status ]

90%

6w agotoday

█ up▒ slow· down

90 percent uptime over 42 days, 6w ago to today
import { GraphUptime } from "@buenalabs/buena-graphs";

<GraphUptime
  title="status"
  from="6w ago"
  to="today"
  days={[
    "ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok",
    "ok", "ok", "ok", "ok", "degraded", "ok", "ok", "ok", "ok", "ok", "ok",
    "ok", "ok", "down", "degraded", "ok", "ok", "ok", "ok", "ok", "ok",
    "ok", "ok", "ok", "ok", "ok", "ok", "degraded", "ok", "ok",
  ]}
/>

Cells

GraphCells measured

Small multiples of an on-and-off grid — the same shape drawn once per group, for comparing patterns rather than magnitudes.

[ days with a commit ]

2026-02

2026-07

2026-08

import { GraphCells } from "@buenalabs/buena-graphs";

<GraphCells
  title="days with a commit"
  items={[
    {
      label: "2026-02",
      cells: [
      [0, 1, 0],
      [0, 0, 0],
      [0, 1, 0],
      [0, 1, 0],
      [0, 0, 0],
      [1, 0, 0],
      [1, 0, 0],
    ],
    },
    {
      label: "2026-07",
      cells: [
      [0, 0, 0, 0, 1],
      [0, 1, 0, 1, 1],
      [0, 1, 1, 1, 1],
      [0, 0, 1, 0, 1],
      [1, 0, 0, 0, 1],
      [1, 0, 1, 1, 0],
      [1, 0, 1, 1, 0],
    ],
    },
    {
      label: "2026-08",
      cells: [
      [0, 0, 0, 0, 1],
      [0, 1, 0, 0, 0],
      [0, 0, 0, 0, 1],
      [0, 0, 0, 1, 0],
      [0, 0, 1, 1, 0],
      [0, 0, 1, 0, 1],
      [0, 0, 0, 0, 0],
    ],
    },
  ]}
/>

Waffle

GraphWaffle measured

A percentage as a block of cells, when a bar would not show the remainder.

[ july's share ]

70%

169 of 243 commits landed in July

70 percent. 169 of 243 commits landed in July
import { GraphWaffle } from "@buenalabs/buena-graphs";

<GraphWaffle
  title="july's share"
  value={0.695}
  cells={100}
  columns={20}
  caption="169 of 243 commits landed in July"
/>

Series

A sequence over time, at four levels of ceremony — from one line of glyphs to a plot with a scale.

Spark

GraphSpark measured

A sparkline in block glyphs, scaled to its own highest point.

[ per week ]

29 weeks

Sparkline with 29 points. 29 weeks
import { GraphSpark } from "@buenalabs/buena-graphs";

<GraphSpark
  title="per week"
  data={[
    27, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 20, 7,
    18, 44, 4, 13, 19, 5,
  ]}
  caption="29 weeks"
/>

Plot

GraphPlot measured

A line or area plot with a y-scale, for when the magnitude matters.

[ running total ]
2430
2026-022026-08
area plot, 29 points, min 0, max 243
import { GraphPlot } from "@buenalabs/buena-graphs";

<GraphPlot
  title="running total"
  data={[
    27, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 113, 133, 140, 158, 202, 206, 219, 238, 243,
  ]}
  labels={["2026-02", "2026-08"]}
  height={7}
  variant="area"
/>

KPI

GraphKpi measured

One number with its trend under it — a headline that shows its working.

[ commits ]

243

since the first commit

197 days

243 since the first commit. 197 days
import { GraphKpi } from "@buenalabs/buena-graphs";

<GraphKpi
  title="commits"
  value="243"
  label="since the first commit"
  hint="197 days"
  data={[
    27, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 20, 7,
    18, 44, 4, 13, 19, 5,
  ]}
/>

Heatmap

GraphHeatmap measured

A punchcard: labelled rows against labelled columns, intensity by glyph.

[ when ]
0003060912151821
  • Sun
  • Mon
  • Tue
  • Wed
  • Thu
  • Fri
  • Sat

LessMore

import { GraphHeatmap } from "@buenalabs/buena-graphs";

<GraphHeatmap
  title="when"
  columns={["00", "03", "06", "09", "12", "15", "18", "21"]}
  rows={[
    { label: "Sun", values: [22, 18, 2, 2, 4, 7, 2, 3] },
    { label: "Mon", values: [0, 0, 1, 0, 2, 0, 0, 1] },
    { label: "Tue", values: [0, 0, 0, 5, 1, 1, 7, 18] },
    { label: "Wed", values: [6, 21, 6, 0, 1, 2, 1, 2] },
    { label: "Thu", values: [0, 0, 0, 2, 1, 1, 13, 6] },
    { label: "Fri", values: [0, 0, 0, 0, 1, 8, 5, 2] },
    { label: "Sat", values: [12, 1, 0, 4, 11, 9, 15, 17] },
  ]}
/>

Slope

GraphSlope measured

Two columns and the lines between them — what moved, and which way.

[ metrics ]
typical monobuena
  • advance600618
  • cap height730699
  • x-height550524
import { GraphSlope } from "@buenalabs/buena-graphs";

<GraphSlope
  title="metrics"
  fromLabel="typical mono"
  toLabel="buena"
  items={[
    { label: "advance", from: 600, to: 618 },
    { label: "cap height", from: 730, to: 699 },
    { label: "x-height", from: 550, to: 524 },
  ]}
/>

Magnitude

Comparing sizes. A bar is a count of block elements, so the length is literal — you can count it.

Bars

GraphBars measured

Two series above and below a label — a before and after of the same categories, with the thing between them named.

[ commits by area ]
█████ ███████

before the gap

four months
█████ ██ ████

after it

import { GraphBars } from "@buenalabs/buena-graphs";

<GraphBars
  title="commits by area"
  from={{ label: "before the gap", values: [16, 3, 14] }}
  to={{ label: "after it", values: [101, 23, 86] }}
  processor="four months"
/>

Rank

GraphRank measured

An ordered bar list — the shape you want for a top-n.

[ commits by area ]
  1. copy83
  2. machinery66
  3. style20
import { GraphRank } from "@buenalabs/buena-graphs";

<GraphRank
  title="commits by area"
  items={[
    { label: "copy", value: 83 },
    { label: "machinery", value: 66 },
    { label: "style", value: 20 },
  ]}
/>

Meter

GraphMeter measured

A single value on a track — the smallest chart that is still a chart.

[ days worked ]

16%

32 of 197 days in the span had a commit

16 percent 32 of 197 days in the span had a commit
import { GraphMeter } from "@buenalabs/buena-graphs";

<GraphMeter
  title="days worked"
  value={0.162}
  caption="32 of 197 days in the span had a commit"
  ticks={24}
/>

Bullet

GraphBullet sample data

Value against target on one track, for a number with something to beat.

[ against target ]
  • ligatures159 / 140
  • features51 / 40
  • weights8 / 8
import { GraphBullet } from "@buenalabs/buena-graphs";

<GraphBullet
  title="against target"
  items={[
    { label: "ligatures", value: 159, target: 140, max: 200 },
    { label: "features", value: 51, target: 40, max: 60 },
    { label: "weights", value: 8, target: 8, max: 10 },
  ]}
/>

Stack

GraphStack measured

Parts of a whole, one row per group. The palette that earns three hues.

[ by area ]
  • 2026-02
  • 2026-06
  • 2026-07
  • 2026-08
  • copy
  • style
  • machinery
import { GraphStack } from "@buenalabs/buena-graphs";

<GraphStack
  title="by area"
  rows={[
    {
      label: "2026-02",
      segments: [
      { label: "copy", value: 16 },
      { label: "style", value: 3 },
      { label: "machinery", value: 13 },
    ],
    },
    {
      label: "2026-06",
      segments: [
      { label: "copy", value: 0 },
      { label: "style", value: 0 },
      { label: "machinery", value: 1 },
    ],
    },
    {
      label: "2026-07",
      segments: [
      { label: "copy", value: 83 },
      { label: "style", value: 20 },
      { label: "machinery", value: 66 },
    ],
    },
    {
      label: "2026-08",
      segments: [
      { label: "copy", value: 18 },
      { label: "style", value: 3 },
      { label: "machinery", value: 20 },
    ],
    },
  ]}
  palette="multi"
  ticks={20}
/>

Funnel

GraphFunnel sample data

Steps that only ever narrow, with the drop shown at each one.

[ glyph pipeline ]
  1. drawn5,406
  2. spaced5,406100%
  3. kerned3,82071%
  4. hinted3,12058%
import { GraphFunnel } from "@buenalabs/buena-graphs";

<GraphFunnel
  title="glyph pipeline"
  steps={[
    { label: "drawn", value: 5406 },
    { label: "spaced", value: 5406 },
    { label: "kerned", value: 3820 },
    { label: "hinted", value: 3120 },
  ]}
  stage="hinted"
/>

Waterfall

GraphWaterfall sample data

How a total was arrived at — a start, the moves, and where it landed.

[ glyph count ]
  • latin1,280
  • cyrillic+420
  • greek+310
  • box + block+220
  • braille+256
  • deduped−180
  • shipped2,306
latin 1,280, cyrillic +420, greek +310, box + block +220, braille +256, deduped −180, shipped 2,306
import { GraphWaterfall } from "@buenalabs/buena-graphs";

<GraphWaterfall
  title="glyph count"
  items={[
    { label: "latin", value: 1280, kind: "start" },
    { label: "cyrillic", value: 420, kind: "in" },
    { label: "greek", value: 310, kind: "in" },
    { label: "box + block", value: 220, kind: "in" },
    { label: "braille", value: 256, kind: "in" },
    { label: "deduped", value: -180, kind: "out" },
    { label: "shipped", value: 2306, kind: "end" },
  ]}
/>

Structure

Shape rather than quantity: what contains what, what follows what, what runs alongside what.

Tree

GraphTree measured

A hierarchy in branch glyphs, with one node carrying the accent.

[ src ]
  • src/
  • components/8
  • ui/4
  • lib/19
  • pages/13
  • styles/1
Tree with 6 nodes
import { GraphTree } from "@buenalabs/buena-graphs";

<GraphTree
  title="src"
  nodes={[
    {
      label: "src/",
      children: [
      {
        label: "components/",
        meta: "8",
        children: [
        { label: "ui/", meta: "4" },
      ],
      },
      { label: "lib/", meta: "19" },
      { label: "pages/", meta: "13" },
      { label: "styles/", meta: "1" },
    ],
    },
  ]}
/>

Flow

GraphFlow measured

Nodes on dashed arrows. Rows read left to right; one path can be accented.

[ build ]
graphs.astro
React SSR
characters
global.css
Tailwind
one stylesheet
dist/
Pages
reader
import { GraphFlow } from "@buenalabs/buena-graphs";

<GraphFlow
  title="build"
  rows={[
    {
      nodes: [
      { label: "graphs.astro" },
      { label: "React SSR", tone: "accent" },
      { label: "characters", tone: "accent" },
    ],
    },
    {
      nodes: [
      { label: "global.css" },
      { label: "Tailwind" },
      { label: "one stylesheet" },
    ],
    },
    {
      nodes: [
      { label: "dist/" },
      { label: "Pages", stretch: true },
      { label: "reader" },
    ],
    },
  ]}
/>

Timeline

GraphTimeline measured

Dated events down a connector, with done, current and upcoming states.

[ ancestry ]
  1. 1955Courier
  2. 1968OCR-B
  3. 2008Nitti
  4. 2014Fira Code
  5. 2026Buena Mono
import { GraphTimeline } from "@buenalabs/buena-graphs";

<GraphTimeline
  title="ancestry"
  events={[
    { date: "1955", label: "Courier", state: "done" },
    { date: "1968", label: "OCR-B", state: "done" },
    { date: "2008", label: "Nitti", state: "done" },
    { date: "2014", label: "Fira Code", state: "done" },
    { date: "2026", label: "Buena Mono", state: "now" },
  ]}
/>

Gantt

GraphGantt measured

Bars on a shared track, measured from day counts rather than drawn.

[ release ]
  • drawing
  • spacing
  • hinting
janfebmar
import { GraphGantt } from "@buenalabs/buena-graphs";

<GraphGantt
  title="release"
  ticks={["jan", "feb", "mar"]}
  columns={30}
  items={[
    { label: "drawing", start: 0, end: 0.462 },
    { label: "spacing", start: 0.462, end: 0.785 },
    { label: "hinting", start: 0.785, end: 1 },
  ]}
  stage="spacing"
/>

Tabular

Rows and columns, where the frame is doing the work of a table rather than of a chart. The last one is not a chart at all.

Table

GraphTable measured

A plain table inside the frame, with per-column alignment and a footer.

[ metrics ]
metrictypicalbuena
cap height730699
x-height550524
advance600618
ligatures139159
features3751
import { GraphTable } from "@buenalabs/buena-graphs";

<GraphTable
  title="metrics"
  headers={["metric", "typical", "buena"]}
  align={["left", "right", "right"]}
  rows={[
    ["cap height", "730", "699"],
    ["x-height", "550", "524"],
    ["advance", "600", "618"],
    ["ligatures", "139", "159"],
  ]}
  footer={["features", "37", "51"]}
/>

Compare

GraphCompare measured

A feature matrix. Booleans draw as ✓ and –; one column takes the accent.

[ features ]
JetBrainsiA WriterFira CodeCascadiabuena
  • Ligatures✓–✓✓✓
  • Small caps––––✓
  • Braille set–––✓✓
  • Ligature count1390125—159
  • OT features3716262451
import { GraphCompare } from "@buenalabs/buena-graphs";

<GraphCompare
  title="features"
  columns={["JetBrains", "iA Writer", "Fira Code", "Cascadia", "buena"]}
  accent="buena"
  rows={[
    {
      label: "Ligatures",
      values: [
      true,
      false,
      true,
      true,
      true,
    ],
    },
    {
      label: "Small caps",
      values: [
      false,
      false,
      false,
      false,
      true,
    ],
    },
    {
      label: "Braille set",
      values: [
      false,
      false,
      false,
      true,
      true,
    ],
    },
    { label: "Ligature count", values: ["139", "0", "125", "—", "159"] },
    { label: "OT features", values: ["37", "16", "26", "24", "51"] },
  ]}
/>

Spec

GraphSpec measured

A definition list — labels down the left, values right, one accented.

[ buena mono ]
advance
618
cap height
699
x-height
524
glyphs
5,406
languages
971
import { GraphSpec } from "@buenalabs/buena-graphs";

<GraphSpec
  title="buena mono"
  rows={[
    { label: "advance", value: "618", accent: true },
    { label: "cap height", value: "699" },
    { label: "x-height", value: "524" },
    { label: "glyphs", value: "5,406" },
    { label: "languages", value: "971" },
  ]}
/>

Stat

GraphStat measured

A row of headline figures, each with a label and an optional hint.

[ at a glance ]
  • 5,406

    glyphs

    3 scripts

  • 159

    ligatures

  • 51

    features

  • 971

    languages

import { GraphStat } from "@buenalabs/buena-graphs";

<GraphStat
  title="at a glance"
  items={[
    { value: "5,406", label: "glyphs", hint: "3 scripts" },
    { value: "159", label: "ligatures", accent: true },
    { value: "51", label: "features" },
    { value: "971", label: "languages" },
  ]}
/>

Diff

GraphDiff sample data

Added, removed and unchanged rows, with a total at the bottom.

[ since 1.0 ]
  • braille patterns+256
  • coding ligatures+20
  • legacy alternates−48
  • small caps923
glyphs+228
import { GraphDiff } from "@buenalabs/buena-graphs";

<GraphDiff
  title="since 1.0"
  rows={[
    { label: "braille patterns", value: "+256", sign: "add" },
    { label: "coding ligatures", value: "+20", sign: "add" },
    { label: "legacy alternates", value: "−48", sign: "remove" },
    { label: "small caps", value: "923", sign: "keep" },
  ]}
  footer={{ label: "glyphs", value: "+228", sign: "add" }}
/>

Invoice

GraphInvoice sample data

A document rather than a chart — the frame doing receipts and statements.

[ invoice ]

From

Buena Labs

hello@buenalabs.io

Bill to

Sample Client

Somewhere

number
BL-0042
issued
2026-08-01
DescriptionQtyRateAmount
Type design — latin401204,800
Spacing and kerning181202,160
Hinting121201,440
subtotal
8,400
total
8,400

Sample data — this one is a layout, not a measurement.

import { GraphInvoice } from "@buenalabs/buena-graphs";

<GraphInvoice
  title="invoice"
  from={{ name: "Buena Labs", lines: ["hello@buenalabs.io"] }}
  to={{ name: "Sample Client", lines: ["Somewhere"] }}
  meta={[
    { label: "number", value: "BL-0042" },
    { label: "issued", value: "2026-08-01" },
  ]}
  items={[
    {
      description: "Type design — latin",
      qty: "40",
      rate: "120",
      amount: "4,800",
    },
    {
      description: "Spacing and kerning",
      qty: "18",
      rate: "120",
      amount: "2,160",
    },
    { description: "Hinting", qty: "12", rate: "120", amount: "1,440" },
  ]}
  totals={[
    { label: "subtotal", value: "8,400" },
    { label: "total", value: "8,400", accent: true },
  ]}
  note="Sample data — this one is a layout, not a measurement."
/>

Clock

The two that read the time. Every other component on this page finishes rendering at build time and needs nothing to run; these two do not.

Timer

GraphTimer sample data

Elapsed time, time since, or a wall clock.

Reads the clock every second. Rendered here with no client directive, so what you see is the zero state it starts from; add the directive in the code below and it runs.

[ elapsed ]

00:00:00

since the last release

timer
import { GraphTimer } from "@buenalabs/buena-graphs";

<GraphTimer
  client:visible
  title="elapsed"
  kind="elapsed"
  at="2026-08-01T09:00:00Z"
  caption="since the last release"
/>

Countdown

GraphCountdown sample data

Time remaining until an instant, with a message for when it lands.

Counts down every second. Rendered here with no client directive, so what you see is the zero state it starts from; add the directive in the code below and it runs.

[ until ]

00:00:00

next release window

remaining 00:00:00
import { GraphCountdown } from "@buenalabs/buena-graphs";

<GraphCountdown
  client:visible
  title="until"
  to="2027-01-01T00:00:00Z"
  done="shipped"
  caption="next release window"
/>

Installing them

mdx-graphs is not an npm package — it is shadcn-registry copy-in, so the components land in your repository and you own them from there. One command per component, or all for the set:

pnpm dlx shadcn@latest add https://mdx-graphs.kshv.me/r/graph-spark.json

The copy lives in @buenalabs/buena-graphs (extracted from this site 2026-09-04) with four deliberate edits, all documented at the top of the package’s src/components/index.ts: the imports point at siblings, colour is bound to this site’s tokens rather than the library’s, nothing is dimmed below the contrast floor, and the animation runtime is replaced by a static shim so these render at build time and ship as characters. The specimen section explains why that last one matters.