Skip to content

Semiotic v3.8.0

Choose a tag to compare

@emeeks emeeks released this 13 Jul 20:45

Added

  • StreamPhysicsFrame and physics process runtime. A deterministic,
    streaming physics frame for data stories where motion is the mechanism:
    sampling, lateness, queues, routing, collision, threshold crossing, and
    accumulation. It includes resident worker execution; running/paused/settled
    lifecycle; chart-derived colliders, regions, portals, absorption, forces,
    annotations, selection, observations, semantic interaction, and an imperative
    control surface; optional Matter and Rapier adapters; capacity queues, finite
    service-resource pools, service-level and dependency-gate controllers,
    journey ledgers, reference envelopes, and trace comparison; accessible
    settled projections and tables; deterministic SVG/evidence output and
    server-stepped animated GIF frames; plus EventDrop, Galton board, gauntlet,
    pile, collision, physical-flow, process-flow, and custom physics HOCs.

  • ChartContainer notifications. New notifications prop surfaces
    chart-level notices that have no single mark to anchor to (a data-pitfalls
    or accessibility-audit finding about the whole chart, an unplaceable
    data-quality result) and custom user-authored notes. They collapse into a
    single severity-colored toolbar bell with a count badge — the bell
    adopts the icon and color of the most severe visible notice — and clicking
    it opens a popover with the dismissible cards, so a notice arriving or
    being dismissed never reflows the chart body. Each ChartNotification is
    { id?, level?, title?, message, source?, dismissible? }; levels (info |
    success | warning | error | neutral) resolve through the theme's
    semantic role CSS variables, a screen-reader-only aria-live="polite"
    region announces the current count + most-severe level so notices arriving
    while streaming are still voiced with the popover collapsed, and dismissal
    is tracked internally by id with an onNotificationDismiss callback for
    host stores/telemetry. Semantic class hooks:
    semiotic-chart-notifications (wrapper), -toggle (bell), -badge,
    -popover, and semiotic-chart-notification + --{level} /
    -source/-title/-message/-dismiss (cards). Types exported from
    semiotic and semiotic/ai; demonstrated on the Chart Container feature
    page and the Chart Clinic example.

  • Worker-based force layout. ForceDirectedGraph gains layoutExecution
    ("auto" default | "worker" | "sync"), layoutLoadingContent, and
    onLayoutStateChange; in auto mode, layouts whose estimated cost
    (iterations × (nodes + edges)) exceeds a threshold settle in a short-lived
    module Web Worker and fall back to the synchronous path when workers are
    unavailable. New forceLayoutAsync() (Promise sibling of the forceLayout
    recipe, identical deterministic output) and useForceLayout() (React wrapper;
    SSR and first hydration stay synchronous for markup parity, and settled
    positions are memoized by graph identity + options so remounts don't re-enter
    a loading state). Ships a packaged forceLayoutWorker.js asset — CSP
    deployments need worker-src 'self'.

  • x-band annotation. Full-height vertical shaded region (x0, x1,
    fill, fillOpacity, label) for marking eras/phases, rendered by both the
    canvas annotation rules and static SSR output; annotations with a missing
    bound are skipped in both.

  • intervalLanesLayout minBarWidth (default 2): zero- and short-duration
    intervals stay visible and hoverable on long domains.

  • Custom-layout readback: ref.current.getCustomLayout(). All four custom
    chart HOCs (XY/Ordinal/Network/Geo) expose the most recent layout(ctx)
    result on their ref, beside getData()/getScales() — hosts that need the
    computed placement (stats readouts, inspectors, validation) no longer re-run
    the layout function themselves. null before the first layout or on
    built-in chart types.

  • unwrapDatum also unwraps .datum nesting (some interaction payloads
    nest the raw object there rather than under .data), and is now documented
    as the single unwrap path for both onObservation and
    frameProps.tooltipContent values.

Changed

  • Force layout model overhauled (degree-aware charge, degree-normalized link
    strength, radius-aware collision, weaker centering; the forceLayout recipe is
    now backed by d3-force). Layouts settle to better-spread positions, but the
    same seed produces different geometry than earlier 3.x betas — regenerate
    position-pinned snapshots. forceStrength documentation was corrected to its
    actual link-attraction semantics, and its response curve changed with the new
    model, so hand-tuned values may need revisiting.
  • intervalLanesLayout packs in rendered-pixel space, so the minBarWidth
    floor and inclusive end + unit extension can no longer overlap a same-track
    neighbor (previously visible as darker doubled fills when one interval ended
    the same unit the next began).
  • DataPitfalls and GoFish adapters remain experimental. The DataPitfalls
    bridge is exposed from semiotic/experimental as
    unstable_toDataPitfallsChain / unstable_buildDataPitfallsBridge, with
    return-path helpers for DataPitfalls PR #35 reports:
    unstable_toDataPitfallsNotifications for chart-level findings and
    unstable_toDataPitfallsAnnotations for host-anchored Semiotic v3
    annotations. The GoFish DisplayList adapter remains unstable_fromGofishIR
    on the same endpoint. Neither adapter is part of the stable API surface yet.
  • Force layout worker session. runForceLayoutWorker reuses a long-lived
    ForceLayoutWorkerSession (request IDs, no spawn/terminate per layout),
    matching the physics worker lifecycle. Abort cancels the pending request
    without killing the shared worker.
  • Growing-window default cap. windowMode: "growing" now defaults
    maxCapacity to 100_000 (was 1_000_000). Dev builds log a one-time
    warning when the buffer first crosses 50_000 points.
  • world-atlas is an optional peer. Built-in reference geographies still
    work when the package is installed; consumers who never call
    resolveReferenceGeography no longer take it as a hard dependency.
    (Still a devDependency for tests/docs.)
  • Library build target raised from es2015 to es2020.
  • CI: full gate suite runs once on Node 22; other engines run a smoke
    matrix (install, dist, vitest, typecheck).
  • size-limit budgets added for physics, server, ai, recipes,
    utils, and value entry points.
  • Stream frames memoized: StreamXYFrame, StreamOrdinalFrame,
    StreamNetworkFrame, StreamGeoFrame, and StreamPhysicsFrame are
    React.memo-wrapped so parent re-renders with stable props skip the
    frame body.
  • Interaction canvas idle skip on XY and Geo (one clear when hover ends).
  • Shared frameThemeColors module for version-cached theme/background
    resolution (StreamXYFrame uses it; other frames can adopt the same helper).
  • RingBuffer.resize uses slice for shrink (avoids O(n²) shift loops
    when a growing window hits its cap).
  • pipelineIdentityOps shared helpers for id-keyed remove/update paths.
  • Shared paintCanvasBackground helper used by XY / Ordinal / Network / Geo
    frames (CSS-var-safe fill, transparent + backgroundGraphics opt-outs).
  • Network dirty-canvas path: full clear/redraw only when data, transition,
    particles, encodings, or continuous animation need it — annotation-only rAF
    retries no longer thrash the data canvas.
  • Root entry diet: physics HOCs (GaltonBoardChart, GauntletChart,
    PhysicsPileChart, etc.) are no longer exported from semiotic. Import
    from semiotic/physics (or semiotic/ai for tooling). Measured full
    package entry ~233 KB gz (was ~296 KB gz).
  • XY decay/pulse share a version-cached datum→index map
    (buildDatumIndexMap) so continuous frames do not rebuild the map twice.
  • Geo dirty-canvas path: hover-only repaints skip the data canvas and
    only update the interaction layer.
  • Shared paintNeeds helpers (needsDataCanvasPaint /
    needsInteractionCanvasPaint) used by Network/Geo/XY paint gates.
  • Test typecheck is clean: baseline emptied (~228 → 0 known errors).
    Cleared keyboardNav (82), ordinalSceneBuilders (45), recipes, heatmap,
    hydration suites, networkColoring, and the remaining debt files.

Deprecated

  • GuantletChart typo alias of GauntletChart — use GauntletChart.
    Removal planned for the next major.

Docs

  • CONTRIBUTING.md / DEVELOPMENT.md updated for the tsup + Vite toolchain
    (removed stale Rollup/Parcel/src/processing guidance).