Repository navigation
SpatialBoard 0.3.0
Six fixes and additions driven by real host-app usage of the data-flow board.
Added
fitToContent/fitToNodes(and their animated variants) accept options:padding(canvas-space margin, defaults unchanged),insets(screen-pixel bands reserved for host chrome floating over the canvas — content centers in the remaining region), andmaxZoom(framing-zoom cap, so fitting a single small node stops zooming all the way in).FitOptions/FitInsetsare exported from both the board andspatialboard/engineentries. Option values are sanitized: a NaN/InfinitypaddingormaxZoomand negative/non-finite insets can never poison the viewport transform.- Fits requested before the board's first size measurement are parked and applied when the container measures, instead of framing the 2000×1500 stand-in defaults. A
fitToContent()inside a seeding effect now just works — no more double-rAF / setTimeout dances in hosts.fitToFrameparks the same way, and attaching a different container re-arms parking (a reused engine remounted into another panel waits for the new measurement instead of framing the previous container's size). Headless engines (no container attached) keep fitting immediately. PortValueadmits arrays (unknown[]): matrices, vectors, and token lists flow through ports directly instead of being wrapped in an object to satisfy the type. (Note for consumers narrowingPortValue: aftertypeof v === "object"the type is nowRecord<string, unknown> | unknown[]— code assigning that to aRecordor indexing by string needs anArray.isArraybranch.)
Changed
- Output change detection is deep (SameValueZero primitives, arrays, plain objects, depth-capped), and a flush now skips downstream nodes whose upstream outputs did not actually change — a freshly built but structurally equal payload no longer recomputes the downstream graph. A
computethat reads external state and relied on those accidental recomputes should callmarkDirtyexplicitly. Structural comparison applies to plain data only: Date, Map, Set, class instances, and subclassed arrays compare by reference, so a fresh exotic instance always counts as a change.
Fixed
- Duplicate port wires between the same pair of nodes no longer make the target read as a cycle (its
computesilently never ran;cycleNodeIdsflagged it). The topological sort now counts in-degree per unique adjacency, so twin wires — easy to create from a StrictMode double-run seeding effect — cannot wedge a node.createEdgeadditionally returns the existing edge id for an exact duplicate port wire instead of stacking a twin. animatePanTo(x, y, 0)— and any camera animation given a zero, negative, or NaN duration — now snaps to the target instead of tweening elapsed/0 into NaN viewport transforms that blanked the canvas.- Port wires no longer intercept pointer events over the solid cards they cross: buttons, inputs, and draggable cells inside a card stay clickable under a crossing wire. The wire remains selectable in the gaps, and the right-click "Objects here" list reaches it even where a card covers it. Freeform edges keep their full hit priority, so annotation arrows over images behave as before.
- An inline
nodeTypesprop (nodeTypes={[...coreBoardNodes, myType]}, the README pattern) no longer rebuilds the registry — and recomputes the whole data-flow graph — on every host render; when acomputepublished into host state, that rebuild loop could hang the page.
Full details in CHANGELOG.md.