---
title: "Architecture"
description: High-level architecture of nf-metro — the parse, layout, and render pipeline and how the subsystems fit together.
sidebar:
  order: 1
---

import { LinkCard, CardGrid } from "@astrojs/starlight/components";

nf-metro turns a Mermaid `graph LR` definition (augmented with `%%metro`
directives) into a metro-map-style SVG. The pipeline has three stages:

```text
Parse  ->  Layout  ->  Render
```

Each stage hands a single `MetroGraph` (defined in
[`src/nf_metro/parser/model.py`](https://github.com/seqeralabs/nf-metro/blob/main/src/nf_metro/parser/model.py))
to the next. The graph is mutated in place: parsing fills in stations,
edges, lines, sections, and ports; layout writes coordinates onto those
objects; rendering reads them.

## Stages

### Parse (`src/nf_metro/parser/`)

`parse_metro_mermaid` in `parser/mermaid.py` is a line-by-line regex
parser. It reads Mermaid subgraphs (sections), nodes (stations), and
edges, plus the `%%metro` directive extensions. After the line scan it
runs a post-parse pass that auto-infers layout, then rewrites
inter-section edges into port/junction chains via `_resolve_sections`.

See [Parser](/nf-metro/dev/parser/) for the directive model and the
parse-then-resolve flow.

### Layout (`src/nf_metro/layout/`)

`compute_layout` in `layout/engine.py` assigns every station, port,
junction, and section bbox an `(x, y)`. It chains many small phases,
split into an anchor-setting (structural) layer and a content-placement
layer. The phase implementations live in `layout/phases/`; the
per-phase preconditions, postconditions, and invariants are documented
in
[`src/nf_metro/layout/CONTRACT.md`](https://github.com/seqeralabs/nf-metro/blob/main/src/nf_metro/layout/CONTRACT.md).

Edge routing (horizontal runs plus 45-degree diagonal transitions, with
L-shaped inter-section routing) lives in `layout/routing/`.

See [Layout pipeline](/nf-metro/dev/layout_pipeline/) for the full phase-by-phase
walkthrough and [Routing](/nf-metro/dev/routing/) for the route families.

### Render (`src/nf_metro/render/`)

`render_svg` in `render/svg.py` draws section boxes, routed edges (with
curved corners), pill-shaped station markers, labels, and the legend
using the `drawsvg` library. Visual properties come from a `Theme`
(`render/style.py`); themes are registered in `themes/__init__.py`.
`render/animate.py` adds travelling balls along the routed paths (the
`--animate` CLI flag).

## Reference docs

<CardGrid>
  <LinkCard
    title="Layout pipeline"
    href="/nf-metro/dev/layout_pipeline/"
    description="Phase-by-phase walkthrough of how coordinates are assigned."
  />
  <LinkCard
    title="Routing"
    href="/nf-metro/dev/routing/"
    description="Edge routing families, dispatch order, bundles, and runtime guards."
  />
  <LinkCard
    title="Parser"
    href="/nf-metro/dev/parser/"
    description="The Lark grammar, directive model, and post-parse rewrites."
  />
  <LinkCard
    title="Render"
    href="/nf-metro/dev/render/"
    description="SVG, HTML, bridges, manifest, legend, and animation."
  />
  <LinkCard
    title="Inter-section dispatch"
    href="/nf-metro/dev/inter_section_dispatch/"
    description="The declarative dispatch table for inter-section route shapes."
  />
  <LinkCard
    title="Routing gate coverage"
    href="/nf-metro/dev/routing_gate_coverage/"
    description="Auto-generated matrix of which handler arms are exercised by the corpus."
  />
  <LinkCard
    title="Routing gate triage"
    href="/nf-metro/dev/routing_gate_triage/"
    description="Process for triaging un-exercised or needs-review gate arms."
  />
  <LinkCard
    title="Testing"
    href="/nf-metro/dev/testing/"
    description="Test structure, the four validation layers, and adding fixtures."
  />
</CardGrid>

The per-phase preconditions, postconditions, and invariants are in [`CONTRACT.md`](https://github.com/seqeralabs/nf-metro/blob/main/src/nf_metro/layout/CONTRACT.md). The topology stress fixture inventory is in [`examples/topologies/README.md`](https://github.com/seqeralabs/nf-metro/blob/main/examples/topologies/README.md).

## Data model

The central structure is `MetroGraph` (`parser/model.py`), holding:

- `lines` (`MetroLine`): coloured routes, with an optional `style`
  (`solid` / `dashed` / `dotted`).
- `stations` (`Station`): mutable dataclasses; layout writes `x`, `y`,
  `layer`, `track` directly onto them. `is_port` stations participate
  in layout but are invisible at render time.
- `edges` (`Edge`): directed, each tagged with a `line_id`.
- `sections` (`Section`): subgraph groupings with a `direction`
  (`LR` / `RL` / `TB`), grid position, and bbox.
- `ports` (`Port`): synthetic entry/exit points on section boundaries,
  created during `_resolve_sections`.
