Skip to main content
Glama
ChenYCL

web-design-harvester

by ChenYCL

web-design-harvester

렌더링된 웹 페이지를 LLM이 빌드할 수 있는 디자인 스펙으로 변환합니다: 섹션별 스크린샷, 정제된 계산 CSS, 디자인 토큰, 반응형 델타, 그리고 알파 채널까지 분석된 에셋.

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에서 블록 선택 → Copy all CSS → 2000줄이 넘는 코드를 채팅에 붙여넣기 → 모델이 중요한 몇 가지 값을 찾아내기 → 불일치 부분 스크린샷 → 일곱 번, 여덟 번 반복.

그 과정의 모든 단계가 기계적이고, 원본 자료는 보기보다 나쁩니다: Figma의 CSS 내보내기는 읽을 수 없는 음수 좌표를 가진 회전된 프레임, display: none 플레이스홀더 레이어, 데스크톱과 모바일 변형이 뒤섞여 있습니다.

렌더링된 DOM에는 그런 문제가 없습니다. 라이브 페이지에서 getComputedStyle()을 호출하는 것은 해석된 진실입니다. 원하는 어떤 브레이크포인트에서든, 네트워크의 에셋 목록이 첨부된 상태로 말이죠. 이 도구는 그것을 읽고 기록합니다.

Figma REST API는 선택지가 아님

GET /v1/files/{key}editorType: "sites" 또는 "make"인 파일에 대해 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, 스테이징

✅ 예

URL을 그냥 전달하세요.

미리보기 iframe URL은 단독으로 작동하지 않음

페이지처럼 보이고 HTTP 200을 반환하지만, 가져오면 postMessage 리스너만 포함된 ~3.6KB 셸만 얻을 수 있습니다. 자체 콘텐츠가 없습니다:

// 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

사이트의 코드는 로그인된 figma.com 탭MessagePort를 통해 도착합니다. URL을 직접 로드하면 아무리 기다려도 빈 문서가 표시됩니다. 제공할 토큰도, 설정할 헤더도 없습니다 — 콘텐츠가 그냥 거기에 없습니다.

게시되지 않은 사이트: 자신의 브라우저에 연결

원격 디버깅으로 Chrome을 시작하고, Figma에 로그인하고, 사이트의 미리보기를 연 다음, 하베스터를 해당 탭에 연결하세요:

# 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

익숙하지 않은 페이지에서는 outline 또는 blocks부터 시작하세요. 빠르고 전체 실행을 시작하기 전에 자동 분할이 합리적인 섹션을 찾았는지 알려줍니다.

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: 1scale: 'css'를 함께 사용하면 PNG에서 측정한 거리가 CSS 픽셀입니다. 변환 계수가 없으므로 변환 실수도 없습니다. (Figma의 @2x 내보내기는 1440px 디자인에 1798 이미지 픽셀을 넣습니다 — 모든 측정값을 먼저 1.2486으로 나눠야 했고, 잘못 나누면 그럴듯하지만 틀린 숫자가 나왔습니다.)

계산 스타일은 덤프가 아니라 정제됩니다. 모든 요소에 세 가지 필터가 실행됩니다: 해당 태그의 UA 기본값은 제거되고, 부모가 이미 명시한 상속 값은 제거되며, 거의 모든 노드에 나타나는 선언(box-sizing: border-box 등)은 추출되어 한 번만 명시됩니다. 남는 것은 차이가 나는 것뿐이며, 그것이 실제로 작성해야 하는 것입니다. 실제로 이는 원시 덤프보다 약 한 자릿수 더 작습니다.

에셋은 추측이 아니라 측정됩니다. 모든 이미지와 비디오에 대해 도구는 프레임을 디코딩하고 알파 채널에서 콘텐츠 경계 상자를 찾습니다. 디자인 에셋은 흔히 1200×1200 정사각형으로 제공되면서 아트워크는 중앙에서 벗어난 1049×677 영역을 차지합니다 — 파일 크기만으로는 보이지 않으며, object-contain(죽은 공간)과 object-cover + center(축에서 벗어난 크롭) 모두 틀립니다. 출력은 사용할 object-position을 명시합니다.

알파가 있는 VP9 WebM은 특별히 처리됩니다: ffprobepix_fmt=yuv420p를 보고하고 알파 채널을 표시하지 않지만, 브라우저는 올바르게 합성합니다. 알파는 libvpx-vp9 디코더를 강제할 때만 나타납니다.

불가능한 레이아웃은 첫 실행에서 지적됩니다. 에셋의 콘텐츠 비율과 그것이 놓인 박스가 심하게 불일치하면 어떤 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_outline, harvest_blocks, harvest_block, harvest_tokens, harvest_assets, harvest_screenshot, harvest_analyse_asset, harvest_site, harvest_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"

루프백에만 바인딩됩니다 — 임의의 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과 스크린샷 모두에서 구멍입니다. 도구는 이를 감지하고 크기, 출처 및 srcblock.md에 나열하지만 내부를 볼 수는 없습니다. 프레임이 렌더링하는 것은 별도로 처리해야 합니다.

  • 호버 및 포커스 스타일은 캡처되지 않습니다 — 라이브 상호작용이 필요합니다. interactions.md는 각 요소의 transition 속성과 지속 시간을 제공하여 무엇이 어떻게, 얼마나 빠르게 애니메이션되는지 알려주지만 최종 상태는 알려주지 않습니다.

  • 스트리밍 비디오 (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