---
title: "v1.0.0"
slug: releases/1.0.0
---

_2026-06-30_ · [GitHub release](https://github.com/seqeralabs/nf-metro/releases/tag/1.0.0) · [Diff](https://github.com/seqeralabs/nf-metro/compare/0.7.2...1.0.0)

Major milestone release and first release under the [seqeralabs](https://github.com/seqeralabs/nf-metro) GitHub organisation. 300+ commits since 0.7.2. The `.mmd` input format is backward compatible - existing files render without edits (many will look better thanks to the routing work below).

## All four flow directions

nf-metro now supports all four Mermaid graph directions: `LR`, `RL`, `TB`, and `BT`. Previously only `LR` and `TB` were supported; `RL` and `BT` are their respective mirrors, with full routing vocabulary for fold sections, bypass-V, convergence sinks, and perpendicular entries.

## Routing engine

The majority of the code change in this release is engine work, and most of it is structural rather than a list of isolated fixes. Three large programs ran across the cycle, then a focused fold-routing sprint closed it out.

**Centreline-builder unification.** Edge routing was consolidated onto a single centreline builder that owns corner anchoring and tapering for every route family - entry-wrap, perpendicular-exit up-and-over, U-shaped bypass, TOP-entry staircase, fan L-shapes, and inter-section bundles. What used to be scattered per-case path construction now flows through one declarative inter-section dispatch table and one builder, so curves are correct by construction rather than patched after the fact (#791-#814, plus the #845 symbolic gap-slot model).

**Direction-agnostic layout (AxisFrame).** Layout heuristics that were written against hardcoded `"TB"` string checks were migrated to an `AxisFrame` abstraction with lane accessors and a single offset-regime applier, and the core handlers adopted a `Direction` enum. This is what made the new `RL` and `BT` directions tractable: every routing handler now operates on one canonical orientation, and the per-direction special cases were retired. The `LR`/`TB` rotation model was extended so `RL` and `BT` are derived by mirroring at the seam-classifier layer (#918-#922, #1029-#1049).

**Robustness hardening.** A gate-arm triage pass gave every un-exercised branch in the layout and routing modules a verdict - reachable (with a new fixture), defensive, or a filed bug - and the inter-phase state shared between layout stages was formalised into an explicit protocol. A guard registry with a cost audit and golden baseline now reds CI the moment a layout regresses (#687, #673, #921).

**Fold-threshold routing.** Folded sections (where a line wraps across a column boundary) got the most targeted-fix work, late in the cycle. The keystone: fold-back routes that cannot be drawn cleanly now raise a `FoldThresholdError` and are treated as an authoring constraint rather than emitting broken geometry (#1088). On top of that gate:

- Perpendicular-entry fans slot onto parallel approach channels by feeder order instead of overlapping (#1144).
- Folded LEFT-exit staircase bundle ordering and concentric nesting (#1143, #1161).
- Folded bbox bottom aligns to the target section's settled content bottom, not its live bounding box, preventing balance drift on tall fold targets (#1162).
- Tight 1-row folds no longer leave a visible run-out stub on the bypass-V (#1177).
- Same-side cul-de-sac entry re-anchors the interior-consumer port instead of routing around it, removing a whole class of U-route generation (#1182).
- Opposing-line fold-backs under fold compression raise `FoldThresholdError` rather than tangling (#1187).
- Convergence-sink ports no longer face the wrong section after fold relocation (#1167).
- Disconnected components renormalise grid rows after stacking, preventing section overlap (#1164).
- Corridor-fed single-line sections re-centre instead of drifting off-trunk (#1173); same-column RIGHT-entry corridor descent no longer jogs before dropping (#1178).
- TB-section bypass-V seats on the line's lane-side grid column, not a fixed offset (#1163); the post-bypass settling pass runs in both validate modes (#1171); convergence-split placement is deterministic across runs (#1168).

**Spacing and symmetry.**

- Symmetric 2-way diamonds compact to half pitch through the grid-snap, halving wasted horizontal space (#1076).
- Upright (TB/BT) label and icon spacing derives from the `AxisFrame` rather than hardcoded `"TB"` checks (#1043).
- Light theme line width corrected to match `OFFSET_STEP` (4 px -> 3 px) (#1073).

## CSS offset-path animations

Ball animations switch from SMIL `<animateMotion>` to CSS `offset-path`. SMIL is disabled in some host environments and causes SVG-in-HTML embedding issues; `offset-path` works reliably across all modern browsers.

## Light and dark as independent axes

Brand (`nfcore`, `seqera`) and display mode (`light`, `dark`) are now independent. A single rendered SVG carries both palettes via CSS `light-dark()` and adapts to the viewer's `color-scheme` automatically. Logo assets also adapt per `color-scheme` with no extra directives required.

## Render API and render-many

A stable Python API:

```python
from nf_metro.api import render_string, RenderConfig

svg = render_string(
    graph_text,
    theme="nfcore",
    mode="dark",
    config=RenderConfig(embed_font=True, responsive=True),
)
```

`render_string` is the one-call entry point. `RenderConfig` is a typed dataclass bundling the render-side output options (font embedding, responsive viewBox, class prefixes, color-scheme handling) for callers who prefer a config object over keyword arguments. The `render-many` CLI command batch-renders a JSON manifest of jobs in a single process, amortising interpreter and import startup across the whole corpus.

## Embedded data manifest

Every render now carries a machine-readable JSON manifest - station visual centres, pill dimensions, and line metadata - factored into a dependency-free `nf_metro.manifest` package and documented as a standard. This is what lets `nf-metro serve` accept a previously rendered SVG as input, and it gives host systems a stable way to map screen coordinates back to graph elements (#623).

## Font portability

Renders can embed the Inter font or convert text to vector paths, so maps display identically whether or not the host has the font installed - important for SVGs that travel into PDFs, slides, and other documents (#839).

## Live workflow visualisation (`nf-metro serve`)

`nf-metro serve` connects to a running Nextflow workflow and renders a live metro map in the browser, updating as processes progress. New in this release:

- **SVG input** - accepts a previously rendered SVG (with embedded manifest) instead of a `.mmd` source.
- **`auto_process` mapping** - `%%metro auto_process: true` and `process_scope:` collapse a Nextflow DAG into a lean process-level map automatically.

## Interactive browser playground

A browser-based editor powered by [Pyodide](https://pyodide.org/) runs the full Python engine client-side - edit `.mmd` source, see the map update live. Features: example dropdown, Nextflow DAG import, graphical topology editing, zoom controls, brand/mode toggles, gzip-compressed share URLs, and a service-worker cache so the Pyodide runtime loads instantly after the first visit.

## New documentation site

Rebuilt in [Astro](https://astro.build/) / [Starlight](https://starlight.astro.build/) with a Seqera-branded theme, replacing MkDocs-Material. Metro maps render live at build time; the `<Metro>` component presents source, CLI command, and rendered map as a three-panel toggle. Versioned docs with an in-page version switcher, Pagefind full-text search, ZoomableSVG lightbox, color-chip swatches in code blocks, and link validation in CI.

## CI

- 3-way parallel test split with `pytest-split` to cut CI wall-clock time.
- Python 3.10 dropped (EOL); minimum is now Python 3.11.
- All GitHub Actions refs pinned to full commit SHAs (seqeralabs org policy).
- Incremental render-diff: PR previews only re-render changed fixtures.
