Install
$ agentstack add skill-mythkiven-figma-ios-codegen-figma-ios-vector-vs-code ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Figma 矢量图形处理策略
⛔ 红线规则(最高优先级,覆盖所有下文)
含「语义子节点」的容器节点,即使被 figma-ios-preload-data 标记为 is_export_asset=true,也禁止整组用切图替代,必须按子节点逐一生成代码。
判定:什么是「语义子节点」
只要节点的子树(含跨层)中任意一个节点满足以下任一条件,该节点就含语义子节点:
| 条件 | 说明 | 例 | |---|---|---| | type == "TEXT" | 含可读文本 | "STEP.1"、"找人试音"、"绝地求生" | | type == "INSTANCE" | 含组件实例(按钮/标签/图标 …) | 品类卡片、段位标签、性别 pill | | _role.is_iconfont == true | 含 iconfont | next/query/check 图标 | | _role.is_iconfont_library | 含 iconfont 集合容器 | iconfont_24 | | _role.is_list_container | 含横向 / 纵向列表容器 | 可滚动、Tag 集合 |
> 设计师在 Figma 上勾导出(export)经常是出于"备份给开发"目的,不代表这个组应该当成一张静态图。把"步骤条整组""5 个品类整组"做成切图,会直接导致:① 文字写死、改不了;② 状态切换不可能(选中/未选中);③ 国际化失败;④ 视觉看似 OK 实则功能完全缺失。这是历史上多次出现的高发陷阱,必须强制规避。
决策伪代码(先于"代码绘制 vs 下载图片"决策)
def can_use_export_asset(node):
if not (node.get("export") or {}).get("is_export_asset"):
return False
# 判定是否含语义子节点
for child in walk_subtree(node):
if child["type"] in ("TEXT", "INSTANCE"):
return False
role = child.get("_role") or {}
if role.get("is_iconfont") or role.get("is_iconfont_library"):
return False
if role.get("is_list_container"):
return False
return True # 子树纯几何/矢量,整组切图安全
允许整组切图的典型场景(白名单)
- 纯位图节点(
fills[].type == "IMAGE") BOOLEAN_OPERATION美术字 / Logo(无 TEXT 子节点)- 纯矢量装饰(背景插画、底纹)
- 单个 imageset 的图标(无子节点)
红线违反后的处置
如果你已经写出 UIImageView(image: UIImage(named: "img_xxx")) 来代替一个含 TEXT/INSTANCE 的节点,回退该实现,改为:
- 把这个 GROUP/FRAME 当作
UIView容器; - 它的子节点逐一生成对应的
UILabel/UIButton/UIView/ iconfontUILabel; - 不需要切图(因为切图是为了避免重写美术字之类的 BOOLEAN_OPERATION,与文字/图标无关)。
> 例外:节点确实是「设计师做的截屏占位图」(如设计稿里贴了一张"竞品截图"用作后续修改参考),且团队明确要先按图占位的 → 在代码顶部加 // TODO(阶段2): 拆解 为子节点实现,并在 README 列出,不允许直接当阶段 2 交付。
本 Skill 的职责
规定在 Figma → iOS 代码生成时:
- 哪些矢量图形必须下载为图片 Assets
- 哪些矢量图形应该用代码绘制(
UIView+CALayer+UIBezierPath) - 如何判断和决策
决策流程图
Figma 矢量节点
↓
┌──────────────────────────────────────┐
│ 1. 是否为简单几何形状? │
│ - 矩形、圆角矩形、圆形、椭圆 │
│ - 纯色填充或简单渐变 │
│ - 无复杂路径或布尔运算 │
└──────────────────────────────────────┘
↓ 是 ↓ 否
用代码绘制 继续判断
↓
┌──────────────────────────────────────┐
│ 2. 是否为复杂矢量图形? │
│ - 贝塞尔曲线路径(≥3个) │
│ - 布尔运算(UNION/SUBTRACT/EXCLUDE)│
│ - 美术字体、Logo、特殊图标 │
└──────────────────────────────────────┘
↓ 是 ↓ 否
下载为图片 用代码绘制
规则 1:用代码绘制(推荐优先)
适用场景
以下 Figma 节点类型必须用代码绘制,禁止下载为图片:
| Figma 类型 | 识别特征 | iOS 实现 | 示例 | |-----------|---------|---------|------| | 矩形 | RECTANGLE,无圆角或圆角简单 | UIView + backgroundColor | 纯色背景 | | 圆角矩形 | RECTANGLE,cornerRadius ≤ 50 | UIView + layer.cornerRadius | 按钮背景 | | 圆形 | ELLIPSE,宽高相等 | UIView + layer.cornerRadius = width/2 | 头像容器 | | 渐变背景 | fills[0].type == "GRADIENT_LINEAR" | CAGradientLayer | 渐变按钮 | | 纯色图形 | 单一 SOLID 填充,简单形状 | UIView + backgroundColor | 分隔线 | | 边框 | strokes 数组 | layer.borderWidth + borderColor | 输入框边框 |
⚠️ 强制规则:用数据包字段判断"代码绘制 vs 切图"
figma-ios-preload-data 已经在阶段 1 把每个节点的 type / fills / strokes / corner_radius / vector_geometry / effects / export.is_export_asset 全部规范化进 design.json,并:
- 设计师有 export →
node.export.is_export_asset = true且对应 imageset 已在assets/ios/→ 直接用切图 - 设计师无 export → 按下面的判定标准决定 代码绘制 或 生成 mock 图片
1. design.json[node].export.is_export_asset == true
→ 用 assets/ios/manifest.json 中的 asset_name → UIImage(named:)
2. 否则按 should_draw_with_code(node) 判断(见下面"判断标准")
→ true: 用代码绘制(UIView/CALayer/CAGradientLayer)
→ false: 加 TODO 注释 + mock 占位
> 阶段 2 不再调 MCP / Figma REST API;判断只看 design.json[node] 字段。
判断标准(代码绘制)
满足以下所有条件时,用代码绘制:
✅ 形状简单(矩形/圆/椭圆)
✅ 填充简单(纯色/线性渐变/径向渐变)
✅ 无复杂路径(子路径 ≤ 1 个)
✅ 无布尔运算(UNION/SUBTRACT/INTERSECT/EXCLUDE)
✅ 圆角简单(`cornerRadius` 统一或仅部分圆角)
✅ 尺寸固定或可缩放(不依赖精确像素)
✅ 无复杂效果(effects 数组为空或 visible=false)
⚠️ 特殊检查:VECTOR 节点的复杂圆角
问题背景:
Figma 的 VECTOR 节点可能包含复杂的圆角路径(如步进器的单边圆角),但 corner_radius 会显示为 0。
触发条件(数据包字段):
node.type == "VECTOR"(或含路径的布尔/星形等)node.corner_radius缺失或为 0,且无明显corner_radii- 但
node.vector_geometry.fill_paths或stroke_paths非空(阶段 1 从 RESTfillGeometry/strokeGeometry写入)
判断:读 SVG path 字符串:
design.json[node].vector_geometry.fill_paths[].data
design.json[node].vector_geometry.stroke_paths[].data
(旧文档里的 vector_paths 已废弃,数据包不再写该字段。)
判断圆角类型:
分析 SVG path:
| Path 特征 | 识别方法 | 圆角类型 | |----------|---------|---------| | C 或 A 命令 | 有圆弧(贝塞尔曲线或弧线)| 有圆角 | | 圆弧在四周 | 4 个 C/A 命令分布均匀 | 全圆角 | | 圆弧在部分边 | 1-2 个 C/A 命令 | 单边或双边圆角 | | 无 C/A 命令 | 只有 L/H/V 命令 | 无圆角(矩形)|
决策表:
| SVG path 特征 | 圆角类型 | iOS 实现 | 代码绘制? | |-------------|---------|---------|-----------| | 无 C/A 命令 | 无圆角 | UIView + backgroundColor | ✅ 是 | | 4 个相同的圆弧 | 全圆角 | layer.cornerRadius = X | ✅ 是 | | 单边或双边圆弧 | 部分圆角 | layer.cornerRadius + layer.maskedCorners | ✅ 是 | | 复杂路径 | 不规则圆角 | 下载图片或 UIBezierPath | ❌ 否 |
实现示例(单边圆角):
// 步进器减少按钮(左边圆角,右边直角)
// design.json: type=VECTOR, corner_radius=0
// vector_geometry.fill_paths[0].data: "M0 16C0 7.16344 7.16344 0 16 0H32V32H16C7.16344 32 0 24.8366 0 16Z"
// 识别:左边有圆弧,右边是直线 → 单边圆角
private lazy var decreaseBackgroundView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(white: 1.0, alpha: 0.1)
// 左边圆角,右边直角
v.layer.cornerRadius = 16 // 高度 32 / 2 = 16
v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner] // 左上和左下
return v
}()
// 步进器增加按钮(右边圆角,左边直角)
private lazy var increaseBackgroundView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(white: 1.0, alpha: 0.1)
// 右边圆角,左边直角
v.layer.cornerRadius = 16
v.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner] // 右上和右下
return v
}()
iOS 12.0+ 兼容性:
- ✅
layer.maskedCorners可用于 iOS 11.0+ - ✅ 项目最低部署 iOS 12.0,可以安全使用
常见单边圆角场景:
// 左边圆角
v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
// 右边圆角
v.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
// 上边圆角
v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
// 下边圆角
v.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
// 对角圆角(左上+右下)
v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner]
检查清单(VECTOR 节点):
□ 已读取 design.json[node].corner_radius
□ 如果 corner_radius = 0 且 type = VECTOR
→ 已读取 design.json[node].vector_geometry.fill_paths / stroke_paths
→ 已解析 SVG path(`.data`)
→ 已判断圆角类型
□ 如果是单边圆角 → 使用 layer.maskedCorners
□ 如果是复杂路径 → 下载图片或 UIBezierPath
判断标准(代码绘制)
满足以下所有条件时,用代码绘制:
✅ 形状简单(矩形/圆/椭圆)
✅ 填充简单(纯色/线性渐变/径向渐变)
✅ 无复杂路径(子路径 ≤ 1 个)
✅ 无布尔运算(UNION/SUBTRACT/INTERSECT/EXCLUDE)
✅ 圆角简单(`cornerRadius` 统一或仅部分圆角)
✅ 尺寸固定或可缩放(不依赖精确像素)
✅ 无复杂效果(effects 数组为空或 visible=false)
示例 1:Mask(黄色圆角矩形)
Figma 数据:
{
"id": "1:306",
"name": "Mask",
"type": "VECTOR",
"fills": [{
"type": "SOLID",
"color": {"r": 1.0, "g": 0.9647, "b": 0.0235} // #FFF606
}],
"cornerRadius": 25.0,
"cornerSmoothing": 0.6,
"absoluteBoundingBox": {"width": 343.0, "height": 48.0}
}
判断:
- ✅ 形状简单:矩形
- ✅ 填充简单:纯色 #FFF606
- ✅ 无复杂路径
- ✅ 无布尔运算
- ✅ 圆角简单:25px 统一圆角
结论:用代码绘制 ✅
iOS 代码:
// ✅ 推荐:用代码绘制(0KB,易维护)
private lazy var maskView: UIView = {
let v = UIView()
v.backgroundColor = MKUIStyle.mk_cXX() /* color_map: #FFF606 */ // 黄色
v.layer.cornerRadius = 25
v.layer.cornerCurve = .continuous // 平滑圆角(iOS 13+)
return v
}()
iOS 12 兼容:
// iOS 12 不支持 .continuous,使用普通圆角
v.layer.cornerRadius = 25
// 如果需要更平滑的效果,可以略微增大圆角值
v.layer.cornerRadius = 27 // 视觉上接近 cornerSmoothing: 0.6
示例 2:渐变背景
Figma 数据:
{
"fills": [{
"type": "GRADIENT_LINEAR",
"gradientStops": [
{"color": {"r": 0, "g": 0.576, "b": 0.933}, "position": 0},
{"color": {"r": 0.118, "g": 0.396, "b": 0.859}, "position": 1}
]
}]
}
iOS 代码:
// ✅ 推荐:用 CAGradientLayer(0KB)
private func setupGradient() {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [
MKUIStyle.mk_cXX() /* color_map: #0093EE */.cgColor, // 起始色
MKUIStyle.mk_cXX() /* color_map: #1E65DC */.cgColor // 结束色
]
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5) // 左
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5) // 右
backgroundView.layer.insertSublayer(gradientLayer, at: 0)
}
override func layoutSubviews() {
super.layoutSubviews()
// 更新渐变层大小
backgroundView.layer.sublayers?.first?.frame = backgroundView.bounds
}
规则 2:下载为图片(必须)
适用场景
以下 Figma 节点类型必须下载为图片 Assets:
| Figma 类型 | 识别特征 | 原因 | 示例 | |-----------|---------|------|------| | 复杂贝塞尔曲线 | 子路径 ≥ 3 个 | 代码实现成本高,易出错 | 美术字体、Logo | | 布尔运算 | BOOLEAN_OPERATION(UNION/SUBTRACT/INTERSECT/EXCLUDE)| 需要精确像素级控制 | 特殊形状、镂空图形 | | 图片填充 | fills[0].type == "IMAGE" | 本身就是图片 | 背景图片、照片 | | 复杂渐变 | 多个渐变点(≥3 个)、径向渐变 + 复杂形状 | iOS 原生渐变限制 | 艺术效果 | | 阴影/模糊复杂 | 多层阴影、特殊混合模式 | 代码难以完美复现 | 特效文字 | | 设计师明确标注 | Figma 评论中要求"图片形式" | 尊重设计意图 | - |
判断标准(下载图片)
满足以下任一条件时,下载为图片:
❌ 布尔运算(BOOLEAN_OPERATION)
❌ 贝塞尔曲线路径 ≥ 3 个
❌ 图片填充(fills[0].type == "IMAGE")
❌ 复杂渐变(≥ 3 个渐变点)
❌ 特殊效果(阴影叠加、混合模式)
❌ 美术字体、Logo、品牌图形
❌ 评论中明确要求
示例 3:形状结合(美术字体)
Figma 数据:
{
"id": "1:310",
"name": "形状结合",
"type": "BOOLEAN_OPERATION",
"booleanOperation": "EXCLUDE",
"children": [
{"id": "1:311", "name": "路径", "type": "VECTOR"},
{"id": "1:312", "name": "路径", "type": "VECTOR"},
... // 共 14 个子路径
],
"fills": [{"type": "SOLID", "color": {...}}]
}
判断:
- ❌ 布尔运算:
EXCLUDE(排除) - ❌ 贝塞尔曲线路径:14 个
- ❌ 用途:美术字体"找人试音"
结论:必须下载为图片 ✅
下载步骤(已由 figma-ios-preload-data 完成):
- 设计师点了 export →
node.export.is_export_asset=true→ 数据包阶段 1 已下载 - 设计师没点 export 但代码绘制不可行 → 在 README 标注 TODO,请设计补 export 后重新跑数据包
- 阶段 2 直接
UIImage(named: assets/ios/manifest.items[node_id].asset_name)
iOS 代码:
// ✅ 正确:使用图片 Assets
private lazy var textShapeImageView: UIImageView = {
let v = UIImageView()
v.contentMode = .scaleAspectFit
v.image = UIImage(named: "img_99a99_button_text_shape")
return v
}()
规则 3:边界情况决策
情况 1:圆角矩形(cornerRadius > 50)
判断:
- 如果
cornerRadius接近宽度或高度的 50%(类似胶囊形状) - 且无其他复杂效果
决策:仍然用代码绘制 ✅
// 胶囊形状
v.layer.cornerRadius = v.bounds.height / 2
情况 2:仅一个边有圆角
Figma 特征:
{
"rectangleCornerRadii": [10, 10, 0, 0] // 仅顶部圆角
}
iOS 实现:
// iOS 11+
let path = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: 10, height: 10)
)
let mask = CAShapeLayer()
mask.path = path.cgPath
v.layer.mask = mask
决策:用代码绘制 ✅(略微复杂,但仍可控)
情况 3:简单 Logo(≤2 个路径)
判断:
- 虽然是矢量图形,但路径数量少
- 用途明确为 Logo 或品牌标识
决策:下载为图片 ✅(保证品牌一致性)
情况 4:Icon(iconfont 可用)
判断:
- 设计稿中使用
iconfont/icon_xxx_24命名 - 项目 iconfont 库中有对应图标
决策:用 iconfont ✅(详见 [figma-ios-iconfont-mapping](../figma-ios-iconfont-mapping/SKILL.md))
// 使用 iconfont(最优)
iconLabel.font = MKIconFont.iconFont(withSize: 24) // iconfont_map.font
iconLabel.text = MKIconFont.shared().mk_icon_xxx // iconfont_map.text
实施步骤
步骤 1:从数据包读节点
node = design["nodes"][node_id]
node_type = node["type"] # RECTANGLE / VECTOR / BOOLEAN_OPERATION / ...
fills = node.get("fills", []) # [{"type":"SOLID","color":"rgba(...)"}, ...]
strokes = node.get("strokes", [])
corner_radius = node.get("corner_radius", 0)
children_count = len(node.get("children", []))
boolean_op = node.get("boolean_operation") # UNION / SUBTRACT / INTERSECT / EXCLUDE
is_export = (node.get("export") or {}).get("is_export_asset", False)
步骤 2:应用决策树
def should_download_as_image(node):
if (node.get("export") or {}).get("is_export_asset"):
return True
if any((f.get("type") == "IMAGE") for f in node.get("fills", [])):
return True
if node.get("type") == "BOOLEAN_OPERATION":
return True
if len(node.get("children", [])) >= 3:
return True
for f in node.get("fills", []):
if f.get("type") in ("GRADIENT_LINEAR", "GRADIENT_RADIAL") \
and len(f.get("gradient_stops", [])) >= 3:
return True
name = node.get("name", "").lower()
if any(k in name for k in ["logo", "美术", "艺术", "形状结合", "shape"]):
return True
return False
> 该节点已被 figma-ios-preload-data 标记 _role.is_export_asset 时,imageset 已经在 assets/ios/,直接 UIImage(named: ...)。
步骤 3:生成对应代码
场景 A:用代码绘制
// Figma 节点 1:306 - Mask(黄色圆角矩形)
// 决策: 简单矩形 + 纯色 + 统一圆角 → 用代码绘制 ✅
private lazy var maskView: UIView = {
let v = UIView()
v.backgroundColor = MKUIStyle.mk_cXX() /* color_map: #FFF606 */
v.layer.cornerRadius = 25
v.layer.cornerCurve = .continuous // iOS 13+
return v
}()
场景 B:下载为图片
// Figma 节点 1:310 - 形状结合(美术字体)
// 决策: BOOLEAN_OPERATION + 14个路径 → 下载为图片 ✅
// Assets: img_99a99_button_text_shape
private lazy var textShapeImageView: UIImageView = {
let v = UIImageView()
v.contentMode = .scaleAspectFit
v.image = UIImage(named: "img_99a99_button_text_shape")
return v
}()
代码注释规范
必须包含的信息
// Figma 节点 -
// 决策: → ✅
// [如果是图片] Assets:
// [如果是代码] 实现:
示例
// ✅ 代码绘制示例
// Figma 节点 1:289 - 矩形(步骤指示器背景)
// 决策: 线性渐变 + 边框 + 圆角 → 用代码绘制(CAGradientLayer)✅
// 实现: CAGradientLayer + layer.borderWidth
private lazy var backgroundView: UIView = {
let v = UIView()
v.layer.cornerRadius = 16
v.layer.borderWidth = 1
v.layer.borderColor = UIColor.white.withAlphaComponent(0.15).cgColor
return v
}()
// ✅ 图片下载示例
// Figma 节点 1:310 - 形状结合("找人试音"美术字)
// 决策: BOOLEAN_OPERATION(EXCLUDE) + 14个路径 → 下载为图片 ✅
// Assets: img_99a99_button_text_shape (2KB)
// 尺寸: 85×19
private lazy var textShapeImageView: UIImageView = {
let v = UIImageView()
v.contentMode = .scaleAspectFit
v.image = UIImage(named: "img_99a99_button_text_shape")
return v
}()
优势对比
用代码绘制 ✅
优势:
- ✅ 包体积:0KB
- ✅ 可维护性:易于调整颜色、尺寸、圆角
- ✅ 适配性:支持动态颜色(深色模式)、动态尺寸
- ✅ 性能:矢量缩放,无失真
劣势:
- ⚠️ 开发成本:需要写代码
- ⚠️ 限制:复杂图形无法实现
下载为图片 ✅
优势:
- ✅ 准确性:100% 还原设计稿
- ✅ 复杂度:支持任意复杂图形
- ✅ 开发速度:直接使用 UIImage
劣势:
- ⚠️ 包体积:每个图片 1-10KB
- ⚠️ 维护成本:修改需要重新导出
- ⚠️ 适配性:深色模式需要两套图
常见错误
❌ 错误 1:简单图形也下载为图片
// ❌ 不推荐:纯色圆角矩形下载为图片(浪费 2KB)
maskImageView.image = UIImage(named: "img_xxx_mask")
// ✅ 推荐:用代码绘制(0KB)
v.backgroundColor = MKUIStyle.mk_cXX() /* color_map: #FFF606 */
v.layer.cornerRadius = 25
❌ 错误 2:复杂图形用代码硬写
// ❌ 不推荐:14 个贝塞尔路径用代码手写(易出错)
let path = UIBezierPath()
path.move(to: CGPoint(x: 155, y: 700))
path.addCurve(to: ..., controlPoint1: ..., controlPoint2: ...)
// ... 100+ 行代码
// ✅ 推荐:下载为图片(2KB,准确)
textImageView.image = UIImage(named: "img_xxx_text_shape")
❌ 错误 3:忘记 iOS 12 兼容
// ❌ iOS 12 崩溃
v.layer.cornerCurve = .continuous // iOS 13+
// ✅ iOS 12 兼容
if #available(iOS 13.0, *) {
v.layer.cornerCurve = .continuous
}
❌ 错误 4:属性名与系统冲突
// ❌ 编译错误:UIView 已有只读属性 maskView
private lazy var maskView: UIView = { ... }()
// ✅ 正确:使用描述性名称避免冲突
private lazy var yellowMaskBackgroundView: UIView = { ... }()
禁止使用的属性名(与 UIKit 冲突):
- ❌
backgroundView- UICollectionViewCell 已有此属性(iOS 14+,改用cellBackgroundView) - ❌
maskView- UIView 已有此属性 - ❌
layer- UIView 已有此属性 - ❌
frame- UIView 已有此属性 - ❌
bounds- UIView 已有此属性 - ❌
superview- UIView 已有此属性 - ❌
subviews- UIView 已有此属性 - ❌
backgroundColor- UIView 已有此属性(除非 override) - ❌ `is
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mythkiven
- Source: mythkiven/figma-ios-codegen
- License: MIT
- Homepage: https://github.com/mythkiven/figma-ios-codegen/tree/main/docs
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.