Skip to content

@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.

bash
npm install @metta-ts/grapher

It 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.

ts
import { grapher } from "@metta-ts/grapher";

grapher("#app")
  .load("(= (double $x) (* $x 2))\n(double 21)")
  .blocks() // or .graph()
  .play(); // animate the reduction
stepdoes
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
.grapherthe underlying MeTTaGrapher instance, for anything the chain does not cover

The MeTTaGrapher class

ts
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

methodreturnsdoes
loadSource(src)voidreplace the whole program from source
loadAtoms(atoms)voidreplace it from atoms
load(json)voidrestore a saved graph exactly, positions and all
save()GraphJsonserialize the graph to JSON
toSource()stringthe program as MeTTa source
atoms()Atom[]one atom per head

View, layout, and camera

methoddoes
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

methoddoes
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.

methodreturnsdoes
playTrace(nodeId?)voidstart a playthrough of a head (the given node, or the current query)
traceForward() / traceBack()voidstep one reduction
traceRestart()voidjump back to the first state
stopTrace()voidleave the playthrough and return to the editable program
isTracing()booleanwhether a playthrough is on
traceInfo(){ index, total } | nullposition in the trace
setTraceDuration(ms)voidhow long each step's morph takes, so a host's speed control can slow the animation itself
uiState()objecta snapshot of view mode, tracing, and control availability, for mirroring into a host UI

Blocks view

methodreturnsdoes
blockReduce()booleanreduce the focused block one step
blockBack()booleanundo the last block reduction or edit
blockCanStepBack()booleanwhether an undo is available
blockSource()stringthe block view's current program as source

GIF export

ts
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

methoddoes
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.

metta
!(add-atom &grapher (color (fact 5) red))
!(add-atom &grapher (highlight if))
!(add-atom &grapher (background "#141a2e"))
directiveeffect
(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).

Released under the MIT License.