Build1 publisher3 min readPublished
A layered layout confines a JSON edit to the node it changed and its later siblings
The developer behind Treease keeps full data, the full layout tree and the on-screen subgraph as three separate things, so editing one field in a 50 MB document does not restart the geometry for every node.
The Engineer · Build desk

What happened
- A dev.to post collects the optimizations its author made while building Treease, a canvas JSON viewer, to work with 50 MB documents.
- The straightforward pipeline runs full data to full layout tree to full graph to full canvas scene, and once any step works on the full data set a local interaction becomes global work.
- The layered layout derives geometry directly from JSON structure and reading order, under four rules covering the root corner, shared X per depth, Y from the preceding sibling, and row-to-row edges.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint Buying incremental updates means giving up the mutually-influencing layout, so a tool cannot spread nodes to balance the picture and still keep edits local.
- capability Geometry that ignores global balance makes streaming ingest workable: a document can be laid out as it arrives, because no arriving node changes what was already placed above and to its left.
- cost The saving is uneven. An edit deep in a column is nearly free, while an edit at the top of a long column pays for every sibling below it, so the win depends on where users actually type.
- decision Anyone copying the split still has to choose an in-memory form, because a layout that touches four nodes can still crawl if locating those four means chasing pointers across scattered objects.
The incremental behaviour comes out of one rule. The first node at each depth takes its Y coordinate from the lowest boundary of the preceding sibling's subtree plus a fixed vertical gap [11]. A node's position therefore depends on what precedes it in reading order and on nothing that follows. X comes from the rightmost boundary of the parent subtree plus a fixed horizontal gap [10].
In the post's diagram, the order document draws five boxes: root, customer, orders, A-100 and A-101 [20]. Adding a coupon field to A-100 changes A-100's height, pushes the total row down inside it, and moves later sibling nodes at the same depth [14]. Two boxes of five [1]. A layout that decides positions by asking whether the whole graph looks balanced reconsiders all five, because every position there is decided in relation to all the others [6].
That ratio belongs to the example, which was hand-built to show the property. It transfers to a real document only when edits land late in their column. Since each sibling's Y is the bottom of the previous sibling plus a gap [11], a row added to the first node in a long column shifts every node after it [2]. The post states the bound plainly: the layout propagates "only when the change pushes later content out of the way, and only in the direction where that propagation is necessary" [15].
The layered rules give up the picture the post itself calls easy to read [7]. Balanced layouts spread nodes apart and avoid overlap [6]. The layered one starts at the upper-left corner and grows right and downward [9], and each edge runs from the matching row in the parent to the first row of the child instead of between the two boxes' geometric centers [12].
The other cost is where those nodes sit in memory. Even an algorithm that updates only a few nodes wastes time if finding those nodes means jumping through many scattered objects in memory [16]. An object tree of pointers matches the way people think about JSON [17]. Walking that tree, the machine reads one object, jumps to an array, jumps to another object, then to a string, and those objects may live in completely different parts of memory [17]. The alternative the post reaches for is grouping records by type [18].
Treease's developer wrote, "While building Treease to work with 50 MB documents, I made a series of optimizations." [1] The write-up does not put timings next to that figure [21], and it excludes the drawing side on purpose: it covers what to compute, read and update, not virtualization or what to draw, and points to a companion article on viewport virtualization [19].
Adopting the split means maintaining three representations of the same document, kept in step. Search and editing run against the full data and the full layout tree; incremental updates run against the subgraph; pan, zoom and click run against local canvas objects [4]. Offscreen nodes still exist in the data and the layout. Path navigation keeps its context while the canvas holds only a slice [5].
What to watch
- Whether the type-grouped record store gets published with timings for the 50 MB case, since the write-up argues it from pointer-chasing costs alone.
- Whether streaming appends into a long array reflow the whole column, which is the case the Y rule handles worst.
- Whether the viewport virtualization work and this data/layout/subgraph split are shown operating together on the same document.