Customisation Guide — UI07 Ember
Marketing kit · Next.js 16 App Router · Tailwind v4 · TypeScript strict · static export. Brand colour: coral / red, OKLCH hue 22°. Dark mode is the default.
Token Architecture
A 3-tier OKLCH colour system lives in src/app/globals.css:
Tier 1: Primitives → Named colour stops: --p-accent-50…950 (coral, hue 22°),
--p-ink-50…950 (warm near-black, hue 7° = accent − 15°)
Tier 2: Semantics → Role tokens: --primary, --bg, --card, --border,
--text-primary, --gradient-hero, --glow-*, --severity-*
Tier 3: Components → Tailwind/shadcn arbitrary props: bg-(--card), text-(--primary), …
To re-brand the colour, change the Tier-1 hue in globals.css and everything CSS cascades automatically. Edit the --p-accent-* ramp hue (and, for a matched warm canvas, the --p-ink-* ramp hue to accent − 15). Tiers 2 and 3 inherit; no per-component edits.
The two colour surfaces that are NOT plain CSS
CSS custom properties can't be read by a WebGL shader, a build-time image, or an SSR crash page. UI07 handles each so a re-hue still reaches them:
| Surface | How it gets the brand colour | On re-hue |
|---|---|---|
Hero FogSphere orb (components/sections/hero.tsx) | useBrandColors() (src/lib/use-brand-colors.ts) reads --primary / --p-accent-300 from the live DOM at runtime and re-reads on theme change | Automatic — follows globals.css, no edit |
OG image (app/opengraph-image.tsx) | Imports BRAND from src/lib/tokens.ts | Edit BRAND in tokens.ts |
Crash page (app/global-error.tsx) | Imports BRAND from src/lib/tokens.ts | Edit BRAND in tokens.ts |
Favicon (app/icon.svg) | Static SVG fill literal | Edit the hex in icon.svg |
WebGL fallback uniforms (ambient-glow.tsx, error.tsx) | RGB-float triplets (error/danger semantics, not the brand accent) | Usually leave — these are status colours |
So a full colour re-brand is: globals.css Tier-1 hue + tokens.ts BRAND hexes + icon.svg. Everything else cascades.
src/lib/tokens.tsis the single source of truth for literal-hex contexts.BRAND.primary.accent,BRAND.surface.*, etc. must stay in sync with the OKLCH primitives — the file documents the sRGB equivalents.
Rebranding Checklist
1. src/config/site.ts — brand metadata (single source of truth)
export const SITE_CONFIG = {
name: "Ember",
tagline: "Build. Ship. Grow.",
url: "https://ember.app",
legal: { /* effective dates, copyright name */ },
nav: [ /* header nav items */ ],
social: { twitter, github, linkedin }, // "/#" sentinels hide the icons
contact: { email, sales, legal, privacy, security },
legalEntity: { companyName, companyNumber, placeOfRegistration, registeredAddress, vatNumber, regulator, regulatorNumber },
regions: { uk, eu, us }, // toggles region-conditional legal links
compliance: { dmca, ccpa, modernSlaveryStatementUrl },
};
Every page reads SITE_CONFIG. The legalEntity defaults are deliberate REPLACE WITH … sentinels (Gate 17 compliance — an unedited build is visibly wrong, not plausibly-real). Fill them with your real registered-entity details before publishing.
2. src/app/globals.css — colour
- Coral hue: change
22→ your hue in the--p-accent-*ramp (lines under "PRIMITIVE: Coral accent ramp"). For a non-warm brand, also set the--p-ink-*ramp hue toyour-hue − 15. - Chroma: the ramp ships at 0.17 (a clean coral). Bump toward 0.20 for more saturation if your hue tolerates it.
- Semantic coral tokens (
--gradient-hero,--glow-*,--heat-*,--gradient-edge) carry the hue inline — they're updated alongside the ramp (search the file for the hue number).
3. src/lib/tokens.ts — literal-hex fallbacks
Update BRAND.primary.accent / .hover / .accentRgb / .glow / .muted and BRAND.surface.* to the sRGB equivalents of your new OKLCH values (convert at oklch.com or via the canvas trick useBrandColors uses). Feeds the OG image, crash page, and any WebGL default.
4. src/app/icon.svg — favicon
Static SVG. Update the <rect fill="…"> to your brand hex.
5. Fonts — src/app/layout.tsx + globals.css
The kit loads two fonts in layout.tsx:
- Sans / body:
Geistvianext/font/google→--font-geist-sans→--font-sans - Display / headings:
Cabinet Grotesk(Fontshare) self-hosted vianext/font/localfromsrc/app/fonts/CabinetGrotesk-Variable.woff2→--font-cabinet→--font-display. It's a variable font (weight 100–900) and is bundled locally, so the build has no font CDN dependency. Licence:src/app/fonts/CabinetGrotesk-LICENSE.txt(free for commercial use).
To change the display font: drop your woff2 in src/app/fonts/, update the localFont({ src }) path in layout.tsx, and keep the --font-cabinet variable (or rename it and update --font-display in globals.css). Headings use font-display; body uses the default sans.
6. public/ + OG image
- Favicon is
src/app/icon.svg(above). Replacepublic/brand assets (logos) as needed. - The social share image is generated at build time by
src/app/opengraph-image.tsx(readsSITE_CONFIG+BRAND) — no staticog-image.pngto replace; restyle the component if desired.
7. Demo content
Every page with sample content carries a /* DEMO_CONTENT */ header. See DEMO_CONTENT.md for the full replacement inventory.
Kit-specific surfaces
- Hero orb (
components/sections/hero.tsx→fog-sphere.tsx): a ray-marched coral fog-orb. Colour auto-tracks--primaryviauseBrandColors(). Tune size/motion through the<FogSphere>props (sphereRadius, brightness, turbulence*, opacity). A theme-aware contrast scrim sits between the orb and the hero text. - Audience cluster map (
components/ui/audience-cluster-map.tsx): the signature visualisation. Cluster tones readvar(--p-accent-500)/--p-status-bounced/--p-cluster-dormant— re-hues with the brand.
Dark / Light Mode
Dark is the default (className="… dark" on <html> in layout.tsx). Light mode applies via the .light class (theme toggle). All tokens have light-mode values under the @variant dark / light blocks in globals.css; the scrim and orb are theme-aware. Test both.
Adding New Pages
- Create
src/app/your-page/page.tsx. - Import
Navbar/Footerfrom@/components/layout/. - Use semantic tokens only —
text-(--fg),bg-(--card),text-(--primary),border-(--border),--severity-*for status. Never hardcode hex or Tailwind named colours (bg-violet-500, etc.) — they won't follow a re-hue. - Use
font-displayfor headings,animate-enterfor entrance.
Template Empire — Halbon Labs — UI07 Ember