You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
CrucibleChart. A new physics-backed HOC (semiotic/physics) where
bounded peer components undergo authored phases and events, form
declared products, and settle into reason-labelled outlets with source
lineage — the ledger/projection is authoritative, motion never infers
classification, timing, membership, loss, or routing. buildCrucibleProductEvents(...) is pure authoring sugar for combine → contribute* → complete-product. The ref handle's replay()
atomically restarts the deterministic tape mid-run; reset()
restores-and-pauses. Ships with SSR support, AI/schema registration
(CrucibleChart.capability.ts), and full test coverage.
Word Trails recipe.wordTrailsLayout (semiotic/recipes) is a
quantitatively anchored word-cloud layout: column = category, segment =
ordered vertical position, weight = font size, with overlap-free stable
placement. wordTrailsProgressiveReveal(...) fades future/past segments
without reflow for scrollytelling-style reveals.
Net Ensemble recipe.netEnsembleLayout (semiotic/recipes) lays out
ensembles of disconnected/trivially-connected DAGs as small multiples in
motif bands — splitting into weakly-connected components, classifying each
by directedness (single sink vs. branching), and grouping order-isomorphic
motifs via Weisfeiler–Leman fingerprinting. analyzeNetEnsemble(nodes, edges) is the pure headless census with no rendering. Demo at /recipes/net-ensemble.
DistanceCartogram strip layout. A new cartogramLayout: "radial" | "strip" prop adds a Langren-style 1D cost-axis layout (origin left, cost
right), used automatically in mode="sparkline" and available in any mode.
ForceDirectedGraph node/edge stroke separation.nodeStroke/ nodeStrokeWidth (node-only outline) and edgeColor/edgeWidth/ edgeOpacity (edge-only stroke) let a caller style nodes and edges
independently; the generic stroke/strokeWidth/opacity props continue
to style all marks uniformly. Precedence per property: specific > generic >
built-in default.
RenderEvidence exposes the resolved margin and plot rectangle. renderChartWithEvidence now returns margin: {top,right,bottom,left} and plot: {x,y,width,height} — the actual geometry Semiotic used after
auto-reservation (e.g. a legend), matching exactly where the SVG's data-area group is translated. A caller hand-drawing an SSR overlay no
longer has to guess or conservatively bail when it can't reconstruct the
plot rectangle from its input margin alone.
Chart-aware numeric data audit.semiotic/ai, semiotic/ai/core, semiotic/utils, and semiotic/utils/core now export auditData, formatDataAudit, profileNumericFields, and toDataAuditNotifications.
Serializable numericContracts on chart
capabilities detect non-finite/non-numeric values, zero-span or single-row
domains, invalid log inputs, negative size geometry, unsafe normalized or
part-to-whole totals, and scale-dominating outliers with bounded row evidence. diagnoseConfig inherits the checks, schema-driven docs playgrounds show a
live Data Truth Lens, and ChartContainer dataAudit can surface findings in
its existing accessible notification bell.
Data Viz for Dummies example. A scrollytelling example organizes seven
chart families by a two-way taxonomy (data structure vs. analytical task)
through a fictional basketball season.
Changed
Frame-batched network ingestion. Sequential StreamNetworkFrame.push()
calls now share one layout pass per animation frame instead of recomputing the
whole layout for every edge. pushMany() absorbs pending single-push layout
work into its synchronous batch; reads/mutations flush first, and clear()
cancels uncommitted layout work so imperative semantics stay deterministic.
Fixed
renderChart honors custom svgAnnotationRules server-side. A chart's svgAnnotationRules (top-level or frameProps) now runs during static/SSR
rendering the same way it does on the client — custom annotation shapes
(endpoint bulbs, hover guides, bespoke glyphs) no longer silently vanish from renderChart/renderChartWithEvidence output. Passed through for XY,
ordinal, network, and geo static render paths alike.
SSR annotation context now infers frameType from scales/projection,
matching the client overlay. A non-ordinal static render (geo, bare
network) no longer advertises a default vertical ordinal projection,
which could make a custom svgAnnotationRules rule branching on frame type
resolve incorrectly server-side.
frameProps escape-hatch overrides for showAxes/showLegend/ showLabels/showGrid/xLabel/yLabel/categoryLabel/valueLabel no
longer silently dropped in renderChart. The static common-prop builder
used to reassert each of these from the mode-resolved default after
spreading frameProps, clobbering an explicit override the live HOC
otherwise honors (frameProps spreads last there). A chart passing frameProps={{ showAxes: false }} (or any of the above) server-side now
renders identically to the live component instead of always showing the
mode's default axis/label chrome.
Ordinal x-threshold annotation now renders in SSR. On a horizontal
ordinal chart (bar, swimlane, etc.) the value axis IS the x axis, but the
static renderer never populated an XY-style scales.x for ordinal frames,
so x-threshold always silently dropped — while the client (OrdinalSVGOverlay)
already resolved it correctly against the r-scale. x-threshold now mirrors
the same orientation-aware resolution y-threshold already had.
profileNumericFields no longer misclassifies dirty-numeric strings.
Whitespace-only strings (" ") now count as missing rather than
non-numeric, and an explicit "NaN"/"Infinity"/"-Infinity" string now
counts as a non-finite hazard rather than being lumped in with unparseable
garbage — distinguished from garbage (which also parses to NaN) by the
literal token, not the parsed value.
PhysicsSettledSVG's renderBodySVG now receives the resolved idPrefix. A custom body renderer emitting its own <defs> (a <filter>, a gradient) can namespace those ids — SVG ids are
document-global, so without this, two settled-physics SVGs embedded in one
document could collide and mis-apply each other's filter. CrucibleChart's settled-product glow filter now uses it.