
Takes a screenshot of any UI and spits out working code in React, Vue, or plain HTML/CSS. It analyzes layout structure, extracts exact colors, matches spacing, and builds component hierarchies that actually make sense. Defaults to React with Tailwind for modern stuff, plain HTML/CSS for simpler pages. The skill is thorough about responsive design and accessibility attributes, which saves you from backtracking later. Honestly most useful when you see a design you want to replicate quickly or need to turn mockups into a starting point without writing boilerplate from scratch. Won't be pixel perfect on complex designs, but it gets you 80% there with clean, deployable code.
npx -y skills add onewave-ai/claude-skills --skill screenshot-to-code --agent claude-codeInstalls into .claude/skills of the current project.
Recreate the UI in the image as clean, responsive, accessible code, then check the render against the image.
Pick the target stack. If the user is inside a project, match it: read package.json for React/Next/Vue and the Tailwind version, and reuse existing components, tokens, and icon libraries. Do not ask when the repo already answers it. With no project:
index.html (Tailwind via the browser build, see references/stack-setup.md).Write a short spec before coding. Looking at the image, note:
Estimate sizes from the image resolution. If the screenshot is 2x (a Retina capture 2880px wide is a 1440px layout), halve the pixel measurements.
Build. Use semantic elements (header, nav, main, section, button, a), extract repeated pieces into components, and put tokens in one place (Tailwind v4 @theme or CSS custom properties) rather than scattering hex codes. Use real text from the image, not lorem ipsum. For images and logos you cannot extract, use sized placeholders with descriptive alt text. Use an icon library the project already has (default: lucide-react), not hand-drawn SVGs or emoji.
Make it responsive. Build for the screenshot's viewport first, then define how it collapses: multi-column grids stack, navs become a menu button, and type scales down with clamp() or responsive utilities. If the screenshot is mobile, go the other direction.
Render and compare. If you can run a browser (Playwright, a headless browser, or a browser tool), screenshot the result at the source image's viewport width and compare side by side. See references/visual-check.md. Fix the largest differences first: layout and alignment, then spacing, then type size and weight, then color. Two or three passes is usually enough; stop when remaining differences are at the level of font rendering.
Deliver. Provide the files, how to run them, and a short list of assumptions (fonts guessed, states invented, content inferred). Name anything that needs real assets.
propTypes checks were removed from React 19; do not add them. forwardRef is not needed for passing ref to function components.@import "tailwindcss"; and @theme { --color-brand: #...; }, not a tailwind.config.js and not the v3 @tailwind base/components/utilities directives. Custom tokens become utilities automatically (bg-brand).app/, components are Server Components by default. Add "use client" only to components that use state, effects, or event handlers.Setup commands for each stack are in references/stack-setup.md.
Input: a 1440px-wide screenshot of a pricing section - centered heading, three plan cards with the middle one highlighted, feature checklists, and a button per card.
Spec:
#0B1220, card #111A2E, accent #3B82F6, text #E5E7EB, muted #94A3B8; Inter-like sans; radius 12pxPlanCard with name, price, features[], highlighted, ctaBuild: PricingSection.tsx mapping a plans array into PlanCard; highlighted adds an accent border and a "Most popular" label; grid-cols-1 md:grid-cols-3. Check icons from lucide-react.
Compare: the first render has cards 40px too tall because of button padding, and the heading weight is 600 against a 700 in the image. Fix both, re-render, and deliver with an assumptions list: toggle not built, font assumed Inter.
focus-visible styles even though the screenshot cannot show them. Inputs need labels.