https://github.com/shuakami/paperchart
Quiet, editorial chart PNGs for technical blog posts. 15 primitives, six themes, one CLI.
https://github.com/shuakami/paperchart
agent-skills agentskills anthropic-style blog charts data-visualization editorial linear-style minimal-design openai-style playwright react recharts skills-sh technical-writing typescript vercel-style
Last synced: 1 day ago
JSON representation
Quiet, editorial chart PNGs for technical blog posts. 15 primitives, six themes, one CLI.
- Host: GitHub
- URL: https://github.com/shuakami/paperchart
- Owner: shuakami
- License: mit
- Created: 2026-04-23T11:05:43.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-04-23T11:07:55.000Z (2 months ago)
- Last Synced: 2026-04-23T11:29:54.854Z (2 months ago)
- Topics: agent-skills, agentskills, anthropic-style, blog, charts, data-visualization, editorial, linear-style, minimal-design, openai-style, playwright, react, recharts, skills-sh, technical-writing, typescript, vercel-style
- Homepage: https://shuakami.github.io/paperchart/
- Size: 0 Bytes
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# paperchart

Clean chart PNGs for technical blog posts. One command in, one image out.
```bash
npx github:shuakami/paperchart latency -i data.json -o latency.png
```
Or install as an open agent skill so Claude Code, Cursor, Codex and Gemini can pick the style up automatically:
```bash
npx skills add shuakami/paperchart
```
Thirty-two chart primitives (including Mermaid-style flowchart, architecture, sequence, state, and ER diagrams), six themes, a headless-Chromium pipeline that renders every figure at 2×-DPR. Designed to be driven by AI agents — feed it a structured JSON file, get a figure you can ship.
---
## Gallery
A quick look at every primitive. Each one is rendered live on the [landing page](https://shuakami.github.io/paperchart/) and can be re-rendered into a PNG with the CLI.
### Tables and rankings
| | |
| --- | --- |
|  |  |
| **`table`** — column-major comparison table for model / product / tier release posts. | **`ranking`** — sorted leaderboard with one accented row, for eval rankings and top-N lists. |
### Bars and distributions
| | |
| --- | --- |
|  |  |
| **`latency`** — grouped horizontal bars, log-scaled x axis, for percentile comparisons. | **`bytes`** — stacked horizontal bars with an explicit gap, for first-load vs deferred payloads. |
|  |  |
| **`stacked-bar`** — per-row segment stack, for composition of a measure across categories. | **`grouped-bar`** — side-by-side bars per group, for two to four series compared across groups. |
|  |  |
| **`dumbbell`** — paired before / after endpoints per row, bi-temporal comparisons at a fixed moment. | **`slope`** — two-point lines per series, simple before / after trend. |
|  |  |
| **`histogram`** — frequency bins, for distribution shape. | **`box-plot`** — five-number-summary rows, for distribution comparison. |
|  |  |
| **`cdf`** — cumulative distribution, for tail-sensitive comparisons. | **`waterfall`** — signed-delta steps, for build-ups and break-downs. |
### Time, flow, and structure
| | |
| --- | --- |
|  |  |
| **`line`** — multi-series time series, the classical line chart. | **`area`** — stacked area, for composition over time. |
|  |  |
| **`small-multiples`** — N panels sharing axes, per-segment sparkline grid. | **`timeline`** — swim-lane phases on a time axis, for roadmaps and release histories. |
|  |  |
| **`funnel`** — stage bars with drop-off annotations, for acquisition / activation funnels. | **`sankey`** — two-column flow diagram, for attribution and token allocation. |
|  |  |
| **`treemap`** — squarified hierarchical tiles, for bundle / budget composition. | **`radar`** — multi-axis polygon, for capability profile and coverage map. |
### Matrices, points, calendars
| | |
| --- | --- |
|  |  |
| **`scatter`** — points + optional regression, for correlation plots. | **`heatmap`** — row × column matrix, for confusion matrices and cross-tabs. |
|  |  |
| **`calendar-heatmap`** — 53×7 daily grid, daily activity over a year. | **`recall`** — per-row dot plot with overlapping markers, showing two engines return the same set. |
### Architecture and explanation
| | |
| --- | --- |
|  |  |
| **`critical-path`** — horizontal timeline with named milestones, for resource waterfalls. | **`pack-layout`** — byte-level composition + bit header, for explaining a binary format. |
|  |  |
| **`delivery`** — three-up panel comparison, for architecture options where one variant is emphasised. | **`flowchart`** — layered DAG with decisions and stores, for request pipelines and retry logic. |
|  |  |
| **`architecture`** — grouped services with labelled connections, for system architecture diagrams. | **`sequence`** — lifelines with directed messages and notes, for API request flows. |
|  |  |
| **`state-diagram`** — states with labelled transitions and pseudostates, for UI state machines. | **`er-diagram`** — entity boxes with crow's-foot cardinality, for database schema walkthroughs. |
All thirty-two are also live at [shuakami.github.io/paperchart](https://shuakami.github.io/paperchart/). Pass `?theme=ink` (or `slate` / `forest` / `mono` / `dusk`) to see any of them in another palette.
---
## Quick start
```bash
# pick any chart type, point it at JSON, name the output:
npx github:shuakami/paperchart latency -i data.json -o out/latency.png
npx github:shuakami/paperchart bytes -i data.json -o out/bytes.png
npx github:shuakami/paperchart recall -i data.json -o out/recall.png
# render a sample without writing any JSON first:
npx github:shuakami/paperchart latency --defaults -o sample.png
```
The CLI starts a tiny local HTTP server, renders the React view inside headless Chromium, screenshots it, and exits. No dev server to run, no `npm install` inside your project, no React editing.
**First run** downloads the Chromium binary (~200 MB). Re-runs are fast.
## The chart primitives
| slug | what it is | good for |
| --- | --- | --- |
| `table` | column-major comparison table | model / product / tier release posts |
| `latency` | grouped horizontal bars, log-scaled x axis | before / after distributions, percentile comparisons |
| `bytes` | stacked horizontal bars with an explicit gap | splitting a payload into a first-load block and a deferred block |
| `stacked-bar` | per-row segment stack | composition of a measure across categories |
| `grouped-bar` | side-by-side bars per group | two to four series compared across groups |
| `ranking` | sorted leaderboard with one accented row | eval rankings, top-N lists |
| `dumbbell` | paired before / after endpoints per row | bi-temporal comparison at a fixed moment |
| `slope` | two-point lines per series | simple before / after trend |
| `line` | multi-series time series | classical line chart |
| `area` | stacked area | composition over time |
| `small-multiples` | N panels sharing axes | per-segment sparkline grid |
| `timeline` | swim-lane phases on a time axis | roadmaps, release histories |
| `funnel` | stage bars with drop-off annotations | acquisition / activation funnels |
| `sankey` | two-column flow diagram | attribution, token allocation |
| `treemap` | squarified hierarchical tiles | bundle / budget composition |
| `radar` | multi-axis polygon | capability profile, coverage map |
| `scatter` | points + optional regression | correlation plots |
| `heatmap` | row × column matrix | confusion matrices, cross-tabs |
| `calendar-heatmap` | 53×7 daily grid | daily activity over a year |
| `histogram` | frequency bins | distribution shape |
| `box-plot` | five-number-summary rows | distribution comparison |
| `cdf` | cumulative distribution | tail-sensitive comparisons |
| `waterfall` | signed-delta steps | build-ups and break-downs |
| `critical-path` | horizontal timeline with named milestones | network waterfalls, deferred vs blocking resources |
| `pack-layout` | byte-level composition + bit header | explaining a binary format on a single page |
| `recall` | per-row dot plot with overlapping markers | showing that two or more engines return the same result set |
| `delivery` | three-up panel comparison | architecture options where only one variant is emphasised |
| `flowchart` | layered DAG with decisions and stores | request pipelines, retrieval flows, retry logic |
| `architecture` | grouped services with labelled connections | system architecture diagrams |
| `sequence` | lifelines with directed messages and notes | API request flows, RPC traces |
| `state-diagram` | states with labelled transitions and pseudostates | UI and protocol state machines |
| `er-diagram` | entity boxes with crow's-foot cardinality | database schema walkthroughs |
Hit each live at [shuakami.github.io/paperchart](https://shuakami.github.io/paperchart/) — or scroll up to the gallery above for a pre-rendered preview of every primitive.
## JSON schemas
Every type takes a single JSON document. Numbers stay raw; the renderer handles units, alignment, colour.
### `latency` — `Row[]`
```jsonc
[
{
"group": "baseline",
"caption": "fuzzy scoring over the JSON index shipped inside the chunk",
"color": "neutral", // "neutral" | "accent"
"bars": [
{ "level": "p50", "ms": 13.32 },
{ "level": "p95", "ms": 23.94 },
{ "level": "p99", "ms": 25.41 }
]
},
{ "group": "inverted index", "caption": "...", "color": "neutral", "bars": [ /* ... */ ] },
{ "group": "externalized pack", "caption": "...", "color": "accent", "bars": [ /* ... */ ] }
]
```
Row count is fixed at 3 in v0.1.
### `bytes` — `Row[]`
```jsonc
[
{
"group": "baseline",
"caption": "index + pages JSON inlined as a string literal inside the JS chunk",
"accent": false,
"segments": [
{ "kb": 87, "fill": "neutral", "tag": "JSON index + pages" },
{ "kb": 20, "fill": "neutral", "tag": "runtime + UI glue" }
],
"firstLoadKB": 107,
"deferredKB": 0
}
// up to 3 rows
]
```
`fill` accepts `"neutral"` or `"accent"` (or a hex string, for escape hatches).
### `recall` — `Query[]`
```jsonc
[
{ "query": "weather", "hits": 5, "sets": "equal" },
{ "query": "bilibili", "hits": 7, "sets": "equal" },
{ "query": "图片", "hits": 12, "sets": "equal" }
// 20 queries in the default layout
]
```
### `critical-path` — `Row[]`
```jsonc
[
{ "label": "index.html", "detail": "server-rendered document shell", "startMs": 0, "endMs": 40, "kb": 4, "critical": true },
{ "label": "framework runtime","detail": "React runtime chunk", "startMs": 30, "endMs": 140, "kb": 48, "critical": true },
{ "label": "/search-pack.bin", "detail": "fetched only when user searches","startMs": 620, "endMs": 760, "kb": 78, "critical": false }
]
```
6 rows in the default layout.
### `pack-layout` — `Segment[]`
```jsonc
[
{ "label": "Docs", "detail": "id, title, url, summary", "bytes": 51842, "accent": false },
{ "label": "Tokens", "detail": "type flag + bytes + posting deltas", "bytes": 212908, "accent": true },
{ "label": "Corrections", "detail": "spell-correction candidates", "bytes": 37270, "accent": false }
]
```
### `delivery` — panel spec
```jsonc
{
"header": "how search reaches the browser",
"subheader": "same corpus, three delivery shapes",
"panels": [
{
"title": "baseline",
"subtitle": "JSON index + pages inlined inside the JS chunk",
"accent": false,
"assets": [
{ "label": "docs JS chunk", "detail": "pages JSON + index + UI", "kb": 87, "kind": "main" },
{ "label": "runtime", "detail": "shipped in the same chunk", "kb": 20, "kind": "main" }
],
"note": "Index, scorer and UI all travel together in the first-paint payload."
}
// up to 3 panels
]
}
```
## CLI flags
```
paperchart -i data.json -o out.png [options]
-i, --input Path to JSON input.
-o, --output Path to PNG output.
--defaults Render the built-in sample (skip -i).
-w, --width Viewport width in CSS pixels. Default 1600.
--dpr Device pixel ratio. Default 2.
--help Print usage.
```
## Themes
Every chart reads a five-token theme — `bg`, `ink`, `muted`, `accent`, `secondary`, `rule`. No hex is hard-coded inside chart code; the same JSON renders into any theme by passing `--theme `.
| name | feel | accent |
| --- | --- | --- |
| `paper` | warm off-white, the default | rust `#C75F3C` |
| `ink` | near-white, OpenAI research | graphite `#111111` |
| `slate` | cool neutral, Stripe Press | deep blue `#3B5BDB` |
| `forest` | warm off-white, foliage accent | green `#2F6B48` |
| `mono` | pure monochrome | black `#000000` |
| `dusk` | charcoal background, warm orange | amber `#E58A4A` |
No gradients, no shadows, no decorative rounded corners. Inline labels beat titles.
## Deeper customisation
If you need something the CLI does not cover — different sizes, an extra annotation layer, a different colour — clone the repo and edit the TSX directly:
```bash
git clone https://github.com/shuakami/paperchart.git
cd paperchart
npm install
npm run dev # live preview at http://127.0.0.1:5173/
npm run snap # render every chart to ./out/*.png
```
Each chart lives in its own file under [`src/charts/`](./src/charts); the default data array is at the top. Edit the numbers, save, open the URL — everything re-renders.
## Installing as an agent skill
This repo follows the [agentskills.io specification](https://agentskills.io/specification): a root [`SKILL.md`](./SKILL.md) teaches agents the overall style and how to call the CLI; focused per-chart skills live under [`skills/`](./skills).
```bash
npx skills add shuakami/paperchart
```
After install, the skill is visible to Claude Code, Cursor, Codex, Gemini CLI and anything else that loads SKILL.md files from `.agents/skills/` or `.claude/skills/`. Agents will know the palette, the typography rules, the six chart shapes, and how to call `paperchart` from the shell.
## License
MIT © [shuakami](https://github.com/shuakami)