# figma-preview-mcp

一个 Model Context Protocol (MCP) 服务器，提供从 Figma 设计稿到代码还原的完整工具链——**设计稿预览、Layout AST 生成、切图导出、程序化布局验收**，一站式解决 Figma-to-Code 的全流程。

> 💡 核心理念：在 Figma 原始数据和 AI 编码之间，插入一个结构化中间层 —— **Enriched Layout AST**，将 AI "理解设计稿"的过程转变为"翻译结构化数据"的确定性任务。

---

## ✨ 功能特性

### 🎨 设计稿预览 & 检查
- 📸 **高保真预览** — 在浏览器中预览 Figma 设计稿，100% 还原视觉效果
- 🖱️ **节点检查器** — 悬停查看节点名称，点击复制节点信息到剪贴板
- 🔍 **节点详情查询** — 获取完整节点数据，包括被压缩的内联样式和字符级文字样式

### 🧠 Layout AST 生成 & 布局推断
- 🌳 **Enriched Layout AST** — 将 Figma 节点树转化为结构化布局 JSON，包含预计算的 flex 属性、样式、flags
- � **布局推断引擎** — "Figma 优先 + 坐标交叉验证"策略，从精确坐标反推 flex-direction、gap、alignment、padding
- 📦 **模块化拆分** — 大页面（60+ 节点）自动拆分为多个模块，每个模块独立 AST 文件，避免 LLM 上下文溢出
- 🏷️ **图形子树识别** — 自动标记 `isGraphicSubtree`，AI 知道哪些节点该用 `<img>` 而非 CSS 还原

### 🖼️ 切图资源导出
- ✂️ **批量图片下载** — 支持 SVG / PNG 格式，批量导出最多 50 个节点
- 🔬 **Retina 支持** — PNG 默认 2x 导出，可配置 1-4x 缩放

### ✅ 程序化布局验收
- 📏 **verify_layout_bounds** — 用 Puppeteer 测量开发页面实际 DOM 边界，与 Figma 精确坐标逐节点对比
- 🩺 **差异诊断系统** — 5 种诊断模式（SIBLING_SHIFT / WIDTH_OVERFLOW / ALIGNMENT_OFF / CUMULATIVE_DRIFT / MISSING），精准定位布局偏差原因
- 🔄 **验收-修复闭环** — AI 根据结构化报告自动修复，循环验收直到通过

### 📷 截图工具
- 🖥️ **Figma API 截图** — 直接从 Figma 导出高清截图
- 🌐 **URL 截图** — 截取任意网页，支持 CSS 选择器定位特定元素

---

## 🏗️ 整体架构

![整体架构图](./docs/images/article-main-architecture.svg)

```
Figma API ──► NodeTree + AbsoluteBounds ──► BoundsCache
                                                │
                              ┌──────────────────┼──────────────────┐
                              ▼                  ▼                  ▼
                      render_preview    Layout Inference    generate_layout_ast
                      (交互式预览)       Engine (推断引擎)    (结构化 AST)
                                                                    │
                                         ┌──────────────────────────┤
                                         ▼                          ▼
                                  Module Map (拆分)         verify_layout_bounds
                                         │                    (程序化验收)
                                         ▼                          │
                                    AI 编码 ◄──── 修复循环 ◄────────┘
```

---

## 🚀 快速开始

### 1. 获取 Figma Access Token

1. 打开 [Figma](https://www.figma.com)，进入 **Account Settings**
2. 滚动到 **Personal access tokens**
3. 点击 **Generate new token**，命名并复制 token

### 2. 安装配置

在 MCP 配置文件中添加（如 `mcp.json` 或 Claude Desktop 的 `claude_desktop_config.json`）：

```json
{
  "mcpServers": {
    "figma-preview-mcp": {
      "command": "npx",
      "args": ["-y", "figma-preview-mcp"],
      "env": {
        "FIGMA_TOKEN": "figd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

> **注意:** 将 `FIGMA_TOKEN` 替换为你的 Figma 个人访问令牌。

---

## 🎮 MCP 工具一览

### `render_preview`
渲染 Figma 设计稿的交互式预览页面，同时缓存所有节点的精确边界数据。

```
调用 render_preview:
  fileKey: "YOUR_FILE_KEY"
  nodeId: "985-14549"
```

| 参数 | 必需 | 说明 |
|------|------|------|
| `fileKey` | ✅ | Figma 文件 Key |
| `nodeId` | 否 | 目标节点 ID |
| `yaml` | 否 | 来自其他 MCP 的 YAML 数据（备选输入） |

### `generate_layout_ast`
生成 Enriched Layout AST —— 包含预计算布局属性、样式和 flags 的结构化 JSON。

```
调用 generate_layout_ast:
  fileKey: "YOUR_FILE_KEY"
  nodeId: "985-14549"
  outputDir: "/project/.codemaker/figma-specs/my-page"   # 可选，传入则启用模块化
  splitThreshold: 60                                       # 可选，默认 60
```

| 参数 | 必需 | 说明 |
|------|------|------|
| `fileKey` | ✅ | Figma 文件 Key |
| `nodeId` | ✅ | 根节点 ID（需先调用 render_preview） |
| `outputDir` | 否 | 模块化输出目录。传入后大页面自动拆分 |
| `splitThreshold` | 否 | 每模块最大节点数（默认 60） |

**输出两种模式：**
- **普通模式**（≤ 阈值节点）：直接返回完整 AST JSON
- **模块化模式**（> 阈值节点）：输出文件到 `outputDir`，返回轻量级 Module Map

```
outputDir/
├── module-map.json          # 模块索引（文件名、节点数、切图清单）
├── skeleton.json            # 根容器布局 + 模块占位符
├── module-0-header.ast.json # 模块 0 完整 AST
├── module-1-hero.ast.json   # 模块 1 完整 AST
└── module-2-footer.ast.json # 模块 2 完整 AST
```

### `verify_layout_bounds`
程序化布局验收：用 Puppeteer 测量开发页面 DOM 边界，与 Figma 精确坐标逐节点对比。

```
调用 verify_layout_bounds:
  fileKey: "YOUR_FILE_KEY"
  nodeId: "985-14549"
  url: "http://localhost:5173"
  threshold: 2                   # 可选，像素容差，默认 2
```

| 参数 | 必需 | 说明 |
|------|------|------|
| `fileKey` | ✅ | Figma 文件 Key |
| `nodeId` | ✅ | 根节点 ID（需先调用 render_preview） |
| `url` | ✅ | 开发页面 URL |
| `threshold` | 否 | 像素容差（默认 2px） |

**输出包含：**
- `matchRate` — 匹配率百分比
- `matched` — 匹配的节点列表
- `mismatched` — 不匹配的节点 + 偏差详情 + 诊断模式
- `missing` — 缺失的节点列表

**差异诊断模式：**

| 模式 | 含义 |
|------|------|
| `SIBLING_SHIFT` | 同父多个兄弟节点偏移相同，前方兄弟尺寸有误 |
| `WIDTH_OVERFLOW` | 宽度溢出至父元素边界，缺少宽度约束 |
| `ALIGNMENT_OFF` | 同行/列子节点交叉轴偏移不一致，对齐属性错误 |
| `CUMULATIVE_DRIFT` | 连续子节点偏移递增，gap 或尺寸有累积偏差 |
| `MISSING` | AST 中有但 DOM 中无对应节点 |

### `get_node_details`
获取指定节点的完整数据，包括内联样式、字符级文字样式等在预览中可能被压缩的信息。

```
调用 get_node_details:
  fileKey: "YOUR_FILE_KEY"
  nodeId: "981-18766"
  depth: 1
```

### `download_figma_images`
批量下载图片资源（图标、插图、照片），支持 SVG 和 PNG 格式。

```
调用 download_figma_images:
  fileKey: "YOUR_FILE_KEY"
  nodes: [
    { "nodeId": "985:14560", "fileName": "icon_arrow.svg" },
    { "nodeId": "985:14570", "fileName": "img_banner.png", "format": "png" }
  ]
  localPath: "/project/src/assets/images"
  pngScale: 2
```

### `take_preview_screenshot`
截图工具，支持 Figma API 截图和 URL 网页截图两种模式。

```
# Figma API 模式
调用 take_preview_screenshot:
  fileKey: "YOUR_FILE_KEY"
  nodeId: "985-14549"

# URL 模式
调用 take_preview_screenshot:
  url: "http://localhost:5173"
  selector: ".main-container"    # 可选
```

---

## 🔄 推荐工作流：figma-to-code Skill

配合 **`figma-to-code` Skill** 使用，可实现标准化的 5 阶段闭环工作流：

![Skill 标准工作流](./docs/images/article-skill-workflow.svg)

```
Phase 1: 设计稿解析 + Layout AST 生成
    ↓
Phase 2: 资源切图导出
    ↓
Phase 3: 编码实现（AST → HTML/CSS 的确定性翻译）
    ↓
Phase 4: 自动化布局验收（verify_layout_bounds）
    ↓
Phase 5: 精准修复 → 循环回 Phase 4 直到通过
```

### 验收-修复闭环

![验收修复闭环](./docs/images/article-verification-loop.svg)

**关键约束：**
- AST 是编码的唯一参考，不允许 AI 自行猜测样式
- 每个 HTML 元素必须添加 `data-node-id` 属性用于验收匹配
- 编码完成后必须执行验收，不能跳过
- 循环修复直到 `matchRate ≥ 85%`（安全阀：最多 5 轮）

---

## 🧩 核心技术要点

### 布局推断引擎

采用三级优先级策略：

1. **Figma Auto Layout 优先** — 有 `layoutMode` 时直接采信，但用精确坐标交叉验证 gap/padding
2. **坐标推断** — 无 Auto Layout 时，从子节点坐标反推 direction、gap、alignment
3. **保守降级** — 推断不确定时降级为 `position: absolute`，宁可不推断也不推错

```
ε = 3px (容差)
yGroups = groupByProximity(children.y, ε)
xGroups = groupByProximity(children.x, ε)

yGroups.length === 1 → row
xGroups.length === 1 → column
otherwise → absolute
```

### Enriched AST 节点结构

```json
{
  "nodeId": "985:14549",
  "name": "card-container",
  "type": "FRAME",
  "bounds": { "x": 16, "y": 100, "width": 343, "height": 200 },
  "layout": {
    "display": "flex",
    "flexDirection": "column",
    "gap": 12,
    "alignItems": "flex-start",
    "padding": { "top": 16, "right": 16, "bottom": 16, "left": 16 },
    "source": "figma | inferred | absolute",
    "selfSizing": { "horizontal": "fill", "vertical": "hug" }
  },
  "style": { "backgroundColor": "#ffffff", "borderRadius": "12px" },
  "flags": {
    "isGraphicSubtree": false,
    "isAbsoluteOverlay": false,
    "needsDetailFetch": false
  },
  "children": [...]
}
```

### 验收原理

- **Viewport 精确匹配** — `deviceScaleFactor: 1`，CSS 像素与 Figma 像素 1:1 对应
- **坐标归一化** — 所有浏览器坐标相对于根容器，消除页面 margin/padding 影响
- **data-node-id 桥接** — 通过 DOM 属性 `data-node-id` 实现 Figma 节点与 HTML 元素的精确映射

---

## ⚙️ 配置项

| 环境变量 | 必需 | 说明 |
|---------|------|------|
| `FIGMA_TOKEN` | ✅ 是 | Figma 个人访问令牌 |
| `PORT` | 否 | HTTP 服务器端口（默认 `3456`） |

---

## 🛠️ 本地开发

```bash
# 克隆仓库
cd figma-preview-mcp/src

# 安装依赖
npm install

# 构建
npm run build

# 开发模式
npm run dev

# 在 MCP 配置中使用本地构建:
# "command": "node"
# "args": ["/absolute/path/to/src/dist/index.js"]
```

---

## 📋 系统要求

- Node.js ≥ 18.0.0
- 有效的 Figma 访问令牌
- Puppeteer 兼容环境（用于 verify_layout_bounds 和截图功能）

---

## 📄 许可证

MIT