0015. Layout engine, constraints and routing
Status: accepted (layout-engine change, 10 October 2026)
Context
Section titled “Context”Until this change only fully placed diagrams rendered: layout auto and layout assisted reported
layout.mode-unsupported. The proposal asks for several things:
- automatic and assisted layout that respects written positions;
- strong constraints and explicit conflicts;
- named ports and several route kinds;
- composition checks;
- an engine that can be replaced.
It names ELK. Layout must stay synchronous, because every host, edit and test calls
layoutDiagram synchronously.
Decision
Section titled “Decision”- Engine interface.
@meltemi/diagrams-layoutdefinesLayoutEngine.arrange(request), which is synchronous.- The request lists boxes with sizes, parent groups, ports and fixed centres, groups with their paddings, and relations with ports and kind.
- The result gives centres and edge points.
- Hosts pass the engine in
LayoutOptions.engine. Without one, unplacedautoandassisteddiagrams reportlayout.mode-unsupported.
- ELK.
@meltemi/diagrams-layout-elkwrapselkjs0.12.0, pinned exactly.- It loads
elkjs/lib/elk-worker.min.jsand calls its dispatcher directly, which lays out synchronously. - It uses the layered algorithm: the direction mapped to
elk.direction, groups as compound nodes withINCLUDE_CHILDREN, and orthogonal routing. - Spacing is 40, 70 and 16 px.
- Stability comes from model order and a fixed random seed. Primary relations get priority for straightness and direction.
- It loads
- Ports in ELK.
- Named ports are fixed points.
- Every other relation end of a box with ports gets its own port, on its compass side or on the
side where relations enter or leave. With
FIXED_POS, ELK attaches a relation without a port to a corner of the box, which bent straight chains by half a box.
- Modes.
autotakes ELK’s centres and routes and ignores places, reporting the first one.assistedfixes placed boxes. Each free box keeps its offset from the nearest placed box in ELK’s arrangement, and is pushed out of overlaps along the direction.- A single mean offset broke the order of boxes when the placed ones were further apart than ELK would put them.
- Constraints.
align,row,column,orderanddistanceare solved after arrangement by projecting free boxes for up to 20 rounds.- Placed boxes never move. What still fails is
layout.constraint-conflict, and the scene is still drawn.
- Routing.
routing auto|orthogonal|polyline|bezieris a diagram property and a relation style.- Bézier connectors are Catmull-Rom curves drawn as paths.
- In
automode, straight and curved connectors join their anchors directly, because a curve through ELK’s orthogonal bends loops. - Parallel relations take lanes 16 px apart.
- Composition checks. The checks for overlaps, labels under connectors, group margins and connectors running together are warnings. They sweep boxes sorted by x, so 500 boxes take milliseconds instead of the half second of a pairwise check.
- Writing positions down.
planEditgainsarrange, andsetPositionturnslayout autointolayout assisted.meltemi-diagrams layoutlays a diagram out withLayoutOptions.layoutset toassisted, or toautowith--all.- It reads
LayoutResult.boxesin diagram coordinates and writes them witharrange. Exporting before and after gives the same SVG.
ELK licence
Section titled “ELK licence”elkjs is licensed EPL-2.0 OR GPL-3.0-or-later; Meltemi Diagrams uses it under EPL-2.0.
- It is installed unmodified from npm and imported only by
@meltemi/diagrams-layout-elk, so the rest of the code base does not depend on it. THIRD_PARTY_LICENSES.mdlists it with its licence.- Builds that bundle it, such as the editor or the playground, must ship the EPL-2.0 notice and say
where its source is:
https://github.com/kieler/elkjs, version 0.12.0. - Changes to elkjs itself would have to be published under EPL-2.0. We make none.
Alternatives considered
Section titled “Alternatives considered”- An asynchronous engine API. It would make every host, edit and test asynchronous for one dependency. If the synchronous dispatcher ever disappears, an asynchronous host can wrap the public promise API behind the same interface.
- Our own layered algorithm. It would repeat years of work that ELK already does well, and the proposal names ELK.
- Dagre. It is unmaintained, has no compound-node ports and does not route orthogonally.
- Solving constraints inside ELK. ELK’s layered algorithm has no general alignment constraints. Projecting afterwards keeps placed boxes exact and conflicts explicit.
Consequences
Section titled “Consequences”- The command line, the editor and every export pass the ELK engine. The corpus SVG tests render
autoandassistedsheets with it. - Sheets that write
placewithout alayoutstatement now getlayout.placement-ignored. They should saylayout manual, orlayout assistedwhen they want the engine to place the rest. - Exporting with
--stdoutprints diagnostics to stderr, so stdout holds only the SVG.