zombie-mermaid
v5.14.2
Published
Render Mermaid diagrams as beautiful SVGs or ASCII art. Ultra-fast, fully themeable, zero DOM dependencies. Maintained fork of beautiful-mermaid.
Maintainers
Readme
Render Mermaid diagrams as beautiful SVGs or ASCII art
Ultra-fast, fully themeable, zero DOM dependencies. A maintained fork of beautiful-mermaid that refuses to die.
Why This Fork Exists
beautiful-mermaid is a genuinely good library — fast, beautiful, and works everywhere from rich UIs to plain terminals. Checkable facts, as of 2026-10-13: the last push to upstream's main was 2026-05-06 and its latest release is v1.1.2 (2026-02-26); it has 43 open pull requests (19 opened before 2026-04-13) and 50 open issues (live counts at those links; the figures above are a dated snapshot). I maintain zombie-mermaid as the fork that won't stay buried: pulling in upstream fixes, giving PRs stuck in the upstream queue a home, and actually shipping releases. Craft and Craft Agents aren't part of this project's process going forward; this is an independently maintained continuation.
This isn't just a claim — see what this fork fixes for an evidence-based before/after showcase (59 fixes): every bug listed there is rendered by the actual pre-fix and post-fix code, not described from memory.
It's still MIT-licensed, still built on the same foundation, and still credits the original authors — including the ASCII rendering engine's origins — in Attribution below. Who maintains it, how releases are published, and what is claimed: provenance and continuity.
Migrating from beautiful-mermaid
Swap the package (npm uninstall beautiful-mermaid && npm install zombie-mermaid, Node.js 24+) and change the import path; renderMermaidSVG, renderMermaidSVGAsync, renderMermaidASCII and parseMermaid keep the same signatures. In browsers and bundlers, also register elkjs once (Node, Bun, the CLI and MCP do it for you):
import ELK from 'elkjs/lib/elk.bundled.js'
import { registerElk, renderMermaidSVG } from 'zombie-mermaid'
registerElk(ELK) // once, before the first renderSome fixes change existing output, so diff your stored diagrams first: see the migration guide and the elkjs guide.
The Problem With Default Mermaid Rendering
Diagrams are essential for AI-assisted programming. When you're working with an AI coding assistant, being able to visualize data flows, state machines, and system architecture—directly in your terminal or chat interface—makes complex concepts instantly graspable.
Mermaid is the de facto standard for text-based diagrams. It's brilliant. But the default renderer has problems:
- Aesthetics — Might be personal preference, but wished they looked more professional
- Complex theming — Customizing colors requires wrestling with CSS classes
- No terminal output — Can't render to ASCII for CLI tools
- Heavy dependencies — Pulls in a lot of code for simple diagrams
Bundle Size
The two size badges above track the gzipped size of each renderer, and update automatically with every release:
- ascii-renderer — the ASCII/Unicode renderer plus
@zombie-mermaid/coreand@zombie-mermaid/mermaid-parser. It has no third-party dependencies, so this is whatzombie-mermaid/asciicosts. - svg-renderer (incl. deps) — the SVG renderer, core and parser, plus its
third-party dependencies, reported two ways: the base figure, and the figure
with ELK.js (the layout engine) registered.
ELK.js is an optional peer: about 466 KB gzipped on its own, one pre-bundled
file that can't be tree-shaken, and only shipped if your app registers it
(see the migration guide).
entitiesis counted tree-shaken, since the renderer uses one function from it.
Both figures gzip a plain concatenation of the built files, so they approximate
what you'd ship, not what any particular bundler emits. The umbrella
zombie-mermaid entry re-exports both renderers; its all-in total is
, the worst case. With a
bundler, importing only
renderMermaidASCII from the root drops the SVG
renderer (every package here is "sideEffects": false), and the root entry no
longer includes ELK.js unless you register it. Without a bundler — Node, a CLI, a
serverless function — you can import from zombie-mermaid/ascii to skip loading
the SVG renderer at all (see ASCII Output).
Features
- 9 diagram types — Flowcharts (including State), Sequence, Class, ER, XY Charts (bar, line, combined), Architecture, C4, Pie, and Quadrant charts
- Dual output — SVG for rich UIs, ASCII/Unicode for terminals
- Synchronous rendering — No async, no flash. Works with React
useMemo() - 15 built-in themes — And dead simple to add your own
- Full Shiki compatibility — Use any VS Code theme directly
- Live theme switching — CSS custom properties, no re-render needed
- Mono mode — Beautiful diagrams from just 2 colors
- Zero DOM dependencies — Pure TypeScript, works everywhere
- Ultra-fast — Renders 100+ diagrams in under 500ms
- Accessible SVG output, CI-enforced — every diagram type always gets a
role-correct, nameable root<svg>; see the accessibility conformance statement for exactly what's guaranteed
Installation
Requires Node.js 24 or newer (engines in package.json).
npm install zombie-mermaid
# or
bun add zombie-mermaid
# or
pnpm add zombie-mermaidNot sure this is the right package? See Which package do I install?.
Upgrading from 4.x? Node.js 24 or newer is now required.
elkjsis now an optional peer dependency: browser and bundler apps must callregisterElk(ELK)once (see the migration guide). The package no longer shipssrc/(see #1538).
elkjsin the umbrella package: the sub-packages (@zombie-mermaid/svg-renderer) treatelkjsas an optional peer, butzombie-mermaiditself lists it as a regular dependency so the CLI and MCP server work out of the box. See what happens if you remove it.
Only need one output format? @zombie-mermaid/ascii-renderer and @zombie-mermaid/svg-renderer are published standalone — see Packages below.
Quick Start
SVG Output
import { renderMermaidSVG } from 'zombie-mermaid'
const svg = renderMermaidSVG(`
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Action]
B -->|No| D[End]
`)Rendering is fully synchronous — no await, no promises. The ELK.js layout engine runs synchronously via a FakeWorker bypass, so you get your SVG string instantly.
Flowchart, state, class, ER and architecture diagrams are laid out by
elkjs, an optional peer dependency.
Under Node and Bun it is loaded automatically. In a browser or bundler, register
it once (npm install elkjs):
import ELK from 'elkjs/lib/elk.bundled.js'
import { registerElk } from 'zombie-mermaid'
registerElk(ELK)Architecture diagrams (architecture-beta, see Supported Diagrams) are laid out by elkjs too.
Sequence, pie, quadrant, xychart and C4 diagrams, and all ASCII output, need no elkjs
and no registration. Rendering a graph diagram with no elkjs available throws an
ElkNotRegisteredError that says how to fix it.
Flowcharts without elkjs. Pass layout: 'simple' to lay a flowchart out with a
small built-in layered layout instead of ELK. It needs no elkjs, adds about 3.5 KB
gzipped, and is opt-in: the default output never changes. It is a rougher match for
ELK on edge routing, and a subgraph's own direction is ignored. State, class, ER
and architecture diagrams still need elkjs. See
the decision record for the measured quality
gap.
const svg = renderMermaidSVG('graph TD\n A --> B', { layout: 'simple' }) // no registerElk()Need async? Use renderMermaidSVGAsync() — same output, returns a Promise<string>.
ASCII Output
import { renderMermaidASCII } from 'zombie-mermaid'
const ascii = renderMermaidASCII(`graph LR; A --> B --> C`)┌───┐ ┌───┐ ┌───┐
│ │ │ │ │ │
│ A │────►│ B │────►│ C │
│ │ │ │ │ │
└───┘ └───┘ └───┘ASCII-only consumers (a CLI, a terminal UI, a serverless function) can import
from zombie-mermaid/ascii instead of the package root. The root entry also
loads the SVG renderer (about 74 KB gzipped, plus elkjs only if you register
it); the /ascii subpath never touches either:
import { renderMermaidASCII } from 'zombie-mermaid/ascii'Using this from React? See React Integration for a zero-flash useMemo() pattern.
CLI
Installing the package also exposes a zombie-mermaid binary. To run just the CLI, without the library's other entry points, use npx @zombie-mermaid/cli render diagram.mmd --ascii (same CLI, published as @zombie-mermaid/cli):
zombie-mermaid render diagram.mmd --ascii # Print ASCII/Unicode to terminal
zombie-mermaid render diagram.mmd --svg # Render to diagram.svg (name from the input)
zombie-mermaid render diagram.mmd --svg -o out.svg # Render to a named SVG file
zombie-mermaid render diagram.mmd --svg -o out.svg --resolve-colors # …with concrete colors, for resvg/Inkscape/etc.
zombie-mermaid render diagram.mmd -o out.svg # Same — the format is inferred from .svg
zombie-mermaid render diagram.mmd --svg -o - | pbcopy # Write the SVG to stdout
zombie-mermaid render diagram.mmd --ascii -o out.txt # Write the ASCII rendering to a file
zombie-mermaid render diagram.mmd --html # Self-contained pan/zoom HTML viewer
zombie-mermaid render diagram.mmd --png # Rasterize to diagram.png
cat diagram.mmd | zombie-mermaid render --ascii # Read from stdin
zombie-mermaid --check README.md docs/*.md # Validate every mermaid block in Markdown; exit 1 with file:line diagnostics
zombie-mermaid themes # List built-in theme names
zombie-mermaid --help # Show all options--theme <name> applies a built-in theme (from themes) to either output mode. --resolve-colors replaces the CSS var()/color-mix() theming in SVG output with computed colors so rasterizers that don't evaluate CSS (resvg, librsvg, Inkscape) render the theme instead of black — see docs/theming.md.
--direction <dir> (TD, TB, BT, LR, or RL) overrides the diagram's layout direction in either output mode without editing the source — flowchart, state, and ER diagrams; a nested subgraph's own direction still applies on top of it. The same override is available to library callers as the direction render option (see API Reference).
--hyperlinks (with --ascii) turns click hrefs into OSC 8 terminal
hyperlinks — off by default, since terminal and pager support varies (see
ASCII terminal hyperlinks).
--profile markdown (with --ascii) emits plain ASCII characters with no color, for pasting into issues, commits and fenced blocks (the profile option in the library and the MCP render_mermaid_ascii tool).
--layout mermaid (with --ascii, opt-in) draws a flowchart from mermaid's own ELK layout instead of the grid renderer; the library equivalent is renderMermaidASCIIWithLayout from zombie-mermaid/ascii-layout. It needs the optional peer elkjs-0.9.3 (pnpm add elkjs-0.9.3@npm:[email protected]), which is loaded only when the flag is used. Diagrams with subgraphs or unmodelled shapes, non-flowchart diagrams, layout failures, and drawings that cannot fit 120 columns (--layout mermaid-wide / maxCols: Infinity keeps the wide text) fall back to the default renderer, and stderr (or the result's fallbackReason) says which one ran. Merged parallel edges hide edge multiplicity; results depend on mermaid 12.1.0 and elkjs 0.9.3. Not available in the MCP tool. See known differences.
Output rules. -o is the destination for the run's file output — SVG, HTML, or PNG when --svg/--html/--png is given, otherwise the ASCII rendering — and -o - sends it to stdout instead. A recognised extension (.svg, .html/.htm, .txt, .png) picks the format on its own, so the flag can be dropped; an extension that contradicts an explicit flag (--svg -o out.txt) is an error, while unrecognised ones are simply used as given. --svg/--html/--png with no -o writes <input stem>.svg/.html/.png beside the input (stdin input has no name to derive from, so it must pass -o). Only one of --svg/--html/--png can be set at a time — run the command twice for more than one. ASCII always prints to the terminal when one of them is also requested (--ascii --svg -o out.svg), and never carries ANSI colour codes when written to a file. An existing output file is never overwritten unless you pass --force/-f.
--html wraps the rendered SVG in a self-contained pan/zoom viewer — one file, no server, no network — with drag/scroll pan, ctrl/cmd+scroll and pinch to zoom, fit/1:1 buttons, a light/dark toggle that follows prefers-color-scheme, and keyboard controls. It opens straight from disk (including over file://, no server needed) and survives being emailed as a single attachment — see Using the self-contained HTML viewer for the full controls reference. This is the one place in the project that ships client-side JavaScript, and deliberately so — see docs/decisions/no-script-interactivity.md: the library's own SVG output stays permanently script-free, and this viewer is a separate CLI artifact wrapping that output, never part of it.
--png rasterizes the diagram for anywhere SVG isn't accepted — issue trackers, Slack, docs tools, email — at the SVG's own pixel dimensions (1:1, no scaling). It always resolves CSS colors first, automatically, the same substitution --resolve-colors does for --svg — a rasterizer can't evaluate var()/color-mix(), so skipping this would render the whole theme black. Rasterization is via @resvg/resvg-js, listed as an optionalDependency: a normal install pulls its native binary like any other dependency, but a platform it has no prebuilt binary for, or an install run with --no-optional, simply skips it — --png then fails with a clear error telling you how to install it explicitly, rather than breaking the rest of the CLI.
MCP Server
🧪 Experimental — shipped to gauge interest, not a finished or best-effort implementation. This is a first cut covering the common case; the tool surface may change based on feedback. Try it and open an issue with what you'd want from it.
zombie-mermaid mcp starts a Model Context Protocol server on stdio, exposing the library's rendering as seven tools: render_mermaid_svg, render_mermaid_ascii, validate_mermaid, check_mermaid_sequence_activations, fix_mermaid_sequence_activations, list_themes, and list_diagram_types. render_mermaid_svg also takes optional bg/fg hex color overrides (applied on top of theme) and an optional outputPath that writes the SVG to disk and returns { saved, size } instead of the SVG text. outputPath must end in .svg and resolve inside the server's working directory (the directory your MCP client launched it from); its parent directory must already exist, symlinks and non-regular files are refused, and an existing .svg file at that path is overwritten. Per-tool arguments and return shapes are in the MCP tool reference. Point an MCP client (Claude Desktop, Claude Code, or anything else that speaks MCP) at it to render Mermaid diagrams directly in a conversation, without shelling out to the CLI or importing the library.
Example Claude Desktop / Claude Code MCP server config:
{
"mcpServers": {
"zombie-mermaid": {
"command": "npx",
"args": ["-y", "zombie-mermaid", "mcp"]
}
}
}The five diagram tools (including validate_mermaid, parse-only) accept a diagram string (list_themes and list_diagram_types take no arguments). The two render tools also take a handful of rendering options (theme, transparent, font for SVG; useAscii, paddingX/paddingY/boxBorderPadding for ASCII) — see each tool's inputSchema for the full, current list. Invalid Mermaid syntax comes back as a normal tool error (isError: true) rather than crashing the connection; validate_mermaid is the exception and reports it as a normal { valid: false, diagnostics } result.
check_mermaid_sequence_activations is a mechanical, deterministic check — no LLM judgment involved — for a specific gap in existing Mermaid validators: every activate X (or + arrow shorthand) in a sequenceDiagram must be closed by a matching deactivate X (- shorthand) before the diagram ends. It returns a JSON report ({ ok, issues }) rather than rendering anything, and errors (isError: true) if given a non-sequence diagram.
fix_mermaid_sequence_activations runs the same check and, where mechanically safe, returns a corrected diagram: a dangling activate X with no matching deactivate X gets one appended automatically. An unmatched deactivate X (nothing open) is reported but not auto-fixed — deciding whether to delete that statement or insert a preceding activate X needs source-position context this tool doesn't have, so it's left for a human (or a future LLM-based layer) to resolve. Returns { ok, fixedDiagram, fixesApplied, remainingIssues }.
To embed the server in your own process instead of running it as a subcommand, import zombie-mermaid/mcp and connect it to any MCP Transport yourself:
import { createMcpServer } from 'zombie-mermaid/mcp'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
const server = createMcpServer()
await server.connect(new StdioServerTransport())Agent Skill
skills/zombie-mermaid/SKILL.md packages the
CLI and MCP server above as an Agent Skill, for agents that
discover capabilities that way:
npx skills add dfadler/zombie-mermaidIt is a thin wrapper — instructions and example invocations only. No renderer is vendored into it, so there is no second copy of the pipeline to keep in sync with the package.
Packages
This repo is a pnpm-workspace monorepo. Most consumers only need the umbrella zombie-mermaid package above; internally it's built from workspace packages under packages/, all published under the @zombie-mermaid npm scope and version-locked with it:
@zombie-mermaid/ascii-renderer— the ASCII/Unicode renderer, published standalone for anyone who wants terminal output withoutsvg-rendererorelkjs. The exact codezombie-mermaid/asciire-exports.@zombie-mermaid/svg-renderer— the ELK.js-backed SVG layout and rendering engine, also published standalone.@zombie-mermaid/core,@zombie-mermaid/mermaid-parser,@zombie-mermaid/mcp— shared types/theming, the diagram parsers, and the MCP server implementation, respectively. Published under the scope (so the names can't be squatted) and version-locked with the rest, but internal-only: no standalone support commitment beyond backing the umbrella and the two renderer packages above.
See docs/decisions/monorepo-conversion.md for the full package-split and publish-strategy history.
Docs
- Guides — task-oriented walkthroughs: browsing the samples, choosing a theme, using the HTML viewer, upgrading from 2.x to 5.x
- Accessibility — conformance statement: what's guaranteed (and CI-enforced), what's implemented but unverified by automation, and what isn't covered
- Theming — the two-color foundation, enriched mode, built-in themes, custom themes, Shiki compatibility
- Supported Diagrams — syntax for every diagram type, XY chart styling, and ASCII rendering options
- React Integration — zero-flash rendering with
useMemo() - API Reference — full function and options reference
- Versioning and deprecation policy — what counts as a breaking change, and how old majors are supported and deprecated
- Migrating from
beautiful-mermaid— what's drop-in, which fixes change rendered output, and how to audit your own diagrams before upgrading
More design write-ups and reference material live in docs/.
Attribution
The ASCII rendering engine is based on mermaid-ascii by Alexander Grooff, ported from Go to TypeScript and extended with:
- Sequence diagram support
- Class diagram support
- ER diagram support
- Unicode box-drawing characters
- Configurable spacing and padding
Thank you Alexander for the excellent foundation!
Contributing
See CONTRIBUTING.md for local setup, the test/lint workflow, and how changesets and releases work (RELEASING.md). Security issues should go through SECURITY.md instead of a public issue. Released versions are tracked in CHANGELOG.md.
License
MIT — see LICENSE for details.
