Editor
The editor is a tree of blocks. A React component renders it. A constellation of vanilla-TypeScript primitives gives it teeth.
It is the lynchpin for six products: gitpress, kelex, ezmode guilds, courses, ctrl, veneer. Each consumer brings its own block types, composites, and rules. The editor is the shared authoring core.
What It Is
A page builder. The data model is a flat array of blocks, each block carrying an id, a type, optional content, optional children-ID references, optional parent ID, optional metadata. Trees are by reference, not by nesting. See Data Model for the shapes.
The primitives are framework-agnostic. They run wherever the DOM runs. The React component layer at packages/ui/src/components/ui/editor.tsx adapts them. The component layer is the only React-specific piece.
Serialization is pluggable. Blocks are the universal IR. MDX, JSON, composite JSON, and blueprint JSON are adapters that conform to the EditorSerializer interface at packages/ui/src/primitives/serializer.ts:65. See Serialization for the full surface.
What It Is Not
Not a Markdown editor. MDX is one serialization format. The block tree is the truth.
Not a Figma clone. Figma’s data model is a scene graph of geometric primitives. The editor’s data model is structured content. Different problem.
Not a control panel. Control panels expose every property as a labeled input. The editor exposes blocks. Properties live in meta and are surfaced through block-specific UI when needed.
Not a token editor. The editor renders content. Tokens are a separate concern handled by @rafters/design-tokens.
Mental Model
A consumer thinks in three layers.
Blocks are the data. A flat array. Each block is a typed shape with optional content and references. Adding a new block type is adding a string to the type system and a renderer for it.
Primitives are the capabilities. Selection, focus, drag, drop, history, clipboard, slash commands, inline formatting, palettes, rules. They are imported and composed. They emit events. The composition primitives block-handler and document-editor orchestrate the leaves through nanostores atoms. Everything else is a leaf and stays callback-driven.
Adapters are the translations. An EditorSerializer deserializes external content into blocks and serializes blocks back. Consumers pick the adapter that matches their format. Most consumers want mdxSerializer from @rafters/ui.
Where To Go Next
If you are integrating the editor into a product, start at Component for the React surface and Serialization for the format adapter you’ll plug in.
If you are extending the primitives or contributing, start at Architecture for the rules that keep six consumers from stepping on each other.
If you are reading source and need to know what a type means, Data Model is the canonical reference.
If something feels broken, the Known Gaps page is the honest list.
Status
The editor surface has drift. Some types are exported but not wired into the React component. The composites package imports from the ui package in two places where it shouldn’t. The inline-formatter has a serialize bridge that the editor never calls, so user-applied formatting is lost on save. Each gap is documented at Known Gaps with file:line and a sketch of the fix.
The audit that produced these docs is recent. The behavior matrix at Behavior Matrix lists testable claims per primitive so future drift surfaces fast.