Layout-fidelity scorecard
How closely our flowchart, state, class and ER layouts match official mermaid.js: the share of node pairs placed in the same above/below/beside relation (vertical, horizontal) and of node/subgraph pairs that agree on containment. Only relative placement is compared. Each sample has an explicit floor for its lowest figure (default 85%, lower overrides in SAMPLE_FLOORS); --thresholds exits 1 on a breach. Floors guard against regressions, they do not claim parity. Method: scripts/layout-oracle.ts.
Reference: mermaid 12.2.0. Since mermaid 12.0.0 its default layout engine for these diagram types is ELK (it was dagre before). Generated 2026-11-02 at ae439b3 with pnpm run layout:scorecard, tolerance 20px.
Latest run (means over samples)
| Type | Samples | Vertical | Horizontal | Containment |
|---|---|---|---|---|
| Flowchart | 56 | 100% | 98% | 100% |
| State | 7 | 100% | 98% | 100% |
| Class | 29 | 100% | 100% | 100% |
| ER | 20 | 100% | 100% | - |
Trend (last 20 recorded runs)
Runs recorded before 12.1.0 were measured against mermaid 11.17.2 (dagre) and cover flowcharts only. The reference changed engine, so do not read a trend across that change.
| Date | Commit | Mermaid | Type | Samples | Vertical | Horizontal | Containment |
|---|---|---|---|---|---|---|---|
| 2026-10-30 | 036684d | 12.2.0 | Flowchart | 53 | 100% | 98% | 100% |
| 2026-10-30 | 036684d | 12.2.0 | State | 7 | 100% | 98% | 100% |
| 2026-10-30 | 036684d | 12.2.0 | Class | 29 | 100% | 100% | 100% |
| 2026-10-30 | 036684d | 12.2.0 | ER | 20 | 100% | 100% | - |
| 2026-10-30 | 151f853 | 12.2.0 | Flowchart | 53 | 100% | 98% | 100% |
| 2026-10-30 | 151f853 | 12.2.0 | State | 7 | 100% | 98% | 100% |
| 2026-10-30 | 151f853 | 12.2.0 | Class | 29 | 100% | 100% | 100% |
| 2026-10-30 | 151f853 | 12.2.0 | ER | 20 | 100% | 100% | - |
| 2026-10-31 | ac52e8a | 12.2.0 | Flowchart | 53 | 100% | 98% | 100% |
| 2026-10-31 | ac52e8a | 12.2.0 | State | 7 | 100% | 98% | 100% |
| 2026-10-31 | ac52e8a | 12.2.0 | Class | 29 | 100% | 100% | 100% |
| 2026-10-31 | ac52e8a | 12.2.0 | ER | 20 | 100% | 100% | - |
| 2026-10-31 | 67dd7ff | 12.2.0 | Flowchart | 53 | 100% | 98% | 100% |
| 2026-10-31 | 67dd7ff | 12.2.0 | State | 7 | 100% | 98% | 100% |
| 2026-10-31 | 67dd7ff | 12.2.0 | Class | 29 | 100% | 100% | 100% |
| 2026-10-31 | 67dd7ff | 12.2.0 | ER | 20 | 100% | 100% | - |
| 2026-11-02 | ae439b3 | 12.2.0 | Flowchart | 56 | 100% | 98% | 100% |
| 2026-11-02 | ae439b3 | 12.2.0 | State | 7 | 100% | 98% | 100% |
| 2026-11-02 | ae439b3 | 12.2.0 | Class | 29 | 100% | 100% | 100% |
| 2026-11-02 | ae439b3 | 12.2.0 | ER | 20 | 100% | 100% | - |
Edge labels (ASCII)
Where an edge label sits between its two nodes (0 = source end, 1 = target end; official mermaid centres it at about 0.5), averaged over the cases in scripts/label-position-oracle.ts. Delta is the mean absolute difference between the two renderers. Descriptive only, no floor.
| Date | Commit | Mermaid | Cases | Official | ASCII | Delta |
|---|---|---|---|---|---|---|
| 2026-10-27 | a70ae2e | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-10-30 | 507a226 | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-10-30 | 79a0125 | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-10-30 | 961cbfa | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-10-30 | 036684d | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-10-30 | 151f853 | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-10-31 | ac52e8a | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-10-31 | 67dd7ff | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
| 2026-11-02 | ae439b3 | 12.2.0 | 4 | 0.50 | 0.53 | 0.06 |
Sequence diagrams (order)
Sequence has no layout engine to compare, so the share of agreeing pairs is taken for participant left-to-right order and message top-to-bottom order, and the share of messages pointing the same way (scripts/sequence-oracle.ts). Every sample must score 100% (SEQUENCE_FLOOR; --thresholds exits 1 otherwise), so this guards against regressions in a grid that agrees today. It says nothing about pixel positions or spacing.
| Date | Commit | Mermaid | Samples | Participants | Messages | Direction |
|---|---|---|---|---|---|---|
| 2026-10-30 | 507a226 | 12.2.0 | 21 | 100% | 100% | 100% |
| 2026-10-30 | 79a0125 | 12.2.0 | 21 | 100% | 100% | 100% |
| 2026-10-30 | 961cbfa | 12.2.0 | 21 | 100% | 100% | 100% |
| 2026-10-30 | 036684d | 12.2.0 | 21 | 100% | 100% | 100% |
| 2026-10-30 | 151f853 | 12.2.0 | 21 | 100% | 100% | 100% |
| 2026-10-31 | ac52e8a | 12.2.0 | 21 | 100% | 100% | 100% |
| 2026-10-31 | 67dd7ff | 12.2.0 | 21 | 100% | 100% | 100% |
| 2026-11-02 | ae439b3 | 12.2.0 | 24 | 100% | 100% | 100% |
Pie charts (angles)
A pie has no nodes, so the share of drawn slices whose start and sweep angle agree (within ANGLE_TOLERANCE), of slices printing the same percentage and of legend rows with the same text is taken (scripts/pie-oracle.ts). Slices are matched by position, so a different slice order counts as an angle disagreement. Every sample must score 100% (PIE_FLOOR; --thresholds exits 1 otherwise). It says nothing about radius, centre or fonts.
| Date | Commit | Mermaid | Samples | Angles | Labels | Legend |
|---|---|---|---|---|---|---|
| 2026-10-30 | 79a0125 | 12.2.0 | 19 | 100% | 100% | 100% |
| 2026-10-30 | 961cbfa | 12.2.0 | 19 | 100% | 100% | 100% |
| 2026-10-30 | 036684d | 12.2.0 | 19 | 100% | 100% | 100% |
| 2026-10-30 | 151f853 | 12.2.0 | 19 | 100% | 100% | 100% |
| 2026-10-31 | ac52e8a | 12.2.0 | 19 | 100% | 100% | 100% |
| 2026-10-31 | 67dd7ff | 12.2.0 | 19 | 100% | 100% | 100% |
| 2026-11-02 | ae439b3 | 12.2.0 | 19 | 100% | 100% | 100% |
C4 diagrams (placement)
C4 has no layout engine to compare, so the share of box pairs on the same side of each other (columns and rows, within PLACE_TOLERANCE), of boxes inside the same boundaries, of relationships with the same label and technology text and of relationships running the same way is taken (scripts/c4-oracle.ts). Every sample must score 100% (C4_FLOOR; --thresholds exits 1 otherwise) except those held lower in C4_SAMPLE_FLOORS, where our placement really differs. It says nothing about box sizes or fonts.
| Date | Commit | Mermaid | Samples | Horizontal | Vertical | Containment | Relationships | Direction |
|---|---|---|---|---|---|---|---|---|
| 2026-10-30 | 961cbfa | 12.2.0 | 3 | 91% | 93% | 100% | 100% | 93% |
| 2026-10-30 | 036684d | 12.2.0 | 3 | 91% | 93% | 100% | 100% | 93% |
| 2026-10-30 | 151f853 | 12.2.0 | 3 | 91% | 93% | 100% | 100% | 93% |
| 2026-10-31 | ac52e8a | 12.2.0 | 3 | 91% | 93% | 100% | 100% | 93% |
| 2026-10-31 | 67dd7ff | 12.2.0 | 3 | 91% | 93% | 100% | 100% | 93% |
| 2026-11-02 | ae439b3 | 12.2.0 | 3 | 100% | 100% | 100% | 100% | 100% |
XY charts (axes and data)
An xychart has no nodes, so the share of axis labels with the same text, of axis labels at the same fraction of their axis and of bars and line points at the same category and value fraction is taken (scripts/xychart-oracle.ts). Positions are fractions of the axis, so canvas size does not count. Every sample must score 100% (XYCHART_FLOOR; --thresholds exits 1 otherwise). It says nothing about colors, fonts or bar widths.
| Date | Commit | Mermaid | Samples | Labels | Ticks | Data |
|---|---|---|---|---|---|---|
| 2026-10-30 | 036684d | 12.2.0 | 10 | 100% | 100% | 90% |
| 2026-10-31 | ac52e8a | 12.2.0 | 10 | 100% | 100% | 90% |
| 2026-10-31 | 67dd7ff | 12.2.0 | 10 | 100% | 100% | 90% |
| 2026-11-02 | ae439b3 | 12.2.0 | 10 | 100% | 100% | 100% |
Architecture diagrams (placement)
Mermaid places architecture services with cytoscape fcose, constrained by the L/R/T/B sides in the source. A force layout moves with its seed and font metrics, so only relative placement is scored: the share of service pairs above / below / beside each other and of (service, group) pairs agreeing on containment, with services within ARCH_TOLERANCE (half an icon) counted as level (scripts/architecture-oracle.ts). Every sample must stay at or above ARCH_FLOOR (--thresholds exits 1 otherwise), a regression guard, not a parity claim. It says nothing about distances or edge routes.
| Date | Commit | Mermaid | Samples | Vertical | Horizontal | Containment |
|---|---|---|---|---|---|---|
| 2026-10-30 | 151f853 | 12.2.0 | 3 | 68% | 84% | 97% |
| 2026-10-31 | ac52e8a | 12.2.0 | 3 | 68% | 84% | 97% |
| 2026-10-31 | 67dd7ff | 12.2.0 | 3 | 68% | 84% | 97% |
| 2026-11-02 | ae439b3 | 12.2.0 | 3 | 74% | 90% | 97% |
Per sample
Flowchart (lowest first)
| Sample | Vertical | Horizontal | Containment | Nodes | Floor | Status |
|---|---|---|---|---|---|---|
| Flowchart: Self-Loop with In and Out Neighbours (TD) | 100% | 33% | - | 3 | 30% | pass |
| Flowchart: Dense Duplicate Edges (TD) | 100% | 67% | - | 3 | 65% | pass |
| System Architecture | 89% | 100% | 100% | 10 | 85% | pass |
| Fan-Out Under Half-Column Parent | 100% | 97% | - | 9 | 85% | pass |
| Simple Flow | 100% | 100% | - | 3 | 85% | pass |
| Original Node Shapes | 100% | 100% | - | 5 | 85% | pass |
| Subroutine and Hexagon Shapes | 100% | 100% | - | 3 | 85% | pass |
| Cylinder and Trapezoid Shapes | 100% | 100% | - | 4 | 85% | pass |
| Twelve Core Flowchart Shapes | 100% | 100% | - | 12 | 85% | pass |
| All Edge Styles | 100% | 100% | - | 4 | 85% | pass |
| No-Arrow Edges | 100% | 100% | - | 4 | 85% | pass |
| Text-Embedded Labels | 100% | 100% | - | 5 | 85% | pass |
| Bidirectional Arrows | 100% | 100% | - | 4 | 85% | pass |
| Parallel Links (&) | 100% | 100% | - | 5 | 85% | pass |
| Chained Edges | 100% | 100% | - | 5 | 85% | pass |
| linkStyle: Color-Coded Edges | 100% | 100% | - | 5 | 85% | pass |
| linkStyle: Default + Override | 100% | 100% | - | 5 | 85% | pass |
| Direction: Left-Right (LR) | 100% | 100% | - | 3 | 85% | pass |
| Direction: Bottom-Top (BT) | 100% | 100% | - | 3 | 85% | pass |
| Subgraphs | 100% | 100% | 100% | 4 | 85% | pass |
| Nested Subgraphs | 100% | 100% | 100% | 5 | 95% | pass |
| Subgraph Direction Override | 100% | 100% | 100% | 6 | 85% | pass |
| ::: Class Shorthand | 100% | 100% | - | 3 | 85% | pass |
| Inline Style Overrides | 100% | 100% | - | 3 | 85% | pass |
| CI/CD Pipeline | 100% | 100% | 100% | 7 | 85% | pass |
| Decision Tree | 100% | 100% | - | 7 | 85% | pass |
| Git Branching Workflow | 100% | 100% | - | 7 | 85% | pass |
| Interactivity: Links and Tooltips | 100% | 100% | - | 3 | 85% | pass |
| Interactivity: Animated Edge | 100% | 100% | - | 3 | 85% | pass |
| Labeled Fan-In (LR) | 100% | 100% | - | 4 | 85% | pass |
| Direction: Right-Left (RL) | 100% | 100% | - | 4 | 85% | pass |
| Nested Subgraphs (RL) | 100% | 100% | 100% | 4 | 85% | pass |
| Nested Subgraphs (BT) | 100% | 100% | 100% | 4 | 85% | pass |
| Edges Into and Out of Subgraphs | 100% | 100% | 100% | 8 | 85% | pass |
| Vertical Edge Labels | 100% | 100% | - | 5 | 85% | pass |
| Flowchart: CJK Labels | 100% | 100% | 100% | 4 | 95% | pass |
| Flowchart: Three Parallel Edges (TD) | 100% | 100% | - | 2 | 85% | pass |
| Flowchart: Three Parallel Edges Plus Reciprocal (TD) | 100% | 100% | - | 2 | 85% | pass |
| Flowchart: Four Parallel Edges (TD) | 100% | 100% | - | 2 | 85% | pass |
| Flowchart: Five Cluster Exit Siblings (TD) | 100% | 100% | 100% | 4 | 85% | pass |
| LR Fan-In With Bypass Edge | 100% | 100% | - | 3 | 85% | pass |
| Reciprocal and Duplicate Edges RL | 100% | 100% | - | 2 | 85% | pass |
| Decision Self-Loop with Duplicate Edges | 100% | 100% | - | 4 | 85% | pass |
| LR Bypass Edge In A Chain | 100% | 100% | - | 4 | 85% | pass |
| Flowchart: Five Parallel Edges (TD) | 100% | 100% | - | 2 | 85% | pass |
| Flowchart: Five Parallel Edges with Reciprocals (LR) | 100% | 100% | - | 2 | 85% | pass |
| Flowchart: Six Cluster Exit Siblings (TD) | 100% | 100% | 100% | 4 | 85% | pass |
| Flowchart: Parallel Edges with Back Edges (TD) | 100% | 100% | - | 2 | 85% | pass |
| Flowchart: Cluster Exit Siblings with No Other Exit (TD) | 100% | 100% | 100% | 3 | 85% | pass |
| Flowchart: Nine Cluster Exit Siblings (TD) | 100% | 100% | 100% | 4 | 85% | pass |
| Flowchart: Self-Loop with In and Out Neighbours (LR) | 100% | 100% | - | 3 | 85% | pass |
| Flowchart: Dense Duplicate Edges (LR) | 100% | 100% | - | 3 | 85% | pass |
| Parallelogram Shapes (LR) | 100% | 100% | - | 4 | 85% | pass |
| Parallelogram Shapes (RL) | 100% | 100% | - | 4 | 85% | pass |
| Parallelogram Shapes (BT) | 100% | 100% | - | 4 | 85% | pass |
| Duplicate Self-Loops | - | - | - | 1 | 85% | n/a |
State (lowest first)
Not scored (the oracle errored): zombie-mermaid.
| Sample | Vertical | Horizontal | Containment | Nodes | Floor | Status |
|---|---|---|---|---|---|---|
| State: Notes | 100% | 83% | - | 4 | 80% | pass |
| State: Basic State Diagram | 100% | 100% | - | 5 | 85% | pass |
| State: Composite States | 100% | 100% | 100% | 8 | 85% | pass |
| State: Connection Lifecycle | 100% | 100% | - | 7 | 85% | pass |
| State: CJK State Names | 100% | 100% | - | 6 | 85% | pass |
| State: Choice, Fork and Join | 100% | 100% | - | 7 | 85% | pass |
| State: Concurrent Regions | 100% | 100% | 100% | 4 | 85% | pass |
Class (lowest first)
| Sample | Vertical | Horizontal | Containment | Nodes | Floor | Status |
|---|---|---|---|---|---|---|
| Class: Inheritance (<|--) | 100% | 100% | - | 3 | 95% | pass |
| Class: Composition (*--) | 100% | 100% | - | 2 | 85% | pass |
| Class: Aggregation | 100% | 100% | - | 2 | 85% | pass |
| Class: Association (-->) | 100% | 100% | - | 2 | 85% | pass |
| Class: Dependency (..>) | 100% | 100% | - | 2 | 85% | pass |
| Class: Realization (..|>) | 100% | 100% | - | 2 | 85% | pass |
| Class: All 6 Relationship Types | 100% | 100% | - | 12 | 85% | pass |
| Class: Relationship Labels | 100% | 100% | - | 3 | 95% | pass |
| Class: Design Pattern — Observer | 100% | 100% | - | 5 | 85% | pass |
| Class: MVC Architecture | 100% | 100% | - | 3 | 95% | pass |
| Class: Full Hierarchy | 100% | 100% | - | 6 | 95% | pass |
| Class: Namespaces | 100% | 100% | 100% | 3 | 95% | pass |
| Class: classDiagram-v2 Header | 100% | 100% | - | 2 | 85% | pass |
| Class: Bidirectional Relationships | 100% | 100% | - | 4 | 85% | pass |
| Class: Lollipop Interface | 100% | 100% | - | 2 | 85% | pass |
| Class: Backtick Class Names | 100% | 100% | - | 2 | 85% | pass |
| Class: Mixed Newly Accepted Syntax | 100% | 100% | - | 5 | 85% | pass |
| Class: Relationship Cardinalities | 100% | 100% | - | 4 | 85% | pass |
| Class: Cardinalities on Every Relationship Kind | 100% | 100% | - | 12 | 85% | pass |
| Class: Cardinalities with Shared Ends | 100% | 100% | - | 4 | 85% | pass |
| Class: Direction LR | 100% | 100% | - | 4 | 85% | pass |
| Class: Direction BT | 100% | 100% | - | 4 | 85% | pass |
| Class: Direction RL with Namespaces | 100% | 100% | 100% | 3 | 85% | pass |
| Class: Two Namespaces with Cross Edges | 100% | 100% | 100% | 4 | 85% | pass |
| Class: Basic Class | - | - | - | 1 | 85% | n/a |
| Class: Visibility Markers | - | - | - | 1 | 85% | n/a |
| Class: Interface Annotation | - | - | - | 1 | 85% | n/a |
| Class: Abstract Annotation | - | - | - | 1 | 85% | n/a |
| Class: Enum Annotation | - | - | - | 1 | 85% | n/a |
ER (lowest first)
| Sample | Vertical | Horizontal | Containment | Nodes | Floor | Status |
|---|---|---|---|---|---|---|
| ER: Basic Relationship | 100% | 100% | - | 2 | 85% | pass |
| ER: Exactly One to Exactly One (||--||) | 100% | 100% | - | 2 | 85% | pass |
| ER: Exactly One to Zero-or-Many | 100% | 100% | - | 2 | 85% | pass |
| ER: Zero-or-One to One-or-Many | 100% | 100% | - | 2 | 85% | pass |
| ER: One-or-More to Zero-or-Many | 100% | 100% | - | 2 | 85% | pass |
| ER: All Cardinality Types | 100% | 100% | - | 8 | 85% | pass |
| ER: Identifying (Solid) Relationship | 100% | 100% | - | 2 | 85% | pass |
| ER: Non-Identifying (Dashed) Relationship | 100% | 100% | - | 3 | 85% | pass |
| ER: Mixed Identifying & Non-Identifying | 100% | 100% | - | 5 | 85% | pass |
| ER: E-Commerce Schema | 100% | 100% | - | 4 | 85% | pass |
| ER: Blog Platform Schema | 100% | 100% | - | 4 | 85% | pass |
| ER: School Management Schema | 100% | 100% | - | 4 | 85% | pass |
| ER: Word-Form Cardinalities and .- / -. Lines | 100% | 100% | - | 8 | 85% | pass |
| ER: Remaining Cardinality Spellings | 100% | 100% | - | 5 | 85% | pass |
| ER: Style, classDef and Class | 100% | 100% | - | 3 | 85% | pass |
| ER: Crossing Edges and Edge Labels | 100% | 100% | - | 5 | 85% | pass |
| ER: Attribute Comments | 100% | 100% | - | 2 | 85% | pass |
| ER: Entity with Attributes | - | - | - | 1 | 85% | n/a |
| ER: Attribute Keys (PK, FK, UK) | - | - | - | 1 | 85% | n/a |
| ER: Multiple Keys per Attribute | - | - | - | 1 | 85% | n/a |
Diagram types not scored
sequence: mermaid draws it on a fixed grid (participants left to right in declaration order, messages top to bottom in source order), not with a layout engine, so node placement says nothing. Order and direction are scored separately, in the Sequence section.
architecture-beta: mermaid places services with cytoscape fcose constrained by the explicit L/R/T/B port sides in the source, a force layout whose distances are not comparable. Relative placement and group containment are scored separately, in the Architecture section.
xychart-beta: no nodes: positions come from axis labels and data values. Label text, tick positions and bar/line data positions are scored separately, in the XY charts section.
pie: no nodes: positions come from data values. Slice angles, percentages and legend rows are scored separately, in the Pie section.
c4: mermaid places C4 boxes on a fixed grid in shape order, not with a layout engine over edges. Box placement, boundary containment and relationships are scored separately, in the C4 section.