Edit text. See the tree. Collaborate in real-time.
Canopy is an incremental projectional editor where text and abstract syntax trees stay perfectly synchronized — powered by CRDTs for real-time collaboration. Built in MoonBit, targeting WebAssembly.
The naming follows an organic metaphor: loom weaves structure, seam joins layers, and the canopy emerges above the trees as the surface you interact with.
Try the demo · Architecture · Paper (eg-walker)
Most editors treat source code as flat text. Canopy treats it as a living tree.
Text and tree are two views of the same truth. Type in the text editor and watch the AST update instantly. Restructure a node in the tree view and see the source code regenerate. Both directions, always consistent.
Collaboration through CRDTs, not central servers. Canopy uses the eg-walker algorithm with FugueMax — a sequence CRDT that preserves user intent even under concurrent edits. No operational transform, no conflict resolution hacks.
Incremental by design. The parser framework (loom) achieves O(1) subtree reuse through position-independent CST nodes. Edit one character, reparse one subtree — the rest is shared from the previous parse.
Principled architecture. The entire pipeline — parsing, projection, rendering — follows an incremental hylomorphism pattern: unfold text into trees, fold trees into views, and do it incrementally.
The demo language is lambda calculus with arithmetic — small enough to understand fully, rich enough to exercise every feature:
λx.x -- identity
(λf.λx.f x) 5 -- application
1 + 2 - 3 -- arithmetic
if x then 1 else 0 -- conditionals
let double = λx.x + x -- definitions
double 5
Prerequisites: MoonBit and Node.js
git clone --recursive https://github.com/dowdiness/canopy.git
cd canopy
moon testRun the projectional editor locally:
moon build --target js
cd examples/rabbita && npm install && npm run devOpens at localhost:5173.
Monorepo with reusable libraries extracted as git submodules:
| Module | Description |
|---|---|
| event-graph-walker | CRDT library — eg-walker algorithm with FugueMax |
| loom | Incremental parser framework with position-independent CST |
| editor | Editor abstractions — SyncEditor, text/tree synchronization |
| projection | Projectional editing — ProjNode, TreeEditorState |
| Example | Description |
|---|---|
| rabbita | Projectional editor with tree-first UI — the main demo |
| ideal | Extended rabbita with inspector panel and benchmark suite |
| web | Text-only CRDT editor with real-time syntax highlighting |
| demo-react | React 19 + Valtio demo with undo/redo and collaboration |
| prosemirror | ProseMirror + CodeMirror integration example |
The relay-server provides a Cloudflare Workers relay for peer-to-peer CRDT sync.
- Architecture — Incremental Hylomorphism, Anamorphism Discipline, Projectional Editing
- Development — Workflow, conventions, testing
- Performance — Benchmarks and optimization notes
# Run all tests
moon test
# Format and update interfaces
moon info && moon fmt
# Benchmarks (always use --release)
moon bench --releaseSee Development Guide for the full workflow, including submodule management.