- 前端
- 桌面应用
- AI 应用
- MCP 服务
【免费下载链接】open-pencil
AI-native design editor. Open-source Figma alternative.
OpenPencil 是 AI 原生的开源设计编辑器(Figma 开源替代方案),其组件系统是整个设计复用体系的核心:编辑主组件后所有实例自动同步更新,组件集(component set)与变体(variant)支持多维参数化设计,行为(behaviour)机制让组件在预览中作为真实的 Reka UI 控件运行,组件库则以不可变修订(revision)的方式实现跨文档复用。本文以官方用户指南 components.md 为主体骨架,结合仓库源码与开发文档,完整讲解组件从创建、参数化、行为化到发布复用的全流程,读完你将掌握 OpenPencil 组件系统的全部操作与底层原理。
什么是组件:可复用设计元素的基石
组件(Component)是可复用的设计元素。其核心语义是:编辑主组件(main component),所有实例(instance)自动随之更新。这不同于传统的"复制粘贴"——复制产生的是独立对象,而组件实例始终与主组件保持链接关系,形成"一处修改、处处生效"的设计系统工作流。
从源码结构看,组件这一概念直接映射到场景图(scene graph)中的COMPONENT与COMPONENT_SET节点类型,实例则通过INSTANCE节点携带指向主组件的引用;完整的组件实例关系模型位于 packages/core/src/editor/components/ 目录下,包含create.ts(创建)、instances.ts(实例)、properties.ts(属性)、variant-set.ts(变体集)与slots/(插槽)等模块。
浏览组件:Assets 面板
打开左侧面板的Assets标签页,可以浏览本地组件和已启用的组件库资源:
- 支持网格视图与列表视图两种浏览方式,可按组件名称搜索;
- 点击组件、按Enter键,或将其拖拽到画布上,均可完成插入。
本地资源按来源页面分组展示。已发布的库资源(library assets)在其修订版本已下载的情况下始终可用——即使远端提供方暂时离线,也不会影响浏览与插入。
Assets 面板的界面实现在 AssetsPanel.vue 与 AssetThumbnail.vue,面板内的资源查找逻辑位于 assets-panel/page.ts。
创建组件
从 Frame 或 Group 创建
选中一个 Frame 或 Group,按下⌥⌘K(Windows/Linux 为Ctrl+Alt+K),选中内容即成为一个可复用组件。
从源码看,这一行为对应 create.ts 中的becomesComponent()判断:
export function becomesComponent(node: SceneNode): boolean { return node.type === 'FRAME' || node.type === 'GROUP' }Frame 和 Group 会被就地转换为组件(与 Figma 的画布操作和插件 API 行为一致),而不是套一层新的容器。
从其他图层创建
如果是任意其他图层(或若干图层),OpenPencil 会在这些图层的边界框处包裹一个新的白色组件,位置取图层列表中顶层图层所在位置;当只包裹单个图层时,组件自动以该图层命名。
这一规则同样在 componentWrapProps() 中有直接体现——包裹容器的属性取自newLayerDefaults('COMPONENT')(白色背景的默认外观),并在nodes.length === 1时把组件名设为被包裹图层的名称。
组件创建完成后,画布上会显示一个紫色标签 + 菱形图标,用于标识组件身份。
组件集与变体(Component Sets and Variants)
创建组件集
选中两个及以上组件,按下⇧⌘K(Windows/Linux 为Shift+Ctrl+K),即可合并为一个组件集——一个包含多个变体组件的容器,外观为紫色虚线边框,子元素四周带 20 px 内边距,与 Figma 的呈现一致。
通过脚本调用figma.combineAsVariants()创建的组件集则精确包裹其组件(不附加额外边距),与 Figma 插件 API 的行为一致。对应实现位于 figma-api/components.ts,其中明确要求传入的必须是互不相同的COMPONENT节点(combineAsVariants requires distinct COMPONENT nodes),相关测试见 combine-variants.test.ts。
多维变体与稀疏组合
组件集中的每个组件可以跨多个变体维度(variant dimensions)定义取值,例如Size=Small、State=Hover、Theme=Dark。OpenPencil 支持稀疏组合(sparse combinations)——组件集无需包含所有可能的组合,只定义实际用到的组合即可。
组件集左上角的变体是默认变体。当更新后的修订中不再包含某个精确组合时,系统会用左上角默认变体作为回退(fallback)呈现。
管理变体维度
通过组件属性面板可以添加、重命名、重新排序和删除变体维度及其取值;重复的组合会被拒绝。变体模型、定义与历史管理的实现位于 editor/components/variants/ 目录(definitions.ts、model.ts、history.ts)。
组件属性(Component Properties)
组件和组件集支持四类可复用属性:
- 文本属性(text)——绑定到某个后代文本图层;
- 布尔可见性(boolean visibility)——控制图层的显示/隐藏;
- 实例替换(instance-swap)——允许实例替换为其他组件/组件集;
- 插槽属性(slot)——允许实例替换插槽内容。
工作流为:先将属性链接到某个后代字段(descendant field),然后选中实例即可直接编辑其分配值(assigned value),无需分离(detach)实例。这些属性及其分配值在保存并重新打开.fig文件后依然保留。
插槽(Slots)
插槽是主组件中的一个 Frame,其内容允许每个实例各自替换。
- 创建插槽:在主组件内选中一个 Frame,通过右键菜单或 Slots 区域的Create slot创建;也可以选中其他图层,将其包裹进一个新的插槽 Frame。
- 插槽设置:可以设置插槽的描述(description)、偏好使用的组件(preferred components)、以及容纳条目数量(how many items it holds);实例内容超出这些限制时会显示警告。
- 实例内编辑:在实例中可以添加、重排、删除插槽条目,或重置为组件的原始内容。
插槽的作者(authoring)与历史逻辑分别实现在 editor/components/slots/authoring.ts 与 editor/components/slots/history.ts,插槽编辑的入口封装在 editor/components/slots/index.ts。
行为与预览(Behaviours and Preview)
行为(behaviour)让主组件或组件集像真实控件一样工作,其基础是 Reka UI 的无头(headless)原语。OpenPencil 支持 15 种行为,按面板中的展示顺序依次为:
Button(按钮)、Text field(文本输入)、Textarea(多行文本)、Number field(数字输入)、Toggle、Switch(开关)、Checkbox(复选框)、Radio(单选)、Radio group(单选组)、Toggle group(切换组)、Slider(滑块)、Progress(进度条)、Tabs(标签页)、Collapsible(折叠面板)、Accordion(手风琴)。
这 15 种行为种类直接定义在 scene-graph/src/behaviours/kinds.ts 的BEHAVIOUR_KINDS常量中。选中组件后,在Behaviour区域点击+即可选择一种行为。
行为的三类绑定
行为不会新增任何节点类型,而是描述如何复用组件已有的属性、插槽和变体。Behaviour 区域会列出控件需要的内容:
- Values(值)——承载控件状态值的属性:
- On / Checked / Pressed / Open / Filled / Disabled 这类布尔状态:绑定到一个变体属性(并指定哪些取值代表开/关)或布尔属性;
- 字段类文本:绑定到一个文本属性;
- 滑块的数值:使用行为自身的 minimum、maximum、step、default(因为 Figma 没有 number 类型的属性,数字由行为自带的范围定义,见 kinds.ts 中
BehaviourValueType = 'boolean' | 'text' | 'number' | 'choice')。
- Parts(部件)——绘制控件各部件(part)的插槽,例如 Switch 的 thumb(滑块)、Slider 的 track/range/thumb、Tab list 的触发器列表;组的 items 插槽则持有其 radio、toggle 或 collapsible 的实例。
- States(状态)——一个变体属性,其取值分别绘制 default、hover、pressed、focus、disabled 五种交互状态;与这些状态同名(rest/hover/pressed/focus/disabled)的取值会被自动匹配。交互状态的完整集合定义在 kinds.ts 的
INTERACTION_STATES常量中。
自动补齐缺失的绑定
控件必需的行排在前面,其余归入More options。当组件还没有可绑定的内容时,某行会提供"创建"入口:
- 文本层 + 文本属性;
- Off 和 On 变体;
- 一个插槽;
- States提供Add state variants,一键为组件添加 Default、Hover、Pressed、Focus、Disabled 五个变体。
这里有两个值得注意的规则:一个孤立的(lone)主组件通过这种方式获得变体后,会自动转成组件集;而组件集新增的插槽会出现在每个变体中。在控件尚未完全可用前,其名称下方会有一行提示文字说明还缺什么,点击即可跳到对应位置。
预览:把画布变成真实控件
按⌥⌘↩(Windows/Linux 为Ctrl+Alt+Enter),或选择View → Preview,或点击 Share 旁的 ▶ 按钮,即可进入预览模式:
- 每个包含控件的顶层图层都会作为真实的 Reka UI 组件在画布上方实时运行,外观由组件的变体绘制:开关可拨动、滑块可拖拽、标签页和手风琴可开合、文本字段是带有浏览器光标/选区/粘贴能力的真实输入框;
- 预览永远不会修改文档或文档历史;
- Reset将所有控件恢复为设计稿状态;
- 按Esc或点击胶囊按钮的关闭按钮返回编辑模式;
- 在分屏视图中,每个画布各自独立预览。
行为会随.fig文件保存,并在发布组件库时随库组件一起发布。
预览的底层机制
预览机制的完整说明见开发文档 behaviours-and-preview.md,其核心要点如下:
- 行为模型存储:行为作为组件/组件集插件数据(plugin data)的
behaviour字段存储,属性与插槽按 id 绑定;模型定义在@open-pencil/scene-graph(packages/scene-graph/src/behaviours/,含model.ts、schema.ts、spec.ts)。其 role 为content,因此会随库资源一起传输并计入更新哈希。 - 预览岛(islands):预览是每个窗格的独立模式(
EditorViewState.play)。Core 的playIslandRoots挑选页面中持有带行为实例的顶层图层,渲染器在预览时跳过它们,由PlayIslands为每个根挂载一个岛,覆盖在画布当前平移缩放下。 - Shadow DOM 隔离:每个岛渲染到自己的 shadow root 中——应用 CSS 不会渗入,岛内 CSS 不会外泄,应用已加载的字体生效,岛随画布同一帧移动。
- 状态投影:
resolvePlayState把岛的图层复制进一个私有图(private graph),按实例状态呈现匹配的变体、布尔属性与控件暴露的图层(如 tab panels)——文档本身不被修改。 - DOM 投影与 Reka 角色:私有图经由
@open-pencil/dom-css投影到 DOM(与 HTML 导出一致的管线);每个图层获得一个角色(根、部件、组条目、tab 触发器/面板、文本输入等),由behaviourControls与controlRoles分配,随后用asChild把图层包进对应的 Reka UI 原语,从而复用浏览器的输入、焦点、键盘导航与无障碍能力。 - 代码导出同源:导出读取与预览相同的模型——
behaviourArgs把 on/off 变体属性映射为checked/pressed/open/disabledprops;stateStyles把变体集合并为单一标记树(rest 变体为基座,其余变体按data-state、:hover等条件生成规则),stateStylesToCSS/stateStylesToTailwind分别输出可读类名的样式表或 Tailwind 工具类。
组件库(Component Libraries)
组件库以**不可变修订(immutable revision)**方式发布可复用组件。每个已发布的资源具有稳定的 library、asset、revision 三重身份标识,因此不同实例可以停留在不同修订上,直到你显式更新它们。
发布库
- 创建要共享的组件和组件集;
- 打开Assets,选择Manage libraries;
- 选择Publish library;
- 输入稳定的库 ID(library ID)与显示名称——库 ID 在首次发布后即被锁定,不可更改;
- 可选:搜索变更列表并输入修订描述(revision description);
- 勾选要包含的已新增、已修改、已重命名或已移除的资源;
- 确认目标位置并选择Publish library。
在后续发布中,未勾选的变更保持"待处理"(pending)状态;未变化的资源保留其此前发布的定义;已被移除的定义在文档仍引用其历史修订时依然可用。
启用并插入库资源
打开Assets → Manage libraries启用已发布的库,其组件会与本地组件一同出现在 Assets 面板中,同样通过点击、键盘或拖拽插入画布。
已发布定义在消费文档中是只读的。要修改定义,需编辑源文档并发布另一个修订;链接到这些定义的实例仍可通过组件属性和覆盖(overrides)编辑。
审查并接受更新
打开Manage libraries → Updates可发现更新的修订。发现(discovery)过程不会修改文档。你可以并排对比当前与更新后的实例、在受影响的实例间导航,然后选择更新范围:
- 选中的实例;
- 某个资源的全部实例;
- 当前页上的实例;
- 所有页面上的实例。
OpenPencil 会保留兼容的文本、可见性与实例替换分配。若精确变体已不存在,审查界面会在你接受前指出左上角回退变体。应用更新会创建一个撤销条目(undo entry)。
本地、存储与离线使用
库可以使用本地浏览器目录(local browser catalog)或配置的存储提供方(storage provider)。远端发布使用不可变修订对象 + 条件最新指针(conditional latest pointer),防止两位发布者互相静默覆盖。
已下载的修订会缓存在本地:文档离线时依然可以渲染和插入已下载的定义;完整性校验失败会如实报告,而不会被缓存数据掩盖。
保存消费文档
已启用库的绑定(bindings)与物化定义(materialized definitions)随.fig文档保存。重新打开消费文件时,即使其远端库不可用,链接的实例与修订身份也会完整保留。
创建实例(Creating Instances)
右键点击组件,从右键菜单中选择Create instance,实例即出现在源组件右侧40 px处,视觉上与源组件完全一致。
这一 40 px 偏移在 instances.ts 的defaultInstancePlacement()中有直接实现——新实例的世界坐标取bounds.x + bounds.width + 40(即源组件包围盒右侧偏移 40 px),再转换到父级局部坐标系。
需要注意:实例创建只能通过右键菜单完成,没有对应的工具栏按钮。
分离实例(Detaching an Instance)
选中实例,按⌥⌘B(Windows/Linux 为Ctrl+Alt+B)将其分离。分离后实例变成一个普通 Frame,与源组件不再有任何链接,所有覆盖(overrides)被烘焙(baked in)进图层。
转到主组件(Go to Main Component)
右键点击实例,选择Go to main component。编辑器会导航到主组件并选中它,必要时自动切换页面。
实时同步(Live Sync)
编辑组件时,其所有实例自动更新。同步的属性包括:
- 宽与高(width and height)
- 填充、描边与效果(fills, strokes, and effects)
- 不透明度与圆角(opacity and corner radii)
- 布局属性(自动布局设置)
- 内容裁剪设置(clips content setting)
同步在组件内的节点更新、移动和缩放后自动触发。其核心实现位于 editor/component-sync.ts,其中componentSyncOrder()负责计算受同步影响组件的传播顺序,保证同步按依赖拓扑正确执行;对应的行为测试覆盖见 component-sync.test.ts 与 page-instance-sync.test.ts。
覆盖(Overrides)
实例可以覆盖特定属性而不破坏同步链接。某个属性在实例上被覆盖后,同步时该属性会被跳过——其余属性仍继续跟随主组件更新。
可覆盖的属性
子层级(child-level)覆盖支持:名称、文本、字号、字重、字体族,以及全部视觉与布局属性(填充、描边、效果、不透明度、圆角、尺寸)。
新子级(New Children)
当组件新增一个子级时,所有既有实例自动获得该子级的一个克隆副本;实例中的子级顺序始终与组件保持一致。
命中测试(Hit Testing)
组件与实例是不透明容器——单击其子级选中的是组件/实例本身,而不是子级。双击可进入组件内部并选中其子级。
视觉处理(Visual Treatment)
| 元素 | 外观 |
|---|---|
| 组件标签 | 紫色 + 菱形图标,始终可见 |
| 实例标签 | 紫色 + 菱形图标,始终可见 |
| 组件集边框 | 紫色虚线轮廓 |
快捷键速查(Keyboard Shortcuts)
| 操作 | Mac | Windows / Linux |
|---|---|---|
| 创建组件 | ⌥⌘K | Ctrl+Alt+K |
| 创建组件集 | ⇧⌘K | Shift+Ctrl+K |
| 分离实例 | ⌥⌘B | Ctrl+Alt+B |
| 预览 | ⌥⌘↩ | Ctrl+Alt+Enter |
实战提示(Tips)
- 实例内编辑文本会创建覆盖——之后组件内容变化不会覆盖这段文本,这是设计系统中最常用的局部差异化手段;
- 用组件集组织多维变体(尺寸、状态、主题等),例如
Size、State、Theme三个维度组合成按钮矩阵; - 可复用资源应从其源文档发布;已发布定义在消费文档中是有意只读的,修改需回到源文档再发布新修订;
- 当某次修订移除了某个精确变体组合时,先审查再接受更新,确认左上角回退变体符合预期(应用更新会创建撤销条目,但审慎仍优于事后回退);
- 需要离线继续工作的团队,应提前确保所需库修订已下载——缓存机制保证离线时仍可渲染和插入;
- 关于组件相关的全部右键菜单动作,可参阅 Context Menu;行为与预览的架构细节可深入 behaviours-and-preview.md。
延伸阅读
- 行为种类与交互状态的完整定义:scene-graph/src/behaviours/kinds.ts
- 行为模型、预览岛与代码导出架构:behaviours-and-preview.md
- 组件创建/包裹规则实现:editor/components/create.ts
- 实例放置与创建实现:editor/components/instances.ts
- 实时同步实现:editor/component-sync.ts
- 组件集合并(
combineAsVariants)实现:figma-api/components.ts - 行为 API 测试:behaviours.test.ts
- 变体合并测试:combine-variants.test.ts
- 前端
- 桌面应用
- AI 应用
- MCP 服务
【免费下载链接】open-pencil
AI-native design editor. Open-source Figma alternative.
相关推荐
OpenPencil 组件系统实战指南:主组件、实例、变体与组件库的完整工作流
OpenPencil 组件系统实战指南:主组件、实例、变体与组件库的完整工作流 OpenPencil(开源 Figma 替代品、AI 原生设计编辑器)的组件系统
前端桌面应用AI 应用MCP 服务OpenPencil 组件系统深度指南:组件、实例、变体覆盖与组件库实战
OpenPencil 组件系统深度指南:组件、实例、变体覆盖与组件库实战 组件(Components)是 OpenPencil 中最核心的复用机制:把一组设计元
前端桌面应用AI 应用MCP 服务OpenPencil 组件体系实战指南:组件、组件集、变体与组件库全解析
OpenPencil 组件体系实战指南:组件、组件集、变体与组件库全解析 OpenPencil 是一款开源的 AI 原生设计编辑器(Figma 替代方案)。本文
前端桌面应用AI 应用MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考