Install
$ agentstack add skill-iml1s-flutter-claude-skills-figma-playwright-fallback ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
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 →About
为什么需要这个
Figma MCP 工具(get_design_context、get_screenshot、get_metadata)对 View seat 用户有 限额。打到上限后所有 Figma MCP 工具同池锁死。Playwright MCP 不算 Figma 配额,所以 可以用浏览器直进 Figma web 操作。
唯一缺陷:Playwright 拿不到 MCP 独有的 Code Connect 代码转换。但看 layout、找 node-id、 读颜色 token、截图对比都完全够用。
已知坑(别再踩)
| ✗ 不要 | 原因 | |-------|-----| | dispatchEvent(MouseEvent) 或 element.click() 切 Figma page | Figma 的 PagesRowWrapper 监听 React synthetic events + pointerdown/up 序列,单发 click 不触发 | | mac-use-mcp__click | 它操作的是真实用户 Chrome,不是 Playwright 的 Chromium | | / 快捷键搜 node | Figma / 是 Comment | | Cmd+P | Figma Quick Actions 选单,不能搜 node | | Cmd+Shift+C 想拿 SVG | 那是 Copy as PNG,不是 SVG。走 Properties → Export panel(见步骤 6.5) | | 靠 a[href] 查找 recents 文件 | Figma recents 卡片用 role="group",不是 anchor | | 靠视觉"猜" logo path 比例 | 必须用步骤 6.5 拿 Figma 原始 SVG path。用户明确说过"不要用猜的" |
标准工作流
步骤 0:先 load 工具
ToolSearch query="select:mcp__playwright__browser_navigate,mcp__playwright__browser_snapshot,mcp__playwright__browser_click,mcp__playwright__browser_evaluate,mcp__playwright__browser_press_key,mcp__playwright__browser_take_screenshot,mcp__playwright__browser_resize,mcp__playwright__browser_wait_for"
步骤 1:扩大 viewport(默认太窄,canvas 被侧栏挤占)
browser_resize width=1920 height=1200
步骤 2:入口
知道 fileKey 和 nodeId 时 —— 直接 URL
browser_navigate url=https://www.figma.com/design/{fileKey}/?node-id={nodeA}-{nodeB}
URL 里 node-id 用 -,传给 Figma MCP 工具时用 :。
不知道 fileKey 时 —— 从 recents 找
browser_navigate url=https://www.figma.com/files/recent
browser_snapshot depth=6 # 拿 role="group" 的 file 卡片 ref
browser_click ref={fileGroup} doubleClick=true
关键:必须 doubleClick: true 才打开文件,单 click 只是选中。
步骤 3:切 page
Pages 面板的 row 是 [data-testid="PagesRowWrapper"]。JS .click() 和 dispatchEvent 都打不过 Figma 的 page 切换。两种可行方式:
A. 用 Playwright 真 click(优先):
browser_snapshot depth=12
# 在 snapshot 的 .md 文件里找目标 page 名 → 拿 ref=eXXX
browser_click ref=eXXX
B. 直接 URL 跳: 如果知道目标 page 上任意一个 node 的 node-id,直接 browser_navigate URL 里带 node-id={nodeA}-{nodeB},Figma 会自动切到那个 node 所在的 page。判断当前在哪个 page 的标记:Pages 面板里 选中 page 行的 ` 带 aria-current="page"`。
检查当前 page:读 snippets/check-current-page.js。
步骤 4:列 layers + 拿 node-id
左侧 Layers 面板每个 row 有 data-testid="{nodeA}:{nodeB}-layers-panel-row"。
读 snippets/list-layers.js。
Virtual scroll 注意:Layers 面板只渲染可见 layer。如果 layer 被滚出视区,需要先 chevron 展开父 group,或者直接用 Figma 的 Cmd+F Find。
步骤 5:导航到具体 node
browser_navigate url=https://www.figma.com/design/{fileKey}/?node-id={nodeA}-{nodeB}
browser_press_key key=Shift+2 # zoom to selection
常用快捷键:
Shift+2:zoom to selectedShift+1:fit whole pageMeta+Equal/Meta+Minus:放大/缩小Meta+F:Find(搜 text 定位 frame)
步骤 6:提取属性(颜色/尺寸/border)
选中 node 后,右侧 Properties 面板展示所有属性(Colors / Layout / Borders / Effects)。
读 snippets/extract-properties.js。
步骤 6.5:导出选中 node 为 SVG(要拿精确 path 时必用)
场景:logo/icon 只从 Figma 原始资源导出才精准。Copy as SVG 没键盘快捷键(Cmd+Shift+C 是 Copy as PNG,不是 SVG,不要用),Edit 主菜单走 Playwright 复杂。正确路径是右侧 Properties panel 底部 Export section。
已验证流程(三次分步 browser_evaluate,详细代码见 snippets/export-svg-via-panel.js):
- hook + add export — 在
window上注入URL.createObjectURL拦截器(Figma 导出走URL.createObjectURL(Blob)),然后点button[aria-label="Add export settings"] - 切格式到 SVG(两步)—
- 点 PNG combobox(
[role="combobox"]里textContent=="PNG"那个),等 1s 下拉出来 - 点
[role="option"]里textContent=="SVG"的 option
- 点 Export + 拿 blob — 点
buttontextContent 以"Export "开头的那个,然后轮询window.__capturedBlobs拿type==='image/svg+xml'的 blob,fetch(blob.url)取文字内容
成功判据:返回 { ok: true, length: 48000+, svg: " 找相关 `,连同 mask + defs 一并拎出来。写新 SVG 时用 viewBox="{x} {y} {size} {size}"` 正好截取 logo bbox 周围一个正方形区域(让 logo 在 widget 里居中)。
陷阱:
mask id别和页面其他 mask 冲突,自己改个 suffix(如mask0_logo替代mask0_1281_8037)linearGradient的x1/y1/x2/y2是绝对坐标(gradientUnits="userSpaceOnUse"),和 viewBox 坐标系同一套,不要 平移 path 而不平移 gradient 坐标,否则渐变方向会错- 如果平移了 path,必须同步平移 gradient stops 坐标,或者改用
gradientUnits="objectBoundingBox"
步骤 7:截图对比
browser_take_screenshot filename=figma-target.png type=png
快速查找 snippets
| 需求 | Snippet | 一句话描述 | |-----|---------|-----------| | 列出 Pages 面板所有 page 名 | snippets/list-pages.js | 返回所有 [data-testid="PagesRowWrapper"] 的文字 | | 检查当前选中的 page | snippets/check-current-page.js | 找 aria-current="page" 的 page row | | 列出 Layers 面板 + node-id | snippets/list-layers.js | 返回 {nodeId, text} 数组 | | 按 text 搜 layer → 拿 node-id | snippets/find-layer-by-text.js | 深度搜索目标 text 所在 layer 的 node-id | | 拿当前选中 node 的 Properties | snippets/extract-properties.js | 读右侧面板 Colors/Layout/Borders | | 关登录 dialog + AI promo popup | snippets/dismiss-popups.js | 页面载完后常见的两个 dialog | | 导出选中 node 为 SVG | snippets/export-svg-via-panel.js | Properties → Export → +SVG → Export,截获 blob URL + fetch 内容 |
每个 snippet 都是一个 self-contained function,粘贴进 browser_evaluate 的 function 参数即可。
账号说明
| 字段 | 值 | |-----|---| | 账号 | | | Seat | View(Organization: Design Sharing株式会社) | | Tier | starter | | Figma MCP 限额 | 是(限额后此 skill 生效) |
用 mcp__claude_ai_Figma__whoami 查当前登录状态。
URL 格式速查
| 来源 | URL | 变换到 MCP nodeId | |-----|-----|------------------| | Figma 分享 URL figma.com/design/{fileKey}/?node-id=1-2 | fileKey = {fileKey} | nodeId = 1:2(- 换 :) | | 带 branch figma.com/design/:fileKey/branch/:branchKey/... | fileKey 用 branchKey | 同上 | | Figma Make figma.com/make/:makeFileKey/... | fileKey = makeFileKey | 需 get_figjam 读 |
与 MCP 工具互补
- 有配额时:优先
mcp__claude_ai_Figma__get_design_context(一次拿代码+截图+属性) - 配额耗尽时:用本 skill 通过 Playwright 拿截图 + 从右侧 Properties 面板读 token
- 要 Code Connect:只能等配额恢复,Playwright 拿不到
- 要大量截图:Playwright 更好(没限额)
- 要精确 spec:用 MCP(属性更全),Playwright 只拿可见属性
关联 memory
reference_figma_playwright_navigation.md— 2026-03 第一次摸索的记录feedback_figma_mcp_workflow.md— MCP 限额规律reference_figma_design.md— project-specific Figma URL 清单
实战发现 2026-04-23(红包 Figma 抓取)
1. Chrome extension bridge mode ≠ isolated Chromium
本次实测 Playwright 打开的是 chrome-extension://... URL,是通过 Chrome 原生 extension API 代理 user Chrome,不是 Playwright 隔离的 Chromium 实例。
对 CrowdStrike 等企业 EDR 环境的含义:
- 不触发恶意软件拦截(走 Chrome extension API,非
cliclick/AppleScript 跨进程) - 但会操作用户真实 browser tab,用户能看到 Figma 页面切换
- 与用户约定好 "Playwright 操作 Chrome tab 期间不要切走 Figma" 即可
与上次 session(2026-04 之前)的区别:之前因为 ~/.claude.json worktree entry 缺失, Playwright MCP 未注册;本次 session 已正确注册,工具可用。
2. node-id 可能是 Text label 而不是 frame component
红包抓取中,以下 node-id 均被 Shift+2 zoom 确认为 Text label,不是气泡组件:
18912:184525(幸运红包)— SF Pro 400 84px,336×84,#FFFFFF18912:184526(普通红包)— 同上
辨识方法:
- Shift+2 zoom 后若看到大字(全屏单个词语)而非组件框线 → Text node
- Layers 面板图标是 T(Text)而非 frame(矩形框图标)
- Properties 面板右侧会显示 "Typography" section 而非 "Variants"
真实气泡 frame 应从 Layers 面板找 Frame 14200XXXXX 型节点,或命名为 控制台 的 frame (Figma 约定:实际可点组件放在 "控制台" frame 里)。
3. Shift+1 / Shift+2 实际差异
| 快捷键 | 行为 | 用途 | |---|---|---| | Shift+2 | Zoom to selected node(精确对齐到选中节点) | 抓单个 frame 截图用这个 | | Shift+1 | Fit entire page(看整个 page 全貌) | 想拿大局 overview 用这个 | | Meta+= | Zoom in 一级 | - | | Meta+- | Zoom out 一级 | - |
Shift+2 之后截图才是 "该 node 居中铺满" 的效果;Shift+1 会看到整个 page,frame 很小。
4. DOM query 抽 token 的 JS snippet
list-layers.js 模板(抓 Layers 面板 node-id 用):
(() => {
const rows = document.querySelectorAll('[data-testid$="-layers-panel-row"]');
return Array.from(rows).map(el => {
const testId = el.getAttribute('data-testid') || '';
const match = testId.match(/^(\d+):(\d+)-layers-panel-row$/);
const nodeId = match ? `${match[1]}:${match[2]}` : null;
const text = el.innerText?.trim() || '';
const scrollAt = el.getBoundingClientRect().top;
return { nodeId, text, scrollAt };
}).filter(r => r.nodeId);
})();
extract-properties.js 模板(抓右侧 Properties 面板 Colors 用):
(() => {
const panel = document.querySelector('[data-testid="properties-panel"]')
|| document.querySelector('.properties-panel');
if (!panel) return { error: 'panel not found' };
const colorEls = panel.querySelectorAll('[data-testid*="color"], .color-swatch');
return Array.from(colorEls).map(el => ({
hex: el.getAttribute('data-color') || el.style.backgroundColor || el.innerText,
label: el.closest('[data-testid*="row"]')?.innerText?.trim()
}));
})();
> 注:Figma 会重构 DOM,data-testid 格式可能随版本变。如果上面 selector 失效, > 用 document.querySelector('[data-testid]') 先探路,再调整。
5. 失败兜底原则
如果 Playwright 完全不可用(MCP 没 register,工具 list 里找不到 mcp__playwright__*):
禁止:
- 试 AppleScript(CrowdStrike 拦截 -1712)
- 试 cliclick / mac-use 操作真实 Chrome 窗口
- 连续试 stealth workaround
正确做法:
- 直接告知用户:Playwright MCP 未注册,需要重启 Claude Code(新 session 会读
~/.claude.jsonworktree entry) - 等用户重启后,先 ToolSearch 验证
mcp__playwright__browser_navigate可用再继续 - 如果连重启都无效,检查
~/.claude.json里当前 worktree 路径是否有mcpServers.playwright条目
Related skills
figma-use→figma-implement-design— use as fallback when Figma MCP is unavailable. Primary path: figma-use; fallback: figma-playwright-fallback.playwright-figma-scrape— more feature-rich Playwright-based scraping when figma-playwright-fallback proves insufficient.verify-ui→visual-verdict— after scraping Figma, verify implementation matches design.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ImL1s
- Source: ImL1s/flutter-claude-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.