Graphviz Diagram Style Guide

Table of Contents

Design philosophy

Every diagram on wal.sh is a claim about structure. The visual language should make structural relationships legible without decoration. Three principles govern the system:

  1. Color encodes semantics, not decoration. Each of the six color families carries a fixed meaning across all diagrams. Blue is input and primary flow. Green is output and success. Red is error and critical path. When a reader sees a green node on any page, they know it represents an output or success state without checking a legend. This contract holds across 50+ diagrams and must not be broken for aesthetic reasons.
  2. Diagrams carry the color; banners stay quiet. Research page banners are greyscale (728 × 90, leaderboard format). The pastel diagrams are the visual centerpiece of each page. A color banner would compete with the diagram for the reader's attention. Greyscale banners recede; diagrams advance.
  3. The palette is a protocol, not a preference. The Tailwind 100/700 pairs were chosen because they are widely known, machine-readable, and have accessible contrast ratios. Switching to a different palette would require updating every diagram simultaneously. The cost of that coordination is the reason the palette is documented here rather than left implicit.

The six color families

Family Fill (100) Border/Text (700) Cluster BG (50) Semantic role
Blue #dbeafe #1d4ed8 #eff6ff Primary data flow, input, process
Purple #ede9fe #6b21a8 #f5f3ff Abstraction, protocol, API
Green #dcfce7 #15803d #f0fdf4 Output, success, storage
Amber #fef3c7 #b45309 #fffbeb Config, orchestration, external
Yellow #fef9c3 #a16207 #fefce8 Warning, intermediate, cache
Red #fee2e2 #b91c1c #fef2f2 Error, critical path, alert

The 100-weight fills are pastel backgrounds. The 700-weight values serve triple duty: node border, node text, and cluster label. The 50-weight is for cluster backgrounds only — lighter than the node fill so the cluster recedes behind its contents.

Diagram archetypes

The site uses six recurring diagram structures. Each has conventions for layout direction, color assignment, and cluster usage.

Pipeline

Pipelines show data flowing through sequential transformations. They read left to right (rankdir=LR). Color follows the data lifecycle: blue for ingestion, amber for processing, green for output. Intermediate stores (caches, queues) are yellow.

rankdir=LR

[blue: source] → [blue: ingest] → [amber: transform] → [green: output]
                                          ↓
                                   [yellow: cache]

Examples: diagram-rag-pipeline, diagram-ci-cd-pipeline, diagram-2019-ml-pipeline, jq/diagram-pipeline, kubeflow/diagram-pipeline.

Clusters group stages that share a concern (ingestion plane, serving plane). Each cluster border matches the dominant color family of its contents.

Layer stack

Layer stacks show architectural layers from top (user-facing) to bottom (substrate). They read top to bottom (rankdir=TB). Each layer is a cluster with a distinct color family. The top layer is typically blue (closest to the user); lower layers shift through purple, amber, and green.

rankdir=TB

┌─ blue: Model layer ─────────────┐
│  [blue: Opus]  [blue: Haiku]    │
└─────────────────────────────────┘
         ↓
┌─ purple: Capability layer ──────┐
│  [purple: hooks] [purple: MCP]  │
└─────────────────────────────────┘
         ↓
┌─ green: State layer ────────────┐
│  [green: settings] [green: db]  │
└─────────────────────────────────┘

Examples: 2026-q2-claude-code-features/diagram-feature-surface, diagram-tool-systems-layers, diagram-llm-frameworks-taxonomy, 2026-q2-cloudflare-agents/diagram-stack.

The convention: each layer gets its own color family, and the cluster border matches the nodes inside it. Cross-layer edges use the default grey (#888); failure-path edges use red.

Comparison

Comparisons place two or more systems side by side. They use rankdir=TB with clusters arranged horizontally via rank=same or Graphviz's natural layout. Each system gets a distinct color family. The contrast between cluster colors is the primary visual signal.

rankdir=TB

┌─ blue: System A ──┐     ┌─ amber: System B ──┐
│  [blue: node]      │     │  [amber: node]      │
│  [blue: node]      │     │  [amber: node]      │
└────────────────────┘     └─────────────────────┘

Examples: 2026-agent-isolation-freebsd-jails/diagram-isolation-comparison (blue=DIY jails, amber=Cloudflare sandbox), diagram-datalayer-schema-compare (four schema formats, four colors), diagram-eda-vs-actor, 2025-terminal-ai-agents/diagram-comparison.

The rule: never use the same color family for both sides of a comparison. The reader should distinguish the two systems by color alone.

State machine

State machines show transitions between states. They read left to right (rankdir=LR). Each state gets a color that reflects its semantic nature: green for healthy/fresh, amber for degraded/stale, blue for active/processing, purple for fallback, red for terminal/error.

rankdir=LR

[green: fresh] → [amber: stale] → [blue: revalidating] → [green: fresh]
                       ↓                    ↓
                [purple: serve-stale]  [red: evicted]

Example: diagram-cache-states (HTTP cache lifecycle per RFC 9111).

State machines are the only archetype where individual nodes routinely use different color families. The color of each node is its most important visual attribute — it tells the reader whether the state is healthy, degraded, or terminal before they read the label.

Process loop

Process loops show a cyclical workflow with named phases. They read left to right (rankdir=LR) to emphasize the forward flow, with a dashed feedback edge closing the loop. Each phase is a cluster with a distinct color family, typically cycling through blue, purple, amber, green.

rankdir=LR

┌─ blue: Propose ─┐  →  ┌─ purple: Challenge ─┐  →  ┌─ amber: Defend ─┐  →  ┌─ green: Refine ─┐
│  [blue: scan]    │     │  [purple: question]  │     │  [amber: answer] │     │  [green: summary]│
└──────────────────┘     └──────────────────────┘     └─────────────────┘     └─────────────────┘
         ↑                                                                             │
         └─────────────────────── dashed: resubmit ────────────────────────────────────┘

Example: 2026-elenctic-vibe-code-review/diagram-review-loop.

The feedback edge (green → blue) is always dashed and uses the default grey. Exception nodes (e.g., operational override) use red and connect with red dashed edges.

Ecosystem map

Ecosystem maps show the relationships between tools, libraries, or systems in a domain. They use rankdir=TB with clusters grouping related items by category. Color assignment follows function: blue for core implementations, purple for protocols/standards, green for outputs/tooling, amber for configuration/build, yellow for community/ecosystem, red for deprecated or risky components.

rankdir=TB

┌─ blue: Core ────────┐
│  [blue: impl A]      │
│  [blue: impl B]      │
└──────────────────────┘
         ↓
┌─ purple: Protocols ──┐     ┌─ amber: Build ──────┐
│  [purple: spec]       │     │  [amber: toolchain]  │
└───────────────────────┘     └──────────────────────┘

Examples: diagram-scheme-llm-toolkit, 2025-terminal-ai-agents/diagram-ecosystem, diagram-clojure-ecosystem.

Typography

All text uses fontname"Helvetica"=. Three sizes, no exceptions:

Element fontsize
Graph label 11
Node label 10
Edge label 9

Node conventions

Every node uses shape=box with style"rounded,filled"=. The three color attributes are mandatory and must come from the same family:

If a node has fillcolor but is missing color or fontcolor, the diagram is broken. Black text on a pastel background means a missing fontcolor.

Special shapes

  • shape=note: used for annotation nodes (reviewee, reviewer, legend entries). Still uses the palette; still needs all three color attributes.
  • shape=diamond: used for decision points in pipelines. Typically amber (config/decision semantics).
  • shape=plain: used for invisible structural nodes (start/end markers in state machines). No fill, no border.

Cluster conventions

Clusters group related nodes. The default style is border-only — a colored border with a white interior. This keeps the diagram clean: the pastel node fills carry the color, and the cluster border frames them without adding visual weight.

Use style"rounded,filled"= with a 50-weight fillcolor only when the cluster background needs to distinguish a region from the graph background (e.g., layer stacks where the layers must be visually separated, or comparison diagrams where two systems sit side by side and need distinct background tints). Prefer border-only for most diagrams.

Edge conventions

  • Default: color"#888", =fontcolor"#555"=
  • Failure/error paths: color"#b91c1c", =fontcolor"#b91c1c"=
  • Optional/fallback: style=dashed
  • Deprecated/pressure: style=dotted
  • Feedback loops: style=dashed with default grey (the loop is structural, not semantic)

Backgrounds

  • Graph: bgcolor=white (always)
  • Cluster: 50-weight of the cluster's color family
  • Never use #fafafa for clusters; it has no semantic meaning

What to avoid

  • Shorthand hex (#369, #d63): always use full 6-digit hex
  • Named HTML colors (lightblue, yellow): not reproducible across renderers
  • Dark backgrounds with light text: inverts the site's light theme
  • Hard saturated fills: always use the 100-weight pastel
  • Non-Helvetica fonts: the site CSS uses sans-serif
  • Neutral grey clusters (#444 / #fafafa): every cluster should use a color family that matches the semantic role of its contents
  • Missing fontcolor: if you see black text on a pastel node, the fontcolor attribute is missing

Banner conventions

Research page banners are 728 × 90 pixels, greyscale, leaderboard format.

magick input.png -resize 728x90^ -gravity center -extent 728x90 -colorspace Gray output.png

Org reference:

#+ATTR_HTML: :alt Description :class banner-leaderboard :width 728 :height 90
[[file:banner.png]]

Real examples by archetype

Archetype Canonical example Page
Pipeline diagram-rag-pipeline RAG system
Pipeline diagram-observability REPL-driven flight tracking
Layer stack diagram-feature-surface Claude Code features Q2
Layer stack diagram-layers Unix V4
Comparison diagram-isolation-comparison Agent isolation (jails)
State machine diagram-cache-states HTTP cache (RFC 9111)
State machine diagram-order-states TLA+ system design
State machine diagram-process-lifecycle Unix V4
Process loop diagram-review-loop Elenctic vibe code review
Ecosystem map diagram-ecosystem Unix V4 games
Ecosystem map diagram-scheme-llm-toolkit Scheme LLM toolkit

ASCII diagram policy

Any ASCII arrow diagram in a #+begin_example block that represents a data flow, state machine, or architecture should be converted to a graphviz dot diagram for visual consistency. ASCII directory trees (├── .config/) and inline prose arrows (agent loops 200\times \to costs $0.00) stay as text.

Migration status

As of 2026-05-19, all 53+ .dot files follow the canonical palette. The migration from legacy shorthand hex is complete. Twelve mermaid diagrams in agentic-systems-q4-2024 converted to dot. New research pages are audited on arrival. Four research pages that had zero diagrams (TLA+, Unix V4, Unix V4 Games, flight-tracking observability) now have them.

diagram-style-guide.png

Author: Jason Walsh

jwalsh@nexus

Last Updated: 2026-05-19 23:34:09

build: 2026-05-20 03:32 | sha: 12ce5fe