agentsclimarketplace

Paperchart

Skill shuakami/paperchart

Quiet, editorial chart PNGs for technical blog posts. 15 primitives, six themes, one CLI.

Install
npx -y skills add shuakami/paperchart

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Generate clean, calm chart PNGs in the spirit of Anthropic and OpenAI blog posts. Trigger when the user asks to produce a chart, model comparison table, diagram or infographic for a technical blog post, release notes, a research write-up or a slide deck and wants a single restrained palette, minimal chrome, heavy inline labelling, and PNG output rendered from React at native resolution. The primary surface is a shell CLI named `paperchart` that takes a JSON file and writes a PNG. Thirty-two primitives covering charts (line, area, scatter, heatmap, calendar heatmap, histogram, cdf, box-plot, ranking, dumbbell, slope, waterfall, small-multiples, timeline, funnel, sankey, treemap, radar, table, stacked-bar, grouped-bar, critical-path, pack-layout, latency, bytes, recall) and Mermaid-style structural diagrams (flowchart, architecture, sequence, state-diagram, er-diagram, delivery). Six themes, layout + style overrides per chart.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

9.6 KB, as published. Nobody here has run it

paperchart

A six-primitive chart toolkit for rendering quiet, print-weight charts to PNG. The surface is a shell CLI: feed it a JSON file, get a 2×-DPR figure.

Trigger on any of: "make a chart for this blog post", "render a before / after benchmark as an image", "I need a figure for my paper / release notes / announcement", "design a minimal chart in the style of Anthropic or OpenAI research posts", "draw a binary layout / critical path / latency comparison / recall parity chart".

Do not use this skill when the user asks for an interactive dashboard, a real-time graph, or a chart with brand colours other than the paperchart palette. This skill is opinionated on purpose.

The CLI

paperchart <type> -i data.json -o out.png [--width 1600] [--dpr 2]
paperchart <type> --defaults -o out.png      # render the built-in sample

Types: table, latency, bytes, stacked-bar, grouped-bar, funnel, ranking, dumbbell, slope, line, area, small-multiples, timeline, scatter, heatmap, calendar-heatmap, histogram, box-plot, cdf, radar, treemap, sankey, waterfall, critical-path, recall, pack-layout, delivery, flowchart, architecture, sequence, state-diagram, er-diagram.

Themes: paper (warm off-white, rust), ink (near-white, black), slate (cool grey, deep blue), forest (off-white, forest green), mono (pure monochrome), dusk (dark charcoal, warm orange). Pass --theme <name> on the CLI or put "theme": "<name>" in the JSON envelope.

Invoke it with npx github:shuakami/paperchart <type> -i data.json -o out.png from any directory. On first run npm clones the repo, runs prepare to build the Vite bundle, and playwright-chromium's postinstall downloads headless Chromium once (~200 MB). Subsequent runs are near-instant.

If the skill has already been installed via npx skills add shuakami/paperchart, the full repo is available under .claude/skills/paperchart/ (or .agents/skills/paperchart/ on non-Claude agents). You can also just cd there and node bin/paperchart.mjs <type> -i data.json -o out.png.

Authoring recipe

When the user asks for a chart:

  1. Pick the primitive whose shape fits the data. One primitive per figure. If none fit, decline and explain why — do not invent a new chart kind inline.
  2. Write the JSON file with the shape documented below for that primitive. Keep captions short — 6 to 12 words. Use the accent colour on exactly one row / segment / panel. Leave the rest neutral.
  3. Run the CLI. Show the user the output path. If they want to iterate, edit the JSON and re-run — the file is the single source of truth.
  4. Never embed chart titles inside the chart. Titles belong in the blog prose next to the image.

The input envelope

Every chart accepts the same shape:

{
  "theme": "ink",
  "layout": { "width": 1800, "fontScale": 1.05, "xAxisCaption": "..." },
  "style": { "accent": "#1f6feb" },
  "data": <chart-specific payload>
}

theme, layout, and style are optional. If you pass just data (or wrap your data as a bare array), the chart uses good defaults.

Primitive schemas

Short form. Full schemas are in the project README and in the per-type skills/<type>/SKILL.md files.

  • table{ columns: [{ key, label, align?, unit?, group? }], rows: [{ label, caption?, highlight?, values: { [key]: number | string } }] }. Model / config / product comparison. Exactly one highlight: true row.
  • latencyRow[]. Each row: { group, caption, color, bars: [{ level, ms }] }.
  • bytesRow[]. Each row: { group, caption, accent, segments: [{ kb, fill, tag }], firstLoadKB, deferredKB }.
  • stacked-barRow[] where each row is { label, caption?, segments: [{ key, value, color? }] }. Composition per row.
  • grouped-bar{ series: [{ key, label, color? }], groups: [{ label, caption?, values: { [key]: number } }] }.
  • rankingRow[]. Each row: { label, caption?, value, accent? }. Sorted leaderboard, one accented row.
  • dumbbellRow[]. Each row: { label, before, after }.
  • slope{ startLabel, endLabel, unit?, series: [{ label, start, end, accent? }] }.
  • line{ xLabels, series: [{ label, values, accent? }] }.
  • area{ xLabels, series: [{ label, values }] } (stacked).
  • small-multiples{ xLabels?, unit?, panels: [{ label, caption?, values, accent? }] }.
  • scatterPoint[] with optional regression line.
  • heatmap{ rowLabels, colLabels, values: number[][] }.
  • histogram{ bins: [{ x0, x1, count }] }.
  • cdf{ points: [{ value, cumulative }] }.
  • waterfall{ steps: [{ label, delta, subtotal? }] }.
  • timelineRow[] where each row is { label, caption?, spans: [{ start, end, label, accent? }], milestones?: [{ at, label }] }.
  • funnelStage[]. Each stage: { label, caption?, count, accent? }. Drop-off auto-computed between stages.
  • sankey{ sources: Node[], targets: Node[], flows: [{ from, to, value }] }. Two-column flow diagram.
  • treemapItem[] where each item is { label, value, caption?, accent?, children?: [{ label, value }] }. Two-level squarified.
  • radar{ axes: [{ key, label, caption?, max? }], series: [{ label, caption?, accent?, values: { [axisKey]: number } }] }.
  • box-plotRow[]. Each row: { label, caption?, min, q1, median, q3, max, outliers?, accent? }.
  • calendar-heatmap{ start?: "YYYY-MM-DD", days: [{ date, value }] } or just [{ date, value }].
  • critical-pathRow[]. Each row: { label, detail, startMs, endMs, kb, critical: boolean }.
  • recallQuery[]. Each query: { query, hits, sets: "equal" }.
  • pack-layoutSegment[]. Each segment: { label, detail, bytes, accent: boolean }.
  • delivery{ header, subheader, panels: PanelSpec[] } with up to 3 panels.
  • flowchart{ direction?: "TD" | "LR", nodes: [{ id, label, caption?, shape?: "rect" | "round" | "stadium" | "diamond" | "cylinder", accent? }], edges: [{ from, to, label?, dashed?, accent? }] }. Layered DAG, back-edges detected and drawn as loop-backs.
  • architecture{ groups: [{ id, label, caption?, services: [{ id, label, caption?, accent? }] }], connections: [{ from, to, label?, dashed?, accent?, bidirectional? }] }. Groups stack left-to-right; services stack top-to-bottom inside each group.
  • sequence{ actors: [{ id, label, caption? }], steps: [{ kind: "msg", from, to, label?, reply?, async?, accent? } | { kind: "note", over: id | [id, id], text }] }. Time flows downward.
  • state-diagram{ direction?: "TD" | "LR", states: [{ id, label, caption?, start?, end?, accent? }], transitions: [{ from, to, label?, dashed?, accent? }] }. Start / end pseudostates render as • / ⦾.
  • er-diagram{ entities: [{ id, label, caption?, accent?, fields: [{ name, type?, pk?, fk?, note? }] }], relationships: [{ from, to, fromCard, toCard, label?, accent? }] } where cardinality codes are "1", "0..1", "M", "1..M", "0..M".

The palette — five values only

rolehex
page / card background#F6F1EA
accent (one element per chart)#C75F3C
secondary neutral#D6B99B
ink#2B2A27
rule / hairline#E6DCCE

No gradients, no shadows, no rounded corners, no emojis.

Typography

Inter, weights 400 / 500 / 600, sizes 13 to 26 px. Tabular numerals for any numeric value. Group title: 22 px / 600. Caption: 14 px / 400 at 62 % opacity. Axis caption: 15 px / 400 at 62 % opacity. Inline value: 16–17 px / 500.

Composition rules

  1. No chart titles. The blog prose explains what the chart shows.
  2. Inline labels over legends. Put axis names on the axis, group names next to groups, values next to bars.
  3. Single accent. Only one colour stands out.
  4. Generous whitespace. Give every row at least 200 px vertical room if it has a caption beneath the group name.
  5. Native-size PNG. Never ask the user to scale the chart down in the final layout — fonts get compressed horizontally and everything looks cheap.

Deeper customisation

If the user needs something the CLI does not cover (different sizes, extra annotations, a different accent placement), point them at the repository. Every chart lives in its own file under src/charts/ with the default data array at the top; edit, save, run npm run snap.

Repository

https://github.com/shuakami/paperchart

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.