ADR-007: Hand-Crafted SVGs over Mermaid for Architecture Diagrams
ADR-007: Hand-Crafted SVGs over Mermaid for Architecture Diagrams
Section titled “ADR-007: Hand-Crafted SVGs over Mermaid for Architecture Diagrams”Status: Accepted Date: 2026-02-14 Author: Spencer Fuller
Context
Section titled “Context”The portfolio site (spencerfuller.dev) runs on Astro Starlight, deployed to Cloudflare Pages. Architecture diagrams are critical — they communicate system design at a glance and are often the first thing a reviewer looks at on a project page.
The initial implementation used Mermaid.js for all diagrams: flowcharts, sequence diagrams, layer stacks. Mermaid is appealing because it’s code-defined (version-controllable, diffable) and renders automatically from text descriptions. Astro has Mermaid integration via astro-mermaid.
The problem became apparent once content was deployed. Mermaid renders diagrams at a fixed internal width that doesn’t respect the page’s content column. On a site with --sl-content-width: 75rem and no right sidebar, diagrams rendered at roughly 40-50% of available width — too small to read without squinting. Specific issues:
- Fixed rendering width. Mermaid’s SVG output uses hardcoded
viewBoxdimensions based on node count and layout algorithm. There’s no straightforward way to say “fill the available width.” The%%{init: {'theme': 'dark', 'themeVariables': {...}}}%%directives control colors, not layout dimensions. - Text truncation in complex diagrams. Architecture diagrams with long labels (service names, descriptions, protocol details) get truncated or wrapped awkwardly. Mermaid’s auto-layout optimizes for compactness, not readability.
- No click-to-zoom. Mermaid renders inline. For dense architecture diagrams, readers need to zoom in on subsections. There’s no built-in interaction — it’s a static inline SVG.
- Dark theme inconsistency. Despite using the
darktheme preset, Mermaid’s colors didn’t match the site’s custom dark palette (Starlight’s slate/blue scheme). Every diagram needed theme variable overrides, and the results still looked like “a different application embedded in the page.” - Layout algorithm fights intent. Mermaid’s Dagre/ELK layout engines decide where nodes go. For architecture diagrams, spatial arrangement carries meaning — infrastructure at the bottom, applications in the middle, agents at the top. Mermaid rearranges to minimize edge crossings, which sometimes puts things in nonsensical positions.
15 diagrams across 9 pages were affected: system architecture overviews, trust layer stacks, communication sequences, tool ecosystems, pipeline flows, and cluster topologies.
Decision
Section titled “Decision”Replace all Mermaid diagrams with hand-crafted SVGs stored in public/diagrams/. Add a CSS + inline JS lightbox for click-to-maximize viewing. Remove the Mermaid rendering dependency.
Each SVG is authored directly (not exported from a GUI tool), using a consistent design language:
- Dark background (
#1e293bbase, matching the site’s slate palette) - Consistent color coding (teal for agents, amber for tools, emerald for infrastructure, rose for security)
- Rounded rectangles with subtle gradients for depth
- Dashed borders for external/optional components
- Arrow markers for data flow direction
viewBox-based scaling that fills available width responsively
Rationale
Section titled “Rationale”-
Full layout control. SVGs give complete control over where every element sits. Spatial arrangement is intentional — infrastructure at the bottom, application layer in the middle, agents at the top. This isn’t decoration; it’s how engineers read architecture diagrams. Mermaid’s auto-layout actively fights this by rearranging elements to minimize edge crossings.
-
Responsive width. SVGs with
viewBoxandwidth="100%"fill whatever container they’re in. On a wide monitor, the diagram stretches to use available space. On mobile, it scales down proportionally. Mermaid’s fixed-width output required CSS hacks that never worked reliably across breakpoints. -
Visual consistency with the site. Hand-crafted SVGs use the exact same color tokens as the site’s CSS custom properties. They look like part of the page, not an embedded third-party widget. The dark theme matches perfectly because it’s the same palette.
-
Click-to-maximize for dense diagrams. The lightbox implementation (pure CSS + minimal inline JS, zero dependencies) lets readers click any diagram to view it full-viewport. For a 15-node architecture diagram, this is the difference between “I can sort of see the boxes” and “I can read every label and trace every connection.” Implementation: CSS overlay with
position: fixed, triggered by click handler, dismissed by clicking the overlay or pressing Escape. -
AI-assisted authoring mitigates effort. The traditional argument against hand-crafted SVGs is that they’re time-intensive to create and maintain. With AI-assisted authoring, the effort equation changes substantially. Describing the desired layout in natural language and iterating on the SVG output is faster than fighting Mermaid’s layout algorithm to produce a specific arrangement. 15 diagrams were created and refined in a single session.
Alternatives Considered
Section titled “Alternatives Considered”| Alternative | Why Not |
|---|---|
| Mermaid with CSS overrides | Attempted first. Applied max-width: 100%, container scaling, font-size bumps. Mermaid’s internal SVG dimensions are set before CSS applies — the SVG viewBox is calculated from content, and CSS scaling introduces blurriness or misaligned text. Spent more time fighting the tool than it would take to just draw the diagrams. |
| Excalidraw / draw.io exports | GUI tools produce SVGs, but they’re bloated (draw.io exports carry XML namespaces, embedded fonts, and style blocks that triple file size) and not easily diffable. Excalidraw’s hand-drawn aesthetic doesn’t match a professional portfolio. Neither integrates with the site’s color system without post-processing. |
| D3.js / Observable | Programmatic SVG generation with full control. Powerful but overkill — these are static architecture diagrams, not interactive data visualizations. Adding a D3 runtime dependency for diagrams that don’t change after deployment adds bundle size and complexity for zero benefit. |
| Image exports (PNG/WebP) | Raster images from any diagramming tool. Lose resolution on zoom, don’t scale responsively, can’t be searched/selected, and file sizes are 5-10x larger than equivalent SVGs. Not acceptable for a technical portfolio where readers expect crisp diagrams at any zoom level. |
| Keep Mermaid for simple diagrams, SVG for complex ones | Considered a hybrid approach. Rejected because visual inconsistency between Mermaid-styled and hand-crafted diagrams is jarring — two different color schemes, two different layout philosophies, two different interaction models on the same site. Consistency matters more than saving effort on simple diagrams. |
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- All 15 diagrams render at full content width, are readable without zooming, and scale responsively across viewport sizes
- Click-to-maximize lightbox works on all diagrams with zero JavaScript dependencies (inline event handlers + CSS)
- Diagrams are visually indistinguishable from the site’s design system — same colors, same rounded-corner aesthetic, same dark theme
- SVG files are version-controlled, diffable, and average 4-8KB each (total: ~90KB for 15 diagrams)
- AI-assisted authoring workflow established: describe layout → generate SVG → iterate on specifics → commit. Reusable for future diagrams
Negative
Section titled “Negative”- Manual maintenance burden. When architecture changes, diagrams must be manually updated. There’s no “regenerate from code” — each SVG must be edited directly. Mitigated by the AI-assisted workflow (describe the change, get an updated SVG) but it’s still more friction than editing a Mermaid code block
- No single source of truth. Mermaid diagrams are derived from a text description — the description is the diagram. SVGs are the final artifact with no generating source. If the intent behind a layout choice isn’t documented elsewhere, it’s lost. Mitigated by keeping SVG markup clean and commented
- Skill requirement for manual edits. Direct SVG editing requires understanding
viewBox, coordinate systems, path syntax, and transform attributes. Not as accessible as editing Mermaid’s human-readable syntax. For this project, the author (AI-assisted) handles all diagram work, so this is a non-issue in practice astro-mermaidstill imported. The Mermaid integration package remains inastro.config.mjsas of this writing — a cleanup candidate now that no diagrams use it. Removing it will reduce build dependencies