Project

sirena

0.0
The project is in a healthy, maintained state
Sirena is a pure Ruby implementation of Mermaid diagram rendering. It parses Mermaid syntax and generates SVG output using Parslet grammars and ELK layout. Supports 24 diagram types: flowcharts, sequence, class, state, ER, C4, block, architecture, Gantt, timeline, Git graph, mindmap, Kanban, user journey, pie, quadrant, radar, XY charts, requirement, Sankey, packet, treemap, info, and error displays.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0
>= 0

Runtime

 Project Readme

Sirena

RubyGems Version License Build

Purpose

Sirena is a pure Ruby interpreter of commonly-used diagram generation languages into SVG format.

Sirena currently supports the following diagram definition syntaxes:

  • Mermaid - the text-based diagramming language defined in mermaid-js

Sirena aims to provide high compatibility with the original tools while offering a pure Ruby implementation that can be easily integrated into Ruby-based workflows and tools.

Note
The name "Sirena" is derived from "Siren", a mythological creature known for its enchanting songs that lure sailors, as its usage in multiple languages refer to mermaids.

Implementation notes

The library follows strict object-oriented principles with a model-driven architecture. Most diagram models use Lutaml::Model, but not all data structures do: six diagram classes (PacketField, RadarAxis, RadarCurve, TreemapNode, XYAxis, XYDataset) are plain Ruby classes. Six diagram types (flowchart, class, state, ER, Sankey, timeline) lay out to a typed Layout::Scene; the other types still build a graph or legacy layout structure. See ARCHITECTURE.md for the stages.

Features

Diagram language support

Mermaid defines a set of diagram type languages for composing different diagram types.

Sirena registers 24 diagram types. 23 are Mermaid input languages; the 24th is error, the fallback Mermaid.js renders when its own parsing fails. Mermaid’s ZenUML is not registered. Per-type compatibility with real Mermaid.js input varies (see below).

Mermaid diagram types

Sirena registers 24 Mermaid diagram types end-to-end (parser, transform, and renderer). Registration is not the same as full compatibility: the per-type pass rates against the mermaid-js corpus are generated from scoreboard/corpus.json onto the compatibility page.

  • Flowchart - Directional graphs with various node shapes and edge types

  • Sequence diagram - Message flows between participants over time

  • Class diagram - UML class relationships and hierarchies

  • State diagram - State machine transitions and hierarchies

  • Entity-relationship diagram - Database schema relationships

  • User journey - User interaction flows with satisfaction levels

  • Gantt chart - Project timelines and task dependencies

  • Pie chart - Proportional data visualization

  • Quadrant chart - 2D data point categorization

  • Requirement diagram - Requirements and their relationships

  • Git graph - Git branching and commit history

  • Mindmap - Hierarchical mind mapping

  • Timeline - Event sequences over time

  • Sankey diagram - Flow quantities between nodes

  • XY chart - Line and bar charts with axes

  • Block diagram - Block-based architecture diagrams

  • Packet diagram - Network packet structure

  • C4 diagram - Software architecture contexts and containers

  • Architecture diagram - Service and component architecture

  • Kanban board - Workflow status tracking

  • Radar chart - Multi-dimensional data comparison

  • Treemap - Hierarchical data as nested rectangles

  • Error diagram - Error message display

  • Info diagram - Information display

See examples/README.adoc for working examples of all diagram types.

Core capabilities

  • Pure Ruby implementation - No JavaScript dependencies

  • Parslet-based parsing - Declarative grammars with line and column in parse errors

  • SVG output - Standards-compliant SVG 1.2

  • Theme support - 4 built-in themes, custom theme support

  • Auto-detection - Automatic diagram type detection

  • Batch processing - Process multiple diagrams at once

  • CLI tool - Command-line interface for standalone usage

  • Programmatic API - Ruby library for custom workflows

  • Metanorma-oriented SVG - Self-contained SVG for embedding in Metanorma documents; flowchart, sequence, class, pie and Gantt renders pass svg_conform’s `:metanorma conformance check with zero errors (checked directly against SvgConform.validate; spec/sirena/svg_conformance_spec.rb runs this on every suite run against shipped examples, reference fixtures, and the mermaid corpus)

Installation

Via RubyGems

Add Sirena to your Gemfile:

gem 'sirena'

Then execute:

bundle install

Or install it directly:

gem install sirena

Requirements

Ruby 3.2 or higher.

Quick start

Command-line usage

Render a single Mermaid diagram to SVG:

sirena render diagram.mmd -o output.svg

Create a PlantUML class diagram in diagram.puml:

@startuml
class User
class Account
User --> Account : owns
@enduml

Then render it by loading the bundled notation:

sirena render --require sirena/notation/plantuml diagram.puml -o output.svg

The same notation renders PlantUML sequence diagrams. Create sequence.puml:

@startuml
Alice -> Bob : hello
Bob --> Alice : hi
@enduml

Then render it the same way:

sirena render --require sirena/notation/plantuml sequence.puml -o sequence.svg

Render all Mermaid files in a directory:

sirena batch -i input_dir/ -o output_dir/

List all supported diagram types:

sirena types

Programmatic usage

Use Sirena in your Ruby code:

require 'sirena'

# Render from a string
mermaid_code = <<~MERMAID
  graph TD
    A[Start] --> B[Process]
    B --> C[End]
MERMAID

svg = Sirena.render(mermaid_code)
File.write('output.svg', svg)

# Render from a file
svg = Sirena.render(File.read('diagram.mmd'))
File.write('output.svg', svg)

# Pick a built-in theme
svg = Sirena.render(mermaid_code, theme: 'dark')

Examples

Browse examples/README.adoc for 53 example sources across all 24 diagram types; 52 have a tracked SVG (one .beta.mmd source does not render yet).

Documentation

Documentation is available at the Sirena Documentation Site.

Documentation Structure

The documentation uses a 6-collection architecture:

  1. Core Topics - Compatibility and comparison

  2. Tutorials - Step-by-step learning paths

  3. Guides - Task-oriented how-to documentation

  4. Diagram Types - Complete reference for all 24 diagram types with examples

  5. Features - Detailed capability documentation

  6. References - Reference index

See the documentation site for the complete guide.

Architecture

General

Sirena implements a pipeline architecture that transforms Mermaid source code through distinct processing stages, each with clear responsibilities and well-defined interfaces.

All parsers use Parslet, a powerful PEG (Parsing Expression Grammar) library that provides composability and declarative grammars. The 3-layer Parslet architecture (Grammar → Builder → Parser) is not universal: 10 of the 26 files under lib/sirena/parser/builders/ subclass Parslet::Transform, the rest are plain classes or helpers, and User Journey builds its model directly in the parser.

Layout uses a built-in fallback grid (Layout::Grid) by default. Flowcharts can be placed by the elkrb gem instead with layout_engine: :elk. Sirena is a pure Ruby implementation with no JavaScript dependencies, generating standards-compliant SVG 1.2 output suitable for direct integration with Metanorma documentation frameworks.

Sirena processing pipeline
Mermaid Syntax Input (String)
         │
         ▼
    ┌─────────┐
    │ Parser  │  Parslet Grammar → Transform → Parser
    └────┬────┘  (3-layer architecture)
         │
         ▼
   ┌───────────┐
   │ Diagram   │  Lutaml::Model AST
   │   Model   │  (Flowchart, Sequence, etc.)
   └─────┬─────┘
         │
         ▼
   ┌───────────┐
   │Transform  │  Diagram → Graph Conversion
   │  Layer    │
   └─────┬─────┘
         │
         ▼
   ┌───────────┐
   │  Layout   │  Position Computation
   │  Engine   │  (Node positions, edge routes)
   └─────┬─────┘
         │
         ▼
   ┌───────────┐
   │    SVG    │  Graph → SVG Conversion
   │ Renderer  │
   └─────┬─────┘
         │
         ▼
   ┌───────────┐
   │    SVG    │  Lutaml::Model Structure
   │  Builder  │
   └─────┬─────┘
         │
         ▼
  SVG XML Output (String)
Component relationships
Sirena (Root Module)
    │
    ├── Engine (Orchestrator)
    │     ├── coordinates overall flow
    │     ├── delegates to Parser
    │     ├── delegates to Transform
    │     └── delegates to Renderer
    │
    ├── Parser (Parslet-based Syntax Analysis)
    │     ├── Grammars (Parslet rules)
    │     ├── Transforms (tree conversion)
    │     └── produces Diagram Models
    │
    ├── Diagram (Domain Models)
    │     ├── Architecture
    │     ├── Block
    │     ├── C4
    │     ├── ClassDiagram
    │     ├── ErDiagram
    │     ├── Error
    │     ├── Flowchart
    │     ├── Gantt
    │     ├── GitGraph
    │     ├── Info
    │     ├── Kanban
    │     ├── Mindmap
    │     ├── Packet
    │     ├── Pie
    │     ├── Quadrant
    │     ├── Radar
    │     ├── Requirement
    │     ├── Sankey
    │     ├── Sequence
    │     ├── StateDiagram
    │     ├── Timeline
    │     ├── Treemap
    │     ├── UserJourney
    │     └── XyChart
    │
    ├── Transform (Model Conversion)
    │     └── diagram-specific converters
    │
    ├── Renderer (SVG Generation)
    │     └── diagram-specific renderers
    │
    ├── Svg (SVG Models)
    │     ├── Document, Element, Group
    │     ├── Path, Text, Rect
    │     └── Circle, Line, Polygon
    │
    └── DiagramRegistry (Type Registration)
          └── maps types to handlers

Parslet-based parser architecture

All 24 implemented diagram types use Parslet for grammar parsing, but only 10 of the 26 files under lib/sirena/parser/builders/ subclass Parslet::Transform. Where the 3-layer pattern is followed it looks like this:

  1. Layer 1: Grammar (Parslet::Parser) - Defines syntax rules using Parslet DSL, parses text into intermediate tree structures

  2. Layer 2: Builder (Parslet::Transform) - Converts intermediate trees to typed Diagram models using pattern matching

  3. Layer 3: Parser - Orchestrates Grammar and Transform, provides public API

Several types deviate: lib/sirena/parser/builders/architecture.rb and lib/sirena/parser/builders/class_diagram.rb (among other builders under lib/sirena/parser/builders/) are plain Ruby classes rather than Parslet::Transform subclasses, and Sirena::Parser::UserJourney#parse builds its diagram model directly from the parse tree without a separate Transform layer.

This architecture provides:

  • Line and column in parse errors (for example Parse error at line 9, column 8)

  • Composability through shared grammar rules across diagram types

  • Maintainability via declarative, self-documenting syntax rules

  • Typed models (Lutaml::Model) for most diagram types

See ARCHITECTURE.md for detailed architecture documentation.

Test coverage

General

Sirena’s test suite exercises the extracted mermaid-js corpus (spec/mermaid/) across all registered diagram types. The mermaid:validate rake task (tasks/generate_mermaid_fixtures.rake) checks only that Sirena.render runs without raising on each corpus source; it does not compare output against mermaid-cli reference SVGs. Comparison against mermaid-cli-generated reference output is a separate, optional task (rake mermaid:compare, not run in CI or the default suite) — see "Mermaid-js compatibility validation" below.

Mermaid-js compatibility validation

spec/fixtures_mermaid/ contains 847 unique mmdc-generated reference SVGs (each duplicated into a correct/ subdirectory, so a naive file count reads ~1,694); no automated spec currently compares rendered output against them.

Copyright Ribose.

This software is licensed under the BSD-2-Clause license.