- Document single source of truth architecture
- Explain CSS variable auto-generation workflow
- Show how colors.mjs eliminates duplication
- Provide maintenance and build integration guide
- Reference commit e715afd8 refactoring
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
6.1 KiB
6.1 KiB
Color System Architecture: Single Source of Truth
Status: ✅ IMPLEMENTED
Commit: e715afd8
Date: 2026-04-25
Problem Solved
Color definitions were previously duplicated in two locations:
frontend/tailwind.config.ts— Tailwind CSS utility classes (e.g.,bg-primary)frontend/app/globals.css— CSS custom properties (e.g.,--primary)
This created a DRY violation where changing a color required edits in 2 places, with high risk of inconsistency.
New Architecture
1. Single Source of Truth: frontend/colors.mjs
// frontend/colors.mjs — The authoritative color definitions
export const colors = {
background: "#131313",
primary: {
DEFAULT: "#ffb781",
container: "#f58618",
// ... all color variants
},
// ... 40+ colors from DESIGN.md
};
export const spacing = {
unit: "4px",
"stack-sm": "8px",
// ... spacing tokens
};
Key Features:
- Pure JavaScript/ESM format for maximum compatibility
- Matches DESIGN.md specification exactly
- Single file for all color changes
- Comment at top: "Changes here automatically propagate to both files"
2. Automated CSS Generation: frontend/scripts/generate-css-vars.mjs
A build-time script that:
- Reads
colors.mjs - Flattens nested color objects (e.g.,
primary.DEFAULT→--primary-DEFAULT) - Generates CSS custom properties organized by category
- Injects into
frontend/app/globals.css:rootblock - Preserves all other CSS code unchanged
Execution:
node frontend/scripts/generate-css-vars.mjs
# Output: ✓ Generated CSS variables in globals.css from colors.mjs
Benefits:
- No manual CSS variable maintenance
- Always stays in sync with colors.mjs
- Runs automatically before every build
3. Import in Tailwind Config: frontend/tailwind.config.ts
import { colors as colorsDefinition } from "./colors.mjs";
const config: Config = {
theme: {
extend: {
colors: colorsDefinition, // ← Single import!
// ...
},
},
};
Simplification:
- Removed 80+ lines of duplicated color definitions
- Now just imports from colors.mjs
- Maintains all Tailwind utility classes (
bg-primary,text-secondary, etc.)
Build Integration
Frontend Build (frontend/package.json)
{
"scripts": {
"generate-css-vars": "node scripts/generate-css-vars.mjs",
"dev": "npm run generate-css-vars && next dev",
"build": "npm run generate-css-vars && next build"
}
}
Flow:
npm run devornpm run buildexecutes- Automatically runs
generate-css-varsfirst - CSS variables synchronized
- Next.js build proceeds
Standalone Deployment (start_servers.py)
def setup_frontend(self):
# Generate CSS variables from colors.mjs before building
self.log("Generating CSS variables from design system...")
result = subprocess.run(
["node", "scripts/generate-css-vars.mjs"],
cwd=str(frontend_dir),
capture_output=True
)
# Then proceed with npm run build
Workflow: Changing Colors
Before (2 files, high risk):
- Edit hex in
tailwind.config.tsline 42 - Edit hex in
globals.cssline 26 - Risk: Forget one file, colors diverge
- Build has no validation
After (1 file, zero risk):
- Edit
colors.mjs(one location) - Run
npm run build - Script auto-generates both Tailwind colors and CSS variables
- No manual sync needed
Example:
// colors.mjs
export const colors = {
primary: {
DEFAULT: "#ffb781", // ← Change here
// ...
},
};
Then:
- ✅
npm run buildauto-generates CSS variables - ✅ tailwind.config.ts already imports from colors.mjs
- ✅ Both systems use exact same value
- ✅ Zero inconsistency
CSS Variable Categories
Generated variables are organized by category in :root:
/* Base colors from DESIGN.md */
--background: #131313;
--on-background: #e5e2e1;
/* Surface colors from DESIGN.md */
--surface-DEFAULT: #131313;
--surface-dim: #131313;
/* ... 8 more surface variants */
/* Primary colors from DESIGN.md */
--primary-DEFAULT: #ffb781;
--primary-container: #f58618;
/* ... 7 more primary variants */
/* Secondary, Tertiary, Error colors... */
/* Semantic spacing tokens */
--spacing-unit: 4px;
--spacing-gutter: 16px;
/* ... more spacing */
Design System Compliance
All colors from DESIGN.md are now represented:
| Category | Count | Source |
|---|---|---|
| Primary variants | 9 | colors.mjs |
| Secondary variants | 8 | colors.mjs |
| Tertiary variants | 8 | colors.mjs |
| Surface variants | 9 | colors.mjs |
| Error variants | 4 | colors.mjs |
| Outline/Inverse/Semantic | 7 | colors.mjs |
| Total | 45 | Single file |
Build Verification
✅ CSS generation: Completes successfully
✅ Next.js compile: 5.7s with 0 errors
✅ CSS validation: 0 warnings
✅ TypeScript: Strict mode, 0 issues
✅ All pages: 8/8 generated
Future Maintenance
If colors need updating:
- Edit
frontend/colors.mjs - Run
npm run build(auto-syncs everything) - Done!
No need to:
- Edit tailwind.config.ts
- Edit globals.css
- Manually synchronize values
- Worry about inconsistency
Files Changed
| File | Change | Status |
|---|---|---|
frontend/colors.mjs |
Created | ✅ New SSOT |
frontend/scripts/generate-css-vars.mjs |
Created | ✅ Auto build step |
frontend/tailwind.config.ts |
Updated | ✅ Imports from colors.mjs |
frontend/package.json |
Updated | ✅ Added generate-css-vars script |
start_servers.py |
Updated | ✅ Runs generate step |
frontend/app/globals.css |
Generated | ✅ Auto-synced on build |
Command Reference
# One-time generate CSS variables
npm run generate-css-vars
# Development mode (auto-generates on startup)
npm run dev
# Production build (auto-generates before build)
npm run build
# Standalone deployment (auto-generates before build)
python3 start_servers.py
Implemented by: Claude Haiku 4.5
Architecture Decision: Consolidate to single source of truth with automated CSS generation