# How the Style Guide Theming System Maps Semantic Roles to Colors in Diagram-Design

> Discover how the DiagramDesign style guide maps semantic roles to colors using a central lookup table. Learn how human-readable tokens link to hex values for consistent theming.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: deep-dive
- Published: 2026-09-13

---

**The Diagram-Design style guide theming system maps semantic roles to colors through a centralized lookup table in [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md), where human-readable tokens like `accent` and `ink` are paired with concrete hex values that templates reference at render time.**

The Diagram-Design repository implements a robust theming architecture that separates visual intent from implementation details. This article explores how the style guide theming system translates abstract semantic roles into concrete color values, enabling consistent branding across all diagram outputs. By centralizing every color token in a single source-of-truth file, the system ensures that changing one line instantly re-skins every diagram in a project.

## How Semantic Role Mapping Works

The mapping process begins with [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md), which acts as the central token table. This file contains a markdown table that pairs semantic role names—such as `paper`, `ink`, `muted`, `accent`, `link`, `error`, `warning`, and `success`—with their corresponding hex or RGBA values.

When the rendering engine initializes, it parses this file into a Python dictionary that serves as a lookup table during template processing. Rather than embedding hard-coded hex values in SVG or HTML templates, every visual element references a semantic role name using syntax like `{{accent}}` or `fill="accent"`. At render time, the engine substitutes the concrete color value from the dictionary for each encountered role.

## Core Components of the Theming System

### The Central Token Table

The file [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md) defines the complete color vocabulary for the skill. Each row in the table maps a semantic role to a concrete value, creating a contract between design intent and implementation. The default skin ships with values like atomic-tangerine for accents and blue-slate for muted elements, but these can be overridden without modifying diagram logic.

### Profile-Based Customization

Users can create brand-specific variants through the profile system. The onboarding flow documented in [`skills/diagram-design/references/onboarding.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/onboarding.md) extracts brand palettes and either writes a diff to the central style guide or saves a separate profile to `~/.diagram-design/profiles/<slug>.md`. Projects reference these external profiles via `.diagram-design` marker files, allowing parallel workspaces to maintain different brand skins without altering the installed plugin files.

### Automatic Dark and Light Mode Inversion

The style guide theming system handles theme inversion by monitoring the `paper` color value. When a dark `paper` color is detected, the engine inverts all other roles to preserve contrast ratios, eliminating the need to maintain separate dark-mode color tables.

## Implementation Examples

### Loading the Style Guide Dictionary

The `load_style_guide` function in [`utils/style_guide.py`](https://github.com/cathrynlavery/diagram-design/blob/main/utils/style_guide.py) parses the markdown table into a dictionary:

```python

# utils/style_guide.py

import toml
from pathlib import Path

def load_style_guide(root: Path) -> dict[str, str]:
    """
    Reads ``skills/diagram-design/references/style-guide.md`` and returns a
    mapping of semantic role names to concrete colour strings.
    """
    guide_path = root / "skills" / "diagram-design" / "references" / "style-guide.md"
    # The file uses a simple Markdown table; we parse the lines that look like:

    # | accent | #eb6c36 |

    role_map = {}
    for line in guide_path.read_text().splitlines():
        if line.startswith("|") and "|" in line[1:]:
            parts = [p.strip() for p in line.strip("|").split("|")]
            if len(parts) >= 2 and parts[0] and parts[1]:
                role, colour = parts[0], parts[1]
                # Guard against header rows like "Role | Colour"

                if role.lower() != "role":
                    role_map[role] = colour
    return role_map

```

### Referencing Semantic Roles in Templates

Diagram templates never hard-code colors. Instead, they query the role map, as shown in this simplified bar chart renderer:

```python

# diagrams/bar.py (simplified)

from utils.style_guide import load_style_guide

def render_bar_chart(data, project_root):
    colors = load_style_guide(project_root)

    # “accent” is the focal series colour, “muted” is the non‑focal series

    accent_fill = colors["accent"]
    muted_fill  = colors["muted"]

    svg = f'''
    <svg width="200" height="100">
      <rect x="10"  y="20" width="40" height="60" fill="{accent_fill}" />
      <rect x="60"  y="40" width="40" height="40" fill="{muted_fill}" />
    </svg>
    '''
    return svg

```

### Swapping Themes via the Profile System

The `apply_profile` function in [`utils/profile.py`](https://github.com/cathrynlavery/diagram-design/blob/main/utils/profile.py) enables instant re-skinning by replacing the active style guide:

```python

# utils/profile.py

from pathlib import Path
import shutil

def apply_profile(project_root: Path, profile_slug: str):
    """
    Copies the profile file ``~/.diagram-design/profiles/<slug>.md`` over the
    installed style‑guide, without touching the repo‑controlled copy.
    """
    profile_path = Path.home() / ".diagram-design" / "profiles" / f"{profile_slug}.md"
    target = project_root / "skills" / "diagram-design" / "references" / "style-guide.md"
    shutil.copyfile(profile_path, target)

```

## Validation and Linting

To prevent "magic" colors from leaking into outputs, the [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) script validates that every color used in a diagram originates from a role defined in [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md). This linting step enforces the semantic contract and ensures that all visual tokens remain centrally manageable according to the style guide theming system rules.

## Summary

- The style guide theming system centralizes color definitions in [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md) using semantic roles like `paper`, `ink`, and `accent`.
- Templates reference role names rather than hex values, enabling instant global updates by modifying a single file.
- The profile system supports brand-specific customization through external files stored in `~/.diagram-design/profiles/` and documented in [`skills/diagram-design/references/profiles.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/profiles.md).
- Automatic dark/light inversion detects the `paper` color and adjusts contrast ratios without manual intervention.
- The [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) linter ensures strict adherence to the semantic color palette.

## Frequently Asked Questions

### What file contains the color definitions in Diagram-Design?

All color definitions reside in [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md). This markdown table maps semantic role names to concrete hex or RGBA values, serving as the single source of truth for the entire theming system.

### How do I create a custom brand theme without modifying the default files?

Use the profile system. Run the onboarding flow documented in [`skills/diagram-design/references/onboarding.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/onboarding.md) to generate a brand palette, then save it as a profile to `~/.diagram-design/profiles/<your-brand>.md`. Activate it using the `profile` command documented in [`commands/profile.md`](https://github.com/cathrynlavery/diagram-design/blob/main/commands/profile.md) or by pointing your project to it with a `.diagram-design` marker file.

### Does Diagram-Design support dark mode automatically?

Yes. When the `paper` role is set to a dark color, the system automatically inverts other semantic roles to maintain contrast ratios. This eliminates the need to maintain separate color tables for light and dark themes.

### How does the system prevent hard-coded colors in diagrams?

The [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) linter validates every color value in diagram outputs against the roles defined in [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md). If a color appears that isn't mapped to a semantic role, the linter flags it as an error, enforcing the semantic-to-concrete mapping discipline.