Figma 变量于 2023 年发布,是该平台对设计 Token 的期待已久的回应。这个功能十分强大:命名的原始值集合——颜色、数字、字符串、布尔值——可以绑定到任何组件的任何属性。更改变量,每个实例都会更新。添加深色模式集合,每个变量绑定都会自动切换。

对于 AI 代码生成,变量不仅仅是有用的。它们是将 Figma 文件从像素完美的原型转变为 Agent 可以正确实现的规范的机制。当颜色有名称——color/brand/primary,而不是 #7F5CFE——Agent 就可以将其映射到代码 Token,正确实现深色模式,并产生参与你实际设计系统的输出。

问题是:目前大多数在用的 Figma 文件都没有设置变量。figmascope 处理这两种情况。本文解释如何处理。

变量究竟是什么

Figma 变量是绑定到集合的命名标量。集合按模式组织变量——"浅色"和"深色"是典型例子。集合中的每个变量可以有不同的每模式值:color/surface/background 在浅色模式下是 #FFFFFF,在深色模式下是 #0D0D0D。绑定会传播:引用 color/surface/background 的每个填充在切换模式时都会更新。

变量可以是颜色、数字、字符串或布尔值。实践中,影响最大的是颜色和数字——涵盖典型设计系统中大部分 Token 覆盖面:调色板、间距比例、圆角半径、字体大小、海拔值。

Figma 通过 REST API 将变量公开为 localVariables 集合。每个变量有 ID、名称、类型和每模式值。引用变量的组件属性携带带有变量 ID 的 boundVariables 字段。这是可以干净地通过提取流水线传递的结构化数据。

顺利的情况:变量存在

当 Figma 文件有变量时,figmascope 从 API 读取它们,并按照与 W3C 设计 Token 社区组兼容的结构构建 tokens.json。每个 Token 有 $value$type。颜色 Token 获得带有可选透明度的十六进制值。间距 Token 获得带有 px 单位提示的数值。Token 名称遵循变量的集合和名称路径:

{
  "color": {
    "brand": {
      "primary": { "$value": "#7F5CFE", "$type": "color" }
    },
    "surface": {
      "background": { "$value": "#FFFFFF", "$type": "color" }
    }
  },
  "spacing": {
    "4": { "$value": 4, "$type": "number" },
    "8": { "$value": 8, "$type": "number" },
    "16": { "$value": 16, "$type": "number" }
  }
}

构建逐屏 IR 时,每个有 boundVariables 引用的填充都会获得 Token 名称而非解析后的十六进制。节点携带:

"fills": [{ "type": "SOLID", "tokenRef": "color/brand/primary" }]

不是 #7F5CFE,而是 Token 名称。Agent 读取这个并生成 background-color: var(--color-brand-primary)Color.brandPrimary 或目标框架的 Token 消费模式。这就是你想要的输出:与设计系统连接的代码,而不是设计师一更新颜色就会出问题的代码。

语义命名是代码随时间保持良好与代码漂移之间的区别。源代码中的十六进制值是一种负担;Token 引用是一种契约。变量是使 Figma 文件能够表达契约而非像素的机制。

现实:大多数文件没有变量

变量需要 Figma Professional 或更高版本的计划。它们需要设计师来设置——这意味着创建集合、命名变量,并手动将它们绑定到每个组件属性。在成熟、维护良好的设计系统文件上这已经完成。在初创公司的产品 Figma 文件、自由职业者的客户文件,或任何早于变量功能的文件上,通常没有设置。

figmascope 的设计也对这些文件有用。它优雅降级:当变量缺失时,它回退到基于频率的 Token 推断。

回退方案:从频率推断

推断算法如下:

  1. 遍历每个导出框架中的每个叶节点。
  2. 收集所有填充颜色、间距值和圆角半径。
  3. 统计每个唯一值的出现次数。
  4. 出现次数超过频率阈值的值被提升为推断 Token。
  5. 每个 Token 获得一个值派生的名称:color.7f5cfespacing.16radius.8

输出的 tokens.json 在结构上与变量路径类似,但名称是值派生的而非语义的:

{
  "color": {
    "7f5cfe": { "$value": "#7F5CFE", "$type": "color" },
    "f6f2ea": { "$value": "#F6F2EA", "$type": "color" }
  },
  "spacing": {
    "16": { "$value": 16, "$type": "number" },
    "8": { "$value": 8, "$type": "number" }
  }
}

在 IR 中,使用这些值的节点获得 Token 引用:"tokenRef": "color.7f5cfe"。不是硬编码的字面量,而是引用——只是指向推断 Token 而非命名 Token。

Agent 仍然生成 Token 引用的代码。var(--color-7f5cfe) 不如 var(--color-brand-primary) 可读,但它仍然是 Token——你可以查找替换它、重命名它、审计它的用法。它是值上的命名句柄,而不是魔法数字。

tokensSource 字段

每个 figmascope 包都包含一个 _meta.json,记录包中的内容及其生成方式。tokensSource 字段有三个可能的值:

这很重要,因为它告诉消费的 Agent(以及阅读包的开发者)对 Token 名称的信任程度。figma-variables 包是你设计系统的真相来源。inferred-from-frequency 包是有用的结构脚手架,需要设计师命名审查才能成为规范。none 包是一个需要后期 Token 化的硬编码值起点。

诚实的元数据被低估了。静默推断而不将其标记为推断的工具会制造虚假信心。figmascope 明确呈现推断链,让你知道你在使用什么。

为什么频率推断比什么都没有要好

频率推断的替代方案是在每个填充节点中输出解析后的字面值——每个使用该颜色的填充节点中都有 #7F5CFE。这产生了更难重构、更难审计、更难在最终添加设计系统时连接的代码。

频率推断至少提取了设计实际使用的值集合。如果 #7F5CFE 在设计中出现了 47 次,这是一个信号:这是主色,而不是强调色。Token 名称不知道这一点——它只是 color.7f5cfe——但频率数据讲述了故事。获得推断 Token 的 Agent 可以对哪些值是主要的、哪些是一次性的做出合理的猜测。

更实际的是:频率推断给你一个可以跨版本差异比较的 tokens.json。如果你在设计师更改了一个重复颜色后两次导出同一文件,差异显示 Token 值发生了变化。没有推断,你将追踪分散在多个 IR 文件中的每个单独字面量变化。

设计师仍应做什么

频率推断是兼容层,不是变量的替代品。正确的路径是让设计师为参与设计系统的所有值采用变量:品牌颜色、中性比例、间距比例、圆角半径、海拔、字体排版。一旦这些到位,figmascope 包就从脚手架质量 Token 升级为生产质量 Token。

变量还解锁了包中的主题:每个 Token 有多个模式值。具有浅色/深色模式的文件产生一个带有每模式值的 tokens.json,可以直接输入带有媒体查询覆盖的 CSS 自定义属性或平台特定的主题对象。这是无法从单一设计快照推断的——它需要通过变量表达的明确设计意图。

升级路径是渐进式的。团队可以从今天的推断质量 Token 开始,随着设计系统的成熟逐步采用变量,并自动获得更好的包。tokensSource 字段跟踪你在这一进程中的位置。

完整 Token 流水线

为了具体说明,以下是 figmascope 对 IR 中每个填充使用的完整解析顺序:

  1. 节点是否有 boundVariables.fills 引用?如果是,解析为变量名称和模式零值。Token 来源:figma-variables
  2. 解析后的值是否出现在推断频率 Token(高于阈值)中?如果是,映射到推断 Token 名称。Token 来源:inferred-from-frequency
  3. 否则:直接使用解析后的十六进制值。无 Token 引用。Token 来源:none

按顺序尝试步骤。最高质量的来源获胜。_meta.json 中的 tokensSource 字段反映整个包的主导路径。

这意味着部分配置变量的文件——某些组件有绑定,其他没有——产生混合包。有变量的地方使用命名 Token,没有的地方使用推断 Token。这是正确的行为:使用每一点可用的结构化信息,在缺失的地方优雅降级,并对每个值采用的路径诚实。

figmascope 应用导出你的包,看看你的文件产生哪个 tokensSource。然后将包与 Claude CodeCursor 一起使用,进行精准的 Token 引用代码生成。