Dual-Domain Identity System
One codebase, two completely different brand identities — served at runtime by domain, with zero build-time duplication.
They couldn't share a palette.
Problem
FORMÆTRIX (a literary studio) and ryanpyles.com (a personal archive) needed to coexist in a single Next.js repository without bleeding into each other visually, semantically, or structurally.
Maintaining two separate repositories for what was essentially one interconnected system would have meant duplicating layout infrastructure, navigation logic, SEO primitives, and the entire design token architecture — then keeping them synchronized indefinitely.
The real constraint was that the two identities are aesthetically opposite: one is a dark, high-contrast studio brand with orange accents; the other is a manuscript-paper archive with terracotta and brass.
Approach
The solution was domain-scoped CSS custom property remapping layered over a shared token system. Every shared component reads color through semantic names (--color-black, --color-white, --color-accent) — and a single [data-domain] attribute on the root layout element redefines what those names resolve to per domain.
- Middleware domain detection:edge-level request inspection reads the Host header and sets a response header, which the root layout uses to select the domain branch. No client-side JS, no cookie dependency.
- CSS custom property inversion:under [data-domain='ryan'], --color-black becomes the paper background (#F5F1EA) and --color-white becomes the ink foreground (#1A1A1A). The semantic names invert in meaning but every downstream component still just reads var(--color-white) for foreground text — no per-component changes needed.
- Route isolation:formaetrix pages live under /formaetrix/* with their own layout. Ryan pages are root-level. Both share the same SiteLayout component, Navigation, Footer, Section, and ProjectCard — differentiated entirely by the data-domain cascade.
- Content separation:ryanBooks and formaetrixBooks are typed and colocated in content/books/ but exported separately. No cross-contamination at the data layer.
Demo
The same Navigation and Section components rendered under each domain's CSS scope. Toggle to see the token inversion in effect.
Technical Detail
CSS custom property inheritance respects the DOM tree — [data-domain='ryan'] on the <html> element means every descendant's var(--color-black) resolves to #F5F1EA, even inside a shared component that was written for the formaetrix dark register.
The only place domain logic appears in component code is in components that need domain-exclusive behavior (like BlobNav, which only renders on formaetrix).
The performance profile is clean: no client-side domain detection, no hydration mismatch risk, no extra CSS bundles. Both domains share the same stylesheet and same JS bundle.
Zero conditional rendering in shared components. They simply inherit the correct values.
Outcome
A single deployable unit serving two distinct brand identities. Adding a third domain (hypothetically) would require one new [data-domain] block in globals.css and a middleware Host match — no new components, no new routes, no new build configuration.
- 0shared components duplicated
- 1stylesheet and one JS bundle, for both domains
- 2independent visual identities from one token system
- Edge-level domain detection with no client JS