semiotic 3.7.0 → 3.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CLAUDE.md +3 -2
  2. package/README.md +46 -7
  3. package/ai/behaviorContracts.cjs +19 -9
  4. package/ai/cli.js +15 -0
  5. package/ai/dist/mcp-server.js +583 -66
  6. package/ai/schema.json +1 -1
  7. package/ai/system-prompt.md +3 -3
  8. package/dist/components/AccessibleNavTree.d.ts +2 -1
  9. package/dist/components/Annotation.d.ts +1 -1
  10. package/dist/components/CategoryColors.d.ts +1 -1
  11. package/dist/components/ChartGrid.d.ts +1 -1
  12. package/dist/components/ContextLayout.d.ts +1 -1
  13. package/dist/components/DataSummaryContext.d.ts +1 -1
  14. package/dist/components/DetailsPanel.d.ts +1 -1
  15. package/dist/components/Legend.d.ts +3 -2
  16. package/dist/components/LinkedCharts.d.ts +1 -1
  17. package/dist/components/ThemeProvider.d.ts +1 -1
  18. package/dist/components/Tooltip/FlippingTooltip.d.ts +1 -1
  19. package/dist/components/Tooltip/Tooltip.d.ts +2 -2
  20. package/dist/components/ai/qualityScorecard.d.ts +11 -0
  21. package/dist/components/charts/geo/ChoroplethMap.d.ts +2 -1
  22. package/dist/components/charts/network/CirclePack.d.ts +2 -1
  23. package/dist/components/charts/network/OrbitDiagram.d.ts +1 -1
  24. package/dist/components/charts/network/TreeDiagram.d.ts +2 -1
  25. package/dist/components/charts/network/Treemap.d.ts +2 -1
  26. package/dist/components/charts/realtime/RealtimeHistogram.d.ts +1 -1
  27. package/dist/components/charts/shared/ChartError.d.ts +2 -1
  28. package/dist/components/charts/shared/withChartWrapper.d.ts +1 -1
  29. package/dist/components/charts/xy/MinimapChart.d.ts +2 -1
  30. package/dist/components/charts/xy/ScatterplotMatrix.d.ts +2 -1
  31. package/dist/components/semiotic-server.d.ts +2 -1
  32. package/dist/components/server/renderEvidence.d.ts +92 -0
  33. package/dist/components/server/renderToStaticSVG.d.ts +14 -1
  34. package/dist/components/stream/AccessibleDataTable.d.ts +5 -5
  35. package/dist/components/stream/FocusRing.d.ts +2 -1
  36. package/dist/components/stream/MarginalGraphics.d.ts +2 -1
  37. package/dist/components/stream/NetworkCanvasHitTester.d.ts +3 -2
  38. package/dist/components/stream/NetworkPipelineStore.d.ts +46 -1
  39. package/dist/components/stream/NetworkSVGOverlay.d.ts +2 -1
  40. package/dist/components/stream/OrdinalBrushOverlay.d.ts +19 -1
  41. package/dist/components/stream/OrdinalSVGOverlay.d.ts +2 -2
  42. package/dist/components/stream/PipelineStore.d.ts +6 -0
  43. package/dist/components/stream/SVGOverlay.d.ts +3 -2
  44. package/dist/components/stream/StalenessBadge.d.ts +19 -0
  45. package/dist/components/stream/XYBrushOverlay.d.ts +21 -1
  46. package/dist/components/stream/quadtreeHitTest.d.ts +7 -1
  47. package/dist/geo.min.js +1 -1
  48. package/dist/geo.module.min.js +1 -1
  49. package/dist/network.min.js +1 -1
  50. package/dist/network.module.min.js +1 -1
  51. package/dist/ordinal.min.js +1 -1
  52. package/dist/ordinal.module.min.js +1 -1
  53. package/dist/realtime.min.js +1 -1
  54. package/dist/realtime.module.min.js +1 -1
  55. package/dist/semiotic-ai.min.js +1 -1
  56. package/dist/semiotic-ai.module.min.js +1 -1
  57. package/dist/semiotic-server.d.ts +2 -1
  58. package/dist/semiotic-themes.min.js +1 -1
  59. package/dist/semiotic-themes.module.min.js +1 -1
  60. package/dist/semiotic-utils.min.js +1 -1
  61. package/dist/semiotic-utils.module.min.js +1 -1
  62. package/dist/semiotic-value.min.js +1 -1
  63. package/dist/semiotic-value.module.min.js +1 -1
  64. package/dist/semiotic.min.js +1 -1
  65. package/dist/semiotic.module.min.js +1 -1
  66. package/dist/server.min.js +1 -1
  67. package/dist/server.module.min.js +1 -1
  68. package/dist/xy.min.js +1 -1
  69. package/dist/xy.module.min.js +1 -1
  70. package/package.json +2 -2
package/CLAUDE.md CHANGED
@@ -4,7 +4,7 @@
4
4
  - Install: `npm install semiotic`
5
5
  <!-- semiotic-bundle-sizes:start -->
6
6
  <!-- Auto-generated by scripts/sync-bundle-sizes.mjs — do not edit by hand. -->
7
- - **Use sub-path imports** — `semiotic/xy` (90KB gz), `semiotic/ordinal` (74KB gz), `semiotic/network` (68KB gz), `semiotic/geo` (55KB gz), `semiotic/realtime` (95KB gz), `semiotic/server` (127KB gz), `semiotic/utils` (37KB gz), `semiotic/recipes` (9KB gz), `semiotic/themes` (4KB gz), `semiotic/data` (3KB gz), `semiotic/value` (6KB gz), `semiotic/ai` (246KB gz). Full `semiotic` is 203KB gz.
7
+ - **Use sub-path imports** — `semiotic/xy` (90KB gz), `semiotic/ordinal` (74KB gz), `semiotic/network` (68KB gz), `semiotic/geo` (55KB gz), `semiotic/realtime` (95KB gz), `semiotic/server` (128KB gz), `semiotic/utils` (38KB gz), `semiotic/recipes` (9KB gz), `semiotic/themes` (4KB gz), `semiotic/data` (3KB gz), `semiotic/value` (6KB gz), `semiotic/ai` (250KB gz). Full `semiotic` is 203KB gz.
8
8
  <!-- semiotic-bundle-sizes:end -->
9
9
  - CLI: `npx semiotic-ai [--schema|--compact|--examples|--doctor|--audit-a11y]` · MCP: `npx semiotic-mcp`
10
10
 
@@ -160,9 +160,10 @@ Also: **ScatterplotMatrix**, **ChartContainer** (`title`, `subtitle`, `actions`)
160
160
  HOC charts render SVG automatically in server environments. For standalone generation:
161
161
 
162
162
  ```ts
163
- import { renderChart, renderToImage, renderToAnimatedGif, renderDashboard } from "semiotic/server"
163
+ import { renderChart, renderChartWithEvidence, renderToImage, renderToAnimatedGif, renderDashboard } from "semiotic/server"
164
164
 
165
165
  const svg = renderChart("BarChart", { data, categoryAccessor, valueAccessor, theme: "tufte", showLegend, showGrid, annotations })
166
+ const { svg: svg2, evidence } = renderChartWithEvidence("BarChart", { data, categoryAccessor, valueAccessor }) // evidence: { markCount, markCountByType, empty, xDomain?, yDomain?, categories?, nodeCount?, edgeCount?, annotationCount, ariaLabel, warnings } — ground truth from the rendered scene; check `evidence.empty`/`markCount` instead of parsing SVG. MCP renderChart returns the same block.
166
167
  const png = await renderToImage("LineChart", { ... }, { format: "png", scale: 2 }) // requires sharp
167
168
  const gif = await renderToAnimatedGif("line", data, { xAccessor, yAccessor, theme: "dark" }, { fps: 12, transitionFrames: 4, decay: { type: "linear" } }) // requires sharp + gifenc
168
169
  const dashboard = renderDashboard([{ component: "BarChart", props }, { component: "PieChart", colSpan: 2, props }], { title, theme, layout: { columns: 2 } })
package/README.md CHANGED
@@ -12,6 +12,18 @@ Simple charts in 5 lines. Network graphs, streaming data, and coordinated
12
12
  dashboards when you need them. Structured schemas and an MCP server so
13
13
  AI coding assistants generate correct chart code on the first try.
14
14
 
15
+ ## What's New in 3.7.2
16
+
17
+ 3.7.2 is a deployment and docs-polish patch release:
18
+
19
+ - `semiotic-mcp --http` now runs in stateless Streamable HTTP mode, with JSON responses,
20
+ health endpoints, optional `MCP_ALLOWED_HOSTS` host-header protection, and serverless-friendly
21
+ request teardown.
22
+ - `deploy/cloud-run` contains a minimal Google Cloud Run wrapper for publishing the MCP server as a
23
+ public read-only connector for ChatGPT, Claude, and other MCP clients.
24
+ - The Accessibility docs' visible navigation tree and bidirectional BarChart examples now honor
25
+ dark mode, and the contested-annotations blog demo renders its editorial-status callouts reliably.
26
+
15
27
  ```jsx
16
28
  import { LineChart } from "semiotic/xy"
17
29
 
@@ -35,11 +47,11 @@ generate correct code without examples.
35
47
  Semiotic ships with everything an AI coding assistant needs to generate
36
48
  correct visualizations without trial and error:
37
49
 
38
- - **`semiotic/ai`** — a single import with the 47-chart capability catalog (XY, ordinal, network, realtime, geo, value), optimized for LLM code generation. Prefer family subpaths such as `semiotic/xy`, `semiotic/geo`, and `semiotic/value` when bundle size matters.
50
+ - **`semiotic/ai`** — a single import with the 47-chart capability catalog (XY, ordinal, network, realtime, geo, value), optimized for LLM code generation. 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.
39
51
  - **`ai/schema.json`** — machine-readable prop schemas for every component
40
52
  - **`npx semiotic-mcp`** — an MCP server for tool-based chart rendering in any MCP client
41
53
  - **`npx semiotic-ai --doctor`** — validate component + props JSON from the command line with typo suggestions and anti-pattern detection
42
- - **`diagnoseConfig(component, props)`** — programmatic anti-pattern detector with 12 checks and actionable fixes
54
+ - **`diagnoseConfig(component, props)`** — programmatic anti-pattern detector with actionable fixes, spanning validation, encoding, accessibility, and misleading-design (deception) checks
43
55
  - **`CLAUDE.md`** — instruction files auto-synced for Claude, Cursor, Copilot, Windsurf, and Cline
44
56
  - **`llms.txt`** — machine-readable documentation following the emerging standard
45
57
 
@@ -320,13 +332,13 @@ Semiotic ships 12 entry points. **Don't import from `"semiotic"` unless you need
320
332
  | `semiotic/network` | **68 KB** | ForceDirectedGraph, SankeyDiagram, ProcessSankey, Treemap, + 4 more |
321
333
  | `semiotic/geo` | **55 KB** | ChoroplethMap, FlowMap, DistanceCartogram, ProportionalSymbolMap |
322
334
  | `semiotic/realtime` | **95 KB** | RealtimeLineChart, RealtimeHistogram, + 4 streaming charts |
323
- | `semiotic/server` | **127 KB** | renderChart, renderDashboard, renderToImage, renderToAnimatedGif |
324
- | `semiotic/utils` | **37 KB** | ThemeProvider, validators, serialization — no chart components |
335
+ | `semiotic/server` | **128 KB** | renderChart, renderDashboard, renderToImage, renderToAnimatedGif |
336
+ | `semiotic/utils` | **38 KB** | ThemeProvider, validators, serialization — no chart components |
325
337
  | `semiotic/recipes` | **9 KB** | Pure layout functions (waffle, marimekko, flextree, dagre, …) |
326
338
  | `semiotic/themes` | **4 KB** | Theme presets only (tufte, carbon, etc.) |
327
339
  | `semiotic/data` | **3 KB** | bin, rollup, groupBy, pivot, fromVegaLite |
328
340
  | `semiotic/value` | **6 KB** | BigNumber — focal-value KPI / scorecard (SingleValueFrame POC) |
329
- | `semiotic/ai` | **246 KB** | All 47 schema-backed charts + validation — optimized for LLM code generation |
341
+ | `semiotic/ai` | **250 KB** | All 47 schema-backed charts + validation — optimized for LLM code generation |
330
342
  | `semiotic` | **203 KB** | Everything below (full bundle) |
331
343
 
332
344
  <!-- semiotic-bundle-sizes:end -->
@@ -411,13 +423,20 @@ Add to your MCP client config (e.g. `claude_desktop_config.json` for Claude Desk
411
423
  }
412
424
  ```
413
425
 
414
- No API keys or authentication required. The server runs locally via stdio. HTTP mode is also available for inspectors and web clients: `npx semiotic-mcp --http --port 3001`.
426
+ No 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`. In 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.
427
+
428
+ For ChatGPT developer mode, expose the HTTP endpoint over HTTPS with a tunnel and create a connector that points at `https://<your-tunnel>/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.
429
+
430
+ For a hosted deployment, see `deploy/cloud-run`. The wrapper runs the published `semiotic-mcp`
431
+ binary, exposes `/mcp` plus health endpoints, and supports `MCP_ALLOWED_HOSTS` for production
432
+ host-header allowlisting.
415
433
 
416
434
  ### Tools
417
435
 
418
436
  | Tool | Description |
419
437
  |------|-------------|
420
- | **`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 or validation errors with fix suggestions. |
438
+ | **`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. |
439
+ | **`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. |
421
440
  | **`getSchema`** | Return the prop schema for a specific component. Pass `{ component: "LineChart" }` to get its props, or omit `component` to list all 47 chart schemas. Components marked `[renderable]` are available through `renderChart`; realtime charts require a browser/live environment. |
422
441
  | **`suggestChart`** | Legacy sample-row recommender. Pass `{ data: [{...}, ...] }` with 1–5 sample objects plus optional broad intent/capability filters. |
423
442
  | **`suggestCharts`** | Capability-based recommender for bounded row data. Returns ranked chart suggestions with scores, reasons, caveats, import paths, and ready-to-use props. |
@@ -439,6 +458,7 @@ No API keys or authentication required. The server runs locally via stdio. HTTP
439
458
  | **`semiotic://behavior-contracts`** | Agent-visible semantic rules for color precedence, required prop combinations, push refs, and renderability. |
440
459
  | **`semiotic://system-prompt`** | Compact AI instructions with import rules, chart props, SSR guidance, and pitfalls. |
441
460
  | **`semiotic://examples`** | Copy-paste chart examples by data shape. |
461
+ | **`ui://semiotic/chart-widget.html`** | ChatGPT Apps / MCP Apps widget template used by `renderInteractiveChart`. |
442
462
 
443
463
  ### Prompts
444
464
 
@@ -490,6 +510,25 @@ Args: {
490
510
  → Returns: <svg>...</svg>
491
511
  ```
492
512
 
513
+ ### Example: render a ChatGPT Apps widget
514
+
515
+ ```
516
+ Tool: renderInteractiveChart
517
+ Args: {
518
+ "component": "BarChart",
519
+ "props": {
520
+ "title": "Revenue by Quarter",
521
+ "data": [
522
+ { "quarter": "Q1", "revenue": 120 },
523
+ { "quarter": "Q2", "revenue": 180 }
524
+ ],
525
+ "categoryAccessor": "quarter",
526
+ "valueAccessor": "revenue"
527
+ }
528
+ }
529
+ → Returns: structured chart summary for the model + hidden SVG/widget metadata for ChatGPT.
530
+ ```
531
+
493
532
  ### Example: diagnose a broken config
494
533
 
495
534
  ```
@@ -15,13 +15,17 @@ const DOC_MARKER_START = "<!-- semiotic-behavior-contracts:start -->"
15
15
  const DOC_MARKER_END = "<!-- semiotic-behavior-contracts:end -->"
16
16
 
17
17
  // Components whose static config requires `data` are derived from
18
- // `ai/schema.json` rather than maintained as a hand-curated list. The schema
19
- // already declares which components require data — duplicating that here led
20
- // to drift (Heatmap, FunnelChart, MinimapChart, ScatterplotMatrix, and the
21
- // hierarchy charts were schema-required but missing from the local list,
22
- // which made `dataRequiredForUsageMode` incorrectly return `false` and
23
- // suppressed the "data is required" error in --doctor / MCP diagnoseConfig
24
- // even when usageMode wasn't `push`).
18
+ // `ai/schema.json` rather than maintained as a hand-curated list.
19
+ //
20
+ // A component needs data in STATIC usage if its schema declares a `data` input
21
+ // prop NOT merely if `data` is in the `required` array. `required` lists the
22
+ // semantic accessors a chart needs (highAccessor, subcategoryAccessor, series,
23
+ // …), and several data-driven charts don't put `data` itself there:
24
+ // CandlestickChart, MultiAxisLineChart, QuadrantChart, DifferenceChart,
25
+ // LikertChart, and SwimlaneChart. Keying off `required.includes("data")` missed
26
+ // exactly those — they'd render blank with no data yet passed --doctor / MCP
27
+ // diagnoseConfig as "OK" in static mode. Keying off the presence of a `data`
28
+ // property catches them (and still includes the charts that DO list `data`).
25
29
  //
26
30
  // `STATIC_DATA_COMPONENTS` stays exported as a Set for test/legacy callers
27
31
  // that probe the surface, and is rebuilt from disk at module load time.
@@ -41,8 +45,10 @@ function loadStaticDataComponentsFromSchema() {
41
45
  const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8"))
42
46
  const out = new Set()
43
47
  for (const tool of schema.tools || []) {
44
- const required = tool.function?.parameters?.required || []
45
- if (required.includes("data")) out.add(tool.function.name)
48
+ const properties = tool.function?.parameters?.properties || {}
49
+ // Data-driven if the schema declares a `data` input prop, regardless of
50
+ // whether `data` appears in `required` (see note above).
51
+ if ("data" in properties) out.add(tool.function.name)
46
52
  }
47
53
  if (out.size > 0) return out
48
54
  } catch {
@@ -114,6 +120,10 @@ const PUSH_MODE_COMPONENTS = [
114
120
  "Scatterplot",
115
121
  "BubbleChart",
116
122
  "ConnectedScatterplot",
123
+ "CandlestickChart",
124
+ "MultiAxisLineChart",
125
+ "QuadrantChart",
126
+ "DifferenceChart",
117
127
  "BarChart",
118
128
  "StackedBarChart",
119
129
  "GroupedBarChart",
package/ai/cli.js CHANGED
@@ -163,6 +163,21 @@ function validatePropsWithSchema(componentName, props, usageMode = "static") {
163
163
  }
164
164
  }
165
165
 
166
+ // Array-shape charts that declare a `data` schema prop need it in static
167
+ // usage even when "data" isn't in `required` (those lists hold semantic
168
+ // accessors). Without this, --doctor passed dataless static CandlestickChart /
169
+ // MultiAxisLineChart / QuadrantChart / DifferenceChart / SwimlaneChart /
170
+ // LikertChart configs that render blank. dataRequiredForUsageMode is true for
171
+ // them in static and false in push, mirroring the MCP diagnoseConfig path.
172
+ if (
173
+ "data" in properties &&
174
+ !required.includes("data") &&
175
+ dataRequiredForUsageMode(component.name, usageMode) &&
176
+ (props.data === undefined || props.data === null)
177
+ ) {
178
+ errors.push(`"data" is required for ${component.name}.`)
179
+ }
180
+
166
181
  for (const [propName, value] of Object.entries(props)) {
167
182
  if (value === undefined || value === null) continue
168
183
  const propSchema = properties[propName]