UseDeploy design system
The aesthetic point of view, where tokens and primitives live, and the rules every page follows.
The frontend has one design system — internally referred to as UseDeploy. It's a refined-minimalism palette descended from Vercel's marketing surfaces and the UseDeploy studio aesthetic: pure black base, paper-white foreground, hairline white-on-white borders at low alpha, a violet ambient glow as the only chromatic signature, and emerald reserved for status dots.
It is not a light theme dressed up dark. It is dark-first. The .dark class exists only so the future theme-switcher (#147) can ship without breaking surfaces — both :root and .dark resolve to the same palette today.
Where it lives
- Tokens —
apps/client/app/globals.css. OKLCH variables in:root, mapped into Tailwind via@theme inline { --color-*: var(--*) }. - Primitives —
apps/client/components/brand/.BrandMark,VersionChip,GridGlowBackground,NoiseOverlay,MonoLabel,AuthCard,BrandCard. Re-exported from@/components/brand. - Fonts — Geist Sans + Geist Mono, loaded once in
apps/client/app/layout.tsxand exposed as--font-geist-sans/--font-geist-monofor the whole app. - Custom utilities —
apps/client/app/globals.css@layer utilities.label-mono,shadow-soft,shadow-soft-lg,card-premium,card-lift.
Why it's centralized
Before the migration tracked in Tasky #145–#151, the codebase ran two themes side by side:
- The dashboard used a light "Brubank Ocean" palette.
- Landing and auth used a hand-coded
bg-blackVercel-derived dark theme.
Three duplicated wrapper definitions, three drifting palettes. We had pages whose bg-white card on bg-white card on bg-black hero looked plainly broken because no surface shared tokens.
The fix was the rule that now lives in CLAUDE.md: never declare bg-black / text-white / hardcoded oklch(...) literals in components. Use semantic tokens (bg-background, text-foreground, border-border, bg-card, text-muted-foreground, text-accent) and the brand primitives.
The four rules
- Use semantic tokens, never raw colors. The full table is on the tokens page.
- Don't re-load Geist per component with
next/font/google— the root layout owns it. - Don't inline the UseDeploy wordmark, the grid+glow background, or the version chip. Import from
@/components/brand. - Auth pages wrap content in
<AuthCard>. The(auth)/layout.tsxowns the page chrome; pages own only their form.
Do / don't
// DON'T — hardcoded colors, drifts off the theme.
<div className="bg-black text-white border border-white/10">
// DO — token-driven, dark/light future-proof.
<div className="bg-background text-foreground border border-border">// DON'T — re-rolls the wordmark; will diverge.
<span className="font-semibold tracking-tight">UseDeploy</span>
// DO — imports the canonical primitive.
import { BrandMark } from '@/components/brand';
<BrandMark />See conventions for the full list.