Write. It structures itself.
Canopy is an editor that understands your program, not just your characters. As you type, it parses incrementally, shows you scope and types, evaluates expressions live, and formats your code — all without leaving the flow. Two people can edit the same document simultaneously, with no server. Edits merge automatically.
Try the live demo · Architecture · eg-walker paper
Most editors treat source code as flat text. You type characters, and the tool does its best to guess what you meant — syntax highlighting, auto-complete, error squiggles — all reconstructed after the fact from dead text.
Canopy treats your program as a living structure. Text and syntax tree are two synchronized views of the same document. Type in one, the other updates. Restructure in one, the other follows. The editor doesn't guess what your code means — it knows, because it maintains the meaning incrementally as you type.
The goal: close the gap between what you think and what the tool understands. When the editor holds the same mental model you do — scope, types, values, dependencies — it can show you what matters, when it matters, without you having to search for it.
The demo language is lambda calculus — small enough to understand fully, rich enough to exercise the full pipeline:
let double = λx. x + x
let result = double 5
if result then result else 0
As you type this, Canopy:
- Parses incrementally (one character change → one subtree reparse)
- Resolves scope (knows
xis bound byλ,doublerefers to the definition above) - Formats with syntax highlighting through the pretty-printer
- Evaluates
double 5 → 10andif result then result else 0 → 10 - Synchronizes with any connected peer via CRDT
Four stages, each incremental:
Text CRDT → Incremental Parse → Projection → Rendering
↑ │
└────── structural edits feed back ──────────┘
-
Text CRDT (event-graph-walker) — The document lives in a FugueMax sequence CRDT. All edits — keystrokes, remote operations, undo/redo — enter here. Peers sync directly, no central server.
-
Incremental parsing (loom) — Only the affected region is reparsed. Unchanged subtrees are reused from the previous parse through position-independent CST nodes.
-
Projection — The syntax tree maps to a projection tree with stable node IDs and source spans. Node identity survives reparses, so UI state (selection, scroll) is preserved.
-
Rendering — The protocol layer computes incremental view patches. Only changed nodes reach the frontend. Multiple representations — formatted text, tree view, graph visualization — render from the same projection.
Canopy is a framework, not just an editor. Define a grammar for your language, implement a few traits, and you get incremental parsing, structural editing, pretty-printing, and CRDT collaboration out of the box.
But the long-term vision goes further. The code editor is a vertical slice of something larger: a system where you write freely, structure emerges automatically, and the right information surfaces when you need it. Every layer of the editor — incremental computation, semantic analysis, reactive projections, peer-to-peer sync — is a building block for that system.
Read more: Product Vision · The Projectional Bridge · Multi-Representation System
Text is ground truth, structure is derived. The text CRDT stores the document; everything else is computed. This means collaboration operates on a proven data structure, and the pipeline from text to view is a deterministic function of document state.
Language support is data, not code. Adding a new language means providing a grammar and a projection mapping. The framework handles parsing, reconciliation, undo/redo, and collaboration generically. Lambda calculus and JSON share the same core.
Multiple representations from one source. The Printable trait family (Show, Debug, Source, Pretty) gives every language four text representations. Source guarantees parse(to_source(x)) == x. Pretty produces width-aware, syntax-annotated formatted output. Adding a new text format = adding a render function, not changing language code.
Incremental by construction. Every stage — parsing, projection, rendering — recomputes only what changed. This isn't bolted-on caching; it's the architectural principle the framework is built around.
Core libraries:
| Library | Purpose |
|---|---|
| event-graph-walker | CRDT engine — eg-walker with FugueMax, O(log n) ancestor queries |
| loom | Incremental parser framework, CST library, reactive signals, pretty-printer |
| editor | SyncEditor — wires CRDT, parser, projection, undo, collaboration |
| protocol | ViewPatch, ViewNode, UserIntent — framework-agnostic frontend protocol |
| core | ProjNode[T], NodeId, SourceMap, reconciliation |
| projection | TreeEditorState, interactive tree operations |
Language packages:
| Package | Language |
|---|---|
| lang/lambda | Lambda calculus with arithmetic, conditionals, let-bindings |
| lang/json | JSON structural editing |
Examples:
| Example | Description | Live Demo |
|---|---|---|
| web | Canonical demo — lambda + JSON editors with syntax-highlighted pretty-print | canopy-lambda-editor.pages.dev |
| ideal | Full-featured editor with inspector, benchmarks | canopy-ideal.pages.dev |
| prosemirror | ProseMirror structural editing integration | canopy-prosemirror.pages.dev |
| canvas | Infinite canvas (experimental) | canopy-canvas.pages.dev |
| block-editor | Block-based structural editing | canopy-block-editor.pages.dev |
Prerequisites: MoonBit and Node.js
git clone --recursive https://github.com/dowdiness/canopy.git
cd canopy
moon test # 684+ tests
moon build --target js
cd examples/web && npm install && npm run dev # localhost:5173Vision and architecture:
- Product Vision — the full picture: write, auto-structure, surface
- The Projectional Bridge — why: syntax → semantics → intent → mental model
- Multi-Representation System — the Printable trait family and expression problem
- Incremental Hylomorphism — the compositional engine underneath
Development:
- Development Workflow — how to make changes, run tests, manage submodules
- Conventions — MoonBit coding patterns
- TODO — active backlog
moon test # run all tests
moon info && moon fmt # update interfaces and format
moon bench --release # benchmarks (always use --release)See the Development Guide for details.
- Eg-walker: CRDTs for Truly Concurrent Sequence Editing — the CRDT algorithm
- MoonBit — the implementation language
