{"id":13426402,"url":"https://github.com/nteract/semiotic","last_synced_at":"2026-08-27T19:10:35.634Z","repository":{"id":23782342,"uuid":"85225460","full_name":"nteract/semiotic","owner":"nteract","description":"React data visualization library for streaming, networks, and AI-assisted development","archived":false,"fork":false,"pushed_at":"2026-08-20T03:37:39.000Z","size":150579,"stargazers_count":2691,"open_issues_count":1,"forks_count":136,"subscribers_count":41,"default_branch":"main","last_synced_at":"2026-08-20T08:45:29.213Z","etag":null,"topics":["ai","d3","data-visualization","nteract","react","streaming","visualization"],"latest_commit_sha":null,"homepage":"https://semiotic.nteract.io","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nteract.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","claude":"CLAUDE.md","gemini":null,"cursor":null,"copilot":".github/copilot-instructions.md","dco":null,"cla":null,"disclosure":null}},"created_at":"2017-03-16T17:46:24.000Z","updated_at":"2026-08-20T03:17:55.000Z","dependencies_parsed_at":"2023-02-16T16:30:44.456Z","dependency_job_id":"8367f6fd-5802-4383-b4e4-7b00a0055513","html_url":"https://github.com/nteract/semiotic","commit_stats":{"total_commits":2329,"total_committers":39,"mean_commits":"59.717948717948715","dds":"0.28595963933018465","last_synced_commit":"1bf2138b05955b75dedcc7ebb6f98d6ee96b257a"},"previous_names":[],"tags_count":224,"template":false,"template_full_name":null,"purl":"pkg:github/nteract/semiotic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nteract%2Fsemiotic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nteract%2Fsemiotic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nteract%2Fsemiotic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nteract%2Fsemiotic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nteract","download_url":"https://codeload.github.com/nteract/semiotic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nteract%2Fsemiotic/sbom","scorecard":{"id":697618,"data":{"date":"2025-08-11","repo":{"name":"github.com/nteract/semiotic","commit":"b64e5db4a6e601e5b98c882474fe5738600ee3c6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/13 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql-analysis.yml:29","Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql-analysis.yml:28","Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1","Warn: no topLevel permission defined: .github/workflows/node.js.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Security-Policy","score":9,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/nteract/semiotic/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/nteract/semiotic/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:56: update your workflow using https://app.stepsecurity.io/secureworkflow/nteract/semiotic/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:70: update your workflow using https://app.stepsecurity.io/secureworkflow/nteract/semiotic/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/nteract/semiotic/node.js.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/nteract/semiotic/node.js.yml/main?enable=pin","Warn: npmCommand not pinned by hash: scripts/create-release-branch.sh:9","Warn: npmCommand not pinned by hash: scripts/publish-release.sh:28","Warn: npmCommand not pinned by hash: .github/workflows/node.js.yml:28","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"SAST","score":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 0 commits out of 20 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"21 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-xq7p-g2vc-g82p","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-ff7x-qrg7-qggm","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-w5p7-h5w8-2hfq","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T04:11:54.446Z","repository_id":23782342,"created_at":"2025-08-22T04:11:54.446Z","updated_at":"2025-08-22T04:11:54.446Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36946609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-08-22T15:14:58.755Z","status":"online","status_checked_at":"2026-08-27T02:00:07.166Z","response_time":96,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","d3","data-visualization","nteract","react","streaming","visualization"],"created_at":"2024-07-31T00:01:33.632Z","updated_at":"2026-08-27T19:10:35.627Z","avatar_url":"https://github.com/nteract.png","language":"TypeScript","funding_links":[],"categories":["Data Visualization","JavaScript","UI Components","Charts","Uncategorized","data-visualization","TypeScript","📊 Data \u0026 Analytics"],"sub_categories":["Data Visualization","Uncategorized"],"readme":"[![MCP Toplist](https://mcptoplist.com/badge/io.github.nteract%2Fsemiotic.svg)](https://mcptoplist.com/server/io.github.nteract%2Fsemiotic)\n\n[![Semiotic](semiotic_logo_horizontal.png \"semiotic\")](https://semiotic.nteract.io)\n\n[![CI](https://github.com/nteract/semiotic/actions/workflows/node.js.yml/badge.svg?branch=main)](https://github.com/nteract/semiotic/actions/workflows/node.js.yml)\n[![npm version](https://img.shields.io/npm/v/semiotic.svg)](https://www.npmjs.com/package/semiotic)\n[![TypeScript](https://img.shields.io/badge/TypeScript-built--in-blue.svg)](https://www.typescriptlang.org/)\n[![MseeP.ai Security Assessment Badge](https://mseep.net/pr/nteract-semiotic-badge.png)](https://mseep.ai/app/nteract-semiotic)\n\nA React data visualization library designed for AI-assisted development.\n\nSimple charts in 5 lines. Network graphs, streaming data, and coordinated\ndashboards when you need them. Structured schemas and an MCP server so\nAI coding assistants generate correct chart code on the first try.\n\n\u003c!-- semiotic-readme-dashboard:start --\u003e\n\u003cimg src=\"./docs/public/assets/img/semiotic-release-dashboard.svg\" alt=\"Semiotic release dashboard showing chart count, bundle sizes, capability coverage, chart families, and documentation growth\" width=\"100%\"\u003e\n\u003c!-- semiotic-readme-dashboard:end --\u003e\n\n## What's New in 3.9.1\n\n3.9.1 is a focused patch release. It removes the webpack “conflicting star\nexports” warning emitted by `semiotic/utils`, while keeping every existing\nutility—including `resolveResponsiveDimension` and `useResponsiveSize`—available\nfrom the same public entry point.\n\n## Why Semiotic\n\nSemiotic is a data visualization library for React that combines broad chart\ncoverage with first-class AI tooling. It handles the chart types that most\nlibraries skip — network graphs, streaming data, statistical distributions,\ncoordinated views — and ships with machine-readable schemas so LLMs can\ngenerate correct code without examples.\n\n### Built for AI-assisted development\n\nSemiotic ships with everything an AI coding assistant needs to generate\ncorrect visualizations without trial and error:\n\n- **`semiotic/ai`** — a single import with the schema-backed chart capability catalog (XY, ordinal, network, realtime, geo, value, and portable recipes), optimized for LLM code generation. See `ai/surface-manifest.json` for the generated current inventory. Note: the published entry files are pre-bundled, so importing one chart from `semiotic/ai` still ships most of the bundle — treat it as a codegen/tooling surface and use family subpaths (`semiotic/xy`, `semiotic/geo`, `semiotic/value`, …) in production code, at roughly half the single-chart cost.\n- **`ai/schema.json`** — machine-readable prop schemas for every component\n- **`npx semiotic-mcp`** — an MCP server for tool-based chart rendering in any MCP client\n- **`npx semiotic-ai --doctor`** — validate component + props JSON from the command line with typo suggestions and anti-pattern detection\n- **`diagnoseConfig(component, props)`** — programmatic anti-pattern detector with actionable fixes, spanning validation, encoding, accessibility, and misleading-design (deception) checks\n- **`auditData(component, props, data?)`** — chart-aware numeric preflight for inputs that pass schema validation but break the math: non-finite values, zero-span domains, invalid log inputs, negative size geometry, unsafe normalized totals, and scale-dominating outliers. Returns bounded row evidence and flows into `diagnoseConfig`, Chart Clinic, CLI doctor, and opt-in `ChartContainer` notifications\n- **`AGENTS.md`** — concise repository workflow shared by modern coding agents;\n  `CLAUDE.md` imports it and Copilot receives a short compatibility bridge\n- **`ai/reference.md`** — complete on-demand product reference, kept out of\n  always-loaded coding-agent context\n- **`llms.txt`** — machine-readable documentation following the emerging standard\n\nEvery chart includes a built-in error boundary, dev-mode validation\nwarnings with typo suggestions, and accessibility features (canvas\n`aria-label`, keyboard-navigable legends, `aria-live` tooltips, SVG\n`\u003ctitle\u003e`/`\u003cdesc\u003e`) so AI-generated code fails gracefully with\nactionable diagnostics instead of a blank screen.\n\n### Accessibility is a release surface\n\nThe [European Accessibility Act](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=legissum%3A4403933)\nhas applied to covered products and services since 28 June 2025. A chart\nlibrary cannot certify an application's legal compliance: scope, content,\nsurrounding controls, testing, and national enforcement remain the\napplication owner's responsibility. Semiotic supplies testable infrastructure\nfor that work: keyboard interaction, accessible data tables, layered\ndescriptions, structured navigation, reduced-motion and forced-colors paths,\nand WCAG-derived contrast tests for shipped theme presets. See the\n[Accessibility docs](https://semiotic.nteract.io/accessibility/overview) and\nrun the application's own assistive-technology and user testing.\n\n### Beyond standard charts\n\n**Network visualization.** Force-directed graphs, Sankey diagrams, chord\ndiagrams, tree layouts, treemaps, circle packing, and orbit diagrams — all\nas React components with the same prop API as LineChart.\n\n**Streaming data.** Realtime charts render on canvas at 60fps with a\nref-based push API. Rapid network edge pushes coalesce into one layout per\nanimation frame, while read/mutation methods preserve synchronous read-after-write\nsemantics. Built-in decay, pulse, and staleness encoding for monitoring dashboards.\n\n**Coordinated views.** `LinkedCharts` provides hover cross-highlighting,\nbrush cross-filtering, coordinate-based linked crosshairs, and selection\nsynchronization across any combination of chart types through shared selection state.\n\n**Geographic visualization.** Choropleth maps, proportional symbol maps, flow\nmaps with animated particles, and distance cartograms — all canvas-rendered\nwith d3-geo projections, zoom/pan, tile basemaps, and drag-rotate globe spinning.\n\n**Statistical summaries.** Box plots, violin plots, swarm plots, histograms,\nLOESS smoothing, forecast with confidence envelopes, and anomaly detection.\nMarginal distribution graphics on scatterplot axes with a single prop.\n\n**First-class annotations.** Annotations are data-bound objects, not post-hoc\nartwork. Labels, callouts, thresholds, enclosures, statistical overlays, and\nReact widgets move with the chart and render through browser, SSR, and export\npaths. Opt into placement, hierarchy, density, progressive disclosure,\naudience-aware amount, provenance, and editorial lifecycle when the chart\nneeds to communicate more than its encoding alone.\n\n### Choose the API layer\n\n| Layer | For | Example |\n|---|---|---|\n| **Charts** | Common chart forms with chart-level props | `\u003cLineChart data={d} xAccessor=\"x\" yAccessor=\"y\" /\u003e` |\n| **Frames** | Full control over rendering, interaction, and layout | `\u003cStreamXYFrame chartType=\"line\" lineStyle={...} /\u003e` |\n\nChart HOCs register only the mark plugins they need. Direct `StreamXYFrame`\nloads the remaining built-ins on first client paint. Call\n`registerBuiltInXYPlugins()` from `semiotic/xy` or `semiotic/realtime/core`\nbefore the first render when SSR or the first frame must include marks.\n\nEvery Chart component accepts a `frameProps` prop to access the underlying\nFrame API without leaving the simpler interface.\n\n### Serialization and interop\n\nCharts serialize to JSON and back: `toConfig`, `fromConfig`, `toURL`,\n`copyConfig`, `configToJSX`. Have Vega-Lite specs? `fromVegaLite(spec)`\ntranslates them to Semiotic configs — works with `configToJSX()` for\nfull round-trip from notebooks and AI-generated specs.\n\nNeed an external pitfall review? The experimental `unstable_toDataPitfallsChain()` builds a\ndependency-free chain input for [`datapitfalls`](https://github.com/bjonesdataliteracy/datapitfalls),\ncombining the Semiotic config, JSX, reader grounding, diagnostics,\naccessibility audit, and optional rendered SVG/image evidence:\n\n```ts\nimport { unstable_toDataPitfallsChain } from \"semiotic/experimental\"\nimport { detectPitfalls } from \"datapitfalls\"\n\nconst input = unstable_toDataPitfallsChain(\"LineChart\", props, {\n  narrative: \"Monthly sales are accelerating.\",\n  rendered: { svg, evidence },\n})\n\nconst report = await detectPitfalls(input, { apiKey: process.env.ANTHROPIC_API_KEY })\n```\n\nThe return path stays dependency-free too. Use whole-chart findings as\n`ChartContainer` notifications, and only turn findings into annotations after\nyour app can anchor them to marks or semantic positions:\n\n```tsx\nimport { ChartContainer } from \"semiotic\"\nimport { LineChart } from \"semiotic/xy\"\nimport {\n  unstable_toDataPitfallsAnnotations,\n  unstable_toDataPitfallsNotifications,\n} from \"semiotic/experimental\"\n\nconst notifications = unstable_toDataPitfallsNotifications(report)\nconst annotations = unstable_toDataPitfallsAnnotations(report, {\n  anchorFor: (finding) =\u003e\n    finding.ruleId === \"truncated-axis\" ? { x: 9, y: 9000 } : null,\n})\n\n\u003cChartContainer notifications={notifications}\u003e\n  \u003cLineChart {...props} annotations={annotations} /\u003e\n\u003c/ChartContainer\u003e\n```\n\n### When to use something else\n\nNeed a standard bar or line chart for a dashboard you'll never need to\ncustomize beyond colors and labels? [Recharts](https://recharts.org) has a\nlarger ecosystem and more community examples. Need GPU-accelerated rendering\nfor millions of data points? [Apache ECharts](https://echarts.apache.org)\nhandles that scale.\n\nSemiotic is for projects that outgrow those libraries — when you need\nnetwork graphs alongside time series, streaming data alongside static\nsnapshots, or coordinated views across chart types.\n\n## Install\n\n```bash\nnpm install semiotic\n```\n\nRequires React 18.1+ or React 19.\n\n## Quick Examples\n\n### Coordinated Dashboard\n\nHover one chart and highlight the same data in another through a shared selection:\n\n```jsx\nimport { LinkedCharts, Scatterplot, BarChart } from \"semiotic\"\n\n\u003cLinkedCharts\u003e\n  \u003cScatterplot\n    data={data} xAccessor=\"age\" yAccessor=\"income\" colorBy=\"region\"\n    linkedHover={{ name: \"hl\", fields: [\"region\"] }}\n    selection={{ name: \"hl\" }}\n  /\u003e\n  \u003cBarChart\n    data={summary} categoryAccessor=\"region\" valueAccessor=\"total\"\n    selection={{ name: \"hl\" }}\n  /\u003e\n\u003c/LinkedCharts\u003e\n```\n\n### Streaming Metrics with Decay\n\nLive data fades old points, flashes new ones, flags stale feeds:\n\n```jsx\nimport { RealtimeLineChart } from \"semiotic\"\n\nconst chartRef = useRef()\nchartRef.current.push({ time: Date.now(), value: cpuLoad })\n\n\u003cRealtimeLineChart\n  ref={chartRef}\n  timeAccessor=\"time\"\n  valueAccessor=\"value\"\n  decay={{ type: \"exponential\", halfLife: 100 }}\n  staleness={{ threshold: 5000, showBadge: true }}\n/\u003e\n```\n\n### Network Graphs\n\nForce-directed graphs and Sankey diagrams — same API as LineChart:\n\n```jsx\nimport { ForceDirectedGraph, SankeyDiagram } from \"semiotic\"\n\n\u003cForceDirectedGraph\n  nodes={people} edges={friendships}\n  colorBy=\"team\" nodeSize={8} showLabels\n/\u003e\n\n\u003cSankeyDiagram\n  edges={budgetFlows}\n  sourceAccessor=\"from\" targetAccessor=\"to\" valueAccessor=\"amount\"\n/\u003e\n```\n\n### Geographic Visualization\n\nChoropleth maps, flow maps, and distance cartograms with canvas rendering,\nzoom/pan, tile basemaps, and animated particles:\n\n```jsx\nimport { ChoroplethMap, FlowMap, DistanceCartogram } from \"semiotic/geo\"\n\n\u003cChoroplethMap\n  areas={geoJsonFeatures} valueAccessor=\"gdp\"\n  colorScheme=\"viridis\" projection=\"equalEarth\" zoomable tooltip\n/\u003e\n\n\u003cFlowMap\n  nodes={airports} flows={routes} valueAccessor=\"passengers\"\n  showParticles particleStyle={{ color: \"source\", speedMultiplier: 1.5 }}\n/\u003e\n\n\u003cDistanceCartogram\n  points={cities} center=\"rome\" costAccessor=\"travelDays\"\n  showRings costLabel=\"days\" lines={routes}\n/\u003e\n```\n\n### Streaming System Monitor\n\nLive service topology with threshold alerting and click-to-inspect:\n\n```jsx\nimport { StreamNetworkFrame, ChartContainer, DetailsPanel, LinkedCharts } from \"semiotic\"\n\nconst chartRef = useRef()\nchartRef.current.push({ source: \"API\", target: \"Orders\", value: 15 })\n\n\u003cLinkedCharts\u003e\n  \u003cChartContainer title=\"System Monitor\" status=\"live\"\n    detailsPanel={\n      \u003cDetailsPanel position=\"right\" trigger=\"click\"\u003e\n        {(datum) =\u003e \u003cdiv\u003e{datum.id}: {datum.value} req/s\u003c/div\u003e}\n      \u003c/DetailsPanel\u003e\n    }\u003e\n    \u003cStreamNetworkFrame ref={chartRef} chartType=\"sankey\"\n      showParticles particleStyle={{ proportionalSpeed: true }}\n      thresholds={{ metric: n =\u003e n.value, warning: 100, critical: 250 }}\n    /\u003e\n  \u003c/ChartContainer\u003e\n\u003c/LinkedCharts\u003e\n```\n\n### Standard Charts\n\nLine, bar, scatter, and area charts share the same accessor-driven API:\n\n```jsx\nimport { LineChart, BarChart } from \"semiotic\"\n\n\u003cLineChart\n  data={salesData}\n  xAccessor=\"month\" yAccessor=\"revenue\"\n  curve=\"monotoneX\" showPoints\n/\u003e\n\n\u003cBarChart\n  data={categoryData}\n  categoryAccessor=\"department\" valueAccessor=\"sales\"\n  orientation=\"horizontal\" colorBy=\"region\"\n/\u003e\n```\n\n## All Chart Components\n\n| Category | Components |\n|---|---|\n| **XY** | `LineChart` `AreaChart` `DifferenceChart` `StackedAreaChart` `Scatterplot` `ConnectedScatterplot` `BubbleChart` `Heatmap` `QuadrantChart` `MultiAxisLineChart` `MinimapChart` `CandlestickChart` `ScatterplotMatrix` |\n| **Categorical** | `BarChart` `StackedBarChart` `GroupedBarChart` `LikertChart` `SwimlaneChart` `FunnelChart` `SwarmPlot` `BoxPlot` `Histogram` `ViolinPlot` `RidgelinePlot` `DotPlot` `PieChart` `DonutChart` `GaugeChart` |\n| **Network** | `ForceDirectedGraph` `ChordDiagram` `SankeyDiagram` `ProcessSankey` `TreeDiagram` `Treemap` `CirclePack` `OrbitDiagram` |\n| **Geo** | `ChoroplethMap` `ProportionalSymbolMap` `FlowMap` `DistanceCartogram` |\n| **Realtime** | `RealtimeLineChart` `RealtimeHistogram` `RealtimeSwarmChart` `RealtimeWaterfallChart` `RealtimeHeatmap` |\n| **Coordination** | `LinkedCharts` |\n| **Layout** | `ChartGrid` `ContextLayout` `CategoryColorProvider` |\n| **Frames** | `StreamXYFrame` `StreamOrdinalFrame` `StreamNetworkFrame` `StreamGeoFrame` |\n\n### Vega-Lite Translation\n\nPaste a Vega-Lite spec, get a Semiotic chart:\n\n```jsx\nimport { fromVegaLite } from \"semiotic/data\"\nimport { configToJSX, fromConfig } from \"semiotic\"\n\nconst config = fromVegaLite({\n  mark: \"bar\",\n  data: { values: [{ a: \"A\", b: 28 }, { a: \"B\", b: 55 }] },\n  encoding: {\n    x: { field: \"a\", type: \"nominal\" },\n    y: { field: \"b\", type: \"quantitative\" },\n  },\n})\n\n// Render directly\nconst { componentName, props } = fromConfig(config)\n// → componentName: \"BarChart\", props: { data, categoryAccessor: \"a\", valueAccessor: \"b\" }\n\n// Or generate JSX code\nconfigToJSX(config)\n// → \u003cBarChart data={[...]} categoryAccessor=\"a\" valueAccessor=\"b\" /\u003e\n```\n\nSupports bar, line, area, point, rect, arc, tick marks with encoding translation\nfor color, size, aggregation, and binning.\n\n### Conversation Arc Telemetry\n\nCapture and replay the path an AI-assisted chart session took:\n\n```ts\nimport {\n  createLocalStorageConversationArcSink,\n  enableConversationArc,\n  getConversationArcStore,\n  loadConversationArc,\n  registerConversationArcSink,\n} from \"semiotic/ai\"\n\nconst sink = createLocalStorageConversationArcSink({ key: \"my-app:arc\" })\nregisterConversationArcSink(sink)\nenableConversationArc({ sessionId: \"session-abc\" })\n\ngetConversationArcStore().record({ type: \"chart-rendered\", component: \"LineChart\" })\nloadConversationArc(sink.load(), { enabled: false })\n```\n\n## Bundle Sizes\n\nSemiotic ships 32 stable JavaScript entry points (31 subpaths plus the root). **Don't import from `\"semiotic\"` unless you need everything** — use the smallest sub-path that matches your charts or tooling.\n\nThe numbers below are **first-party artifact cost**: the gzip size of Semiotic's own code for each sub-path. They exclude React and other runtime dependencies, so they are not a prediction of a cold application bundle. Do not add artifact rows to estimate an app: dependency resolution and cross-import deduplication happen in the consumer bundler and are measured separately below.\n\n\u003c!-- semiotic-bundle-sizes:start --\u003e\n\u003c!-- Auto-generated by `scripts/sync-bundle-sizes.mjs`. Edit dist/*, not this block. --\u003e\n\n| Entry Point | gzip | What's inside |\n|---|---|---|\n| `semiotic/access` | **35 KB** | Chart Access Contract factory and first-wave baseline contracts |\n| `semiotic/evidence` | **50 KB** | Chart Evidence Envelope, deterministic hashing, and publication gate |\n| `semiotic/line` | **135 KB** | LineChart only — one-chart micro boundary |\n| `semiotic/xy` | **166 KB** | LineChart, AreaChart, Scatterplot, Heatmap, + 8 more XY charts |\n| `semiotic/ordinal` | **130 KB** | BarChart, PieChart, BoxPlot, Histogram, + 11 more categorical charts |\n| `semiotic/network` | **157 KB** | ForceDirectedGraph, SankeyDiagram, ProcessSankey, Treemap, + 4 more |\n| `semiotic/geo` | **113 KB** | ChoroplethMap, FlowMap, DistanceCartogram, ProportionalSymbolMap |\n| `semiotic/realtime` | **162 KB** | RealtimeLineChart, RealtimeHistogram, + 4 streaming charts |\n| `semiotic/realtime/core` | **161 KB** | Streaming chart types, HOCs, and buffer helpers |\n| `semiotic/realtime/react` | **1 KB** | Stream status and synced push hooks |\n| `semiotic/server` | **216 KB** | renderChart, renderDashboard, renderToImage, renderToAnimatedGif |\n| `semiotic/server/node` | **216 KB** | renderChart, renderDashboard, renderToImage, renderToAnimatedGif |\n| `semiotic/server/edge` | **222 KB** | renderChart, renderChartWithEvidence, renderToStaticSVG, renderDashboard |\n| `semiotic/utils` | **102 KB** | ThemeProvider, numeric/accessibility audits, serialization — no chart components |\n| `semiotic/utils/core` | **95 KB** | Pure theme helpers, numeric/accessibility audits, and serialization |\n| `semiotic/utils/react` | **7 KB** | ThemeProvider, useTheme, useReducedMotion, useHighContrast, useStreamStatus |\n| `semiotic/recipes` | **95 KB** | Pure layout functions (waffle, marimekko, flextree, dagre, …) |\n| `semiotic/recipes/core` | **87 KB** | Pure layout functions (waffle, marimekko, flextree, dagre, …) |\n| `semiotic/recipes/react` | **8 KB** | Glyph and React layout-selection helpers |\n| `semiotic/themes` | **12 KB** | Theme presets only (tufte, carbon, etc.) |\n| `semiotic/themes/core` | **12 KB** | Theme presets and token helpers |\n| `semiotic/themes/react` | **7 KB** | ThemeProvider/useTheme and hooks |\n| `semiotic/data` | **4 KB** | bin, rollup, groupBy, pivot, fromVegaLite |\n| `semiotic/value` | **6 KB** | BigNumber — focal-value KPI / scorecard (SingleValueFrame POC) |\n| `semiotic/physics` | **168 KB** | GaltonBoardChart, EventDropChart, UnitPileChart, CollisionSwarmChart, PacketFlowChart, PhysicsCustomChart |\n| `semiotic/physics/matter` | **1 KB** | Matter.js migration helpers + optional peer guard (no chart components) |\n| `semiotic/physics/rapier` | **1 KB** | Rapier peer guard + adapter decision metadata (no chart components) |\n| `semiotic/ai` | **552 KB** | All schema-backed charts + validation — optimized for LLM code generation |\n| `semiotic/ai/core` | **101 KB** | suggestCharts, auditData, describeChart, repairChartConfig, tool adapters — no chart components |\n| `semiotic/controls` | **11 KB** | DirectManipulationControl, CircularBrush, MobileStandardControls, auditVisualizationControls — no frame renderer |\n| `semiotic/rough` | **3 KB** | Optional deterministic Rough.js paint backend — exact Semiotic geometry remains authoritative |\n| `semiotic` | **359 KB** | Everything below (full bundle) |\n\n\u003c!-- semiotic-bundle-sizes:end --\u003e\n\n### Cold-consumer named imports\n\nThe table above is **first-party artifact cost**, not an application bundle. The generated table\nbelow measures a different thing: a fresh consumer bundles one retained named import from a packed\n`semiotic` tarball through the public export path. It includes Semiotic and its resolved runtime dependencies,\nbut externalizes React/React DOM and optional adapter peers that the host application owns. Each row\nstarts cold, so use it to compare one public import choice—not to add together an application's rows.\nThe checked machine-readable baseline is `benchmarks/setup/cold-consumer-imports.json`; refresh it\nafter a production build with `npm run docs:cold-consumer`.\n\n\u003c!-- semiotic-cold-consumer:start --\u003e\n\u003c!-- Auto-generated by `scripts/measure-cold-consumer.mjs`. Do not edit by hand. --\u003e\n\nMethod: fresh `npm pack --ignore-scripts` tarball → temporary consumer → minified/tree-shaken esbuild ESM bundle → gzip -9. React/React DOM and optional adapter peers are external; Semiotic and its resolved runtime dependencies are included.\n\n| Public named import | Runtime | gzip cold-consumer bundle |\n|---|---:|---:|\n| `import { LineChart } from \"semiotic\"` | browser | **139.3 KiB** |\n| `import { LineChart } from \"semiotic/xy\"` | browser | **139.7 KiB** |\n| `import { LineChart } from \"semiotic/line\"` | browser | **139.5 KiB** |\n| `import { BarChart } from \"semiotic/ordinal\"` | browser | **132.5 KiB** |\n| `import { SankeyDiagram } from \"semiotic/network\"` | browser | **156.6 KiB** |\n| `import { RealtimeLineChart } from \"semiotic/realtime\"` | browser | **140.2 KiB** |\n| `import { RingBuffer } from \"semiotic/realtime/core\"` | browser | **0.7 KiB** |\n| `import { useStreamStatus } from \"semiotic/realtime/react\"` | browser | **0.6 KiB** |\n| `import { GaltonBoardChart } from \"semiotic/physics\"` | browser | **149.7 KiB** |\n| `import { MATTER_PHYSICS_CAPABILITIES } from \"semiotic/physics/matter\"` | browser | **0.2 KiB** |\n| `import { RAPIER_PHYSICS_CAPABILITIES } from \"semiotic/physics/rapier\"` | browser | **0.2 KiB** |\n| `import { renderChart } from \"semiotic/server\"` | node | **262.4 KiB** |\n| `import { generateFrameSVGs } from \"semiotic/server/edge\"` | node | **118.2 KiB** |\n| `import { renderToImage } from \"semiotic/server/node\"` | node | **263.0 KiB** |\n| `import { suggestCharts } from \"semiotic/ai\"` | browser | **252.3 KiB** |\n| `import { suggestCharts } from \"semiotic/ai/core\"` | browser | **44.7 KiB** |\n| `import { createChartAccessContract } from \"semiotic/access\"` | browser | **30.9 KiB** |\n| `import { toEvidenceEnvelope } from \"semiotic/evidence\"` | browser | **39.8 KiB** |\n| `import { bin } from \"semiotic/data\"` | browser | **0.4 KiB** |\n| `import { ChoroplethMap } from \"semiotic/geo\"` | browser | **115.0 KiB** |\n| `import { createRoughRenderMode } from \"semiotic/rough\"` | browser | **3.1 KiB** |\n| `import { resolveThemePreset } from \"semiotic/themes\"` | browser | **2.6 KiB** |\n| `import { resolveThemePreset } from \"semiotic/themes/core\"` | browser | **2.6 KiB** |\n| `import { ThemeProvider } from \"semiotic/themes/react\"` | browser | **5.2 KiB** |\n| `import { validateProps } from \"semiotic/utils\"` | browser | **9.2 KiB** |\n| `import { smartTickFormat } from \"semiotic/utils/core\"` | browser | **6.9 KiB** |\n| `import { useReducedMotion } from \"semiotic/utils/react\"` | browser | **2.4 KiB** |\n| `import { waffleLayout } from \"semiotic/recipes\"` | browser | **1.7 KiB** |\n| `import { waffleLayout } from \"semiotic/recipes/core\"` | browser | **1.7 KiB** |\n| `import { Glyph } from \"semiotic/recipes/react\"` | browser | **0.8 KiB** |\n| `import { BigNumber } from \"semiotic/value\"` | browser | **5.9 KiB** |\n| `import { DirectManipulationControl } from \"semiotic/controls\"` | browser | **1.3 KiB** |\n\n**Line-boundary interpretation:** the retained named import from `semiotic/line` emits 422.7 KiB raw versus 422.7 KiB from `semiotic/xy`; gzip differs by 0.2 KiB (0.1%). Tree-shaking converges both paths on the same LineChart implementation graph. Treat `semiotic/line` as a narrower API/direct-ESM artifact boundary, not an application-bundle saving. Do not add another per-chart entry until its packed named import beats the family path by both 10 KiB gzip and 7%.\n\n\u003c!-- semiotic-cold-consumer:end --\u003e\n\n**d3 packaging model:** Semiotic externalizes the twelve d3 modules it imports\nand declares them as normal runtime dependencies. Consumers do not need to\ninstall d3 packages manually; their bundler resolves, deduplicates, and\ntree-shakes that dependency graph. A packed webpack comparison favored this\nmodel in three of four representative chart families, and a Next 16 webpack\nroute was 22.8 KiB gzip smaller than the fully bundled alternative. The one\nbundled win, Sankey, was only 1.0 KiB gzip. This choice retains a 22-package,\n1.9 MB unpacked d3 install closure in exchange for smaller common application\ngraphs and an ordinary dependency contract. The checked policy is\n`npm run check:d3-packaging`; the reproducible evidence is in\n`benchmarks/setup/d3-packaging.json` and can be regenerated with\n`npm run measure:d3-packaging -- --toolchain-root \u003cdir\u003e` after installing\nwebpack and Next in that isolated toolchain directory.\n\n```jsx\n// Import from the sub-path, not from \"semiotic\"\nimport { LineChart } from \"semiotic/xy\"\nimport { BarChart } from \"semiotic/ordinal\"\nimport { SankeyDiagram } from \"semiotic/network\"\nimport { ChoroplethMap } from \"semiotic/geo\"\n```\n\n**Tree-shaking \u0026 multi-subpath imports**: Family entries (`semiotic/xy`, `semiotic/network`, `semiotic/ai`, …) are built as one ESM graph with **shared chunks**. Stream frames, renderers, and other common code ship once and are imported by every entry that needs them — so combining `semiotic/ai` + `semiotic/xy` + `semiotic/network` does **not** mean paying for three full copies of the runtime. The package is marked `\"sideEffects\": false`, so modern bundlers keep only the named exports you retain (e.g. `LineChart` + `suggestCharts`). Prefer family subpaths for clarity; import AI helpers from `semiotic/ai` or the lighter `semiotic/ai/core` when you do not need the chart catalog.\n\n**When to use `\"semiotic\"`**: Fine when you want one import for mixed families. Shared chunks prevent duplicated runtime code across family subpaths; the cold-consumer table above is the better guide for a single named import.\n\n**CommonJS compatibility note:** `require(\"semiotic/xy\")` loads the shared\nCommonJS client bundle (about 2.1 MB before compression) so React contexts stay\nsingletons across family imports. Prefer ESM imports in browser builds when\nbundle size matters; splitting that CJS client without a context-identity\ncontract would be unsafe.\n\n## TypeScript\n\nBuilt with `strict: true`. Full type definitions ship with the package.\nGenerics for type-safe accessors:\n\n```tsx\ninterface Sale { month: number; revenue: number }\n\n\u003cLineChart\u003cSale\u003e\n  data={sales}\n  xAccessor=\"month\"    // TS validates this is keyof Sale\n  yAccessor=\"revenue\"\n/\u003e\n```\n\n## Server-Side Rendering\n\nAll chart components render SVG automatically in server environments — no\nspecial imports or configuration needed. Non-streaming chart HOCs can be\nimported and rendered directly from a Next.js Server Component: Semiotic's\n`\"use client\"` directive defines the package boundary, so the importing page\ndoes not need its own wrapper or directive. Props crossing that boundary must\nremain serializable; add an app-owned client wrapper only when you introduce\nhooks, callback props, browser state, or a push-driven streaming chart.\n\n```jsx\n// app/dashboard/page.tsx — a Next.js Server Component\nimport { LineChart } from \"semiotic/xy\"\n\n// Server: renders \u003csvg\u003e with path/circle/rect elements\n// Client: renders \u003ccanvas\u003e with SVG overlay for axes\nexport default async function DashboardPage() {\n  const data = await fetchMetrics()\n  return \u003cLineChart data={data} xAccessor=\"date\" yAccessor=\"value\" /\u003e\n}\n```\n\nFor standalone SVG/PNG/GIF generation (email, OG images, PDF, Slack), use the server entry point:\n\n```js\nimport { renderChart, renderToImage, renderToAnimatedGif } from \"semiotic/server\"\n\n// SVG — sync, no dependencies\nconst svg = renderChart(\"LineChart\", {\n  data, xAccessor: \"date\", yAccessor: \"value\",\n  theme: \"tufte\", title: \"Revenue Trend\",\n})\n\n// PNG — async, requires sharp\nconst png = await renderToImage(\"BarChart\", { data, ... }, { format: \"png\", scale: 2 })\n\n// Animated GIF — async, requires sharp + gifenc\nconst gif = await renderToAnimatedGif(\"line\", data, { ... }, { fps: 12 })\n```\n\n## MCP Server\n\nmcp-name: io.github.nteract/semiotic\n\nSemiotic ships with an [MCP server](https://modelcontextprotocol.io) that lets AI coding assistants render charts, diagnose configuration problems, discover schemas, read packaged AI guidance, and get chart recommendations via tool calls.\n\n### Setup\n\nAdd to your MCP client config (e.g. `claude_desktop_config.json` for Claude Desktop):\n\n```json\n{\n  \"mcpServers\": {\n    \"semiotic\": {\n      \"command\": \"npx\",\n      \"args\": [\"semiotic-mcp\"]\n    }\n  }\n}\n```\n\nNo API keys or authentication required. The server runs locally via stdio. HTTP mode is also available for inspectors, web clients, and ChatGPT Apps SDK experiments: `npx semiotic-mcp --http --port 3001`. It binds to `127.0.0.1` by default; intentionally expose another interface with `--host 0.0.0.0` or `MCP_HOST=0.0.0.0`. Since 3.7.2, HTTP mode is stateless: each request gets a fresh read-only MCP server + transport, so it can autoscale on serverless hosts without sticky sessions.\n\nFor ChatGPT developer mode, expose the HTTP endpoint over HTTPS with a tunnel and create a connector that points at `https://\u003cyour-tunnel\u003e/mcp`. The experimental Apps SDK surface is `renderInteractiveChart`, which returns a `text/html;profile=mcp-app` widget template plus a hidden SVG payload rendered by Semiotic on the MCP server.\n\nFor a hosted deployment, see `deploy/cloud-run`. The wrapper runs the published `semiotic-mcp`\nbinary, exposes `/mcp` plus health endpoints, and supports `MCP_ALLOWED_HOSTS` for production\nhost-header allowlisting. For ChatGPT Apps domain verification, set\n`OPENAI_APPS_CHALLENGE_TOKEN` so HTTP mode serves the raw token from\n`/.well-known/openai-apps-challenge`.\n\n### Tools\n\n| Tool | Description |\n|------|-------------|\n| **`renderChart`** | Render a Semiotic chart to static SVG. Supports the components returned by `getSchema` that are marked `[renderable]`. Pass `{ component: \"LineChart\", props: { data: [...], xAccessor: \"x\", yAccessor: \"y\" } }`. Returns SVG string plus a \"Render evidence\" JSON block (mark counts by scene type, resolved axis domains, empty flag, annotation count, accessible name) so agents can verify the chart drew data marks, or validation errors with fix suggestions. |\n| **`renderInteractiveChart`** | Render a static-data chart as a ChatGPT Apps widget. Uses the same Semiotic server render path as `renderChart`, then hydrates an iframe UI with fit, zoom, data, hover, and render-evidence controls. |\n| **`getSchema`** | Return the prop schema for a specific component. Pass `{ component: \"LineChart\" }` to get its props, or omit `component` to list the complete schema-backed catalog. Components marked `[renderable]` are available through `renderChart`; realtime charts require a browser/live environment. |\n| **`suggestChart`** | Sample-row recommender. Pass `{ data: [{...}, ...] }` with 1–5 sample objects plus optional broad intent/capability filters. |\n| **`suggestCharts`** | Capability-based recommender for bounded row data. Returns ranked chart suggestions with scores, reasons, caveats, import paths, and ready-to-use props. |\n| **`suggestStreamCharts`** | Recommend realtime charts from a stream schema, throughput, and retention hints. |\n| **`suggestDashboard`** | Build a multi-panel dashboard suggestion that covers distinct analytical intents. |\n| **`suggestStretchCharts`** | Recommend audience-literacy stretch picks from an `AudienceProfile`. |\n| **`repairChartConfig`** | Check whether a requested chart fits a dataset and return ranked alternatives when it does not. |\n| **`interrogateChart`** | Return a statistical summary and chart-aware context for answering natural-language questions with optional annotations. |\n| **`diagnoseConfig`** | Check a chart configuration for common problems — empty data, bad dimensions, missing accessors, wrong data shape, and more. Returns a human-readable diagnostic report with actionable fixes. |\n| **`reportIssue`** | Generate a pre-filled GitHub issue URL for bug reports or feature requests. Pass `{ title: \"...\", body: \"...\", labels: [\"bug\"] }`. Returns a URL the user can open to submit. |\n| **`applyTheme`** | List named theme presets or return ThemeProvider/CSS/token usage for a preset such as `{ name: \"tufte\" }`. |\n\n### Resources\n\n| Resource | Description |\n|----------|-------------|\n| **`semiotic://schema`** | Full machine-readable component schema JSON. |\n| **`semiotic://schema-index`** | Compact discovery index with categories, renderability, import paths, and each component's schema resource URI. |\n| **`semiotic://schema/{component}`** | One component's schema, metadata, accessibility guidance, and behavior contracts (for example `semiotic://schema/LineChart`). |\n| **`semiotic://components`** | Backward-compatible component index showing renderable/browser-only status and MCP categories. |\n| **`semiotic://surface-manifest`** | Generated inventory of the current AI schema, exports, renderability, tools, resources, and prompts. |\n| **`semiotic://behavior-contracts`** | Agent-visible semantic rules for color precedence, required prop combinations, push refs, and renderability. |\n| **`semiotic://system-prompt`** | Compact AI instructions with import rules, chart props, SSR guidance, and pitfalls. |\n| **`semiotic://examples`** | Copy-paste chart examples by data shape. |\n| **`ui://semiotic/chart-widget.html`** | ChatGPT Apps / MCP Apps widget template used by `renderInteractiveChart`. |\n\n### Prompts\n\n| Prompt | Description |\n|--------|-------------|\n| **`build-semiotic-chart`** | Reusable workflow for choosing a chart, reading schema, diagnosing props, and rendering a preview. |\n| **`debug-semiotic-chart`** | Reusable workflow for debugging invalid props, rendering failures, and issue reports. |\n\n### Example: get schema for a component\n\n```\nTool: getSchema\nArgs: { \"component\": \"LineChart\" }\n→ Returns: { \"name\": \"LineChart\", \"description\": \"...\", \"parameters\": { \"properties\": { \"data\": ..., \"xAccessor\": ..., ... } } }\n```\n\n### Example: suggest a chart for your data\n\n```\nTool: suggestChart\nArgs: {\n  \"data\": [\n    { \"month\": \"Jan\", \"revenue\": 120, \"region\": \"East\" },\n    { \"month\": \"Feb\", \"revenue\": 180, \"region\": \"West\" }\n  ]\n}\n→ Returns:\n  1. BarChart (high confidence) — categorical field (region) with values (revenue)\n  2. StackedBarChart (medium confidence) — two categorical fields (month, region)\n  3. DonutChart (medium confidence) — 2 categories — proportional composition\n```\n\n### Example: render a chart\n\n```\nTool: renderChart\nArgs: {\n  \"component\": \"BarChart\",\n  \"props\": {\n    \"data\": [\n      { \"category\": \"Q1\", \"revenue\": 120 },\n      { \"category\": \"Q2\", \"revenue\": 180 },\n      { \"category\": \"Q3\", \"revenue\": 150 }\n    ],\n    \"categoryAccessor\": \"category\",\n    \"valueAccessor\": \"revenue\"\n  }\n}\n→ Returns: \u003csvg\u003e...\u003c/svg\u003e\n```\n\n### Example: render a ChatGPT Apps widget\n\n```\nTool: renderInteractiveChart\nArgs: {\n  \"component\": \"BarChart\",\n  \"props\": {\n    \"title\": \"Revenue by Quarter\",\n    \"data\": [\n      { \"quarter\": \"Q1\", \"revenue\": 120 },\n      { \"quarter\": \"Q2\", \"revenue\": 180 }\n    ],\n    \"categoryAccessor\": \"quarter\",\n    \"valueAccessor\": \"revenue\"\n  }\n}\n→ Returns: structured chart summary for the model + hidden SVG/widget metadata for ChatGPT.\n```\n\n### Example: diagnose a broken config\n\n```\nTool: diagnoseConfig\nArgs: { \"component\": \"LineChart\", \"props\": { \"data\": [] } }\n→ Returns: ✗ [EMPTY_DATA] data is an empty array — Fix: provide at least one data point\n```\n\n### Example: report an issue\n\n```\nTool: reportIssue\nArgs: {\n  \"title\": \"Bug: BarChart tooltip shows undefined for custom accessor\",\n  \"body\": \"When using valueAccessor='amount', tooltip displays 'undefined'.\\n\\ndiagnoseConfig output: ✓ no issues detected.\",\n  \"labels\": [\"bug\"]\n}\n→ Returns: Open this URL to submit the issue: https://github.com/nteract/semiotic/issues/new?...\n```\n\n### CLI alternative\n\nFor quick validation without an MCP client:\n\n```bash\nnpx semiotic-ai --list         # list components with import paths and renderability\nnpx semiotic-ai --list --json  # machine-readable component index\nnpx semiotic-ai --schema GaugeChart\nnpx semiotic-ai --suggest '{\"data\":[{\"category\":\"A\",\"value\":10}],\"intent\":\"comparison\"}'\nnpx semiotic-ai --doctor       # validate component + props JSON\nnpx semiotic-ai --schema       # dump all chart schemas\nnpx semiotic-ai --compact      # compact schema (fewer tokens)\n```\n\n`--doctor` uses the full `diagnoseConfig` checks when `dist` is available and falls back to schema-only validation in clean source checkouts.\n\n## Where to find Semiotic for AI assistants\n\nSemiotic is indexed by AI-coding-agent documentation tools so your assistant (Claude Code, Cursor, Cline, Copilot, etc.) can pull current docs and tools without copy-paste:\n\n- **Context7** — [context7.com/nteract/semiotic](https://context7.com/nteract/semiotic) (configured via `context7.json`)\n- **DeepWiki** — [deepwiki.com/nteract/semiotic](https://deepwiki.com/nteract/semiotic)\n- **GitMCP** — [gitmcp.io/nteract/semiotic](https://gitmcp.io/nteract/semiotic) (exposes the repo as an MCP endpoint directly)\n- **Official MCP Registry** — search \"semiotic\" at [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io)\n\nThe Official MCP Registry is the canonical MCP directory record; it is distinct\nfrom acceptance into any assistant vendor's curated connector directory.\nSecondary-directory freshness and release ownership are tracked in\n[MCP_DISTRIBUTION.md](https://github.com/nteract/semiotic/blob/main/MCP_DISTRIBUTION.md).\n\nAgent-facing API surface:\n\n- **`AGENTS.md`** is the concise repository development contract and **`CLAUDE.md`** imports it for Claude Code. These stay repository-local rather than shipping irrelevant contributor instructions to package consumers.\n- **`ai/reference.md`**, **`ai/schema.json`**, **`ai/surface-manifest.json`**, **`ai/behaviorContracts.cjs`**, and **`agent-skill/semiotic-charts/SKILL.md`** are bundled in the npm tarball (see `package.json#files`). The reference is the on-demand product guide printed by `npx semiotic-ai`; the schema, manifest, contracts, and portable skill provide structured generation and validation guidance.\n- [**`semiotic.nteract.io/llms.txt`**](https://semiotic.nteract.io/llms.txt) + [**`/llms-full.txt`**](https://semiotic.nteract.io/llms-full.txt) — deployed at the docs site per the [llms.txt standard](https://llmstxt.org). Agents fetch the navigation map (`llms.txt`) or the full inlined docs (`llms-full.txt`) over HTTP; they're not part of the npm package itself.\n\n## Documentation\n\n[Interactive docs and examples](https://semiotic.nteract.io)\n\n- [Getting Started](https://semiotic.nteract.io/getting-started)\n- [Charts](https://semiotic.nteract.io/charts) — chart types with live examples\n- [Frames](https://semiotic.nteract.io/frames) — full Frame API reference\n- [Features](https://semiotic.nteract.io/features) — axes, tooltips, interaction, responsive behavior, and composition\n- [Annotations](https://semiotic.nteract.io/annotations) — first-class annotation types, design guidance, provenance, and lifecycle\n- [Cookbook](https://semiotic.nteract.io/cookbook) — advanced patterns and recipes\n- [Playground](https://semiotic.nteract.io/playground) — interactive prop exploration\n\n## Upgrading\n\n- [Migration Guide](./MIGRATION.md) — upgrading from v1.x or v2.x\n- [Changelog](./CHANGELOG.md) — full release history\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md). Our community follows the nteract\n[Code of Conduct](https://github.com/nteract/nteract/blob/main/CODE_OF_CONDUCT.md).\n\n## Acknowledgments\n\nDevelopment of this library owes a lot to Susie Lu, Jason Reid, James Womack,\nMatt Herman, Shelby Sturgis, and Tristan Reid.\n\nThe Sankey layout engine is based on [sankey-plus](https://github.com/tomshanley/sankey-plus)\nby [Tom Shanley](https://github.com/tomshanley), which improved on his earlier\n`d3-sankey-circular` with better cycle detection, hierarchical arc stacking,\nand dynamic extent adjustment.\n\n_Semiotic icon based on an icon by Andre Schauer._\n\n## License\n\n[Apache 2.0](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnteract%2Fsemiotic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnteract%2Fsemiotic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnteract%2Fsemiotic/lists"}