Convert screenshots and wireframes to production code with color extraction and layout analysis
Convert visual designs (screenshots, wireframes, mockups) into production-ready component code. This skill guides AI vision analysis for color extraction, layout detection, spacing inference, and component hierarchy identification.
When analyzing a design image (screenshot, wireframe, or mockup), follow this systematic approach:
Identify the primary layout pattern:
Determine layout technique:
Example analysis:
Layout: Two-column layout with sidebar navigation on left
Technique: CSS Grid with grid-template-columns: 250px 1fr
Sidebar: Fixed height, vertical nav list, logo at top
Main: Padding around content, scrollable
Extract colors systematically:
Generate color variables:
:root {
/* Brand colors */
--primary: #3B82F6;
--primary-hover: #2563EB;
--primary-light: #DBEAFE;
--secondary: #8B5CF6;
/* Neutral colors */
--gray-50: #F9FAFB;
--gray-100: #F3F4F6;
--gray-200: #E5E7EB;
--gray-300: #D1D5DB;
--gray-400: #9CA3AF;
--gray-500: #6B7280;
--gray-600: #4B5563;
--gray-700: #374151;
--gray-800: #1F2937;
--gray-900: #111827;
/* Semantic colors */
--success: #10B981;
--error: #EF4444;
--warning: #F59E0B;
--info: #3B82F6;
/* Surface colors */
--bg-primary: #FFFFFF;
--bg-secondary: #F9FAFB;
--bg-tertiary: #F3F4F6;
/* Text colors */
--text-primary: #111827;
--text-secondary: #6B7280;
--text-tertiary: #9CA3AF;
/* Border colors */
--border-color: #E5E7EB;
--border-focus: #3B82F6;
}
Dark mode consideration: If the design has a dark theme, create a dark color scheme:
[data-theme="dark"] {
--bg-primary: #111827;
--bg-secondary: #1F2937;
--bg-tertiary: #374151;
--text-primary: #F9FAFB;
--text-secondary: #D1D5DB;
--border-color: #374151;
}
Break down the design into component tree:
Example hierarchy:
DashboardLayout
├── Sidebar
│ ├── Logo
│ ├── Navigation
│ │ ├── NavItem (active)
│ │ ├── NavItem
│ │ └── NavItem
│ └── UserProfile
├── Header
│ ├── SearchBar
│ ├── NotificationBell
│ └── UserAvatar
└── Main
├── PageHeader
│ ├── Heading
│ └── ActionButton
├── MetricsGrid
│ ├── MetricCard
│ ├── MetricCard
│ └── MetricCard
└── DataTable
Identify reusable patterns:
Establish spacing scale: Analyze the visual rhythm and infer spacing values:
Create spacing scale:
:root {
--spacing-1: 0.25rem; /* 4px */
--spacing-2: 0.5rem; /* 8px */
--spacing-3: 0.75rem; /* 12px */
--spacing-4: 1rem; /* 16px */
--spacing-5: 1.25rem; /* 20px */
--spacing-6: 1.5rem; /* 24px */
--spacing-8: 2rem; /* 32px */
--spacing-10: 2.5rem; /* 40px */
--spacing-12: 3rem; /* 48px */
--spacing-16: 4rem; /* 64px */
}
Infer element sizes:
Border radius scale:
:root {
--radius-sm: 0.25rem; /* 4px - inputs, small buttons */
--radius-md: 0.375rem; /* 6px - cards, buttons */
--radius-lg: 0.5rem; /* 8px - large cards, modals */
--radius-xl: 0.75rem; /* 12px - hero sections */
--radius-full: 9999px; /* Pills, avatars */
}
Analyze text hierarchy:
Create type scale:
:root {
/* Font families */
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-serif: 'Merriweather', Georgia, serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
/* 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: 1.875rem; /* 30px */
--text-4xl: 2.25rem; /* 36px */
--text-5xl: 3rem; /* 48px */
/* Line heights */
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 2;
/* Font weights */
--font-light: 300;
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
}
Apply to heading styles:
h1 {
font-size: var(--text-4xl);
font-weight: var(--font-bold);
line-height: var(--leading-tight);
letter-spacing: -0.02em;
color: var(--text-primary);
}
h2 {
font-size: var(--text-3xl);
font-weight: var(--font-semibold);
line-height: var(--leading-tight);
color: var(--text-primary);
}
p {
font-size: var(--text-base);
font-weight: var(--font-normal);
line-height: var(--leading-relaxed);
color: var(--text-secondary);
}
Identify shadow layers:
Create shadow scale:
:root {
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
Identify state variations:
Example button states:
.button {
background: var(--primary);
color: white;
padding: 0.5rem 1rem;
border-radius: var(--radius-md);
transition: all 0.2s ease;
}
.button:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
.button:active {
transform: translateY(0);
box-shadow: var(--shadow-sm);
}
.button:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
.button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.button.loading {
position: relative;
color: transparent;
}
.button.loading::after {
content: '';
position: absolute;
width: 16px;
height: 16px;
border: 2px solid white;
border-top-color: transparent;
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
When design details are unclear:
Programmatic color generation:
const lighten = (color: string, amount: number): string => {
// HSL manipulation to create lighter shade
const hsl = hexToHSL(color);
return hslToHex({ ...hsl, l: Math.min(hsl.l + amount, 100) });
};
const darken = (color: string, amount: number): string => {
const hsl = hexToHSL(color);
return hslToHex({ ...hsl, l: Math.max(hsl.l - amount, 0) });
};
// Usage
const primaryLight = lighten('#3B82F6', 20);
const primaryDark = darken('#3B82F6', 15);
Mobile-first approach:
/* Mobile styles (default) */
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
padding: 1rem;
}
/* Tablet (768px+) */
@media (min-width: 768px) {
.grid {
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
padding: 1.5rem;
}
}
/* Desktop (1024px+) */
@media (min-width: 1024px) {
.grid {
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
padding: 2rem;
}
}
Fluid typography:
h1 {
font-size: clamp(1.875rem, 5vw, 3rem);
}
p {
font-size: clamp(0.875rem, 2vw, 1rem);
}
Container queries for components:
.card {
container-type: inline-size;
}
.card__content {
display: flex;
flex-direction: column;
}
@container (min-width: 400px) {
.card__content {
flex-direction: row;
gap: 1rem;
}
}
Prompt: "Convert this hero section screenshot to code" (image with large heading, subtitle, CTA buttons, background image)
Expected Output:
Prompt: "Convert this card grid wireframe to code" (image showing 3-column grid of cards)
Expected Output:
Prompt: "Convert this contact form mockup to code" (image with inputs, labels, submit button)
Expected Output:
Prompt: "Convert this navigation bar design to code" (image with logo, nav links, user menu)
Expected Output: