Extract Design System from Website
SkillWeb & browsingReverse-engineer a design system from a live website (public URL or localhost). Extracts colors, typography, spacing, shadows, radii, breakpoints, and component patterns using a headed Playwright browser. Captures screenshots of pages, components, and interactive states at real device resolutions. Produces structured design tokens and optionally seeds a Penpot project.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Extract Design System from Website skill
What this skill tells your AI
The instructions your AI receives, as published by espennilsen/pi in skills/extract-design-system/SKILL.md and read by ahel’s review.
Reverse-engineer a complete design system from a live website using two passes:
- CSS source analysis — fetch and parse stylesheets for declared values
- Headed Playwright extraction — visually browse the site, interact with elements, extract computed styles, and capture screenshots at real device resolutions
Prerequisites
- Playwright installed (
npx playwright install chromiumif not set up) web_fetchtool for fetching raw HTML/CSS source
Quick Start
Run the extraction script against the target URL:
node scripts/extract.mjs <url> [outDir] [subpage1,subpage2,...]
Examples:
node scripts/extract.mjs https://example.com
node scripts/extract.mjs https://example.com ./my-tokens "/about,/pricing,/docs"
node scripts/extract.mjs http://localhost:3000 extracted "/dashboard,/settings"
The script opens a visible browser (headless: false) so you can watch the
extraction. It uses real device profiles for accurate screenshots:
| Breakpoint | Device | Viewport | DPR | Real image size |
|---|---|---|---|---|
| Mobile | iPhone 15 | 393×659 | 3x | 1179×1977 |
| Tablet | iPad Pro 11 | 834×1194 | 2x | 1668×2388 |
| Desktop | — | 1440×900 | 2x | 2880×1800 |
| Wide | — | 1920×1080 | 2x | 3840×2160 |
Mobile and tablet use Playwright's built-in device descriptors (correct UA,
isMobile, hasTouch) so sites serving different layouts render correctly.
Output Structure
{outDir}/
├── screenshots/
│ ├── pages/ — full-page at 4 breakpoints × each page
│ │ ├── home-mobile.png
│ │ ├── home-desktop.png
│ │ ├── home-dark-mode.png
│ │ └── ...
│ └── components/ — isolated component + hover/focus states
│ ├── nav.png
│ ├── button-primary.png
│ ├── button-primary-hover.png
│ ├── button-primary-focus.png
│ ├── nav-mobile-open.png
│ └── ...
└── raw/
├── colors.json — CSS custom properties + computed colors
├── colors-dark.json — dark mode variables (if detected)
├── typography.json — font families, type styles, @font-face
├── spacing.json — spacing, radii, shadows, borders, max-widths
└── components.json — component manifest + responsive layout data
Workflow
Step 1: Run the Extraction Script
node scripts/extract.mjs "TARGET_URL" "extracted-design-system" "/about,/pricing"
The script automatically:
- Extracts CSS custom properties and computed colors from 800 sampled elements
- Captures typography from all semantic elements (h1-h6, p, a, button, etc.)
- Measures spacing, radii, shadows, and borders
- Screenshots every page at 4 breakpoints with real device contexts
- Isolates and screenshots 17 common component types
- Captures hover and focus states on interactive elements
- Tests mobile nav by clicking hamburger-like buttons at iPhone viewport
- Detects dark mode via
prefers-color-schemeemulation and toggle sniffing
Step 2: CSS Source Analysis (supplementary)
The script captures computed values. This step catches declared values from CSS source that may not be active on the current page:
# Fetch stylesheets identified in the HTML
web_fetch <stylesheet-url>
# Look for things the computed pass might miss:
# - Media query breakpoints
# - Keyframe animations
# - CSS custom property definitions with fallbacks
# - Commented-out or unused styles that reveal design intent
Step 3: Organize Raw Data into Tokens
Review raw/colors.json, raw/typography.json, raw/spacing.json and the
screenshots. Then organize into a structured token file.
Colors → Palette
Group extracted colors into categories:
| Category | What to look for |
|---|---|
| Primary | Brand color, CTA buttons, most prominent accent |
| Secondary | Supporting accent, secondary buttons |
| Neutral | Backgrounds, text, borders — the gray scale |
| Success | Green tones (confirmations, checkmarks) |
| Warning | Yellow/amber tones (alerts) |
| Error | Red tones (errors, delete actions) |
| Info | Blue tones (informational messages) |
Deduplicate near-identical colors (ΔE < 3 in OKLCH space). A site with 47 slightly different grays probably intended 5-8.
Typography → Scale
Map extracted font sizes to a named scale:
| Name | Size range |
|---|---|
| caption | ≤12px |
| small | 13-14px |
| body (base) | 15-16px |
| large | 17-18px |
| h6-h1 | 18-48px |
| display | 48px+ |
Spacing → Grid
Snap raw pixel values to the nearest standard grid:
4px grid: 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96
8px grid: 8, 16, 24, 32, 40, 48, 56, 64, 80, 96
Pick whichever grid the extracted values align to with the least rounding.
Components → Inventory
For each component in the screenshots, document:
- Visual appearance (size, colors, spacing)
- Variants observed (different sizes, states)
- Interactive behavior (from hover/focus screenshots)
- Closest shadcn-svelte equivalent
Step 4: Compile Token File
Write the organized data to tokens.json:
{
"$schema": "extracted-design-tokens",
"source": "https://example.com",
"extracted": "2026-03-09",
"framework_detected": "tailwind|bootstrap|custom|none",
"dark_mode": true,
"colors": {
"light": {
"primary": { "50": "#...", "500": "#...", "900": "#..." },
"neutral": { "50": "#...", "950": "#..." }
},
"dark": { }
},
"typography": {
"fontFamilies": { "sans": "...", "mono": "..." },
"scale": { "h1": { "size": "36px", "weight": 700, "lineHeight": 1.2 } }
},
"spacing": { "grid": "4px", "scale": [0, 4, 8, 12, 16, 24, 32, 48, 64, 96] },
"radii": { "sm": "4px", "md": "8px", "lg": "12px" },
"shadows": { "sm": "...", "md": "...", "lg": "..." },
"components": { "buttons": { "variants": ["primary", "secondary"] } }
}
Step 5: Seed Penpot (optional)
If requested, create a Penpot project from the tokens using pi-penpot:
- Create project named after the source site
- Create a "Design System" page with color swatches, type samples, spacing ruler
- Create pages for each major screen, importing screenshots as references
- Build components matching the extracted inventory
Step 6: Generate Tailwind Config (optional)
Map tokens to a Tailwind config with CSS custom properties for runtime theming.
Tips
- Pass 3-5 subpages for broader component coverage
- CSS custom properties are gold — sites using them have self-documented tokens
- Watch the browser — headed mode reveals cookie banners, auth walls, and popups that block extraction
- Interactive states matter — hover/focus screenshots catch design intent static captures miss
- Don't over-extract — focus on intentional design decisions, not every computed value
- Remove
slowMoin the script for faster extraction once verified - Check for dark mode — the script detects it automatically via both
prefers-color-schemeand toggle buttons
Signals
- GitHub stars
- 118
- Forks
- 13
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
extract-design-system-espennilsen- Source
- github.com/espennilsen/pi