- Type
- IBM Plex Serif
- Radius
- 3 px
- Mood
- Editorial
- Open
- 2 briefs
The day of a solo freelance designer.
Tuesday morning, a fintech client — cold navy, sharp serif. By lunch, an indie skincare brand — warm peach, editorial type. Hours inside those brands in Figma. Then the brief manager opens, and it's all the same gray SaaS chrome.
The tools that should help you stay grounded in each client's context strip that context away. The brand work happens in brand-shaped containers; the meta-work (briefs, references, deliverables) happens in a beige room.
"Project tools look the same no matter who you're working for. Brief looks like the brand you're working in." — the premise
The tool can be the context cue.
If the surface itself confirms which client you're working in, the cognitive shift happens at the level of the room you're sitting in — not inside your head.
Theming isn't decoration here. It's load-bearing. It's the product premise. Which means the engineering has to support it from the foundation, not bolt it on as a skin selector.
Three decisions that shaped everything.
Locked before any pixels: who Brief is for, how theming gets created, how big the surface area is. Each pick narrowed the design space.
Solo freelance creative
One operator, multiple clients. Cleanest narrative for the per-client theming premise without org/role/permissions noise diluting it.
Hybrid: presets + AI + manual
AI extraction from a brand asset is the wow moment. Presets give a 10-second path. Manual is the escape hatch. No dead ends.
Six hi-fi surfaces
Enough range to prove theming propagates across different layouts (list, detail, form, board, table, builder). Polish-per-surface that holds up under interview scrutiny.
Drafting Table.
A near-black slate ground with cream foreground and warm sand accents. The chrome is intentionally restrained — not because it's the safe choice, but because it's the right one given the premise.
"The chrome is a gallery wall. Client themes are the prints."
If the chrome is rich, it competes with client identity. If it's dead, the product feels generic. A dark, considered stage lets every client theme — peach, navy, neon green, forest — read as a saturated artifact pinned against a shared backdrop.
One override mechanism, four layers.
Per-client theming is a single CSS attribute scope, not a skin selector. No per-client React components. No switch statements in JSX. Swap the active client and the entire surface re-themes — the foundation does the work.
Primitives
Raw OKLCH ramps (slate 50–950, sand 100–700), type scale, spacing, radii, shadows. Mode-agnostic. Never used directly in components.
Chrome semantic
The Drafting Table layer: --chrome-bg, --chrome-fg, --chrome-surface, --chrome-accent… mode-aware, with light + dark variants.
Client semantic
Defaults aliased to chrome. Override scope is [data-client-theme="dandy"] on any ancestor. Each client provides a complete environment: colors, fonts, radius personality.
Component
Read --client-* tokens by default. Chrome surfaces use --chrome-* directly. Same component renders differently inside [data-client-theme="dandy"] vs [data-client-theme="halo"].
/* L3 — concrete client overrides */ [data-client-theme="dandy"] { --client-bg: oklch(0.985 0.005 250); --client-accent: oklch(0.32 0.130 260); --client-display-font: 'IBM Plex Serif', serif; --client-radius: 3px; } [data-client-theme="sundial"] { --client-bg: oklch(0.965 0.025 60); --client-accent: oklch(0.65 0.150 35); --client-display-font: 'DM Serif Display', serif; --client-radius: 16px; }
Theme switch in 420 ms.
Hit ⌘K, pick a client. Colors morph through CSS transitions over 420 ms ease-out-quint. Content cross-fades on top of that — old fades out at 140 ms with a 3 px lift, new fades in at 220 ms with a 4 px settle. Colors lead, content follows.
The choreography matters because this is the demo. Every other animation in Brief stays restrained (150–250 ms, ease-out, state changes only). The theme transition earns the longer beat because it's the product's premise made visible.
/* The whole transition hookup */ [data-themed] * { transition: background-color 420ms var(--ease-out-quint), color 420ms var(--ease-out-quint), border-color 420ms var(--ease-out-quint), fill 420ms var(--ease-out-quint), stroke 420ms var(--ease-out-quint); }
Four clients, four worlds.
Mock client roster spans warm/cool/bold/earthy — chosen so theme swaps are visually dramatic and the token system has to handle real range, not nudges from a single base.
- Type
- DM Serif Display
- Radius
- 16 px
- Mood
- Sun-warmed
- Open
- 1 brief
- Type
- JetBrains Mono
- Radius
- 0 px
- Mood
- Late-night
- Open
- 3 briefs
- Type
- General Sans
- Radius
- 6 px
- Mood
- Honest
- Open
- 1 brief
Surface inventory.
Every surface lives in one of two registers: chrome (the Drafting Table dark stage) or themed (the active client's world). The tag below each card calls out which.
Workspace home
Client switcher, recent activity, and the live theme demo card that lets the theme switch happen in place.
ChromeClient workspace
The "you've crossed contexts" moment. Briefs in flight, brand environment spec strip, themed hero with accent halo.
ThemedBrief detail
Document-style layout. Objective, audience, deliverables checklist, brand voice tags, milestone timeline, sticky sidebar rail.
ThemedReferences board
Hi-fi composition tiles — type specimens, gradient-mesh scenes, layout sketches, swatches, links. Designerly, not flat colored cards.
ThemedFiles / deliverables
Versioned table with extension-colored icons, status pills, hover affordance. Themed surface treating tabular data with care.
ThemedTheme builder
The hybrid onboarding: upload + AI extract, preset gallery, manual token tuning. Sticky live preview that updates as you adjust.
Chrome → ThemedDesign intent and engineering architecture, written together.
For UX engineering work, three things live or die together: a design premise worth building, a token architecture that supports it, and motion that makes the moment readable.
The "client themes adapt the surface" idea only works if the token system is built to support it from the foundation. The token system only matters if there's a design idea that demands it. The 420 ms theme transition only feels intentional if the rest of the motion stays restrained. None of these can be back-filled.
"Per-client theming is one CSS attribute scope, not a skin selector."