MCPcopy Index your code
hub / github.com/Latias94/merman

github.com/Latias94/merman @v0.7.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.7.0 ↗ · + Follow
10,896 symbols 36,948 edges 846 files 154 documented · 1% updated 1d agov0.8.0-alpha.2 · 2026-06-23★ 4221 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

merman

Mermaid, but headless, in Rust.

CI Crates.io Documentation Crates.io Downloads Made with Rust

License: MIT License: Apache 2.0

Merman is a parity-focused, headless Rust implementation of Mermaid for parsing, layout, and browserless rendering. It targets mermaid@11.15.0, produces semantic JSON, layout JSON, SVG, raster formats, and ASCII/Unicode output, and does not launch a browser to render diagrams.

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. Disclaimer: Merman is not affiliated with, endorsed by, or sponsored by the Mermaid project or its maintainers. It is an independent compatibility implementation by Mermaid users. Many examples and fixtures in this repository are extracted from Mermaid documentation or tests, either verbatim or with small updates for local context; see THIRD_PARTY_NOTICES.md for Mermaid license and provenance notes.

Try it in the browser: Merman Playground.

Choose Your Entry Point

You want to... Start with Notes
Try or share Mermaid diagrams in the browser Merman Playground Static live editor powered by the wasm web package.
Render Mermaid from Rust merman Enable render for SVG, ascii for terminal text, raster for PNG/JPG/PDF.
Use a command-line tool merman-cli Detect, parse, layout, render SVG, render raster formats, and render ASCII/Unicode text.
Render diagrams in Rust API docs merman-rustdoc Proc-macro integration for rustdoc that turns Mermaid fences into inline headless SVG.
Embed in a browser or TypeScript app @mermanjs/web wasm-bindgen output plus TypeScript helpers for SVG, JSON, validation, metadata, and DOM rendering.
Parse Mermaid or produce semantic JSON merman-core Parser, metadata, semantic JSON, and typed render models without layout/render dependencies.
Embed from C, C++, Swift, Kotlin, Dart, Python, or another native host merman-ffi Stable C ABI plus platform wrappers. See FFI protocol, Android, Apple, Flutter/Dart, and Python UniFFI.
Work on layout/rendering internals merman-render Low-level layout and SVG stack used by the public merman facade.

What Merman Outputs

  • Semantic JSON for Mermaid diagrams.
  • Layout JSON with computed geometry and routes.
  • Mermaid-like SVG from a fully headless Rust renderer.
  • ASCII/Unicode diagrams for terminals, logs, and documentation snippets.
  • PNG, JPG, and PDF via SVG rasterization/conversion.

Diagram coverage and current parity status live in docs/alignment/STATUS.md.

Performance

merman includes a corpus-driven benchmark harness for comparing native merman, mermaid-rs-renderer, and upstream Mermaid JS v11.15.0. In a local warm-render standard suite run on Apple M4, merman measured all 34 requested fixtures and used about 1.8% to 23.0% of Mermaid JS render time across successful Mermaid JS cases, roughly 4.3x to 56.4x faster, with a median speedup around 15.8x.

Performance numbers are not a substitute for SVG parity. Missing, skipped, errored, and quality comparison results are reported separately by the benchmark harness. See docs/performance/BENCHMARKING.md for methodology and commands.

Install

# Command-line tool
cargo install merman-cli --version 0.7.0

# Rust library: SVG rendering
cargo add merman@0.7.0 --features render

# Rust library: ASCII/Unicode text output
cargo add merman@0.7.0 --features ascii

# Rust library: SVG + PNG/JPG/PDF
cargo add merman@0.7.0 --features raster

# Rustdoc integration
cargo add merman-rustdoc@0.7.0 --optional

# Browser / TypeScript package
npm install @mermanjs/web

# Flutter package
flutter pub add merman

# Python package (experimental UniFFI wheels)
pip install merman

For rustdoc feature setup and examples, see crates/merman-rustdoc/README.md.

From a local checkout:

cargo install --path crates/merman-cli
cargo build -p merman-ffi --release

Use crates/merman-ffi/include/merman.h and link the platform-specific library artifact from target/release for native embedding.

MSRV is rust-version = 1.95.

Contents

Quickstart (library)

For most Rust applications, start with merman::render::HeadlessRenderer:

use merman::render::HeadlessRenderer;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let renderer = HeadlessRenderer::new().with_diagram_id("readme-example");
    let svg = renderer
        .render_svg_sync("flowchart TD\nA[Start] --> B[Done]")?
        .unwrap();

    println!("{svg}");
    Ok(())
}

Use render_svg_sync() when you want Mermaid-parity SVG. Use render_svg_resvg_safe_sync() when the result will be rasterized or shown by an SVG engine that does not support <foreignObject> well. Use the ascii feature and merman::ascii::HeadlessAsciiRenderer for terminal text output.

Rust examples

The crates/merman/examples programs are ordered as a progressive Rust integration path. Each example reads Mermaid source from stdin when provided and falls back to a small built-in diagram. When stdin is an interactive terminal, examples 01 through 08 and 11 do not wait for input; they print a short note to stderr and render their built-in example. See the crates/merman/examples directory and its README.md for copyable commands with custom stdin and output files.

Step Goal Feature Command
01 Render SVG with the high-level facade render cargo run -p merman --features render --example example_01_svg_basic > out.svg
02 Parse Mermaid to semantic JSON none cargo run -p merman --example example_02_semantic_json
03 Produce layout JSON render cargo run -p merman --features render --example example_03_layout_json
04 Render terminal text ascii cargo run -p merman --features ascii --example example_04_ascii_output
05 Render PNG from Rust raster cargo run -p merman --features raster --example example_05_raster_output -- target/example.png
06 Apply an SVG output pipeline render cargo run -p merman --features render --example example_06_svg_pipeline > pipeline.svg
07 Use Mermaid theme variables and themeCSS render cargo run -p merman --features render --example example_07_theme_css > themed.svg
08 Make time-sensitive Gantt parsing deterministic none cargo run -p merman --example example_08_deterministic_gantt
09 Inline multiple diagrams without SVG id collisions render cargo run -p merman --features render --example example_09_multiple_diagrams
10 Integrate with a desktop GUI host via egui egui-example cargo run -p merman --features egui-example --example example_10_integration_egui
11 Build a custom host output environment render cargo run -p merman --features render --example example_11_custom_output_environment > host-preview.svg

The egui example is intentionally a host-integration skeleton rather than a full playground: it keeps a long-lived renderer, edits Mermaid source, previews a raster texture, reports render errors, and saves SVG/PNG outputs.

Quickstart (CLI)

# Detect diagram type
merman-cli detect path/to/diagram.mmd

# Parse -> semantic JSON
merman-cli parse path/to/diagram.mmd --pretty

# Layout -> layout JSON
merman-cli layout path/to/diagram.mmd --pretty

# Render SVG
merman-cli render path/to/diagram.mmd --out out.svg

# Render terminal text output
merman-cli render --format unicode path/to/diagram.mmd
merman-cli render --format ascii path/to/diagram.mmd

# Terminal text supports common flowchart directions, labels, shapes, and simple subgraphs
printf "flowchart TB\nsubgraph one\nA((Start)) -- go --> B[(DB)]\nend\n" |
  merman-cli render --format ascii -

# Render raster formats
merman-cli render --format png --out out.png path/to/diagram.mmd
merman-cli render --format jpg --out out.jpg path/to/diagram.mmd
merman-cli render --format pdf --out out.pdf path/to/diagram.mmd

Minimal end-to-end example:

cat > example.mmd <<'EOF'
flowchart TD
  A[Start] --> B{Decision}
  B -->|Yes| C[Do thing]
  B -->|No| D[Do other thing]
EOF

merman-cli render example.mmd --out example.svg
merman-cli render --format ascii example.mmd
@'
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

Library API details

The merman crate is a convenience wrapper around merman-core (parsing) and output crates such as merman-render (layout + SVG) and merman-ascii (ASCII/Unicode text). Enable the render feature when you want layout + SVG, ascii when you want text output, and raster when you also need PNG/JPG/PDF from Rust (no CLI required).

use merman_core::{Engine, ParseOptions};
use merman::render::{
    headless_layout_options, render_svg_sync, sanitize_svg_id, SvgRenderOptions,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let engine = Engine::new();

    let layout = headless_layout_options();

    // For UIs that inline multiple diagrams, set a per-diagram SVG id to avoid internal `<defs>`
    // and accessibility id collisions.
    let svg_opts = SvgRenderOptions {
        diagram_id: Some(sanitize_svg_id("example-diagram")),
        ..SvgRenderOptions::default()
    };

    // Executor-free synchronous entrypoint (the work is CPU-bound and does not perform I/O).
    let svg = render_svg_sync(
        &engine,
        "flowchart TD; A-->B;",
        ParseOptions::default(),
        &layout,
        &svg_opts,
    )?
    .unwrap();

    println!("{svg}");
    Ok(())
}

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_with_type_sync(...) to skip type detection.

If your downstream renderer does not support SVG <foreignObject> (common for rasterizers), prefer HeadlessRenderer::render_svg_resvg_safe_sync(). Use HeadlessRenderer::render_svg_readable_sync() when you want to keep the original <foreignObject> nodes and add best-effort <text>/<tspan> fallback overlays.

When you enable the raster feature, PNG/JPG conversion is target-aware and budgeted. A Mermaid SVG can legitimately have a very large viewBox; browser previews usually draw that vector SVG inside a smaller container, while a headless PNG/JPG path must allocate a concrete pixmap. Use RasterOptions::with_fit_to(...) for preview-sized output, scale for device-pixel ratio, and RasterSizeLimit for the final pixmap budget. The default PNG/JPG budget caps output at 8192px per side and 8192*8192 pixels; trusted oversized exports can call RasterOptions::with_unbounded_size().

Runnable raster example:

cargo run -p merman --features raster --example example_05_raster_output
printf "flowchart LR\nA --> B\n" | \
  cargo run -p merman --features raster --example example_05_raster_output -- target/example.png

The split is in

Extension points exported contracts — how you extend this code

Core symbols most depended-on inside this repo

Shape

Function 7,830
Method 1,695
Class 1,118
Enum 193
Interface 60

Languages

Rust92%
TypeScript6%
Python1%
Kotlin1%
C++1%
C1%

Modules by API surface

crates/manatee/src/algo/fcose/mod.rs131 symbols
crates/xtask/src/cmd/debug/architecture.rs123 symbols
crates/dugong-graphlib/src/graph/core.rs113 symbols
crates/merman-render/src/model.rs108 symbols
crates/merman-core/src/diagrams/block.rs107 symbols
crates/merman-core/src/diagrams/c4.rs103 symbols
crates/merman-render/src/svg/parity/theme.rs102 symbols
crates/merman-render/src/venn.rs91 symbols
crates/xtask/src/svgdom.rs81 symbols
crates/merman-core/src/tests/flowchart.rs81 symbols
crates/merman/src/render/mod.rs79 symbols
crates/merman-core/src/diagrams/git_graph.rs78 symbols

For agents

$ claude mcp add merman \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page