# Spike: Mermaid Diagram Style Guide for Blue Documents
| | |
|---|---|
| **Status** | Done |
| **Date** | 2026-01-30 |
| **Time Box** | 30 minutes |
---
## Question
How can we ensure Mermaid diagrams in Blue documents are readable in both light and dark modes, prefer vertical flow, and have consistent styling?
---
## Problem Analysis
From the screenshot, the current diagram has these issues:
1. **Subgraph labels unreadable** — "Superviber Control Plane" and "Client Infrastructure" use dark text on colored backgrounds
2. **Fill colors designed for light mode** — `#e8f5e9`, `#e3f2fd`, `#fff3e0` are light pastels that look washed out in dark mode
3. **Node text invisible** — Dark nodes (`#333`) have no explicit text color
4. **Horizontal sprawl** — Some diagrams use `LR` when `TB` would be more readable
## Mermaid Theme Options
### Option A: Use `dark` Theme
```mermaid
%%{init: {'theme': 'dark'}}%%
flowchart TB
A[Node A] --> B[Node B]
```
**Problem**: Still doesn't control subgraph label colors well.
### Option B: Use `base` Theme with Custom Variables
```mermaid
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#4a5568',
'primaryTextColor': '#fff',
'primaryBorderColor': '#718096',
'lineColor': '#718096',
'secondaryColor': '#2d3748',
'tertiaryColor': '#1a202c'
}
}}%%
```
**Problem**: Verbose, must repeat in every diagram.
### Option C: Use `neutral` Theme (Recommended)
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TB
subgraph SV["Superviber Control Plane"]
ORCH[Orchestration]
BILL[Billing]
end
```
**Benefit**: Works in both light and dark modes. Grayscale palette avoids color contrast issues.
---
## Recommended Style Guide
### 1. Always Use `neutral` Theme
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TB
...
```
### 2. Prefer Top-to-Bottom Flow (`TB`)
```mermaid
flowchart TB ← vertical flow
```
Not:
```mermaid
flowchart LR ← horizontal, requires scrolling
```
### 3. Avoid Custom Fill Colors
**Don't do this:**
```mermaid
style CLIENT fill:#e8f5e9
```
**Do this instead:**
```mermaid
%% Let neutral theme handle colors
%% Use node shapes for visual distinction
```
### 4. Use Subgraph Labels Without Styling
```mermaid
subgraph CLIENT["Client Infrastructure"]
%% No style directive needed
end
```
### 5. Use Shape Variations for Distinction
| Shape | Syntax | Use Case |
|-------|--------|----------|
| Rectangle | `[text]` | Services, components |
| Rounded | `(text)` | User-facing elements |
| Database | `[(text)]` | Data stores |
| Stadium | `([text])` | External systems |
| Hexagon | `{{text}}` | Decision points |
### 6. Keep Edge Labels Short
```mermaid
A -->|"mTLS"| B ← good
A -->|"Mutual TLS encrypted connection over port 443"| B ← too long
```
---
## Example: ADR 0017 Diagram Rewritten
### Before (problematic)
```mermaid
flowchart TB
subgraph CLIENT["Client Infrastructure"]
AGENT["Superviber Agent
(Claude Code)"]
CODE[("Source Code
Credentials
Secrets")]
end
subgraph SV["Superviber Control Plane"]
ORCH["Orchestration"]
BILL["Billing"]
TELEM["Telemetry"]
end
style CLIENT fill:#e8f5e9
style SV fill:#e3f2fd
```
### After (neutral theme, readable)
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TB
subgraph USER["Developer"]
WEB["Web Interface"]
end
subgraph SV["Superviber Control Plane"]
ORCH["Orchestration"]
BILL["Billing"]
TELEM["Telemetry"]
end
subgraph CLIENT["Client Infrastructure"]
AGENT["Superviber Agent"]
CODE[("Source Code
Credentials")]
end
WEB -->|"Session"| ORCH
ORCH -->|"Route"| AGENT
AGENT <-->|"Local"| CODE
AGENT -->|"Metrics"| TELEM
TELEM --> BILL
```
---
## Implementation Options
### Option 1: Style Guide Only (Documentation)
Add to `.blue/docs/style-guide.md`:
- Always use `%%{init: {'theme': 'neutral'}}%%`
- Prefer `flowchart TB`
- Avoid custom `style` directives
**Pros**: Simple, no tooling
**Cons**: Relies on authors remembering
### Option 2: Lint Rule
Add to `blue_lint`:
```rust
// Check for Mermaid blocks missing neutral theme
if mermaid_block && !contains("theme': 'neutral'") {
warn("Mermaid diagram should use neutral theme for dark mode compatibility")
}
```
**Pros**: Automated enforcement
**Cons**: Requires implementation
### Option 3: Pre-render with Consistent Theme
Use `mmdc` CLI to pre-render all Mermaid to SVG/PNG with fixed theme at build time.
**Pros**: Guaranteed consistency
**Cons**: Loses live preview in editors
---
## Decision
**Chosen approach**: Option C (`neutral` theme) + Option 2 (Lint rule)
### Why `neutral` Theme
- Works in both light and dark modes without customization
- Grayscale palette avoids color contrast issues
- No need to repeat verbose `themeVariables` in every diagram
- Subgraph labels are readable by default
### Lint Rule Specification
Add to `blue_lint`:
```rust
/// Checks Mermaid code blocks for neutral theme declaration
fn lint_mermaid_theme(content: &str) -> Vec {
let mut warnings = vec![];
// Find all mermaid code blocks
for (line_num, block) in find_mermaid_blocks(content) {
if !block.contains("'theme': 'neutral'") && !block.contains("\"theme\": \"neutral\"") {
warnings.push(LintWarning {
line: line_num,
message: "Mermaid diagram should use neutral theme: %%{init: {'theme': 'neutral'}}%%".into(),
severity: Severity::Warning,
});
}
}
warnings
}
```
### Implementation Tasks
1. ✅ **Document decision** — This spike
2. ⬜ **Update ADR 0017** — Apply neutral theme to diagram
3. ⬜ **Add lint rule** — Implement in `blue_lint` crate
4. ⬜ **Create style guide** — Add `.blue/docs/mermaid-style-guide.md`
---
## Quick Reference Card
```markdown
## Blue Mermaid Cheatsheet
Always start with:
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TB
```
Shapes:
- [Rectangle] — services
- (Rounded) — user-facing
- [(Database)] — data stores
- {{Hexagon}} — decisions
Don't use:
- style X fill:#color
- flowchart LR (prefer TB)
- Long edge labels
```
---
*Investigation by Blue*