beautiful-mermaid README

The project's README from github.com/lukilabs/beautiful-mermaid. As one markdown file: README.md.

beautiful-mermaid

Render Mermaid diagrams as beautiful SVGs or ASCII art

Ultra-fast, fully themeable, zero DOM dependencies. Built for the AI era.

beautiful-mermaid sequence diagram example

npm version License

Live Demo & Samples

→ Use it live in Craft Agents


Why We Built This

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:

We built beautiful-mermaid at Craft to power diagrams in Craft Agents. It's fast, beautiful, and works everywhere—from rich UIs to plain terminals.

The ASCII rendering engine is based on mermaid-ascii by Alexander Grooff. We ported it from Go to TypeScript and extended it. Thank you Alexander for the excellent foundation! (And inspiration that this was possible.)

Features

Installation

npm install beautiful-mermaid
# or
bun add beautiful-mermaid
# or
pnpm add beautiful-mermaid

Quick Start

SVG Output

import { renderMermaidSVG } from 'beautiful-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.

Need async? Use renderMermaidSVGAsync() — same output, returns a Promise<string>.

ASCII Output

import { renderMermaidASCII } from 'beautiful-mermaid'

const ascii = renderMermaidASCII(`graph LR; A --> B --> C`)
┌───┐     ┌───┐     ┌───┐
│   │     │   │     │   │
│ A │────►│ B │────►│ C │
│   │     │   │     │   │
└───┘     └───┘     └───┘

React Integration

Because rendering is synchronous, you can use useMemo() for zero-flash diagram rendering:

import { renderMermaidSVG } from 'beautiful-mermaid'

function MermaidDiagram({ code }: { code: string }) {
  const { svg, error } = React.useMemo(() => {
    try {
      return {
        svg: renderMermaidSVG(code, {
          bg: 'var(--background)',
          fg: 'var(--foreground)',
          transparent: true,
        }),
        error: null,
      }
    } catch (err) {
      return { svg: null, error: err instanceof Error ? err : new Error(String(err)) }
    }
  }, [code])

  if (error) return <pre>{error.message}</pre>
  return <div dangerouslySetInnerHTML={{ __html: svg! }} />
}

Why this works well:


Theming

The theming system is the heart of beautiful-mermaid. It's designed to be both powerful and dead simple.

The Two-Color Foundation

Every diagram needs just two colors: background (bg) and foreground (fg). That's it. From these two colors, the entire diagram is derived using color-mix():

const svg = renderMermaidSVG(diagram, {
  bg: '#1a1b26',  // Background
  fg: '#a9b1d6',  // Foreground
})

This is Mono Mode—a coherent, beautiful diagram from just two colors. The system automatically derives:

Element Derivation
Text --fg at 100%
Secondary text --fg at 60% into --bg
Edge labels --fg at 40% into --bg
Faint text --fg at 25% into --bg
Connectors --fg at 50% into --bg
Arrow heads --fg at 85% into --bg
Node fill --fg at 3% into --bg
Group header --fg at 5% into --bg
Inner strokes --fg at 12% into --bg
Node stroke --fg at 20% into --bg

Enriched Mode

For richer themes, you can provide optional "enrichment" colors that override specific derivations:

const svg = renderMermaidSVG(diagram, {
  bg: '#1a1b26',
  fg: '#a9b1d6',
  // Optional enrichment:
  line: '#3d59a1',    // Edge/connector color
  accent: '#7aa2f7',  // Arrow heads, highlights
  muted: '#565f89',   // Secondary text, labels
  surface: '#292e42', // Node fill tint
  border: '#3d59a1',  // Node stroke
})

If an enrichment color isn't provided, it falls back to the color-mix() derivation. This means you can provide just the colors you care about.

CSS Custom Properties = Live Switching

All colors are CSS custom properties on the <svg> element. This means you can switch themes instantly without re-rendering:

// Switch theme by updating CSS variables
svg.style.setProperty('--bg', '#282a36')
svg.style.setProperty('--fg', '#f8f8f2')
// The entire diagram updates immediately

For React apps, pass CSS variable references instead of hex values:

const svg = renderMermaidSVG(diagram, {
  bg: 'var(--background)',
  fg: 'var(--foreground)',
  accent: 'var(--accent)',
  transparent: true,
})
// Theme switches apply automatically via CSS cascade — no re-render needed

Built-in Themes

15 carefully curated themes ship out of the box:

Theme Type Background Accent
zinc-light Light #FFFFFF Derived
zinc-dark Dark #18181B Derived
tokyo-night Dark #1a1b26 #7aa2f7
tokyo-night-storm Dark #24283b #7aa2f7
tokyo-night-light Light #d5d6db #34548a
catppuccin-mocha Dark #1e1e2e #cba6f7
catppuccin-latte Light #eff1f5 #8839ef
nord Dark #2e3440 #88c0d0
nord-light Light #eceff4 #5e81ac
dracula Dark #282a36 #bd93f9
github-light Light #ffffff #0969da
github-dark Dark #0d1117 #4493f8
solarized-light Light #fdf6e3 #268bd2
solarized-dark Dark #002b36 #268bd2
one-dark Dark #282c34 #c678dd
import { renderMermaidSVG, THEMES } from 'beautiful-mermaid'

const svg = renderMermaidSVG(diagram, THEMES['tokyo-night'])

Adding Your Own Theme

Creating a theme is trivial. At minimum, just provide bg and fg:

const myTheme = {
  bg: '#0f0f0f',
  fg: '#e0e0e0',
}

const svg = renderMermaidSVG(diagram, myTheme)

Want richer colors? Add any of the optional enrichments:

const myRichTheme = {
  bg: '#0f0f0f',
  fg: '#e0e0e0',
  accent: '#ff6b6b',  // Pop of color for arrows
  muted: '#666666',   // Subdued labels
}

Full Shiki Compatibility

Use any VS Code theme directly via Shiki integration. This gives you access to hundreds of community themes:

import { getSingletonHighlighter } from 'shiki'
import { renderMermaidSVG, fromShikiTheme } from 'beautiful-mermaid'

// Load any theme from Shiki's registry
const highlighter = await getSingletonHighlighter({
  themes: ['vitesse-dark', 'rose-pine', 'material-theme-darker']
})

// Extract diagram colors from the theme
const colors = fromShikiTheme(highlighter.getTheme('vitesse-dark'))

const svg = renderMermaidSVG(diagram, colors)

The fromShikiTheme() function intelligently maps VS Code editor colors to diagram roles:

Editor Color Diagram Role
editor.background bg
editor.foreground fg
editorLineNumber.foreground line
focusBorder / keyword token accent
comment token muted
editor.selectionBackground surface
editorWidget.border border

Supported Diagrams

Flowcharts

graph TD
  A[Start] --> B{Decision}
  B -->|Yes| C[Process]
  B -->|No| D[End]
  C --> D

All directions supported: TD (top-down), LR (left-right), BT (bottom-top), RL (right-left).

State Diagrams

stateDiagram-v2
  [*] --> Idle
  Idle --> Processing: start
  Processing --> Complete: done
  Complete --> [*]

Sequence Diagrams

sequenceDiagram
  Alice->>Bob: Hello Bob!
  Bob-->>Alice: Hi Alice!
  Alice->>Bob: How are you?
  Bob-->>Alice: Great, thanks!

Class Diagrams

classDiagram
  Animal <|-- Duck
  Animal <|-- Fish
  Animal: +int age
  Animal: +String gender
  Animal: +isMammal() bool
  Duck: +String beakColor
  Duck: +swim()
  Duck: +quack()

ER Diagrams

erDiagram
  CUSTOMER ||--o{ ORDER : places
  ORDER ||--|{ LINE_ITEM : contains
  PRODUCT ||--o{ LINE_ITEM : "is in"

Inline Edge Styling

Use linkStyle to override edge colors and stroke widths — just like Mermaid's linkStyle:

graph TD
  A --> B --> C
  linkStyle 0 stroke:#ff0000,stroke-width:2px
  linkStyle default stroke:#888888
Syntax Effect
linkStyle 0 stroke:#f00 Style a single edge by index (0-based)
linkStyle 0,2 stroke:#f00 Style multiple edges at once
linkStyle default stroke:#888 Default style applied to all edges

Index-specific styles override the default. Supported properties: stroke, stroke-width.

Works in both flowcharts and state diagrams.

XY Charts

Bar charts, line charts, and combinations — using Mermaid's xychart-beta syntax.

Bar chart:

xychart-beta
    title "Monthly Revenue"
    x-axis [Jan, Feb, Mar, Apr, May, Jun]
    y-axis "Revenue ($K)" 0 --> 500
    bar [180, 250, 310, 280, 350, 420]

Line chart:

xychart-beta
    title "User Growth"
    x-axis [Jan, Feb, Mar, Apr, May, Jun]
    line [1200, 1800, 2500, 3100, 3800, 4500]

Combined bar + line:

xychart-beta
    title "Sales with Trend"
    x-axis [Jan, Feb, Mar, Apr, May, Jun]
    bar [300, 380, 280, 450, 350, 520]
    line [300, 330, 320, 353, 352, 395]

Horizontal orientation:

xychart-beta horizontal
    title "Language Popularity"
    x-axis [Python, JavaScript, Java, Go, Rust]
    bar [30, 25, 20, 12, 8]

Axis configuration:

Multi-series: Add multiple bar and/or line declarations. Each series gets a distinct color from a monochromatic palette derived from the theme's accent color.

XY Chart Styling

The chart renderer follows a clean, minimal design philosophy inspired by Apple and Craft:


ASCII Output

For terminal environments, CLI tools, or anywhere you need plain text, render to ASCII or Unicode box-drawing characters:

import { renderMermaidASCII } from 'beautiful-mermaid'

// Unicode mode (default) — prettier box drawing
const unicode = renderMermaidASCII(`graph LR; A --> B`)

// Pure ASCII mode — maximum compatibility
const ascii = renderMermaidASCII(`graph LR; A --> B`, { useAscii: true })

Unicode output:

┌───┐     ┌───┐
│   │     │   │
│ A │────►│ B │
│   │     │   │
└───┘     └───┘

ASCII output:

+---+     +---+
|   |     |   |
| A |---->| B |
|   |     |   |
+---+     +---+

ASCII Options

renderMermaidASCII(diagram, {
  useAscii: false,      // true = ASCII, false = Unicode (default)
  paddingX: 5,          // Horizontal spacing between nodes
  paddingY: 5,          // Vertical spacing between nodes
  boxBorderPadding: 1,  // Padding inside node boxes
  colorMode: 'auto',    // 'none' | 'auto' | 'ansi16' | 'ansi256' | 'truecolor' | 'html'
  theme: { ... },       // Partial<AsciiTheme> — override default colors
})

ASCII XY Charts

XY charts render to ASCII with dedicated chart-drawing characters:


API Reference

renderMermaidSVG(text, options?): string

Render a Mermaid diagram to SVG. Synchronous. Auto-detects diagram type.

Parameters:

RenderOptions:

Option Type Default Description
bg string #FFFFFF Background color (or CSS variable)
fg string #27272A Foreground color (or CSS variable)
line string? — Edge/connector color
accent string? — Arrow heads, highlights
muted string? — Secondary text, labels
surface string? — Node fill tint
border string? — Node stroke color
font string Inter Font family
transparent boolean false Render with transparent background
padding number 40 Canvas padding in px
nodeSpacing number 24 Horizontal spacing between sibling nodes
layerSpacing number 40 Vertical spacing between layers
componentSpacing number 24 Spacing between disconnected components
thoroughness number 3 Crossing minimization trials (1-7, higher = better but slower)
interactive boolean false Enable hover tooltips on XY chart bars and data points

XY Charts: Diagrams starting with xychart-beta are auto-detected — no separate function needed. The accent color option drives the chart series color palette.

renderMermaidSVGAsync(text, options?): Promise<string>

Async version of renderMermaidSVG(). Same output, returns a Promise<string>. Useful in async server handlers or data loaders.

renderMermaidASCII(text, options?): string

Render a Mermaid diagram to ASCII/Unicode text. Synchronous.

AsciiRenderOptions:

Option Type Default Description
useAscii boolean false Use ASCII instead of Unicode
paddingX number 5 Horizontal node spacing
paddingY number 5 Vertical node spacing
boxBorderPadding number 1 Inner box padding
colorMode string 'auto' 'none', 'auto', 'ansi16', 'ansi256', 'truecolor', or 'html'
theme Partial<AsciiTheme> — Override default colors for ASCII output

parseMermaid(text): MermaidGraph

Parse Mermaid source into a structured graph object (for custom processing).

fromShikiTheme(theme): DiagramColors

Extract diagram colors from a Shiki theme object.

THEMES: Record<string, DiagramColors>

Object containing all 15 built-in themes.

DEFAULTS: { bg: string, fg: string }

Default colors (#FFFFFF / #27272A).


Attribution

The ASCII rendering engine is based on mermaid-ascii by Alexander Grooff. We ported it from Go to TypeScript and extended it with:

Thank you Alexander for the excellent foundation!


License

MIT — see LICENSE for details.


Built with care by the team at Craft

beautiful-mermaid (lukilabs/beautiful-mermaid)

Searching Database…

What is this?beautiful-mermaid is a TypeScript library that renders Mermaid diagrams as polished SVGs or ASCII/Unicode art, built so AI coding assistants and chat UIs can show flowcharts, state machines, and other diagrams inline.
Is this a standalone diagramming app or a library I import into my code?It is a pure TypeScript library with no DOM dependencies, meant to be imported into your own app, server, or CLI tool rather than run on its own.
How do I render a diagram with it?Call renderMermaidSVG(text, options) for an SVG string or renderMermaidASCII(text, options) for terminal output; both auto-detect the diagram type and run synchronously so no await is needed.
Does it drag in the full Mermaid.js stack or a browser environment?No — it only relies on elkjs for layout and entities for parsing, and has zero DOM dependencies, so it works in browsers, Node, and plain terminals alike.
Does it support every Mermaid diagram syntax?Only six diagram types are supported: flowcharts, state, sequence, class, ER diagrams, and XY charts (bar/line/combined). Other Mermaid diagram kinds aren't mentioned as supported.
Can I reuse my VS Code theme for diagrams?Yes — fromShikiTheme() reads any Shiki-compatible VS Code theme and maps its editor colors (background, foreground, selection, etc.) to diagram roles automatically.
Where did the ASCII rendering engine come from?It's based on mermaid-ascii by Alexander Grooff, ported from Go to TypeScript and extended with sequence, class, and ER diagram support plus Unicode box-drawing characters.
How fast is it, and does it block rendering?It's synchronous and can render over 100 diagrams in under 500ms, which lets it be used directly inside React's useMemo() without flashing.
Can I theme a diagram with only two colors?Yes — Mono Mode derives an entire coherent palette (text, strokes, arrows, fills) from just a background and foreground color using CSS color-mix(), and you can add optional 'enrichment' colors for more control.
Creator
lukilabs
Size
1.9 MB
Stars
11.2K
Age
8mo
Commits · 90 Days