编辑器插件
概述
编辑器插件用于扩展 Zephyr3d Editor 本身。一个插件可以添加:
- 主菜单和右键菜单项
- 工具栏按钮
- 自定义编辑工具
- 自定义属性面板访问器
- 插件设置与持久化状态
当前界面入口是 Project -> Plugin Manager...,用于管理安装的所有编辑器插件;这些插件保存在编辑器的全局数据库中,并在同一浏览器配置下对所有本地项目可见。
安装与管理
打开 Project -> Plugin Manager...,然后可以使用以下操作:
Install...:从.zip插件包安装Install Folder...:从未打包的插件目录安装Link...:在桌面端将插件根目录直接链接到编辑器,供开发调试使用New Template...:在编辑器里生成一个起步模板插件
插件安装后,可以继续:
- 通过插件列表前的复选框启用或禁用
- 使用
Browse Files...查看和编辑插件文件 - 使用
Install Package...安装第三方 npm 依赖 - 使用
Settings...配置插件暴露出的设置项 - 将插件从编辑器中移除
说明:
Install...和Install Folder...面向正式安装/发布使用Link...仅用于桌面端开发模式,不适用于浏览器版编辑器Link...链接的是插件根目录,不是src/,也不是dist/
插件目录结构
推荐使用带 plugin.json 清单文件的多文件插件包,清单位于插件根目录:
my-editor-plugin/
plugin.json
index.ts
icons/
tool.svg
utils/
commands.ts示例 plugin.json:
{
"id": "com.example.demo-plugin",
"name": "Demo Plugin",
"version": "0.1.0",
"description": "Example editor plugin for Zephyr3d.",
"entry": "index.ts"
}清单字段说明:
id:必填,且必须全局唯一entry:必填,表示插件入口模块的相对路径name、version、description:可选,但建议填写dependencies:可选,声明插件使用的第三方包
桌面端开发模式
桌面端开发模式支持让编辑器直接读取插件源码,而不是先构建 dist 再安装。
推荐目录结构如下:
my-editor-plugin/
plugin.dev.json
plugin.json
src/
index.ts
libs/
deps.lock.json
deps/
dist/
index.js
plugin.json其中:
plugin.dev.json:开发态清单,供桌面端Link...使用plugin.json:发布态清单,供正式安装包或dist产物使用src/:插件源码入口libs/deps/:编辑器为开发态插件缓存的第三方依赖dist/:构建后的发布产物
开发态示例 plugin.dev.json:
{
"id": "com.example.demo-plugin",
"name": "Demo Plugin",
"version": "0.1.0",
"description": "Example editor plugin for Zephyr3d.",
"entry": "src/index.ts",
"dependencies": {
"nanoid": "^5.0.0"
}
}开发流程:
- 启动桌面版编辑器开发环境
- 打开
Project -> Plugin Manager... - 点击
Link... - 选择插件根目录
- 修改源码后,手动点击
Refresh
开发态特点:
- 编辑器直接加载
src下源码,不需要先执行npm install - 如果
plugin.dev.json的dependencies声明了第三方包,编辑器会在首次需要时自动下载并缓存到libs/deps/ - 后续刷新会优先复用本地
libs/deps和libs/deps.lock.json - 开发态
Refresh只会重新校验plugin.dev.json和入口依赖图,不会递归扫描整个插件目录
注意事项:
- 开发态第三方包必须声明在
plugin.dev.json.dependencies中 Link...后插件源码变更不会自动热重载,需要手动点击Refresh- 如果首次下载依赖时离线,且本地又没有
libs/deps缓存,则插件加载会失败
发布模式
发布时仍然建议使用传统的安装包/构建产物流程。
发布流程:
- 安装插件构建依赖
- 执行构建,生成
dist/ - 确认
dist/plugin.json与dist/index.js等产物完整 - 使用
Install...安装.zip包,或使用Install Folder...安装发布目录
发布态特点:
- 使用构建后的 JavaScript 产物,加载速度通常快于开发态源码模式
- 更适合分发给其他人或用于稳定版本交付
plugin.json应描述发布态入口,例如dist/index.js或发布目录内入口文件
最小插件示例
从 @zephyr3d/editor/editor-plugin 导入插件类型,并默认导出插件定义:
import type { EditorPluginDefinition } from '@zephyr3d/editor/editor-plugin';
import { SceneNode } from '@zephyr3d/scene';
const plugin: EditorPluginDefinition = {
activate(ctx) {
ctx.registerMenuItems({
location: 'main',
items: [
{
id: 'com.example.demo-plugin.menu',
label: 'Demo Plugin',
subMenus: [
{
id: 'com.example.demo-plugin.about',
label: 'About...',
action: async () => {
await ctx.ui.message('Demo Plugin', 'The plugin is active.');
}
}
]
}
]
});
ctx.registerMenuItems({
location: 'scene-hierarchy',
items: (menuCtx) => [
{
id: 'com.example.demo-plugin.add-empty-child',
label: 'Add Empty Child',
visible: () => menuCtx.target instanceof SceneNode,
action: async () => {
if (!(menuCtx.target instanceof SceneNode) || !menuCtx.scene) {
return;
}
await menuCtx.scene.commands.addChildNode(menuCtx.target, SceneNode);
menuCtx.scene.refreshProperties();
menuCtx.scene.notifySceneChanged();
}
}
]
});
}
};
export default plugin;插件 API
EditorPluginContext 是传给 activate(ctx) 的主入口对象。
常用能力包括:
ctx.project:读写项目文件、创建目录、打开代码文件ctx.system:保存插件级的全局状态与设置ctx.ui:显示消息框、确认框,以及项目文件/目录选择器ctx.registerMenuItems(...):注册菜单项ctx.registerToolbarItem(...):注册工具栏按钮ctx.registerEditTool(...):注册自定义场景编辑工具ctx.registerPropertyAccessors(...):扩展属性面板ctx.on(...):监听编辑器事件,例如场景打开、选择变化、节点变化ctx.log(...):输出插件日志
菜单贡献函数会收到 EditorMenuContext,其中包含:
scene:场景相关菜单里可用assets:资源浏览器相关菜单里可用target:当前被点击的节点、文件或其他目标对象
如果你直接修改了场景数据,记得调用:
ctx.refreshProperties()ctx.notifySceneChanged()
场景命令
涉及场景结构或可撤销编辑时,建议通过 EditorSceneContext.commands 操作。
内置命令辅助方法包括:
addChildNode()addShapeNode()instantiatePrefab()deleteNode()reparentNode()cloneNode()executeCommand()executeUserCallback()
这个 API 会出现在带场景语义的上下文里,例如 menuCtx.scene 和 editCtx.scene。
示例:
await menuCtx.scene.commands.executeCommand(new MyCustomCommand(...));如果只是一次临时的可撤销操作,也可以直接使用:
await menuCtx.scene.commands.executeUserCallback(
async () => {
target.visible = false;
},
async () => {
target.visible = true;
}
);设置与状态
插件可以在定义对象上声明设置结构:
const plugin: EditorPluginDefinition = {
settings: {
endpoint: {
type: 'string',
label: 'API Endpoint',
description: 'Base URL used by the plugin.'
},
autoSync: {
type: 'boolean',
label: 'Auto Sync',
default: true
}
},
activate(ctx) {
// ...
}
};运行时可用:
ctx.system.getSettings()/ctx.system.saveSettings():保存插件级全局设置ctx.system.getState()/ctx.system.saveState():保存插件级全局状态ctx.project.getSettings()/ctx.project.saveSettings():保存项目级数据
跨项目共享的配置适合放在 ctx.system,只属于当前项目的数据适合放在 ctx.project。
第三方包
如果插件需要 npm 包:
- 打开
Project -> Plugin Manager... - 选中目标插件
- 点击
Install Package... - 输入包名或版本声明,例如
nanoid或nanoid@5
安装完成后即可直接导入:
import { nanoid } from 'nanoid';已安装包的版本会同步记录到 plugin.json 的 dependencies 字段中。
对于桌面端开发态插件:
- 优先在
plugin.dev.json中声明dependencies - 点击
Refresh时,编辑器会自动同步缺失依赖到libs/deps/ - 一般不需要先手动执行
npm install