beautiful-mermaid

repository·main·Indexed 27 days ago

https://github.com/lukilabs/beautiful-mermaid

A high-performance, synchronous Mermaid diagram renderer that produces SVGs or ASCII art. It features zero DOM dependencies, deep themeability via CSS variables, and full Shiki compatibility. The library supports Flowcharts, State, Sequence, Class, ER, and XY Charts, providing both synchronous and asynchronous SVG rendering and a customizable ASCII/Unicode output for terminal or CLI environments.

Tokens
13.8K
Snippets
37
Records
60
Agent score
90%

What's inside beautiful-mermaid

  1. Understand the Parse → Layout → Render pipeline

    main

    The project follows a consistent three-stage pipeline for all diagram types:

    1. Parser (parser.ts): A pure function that takes string[] (preprocessed lines) and returns a typed AST (e.g., ErDiagram, XYChart).
    2. Layout (layout.ts): An async function that takes the parsed AST and RenderOptions to return a positioned structure with pixel coordinates. It uses estimateTextWidth() for sizing.
    3. Renderer (renderer.ts): A function that takes the positioned structure, DiagramColors, font, and transparency settings to return an SVG string. It uses CSS custom properties for all coloring.
  2. Use XY Charts (Bar, Line, and Combined)

    main

    The library supports xychart-beta syntax for creating modern, polished charts. XY charts feature rounded bars, smooth cubic spline curves, and a monochromatic palette driven by the theme's accent color. If interactive: true is set in SVG options, tooltips will appear on hover.

    // 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]
  3. Integrate beautiful-mermaid with React

    main

    Since rendering is synchronous, use React.useMemo() to compute the SVG string. This prevents the 'flash' of unrendered content often seen with async renderers. You can pass CSS variables (e.g., var(--background)) to the options to allow the SVG to inherit theme changes from your application's CSS without requiring a React re-render.

    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! }} />
    }
  4. Style flowchart edges with linkStyle

    main

    You can override edge colors and stroke widths in flowcharts and state diagrams using the linkStyle syntax. This works similarly to standard Mermaid syntax.

    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 |
  5. Mermaid XY Chart (xychart-beta) Syntax Reference

    main

    The xychart-beta diagram type supports bar charts, line charts, or combinations of both. It can use categorical x-axes (labels) or numeric x-axes (ranges). You can also specify a horizontal orientation.

    Vertical Chart (Default)

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

    Horizontal Chart

    Add the horizontal keyword after the diagram type:

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

    Numeric X-Axis

    Instead of categories, provide a numeric range using -->:

    xychart-beta
        x-axis 0 --> 100
        y-axis 0 --> 50
        line [10, 20, 35, 40, 45]
    xychart-beta
        title "Sales Revenue"
        x-axis [jan, feb, mar, apr, may, jun]
        y-axis "Revenue (USD)" 4000 --> 11000
        bar [5000, 6000, 7500, 8200, 9800, 10500]
        line [5000, 6000, 7500, 8200, 9800, 10500]
  6. Implement XY Chart support in the rendering pipeline

    main

    To add support for xychart-beta or xychart diagrams, you must update the main entry point to detect the diagram type and route it through the Parse → Layout → Render pipeline.

    1. Update detectDiagramType: Add logic to identify the diagram type using a word boundary (\b) to ensure xychart-beta is correctly matched even if followed by other parameters.
    2. Update renderMermaid: Add a case for xychart that coordinates the three stages: parseXYChart, layoutXYChart, and renderXYChartSvg.
    // 1. Update detection logic
    function detectDiagramType(text: string): 'flowchart' | 'sequence' | 'class' | 'er' | 'xychart' {
      const firstLine = text.trim().split(/[\n;]/)[0]?.trim().toLowerCase() ?? ''
    
      if (/^xychart-beta\b/.test(firstLine)) return 'xychart'
      if (/^xychart\b/.test(firstLine)) return 'xychart'
      // ... other types
      return 'flowchart'
    }
    
    // 2. Update the render switch
    case 'xychart': {
      const chart = parseXYChart(lines)
      const positioned = await layoutXYChart(chart, options)
      return renderXYChartSvg(positioned, colors, font, transparent)
    }
  7. Configure theming via CSS Custom Properties

    main

    Theming is handled through CSS custom properties applied to the <svg> tag. Renderers do not hardcode colors; they reference derived internal variables.

    Required Variables:

    • --bg: Background color
    • --fg: Foreground color

    Optional Enrichment Variables:

    • --line: Line color
    • --accent: Accent color
    • --muted: Muted color
    • --surface: Surface color
    • --border: Border color

    Internal Derived Variables: Renderers use variables like --_text, --_line, and --_node-fill, which are computed within the SVG <style> block using color-mix() based on the provided theme variables.

  8. Configure diagram themes

    main

    Themes are defined by a background color (bg) and a foreground color (fg). The engine uses color-mix() to derive all other element colors (like connectors, text, and nodes) automatically.

    For more control, you can provide an 'Enriched Mode' configuration with specific colors for roles like line, accent, muted, surface, and border.

    // Mono Mode (Two-color foundation)
    const svg = renderMermaidSVG(diagram, {
      bg: '#1a1b26',
      fg: '#a9b1d6',
    })
    
    // Enriched Mode (Custom overrides)
    const svg = renderMermaidSVG(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
    })
  9. Generate the visual test suite HTML

    main

    The index.ts file can be used to generate a dynamic index.html file that showcases all beautiful-mermaid rendering capabilities. This generated HTML acts as a visual test suite, exercising every supported feature, shape, edge type, block construct, and theme variant. The resulting page renders diagrams client-side in real time using a bundled version of the mermaid renderer.

    bun run index.ts
  10. Render Mermaid diagrams to ASCII or Unicode

    main

    Use renderMermaidASCII to render diagrams for terminal environments or plain text files. By default, it uses Unicode box-drawing characters for a prettier look, but you can force pure ASCII mode for maximum compatibility.

    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 })