@nodebraid/renderer-svg
Package is not publicly released
This name describes the current source-module boundary; it does not mean the package can be installed from npm. Follow the source-based Quick Start to verify it.
Problems it solves
@nodebraid/renderer-svg is the first official concrete Provider for @nodebraid/renderer-api. It projects Document, Session, Hit Testing, and standardized browser input into an application-owned SVGSVGElement, validating the Renderer contract against a real DOM without leaking SVG types into Kernel, Session, or the public Renderer API.
It provides generic rectangular Nodes, straight Edges, and a stable DOM seam. It does not interpret product Node types, business data, or component frameworks.
When to use it
- You need an official Renderer Provider that integrates with an existing SVG element;
- You want to verify the complete Renderer path across Document Commits, Selection, Viewport, Hit Testing, and browser input;
- Your application will define product visuals and editing behavior through CSS and higher-level Interaction;
- You want to use a named Factory directly or connect it to the Runtime through
@nodebraid/plugin-renderer.
If the product needs HTML/React component Nodes, arbitrary Port shapes/positions, complex Edges, component mounting, or complete editor interaction, this package is not a substitute for those capabilities.
What it provides
- A synchronous
createSvgRenderer(config)Factory bound to one existingSVGSVGElement; - Generic rectangular Nodes, straight Edges, Selection markers, and Viewport projection;
- A real-DOM bridge for Pointer, Wheel, Keyboard, Focus, and Pointer Capture;
- Node Drag, Viewport Pan, Box Selection marquee, and Connection Preview Projections plus Port or Node-level source/target Anchor Hit Results;
- canonical boundary Geometry, stable DOM seams, and port-qualified Edge endpoints for source/target Ports;
- CSS-screen-pixel to SVG-user-space conversion and semantic Hit Testing;
- Stable classes,
data-nodebraid-*attributes, canonical layer order, and keyed DOM identity; - Atomic Document/Session updates, continuous revision validation, rollback on failure, and reset recovery;
- Provider-specific
SvgRendererErrorvalues plus the complete structured Renderer contract errors.
The Provider manages only the projection subtree it creates under the Target. The caller retains ownership of existing SVG content; disposal removes only Provider-owned content.
Dependencies and composition
This package depends on the backend-neutral contract from @nodebraid/renderer-api and the Kernel, Session, Interaction Projection, and Diagnostics value contracts used by it. It does not depend on the Plugin Host, a framework adapter, the Interaction state machine, or @nodebraid/core.
Applications can create the Renderer directly. To get Runtime lifecycle and Kernel/Session synchronization, pass createSvgRenderer to @nodebraid/plugin-renderer. NodeBraid does not select this Provider by default, and @nodebraid/core does not re-export it.
Public entry points
import {
createSvgRenderer,
SvgRendererError,
type SvgDomEventPolicy,
type SvgInputPolicies,
type SvgRendererConfig,
type SvgNodeContentContext,
type SvgNodeContentFactory,
type SvgRendererErrorCode,
} from '@nodebraid/renderer-svg';
const target = document.querySelector<SVGSVGElement>('#canvas');
if (!target) throw new Error('Missing SVG target.');
const renderer = createSvgRenderer({
target,
edgeHitTolerance: 4,
input: {
wheel: { preventDefault: true },
},
});
try {
// Deliver Document and Session projections through the Renderer contract.
} finally {
await renderer.dispose();
}Factory config is an immutable Provider-specific value. target is required; edgeHitTolerance is a non-negative CSS-pixel value; and input controls preventDefault / stopPropagation policies separately for Pointer, Wheel, Keyboard, and Context Menu events.
DOM and styling seam
The Provider writes geometry, stable classes, and data-nodebraid-* attributes, but it does not inject a runtime theme. Applications can start with minimal styles:
.nodebraid-renderer-svg__node {
fill: white;
stroke: currentColor;
}
.nodebraid-renderer-svg__edge {
stroke: currentColor;
}
.nodebraid-renderer-svg__connection-anchor,
.nodebraid-renderer-svg__port {
r: 4px;
fill: currentColor;
}
[data-nodebraid-selected='true'] {
stroke-width: 2;
}These attributes are stable seams for CSS, tests, and light DOM integration, not a business-component API. Semantic Node and Edge Hit Testing follows the Provider's Geometry model rather than the browser paint target.
Lifecycle and error semantics
An available Target can host only one SVG Renderer Instance at a time. The Factory synchronously validates config, Target type, connection state, dimensions, coordinate transforms, and occupancy. The Target remains reserved from creation until asynchronous cleanup finishes so two instances cannot interleave ownership of one projection.
| Code | Applicable failure |
|---|---|
INVALID_CONFIG | Unknown config keys, an invalid tolerance, or invalid input policies |
INVALID_NODE_CONTENT | Invalid, mounted or already-owned SVG content |
INVALID_TARGET | target is not a valid SVGSVGElement |
TARGET_OCCUPIED | Another active or still-cleaning-up Instance owns the Target |
TARGET_UNAVAILABLE | The Target is disconnected, has no usable size, or has no invertible CTM |
Document revision, Session, Input subscriber, Pointer, and disposed-state failures continue to use RendererError from @nodebraid/renderer-api. The Provider does not swallow failures. Structural validation occurs before projection changes, and a failure that cannot be rolled back safely explicitly requires the next reset to rebuild the Baseline.
Limitations and non-goals
- Requires explicit Node Size, uses rectangular interaction bounds, and renders straight Edges between valid endpoints;
- Nodes without Ports use node-level Connection Anchors; Ports use canonical boundary Geometry, while self-loops, curved Edges, Edge markers/labels, component lifecycles and animation remain unsupported;
- No default theme, theme Registry, component slots, or framework adapter;
- Does not interpret Interaction behavior and provides no Commands, drag state machine, Selection writes, or persistence; it only displays an accepted semantic Projection;
- Does not create the SVG Target or take ownership of the caller's existing Target children;
- Not a default Renderer and provides no Registry, default export, or Plugin wrapper.
Verification evidence
Type tests lock down the named synchronous Factory, Config, and error entry points. Bun tests cover config and value semantics. Real-Chromium tests cover SVG and Interaction projection, DOM identity, continuous Commits, Session, Hit Testing, screen-to-SVG coordinate conversion, ResizeObserver, native input policies, Pointer Capture, lost capture, Focus, Runtime Plugin composition, Target reservation, rollback, and disposal. Declaration-artifact checks also ensure that public entry points do not leak implementation details.
Custom Node content
SvgRendererConfig.createNodeContent synchronously constructs fresh, unattached SVG content from nodeId, type, size, opaque data and the target's document. The application interprets its own data and uses Node-local coordinates. The Provider owns the returned subtree and stable outer Node, positioning, Selection, rectangular hit bounds and Ports. There is no component or event-resource lifecycle.
Without the callback the original rectangle DOM is retained. A reset reconstructs content; ordinary commits rebuild it only for new Nodes or type/size/data changes. Dragging, position, Selection and Viewport changes preserve content. Circle visuals still have rectangular hits. No automatic clipping is introduced.
All candidate content is prepared before live DOM mutation, and child replacement participates in rollback. Invalid output and original callback failures are exposed. This Renderer atomicity cannot undo a Kernel Commit already consumed by Runtime; application validation belongs before data submission.
Every reset also reconstructs content when Runtime independently registers or disposes a Port Contribution at the same Document revision. This keeps the existing Renderer protocol: an incremental Port geometry change is distinct from a Port-only Runtime reset.