每次 figmascope 导出都会生成一个包含七个产物的 .zip 压缩包。CONTEXT.md 是其中第一个被读取的文件——这是有意为之的设计。它不是 README,不是自动生成的文档,而是设计稿与负责将其转化为代码的 Agent 之间的一份编译器式契约。

本文将逐步介绍其内容、结构设计的原因,以及跳过它会出现什么问题。

契约与文档的区别

文档描述已有的内容,契约规定必须为真的条件。这一区别在读者是 LLM 时尤为重要——LLM 会在没有更好选项时,毫不犹豫地发明间距值、压扁布局层级或硬编码十六进制颜色。

CONTEXT.md 以目标声明开头:

# CONTEXT.md — Jetpack Compose target

This file is the authoritative spec for generating UI code from this bundle.
Read it before reading any other file.

"Jetpack Compose target" 并非装饰。Agent 用它来选择可组合基元、处理 dp 与 sp 单位、了解 Modifier.padding() 是间距的正确抽象,以及 Box 配合 Alignment 是处理叠加布局的方式。React/Tailwind 目标会生成包含不同基元约束的 CONTEXT.md。

"先读这个文件"的指令也是刻意设计的。Agent 按顺序处理上下文 Token。如果 Token 规则在 Agent 已经开始对某个组件进行推理之后才出现,约束就来得太晚了。将契约前置意味着规则在生成的第一个 Token 时就已生效。

严格约束部分

CONTEXT.md 最关键的部分是约束块:

## Strict constraints (must follow)

- Never hardcode dp values if a token exists within ±2dp
- Never flatten layout hierarchy — preserve every stack/overlay/absolute node
- Use stringRef values from strings.json, never inline literal text
- Treat missing fields as absent, not zero
- Do not invent component names not present in components/inventory.json

每条约束都源于我们观察到 Agent 违反它的真实案例。±2dp Token 规则是最典型的例子。没有这条规则,Agent 遇到堆叠节点上的 gap: 14 会直接写 Arrangement.spacedBy(14.dp)。有了这条规则,它会检查 spacing.16spacing.12 是否在 2dp 以内,并使用 Token 替代。这是截然不同的输出——当 Token 值变更时,前者能保持一致性,后者不行。

层级规则的存在是因为 Compose 是一棵布局树。当 Agent 将嵌套堆叠压扁为一组定位元素的平铺列表时,会破坏原始结构隐含的响应式行为。IR 保留每一层嵌套是有原因的——参见 逐屏 IR — Stack、Overlay、Absolute、Leaf,了解嵌套如何编码布局意图。

约束不是"如果你愿意就用 Token",而是"只要 Token 存在就绝对不能硬编码"。这是禁令,不是建议。LLM 对禁令和建议的反应是不同的。

stringRef 规则对国际化至关重要。如果 Agent 内联了 "Speed Test" 而不是引用资源键,就制造了一个本地化漏洞。该约束明确地将 Agent 指向 strings.json

Agent 如何顺序读取 CONTEXT.md

LLM 上下文窗口从左到右处理 Token。CONTEXT.md 的结构充分利用了这一特性。顺序如下:

  1. 目标声明(设定整个生成框架)
  2. 严格约束(适用于每个决策的禁令)
  3. 包映射(存在哪些文件及各自包含的内容)
  4. Token 使用规则(如何解析间距、颜色、圆角、字体排版)
  5. 范围说明(诚实地标注——本包覆盖和不覆盖的内容)

包映射部分告诉 Agent 应该读取哪些文件以及读取顺序:

## Bundle contents

- tokens.json — design tokens (spacing, radius, color, typography)
- screens/*.json — per-screen IR in stack/overlay/absolute/leaf format
- components/inventory.json — component identity list
- strings.json — i18n resource keys
- _meta.json — generation metadata and warnings

没有这张映射表,Agent 可能不知道 components/inventory.json 的存在,或者将 _meta.json 误当作主规范。明确的枚举引导了读取顺序。

范围说明 — v0.4 诚实标注的未覆盖内容

范围说明部分是 figmascope 记录自身局限性的地方。这是刻意为之且不可妥协的。不知道规范不完整的 Agent 会自信地用发明来填补空白,这比知道空白存在更糟糕。

## Scope notes (v0.4)

- Gradient fills are not supported. Nodes with gradient fills emit a warning
  in _meta.json under warnings. Treat as a solid fill approximation or TODO.
- Typography tokens require Figma Variables to be populated. If tokensSource
  is "inferred-from-frequency" or "none", typography coverage may be partial.
- This bundle covers UI structure only. Navigation, state management,
  and network calls are outside scope.
- Component instances are identified by componentId. Full component
  source props are not included — the inventory gives identity, not implementation.

渐变警告尤为重要。Figma 支持复杂的渐变填充,这在 Compose 中没有直接等价物,需要自定义绘制。figmascope 不会静默丢弃渐变或生成错误代码,而是在 _meta.json 中发出 background-gradient-not-supported:<name> 警告,并在此处注明,让 Agent 将受影响节点视为已知缺口,而不是自身输出中的 bug。

字体排版说明与 _meta.json 中的 tokensSource 字段相关联。当 Figma 文件没有变量时,figmascope 会从频率推断 Token——常见值成为 Token,稀少值则不。范围说明告诉 Agent 这种推断并不完美,不要假设字体排版已全覆盖。参见 tokens.json 详解,了解推断回退机制的工作原理。

错误 / 正确 示例

让我们看个具体例子。给定一个 gap: 16 的堆叠节点,Token 文件包含 spacing.16: 16

无 CONTEXT.md 约束(错误):

Column(
    modifier = Modifier.padding(horizontal = 24.dp),
    verticalArrangement = Arrangement.spacedBy(16.dp)
) {

有 CONTEXT.md 约束(正确):

Column(
    modifier = Modifier.padding(horizontal = Spacing.spacing24),
    verticalArrangement = Arrangement.spacedBy(Spacing.spacing16)
) {

正确的输出使用了 Token 引用。当设计系统将 spacing.16 从 16dp 改为 14dp 时,代码无需全库搜索替换即可保持正确。

另一个例子——字符串处理。给定一个 text: "Speed Test"stringRef: "speed.test" 的叶子节点:

错误:

Text(text = "Speed Test")

正确:

Text(text = stringResource(R.string.speed_test))

约束将 Agent 指向 strings.json,键为 speed.test,Agent 知道如何将点分表示法映射为 Android 资源 ID。只有在 Agent 生成组件之前读取了约束,这才成为可能。

为什么不直接在提示词中写这些指令?

你可以在提示词中手动写这些指令。figmascope 将其外化为文件,原因如下:

目标不是绕过 Agent 的默认行为进行提示词工程,而是交付一份让默认行为变得无关紧要的规范。

与其他方案的结构比较

Figma 的 Dev Mode 输出测量值、变量和代码片段,但不产生规范。使用 Dev Mode 输出的 Agent 必须从示例中推断规则——这意味着它会对边缘情况推断出错误的规则。

Locofy 等类似工具直接生成代码,没有 CONTEXT.md 的等价物,因为它们不期望 Agent 读取规范——它们期望自己就是 Agent。当工具的代码生成与你的技术栈完全匹配时这没问题;但当你有项目特定的命名约定、自定义组件库或工具不了解的设计 Token 时就不适用了。

CONTEXT.md 是机器可读的设计简报。在大型语言模型出现之前,它以 Confluence 页面或 Notion 文档的形式存在于每次设计交付中,只不过现在是为真正遵守规则的受众而构建的。

如何使用它

在 Cursor 或 Claude Code 中打开 figmascope 导出包时:

  1. 在任何关于设计的提示之前,将 @CONTEXT.md 添加到上下文中。
  2. 引用你正在处理的屏幕 JSON:@screens/home.json
  3. 如果涉及 Token,添加 @tokens.json
  4. 如果处理字符串,添加 @strings.json

CONTEXT.md 约束一旦加载,在整个会话中都会生效。你不需要每次提示都重新添加——只需在开始时添加一次,让它为后续每次生成提供框架。

包中的其他产物在本系列的其余文章中介绍。从 tokens.json 详解 开始,了解 Token 系统如何处理有无 Figma 变量的文件;或阅读 逐屏 IR,了解 Figma 布局如何映射到 stack/overlay/absolute/leaf 节点。准备好尝试了吗?在 figmascope.dev 粘贴你的 Figma URL 并导出你的第一个包。