Skip to content

Semiotic v3.8.5

Choose a tag to compare

@github-actions github-actions released this 23 Jul 00:41
95dbdc1

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.