AI-generated Mermaid: fix the layout
Models write Mermaid flowcharts well and lay them out badly. The syntax is usually correct. The picture is not: a return edge cuts through a box, a branch lands on the wrong side, the order of nodes hides the main path. Mermaid has no syntax for positions, so there is nothing in the text to correct.
The fix is to paste the output into the Mermaid visual editor, drag the nodes and connectors into place, and copy the text back. The editor writes the positions into one comment line that other Mermaid renderers ignore, so the diagram still renders on GitHub and still round-trips through the model.
The editor opens flowcharts only, written as flowchart or graph. It does
not open sequence, class, Gantt or any other Mermaid diagram type. See
what to do with those below.
Before: what a model gives you
Here is an order flow of the kind a model writes when asked for one. The
syntax is fine. Both diagrams on this page are rendered by the
@react-markdown-kit/mermaid plugin itself, not screenshots.
```mermaid
flowchart TD
A[Receive order] --> B{Stock available?}
B -->|yes| C[Reserve items]
B -->|no| D[Backorder]
C --> E{Payment ok?}
E -->|yes| F[Ship]
E -->|no| G[Notify customer]
G --> A
D --> G
F --> H[Close order]
```
Read the render. The return edge from Notify customer to Receive order
runs as one straight line through the middle of the diagram and across the
Backorder box. The happy path from Receive order to Close order is not
the line the eye follows.
After: the same diagram with a layout annotation
The same ten lines of Mermaid, with one comment appended. Every node, edge and
label is unchanged. The return edge now goes around the outside, the no
branch has its own column, and the main path runs straight down the left.
```mermaid
flowchart TD
A[Receive order] --> B{Stock available?}
B -->|yes| C[Reserve items]
B -->|no| D[Backorder]
C --> E{Payment ok?}
E -->|yes| F[Ship]
E -->|no| G[Notify customer]
G --> A
D --> G
F --> H[Close order]
%% rmk-layout v1 {"canvasHeight":780,"canvasWidth":600,"nodes":{"A":{"x":200,"y":20,"width":160,"height":70},"B":{"x":170,"y":140,"width":220,"height":90},"C":{"x":60,"y":290,"width":160,"height":70},"D":{"x":340,"y":290,"width":160,"height":70},"E":{"x":30,"y":410,"width":220,"height":90},"F":{"x":60,"y":560,"width":160,"height":70},"G":{"x":340,"y":560,"width":160,"height":70},"H":{"x":60,"y":680,"width":160,"height":70}},"edges":{"B->C":{"x":164,"y":185,"width":-24,"height":99,"waypoints":[{"x":140,"y":185}],"start":{"fixedPoint":[0,0.5]},"end":{"fixedPoint":[0.5,0]}},"B->D":{"x":396,"y":185,"width":24,"height":99,"waypoints":[{"x":420,"y":185}],"start":{"fixedPoint":[1,0.5]},"end":{"fixedPoint":[0.5,0]}},"E->G":{"x":256,"y":455,"width":78,"height":140,"waypoints":[{"x":290,"y":455},{"x":290,"y":595}],"start":{"fixedPoint":[1,0.5]},"end":{"fixedPoint":[0,0.5]}},"G->A":{"x":506,"y":595,"width":-140,"height":-540,"waypoints":[{"x":560,"y":595},{"x":560,"y":55}],"start":{"fixedPoint":[1,0.5]},"end":{"fixedPoint":[1,0.5]}}}}
```
That last line is what the editor writes when you drag. It holds the canvas size, a box per node and a route per edge, keyed by the Mermaid ids already in the text. It never repeats what the syntax says: the nodes, the edges, the labels and the colours stay in the Mermaid lines, and only the geometry goes in the comment.
How to fix a diagram in four steps
- Copy the
mermaidcode block from the chat, without the fence markers. - Open mermaid.reactmarkdownkit.com and paste it into the code pane on the left. The canvas on the right re-parses as you type.
- Drag boxes on the canvas. Drag a connector's line to add a bend, or select it and toggle elbow routing. The code pane updates after each change, so what you see there is what you will copy.
- Copy the code pane, or press Copy as Mermaid on the canvas toolbar.
Both give the original flowchart plus one
%% rmk-layout v1line. Paste it into your README, wiki page or Markdown file. To publish without the layout line, delete the last line.
Nothing is uploaded. The page runs in the browser with no account, and the editor behind it is the MIT licensed @react-markdown-kit/mermaid package.
Why the layout survives
%% starts a comment in Mermaid (flowchart syntax, comments).
Mermaid.js and the hosts that render mermaid fences with it, such as GitHub,
skip the line, so the annotated diagram renders there exactly as the
unannotated one does (each host's own documentation is listed in
where the output works).
The plugin reads the line back and reproduces the drawing.
The annotation is a versioned format with a written specification,
LAYOUT_ANNOTATION.md,
shipped inside the package. Three properties matter here:
- One line, placed last. The line grammar is
%% rmk-layout v1 {…}with a single JSON object. A fence carries at most one. - Lossless. For any drawing, writing the annotation and reading it back
gives the same drawing, and writing again gives the same bytes.
layout-annotation.test.tsandmermaid-parse.test.tscover both guarantees. - Fails closed. A damaged annotation is rejected as a whole, the flowchart
is auto-laid out, and the compile result carries a
DIAGRAM_LAYOUT_INVALIDwarning with the path of the first problem. A broken comment can never make the diagram unreadable.
Round-tripping through the model
Because the layout is text, it goes wherever the text goes. Paste the annotated block back into the chat and ask for a change. A model that edits the flowchart lines and leaves the comment alone hands you back a diagram with its positions intact. Entries are keyed by node id, so a node the model removes leaves a stale key that is ignored, not an error, and a node it adds has no entry and is placed automatically until you drag it once.
Two habits make this reliable:
- Ask the model to keep the
%% rmk-layoutline unchanged. It is one sentence in the prompt. - If the model rewrites node ids, drag once more. The flowchart still renders; only the moved boxes fall back to automatic layout.
The same holds for a Markdown file in a repository. The diff of a layout fix is one changed line at the end of the block, and the writer emits a canonical form (fixed member order, numbers to two decimals), so a later fix diffs only what moved.
When the model emits a sequence or class diagram
This editor does not open them. sequenceDiagram, classDiagram, gantt,
pie and the other Mermaid diagram types stay ordinary code blocks in the
plugin: rendered as source, edited as text, never mistaken for something the
canvas can open. The parser is covered by
mermaid-parse.test.ts,
and the exact flowchart subset is listed in the
plugin reference.
For those diagram types, paste the output into
mermaid.live, the Mermaid project's own editor. It
renders every diagram type with Mermaid.js and shows syntax errors as you
type. It does not offer drag and drop, so layout fixes there are edits to the
text: reorder the statements, or add direction and subgraph lines.
If the model gave you a flowchart drawn as a sequence diagram (a linear list
of steps with no decisions), ask it for a flowchart TD of the same steps and
open that here.
Handing the fixed diagram to a teammate
Press Copy link in the code pane's head. The whole diagram, layout line
included, is compressed into the URL hash in the #pako: form mermaid.live
uses, so the link needs no server and nothing is stored anywhere. Opening the
link restores the drawing on the canvas, ready to drag again.
Share opens a panel with the same link, a badge for a README and an
<iframe> snippet that embeds the editor with the diagram loaded:
[](https://mermaid.reactmarkdownkit.com/#pako:<payload>)
The hash format and its fallback are tested in
tests/mermaid-share.test.ts:
pako: carries zlib-deflated UTF-8 as base64url, base64: carries the plain
text when a browser lacks the streams API, and a bad payload reads as nothing
rather than throwing.
Rendering the result in React
The same package renders the fence in a React app as static SVG, with no
Mermaid.js runtime, no script, no event attribute, no foreignObject and no
external reference
(extension.test.tsx
asserts it). The layout line is honoured, so what you fixed is what your users
see.
import Markdown, { defineMarkdownPreset } from '@react-markdown-kit/renderer'
import { mermaid } from '@react-markdown-kit/mermaid'
const preset = defineMarkdownPreset({ extensions: [mermaid()] })
<Markdown preset={preset}>{content}</Markdown>
FAQ
- Why does my AI-generated Mermaid diagram look wrong?
- Mermaid syntax has no positions. Every renderer lays the flowchart out by itself, so a return edge or a dense branch lands wherever the algorithm puts it. The text is usually right; the layout is what needs fixing.
- Can I move nodes in a Mermaid flowchart?
- Not in Mermaid syntax alone. In the visual editor at mermaid.reactmarkdownkit.com you drag boxes and connectors, and the positions are written into one %% rmk-layout v1 comment on the last line. Other Mermaid renderers ignore the comment and lay the flowchart out as before.
- Will the fixed layout survive a round trip through the model?
- The layout is one comment line inside the code block, so it travels with the text. Ask the model to keep the %% rmk-layout line when it edits the diagram. If the line is dropped or damaged, the flowchart still renders with automatic layout.
Next
Open the Mermaid visual editor · @react-markdown-kit/mermaid on npm · Mermaid Live Editor alternative · Mermaid in React Markdown · Flowchart to Mermaid · Plugin reference