screenshot-to-code skill
Convert UI screenshots to clean frontend code using the screenshot-to-code API.
Best use case
screenshot-to-code skill is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Convert UI screenshots to clean frontend code using the screenshot-to-code API.
Teams using screenshot-to-code skill should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/screenshot-to-code/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How screenshot-to-code skill Compares
| Feature / Agent | screenshot-to-code skill | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Convert UI screenshots to clean frontend code using the screenshot-to-code API.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# screenshot-to-code skill
Convert UI screenshots to clean frontend code using the screenshot-to-code API.
## Base URL
```
http://localhost:4500/api
```
Dashboard: `http://localhost:4501`
## Converting a screenshot
Upload an image file and choose a framework.
```
POST /convert
Content-Type: multipart/form-data
Fields:
image File PNG, JPG, WEBP, GIF. Max 10 MB.
framework string html-css | react-tailwind | vue
prompt string Optional additional instructions for the LLM.
model string Optional model override (defaults to settings).
```
Response:
```json
{
"id": "conv_01j8w4r9",
"status": "done",
"filename": "dashboard_ui.png",
"framework": "react-tailwind",
"iterations": 1,
"code_length": 3842,
"created_at": "2026-03-20T14:00:00Z"
}
```
Status values: `pending` | `generating` | `done` | `error`
While status is `generating`, poll `GET /convert/:id` to check progress.
## Fetching conversion status and code
```
GET /convert/:id
```
Returns the conversion record including `status`, `error_message` (if any), and `iterations`.
```
GET /convert/:id/code
GET /convert/:id/code?v=2
```
Returns the raw code as `text/plain`. Use the `v` query parameter to fetch a specific iteration version (1-based). Omit for the latest.
## Iterating on a conversion
Send a natural-language prompt to refine the generated code.
```
POST /convert/:id/iterate
Content-Type: application/json
{
"prompt": "Make the sidebar dark navy and add a data table below the chart"
}
```
Response includes the updated conversion with `iterations` incremented by 1.
Each iteration appends to the history. Fetch any version via `GET /convert/:id/code?v=N`.
## Listing conversions (history)
```
GET /conversions
GET /conversions?framework=react-tailwind
GET /conversions?q=dashboard
GET /conversions?status=done
GET /conversions?limit=20&offset=0
```
Response:
```json
{
"items": [
{
"id": "conv_01j8w4r9",
"filename": "dashboard_ui.png",
"framework": "react-tailwind",
"status": "done",
"iterations": 3,
"created_at": "2026-03-20T14:00:00Z"
}
],
"total": 12,
"limit": 20,
"offset": 0
}
```
## Deleting a conversion
```
DELETE /convert/:id
```
Removes the conversion record and all associated uploaded images and generated code.
## Settings
```
GET /settings
PATCH /settings
```
PATCH body (all fields optional):
```json
{
"provider": "openai",
"vision_model": "gpt-4o",
"base_url": "",
"max_image_mb": 10,
"resize_images": true,
"max_resolution": "1920x1080",
"default_framework": "react-tailwind",
"system_prompt": "You are an expert frontend developer...",
"retention_hours": 24
}
```
## Testing the LLM connection
```
POST /settings/test-connection
```
Sends a small test prompt to the configured LLM provider. Returns `{ "ok": true }` or `{ "ok": false, "error": "..." }`.
## API key management
The API key is stored AES-256-GCM encrypted in the SQLite database. To update it:
```
PATCH /settings
{ "api_key": "sk-new-key-here" }
```
Retrieve the masked key via `GET /settings` - the value is returned as `"sk-••••...••••"`.
## Environment variables
| Variable | Default | Description |
|---|---|---|
| `S2C_PORT` | `4500` | API server port |
| `S2C_DASHBOARD_PORT` | `4501` | Vite dev server port |
| `S2C_OPENAI_KEY` | | LLM provider API key (encrypted at rest) |
| `S2C_VISION_MODEL` | `gpt-4o` | Vision model |
| `S2C_BASE_URL` | | Custom OpenAI-compatible base URL |
| `S2C_MAX_IMAGE_MB` | `10` | Upload size limit |
| `S2C_RESIZE_IMAGES` | `1` | Resize before LLM (1=yes, 0=no) |
| `S2C_RETENTION_HOURS` | `24` | Auto-delete uploaded images after N hours |
## Framework output filenames
| Framework | Output filename |
|---|---|
| `html-css` | `index.html` (self-contained with inline `<style>`) |
| `react-tailwind` | `ComponentName.tsx` (assumes Vite + Tailwind project) |
| `vue` | `ComponentName.vue` (SFC with `<script setup lang="ts">`) |
The component name is inferred from the uploaded filename (e.g. `dashboard_ui.png` -> `Dashboard.tsx`).
## Conversion lifecycle
1. Image uploaded, stored with UUID in `/data/uploads/`.
2. If `resize_images=1`, sharp resizes to max 1920x1080 JPEG at 85% quality.
3. Image converted to base64 and included in a multimodal LLM message.
4. LLM response streamed; code block extracted from the first fenced code block.
5. Code stored in the `iterations` table linked to the conversion ID.
6. Status set to `done`. Uploaded image deleted after `retention_hours`.
## Troubleshooting
| Problem | Fix |
|---|---|
| `image_too_large` | Reduce file size or increase `S2C_MAX_IMAGE_MB` in settings. |
| `no_code_extracted` | The LLM did not output a code block. Add a more specific prompt or switch to a stronger model. |
| `429 rate_limit_exceeded` | The API will retry automatically with exponential backoff up to 3 times. |
| `model_not_supported` | The selected model does not support vision input. Use `gpt-4o` or `claude-3-5-sonnet-20241022`. |
| Preview blank | The generated code may have import errors. Check the browser console in fullscreen preview mode. |Related Skills
puppeteer-screenshots
Capture webpage screenshots using Puppeteer in a managed queue with configurable concurrency and timeout. Use when you need to automate page thumbnail generation, capture visual snapshots of URLs, or manage a screenshot pipeline with retry logic. Triggers include "capture screenshot", "take thumbnail", "screenshot queue", "Puppeteer capture", or any task involving automated webpage screenshots.
Skill: Uptime Monitoring
## Overview
Skill: Status Page
## Overview
Skill: unit-conversion
## Overview
Skill: recipe-scaler
## Overview
reading-list
Operate the reading-list API to save, manage, tag, search, and export articles.
email-digest
Configure, test, and troubleshoot the reading-list daily email digest delivered via nodemailer.
websocket-realtime
Use the WebSocket connection in poll-builder to receive live vote updates. Use when you need to stream real-time poll results, monitor a poll for new votes, or build a live dashboard. Triggers include "live results", "real-time updates", "stream votes", "watch poll", or "WebSocket".
poll-builder
Self-hosted poll creation tool with real-time results. Use when you need to create a poll, check vote counts, close a poll, export results, or get the shareable link for a poll. Triggers include "create poll", "vote", "poll results", "survey", "collect votes", "share poll", or any task involving polling or voting.
Skill: personal-finance
## Overview
Skill: csv-import
## Overview
Skill: Syntax Highlighting
## Purpose