Handbook
Kernel owns the tree and Steps. View projects to DOM and maps input back. Optional AI and collab attach without introducing a second document type.
Doc (schema tree)
│ apply / invert / map / history
│ mdToDoc · docToMd · appendText · diffById
▼
markloom ← zero DOM, zero Preact
│
├── markloom/view Editor · render · selection · input
├── markloom/ai stream transports + chrome
├── markloom/collab OT client
└── markloom/react thin React host
| Module | Role |
|---|---|
tree/types | Node, Mark, Position (path), Selection |
tree/schema | Grammar + meta-bounds (depth / type budget) |
tree/addr | path addressing: nodeAt, resolve, replaceAt, spliceAt |
tree/step | 4 faces + apply + invert |
tree/map | Step × Position → Position′ (collab / async) |
tree/ai | id↔path: appendText, rewriteNode, diffById |
tree/history | undo / redo = invert stack |
md | mdast isomorphism + clean-block spans |
DOM event ──mapInput──▶ Step[] ──commit──▶ Doc
▲ │
└──────── render + restore selection ──┘
composition freeze / flush (IME)
contentEditable is fully owned via beforeinput.
The model is the only truth; DOM cannot drift into a second document.
Composition is not “let the browser finish.” On compositionstart the editor snapshots a base;
on compositionend it takes diff(base, DOM) and merges against the model.
That is a 3-way merge, not a 2-way overwrite — critical for CJK and other IME paths.
Steps and map use structural paths (functor laws).
Agents and AI use stable block ids (pathOfId / buildIdIndex).
When structure moves, paths change; ids do not.
apply ∘ invert = identity — undo and AI discard trust this.map locality — untouched subtrees keep positions; touched ones translate or clamp.pointToDom ∘ domToPoint = identity — selection must not drift a character.
Extension registers marks, blocks, keymaps, input rules, paste rules, decorations.
markloomKit() is the default preset (StarterKit-shaped).
Input pipeline control flow (guards, IME merge, atom selection) stays in the kernel —
extensions contribute declarative data, not reordered plugins.