AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Playwright Figma Scrape

skill-iml1s-flutter-claude-skills-playwright-figma-scrape · by ImL1s

|

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-iml1s-flutter-claude-skills-playwright-figma-scrape

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-iml1s-flutter-claude-skills-playwright-figma-scrape)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Playwright Figma Scrape? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

為什麼用這個 skill

Figma 官方 MCP 工具(get_design_contextget_screenshotget_metadata)有 View seat 配額限制,超限後所有 Figma MCP 工具同池鎖死。Playwright MCP 不算 Figma 配額,可以:

  • 批量抓取 — 一次抓 N 個 frame(MCP 只能一個一個)
  • DOM 提取 — 從 Figma web UI 讀 Properties panel 提 token
  • 畫 layer 結構圖 — 列出所有 node-id + 名稱建立 inventory
  • 系統對齊驗證 — Figma 實際值 vs 代碼當前值逐項對照

唯一缺陷:Playwright 拿不到 Figma MCP 獨有的 Code Connect 代碼映射。但截圖、token、layer 結構、視覺對比都完全夠用。


環境前置條件

必須

  • mcp__playwright__browser_* tools 可用(Claude Code session 有加載 Playwright MCP)
  • Figma account 已登入(瀏覽器有 session cookie 或 Chrome extension bridge 模式)
  • 知道 target Figma fileKey(從 URL 抽出)

推薦

  • 知道至少一個 nodeId 當起始點(否則從 recents 找)
  • 有 Figma PAT(Personal Access Token)備用 REST API 路徑

檢測工具可用性

ToolSearch query="select:mcp__playwright__browser_navigate,mcp__playwright__browser_resize,mcp__playwright__browser_take_screenshot,mcp__playwright__browser_evaluate,mcp__playwright__browser_press_key,mcp__playwright__browser_wait_for,mcp__playwright__browser_snapshot"

Playwright MCP 沒 load → stop + report:告訴用戶「需要重啟 Claude Code」。不要試 AppleScript / cliclick / mac-use 等野路子(見「環境合規」章節)。


核心工作流(8 步)

Step 0:Load Playwright tools

用 ToolSearch 一次 select 所有需要的 Playwright tools(見上方 detect 命令)。

Step 1:擴大 viewport

browser_resize width=1920 height=1200

預設 viewport 太窄,Figma canvas 會被側欄擠占。1920x1200 是 Figma 官方推薦的設計稿可讀寬度。

Step 2:導航到 Figma file

知道 fileKey + nodeId 時(最快)

browser_navigate url=https://www.figma.com/design/{fileKey}/?node-id={nodeA}-{nodeB}

> URL 裡 node-id 用 - 分隔(如 18912-184525),MCP tool 參數用 : 分隔(如 18912:184525)。

只知道 fileKey 不知道 nodeId

browser_navigate url=https://www.figma.com/design/{fileKey}

啥都不知道,從 recents 找

browser_navigate url=https://www.figma.com/files/recent
browser_snapshot depth=6
# 從 snapshot 找 role="group" 的 file 卡片 ref
browser_click ref={fileGroupRef} doubleClick=true

關鍵:從 recents 開啟必須 doubleClick: true,單 click 只是選中。

Step 3:等 Figma 載入

browser_wait_for time=5

Figma 是 SPA,資源載入慢。首次開啟要至少 5 秒才能互動。後續 navigate 同 file 的不同 node 只需 2-3 秒。

Step 4:切 Page(如需要)

Figma 檔案通常有多個 page,想抓的設計可能在特定 page(如「附件/紅包」)。

A. 真實 click(優先)

browser_snapshot depth=12
# 在 snapshot markdown 找目標 page 名 + ref=eXXX
browser_click ref=eXXX

B. URL 直跳 如果知道目標 page 裡任意一個 node-id,直接 browser_navigate URL 帶 node-id={nodeA}-{nodeB},Figma 自動切到該 node 所在的 page。判斷當前 page:Pages 面板選中 page 的 `aria-current="page"`。

已知坑

  • dispatchEvent(MouseEvent) 或 element.click() 切 Figma page 不會生效(Figma 的 PagesRowWrapper 監聽 React synthetic events + pointerdown/up 序列,單發 click 不觸發)
  • 必須用 mcp__playwright__browser_click 真實 click,不是 JS click

Step 5:View 調整

Figma 快捷鍵:

| 快捷鍵 | 作用 | 何時用 | |-------|------|-------| | Shift+1 | Fit view to entire page | 想看 page overview 結構 | | Shift+2 | Zoom to selected node | 精確對齊單個節點 | | Shift+0 | Zoom to 100% | 按 1:1 實際尺寸顯示 | | Cmd++ / Cmd+- | 縮放 | 微調 |

典型順序:先 Shift+1 看全貌確認方向 → 點某個 node → Shift+2 zoom 上去截圖。

Step 6:列 Layers(建 inventory)

browser_evaluate 執行 JS 從 Layers panel DOM 讀 node-id + 名稱。

基本 snippet(單次查詢)

() => {
  // Figma Layers panel 每個 row 有 data-testid="{nodeA}:{nodeB}-layers-panel-row"
  const rows = document.querySelectorAll('[data-testid$="-layers-panel-row"]');
  const out = [];
  rows.forEach(r => {
    const tid = r.getAttribute('data-testid');
    const m = tid.match(/^(.+?)-layers-panel-row$/);
    if (!m) return;
    const name = (r.innerText || r.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 60);
    out.push({ nodeId: m[1], name });
  });
  return out;
}

⚠️ Virtual scroll 限制(實測 2026-04-23 ✓):Layers panel 只渲染可見 layer。不滾動只能拿到 ~62 個 node;滾動後可拿到 111 個(本次實測數字)。必須滾動才能建完整 inventory

滾動收集 snippet(正確做法)

async () => {
  const container = document.querySelector('[class*="layersPanel"]') ||
                    document.querySelector('[data-testid*="layers"]');
  const seen = new Map();

  const collect = () => {
    document.querySelectorAll('[data-testid$="-layers-panel-row"]').forEach(r => {
      const tid = r.getAttribute('data-testid');
      const m = tid.match(/^(.+?)-layers-panel-row$/);
      if (!m) return;
      if (seen.has(m[1])) return;  // 去重
      const name = (r.innerText || '').trim().replace(/\s+/g, ' ').slice(0, 60);
      seen.set(m[1], { nodeId: m[1], name });
    });
  };

  collect();  // 收集首批可見項

  if (container) {
    const scrollStep = 300;
    let lastScrollTop = -1;
    while (container.scrollTop !== lastScrollTop) {
      lastScrollTop = container.scrollTop;
      container.scrollTop += scrollStep;
      await new Promise(r => setTimeout(r, 200));  // 等虛擬列表渲染
      collect();
    }
  }

  return [...seen.values()];
}

> 每次 scrollTop += 300 → wait 200ms(等虛擬列表重繪)→ 再 collect → 直到 scrollTop 不再變化。 > 去重靠 Map key(nodeId),合併結果即完整 inventory。

其他替代方法(當 Layers panel 收合時):

  • 用 Figma Cmd+F Find 搜名字 → 精確定位
  • 手動展開所有 group(點 chevron)後再 query

已知坑

  • node-id 看起來像 frame component 實際是 Text label —— 抓的時候 Shift+2 zoom 上去看到大字而非組件,就是命中了 Text node。要從 Layers 找父節點(通常是 Frame xxx 名的節點)。

Step 7:逐個 frame 截圖

# 對每個 frame:
browser_navigate url=https://www.figma.com/design/{fileKey}/?node-id={nodeA}-{nodeB}
browser_wait_for time=2
browser_press_key key=Shift+2
browser_wait_for time=1
browser_take_screenshot filename=/screenshots/{name}.png type=png

檔名慣例{category}-{descriptor}-{nodeA-nodeB}.png,例如:

  • bubble-lucky-rp-18912-184525.png(紅包氣泡類型)
  • detail-header-18912-184529.png(詳情頁 header)
  • animation-frame-01-28272-99441.png(動畫關鍵幀)

截圖包含側欄:Playwright browser_take_screenshot 預設截 viewport,左右側欄會被包含。要純 canvas 可以:

  • clip 參數限定區域(未來擴展)
  • 或截完後 Bash 用 sips -c 裁剪

Step 8:DOM 提取 design token

每個 frame 選中時,右側 Properties panel 顯示其 layout / typography / colors / padding / radius。JS 抽出:

() => {
  // Figma 右側 Properties panel
  const panel = document.querySelector('[class*="right_panel"]') ||
                document.querySelector('[data-testid="properties-panel"]');
  if (!panel) return { error: 'properties panel not found, selection may have changed' };

  // 全文抓(最簡單可靠)—— 實測 2026-04-23 ✓:innerText 格式穩定,可用 regex 解析
  const fullText = panel.innerText || panel.textContent || '';

  // 結構化解析(需根據實際 DOM 調整 selector)
  const sections = {};
  panel.querySelectorAll('[class*="section"]').forEach(s => {
    const title = (s.querySelector('[class*="title"]')?.innerText || '').trim();
    if (title) sections[title] = (s.innerText || '').replace(title, '').trim().slice(0, 500);
  });

  return {
    fullText: fullText.slice(0, 3000),
    sections,
  };
}

常見 token 欄位(文字中會出現):

  • Layout: Width / Height
  • Typography: Font / Weight / Size / Line height / Letter spacing
  • Colors: Hex values (e.g., #E75140)、token label(如 固定色/红包/红包颜色
  • Fills / Strokes: fill color + opacity
  • Effects: shadow (x y blur spread color alpha)
  • Padding: vertical / horizontal
  • Gap: auto layout spacing
  • Corner radius: per-corner or uniform
  • Content:Text node 的文字內容

View seat 限制下 Properties panel 能讀什麼(實測 2026-04-23 ✓)

> 很多人誤以為 View seat = Properties panel 也看不到。不對

| 可讀 ✅ | 不可讀 ❌ | |--------|---------| | Width / Height / Padding / Gap | Dev Mode code snippet(需 Editor seat) | | Colors(含 token label 如 固定色/红包/红包颜色) | Code Connect 組件映射 | | Typography(Font / Weight / Size / Line height) | Inspect panel 進階 API 數據 | | Corner radius | — | | Content(Text node 文字) | — | | Modes / Component properties | — | | Export 設定 | — |

結論:View seat 下 innerText 抽 Properties panel 完全可用,能拿到所有視覺 token。只有代碼生成相關功能需要升 seat。


高階 Pattern

Pattern 1:系統性 frame inventory

抓完 Layers 後建 JSON 存檔:

// 存到 .omc/figma-snapshots//frame-inventory-raw.json
const inventory = [... /* from Step 6 snippet */];
// 按名稱前綴分類(如 "Frame xxx" = 設計稿 frame,"T xxx" = Text label)

然後逐個 navigate + screenshot,把 inventory 內容擴充 screenshotPath 欄位。

Pattern 2:Figma vs 代碼 token 對照

  1. Step 8 提取當前 frame token
  2. Read 代碼的 colors.dart / font.dart / theme.dart
  3. 生成對照表:
| Token | Figma 原始值 | 當前代碼 | 一致? |
| xxx | #E75140 | 0xFFE75140 | ✅ |
| yyy | rgba(189,88,78,0.10) | 0x1ABD584E | ✅ |
| zzz | (Figma 無此 token) | 0x40BD584E | ⚠️ code 獨有 |

Pattern 3:動畫關鍵幀抓取

Figma 沒有原生動畫時序,但設計師會畫連續多個 frame 表示動畫各階段。命名如:

  • animation-open-01-start
  • animation-open-02-scale-up
  • animation-open-03-reveal

抓的時候按順序 screenshot,檔名保留順序 animation-{stage}-{nn}-{nodeId}.png,方便之後逐幀對齊實現。

Pattern 4:REST API fallback(PAT 有時)

如果有 Figma PAT(不是 View seat 限制的 MCP token,是個人 API token),可繞開 Playwright:

# 單 node screenshot(PNG)
curl -H "X-FIGMA-TOKEN: $PAT" \
  "https://api.figma.com/v1/images/{fileKey}?ids={nodeId}&format=png&scale=2" | jq -r '.images["{nodeId}"]' | xargs curl -o {out}.png
# Node metadata(含完整 layer tree + style)
curl -H "X-FIGMA-TOKEN: $PAT" \
  "https://api.figma.com/v1/files/{fileKey}/nodes?ids={nodeId}"

PAT 存 Keychain

security add-generic-password -s "figma-pat" -a "$USER" -w "" -U
# 讀取
PAT=$(security find-generic-password -s "figma-pat" -a "$USER" -w)

已知坑(別再踩)

| ✗ 不要 | 原因 | |-------|-----| | dispatchEvent(MouseEvent)element.click() 切 Figma page | Figma 監聽 React synthetic events + pointerdown/up 序列,單發 click 不觸發 | | mac-use-mcp__click | 操作的是真實用戶 Chrome,不是 Playwright 的 browser 實例 | | / 快捷鍵搜 node | Figma / 是 Comment | | Cmd+P | Figma Quick Actions 選單,不能搜 node | | Cmd+Shift+C 想拿 SVG | 是 Copy as PNG,不是 SVG。要 SVG 走 Properties → Export panel | | 靠 a[href] 查找 recents 文件 | Figma recents 卡片用 role="group",不是 anchor | | Shift+2 看到大字 = 組件 | 可能是 Text label(不是 frame),要從 Layers 找父節點 | | 靠視覺「猜」設計規格 | 必須用 DOM 抽精確值,不要用估 | | PageDown 鍵在 Figma canvas 上按 | PageDown 會切換整個 Figma Page(不是 scroll canvas!)實測 2026-04-23 ✓:按 PageDown → 跳去下一個 page(如「聯系人·發現」),截圖就錯了。滾動 canvas 要用 browser_scroll 或 Layers panel container scroll,不要用 PageDown | | 不滾 Layers panel 直接 query | 只拿到可見 ~62 個 node,完整 inventory 需滾動收集(見 Step 6 滾動 snippet)|

Text label 判斷法(實測 2026-04-23 ✓)

navigate 到一個 node → Shift+2 zoom → 若畫面中央出現 超大字(如 84px「幸運紅包」),這是 Figma 文件內部分區標題 Text label,不是用戶可見的 UI component。

快速辨識:

  1. Properties panel 右側看 Typography 區:出現 Font / Weight / Size 就是 Text node
  2. Layers panel 該行有 T icon(Text),Frame icon 是方塊
  3. 尺寸是 {n×84}px(每個漢字 84px 寬),高度固定 84px

確認是 Text label 後,按 Escape 跳到父節點(Layers 面板自動選中父層)。找 Frame 14200XXXXX控制台 命名的 Frame 才是真正的 UI component。

Escape 跳父節點法(實測 2026-04-23 ✓)

在 Figma canvas 已選中某節點時按 Escape,會跳到該節點的直接父節點(等同 Layers panel 往上一層)。本次實測:從 Text label 18912:184525(幸運紅包)按 Escape 後跳到父 Frame 12116:222139(page root frame),確認氣泡 UI 無獨立 component 節點。

用法

  1. navigate 到未知節點
  2. Shift+2 zoom 確認是 Text label 或 sub-layer
  3. Escape → 看 URL + Layers panel 選中項變化 → 新 node-id 即父節點
  4. 重複 Escape 可沿樹向上爬,直到找到目標 Frame

Figma annotation text 藏 UX 決策(實測 2026-04-23 ✓)

截圖只捕捉視覺 UI。Figma 文字標注(設計師在 canvas 上附加的說明文字)含有截圖不可見的架構決策。

本次實測:node 18912:184683 的 annotation text 為「查看詳情入口進入該頁面的都帶返回按鈕」,揭示詳情頁是 full-screen page(非 modal),這是與代碼現狀最大的架構偏離。純靠截圖無法發現。

操作方式

// 從 Properties panel innerText 抽取 annotation / comment
() => {
  const panel = document.querySelector('[class*="right_panel"]');
  return panel ? panel.innerText.slice(0, 3000) : 'not found';
}

或直接 browser_snapshot depth=12 看 Figma Annotations 面板(右側面板切換到「Annotations」tab)。

何時特別重要

  • 「這頁怎麼打開」(push vs modal)
  • 「有沒有返回按鈕」
  • 「是否支持手勢關閉」
  • 任何涉及導航方式的 UX 決策

Mobile mockup 內部 UI 無獨立 Figma node

Figma 設計師會把 UI 放在 mobile 手機框 mockup 內,mockup 內的 UI sub-layer 不是獨立 reusable component,無獨立 node-id 可直接訪問。

本次實測:紅包氣泡 UI 是 page root frame 12116:222139 下的 mobile mockup sub-layer。9 個紅包 Text label 的父節點全部指向 12116:222139(page root),表示氣泡無獨立 component。

含義

  • 不要期望每個 UI 元素都有獨立 node-id
  • 無 node-id 的 UI → 以代碼現狀為準(不等 Figma node 抓取)
  • 想看 mockup 內部 UI → 截 parent frame + Shift+1 全局截圖,用截圖推算比例

環境合規:別做疑似惡意軟體行為

> 企業環境可能裝有 EDR(如 CrowdStrike Falcon Sensor),任何看起來像惡意軟件的自動化手法會觸發安全告警。

❌ 禁止

  • 隱藏 / 最小化 Terminal 視窗(「想偷偷切換 app」= 惡意軟件典型手法)
  • AppleScript 跨 process event(tell application "Chrome" to ...)—— EDR 攔截,timeout -1712
  • 操作用戶前台視窗(user 正在用的 Chrome / VSCode / IM app 等)
  • cliclick / 鍵盤模擬 / 滑鼠模擬搶焦點
  • 任何「偷偷進行」或「繞過 UI」的 workaround

✅ 正確做法

  • Playwright MCP — Chrome extension bridge 模式。本 skill 推薦
  • Figma REST API + PAT — 純 HTTP 零 UI 操作
  • MCP 工具不可用 → 停 + 報告,不試其他 stealth 手段
  • 寧可任務失敗,不觸發安全警報

Playwright MCP 的 browser 實際是什麼

本 skill 實測(2026-04-23):mcp__playwright__browser_* 工具走 Chrome extension bridge(URL 顯示 chrome-extension://mmlmfjhmonkocbjadbfplnigmagldckm/connect.html),是 Chrome 原生 extension API 代理用戶 Chrome,不是完全 isolated Chromium。

含義

  • ✅ 不觸發 EDR 惡意軟件檢測(是 Chrome 原生行為)
  • ⚠️ 會操作用戶真實 Chrome tab(會開新 tab 或佔用現有 tab)
  • ⚠️ 依賴用戶 Chrome 已登入 Figma(session cookie)

如果嚴格要求 isolated browser(不碰用戶 Chrome),需要另用 Playwright CLI(非 MCP)或 Puppeteer with --user-data-dir=


失敗模式 + 復原

| 失敗 | 診斷 | 復原 | |-----|------|-----| | browser_navigate 報 timeout | Figma 載入慢 / 網路問題 | 增加 browser_wait_for time=10,重試一次 | | browser_take_screenshot 只拿到空白畫布 | Figma 還沒完全渲染 | Shift+1 fit view + wait 3s 再截 | | browser_evaluate 返回空 [] | Layers panel 收合了 / virtual scroll | Cmd+F Find 定位目標後再 query;或展開所有 group | | Playwright MCP 工具不可用 | Claude Code session 沒 register | 停 + 重啟 Claude Code,不要切 AppleScript / cliclick | | Figma 顯示 "Request access" | Dev Mode / Code Connect 需要 seat 升級 | 不拿 code,只拿 screenshot + DOM token | | File 顯示 login page | Chrome extension bridge 沒登入 Figma | 用戶在 Chrome 裡手動登入 Figma 後重試 | | 抓的 screenshot 側欄佔一半 | viewport 太小 | browser_resize 1920x1200 + 按 \\ 切全屏模式(Figma 預設 shortcut) |


完整 workflow template(可複製)

# 1. Load tools
ToolSearch "select:mcp__playwright__browser_navigate,browser_resize,browser_take_screenshot,browser_evaluate,browser_press_key,browser_wait_for,browser_snapshot"

# 2. Prep
browser_resize 1920x1200
browser_navigate https://www.figma.com/design/{fileKey}/?node-id={root}
browser_wait_for time=5

# 3. Build inventory (Step 6 snippet)
browser_evaluate ""
# → save to .omc/figma-snapshots/{feature}/frame-inventory-raw.json

# 4. Overview screenshots (Shift+1 per section root)
for section in [附件, 紅包皮, 發包, ...]:
  browser_navigate url=...?node-id={section-root}
  browser_wait_for time=2
  browser_press_key key=Shift+1
  browser_wait_for time=1
  browser_take_screenshot filename=section-{name}.png

# 5. Detail screenshots (Shift+2 per frame)
for frame in inventory:
  browser_navigate url=...?node-id={frame.nodeId}
  browser_wait_for time=2
  browser_press_key key=Shift+2
  browser_wait_for time=1
  browser_take_screenshot filename=frame-{frame.name}-{frame.nodeId}.png
  browser_evaluate ""
  # → append token to tokens-raw.json

# 6. Generate outputs
# frame-inventory.md(人類可讀版 inventory)
# tokens.md(Figma vs 代碼對照)
# README.md(抓取狀態彙總)

產出結構建議

.omc/figma-snapshots/{feature}/
├── README.md               # 抓取狀態彙總(成功/失敗/Phase 歸屬)
├── frame-inventory.md      # 人類可讀 frame 清單
├── frame-inventory-raw.json # 原始 inventory 數據
├── tokens.md               # Figma vs 代碼對照
├── tokens-raw.json         # 原始 DOM token
└── screenshots/
    ├── section-01-attachment.png
    ├── section-02-theme.png
    ├── frame-bubble-lucky-18912-184525.png
    ├── frame-detail-header-18912-184529.png
    ├── animation-open-01-xxx.png
    └── ...

觸發關鍵詞

當用戶說以下任何一個,考慮用本 skill:

  • 「抓 Figma 設計稿」「批量截圖 Figma」「提 Figma token」
  • 「Figma MCP 用不了」「View seat 限額」「tool call limit」
  • 「對齊 Figma」「Figma vs 代碼」「驗證 Figma」
  • 「列 Figma frame」「建 Figma inventory」
  • 「用 Playwright 抓 Figma」「繞開 Figma MCP」

Related skills

  • figma-use — use the official Figma MCP when quota is available (preferred). playwright-figma-scrape is a fallback for when Figma MCP hits View seat limits.
  • verify-ui — use after playwright-figma-scrape to do visual comparison verification between Figma mockups and actual code.
  • **visual-verdict

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.