semiotic 3.5.4 → 3.6.0
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.
- package/CLAUDE.md +61 -3
- package/README.md +17 -10
- package/ai/dist/mcp-server.js +249 -2
- package/ai/schema.json +34 -9
- package/ai/system-prompt.md +1 -1
- package/dist/components/ai/audienceProfile.d.ts +90 -0
- package/dist/components/ai/audiences.d.ts +31 -0
- package/dist/components/ai/chartCapabilities.d.ts +55 -0
- package/dist/components/ai/chartCapabilityTypes.d.ts +196 -0
- package/dist/components/ai/diffProfile.d.ts +51 -0
- package/dist/components/ai/inferIntent.d.ts +24 -0
- package/dist/components/ai/intents.d.ts +34 -0
- package/dist/components/ai/profileData.d.ts +16 -0
- package/dist/components/ai/qualityFixtures.d.ts +2 -0
- package/dist/components/ai/qualityScorecard.d.ts +82 -0
- package/dist/components/ai/repairChartConfig.d.ts +73 -0
- package/dist/components/ai/streamingTypes.d.ts +64 -0
- package/dist/components/ai/suggestCharts.d.ts +76 -0
- package/dist/components/ai/suggestDashboard.d.ts +92 -0
- package/dist/components/ai/suggestStreamCharts.d.ts +34 -0
- package/dist/components/ai/suggestStretchCharts.d.ts +60 -0
- package/dist/components/ai/useChartSuggestions.d.ts +22 -0
- package/dist/components/charts/geo/ChoroplethMap.capability.d.ts +2 -0
- package/dist/components/charts/geo/DistanceCartogram.capability.d.ts +2 -0
- package/dist/components/charts/geo/FlowMap.capability.d.ts +2 -0
- package/dist/components/charts/geo/ProportionalSymbolMap.capability.d.ts +2 -0
- package/dist/components/charts/index.d.ts +1 -1
- package/dist/components/charts/network/ChordDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/CirclePack.capability.d.ts +2 -0
- package/dist/components/charts/network/ForceDirectedGraph.capability.d.ts +2 -0
- package/dist/components/charts/network/OrbitDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/ProcessSankey.capability.d.ts +2 -0
- package/dist/components/charts/network/SankeyDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/TreeDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/Treemap.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/BarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/BoxPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/DonutChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/DotPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/FunnelChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/GaugeChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/GroupedBarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/Histogram.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/Histogram.d.ts +4 -2
- package/dist/components/charts/ordinal/LikertChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/LikertChart.d.ts +1 -1
- package/dist/components/charts/ordinal/LikertChart.defaults.d.ts +1 -0
- package/dist/components/charts/ordinal/PieChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/RidgelinePlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/StackedBarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/SwarmPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/SwimlaneChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/ViolinPlot.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeHeatmap.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeHistogram.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeLineChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeSwarmChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeWaterfallChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/TemporalHistogram.capability.d.ts +7 -0
- package/dist/components/charts/shared/chartSpecs.d.ts +0 -34
- package/dist/components/charts/xy/AreaChart.capability.d.ts +10 -0
- package/dist/components/charts/xy/BubbleChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/CandlestickChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/ConnectedScatterplot.capability.d.ts +2 -0
- package/dist/components/charts/xy/DifferenceChart.capability.d.ts +8 -0
- package/dist/components/charts/xy/Heatmap.capability.d.ts +9 -0
- package/dist/components/charts/xy/LineChart.capability.d.ts +9 -0
- package/dist/components/charts/xy/MinimapChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/MultiAxisLineChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/QuadrantChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/QuadrantChart.d.ts +5 -2
- package/dist/components/charts/xy/QuadrantChart.defaults.d.ts +2 -0
- package/dist/components/charts/xy/Scatterplot.capability.d.ts +2 -0
- package/dist/components/charts/xy/StackedAreaChart.capability.d.ts +2 -0
- package/dist/components/data/DataSummarizer.d.ts +45 -0
- package/dist/components/semiotic-ai.d.ts +35 -0
- package/dist/components/semiotic-xy.d.ts +1 -1
- package/dist/components/semiotic.d.ts +1 -1
- package/dist/components/store/useChartFocus.d.ts +43 -0
- package/dist/components/store/useChartInterrogation.d.ts +141 -0
- package/dist/ordinal.min.js +1 -1
- package/dist/ordinal.module.min.js +1 -1
- package/dist/semiotic-ai.d.ts +35 -0
- package/dist/semiotic-ai.min.js +1 -1
- package/dist/semiotic-ai.module.min.js +1 -1
- package/dist/semiotic-utils.min.js +1 -1
- package/dist/semiotic-utils.module.min.js +1 -1
- package/dist/semiotic-xy.d.ts +1 -1
- package/dist/semiotic.d.ts +1 -1
- package/dist/semiotic.min.js +1 -1
- package/dist/semiotic.module.min.js +1 -1
- package/dist/xy.min.js +1 -1
- package/dist/xy.module.min.js +1 -1
- package/package.json +13 -4
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` (
|
|
7
|
+
- **Use sub-path imports** — `semiotic/xy` (86KB gz), `semiotic/ordinal` (70KB gz), `semiotic/network` (64KB gz), `semiotic/geo` (52KB gz), `semiotic/realtime` (91KB gz), `semiotic/server` (122KB gz), `semiotic/utils` (22KB gz), `semiotic/recipes` (5KB gz), `semiotic/themes` (4KB gz), `semiotic/data` (3KB gz), `semiotic/ai` (211KB gz). Full `semiotic` is 190KB gz.
|
|
8
8
|
<!-- semiotic-bundle-sizes:end -->
|
|
9
9
|
- CLI: `npx semiotic-ai [--schema|--compact|--examples|--doctor]`
|
|
10
10
|
- MCP: `npx semiotic-mcp`
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
**Scatterplot** — `data`, `xAccessor`, `yAccessor`, `colorBy`, `sizeBy`, `sizeRange`, `pointRadius` (5), `pointOpacity` (0.8), `marginalGraphics`, `regression` (boolean | "linear" | "polynomial" | "loess" | RegressionConfig — sugar for a trend-annotation overlay; sits underneath user annotations)
|
|
31
31
|
**BubbleChart** — Scatterplot + `sizeBy` (required), `sizeRange` ([5,40]), `regression`
|
|
32
32
|
**ConnectedScatterplot** — + `orderAccessor`, `regression`
|
|
33
|
-
**QuadrantChart** — Scatterplot + `quadrants`
|
|
33
|
+
**QuadrantChart** — Scatterplot + optional `quadrants` overrides, `xCenter`, `yCenter`
|
|
34
34
|
**MultiAxisLineChart** — Dual Y-axis. `series` (required: `[{ yAccessor, label?, color?, format?, extent? }]`). Falls back to multi-line if not 2 series.
|
|
35
35
|
**Heatmap** — `data`, `xAccessor`, `yAccessor`, `valueAccessor`, `colorScheme`, `showValues`, `cellBorderColor`
|
|
36
36
|
**ScatterplotMatrix** — `data`, `fields` (array of numeric field names for grid)
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
**DonutChart** — PieChart + `innerRadius` (60), `centerContent`
|
|
53
53
|
**FunnelChart** — `stepAccessor`, `valueAccessor`, `categoryAccessor` (optional), `connectorOpacity`, `orientation`
|
|
54
54
|
**SwimlaneChart** — `categoryAccessor`, `subcategoryAccessor` (required), `valueAccessor`, `colorBy` (defaults to subcategoryAccessor), `orientation`, `roundedTop` (pixel radius applied to both outer ends of each lane — left+right for horizontal, top+bottom for vertical. Middle segments stay square so adjacent pieces butt against each other; single-segment lanes round all four corners.)
|
|
55
|
-
**LikertChart** — `categoryAccessor`, `valueAccessor`|`levelAccessor`+`countAccessor`, `levels
|
|
55
|
+
**LikertChart** — `categoryAccessor`, `valueAccessor`|`levelAccessor`+`countAccessor`, optional `levels`, `orientation`, `colorScheme`
|
|
56
56
|
**GaugeChart** — `value` (required), `min`, `max`, `thresholds`, `arcWidth`, `cornerRadius` (pixel radius for rounded segment ends — same semantics as DonutChart), `sweep`, `fillZones`, `showNeedle`, `centerContent`
|
|
57
57
|
|
|
58
58
|
All ordinal: `colorBy`, `colorScheme`, `categoryFormat` (string|ReactNode), `showCategoryTicks` (true).
|
|
@@ -267,6 +267,64 @@ Canvas scene builders read CSS variables via `getComputedStyle` on the canvas DO
|
|
|
267
267
|
## AI Features
|
|
268
268
|
`onObservation`/`useChartObserver`, `toConfig`/`fromConfig`/`toURL`/`fromURL`/`copyConfig`/`configToJSX`, `validateProps(component, props)`, `diagnoseConfig(component, props)`, `exportChart(div, { format })`, `npx semiotic-ai --doctor`
|
|
269
269
|
|
|
270
|
+
### Conversational Interrogation (`semiotic/ai`)
|
|
271
|
+
Headless hook for "chat with the chart" interactions. The library ships no UI — bring your own chat surface.
|
|
272
|
+
- **`useChartInterrogation({ data, onQuery, componentName?, props?, initialAnnotations? })`** → `{ ask(query), history, summary, annotations, loading, error, reset }`
|
|
273
|
+
- **`onQuery: (query, context) => Promise<{ answer, annotations? }>`** — call your LLM here. `context` is `{ data, summary, componentName?, props? }`.
|
|
274
|
+
- **`summary`**: LLM-friendly statistical summary (`rowCount`, per-field `{ min, max, mean, median }` for numerics, top-k for categoricals, ISO range for dates). Available before any ask().
|
|
275
|
+
- **`annotations`**: Merged `initialAnnotations` + latest AI response. Wire to the chart's `annotations` prop for visual highlighting.
|
|
276
|
+
- **`summarizeData(data, options?)`**: Standalone for server-side prompting or batch jobs.
|
|
277
|
+
- **MCP Tool**: `interrogateChart(component, props, query)` returns the same statistical summary and AI-facing instructions.
|
|
278
|
+
|
|
279
|
+
```jsx
|
|
280
|
+
import { LineChart, useChartInterrogation } from "semiotic/ai"
|
|
281
|
+
|
|
282
|
+
function InterrogatableChart({ data }) {
|
|
283
|
+
const { ask, history, annotations, loading } = useChartInterrogation({
|
|
284
|
+
data,
|
|
285
|
+
componentName: "LineChart",
|
|
286
|
+
props: { xAccessor: "month", yAccessor: "revenue" },
|
|
287
|
+
onQuery: async (query, { summary }) => {
|
|
288
|
+
const res = await myLLMCall(query, summary)
|
|
289
|
+
return { answer: res.text, annotations: res.highlights }
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
return (
|
|
293
|
+
<>
|
|
294
|
+
<LineChart data={data} xAccessor="month" yAccessor="revenue" annotations={annotations} />
|
|
295
|
+
<YourChatUI history={history} loading={loading} onAsk={ask} />
|
|
296
|
+
</>
|
|
297
|
+
)
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Chart Capability Layer (`semiotic/ai`)
|
|
302
|
+
Heuristic chart-suggestion engine. Charts ship capability descriptors next to their TSX files; the engine ranks them against a profiled dataset by intent. No LLM call required.
|
|
303
|
+
|
|
304
|
+
- **`profileData(data, { rawInput?, seriesField? })`** → `ChartDataProfile` (extends `DataSummary`): candidate fields per role (x/y/series/category/size/time), distinct counts, monotonicity, structure detection (hierarchy/network/geo).
|
|
305
|
+
- **`suggestCharts(data, { intent?, allow?, deny?, maxResults?, includeVariants?, minScore? })`** → ranked `Suggestion[]` with `{ component, family, importPath, variant?, score, intentScores, rubric, reasons, caveats, props }`. `props` is spreadable directly into the matching chart.
|
|
306
|
+
- **`scoreChart(component, data, { intent?, variantKey? })`** → evaluate a specific chart for a dataset (does it fit, how well, why/why not).
|
|
307
|
+
- **`useChartSuggestions(data, options)`** → memoized React hook returning `{ suggestions, profile }`.
|
|
308
|
+
- **`registerChartCapability(capability)`** / **`unregisterChartCapability(name)`** — runtime registration for custom charts.
|
|
309
|
+
- **Intent taxonomy**: 13 built-in intents (`trend`, `compare-series`, `compare-categories`, `rank`, `part-to-whole`, `distribution`, `correlation`, `flow`, `hierarchy`, `geo`, `outlier-detection`, `composition-over-time`, `change-detection`). Extend via `registerIntent(descriptor)`.
|
|
310
|
+
- **Capability authoring**: create `Foo.capability.ts` next to `Foo.tsx`, then append to the registry in `src/components/ai/chartCapabilities.ts`. Each capability declares `family`, `rubric` (familiarity/accuracy/precision 1-5), `fits(profile)` gate, `intentScores`, optional `variants` with `intentDeltas`, and `buildProps(profile, variant)`.
|
|
311
|
+
- **Variants encode that settings change what a chart is good for**: e.g. `StackedAreaChart`'s `streamgraph` variant boosts trend but penalizes part-to-whole.
|
|
312
|
+
- **Interrogation tie-in**: pass `includeSuggestions: true` to `useChartInterrogation` and the same ranked list lands in `context.suggestions` for the LLM.
|
|
313
|
+
- **MCP tool**: `suggestCharts(data, intent?)` returns the ranked list as structured content.
|
|
314
|
+
|
|
315
|
+
```jsx
|
|
316
|
+
import { useChartSuggestions, LineChart, BarChart, /* ... */ } from "semiotic/ai"
|
|
317
|
+
|
|
318
|
+
const COMPONENT_MAP = { LineChart, BarChart, /* ... */ }
|
|
319
|
+
function SuggestedChart({ data, intent }) {
|
|
320
|
+
const { suggestions } = useChartSuggestions(data, { intent })
|
|
321
|
+
const top = suggestions[0]
|
|
322
|
+
if (!top) return null
|
|
323
|
+
const Component = COMPONENT_MAP[top.component]
|
|
324
|
+
return <Component {...top.props} />
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
270
328
|
|
|
271
329
|
## AI Behavior Contracts
|
|
272
330
|
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ generate correct code without examples.
|
|
|
35
35
|
Semiotic ships with everything an AI coding assistant needs to generate
|
|
36
36
|
correct visualizations without trial and error:
|
|
37
37
|
|
|
38
|
-
- **`semiotic/ai`** — a single import with
|
|
38
|
+
- **`semiotic/ai`** — a single import with 42 HOC charts (XY, ordinal, network, realtime), optimized for LLM code generation. Geo charts are in `semiotic/geo` to keep d3-geo out of non-geo bundles.
|
|
39
39
|
- **`ai/schema.json`** — machine-readable prop schemas for every component
|
|
40
40
|
- **`npx semiotic-mcp`** — an MCP server for tool-based chart rendering in any MCP client
|
|
41
41
|
- **`npx semiotic-ai --doctor`** — validate component + props JSON from the command line with typo suggestions and anti-pattern detection
|
|
@@ -287,18 +287,18 @@ Semiotic ships 12 entry points. **Don't import from `"semiotic"` unless you need
|
|
|
287
287
|
|
|
288
288
|
| Entry Point | gzip | What's inside |
|
|
289
289
|
|---|---|---|
|
|
290
|
-
| `semiotic/xy` | **
|
|
291
|
-
| `semiotic/ordinal` | **
|
|
292
|
-
| `semiotic/network` | **
|
|
290
|
+
| `semiotic/xy` | **86 KB** | LineChart, AreaChart, Scatterplot, Heatmap, + 8 more XY charts |
|
|
291
|
+
| `semiotic/ordinal` | **70 KB** | BarChart, PieChart, BoxPlot, Histogram, + 11 more categorical charts |
|
|
292
|
+
| `semiotic/network` | **64 KB** | ForceDirectedGraph, SankeyDiagram, ProcessSankey, Treemap, + 4 more |
|
|
293
293
|
| `semiotic/geo` | **52 KB** | ChoroplethMap, FlowMap, DistanceCartogram, ProportionalSymbolMap |
|
|
294
|
-
| `semiotic/realtime` | **
|
|
294
|
+
| `semiotic/realtime` | **91 KB** | RealtimeLineChart, RealtimeHistogram, + 4 streaming charts |
|
|
295
295
|
| `semiotic/server` | **122 KB** | renderChart, renderDashboard, renderToImage, renderToAnimatedGif |
|
|
296
296
|
| `semiotic/utils` | **22 KB** | ThemeProvider, validators, serialization — no chart components |
|
|
297
297
|
| `semiotic/recipes` | **5 KB** | Pure layout functions (waffle, marimekko, flextree, dagre, …) |
|
|
298
298
|
| `semiotic/themes` | **4 KB** | Theme presets only (tufte, carbon, etc.) |
|
|
299
299
|
| `semiotic/data` | **3 KB** | bin, rollup, groupBy, pivot, fromVegaLite |
|
|
300
|
-
| `semiotic/ai` | **
|
|
301
|
-
| `semiotic` | **
|
|
300
|
+
| `semiotic/ai` | **211 KB** | All 42 HOCs + validation — optimized for LLM code generation |
|
|
301
|
+
| `semiotic` | **190 KB** | Everything below (full bundle) |
|
|
302
302
|
|
|
303
303
|
<!-- semiotic-bundle-sizes:end -->
|
|
304
304
|
|
|
@@ -389,8 +389,14 @@ No API keys or authentication required. The server runs locally via stdio. HTTP
|
|
|
389
389
|
| Tool | Description |
|
|
390
390
|
|------|-------------|
|
|
391
391
|
| **`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. |
|
|
392
|
-
| **`getSchema`** | Return the prop schema for a specific component. Pass `{ component: "LineChart" }` to get its props, or omit `component` to list all
|
|
393
|
-
| **`suggestChart`** |
|
|
392
|
+
| **`getSchema`** | Return the prop schema for a specific component. Pass `{ component: "LineChart" }` to get its props, or omit `component` to list all 46 chart schemas. Components marked `[renderable]` are available through `renderChart`; realtime charts require a browser/live environment. |
|
|
393
|
+
| **`suggestChart`** | Legacy sample-row recommender. Pass `{ data: [{...}, ...] }` with 1–5 sample objects plus optional broad intent/capability filters. |
|
|
394
|
+
| **`suggestCharts`** | Capability-based recommender for bounded row data. Returns ranked chart suggestions with scores, reasons, caveats, import paths, and ready-to-use props. |
|
|
395
|
+
| **`suggestStreamCharts`** | Recommend realtime charts from a stream schema, throughput, and retention hints. |
|
|
396
|
+
| **`suggestDashboard`** | Build a multi-panel dashboard suggestion that covers distinct analytical intents. |
|
|
397
|
+
| **`suggestStretchCharts`** | Recommend audience-literacy stretch picks from an `AudienceProfile`. |
|
|
398
|
+
| **`repairChartConfig`** | Check whether a requested chart fits a dataset and return ranked alternatives when it does not. |
|
|
399
|
+
| **`interrogateChart`** | Return a statistical summary and chart-aware context for answering natural-language questions with optional annotations. |
|
|
394
400
|
| **`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. |
|
|
395
401
|
| **`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. |
|
|
396
402
|
| **`applyTheme`** | List named theme presets or return ThemeProvider/CSS/token usage for a preset such as `{ name: "tufte" }`. |
|
|
@@ -401,6 +407,7 @@ No API keys or authentication required. The server runs locally via stdio. HTTP
|
|
|
401
407
|
|----------|-------------|
|
|
402
408
|
| **`semiotic://schema`** | Full machine-readable component schema JSON. |
|
|
403
409
|
| **`semiotic://components`** | Component index showing renderable/browser-only status and MCP categories. |
|
|
410
|
+
| **`semiotic://behavior-contracts`** | Agent-visible semantic rules for color precedence, required prop combinations, push refs, and renderability. |
|
|
404
411
|
| **`semiotic://system-prompt`** | Compact AI instructions with import rules, chart props, SSR guidance, and pitfalls. |
|
|
405
412
|
| **`semiotic://examples`** | Copy-paste chart examples by data shape. |
|
|
406
413
|
|
|
@@ -502,7 +509,7 @@ Semiotic is indexed by AI-coding-agent documentation tools so your assistant (Cl
|
|
|
502
509
|
|
|
503
510
|
Agent-facing API surface:
|
|
504
511
|
|
|
505
|
-
- **`CLAUDE.md`**, **`ai/schema.json`**, **`ai/behaviorContracts.cjs`** — bundled in the npm tarball (see `package.json#files`); agents that install Semiotic locally read these directly. `CLAUDE.md` is the quick-start cheat sheet (HOC props, push API, theming, usage notes); `ai/schema.json` is the JSON Schema for every chart's prop surface (
|
|
512
|
+
- **`CLAUDE.md`**, **`ai/schema.json`**, **`ai/behaviorContracts.cjs`** — bundled in the npm tarball (see `package.json#files`); agents that install Semiotic locally read these directly. `CLAUDE.md` is the quick-start cheat sheet (HOC props, push API, theming, usage notes); `ai/schema.json` is the JSON Schema for every chart's prop surface (46 charts); `ai/behaviorContracts.cjs` carries the agent-visible semantic rules (color precedence, push-mode requirements, ID-accessor contracts).
|
|
506
513
|
- [**`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.
|
|
507
514
|
|
|
508
515
|
## Documentation
|
package/ai/dist/mcp-server.js
CHANGED
|
@@ -32743,6 +32743,166 @@ Dark-mode presets: ${THEME_PRESET_NAMES.filter((n) => n.includes("dark")).join("
|
|
|
32743
32743
|
content: [{ type: "text", text: usage.join("\n") }]
|
|
32744
32744
|
};
|
|
32745
32745
|
}
|
|
32746
|
+
async function suggestChartsHandler(args) {
|
|
32747
|
+
const { data, intent, maxResults, allow, deny, audience } = args;
|
|
32748
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32749
|
+
const suggestions = (0, import_ai3.suggestCharts)(data, {
|
|
32750
|
+
intent: intentArg,
|
|
32751
|
+
allow,
|
|
32752
|
+
deny,
|
|
32753
|
+
maxResults: maxResults ?? 8,
|
|
32754
|
+
audience
|
|
32755
|
+
});
|
|
32756
|
+
const lines = [
|
|
32757
|
+
`${suggestions.length} suggestion${suggestions.length === 1 ? "" : "s"} for ${data.length} rows${intentArg ? ` (intent: ${intentArg.join(", ")})` : ""}:`,
|
|
32758
|
+
"",
|
|
32759
|
+
...suggestions.map((s, i) => {
|
|
32760
|
+
const variantTag = s.variant ? ` / ${s.variant.label}` : "";
|
|
32761
|
+
const reasons = s.reasons.length ? ` \u2014 ${s.reasons.join("; ")}` : "";
|
|
32762
|
+
const caveats = s.caveats.length ? `
|
|
32763
|
+
caveats: ${s.caveats.join("; ")}` : "";
|
|
32764
|
+
return `${i + 1}. ${s.component}${variantTag} (score ${s.score.toFixed(1)}/5, familiarity ${s.rubric.familiarity}, accuracy ${s.rubric.accuracy})${reasons}${caveats}`;
|
|
32765
|
+
})
|
|
32766
|
+
];
|
|
32767
|
+
return {
|
|
32768
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32769
|
+
structuredContent: { suggestions }
|
|
32770
|
+
};
|
|
32771
|
+
}
|
|
32772
|
+
async function suggestStreamChartsHandler(args) {
|
|
32773
|
+
const { schema: schema2, intent, maxResults } = args;
|
|
32774
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32775
|
+
const suggestions = (0, import_ai3.suggestStreamCharts)(schema2, {
|
|
32776
|
+
intent: intentArg,
|
|
32777
|
+
maxResults: maxResults ?? 8
|
|
32778
|
+
});
|
|
32779
|
+
const lines = [
|
|
32780
|
+
`${suggestions.length} stream chart suggestion${suggestions.length === 1 ? "" : "s"}${intentArg ? ` (intent: ${intentArg.join(", ")})` : ""}`,
|
|
32781
|
+
...schema2.throughput ? [`throughput: ${schema2.throughput}`] : [],
|
|
32782
|
+
...schema2.retention ? [`retention: ${schema2.retention}`] : [],
|
|
32783
|
+
"",
|
|
32784
|
+
...suggestions.map((s, i) => {
|
|
32785
|
+
const reasons = s.reasons.length ? ` \u2014 ${s.reasons.join("; ")}` : "";
|
|
32786
|
+
const caveats = s.caveats.length ? `
|
|
32787
|
+
caveats: ${s.caveats.join("; ")}` : "";
|
|
32788
|
+
return `${i + 1}. ${s.component} (score ${s.score.toFixed(1)}/5)${reasons}${caveats}`;
|
|
32789
|
+
})
|
|
32790
|
+
];
|
|
32791
|
+
return {
|
|
32792
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32793
|
+
structuredContent: { suggestions, schema: schema2 }
|
|
32794
|
+
};
|
|
32795
|
+
}
|
|
32796
|
+
async function suggestDashboardHandler(args) {
|
|
32797
|
+
const { data, intents, maxPanels, diversifyByFamily, audience } = args;
|
|
32798
|
+
const dashboard = (0, import_ai3.suggestDashboard)(data, {
|
|
32799
|
+
intents,
|
|
32800
|
+
maxPanels: maxPanels ?? 6,
|
|
32801
|
+
diversifyByFamily: diversifyByFamily !== false,
|
|
32802
|
+
audience
|
|
32803
|
+
});
|
|
32804
|
+
const lines = [];
|
|
32805
|
+
lines.push(`Dashboard: ${dashboard.panels.length} panels covering ${dashboard.intentsCovered.join(", ") || "\u2014"}`);
|
|
32806
|
+
if (dashboard.intentsMissing.length) {
|
|
32807
|
+
lines.push(`Intents this data couldn't fill: ${dashboard.intentsMissing.join(", ")}`);
|
|
32808
|
+
}
|
|
32809
|
+
lines.push("");
|
|
32810
|
+
for (let i = 0; i < dashboard.panels.length; i++) {
|
|
32811
|
+
const { intent, suggestion } = dashboard.panels[i];
|
|
32812
|
+
const variantTag = suggestion.variant ? ` / ${suggestion.variant.label}` : "";
|
|
32813
|
+
lines.push(`${i + 1}. [${intent}] ${suggestion.component}${variantTag} (score ${suggestion.score.toFixed(1)}/5)`);
|
|
32814
|
+
if (suggestion.reasons.length) lines.push(` ${suggestion.reasons.join("; ")}`);
|
|
32815
|
+
}
|
|
32816
|
+
if (dashboard.stretchPanels.length > 0) {
|
|
32817
|
+
lines.push("");
|
|
32818
|
+
lines.push(`Stretch picks (audience-unfamiliar but fitting):`);
|
|
32819
|
+
for (const stretch of dashboard.stretchPanels) {
|
|
32820
|
+
const variantTag = stretch.suggestion.variant ? ` / ${stretch.suggestion.variant.label}` : "";
|
|
32821
|
+
lines.push(` ${stretch.suggestion.component}${variantTag} (familiarity ${stretch.familiarity}) \u2014 ${stretch.rationale}`);
|
|
32822
|
+
}
|
|
32823
|
+
}
|
|
32824
|
+
return {
|
|
32825
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32826
|
+
structuredContent: dashboard
|
|
32827
|
+
};
|
|
32828
|
+
}
|
|
32829
|
+
async function suggestStretchChartsHandler(args) {
|
|
32830
|
+
const { data, audience, intent, maxResults } = args;
|
|
32831
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32832
|
+
const stretches = (0, import_ai3.suggestStretchCharts)(data, {
|
|
32833
|
+
audience,
|
|
32834
|
+
intent: intentArg,
|
|
32835
|
+
maxResults: maxResults ?? 5
|
|
32836
|
+
});
|
|
32837
|
+
const lines = [
|
|
32838
|
+
`${stretches.length} stretch pick${stretches.length === 1 ? "" : "s"} for "${audience.name ?? "audience"}":`,
|
|
32839
|
+
"",
|
|
32840
|
+
...stretches.map((s, i) => {
|
|
32841
|
+
const variantTag = s.suggestion.variant ? ` / ${s.suggestion.variant.label}` : "";
|
|
32842
|
+
const replacing = s.replacing ? ` (could replace ${s.replacing})` : "";
|
|
32843
|
+
return `${i + 1}. ${s.suggestion.component}${variantTag} (familiarity ${s.familiarity}/5)${replacing}
|
|
32844
|
+
${s.rationale}`;
|
|
32845
|
+
})
|
|
32846
|
+
];
|
|
32847
|
+
return {
|
|
32848
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32849
|
+
structuredContent: { stretches, audience: audience.name ?? null }
|
|
32850
|
+
};
|
|
32851
|
+
}
|
|
32852
|
+
async function repairChartConfigHandler(args) {
|
|
32853
|
+
const { component, data, intent, maxAlternatives } = args;
|
|
32854
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32855
|
+
const result = (0, import_ai3.repairChartConfig)(component, data, {
|
|
32856
|
+
intent: intentArg,
|
|
32857
|
+
maxAlternatives: maxAlternatives ?? 3
|
|
32858
|
+
});
|
|
32859
|
+
const lines = [];
|
|
32860
|
+
if (result.status === "ok") {
|
|
32861
|
+
lines.push(`\u2705 ${component} fits this dataset \u2014 no repair needed.`);
|
|
32862
|
+
} else if (result.status === "alternative") {
|
|
32863
|
+
lines.push(`\u26A0 ${component} doesn't fit: ${result.reason}`);
|
|
32864
|
+
lines.push("");
|
|
32865
|
+
lines.push(`Alternatives that fit${intentArg ? ` (ranked by intent: ${intentArg.join(", ")})` : ""}:`);
|
|
32866
|
+
for (let i = 0; i < result.alternatives.length; i++) {
|
|
32867
|
+
const s = result.alternatives[i];
|
|
32868
|
+
const variantTag = s.variant ? ` / ${s.variant.label}` : "";
|
|
32869
|
+
const reasons = s.reasons.length ? ` \u2014 ${s.reasons.join("; ")}` : "";
|
|
32870
|
+
lines.push(`${i + 1}. ${s.component}${variantTag} (score ${s.score.toFixed(1)}/5)${reasons}`);
|
|
32871
|
+
}
|
|
32872
|
+
} else {
|
|
32873
|
+
lines.push(`\u2753 No capability registered for "${component}". Closest matches:`);
|
|
32874
|
+
for (let i = 0; i < result.alternatives.length; i++) {
|
|
32875
|
+
const s = result.alternatives[i];
|
|
32876
|
+
lines.push(`${i + 1}. ${s.component} (${s.family}, score ${s.score.toFixed(1)}/5)`);
|
|
32877
|
+
}
|
|
32878
|
+
}
|
|
32879
|
+
return {
|
|
32880
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32881
|
+
structuredContent: result
|
|
32882
|
+
};
|
|
32883
|
+
}
|
|
32884
|
+
async function interrogateChartHandler(args) {
|
|
32885
|
+
const { component, props, query } = args;
|
|
32886
|
+
const data = props.data || props.nodes || [];
|
|
32887
|
+
const summary = (0, import_ai3.summarizeData)(data);
|
|
32888
|
+
const content = [
|
|
32889
|
+
{ type: "text", text: `Statistical summary for ${component}:
|
|
32890
|
+
${JSON.stringify(summary, null, 2)}` }
|
|
32891
|
+
];
|
|
32892
|
+
if (query) {
|
|
32893
|
+
content.push({
|
|
32894
|
+
type: "text",
|
|
32895
|
+
text: `User Question: "${query}"
|
|
32896
|
+
|
|
32897
|
+
Contextual instructions:
|
|
32898
|
+
1. Analyze the statistical summary to answer the question.
|
|
32899
|
+
2. Return a natural language response.
|
|
32900
|
+
3. Optionally suggest a JSON array of Semiotic annotations to visually highlight the answer on the chart (e.g. { type: "callout", x: "Mar", y: 1500, label: "Peak month" }).
|
|
32901
|
+
4. Use the accessor names from the provided props (e.g. xAccessor, yAccessor).`
|
|
32902
|
+
});
|
|
32903
|
+
}
|
|
32904
|
+
return { content, structuredContent: { summary, component, props } };
|
|
32905
|
+
}
|
|
32746
32906
|
function createServer2() {
|
|
32747
32907
|
const srv = new McpServer({
|
|
32748
32908
|
name: "semiotic",
|
|
@@ -32822,7 +32982,7 @@ function createServer2() {
|
|
|
32822
32982
|
"Use this MCP workflow:",
|
|
32823
32983
|
"1. Read semiotic://system-prompt for compact API rules and pitfalls.",
|
|
32824
32984
|
"2. Read semiotic://behavior-contracts for semantic rules that schema shape alone cannot express.",
|
|
32825
|
-
"3. If no component is specified, call
|
|
32985
|
+
"3. If no component is specified, call suggestCharts with representative rows and the intent.",
|
|
32826
32986
|
"4. Call getSchema for the selected component before writing JSX or renderChart props.",
|
|
32827
32987
|
'5. Call diagnoseConfig with usageMode="static" for renderChart/static data, or usageMode="push" for ref-based React code that intentionally omits data.',
|
|
32828
32988
|
"6. Fix all diagnoseConfig errors before presenting code.",
|
|
@@ -32927,6 +33087,93 @@ function createServer2() {
|
|
|
32927
33087
|
},
|
|
32928
33088
|
applyThemeHandler
|
|
32929
33089
|
);
|
|
33090
|
+
srv.tool(
|
|
33091
|
+
"interrogateChart",
|
|
33092
|
+
"Conversational interrogation of a Semiotic chart. Extract a statistical summary and answer natural language questions about the data, trends, and outliers. Returns a summary and guidance for an AI to generate a textual answer and visual annotations.",
|
|
33093
|
+
{
|
|
33094
|
+
component: external_exports3.string().describe("Chart component name, e.g. 'LineChart'"),
|
|
33095
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).describe("The full chart props including data"),
|
|
33096
|
+
query: external_exports3.string().optional().describe("A natural language question about the chart data")
|
|
33097
|
+
},
|
|
33098
|
+
interrogateChartHandler
|
|
33099
|
+
);
|
|
33100
|
+
srv.tool(
|
|
33101
|
+
"suggestStreamCharts",
|
|
33102
|
+
"Recommend realtime/streaming Semiotic charts for a schema (not row data). Pass a schema describing field types plus optional throughput ('low'|'medium'|'high') and retention ('windowed'|'cumulative') hints; the engine ranks realtime charts (RealtimeLineChart, RealtimeHistogram, RealtimeHeatmap, RealtimeWaterfallChart, RealtimeSwarmChart, TemporalHistogram) by their fit. Use when the user is wiring up a live dashboard or monitoring view rather than visualizing a bounded dataset.",
|
|
33103
|
+
{
|
|
33104
|
+
schema: external_exports3.object({
|
|
33105
|
+
fields: external_exports3.array(
|
|
33106
|
+
external_exports3.object({
|
|
33107
|
+
name: external_exports3.string(),
|
|
33108
|
+
kind: external_exports3.enum(["numeric", "categorical", "date", "boolean"]),
|
|
33109
|
+
role: external_exports3.enum(["x", "y", "value", "category", "series", "size"]).optional()
|
|
33110
|
+
})
|
|
33111
|
+
),
|
|
33112
|
+
throughput: external_exports3.enum(["low", "medium", "high"]).optional(),
|
|
33113
|
+
retention: external_exports3.enum(["windowed", "cumulative"]).optional()
|
|
33114
|
+
}).describe("Stream schema \u2014 fields plus throughput/retention hints. No row data."),
|
|
33115
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional().describe("Ranking intent."),
|
|
33116
|
+
maxResults: external_exports3.number().int().min(1).max(20).optional()
|
|
33117
|
+
},
|
|
33118
|
+
suggestStreamChartsHandler
|
|
33119
|
+
);
|
|
33120
|
+
srv.tool(
|
|
33121
|
+
"suggestDashboard",
|
|
33122
|
+
"Generate a dashboard of complementary chart panels for a dataset \u2014 each panel answers a distinct analytical intent (trend, rank, distribution, correlation, etc.) and the engine diversifies by chart family by default. Heuristic only; no LLM call. Use when the user asks 'show me this data' or 'build me a dashboard' rather than picking one chart.",
|
|
33123
|
+
{
|
|
33124
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
33125
|
+
intents: external_exports3.array(external_exports3.string()).optional().describe("Intents to cover. Omit to let the engine pick based on the data shape."),
|
|
33126
|
+
maxPanels: external_exports3.number().int().min(1).max(12).optional().describe("Maximum panels (default 6)."),
|
|
33127
|
+
diversifyByFamily: external_exports3.boolean().optional().describe("Prefer not to repeat chart families across panels (default true).")
|
|
33128
|
+
},
|
|
33129
|
+
suggestDashboardHandler
|
|
33130
|
+
);
|
|
33131
|
+
srv.tool(
|
|
33132
|
+
"suggestStretchCharts",
|
|
33133
|
+
"Recommend literacy-growth chart picks for a dataset given an AudienceProfile. Returns charts the data supports but the audience is unfamiliar with (familiarity \u2264 3, or \u2264 4 at exposureLevel 2), each paired with the familiar chart it could substitute for and a rationale. Use when the consumer wants to gently expose users to less familiar but more analytically appropriate visualizations.",
|
|
33134
|
+
{
|
|
33135
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data."),
|
|
33136
|
+
audience: external_exports3.object({
|
|
33137
|
+
name: external_exports3.string().optional(),
|
|
33138
|
+
familiarity: external_exports3.record(external_exports3.string(), external_exports3.number()).optional(),
|
|
33139
|
+
targets: external_exports3.record(
|
|
33140
|
+
external_exports3.string(),
|
|
33141
|
+
external_exports3.object({
|
|
33142
|
+
direction: external_exports3.enum(["increase", "decrease"]),
|
|
33143
|
+
weight: external_exports3.number().int().min(1).max(3).optional(),
|
|
33144
|
+
reason: external_exports3.string().optional()
|
|
33145
|
+
})
|
|
33146
|
+
).optional(),
|
|
33147
|
+
exposureLevel: external_exports3.union([external_exports3.literal(0), external_exports3.literal(1), external_exports3.literal(2)]).optional()
|
|
33148
|
+
}).describe("Audience profile \u2014 familiarity, targets, exposure level."),
|
|
33149
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional(),
|
|
33150
|
+
maxResults: external_exports3.number().int().min(1).max(20).optional()
|
|
33151
|
+
},
|
|
33152
|
+
suggestStretchChartsHandler
|
|
33153
|
+
);
|
|
33154
|
+
srv.tool(
|
|
33155
|
+
"repairChartConfig",
|
|
33156
|
+
"Validate that a chart component is a sensible choice for a dataset, and if not, propose alternatives that fit. Use when a user asks for a specific chart and you want to confirm it's appropriate, or when you've drafted a config and want to verify it. Returns either ok (no change needed), alternative (chart doesn't fit; here are ranked replacements with rationale), or unknown (no capability registered).",
|
|
33157
|
+
{
|
|
33158
|
+
component: external_exports3.string().describe("Chart component name to validate, e.g. 'PieChart'"),
|
|
33159
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
33160
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional().describe("User intent \u2014 informs ranking of alternatives when the chart doesn't fit."),
|
|
33161
|
+
maxAlternatives: external_exports3.number().int().min(1).max(10).optional().describe("Cap on alternatives returned (default 3).")
|
|
33162
|
+
},
|
|
33163
|
+
repairChartConfigHandler
|
|
33164
|
+
);
|
|
33165
|
+
srv.tool(
|
|
33166
|
+
"suggestCharts",
|
|
33167
|
+
"Recommend Semiotic charts for a dataset using heuristic capability descriptors. Each chart declares which data shapes it serves and which intents (trend, compare-categories, distribution, correlation, part-to-whole, etc.) it answers \u2014 the engine returns a ranked list with scores, reasons, caveats, and ready-to-use props. Heuristic only; no LLM call. Use the result as structured context when answering 'what chart should I use?' or generating chart code.",
|
|
33168
|
+
{
|
|
33169
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
33170
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional().describe("Ranking intent. One of: trend, compare-series, compare-categories, rank, part-to-whole, distribution, correlation, flow, hierarchy, geo, outlier-detection, composition-over-time, change-detection. Custom intents accepted."),
|
|
33171
|
+
maxResults: external_exports3.number().int().min(1).max(40).optional().describe("Cap on suggestions returned (default 8)."),
|
|
33172
|
+
allow: external_exports3.array(external_exports3.string()).optional().describe("Restrict to these component names."),
|
|
33173
|
+
deny: external_exports3.array(external_exports3.string()).optional().describe("Exclude these component names.")
|
|
33174
|
+
},
|
|
33175
|
+
suggestChartsHandler
|
|
33176
|
+
);
|
|
32930
33177
|
return srv;
|
|
32931
33178
|
}
|
|
32932
33179
|
var cliArgs = process.argv.slice(2);
|
|
@@ -32973,7 +33220,7 @@ async function main() {
|
|
|
32973
33220
|
});
|
|
32974
33221
|
httpServer.listen(port, () => {
|
|
32975
33222
|
console.error(`Semiotic MCP server (HTTP) listening on http://localhost:${port}`);
|
|
32976
|
-
console.error("Tools: getSchema, suggestChart, renderChart, diagnoseConfig, reportIssue, applyTheme");
|
|
33223
|
+
console.error("Tools: getSchema, suggestChart, suggestCharts, suggestStreamCharts, suggestDashboard, suggestStretchCharts, repairChartConfig, renderChart, interrogateChart, diagnoseConfig, reportIssue, applyTheme");
|
|
32977
33224
|
console.error("Resources: semiotic://schema, semiotic://components, semiotic://behavior-contracts, semiotic://system-prompt, semiotic://examples");
|
|
32978
33225
|
});
|
|
32979
33226
|
} else {
|
package/ai/schema.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"name": "semiotic",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.6.0",
|
|
5
5
|
"description": "React data visualization library for charts, networks, and beyond",
|
|
6
6
|
"tools": [
|
|
7
7
|
{
|
|
@@ -880,7 +880,29 @@
|
|
|
880
880
|
},
|
|
881
881
|
"quadrants": {
|
|
882
882
|
"type": "object",
|
|
883
|
-
"description": "
|
|
883
|
+
"description": "Optional configuration overrides for the four quadrants: { topRight, topLeft, bottomRight, bottomLeft }, each with partial { label, color, opacity }. Omitted quadrants and fields use built-in defaults.",
|
|
884
|
+
"default": {
|
|
885
|
+
"topLeft": {
|
|
886
|
+
"label": "Low / High",
|
|
887
|
+
"color": "#E9C46A",
|
|
888
|
+
"opacity": 0.08
|
|
889
|
+
},
|
|
890
|
+
"topRight": {
|
|
891
|
+
"label": "High / High",
|
|
892
|
+
"color": "#2A9D8F",
|
|
893
|
+
"opacity": 0.08
|
|
894
|
+
},
|
|
895
|
+
"bottomLeft": {
|
|
896
|
+
"label": "Low / Low",
|
|
897
|
+
"color": "#E76F51",
|
|
898
|
+
"opacity": 0.08
|
|
899
|
+
},
|
|
900
|
+
"bottomRight": {
|
|
901
|
+
"label": "High / Low",
|
|
902
|
+
"color": "#86BBD8",
|
|
903
|
+
"opacity": 0.08
|
|
904
|
+
}
|
|
905
|
+
}
|
|
884
906
|
},
|
|
885
907
|
"showQuadrantLabels": {
|
|
886
908
|
"type": "boolean",
|
|
@@ -913,9 +935,7 @@
|
|
|
913
935
|
"default": 0.8
|
|
914
936
|
}
|
|
915
937
|
},
|
|
916
|
-
"required": [
|
|
917
|
-
"quadrants"
|
|
918
|
-
]
|
|
938
|
+
"required": []
|
|
919
939
|
}
|
|
920
940
|
}
|
|
921
941
|
},
|
|
@@ -2160,7 +2180,14 @@
|
|
|
2160
2180
|
},
|
|
2161
2181
|
"levels": {
|
|
2162
2182
|
"type": "array",
|
|
2163
|
-
"description": "Ordered response labels, most negative to most positive
|
|
2183
|
+
"description": "Ordered response labels, most negative to most positive. Defaults to a 5-point Very Low to Very High scale. Odd count = center is neutral.",
|
|
2184
|
+
"default": [
|
|
2185
|
+
"Very Low",
|
|
2186
|
+
"Low",
|
|
2187
|
+
"Neutral",
|
|
2188
|
+
"High",
|
|
2189
|
+
"Very High"
|
|
2190
|
+
]
|
|
2164
2191
|
},
|
|
2165
2192
|
"categoryAccessor": {
|
|
2166
2193
|
"type": [
|
|
@@ -2206,9 +2233,7 @@
|
|
|
2206
2233
|
"default": 20
|
|
2207
2234
|
}
|
|
2208
2235
|
},
|
|
2209
|
-
"required": [
|
|
2210
|
-
"levels"
|
|
2211
|
-
]
|
|
2236
|
+
"required": []
|
|
2212
2237
|
}
|
|
2213
2238
|
}
|
|
2214
2239
|
},
|
package/ai/system-prompt.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- semiotic-bundle-sizes:start -->
|
|
4
4
|
<!-- Auto-generated by scripts/sync-bundle-sizes.mjs — do not edit by hand. -->
|
|
5
|
-
**Use sub-path imports** — `semiotic/xy` (
|
|
5
|
+
**Use sub-path imports** — `semiotic/xy` (86KB gz), `semiotic/ordinal` (70KB gz), `semiotic/network` (64KB gz), `semiotic/geo` (52KB gz), `semiotic/realtime` (91KB gz), `semiotic/server` (122KB gz), `semiotic/utils` (22KB gz), `semiotic/recipes` (5KB gz), `semiotic/themes` (4KB gz), `semiotic/data` (3KB gz), `semiotic/ai` (211KB gz). Full `semiotic` is 190KB gz.
|
|
6
6
|
<!-- semiotic-bundle-sizes:end -->
|
|
7
7
|
|
|
8
8
|
## Flat Array Data (`data: object[]`)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ChartRubric } from "./chartCapabilityTypes";
|
|
2
|
+
/**
|
|
3
|
+
* A serializable description of who's reading the charts and what the
|
|
4
|
+
* organization is trying to grow.
|
|
5
|
+
*
|
|
6
|
+
* Semiotic does not measure familiarity — it consumes measurements. Orgs
|
|
7
|
+
* produce an AudienceProfile through whatever channel makes sense (surveys,
|
|
8
|
+
* telemetry, manager judgment, training records) and pass it to the
|
|
9
|
+
* suggestion APIs. The library applies the bias and returns rankings that
|
|
10
|
+
* reflect the audience instead of a generic data-literate baseline.
|
|
11
|
+
*
|
|
12
|
+
* Strategy memo: docs/strategy/audience-profiles.md
|
|
13
|
+
*/
|
|
14
|
+
export interface AudienceProfile {
|
|
15
|
+
/**
|
|
16
|
+
* Display name. Surfaced in suggestion `reasons[]` when a target fires so
|
|
17
|
+
* users can see whose policy is influencing the ranking.
|
|
18
|
+
*/
|
|
19
|
+
name?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Per-chart familiarity override (1..5). Replaces the descriptor's
|
|
22
|
+
* `rubric.familiarity`. Charts not listed fall back to the descriptor.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* familiarity: { BarChart: 5, LineChart: 5, PieChart: 4, BoxPlot: 2 }
|
|
26
|
+
*/
|
|
27
|
+
familiarity?: Partial<Record<string, number>>;
|
|
28
|
+
/**
|
|
29
|
+
* Adoption targets — which charts the org is trying to grow or reduce.
|
|
30
|
+
* The engine applies a meaningful score bias (±1..3 depending on weight)
|
|
31
|
+
* so growth targets win close calls and decrease targets fall back unless
|
|
32
|
+
* they're the only fit.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* targets: {
|
|
36
|
+
* PieChart: { direction: "decrease", weight: 1 },
|
|
37
|
+
* BoxPlot: { direction: "increase", weight: 2,
|
|
38
|
+
* reason: "we want the team reading distributions, not means" }
|
|
39
|
+
* }
|
|
40
|
+
*/
|
|
41
|
+
targets?: Partial<Record<string, AudienceTarget>>;
|
|
42
|
+
/**
|
|
43
|
+
* Controls visibility of stretch picks (unfamiliar-but-relevant charts).
|
|
44
|
+
* 0 — never surface stretches; familiar-only rankings
|
|
45
|
+
* 1 — surface in a separate `stretchSuggestions` list (default when audience set)
|
|
46
|
+
* 2 — same as 1 but lowers the familiarity threshold (≤4) for what counts as stretch,
|
|
47
|
+
* widening the menu
|
|
48
|
+
*/
|
|
49
|
+
exposureLevel?: 0 | 1 | 2;
|
|
50
|
+
}
|
|
51
|
+
export interface AudienceTarget {
|
|
52
|
+
direction: "increase" | "decrease";
|
|
53
|
+
/** 1..3 — controls bias magnitude. Default 1. */
|
|
54
|
+
weight?: number;
|
|
55
|
+
/** Human-readable rationale. Surfaces in suggestion.reasons when the target fires. */
|
|
56
|
+
reason?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface AudienceBiasResult {
|
|
59
|
+
/** Composite score after audience adjustments. Unclamped — can range outside 0..5. */
|
|
60
|
+
score: number;
|
|
61
|
+
/** Effective rubric for the chart after audience overrides. */
|
|
62
|
+
rubric: ChartRubric;
|
|
63
|
+
/** Reason string to append to the suggestion when a target fired. */
|
|
64
|
+
appliedReason?: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Apply an AudienceProfile's bias to a chart's composite score and rubric.
|
|
68
|
+
* Pure function — used by both `suggestCharts` and `suggestStretchCharts`.
|
|
69
|
+
*
|
|
70
|
+
* Two terms compose additively:
|
|
71
|
+
* • Familiarity bias: (audienceFamiliarity − 3) × 0.5
|
|
72
|
+
* — Range ±1.0. At familiarity 5 we add 1.0; at 1 we subtract 1.0.
|
|
73
|
+
* • Target bias: ±1.0 × weight
|
|
74
|
+
* — Range ±3.0 for weight=3. Strong enough to reorder rankings,
|
|
75
|
+
* not so strong that it overrides chart correctness for the data shape.
|
|
76
|
+
*
|
|
77
|
+
* Score is left unclamped so internal sorting reflects the magnitude of bias.
|
|
78
|
+
*/
|
|
79
|
+
export declare function applyAudienceBias(baseScore: number, baseRubric: ChartRubric, component: string, audience: AudienceProfile | undefined): AudienceBiasResult;
|
|
80
|
+
/**
|
|
81
|
+
* Resolve the effective familiarity for a chart under an audience. Used by
|
|
82
|
+
* the stretch surface to decide whether a chart qualifies as "unfamiliar."
|
|
83
|
+
*/
|
|
84
|
+
export declare function effectiveFamiliarity(component: string, defaultFamiliarity: number, audience: AudienceProfile | undefined): number;
|
|
85
|
+
/**
|
|
86
|
+
* Familiarity threshold for what counts as a "stretch" pick under this audience.
|
|
87
|
+
* Tighter for exposureLevel 1, wider for 2. Returns the highest familiarity a
|
|
88
|
+
* chart can have and still appear in the stretch surface.
|
|
89
|
+
*/
|
|
90
|
+
export declare function stretchFamiliarityCeiling(audience: AudienceProfile | undefined): number;
|