Skip to main content

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.

A model-style flowchart with automatic layout
Markdown
```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]
```
Rendered
DiagramReceive orderStock available?Reserve itemsBackorderPayment ok?ShipNotify customerClose orderyesnoyesno

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.

The same flowchart after dragging, positions kept in the last line
Markdown
```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]}}}}
```
Rendered
DiagramReceive orderStockavailable?Reserve itemsBackorderPayment ok?ShipNotify customerClose orderyesnoyesno

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

  1. Copy the mermaid code block from the chat, without the fence markers.
  2. Open mermaid.reactmarkdownkit.com and paste it into the code pane on the left. The canvas on the right re-parses as you type.
  3. 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.
  4. Copy the code pane, or press Copy as Mermaid on the canvas toolbar. Both give the original flowchart plus one %% rmk-layout v1 line. 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.ts and mermaid-parse.test.ts cover 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_INVALID warning 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-layout line 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:

[![Open in visual editor](https://mermaid.reactmarkdownkit.com/badge.svg)](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>
Mermaid in React Markdown, without Mermaid.js

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