# How to Create Dark Mode Variants Using the Diagram-Design Skin System

> Effortlessly create dark mode variants with the diagram-design skin system. Define light tokens and run the linter for automatic dark theme generation. Learn more now.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: how-to-guide
- Published: 2026-08-14

---

**Create dark mode variants by defining light tokens in [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md) and running the skin linter, which automatically applies the inversion rule to generate `*-dark.html` files.**

The [cathrynlavery/diagram-design](https://github.com/cathrynlavery/diagram-design) repository uses a token-based skin system that eliminates manual dark mode editing. This guide explains how to create dark mode variants using the skin system's automatic inversion pipeline.

## How the Skin System Handles Dark Mode

The Diagram-Design skill treats dark mode as a **derived output**, not a parallel design. All visual tokens—colors, typography, and spacing—live in a single file: [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md). When you modify these tokens, the skin system can regenerate both light and dark variants deterministically.

This approach guarantees visual consistency. Every diagram template and example consumes the same token definitions, so a single change propagates everywhere.

## Step 1: Define Light Mode Tokens in style-guide.md

Open [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md) and edit the core color tokens. These define your light (default) skin:

| Token | Purpose | Example Value |
|-------|---------|---------------|
| `paper` | Background color | `rgba(245,245,245,1)` |
| `ink` | Primary text color | `rgba(30,30,30,1)` |
| `accent` | Highlight/branding color | `rgba(0,112,243,1)` |
| `muted` | Secondary text | `rgba(120,120,120,1)` |
| `link` | Interactive elements | `rgba(0,112,243,1)` |

The skin system treats these as your canonical definitions. Dark mode colors are computed from them, never hand-authored.

## Step 2: Apply the Automatic Inversion Rule

The inversion rule, documented in [`skills/diagram-design/references/onboarding.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/onboarding.md), transforms light tokens into dark equivalents:

- **Paper** inverts to **ink** — the background becomes the text color
- **Ink** inverts to **paper** — text becomes the background color
- **Accent**, **muted**, and **link** swap but preserve relative luminance

For example, a light paper value of `rgba(245,245,245,1)` (white-smoke) becomes `rgba(ink-rgb, 1)` in dark mode—using the actual RGB value defined for your `ink` token. This ensures perfect contrast regardless of your custom brand colors.

## Step 3: Regenerate Dark HTML with the Skin Linter

The [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) tool validates your tokens and produces paired HTML outputs.

**Regenerate all examples:**

```bash
python3 scripts/lint-skin.py --all --baseline

```

**Regenerate a single example:**

```bash
python3 scripts/lint-skin.py skills/diagram-design/assets/example-process.html

```

The linter performs two critical functions:

1. **Validation** — confirms that tokens follow the skin contract (required fields, valid color formats, accessible contrast ratios)
2. **Generation** — outputs both `example-<type>.html` and `example-<type>-dark.html` for each diagram type

Dark files are suffixed with `-dark` and placed in `skills/diagram-design/assets/`.

## Step 4: Use Dark Variants in Your Application

Reference the generated dark files directly, or let the browser select based on user preference.

**Embedding with `prefers-color-scheme`:**

```html
<link rel="stylesheet" href="style.css">

<!-- Light variant -->
<link rel="stylesheet" href="skills/diagram-design/assets/example-process.html" media="(prefers-color-scheme: light)">

<!-- Dark variant -->
<link rel="stylesheet" href="skills/diagram-design/assets/example-process-dark.html" media="(prefers-color-scheme: dark)">

```

**Direct linking:**

```html
<!-- Force dark mode regardless of system preference -->
<iframe src="skills/diagram-design/assets/example-process-dark.html"></iframe>

```

Type-specific reference docs like [`skills/diagram-design/references/type-process.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/type-process.md) list the available dark variants for each diagram category.

## Key Files in the Dark Mode Pipeline

| File | Role |
|------|------|
| [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md) | Single source of truth for all skin tokens |
| [`skills/diagram-design/references/onboarding.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/onboarding.md) | Documents the inversion rule transformation |
| [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) | Validates tokens and generates paired light/dark HTML |
| `skills/diagram-design/references/type-<type>.md` | Indexes generated `*-dark.html` files |
| `skills/diagram-design/assets/*-dark.html` | Final dark mode diagram outputs |

## Modifying the Inversion Rule

The inversion logic lives in [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py). While the default behavior swaps paper↔ink and preserves accent, advanced users can pass `--invert-strategy` flags to customize:

- `luminance-preserve` — maintains perceptual brightness (default)
- `hue-rotate` — shifts complementary colors
- `custom-map` — uses explicit token mappings defined in [`skin.config.json`](https://github.com/cathrynlavery/diagram-design/blob/main/skin.config.json)

Run `python3 scripts/lint-skin.py --help` for available options.

## Summary

- **Edit [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md)** to set light mode tokens—dark mode derives automatically from the inversion rule
- **Run [`lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/lint-skin.py)** to validate and regenerate both variants; never hand-edit `*-dark.html` files
- **Embed dark variants** using `prefers-color-scheme` media queries or direct file references
- **Trust the pipeline**: any token change propagates to all diagram types instantly

## Frequently Asked Questions

### Can I override dark mode colors manually without changing light tokens?

No. The skin system enforces derivation from light tokens to guarantee accessibility and consistency. To change dark mode appearance, modify the source tokens in [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md) or adjust the inversion strategy in [`lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/lint-skin.py).

### What happens if my light mode colors fail accessibility contrast checks?

The skin linter fails with a descriptive error before generating any HTML. Fix the contrast ratio in [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md)—the dark variant will inherit the correction automatically.

### Does the skin system support more than two color schemes?

The current implementation generates exactly two variants: light and dark. For additional schemes (sepia, high-contrast), fork [`lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/lint-skin.py) and extend the `--all` flag to accept custom transformation profiles.

### How do I preview dark mode during local development?

Run `python3 scripts/lint-skin.py --watch` to regenerate on file changes, then open `skills/diagram-design/assets/example-<type>-dark.html` directly in your browser or use DevTools to force `prefers-color-scheme: dark`.