ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenPencil 脚本化自动化:用 `openpencil eval` 与 Figma 兼容插件 API 批量查询、修改与生成设计文档

OpenPencil 脚本化自动化:用 `openpencil eval` 与 Figma 兼容插件 API 批量查询、修改与生成设计文档 前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载openpencil eval是 OpenPencil CLI 内置的 JavaScript 执行入口它在一个已加载的设计文档上运行任意脚本并向脚本暴露一个与 Figma Plugin API 高度兼容的全局对象figma从而在不打开编辑器界面的前提下完成批量修改、结构检查、测试数据填充与设计自动化。读完本文你将掌握eval的完整命令行用法内联代码、stdin 脚本、写回文件、连接桌面应用、输出控制技巧以及底层FigmaAPI代理层所提供的能力边界与当前限制。本文以 CLI 脚本化指南 为骨架并结合 eval 命令实现、FigmaAPI 核心实现 与 节点代理实现 等源码展开帮助你既会用也懂为什么。一、openpencil eval是什么openpencil eval在 CLI 命令体系见 CLI 主入口中对应eval子命令其功能定位是在一个设计文档上执行 JavaScript并提供全局对象figmaeval.ts 的元信息 将其描述为 Execute JavaScript with Figma plugin API。它典型地服务于以下几类场景批量修改modifiche in serie一次性给文档中所有同类节点改名、改填充色、统一字号免去逐层手工操作结构检查ispezione统计页面节点数量、查找所有 FRAME、定位文本超限等测试数据dati di test用脚本批量生成用于验证的页面与元素自动化automazione把脚本写进 CI 或构建流水线配合--write就地改文档无需人工打开编辑器。与图形界面交互不同eval是典型的无头headless执行路径脚本通过figma对象直接操作内存中的 SceneGraph执行完成后按需序列化回文件。二、基本用法内联代码与-c参数最简单的方式是通过-c--code传入一段 JavaScriptopenpencil eval design.fig -c return figma.currentPage.children.length这条命令加载design.fig统计当前页面的直接子节点数量并打印。关于-c的执行语义文档与源码一致地说明了一个关键规则如果代码不是以return开头OpenPencil 会把它包进一个异步函数执行并返回可能的运行结果。对应的底层实现位于 eval.ts 的代码包装逻辑const wrappedCode code.trim().startsWith(return) ? code : return (async () { ${code} })() const fn new AsyncFunction(figma, wrappedCode) result await fn(figma)也就是说代码以return开头时按表达式方式直接执行返回值即脚本结果否则自动包装为async函数体因此你可以在其中使用await进行异步调用例如等待字体加载、图像处理等引擎用new AsyncFunction(figma, ...)构造执行器figma作为唯一入参注入这正是脚本中能直接使用全局figma的来源。从 FigmaAPI 构造函数 可以看到figma对象在无头模式下由new FigmaAPI(graph)创建直接绑定到加载出的 SceneGraph 实例上。三、查询对象遍历与过滤 APIeval最常见的用途之一是查询文档给出的典型示例openpencil eval design.fig -c return figma.currentPage.findAll((n) n.type FRAME)findAll会深度遍历页面下所有后代节点并把满足回调条件的节点以数组形式返回。除了findAll节点代理还提供一整套遍历工具见 proxy.ts 的遍历方法方法作用findAll(callback?)深度遍历全部后代返回匹配节点数组findOne(callback)返回第一个匹配节点或nullfindChildren(callback?)仅遍历直接子节点findChild(callback)返回第一个匹配的直接子节点findAllWithCriteria({ types })按节点类型过滤如{ types: [TEXT] }常用过滤条件包括节点类型FRAME、TEXT、RECTANGLE、COMPONENT、INSTANCE等与属性名称、填充、布局模式等。返回的节点是惰性代理对象可直接继续读取属性或调用方法。四、修改与保存--write与--output脚本对文档的修改默认只发生在内存中不会触碰原文件。文档明确了两种写回方式--write或-w将修改覆盖写回输入文件--output或-o将修改写入另一个新文件原文件保持不变。例如# 原地修改 openpencil eval design.fig -w -c const f figma.currentPage.findAll(n n.type FRAME); f.forEach(x x.name 卡片); return f.length # 输出到新文件 openpencil eval design.fig -o output.fig -c return figma.currentPage.children.length底层的保存实现eval.ts 的写回逻辑使用IORegistry与内置格式注册表将 SceneGraph 序列化为.fig文件const { BUILTIN_IO_FORMATS, IORegistry } await import(open-pencil/core/io) const io new IORegistry(BUILTIN_IO_FORMATS) const outPath args.output ? args.output : file const result await io.writeDocument(fig, graph) await writeFile(outPath, result.data as Uint8Array)可以看出--output的优先级高于--write只要提供了--output就写入该路径否则才覆盖输入文件。写回成功后若未使用--quietCLI 会向 stderr 打印Written to 路径提示。五、从 stdin 读取脚本对于较长或多行脚本命令行内联既不便于维护也不利于转义。文档推荐使用 stdin 管道cat transform.js | openpencil eval design.fig --stdin --write实现上--stdin会把进程标准输入全部读取为 UTF-8 文本当作代码eval.ts 的 stdin 读取与-c走同一条执行路径。这样你就能把可复用的脚本放在独立文件里配合 git 版本管理实现脚本化重构文档。需要说明--code与--stdin二选一若两者都未提供CLI 会报错并退出eval.ts 的代码校验。六、对桌面应用当前打开的文档执行脚本如果省略文件路径参数eval会转而连接到正在运行的 OpenPencil 桌面应用对当前活动文档执行脚本openpencil eval -c return figma.currentPage.children.length这条路径走的是App 模式CLI 通过 app-client.ts 的 RPC 通道 读取 MCP 发现文件discovery file拿到本地 socket/HTTP 端口与鉴权令牌然后向桌面应用发起POST /rpc请求命令名为evaleval.ts 的 App 模式分支。请求默认 30 秒超时当本地 socket 不可达时还会自动回退到 TCP 通道。桌面应用侧收到代码后在当前文档上执行结果再原路返回 CLI 打印。这一模式适合边看边调的工作流你在编辑器里打开文件、随时用 CLI 脚本查询或修改当前画布内容无需关心文件路径与保存位置。七、输出控制JSON、非交互环境与--quiet文档指出在非交互环境下eval默认使用 JSON 输出--json可以显式强制 JSON--quiet-q则在仅写文件时隐藏输出。对应实现eval.ts 的结果打印非常直白function printResult(value: unknown, json: boolean) { if (json || !process.stdout.isTTY) { console.log(JSON.stringify(value, null, 2)) } else { console.log(value) } }即只要标准输出不是 TTY管道、重定向、CI 环境就一律输出带缩进的 JSON在终端里则打印可读值。--json在交互终端里强制 JSON。结果在打印前还会经过序列化处理serializeResult对象若带有toJSON方法则调用之数组逐项递归。这正是节点代理能够以 JSON 形态输出的原因——每个节点都实现了toJSON(maxDepth?)见 proxy.ts 的序列化方法可控制输出深度。典型的管道消费方式# 把查询结果交给 jq 处理 openpencil eval design.fig -c return figma.currentPage.findAll(n n.type TEXT).map(t ({ id: t.id, text: t.characters })) | jq .[0:10]八、Figma 兼容 API能力全览eval的核心价值在于 API 兼容性API 遵循 Figma Plugin API 的模型但直接运行在 OpenPencil 的 SceneGraph 与文件格式之上。文档特别强调figma.currentPage、createFrame、appendChild、fills、fontSize、layoutMode、strokeWeight等标识符与官方 Figma 插件 API 保持一致熟悉 Figma 插件的开发者几乎零成本迁移。结合 FigmaAPI 类 与 FigmaNodeProxy 类当前覆盖的能力可以归纳为以下几层。8.1 文档与页面级figma.*API说明figma.currentPage当前页面代理可读可写赋值为其他页代理即可切换带selection属性figma.root文档根节点代理figma.getNodeById(id)按 ID 取节点不存在返回nullfigma.viewport视口中心、缩放以及scrollAndZoomIntoView(nodes)figma.createPage()新建页面并返回代理figma.mixed混合值哨兵对应 Figma 的figma.mixed8.2 对象创建figma.createXxx创建方法均将新节点挂到当前页面下实现见 index.ts 的创建逻辑createFrame、createRectangle、createEllipse、createText、createLine、createPolygon、createStar、createVector、createComponent、createSection。// 生成一页卡片原型 const page figma.createFrame() page.name Card page.resize(320, 200) page.fills [{ type: SOLID, color: { r: 0.95, g: 0.95, b: 0.95 } }] const title figma.createText() title.characters Hello OpenPencil title.fontSize 24 title.fontName { family: Inter, style: SemiBold } page.appendChild(title)8.3 树与层级操作节点方法方法说明node.parent/node.children读父节点、子节点数组node.appendChild(child)将子节点移入当前节点node.insertChild(index, child)按索引插入子节点node.clone()深克隆子树node.remove()删除节点figma.group(nodes, parent, index?)成组figma.ungroup(node)解组返回原子节点数组所有写操作都会经过可编辑性校验并记录实例覆盖proxy.ts 的_update确保与编辑器撤销/实例机制兼容。8.4 组件与实例figma.createComponentFromNode(node)把现有节点提升为组件node.createInstance()基于组件创建实例node.mainComponent读取实例对应的主组件figma.exposeInstanceSwap(...)暴露可切换的实例槽。8.5 变量Variables变量系统覆盖了集合、变量与绑定的全套 CRUD读取getVariableById、getLocalVariables(type?)、getLocalVariableCollections、getVariableCollectionById写入createVariable、setVariableValue、deleteVariable、createVariableCollection、deleteVariableCollection绑定bindVariable(nodeId, field, variableId)、unbindVariable(nodeId, field)。8.6 节点常用属性节点代理几何与变换x、y、width、height、rotation、resize、rescale、absoluteBoundingBox、relativeTransform、absoluteTransform。视觉样式fills、strokes、effects、opacity、visible、locked、blendMode、clipsContent、cornerRadius含各角独立半径与MIXED混合值、isMask、maskType。自动布局layoutMode、layoutDirection、primaryAxisAlignItems、counterAxisAlignItems、itemSpacing、counterAxisSpacing、四向padding*、layoutWrap、尺寸模式与constraints。描边strokeWeight、strokeAlign、dashPattern、strokeCap、strokeJoin、strokeMiterLimit以及四边独立粗细strokeTopWeight等。文本characters、fontSize、fontName、fontWeight、textAlignHorizontal/Vertical、textDirection、textAutoResize、letterSpacing、lineHeight、textCase、textDecoration、maxLines、textTruncation并支持insertCharacters(start, text)与deleteCharacters(start, end)细粒度文本编辑。插件数据getPluginData/setPluginData/getPluginDataKeys以及getSharedPluginData/setSharedPluginData可随文档持久化脚本自己的元数据。九、当前限制Limiti文档明确标注了当前尚未提供完整等价物的 API 清单编写脚本时需要避开或自行绕过node.exportAsync()节点导出尚无完整等价物源码中提供的是可选的exportImage通道见 index.ts 的可选导出具体可用性取决于运行宿主node.setBoundVariable()变量绑定目前通过figma.bindVariable(nodeId, field, variableId)完成逐节点方法尚未对齐node.detachInstance()实例解绑尚未提供figma.combineAsVariants()文档标注未提供需要说明的是从 index.ts 的 variants 实现 看combineAsVariants已存在于FigmaAPI类中说明该能力正在逐步补齐实际行为以你所使用的发布版本为准样式Styles颜色/文本/效果样式系统尚无完整 API矢量布尔运算文档标注所有布尔矢量操作尚无完整等价物同样地源码已包含booleanOperation、union、subtract、intersect、exclude与flattenindex.ts 的布尔操作属于文档保守声明、实现逐步跟进的状态。建议在编写脚本前先在目标版本上对上述 API 做一次冒烟测试以确认实际支持情况。十、执行原理从文件到figma再到结果了解eval的完整执行链路有助于排查脚本问题。无头模式的流程如下结合 eval.ts、headless.ts 与 app-client.ts加载文档loadDocument(file)读取文件字节经IORegistry.readDocument解析为 SceneGraph并立即computeAllLayouts计算布局headless.ts 的加载逻辑物化惰性数据populateWholeDocument(graph)调用populateAllLazyFigImportRoots填充惰性加载的 Fig 导入子树再重新计算全部布局headless.ts 的填充逻辑保证脚本读到的树是完整、布局已收敛的构建 APInew FigmaAPI(graph)建立代理层wrapNode(id)为每个 SceneGraph 节点缓存生成FigmaNodeProxyindex.ts 的代理缓存执行代码按return前缀规则包装代码new AsyncFunction(figma, code)执行并await结果输出/写回结果经serializeResult后按 TTY 与否决定 JSON 格式需要写回时经IORegistry.writeDocument(fig, graph)序列化为.fig字节再落盘。App 模式则跳过 13 的本地加载改为通过 RPC 让桌面应用在其内部文档上执行同样的代码第 4 步结果经序列化回传 CLI第 5 步。十一、实战示例汇总# 1) 统计当前页面的帧数量 openpencil eval design.fig -c return figma.currentPage.children.length # 2) 找出全部文本节点并输出 JSON管道到 jq openpencil eval design.fig -c return figma.currentPage.findAll(n n.type TEXT).map(t ({ id: t.id, text: t.characters })) | jq # 3) 批量修改给所有 FRAME 加统一命名前缀并写回 openpencil eval design.fig -w -c const frames figma.currentPage.findAll(n n.type FRAME); for (const f of frames) f.name comp- f.name; return frames.length # 4) 生成测试数据到新文件 openpencil eval design.fig -o generated.fig -c const page figma.createFrame(); page.resize(100, 100); for (let i 0; i 8; i) { const dot figma.createEllipse(); dot.x i * 30; dot.resize(20, 20); page.appendChild(dot); } return page.children.length # 5) 通过 stdin 脚本操作当前桌面文档 cat fix-names.js | openpencil eval --stdin结语openpencil eval把 Figma 插件生态的编程心智模型带进了 OpenPencil 的文档处理流程既能在无头环境中批量查询与改写.fig文件也能通过省略路径一键操控桌面应用中的活动文档。理解它的执行链路loadDocument → populateWholeDocument → FigmaAPI → AsyncFunction → IORegistry 写回后你就能把设计文档纳入脚本化、可版本化的工程体系。需要更进一步时可以继续阅读同一目录下的 CLI 检查、CLI 分析 与 CLI 导出 文档把查询、分析与导出也串进同一条自动化流水线。赞分享前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载相关推荐OpenPencil 脚本化用 openpencil eval 与 Figma 兼容 API 无头驱动设计文档OpenPencil 脚本化用 openpencil eval 与 Figma 兼容 API 无头驱动设计文档 openpencil eval 是 OpenP前端桌面应用AI 应用MCP 服务OpenPencil CLI 脚本编程用 openpencil eval 执行 Figma 兼容的 JavaScript 自动化设计OpenPencil CLI 脚本编程用 openpencil eval 执行 Figma 兼容的 JavaScript 自动化设计 openpencil e前端桌面应用AI 应用MCP 服务OpenPencil 脚本引擎入门用 openpencil eval 与 Figma 兼容 API 无头操作设计文档OpenPencil 脚本引擎入门用 openpencil eval 与 Figma 兼容 API 无头操作设计文档 openpencil eval 是 Op前端桌面应用AI 应用MCP 服务上一篇告别插件管理障碍vim-plug无障碍优化指南下一篇Apache Ossie 治理模式详解The Apache Way与PPMC运作机制完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表