Skip to content
brand guide · v4 forge · agent-readable

Tokens, components, rules.

Machine-readable reference for reconstructing the v4 design system. Source of truth: src/styles/v4.css. Every row exposes data-token, data-value, and data-usage for scraping.

00

Principles

#principles
  1. 01Dark, warm, metallic. Never cool blue. Never pure black (#000) or pure white (#fff) — always the warm tokens.
  2. 02Type does the heavy lifting. Decoration earns its place by reinforcing hierarchy, never by filling space.
  3. 03Motion is ambient by default and reactive on intent. Nothing animates just to prove it can.
  4. 04Brutalist geometry: zero radius, hairline borders, generous whitespace.
  5. 05Every interactive element has a defined hover, focus, and reduced-motion fallback.
  6. 06Mono for telemetry, display for impact, sans for reading, serif only for narrative.
01

Color tokens

#color
--v4-bg
hsl(24 18% 11%)
--v4-bg-2
hsl(24 16% 14%)
--v4-fg
hsl(36 35% 94%)
--v4-fg-dim
hsl(32 14% 66%)
--v4-rule
hsl(28 14% 22%)
--v4-accent
hsl(18 88% 60%)
--v4-accent-2
hsl(38 85% 62%)
--v4-accent-deep
hsl(14 70% 42%)
tokenhsl tripletusage
--v4-bg24 18% 11%Page background. Default surface behind everything.
--v4-bg-224 16% 14%Raised surface. Cards, panels, anything that should sit above bg.
--v4-fg36 35% 94%Primary text and high-emphasis UI on bg/bg-2.
--v4-fg-dim32 14% 66%Secondary text, captions, metadata, muted labels.
--v4-rule28 14% 22%Hairline borders, dividers, card outlines.
--v4-accent18 88% 60%Primary signal color. Hover, focus, key CTAs, links igniting.
--v4-accent-238 85% 62%Secondary status / warm amber. Tickers, pulse dots, CTA fill.
--v4-accent-deep14 70% 42%Deep ember. Gradient anchor only. Never a fill on its own.

Wrap every value in hsl(var(--token)). Never hardcode hex. For alpha use hsl(var(--v4-accent) / 0.55).

02

Typography stacks

#typography
tokenfont-family stackusage
font-family / display"Space Grotesk", "Inter", system-ui, sans-serifHeadings, hero word, large display. Tight letter-spacing (-0.04em), line-height 0.9.
font-family / body"Inter", system-ui, sans-serifAll running UI text and paragraphs. Feature settings: ss01, ss02, cv11.
font-family / mono"JetBrains Mono", ui-monospace, monospaceCode, metrics, labels, role tags, anything that should read as system telemetry.
font-family / prose"Fraunces", "Iowan Old Style", Georgia, serifNarrative sections only (.v4-prose). Never UI chrome.
03

Type scale

#scale
tokensize / line / trackingusage
display-xlclamp(64px, 12vw, 200px) / 0.85Hero word. One per page max.
display-lclamp(40px, 6vw, 84px) / 0.9Section openers.
h148px / 0.95 / -0.03emPage titles.
h232px / 1.0 / -0.02emSubsection.
body16px / 1.55Default paragraph.
small13px / 1.45Captions, footnotes.
mono-tag11px / 1.0 / 0.04em uppercaseRole tags, status labels, ticker items.
04

Spacing & geometry

#spacing
tokenvalueusage
radius0Brutalist baseline. No rounded corners on primary surfaces. Pills (999px) only for status dots.
border-width1px hairlineAll structural borders. Never thicker than 1px on cards.
grid-dot24px x 24px.v4-grid background. Do not change pitch.
card-padding24px (mobile) / 32px (md+)Inner padding for .v4-card.
section-gap96px–160px verticalBetween top-level sections. Generous, not cramped.
05

Motion tokens

#motion
tokenvalueusage
duration / micro150–250msHover color shifts, link underline retract.
duration / standard350–550msCard lift, CTA fill slide, ghost button ignite.
duration / ambient14s–22sAurora drift, scanline sweep, marquee tape. Background only.
ease / uicubic-bezier(.2,.8,.2,1)All interactive lifts and translations.
ease / wipecubic-bezier(.7,0,.2,1)Underline wipes, CTA fill reveals.
cursorcustom 18px dot, mix-blend-mode: differenceHide native cursor on fine pointers (.v4-root { cursor: none }). Restore on coarse pointers via @media (hover: none).
reduced-motion@media (prefers-reduced-motion: reduce)Disable .v4-aurora, .v4-scan, .v4-tape, .v4-pulse, .v4-noise drift, all .v4-card transitions.
06

Components

#components

Card

.v4-card

Linear gradient bg-2 → bg, 1px rule border, cursor-tracked radial spotlight via --mx/--my CSS vars set in JS on mousemove.

  • DO lift -6px on hover and warm border to accent at 55% alpha.
  • DO update --mx and --my from pointer events for the spotlight.
  • DON'T apply border-radius. DON'T stack box-shadows beyond the defined elevation.

Primary CTA

.v4-cta

Bordered block with ::before fill that translates from translateY(101%) → 0 on hover. Arrow child .v4-cta-arrow translates +4px,-1px.

  • DO keep text color stable; let the slide fill provide contrast.
  • DON'T animate background-color directly — use the ::before transform.

Ghost button

.v4-ghost

Transparent fill, fg-dim border. Border ignites to fg + 4% fg fill on hover.

  • DO use as the secondary action next to a .v4-cta. DON'T pair two ghosts side by side.

Kinetic link

.v4-link

Inline element with ::after underline that scaleX from right→left on enter, retracts left→right on leave.

  • DO use for any inline navigation or external link. DON'T add it to button-shaped elements.

Outline display

.v4-outline

1px text-stroke in fg, transparent fill. Fills to accent on hover over 350ms.

  • DO use for large list items and section indices. DON'T use below 32px — stroke breaks down.

Marquee tape

.v4-tape / .v4-tape-wrap

Duplicated content track, 38s linear translateX -50%. Pauses on wrapper hover.

  • DO duplicate content exactly twice for seamless loop. DON'T speed up below 25s — reads as nervous.

Pulse dot

.v4-pulse

999px dot, accent-2, breathing scale + expanding box-shadow ring at 1.8s.

  • DO use as live/status indicator only. DON'T use more than one per visible viewport.

Cursor

.v4-cursor

Fixed 18px circle, mix-blend-mode: difference. States: default / .is-hover (56px accent-2) / .is-text (4×28 bar).

  • DO hide on coarse pointers. DO update transform via rAF, not React state, for snappiness.
  • DON'T apply transitions to transform — only width/height/background/border-radius.

Aurora + scan

.v4-aurora / .v4-scan

Fixed full-viewport layers behind content. Aurora: 3 radial gradients, 22s drift. Scan: 18vh band, 14s linear sweep.

  • DO mount once at the layout root. DON'T nest inside scrolling containers.

SystemCanvas (multi-agent swarm)

<SystemCanvas />

Canvas background simulating 26–44 agents (viewport-scaled) with task rings, progress arcs, and message lines. Whisper-intensity defaults: ring alpha 0.32, arc 0.85, message 0.6, label 0.42.

  • DO mount as the hero background only.
  • DO reduce agent count to ~16 if FPS drops below 50 on integrated GPUs.
  • DON'T render above interactive content.
07

Anti-patterns

#anti-patterns
  • Rounded corners on cards, buttons, or inputs.
  • Pure black (#000) or pure white (#fff) anywhere.
  • Cool blue accents. The system is warm ember/amber only.
  • Drop shadows for elevation. Use border + spotlight instead.
  • Animating opacity/transform on every element 'because framer-motion'. Reserve motion for hero, reveals, and intentional micro-interactions.
  • Centered body paragraphs. Left-align all reading text.
  • Multiple .v4-pulse dots in one viewport.
  • Replacing the custom cursor with a CSS-only hover ring — it loses the difference blend.
08

Porting to Next.js 16.2

#porting
Routes

react-router-dom → app/ directory. /v4 → app/v4/page.tsx. /work → app/work/page.tsx. /work/:slug → app/work/[slug]/page.tsx with generateStaticParams over v4-projects.

Client boundaries

Cursor, SystemCanvas, framer-motion components must be marked 'use client'. Dynamic-import with ssr:false where window/document is read at module scope.

Fonts

Replace any <link> tags with next/font/google for Space Grotesk, Inter, JetBrains Mono, Fraunces. Bind to CSS variables --font-display, --font-body, --font-mono, --font-prose in the root layout.

Metadata

Delete <V4SEO>. Use export const metadata per page. Move OG/canonical to per-route metadata objects.

Styles

Copy src/index.css, src/styles/v4.css verbatim into app/globals.css and styles/v4.css. Tokens map 1:1. Tailwind v3 config ports unchanged; Tailwind v4 requires moving theme into @theme CSS.

Cursor restoration

html { cursor: none } must only apply on (hover: hover) and (pointer: fine). Restore via media query for touch.

Reduced motion

Honor prefers-reduced-motion in every animated component. Aurora, scan, marquee, and pulse must disable, not slow.

Data

src/data/v4-projects.ts is framework-agnostic. Move to lib/v4-projects.ts. Use generateStaticParams in [slug]/page.tsx.