Pipeline
The engine behaves like a compiler. Every stage adds one category of decision and passes a stricter representation forward.
flowchart TB
subgraph Semantics["semantic ownership"]
Parse["parse"] --> Prepare["prepare / lower"]
end
subgraph Geometry["geometry ownership"]
Measure["measure"] --> Place["place"] --> Route["route + labels"]
end
subgraph Output["output ownership"]
Materialize["materialize notation"] --> Frame["frame document"]
end
Prepare --> Measure
Route --> Materialize
Contract["EngineContract"] -. "capabilities" .-> Measure
Contract -.-> Place
Contract -.-> Route
Contract -.-> Materialize
Contract -.-> FrameWhy the intermediate types matter
Section titled “Why the intermediate types matter”Without typed handoffs, a router can quietly resize a node, a renderer can silently nudge a label, or a family can smuggle layout hints into display text. The types make ownership searchable:
GraphIRowns normalized meaning.MeasuredGraphowns content dimensions.Placementowns node/group coordinates and routing ownership.RoutedGraphowns final connectors and edge-label positions.MaterializedGraphowns neutral notation and semantic styling.NGDowns the final coordinate space and paint order.
Contract injection
Section titled “Contract injection”EngineContract is the only description of consumer capabilities passed into
the engine. Most importantly, measureText supplies the same font metrics the
consumer will render. The default contract is immutable; a different consumer
replaces the whole contract rather than mutating global configuration.
Determinism
Section titled “Determinism”Each stage uses stable iteration and tie-breaking. The engine bans wall-clock and random sources structurally. Given the same prepared program and contract, the final NGD is byte-identical—not merely visually similar.