name: ky-design-to-html-skill description: Convert UI screenshots and design mockups to HTML/CSS with asset separation, canvas adaptation, and visual error correction triggers: - convert this UI screenshot to HTML - recreate this design as HTML/CSS - turn this mockup into a webpage - restore this UI screenshot to code - generate HTML from this design screenshot - build HTML/CSS from this UI image - reproduce this page design in HTML - translate this screenshot to static HTML
KY Design to HTML Skill
Skill by ara.so — Design Skills collection.
A Codex/Claude skill for converting UI screenshots and design mockups into HTML/CSS with proper asset separation, canvas ratio handling, screenshot validation, and visual error correction.
What This Project Does
KY Design to HTML is not a "generate UI from description" tool. It focuses on recreating existing UI screenshots or design files as accurate HTML/CSS implementations.
The skill solves the common problem where AI tries to do everything at once (understand layout + replicate styles + draw complex assets) and produces broken, distorted, or blurry results.
Instead, it enforces a structured workflow:
- Decompose the page into a structure map
- Separate code-based elements from visual assets
- Set canvas ratios (design dimensions vs. browser viewport)
- Write HTML/CSS with proper structure
- Screenshot validation in browser
- Compare and correct visual errors
Installation
For Codex
mkdir -p ~/.codex/skills
cp -r ky-design-to-html ~/.codex/skills/
For Claude
mkdir -p ~/.claude/skills
cp -r ky-design-to-html ~/.claude/skills/
Verify Installation
The skill should appear in your agent's skill list. Check that these files exist:
ky-design-to-html/
├── SKILL.md
├── agents/
│ └── openai.yaml
├── references/
│ ├── asset-handling.md
│ └── visual-error-taxonomy.md
└── scripts/
└── screenshot_page.py
Key Commands
Basic Usage
When working with an AI agent that has this skill installed:
Use $ky-design-to-html to recreate this UI screenshot as HTML/CSS.
Or in Chinese:
使用 ky-design-to-html,把这张 UI 截图还原成一个 HTML/CSS 页面。
Screenshot Validation Script
The skill includes a Python screenshot utility for validation:
python scripts/screenshot_page.py <html_file> <output_screenshot.png> [--width 1920] [--height 1080]
Example:
python scripts/screenshot_page.py landing.html screenshot.png --width 1440 --height 900
Environment Requirements:
pip install playwright
playwright install chromium
Core Workflow
The skill enforces this process:
1. Page Decomposition
Before writing code, identify:
- Layout structure (header, hero, features, footer, etc.)
- Text elements (headings, paragraphs, buttons)
- Visual assets (icons, images, backgrounds, gradients)
- Interactive elements (buttons, links, forms)
2. Asset Separation Strategy
Decide what should be:
- Pure CSS: Simple shapes, solid colors, basic gradients, shadows
- SVG inline: Icons, logos, simple illustrations
- Image files: Photos, complex graphics, textures
- Placeholder data URLs: Temporary images during prototyping
Reference: See references/asset-handling.md for decision matrix.
3. Canvas & Viewport Setup
Define the design canvas dimensions and browser viewport:
<!-- Design canvas: 1440x900 -->
<!-- Browser viewport: 1920x1080 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin: 0;
padding: 0;
width: 1440px;
margin: 0 auto;
}
</style>
</head>
4. HTML/CSS Implementation
Write semantic, structured HTML with scoped CSS:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Landing Page</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #ffffff;
width: 1440px;
margin: 0 auto;
}
.hero {
padding: 80px 60px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.hero h1 {
font-size: 56px;
font-weight: 700;
line-height: 1.2;
margin-bottom: 24px;
}
.hero p {
font-size: 20px;
line-height: 1.6;
opacity: 0.9;
max-width: 600px;
}
.cta-button {
display: inline-block;
padding: 16px 32px;
background: white;
color: #667eea;
text-decoration: none;
border-radius: 8px;
font-weight: 600;
margin-top: 32px;
transition: transform 0.2s;
}
.cta-button:hover {
transform: translateY(-2px);
}
.features {
padding: 80px 60px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 40px;
}
.feature-card {
padding: 32px;
background: #f7f9fc;
border-radius: 12px;
}
.feature-icon {
width: 48px;
height: 48px;
background: #667eea;
border-radius: 8px;
margin-bottom: 16px;
}
.feature-card h3 {
font-size: 24px;
margin-bottom: 12px;
color: #1a202c;
}
.feature-card p {
font-size: 16px;
line-height: 1.6;
color: #4a5568;
}
</style>
</head>
<body>
<section class="hero">
<h1>Build amazing products<br>with confidence</h1>
<p>The complete platform for building and scaling your SaaS application, from prototype to production.</p>
<a href="#" class="cta-button">Get Started</a>
</section>
<section class="features">
<div class="feature-card">
<div class="feature-icon"></div>
<h3>Lightning Fast</h3>
<p>Optimized performance that scales with your users, from day one to day 1000.</p>
</div>
<div class="feature-card">
<div class="feature-icon"></div>
<h3>Secure by Default</h3>
<p>Enterprise-grade security built in, so you can focus on building features.</p>
</div>
<div class="feature-card">
<div class="feature-icon"></div>
<h3>Developer First</h3>
<p>Beautiful APIs and documentation that developers actually enjoy using.</p>
</div>
</section>
</body>
</html>
5. Screenshot Validation
Use the included script to capture the rendered page:
# scripts/screenshot_page.py usage
from playwright.sync_api import sync_playwright
import sys
def screenshot_page(html_path, output_path, width=1920, height=1080):
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={'width': width, 'height': height})
page.goto(f'file://{html_path}')
page.screenshot(path=output_path, full_page=True)
browser.close()
if __name__ == '__main__':
screenshot_page(sys.argv[1], sys.argv[2],
int(sys.argv[3]) if len(sys.argv) > 3 else 1920,
int(sys.argv[4]) if len(sys.argv) > 4 else 1080)
Run it:
python scripts/screenshot_page.py output.html validation.png --width 1440 --height 900
6. Visual Error Correction
Compare the screenshot against the original design and identify errors:
Common visual errors (see references/visual-error-taxonomy.md):
- Layout shift: Element positions don't match
- Size mismatch: Width/height proportions off
- Color deviation: RGB values don't match
- Font mismatch: Wrong typeface, weight, or size
- Spacing errors: Padding/margin inconsistencies
- Border/radius: Wrong corner radius or border width
- Shadow mismatch: Box-shadow values incorrect
- Alignment: Text or elements not properly aligned
Correction process:
/* Before - misaligned spacing */
.hero {
padding: 60px 40px; /* Too small */
}
/* After - matched to screenshot */
.hero {
padding: 80px 60px; /* Correct */
}
Configuration
Asset Handling Rules
From references/asset-handling.md:
| Asset Type | Method | When to Use |
|---|---|---|
| Simple icons | CSS or inline SVG | Geometric shapes, < 3 colors |
| Complex icons | SVG file or data URL | Illustrations, gradients |
| Photos | <img> with placeholder |
Always |
| Backgrounds | CSS gradient | Simple linear/radial |
| Textures | Background image | Patterns, noise |
| Logos | Inline SVG | Vector, needs to scale |
Visual Error Priorities
From references/visual-error-taxonomy.md:
- Critical: Layout structure, major positioning
- High: Typography (size, weight, spacing)
- Medium: Colors, shadows, borders
- Low: Subtle gradients, minor spacing
Common Patterns
Landing Page with Hero Section
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
.container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
.hero { padding: 120px 0; text-align: center; background: #f8f9fa; }
.hero h1 { font-size: 48px; font-weight: 700; margin-bottom: 24px; }
.hero p { font-size: 20px; color: #6c757d; max-width: 600px; margin: 0 auto; }
</style>
</head>
<body>
<section class="hero">
<div class="container">
<h1>Your Product Name</h1>
<p>A compelling description of what your product does and why it matters.</p>
</div>
</section>
</body>
</html>
Dashboard Layout with Sidebar
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.layout { display: flex; height: 100vh; }
.sidebar { width: 240px; background: #1a202c; color: white; padding: 24px; }
.main { flex: 1; background: #f7fafc; padding: 32px; overflow-y: auto; }
.nav-item { padding: 12px; margin: 8px 0; border-radius: 6px; cursor: pointer; }
.nav-item:hover { background: #2d3748; }
.card { background: white; padding: 24px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
</style>
</head>
<body>
<div class="layout">
<aside class="sidebar">
<div class="nav-item">Dashboard</div>
<div class="nav-item">Analytics</div>
<div class="nav-item">Settings</div>
</aside>
<main class="main">
<div class="card">
<h2>Dashboard Content</h2>
<p>Main content area</p>
</div>
</main>
</div>
</body>
</html>
Empty State Page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body { margin: 0; font-family: -apple-system, sans-serif; }
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
text-align: center;
padding: 40px;
}
.empty-icon {
width: 120px;
height: 120px;
background: #e2e8f0;
border-radius: 50%;
margin-bottom: 24px;
}
.empty-state h2 { font-size: 24px; margin-bottom: 12px; color: #1a202c; }
.empty-state p { font-size: 16px; color: #718096; max-width: 400px; }
.cta {
margin-top: 24px;
padding: 12px 24px;
background: #3182ce;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="empty-state">
<div class="empty-icon"></div>
<h2>No items yet</h2>
<p>Get started by creating your first item. It only takes a few seconds.</p>
<button class="cta">Create Item</button>
</div>
</body>
</html>
Troubleshooting
Issue: Screenshot looks squished or stretched
Cause: Canvas width doesn't match design dimensions.
Solution:
body {
width: 1440px; /* Match your design canvas */
margin: 0 auto;
}
Issue: Colors don't match the screenshot
Cause: Wrong color values or color space.
Solution: Use a color picker tool on the original screenshot:
/* Before - guessed color */
background: #6600ff;
/* After - picked from screenshot */
background: #667eea;
Issue: Fonts look different
Cause: System font fallback or wrong font-weight.
Solution:
/* Specify exact font stack */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
font-weight: 600; /* Use exact weight from design */
Issue: Spacing is off
Cause: Wrong padding/margin values.
Solution: Use browser DevTools to inspect and adjust:
/* Measure exact spacing from screenshot */
.hero {
padding: 80px 60px; /* Top/bottom: 80px, Left/right: 60px */
}
.hero h1 {
margin-bottom: 24px; /* Exact spacing below heading */
}
Issue: Screenshot script fails
Cause: Playwright not installed.
Solution:
pip install playwright
playwright install chromium
Issue: Layout breaks at different viewport sizes
Cause: Design is fixed-width, not responsive.
Solution: This skill focuses on recreating the exact design, not making it responsive. If you need responsive:
@media (max-width: 1440px) {
body {
width: 100%;
padding: 0 24px;
}
}
Real-World Example
Input: Screenshot of a SaaS landing page (1440x900 design canvas)
Agent workflow:
- Decompose: Header with logo + nav, hero section, 3-column features, footer
- Asset separation: Logo as inline SVG, hero background as CSS gradient, feature icons as CSS shapes
- Set canvas:
body { width: 1440px; margin: 0 auto; } - Write HTML/CSS: Semantic structure with exact spacing
- Screenshot:
python scripts/screenshot_page.py output.html check.png --width 1920 --height 1080 - Compare: Hero padding too small, feature cards missing border-radius
- Correct: Update CSS, re-screenshot, validate
Final deliverable: Single HTML file that renders pixel-perfect to the original design.
Best Practices
- Always separate assets first before writing code
- Set explicit canvas dimensions to prevent layout shift
- Use CSS variables for repeated values:
:root {
--primary: #667eea;
--spacing-lg: 80px;
--spacing-md: 40px;
--spacing-sm: 24px;
--border-radius: 8px;
}
.hero {
padding: var(--spacing-lg) var(--spacing-md);
background: var(--primary);
}
- Screenshot early and often to catch errors
- Work top-to-bottom (header → hero → content → footer)
- Validate typography separately (font-size, weight, line-height, letter-spacing)
This skill produces static, pixel-perfect HTML/CSS recreations of UI screenshots, not responsive or interactive web apps. For production use, you'll need to add JavaScript, make it responsive, and integrate with your backend.