I Built a Screenshot-to-React Generator in 3 Hours

I Built a Screenshot-to-React Generator in 3 Hours

我在 3 小时内构建了一个“截图转 React”生成器

I got tired of translating Figma screens and UI screenshots into JSX before I could touch any real frontend work — routing, state, architecture, the stuff that actually matters. So I built a tool to do it for me. Drop a screenshot. Get a live, rendered React + Tailwind component. Streaming. In your browser. No build step. Here’s how it works and what broke along the way. 我厌倦了在进行真正的开发工作(如路由、状态管理、架构设计等真正重要的事情)之前,还要手动将 Figma 界面和 UI 截图转换为 JSX 代码。所以我构建了一个工具来帮我完成这项工作。只需上传一张截图,就能获得一个实时渲染的 React + Tailwind 组件。流式传输,直接在浏览器中运行,无需构建步骤。以下是它的工作原理以及我在过程中遇到的坑。

The Stack

技术栈

  • Next.js 14 — frontend, split-panel UI

  • Go — backend, image compression, SSE streaming

  • Claude API (claude-sonnet-4-5) — vision + code generation

  • Babel Standalone + Tailwind CDN — zero-build iframe preview

  • localStorage — conversion history

  • Next.js 14 — 前端,分屏 UI

  • Go — 后端,图像压缩,SSE 流式传输

  • Claude API (claude-sonnet-4-5) — 视觉识别 + 代码生成

  • Babel Standalone + Tailwind CDN — 无需构建的 iframe 预览

  • localStorage — 转换历史记录

How It Works

工作原理

Screenshot → Go (compress + resize) → Claude Vision (streaming) → SSE → Next.js → iframe preview 截图 → Go(压缩 + 调整大小)→ Claude Vision(流式传输)→ SSE → Next.js → iframe 预览

The Go backend compresses the image to under 5MB, base64 encodes it, and opens a streaming connection to Claude’s API. Each text delta gets forwarded to the browser as a JSON SSE event: Go 后端将图像压缩到 5MB 以下,进行 base64 编码,并打开与 Claude API 的流式连接。每个文本增量(delta)都会作为 JSON SSE 事件转发到浏览器:

data: {"delta":"import"} data: {"delta":" React from 'react';"}

The frontend accumulates the stream into a code string. Once generation finishes, the code gets injected into an iframe using document.write() — React, Babel, and Tailwind loaded via CDN. The component renders instantly with no build step. 前端将流累积成一个代码字符串。生成完成后,代码通过 document.write() 注入到 iframe 中——React、Babel 和 Tailwind 均通过 CDN 加载。组件无需构建步骤即可立即渲染。

The Bugs That Hurt

那些令人头疼的 Bug

Chunk concatenation. Claude streams tokens. import and React arrive as separate events. Early on I was joining them naively and getting importReact from 'react' — which Babel rejects. Fix: wrapped each delta in a JSON object on the Go side, read obj.delta on the frontend. JSON preserves whitespace exactly. 分块拼接。 Claude 以流式传输 Token。importReact 会作为独立的事件到达。起初我简单地将它们拼接在一起,结果变成了 importReact from 'react',这导致 Babel 报错。修复方法:在 Go 端将每个增量包装在 JSON 对象中,并在前端读取 obj.delta。JSON 能够精确保留空格。

Import statements in the iframe. The iframe loads React via CDN. If the generated code also has import React from 'react', Babel throws. Fix: stripped all imports and replaced export default before injecting. iframe 中的导入语句。 iframe 通过 CDN 加载了 React。如果生成的代码中也包含 import React from 'react',Babel 就会报错。修复方法:在注入前删除了所有导入语句,并将 export default 替换为变量赋值。

Image media type mismatch. Screenshots saved as .png sometimes contain JPEG bytes. Claude rejects the mismatch. Fix: since the Go compressor always outputs JPEG, I hardcoded image/jpeg as the declared media type regardless of the input format. 图像媒体类型不匹配。 保存为 .png 的截图有时包含 JPEG 字节,Claude 会拒绝这种不匹配。修复方法:由于 Go 压缩器总是输出 JPEG,我将媒体类型硬编码为 image/jpeg,不再考虑输入格式。

The Prompt That Works

有效的提示词 (Prompt)

You are an expert React and Tailwind CSS developer. Generate a complete, production-ready React functional component that faithfully reproduces the screenshot’s layout, spacing, colors, and typography. Tailwind utility classes only — no inline styles. Realistic placeholder text, not Lorem Ipsum. Mobile-first responsive classes. Hover and focus states on interactive elements. Return ONLY the component code, no markdown fences. Self-contained, no required props. 你是一位专业的 React 和 Tailwind CSS 开发人员。请生成一个完整的、生产就绪的 React 函数式组件,忠实还原截图中的布局、间距、颜色和排版。仅使用 Tailwind 工具类,不要使用内联样式。使用真实的占位符文本,而不是 Lorem Ipsum。采用移动优先的响应式类。为交互元素添加 Hover 和 Focus 状态。仅返回组件代码,不要使用 Markdown 代码块。组件需自包含,无需外部 props。

“No markdown fences” is critical — without it Claude wraps output in triple backticks and Babel chokes on them. “不要使用 Markdown 代码块”至关重要——否则 Claude 会用三个反引号包裹输出,导致 Babel 无法解析。

What It Actually Produces

实际产出效果

Tested on a Personal Details mobile screen, a dark SaaS landing page, and an analytic dashboard. All three came back with correct layout structure, color palette, component hierarchy, and interactive states. Light tweaking needed, but production-usable as a starting point. What it doesn’t nail: exact hex colors (approximates to nearest Tailwind value), complex animations, data-driven elements. 在个人资料移动端页面、深色 SaaS 落地页和分析仪表板上进行了测试。这三个页面的布局结构、配色方案、组件层级和交互状态都非常准确。虽然需要轻微调整,但作为起点已经可以直接用于生产。它无法完美处理的地方:精确的十六进制颜色(会近似为最接近的 Tailwind 值)、复杂的动画以及数据驱动的元素。

Cost

成本

Under $5 total — including every debug run and demo conversion during the build. Each conversion is ~500–800 prompt tokens + image tokens + ~2000 generation tokens. A few cents per screenshot. The tool replaces 30–60 minutes of manual JSX work per screen. 总成本不到 5 美元——包括构建过程中的所有调试运行和演示转换。每次转换大约消耗 500–800 个提示词 Token + 图像 Token + 约 2000 个生成 Token。每张截图仅需几美分。该工具为每个页面节省了 30–60 分钟的手动 JSX 编写时间。

The Point

核心意义

This doesn’t replace frontend engineering. It removes the part that doesn’t need one — translating static visuals into boilerplate markup. Get the structure from the screenshot, then spend your time on architecture, state, performance, and the interactions that actually require expertise. 这并不能取代前端工程。它只是去除了那些不需要人工参与的部分——即把静态视觉稿转换为样板代码。从截图中获取结构,然后将你的时间花在架构、状态管理、性能优化以及真正需要专业知识的交互逻辑上。

Code

代码

Full source on GitHub: github.com/norbertose/screenshot-figma-to-react Stack: Next.js · Go · Claude API. Clone it, swap in your ANTHROPIC_API_KEY, and run. 完整源码请见 GitHub:github.com/norbertose/screenshot-figma-to-react 技术栈:Next.js · Go · Claude API。克隆项目,替换你的 ANTHROPIC_API_KEY 即可运行。