figma-implement-design 后处理器。在 figma MCP 生成完 UI 代码后触发,把 MCP 产出的扁平代码补全成项目规范结构(下载 CDN 图到 assets/image/3.0x/{module}/、改 Image.network 为 Image.asset、加 Controller+Binding、登记路由、反推 spec/plan、归档 manifest、生成测试 + review)。和 figma-implement-design 搭配使用,不抢活只补全。
figma-implement-design 刚跑完,生成了 UI 代码(一般在 lib/features/{m}/ 或项目根的散落位置)反例(不要用这个 skill):
flutter-flow-featureflutter-design-to-codefigma-implement-design (MCP 原生) flutter-post-figma (本 skill)
───────────────────────────── ─────────────────────────────
读 Figma 节点树 接管 MCP 产出
解析 UI 结构(Stack/Column/Row) 扫描代码里的 Figma CDN URL
生成 Dart widget 代码 curl 下载到 assets/image/3.0x/{m}/
处理矩形/文字/颜色/位置 改 Image.network → Image.asset
移到三件套结构(Page/Controller/Binding)
登记路由 + 更新 pubspec
反推 spec.md + plan.md
产出 manifest-v{N}.yaml 归档
写单元测试
跑 analyze + 产 review
docs/_context/tech-stack.mddocs/_context/conventions.md_design/app_exception.dartlib/features/{m}/ 或其他位置)module_name: snake_case 模块名(如 splash)mcp_output_paths[]: figma-implement-design 生成的 Dart 文件路径(可能多个)docs/_context/api-global.yaml(有接口需求时用)读所有 MCP 生成的 .dart 文件,提取:
SplashPage / LoginPage)Image.network("https://www.figma.com/api/mcp/asset/...") 或 'https://...' 字符串SvgPicture.network(...) 同理输出一个资源清单给用户看:
扫到 5 个图资源:
[1] Image.network "https://www.figma.com/api/mcp/asset/abc..." (line 12)
[2] Image.network "https://www.figma.com/api/mcp/asset/def..." (line 23)
...
建议命名:
[1] → logo_splash.png
[2] → img_splash_1.png
...
生成单行 curl 清单(不要自己跑):
cd /Users/tg/Desktop/d/{project}/assets/image/3.0x/{module}
curl -L -o logo_splash.png "https://www.figma.com/api/mcp/asset/abc..."
curl -L -o img_splash_1.png "https://www.figma.com/api/mcp/asset/def..."
ls -lh
⛔ 不要自己跑 curl,给用户清单让他终端粘贴运行(避免权限/网络问题卡住)。
等用户说"图下完了"再进 Step 3。
ls -lh assets/image/3.0x/{module}/
file assets/image/3.0x/{module}/*.png
⛔ 禁止用 Read 工具读图片文件(>1MB 会 API 400 卡死),用 Bash 代替。
把 MCP 产出的:
Image.network('https://www.figma.com/api/mcp/asset/abc...')
改成:
Image.asset('assets/image/3.0x/{module}/logo_splash.png', fit: BoxFit.cover)
SVG 同理:SvgPicture.network(...) → SvgPicture.asset(...)
如果某张图 curl 没下来(size=0 或不存在),改成占位:
// TODO(post-figma): 替换为 assets/image/3.0x/splash/img_splash_1.png
Container(
color: Colors.grey[300],
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Center(child: Text('TODO: img_splash_1', style: TextStyle(color: Colors.red))),
)
MCP 一般把所有东西塞在一个 Page 类里。要拆成:
lib/features/{m}/presentation/pages/{page_name}/{page_name}_page.dart — View(GetView<Controller>)lib/features/{m}/presentation/pages/{page_name}/{page_name}_controller.dart — GetxControllerlib/features/{m}/presentation/pages/{page_name}/{page_name}_binding.dart — BindingsMCP 生成的如果是 StatelessWidget + 无状态,可以直接改 extends GetView<Controller>。 有状态逻辑的(定时器/异步/用户输入),把 setState 搬到 Controller 的 obs 变量里。
如果项目用了 flutter_screenutil:
80 → 80.w16 → 16.sp8 → 8.r判断:看 pubspec.yaml 有 flutter_screenutil 就加,没有跳过。
lib/app/routes/app_routes.dart 加路由常量(如果没有)lib/app/routes/app_pages.dart 的 routes 列表加 GetPagepubspec.yaml 的 flutter: assets: 段加 - assets/image/3.0x/{module}/(如果没有)fvm flutter pub get产出 docs/specs/{module}.md(7 段齐):
产出 docs/plans/{module}.md:任务清单 + 依赖图(已完成,回顾性 plan)
产出 docs/manifests/manifest-v{N}.yaml:归档(N = 下一个版本号)
test/features/{m}/{m}_controller_test.dart — Controller 的核心方法测试docs/review/{date}-{m}.md — review 报告,列出:
fvm flutter analyze 必须 0 errorfvm flutter test test/features/{m}/ 必须通过lib/features/{m}/presentation/pages/{page}/
├── {page}_page.dart ← 基于 MCP 产出改造
├── {page}_controller.dart ← 新建(从 MCP 代码提取状态)
└── {page}_binding.dart ← 新建(tearoff 模式)
lib/features/{m}/data/ ← 如果有接口(无接口可省)
├── models/
├── repositories/
└── mock/
assets/image/3.0x/{m}/ ← 下载的图
├── logo_*.png / .svg
├── img_*_1.png
└── ...
docs/specs/{m}.md ← 反推的 spec
docs/plans/{m}.md ← 反推的 plan
docs/manifests/manifest-v{N}.yaml ← 归档
docs/review/{date}-{m}.md ← review
test/features/{m}/ ← 测试
pubspec.yaml ← assets 段更新
lib/app/routes/app_pages.dart ← 路由登记
每次生成 UI 代码前,先过一遍这个清单。违反会编译通过但运行时崩。
// ❌ 崩:Matrix4.scale(x, y, z) 3 参数版 UnimplementedError
Transform(transform: Matrix4.scale(1, -1, 1))
// ✅ 用组合替代
Transform.flip(flipY: true, child: ...) // 垂直翻转
Transform.rotate(angle: pi/2, child: ...) // 旋转
Transform.scale(scaleX: 1.5, child: ...) // 单轴缩放
Matrix4.diagonal3Values(1, -1, 1) // 如一定要 Matrix4
curl 下来的文件必须验证格式,扩展名错了 Flutter 加载会崩:
# 每次 curl 后必跑
file assets/image/3.0x/{m}/*
# 看输出是否匹配扩展名:
# ✅ "PNG image data" + 扩展名 .png → 对
# ✅ "SVG Scalable Vector Graphics" + .svg → 对
# ❌ "SVG Scalable..." + .png → 用 mv 改扩展名
# ❌ "HTML document" → URL 失效,重下
flutter_svg 不支持 var() CSS 变量,会静默不渲染:
<!-- ❌ flutter_svg 不认 -->
<path fill="var(--fill-0, white)" />
<!-- ✅ 替换为字面量 -->
<path fill="#FFFFFF" />
SVG 下载后必扫一眼:
grep -l "var(" assets/image/3.0x/{m}/*.svg && \
echo "⚠️ 有 CSS 变量,需要替换为字面量颜色"
Transform.rotate / Transform.scale 只影响绘制,不影响布局尺寸:
// ❌ 旋转后元素仍占原始位置,布局会错乱
Positioned(
child: Transform.rotate(angle: pi/2, child: Image.asset(...)),
)
// ✅ 用 Positioned.fill / OverflowBox 让元素占满或溢出
Positioned.fill(child: Image.asset(..., fit: BoxFit.cover))
OverflowBox(
maxWidth: double.infinity,
child: Transform.rotate(angle: pi/2, child: ...),
)
// SVG 用 SvgPicture.asset(需 import 'package:flutter_svg/flutter_svg.dart')
// PNG/JPG 用 Image.asset
// 扩展名决定用哪个,不要混用
Flutter 3.27+ 用 withValues:
Colors.white.withOpacity(0.5) // ❌ deprecated
Colors.white.withValues(alpha: 0.5) // ✅
ListView(children: [...]) // ❌ 长列表性能差
ListView.builder(itemBuilder: ...) // ✅
用了 flutter_screenutil 就用响应式后缀:
SizedBox(width: 120) // ❌ 不适配不同屏
SizedBox(width: 120.w) // ✅ .w = 按宽度适配
TextStyle(fontSize: 16.sp) // ✅ .sp = 按字号适配
Read 工具对 >1MB 图会 API 400。验证用:
ls -lh <path> # 大小
file <path> # 格式
如果删除了 Transform.rotate,记得检查还用不用 pi:
grep -c "\\bpi\\b" {file} # 0 次就删 import 'dart:math'
给清单让用户跑,避开权限/卡顿问题。
API 400 必卡。用 ls -lh / file 验证。
MCP 产出缺 Controller/Binding/路由登记/测试,必须补。
会报错 "Unable to load asset"。必须用占位块 + TODO。
归档缺失,后续无法回溯。
lib/features/{m}/presentation/pages/{page}/ 三件套齐assets/image/3.0x/{m}/ 所有图存在(或占位 TODO 明确)figma.com/api/mcp/asset 硬编码(reflector 会拦截)docs/specs/{m}.md / docs/plans/{m}.md / docs/manifests/manifest-v{N}.yaml 存在test/features/{m}/ 存在docs/review/{date}-{m}.md 存在fvm flutter analyze 0 error| Skill | 职责 |
|---|---|
figma-implement-design (MCP 原生) | 从 Figma 生成 UI Dart 代码 |
flutter-post-figma (本 skill) | 接手 MCP 产出,补全成规范结构 |
flutter-flow-feature | 无 Figma 时的自然语言开发 |
flutter-design-to-code | 纯 UI 改版(不走完整 9 步) |
flutter-page-gen | 被 post-figma 调用来生成三件套骨架 |
flutter-manifest-init | 被 post-figma 调用来归档 |
典型调用链:
用户 "做 X 页 [figma URL]"
↓
router.sh stdout 注入: "先 figma-implement-design,再 flutter-post-figma"
↓
figma-implement-design 跑(MCP)
↓
flutter-post-figma 接力(本 skill)
↓
完成