Architecture
@inkroom/editor ← one install, the whole product ├── @inkroom/ui toolbar · menus · dialogs · table controls · themes │ └── @inkroom/core schema · commands · input rules · dual-mode engine │ └── @inkroom/markdown mdast ⇄ ProseMirror bridge (the crown jewel) ├── @inkroom/i18n 10 locales + tiny runtime └── wrappers @inkroom/react · @inkroom/vue · @inkroom/vanillaplugins (lazy) plugin-code · plugin-math · plugin-mermaidcompat @inkroom/toast-compat (+ inkroom-migrate-toast)pro (commercial) collab · sync-server · comments · track-changes · docx · pdf · ai · licenseDecisions that shape everything
One fixed schema. Every Inkroom document shares one ProseMirror schema —
math, footnotes, raw HTML and front matter are always present, plugins only
change rendering and input. Documents are portable between deployments and
md → doc → md can be a hard guarantee (see round-trip.md).
Markdown is the source of truth. @inkroom/markdown maps mdast ⇄
ProseMirror mechanically (node names mirror mdast) on top of micromark —
the same exactness CommonMark reference tooling uses. Large documents parse
in safe block-boundary chunks (perf.md). Position maps travel
with every conversion, which is what makes cursor-preserving mode switches
possible.
The source mode is ProseMirror too. A one-node-per-line schema gives the markdown view the same undo, IME and mobile behavior as the WYSIWYG view — without shipping a second editor (this replaces the CodeMirror tui.editor bundled).
Tables ride prosemirror-tables. Cell selection, spans and fix-up logic are a decade-hardened problem; Inkroom adds GFM awareness — pipe tables when expressible, fixed-format HTML (lifted back to editable tables on parse) when merged.
UI is dependency-free vanilla TS. One implementation serves React, Vue and vanilla through thin adapters; theming is CSS custom properties; every menu follows the WAI-ARIA APG patterns and axe gates CI.
Pro is a plugin, not a fork. Collaboration overrides the history plugin
via a declared capability; track-changes rewrites transactions through
appendTransaction; comments keep anchors in plugin state. The core never
checks a license — pro packages verify Ed25519 keys locally and never
degrade production (licensing.md).
Where to read code first
packages/markdown/src/from-mdast.ts— the bridge, with position trackingpackages/core/src/dual/controller.ts— dual-mode lifecyclepackages/markdown/src/chunk.ts— chunked parsingpro/track-changes/src/index.ts— the suggestion rewrite engine