Skip to content

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 -.-> Frame

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:

  • GraphIR owns normalized meaning.
  • MeasuredGraph owns content dimensions.
  • Placement owns node/group coordinates and routing ownership.
  • RoutedGraph owns final connectors and edge-label positions.
  • MaterializedGraph owns neutral notation and semantic styling.
  • NGD owns the final coordinate space and paint order.

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.

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.