web-design-harvester
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는 모든 유형에서 작동하지만, 노드 엔드포인트는
그렇지 않습니다.
브라우저 앞에 페이지를 가져오기
이 부분이 사람들을 헷갈리게 만드는 부분이라 정확히 설명할 가치가 있습니다.
보유한 것 | 작동하나요? | 방법 |
게시된 사이트 | ✅ 예 | URL을 그냥 전달하세요. 일반 공개 페이지입니다. |
미리보기 iframe | ❌ 아니요 | 아래 참조. |
게시되지 않은 사이트, Chrome에서 열린 상태 | ✅ 예 |
|
기타 모든 사이트, 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옵션 | 기본값 | |||||
|
| 출력 디렉터리 | ||||
|
| 브레이크포인트, 예: |
| auto | 블록 경계 강제 | |
|
| 페이지 안정화 후 추가 대기 시간 | ||||
|
| 블록당 노드 상한 | ||||
| 에셋 다운로드 및 분석 건너뛰기 | |||||
| 먼저 출력 디렉터리 비우기 | |||||
| 브라우저 창 표시 | |||||
| 프로필 재사용, 실행 간 로그인 유지 | |||||
| 실행 중인 Chrome에 연결 (포트 또는 ws:// URL) | |||||
| 기계 판독 가능한 stdout |
익숙하지 않은 페이지에서는 outline 또는 blocks부터 시작하세요. 빠르고
전체 실행을 시작하기 전에 자동 분할이 합리적인 섹션을 찾았는지 알려줍니다.
node bin/harvest.mjs blocks https://figma.site --widths 1440strategy: 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 hashblock.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 내보내기는 1440px 디자인에
1798 이미지 픽셀을 넣습니다 — 모든 측정값을 먼저 1.2486으로 나눠야 했고, 잘못
나누면 그럴듯하지만 틀린 숫자가 나왔습니다.)
계산 스타일은 덤프가 아니라 정제됩니다. 모든 요소에 세 가지 필터가
실행됩니다: 해당 태그의 UA 기본값은 제거되고, 부모가 이미 명시한 상속 값은
제거되며, 거의 모든 노드에 나타나는 선언(box-sizing: border-box 등)은
추출되어 한 번만 명시됩니다. 남는 것은 차이가 나는 것뿐이며, 그것이 실제로
작성해야 하는 것입니다. 실제로 이는 원시 덤프보다 약 한 자릿수 더 작습니다.
에셋은 추측이 아니라 측정됩니다. 모든 이미지와 비디오에 대해 도구는 프레임을
디코딩하고 알파 채널에서 콘텐츠 경계 상자를 찾습니다. 디자인 에셋은 흔히
1200×1200 정사각형으로 제공되면서 아트워크는 중앙에서 벗어난 1049×677 영역을
차지합니다 — 파일 크기만으로는 보이지 않으며, object-contain(죽은 공간)과
object-cover + center(축에서 벗어난 크롭) 모두 틀립니다. 출력은 사용할
object-position을 명시합니다.
알파가 있는 VP9 WebM은 특별히 처리됩니다: ffprobe는 pix_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 Chromium —
npm install이 postinstall 훅을 통해 가져옵니다ffmpeg / ffprobe (선택 사항) — 콘텐츠 박스, 팔레트 및 비디오 분석에 필요합니다. 없어도 다른 모든 것은 실행됩니다; 에셋 인텔리전스는 경고와 함께 건너뜁니다.
brew install ffmpeg
npm test # 46 tests, ~10s, hermetic (local fixture, no network)알려진 제한 사항
교차 출처 iframe은 DOM과 스크린샷 모두에서 구멍입니다. 도구는 이를 감지하고 크기, 출처 및
src를block.md에 나열하지만 내부를 볼 수는 없습니다. 프레임이 렌더링하는 것은 별도로 처리해야 합니다.호버 및 포커스 스타일은 캡처되지 않습니다 — 라이브 상호작용이 필요합니다.
interactions.md는 각 요소의 transition 속성과 지속 시간을 제공하여 무엇이 어떻게, 얼마나 빠르게 애니메이션되는지 알려주지만 최종 상태는 알려주지 않습니다.스트리밍 비디오 (DASH/fMP4)는 유효한 독립 파일이 아닌 세그먼트로 도착합니다. 손상된 것으로 보고되지 않고 레이블이 지정됩니다.
Canvas 및 WebGL 콘텐츠는 스크린샷에서 픽셀로 캡처됩니다. 추출할 구조가 없습니다.
스크롤 기반 애니메이션은 한 지점에서 샘플링됩니다. 페이지는 리빌을 트리거하기 위해 먼저 끝까지 스크롤된 다음 맨 위로 돌아갑니다; 스크롤 위치에 따라 나타나는 섹션은 최종 상태가 아닐 수 있습니다.
This server cannot be installed
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.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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