Repository navigation
Semiotic v3.13.0
Network camera and semantic zoom
The opt-in semiotic/network/zoom camera keeps custom layouts in authored
coordinates while synchronizing canvas, SVG, HTML cards, hit testing and
keyboard focus. This release improves camera and pointer-update performance,
adds discrete LOD subscriptions, viewport insets, mark-id navigation, camera
anchoring across layout runs and retained-scene SVG export, and supports
ordinary-arrow panning as an explicit keyboard policy. Existing charts and
default arrow-key node navigation retain their behavior.
Added
zoomOptions.keyboard: { arrowKeys: "pan" }opts ordinary arrow keys into
60-screen-pixel panning. Alt+arrows still pan and plus/minus still zoom.
Boolean settings retain their behavior;{ arrowKeys: "navigate" }explicitly
selects default node navigation. Editable content and browser shortcuts are
unaffected.exportNetworkViewSVGfromsemiotic/server,semiotic/server/nodeand
semiotic/server/edgeexports a retained network scene with a fitted, identity
or explicit camera. SVG backgrounds, marks and card overlays are preserved;
HTML cards require SVG equivalents. Fit supports explicit decoration bounds
and scales outside the interactive camera's limits.- Custom network layouts can return
edgeHitTesting: falseto keep node
interactions while skipping edge hover, clicks, and cursors. useNetworkLODLevel(width, options)fromsemiotic/network/zoomreturns a
discrete detail level without rerendering cards for unchanged levels during
camera movement. It preserves hysteresis, settle-only promotion, and focused
editor detail throughkeepDetail.zoomOptions.insetsreserves screen-pixel plot strips covered by chrome such
as an inspect panel. Fit, reveal, pan bounds and centered zoom (buttons,
plus/minus keys, locked axes) use the remaining viewport; changing insets
alone does not move the camera. The handle addscenterOn(rectOrPoint, { k?, duration?, insets? }), andfitToContentaccepts{ padding, minZoom, maxZoom, duration };paddingmay be set per side, and
unspecified sides keepfitPadding.- Mark-id camera navigation:
getMarkBounds(id)reads an HTML mark's box, or
else a scene node's, from the retained layout, alongsidecenterOnMark,
fitToMarksandrevealMark.zoomOptions.anchor: { markId }keeps that
mark's center at the same screen position when the layout runs again,
translating the camera once per layout commit.NetworkZoomSourceadds
"center"and"anchor". useNetworkZoom(selector, isEqual?)rerenders only when the selected camera
value changes.- Compositional DAG interfaces from
semiotic/recipes/core:
prepareCompositionalGraphvalidates versioned nodes, parts, ports, edges
and explicit transfers, where every connection keeps its own ID;
routeCompositionalGraphsolves authored positions inroute-onlymode or
explicit order freedoms in boundedoptimizemode and reports infeasible
pins, missing anchors, unsupported compound routing and congestion through
diagnostics;compositionalDagLayoutrenders the solved layout through
NetworkCustomChart.patchCompositionalGraph,traceCompositionalGraph,
CompositionalLayoutController,createCompositionalWorkerEngine,
installCompositionalWorker,projectCompositionalScrolland
CompositionalMeasurementTransactioncover mutation, tracing, asynchronous
engines, scrolling and measurement;CompositionalNavigatorfrom
semiotic/recipes/reactadds keyboard access to parts and ports. Solved
layouts are deeply frozen without freezing the caller's graph, view or
geometry objects. See/custom-charts#compositional-dags,
/examples/compositional-dagand/examples/pipeline-explorer. - Network edge identity:
frameProps={{ edgeIdentity: "id", edgeIdAccessor }}
keys edges by their own IDs instead of the source+target pair, so duplicate
connections between the same owners stay distinct across bounded data,
pushes, updates and static rendering. The frame ref adds
updateEdgeById(id, updater)and single-IDremoveEdge(id). Clear retained
push data before switching back to pair identity. - EventDrop live mode:
liveenables incremental admission, camera follow,
bounded body retirement and a historical ledger;emittersruns built-in
fixed-step sources in sync or worker execution;arrival: { mode: "travel" }
animates bodies from source tiles withhistory: "present" | "travel";
sources,sourceRail,sourceAccessor,onSourceClickandwindowChrome
describe and style sources and windows;timeUnitfixes pacing units;
onLedgerChange,onWatermarkChangeandonClockTick(throttled by
clockTickMs) report admission, watermark and clock state; the handle adds
getLedger,getSourceStats,getWatermark,getClock,setTimeScale,
snapshotandrestore.semiotic/physicsexportsuseEmitters,
syntheticArrivals,createSyntheticEmitterand the pure
EventDropLedger. Live rows without a finite event time are skipped with a
development warning, as replay already skipped them. See
/examples/emitter-playground. registerPhysicsLivePrograms()fromsemiotic/physicsenables
PhysicsPipelineStoreemittersand liveeventDropprograms when you
construct or restore a store yourself. EventDropChart and the physics worker
register them automatically, so other physics charts no longer bundle the
EventDrop live runtime: aGaltonBoardChart-only import drops from
100.6 to 93.3 KiB gzip.- FlowCircuitChart, DependencyForestChart and MotifBraidChart accept
tooltip. FlowCircuitChart's flat view now shows the same module and pipe
tooltips as its projected view; passtooltip={false}to hide them. - Physics frames show tooltips for semantic items drawn in SVG overlays: an
element whosedata-semiotic-semantic-idnames an item gets pointer hover,
observations and dismissal, rendered bysemanticItemTooltipContentor a
chart'stooltipcallback. - Escape dismisses a pointer tooltip in every frame family without moving the
pointer (WCAG 1.4.13); the next pointer move shows it again.
Changed
- Static SVG IDs carry a per-chart prefix, so the groups named for Figma layers
read<prefix>-data-area,<prefix>-axesand so on.chartIdsets the
prefix; otherwise it derives from the rendered markup, so identical input
renders byte-identical SVG while charts that differ in size, data, theme or
any other rendered detail never share gradient, clip, pattern or title IDs
when inlined in one document. Repeated identical charts share IDs unless
they receive distinctchartIdvalues.renderDashboardscopes its charts
the same way. - XY charts paint their background in an SVG layer beneath the grid and keep
the mark canvas transparent, as ordinal charts do, so gridlines and axis
baselines draw under data marks instead of over them. Browser PNG export
composites those SVG background layers under the canvas. The firstrect
in an XY chart is now that full-frame backdrop, so select annotation shapes
by their own classes. - Zero-duration programmatic camera moves (
zoomTo(view, 0),panBy, and
zero-duration fit, center, reset and anchoring) apply in a microtask instead
of the next animation frame. A correction made from a React effect therefore
paints in the same frame as the layout change, with newly visible cards
mounted; moves chained in one task compose. Wheel, drag, pinch and keyboard
input still apply once per animation frame.
Fixed
- Physics
tooltip={false}hides tooltips without stopping hover
observations, linked hover or selection, as in every other family. - Live physics stores report
settledonce handoffs, bounded producers and
bodies finish, and an uncapped settle (including reduced motion) holds
producers instead of advancing the live clock to the step limit. - Live EventDrop changes to window size, units, origin or emitter source
schedules start a new run instead of failing inside an effect. - Physics worker mirrors keep host pushes, removals, pauses and restores
through worker frames computed before the worker received them, including a
worker restart; a removal during an in-flight tick no longer falls back to
synchronous execution, and replacing a worker while a command is pending no
longer disables worker execution for the chart. - Compositional worker engines reject pending requests on a Worker
error
or portmessageerror, and the worker reports a result it cannot post.
Acceptance rejects unknown statuses and terminals attached to another
node's display box. Large graphs no longer overflow the argument limit while
bounding, and indexed terminal lookups halve route-only solves of 800
owners and 4,000 edges. - Charts commit the overlay state a canvas repaint sets (axes, annotations,
interactive graphics, network HTML marks and overlays) in the same animation
frame, so a data or config update no longer shows new marks against the
previous frame's axes, annotations or cards. Network data and layout
rebuilds skip the 30 Hz overlay throttle, which still applies to animation
and transition frames. A fresh client mount paints its canvas and overlay
before the browser displays its first frame instead of one animation frame
later. - Physics chart resizes and encoding changes preserve arrival state: visible
bodies stay visible, queued arrivals keep their deadlines and order, and
removed bodies stay removed. This fixes late arrivals disappearing from the
watermark lesson during responsive relayouts. - Tooltips commit their placement before paint, including size changes that
ResizeObserver reports after browser layout, while preserving flipping,
boundary clamping, transitions and resize behavior. - Static network exports apply default label colors without mutating retained
labels, supporting frozen scenes and reuse across themes. - Static network rendering preserves custom scenes and SVG decorations supplied
without raw topology, including saved layouts used for export. - Network content bounds include pointed and rotated symbol paths, preventing
automatic fit from clipping triangles, stars and custom symbols. - Network tooltip and keyboard-focus updates subscribe independently of the
retained frame. Custom edge indexes preserve exact Canvas hits, node priority
and paint order while pruning overlapping cubic links with conservative
sub-curve bounds. Color-only restyles reuse the index; geometry, stroke and
fill changes refresh it. Keyboard announcements now honor authored
accessibility.tableFields, matching accessible data tables. - Network path hits reject distant candidates using cached conservative
bounds before exact Canvas tests. Custom layouts prepare a spatial index at
scene commit, preserving first-hover responsiveness, stroke tolerance under zoom,
filled bands, sharp joins, and changes to retained geometry or styles. - Uncontrolled network camera updates apply HTML/SVG transforms and repaint
canvas synchronously without rerendering the chart. Culling updates mounted
cards only when membership changes; viewport reports, focused tooltips and
annotation widgets stay current during motion. Existing projected-size and
LOD hooks retain live sizes. Invisible semantic edge targets skip Canvas paint
while remaining interactive. - Network zoom gestures preserve node and edge clicks and touch taps while
drag-to-pan is enabled. Pointer capture now stays on the original target;
clicks following a drag remain suppressed. - Tooltip content that paints its own surface inside a component (a
styled-components tooltip, for example) shows one box. Semiotic reads
data-semiotic-tooltip-chromeon the rendered root element, through any
wrapper components, in addition to the element a renderer returns, so neither
the renderer nor its wrappers needmarkTooltipChrome. Content that renders
nothing, such as a wrapper component returningnull, shows no box. This
covers every frame tooltip (XY, ordinal, network, geo, physics, and
ScatterplotMatrix) andTooltipRootwithout an explicitchrome; an explicit
chartchromeconfig still wins. - A tooltip whose chrome is dropped after rendering is placed from its
re-measured box, and that first placement jumps instead of easing from the
chrome-sized position.
Security
- MCP HTTP mode now rejects browser origins unless explicitly listed in
MCP_ALLOWED_ORIGINSand validates Host against the bind hostname by default.
These checks also cover preflight, health, and challenge requests. Configure
MCP_ALLOWED_HOSTSfor hosted services and tunnels; binding to all interfaces
does not disable Host validation. Native clients without Origin and the
default stdio transport continue to work. CORS no longer grants wildcard access.
Ahost:443orhost:80entry also matches a Host header without a port,
which HTTPS clients send, and alocalhostbind accepts127.0.0.1and
::1. The hosted smoke test now requires a 403, without a CORS grant, for an
unlisted browser Origin. - The bundled MCP server builds against
@modelcontextprotocol/sdk1.32.0
(from 1.31.0), taking the SDK's October 2026 security releases. Semiotic does
not use the affected task store, bearer-auth or client transports, and its
own row, cell and nesting limits already bound tool input.