Learn / Mermaid & the text format
Mermaid & the text format
Diagrams-as-text is how diagrams live in git. Grafloria reads and writes Mermaid-compatible text — and adds the one thing Mermaid cannot express: your hand-arranged positions, in a sidecar that keeps the text valid Mermaid.
Import
import { importDiagramText } from '@grafloria/engine';
const result = importDiagramText(`flowchart LR
a[Start] --> b{Gate}
b -->|yes| c[Ship]
b -->|no| a`);
result.diagram; // a live DiagramModel — 3 nodes, 3 links
result.diagram.getNodes()[0].getData('label'); // 'Start'
result.diagram.getNodes()[0].type; // 'flowchart:process' — typed, not generic
Imported nodes carry semantic types (flowchart:process,
flowchart:decision, ER entities, class boxes…), so they render with the
right glyphs and get type-aware layout — a state machine lays out differently from an
entity-relationship diagram.
Supported types — and the honest line
flowchart/graph, erDiagram,
classDiagram, stateDiagram/stateDiagram-v2,
architecture-beta and block-beta. These six are verified against
real Mermaid by a CI oracle — real Mermaid must accept both the text and what Grafloria
writes back. architecture-beta's sided lines and block-beta's grid
are laid out by the architecture layout. Everything else
is refused loudly rather than rendered wrongly:
const r = importDiagramText('sequenceDiagram\n A->>B: hi');
r.unsupported; // 'sequenceDiagram' — check this field; there is no silent wrong guess
The full Mermaid compatibility story →
Export — and the sidecar trick
import { exportDiagramText } from '@grafloria/engine';
const text = exportDiagramText(diagram);
The output is valid Mermaid that any Mermaid renderer accepts. Positions, sizes and
styling — things Mermaid has no syntax for — ride in a
%%grafloria:document comment block at the end. Mermaid ignores comments;
Grafloria reads them back. So the round trip is lossless for Grafloria and
legible for everyone else: hand-arrange a diagram, export, commit, re-import —
your arrangement survives, and GitHub still previews the file.
The look of an AI-drawn diagram
The diagrams Claude and ChatGPT hand-write as SVG — tinted zones with a caption in a
corner, a bold name over a muted line, coloured labels riding their lines, a red note —
can be written as Mermaid for Grafloria. The body stays Mermaid any renderer accepts:
the look is style, classDef and linkStyle,
<b>Name</b><br/>subtitle labels (or **Name**, or a
markdown string), a <code> subtitle for monospace, and v11's
@{ shape: text } for a note. What Mermaid has no word for rides in
%%grafloria: comments other renderers ignore.
flowchart LR
customer["<b>Customer</b><br/>phone or browser"]
subgraph ours["OUR SIDE · MUST NEVER SEE A CARD"]
api["<b>Our API</b><br/><code>sherkety-erp-api</code>"]
end
note@{ shape: text, label: "if someone swaps the link…" }
customer -.->|"card typed as a<br/>#quot;bank account#quot;"| api
classDef box fill:#fff,stroke:#d0d5dd,shadow:none,rx:4
style ours fill:#f3f4f6,stroke:#d7dbe0,stroke-dasharray:5 4,color:#4b5563,font-weight:bold,letter-spacing:1px
linkStyle 0 interpolate stepBefore stroke:#cf222e,color:#cf222e,font-weight:bold
%% exact position and size — a node or a subgraph
%%grafloria:at customer 20,78 150x292
%% where a zone's caption sits
%%grafloria:group ours caption:bottom-left
%% every edge's default, then one edge's own
%%grafloria:edge * * label:above
%%grafloria:edge customer api from:right@240, to:left@54, label:below, via:300 318
from:/to: pin a line's ends to a point along a side
(right@36 is 36 px down the right side, left@50% halfway);
label: puts the label above or below its line, with no box;
via: lists the bends. linkStyle … color: colours the label,
interpolate stepBefore draws right angles, and shadow:none makes a
flat box. exportDiagramText(diagram, { lossless: false, positions: true })
writes all of it back, so a diagram built on the canvas exports to the same kind of text.
Live: the same diagram from the native API and from Mermaid →
The same look with no coordinates
Pinning every box is exact, and it is geometry by hand. One comment asks for the architecture layout instead: zones become regions on a grid, boxes are sized to their words and aligned in rows, lines run straight where boxes line up and bend in the gutters. What the text then carries is structure and a few relations — none of them a number:
flowchart LR
%%grafloria:layout architecture
customer["<b>Customer</b><br/>phone or browser"]
subgraph hp["HEALTHPAY'S SIDE · CARDS ARE TYPED HERE"]
direction LR
page["<b>HealthPay payment page</b><br/>the card is typed here"]
wallets["<b>HealthPay wallets</b><br/>hold the customer's money"]
end
subgraph ours["OUR SIDE · MUST NEVER SEE A CARD"]
direction LR
api["<b>Our API</b><br/><code>sherkety-erp-api</code>"]
end
fake["<b>Fake card page</b><br/>not HealthPay's"]
note@{ shape: text, label: "if someone swaps the link, the customer lands here (M1)" }
customer -->|card number and CVV| page -->|adds money| wallets
api -->|asks HealthPay to move money| wallets
customer -.-> fake
%% the wallets sit ABOVE the API: the line leaves the API's top
%%grafloria:edge api wallets from:top, to:bottom
%% the fake page hangs BELOW the customer
%%grafloria:edge customer fake from:bottom, to:top
%% a note beside what it warns about
%%grafloria:near note fake right
direction LR inside a subgraph (Mermaid's own) lays the zone's boxes in a
row. A plain side in from:/to: says which way a line leaves — so
where its target sits — and near places a note. An exact
%%grafloria:at still wins for the box it names. Export writes the relations and
the layout back, never the pixels the layout chose.
Live: edit the text, the drawing re-composes →
Live: Mermaid's own architecture-beta and block-beta →
Text and canvas, live
The framework surfaces wire both directions into the live canvas —
instance.exportText() / instance.loadText(text) (React/Vue) and
exportText() / loadText() on the Angular canvas.
loadText reconciles into the existing diagram rather than replacing
it — listeners, plugins and selection survive. That's the pattern behind the Monaco
side-by-side demos: edit text, watch the canvas; drag the canvas, watch the text.
Live: the Mermaid round-trip demos →
bodyEdited and
sidecarInvalid so an editor can tell "the human edited the Mermaid body by
hand" from "the sidecar is stale" and re-layout only when needed.Where next
- Grafloria vs Mermaid — when text-only is enough and when it isn't.
- Layout — what happens when imported text has no positions.