Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/public-chart-json.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@tanstack/charts': minor
---

Add the fixed first-party Chart JSON interchange format, its `chartFromJson`
interpreter, SemVer compatibility, published schema, and editable workbench.
79 changes: 77 additions & 2 deletions API-FRICTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ Each entry records:
| F-290 | Public examples imported a private workspace package | Tooling | resolved |
| F-291 | Renderer capability injection depended on module identity | API/Tooling | resolved |
| F-292 | Fixed preview paints ignored the selected site theme | Tooling | resolved |
| F-293 | Portable calls did not match live constructor semantics | API/Docs/Tooling | resolved |

## Findings

Expand Down Expand Up @@ -3557,8 +3558,10 @@ Each entry records:
deterministic SHA-256 allowlist, safe repository source paths, recursive
imports, debug-only comparison roots, and role-aware authored-source
closures. Focused tests reject unsafe paths, unreferenced assets, public
comparison modules, and inconsistent source totals, roles, or paths. The
loading gate checks every TanStack root's static closure for reference cases
comparison modules, and inconsistent source totals, roles, or paths.
Imported authored JSON participates in the same closure while `case.json`
metadata stays excluded. The loading gate checks every TanStack root's
static closure for reference cases
or competitor packages and proves raw source remains lazy and unpublished.
Main-branch CI uploads the validated artifact and publishes only
`catalog.json` and `assets/*.js` to `catalog-dist`. The publication workflow
Expand Down Expand Up @@ -8429,3 +8432,75 @@ Each entry records:
- Follow-up verification: the generator contract covers all four tokens in both
palettes, and regenerated ShadCN donut, radial, radar, and authored-label
previews render readable dark text and theme-matched separators.

### F-293 — Portable calls did not match live constructor semantics

- Status: resolved
- Severity: high
- Owner: API/Documentation/Tooling
- Observed in: implementing the first-party JSON interchange format
- Friction: the design note serialized public JavaScript calls directly. Its
scale examples invoked factories with unsupported option objects, turned an
inferable scale factory into a configured empty instance, placed tick
formatting on a removed property, and proposed a separate adapter `data`
prop after definition identity had become the application update boundary.
Callback-bearing marks, transforms, and host extensions also had no stable
language-neutral meaning.
- Breadth friction: implementing every callback-free Charts operation produced
292 built-in capabilities, 18 JSON subpaths, 8,041 lines of production JSON
source, 2,715 test lines, and 1,106 lines of canonical documentation. The
result was a second complete Charts API rather than a bounded interchange
profile. Runtime JSON Schema interpretation, separate inspection,
validation, and compilation traversals, two demo systems, and overlapping
manuals amplified that breadth.
- Intermediate friction: reducing the catalog to 42 standard operations and
two DOM operations still left 4,863 production lines, 1,348 test lines,
three entrypoints, two envelopes, four expression forms, a capability author
API, a contract algebra, policy and inspection surfaces, and 473 lines of
canonical documentation. The platform remained much larger than the common
charts it needed to transport.
- Final decision: ship one fixed first-party dialect rather than an extension
platform. Its 16 operations cover eight Cartesian marks, including
full-plot rules and positioned text annotations, one compound pie/donut
mark, four inferable scales, ISO-date access, grouped intervals, and a
categorical color legend. Publish only `@tanstack/charts/json`.
Specialized transforms, callbacks, tooltips, interactions, configured
scales, and other chart families remain host code until a demonstrated
interchange requirement justifies extending the dialect.
- Wire decision: use one closed envelope with `chartsVersion`, `spec`, optional
`data`, optional accessible `metadata`, and optional `$schema`. `$data`
references a named dataset only in a mark's `data` field. `$call` invokes one
fixed operation with named arguments as sibling properties. Remove `kind`,
`inputs`, `options`, `$ref`, `$context`, and the nested `args` object. Host
datasets replace bundled defaults by name.
- Runtime decision: `chartFromJson(jsonText, { data, exactVersion })` parses,
validates, translates, and returns an ordinary static definition in one
call. It throws `ChartJsonError` with stable issues. Remove registries,
capability constructors, policies, inspection, catalogs, executable schema
contracts, compile/bind programs, host generics, and custom compatibility
callbacks. The runtime and published schema share the same internal fixed
operation descriptors; the schema itself is the complete model contract.
- Version decision: release synchronization keeps the dialect in lockstep with
`@tanstack/charts`; `0.15.0` is the immutable first published dialect.
- Schema verification deep-compares the runtime `chartJsonSchema` with the sole
published `schemas/chart.json`, locks all 16 operation branches,
keeps the chart spec closed, and executes the sole bundled example through
scene creation. Release and packed-package gates require both assets.
- Runtime verification covers direct-scene parity, bundled arrays, host
iterable overrides, metadata, exact and backward SemVer behavior, every
retained operation, role placement, unknown calls and arguments, obsolete
grammar, missing data, hostile result shapes, and direct DOM/native-compatible
static typing. Root TypeScript and the focused JSON suite pass.
- Demo verification uses one editable React workbench with bar, donut, and
annotation sources. Apply and Reset preserve the last valid preview after
structured errors; Replace data reruns the same source with a host override.
Component tests, the production build, and desktop and 390-pixel browser
checks cover exact bar, arc, vertical-rule, horizontal-rule, and text-label
geometry, accessible naming, live status, invalid edits, overflow, and
console errors.
- Reduction verification: production JSON source is 1,612 lines across eight
files, down 67% from the pared platform and 80% from the 8,041-line breadth
spike. Tests are 1,029 lines across two files, down 24% from the pared
platform and 62% from the breadth spike.
The public surface is four runtime values, six types, one entrypoint, one
schema, one fixture, one 233-line canonical page, and one demo.
10 changes: 5 additions & 5 deletions MARKETING.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ registry or side-effectful feature installation.
| [Chart.js](https://www.chartjs.org/) and [Apache ECharts](https://echarts.apache.org/en/index.html) | Broad catalogs and Canvas-oriented rendering | Smaller in the current like-for-like consumer benchmark, SVG by default with opt-in Canvas, composable, and designed for product-specific charts |
| [uPlot](https://github.com/leeoniya/uPlot), [Chartist](https://chartist.dev/), [Frappe Charts](https://github.com/frappe/charts), and [Lightweight Charts](https://github.com/tradingview/lightweight-charts) | Deliberately small or specialized charting surfaces | Competitive in the small-bundle class with a broader grammar; TanStack should claim capability-scaled size, not absolute size leadership |
| [AG Charts](https://www.ag-grid.com/charts/) | Enterprise breadth, specialized charts, dense data, controls, and support | Open grammar, D3 interoperability, actual SVG SSR, heterogeneous layers, and no global registry |
| [Vega and Vega-Lite](https://vega.github.io/) | Portable declarative specifications and analysis tooling | Ordinary TypeScript and application integration instead of a JSON visualization runtime |
| [Vega and Vega-Lite](https://vega.github.io/) | Portable declarative specifications and analysis tooling | Typed application authoring plus a small opt-in JSON dialect for common Cartesian and circular charts that translates into an ordinary definition |

### Primary comparisons

Expand Down Expand Up @@ -450,8 +450,8 @@ describe the library as designed by AI or autonomously built.
This is a transparent account of how the implementation was produced, not the
main marketing wedge. Agent-ready, task-oriented documentation remains
supporting proof. The useful product claim is that agents generate and maintain
ordinary TypeScript through the same public API as humans. Avoid generic claims
about being "AI-native."
ordinary TypeScript or first-party Chart JSON through the same public contracts
as humans. Avoid generic claims about being "AI-native."

## Objections

Expand All @@ -472,8 +472,8 @@ TanStack Charts is not currently the best choice for teams that:
chart types immediately.
- Need proven million-point streaming throughput, built-in downsampling, or a
GPU rendering pipeline.
- Want a no-code dashboard builder.
- Need a portable JSON visualization specification.
- Need a no-code dashboard, query, or refresh runtime beyond interpreting a
portable chart definition in a JavaScript host.
- Want a library to choose every scale and chart decision.
- Need commercial support, LTS, or contractual response times.
- Have three permanently standard React charts and value the shortest possible
Expand Down
6 changes: 3 additions & 3 deletions NATIVE-PLATFORM-SUPPORT-SPIKE.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ Do not freeze the current `ChartScene` as a cross-language wire format.
Compose, SwiftUI, and Flutter can consume this, but live callbacks stay in
their host language.

The proposed [`PORTABLE-CHART-SPEC.md`](./PORTABLE-CHART-SPEC.md) registry
model is the right definition-level companion. `$call` and `$data` can describe
a supported portable subset. It should never claim to serialize arbitrary
The first-party [Chart JSON interchange](./docs/reference/json-interchange.md)
is the definition-level companion. Its fixed operations cover a small portable
subset of Cartesian and circular charts. It does not serialize arbitrary
JavaScript accessors, custom tooltip components, or renderer plugins.

### Core refactor
Expand Down
10 changes: 7 additions & 3 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ concerns that Plot intentionally leaves to its host:
- Optional export and motion
- Predictable, task-oriented documentation for humans and AI

The code is the protocol. AI should generate and maintain ordinary TypeScript and JSX or TSRX rather than a JSON chart language, a proprietary DSL, or an agent-specific runtime.
Typed code remains the primary authoring protocol. The first-party Chart JSON
interchange format transports a fixed common-chart subset for AI and system
boundaries; it must translate to an ordinary definition and must not become an
extension platform, second renderer, data-reactivity model, global registry,
or agent runtime.

## Product charter

Expand Down Expand Up @@ -1477,8 +1481,8 @@ These must live behind explicit entry points or dynamic imports.

### Explicit non-goals

- A proprietary chart specification language
- A JSON visualization DSL
- A second normalized chart-type grammar that diverges from chart definitions
- Dashboard sources, queries, refresh policy, or layout inside Chart JSON
- A casually divergent clone that inherits Plot’s API surface without its
behavior or tests
- Runtime data profiling or cleaning
Expand Down
104 changes: 0 additions & 104 deletions PORTABLE-CHART-SPEC.md

This file was deleted.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ pattern.
| [`docs/concepts/scales-and-d3.md`](./docs/concepts/scales-and-d3.md) | Compact scale path and D3 upgrade boundary |
| [`docs/examples/index.md`](./docs/examples/index.md) | Curated chart-family and interaction examples |
| [`docs/guides/ai-authoring.md`](./docs/guides/ai-authoring.md) | Deterministic authoring and validation for coding agents |
| [`docs/reference/json-interchange.md`](./docs/reference/json-interchange.md) | Fixed Chart JSON schema, interpreter, and AI recipe |
| [`docs/reference/index.md`](./docs/reference/index.md) | Complete public API map |
| [`llms.txt`](./llms.txt) | Generated documentation routing index |

Expand Down
8 changes: 4 additions & 4 deletions benchmarks/comparison/bundle-baseline.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"schemaVersion": 4,
"generatedAt": "2026-08-15T07:14:39.579Z",
"generatedAt": "2026-08-20T22:44:45.775Z",
"packageVersions": {
"tanstack": "0.13.0",
"tanstack": "0.14.0",
"chartjs": "4.5.1",
"echarts": "6.1.0",
"recharts": "3.10.1",
Expand All @@ -11,8 +11,8 @@
"sources": {
"tanstack": {
"kind": "workspace",
"revision": "91e2eef1772dc06118ce5aa1e0b388d12bf91918",
"inputDigest": "sha256:07856952e86ead8b51b7517ecd2bcfd8af9fb47ff152125855b752cd51f2f94c"
"revision": "d6644db9e244ff67a43591b73d1697b3dbeaca6a",
"inputDigest": "sha256:73a57d6bc6681bbf5b12f0832bddb052b941427faf28a565b28516906d084bc4"
},
"chartjs": {
"kind": "package",
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/conformance/previews/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schemaVersion": 1,
"width": 288,
"height": 192,
"sourceHash": "136ba5c0be5fdc8fc8c7e18e0663f3ddecfc851acaf585a175f2031ad1468d32",
"sourceHash": "d8b29c81b5b55857afc9b09aba86dc6f1a456264049d5412c9f6a7c597d6c43c",
"assets": [
{
"id": "01-line-gaps",
Expand Down
6 changes: 3 additions & 3 deletions docs/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ turning untested behavior into a checkmark.

| Library | Package | Measured source |
| -------------------------------------------------------------------------------------- | -------------------- | ------------------- |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `91e2eef` |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `d6644db` |
| [Chart.js](https://www.chartjs.org/docs/latest/) | `chart.js` | npm `4.5.1` |
| [Apache ECharts](https://echarts.apache.org/handbook/en/best-practices/canvas-vs-svg/) | `echarts` | npm `6.1.0` |
| [Recharts](https://recharts.github.io/en-US/) | `recharts` | npm `3.10.1` |
| [Observable Plot](https://observablehq.com/plot/features/plots) | `@observablehq/plot` | npm `0.6.17` |

The competitor versions are exact package pins, not latest versions inferred
at page render time. The measured TanStack workspace revision is `91e2eef`.
at page render time. The measured TanStack workspace revision is `d6644db`.

## Capability matrix

Expand Down Expand Up @@ -90,7 +90,7 @@ output model.

## Bundle snapshot

Baseline date: `2026-08-15`.
Baseline date: `2026-08-20`.

Controlled ranges cover 12 independently built, minified browser consumers:
line, bar, area, and scatter at basic, interactive, and advanced tiers. Only
Expand Down
7 changes: 7 additions & 0 deletions docs/concepts/chart-definitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,10 @@ host.update({

Charts owns surface measurement, scene construction, and keyed reconciliation.
It does not own application equality or data reactivity.

## Definitions from Chart JSON

`chartFromJson()` interprets callback-free JSON as the same `ChartDefinition`
used everywhere else. Host data may replace bundled data while callbacks and
interaction remain application code. See
[Chart JSON](../reference/json-interchange.md).
4 changes: 4 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,10 @@
"label": "Chart Definition API",
"to": "reference/chart-definitions"
},
{
"label": "Chart JSON",
"to": "reference/json-interchange"
},
{
"label": "Chart Spec",
"to": "reference/chart-spec"
Expand Down
Loading