SaaS Starter
Frontend

UseDeploy design system

The aesthetic point of view, where tokens and primitives live, and the rules every page follows.

Last updated May 7, 2026

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

  • Tokensapps/client/app/globals.css. OKLCH variables in :root, mapped into Tailwind via @theme inline { --color-*: var(--*) }.
  • Primitivesapps/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.tsx and exposed as --font-geist-sans / --font-geist-mono for the whole app.
  • Custom utilitiesapps/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-black Vercel-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

  1. Use semantic tokens, never raw colors. The full table is on the tokens page.
  2. Don't re-load Geist per component with next/font/google — the root layout owns it.
  3. Don't inline the UseDeploy wordmark, the grid+glow background, or the version chip. Import from @/components/brand.
  4. Auth pages wrap content in <AuthCard>. The (auth)/layout.tsx owns 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.

On this page