Pascal Editor
Pascal architecture: flat nodes, registry dispatch and durable scene versions
Follow a building edit from Zustand scene state through node renderers to SQLite, keeping undo history, graphics and persistence separate.
What you will learn
- A graph stored as a flat map
- Node definitions decide how data becomes graphics
- Persistence is a separate authority
Before you start
- Basic scene-graph, JavaScript and HTTP concepts
- An owned small scene with expected dimensions and relationships
Explain the implementation boundary and reproduce the chapter’s checklist or narrow graph exercise.
Key takeaways
- Flat graph state carries hierarchy and plugin context.
- Registry availability and GPU readiness both affect visibility.
- Undo and durable version checks are different contracts.
A graph stored as a flat map
useScene stores nodes by ID plus rootNodeIds, materials, collections and installedPlugins. Parent and child links encode the hierarchy rather than nesting the entire model directly into React components. The initial scene explicitly connects site, building and level in both directions; this supports consumers that validate ownership differently from the renderer’s traversal.
setScene applies compatibility migrations, removes nodes with missing parents, normalizes roots and removes unreachable nodes when a usable root set exists. It performs one tracked state write so undo does not expose a half-normalized intermediate scene. Dirty-node marking then requests downstream work; the dirty set is not itself a persisted geometry cache.
Node definitions decide how data becomes graphics
NodeRenderer first checks that the node exists, its plugin kind is enabled and a registry definition is present. A custom renderer is loaded through React.lazy and cached by source identity in a WeakMap; otherwise a definition with geometry uses the generic parametric path. Unsupported or absent definitions return no rendered node, which explains why data presence and visible content can diverge.
The viewer’s capability module requests a WebGPU adapter/device, bounds that request and initialization, and attempts WebGL when needed. It releases an abandoned device and disposes failed renderers. Our injected-fake experiment exercised fallback orchestration, not real shader support or output parity; the active graphics backend belongs in any reproducible bug report.
Persistence is a separate authority
The SQLite store serializes scene JSON and measures its UTF-8 bytes against a configurable cap, defaulting to 10 MiB. save checks expectedVersion within a write transaction, increments the stored version and adds a scene revision. An existing explicitly named scene cannot be overwritten by save without an expected version. This is a concrete concurrency contract, not automatic conflict merging.
The returned metadata includes published: true, but in this local store that is a status field, not evidence that an Internet URL was deployed. Likewise, browser undo state and database revisions solve different recovery problems. Design an integration around the authority of each layer instead of letting a successful draw, an undo entry or a metadata flag stand in for all three.
Implementation steps
- 1
Trace one node from scene data to registry definition.
- 2
Inspect the selected renderer and dirty-node behavior.
- 3
Save with an observed version and handle conflicts explicitly.
- 4
Distinguish local metadata from public publication.
Copy-ready example
{"layers":["scene graph","registry and renderer","SQLite revision"],"existingVersion":3,"writeExpectedVersion":3,"nextVersionIfAccepted":4,"publishedFlagMeansInternetDeployment":false}Frequently asked questions
Does expectedVersion merge concurrent edits?
No. It detects a version mismatch so the caller can reload, compare and decide how to proceed.
Does published: true mean the project is online?
Not by itself. It is returned by the inspected local store and does not prove any public deployment.
Sources
- README.mdSource checked 2026-09-08
- LICENSESource checked 2026-09-08
- packages/cli/package.jsonSource checked 2026-09-08
- packages/core/package.jsonSource checked 2026-09-08
- packages/viewer/README.mdSource checked 2026-09-08
- packages/cli/src/runtime.tsSource checked 2026-09-08
- packages/cli/src/editor-process.tsSource checked 2026-09-08
- packages/cli/src/mcp-connector.tsSource checked 2026-09-08
- packages/mcp/src/transports/http.tsSource checked 2026-09-08
- packages/mcp/src/storage/sqlite-scene-store.tsSource checked 2026-09-08
- packages/core/src/store/use-scene.tsSource checked 2026-09-08
- packages/viewer/src/components/renderers/node-renderer.tsxSource checked 2026-09-08
- packages/viewer/src/lib/renderer-capability.tsSource checked 2026-09-08
- packages/core/src/validation/validate-build-json.tsSource checked 2026-09-08
- packages/core/src/utils/heal-scene-graph.tsSource checked 2026-09-08
- packages/mcp/src/storage/slug.tsSource checked 2026-09-08