tpmjs/DESIGN_SYSTEM.md
Ajax Davis 23d5159b28 refactor: replace raw HTML elements with design system components
- Replace <select>, <input>, <label>, <textarea> with UI components
- Update various dashboard and docs pages
- Simplify unsandbox package.json
- Add DESIGN_SYSTEM.md documentation
- Add Claude skills configuration
2026-01-16 16:52:44 +10:00

14 KiB

TPMJS Design System Specification

A technical, precise design system inspired by turbopuffer.com - warm, monospace-driven, with generous whitespace and fieldset-style containers.


Brand Direction

Mood & Personality

  • Technical & Precise - Engineering-focused, trustworthy, developer-first
  • Warm & Distinctive - Not cold/corporate, the copper accent adds warmth
  • Confident & Minimal - Let the content speak, reduce visual noise

Reference Sites

  • turbopuffer.com - Primary inspiration
  • Linear, Vercel - Secondary references for technical clarity

Color Palette

Primary Accent

--color-accent: #A6592D;           /* Copper/terracotta - primary brand color */
--color-accent-hover: #8B4A26;     /* Darker copper for hover states */
--color-accent-light: #D4A574;     /* Light copper for backgrounds/highlights */

Gradient Header

/* Warm gradient for top bar/hero sections */
--gradient-header: linear-gradient(135deg, #D4732A 0%, #8B3D1A 50%, #2D1810 100%);

Neutral Palette

/* Backgrounds */
--color-bg-primary: #FFFFFF;       /* Main background */
--color-bg-secondary: #FAFAFA;     /* Subtle sections */
--color-bg-elevated: #FFFFFF;      /* Cards, elevated surfaces */

/* Text */
--color-text-primary: #1A1A1A;     /* Primary text - near black */
--color-text-secondary: #666666;   /* Secondary/muted text */
--color-text-tertiary: #999999;    /* Placeholder, hints */

/* Borders */
--color-border: #E5E5E5;           /* Default borders */
--color-border-strong: #CCCCCC;    /* Emphasized borders */
--color-border-focus: #A6592D;     /* Focus state - uses accent */

Semantic Colors

--color-success: #22C55E;
--color-error: #EF4444;
--color-warning: #F59E0B;
--color-info: #3B82F6;

Dark Mode (Future)

/* Dark mode should invert while keeping the warm accent */
--color-bg-primary-dark: #0D0D0D;
--color-bg-secondary-dark: #1A1A1A;
--color-text-primary-dark: #F5F5F5;
--color-border-dark: #333333;

Typography

Font Stack

Headings & Code: Monospace

--font-mono: 'JetBrains Mono', 'IBM Plex Mono', 'Fira Code', monospace;

Body Text: Sans-serif (for longer reading)

--font-sans: 'Inter', 'IBM Plex Sans', system-ui, sans-serif;

Type Scale

Element Font Size Weight Line Height Letter Spacing
H1 Mono 48px (3rem) 600 1.1 -0.02em
H2 Mono 36px (2.25rem) 600 1.2 -0.01em
H3 Mono 24px (1.5rem) 600 1.3 0
H4 Mono 20px (1.25rem) 600 1.4 0
Body Large Sans 18px (1.125rem) 400 1.7 0
Body Sans 16px (1rem) 400 1.7 0
Body Small Sans 14px (0.875rem) 400 1.6 0
Caption Sans 12px (0.75rem) 400 1.5 0.01em
Code Mono 14px (0.875rem) 400 1.6 0

Typography Rules

  1. Headings are lowercase - "pricing", "faq", "tools" (not "Pricing", "FAQ", "Tools")
  2. Generous line-height - Minimum 1.6 for body text, 1.7 preferred
  3. Bold sparingly - Use weight 600 for emphasis, not 700+
  4. Monospace for data - Numbers, metrics, technical values always in mono

CSS Variables

/* Font families */
--font-heading: var(--font-mono);
--font-body: var(--font-sans);
--font-code: var(--font-mono);

/* Font sizes */
--text-xs: 0.75rem;    /* 12px */
--text-sm: 0.875rem;   /* 14px */
--text-base: 1rem;     /* 16px */
--text-lg: 1.125rem;   /* 18px */
--text-xl: 1.25rem;    /* 20px */
--text-2xl: 1.5rem;    /* 24px */
--text-3xl: 2.25rem;   /* 36px */
--text-4xl: 3rem;      /* 48px */

/* Line heights */
--leading-tight: 1.2;
--leading-normal: 1.5;
--leading-relaxed: 1.7;

/* Font weights */
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;

Spacing

Spacing Scale

--space-0: 0;
--space-1: 0.25rem;   /* 4px */
--space-2: 0.5rem;    /* 8px */
--space-3: 0.75rem;   /* 12px */
--space-4: 1rem;      /* 16px */
--space-5: 1.25rem;   /* 20px */
--space-6: 1.5rem;    /* 24px */
--space-8: 2rem;      /* 32px */
--space-10: 2.5rem;   /* 40px */
--space-12: 3rem;     /* 48px */
--space-16: 4rem;     /* 64px */
--space-20: 5rem;     /* 80px */
--space-24: 6rem;     /* 96px */

Spacing Philosophy

  • Generous whitespace - When in doubt, add more space
  • Vertical rhythm - Use consistent spacing between sections (typically --space-16 to --space-24)
  • Component padding - Cards and containers use --space-6 to --space-8
  • Text spacing - Paragraphs separated by --space-4 to --space-6

Borders & Containers

Border Radius

--radius-none: 0;      /* DEFAULT - sharp corners */
--radius-sm: 2px;      /* Use sparingly for special cases */
--radius-md: 4px;      /* Use sparingly for special cases */

Rule: Default to 0 border-radius. Sharp corners are the brand.

Border Styles

Dashed (Primary)

border: 1px dashed var(--color-border);

Solid (Emphasis)

border: 2px solid var(--color-text-primary);  /* Featured items */

Fieldset-Style Containers

The signature container style with a label that "cuts into" the border:

<fieldset class="fieldset-container">
  <legend>section title</legend>
  <!-- content -->
</fieldset>
.fieldset-container {
  border: 1px dashed var(--color-border);
  padding: var(--space-6);
  margin: 0;
}

.fieldset-container legend {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-text-secondary);
  padding: 0 var(--space-2);
  text-transform: lowercase;
}

Container Variants

Variant Border Background Use Case
Default 1px dashed transparent Most containers
Elevated 1px dashed white Cards on gray bg
Featured 2px solid white Highlighted item
Ghost none transparent Minimal grouping

Components

Buttons

Primary Button (Accent)

.btn-primary {
  background: var(--color-accent);
  color: white;
  border: none;
  padding: var(--space-3) var(--space-6);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  cursor: pointer;
  transition: background 150ms ease;
}

.btn-primary:hover {
  background: var(--color-accent-hover);
}

Secondary Button (Outline)

.btn-secondary {
  background: transparent;
  color: var(--color-text-primary);
  border: 1px solid var(--color-border);
  padding: var(--space-3) var(--space-6);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  cursor: pointer;
  transition: border-color 150ms ease;
}

.btn-secondary:hover {
  border-color: var(--color-text-primary);
}

Button Sizes

Size Padding Font Size
sm --space-2 --space-4 --text-xs
md --space-3 --space-6 --text-sm
lg --space-4 --space-8 --text-base
a {
  color: var(--color-text-primary);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity 150ms ease;
}

a:hover {
  opacity: 0.7;
}

Rule: Links are underlined, not colored. Use underline as the primary affordance.

Inputs

.input {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-none);
  font-family: var(--font-mono);
  font-size: var(--text-base);
  background: white;
  transition: border-color 150ms ease;
}

.input:focus {
  outline: none;
  border-color: var(--color-accent);
}

.input::placeholder {
  color: var(--color-text-tertiary);
}

Cards

.card {
  border: 1px dashed var(--color-border);
  padding: var(--space-6);
  background: white;
}

.card--featured {
  border: 2px solid var(--color-text-primary);
}

.card__title {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  text-transform: lowercase;
  margin-bottom: var(--space-2);
}

.card__description {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: var(--color-text-secondary);
  line-height: var(--leading-relaxed);
}

Badges

.badge {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  border: 1px solid currentColor;
  text-transform: lowercase;
}

.badge--default { color: var(--color-text-secondary); }
.badge--success { color: var(--color-success); }
.badge--error { color: var(--color-error); }
.badge--warning { color: var(--color-warning); }

Tables

.table-container {
  border: 1px dashed var(--color-border);
  overflow: hidden;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

.table th {
  text-align: left;
  padding: var(--space-4);
  border-bottom: 1px dashed var(--color-border);
  font-weight: var(--font-semibold);
  text-transform: lowercase;
}

.table td {
  padding: var(--space-4);
  border-bottom: 1px dashed var(--color-border);
}

.table tr:last-child td {
  border-bottom: none;
}

Layout

Container Widths

--container-sm: 640px;
--container-md: 768px;
--container-lg: 1024px;
--container-xl: 1280px;

Page Structure

┌─────────────────────────────────────────────┐
│  Gradient Header Bar (announcement)         │
├─────────────────────────────────────────────┤
│  Navigation (sticky, white bg)              │
├─────────────────────────────────────────────┤
│                                             │
│  Hero Section                               │
│  (generous padding: --space-24)             │
│                                             │
├─────────────────────────────────────────────┤
│                                             │
│  Content Sections                           │
│  (separated by --space-16 to --space-24)    │
│                                             │
│  ┌─ fieldset container ─────────────────┐   │
│  │ section title                        │   │
│  │                                      │   │
│  │  Content with generous padding       │   │
│  │                                      │   │
│  └──────────────────────────────────────┘   │
│                                             │
└─────────────────────────────────────────────┘

Interactions

Hover States

  • Buttons: Background color change (accent → darker)
  • Links: Opacity reduction to 0.7
  • Cards: Border color change (border → border-strong)
  • No transforms - Avoid scale/translate on hover (too playful)

Focus States

*:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

Transitions

--transition-fast: 150ms ease;
--transition-base: 200ms ease;
--transition-slow: 300ms ease;

Rule: Keep transitions subtle and fast. No bouncy/spring animations.


Special Elements

Gradient Header Bar

.header-bar {
  background: var(--gradient-header);
  color: white;
  padding: var(--space-2) var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  text-align: center;
}

Technical Diagrams

Use ASCII-style box diagrams with monospace font:

┌─────────────┐      ┌─────────────┐
│   client    │─────▶│    API      │
└─────────────┘      └─────────────┘

Code Blocks

.code-block {
  background: var(--color-bg-secondary);
  border: 1px dashed var(--color-border);
  padding: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  overflow-x: auto;
}

Sliders/Range Inputs

Custom styled with accent color, monospace tooltips showing values.


Do's and Don'ts

Do

  • Use lowercase for headings
  • Use dashed borders for containers
  • Use generous whitespace
  • Use monospace for technical content
  • Use underlines for links
  • Keep interactions subtle and fast
  • Use the copper accent sparingly but confidently

Don't

  • Don't use rounded corners (except for special cases)
  • Don't use drop shadows
  • Don't use gradients (except header bar)
  • Don't use icons where text works
  • Don't use colored links
  • Don't use bouncy animations
  • Don't use multiple accent colors

Implementation Priority

Phase 1: Foundation

  1. Update CSS variables (colors, spacing, typography)
  2. Install fonts (JetBrains Mono, Inter)
  3. Update base styles (reset, typography)

Phase 2: Core Components

  1. Button variants
  2. Input/Form elements
  3. Card/Container styles
  4. Badge variants

Phase 3: Layout

  1. Fieldset-style containers
  2. Page layouts with generous spacing
  3. Navigation updates
  4. Gradient header bar

Phase 4: Polish

  1. Table styles
  2. Code blocks
  3. Interactive elements (sliders, toggles)
  4. Transitions and hover states

References


Last updated: January 2025 Version: 1.0