@vizij/node-graph-wasm
v0.4.9
Published
WASM bindings for Vizij node-graph core.
Maintainers
Readme
@vizij/node-graph-wasm
Vizij’s node graph engine for JavaScript.
This package ships the WebAssembly build of vizij-graph-core together with a TypeScript wrapper, schema helpers, and sample graphs. Load Vizij GraphSpecs, stage host inputs, evaluate outputs, and update node parameters from any modern JS runtime without compiling Rust.
Table of Contents
Overview
- Built from
vizij-graph-corewithwasm-bindgen; the npm package is the canonical JavaScript distribution maintained by the Vizij team. - Provides a high-level
Graphclass, low-level bindings, TypeScript definitions, and ready-to-use fixtures. - Supports both browser and Node environments—
init()chooses the right loader and validates the ABI (abi_version() === 2). - Ships GraphSpec normalisers and schema inspection helpers so editors and tooling can speak the same language as Vizij runtimes.
- Bakes the node registry (
metadata/registry.json) straight from the Rust core so build-time tooling and authoring UIs stay in sync with the runtime.
Key Concepts
- GraphSpec – Declarative JSON describing nodes, parameters, and the explicit
edgesarray that connects node outputs to inputs (selectors, output keys). The package normalises shorthand specs automatically. - Graph Runtime – The
Graphclass owns aGraphRuntime, handlingloadGraph,stageInput,setParam,step, andevalAll. - Staged Inputs – Host-provided values keyed by
TypedPath. They are latched until you replace or remove them. - Evaluation Result –
evalAll()returns per-node port snapshots plus aWriteBatchof sink writes (each with Value + Shape metadata). - Node Schema Registry –
getNodeSchemas()exposes the runtime-supported nodes, ideal for palettes/editors. - ABI Guard –
abi_version()ensures the JS glue and.wasmbinary are compatible. Rebuild when versions change.
Installation
npm install @vizij/node-graph-wasm
# or pnpm add @vizij/node-graph-wasmFor local development inside Vizij:
pnpm run build:wasm:graph
cd npm/@vizij/node-graph-wasm
pnpm install
pnpm run buildLink into vizij-web while iterating:
(cd npm/@vizij/node-graph-wasm && pnpm link --global)
(cd ../vizij-web && pnpm link @vizij/node-graph-wasm)Bundler Configuration
Like the other Vizij wasm packages, this module now exports an ESM wrapper that first attempts a static import of the wasm-bindgen JS glue. Bundlers that support async WebAssembly (Webpack 5, Vite, etc.) should treat pkg/vizij_graph_wasm_bg.wasm as an emitted asset. For Next.js configure:
// next.config.js
module.exports = {
webpack: (config) => {
config.experiments = { ...(config.experiments ?? {}), asyncWebAssembly: true };
config.module.rules.push({
test: /\.wasm$/,
type: "asset/resource",
});
return config;
},
};If you host the wasm binary elsewhere, pass a string URL to init():
await init("https://cdn.example.com/vizij/node_graph_wasm_bg.wasm");Passing a string avoids Webpack’s RelativeURL helper, which previously attempted to call .replace() on a URL object.
API
async function init(input?: InitInput): Promise<void>;
function abi_version(): number;
async function normalizeGraphSpec(spec: GraphSpec | string): Promise<GraphSpec>;
async function getNodeSchemas(): Promise<Registry>;
function getNodeRegistry(): Registry;
function findNodeSignature(typeId: NodeType | string): NodeSignature | undefined;
function requireNodeSignature(typeId: NodeType | string): NodeSignature;
function listNodeTypeIds(): NodeType[];
function groupNodeSignaturesByCategory(): Map<string, NodeSignature[]>;
const nodeRegistryVersion: string;
async function logNodeSchemaDocs(nodeType?: NodeType | string): Promise<void>;
const graphSamples: Record<string, GraphSpec>;
class Graph {
constructor();
loadGraph(specOrJson: GraphSpec | string): void;
unloadGraph(): void;
stageInput(path: string, value: ValueInput, shape?: ShapeJSON, immediateEval?: boolean): void;
clearStagedInputs(): void;
applyStagedInputs(): void;
evalAll(): EvalResult;
setParam(nodeId: string, key: string, value: ValueInput): void;
setTime(t: number): void;
step(dt: number): void;
getWrites(): WriteOpJSON[];
clearWrites(): void;
waitForGraphReady?(): Promise<void>; // only populated when used through React provider
}Normalization, Schema & Docs Helpers
normalizeGraphSpec(spec)– round-trips any GraphSpec (object or JSON string) through the Rust normaliser so shorthand inputs/legacyinputsmaps come back with explicitedges, typed paths, and canonical casing.getNodeSchemas()/getNodeRegistry()– runtime and baked access to the node registry (including ports and params) for palette/editor usage.findNodeSignature(typeId)/requireNodeSignature(typeId)– quick lookups into the baked registry.listNodeTypeIds()/groupNodeSignaturesByCategory()– helpers for palettes or UI grouping.logNodeSchemaDocs(nodeType?)– pretty-prints the schema docs for every node or a specificNodeTyperight to the console (handy while prototyping editors).graphSamples– curated ready-to-load specs that already reflect the canonicaledgesform and typedpathparameters.
Each registry entry exposes:
| Field | Description |
|-------|-------------|
| doc / short_doc | Human-readable description for node palettes and tooltips. |
| inputs / outputs | Port metadata (label, doc, shape hints) useful for editors. |
| params | Parameter schema with expected value types and default values. |
| categories | Optional grouping tags for UI organisation. |
Types (GraphSpec, EvalResult, ValueJSON, ShapeJSON, etc.) are exported from src/types.
Usage
import {
init,
Graph,
normalizeGraphSpec,
graphSamples,
valueAsNumber,
} from "@vizij/node-graph-wasm";
await init();
const graph = new Graph();
const spec = await normalizeGraphSpec(graphSamples.vectorPlayground);
graph.loadGraph(spec);
graph.stageInput("demo/path", { float: 1 }, undefined, true);
const result = graph.evalAll();
const nodeValue =
result.nodes["const"]?.out?.value ?? { type: "float", data: NaN };
console.log("Node value", valueAsNumber(nodeValue));
for (const write of result.writes) {
console.log("Write", write.path, write.value);
}Manual time control:
graph.setTime(0);
graph.step(1 / 60);
graph.evalAll();Staging inputs lazily:
graph.stageInput("demo/path", { vec3: [0, 1, 0] });
graph.applyStagedInputs();
graph.evalAll();Custom loader options
init(input?: InitInput) accepts any input supported by @vizij/wasm-loader:
import { init } from "@vizij/node-graph-wasm";
import { readFile } from "node:fs/promises";
// Host wasm from your CDN
await init(new URL("https://cdn.example.com/vizij/node_graph_wasm_bg.wasm"));
// Node / Electron / tests
const bytes = await readFile("dist/node_graph_wasm_bg.wasm");
await init(bytes);This is useful for service workers, Electron, or any environment that needs explicit control over fetch behaviour.
Samples & Fixtures
The package exports several ready-to-run specs:
graphSamplesmap (e.g.,vectorPlayground,oscillatorBasics,logicGate).- Named exports (
oscillatorBasics,nestedTelemetry, etc.) for convenience. - Helpers:
import { loadNodeGraphBundle } from "@vizij/node-graph-wasm"; const { spec, stage } = await loadNodeGraphBundle("urdf-ik-position"); graph.loadGraph(spec); if (stage) { for (const [path, payload] of Object.entries(stage)) { graph.stageInput(path, payload.value, payload.shape); } }
Fixtures originate from @vizij/test-fixtures so tests and demos share the same assets.
Troubleshooting
- Selector mismatch – Errors such as
selector index 5 out of boundsmean the GraphSpec referenced an array element that does not exist. Normalise the spec and confirm upstream nodes emit the expected shape. set_paramvalidation – Parameters enforce specific value types (float,text, tuple pairs). Coerce values withnormalizeValueJSONbefore callingsetParamto avoid runtime throws.- ABI mismatch – Re-run
pnpm run build:wasm:graphifabi_version()differs from the expected version logged by the package. - Missing fixtures –
loadNodeGraphBundleresolves names from@vizij/test-fixtures. Ensurepnpm run build:sharedhas been executed in local development.
Development & Testing
pnpm run build:wasm:graph # regenerate pkg/
cd npm/@vizij/node-graph-wasm
pnpm testThe Vitest suite runs sample graphs through the wasm bridge, checking evaluation results and write batches. For Rust-side coverage, run cargo test -p vizij-graph-wasm.
Related Packages
vizij-graph-wasm– Rust crate producing the wasm build.vizij-graph-core– underlying evaluator.@vizij/node-graph-react– React integration built on this npm package.@vizij/value-json– shared value helpers used during staging.
Need assistance or spot a bug? Open an issue—robust bindings keep Vizij graphs portable. 🧠
Inspecting Schema Documentation
Each NodeSignature in the schema registry now ships with human-friendly descriptions for the node itself, its ports, and parameters.
import { getNodeSchemas, logNodeSchemaDocs } from "@vizij/node-graph-wasm";
await init();
// Fetch the registry and inspect docs programmatically.
const registry = await getNodeSchemas();
for (const node of registry.nodes) {
console.log(node.name, node.doc); // node.doc is a plain string
for (const port of node.inputs) {
console.log(" input:", port.label, port.doc);
}
}
// Or print a nicely formatted summary for all nodes…
await logNodeSchemaDocs();
// …or just a single node type.
await logNodeSchemaDocs("remap");The same documentation is embedded in the wasm JSON (get_node_schemas_json) so downstream tools can consume it without relying on these helpers.
