A minimal, self-contained template for building third-party plugins for Phaser Editor v5.
This template ships one example plugin (myplugin.example) that contributes a
custom command to the editor. Use it as the starting point for your own
plugin: clone it, rename it, and grow it.
This template is set up so an AI coding assistant can help you build plugin features effectively:
AGENTS.md— an entry point that orients any AI agent (Cursor, Claude Code, etc.) on the architecture, conventions, and build.docs/— task-focused recipes for humans and AI alike: an extension-points catalog plus how-tos for commands, custom editors, content types & the New File wizard, Inspector properties, and theme-correct styles..cursor/skills/phaser-editor-plugin— a Cursor skill that auto-applies when you ask the agent to add plugin functionality and points it at the right doc and example.
The bundled types/*.d.ts give the AI the editor's real API surface, and
myplugin.example is a complete worked example to copy from. Just ask your
assistant something like "add a command that …" or "add an editor for .foo
files" and it will follow these docs.
A Phaser Editor plugin is just a folder containing:
- a
plugin.jsonmanifest, and - one or more JavaScript files (and optional CSS) listed in that manifest.
Loading happens in two steps:
- Discovery (server side). When the editor starts, the server scans its
plugin directories. For every folder that has a
plugin.json, it injects the listedscriptsandstylesinto the editor page. - Registration (client side). When your script runs in the page, it calls
colibri.Platform.addPlugin(...)to register your plugin instance. During startup the editor then calls your plugin'sregisterExtensions(reg)method, where you contribute commands, menus, editors, views, and so on.
There is no webpack or runtime npm dependency. The build is plain TypeScript:
each plugin compiles to a single concatenated file (_out/<id>.js) via tsc
with outFile.
This template compiles against a bundled snapshot of the editor's API types
(types/colibri.d.ts), so you do not need a checkout of the editor source
to build your plugin.
phaser-editor-5-plugin-template/
├── README.md # this file
├── AGENTS.md # AI-agent entry point (architecture + conventions)
├── docs/ # developer recipes (commands, editors, styles, ...)
├── .cursor/skills/ # Cursor skill for plugin development
├── package.json # build scripts + the typescript devDependency
├── update-types.mjs # copies all editor plugin .d.ts into types/
├── tsconfig.json # solution file: references the example plugin's src
├── tsconfig-base.json # shared compiler options
├── types/ # bundled API snapshots, one .d.ts per editor plugin
│ ├── colibri.d.ts # core editor API
│ ├── phasereditor2d.files.d.ts # the New File wizard (Files plugin)
│ ├── phasereditor2d.phaser.d.ts # Phaser + scene types
│ └── ... # every other editor plugin
└── myplugin.example/ # the example plugin (folder name == plugin id)
├── plugin.json # manifest: id + scripts + styles
├── styles/
│ └── TodoEditor.css # theme-scoped styles for the Todo editor
├── _out/ # build output (generated; git-ignored)
│ └── myplugin.example.js
└── src/
├── tsconfig.json # outFile -> ../_out/myplugin.example.js
├── ExamplePlugin.ts # plugin class: registers the command, content type, editor
└── editors/ # the custom "Todo" editor example
├── TodoModel.ts # data model + ".todo" content type id
├── TodoEditor.ts # the editor, viewer, commands, toolbar
├── TodoEditorOutlineProvider.ts # feeds the Outline view
├── TodoEditorProperties.ts # Inspector sections (name/description/state)
└── NewTodoFileExtension.ts # "New Todo File" wizard entry
- Node.js (any recent LTS) and npm.
- An installed copy of Phaser Editor v5 (desktop or the CLI launcher).
npm install
npm run buildThis produces myplugin.example/_out/myplugin.example.js.
Other scripts:
npm run watch— rebuild on every change (great while developing).npm run clean— remove the build output.
After building, make the editor aware of the plugin in any one of these ways:
Copy the plugin folder into your user plugins directory:
cp -r myplugin.example ~/.phasereditor2d/plugins/Restart the editor. The plugin loads automatically.
Point the launcher at this template's root directory. The editor scans each
subfolder for a plugin.json; types/ is ignored because it has none:
PhaserEditor -plugins /path/to/phaser-editor-5-plugin-templateCombine with npm run watch to iterate quickly — rebuild, then reload the
editor page.
In a game project, add the plugin's path to phasereditor2d.config.json:
{
"plugins": ["/path/to/phaser-editor-5-plugin-template/myplugin.example"]
}Once loaded, run the example command in either way:
- Open the command palette with
Ctrl+K, search for "Hello From Plugin". - Or press the shortcut
Ctrl+Alt+H.
You should see a "Hello from myplugin.example!" message.
To turn this into your own plugin, change the id everywhere so the manifest, the compiled file, the namespace, and the build reference all stay in sync:
- Rename the folder
myplugin.example/to your plugin id, e.g.com.acme.tools. - In
com.acme.tools/plugin.json: set"id"and the script path in"scripts". - In
com.acme.tools/src/tsconfig.json: updateoutFileto../_out/com.acme.tools.js. - In
com.acme.tools/src/ExamplePlugin.ts: rename thenamespace, thesuper("...")id, and the command/category ids. - In the root
tsconfig.json: update thereferencespath.
Use a unique, namespaced id (reverse-domain style is a good convention) to avoid
clashing with other plugins. Command ids follow the convention
<pluginId>.<ActionName>.
Add more manager.add({ ... }) calls inside the CommandExtension in
ExamplePlugin.ts. Each command takes:
command: metadata (id,name,tooltip,category).handler: behavior —executeFunc(args)runs the command, and an optionaltestFunc(args)controls when it is enabled (e.g. only in a specific editor).keys: an optional keyboard shortcut (control/shift/alt/metaflags plus akey).
The args passed to the handlers give you the active part, editor, selection,
and window — see colibri.ui.ide.commands in types/colibri.d.ts.
Commands are just one extension point. Browse types/colibri.d.ts for more,
including:
colibri.ui.controls.menus(MenuExtension) — contribute menu entries that reference your command ids.colibri.ui.ide.EditorExtension/WindowExtension— custom editors and views.colibri.core.ContentTypeExtension/colibri.core.io.FileStorageExtension— content types and file storage.
All of them are contributed the same way: reg.addExtension(new ...Extension(...))
inside registerExtensions.
The template also ships a small but complete custom editor that opens
.todo files. It is a rich HTML-based editor (it builds its own DOM instead
of using a tree viewer), and it demonstrates the most common building blocks of
a Phaser Editor editor: a content type, the Outline view, the Inspector
(properties) view, and theme-correct CSS, with selection kept in sync between
all three.
-
Build the plugin and make the editor aware of it (see the sections above).
-
Create a new todo file with the New File wizard, in any of these ways:
- Right-click a folder in the Files view -> New... -> Todo File, or
- press Ctrl+Alt+N and pick Todo File, or
- use the New File button in the main toolbar.
A
tasks.todofile is created (pre-filled with one example task) and opens automatically in the Todo Editor, which pretty-prints each task (name + colored state). -
Use the editor toolbar (or right-click for the context menu) to Add Task, Delete, Move Up, and Move Down. Pressing
Aadds a task;Deleteremoves the selected ones. -
Open the Outline view to see every task listed by name.
-
Open the Inspector view and select a task (in the editor or the outline) to edit its name, state, and description. Changes are reflected immediately and mark the editor dirty (save with
Ctrl+S).
flowchart LR
file[".todo file"] --> ct["Content type<br/>ContentTypeResolverByExtension"]
ct --> factory["ContentTypeEditorFactory"]
factory --> editor["TodoEditor<br/>(FileEditor + HTML task cards)"]
editor -->|"getEditorViewerProvider('Outline')"| outline["TodoEditorOutlineProvider<br/>-> Outline view"]
editor -->|"getPropertyProvider()"| props["TodoEditorPropertySectionProvider<br/>-> Inspector view"]
editor -->|selection| outline
outline -->|onViewerSelectionChanged| editor
editor -->|selection| props
- Content type (TodoModel.ts):
colibri.core.ContentTypeResolverByExtensionmaps thetodoextension to the content type idCONTENT_TYPE_TODO. The data model (TodoModel/TodoTask) serializes to/from JSON. - Editor (TodoEditor.ts):
extends
colibri.ui.ide.FileEditorand builds its own HTML increatePart- a scrollable list of task "cards" (name + colored state badge + description). It tracks its own selection (_selectedTasks), highlights the selected cards, supports Ctrl/Cmd-click for multi-select, loads the file increatePart, saves JSON indoSave, and exposesAdd / Delete / Move Up / Move Downcommands via a toolbar and context menu. - Styles (TodoEditor.css):
theme-correct CSS registered in
plugin.json. Layout is theme-agnostic; colors are scoped per theme class, grouped for the dark-like themes (dark,phaserstudio) and the light-like themes (light,lightBlue,lightGray). - Outline
(TodoEditorOutlineProvider.ts):
an
EditorViewerProviderreturned for the"Outline"key. It lists tasks by name and pushes outline selection back into the editor. - Inspector
(TodoEditorProperties.ts):
a
PropertySectionProviderwith a singlePropertySectionthat renders the name (text), state (menu button), and description (text area). It is returned by both the editor (getPropertyProvider) and the outline provider (getPropertySectionProvider), so it works whichever view has focus. - New File wizard
(NewTodoFileExtension.ts):
extends
phasereditor2d.files.ui.dialogs.NewFileContentExtensionso a Todo File entry appears in the New File wizard (Ctrl+Alt+N), the Files view New... menu, and the New File toolbar button. It generates the initial JSON content and the editor opens the file automatically. This is the same mechanism used by the built-in Scene File and Asset Pack File wizards.
Selection routing: when you click a card, the editor calls setSelection(tasks)
on its Part, which the Inspector view listens to, and it mirrors the selection
to the outline provider. When you click in the Outline, the provider's
onViewerSelectionChanged pushes the selection back into the editor (which then
updates the inspector). A syncOutline flag prevents feedback loops.
Note on bundled types: the editor compiles against
colibri.d.ts, and it returns the outline provider by comparing the key against the literal"Outline"(the value ofOutlineView.EDITOR_VIEWER_PROVIDER_KEY) so it needs no outline/inspector types. The only feature that needs a second declaration file is the New File wizard, because its base class lives in the Files plugin — hence the bundledphasereditor2d.files.d.ts.
The files in types/ are snapshots of the editor API (one .d.ts per
editor plugin), so this template compiles against the full editor API
without an editor checkout. They are taken from a specific editor version.
To refresh them from your editor source, set PHASEREDITOR5_HOME to the folder
that contains phaser-editor-v5 and run the bundled script:
export PHASEREDITOR5_HOME=/path/to/parent # so the source is at
# $PHASEREDITOR5_HOME/phaser-editor-v5/workbench
npm run update-typesThe script copies every <plugin>/_out/<plugin>.d.ts from
$PHASEREDITOR5_HOME/phaser-editor-v5/workbench/source/editor/plugins into
types/. The editor must have been built (its _out folders must exist).
Because types/*.d.ts are all included by
myplugin.example/src/tsconfig.json, every
plugin's API is available to your code immediately after running the script.