D2 Diagram Styling Reference
Overview
D2 is a declarative diagramming language that compiles to SVG. This runbook covers every styling pattern used in domus-* diagrams.
Build Commands
Single File
# Basic SVG output
d2 diagram.d2 diagram.svg
# With dark theme (200 = dark)
d2 --theme 200 diagram.d2 diagram.svg
# Watch mode (rebuilds on save)
d2 --watch diagram.d2 diagram.svg
# Specify layout engine
d2 --layout elk diagram.d2 diagram.svg
Batch Build (Makefile)
# domus-captures Makefile target
make diagrams-d2
diagrams-d2:
@echo "Building D2 diagrams..."
@find docs/modules/ROOT/images/diagrams -name "*.d2" -exec sh -c \
'd2 --theme 200 "$$1" "$${1%.d2}.svg"' _ {} \;
@echo "Done."
Document Structure
Every D2 file follows this structure:
# =============================================================================
# Title / Description
# =============================================================================
direction: right
title: {
label: "// TITLE::HERE"
near: top-center
shape: text
style: {font-size: 28; bold: true; font-color: "#50fa7b"}
}
terminal: {
label: "> command --flags"
near: top-left
shape: text
style: {font-size: 11; font-color: "#6272a4"}
}
# =============================================================================
# NODES
# =============================================================================
# ... nodes here ...
# =============================================================================
# CONNECTIONS
# =============================================================================
# ... connections here ...
# =============================================================================
# FOOTER
# =============================================================================
footer: {
label: "[ site.domain.dev ]"
near: bottom-center
shape: text
style: {font-size: 11; font-color: "#6272a4"}
}
Animated Connections
The animated: true property creates moving "marching ants" effect - dashes flow along the line direction. Only visible in SVG viewed in browser.
Basic Animation
# Simple animated connection
a -> b: {style: {animated: true}}
# With label
a -> b: "flow" {style: {animated: true}}
Animated + Styled
# Colored animated line
a -> b: "critical" {style: {stroke: "#ff5555"; stroke-width: 3; animated: true}}
# Thicker for emphasis
a -> b: "primary" {style: {stroke: "#50fa7b"; stroke-width: 4; animated: true}}
Animated + Dashed
Combining stroke-dash with animated creates moving dashed lines:
# Static dashed (no movement)
a -> b: {style: {stroke-dash: 4}}
# Animated dashed (moves!)
a -> b: {style: {stroke-dash: 4; animated: true}}
Real Example: Workflow Pipeline
stage0 -> stage1: "capture" {style: {stroke: "#ff5555"; stroke-width: 3; animated: true}}
stage1 -> stage2: "process" {style: {stroke: "#ff79c6"; stroke-width: 3; animated: true}}
stage2 -> stage3: "queue" {style: {stroke: "#bd93f9"; stroke-width: 3; animated: true}}
stage3 -> stage4: "approve" {style: {stroke: "#f1fa8c"; stroke-width: 3; animated: true}}
stage4 -> stage5: "deploy" {style: {stroke: "#50fa7b"; stroke-width: 3; animated: true}}
Visual Priority Hierarchy
Use stroke-width, color, and dash patterns to indicate priority:
| Priority | Width | Style | Code |
|---|---|---|---|
P0 Critical |
4 |
Solid, bright red, animated |
|
P1 High |
3 |
Solid, orange, animated |
|
P2 Normal |
2 |
Solid, purple, animated |
|
Background/Deps |
2 |
Dashed, cyan, animated |
|
Monitoring |
1 |
Dashed, dim |
|
focus -> active: "NOW" {style: {stroke: "#ff5555"; stroke-width: 4; animated: true}}
focus -> done: "DONE" {style: {stroke: "#50fa7b"; stroke-width: 3; animated: true}}
focus -> planned: "NEXT" {style: {stroke: "#bd93f9"; stroke-width: 2; animated: true}}
focus -> infra: "RUNS ON" {style: {stroke: "#f5a623"; stroke-width: 2; stroke-dash: 4; animated: true}}
focus -> growth: "LEARNING" {style: {stroke: "#ff79c6"; stroke-width: 2; stroke-dash: 4; animated: true}}
Stroke Dash Values
| Value | Appearance | Use Case |
|---|---|---|
|
Short, tight dashes |
Draft borders, WIP items |
|
Medium dashes |
Dependencies, background flows |
|
Long, loose dashes |
Optional, future items |
Node Styling
Basic Node
node: "Label Text" {
style: {
fill: "#1e1e2e"
stroke: "#f38ba8"
stroke-width: 2
font-color: "#cdd6f4"
font-size: 14
}
}
Complete Node Style Options
node: {
label: "Multi-line\nLabel"
shape: rectangle
style: {
# Background
fill: "#0d0d0d"
# Border
stroke: "#ff5555"
stroke-width: 3
stroke-dash: 5 # Dashed border (WIP/draft)
# Text
font-color: "#ff5555"
font-size: 14
bold: true
italic: false
# Effects
shadow: true # Drop shadow
opacity: 0.8 # Transparency
border-radius: 8 # Rounded corners
}
}
Draft/WIP Node (Dashed Border)
wip_item: ":draft: true" {
style: {
fill: "#1a1a1a"
stroke: "#f1fa8c"
stroke-dash: 3
font-color: "#f1fa8c"
font-size: 10
}
}
Focus/Highlight Node
focus: {
label: "[FOCUS]\n2026-02-21"
shape: diamond
style: {
fill: "#0d0d0d"
stroke: "#f5a623"
stroke-width: 4
font-color: "#f5a623"
font-size: 14
bold: true
shadow: true
}
}
Shapes
| Shape | Visual | Use Case |
|---|---|---|
|
Standard box (default) |
General nodes, items |
|
Rotated square |
Focus points, decisions |
|
Six-sided |
Services, APIs, active items |
|
Database barrel |
Databases, storage, endpoints |
|
Ellipse |
Start/end points |
|
Perfect circle |
Status indicators |
|
Cloud shape |
External services |
|
Folder/box |
Containers, groups |
|
Label only (no shape) |
Titles, annotations, footers |
start: "Begin" {shape: oval}
decision: "Check?" {shape: diamond}
api: "API Service" {shape: hexagon}
db: "Database" {shape: cylinder}
external: "Cloud" {shape: cloud}
title: "Title Text" {shape: text}
Grid Layouts
Create grid-based layouts inside containers:
container: "[2] CLASSIFY" {
style: {
fill: "#0d0d0d"
stroke: "#bd93f9"
stroke-width: 2
font-color: "#bd93f9"
font-size: 16
bold: true
}
grid-columns: 3
grid-gap: 4
w: "WRK" {style: {fill: "#50fa7b"; font-color: "#0d0d0d"; font-size: 9; bold: true}}
mo: "MON" {style: {fill: "#8be9fd"; font-color: "#0d0d0d"; font-size: 9; bold: true}}
mt: "MTG" {style: {fill: "#ff79c6"; font-color: "#0d0d0d"; font-size: 9; bold: true}}
pl: "PLN" {style: {fill: "#f1fa8c"; font-color: "#0d0d0d"; font-size: 9; bold: true}}
lr: "LRN" {style: {fill: "#ffb86c"; font-color: "#0d0d0d"; font-size: 9; bold: true}}
dc: "DOC" {style: {fill: "#8be9fd"; font-color: "#0d0d0d"; font-size: 9; bold: true}}
}
Grid Options
container: {
grid-columns: 3 # Number of columns
grid-rows: 2 # Number of rows (optional)
grid-gap: 4 # Spacing between items
# Items auto-flow into grid
item1: "A"
item2: "B"
item3: "C"
item4: "D"
item5: "E"
item6: "F"
}
Text Labels & Positioning
Title Positioning
title: {
label: "// DOMUS::CAPTURES"
near: top-center
shape: text
style: {font-size: 28; bold: true; font-color: "#ff79c6"}
}
Position Options
| Position | Location |
|---|---|
|
Top left corner |
|
Top center |
|
Top right corner |
|
Bottom left corner |
|
Bottom center |
|
Bottom right corner |
Terminal-Style Header
terminal: {
label: "> domus-infra --status --date=2026-02-21"
near: top-left
shape: text
style: {font-size: 11; font-color: "#6272a4"}
}
Footer
footer: {
label: "[ captures.domusdigitalis.dev ]"
near: bottom-center
shape: text
style: {font-size: 11; font-color: "#6272a4"}
}
Direction
Controls flow direction of the diagram:
direction: right # Left to right (default, preferred)
direction: down # Top to bottom
direction: up # Bottom to top
direction: left # Right to left
Color Palettes
Dracula Theme (Primary)
| Name | Hex | Use |
|---|---|---|
Background |
|
Node fills |
Red |
|
Critical, P0, errors, active |
Orange |
|
High priority, P1 |
Yellow |
|
Warning, review, pending |
Green |
|
Success, complete, deployed |
Purple |
|
Strategic, P2, classify |
Pink |
|
Learning, drafts, personal |
Cyan |
|
Info, monitoring, docs |
Comment |
|
Dim text, annotations |
Catppuccin Mocha (Alternative)
| Name | Hex |
|---|---|
Base |
|
Surface |
|
Red |
|
Peach |
|
Yellow |
|
Green |
|
Mauve |
|
Pink |
|
Blue |
|
Teal |
|
Text |
|
Subtext |
|
Containers (Grouping)
active: "[ACTIVE] IN PROGRESS" {
style: {
fill: "#0d0d0d"
stroke: "#ff5555"
stroke-width: 3
font-color: "#ff5555"
font-size: 16
bold: true
}
grid-columns: 2
k3s: {
label: "K3s Cluster\n--\nmaster-01\nVault Agent"
shape: hexagon
style: {fill: "#ff5555"; font-color: "#0d0d0d"; font-size: 10; bold: true}
}
vault-ha: {
label: "Vault HA\n--\nPhase 5\n3-Node Raft"
shape: hexagon
style: {fill: "#ff5555"; font-color: "#0d0d0d"; font-size: 10; bold: true}
}
}
Connection Types
Basic Arrow
a -> b # Directed
a -- b # Undirected
a <-> b # Bidirectional
With Labels
a -> b: "label"
a -> b: "label" {style: {stroke: "#ff5555"}}
Connection to Container Items
active.k3s -> infra.storage: "VM" {style: {stroke: "#fab387"; stroke-dash: 4}}
active.vault-ha -> infra.vault: "Raft" {style: {stroke: "#50fa7b"; stroke-dash: 4}}
Complete Dark Theme Template
Copy this as a starting point:
# =============================================================================
# Diagram Name - Dark Theme
# =============================================================================
direction: right
title: {
label: "// TITLE::HERE"
near: top-center
shape: text
style: {font-size: 28; bold: true; font-color: "#50fa7b"}
}
terminal: {
label: "> command --help"
near: top-left
shape: text
style: {font-size: 11; font-color: "#6272a4"}
}
# =============================================================================
# NODES
# =============================================================================
focus: {
label: "[FOCUS]"
shape: diamond
style: {
fill: "#0d0d0d"
stroke: "#f5a623"
stroke-width: 4
font-color: "#f5a623"
font-size: 14
bold: true
shadow: true
}
}
stage1: "[1] INTAKE" {
style: {
fill: "#0d0d0d"
stroke: "#ff5555"
stroke-width: 2
font-color: "#ff5555"
font-size: 14
}
}
stage2: "[2] PROCESS" {
style: {
fill: "#0d0d0d"
stroke: "#bd93f9"
stroke-width: 2
font-color: "#bd93f9"
font-size: 14
}
}
stage3: "[3] COMPLETE" {
shape: cylinder
style: {
fill: "#50fa7b"
stroke: "#0d0d0d"
stroke-width: 2
font-color: "#0d0d0d"
font-size: 14
bold: true
shadow: true
}
}
# =============================================================================
# CONNECTIONS
# =============================================================================
focus -> stage1: "START" {style: {stroke: "#f5a623"; stroke-width: 4; animated: true}}
stage1 -> stage2: "process" {style: {stroke: "#ff5555"; stroke-width: 3; animated: true}}
stage2 -> stage3: "complete" {style: {stroke: "#50fa7b"; stroke-width: 3; animated: true}}
# =============================================================================
# FOOTER
# =============================================================================
footer: {
label: "[ site.domusdigitalis.dev ]"
near: bottom-center
shape: text
style: {font-size: 11; font-color: "#6272a4"}
}
File Organization
docs/modules/ROOT/
+-- images/diagrams/ # PRODUCTION - committed SVGs
| +-- workflow.d2 # Source
| +-- workflow.svg # Generated
+-- examples/diagrams/ # DRAFTS - alternative versions
+-- workflow-v2-radial.d2
+-- workflow-v3-vertical.d2
+-- workflow-v7-dark.d2
SVG Output Notes
|
Animation only works in SVG viewed directly in browser.
|
Troubleshooting
Animation Not Showing
-
Verify viewing SVG in browser (not image viewer)
-
Check
animated: trueis insidestyle: {}block -
PNG exports never animate
# WRONG
a -> b: {animated: true}
# CORRECT
a -> b: {style: {animated: true}}
Colors Not Rendering
Use hex format with quotes:
# WRONG
style: {fill: #ff5555}
style: {fill: red}
# CORRECT
style: {fill: "#ff5555"}
Layout Overlapping
-
Try different
direction:values -
Use containers to group related nodes
-
Switch layout engine:
d2 --layout elk
Font Not Bold
# WRONG (must be inside style)
node: {bold: true}
# CORRECT
node: {style: {bold: true}}
Quick Reference
Animated Line
a -> b: {style: {stroke: "#ff5555"; stroke-width: 3; animated: true}}
Dashed Animated
a -> b: {style: {stroke: "#89b4fa"; stroke-dash: 4; animated: true}}
Draft Node
draft: "WIP" {style: {fill: "#1a1a1a"; stroke: "#f1fa8c"; stroke-dash: 3}}
Grid Container
container: {grid-columns: 3; grid-gap: 4; item1: "A"; item2: "B"; item3: "C"}
Title Text
title: {label: "TITLE"; near: top-center; shape: text; style: {font-size: 24; bold: true}}