Skip to content

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/vanilla
plugins (lazy) plugin-code · plugin-math · plugin-mermaid
compat @inkroom/toast-compat (+ inkroom-migrate-toast)
pro (commercial) collab · sync-server · comments · track-changes · docx · pdf · ai · license

Decisions 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

  1. packages/markdown/src/from-mdast.ts — the bridge, with position tracking
  2. packages/core/src/dual/controller.ts — dual-mode lifecycle
  3. packages/markdown/src/chunk.ts — chunked parsing
  4. pro/track-changes/src/index.ts — the suggestion rewrite engine