@metta-ts/grapher
The visual node-graph editor for MeTTa, MeTTaGrapher. It renders a program two ways, as a node graph and as nested blocks, and runs on the same interpreter as the rest of the packages. A node graph is a MeTTa atom, so anything that produces atoms feeds it.
npm install @metta-ts/grapherIt is pure SVG with no runtime dependency. GIF export takes an encoder as an argument, so you only install gifenc if you want that one feature.
The fluent driver
grapher(el) is the quickest way in, in the same style as the eDSL. Every building step returns the handle, so a chain reads as one sentence; the terminal steps source(), gif(), and destroy() end it.
import { grapher } from "@metta-ts/grapher";
grapher("#app")
.load("(= (double $x) (* $x 2))\n(double 21)")
.blocks() // or .graph()
.play(); // animate the reduction| step | does |
|---|---|
load(source) | replace the program from MeTTa source |
atoms(atoms) | replace it from atoms (e.g. eDSL output) |
graph() / blocks() | choose the view |
palette(choice) | recolor the blocks: "site", "teal", or a palette object |
play() | play the reduction of the query |
source() | end the chain, returning the current MeTTa source |
gif(encoder) | end the chain, returning an image/gif Blob (pass await import("gifenc")) |
destroy() | tear down and free the instance |
.grapher | the underlying MeTTaGrapher instance, for anything the chain does not cover |
The MeTTaGrapher class
import { MeTTaGrapher } from "@metta-ts/grapher";
const editor = new MeTTaGrapher(document.getElementById("app")!, { source: "(+ 10 (* 25 2))" });GrapherOptions is { source?: string }. The embedded editor on each docs page also stores its live instance on the canvas element (document.querySelector(".mg-canvas").grapher), so you can drive it from the console.
Loading and reading
| method | returns | does |
|---|---|---|
loadSource(src) | void | replace the whole program from source |
loadAtoms(atoms) | void | replace it from atoms |
load(json) | void | restore a saved graph exactly, positions and all |
save() | GraphJson | serialize the graph to JSON |
toSource() | string | the program as MeTTa source |
atoms() | Atom[] | one atom per head |
View, layout, and camera
| method | does |
|---|---|
setViewMode("graph" | "block") | switch between the node graph and the nested blocks |
setBlockPalette(palette) | recolor the blocks view |
tidy() | lay the graph out as tidy trees and fit it to the view |
fitView(padding?) | fit the current content to the viewport |
zoomBy(factor) | zoom about the center |
panBy(dx, dy) | pan by a screen delta |
Evaluating
| method | does |
|---|---|
evaluate(nodeId) | evaluate every head the node belongs to and label each with its result |
evaluateAll() | evaluate every head in the graph |
completions(prefix) | symbol completions for the node-creation input |
Playing a reduction
playTrace builds a step-by-step trace on the engine and shows the first state; the rest step through it.
| method | returns | does |
|---|---|---|
playTrace(nodeId?) | void | start a playthrough of a head (the given node, or the current query) |
traceForward() / traceBack() | void | step one reduction |
traceRestart() | void | jump back to the first state |
stopTrace() | void | leave the playthrough and return to the editable program |
isTracing() | boolean | whether a playthrough is on |
traceInfo() | { index, total } | null | position in the trace |
setTraceDuration(ms) | void | how long each step's morph takes, so a host's speed control can slow the animation itself |
uiState() | object | a snapshot of view mode, tracing, and control availability, for mirroring into a host UI |
Blocks view
| method | returns | does |
|---|---|---|
blockReduce() | boolean | reduce the focused block one step |
blockBack() | boolean | undo the last block reduction or edit |
blockCanStepBack() | boolean | whether an undo is available |
blockSource() | string | the block view's current program as source |
GIF export
const blob = await editor.exportReductionGif(await import("gifenc"), { width: 720, holdMs: 260 });exportReductionGif(encoder, opts?) returns an image/gif Blob (or null if there is nothing to animate). GifOptions covers width, framesPerStep, maxFrames, and holdMs (how long to hold each settled state, which a host maps from its playback speed).
Events and lifecycle
| method | does |
|---|---|
onChange(cb) | called when the graph changes; returns an unsubscribe function |
onViewChange(cb) | called on any view-state transition (view switch, playthrough step, load) |
onBlockChange(cb) | called on a block-view edit or reduction |
destroy() | remove listeners and the SVG |
Driving appearance from MeTTa
Alongside the program's own space &self, the editor watches an isolated space, &grapher. A program adds directive atoms to it and the editor overlays them; because they live in their own space they never mix with the program's atoms.
!(add-atom &grapher (color (fact 5) red))
!(add-atom &grapher (highlight if))
!(add-atom &grapher (background "#141a2e"))| directive | effect |
|---|---|
(color TARGET COLOR) | fill the node; COLOR is a name (red) or a #hex |
(highlight TARGET) | ring the node |
(focus TARGET) | frame the node |
(label TARGET TEXT) | write text above the node |
(background COLOR) | theme the whole canvas (global, no target) |
A TARGET is a node's name (if, reaching every if) or the term a node stands for ((fact 5), kept exactly as written). Reachable from MeTTa, from TypeScript through the space, or from the eDSL building the atom. bindVizSpace(space), readViz(space) (returns { directives, background }), colorOf, and textOf are exported for reading the space yourself.
Encoding a GIF without the class
reductionGif(states, settings, encoder, opts?) encodes a reduction, given as its list of states (each a frontier of atoms), to a GIF blob directly. This is the routine exportReductionGif wraps. GifEncoderLib is the slice of gifenc it needs, and GifOptions also carries stepMs (milliseconds per morph frame) alongside the fields above.
Lower-level building blocks
For embedding or customizing, the package also exports the pieces the editor is built from: the Graph model (GraphNode, NodeKind); the atom bridge (atomToGraph, graphToAtoms, composeAtom); parseProgram; layout; serialization (toJson, fromJson, toSource, fromSource); evaluation (evaluateHead, loadProgram); the step tracer (reduceStep, reduceTrace); node coloring (colorFor, roleOf); the Renderer and Controller; the Viewport helpers; and the block view (BlockView, layoutAtom, SITE_PALETTE, TEAL_PALETTE).