Community视频与动画github.com

gslvly/sketch-inspector

AI-friendly Sketch design parser. Turn Sketch documents into structured JSON, exported assets and an implementation-ready LayoutIR (flex/grid/absolute/leaf) so any LLM agent can convert Sketch designs into HTML/CSS, React or Vue. Agent skill compatible with Claude Code, Cursor, opencode.

兼容平台Claude Code~Codex CLICursorOpenCode
npx add-skill gslvly/sketch-inspector

name: sketch-inspector description: > 解析 Sketch 图层并导出资源。返回结构化设计数据,包括层级、样式、文本、 颜色,并导出图片资源。用户需要检查 Sketch 设计、提取设计 token、 或根据 Sketch 在任意框架中实现页面时,必须使用此 skill。 metadata: short-description: 解析 Sketch 设计、导出资源、返回结构化数据

Sketch 检查器

将 Sketch 设计转换为结构化数据、图片资源和可实现的页面分块。

使用场景

  • 检查已打开的 Sketch 文档或具体图层
  • 提取结构、样式、文本、颜色、布局和资源信息
  • 根据 Sketch 区域实现 HTML/CSS、React、Vue 或其他页面

前置条件

  • Sketch 正在运行,目标文档已打开
  • Sketch MCP 已开启:General -> Allow AI tools to interact with open documents
  • MCP 服务地址:http://localhost:31126/mcp
  • Sketch Run Code 运行在 JavaScriptCore/CocoaScript 环境,不是普通 Node.js

页面实现强制流程

从 Sketch 生成页面时必须严格执行以下流程,这是唯一最快完成任务的途径,缺少任一步都视为失败:

1. 扫描

提取页面或目标容器的浅层轮廓,确认根节点 layerId

2. 确定路径

  • imageOutputDir:项目图片目录,优先使用现有 images/assets/images/public/images/
  • workTmpDir:临时目录,至少放 result.json;大文件拆分时还会放 manifest.json、section JSON、section HTML

3. 导出

sketch_run_code 中运行导出脚本。

const sketch = require('sketch');

// 参数准备
const layerId = '<目标图层的 layerId>'; // 从步骤 1 扫描获取的目标根节点 ID
const outputDir = '<imageOutputDir 绝对路径>';  // 如: '/Users/edy/project/images'
const outputJsonPath = '<workTmpDir/result.json 绝对路径>';  // 如: '/Users/edy/project/tmp/result.json'

// 执行导出脚本
const exportScript = require('@scripts/export-text-split-assets.js');
const result = exportScript.runExportTextSplitAssets({
  layerId: layerId,
  outputDir: outputDir,
  outputJsonPath: outputJsonPath
});

// 输出结果用于调试
console.log(JSON.stringify(result, null, 2));

返回结果

  • 成功:返回导出统计信息
  • 失败:返回错误信息,检查 layerId 是否有效、路径是否有写入权限

注意

  • 脚本运行在 Sketch JavaScriptCore 环境,不是普通 Node.js
  • 路径必须是绝对路径
  • 输出目录必须存在,脚本不会自动创建

4. 布局推断并覆盖 result.json

Shell 运行:

npx tsx @scripts/sketch_layout_ir_inference.ts \
  <workTmpDir>/result.json \
  <workTmpDir>/result.json

这一步会把导出的原始结构转换成可直接实现的统一布局 JSON,并覆盖原来的 result.json

输出统一 result.json 结构:

  • kind: flex | grid | absolute | leaf
  • direction: row | column(仅 flex)
  • gap: 子元素间距
  • padding: 内边距 { top, right, bottom, left }
  • justifyContent: flex 对齐方式
  • alignItems: 交叉轴对齐方式
  • hasAbsoluteChildren: 当 flex/grid 容器存在直属 absolute 子节点时为 true
  • css.position: "relative":当 flex/grid 容器存在直属 absolute 子节点时显式输出
  • columns / rows: 网格行列数(仅 grid)
  • source: 与当前布局节点对应的实现补充数据,仅保留 sourceClass / asset / background / style / decision / backgroundLayers / derivedFrom 等非布局字段

5. 布局探测后必须分流

布局推断完成后,不允许凭感觉决定实现方式,必须按统一后的 result.json 实际行数分流:

  • result.json 少于或等于 3000 行:直接读取整个 result.json 完成实现,不再拆分
  • result.json 多于 3000 行:必须进入“大文件拆分流程”,禁止直接把整个 JSON 塞给后续实现步骤

行数检查示例:

wc -l <workTmpDir>/result.json

6. 小文件主流程:直接实现

适用条件:result.json 行数 <= 3000

核心规则(MUST FOLLOW):

  1. 禁止普通布局使用 absolute:只有 kind: "absolute" 的节点才允许绝对定位
  2. 有直属 absolute 子节点时,必须信任 result.json 的定位信号:若节点输出了 hasAbsoluteChildren: truecss.position: "relative",实现时必须给该父容器设置已定位状态,不能忽略

生成流程:

  1. 读取完整 result.json
  2. 递归遍历布局树
  3. 根据 kind 生成对应 CSS:
    • flex: display: flex; flex-direction: {direction}; gap: {gap}px; ...
    • grid: display: grid; grid-template-columns: repeat({columns}, 1fr); ...
    • absolute: position: relative; 子元素 position: absolute;
    • leaf: 无布局,渲染内容即可
  4. 直接使用当前节点的 source 完成文本、图片、背景、样式、决策实现,不再回查旧结构 JSON

7. 大文件主流程:拆分 -> 单 Section 实现 -> 回填汇总

适用条件:result.json 行数 > 3000

7.1 拆分 JSON

Shell 运行:

node @scripts/split-result-json.js \
  --inputJsonPath=<workTmpDir>/result.json \
  --outputDir=<workTmpDir> \
  --assetBasePath=images/ \
  --splitStrategy=auto

输出:

  • <workTmpDir>/manifest.json
  • 多个 section JSON
  • 约定好的 implementationPathhtmlMarkercssMarker
  • manifest.json.root.layoutIR:页面主布局语义摘要
  • manifest.json.sections[].layoutIR:section 节点自身的布局语义摘要

7.2 单 Section 实现

每个 section 必须只读取自己的 jsonPath,并按 manifest.json 写入自己的 implementationPath

强制规则:

  • 单 section 实现流程见 @references/single-section-workflow.md
  • section 文件必须是片段:一个 <section> + 一个 <style>
  • section 内只写内部结构和内部样式,不定义主布局容器的外层 margin
  • 非根选择器必须按 className 做作用域隔离
  • 需要深度检查时再用 @scripts/inspect-single-section.js

7.3 回填汇总

所有 section 实现完成后,必须把每个 section 片段回填到总布局文件,不能手工复制粘贴 marker 内容。

主布局文件必须预先满足:

  • htmlMarker 放在页面结构中需要插入 section 的位置
  • cssMarker 必须放在主布局文件的 <style> 块内部,不能放在其他标签、注释区块外层或正文结构中
  • 如果 HTML 和 CSS 分文件,cssMarker 必须放在 cssLayoutPath 指向的 CSS 文件中

Shell 运行:

node @scripts/replace-section-placeholder.js \
  --layoutPath=/path/layout.html \
  --sectionPath=/path/01-section.html \
  --htmlMarker="<!-- 01-section HTML -->" \
  --cssMarker="/* 01-section CSS */"

如果 HTML 和 CSS 在不同文件,额外传 --cssLayoutPath

8. 实现检查清单

实现前确认:

  • 完整读取 result.json
  • 检查每个节点的 kind 字段
  • 检查 meta.background 背景层信息
  • 文本、图片、图层关系已检查
  • 品牌资产和复杂视觉组已识别

9. 交付

报告客观产物:

  • 布局轮廓和目标区域 id
  • result.json 路径和实际行数
  • 使用的是“小文件直接实现”还是“大文件拆分流程”
  • 如走拆分流程:manifest.json 路径、section 数量、回填目标文件路径
  • 布局类型统计(flex/grid/absolute/leaf 数量)
  • 导出资源清单
  • 生成的 HTML/CSS 文件路径

不要输出"已视觉验证"等机器无法判断的结论。

固定脚本

脚本参数和返回结构见 @references/script-api.md

  • @scripts/export-text-split-assets.js:导出图片和 JSON。必填 layerIdoutputDir
  • @scripts/sketch_layout_ir_inference.ts:布局推断并输出统一后的 result.json
  • @scripts/split-result-json.js:大文件主流程脚本,生成 manifest.json 和多个 section JSON
  • @scripts/replace-section-placeholder.js:大文件主流程脚本,把 section 实现回填到总布局文件
  • @scripts/inspect-single-section.js:section 信息不足时做局部深度检查

禁止:自己生成导出脚本、复制脚本源码、重新实现遍历逻辑。

LayoutIR 类型说明

type LayoutKind = 'leaf' | 'flex' | 'grid' | 'absolute'

interface FlexIR {
  kind: 'flex'
  direction: 'row' | 'column'
  gap: number
  padding: { top, right, bottom, left }
  justifyContent: 'flex-start' | 'center' | 'flex-end' | 'space-between'
  alignItems: 'flex-start' | 'center' | 'flex-end' | 'stretch'
  children: LayoutIR[]
}

interface GridIR {
  kind: 'grid'
  columns: number
  rows: number
  columnGap: number
  rowGap: number
  padding: { top, right, bottom, left }
  children: LayoutIR[]
}

interface AbsoluteIR {
  kind: 'absolute'
  children: LayoutIR[]  // 子元素需要绝对定位
}

interface LeafIR {
  kind: 'leaf'
  text?: string
  css: { width?, height? }
}

资源导出规则

  • 图片输出到 imageOutputDir,临时 JSON 放 workTmpDir
  • 图片文件名用 MD5 前 8 位,相同图片复用
  • asset/exports 只保留 pathsrcxywidthheight。生成代码引用 src,不用 path
  • JSON 删除空值和值为 0 的 style 字段
  • 默认过滤隐藏图层
  • 含真实 Text 的节点必须拆分,不能整体导出为图片
  • 普通背景 Rectangle 用代码重建;品牌资产、复杂视觉组优先保真导出

参考索引

  • @references/export-assets.md:资源导出规则
  • @references/script-api.md:脚本参数和返回结构
  • @references/single-section-workflow.md:单 section 实现流程

相关技能