The codebase context for builders
Project structure, token architecture, component anatomy, and a step-by-step guide to adding new components. Hand this file to any builder — human or AI — and they can extend the system without exploring.
What This Is
A React component library + design system + documentation website. It has two interconnected parts:
- Component Library (
/src) — 42+ React components built with Vite + TypeScript. Each component has its own folder with implementation, scoped CSS, and Storybook stories. Components are consumed by the website via the@design-systempath alias. - Documentation Website (
/website) — A separate Next.js app that showcases every component with live, interactive examples. Each component has its own page underwebsite/src/app/components/[component-name]/.
The design spec lives in design.md — read it before touching tokens, colors, or typography.
Quick Start
# Component library dev server
npm run dev # http://localhost:5173
# Storybook (interactive component showcase)
npm run storybook # http://localhost:6006
# Documentation website (separate project)
cd website && npm install && npm run dev # http://localhost:3000
Other useful commands:
npm run build # type-check + build library
npm run lint # ESLint
npm run build-storybook # export static Storybook
Project Structure
/
├── design.md # Design spec — source of truth for tokens, colors, typography
├── src/
│ ├── components/ # 42 component folders (each self-contained)
│ ├── tokens/
│ │ ├── tokens-primitives.css # Raw hex/px values — never use directly in components
│ │ ├── tokens-light.css # Semantic tokens, light theme
│ │ ├── tokens-dark.css # Semantic tokens, dark theme
│ │ └── tokens-typography.css # Font size/weight/line-height scale
│ ├── fonts/ # Nunito Sans + Material Symbols web fonts
│ └── App.tsx # Dev sandbox (generic; components are imported via @design-system)
├── .storybook/ # Storybook config
├── website/ # Next.js docs site (separate npm project)
│ ├── src/app/
│ │ ├── components/ # One folder per component, each with page.tsx + page.module.css
│ │ ├── foundations/ # Design tokens & layout doc pages
│ │ └── about/ # About/work pages
│ └── src/components/ # Shared Next.js UI (Header, Sidebar, Footer, etc.)
└── old-website-reference/ # Archived previous version — do not touch
Token Architecture
Three tiers — never skip a tier:
tokens-primitives.css --primitive-teal-07: #118AB2
↓
tokens-light/dark.css --color-action-primary-bg: var(--primitive-teal-07)
↓
Component CSS background-color: var(--color-action-primary-bg)
- Primitives (
--primitive-*) — raw values. Source of truth. Never referenced in components. - Semantic tokens (
--color-*,--radius-*,--gap-*,--padding-*,--font-*) — always use these in components. - Dark mode is driven by
data-theme="dark"on the root element. Every semantic token has a light and dark value — noprefers-color-schemequeries in components.
Key invariants:
- Teal
--color-action-primary-bg(#118AB2) is only for primary CTA buttons and focus rings. Never decorative. - Never hardcode hex values in component CSS — always a semantic token.
- Buttons are always
--radius-full(pill). Inputs and cards are always--radius-md(12px).
Component Anatomy
Every component lives in its own folder under src/components/:
src/components/Button/
├── Button.tsx # TypeScript implementation + exported interface
├── Button.css # Scoped CSS using semantic token vars
└── Button.stories.ts # Storybook stories (Meta + named Story exports)
Components are imported in the website using the @design-system alias:
import { Button } from '@design-system/components/Button/Button';
CSS class naming: ds-{component} base class, ds-{component}--{modifier} for variants. Example: ds-button, ds-button--primary, ds-button--compact.
How to Add a New Component
- Create the folder:
src/components/MyComponent/ - Write
MyComponent.tsx: Export a named component + a TypeScript interface for props. Use semantic tokens in class names, never inline styles. - Write
MyComponent.css: All CSS vars must be fromtokens-light/dark.css. No hardcoded hex, px values from primitives, or magic numbers. - Write
MyComponent.stories.ts: Export ameta(withtitle: 'Components/MyComponent',tags: ['autodocs']) and at least aDefaultstory plus one per meaningful variant. - Add a website page: Create
website/src/app/components/my-component/page.tsx+page.module.css. Follow the pattern in an existing page (e.g.,website/src/app/components/button/page.tsx). - Register in navigation if needed: check
website/src/config/navigation.ts.
Checklist before shipping a component:
- All colors via semantic tokens
- Dark mode verified (toggle
data-theme="dark"in Storybook) - Disabled state at
opacity: 0.4,cursor: not-allowed - Interactive elements have ARIA roles and keyboard navigation
- At least one Storybook story per variant
- Website showcase page added
Design Principles (distilled from design.md)
- Single typeface: Nunito Sans only. Weight 300 for display/marketing, 600 for in-app headings, 500/400 for body. Inter is an acceptable prototype substitute; avoid Arial/Helvetica.
- White-floor UI: page background is pure white (#FFFFFF light / #050505 dark). Depth comes from the container color ramp (
container-primary→secondary→tertiary) — not shadows. - Teal (#118AB2) is the action color: primary buttons, focus rings, active input borders. Using it decoratively on text or illustrations dilutes its CTA signal.
- Five status variants — no more:
info(blue),positive(green),warning(orange),error(red),neutral(gray). Badge, Alert, Toast, and ProgressBar all share the same--color-status-*token set. - No box shadows on standard containers: the elevation system is color-based. The only shadow in the system is on floating surfaces (popovers, dropdowns):
0 2px 8px rgba(5,5,5,0.08). - Material Symbols Rounded for all icons — 24px default, 20px compact.
- Weight contrast is the heading hierarchy rule:
h2is 30px/300 (light),h3is 22px/600 (bold). Never use the same weight for consecutive heading levels.
Key Files
| File | Purpose |
|---|---|
design.md | Full design spec — colors, typography, spacing, all component rules |
src/tokens/tokens-primitives.css | Raw hex/px values |
src/tokens/tokens-light.css | Semantic token definitions (light) |
src/tokens/tokens-dark.css | Semantic token overrides (dark) |
src/tokens/tokens-typography.css | Font size/weight/line-height scale |
src/components/Button/Button.tsx | Reference implementation for a component |
src/components/Button/Button.stories.ts | Reference for Storybook story structure |
website/src/app/components/button/page.tsx | Reference for a website showcase page |
website/src/config/navigation.ts | Nav links — update when adding pages |
.storybook/main.ts | Storybook config (addons, stories glob) |
Known Gaps (from design.md)
- No
--motion-*token for animation timings — transitions are hardcoded0.2s ease - No
--icon-size-*tokens — icon sizes are hardcoded per component - No
--chart-series-{n}formal token set for ordered chart series colors - No Figma file URL documented yet
- No GitHub Actions CI — no automated lint/test/Storybook build on push