Design Principles for Software Engineers: The Complete Guide
Master visual design fundamentals for building better interfaces. Gestalt psychology, typography, color theory, spacing systems, animation principles, and lessons from design legends like Dieter Rams. Includes case studies of 16 exceptional products.
Design Principles for Software Engineers: The Complete Guide
Updated January 17, 2026
January 2026 Update: This guide consolidates timeless design principles with modern implementation patterns for web and iOS development. It covers Gestalt psychology, typography systems, color theory, visual hierarchy, spacing, and animation—plus lessons from Dieter Rams. See Design Studies for deep dives into 16 exceptional products.
I’ve spent years studying design while building software, absorbing principles from legends like Dieter Rams and dissecting interfaces from products like Linear, Stripe, and Raycast. This guide distills that understanding into the comprehensive reference I wish existed when I started caring about how my software looked and felt.
Design isn’t decoration. It’s communication. Every pixel communicates function, hierarchy, and meaning. The difference between software that feels amateur and software that feels professional is understanding these principles and applying them consistently.
This guide assumes you can already write code. It teaches you to see—to understand why some interfaces feel effortless while others feel chaotic, and more importantly, how to build the former.
Table of Contents
Part 1: Foundations
Part 2: Design Philosophy
Part 3: Implementation
Part 4: Reference
Gestalt Psychology
“The whole is other than the sum of its parts.” — Kurt Koffka
Gestalt psychology, developed in 1920s Germany, explains how humans perceive visual information. The brain doesn’t see individual pixels—it organizes elements into meaningful patterns. Master these principles to control how users perceive your interfaces.
Proximity
Elements close together are perceived as a group.
This is the most powerful Gestalt principle in UI design. Space communicates relationship more than any other visual property.
WRONG (equal spacing = no grouping):
┌─────────────────┐
│ Label │
│ │
│ Input Field │
│ │
│ Label │
│ │
│ Input Field │
└─────────────────┘
RIGHT (unequal spacing = clear groups):
┌─────────────────┐
│ Label │
│ Input Field │ ← Tight (4px) - related
│ │
│ │ ← Wide (24px) - separating groups
│ Label │
│ Input Field │ ← Tight (4px) - related
└─────────────────┘
CSS Implementation:
.form-group {
margin-bottom: 24px; /* Between groups: wide */
}
.form-group label {
margin-bottom: 4px; /* Label to input: tight */
display: block;
}
SwiftUI Implementation:
VStack(alignment: .leading, spacing: 4) { // Tight within group
Text("Email")
.font(.caption)
.foregroundStyle(.secondary)
TextField("[email protected]", text: $email)
.textFieldStyle(.roundedBorder)
}
.padding(.bottom, 24) // Wide between groups
Similarity
Elements sharing visual characteristics appear related.
When elements look the same, users assume they function the same. This is why design systems use consistent button styles, card treatments, and typography.
Example Navigation:
┌───────────────────────────────────┐
│ [Dashboard] [Projects] [Settings] │ ← Same style = same function
│ │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Card │ │Card │ │Card │ │ ← Same style = same content type
│ └─────┘ └─────┘ └─────┘ │
│ │
│ [+ New Project] │ ← Different style = different function
└───────────────────────────────────┘
Figure-Ground
Content should clearly separate from background.
The brain needs to distinguish the “figure” (what to focus on) from the “ground” (the background). Poor figure-ground relationships create visual confusion.
Techniques: - Contrast (light figure on dark ground, or vice versa) - Shadows (elevate figure above ground) - Borders (delineate figure edges) - Blur (blur background, sharpen figure)
/* Strong figure-ground relationship */
.card {
background: var(--color-surface); /* Figure */
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1); /* Elevation */
}
.modal-overlay {
background: rgba(0, 0, 0, 0.5); /* Dim ground */
backdrop-filter: blur(4px); /* Blur ground */
}
Common Region
Elements within a boundary are perceived as grouped.
Enclosing elements within a visual container (card, box, bordered area) signals they belong together.
Continuity
The eye follows paths, lines, and curves.
Use alignment and visual flow to guide attention through your interface.
CONTINUITY IN ALIGNMENT:
┌────────────────────────────────┐
│ Logo [Nav] [Nav] [Nav] │ ← Aligned on horizontal axis
├────────────────────────────────┤
│ │
│ Headline │
│ ───────────────────────────── │ ← Eye follows left edge
│ Paragraph text continues │
│ along the same left edge │
│ │
│ [Primary Action] │ ← Still on the left edge
└────────────────────────────────┘
Closure
The brain completes incomplete shapes.
Users don’t need every pixel drawn—they’ll mentally complete familiar shapes. This allows for more minimal, elegant designs.
/* Horizontal scroll with partial card (closure) */
.card-carousel {
display: flex;
gap: 16px;
overflow-x: auto;
padding-right: 48px; /* Show partial card = scroll hint */
}
.card-carousel .card {
flex: 0 0 280px; /* Fixed width, partial visible */
}
Gestalt Quick Reference
| Principle | Rule | Primary Use |
|---|---|---|
| Proximity | Related = close, unrelated = far | Form fields, content sections |
| Similarity | Same look = same function | Buttons, cards, navigation |
| Figure-Ground | Clear separation of layers | Cards, modals, overlays |
| Common Region | Boundaries group content | Settings sections, user cards |
| Continuity | Follow lines and alignment | Timelines, reading flow |
| Closure | Brain completes shapes | Icons, scroll hints, skeletons |
Typography
“Typography is the craft of endowing human language with a durable visual form.” — Robert Bringhurst
Typography is the foundation of interface design. Text communicates functionality, hierarchy, and brand. Poor typography makes interfaces harder to use; great typography is invisible—it just works.
Type Scale
A consistent scale creates visual harmony. Use a mathematical ratio.
The 1.25 Scale (Recommended for UI):
:root {
/* Base: 16px (1rem) */
--text-xs: 0.64rem; /* 10.24px - use sparingly */
--text-sm: 0.8rem; /* 12.8px - captions, labels */
--text-base: 1rem; /* 16px - body text */
--text-lg: 1.25rem; /* 20px - lead text */
--text-xl: 1.563rem; /* 25px - h4 */
--text-2xl: 1.953rem; /* 31.25px - h3 */
--text-3xl: 2.441rem; /* 39px - h2 */
--text-4xl: 3.052rem; /* 48.8px - h1 */
}
Line Height (Leading)
Line height dramatically affects readability. Different content needs different leading.
| Content Type | Line Height | Why |
|---|---|---|
| Headlines | 1.1 - 1.2 | Tight, bold, short |
| UI Text | 1.3 - 1.4 | Labels, buttons |
| Body Text | 1.5 - 1.7 | Readable paragraphs |
| Long-form | 1.7 - 2.0 | Articles, documentation |
Line Length (Measure)
Optimal line length prevents eye fatigue and improves reading comprehension.
- Optimal: 45-75 characters per line
- Target: 50-65 characters
- Absolute max: 85 characters
p {
max-width: 65ch; /* ch unit = width of '0' character */
}
.article-body {
max-width: 70ch;
margin: 0 auto;
}
Font Selection
System fonts first. They load instantly, match the platform, and are optimized for screens.
:root {
--font-sans: system-ui, -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
--font-mono: ui-monospace, 'SF Mono', 'Cascadia Code',
'JetBrains Mono', Consolas, monospace;
}
Use custom fonts for: - Brand differentiation (marketing sites) - Editorial/publication feel - Specific design intent not achievable with system fonts
Font Weight for Hierarchy
Use weight to establish hierarchy, not just size.
h1 { font-weight: 700; } /* Bold */
h2 { font-weight: 600; } /* Semibold */
h3 { font-weight: 600; } /* Semibold */
.lead { font-weight: 500; } /* Medium */
p { font-weight: 400; } /* Regular */
.meta { font-weight: 400; color: var(--text-muted); }
Typography Quick Reference
| Property | Body Text | Headlines | UI Labels |
|---|---|---|---|
| Size | 16-18px | 24-48px | 12-14px |
| Weight | 400 | 600-700 | 500 |
| Line Height | 1.5-1.7 | 1.1-1.2 | 1.3-1.4 |
| Line Length | 45-75ch | N/A | N/A |
| Alignment | Left | Center OK | Left |
Color Theory
“Color is a power which directly influences the soul.” — Wassily Kandinsky
Color communicates faster than words. It establishes mood, guides attention, signals meaning, and builds brand recognition.
The 60-30-10 Rule
The most reliable color distribution for balanced interfaces.
┌──────────────────────────────────────────┐
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ 60% - Dominant (Background)
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░│ 30% - Secondary (Cards, sections)
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░│
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓██████▓▓▓▓▓▓▓▓▓▓░░░░░░░░│ 10% - Accent (Buttons, links)
└──────────────────────────────────────────┘
Building a Color Palette
Every interface needs these semantic colors:
:root {
/* Brand */
--color-primary: hsl(220, 80%, 50%);
--color-primary-hover: hsl(220, 80%, 45%);
/* Semantic */
--color-success: hsl(142, 76%, 36%); /* Green - positive */
--color-warning: hsl(38, 92%, 50%); /* Amber - caution */
--color-error: hsl(0, 84%, 60%); /* Red - danger */
/* Neutrals */
--color-background: hsl(0, 0%, 100%);
--color-surface: hsl(220, 14%, 96%);
--color-border: hsl(220, 13%, 91%);
/* Text */
--color-text: hsl(220, 13%, 13%);
--color-text-secondary: hsl(220, 9%, 46%);
--color-text-muted: hsl(220, 9%, 64%);
}
Color Psychology
| Color | Psychology | UI Usage |
|---|---|---|
| Blue | Trust, stability, calm | Finance, tech, corporate |
| Green | Growth, nature, success | Health, eco, positive states |
| Red | Energy, urgency, danger | Alerts, sales, errors |
| Orange | Warmth, enthusiasm | CTAs, playful brands |
| Yellow | Optimism, caution | Warnings, highlights |
| Purple | Luxury, creativity | Premium products |
Accessibility Contrast
| Level | Normal Text | Large Text | UI Components |
|---|---|---|---|
| AA | 4.5:1 | 3:1 | 3:1 |
| AAA | 7:1 | 4.5:1 | N/A |
Tools: WebAIM Contrast Checker, Chrome DevTools color picker
Visual Hierarchy
“Design is the silent ambassador of your brand.” — Paul Rand
Visual hierarchy controls what users see first, second, and third. Without clear hierarchy, users must work to find information. With it, interfaces feel effortless.
The Six Tools of Hierarchy
1. Size — Larger elements attract attention first
.hero-title { font-size: 3rem; } /* Dominant */
.section-title { font-size: 1.5rem; } /* Secondary */
.body-text { font-size: 1rem; } /* Baseline */
2. Weight — Bold pops forward, light recedes
h1 { font-weight: 700; }
.lead { font-weight: 500; }
p { font-weight: 400; }
3. Color & Contrast — High contrast = attention
.title { color: var(--color-text); } /* Near black */
.meta { color: var(--color-text-muted); } /* Gray */
4. Position — Key positions matter
F-PATTERN (content pages): Z-PATTERN (landing pages):
████████████████████████ 1 ──────────────────► 2
████████ ↘
████ ↘
██ ↘
3 ──────────────────► 4
5. Whitespace — Isolation creates importance
.hero { padding: 120px 48px; } /* Generous space */
.data-table { padding: 12px; } /* Dense content */
6. Depth & Elevation — Elements that pop forward demand attention
:root {
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.1);
}
.card { box-shadow: var(--shadow-sm); }
.card:hover { box-shadow: var(--shadow-md); }
.modal { box-shadow: var(--shadow-lg); }
The Squint Test
Squint at your design. Can you still see the hierarchy? If yes, it’s strong.
Spacing & Rhythm
“Whitespace is like air: it is necessary for design to breathe.” — Wojciech Zieliński
Spacing is the invisible structure of design. Consistent spacing creates visual rhythm—the feeling that elements belong together in a coherent system.
The 8px Grid
The 8px grid is the industry standard because: - Divides evenly (8, 16, 24, 32, 40, 48…) - Works with common screen densities (1x, 1.5x, 2x, 3x) - Creates consistent rhythm without math
:root {
--space-1: 4px; /* Tight: icon gaps */
--space-2: 8px; /* Compact: inline elements */
--space-3: 12px; /* Snug: form fields */
--space-4: 16px; /* Default: most gaps */
--space-6: 24px; /* Spacious: card padding */
--space-8: 32px; /* Section gaps */
--space-12: 48px; /* Major sections */
--space-16: 64px; /* Page sections */
--space-20: 80px; /* Hero spacing */
}
Internal vs External Spacing
Internal (padding): Space inside an element External (margin): Space between elements
Rule: Internal spacing should typically be larger than external spacing within related groups.
.card {
padding: 24px; /* Internal: spacious */
margin-bottom: 16px; /* External: less than padding */
}
Component Spacing Patterns
Cards:
.card { padding: 24px; border-radius: 12px; }
.card-header { margin-bottom: 16px; }
.card-title { margin-bottom: 4px; } /* Tight to subtitle */
Buttons:
.btn { padding: 12px 24px; border-radius: 8px; }
.btn--sm { padding: 8px 16px; }
.btn--lg { padding: 16px 32px; }
.btn-group { display: flex; gap: 12px; }
Forms:
.form-row { margin-bottom: 24px; }
.form-label { margin-bottom: 4px; }
.form-help { margin-top: 4px; }
.form-actions { margin-top: 32px; display: flex; gap: 12px; }
Spacing Quick Reference
| Context | Recommended Spacing |
|---|---|
| Icon to text | 4-8px |
| Label to input | 4px |
| Between form groups | 24px |
| Card padding | 20-24px |
| Card gap | 16-24px |
| Section padding (mobile) | 48-64px |
| Section padding (desktop) | 80-96px |
| Button padding (h/v) | 24px / 12px |
Animation Principles
“Animation is not the art of drawings that move but the art of movements that are drawn.” — Norman McLaren
Animation brings interfaces to life. Done well, it guides attention, communicates state, and creates emotional connection. Done poorly, it frustrates and distracts.
The Core Principle
Animation should feel inevitable, not decorative.
Good animation: 1. Communicates something that static design cannot 2. Reduces cognitive load by showing relationships 3. Feels natural and expected 4. Disappears from conscious awareness
Bad animation: 1. Exists only because “it looks cool” 2. Slows down the user 3. Calls attention to itself 4. Creates anxiety or impatience
Key Principles for UI
1. Anticipation — Prepare users for what’s coming.
.button {
transition: transform 0.1s ease-out;
}
.button:active {
transform: scale(0.97); /* Slight press before action */
}
2. Follow-Through — Let motion complete naturally with spring-like settling.
.panel {
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
withAnimation(.spring(response: 0.4, dampingFraction: 0.7)) {
isOpen = true
}
3. Ease-In, Ease-Out — Nothing in nature moves at constant speed.
| Curve | When to Use | Character |
|---|---|---|
ease-out |
Entering elements | Quick start, gentle stop |
ease-in |
Exiting elements | Gentle start, quick exit |
ease-in-out |
State changes | Smooth throughout |
linear |
Loading indicators | Continuous, mechanical |
4. Staging — Direct attention to what matters. Only one thing should move at a time unless choreographed as a group.
5. Staggering — Elements should arrive in sequence, not all at once.
.list-item {
animation: fadeSlideIn 0.3s ease-out both;
}
.list-item:nth-child(1) { animation-delay: 0ms; }
.list-item:nth-child(2) { animation-delay: 50ms; }
.list-item:nth-child(3) { animation-delay: 100ms; }
.list-item:nth-child(4) { animation-delay: 150ms; }
@keyframes fadeSlideIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
Timing Guidelines
| Duration | Use Case | Feel |
|---|---|---|
| 50-100ms | Micro-interactions (hover, press) | Instant feedback |
| 150-200ms | Simple state changes (toggle, select) | Snappy |
| 250-350ms | Medium transitions (panel slide, card flip) | Smooth |
| 400-500ms | Large movements (page transitions, modals) | Deliberate |
Performance: The Golden Rule
Only animate transform and opacity — these are GPU-accelerated and don’t trigger layout.
/* BAD: Animating layout */
.panel { transition: left 0.3s, width 0.3s; }
/* GOOD: Using transform */
.panel { transition: transform 0.3s; }
When NOT to Animate
-
User has
prefers-reduced-motionenabledcss @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } -
Animation adds no information — gratuitous spinners, bouncing elements
- Users are in a hurry — error states, form validation, search results
- Animation would slow repeated actions — keyboard shortcuts should bypass animation
Animation Quick Reference
:root {
/* Durations */
--duration-instant: 0.1s;
--duration-fast: 0.15s;
--duration-normal: 0.25s;
--duration-slow: 0.4s;
/* Easings */
--ease-out: cubic-bezier(0.0, 0.0, 0.58, 1.0);
--ease-in: cubic-bezier(0.42, 0.0, 1.0, 1.0);
--ease-in-out: cubic-bezier(0.42, 0.0, 0.58, 1.0);
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
}
Dieter Rams: Ten Principles
“Less, but better.” — Dieter Rams
Dieter Rams is the most influential industrial designer of the 20th century. As head of design at Braun from 1961-1995, he created products that remain timeless decades later. His work directly inspired Apple’s design language.
The Ten Principles of Good Design
1. Good design is innovative Don’t copy. Pair advancing technology with innovative design.
2. Good design makes a product useful Every element must serve a purpose. Form follows function.
3. Good design is aesthetic Beauty isn’t superficial—it’s essential. Products we use daily affect our well-being.
4. Good design makes a product understandable Users shouldn’t need instructions. The interface teaches itself.
5. Good design is unobtrusive Design should support, not overwhelm. The user’s content is the star, not your UI.
/* Obtrusive: UI competes with content */
.editor {
background: linear-gradient(135deg, purple, blue);
border: 3px dashed gold;
}
/* Unobtrusive: UI recedes, content shines */
.editor {
background: var(--color-background);
border: 1px solid var(--color-border);
}
6. Good design is honest Don’t use dark patterns. Don’t over-promise. Be transparent about limitations.
7. Good design is long-lasting Avoid trends that will date quickly. Classic over trendy.
TRENDY (will date): TIMELESS:
- Extreme glassmorphism - Clean typography
- Neon colors, glitch effects - Subtle elevation
- Aggressive gradients - Neutral palette with considered accent
8. Good design is thorough down to the last detail Nothing must be arbitrary. Loading states, empty states, error states—all designed.
9. Good design is environmentally friendly Performance is environmental. Respect user attention. Efficient code.
10. Good design is as little design as possible Remove everything that isn’t necessary. The best design is invisible.
Web Patterns 2025
Modern web design leverages native CSS capabilities that eliminate the need for JavaScript in many cases.
Container Queries
Size components based on their container, not the viewport.
.card-grid {
container-type: inline-size;
container-name: card-grid;
}
.card {
display: grid;
gap: 16px;
padding: 20px;
}
@container card-grid (min-width: 400px) {
.card {
grid-template-columns: auto 1fr;
}
}
@container card-grid (min-width: 600px) {
.card {
padding: 32px;
gap: 24px;
}
}
The :has() Selector
Parent selection based on children—previously impossible without JavaScript.
/* Card with image gets different padding */
.card:has(img) {
padding: 0;
}
.card:has(img) .card-content {
padding: 20px;
}
/* Form group with error */
.form-group:has(.input:invalid) .form-label {
color: var(--color-error);
}
/* Highlight navigation when on that page */
.nav-item:has(a[aria-current="page"]) {
background: var(--color-surface);
}
CSS Nesting
Native nesting without preprocessors.
.card {
background: var(--color-surface);
border-radius: 12px;
padding: 24px;
& .card-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 8px;
}
& .card-body {
color: var(--color-text-secondary);
line-height: 1.6;
}
&:hover {
box-shadow: var(--shadow-md);
}
@media (min-width: 768px) {
padding: 32px;
}
}
HTMX Integration
Server-driven interactivity without heavy JavaScript frameworks.
<!-- Load content on click -->
<button hx-get="/api/more-items"
hx-target="#item-list"
hx-swap="beforeend"
hx-indicator="#loading">
Load More
</button>
<!-- Form with inline validation -->
<form hx-post="/api/contact"
hx-target="#form-response"
hx-swap="outerHTML">
<input type="email" name="email"
hx-post="/api/validate-email"
hx-trigger="blur"
hx-target="next .error" />
<span class="error"></span>
</form>
Design Tokens System
A complete token system for consistency across your application.
:root {
/* Colors */
--color-text: #1a1a1a;
--color-text-secondary: #666666;
--color-text-muted: #999999;
--color-background: #ffffff;
--color-surface: #f8f9fa;
--color-surface-elevated: #ffffff;
--color-border: #e5e7eb;
--color-primary: #3b82f6;
--color-primary-hover: #2563eb;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
/* Typography */
--font-sans: system-ui, -apple-system, sans-serif;
--font-mono: "SF Mono", Consolas, monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 2rem;
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75;
/* Spacing (8px base) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
/* Borders */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
/* Transitions */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--duration-fast: 100ms;
--duration-normal: 200ms;
}
Dark Mode Done Right
Don’t just invert—redesign for dark contexts.
@media (prefers-color-scheme: dark) {
:root {
/* Neutrals */
--color-background: hsl(220, 13%, 10%);
--color-surface: hsl(220, 13%, 15%);
--color-surface-elevated: hsl(220, 13%, 18%);
--color-border: hsl(220, 13%, 23%);
/* Text (inverted) */
--color-text: hsl(220, 9%, 93%);
--color-text-secondary: hsl(220, 9%, 70%);
--color-text-muted: hsl(220, 9%, 55%);
/* Adjust saturation for dark mode */
--color-primary: hsl(220, 80%, 60%);
--color-success: hsl(142, 70%, 45%);
--color-error: hsl(0, 80%, 65%);
/* Shadows in dark mode need adjustment */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
}
}
Dark mode principles: - Reduce saturation on large surfaces - Increase lightness of accent colors - Strengthen shadows (they need more contrast) - Design dark mode intentionally, not as an afterthought
Figma Extraction Workflows
Transforming design files into production code requires systematic extraction of design tokens—colors, typography, spacing, and effects that define your design language.
Figma Variables Export
Figma’s native Variables feature provides the cleanest extraction path:
Export Steps:
1. Open Figma file → Local Variables panel
2. Click collection menu → “Export to JSON”
3. Save as figma-variables.json
JSON Token Structure:
{
"colors": {
"primitive": {
"blue-500": { "value": "#3b82f6", "type": "color" },
"blue-600": { "value": "#2563eb", "type": "color" }
},
"semantic": {
"primary": { "value": "{colors.primitive.blue-500}", "type": "color" },
"primary-hover": { "value": "{colors.primitive.blue-600}", "type": "color" }
}
},
"spacing": {
"1": { "value": "4px", "type": "spacing" },
"2": { "value": "8px", "type": "spacing" },
"4": { "value": "16px", "type": "spacing" }
}
}
Token-to-CSS Transformation
CSS Custom Properties:
:root {
/* Primitive colors (direct values) */
--color-blue-50: #eff6ff;
--color-blue-100: #dbeafe;
--color-blue-500: #3b82f6;
--color-blue-600: #2563eb;
--color-blue-900: #1e3a8a;
/* Semantic colors (reference primitives) */
--color-primary: var(--color-blue-500);
--color-primary-hover: var(--color-blue-600);
--color-background: var(--color-white);
--color-surface: var(--color-gray-50);
/* Spacing (8px grid) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
/* Typography */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--line-height-tight: 1.25;
--line-height-normal: 1.5;
/* Effects */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
}
Dark Mode Tokens:
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--color-gray-900);
--color-surface: var(--color-gray-800);
--color-text: var(--color-gray-100);
--color-text-secondary: var(--color-gray-400);
/* Adjusted shadows for dark mode */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
}
}
Token-to-SwiftUI Transformation
Color Extension:
import SwiftUI
extension Color {
// MARK: - Primitive Colors
static let blue50 = Color(hex: "eff6ff")
static let blue500 = Color(hex: "3b82f6")
static let blue600 = Color(hex: "2563eb")
// MARK: - Semantic Colors
static let brandPrimary = Color.blue500
static let brandPrimaryHover = Color.blue600
// MARK: - Surface Colors
static let surfaceBackground = Color(light: .white, dark: Color(hex: "0f172a"))
static let surfaceElevated = Color(light: Color(hex: "f8fafc"), dark: Color(hex: "1e293b"))
}
extension Color {
init(hex: String) {
// Standard hex parsing implementation
}
init(light: Color, dark: Color) {
self.init(UIColor { traits in
traits.userInterfaceStyle == .dark ? UIColor(dark) : UIColor(light)
})
}
}
Spacing Constants:
enum Spacing {
static let xs: CGFloat = 4 // --space-1
static let sm: CGFloat = 8 // --space-2
static let md: CGFloat = 16 // --space-4
static let lg: CGFloat = 24 // --space-6
static let xl: CGFloat = 32 // --space-8
}
// Usage
VStack(spacing: Spacing.md) {
// ...
}
.padding(Spacing.lg)
Designer Handoff Checklist
What Designers Should Export:
| Asset Type | Format | Notes |
|---|---|---|
| Colors | Variables JSON | Include light + dark modes |
| Typography | Styles export | Font, size, weight, line-height |
| Spacing | Variables JSON | Base unit documented |
| Icons | SVG | Outlined, single color |
| Images | PNG @2x/@3x or WebP | With compression |
| Components | Figma links | For reference during implementation |
Quality Gate Criteria:
- [ ] All colors defined as variables (no hardcoded hex)
- [ ] Typography uses defined text styles
- [ ] Spacing follows grid system (8px base)
- [ ] Dark mode variants provided
- [ ] Interactive states documented (hover, active, disabled)
- [ ] Responsive breakpoints annotated
- [ ] Accessibility requirements noted (contrast ratios)
Developer Receives:
- Token files (JSON/CSS/Swift depending on platform)
- Component specs with measurements
- Asset exports in required formats
- Interaction documentation (states, animations)
- Accessibility annotations
Quick Reference Tables
Gestalt Principles
| Principle | Rule | Use |
|---|---|---|
| Proximity | Related = close | Forms, sections |
| Similarity | Same look = same function | Buttons, cards |
| Figure-Ground | Clear layer separation | Modals, cards |
| Continuity | Follow lines | Timelines, alignment |
| Closure | Brain completes shapes | Icons, scroll hints |
Typography
| Element | Size | Weight | Line Height |
|---|---|---|---|
| Body | 16px | 400 | 1.5-1.7 |
| Headlines | 24-48px | 600-700 | 1.1-1.2 |
| UI Labels | 12-14px | 500 | 1.3-1.4 |
| Captions | 12px | 400 | 1.4 |
Color Roles
| Role | Light Mode | Dark Mode |
|---|---|---|
| Background | #ffffff | #0f172a |
| Surface | #f4f5f7 | #1e293b |
| Border | #e4e6ea | #334155 |
| Text | #1a1a2e | #f1f5f9 |
| Text Muted | #6b7280 | #94a3b8 |
| Primary | #3b82f6 | #60a5fa |
| Success | #22c55e | #4ade80 |
| Error | #ef4444 | #f87171 |
Spacing Scale
| Token | Value | Use |
|---|---|---|
| –space-1 | 4px | Icon gaps |
| –space-2 | 8px | Inline elements |
| –space-4 | 16px | Default gaps |
| –space-6 | 24px | Card padding |
| –space-8 | 32px | Section gaps |
| –space-16 | 64px | Page sections |
Design Checklist
Before shipping any interface, verify:
Gestalt
- [ ] Related elements are closer than unrelated ones (Proximity)
- [ ] Similar functions have similar styles (Similarity)
- [ ] Clear separation between foreground and background (Figure-Ground)
- [ ] Eye flows naturally through layout (Continuity)
Typography
- [ ] Base font size is at least 16px
- [ ] Line height is 1.5+ for body text
- [ ] Line length is under 75 characters
- [ ] Hierarchy is clear (3 levels distinguishable)
- [ ] Consistent scale used throughout
Color
- [ ] All text passes 4.5:1 contrast (WCAG AA)
- [ ] Color is not the only indicator (icons/labels too)
- [ ] Dark mode designed intentionally
- [ ] 60-30-10 distribution followed
Visual Hierarchy
- [ ] Can identify the #1 most important element
- [ ] Eye flows in intended order
- [ ] One clear CTA per section
- [ ] Type scale consistent
Spacing
- [ ] All spacing uses defined scale (no magic numbers)
- [ ] Cards/components have consistent padding
- [ ] Mobile spacing is comfortable
- [ ] Grid alignment is consistent (8px base)
Dieter Rams Check
- [ ] Can anything be removed?
- [ ] Does every element serve function?
- [ ] Would this feel dated in 5 years?
- [ ] Have I designed every state?
Resources
Books: - As Little Design as Possible by Sophie Lovell (Dieter Rams) - The Elements of Typographic Style by Robert Bringhurst
Tools: - WebAIM Contrast Checker - Type Scale Generator - Figma Tokens Studio — Design token management
Design Systems: - Apple HIG - Material Design 3 - Radix UI - shadcn/ui
Design Studies
Deep dives into 16 exceptional products, documenting patterns and principles worth stealing.
Developer Tools
| Product | Key Contribution |
|---|---|
| Figma | Multiplayer presence, context-aware panels |
| Warp | Block-based terminal, CLI-GUI bridge |
| Framer | Visual responsive design, property controls |
| Vercel | Dark mode excellence, ambient status |
| Linear | Optimistic UI, keyboard-first workflow |
| Raycast | Extension system, quick actions |
iOS Native (Apple Design Award Winners)
| Product | Key Contribution |
|---|---|
| Flighty | 15 smart states, Live Activities, data visualization |
| Halide | Intelligent activation, gesture controls |
| Bear | Typography-first, inline tagging |
| Craft | Native-first cross-platform, nested pages |
| Things | Deferred dates, quick entry patterns |
Productivity & AI
| Product | Key Contribution |
|---|---|
| Superhuman | 100ms rule, command palette training, practice onboarding |
| Perplexity | Citation-forward AI, streaming phases |
| Notion | Block system, slash commands |
| Arc | Spaces, split view, command bar |
| Stripe | Documentation excellence, API design |
This guide grows through practice. Design principles are timeless, but their application evolves with technology and understanding.