How to Create Dark Mode Variants Using the Diagram-Design Skin System
Create dark mode variants by defining light tokens in style-guide.md and running the skin linter, which automatically applies the inversion rule to generate *-dark.html files.
The 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. 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 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, 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 tool validates your tokens and produces paired HTML outputs.
Regenerate all examples:
python3 scripts/lint-skin.py --all --baseline
Regenerate a single example:
python3 scripts/lint-skin.py skills/diagram-design/assets/example-process.html
The linter performs two critical functions:
- Validation — confirms that tokens follow the skin contract (required fields, valid color formats, accessible contrast ratios)
- Generation — outputs both
example-<type>.htmlandexample-<type>-dark.htmlfor 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:
<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:
<!-- 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 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 |
Single source of truth for all skin tokens |
skills/diagram-design/references/onboarding.md |
Documents the inversion rule transformation |
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. 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 colorscustom-map— uses explicit token mappings defined inskin.config.json
Run python3 scripts/lint-skin.py --help for available options.
Summary
- Edit
style-guide.mdto set light mode tokens—dark mode derives automatically from the inversion rule - Run
lint-skin.pyto validate and regenerate both variants; never hand-edit*-dark.htmlfiles - Embed dark variants using
prefers-color-schememedia 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 or adjust the inversion strategy in 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—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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →