Skip to main content
Glama
ChenYCL

web-design-harvester

by ChenYCL

web-design-harvester

将渲染后的网页转化为 LLM 可据以构建的设计规格:逐区块截图、提炼后的计算样式(computed CSS)、设计令牌、响应式差异,以及分析到 alpha 通道级别的资源。

专为复刻 Figma Sites 页面而构建,但其中没有任何 Figma 专属内容——它适用于任何能渲染的 URL。

npm install
node bin/harvest.mjs https://example.figma.site --out ./spec --clean
# then point a model at ./spec/README.md

为什么存在

复刻一个设计过去通常是这样的流程:在 Figma 中选择一个区块 → 复制全部 CSS → 将 2000 多行粘贴到聊天中 → 模型从中挖出少数几个关键值 → 对不一致处截图 → 重复,七八次。

每一步都是机械性的,而且源材料比看起来更糟:Figma 的 CSS 导出带有旋转后坐标不可读的负值 frame、display: none 占位图层,以及交错排列的桌面端和移动端变体。

渲染后的 DOM 没有这些问题。在活动页面上调用 getComputedStyle() 得到的是解析后的真实值,可在任意断点获取,并附带网络的资源列表。本工具读取这些信息并将其记录下来。

Figma 的 REST API 不可行

对于 editorType: "sites""make" 的文件,GET /v1/files/{key} 会返回 400 "File type not supported by this endpoint"。只有经典的 design 文件可读。在规划任何提取之前,先检查 /v1/files/{key}/meta——/meta/styles 适用于所有类型,节点端点则不适用。


让页面呈现在浏览器中

这是最容易让人栽跟头的部分,因此值得精确说明。

你拥有的内容

是否可行?

方法

已发布站点 https://<name>.figma.site

✅ 是

直接传入 URL 即可。这是一个普通的公开页面。

预览 iframe https://<uuid>-v2-figmaiframepreview.figma.site

见下文。

未发布站点,已在你的 Chrome 中打开

✅ 是

--cdp——见下文。

任何其他站点、localhost、staging

✅ 是

直接传入 URL 即可。

预览 iframe URL 无法独立工作

它看起来像一个页面并返回 HTTP 200,但获取它只会得到一个约 3.6KB 的空壳,其中仅包含一个 postMessage 监听器。它本身没有任何内容:

// what that URL actually serves, in full:
window.addEventListener('message', (e) => {
  if (isAllowedOrigin(e.origin)) {          // only figma.com and friends
    if (e.data.type === 'iframe-init') {
      script.src = e.data.initScriptURL      // ← the real app comes from the parent

站点的代码通过 MessagePort已登录的 figma.com 标签页传来。直接加载该 URL 只会得到空白文档,无论等待多久。没有可提供的令牌,也没有可设置的请求头——内容根本不存在。

对于未发布站点:附加到你自己的浏览器

以远程调试模式启动 Chrome,登录 Figma,打开站点的 Preview,然后将 harvester 指向该标签页:

# 1. Chrome with a debugging port (use a separate profile to avoid clobbering yours)
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --remote-debugging-port=9222 --user-data-dir=/tmp/figma-profile

# 2. Log into figma.com in that window, open your Sites file, hit Preview.

# 3. Harvest the rendered iframe
node bin/harvest.mjs "https://<uuid>-v2-figmaiframepreview.figma.site" \
  --cdp 9222 --out ./spec

使用 --cdp 时,工具会附加到你的浏览器,不会启动或关闭任何东西。如果条件允许,更简单的替代方案是:发布站点,然后采集公开 URL。

对于位于登录墙之后、你不想每次运行都重新输入的站点,--persist 会在磁盘上保留配置文件,供多次运行之间复用。


使用方法

harvest <url> [options]              full harvest -> spec directory
harvest outline <url>                print the DOM outline (recon)
harvest blocks <url>                 list blocks that would be captured
harvest asset <file...>              analyse local media files
harvest serve [--port 8787]          HTTP daemon, browser stays warm
harvest mcp                          MCP server on stdio

选项

默认值

--out <dir>

./out

输出目录

--widths <list>

1440,375

断点,例如 1440,768,375

--selector <css>

auto

强制指定区块边界

--settle <ms>

800

页面稳定后的额外等待时间

--max-nodes <n>

400

每个区块的节点上限

--skip-assets

跳过下载和分析资源

--clean

先清空输出目录

--headed

显示浏览器窗口

--persist [dir]

复用配置文件,在多次运行之间保留登录状态

--cdp <endpoint>

附加到正在运行的 Chrome(端口或 ws:// URL)

--json

机器可读的 stdout

在不熟悉的页面上,先从 outlineblocks 开始。它们运行很快,能让你在投入完整运行之前了解自动分割是否找到了合理的区块。

node bin/harvest.mjs blocks https://figma.site --widths 1440
strategy: semantic-landmarks
coverage: 100% (11248 of 11248px)

  01  header.fig-suku18       1440×78 @0  [sticky]  What you can do in figma
  02  section.fig-lqoz33    1440×1109 @78            Figma Sites
  03  section.fig-15ba1hq   1440×1117 @1187          Perfect websites every time…
  …

如果边界不正确,传入 --selector "main > section"


输出

spec/
  README.md          ← start here; index, warnings, token summary
  index.json         machine-readable manifest
  tokens.md          design tokens ranked by usage
  tokens.css         the same tokens as CSS custom properties
  responsive.md      every value that changes between breakpoints
  interactions.md    clickable/focusable elements and their transitions
  warnings.json      asset fit problems, in full
  page-desktop.png   full-page screenshot per breakpoint
  page-mobile.png
  blocks/
    02-figma-sites/
      block.md       ← spec sheet for one section
      desktop.png    screenshot, exactly the block's size
      mobile.png
      tree.desktop.json   exact computed values, full precision
      tree.mobile.json
  assets/
    README.md        every asset with content box and fit guidance
    manifest.json
    <files>          deduplicated by content hash

block.md 看起来像这样:

section.fig-lqoz33            1440×1108.6  pad:0/0/32/0  relative  bg:#ffffff
└─ div.fig-umtrpl             1440×1076.6  flex-col  gap:64  pad:64/0/0/0
   ├─ h1.fig-6late5              660×72     mar:0/0/32/0  72/72  ls:-1.44  "Figma Sites"
   └─ a.fig-1jz30fp            135×46.4     flex-row  jc:center  pad:12/22
                                            #ffffff  bg:#000000  r:8  href:/site/new

此外还有每个断点的几何信息、文案、所用资源,以及响应式差异表。旁边的 JSON 包含未删减的完整值,供出现异常时参考。


它能做到而截图做不到的事

截图中 1 CSS 像素 = 1 图像像素。 deviceScaleFactor: 1 加上 scale: 'css' 意味着从 PNG 上量出的距离就是 CSS 像素。无需换算系数,因此不会出现换算错误。(Figma 的 @2x 导出将 1798 个图像像素对应到 1440px 的设计——每项测量都需要先除以 1.2486,而算错就会产生看似合理实则错误的数字。)

计算样式是提炼而非倾倒。 对每个元素运行三个过滤器:丢弃该标签的 UA 默认值,丢弃父元素已声明的继承值,并将几乎每个节点上都出现的声明(box-sizing: border-box 等)提升出来只声明一次。保留下来的就是有差异的部分,也就是你真正需要编写的部分。实际上,这比原始转储大约小一个数量级。

资源是测量而非猜测。 对于每张图片和视频,工具会解码一帧并从 alpha 通道找出内容边界框。设计资源通常以 1200×1200 的正方形交付,而实际图形只占据一个偏离中心的 1049×677 区域——仅从文件尺寸完全看不出来,object-contain(留白)和 object-cover + 居中(偏离轴心裁剪)都会出错。输出会指明应使用的 object-position

带 alpha 通道的 VP9 WebM 需要特殊处理:ffprobe 报告 pix_fmt=yuv420p 且不显示 alpha 通道,但浏览器能正确合成。只有强制使用 libvpx-vp9 解码器时 alpha 通道才会显现。

不可能实现的布局在第一次运行时就指出。 当资源的内容比例与其所在盒子的比例严重不一致时,任何 object-fit 值都无法修复——资源需要重新导出。README 会立即标记这一点,并给出 cover 会丢弃的图形百分比,而不是让你花六轮时间调整 CSS 去修复一个导出问题。

两个断点,因为规格的一半在于差异。 卡片圆角 12px → 6px,标题 20/30 → 16/24,页头内边距 32px → 32px(未变)。这些都无法通过缩放推导出来;responsive.md 列出了每一个发生变化的数值。

任意数量的断点。 --widths 1440,768,375 捕获三个断点,一切随之扩展:每个断点一张截图和一棵样式树,tokens.md 中按断点分别统计使用次数,以及每个相邻对的差异表——desktop → tablet,然后是 tablet → mobile。采用相邻对比而非全部与桌面端对比,因为这反映了媒体查询的编写方式:每一步只重述自上一步以来发生的变化。responsive.md 以矩阵开头,显示哪些区块在哪一步发生变化。

没有任何内容被静默丢弃。 分割之后,工具会检查区块是否铺满整个页面,寻找覆盖任何间隙的元素,并报告覆盖率。确实无法覆盖的区域会被列出而非忽略。截图尺寸会与请求的尺寸进行核对,因为截断的捕获比失败的捕获更糟——它看起来正常,但基于它的每项测量都会悄悄出错。


为模型提供服务

冷启动运行的大部分时间花在浏览器启动和首次绘制上。如果模型在迭代——重新检查那个区块,现在在 768px 下,那个图标是什么颜色——每次提问都付出这个代价会让工具无法使用。两种服务器模式都能保持浏览器及其已加载页面处于热状态。

https://figma.site 上实测:冷启动 26.8 秒 → 热状态 0.03 秒。

MCP (stdio)

{
  "mcpServers": {
    "web-design-harvester": {
      "command": "node",
      "args": ["/absolute/path/to/web-design-harvester/bin/harvest.mjs", "mcp"]
    }
  }
}

工具:harvest_outlineharvest_blocksharvest_blockharvest_tokensharvest_assetsharvest_screenshotharvest_analyse_assetharvest_siteharvest_status

典型循环是先调用 harvest_blocks 找到区块,再调用 harvest_block 获取其结构——第二次调用只需几十毫秒,因为页面已经打开。

HTTP 守护进程

node bin/harvest.mjs serve --port 8787
curl "http://127.0.0.1:8787/blocks?url=https://figma.site&width=1440"
curl "http://127.0.0.1:8787/block?url=https://figma.site&index=4"

仅绑定到 loopback——它会获取任意 URL 并按指示写入文件,因此不应可从外部访问。如果你确实需要,可以传入 --host。空闲页面在 10 分钟后关闭。


环境要求

  • Node 18+

  • Playwright Chromiumnpm install 通过 postinstall 钩子获取

  • ffmpeg / ffprobe (可选) — 用于内容框、调色板和视频分析。没有它其余功能仍可运行;资源智能分析会被跳过并给出警告。brew install ffmpeg

npm test    # 46 tests, ~10s, hermetic (local fixture, no network)

已知限制

  • 跨域 iframe 是 DOM 和截图中的空洞。工具能检测到它们,并在 block.md 中列出其大小、来源和 src,但无法看到内部。iframe 渲染的任何内容都需要单独处理。

  • 悬停和聚焦样式不会被捕获——它们需要实时交互。interactions.md 会给出每个元素的过渡属性和时长,告诉你什么会动画以及动画速度,但不包含最终状态。

  • 流媒体视频(DASH/fMP4)以分片形式到达,这些分片不是有效的独立文件。它们会被标记,而不会被报告为损坏。

  • Canvas 和 WebGL 内容在截图中以像素形式捕获;没有可提取的结构。

  • 滚动驱动动画只在一个时间点采样。页面会先从头到尾滚动以触发显现效果,然后回到顶部;外观依赖于滚动位置的区块可能不处于其最终状态。

-
license - not tested
Not graded
quality - not tested
C
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Turn any live website into brand colors, fonts, design tokens, SVGs, Lottie and paste-ready code.

  • UI design from prompts, screenshots, and URLs for AI coding agents and theme tokens.

  • Score any URL against a real design contract — 40 checks, A-F grade, token + motion validation.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ChenYCL/web-design-harvester'

If you have feedback or need assistance with the MCP directory API, please join our Discord server