Communitygithub.com

MohamedRamadanSalah/figma-lens

使用 figma-lens 导出的设计文件(design/<frame>/spec.md、tokens.json、截图、SVG 图标)以像素级精度实现 Figma UI,无需 Figma MCP 或 Dev Mode。当用户要求“从 Figma”构建、实现、匹配或修复界面/组件,提及 design/ 文件夹或 figma-lens 导出,或希望生成与 Figma 设计稿匹配的 Flutter 或 Web(HTML/CSS/React/Tailwind)代码时使用。

figma-lens 是什么?

figma-lens 是一款 Figma 插件与本地桥接工具,可将 Figma 设计稿精确转换为 Flutter 或 Web(HTML/CSS/React/Tailwind)代码。用户只需在 Figma 桌面版中选择画框,点击“Export to Claude”,桥接器便会为每个画框生成一个包含 spec.md、tokens.json、截图、SVG 图标等文件的文件夹。AI 代理通过读取 spec.md 中的精确值(而非测量像素)来构建 UI,并遵循组件映射(figma-lens.map.json)复用现有项目组件,确保代码与设计完全一致。代理使用内置的对比修复循环(`figma-lens check`)自动比对生成结果与 Figma 设计稿,生成差异报告和并排对比图,直至像素级偏差小于 3%。该工具支持 Flutter(包括 Web 和 Android)以及 Web 前端框架,并提供详细的 Figma 到 Flutter/CSS 的映射表,帮助开发者快速实现高保真 UI。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/MohamedRamadanSalah/figma-lens/tree/HEAD/skill/figma-lens

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

figma-lens: 构建与 Figma 匹配的 UI

figma-lens 是一个 Figma 插件加本地桥接器。用户在 Figma 桌面版中选择画框并点击 Export to Claude。桥接器会为每个画框写入一个文件夹:

design/
  INDEX.md              ← 所有导出画框的列表(从这里开始)
  <frame>/              ← 画框名称对应的文件夹
    spec.md             ← 首先阅读:紧凑的图层树,包含精确的值
    spec.json           ← 完整数据(+ Figma 中每个图层的 CSS),当 spec.md 不够用时使用
    tokens.json         ← 变量(所有模式)、样式、原始值的使用次数
    [email protected]       ← 完整渲染图(默认 2 倍)
    sections/NN-name.png← 顶层块的全分辨率裁切
    assets/*.svg        ← 图标/矢量图,可直接使用
    images/*            ← 用作图像填充的原始位图
    compare/            ← 由 `figma-lens check` 写入(report.md、side-by-side.png、diff.png)
figma-lens.map.json     ← (项目根目录)Figma 组件/令牌到此项目的代码映射

figma-lens 命令是 figma-lens 仓库中的 CLI(在那里运行 npm link 可使其全局可用;否则运行 node <figma-lens>/bin/figma-lens.js …)。运行 figma-lens help 查看所有命令。

如果尚未导出

  1. 为用户项目启动桥接器并保持运行(后台):figma-lens bridge --out <project>/design。
  2. 要求用户在 Figma 桌面版中选择画框 → 插件 → 开发 → Figma Lens → Export to Claude。
  3. 读取 design/INDEX.md 确认导出已到达。

如果可以通过导出来完成,永远不要仅凭描述猜测设计。请要求用户导出。

工作流程

  1. 完整阅读 spec.md(它很简短)。注意画框尺寸、布局树、变量、样式和资源。
  2. 查看图片。 逐个阅读 sections/*.png 以了解细节。[email protected] 仅用于全局概览,因为大图在查看时会被缩小。值始终来自 spec,切勿通过测量像素获取。
  3. 使用组件映射(见下方“组件映射”)。spec.md 中每个 ⇒ USE … 都是强制性的:使用该 widget/组件及其属性映射,并使用映射后的令牌((color/primary ⇒ AppColors.primary))代替原始值。对于标记为 (not in map) 的项,在代码库中搜索现有的主题和 widget(Flutter 中为 ThemeData、AppColors、TextTheme、间距常量、lib/widgets;Web 中为 CSS 变量、Tailwind 配置、src/components)。仅在没有令牌存在时使用原始值,并告知用户哪些是你添加的。
  4. 复用组件。 标记为 component Button {Type=Primary} 的图层应使用项目中现有的 Button widget 或组件及其匹配的属性。仅当不存在时才新建一个可复用的组件,并将其添加到映射中。
  5. 自上而下构建,遵循树结构。 自动布局映射为 Row/Column/flex(见下方表格)。仅 @x,y 图层(无自动布局,或 absolute)才需要 Stack/Positioned 或绝对定位。
  6. 使用导出的文件。 将 assets/*.svg 和 images/* 放入项目的资源文件夹并引用它们。切勿重新绘制图标或替换为不同的图标集。
  7. 精确复制文本,包括 spec.md 中 "…" 内的大小写、标点和阿拉伯语/RTL 字符串。包含多个 run 行的文本需要富文本(TextSpan / 嵌套 spans)。
  8. 使用对比修复循环(见下文)进行验证。不要仅靠阅读代码就宣布画面完成;必须通过截图差异来证明。

对比修复循环

构建完画面后,将实际结果与 Figma 对比并修复差异:

  1. 运行构建以显示该画面:
    • Web:启动开发服务器并打开该路由。
    • Flutter Web:flutter run -d web-server --web-port 8080,然后使用该 URL。
    • Flutter Android:在模拟器/设备上运行应用并导航到该画面。
  2. 进行检查:
    • Web / Flutter Web:figma-lens check --design design/<frame> --url http://localhost:<port>/<route>(视口会自动设置为画框的尺寸和缩放比例)。
    • Android:figma-lens check --design design/<frame> --adb --crop-top <status bar px> [--crop-bottom <nav bar px>](状态栏 ≈ 24–48 dp × 设备密度;裁剪掉它以便仅比较应用内容)。
  3. 阅读 design/<frame>/compare/report.md(不匹配百分比、差异最大的区域以及每个区域中的 Figma 图层 ID),并查看 compare/side-by-side.png(Figma | 构建 | 差异,红色 = 不同)。
  4. 自上而下修复:首先修复高度或间距差异(它们会使其下方的所有内容偏移),然后是尺寸、颜色、排版、圆角、阴影。在 spec.md 中查找每个列出的图层 ID,获取精确值。
  5. 重新运行检查。 报告会显示之前的分数,因此你可以看到进度。
  6. 当不匹配度 ≤ 3%(文本抗锯齿永远无法达到 0)或连续两次运行不再改进时停止。然后报告最终分数以及你无法匹配的任何内容及其原因(缺少字体、平台渲染、动态数据)。

规则:修复真实代码,永远不要欺骗差异(不要将设计截图或图片放入应用)。检查时使用与设计相同的数据/文本(必要时使用模拟数据),否则文本差异会主导分数。

组件映射

figma-lens.map.json(项目根目录)将 Figma 组件和令牌映射到此项目的代码:

{
  "components": {
    "Button": { "flutter": "lib/widgets/app_button.dart#AppButton", "web": "src/components/Button.tsx#Button", "props": { "Label": "label", "Type": "variant" } },
    "Icon/*": "SvgPicture.asset('assets/icons/<name>.svg')"
  },
  "tokens": { "color/primary": { "flutter": "AppColors.primary", "web": "var(--color-primary)" } }
}
  • 尚无映射 → 运行 figma-lens map --design design。它会将导出中的每个组件和令牌添加为空值 ("")。
  • 自己填充它:在代码库中搜索每个组件(按名称、外观、属性)和每个令牌值;写入 path#Symbol(或一个表达式)。仅在尚无对应项时保留 ""。"Prefix/*" 匹配整个系列(例如图标)。
  • 编辑映射后,运行 figma-lens render design/<frame>,以便 spec.md 显示 ⇒ USE 箭头。桥接器也会在每次新导出时应用映射。
  • 当你为未映射的组件创建新的可复用 widget 时,将其添加到映射中。

阅读 spec.md

  • 单位是设计像素,等同于 CSS px 和 Flutter 逻辑像素。切勿乘以截图缩放比例。
  • row|column gap G pad t,r,b,l main:X cross:Y 表示自动布局。pad 16 表示所有四边都是 16。gap auto 表示 space-between。
  • w:FILL h:HUG 给出每个轴上的尺寸:FIXED(显示精确尺寸)、HUG(包裹内容)或 FILL(占据可用空间)。
  • @x,y 是相对于父容器的位置。absolute 表示自动布局内的绝对定位子元素。pin H/V 给出约束(MIN = 左/上,MAX = 右/下,STRETCH = 两者,CENTER,SCALE)。
  • bg A + B 从底到顶列出填充。(name) 是 Figma 变量,[style name] 是 Figma 样式。
  • 颜色格式为 #RRGGBB 或 #RRGGBBAA(Alpha 在最后)。
  • 文本格式为 "chars" · Family Style (weight) size/lineHeight color。lineHeight 单位为 px、% 或 auto。ls 是字母间距,单位为 px 或字体大小的百分比。
  • radius 12 设置所有角。radius tl,tr,br,bl 分别设置每个角。smoothing 是 iOS 风格的圆角平滑;可近似处理,除非项目使用了 squircle 包,否则 Flutter 中可忽略。
  • drop-shadow x,y blur B spread S color、inner-shadow、layer-blur R、background-blur R。
  • → assets/x.svg 表示该图层是一个图标。使用指定尺寸的 SVG。
  • vars{itemSpacing=space/md} 表示图层属性绑定到该变量。使用该令牌。

Flutter 映射表

FigmaFlutter
column / rowColumn / Row(Flutter ≥ 3.27 使用 spacing: G,否则使用 SizedBox 间隙)
wrap, rowGap RWrap(spacing: G, runSpacing: R)
pad t,r,b,lPadding(padding: EdgeInsets.fromLTRB(l, t, r, b))。注意顺序。
main MIN / CENTER / MAX / SPACE_BETWEENMainAxisAlignment.start / center / end / spaceBetween
cross MIN / CENTER / MAX / BASELINECrossAxisAlignment.start / center / end / baseline(baseline 需要 textBaseline)
HUG on main axismainAxisSize: MainAxisSize.min
FILL on parent's main axisExpanded(或 Flexible);grow N 设置 flex: N
FILL on parent's cross axis父级设置 CrossAxisAlignment.stretch,或使用 SizedBox(width: double.infinity)
FIXED w×hSizedBox(width: w, height: h)
@x,y / absoluteStack + Positioned(left: x, top: y);使用 pin 实现 right/bottom
bg solidBoxDecoration(color: Color(0xAARRGGBB))。将 Alpha 移到前面:#11223380 → 0x80112233。
gradient-linear from/toLinearGradient(begin: Alignment(fx*2-1, fy*2-1), end: Alignment(tx*2-1, ty*2-1), colors, stops),使用 spec.json 中的 from/to
radiusBorderRadius.circular(r) 或 BorderRadius.only(...)
border W color insideBorder.all(width: W, color: …)(inside 是 Flutter 的默认值;center/outside 需要 strokeAlign)
drop-shadow x,y blur B spread SBoxShadow(offset: Offset(x, y), blurRadius: B, spreadRadius: S, color: …)
background-blur RClipRRect + BackdropFilter(filter: ImageFilter.blur(sigmaX: R/2, sigmaY: R/2))
opacityOpacity(或 paints 的颜色透明度)
text size/lineHeightTextStyle(fontSize: size, height: lineHeight / size)。对于百分比:height: pct/100。设置 leadingDistribution: TextLeadingDistribution.even 以匹配 Figma 的垂直居中。
weight 600FontWeight.w600
ls px / ls %letterSpacing: px / letterSpacing: size * pct / 100
ellipsis maxLines NmaxLines: N, overflow: TextOverflow.ellipsis
align CENTERtextAlign: TextAlign.center。对于 RTL 画面,使用 TextAlign.start 和 EdgeInsetsDirectional。
assets/x.svgSvgPicture.asset('assets/…/x.svg', width:, height:)(flutter_svg)
image fill FILL / FITImage.asset(fit: BoxFit.cover / BoxFit.contain)

Web(CSS / Tailwind / React)映射表

FigmaCSS
column / rowdisplay:flex; flex-direction: column / row; gap: Gpx
wrap, rowGap Rflex-wrap: wrap; column-gap: G; row-gap: R
pad t,r,b,lpadding: t r b l(与 CSS 顺序相同)
main MIN / CENTER / MAX / SPACE_BETWEENjustify-content: flex-start / center / flex-end / space-between
cross MIN / CENTER / MAX / BASELINEalign-items: flex-start / center / flex-end / baseline
HUGwidth/height: fit-content(或直接 auto)
FILL(主轴)flex: 1 1 0; min-width: 0
FILL(交叉轴)align-self: stretch
FIXEDwidth: Wpx; height: Hpx; flex-shrink: 0
@x,y / absolute父级 position: relative;子级 position:absolute; left:x; top:y(使用 pin 实现 right/bottom)
colors #RRGGBBAA直接作为有效的 CSS 使用
gradient-linear Ndeglinear-gradient(Ndeg, c1 p1%, c2 p2%)
drop-shadowbox-shadow: x y B S color(inner-shadow 添加 inset)
layer-blur / background-blur Rfilter: blur(R/2 px) / backdrop-filter: blur(R/2 px)
textfont: weight size/lineHeight family; letter-spacing(ls % → pct/100 em)
ellipsis maxLines Ndisplay:-webkit-box; -webkit-line-clamp:N; -webkit-box-orient:vertical; overflow:hidden
assets/x.svg<img src> 或内联 SVG;保持导出的尺寸

spec.json 还包含 Figma 自身生成的 CSS(css),适用于大多数图层。用它来交叉检查 CSS 值;令牌和布局结构仍来自上述树结构。

规则

  • Spec 中的值优先于你在图片中看到的。当它们冲突时,相信 spec 并提及冲突。
  • 除非用户要求规范化到令牌,否则不要四舍五入或“改进”数值(14 保持 14,而不是 16)。
  • 隐藏图层不会被导出。不要臆想导出中不存在的状态(悬停、错误、空状态);请要求用户导出那些画框。
  • 标记缺失的字体。如果项目中未捆绑该字体家族,请说明并告知用户需要添加什么(pubspec fonts / @font-face)。
  • 对于多个断点或状态,要求用户导出每个画框。每个画框都会成为自己的文件夹。

相关技能