Controlling Branding Consistency Across Projects — And How We Document Our Product Spec
Controlling Branding Consistency Across Projects
Every growing project hits the same wall: your brand colors appear in six different files, your logo path is hardcoded in twelve scripts, and someone just shipped a video with #00D5FF instead of #00D4FF. Nobody notices until it's everywhere.
We hit that wall. Here's how we fixed it.
The Problem: Brand Drift Is Silent
When you build across multiple surfaces — a dashboard, video content, blog posts, social cards, documentation — brand elements naturally scatter. A color hex lives in your CSS variables, your Python render scripts, your Remotion compositions, and your Figma tokens. Change one, miss three.
The symptoms are subtle:
- A video uses a slightly off-brand gradient
- Blog header cards reference a deprecated logo variant
- A new content series invents its own style guide instead of inheriting the parent brand
- Two teams define "primary accent" differently
This isn't a design problem. It's an architecture problem.
Our Solution: .ELEMENT as Brand Central
We created a dedicated directory — .ELEMENT — that serves as the canonical governance root for everything brand-related. Not buried in a config folder. Not scattered across services. One place.
.ELEMENT/
├── BRAND_CENTER.yaml # Master registry: families, assets, resolution rules
├── DESIGN.md # Content design tokens (colors, typography, components)
├── STYLE_GUIDE.md # Voice, tone, narrative principles
├── episodes/ # Per-episode overrides
└── templates/
├── brand_elements.yaml # Asset pack definitions
└── series_manifest.template.yaml # Template for new content programs
BRAND_CENTER.yaml — The Single Source of Truth
This file defines everything:
- Brand families with inheritance:
element_of_creationinherits fromaitherium, which means it gets the full color palette, typography, and asset pack without redeclaring them - Asset resolution order: series override → brand family default → shared template → physical file fallback
- Anti-patterns: explicitly listed, so anyone editing knows what not to do (no duplicating tokens, no hardcoded paths, no per-series style guides without justification)
The key insight: brand families inherit like classes. When we launch a new content program, it starts with the full parent brand and only overrides what's genuinely different.
DESIGN.md — Design Tokens for Content
We maintain two separate design specifications:
| Spec | Governs | Location |
|---|---|---|
| AitherVeil DESIGN.md | Product UI — dashboard, controls, data surfaces | AitherOS/apps/AitherVeil/DESIGN.md |
| .ELEMENT DESIGN.md | Brand content — videos, docs, marketing, educational media | .ELEMENT/DESIGN.md |
This separation is deliberate. Product UI tokens change with feature releases. Brand tokens change with strategic decisions. Different cadences, different owners, different approval processes.
The content DESIGN.md uses a structured format with YAML front matter defining every token:
colors:
void: "#0A0E17"
aitherium: "#00D4FF"
forge: "#FF6B35"
creation: "#00FF88"
cosmos: "#8B5CF6"
Any render pipeline — video, blog card, social template — pulls from this single definition.
Runtime: Logical Asset Keys, Not File Paths
Documentation alone doesn't prevent drift. Code has to enforce it.
We built a brand asset resolver that sits between content pipelines and actual assets. Instead of:
# ❌ Hardcoded — breaks when assets move, duplicates knowledge
background = "aitherium-brandkit/backgrounds/forge-door.png"
Pipelines use logical keys:
# ✅ Resolved through BRAND_CENTER.yaml
background = resolve_asset_reference("use:brand_elements.forge.door")
The resolver:
- Reads
BRAND_CENTER.yamlfor resolution rules - Walks the brand family inheritance chain
- Returns either a resolved file path or a generation prompt
- Falls through gracefully — if the logical key doesn't exist, the raw value passes through as a prompt for image generation
This means a video production pipeline can mix logical references and freeform prompts in the same scene definition, and the resolver handles both.
Documenting the Product Spec: .AITHEROS
Brand consistency is one piece. The larger challenge is documenting how the whole system works — and keeping that documentation alive.
We use a .AITHEROS directory as our architecture documentation root. It's a numbered series of strategy documents:
.AITHEROS/
├── 00-INDEX.md # Table of contents
├── 01-STRATEGY.md # Platform vision
├── 02-ARCHITECTURE.md # System architecture
├── ...
├── 22-BRAND-CENTRAL-AND-CONTENT-SYSTEM.md
└── 23-MEMORY-GRADUATION-AND-HOOK-AUTOMATION.md
Each document follows a consistent pattern:
- What problem it solves (not what it does — why it exists)
- The architectural decision with tradeoffs acknowledged
- Source-of-truth pointers — which files are canonical
- Anti-patterns — what to avoid and why
- Migration path — how to get from current state to target state
Why This Works Better Than a Wiki
Wikis rot. They're disconnected from the codebase, so they drift out of sync within weeks.
.AITHEROS lives in the repo. Every pull request that changes architecture can update the relevant doc in the same commit. Code review catches documentation drift at the same time it catches code issues.
The numbered format also creates a natural reading order for onboarding — start at 00-INDEX.md, read what's relevant, skip what's not.
The Gap Analysis: Where We Are Today
Being honest about what's working and what isn't:
| Area | Status | Notes |
|---|---|---|
| Brand governance docs | ✅ Complete | BRAND_CENTER.yaml + DESIGN.md + .AITHEROS/22 |
| Asset resolution order | ✅ Defined | 4-level fallback chain with inheritance |
| Runtime resolver | ⚠️ Partial | Built and tested, but only used in video production |
| Blog/social pipelines | ❌ Not wired | Still use direct values, not logical keys |
| Remotion compositions | ❌ Not wired | Templates exist but don't call the resolver |
| Architecture docs | ✅ 24 chapters | Numbered, indexed, in-repo |
| Hardcoded brand values in code | ✅ Clean | No stray hex codes or paths in Python services |
The honest summary: the infrastructure is built, the documentation is comprehensive, but adoption across all pipelines is still in progress. The video pipeline uses the resolver. Blog generation, social cards, and Remotion templates don't yet.
This is the natural order — build the foundation, prove it works, then migrate consumers. Forcing every pipeline to adopt simultaneously would be a coordination nightmare.
Practical Takeaways
If you're managing brand consistency across a growing project:
-
Create a single canonical directory for brand governance. Not a folder inside your app. A top-level concern.
-
Define inheritance, not duplication. New content programs should inherit from a parent brand family and only override what's different.
-
Separate product UI tokens from brand content tokens. They change at different speeds for different reasons.
-
Build a resolver, not a style guide. Style guides are read by humans and ignored by code. A resolver is used by code and enforced automatically.
-
Document anti-patterns explicitly. Telling people what not to do is more useful than telling them what to do. "No hardcoded color values in render scripts" is clearer than "use the design system."
-
Keep architecture docs in the repo. Same commit, same review, same history. Wikis are where documentation goes to die.
-
Be honest about adoption gaps. A perfectly documented system that only one pipeline uses is better than no system — but only if you acknowledge the gap and have a plan to close it.
What's Next
The immediate path is wiring the brand resolver into our remaining content pipelines — blog card generation, Remotion video compositions, and social media templates. Each integration is small (a few lines to import and call the resolver), but the cumulative effect is that every content surface becomes brand-aware by default.
The larger ambition: when someone adds a new content series, they fill out a series_manifest.yaml from our template, declare which brand family they inherit from, and every pipeline automatically renders with the correct colors, typography, and asset references. Zero manual coordination.
That's the difference between "we have a brand guide" and "our brand is enforced by architecture."
This post is part of our engineering transparency series. We document how Aitherium is built — including the gaps — because building in public means showing the scaffolding, not just the facade.