AI-native
How a model writes microcharts — the stream grammar, prompt recipes, integration paths, the MCP server, and the machine-readable docs surfaces (llms.txt, catalog.json, Markdown mirrors).
A model can draw a chart mid-sentence. Two properties make that work: every microchart renders from plain data, and
every chart carries a generated, human-readable summary — the same sentence a screen reader speaks, a crawler indexes,
and a model can quote back. A few tokens of text become a real, accessible chart.
This is a live render, not a video: a scripted reply streams in, and the chart syntax it emits becomes shipped microcharts the instant each fence closes. Everything below is the contract behind it.
The same components live in a product UI, a rendered report, and inline in docs like these. This page is the model-facing contract; Where they live shows the rest.
The grammar
A model emits a chart in one of two forms, both forgiving enough to produce reliably mid-stream. Pick a type and a form to see what it writes, what it renders, and the React it's equivalent to:
```microchart sparkline 132 148 141 165 159 182 176 203 ```
<Sparkline
data={[132, 148, 141, 165, 159, 182, 176, 203]}
title="Revenue"
/>The body is whitespace- or comma-separated numbers for series charts, or key=value pairs for composites. These five
cover the questions an assistant answers most — trend, magnitude, change, attainment, cadence — and the same pattern
extends to any chart in the catalog: name a type, pick a body convention, map it to that chart's import.
Wire it up
Turning the grammar into components is a parser and a switch — no framework, a few lines.
Parse the stream
Pull fenced blocks and inline spans out of partially-streamed Markdown. A fence that hasn't closed yet stays raw, then morphs the moment it does.
const FENCE = /```microchart (\w+)\n([\s\S]*?)```/g;const INLINE = /`microchart (\w+) ([^`]+)`/g;const nums = (b: string) => b.split(/[\s,]+/).map(Number).filter(Number.isFinite);const kv = (b: string) => Object.fromEntries( b.split(/\s+/).flatMap((t) => { const i = t.indexOf("="); return i > 0 ? [[t.slice(0, i), t.slice(i + 1)]] : []; }), );Map type → component
One switch. Because geometry is pure and charts render from data alone, the model's chart is identical to one you'd
write by hand.
import { Sparkline } from "@microcharts/react/sparkline";import { SparkBar } from "@microcharts/react/sparkbar";import { Delta } from "@microcharts/react/delta";import { Bullet } from "@microcharts/react/bullet";import { ActivityGrid } from "@microcharts/react/activity-grid";export function ChartBlock({ type, body }: { type: string; body: string }) { switch (type) { case "sparkline": return <Sparkline data={nums(body)} title="Series" />; case "sparkbar": return <SparkBar data={nums(body)} title="Per period" />; case "delta": return <Delta value={Number(body.trim())} title="Change" />; case "bullet": { const p = kv(body); return ( <Bullet value={+p.value} target={p.target ? +p.target : undefined} bands={p.bands?.split(",").map(Number)} title="Attainment" /> ); } case "activity": return <ActivityGrid data={nums(body)} layout="strip" title="Cadence" />; default: return null; // unknown type → leave the text as-is }}Render inline vs block
An inline chart is decorative — the sentence describes it, so pass summary={false}. A standalone chart keeps its
summary; give it a title.
Wrap every inline SVG mark in className="mc-inline" — the class ships in @microcharts/react/styles.css (imported
once in the Quickstart). It seats the mark on the text baseline, so it rides the line like a word in any font. Leave
Delta bare; it is a text metric and owns its own baseline.
NVDA closed +3.8%{" "}
<span className="mc-inline">
<TrendArrow value={0.038} summary={false} />
</span>{" "}
on the session — up <Delta value={0.038} summary={false} /> week over week.Prompt the model
A few lines teach the grammar. Start with the technique that matches how your model is driven — structured output and tool calls first, since that's how most agents run today:
The default for anything production. Have the model return JSON and map it yourself — no parsing of prose. Constrain
type to an enum and the output is always renderable.
type ChartSpec = | { type: "sparkline" | "sparkbar" | "activity"; data: number[]; title?: string } | { type: "delta"; value: number; title?: string } | { type: "bullet"; value: number; target?: number; bands?: number[]; title?: string };// model returns ChartSpec (JSON mode / response_format) → render directlyfunction Chart(spec: ChartSpec) { switch (spec.type) { case "sparkline": return <Sparkline data={spec.data} title={spec.title} />; case "bullet": return <Bullet {...spec} />; // …one arm per type }}Where it runs
A chart is plain text and JSON, so anything that reads or writes text can emit one and render it back — no SDK, no bridge. That spans the chat assistants that answer in prose, the coding agents and IDEs that scaffold the components from the typed catalog, and the frameworks and SDKs that wire tool-call output straight to charts. None of these needed an integration; the output is text.
- Claude
- ChatGPT
- Gemini
- Grok
- DeepSeek
- Kimi
- Meta AI
- Mistral
- Perplexity
- Qwen
- Poe
- Cursor
- Claude Code
- Codex
- v0
- opencode
- Antigravity
- Windsurf
- Zed
- Cline
- Replit
- Continue
- Warp
- Amp
- Roo Code
- StackBlitz
- JetBrains AI
- Pi
- Copilot
- Vercel AI SDK
- OpenAI Agents
- LangChain
- Anthropic SDK
- Hugging Face
- Ollama
- Pydantic AI
- CrewAI
Integration scenarios
Every path from model output to a rendered chart, with the one thing each needs.
The MCP server
Everything above is a model emitting a chart into a surface you control, where your code maps a block to a component. Sometimes there is no such surface — a desktop assistant's reply, a terminal, a draft email. There, the model needs the finished mark.
@microcharts/mcp is a Model Context Protocol server, run over stdio on your own machine, that gives an
assistant three tools: find the chart type that answers a question, get its exact props and a valid sample,
render it to a self-contained SVG with the real generated alt text attached. This library does the rendering, so
what comes back is the same mark the component would produce.
Point any MCP client at it — Claude Desktop, Claude Code, Cursor, VS Code — with the config it already understands:
{ "mcpServers": { "microcharts": { "command": "npx", "args": ["-y", "@microcharts/mcp"] } }}The same three capabilities also ship as Vercel AI SDK tools, for an assistant you're building yourself. See MCP server for the tool reference, the per-client setup, and what each call returns.
Machine-readable surfaces
These routes are generated from the same source as the package, so an agent reads the current API instead of guessing:
The .md mirrors are static files — /docs/ai has a sibling /docs/ai.md — so they resolve on any host with no
runtime, rewrite, or middleware. This site also deploys behind a small Cloudflare Worker that runs on /docs/* only:
send Accept: text/markdown and the same doc URL returns the mirror inline, with Vary: Accept on both the Markdown
and the HTML response. Appending .md always works; the negotiation is a convenience on top.
/llms.txt points at one more surface the cards don't: /agent-setup.md, the paste-and-run setup
prompt for a coding agent, extracted from the Quickstart so the two can't drift. Or skip the URL
entirely:
The agent cheat sheet
Don't make a model memorize the catalog — All charts files every type by the question it answers, and the Charts index shows them at a glance. Everything an agent needs to emit correct microcharts fits on one card. Copy it straight into a system prompt:
- →Import each chart from its own subpath —
@microcharts/react/<name>; add/interactiveonly for hover and keyboard. - →Static charts are hook-free — valid inside a React Server Component, zero client JavaScript.
- →Pass
dataand atitle; the generated summary handles accessibility. Usesummary={false}only when a chart is decorative inside describing text. - →Never add a runtime dependency, and never reach for a pie or gauge — they aren't shipped.
For more, point an assistant at /llms.txt, the fuller /llms-full.txt, or the
machine-readable /catalog.json — or start from the Quickstart and render your
first chart.
Quickstart
Install @microcharts/react — the React sparkline and microchart library. Import styles once, render an accessible SVG chart in a Server Component or add /interactive for hover and keyboard.
All charts
The full microcharts catalog — every shipped chart at word size, grouped by the question its collection answers, each linking to a live page.