How Online Documents Survive 10,000 Blocks: Flat Records, Virtual Scrolling, and One Shared Editor
A document with tens of thousands of blocks stays editable only because data, layout, and rendering are decoupled and loaded on demand. Any frontend that renders long lists or collaborative content can hit the same freeze points, and these are the mechanisms that prevent them.
Block architecture turns a document into a flat map of records with stable ids. A page keeps only its direct child ids; each block carries its own children, parent, type, and data. That flattening is what makes local updates, fine-grained collaboration, paginated loading, and content reuse possible. First-screen load sends structure and a few blocks first, marks the rest as pending, and replaces them as they scroll into view.
Rendering leans on a LayoutTree that stores every block's top and height. Blocks without a measured height get a default value, and when real height arrives the tree corrects that block plus everything after it, while compensating scrollTop so the current viewport block doesn't jump. Only viewport blocks and small buffers are mounted; everything else collapses into placeholders. Rich text is compressed by separating plain text from an attribute pool, and collaborative edits reduce to OT JSON's insert, retain, and delete operations.
New block types register model, view, layout, and common capabilities with a kernel instead of adding branches to a core renderer. The same record can appear in multiple positions, with recordId identifying stored data and blockId identifying a runtime instance. The design separates a structure tree from a layout tree. A suggested build order starts with three block types, then a store, then operations, history, and selection, before adding collaboration and virtual scrolling.
The "just ask AI" advice for OT JSON is practical only if you can verify the generated code; knowing the term is not the same as knowing the invariants that keep concurrent edits consistent.
Separating structure from layout is what lets a document reflow without rebuilding the whole tree; the two-tree model is the load-bearing decision behind stable scrolling.
The recordId/blockId split gives "reuse" a concrete meaning: data can be shared while each position keeps its own runtime identity, which is why sync blocks work.
The proposed build order suggests most editor complexity lives in cross-block concerns, not in individual block rendering; selection, clipboard, and undo all need a global view.