figma-preview-mcp 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -99
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,58 @@
|
|
|
1
1
|
# figma-preview-mcp
|
|
2
2
|
|
|
3
|
-
一个 Model Context Protocol (MCP)
|
|
3
|
+
一个 Model Context Protocol (MCP) 服务器,提供从 Figma 设计稿到代码还原的完整工具链——**设计稿预览、Layout AST 生成、切图导出、程序化布局验收**,一站式解决 Figma-to-Code 的全流程。
|
|
4
|
+
|
|
5
|
+
> 💡 核心理念:在 Figma 原始数据和 AI 编码之间,插入一个结构化中间层 —— **Enriched Layout AST**,将 AI "理解设计稿"的过程转变为"翻译结构化数据"的确定性任务。
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
## ✨ 功能特性
|
|
8
10
|
|
|
11
|
+
### 🎨 设计稿预览 & 检查
|
|
9
12
|
- 📸 **高保真预览** — 在浏览器中预览 Figma 设计稿,100% 还原视觉效果
|
|
10
13
|
- 🖱️ **节点检查器** — 悬停查看节点名称,点击复制节点信息到剪贴板
|
|
11
|
-
- 🔍 **节点详情查询** —
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
- 🔍 **节点详情查询** — 获取完整节点数据,包括被压缩的内联样式和字符级文字样式
|
|
15
|
+
|
|
16
|
+
### 🧠 Layout AST 生成 & 布局推断
|
|
17
|
+
- 🌳 **Enriched Layout AST** — 将 Figma 节点树转化为结构化布局 JSON,包含预计算的 flex 属性、样式、flags
|
|
18
|
+
- � **布局推断引擎** — "Figma 优先 + 坐标交叉验证"策略,从精确坐标反推 flex-direction、gap、alignment、padding
|
|
19
|
+
- 📦 **模块化拆分** — 大页面(60+ 节点)自动拆分为多个模块,每个模块独立 AST 文件,避免 LLM 上下文溢出
|
|
20
|
+
- 🏷️ **图形子树识别** — 自动标记 `isGraphicSubtree`,AI 知道哪些节点该用 `<img>` 而非 CSS 还原
|
|
21
|
+
|
|
22
|
+
### 🖼️ 切图资源导出
|
|
23
|
+
- ✂️ **批量图片下载** — 支持 SVG / PNG 格式,批量导出最多 50 个节点
|
|
24
|
+
- 🔬 **Retina 支持** — PNG 默认 2x 导出,可配置 1-4x 缩放
|
|
25
|
+
|
|
26
|
+
### ✅ 程序化布局验收
|
|
27
|
+
- 📏 **verify_layout_bounds** — 用 Puppeteer 测量开发页面实际 DOM 边界,与 Figma 精确坐标逐节点对比
|
|
28
|
+
- 🩺 **差异诊断系统** — 5 种诊断模式(SIBLING_SHIFT / WIDTH_OVERFLOW / ALIGNMENT_OFF / CUMULATIVE_DRIFT / MISSING),精准定位布局偏差原因
|
|
29
|
+
- 🔄 **验收-修复闭环** — AI 根据结构化报告自动修复,循环验收直到通过
|
|
30
|
+
|
|
31
|
+
### 📷 截图工具
|
|
32
|
+
- 🖥️ **Figma API 截图** — 直接从 Figma 导出高清截图
|
|
33
|
+
- 🌐 **URL 截图** — 截取任意网页,支持 CSS 选择器定位特定元素
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 🏗️ 整体架构
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Figma API ──► NodeTree + AbsoluteBounds ──► BoundsCache
|
|
43
|
+
│
|
|
44
|
+
┌──────────────────┼──────────────────┐
|
|
45
|
+
▼ ▼ ▼
|
|
46
|
+
render_preview Layout Inference generate_layout_ast
|
|
47
|
+
(交互式预览) Engine (推断引擎) (结构化 AST)
|
|
48
|
+
│
|
|
49
|
+
┌──────────────────────────┤
|
|
50
|
+
▼ ▼
|
|
51
|
+
Module Map (拆分) verify_layout_bounds
|
|
52
|
+
│ (程序化验收)
|
|
53
|
+
▼ │
|
|
54
|
+
AI 编码 ◄──── 修复循环 ◄────────┘
|
|
55
|
+
```
|
|
14
56
|
|
|
15
57
|
---
|
|
16
58
|
|
|
@@ -33,8 +75,7 @@
|
|
|
33
75
|
"command": "npx",
|
|
34
76
|
"args": ["-y", "figma-preview-mcp"],
|
|
35
77
|
"env": {
|
|
36
|
-
"FIGMA_TOKEN": "figd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
37
|
-
"PIXELMATCH_THRESHOLD": "0.2"
|
|
78
|
+
"FIGMA_TOKEN": "figd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
38
79
|
}
|
|
39
80
|
}
|
|
40
81
|
}
|
|
@@ -45,137 +86,211 @@
|
|
|
45
86
|
|
|
46
87
|
---
|
|
47
88
|
|
|
48
|
-
## 🎮
|
|
89
|
+
## 🎮 MCP 工具一览
|
|
49
90
|
|
|
50
|
-
|
|
91
|
+
### `render_preview`
|
|
92
|
+
渲染 Figma 设计稿的交互式预览页面,同时缓存所有节点的精确边界数据。
|
|
51
93
|
|
|
52
94
|
```
|
|
53
|
-
|
|
95
|
+
调用 render_preview:
|
|
96
|
+
fileKey: "E2gHeS2vZt48DYiiQhNzkq"
|
|
97
|
+
nodeId: "985-14549"
|
|
54
98
|
```
|
|
55
99
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
### 节点检查器
|
|
63
|
-
|
|
64
|
-
| 操作 | 效果 |
|
|
65
|
-
|------|------|
|
|
66
|
-
| **悬停** 任意元素 | 蓝色高亮边框 + 节点名称提示 |
|
|
67
|
-
| **点击** 任意元素 | 橙色选中边框 + 节点信息复制到剪贴板 |
|
|
68
|
-
| **再次点击** | 取消选中 |
|
|
100
|
+
| 参数 | 必需 | 说明 |
|
|
101
|
+
|------|------|------|
|
|
102
|
+
| `fileKey` | ✅ | Figma 文件 Key |
|
|
103
|
+
| `nodeId` | 否 | 目标节点 ID |
|
|
104
|
+
| `yaml` | 否 | 来自其他 MCP 的 YAML 数据(备选输入) |
|
|
69
105
|
|
|
70
|
-
|
|
106
|
+
### `generate_layout_ast`
|
|
107
|
+
生成 Enriched Layout AST —— 包含预计算布局属性、样式和 flags 的结构化 JSON。
|
|
71
108
|
|
|
72
109
|
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
110
|
+
调用 generate_layout_ast:
|
|
111
|
+
fileKey: "E2gHeS2vZt48DYiiQhNzkq"
|
|
112
|
+
nodeId: "985-14549"
|
|
113
|
+
outputDir: "/project/.codemaker/figma-specs/my-page" # 可选,传入则启用模块化
|
|
114
|
+
splitThreshold: 60 # 可选,默认 60
|
|
77
115
|
```
|
|
78
116
|
|
|
79
|
-
|
|
117
|
+
| 参数 | 必需 | 说明 |
|
|
118
|
+
|------|------|------|
|
|
119
|
+
| `fileKey` | ✅ | Figma 文件 Key |
|
|
120
|
+
| `nodeId` | ✅ | 根节点 ID(需先调用 render_preview) |
|
|
121
|
+
| `outputDir` | 否 | 模块化输出目录。传入后大页面自动拆分 |
|
|
122
|
+
| `splitThreshold` | 否 | 每模块最大节点数(默认 60) |
|
|
80
123
|
|
|
81
|
-
|
|
124
|
+
**输出两种模式:**
|
|
125
|
+
- **普通模式**(≤ 阈值节点):直接返回完整 AST JSON
|
|
126
|
+
- **模块化模式**(> 阈值节点):输出文件到 `outputDir`,返回轻量级 Module Map
|
|
82
127
|
|
|
83
|
-
|
|
128
|
+
```
|
|
129
|
+
outputDir/
|
|
130
|
+
├── module-map.json # 模块索引(文件名、节点数、切图清单)
|
|
131
|
+
├── skeleton.json # 根容器布局 + 模块占位符
|
|
132
|
+
├── module-0-header.ast.json # 模块 0 完整 AST
|
|
133
|
+
├── module-1-hero.ast.json # 模块 1 完整 AST
|
|
134
|
+
└── module-2-footer.ast.json # 模块 2 完整 AST
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `verify_layout_bounds`
|
|
138
|
+
程序化布局验收:用 Puppeteer 测量开发页面 DOM 边界,与 Figma 精确坐标逐节点对比。
|
|
84
139
|
|
|
85
140
|
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
141
|
+
调用 verify_layout_bounds:
|
|
142
|
+
fileKey: "E2gHeS2vZt48DYiiQhNzkq"
|
|
143
|
+
nodeId: "985-14549"
|
|
144
|
+
url: "http://localhost:5173"
|
|
145
|
+
threshold: 2 # 可选,像素容差,默认 2
|
|
91
146
|
```
|
|
92
147
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
148
|
+
| 参数 | 必需 | 说明 |
|
|
149
|
+
|------|------|------|
|
|
150
|
+
| `fileKey` | ✅ | Figma 文件 Key |
|
|
151
|
+
| `nodeId` | ✅ | 根节点 ID(需先调用 render_preview) |
|
|
152
|
+
| `url` | ✅ | 开发页面 URL |
|
|
153
|
+
| `threshold` | 否 | 像素容差(默认 2px) |
|
|
98
154
|
|
|
99
|
-
|
|
155
|
+
**输出包含:**
|
|
156
|
+
- `matchRate` — 匹配率百分比
|
|
157
|
+
- `matched` — 匹配的节点列表
|
|
158
|
+
- `mismatched` — 不匹配的节点 + 偏差详情 + 诊断模式
|
|
159
|
+
- `missing` — 缺失的节点列表
|
|
100
160
|
|
|
101
|
-
|
|
161
|
+
**差异诊断模式:**
|
|
102
162
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
163
|
+
| 模式 | 含义 |
|
|
164
|
+
|------|------|
|
|
165
|
+
| `SIBLING_SHIFT` | 同父多个兄弟节点偏移相同,前方兄弟尺寸有误 |
|
|
166
|
+
| `WIDTH_OVERFLOW` | 宽度溢出至父元素边界,缺少宽度约束 |
|
|
167
|
+
| `ALIGNMENT_OFF` | 同行/列子节点交叉轴偏移不一致,对齐属性错误 |
|
|
168
|
+
| `CUMULATIVE_DRIFT` | 连续子节点偏移递增,gap 或尺寸有累积偏差 |
|
|
169
|
+
| `MISSING` | AST 中有但 DOM 中无对应节点 |
|
|
106
170
|
|
|
107
|
-
|
|
171
|
+
### `get_node_details`
|
|
172
|
+
获取指定节点的完整数据,包括内联样式、字符级文字样式等在预览中可能被压缩的信息。
|
|
108
173
|
|
|
109
|
-
|
|
174
|
+
```
|
|
175
|
+
调用 get_node_details:
|
|
176
|
+
fileKey: "E2gHeS2vZt48DYiiQhNzkq"
|
|
177
|
+
nodeId: "981-18766"
|
|
178
|
+
depth: 1
|
|
179
|
+
```
|
|
110
180
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
3. **执行像素级对比** — 调用 `compare_design_implementation` 对比两张截图
|
|
181
|
+
### `download_figma_images`
|
|
182
|
+
批量下载图片资源(图标、插图、照片),支持 SVG 和 PNG 格式。
|
|
114
183
|
|
|
115
184
|
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
185
|
+
调用 download_figma_images:
|
|
186
|
+
fileKey: "E2gHeS2vZt48DYiiQhNzkq"
|
|
187
|
+
nodes: [
|
|
188
|
+
{ "nodeId": "985:14560", "fileName": "icon_arrow.svg" },
|
|
189
|
+
{ "nodeId": "985:14570", "fileName": "img_banner.png", "format": "png" }
|
|
190
|
+
]
|
|
191
|
+
localPath: "/project/src/assets/images"
|
|
192
|
+
pngScale: 2
|
|
193
|
+
```
|
|
121
194
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
调用 take_screenshot: { filePath: /tmp/dev.png }
|
|
195
|
+
### `take_preview_screenshot`
|
|
196
|
+
截图工具,支持 Figma API 截图和 URL 网页截图两种模式。
|
|
125
197
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
198
|
+
```
|
|
199
|
+
# Figma API 模式
|
|
200
|
+
调用 take_preview_screenshot:
|
|
201
|
+
fileKey: "E2gHeS2vZt48DYiiQhNzkq"
|
|
202
|
+
nodeId: "985-14549"
|
|
203
|
+
|
|
204
|
+
# URL 模式
|
|
205
|
+
调用 take_preview_screenshot:
|
|
206
|
+
url: "http://localhost:5173"
|
|
207
|
+
selector: ".main-container" # 可选
|
|
130
208
|
```
|
|
131
209
|
|
|
132
|
-
|
|
210
|
+
---
|
|
133
211
|
|
|
134
|
-
|
|
135
|
-
2. **差异统计** — 不匹配像素数、差异百分比
|
|
212
|
+
## 🔄 推荐工作流:figma-to-code Skill
|
|
136
213
|
|
|
137
|
-
|
|
138
|
-
```
|
|
139
|
-
## ❌ 像素级对比结果
|
|
214
|
+
配合 **`figma-to-code` Skill** 使用,可实现标准化的 5 阶段闭环工作流:
|
|
140
215
|
|
|
141
|
-
|
|
142
|
-
- 不匹配像素数:**12,345** / 608,400
|
|
143
|
-
- 差异率:**2.03%**
|
|
144
|
-
- 对比尺寸:750 × 812px
|
|
216
|
+

|
|
145
217
|
|
|
146
|
-
|
|
218
|
+
```
|
|
219
|
+
Phase 1: 设计稿解析 + Layout AST 生成
|
|
220
|
+
↓
|
|
221
|
+
Phase 2: 资源切图导出
|
|
222
|
+
↓
|
|
223
|
+
Phase 3: 编码实现(AST → HTML/CSS 的确定性翻译)
|
|
224
|
+
↓
|
|
225
|
+
Phase 4: 自动化布局验收(verify_layout_bounds)
|
|
226
|
+
↓
|
|
227
|
+
Phase 5: 精准修复 → 循环回 Phase 4 直到通过
|
|
147
228
|
```
|
|
148
229
|
|
|
149
|
-
|
|
150
|
-
- `threshold` — 颜色差异灵敏度(0-1,默认 0.2,越小越敏感)
|
|
230
|
+
### 验收-修复闭环
|
|
151
231
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
-
|
|
232
|
+

|
|
233
|
+
|
|
234
|
+
**关键约束:**
|
|
235
|
+
- AST 是编码的唯一参考,不允许 AI 自行猜测样式
|
|
236
|
+
- 每个 HTML 元素必须添加 `data-node-id` 属性用于验收匹配
|
|
237
|
+
- 编码完成后必须执行验收,不能跳过
|
|
238
|
+
- 循环修复直到 `matchRate ≥ 85%`(安全阀:最多 5 轮)
|
|
156
239
|
|
|
157
240
|
---
|
|
158
241
|
|
|
159
|
-
##
|
|
242
|
+
## 🧩 核心技术要点
|
|
243
|
+
|
|
244
|
+
### 布局推断引擎
|
|
245
|
+
|
|
246
|
+
采用三级优先级策略:
|
|
247
|
+
|
|
248
|
+
1. **Figma Auto Layout 优先** — 有 `layoutMode` 时直接采信,但用精确坐标交叉验证 gap/padding
|
|
249
|
+
2. **坐标推断** — 无 Auto Layout 时,从子节点坐标反推 direction、gap、alignment
|
|
250
|
+
3. **保守降级** — 推断不确定时降级为 `position: absolute`,宁可不推断也不推错
|
|
160
251
|
|
|
161
252
|
```
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
253
|
+
ε = 3px (容差)
|
|
254
|
+
yGroups = groupByProximity(children.y, ε)
|
|
255
|
+
xGroups = groupByProximity(children.x, ε)
|
|
256
|
+
|
|
257
|
+
yGroups.length === 1 → row
|
|
258
|
+
xGroups.length === 1 → column
|
|
259
|
+
otherwise → absolute
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Enriched AST 节点结构
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"nodeId": "985:14549",
|
|
267
|
+
"name": "card-container",
|
|
268
|
+
"type": "FRAME",
|
|
269
|
+
"bounds": { "x": 16, "y": 100, "width": 343, "height": 200 },
|
|
270
|
+
"layout": {
|
|
271
|
+
"display": "flex",
|
|
272
|
+
"flexDirection": "column",
|
|
273
|
+
"gap": 12,
|
|
274
|
+
"alignItems": "flex-start",
|
|
275
|
+
"padding": { "top": 16, "right": 16, "bottom": 16, "left": 16 },
|
|
276
|
+
"source": "figma | inferred | absolute",
|
|
277
|
+
"selfSizing": { "horizontal": "fill", "vertical": "hug" }
|
|
278
|
+
},
|
|
279
|
+
"style": { "backgroundColor": "#ffffff", "borderRadius": "12px" },
|
|
280
|
+
"flags": {
|
|
281
|
+
"isGraphicSubtree": false,
|
|
282
|
+
"isAbsoluteOverlay": false,
|
|
283
|
+
"needsDetailFetch": false
|
|
284
|
+
},
|
|
285
|
+
"children": [...]
|
|
286
|
+
}
|
|
174
287
|
```
|
|
175
288
|
|
|
176
|
-
###
|
|
289
|
+
### 验收原理
|
|
177
290
|
|
|
178
|
-
|
|
291
|
+
- **Viewport 精确匹配** — `deviceScaleFactor: 1`,CSS 像素与 Figma 像素 1:1 对应
|
|
292
|
+
- **坐标归一化** — 所有浏览器坐标相对于根容器,消除页面 margin/padding 影响
|
|
293
|
+
- **data-node-id 桥接** — 通过 DOM 属性 `data-node-id` 实现 Figma 节点与 HTML 元素的精确映射
|
|
179
294
|
|
|
180
295
|
---
|
|
181
296
|
|
|
@@ -185,7 +300,6 @@ Figma URL
|
|
|
185
300
|
|---------|------|------|
|
|
186
301
|
| `FIGMA_TOKEN` | ✅ 是 | Figma 个人访问令牌 |
|
|
187
302
|
| `PORT` | 否 | HTTP 服务器端口(默认 `3456`) |
|
|
188
|
-
| `PIXELMATCH_THRESHOLD` | 否 | 像素对比灵敏度阈值 0-1(默认 `0.2`,越小越敏感) |
|
|
189
303
|
|
|
190
304
|
---
|
|
191
305
|
|
|
@@ -193,7 +307,7 @@ Figma URL
|
|
|
193
307
|
|
|
194
308
|
```bash
|
|
195
309
|
# 克隆仓库
|
|
196
|
-
cd figma-preview-mcp
|
|
310
|
+
cd figma-preview-mcp/src
|
|
197
311
|
|
|
198
312
|
# 安装依赖
|
|
199
313
|
npm install
|
|
@@ -201,9 +315,12 @@ npm install
|
|
|
201
315
|
# 构建
|
|
202
316
|
npm run build
|
|
203
317
|
|
|
204
|
-
#
|
|
205
|
-
|
|
206
|
-
|
|
318
|
+
# 开发模式
|
|
319
|
+
npm run dev
|
|
320
|
+
|
|
321
|
+
# 在 MCP 配置中使用本地构建:
|
|
322
|
+
# "command": "node"
|
|
323
|
+
# "args": ["/absolute/path/to/src/dist/index.js"]
|
|
207
324
|
```
|
|
208
325
|
|
|
209
326
|
---
|
|
@@ -212,6 +329,7 @@ npm run build
|
|
|
212
329
|
|
|
213
330
|
- Node.js ≥ 18.0.0
|
|
214
331
|
- 有效的 Figma 访问令牌
|
|
332
|
+
- Puppeteer 兼容环境(用于 verify_layout_bounds 和截图功能)
|
|
215
333
|
|
|
216
334
|
---
|
|
217
335
|
|
package/package.json
CHANGED