Contents

lukilabs/beautiful-mermaid-swift

**Render Mermaid diagrams as beautiful native images, SVGs, and ASCII art**

Overview

BeautifulMermaid is a native Swift port of beautiful-mermaid. Parse and render Mermaid diagrams without WebViews or JavaScript. Uses elk-swift for graph layout — a minimal Swift port of the Eclipse Layout Kernel.

Features

  • 6 diagram types — Flowcharts, State, Sequence, Class, ER, and XY Charts
  • Multiple output formats — Native images (UIImage / NSImage), SVG, and ASCII art
  • 17 built-in themes — Tokyo Night, Dracula, Nord, Gruvbox, and more
  • VS Code theme import — Load any Shiki/VS Code theme via ShikiTheme
  • Mono mode — Beautiful diagrams from just 2 colors
  • SwiftUI integration — Built-in MermaidDiagramView with a value-type MermaidDiagram model
  • CALayer renderingMermaidLayer for lightweight, direct Core Graphics rendering
  • Async rendering — All render methods available as async variants
  • Pure Swift — No WebView, no JavaScript
  • Cross-platform — iOS 15+, macOS 12+, Mac Catalyst 15+, visionOS 1.0+

Installation

Swift Package Manager

Add BeautifulMermaid to your Package.swift:

dependencies: [
    .package(url: "https://github.com/lukilabs/beautiful-mermaid-swift", from: "1.0.0")
]

Then add it to your target dependencies:

.target(
    name: "YourTarget",
    dependencies: [.product(name: "BeautifulMermaid", package: "beautiful-mermaid-swift")]
)

Quick Start

import BeautifulMermaid

let mermaidCode = """
graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Do Something]
    B -->|No| D[Do Something Else]
    C --> E[End]
    D --> E
"""

// Render as image
let image = try MermaidRenderer.renderImage(source: mermaidCode)

// Render as SVG
let svg = try MermaidRenderer.renderSVG(source: mermaidCode, theme: .tokyoNight)

// Render as ASCII art
let ascii = try MermaidRenderer.renderASCII(source: mermaidCode, theme: .zincDark)

SwiftUI

Use the built-in MermaidDiagramView:

import SwiftUI
import BeautifulMermaid

struct ContentView: View {
    var body: some View {
        MermaidDiagramView(
            source: "graph TD; A-->B; B-->C;",
            theme: .catppuccinMocha
        )
    }
}

UIKit / AppKit

MermaidView is a native UIView (iOS) / NSView (macOS) subclass:

import BeautifulMermaid

let mermaidView = MermaidView(frame: CGRect(x: 0, y: 0, width: 400, height: 300))
mermaidView.source = "graph TD; A-->B; B-->C;"
mermaidView.theme = .catppuccinMocha
view.addSubview(mermaidView)

Image Export

Export diagrams as PNG or JPEG data:

let renderer = MermaidImageRenderer()
renderer.theme = .dracula
renderer.scale = 3.0

let pngData = try renderer.renderPNG(from: mermaidCode)
let jpegData = try renderer.renderJPEG(from: mermaidCode, quality: 0.9)

Async Rendering

All render methods have async variants for background processing:

let image = try await MermaidRenderer.renderImageAsync(source: mermaidCode, theme: .nord)
let svg = try await MermaidRenderer.renderSVGAsync(source: mermaidCode)
let ascii = try await MermaidRenderer.renderASCIIAsync(source: mermaidCode)

Theming

Two-Color Theming

At minimum, you only need two colors:

let theme = DiagramTheme(
    background: "#1a1b26",  // Background color
    foreground: "#c0caf5"   // Text/line color
)

From these two colors, the system automatically derives text colors, node fills, strokes, edge colors, and all other UI elements.

Optional Enrichment Colors

For more control, add optional accent colors:

let theme = DiagramTheme(
    background: "#1a1b26",
    foreground: "#c0caf5",
    line: "#565f89",        // Edge lines
    accent: "#7aa2f7",      // Highlighted elements
    muted: "#414868",       // De-emphasized elements
    surface: "#24283b",     // Node backgrounds
    border: "#414868"       // Node borders
)

VS Code / Shiki Theme Import

Import any VS Code color theme:

let shikiTheme = DiagramTheme.ShikiTheme(
    type: "dark",
    colors: [
        "editor.background": "#1e1e1e",
        "editor.foreground": "#d4d4d4",
        "focusBorder": "#007acc"
    ],
    tokenColors: []
)

let theme = DiagramTheme.fromShikiTheme(shikiTheme)

Built-in Themes

| Theme | Description | |-------|-------------| | .zincLight / .zincDark | Default, clean appearance | | .tokyoNight / .tokyoNightStorm / .tokyoNightLight | Popular VS Code theme | | .catppuccinMocha / .catppuccinLatte | Soothing pastel colors | | .nord / .nordLight | Arctic-inspired palette | | .dracula | Classic dark theme | | .githubLight / .githubDark | Familiar GitHub style | | .solarizedLight / .solarizedDark | Eye-friendly colors | | .oneDark | Atom editor style | | .gruvboxDark / .gruvboxLight | Retro groove colors |

Supported Diagrams

### Flowcharts

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/examples/flowchart-dark.png">
  <source media="(prefers-color-scheme: light)" srcset="assets/examples/flowchart-light.png">
  <img src="assets/examples/flowchart-light.png" alt="Flowchart Example" width="400">
</picture>

<details>
<summary>ASCII art output</summary>

```
┌────────────────────────────────────────┐
│              CI Pipeline               │
│                                        │
│                                        │
│ ┌────────────────┐                     │
│ │                │                     │
│ │   Push Code    │◄┄┄┄┄┄┄┄┄┄┄┄┐        │
│ │                │            ┆        │
│ └────────┬───────┘            ┆        │
│          │                    ┆        │
│          │                    ┆        │
│          │                    ┆        │
│          │                    ┆        │
│          ▼                    ┆        │
│ ◇────────────────◇            ┆        │
│ │                │            ┆        │
│ │  Tests Pass?   ├────────────┐        │
│ │                │            ┆        │
│ ◇────────┬───────◇           No        │
│          │                    ┆        │
│         Yes                   ┆        │
│          │                    ┆        │
│          │                    ┆        │
│          ▼                    ▼        │
│ ┌────────────────┐     ┌──────┴──────┐ │
│ │                │     │             │ │
│ │  Build Image   │     │ Fix & Retry │ │
│ │                │     │             │ │
│ └────────┬───────┘     └─────────────┘ │
│          │                    ▲        │
└──────────┼────────────────────┼────────┘
           │                    │
           │                    │
           ▼                    │
  (────────────────)            │
  │                │            │
  │ Deploy Staging │            │
  │                │            │
  (────────┬───────)            │
           │                    │
           │                    │
           │                   No
           │                    │
           ▼                    │
  ◇────────────────◇            │
  │                │            │
  │  QA Approved?  ├────────────┘
  │                │
  ◇────────┬───────◇
           │
          Yes
           │
           │
           ▼
  ◯────────────────◯
  │                │
  │   Production   │
  │                │
  ◯────────────────◯
```
</details>

```
graph TD
    subgraph ci [CI Pipeline]
        A[Push Code] --> B{Tests Pass?}
        B -->|Yes| C[Build Image]
        B -->|No| D[Fix & Retry]
        D -.-> A
    end
    C --> E([Deploy Staging])
    E --> F{QA Approved?}
    F -->|Yes| G((Production))
    F -->|No| D
```

### State Diagrams

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/examples/state-dark.png">
  <source media="(prefers-color-scheme: light)" srcset="assets/examples/state-light.png">
  <img src="assets/examples/state-light.png" alt="State Diagram Example" width="400">
</picture>

<details>
<summary>ASCII art output</summary>

```
●───────────────●
│               │
●───────────────●
        │
        │
        │
        │
        ▼
╭───────────────╮
│               │
│     Closed    │  ├done──┬────────────────────────┐
│               │         │                        │
╰───────┬───────╯         │                        │
        ▲                 │                        │
     connect              │                        │
        │                 │                        │
     timeout              │                        │
        ▼                 │                        ▼
╭───────┴───────╮         │          ╔══════════════════════════╗
│               │         │          ║                          ║
│   Connecting  │         │          ║                          ║
│               │         │          ║                          ║
╰───────┬───────╯         │          ╚══════════════════════════╝
        │                 │
     success              │
        │                 │
        │                 │
        ▼                 │
╭───────────────╮         ├──────────┐
│               │         │          │
│   Connected   │  ├◄─────┼─────success────────────┐
│               │         │          │             │
╰───────┬───────╯         │          │           error
        │                 │          │             │
      close               │          │             │
        │                 │          └─max_retries─┤
        │                 │                        │
        ▼                 │                        ▼
╭───────────────╮         │          ╭─────────────┴────────────╮
│               │         │          │                          │
│ Disconnecting │  ├──────┘          │       Reconnecting       │
│               │                    │                          │
╰───────────────╯                    ╰──────────────────────────╯
```
</details>

```
stateDiagram-v2
    [*] --> Closed
    Closed --> Connecting : connect
    Connecting --> Connected : success
    Connecting --> Closed : timeout
    Connected --> Disconnecting : close
    Connected --> Reconnecting : error
    Reconnecting --> Connected : success
    Reconnecting --> Closed : max_retries
    Disconnecting --> Closed : done
    Closed --> [*]
```

### Sequence Diagrams

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/examples/sequence-dark.png">
  <source media="(prefers-color-scheme: light)" srcset="assets/examples/sequence-light.png">
  <img src="assets/examples/sequence-light.png" alt="Sequence Diagram Example" width="400">
</picture>

<details>
<summary>ASCII art output</summary>

```
┌──────┐       ┌────────────┐               ┌─────────────┐  ┌──────────────┐
│ User │       │ Client App │               │ Auth Server │  │ Resource API │
└───┬──┘       └──────┬─────┘               └──────┬──────┘  └───────┬──────┘
    │                 │                            │                 │
    │   Click Login   │                            │                 │
    │─────────────────▶                            │                 │
    │                 │                            │                 │
    │                 │   Authorization request    │                 │
    │                 │────────────────────────────▶                 │
    │                 │                            │                 │
    │                 Login page                   │                 │
    ◀──────────────────────────────────────────────│                 │
    │                 │                            │                 │
    │                 Credentials                  │                 │
    │──────────────────────────────────────────────▶                 │
    │                 │                            │                 │
    │                 │    Authorization code      │                 │
    │                 ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│                 │
    │                 │                            │                 │
    │                 │  Exchange code for token   │                 │
    │                 │────────────────────────────▶                 │
    │                 │                            │                 │
    │                 │       Access token         │                 │
    │                 ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│                 │
    │                 │                            │                 │
    │                 │               Request + token                │
    │                 │──────────────────────────────────────────────▶
    │                 │                            │                 │
    │                 │             Protected resource               │
    │                 ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│
    │                 │                            │                 │
    │  Display data   │                            │                 │
    ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│                            │                 │
    │                 │                            │                 │
┌───┴──┐       ┌──────┴─────┐               ┌──────┴──────┐  ┌───────┴──────┐
│ User │       │ Client App │               │ Auth Server │  │ Resource API │
└──────┘       └────────────┘               └─────────────┘  └──────────────┘
```
</details>

```
sequenceDiagram
    actor U as User
    participant App as Client App
    participant Auth as Auth Server
    participant API as Resource API
    U->>App: Click Login
    App->>Auth: Authorization request
    Auth->>U: Login page
    U->>Auth: Credentials
    Auth-->>App: Authorization code
    App->>Auth: Exchange code for token
    Auth-->>App: Access token
    App->>API: Request + token
    API-->>App: Protected resource
    App-->>U: Display data
```

### Class Diagrams

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/examples/class-dark.png">
  <source media="(prefers-color-scheme: light)" srcset="assets/examples/class-light.png">
  <img src="assets/examples/class-light.png" alt="Class Diagram Example" width="400">
</picture>

<details>
<summary>ASCII art output</summary>

```
┌────────────────┐
│ <<abstract>>   │
│ Animal         │
├────────────────┤
│ +name: String  │
│ +age: int      │
├────────────────┤
│ +eat(): void   │
│ +sleep(): void │
└────────────────┘
         △
         └──────────────────────────┐
           │                        │
┌────────────────────┐    ┌──────────────────┐
│ Mammal             │    │ Bird             │
├────────────────────┤    ├──────────────────┤
│ +warmBlooded: bool │    │ +canFly: bool    │
├────────────────────┤    ├──────────────────┤
│ +nurse(): void     │    │ +layEggs(): void │
└────────────────────┘    └──────────────────┘
           △                        △
         ┌─└───────────────────┐    └───────────────────┐
         │                     │                        │
┌────────────────┐    ┌─────────────────┐    ┌─────────────────────┐
│ Dog            │    │ Cat             │    │ Parrot              │
├────────────────┤    ├─────────────────┤    ├─────────────────────┤
│ +breed: String │    │ +isIndoor: bool │    │ +vocabulary: String │
├────────────────┤    ├─────────────────┤    ├─────────────────────┤
│ +bark(): void  │    │ +purr(): void   │    │ +speak(): void      │
└────────────────┘    └─────────────────┘    └─────────────────────┘
```
</details>

```
classDiagram
    class Animal {
        <<abstract>>
        +String name
        +int age
        +eat() void
        +sleep() void
    }
    class Mammal {
        +bool warmBlooded
        +nurse() void
    }
    class Bird {
        +bool canFly
        +layEggs() void
    }
    class Dog {
        +String breed
        +bark() void
    }
    class Cat {
        +bool isIndoor
        +purr() void
    }
    class Parrot {
        +String vocabulary
        +speak() void
    }
    Animal <|-- Mammal
    Animal <|-- Bird
    Mammal <|-- Dog
    Mammal <|-- Cat
    Bird <|-- Parrot
```

### ER Diagrams

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/examples/er-dark.png">
  <source media="(prefers-color-scheme: light)" srcset="assets/examples/er-light.png">
  <img src="assets/examples/er-light.png" alt="ER Diagram Example" width="400">
</picture>

<details>
<summary>ASCII art output</summary>

```
┌─────────────────┐      ┌────────────────────┐
│ CUSTOMER        │      │ ORDER              │
├─────────────────┤      ├────────────────────┤
│ PK int id       ││───○╟│ PK int id          │
│    string name  │places│    date created    │
│ UK string email │      │ FK int customer_id │
└─────────────────┘      └────────────────────┘
                                    │
                                  ─── contains
                                  │ │
                                  ╟ │
┌────────────────┐      ┌───────────────────┐
│ PRODUCT        │      │ LINE_ITEM         │
├────────────────┤      ├───────────────────┤
│ PK int id      ││───○╟│ PK int id         │
│    string name │includ│ FK int order_id   │
│    float price │      │ FK int product_id │
└────────────────┘      │    int quantity   │
                        └───────────────────┘
```
</details>

```
erDiagram
    CUSTOMER {
        int id PK
        string name
        string email UK
    }
    ORDER {
        int id PK
        date created
        int customer_id FK
    }
    PRODUCT {
        int id PK
        string name
        float price
    }
    LINE_ITEM {
        int id PK
        int order_id FK
        int product_id FK
        int quantity
    }
    CUSTOMER ||--o{ ORDER : places
    ORDER ||--|{ LINE_ITEM : contains
    PRODUCT ||--o{ LINE_ITEM : includes
```

### XY Charts

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/examples/xychart-dark.png">
  <source media="(prefers-color-scheme: light)" srcset="assets/examples/xychart-light.png">
  <img src="assets/examples/xychart-light.png" alt="XY Chart Example" width="400">
</picture>

<details>
<summary>ASCII art output</summary>

```
                            Sales Revenue
                          █ Bar 1  ─ Line 1

 11000┤····························································
      │                                                  ╭───────█
      │                                                  │████████
 10000┤········································╭─────────╯████████·
      │                                        │████████  ████████
  9000┤········································│████████··████████·
      │                                        │████████  ████████
      │                                        │████████  ████████
  8000┤······························╭─────────╯████████··████████·
      │                    ╭─────────╯████████  ████████  ████████
      │                    │████████  ████████  ████████  ████████
  7000┤····················│████████··████████··████████··████████·
      │                    │████████  ████████  ████████  ████████
      │                    │████████  ████████  ████████  ████████
  6000┤··········╭─────────╯████████··████████··████████··████████·
      │          │████████  ████████  ████████  ████████  ████████
  5000┤·██───────╯████████··████████··████████··████████··████████·
      │ ████████  ████████  ████████  ████████  ████████  ████████
      │ ████████  ████████  ████████  ████████  ████████  ████████
  4000┼·████████··████████··████████··████████··████████··████████·
      ┼─────┬─────────┬─────────┬─────────┬─────────┬─────────┬────
           jan       feb       mar       apr       may       jun
```
</details>

```
xychart-beta
    title "Sales Revenue"
    x-axis [jan, feb, mar, apr, may, jun]
    y-axis "Revenue (in $)" 4000 --> 11000
    bar [5000, 6000, 7500, 8200, 9800, 10500]
    line [5000, 6000, 7500, 8200, 9800, 10500]
```

### Parser Limitations

The parser handles standard Mermaid syntax for supported diagram types. The following features are **not supported**:

- HTML in node labels
- Click callbacks and links
- Tooltips
- FontAwesome icons
- Multiline labels with `<br>` tags
- Styling via `style` and `linkStyle` directives (partial support)
- Subgraph styling

If your diagram uses these features, they will be silently ignored or may cause unexpected output.

Configuration

Render Options

let image = try MermaidRenderer.renderImage(
    source: code,
    theme: .tokyoNight,
    scale: 2.0                // Retina scale (default: 2.0)
)

Layout Configuration

let config = LayoutConfig(
    padding: 20,
    nodeSpacing: 40,
    layerSpacing: 60,
    componentSpacing: 40
)

let renderer = MermaidImageRenderer()
renderer.layoutConfig = config

Layout Directions

Specify direction in your Mermaid code:

  • graph TD or graph TB — Top to bottom (default)
  • graph BT — Bottom to top
  • graph LR — Left to right
  • graph RL — Right to left

Requirements

  • Swift 5.9+
  • iOS 15+ / macOS 12+ / Mac Catalyst 15+ / visionOS 1.0+

License

MIT License — see LICENSE for details.

Acknowledgments

  • beautiful-mermaid — Original TypeScript implementation by Craft
  • elk-swift — ELK layout engine, Swift port of Eclipse Layout Kernel
  • Mermaid — Diagramming syntax specification

Package Metadata

Repository: lukilabs/beautiful-mermaid-swift

Default branch: main

README: README.md