# AI-SketchParse **Repository Path**: coolflyreg163/ai-sketch-parse ## Basic Information - **Project Name**: AI-SketchParse - **Description**: 零运行时依赖的 Sketch 解析工具链(Node ≥ 22.6 / TypeScript 原生执行)—— 读取 Sketch (.sketch) 设计文件,一键产出 SVG / CSS / HTML / React / Vue、DTCG 设计令牌 与导出清单。无需 npm install,node 直接跑 .ts 文件。提供CLI和MCP两种方式解析sketch文件。 - **Primary Language**: NodeJS - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-21 - **Last Updated**: 2026-08-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # AI Sketch Parse **零运行时依赖**(Node ≥ 22.6)的 TypeScript / Node 原生工具链,用于读取 **Sketch(`.sketch`)** 设计文件,并生成前端产出(**SVG**、**CSS**、**HTML/React/Vue**)、**设计令牌(DTCG)** 与导出清单。提供 **三个入口**: 1. **MCP server**(`packages/sketch-mcp`)—— 18 个工具 + 7 个资源 + 2 个提示词 2. **可 import 的 API**(`createSession`、`getSvg`、`getTokens`、`getPage`、`findArtboard`、`getArtboardRaw`、`getProjectTree`、`getProjectManifest`、`exportProject`、`repackSketch` …) 3. **CLI**(`sketch-parse`) > ⚠️ **Node 版本要求**。整个项目运行在 Node 原生 TypeScript 类型剥离(type-stripping)之上,**无需 `npm install` 任何依赖**——`node` 直接执行 `.ts` 文件。见 `package.json` 的 `engines` 字段。 --- ## 核心设计:文档 → 页 → 画板 的层级 `.sketch` 文件内部按 **页面(page)→ 画板(artboard)** 组织: ``` document.json → pages[] 引用 pages/.json pages/.json → _class=page;顶层 layer 即 artboard(一个画板 = 一个 UI 界面) images/*.png 位图资源 ``` 本工具链的所有导出、`tree.json`、`manifest.json`、MCP 工具与资源 URI,**全部遵循同一层级**:`文档名 → 页名 → 画板名`。 ### 层级导出结构(`exportProject` / CLI `--all --out` / MCP `sketch_export_project`) ``` // tokens.json 设计令牌(DTCG) tree.json 文档 → 页 → 画板 的图层树(与文件夹同层级) tree.md 人类可读的文档结构 manifest.json 文档 → 页 → 画板 的导出格式清单 / 每页一个文件夹(中文名保留) / 每画板一个文件夹(重名自动加 ~2、~3 …) preview.svg 自包含预览图(位图内联,可独立打开) artboard.json 画板原始 JSON(未归一化,来自 pages/.json) index.html 解析出的 HTML(令牌作为 CSS 变量、语义化标签) index.css 解析出的 CSS(绝对定位) tree.md 该画板的图层树 svg/.svg 独立 SVG(引用 ../images/) images/* 该画板用到的位图资源 ``` - `tree.json` → `{ "name": , "pages": [{ "id", "name", "artboards": [{ id, name, _class, frame, children }] }] }` - `manifest.json` → `{ "name": , "pages": [{ "id", "name", "artboards": [{ "id", "name", "exports": [{ layerId, layerName, format, scale }] }] }] }` - 两者 `name` 字段 = 导出根目录名(`documentName(session)` = 文件名的 slugify 结果)。 --- ## 项目结构 ``` AI-SketchParse/ ├── .nvmrc, .gitignore, biome.json ├── pnpm-workspace.yaml ├── package.json # workspace 根 — `npm test / build` 别名 ├── mcp/ │ └── claude-desktop.example.json ├── examples/out// # 参考文件的渲染产物(tokens / tree / svg / css / html / …) ├── test/ # 测试用 .sketch 文件(含中文名「数科.sketch」)与导出结果 ├── docs/sketch-reference-files/ # 官方参考 .sketch 文件(已解压,MIT) ├── docs/sketch-document/ # 官方 sketch file-format schema + TS 参考 ├── packages/ │ ├── sketch-parse/ # 内核 + API + CLI(零依赖) │ │ ├── src/ │ │ │ ├── index.ts # 公共 API 入口 │ │ │ ├── cli.ts # CLI 入口 │ │ │ ├── types.ts / enums.ts │ │ │ └── core/ │ │ │ ├── reader/ # zip 解压 + document.json 解析 │ │ │ ├── tree/ # 图层树归一化 / symbol 展开 / 遍历 │ │ │ ├── serialize/ # tree-json / markdown │ │ │ ├── token/ # DTCG 令牌提取 + 校验器 │ │ │ ├── svg/ # SVG 渲染 │ │ │ ├── css/ # CSS 渲染 │ │ │ ├── html/ # HTML / React / Vue 骨架 │ │ │ ├── export/ # 层级项目导出(project.ts / manifest.ts) │ │ │ ├── repack/ # 重新打包(zip-writer.ts / config.ts / repack.ts / tui.ts) │ │ │ └── session.ts # createSession + 层级查询(getPage / findArtboard / getArtboardRaw / getProjectTree / getProjectManifest / documentName) │ │ └── test/*.test.ts # 61 个单元测试 │ └── sketch-mcp/ # MCP stdio server(零依赖) │ ├── src/ │ │ ├── index.ts # JSON-RPC 2.0 stdio 服务 │ │ ├── tools.ts # 18 个工具 │ │ ├── resources.ts # 7 个层级资源 │ │ ├── prompts.ts # 2 个提示词 │ │ ├── sessions.ts # 会话管理 │ │ └── protocol.ts # MCP 协议编解码 │ └── test/tools.test.ts # 11 个端到端测试(stdio JSON-RPC) └── .trae/documents/skills/ # Skill A(sketch-fundamentals)+ Skill B(sketch-design-to-code) ``` --- ## 快速开始(CLI) ```powershell # Windows node packages/sketch-parse/src/cli.ts --all --out ``` `` 可以是 `.sketch` zip,也可以是已解压的目录(含 `document.json`)。 ### 常用 CLI 用法 ```bash # 层级项目导出(文档名 → 页名 → 画板名,含 tokens/tree/manifest + 每画板资源) sketch-parse 数科.sketch --all --out test/out # 仅导出设计令牌(DTCG JSON;若输出以 .css 结尾则导出 CSS 变量) sketch-parse my.sketch --tokens out/tokens.json # 仅导出图层树(文档 → 页 → 画板 层级 JSON) sketch-parse my.sketch --tree out/tree.json # 仅导出 CSS / SVG / HTML(逐画板) sketch-parse my.sketch --css out/c sketch-parse my.sketch --svg out/s sketch-parse my.sketch --html out/h --flavor react # 导出格式清单(文档 → 页 → 画板 层级 JSON) sketch-parse my.sketch --manifest out/manifest.json # 复制位图资源 sketch-parse my.sketch --images out/images # 仅查看结构(Markdown) sketch-parse my.sketch --markdown out/tree.md # 重新打包:TUI 交互选择要保留的页面 / 画板 sketch-parse my.sketch --repack out.sketch # 重新打包:先生成可编辑的选择配置模板 sketch-parse my.sketch --repack-template repack.json # 重新打包:编辑模板后按配置文件选择页面 / 画板 sketch-parse my.sketch --repack out.sketch --repack-config repack.json ``` ### CLI 选项 | 选项 | 说明 | |---|---| | `--tokens ` | 设计令牌(DTCG JSON;`out` 以 `.css` 结尾时输出 CSS 变量) | | `--tree ` | JSON 图层树(文档 → 页 → 画板 层级) | | `--markdown ` | 人类可读结构(Markdown) | | `--svg ` | 每画板一个 SVG | | `--css ` | 每画板一个 CSS(绝对定位) | | `--html ` | 每画板一个 HTML/React/Vue 文件 | | `--images ` | 复制位图资源到目录 | | `--manifest ` | 导出格式清单(JSON) | | `--all --out ` | 全部能力,按层级导出 | | `--repack ` | 重新打包:仅保留所选页面 / 画板(`out` 以 `.sketch` 结尾 → 新 zip;否则输出目录) | | `--repack-config ` | 重新打包的选择配置 JSON(不传则进入 TUI 交互选择) | | `--repack-template ` | 生成可编辑的选择配置模板并退出 | | `--flavor html\|react\|vue` | HTML 输出风味(默认 html) | | `--rotation-mode auto\|rad\|deg` | 旋转角度单位(默认 auto) | | `--concurrency ` | 图片复制并发数(默认 4) | | `--pretty / --no-pretty` | 是否美化输出(默认 pretty) | | `--verbose / --quiet` | 日志级别 | | `--version / --help` | 版本 / 帮助 | --- ## 快速开始(MCP server) ```powershell node packages/sketch-mcp/src/index.ts ``` 将其接入任意 MCP 客户端(Claude Desktop、Trae、Continue、Cline …),参考 `mcp/claude-desktop.example.json`: ```jsonc { "mcpServers": { "sketch": { "command": "node", "args": ["d:/Projects/AI-SketchParse/packages/sketch-mcp/src/index.ts"], "env": { "SKETCH_DEFAULT_PROJECT": "d:/Projects/AI-SketchParse" } } } } ``` ### 18 个 MCP 工具 **加载与元数据** | 工具 | 说明 | |---|---| | `sketch_load` | 加载 `.sketch` 文件 → 返回 `sessionId` + 文档概览(页 / 画板 / 图层统计) | | `sketch_get_meta` | 版本 / app / build + 页及画板 id 列表 | **层级导航(文档 → 页 → 画板)** | 工具 | 说明 | |---|---| | `sketch_list_pages` | 列出所有页,每页带其下的画板(id + name)——与导出层级一致 | | `sketch_get_page` | 按 `pageId` / `pageName` / `pageIndex` 获取单页及其完整画板列表 | | `sketch_find_artboard` | 直接在页下查询画板(页 + 画板的 id/name 组合) | | `sketch_get_artboard_raw` | 返回画板原始(未归一化)JSON,与 `pages/.json` 中存储一致 | | `sketch_list_artboards` | 列出全部画板(可按 `pageId` / `pageIndex` 限定到单页) | | `sketch_get_artboard` | 画板结构化摘要(frame + 颜色 + 排版 + 有界图层树) | | `sketch_get_tree` | 画板 / 页 / 图层的 name/_class/frame 轻量图层树(depth / maxNodes) | | `sketch_get_layer` | 单图层的完整归一化字段 | | `sketch_search_layers` | 按名称 / class 搜索图层 | **设计产出** | 工具 | 说明 | |---|---| | `sketch_get_tokens` | 提取 DTCG 设计令牌(color / typography / spacing / radius / shadow)+ CSS 变量视图 | | `sketch_get_svg` | 画板 → SVG(`` 含渐变 / 滤镜) | | `sketch_get_css` | 画板 → 绝对定位 CSS | | `sketch_get_html` | 画板 → HTML / React / Vue 骨架(令牌作为 `:root` 变量) | | `sketch_list_images` | 画板(或全文档)引用的位图资源 | | `sketch_export` | 导出清单 + 复制位图资源到磁盘 | | `sketch_export_project` | **层级项目导出**到磁盘(文档 → 页 → 画板 文件夹,含文档级 tokens / tree / manifest) | ### 7 个 MCP 资源 资源 URI 与导出层级保持一致: - `sketch://meta` — 文档元数据 - `sketch://artboards`、`sketch://artboards/{id}` — 画板列表 / 单画板摘要 - `sketch://pages` — 层级页列表(每页含其下画板) - `sketch://pages/{pageId}` — 单页及其画板列表 - `sketch://pages/{pageId}/artboards/{artboardId}` — 页下画板摘要 - `sketch://pages/{pageId}/artboards/{artboardId}/raw` — 页下画板的原始 JSON ### 2 个 MCP 提示词 - `design_to_react(ref, artboardId)` — 单画板 → React 组件 的分步配方 - `design_to_html(ref, artboardId)` — 单画板 → 单个 HTML 文件 的配方 --- ## 快速开始(Node API) ```ts import { createSession, getTokens, getSvg, getCss, getHtml, getLayer, getPage, findArtboard, getArtboardRaw, getProjectTree, getProjectManifest, exportProject, repackSketch, makeRepackConfigTemplate, listArtboards, listPages, toTreeJson, toMarkdown, SketchReaderError, } from "@ai-sketch-parse/sketch-parse"; const session = await createSession("./test/数科.sketch"); console.log(listPages(session)); // 所有页,每页含画板 console.log(listArtboards(session)); // 所有画板 console.log(getPage(session, { name: "南网监造" })); // 按页名取页 + 画板列表 const ab = findArtboard(session, { pageName: "南网监造", artboardName: "登录" }); console.log(getArtboardRaw(session, ab!.id)); // 画板原始 JSON console.log(getTokens(session)); // DTCG 设计令牌 console.log(getSvg(session, ab!.id)); // SVG console.log(getCss(session, ab!.id)); // CSS console.log(getHtml(session, ab!.id, { flavor: "react" })); console.log(getProjectTree(session)); // 文档 → 页 → 画板 图层树 console.log(getProjectManifest(session)); // 文档 → 页 → 画板 导出清单 await exportProject(session, "out"); // 层级项目导出到 out//… // 重新打包:生成可编辑的选择配置(列出全部页 + 画板名) console.log(makeRepackConfigTemplate(session)); // 重新打包:仅保留所选页面 / 画板,输出新 .sketch(zip)或目录 await repackSketch( session, { pages: [{ name: "南网监造", artboards: ["登录", "首页"] }, { name: "安培管理系统" }] }, { output: "out/min.sketch" }, ); ``` 所有函数都接收一个 **`SketchSession`**(已解析并索引的文档),**加载一次**即可在多次调用间复用。 --- ## 测试 | 包 | 命令 | 覆盖 | |---|---|---| | `sketch-parse` | `node --test packages/sketch-parse/test/*.test.ts` | 61 个单元测试 ✅ | | `sketch-mcp` | `node --test packages/sketch-mcp/test/*.test.ts` | 11 个端到端测试(stdio JSON-RPC)✅ | 或在 workspace 根目录一次跑完: ``` node --test packages/sketch-parse/test/*.test.ts packages/sketch-mcp/test/*.test.ts ``` --- ## 为什么零依赖? 开发环境(TRAE sandbox)不允许 `npm install`(网络被锁定),因此完全绕过 registry: - **JSON / zip / unzip** → Node 内置 `zlib` + `Buffer`(无 `node-stream-zip`) - **CLI 参数解析** → 手写解析器(无 `commander`) - **并发图片复制** → 自研 `withConcurrency()`(无 `p-queue`) - **设计令牌** → 手写提取 + 轻量 DTCG 校验器(无 AJV) - **MCP** → 紧凑的 JSON-RPC 2.0 stdio 编解码(无 `@modelcontextprotocol/sdk`) 因此**整个工具链只靠 `node` 即可运行**——无需 `pnpm install`。 --- ## License `docs/sketch-reference-files` 中的参考文件为 MIT 许可,详见上游 `LICENSE` 文件。