Skip to main content

Software Guidebook: remark-kroki-a11y

This Software Guidebook follows the structure defined by Simon Brown in his book Software Architecture for Developers. It provides a comprehensive overview of the remark-kroki-a11y plugin architecture.

1. Context

The remark-kroki-a11y plugin operates in the intersection of:

  • Static Site Generators (Docusaurus, mdBook, etc.) that use the unified/remark ecosystem
  • Diagram-as-Code tools (Kroki, PlantUML, Mermaid) that render diagrams from text
  • Web Accessibility requirements (WCAG, European Accessibility Act) that mandate alternatives for visual content

System Context: remark-kroki-a11y

PlantUML source for "System Context: remark-kroki-a11y"
@startuml

title System Context: remark-kroki-a11y Plugin

actor "Content Author" as author
actor "Reader" as reader

rectangle "remark-kroki-a11y\n(plugin)" as plugin

rectangle "Static Site Generator\n(Docusaurus, mdBook, Jekyll)" as ssg
rectangle "Kroki Service" as kroki
rectangle "Web Browser" as browser

author --> ssg : writes Markdown with diagrams
ssg --> plugin : processes via remark pipeline
plugin --> kroki : requests diagram images
ssg --> browser : generates HTML site
reader --> browser : views documentation
@enduml

Sequence diagram with 6 participants: Content Author, Reader, ssg, plugin, kroki and browser.

Interactions:

  • Content Author responds to ssg: 'writes Markdown with diagrams'
  • ssg responds to plugin: 'processes via remark pipeline'
  • plugin responds to kroki: 'requests diagram images'
  • ssg responds to browser: 'generates HTML site'
  • Reader responds to browser: 'views documentation'

For detailed context including stakeholders and external systems, see the README.

2. Functional Overview

The plugin provides the following core functionality:

Use Cases

Use Cases: Core Actors

PlantUML source for "Use Cases: Core Actors"
@startuml
left to right direction
skinparam actorStyle awesome

actor "UML Content\nAuthor" as author
actor "Visually impaired\nprogrammer" as reader
actor "Beginner UML\ndiagram reader" as beginner
actor "CI/CD Pipeline" as ci

rectangle "remark-kroki-a11y Plugin" {
usecase "Generate accessible diagram\nwith natural language description" as UC_BASE
}

author --> UC_BASE : writes diagrams for
reader --> UC_BASE : benefits from
beginner --> UC_BASE : benefits from
ci --> UC_BASE : builds documentation with
@enduml

Sequence diagram with 5 participants: UML Content Author, Visually impaired programmer, Beginner UML diagram reader, CI/CD Pipeline and UC_BASE.

Interactions:

  • UML Content Author responds to UC_BASE: 'writes diagrams for'
  • Visually impaired programmer responds to UC_BASE: 'benefits from'
  • Beginner UML diagram reader responds to UC_BASE: 'benefits from'
  • CI/CD Pipeline responds to UC_BASE: 'builds documentation with'

Configuration Options

OptionUse CaseDefault
showSourceDisplay source code tab for all diagramstrue
hideA11yPer-diagram flag to hide the natural language descriptionfalse
localeSet language for generated descriptions ('en' or 'nl')'en'
a11yDescriptionOverridePer-diagram manual description override-
Extended use cases: configuration options

Use Cases: Plugin Configuration Options

PlantUML source for "Use Cases: Plugin Configuration Options"
@startuml
left to right direction
skinparam actorStyle awesome

actor "UML Content\nAuthor" as author

rectangle "remark-kroki-a11y Plugin" {
usecase "Generate accessible diagram\nwith natural language description" as UC_BASE

usecase "Show/hide source code\n(showSource)" as UC_SOURCE
usecase "Hide A11y description\nfor simplicity (hideA11y)" as UC_HIDE_A11Y
usecase "Explicitly choose language if\nscreenreader detection is wrong\n(locale: 'en' | 'nl')" as UC_LANG
usecase "Override A11y description if it\ninterferes with existing text\n(a11yDescriptionOverride)" as UC_OVERRIDE

' Force UC_BASE to appear at the top
UC_BASE -[hidden]down-> UC_SOURCE
UC_SOURCE -[hidden]down-> UC_HIDE_A11Y
UC_HIDE_A11Y -[hidden]down-> UC_LANG
UC_LANG -[hidden]down-> UC_OVERRIDE

UC_SOURCE .> UC_BASE : <<extend>>
UC_HIDE_A11Y .> UC_BASE : <<extend>>
UC_LANG .> UC_BASE : <<extend>>
UC_OVERRIDE .> UC_BASE : <<extend>>
}

author --> UC_BASE : writes diagrams for
author --> UC_SOURCE : shows/hides source code
author --> UC_HIDE_A11Y : hides A11y description\nfor simplicity
author --> UC_LANG : explicitly chooses language
author --> UC_OVERRIDE : overrides A11y description\nwhen it interferes with text

note right of UC_BASE
Base use case: Plugin parses
diagram source and generates
a natural language description
using deterministic parsers.
end note

note right of UC_OVERRIDE
Escape hatch when automatic
generation is not suitable.
See ADR-0000.
end note
@enduml

Sequence diagram with 6 participants: UML Content Author, UC_BASE, UC_SOURCE, UC_HIDE_A11Y, UC_LANG and UC_OVERRIDE.

Interactions:

  • UML Content Author responds to UC_BASE: 'writes diagrams for'
  • UML Content Author responds to UC_SOURCE: 'shows/hides source code'
  • UML Content Author responds to UC_HIDE_A11Y: 'hides A11y description\nfor simplicity'
  • UML Content Author responds to UC_LANG: 'explicitly chooses language'
  • UML Content Author responds to UC_OVERRIDE: 'overrides A11y description\nwhen it interferes with text'

3. Quality Attributes

The key quality attributes for this plugin are:

Accessibility (Primary)

  • All diagrams must have alternative text descriptions
  • Generated descriptions must be screen reader friendly
  • UI components must be keyboard navigable

Determinism

  • Descriptions are generated by parsers, not AI (see ADR-0000)
  • Same input always produces same output
  • No external API calls for description generation

Extensibility

  • New diagram types can be added via new parsers
  • Support for multiple diagram-as-code formats (PlantUML, Mermaid)

Performance

  • No runtime API calls (build-time only)
  • Minimal impact on build performance

4. Constraints

Technical Constraints

  • Must work within the unified/remark ecosystem
  • Must be compatible with Docusaurus (primary target)
  • Browser support limited by native <details> element support

Organizational Constraints

  • Plugin used in educational context
  • Student contributions welcome for new diagram parsers

External Constraints

  • Depends on Kroki service for diagram rendering
  • PlantUML/Mermaid syntax defines what can be parsed

5. Principles

Core Architectural Principles

  1. Deterministic over AI-generated - Descriptions are generated by parsers that understand diagram syntax, not by LLMs (see ADR-0000)

  2. PlantUML as Internal Representation - PlantUML data structures serve as the canonical format, with adapters for other formats (see ADR-0006)

  3. Build-time processing - All work happens during static site generation, not at runtime

  4. Progressive enhancement - Diagrams work without the plugin; plugin adds accessibility layer

Development Principles

  • BDD Testing - Features defined in Gherkin, tested with Cucumber
  • Single Source Documentation - README/CONTRIBUTING maintained in one place (see ADR-0007)
  • Eating our own dog food - This documentation site uses the plugin to render its diagrams

6. Software Architecture

High-Level Architecture

The plugin operates as a remark plugin in the unified.js processing pipeline:

Markdown → remark-kroki-a11y → remark-kroki-plugin → rehype → HTML

Parse diagram source
Generate description
Add tabs/details HTML

Processing Flow

Sequence Diagram: Build-time Flow

PlantUML source for "Sequence Diagram: Build-time Flow"
@startuml
hide footbox
title Build-time Processing Flow

participant "Static Site\nGenerator" as SSG
participant "remark-kroki-a11y\n(this plugin)" as Plugin
participant "Parser\n(class/state/sequence)" as Parser
participant "remark-kroki-plugin" as KrokiPlugin
participant "Kroki Service" as Kroki

SSG -> SSG: Start build
SSG -> SSG: Load Markdown page

loop for each diagram code block
SSG -> Plugin: Process code block

Plugin -> Plugin: Detect diagram type\n(class/state/sequence)
Plugin -> Parser: Parse diagram source
Parser --> Plugin: Parsed structure\n(classes, relations, etc.)

Plugin -> Plugin: Generate natural language\ndescription (NL or EN)
Plugin -> Plugin: Create tabs HTML:\n- Source code tab\n- Description tab

Plugin --> SSG: Modified AST with\ntabs and description

SSG -> KrokiPlugin: Process same code block
KrokiPlugin -> Kroki: Request SVG/PNG
Kroki --> KrokiPlugin: Diagram image
KrokiPlugin --> SSG: Image embedded in AST
end

SSG -> SSG: Generate HTML output
SSG -> SSG: Write to build folder

@enduml

Sequence diagram with 5 participants: Static Site Generator, remark-kroki-a11y (this plugin), Parser (class/state/sequence), remark-kroki-plugin and Kroki Service.

Interactions:

  • Static Site Generator calls Static Site Generator.Start build()
  • Static Site Generator calls Static Site Generator.Load Markdown page()
  • Static Site Generator calls remark-kroki-a11y (this plugin).Process code block()
  • remark-kroki-a11y (this plugin) calls remark-kroki-a11y (this plugin).Detect diagram type\n(class/state/sequence)
  • remark-kroki-a11y (this plugin) calls Parser (class/state/sequence).Parse diagram source()
  • Parser (class/state/sequence) responds to remark-kroki-a11y (this plugin): 'Parsed structure\n(classes, relations, etc.)'
  • remark-kroki-a11y (this plugin) calls remark-kroki-a11y (this plugin).Generate natural language\ndescription (NL or EN)
  • remark-kroki-a11y (this plugin) calls remark-kroki-a11y (this plugin).Create tabs HTML:\n- Source code tab\n- Description tab()
  • remark-kroki-a11y (this plugin) responds to Static Site Generator: 'Modified AST with\ntabs and description'
  • Static Site Generator calls remark-kroki-plugin.Process same code block()
  • remark-kroki-plugin calls Kroki Service.Request SVG/PNG()
  • Kroki Service responds to remark-kroki-plugin: 'Diagram image'
  • remark-kroki-plugin responds to Static Site Generator: 'Image embedded in AST'
  • Static Site Generator calls Static Site Generator.Generate HTML output()
  • Static Site Generator calls Static Site Generator.Write to build folder()

7. Code

Source Code Structure

src/
├── index.js # Main plugin entry point
├── parsers/
│ ├── classDiagramParser.js # PlantUML/Mermaid class diagrams
│ ├── stateDiagramParser.js # PlantUML state diagrams
│ └── sequenceDiagramParser.js # Sequence diagram parsing
├── diagramTabs.js # Client-side tab switching
└── diagram-tabs.css # Styling for tabs UI

Parser Architecture

Each parser:

  1. Receives raw diagram source code
  2. Parses it into a structured representation
  3. Generates natural language description in the requested locale

For implementation details, see the source files on GitHub.

8. Containers

As a remark plugin, remark-kroki-a11y is an npm package that runs within the static site generator's build process. In a local development setup, the Docusaurus dev server runs on the host machine and communicates with a local Kroki service running in Docker containers.

Container Diagram: Local Development Setup

PlantUML source for "Container Diagram: Local Development Setup"
@startuml

title Container Diagram: Local Development Setup

actor "Content Author" as author

rectangle "Host Machine" {
rectangle "Docusaurus Dev Server\n(Node.js)" as docusaurus
rectangle "remark-kroki-a11y\n(npm package)" as plugin
rectangle "remark-kroki-plugin\n(npm package)" as krokiPlugin
}

rectangle "Docker" {
rectangle "Kroki\n(container)" as kroki
rectangle "kroki-mermaid\n(container)" as mermaid
}

rectangle "Web Browser" as browser

author --> docusaurus : writes Markdown files
docusaurus --> plugin : processes Markdown
docusaurus --> krokiPlugin : processes diagram code blocks
krokiPlugin --> kroki : requests diagram images
kroki --> mermaid : delegates Mermaid diagrams
docusaurus --> browser : serves HTML
@enduml

Sequence diagram with 7 participants: Content Author, docusaurus, plugin, krokiPlugin, kroki, mermaid and browser.

Interactions:

  • Content Author responds to docusaurus: 'writes Markdown files'
  • docusaurus responds to plugin: 'processes Markdown'
  • docusaurus responds to krokiPlugin: 'processes diagram code blocks'
  • krokiPlugin responds to kroki: 'requests diagram images'
  • kroki responds to mermaid: 'delegates Mermaid diagrams'
  • docusaurus responds to browser: 'serves HTML'

The plugin interacts with:

  • remark-kroki-plugin (peer dependency) - Handles Kroki API calls for diagram rendering
  • rehype-raw (required) - Enables raw HTML in MDX output
  • Kroki service - Can be local (Docker) or remote (kroki.io)

9. Components

Component Diagram: Current Implementation

PlantUML source for "Component Diagram: Current Implementation"
@startuml

title Component Diagram: remark-kroki-a11y (Current)

rectangle "remark-kroki-a11y Plugin" {
rectangle "index.js\n(main plugin entry)" as index
rectangle "classDiagramParser.js" as classParser
rectangle "stateDiagramParser.js" as stateParser
rectangle "sequenceDiagramParser.js" as seqParser
rectangle "diagramTabs.js" as tabsGen
}

index --> classParser : delegates class diagrams
index --> stateParser : delegates state diagrams
index --> seqParser : delegates sequence diagrams
index --> tabsGen : uses for UI generation
@enduml
State diagram with 5 state(s) and 4 transition(s). States: 1. index 2. classParser 3. stateParser 4. seqParser 5. tabsGen Transitions: 1. index transitions to classParser when "delegates class diagrams" 2. index transitions to stateParser when "delegates state diagrams" 3. index transitions to seqParser when "delegates sequence diagrams" 4. index transitions to tabsGen when "uses for UI generation"

10. Deployment

npm Package

The plugin is published to npm:

npm install remark-kroki-a11y

GitHub Pages

The documentation site is deployed automatically via GitHub Actions on push to main:

  1. Run tests
  2. Build Docusaurus site
  3. Deploy to GitHub Pages

See .github/workflows/ for pipeline configuration.

Local Development

# From repository root
./start-docs.sh

# Or manually
cd test-docusaurus-site
npm install
npm run start:strict # Recommended: validates broken links

11. Views and Perspectives

Diagram Type Support Matrix

Diagram TypePlantUMLMermaidA11y Status
Class diagrams✅ Full⚠️ To testPartial
State diagrams✅ FullPartial
Sequence diagrams⚠️ Beta⚠️ BetaPartial
Activity diagrams⚠️ BetaPartial
C4 diagrams⚠️ BetaN/APartial

Accessibility Compliance

The plugin contributes to WCAG 2.1 compliance:

  • 1.1.1 Non-text Content (A) - Provides text alternatives for diagrams
  • 2.1.1 Keyboard (A) - Tab/details UI is keyboard accessible
  • 4.1.2 Name, Role, Value (A) - Proper ARIA attributes on diagram images

12. Decisions

Architecture decisions are recorded as ADRs (Architecture Decision Records):

ADRTitleStatus
ADR-0000Deterministic Parsing vs Live LLMAccepted
ADR-0001Ondersteuning relatie richtingenAccepted
ADR-0002Plugin architectuurAccepted
ADR-0003Project languageAccepted
ADR-0004Integrated test Docusaurus siteAccepted
ADR-0005Navigeerbare A11y beschrijvingenAccepted
ADR-0006PlantUML als interne standaardAccepted
ADR-0007Single source documentationAccepted
ADR-0012Integrate remark-kroki-pluginAccepted
ADR-0013i18n frameworkAccepted

For the complete list, see the ADR index.


This Software Guidebook follows the structure from Simon Brown's book "Software Architecture for Developers".