Editor Plugins
Overview
Editor plugins extend the Zephyr3d Editor itself. A plugin can add:
- Main menu items and context menu items
- Toolbar buttons
- Custom edit tools
- Custom property accessors
- Plugin settings and persistent state
The current UI entry is Project -> Plugin Manager.... Despite the name, this panel manages externally installed editor plugins stored in the editor's global database and shared by all local projects in the same browser profile.
Installing Plugins
Open Project -> Plugin Manager..., then use one of the following actions:
Install...to install a packaged plugin from a.zipfileInstall Folder...to install an unpacked plugin folderLink...to link a plugin root folder directly into the editor for development (desktop editor only)New Template...to generate a starter plugin package inside the editor
After a plugin is installed you can:
- Enable or disable it with the checkbox in the plugin list
- Open
Browse Files...to inspect or edit plugin files - Open
Install Package...to add a third-party npm dependency - Open
Settings...if the plugin exposes a settings schema - Remove the plugin from the editor
Notes:
Install...andInstall Folder...are intended for regular installation and distributionLink...is for the desktop development workflow only and is not available in the browser editorLink...links the plugin root folder, notsrc/and notdist/
Package Layout
The recommended format is a multi-file plugin package with a plugin.json manifest at the package root:
my-editor-plugin/
plugin.json
index.ts
icons/
tool.svg
utils/
commands.tsExample plugin.json:
{
"id": "com.example.demo-plugin",
"name": "Demo Plugin",
"version": "0.1.0",
"description": "Example editor plugin for Zephyr3d.",
"entry": "index.ts"
}Manifest fields:
id: required and must be uniqueentry: required, relative path to the plugin entry modulename,version,description: optional but recommendeddependencies: optional third-party packages used by the plugin
Desktop Development Mode
In the desktop editor, development mode lets the editor load plugin sources directly, without building dist and reinstalling after each change.
Recommended folder layout:
my-editor-plugin/
plugin.dev.json
plugin.json
src/
index.ts
libs/
deps.lock.json
deps/
dist/
index.js
plugin.jsonWhere:
plugin.dev.json: development manifest, used by the desktopLink...actionplugin.json: release manifest, used by installable packages or thedistoutputsrc/: plugin source entrylibs/deps/: third-party dependencies cached by the editor for linked pluginsdist/: built release output
Example development manifest 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"
}
}Development workflow:
- Start the desktop editor development environment
- Open
Project -> Plugin Manager... - Click
Link... - Select the plugin root folder
- After changing the sources, click
Refreshmanually
Development mode characteristics:
- The editor loads sources under
srcdirectly; runningnpm installfirst is not required - If
plugin.dev.jsondeclares third-party packages independencies, the editor downloads and caches them intolibs/deps/on first use - Subsequent refreshes reuse the local
libs/depscache andlibs/deps.lock.json - A development-mode
Refreshonly revalidatesplugin.dev.jsonand the entry dependency graph; it does not rescan the whole plugin folder
Caveats:
- Third-party packages used in development mode must be declared in
plugin.dev.json.dependencies - Source changes are not hot-reloaded after
Link...; clickRefreshmanually - If the first dependency download happens offline and there is no local
libs/depscache, plugin loading fails
Release Mode
For distribution, use the regular package/build output workflow.
Release workflow:
- Install the plugin build dependencies
- Run the build to produce
dist/ - Verify that
dist/plugin.json,dist/index.jsand other outputs are complete - Install the
.zippackage withInstall..., or install the release folder withInstall Folder...
Release mode characteristics:
- Uses built JavaScript output, which usually loads faster than development-mode sources
- Better suited for distributing to other users or delivering stable versions
plugin.jsonshould describe the release entry, for exampledist/index.jsor the entry file inside the release folder
Minimal Plugin
Import plugin types from @zephyr3d/editor/editor-plugin and export a default plugin definition:
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;Plugin API
EditorPluginContext is the main entry point passed to activate(ctx).
Common capabilities:
ctx.project: read and write project files, create directories, open code filesctx.system: save plugin-global state and settingsctx.ui: show messages, confirmations, and project file/folder pickersctx.registerMenuItems(...): contribute menu itemsctx.registerToolbarItem(...): contribute toolbar buttonsctx.registerEditTool(...): register custom scene edit toolsctx.registerPropertyAccessors(...): extend the property panelctx.on(...): listen to editor events such as scene open, selection change, and node updatesctx.log(...): write plugin logs
Menu contributions receive an EditorMenuContext with:
scene: available in scene-related menusassets: available in asset browser menustarget: the clicked node, file, or other target object
When you mutate scene data directly, call:
ctx.refreshProperties()ctx.notifySceneChanged()
Scene Commands
Scene-related operations should go through EditorSceneContext.commands.
Available helpers include:
addChildNode()addShapeNode()instantiatePrefab()deleteNode()reparentNode()cloneNode()executeCommand()executeUserCallback()
This API is available from scene-aware contexts such as menuCtx.scene and editCtx.scene.
Example:
await menuCtx.scene.commands.executeCommand(new MyCustomCommand(...));For quick undoable operations without a dedicated command class:
await menuCtx.scene.commands.executeUserCallback(
async () => {
target.visible = false;
},
async () => {
target.visible = true;
}
);Settings And State
Plugins can declare a settings schema on the definition:
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) {
// ...
}
};At runtime:
ctx.system.getSettings()/ctx.system.saveSettings()store plugin-global settingsctx.system.getState()/ctx.system.saveState()store plugin-global state datactx.project.getSettings()/ctx.project.saveSettings()store project-specific data
Use system settings for values shared across projects, and project settings for values that belong to the current project.
Third-Party Packages
If a plugin needs an npm package:
- Open
Project -> Plugin Manager... - Select the plugin
- Click
Install Package... - Enter a package spec such as
nanoidornanoid@5
After installation you can import the package directly:
import { nanoid } from 'nanoid';Installed package versions are tracked in plugin.json under dependencies.
For desktop development-mode (linked) plugins:
- Declare
dependenciesinplugin.dev.jsoninstead - When you click
Refresh, the editor automatically syncs missing dependencies intolibs/deps/ - Running
npm installmanually is generally not needed