Mermaid text, on a canvas you can actually edit

Mermaid renders text to a picture. Grafloria reads that same text into a live diagram you can drag, connect, restyle and delete from — and writes it back out as a body any Mermaid renderer accepts. The text stays the document; the canvas stops being read-only.

live edit the Mermaid on the left — the diagram re-renders as you type loading…
rendering…

This is the real engine parsing real Mermaid in your browser — not a screenshot, not a pre-baked SVG. Try changing a shape to {Decision?}, adding -->|label|, or breaking the syntax on purpose.

Four diagram types, read and written

Mermaid has grown past 29 diagram types. Grafloria speaks four of them — the graph-family ones people actually paste into an editor — and every one is a matched parser + model + generator, because a type that parses but cannot re-emit itself loses everything on first save. The rest fail safe (below), which we consider far better than a plausible-looking wrong diagram.

read + write

flowchart / graph

The full base grammar plus Mermaid-native styling: all node shapes, glued and spaced edges, edge labels, subgraph → real groups, style, classDef, :::, click and direction.

read + write

erDiagram

Entities with typed attribute blocks, PK/FK/UK badges, all sixteen cardinality pairs mapped to crow's-foot markers, identifying vs non-identifying, labelled relationships — landing as interactive table cards, not boxes.

read + write

classDiagram

Classes, members in both spellings, visibility and classifiers, generics, annotations, multiplicity, notes — and all 72 legal relationship operators, derived from the grammar rather than a hand-written table.

read + write

stateDiagram / -v2

States, transitions, scoped [*] and [H] pseudo-states, composite states as nested groups, concurrent -- regions, fork / join / choice, and direction scoped to the composite that declares it.

fails safe

sequenceDiagram, gantt, pie, …

Every other type — journey, gitGraph, mindmap, timeline, C4, sankey, xychart and the rest — returns an explicit unsupported signal naming the type. Never a blank canvas, never a garbage graph. sequenceDiagram is the most-requested next.

It round-trips, and the round trip is the hard part

Reading Mermaid is the easy direction. The interesting one is what happens after somebody moves a node: positions are not expressible in Mermaid's grammar, so a naive exporter throws them away, and every save quietly re-scrambles the diagram.

The visible body always stays valid Mermaid

Grafloria writes a body GitHub, GitLab and mermaid.live all render — and parks everything the grammar cannot say in a %% comment those renderers ignore. So the same text is both a lossless Grafloria document and an ordinary Mermaid snippet. That rule is not a convention we try to remember; it is the constraint the three tiers below exist to enforce.

Tier 1

Mermaid's own extension points

Anything with a native analog uses it: fill and stroke become style / classDef, containers become subgraph, navigation becomes click. Visible, portable, renders everywhere.

Tier 2

%%grafloria: directives

Grafloria-only semantics with no Mermaid analog — edge animation, node status, routing hints — ride in comments, one line per entity. Mermaid skips them; the body still renders.

Tier 3

The document sidecar

A single %%grafloria:document line carries the exact model for a byte-lossless machine round trip, with a body hash so a hand-edit to the visible text wins over the stale sidecar.

// npm i @grafloria/engine
import { importDiagramText, exportDiagramText } from '@grafloria/engine';

// Mermaid in → a real DiagramModel you can render and edit.
const r = importDiagramText(`flowchart TD
  Start([Start]) --> Check{Valid?}
  Check -->|yes| Save[[Persist]]`);

if (r.unsupported) console.warn(`no parser for ${r.unsupported} yet`);
else render({ nodes: r.diagram.getNodes(), edges: r.diagram.getLinks() }, host);

// …and back out. lossless:false gives the plain body for a README;
// the default adds the sidecar so positions survive the trip.
const text = exportDiagramText(diagram, { lossless: false });

Verified against real Mermaid, in CI

A compatibility claim is worth exactly as much as the thing that checks it. Ours is an oracle gate: 28 cases driven through real mermaid v11 in both directions — every input we say we read, and every body we emit, parsed by Mermaid itself on each run. It has already caught an export bug no unit test would have (ER relationship labels colliding with cardinality keywords). Any new type or syntax has to arrive with oracle cases.

The demos are gates too: the Mermaid viewer and the lossless text form both run in CI with real pointer events and pixel-diffed goldens, so the pages on this site cannot rot without failing the build.

What it does not do yet

The gaps below are all lossy, never wrong — the diagram you get is the diagram you wrote, minus something named here. That property matters more to us than the length of the list, so here is the list.

erDiagram three known losses
  • ENTITY["display alias"] parses, but Mermaid 11 has no syntax to write it back — the alias rides the sidecar instead of the visible body.
  • ER style / classDef / ::: directives are ignored, not applied to the entity cards.
  • Relationships are table-level. Mermaid's ER grammar cannot say which column a relationship uses, so the kit's column-pinned edges have nothing to import from. That one is Mermaid's limit, not ours.
classDiagram grouping and two glyphs
  • namespace Foo { … } — the classes survive, the grouping does not. The largest remaining class gap.
  • Both-ends operators (<|--|>, *--o, …) keep their structure and re-export exactly, but draw with one marker: the notation table has no both-ends kind yet.
  • Lollipop ()-- parses and round-trips as a realization, but renders as the dashed triangle rather than the interface ball.
stateDiagram layout, not structure
  • Concurrent regions are modelled and re-exported correctly, but layout does not band them — no dashed divider yet. The structure is right; the picture is not.
  • [H] / [H*] round-trip, but draw as a plain circle instead of the H-in-circle glyph.
  • State classDef / class styling is not applied, and an inline :::hook is captured by name but not re-emitted.
all types layout and the directive channel
  • Imported layout is a naive grid for ER / class / state — no type-aware placement (ER by FK dependency, class by inheritance depth) yet.
  • The Tier-2 %%grafloria: per-entity channel is wired for flowchart only; the other three fall back to the Tier-3 sidecar, which is lossless but opaque.

Mermaid and Mermaid Chart are trademarks of their respective owners; Grafloria is an independent MIT project and implements the Mermaid syntax with its own parser — it does not bundle, fork, or depend on the Mermaid runtime. Coverage described here is current as of July 2026 and is tracked in the engine's gap analysis; corrections and requests are welcome via GitHub issues.