merman
Mermaid, but headless, in Rust.
Think of merman as Mermaid's headless twin: same language, same diagrams, no browser required.
merman is a Rust, headless re-implementation of Mermaid (baseline: mermaid@11.12.3).
Parity is enforced with golden semantic/layout snapshots and upstream SVG DOM baselines, so
changes that affect semantics, layout, or rendering are caught and reviewed.
TL;DR
- Want an executable? Use
merman-cli(render SVG/PNG/JPG/PDF). - Want a library? Use
merman(renderfor SVG;rasterfor PNG/JPG/PDF). - Only need parsing / semantic JSON? Use
merman-core. - Quality gate:
cargo run -p xtask -- verify(fmt + nextest + DOM parity sweep).
Contents
- Status
- Install
- Quickstart (CLI)
- Quickstart (library)
- Showcase
- Quality gates
- Limitations
- Crates
- Links
- Changelog
- License
Status
- Baseline: Mermaid
@11.12.3. - Alignment is enforced via upstream SVG DOM baselines + golden snapshots (“golden-driven parity”).
- DOM parity checks normalize geometry numeric tokens to 3 decimals (
--dom-decimals 3) and compare the canonicalized DOM (not byte-identical SVG). - Current coverage and gates: docs/alignment/STATUS.md.
- Corpus size: 3400+ upstream SVG baselines across 23 diagrams.
- ZenUML is supported in a headless compatibility mode (subset; not parity-gated). See docs/adr/0061-external-diagrams-zenuml.md.
What you get
- Parse Mermaid into a semantic JSON model (headless)
- Compute headless layout (geometry + routes) as JSON
- Render SVG (parity-focused DOM)
- Render PNG (SVG rasterization via
resvg) - Render JPG (SVG rasterization via
resvg) - Render PDF (SVG → PDF conversion via
svg2pdf)
Diagram coverage and current parity status live in docs/alignment/STATUS.md.
Install
From source (today):
From crates.io:
# CLI
# Library (SVG)
# Library (SVG + PNG/JPG/PDF)
MSRV is rust-version = 1.87.
Quickstart (CLI)
# Detect diagram type
# Parse -> semantic JSON
# Layout -> layout JSON
# Render SVG
# Render raster formats
Minimal end-to-end example:
@'
flowchart TD
A[Start] --> B{Decision}
B -->|Yes| C[Do thing]
B -->|No| D[Do other thing]
'@ | Set-Content -Encoding utf8 example.mmd
merman-cli render example.mmd --out example.svg
Quickstart (library)
The merman crate is a convenience wrapper around merman-core (parsing)
and merman-render (layout + SVG).
Enable the render feature when you want layout + SVG. Enable raster when you also need
PNG/JPG/PDF from Rust (no CLI required).
use ;
use ;
If you prefer a bundled "pipeline" instead of passing multiple option structs per call, use
merman::render::HeadlessRenderer.
If you already know the diagram type (e.g. from a Markdown fence info string), prefer
Engine::parse_diagram_as_sync(...) to skip type detection.
If your downstream renderer does not support SVG <foreignObject> (common for rasterizers),
prefer HeadlessRenderer::render_svg_readable_sync() which adds a best-effort <text>/<tspan>
overlay extracted from Mermaid labels.
Showcase
All screenshots below are produced by merman-cli (headless) and committed under
docs/assets/showcase/.
Each example links to an existing fixture so the README stays honest and reproducible.
Architecture (many groups + sparse services)
Fixture: fixtures/architecture/stress_architecture_batch4_many_groups_sparse_services_069.mmd
architecture-beta
%% Authored stress fixture (Mermaid@11.12.3): many groups with sparse services (group rect bounds).
group g1(cloud)[G1]
group g2(cloud)[G2]
group g3(cloud)[G3]
group g4(cloud)[G4]
service a(server)[A] in g1
service b(server)[B] in g2
service c(server)[C] in g3
service d(server)[D] in g4
a:R -- L:b
b:R -- L:c
c:R -- L:d
Mindmap (line breaks in labels)
Fixture: fixtures/mindmap/stress_mindmap_br_variants_031.mmd
mindmap
%% Authored stress fixture (Mermaid@11.12.3): <br> variants inside labels.
root((Root))
n1["line 1<br>line 2"]
n2["line 1<br/>line 2"]
n3["line 1<br />line 2"]
n4["line 1<br \t/>line 2"]
%% plus whitespace variants (see the fixture for the full set)
Sankey (dense shared nodes)
Fixture: fixtures/sankey/stress_sankey_batch1_dense_shared_nodes_007.mmd
%%{init: {"sankey": {"width": 900, "height": 420, "useMaxWidth": true, "showValues": false, "linkColor": "source", "nodeAlignment": "justify"}}}%%
sankey
%% Source: repo-ref/mermaid/packages/mermaid/src/docs/syntax/sankey.md (dense graphs) + authored stress
In,A,10
In,B,8
In,C,6
A,X,5
A,Y,5
B,Y,3
B,Z,5
C,X,2
C,Z,4
X,Out 1,7
X,Out 2,0.5
Y,Out 1,6
Y,Out 3,2
Z,Out 2,7
Z,Loss,2
Gantt (date math + excludes)
Fixture: fixtures/gantt/upstream_docs_gantt_syntax_002.mmd
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes weekends
%% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :until isadded
Functionality added :milestone, isadded, 2014-01-25, 0d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
Stress gallery (more fixtures)
| Architecture (ports + routing) | Mindmap (deep + wide) |
|---|---|
Fixture: fixtures/architecture/stress_architecture_batch5_services_outside_groups_crosslinks_078.mmdNote: Architecture geometry/viewport parity is still being tightened (layout ports in progress); see docs/alignment/STATUS.md. |
Fixture: fixtures/mindmap/stress_deep_wide_combo_011.mmd |
Quality gates
This repo is built around reproducible alignment layers and CI-friendly gates:
- Semantic snapshots:
fixtures/**/*.golden.json - Layout snapshots:
fixtures/**/*.layout.golden.json - Upstream SVG baselines:
fixtures/upstream-svgs/** - DOM parity gates:
xtask compare-all-svgs --check-dom(see docs/adr/0050-release-quality-gates.md)
The goal is not “it looks similar”, but “it stays aligned”.
Quick confidence check:
For a quick “does raster output look sane?” sweep across fixtures (dev-only):
pwsh -NoProfile -ExecutionPolicy Bypass -File tools/preview/export-fixtures-png.ps1 -BuildReleaseCli -CleanOutDir
Limitations
- SVG
<foreignObject>HTML labels are not universally supported (especially in rasterizers). If you need a more compatible output, preferrender_svg_readable_sync(). - Architecture layout/edge routing is still being aligned to upstream Cytoscape/FCoSE; expect differences in dense compound graphs (see
docs/alignment/STATUS.md). - Determinism is a goal: output is stabilized via goldens, DOM canonicalization, and vendored/forked dependencies where needed (see
roughr-merman).
Crates
- Headless parsing:
merman-core - Convenience API:
merman(enablerenderfor layout + SVG) - Rendering + layout stack:
merman-render - Layout ports:
dugong: Dagre-compatible layout (port ofdagrejs/dagre)dugong-graphlib: graph container APIs (port ofdagrejs/graphlib)manatee: compound graph layouts (COSE/FCoSE ports)
Links
- Alignment status: docs/alignment/STATUS.md
- Parity policy: docs/adr/0014-upstream-parity-policy.md
- Release quality gates: docs/adr/0050-release-quality-gates.md
- Upstream Mermaid: mermaid-js/mermaid
- Related: 1jehuang/mermaid-rs-renderer
Changelog
See CHANGELOG.md.
License
Dual-licensed under MIT or Apache-2.0. See LICENSE, LICENSE-MIT, LICENSE-APACHE.