TERMINAL-NATIVE CHARTS
Recharts for
your terminal
Sparklines, line, bar, scatter, candlestick. Composable API, deterministic snapshots, zero deps.
▄▅▆▇███▇▆▅▃▂▁ ▁▂ ▁▁▂▃▃▄▄▅▅▆▆▆▇▇▇██▂▂▁▂▁▁ ▂▂███ ▁▂ ▂120┤ ██ 115┤ ██ ██ 110┤ │ │ ██ ██ │ 105┤██ ██ ██ │ 100┤██ │ │ │ │
│ ⡔⠉⠉⠢⡀ │⡰⠉ ⠑⢄ 60┤⠁ ⠈⢆ │⠢⢄ ⠈⢀⡠⠔ 40┤ ⠱⡀ ⡠⠃ ⠉ │ ⠘⠤⣀⡠⠔⠁ ─ rev ─ cos
CPU ████░░░░░░ 38% MEM ██████░░░░ 62% DISK ████████░░ 84% ●●●○○○○○ 38% ●●●●●○○○ 62% ●●●●●●●○ 84%
Install
bun add @crafter/charts import { plot, chart, renderToAnsi, sparkline } from "@crafter/charts";
// One-liner — just pass an array
console.log(plot([1, 5, 3, 7, 2, 8, 6, 9, 4, 10]));
// Multi-series
console.log(plot([prices, volumes], { height: 12 }));
// Full control
const c = chart({ width: 60, height: 14, charset: "braille" })
.data(rows, { xKey: "x" })
.yAxis({ format: v => "$" + v.toFixed(0) })
.yDomain([0, 200])
.line({ key: "price", color: "green", label: "Price" });
console.log(renderToAnsi(c)); Examples
plot([sin, cos], { height: 10 }) │ ⣀⠤⠒⠊⠉⠉⠉⠉⠑⠢⢄ ⣀⠤⠒⠉⠉ │ ⢀⠤⠊ ⠉⠢⡀ ⡠⠒⠉ 80┤ ⢀⠔⠁ ⠈⠒⢄ ⡠⠊ │⢀⠔⠁ ⠑⡄ ⡠⠊ │⠁ ⠈⠢⢄ ⡠⠊ 60┤ ⠑⢄ ⢀⠤⠊ │ ⠉⠢⡀ ⣀⠔⠁ │⠉⠒⠢⢄ ⣀⠤⠒⠊⠉⠒⠤⡀⢄⣀⣀⣀⣀⣀⡠⠔⠊ ⣀⠔⠊⠉⠉⠒ 40┤ ⠑⠢⢄ ⢀⠔⠉ ⠈⠑⠤⡀ ⢀⠔⠉ │ ⠣⡀ ⢀⠔⠁ ⠈⠢⡀ ⢀⠔⠁ │ ⠈⠢⣀ ⢀⠔⠁ ⠈⠢⣀ ⡠⠔⠁ │ ⠑⠢⢄⣀⣀⣀⠤⠒⠁ ⠑⠢⢄⣀⣀⣀⠤⠊ ┴───────────────┴──────────────┴───────────────┴────────────── 0 10 20 30 ─ revenue ─ costs
line ▅▆▇████▇▇▆▅▃▃▂▂▁▁ ▁▁▂▃▅▅▅▆▆▆▆▅▅▅ column ▄▆▇████▆▅▅▇████▇▅▄▆▇███ win/loss ▀▄▀▀▄▀▄▄▀▀▀▄▀▄▀▀▄▀▀▀▄▀▀▄▀ bar 90% 90% bar 45% 45% bar 15% 15%
▂▄▆▇██▇▅▃▁ ▁▄▆▇██▇▆▄▁
▄▇██████████▆▃ ▁▄▇██████████▆▃
███████████████▅▃▁ ▂▄▆████████████████▅▃▁ ▁▃▆█
▁▃▄▅▆▇█████▇▆▅▄▃▁
▂▃▅▆███████████████████▆▅▃▂
▁▁▂▂▃▄▅▆▇█████████████████████████████▇▆▅▄▃▂▂▁▁
▂▃▄▆▇▇████▇▇▆
▁▃▄▅▆▇▇▇▆▆▆▅▅▅▅▆▇██████████████
▁▃▄▅▅▅▅▅▅▄▄▄▄▄▅▆▇████████████████████████████████ │ ╭─────╮ │ ╭──╯ ╰╮ │ ╭─╯ ╰─╮ 60┤ ╭╯ ╰╮ │──╯ ╰─╮ │ ╰╮ 40┤ ╰─╮ ╭ │ ╰╮ ╭╯ │ ╰─╮ ╭──╯ │ ╰─────╯
│ ⢀⠤⠒⠊⠉⠉⠒⠢⢄ 80┤ ⢀⠔⠁ ⠈⠢⡀ │ ⡠⠃ ⠈⠢⡀ │ ⢀⠜ ⠱⡀ │ ⢠⠃ ⠘⢄ 60┤ ⢠⠃ ⢣ ⡠ │⡰⠁ ⢣ ⡜ │ ⠱⡀ ⡜ 40┤ ⠱⡀ ⢀⠎ │ ⠑⡄ ⡰⠁ │ ⠈⢢ ⡜ │ ⠑⡄ ⢀⠎ 20┤ ⠈⠢⡀ ⢀⡠⠃ │ ⠈⠑⠢⢄⣀⣀⡠⠒⠁ ┴────────────┴────────────┴────────────┴──────────── 0 10 20 30
500┤ ███████ │ ███████ │ ███████ ███████ 400┤ ███████ ███████ │ ███████ ███████ ███████ ███████ │ ███████ ███████ ███████ ███████ 300┤ ███████ ███████ ███████ ███████ │ ███████ ███████ ███████ ███████ ███████ │ ███████ ███████ ███████ ███████ ███████ 200┤ ███████ ███████ ███████ ███████ ███████ │███████ ███████ ███████ ███████ ███████ ███████
25┤
│
20┤
│
15┤ ⣀⠤⠔⠊⠉⠉⠉⠉⠑⠢⠤⡀ ⢀⠤⠒⠊⠉⠉
10┤⣀⠔⠉ ⠈⠒⢄ ⢀⠤⠒⠁
│ ⠉⠢⣀ ⣀⠔⠁
5┤ ⠉⠒⠢⢄⣀⣀⣀⡠⠔⠊⠉
│
0┤ │ ⢀ ⠈ ⠐ │ ⠁ ⠄⠠ ⠄ │ ⠄ ⠐ ⠁ 80┤ ⠈ ⠂ ⠈ ⠂ ⠠ │⠂ 60┤ ⠁ ⠈ ⠠ │ ⠄ ⢀ │ ⠂ ⠠ ⠐ 40┤ ⢀ ⠁ │ ⡀ ⠐ ⡀ ⠁
│ │ 130┤ │ │ │ │ ████ ████ │ │ ████ │ ████ ████ │ │ │ ████ ████ │ 120┤ │ ████ ████ ████ ████ │ │ │ ████ ████ │ │ │ ████ ████ │ │ │████ │ ████ ████ │ │████ ████ │ 110┤████ ████ │ │
M T W T F S S W1 ░░░░▓▓██▒▒▒▒▒▒ W2 ▒▒░░██▒▒░░▒▒ W3 ░░░░▒▒██▒▒▒▒▒▒ W4 ▒▒▓▓▒▒▒▒░░▒▒
░░░░░░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░█████████░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░███████████████░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░██████████████████░░░░░░░░░░░░ ░░░░░░░░░░░░█████████████████████░░░░░░░░░░░░ ░░░░░░░░░░░░█████████████████████░░░░░░░░░░░░ ░░░░░░░░░██████████████████████████████░░░░░░ █████████████████████████████████████████████ 6──────────────────────────────────────────92
CPU ██████░░░░░░░░░░░░░░ 23% MEM ██████████████░░░░░░ 67% DISK ██████████████████░░ 91% CPU ●●○○○○○○ 23% MEM ●●●●●○○○ 67% DISK ●●●●●●●○ 91%
API
plot(data, opts?)
One array in, chart out. Multi-series, domain control, auto-everything.
plot([1, 5, 3, 7, 2, 8]) // one array, done
plot([sin, cos], { height: 12 }) // multi-series
plot(data, { min: 0, max: 100 }) // fixed domain sparkline / sparkColumn / sparkBar / sparkWinLoss / sparkArea
6 inline variants. Line, column (with negatives), progress bar, win/loss, area (multi-line).
sparkline([1, 5, 3, 7], { color: "green" })
sparkColumn([5, -3, 7, -1], { color: "blue", negColor: "red" })
sparkBar(75, 100, { width: 20, showPercent: true })
sparkWinLoss([1, -1, 1, 1, -1])
sparkArea(data, { width: 40, color: "cyan" }) chart(opts?)
Full builder. Chain .data(), .line(), .bar(), .scatter(), .candlestick(), .yDomain(), .xAxis(), .yAxis().
chart({ width: 60, height: 14, charset: "box" })
.data(rows, { xKey: "ts" })
.yAxis({ format: v => "$" + v })
.yDomain([0, 200])
.line({ key: "price", color: "green", label: "Price" }) renderToAnsi / renderToString / renderToHtml
Three output targets. ANSI for terminal, string for CI snapshots, HTML for web.
charset: "braille" | "box" | "ascii" | "block"
Braille = 8x sub-pixel. Box = classic ╭╮╰╯─│ look. ASCII = max compatibility.
.yDomain([min, max])
Fix the y-axis scale. Essential for dashboards with multiple charts that share a range.
Built for the agent era
Zero dependencies
No runtime deps. Works with Bun and Node.
Tiny footprint
Entire library under 50KB published.
TypeScript strict
Fully typed. No any.
Deterministic
renderToString() is byte-stable. Use with toMatchSnapshot().
Braille rendering
4x2 sub-pixel per character. 8x resolution vs ASCII.
Auto-sized
Detects terminal width. Responsive by default.