Expand description
mmdflux — Mermaid diagrams to text, SVG, and MMDS
mmdflux parses Mermaid diagram syntax and renders it as Unicode/ASCII text, SVG, or structured JSON (MMDS). Supported diagram types: flowchart, class, state, and sequence.
§High-Level API
Most consumers only need the facade functions and two config types:
render_diagram— render Mermaid source or MMDS JSON in one callmaterialize_diagram— materialize Mermaid source or MMDS JSON as a graph-familymmds::Documentrender_document— render an already-parsedmmds::Documentdetect_diagram— detect the diagram type without renderingvalidate_diagram— parse and return structured JSON diagnosticsOutputFormat—Text,Ascii,Svg, orMmdsRenderConfig— layout engine, routing, padding, color, and more
Use render_diagram when you have text input. It auto-detects Mermaid
source vs MMDS JSON because both represent the same abstract diagram. Use
materialize_diagram when you want the typed mmds::Document, and use
render_document when you already have one, such as after
views::project.
For document-level workflows, use commands::apply to mutate a document,
mmds::diff::diff_documents to compare two snapshots, and
views::project to produce a read-side view.
use mmdflux::{OutputFormat, RenderConfig, render_diagram};
let input = "graph TD\n A[Collect] --> B[Render]";
// Render as Unicode text
let text = render_diagram(input, OutputFormat::Text, &RenderConfig::default()).unwrap();
println!("{text}");
// Render as SVG
let svg = render_diagram(input, OutputFormat::Svg, &RenderConfig::default()).unwrap();
assert!(svg.contains("<svg"));
// Render as MMDS JSON (structured interchange format)
let json = render_diagram(input, OutputFormat::Mmds, &RenderConfig::default()).unwrap();
assert!(json.contains("\"diagram_type\""));
// MMDS JSON is also accepted as text input.
let replayed = render_diagram(&json, OutputFormat::Text, &RenderConfig::default()).unwrap();
assert!(!replayed.trim().is_empty());§Customizing output
Use RenderConfig to control layout direction, engine selection, edge
routing, padding, color mode, and more:
use mmdflux::{OutputFormat, RenderConfig, render_diagram};
use mmdflux::LayoutConfig;
use mmdflux::format::RoutingStyle;
let config = RenderConfig {
routing_style: Some(RoutingStyle::Direct),
padding: Some(2),
layout: LayoutConfig {
rank_sep: 30.0,
..LayoutConfig::default()
},
..RenderConfig::default()
};
let output = render_diagram("graph LR\n A-->B-->C", OutputFormat::Text, &config).unwrap();
println!("{output}");§Validation
validate_diagram returns structured JSON diagnostics suitable for
editor integrations and CI pipelines:
use mmdflux::validate_diagram;
let result = validate_diagram("graph TD\n A-->B");
let json: serde_json::Value = serde_json::from_str(&result).unwrap();
assert_eq!(json["valid"], true);§Low-Level API
For adapters, tooling, or workflows that need explicit control over the detect → parse → payload → render pipeline, the low-level API provides:
builtins::default_registry— the built-in diagram registryregistry—DiagramRegistry,DiagramInstance, andParsedDiagramtraitspayload— thepayload::Diagramenum returned byParsedDiagram::into_payloadgraph— graph-family IR types (Graph,Node,Edge,Shape,Direction)timeline— timeline-family types (Sequence)mmds— MMDS parsing, hydration tograph::Graph, profile negotiation, and Mermaid regenerationviews— materialized read-side views over canonicalmmds::Documentpayloads
use mmdflux::builtins::default_registry;
use mmdflux::payload::Diagram;
let input = "graph TD\n A[Draft] --> B[Published]";
let registry = default_registry();
// Detect diagram type
let resolved = registry.resolve(input).expect("should detect diagram type");
println!("detected: {} ({:?})", resolved.diagram_id(), resolved.family());
// Parse and build payload
let instance = registry.create(resolved.diagram_id()).unwrap();
let payload = instance
.parse(input).unwrap()
.into_payload().unwrap();
// Inspect the payload
match payload {
Diagram::Flowchart(graph) => {
println!("flowchart with {} nodes", graph.nodes.len());
}
Diagram::Class(graph) => {
println!("class diagram with {} nodes", graph.nodes.len());
}
Diagram::State(graph) => {
println!("state diagram with {} nodes", graph.nodes.len());
}
Diagram::Sequence(seq) => {
println!("sequence with {} participants", seq.participants.len());
}
}§MMDS interchange
MMDS is mmdflux’s structured JSON format for diagram geometry.
Use the mmds module to parse MMDS input, hydrate it to a
graph::Graph, or regenerate Mermaid source. To render MMDS input to
text/SVG, pass it to render_diagram which auto-detects MMDS:
use mmdflux::mmds::{from_str, generate_mermaid_from_str};
let mmds_json = r#"{
"version": 1,
"profiles": ["mmds-core-v1"],
"defaults": {
"node": { "shape": "rectangle" },
"edge": { "stroke": "solid", "arrow_start": "none", "arrow_end": "normal", "minlen": 1 }
},
"geometry_level": "layout",
"metadata": {
"diagram_type": "flowchart",
"direction": "TD",
"bounds": { "width": 100.0, "height": 80.0 }
},
"nodes": [
{ "id": "A", "label": "Start", "position": { "x": 50.0, "y": 20.0 },
"size": { "width": 50.0, "height": 20.0 } },
{ "id": "B", "label": "End", "position": { "x": 50.0, "y": 60.0 },
"size": { "width": 50.0, "height": 20.0 } }
],
"edges": [{ "id": "e0", "source": "A", "target": "B" }]
}"#;
// Hydrate to graph IR
let graph = from_str(mmds_json).unwrap();
assert_eq!(graph.nodes.len(), 2);
// Regenerate Mermaid source
let mermaid = generate_mermaid_from_str(mmds_json).unwrap();
assert!(mermaid.contains("flowchart TD"));§Commands and Model Events
Public MMDS commands mutate a document and emit model events that describe the accepted state transition:
use mmdflux::commands::{Command, apply};
use mmdflux::graph::Shape;
use mmdflux::mmds::Subject;
use mmdflux::mmds::events::ModelEventKind;
use mmdflux::{RenderConfig, materialize_diagram};
let mut document = materialize_diagram(
"graph TD\n A[Gateway] --> B[Billing]",
&RenderConfig::default(),
)?;
let model_events = apply(
&Command::AddNode {
id: "C".to_string(),
label: "Auth".to_string(),
shape: Shape::Rectangle,
parent: None,
},
&mut document,
)?;
assert!(model_events.iter().any(|event| {
event.kind == ModelEventKind::NodeAdded
&& matches!(&event.subject, Subject::Node(id) if id == "C")
}));
assert!(document.nodes.iter().any(|node| node.id == "C"));§Snapshot Diffs
mmds::diff::diff_documents compares two document states and reports a
snapshot diff. Diff changes describe what is different between snapshots;
they do not describe edit intent or command history:
use mmdflux::mmds::Subject;
use mmdflux::mmds::diff::{ChangeKind, diff_documents};
use mmdflux::{RenderConfig, materialize_diagram};
let before = materialize_diagram(
"graph TD\n A[Gateway] --> B[Billing]",
&RenderConfig::default(),
)?;
let after = materialize_diagram(
"graph TD\n A[Gateway] --> B[Billing]\n A --> C[Auth]",
&RenderConfig::default(),
)?;
let diff = diff_documents(&before, &after);
assert!(diff.changes.iter().any(|change| {
change.kind == ChangeKind::NodeAdded
&& matches!(&change.subject, Subject::Node(id) if id == "C")
}));§Views
Use views when an adapter needs a focused read model over a canonical
MMDS payload. V1 views preserve shared coordinates, keep surviving edge IDs
sparse and stable, and return views::ViewEvent values for omitted
elements:
use mmdflux::mmds::Document;
use mmdflux::views::{
AnchorRef, Selector, TraversalDirection, ViewSpec, ViewStatement, project,
};
use mmdflux::{OutputFormat, RenderConfig, materialize_diagram, render_document};
let source = "\
graph TD
A[Gateway] --> B[Auth]
B --> C[Database]
A --> D[Audit]
";
let canonical: Document = materialize_diagram(source, &RenderConfig::default()).unwrap();
let spec = ViewSpec::new(vec![ViewStatement::Include(Selector::Traversal {
anchor: AnchorRef::Node("A".to_string()),
direction: TraversalDirection::Downstream,
hops: 1,
})]);
let (view, events) = project(&canonical, &spec).unwrap();
let text = render_document(&view, OutputFormat::Text, &RenderConfig::default()).unwrap();
assert!(text.contains("Gateway"));
assert_eq!(view.nodes.len(), 3);
assert!(events.iter().any(|event| matches!(
event,
mmdflux::views::ViewEvent::NodeLeftView { id, .. } if id == "C"
)));§Stability
The commands, mmds::events, mmds::diff, and views modules are early
surfaces. The following kinds of changes will land in minor versions and are
not considered breaking under this crate’s SemVer policy:
- new variants on the early-surface enums marked
#[non_exhaustive](includingcommands::Command,commands::EdgeSelector,commands::CommandApplyError,mmds::events::ModelEventKind,mmds::diff::ChangeKind,mmds::Subject,views::ViewStatement,views::Selector,views::ViewEvent,views::ViewError, and the supporting view vocabulary) - new fields on early-surface structs marked
#[non_exhaustive](includingmmds::events::ModelEvent,mmds::diff::Change,mmds::diff::Diff,mmds::MmdsTokenError, andviews::ViewSpec)
What is not covered:
- Renaming, removing, or changing the meaning of an existing variant or field remains a breaking change.
- Adding fields to existing struct-like enum variants
(for example,
Command::AddNode { ... }) is still breaking; individual variants are not currently marked#[non_exhaustive]. - The runtime facade (
render_diagram,materialize_diagram,render_document,detect_diagram,validate_diagram,OutputFormat,RenderConfig,RenderError) follows standard SemVer. views::TraversalDirectionis intentionally exhaustive because its vocabulary is closed.
Re-exports§
pub use errors::RenderError;pub use format::ColorWhen;pub use format::OutputFormat;pub use format::TextColorMode;
Modules§
- builtins
- Built-in diagram registry assembly.
- commands
- Command vocabulary and synchronous MMDS command application.
- errors
- Error and diagnostic types for rendering and validation.
- format
- Output format, curve, edge preset, and routing style definitions.
- graph
- Shared graph-family core.
- mmds
- MMDS interchange contract and document-generation namespace.
- payload
- Runtime payload contract returned by
crate::registry::ParsedDiagram::into_payload. - registry
- Diagram registry for type detection and dispatch.
- simplification
- Post-routing path simplification levels for MMDS and SVG output.
- timeline
- Timeline-family runtime namespaces.
- views
- Materialized diagram views over canonical MMDS payloads.
Structs§
- Engine
Algorithm Id - Combined engine + algorithm identifier for explicit layout engine selection. Combined engine+algorithm identifier for explicit layout engine selection.
- Graph
Text Style Config - Graph-family text style requested through public render config.
- Layout
Config - Layout configuration for the Sugiyama hierarchical engine. Canonical caller-facing graph layout configuration.
- Render
Config - Configuration for rendering.
- Runtime
Config Input - Serde-friendly config input for JSON consumers (Wasm, API). Serde-friendly render config accepted from JSON callers.
- Subgraph
Title Margin - Layout configuration for the Sugiyama hierarchical engine.
Rank-axis margin reserved around a subgraph’s title text, mirroring
Mermaid’s
flowchart.subGraphTitleMargin: { top, bottom }knob. - SvgTheme
Config - SVG theme configuration owned by the runtime facade.
Enums§
- Algorithm
Id - Algorithm identifier (e.g.,
Layered,Mrtree) used in engine selection. Algorithm identifier used in the combined engine+algorithm taxonomy. - Engine
Id - Engine identifier (e.g.,
Flux,Mermaid,Elk). Engine family identifier used in the combined engine+algorithm taxonomy. - Label
Dummy Placement - Layout configuration for the Sugiyama hierarchical engine.
Placement strategy for edge-label dummies within long edge chains.
Orthogonal to
LabelDummyRouting: placement decides where the label dummy sits in the chain, while routing decides how the edge traverses it. - Label
Dummy Routing - Layout configuration for the Sugiyama hierarchical engine.
Routing strategy for how an edge path traverses its label dummy’s rect.
Orthogonal to
LabelDummyPlacement. - Layout
Direction - Layout configuration for the Sugiyama hierarchical engine. Direction for the public graph-layout config.
- Ranker
- Layout configuration for the Sugiyama hierarchical engine. Ranking algorithm selection for the public graph-layout config.
- SvgTheme
Mode - SVG theme rendering mode.
Functions§
- apply_
svg_ surface_ defaults - Apply default SVG surface settings (curve, engine) when format is SVG. Apply SVG surface defaults for flux-layered engine.
- detect_
diagram - Detect the diagram type from input text. Detect the diagram type from input text.
- materialize_
diagram - Detect, parse, solve, and materialize Mermaid source or MMDS JSON as MMDS. Detect, parse, solve, and materialize graph-family text input as MMDS.
- render_
diagram - Detect, parse, and render Mermaid source or MMDS JSON in one call. Detect, parse, and render a diagram from text input in one call.
- render_
document - Render a parsed graph-family MMDS document. Render a parsed graph-family MMDS document.
- validate_
diagram - Validate input and return structured JSON diagnostics. Validate Mermaid input and return structured diagnostics as JSON.