@wsl8297: Mermaid 画流程图、时序图确实省事,但默认渲染谈不上好看,更别说在终端里几乎没法用。 我在 GitHub 挖到一个新开源项目:beautiful-mermaid,专门把 Mermaid 的渲染这件事做漂亮、做实用——既能导出精致的 …
摘要
beautiful-mermaid 是一个纯 TypeScript 实现的开源工具,能将 Mermaid 图表渲染为精美的 SVG 或终端友好的 ASCII 字符画,支持 15 套主题和零 DOM 依赖,适合在 AI 辅助编程中使用。
查看缓存全文
缓存时间: 2026/05/16 15:20
Mermaid 画流程图、时序图确实省事,但默认渲染谈不上好看,更别说在终端里几乎没法用。
我在 GitHub 挖到一个新开源项目:beautiful-mermaid,专门把 Mermaid 的渲染这件事做漂亮、做实用——既能导出精致的 SVG,也能生成终端友好的 ASCII 字符画。
它用纯 TypeScript 实现,不依赖 DOM;常用的五类图表一次覆盖:流程图、状态图、时序图、类图、ER 图。
GitHub:https://github.com/lukilabs/beautiful-mermaid…
主题也很到位:内置 15 套精选主题,强调色、边框色等细节都能细调,还支持直接套用任意 VS Code 主题配色。
更关键的是,颜色全用 CSS 变量驱动:切主题不必重渲染,改变量就能即时生效。
lukilabs/beautiful-mermaid
Source: https://github.com/lukilabs/beautiful-mermaid
beautiful-mermaid
Render Mermaid diagrams as beautiful SVGs or ASCII art
Ultra-fast, fully themeable, zero DOM dependencies. Built for the AI era.

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:
- 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
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
- 6 diagram types — Flowcharts, State, Sequence, Class, ER, and XY Charts (bar, line, combined)
- 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
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:
- No flash — SVG is computed synchronously during render, not in a useEffect
- CSS variables — Pass
var(--background)etc. instead of hex colors. The SVG inherits from your app’s CSS, so theme switches apply instantly without re-rendering - Memoized — Only re-renders when
codechanges
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:
- Categorical x-axis:
x-axis [A, B, C] - Numeric x-axis range:
x-axis 0 --> 100 - Axis titles:
x-axis "Category" [A, B, C] - Y-axis range:
y-axis "Score" 0 --> 100
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:
- Dot grid — A subtle dot pattern fills the plot area instead of traditional solid grid lines
- Rounded bars — All bar corners are rounded for a modern, polished look
- Smooth curves — Line series use natural cubic spline interpolation, producing mathematically smooth curves through all data points (not straight segments or staircase steps)
- Floating labels — No visible axis lines or tick marks; labels float freely for a clutter-free aesthetic
- Drop-shadow lines — Each line series has a subtle shadow beneath it for depth
- Monochromatic palette — Series 0 uses the theme’s accent color; additional series get darker/lighter shades of the same hue with subtle hue drift, adapting automatically to light or dark backgrounds
- Interactive tooltips — When rendered with
interactive: true, hovering over bars or data points shows value tooltips. Multi-line tooltips appear when multiple series share an x-position - Sparse line dots — Lines with 12 or fewer data points show data point dots by default for readability
- Full theme support — All 15 built-in themes (and custom themes) apply to charts. The accent color drives the entire series color palette
- Live theme switching — Chart series colors are CSS custom properties (
--xychart-color-N), so theme changes apply instantly without re-rendering
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:
- Bar charts —
█blocks (Unicode) or#(ASCII mode) - Line charts — Staircase routing with rounded corners:
╭╮╰╯│─(Unicode) or+|-(ASCII) - Multi-series — Each series gets a distinct ANSI color from the theme’s accent palette
- Legends — Automatically shown when multiple series are present
- Horizontal charts — Fully supported with categories on the y-axis
API Reference
renderMermaidSVG(text, options?): string
Render a Mermaid diagram to SVG. Synchronous. Auto-detects diagram type.
Parameters:
text— Mermaid source codeoptions— OptionalRenderOptionsobject
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:
- Sequence diagram support
- Class diagram support
- ER diagram support
- Unicode box-drawing characters
- Configurable spacing and padding
Thank you Alexander for the excellent foundation!
License
MIT — see LICENSE for details.
Built with care by the team at Craft
相似文章
@VincentLogic: 发现个科研绘图神器! nature-skills,用 matplotlib 就能画出 Nature 级别的图。多面板布局、配色、字体、排版都给你整得明明白白,直接输出可编辑的 SVG。 内置了 5 套 Nature 风格的示例模板,支持柱…
nature-skills 是一个基于 matplotlib 的科研绘图工具,内置 Nature 风格模板,支持多种图表类型并输出可编辑的 SVG 格式,旨在简化科研论文的图表制作流程。
@tom_doerr: 将复杂的终端输出转换为带样式的HTML页面 https://github.com/nicobailon/visual-explainer…
visual-explainer 是一个智能体技能,可将复杂的终端输出(如 ASCII 艺术图和管道表格)转换为带有 Mermaid 图表、支持深色/浅色主题以及多种 AI 编码智能体框架的带样式的交互式 HTML 页面。
@VincentLogic: 发现个前端圈公认的动画神器,68K stars 真的不是吹的! anime.js —— 一个轻量级但功能极其强大的 JavaScript 动画引擎。 前端兄弟们又来享福了,这玩意儿简直是“动画师的瑞士军刀”: 全能型选手 不管是 CSS …
Anime.js 是一个轻量级但功能强大的 JavaScript 动画引擎,支持 CSS、SVG、DOM 属性及 JavaScript 对象动画,具有直观的 API、时间线系统、滚动观察器、拖拽和响应式动画等特性,在 GitHub 上拥有 68K stars,是前端开发者和交互设计师的常用工具。
@yaohui12138: 卧槽!本以为claude design已是最强,没想到这个项目也这么好用啊 周六晚上,朋友做的一个 SaaS 后台 UI AI味太重,丑到客户发了个「呵呵」..... 我直接用一个 GitHub 项目1小时帮他重做完。其实就是一个叫 DE…
The article introduces 'awesome-design-md', an open-source collection of DESIGN.md files that reverse-engineer the design systems of major tech companies. It allows developers to use AI coding agents like Claude or Cursor to generate UI with specific brand styles by simply adding a markdown file to their project.
@Xudong07452910: 画 paper 配图画到崩溃,改到天亮? 开源神器 PaperBanana,一句话帮你出图: • 扔进去方法论文本 / PDF + 一句 caption • 多 Agent 自动跑:规划 → 风格化 → 出图 → 自我挑刺 → 重画 • …
PaperBanana 是一个开源工具,利用多 Agent 流水线自动从论文 PDF 和用户描述生成高质量学术插图,支持 GPT-Image、Gemini 等多个 AI 提供商,并提供了 CLI、Python API 和 Web 界面。