research / nodebox
One NodeBox, on the web
NodeBox exists twice: a classic Java desktop app (immutable node graphs, list-matching evaluation, subnetworks) and NodeBox Live, a web version (node types as JavaScript source, JSON documents, data tables). This experiment researches — and prototypes — the ultimate version: what one web-based NodeBox should keep from each ancestor.
The one-sentence answer
Take Java NodeBox's semantics — immutable documents, list-matching evaluation, subnetworks with published ports, deterministic seeds — and NodeBox Live's substance — JSON documents, node types as editable JavaScript, a clean core/UI split — and make the two composition mechanisms one thing: every node type is typed ports + an implementation, whether that implementation is a built-in function, an ES module stored in the document, or a nested network.
From the Java version
List-matching (one rect node → 144 rectangles, shorter inputs cycling) ·
subnetworks as nodes, published ports, breadcrumbs · immutable document + structural
sharing → snapshot undo and identity-keyed render cache · frame/mouse only via
context ports · explicit seeds everywhere · fuzzy node-insert dialog ·
draggable numbers.
From NodeBox Live
JSON document format with sparse values + formatVersion migrations · code nodes: a node type is an ES module source string in the document · core ← runtime ← UI layering, headless-capable core · Canvas2D network editor · SVG export · static-JSON publishing model (documented, faked here).
Try this in the demo
The starter document animates a grid of 144 rectangles sized and colored by their distance to a wandering point — built from ~10 nodes and all three implementation kinds.
- Press ▶ — the
framenode drives twowavenodes. - Select
grid1and drag the “columns” number label. - Double-click
size1 ▸— that's a subnetwork (distance → convert_range) with published ports; press u to come back up. - Double-click empty canvas, type “gear” — a code node stored in the
document. Wire
grid1into its position: one gear per grid point, no loop written anywhere. Edit its source via ƒ. - Select nodes and press ⌘G to group them into a subnetwork. ⌘Z undoes anything. Export the result as svg.
Architecture
core/ |
no-DOM ES modules, JSDoc-typed: graphics.js (plain-data paths/groups,
Canvas2D + SVG renderers), model.js (immutable document, node types, code
node compiler), eval.js (list-matching evaluator + cache),
stdlib.js (~60 classic nodes), persistence.js (fake backend)
|
|---|---|
ui/ |
React 19 + Tailwind via ES import maps and CDN — no build step, htm
instead of JSX. Canvas network editor, parameter panel, viewer, insert/code dialogs.
|
doc/ |
COMPARISON.md — the two codebases, studied · DECISIONS.md — every tradeoff, with what was given up |
What's intentionally fake
Persistence. The demo “saves” to localStorage through
core/persistence.js, which mimics the real API (list/load/save + debounced
autosave) and documents what a backend needs — modeled on NodeBox Live's server: JWT auth,
whole-document JSON saves, publish-to-static-hosting so playback and embedding never touch
the API. Also deferred, by design not omission: code-node sandboxing, expressions, viewer
handles, text nodes, data tables, path booleans — each has a documented landing spot in
DECISIONS.md.
A research experiment · research.enigmeta.com · README