Package Exports
- @vizij/node-graph-wasm
- @vizij/node-graph-wasm/metadata
- @vizij/node-graph-wasm/metadata/registry.json
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
- Key Concepts
- Installation
- API
- Usage
- Samples & Fixtures
- Development & Testing
- Related Packages
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.