
Security News
AI Agent Lands PRs in Major OSS Projects, Targets Maintainers via Cold Outreach
An AI agent is merging PRs into major OSS projects and cold-emailing maintainers to drum up more work.
@vercel/beautiful-mermaid
Advanced tools
Render Mermaid diagrams as beautiful SVGs or ASCII art. Ultra-fast, fully themeable, zero DOM dependencies.
Render Mermaid diagrams as beautiful SVGs or ASCII art
Ultra-fast, fully themeable, animated, zero DOM dependencies. Built for the AI era.

npm install beautiful-mermaid
import { renderMermaid } from 'beautiful-mermaid'
const svg = await renderMermaid(`
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Action]
B -->|No| D[End]
`)
const svg = await renderMermaid(diagram, {
animate: true, // rank-by-rank animation with sane defaults
})
// Or customize:
const svg = await renderMermaid(diagram, {
animate: {
duration: 650,
stagger: 0,
nodeOverlap: 0.35,
nodeAnimation: 'fade-up',
},
})
import { renderMermaidAscii } from 'beautiful-mermaid'
const ascii = renderMermaidAscii(`graph LR; A --> B --> C`)
┌───┐ ┌───┐ ┌───┐
│ │ │ │ │ │
│ A │────►│ B │────►│ C │
│ │ │ │ │ │
└───┘ └───┘ └───┘
<script src="https://unpkg.com/beautiful-mermaid/dist/beautiful-mermaid.browser.global.js"></script>
<script>
const { renderMermaid, THEMES } = beautifulMermaid;
renderMermaid('graph TD; A-->B', { ...THEMES['vercel-dark'], animate: true })
.then(svg => { ... });
</script>
Every diagram needs just two colors: background (bg) and foreground (fg):
const svg = await renderMermaid(diagram, {
bg: '#1a1b26',
fg: '#a9b1d6',
})
Everything else is derived via color-mix().
Override specific derived colors:
const svg = await renderMermaid(diagram, {
bg: '#1a1b26',
fg: '#a9b1d6',
line: '#3d59a1', // Edge/connector color
accent: '#7aa2f7', // Arrow heads, highlights
muted: '#565f89', // Secondary text, labels
surface: '#292e42', // Node fill tint
border: '#3d59a1', // Node stroke
})
17 themes ship out of the box:
import { renderMermaid, THEMES } from 'beautiful-mermaid'
const svg = await renderMermaid(diagram, THEMES['vercel-dark'])
| Theme | Type | Background |
|---|---|---|
vercel-dark | Dark | #0A0A0A |
vercel-light | Light | #FFFFFF |
tokyo-night | Dark | #1a1b26 |
tokyo-night-storm | Dark | #24283b |
tokyo-night-light | Light | #d5d6db |
catppuccin-mocha | Dark | #1e1e2e |
catppuccin-latte | Light | #eff1f5 |
nord | Dark | #2e3440 |
nord-light | Light | #eceff4 |
dracula | Dark | #282a36 |
github-light | Light | #ffffff |
github-dark | Dark | #0d1117 |
solarized-light | Light | #fdf6e3 |
solarized-dark | Dark | #002b36 |
one-dark | Dark | #282c34 |
zinc-dark | Dark | #18181B |
Default theme (when no colors provided) is Vercel dark (#0A0A0A / #EDEDED).
Use any VS Code theme via Shiki:
import { getSingletonHighlighter } from 'shiki'
import { renderMermaid, fromShikiTheme } from 'beautiful-mermaid'
const hl = await getSingletonHighlighter({ themes: ['vitesse-dark'] })
const colors = fromShikiTheme(hl.getTheme('vitesse-dark'))
const svg = await renderMermaid(diagram, colors)
Pass animate: true for rank-by-rank animation with sane defaults, or customize with AnimationOptions.
stroke-dashoffset with pathLength="1"<animateMotion>, synced with edge easingAll CSS-based (works in standalone SVG files, no JS runtime needed). SMIL used only for arrow travel.
interface AnimationOptions {
duration?: number // Each element's animation duration (ms). Default: 650
stagger?: number // Delay between consecutive elements (ms). Default: 0
nodeOverlap?: number // How early node appears before incoming edge finishes
// (0 = wait, 0.5 = halfway, 1 = with edge). Default: 0.35
groupDelay?: number // Extra offset for group container (ms). Default: 110
nodeEasing?: string // CSS easing for nodes/groups. Default: 'ease'
edgeEasing?: string // CSS easing for edge draw-in + arrow travel. Default: 'ease-in-out'
nodeAnimation?: string // 'fade' | 'fade-up' | 'scale' | 'none'. Default: 'fade'
edgeAnimation?: string // 'draw' | 'fade' | 'none'. Default: 'draw'
reducedMotion?: boolean // Respect prefers-reduced-motion. Default: true
}
| Element | Easing | Rationale |
|---|---|---|
| Nodes/groups | nodeEasing | Elements "appear" — deceleration curve |
| Edge lines | edgeEasing | Lines "flow" — acceleration/deceleration |
| Arrow tips | auto-derived from edgeEasing | SMIL keySplines converted from CSS cubic-bezier, guaranteed sync |
| Edge labels | nodeEasing | Labels are content, not motion |
When reducedMotion: true (default), a @media (prefers-reduced-motion: reduce) block disables all animations, showing the diagram instantly.
| Option | Type | Default | Description |
|---|---|---|---|
bg | string | #0A0A0A | Background color |
fg | string | #EDEDED | Foreground color |
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 | Geist | Font family |
fontSize | number | 19.2 | Node label font size (px) |
fontWeight | number | 400 | Node label font weight |
letterSpacing | number | -0.384 | Node label letter spacing (px) |
edgeFontSize | number | 10 | Edge label font size (px) |
nodePaddingX | number | 24 | Horizontal padding inside nodes (px) |
nodePaddingY | number | 24 | Vertical padding inside nodes (px) |
cornerRadius | number | 6 | Node corner radius (px) |
lineWidth | number | 1.5 | Edge stroke width (px) |
edgeBendRadius | number | 8 | Rounded corners on edge bends (px) |
padding | number | 80 | Canvas padding (px) |
nodeSpacing | number | 40 | Horizontal spacing between nodes (px) |
layerSpacing | number | 50 | Vertical spacing between layers (px) |
transparent | boolean | false | Transparent background |
animate | boolean | AnimationOptions | false | Enable animation |
| Option | Type | Default | Description |
|---|---|---|---|
groupFont | string | Geist Mono | Subgraph header font family |
groupFontSize | number | 16 | Subgraph header font size (px) |
groupFontWeight | number | 600 | Subgraph header font weight |
groupTextTransform | string | uppercase | Subgraph header text transform |
groupCornerRadius | number | 3 | Subgraph corner radius (px) |
groupBorderColor | string | #454545 | Subgraph border color |
groupPaddingX | number | 32 | Subgraph horizontal padding (px) |
groupPaddingY | number | 32 | Subgraph vertical padding (px) |
Subgraph backgrounds use a diagonal hatching pattern.
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Process]
B -->|No| D[End]
All directions: TD, LR, BT, RL. Subgraphs supported.
stateDiagram-v2
[*] --> Idle
Idle --> Processing: start
Processing --> Complete: done
Complete --> [*]
sequenceDiagram
Alice->>Bob: Hello Bob!
Bob-->>Alice: Hi Alice!
classDiagram
Animal <|-- Duck
Animal: +int age
Duck: +swim()
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE_ITEM : contains
import { renderMermaidAscii } from 'beautiful-mermaid'
const unicode = renderMermaidAscii(`graph LR; A --> B`)
const ascii = renderMermaidAscii(`graph LR; A --> B`, { useAscii: true })
| Option | Type | Default | Description |
|---|---|---|---|
useAscii | boolean | false | ASCII instead of Unicode |
paddingX | number | 5 | Horizontal node spacing |
paddingY | number | 5 | Vertical node spacing |
boxBorderPadding | number | 1 | Inner box padding |
ASCII rendering based on mermaid-ascii by Alexander Grooff (ported from Go, extended with sequence/class/ER support).
MIT — see LICENSE for details.
Built with care by the team at Craft
FAQs
Render Mermaid diagrams as beautiful SVGs or ASCII art. Ultra-fast, fully themeable, zero DOM dependencies.
The npm package @vercel/beautiful-mermaid receives a total of 0 weekly downloads. As such, @vercel/beautiful-mermaid popularity was classified as not popular.
We found that @vercel/beautiful-mermaid demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 375 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
An AI agent is merging PRs into major OSS projects and cold-emailing maintainers to drum up more work.

Research
/Security News
Chrome extension CL Suite by @CLMasters neutralizes 2FA for Facebook and Meta Business accounts while exfiltrating Business Manager contact and analytics data.

Security News
After Matplotlib rejected an AI-written PR, the agent fired back with a blog post, igniting debate over AI contributions and maintainer burden.