Sirena
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 `:metanormaconformance check with zero errors (checked directly againstSvgConform.validate;spec/sirena/svg_conformance_spec.rbruns 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 installOr install it directly:
gem install sirenaRequirements
Ruby 3.2 or higher.
Quick start
Command-line usage
Render a single Mermaid diagram to SVG:
sirena render diagram.mmd -o output.svgCreate 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 typesProgrammatic 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.
Quick links
-
Tool Comparison - Compare Sirena with Mermaid.js, PlantUML, and Graphviz
-
Mermaid.js Compatibility - Detailed syntax compatibility matrix
-
Diagram Types Reference - Complete syntax reference for all 24 diagram types
Documentation Structure
The documentation uses a 6-collection architecture:
-
Core Topics - Compatibility and comparison
-
Tutorials - Step-by-step learning paths
-
Guides - Task-oriented how-to documentation
-
Diagram Types - Complete reference for all 24 diagram types with examples
-
Features - Detailed capability documentation
-
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.
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)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 handlersParslet-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:
-
Layer 1: Grammar (Parslet::Parser) - Defines syntax rules using Parslet DSL, parses text into intermediate tree structures
-
Layer 2: Builder (Parslet::Transform) - Converts intermediate trees to typed Diagram models using pattern matching
-
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 and license
Copyright Ribose.
This software is licensed under the BSD-2-Clause license.