| name | layaair-ide-plugin |
| description | Create LayaAir IDE editor plugins (extensions). TRIGGER when: user asks to create/build/write a plugin, panel, editor panel, menu, inspector field, build plugin, asset processor, custom editor, scene hook, gizmo, or any editor extension. Also trigger when user mentions LayaAir/Laya/laya, @IEditor, @IEditorEnv, EditorPanel, panel/面板, or wants to extend the IDE. Chinese triggers: 编辑器插件, 编辑器面板, 插件面板, 面板插件, 写一个面板, 写个插件. This project IS the LayaAir IDE — any request to write an editor plugin or panel in this repo should use this skill. |
LayaAir IDE Plugin Development Skill
You are an expert at developing LayaAir IDE editor plugins (extensions). Generate production-ready TypeScript plugin code following LayaAir 3.x conventions.
Architecture Overview
LayaAir IDE runs on Electron with three processes:
- UI process: Editor panels, menus, dialogs. Uses
@IEditor.* decorators. Global object: Editor
- Scene process: Engine/scene logic, gizmos, build. Uses
@IEditorEnv.* decorators. Global object: EditorEnv
- Preview process: Runtime preview. No Node.js, uses Laya engine only.
Scripts compile to: bundle.editor.js (UI), bundle.scene.js (Scene), bundle.js (Preview).
Plugin Location
Plugins are created in user projects, not in the IDE source. Plugin scripts can be placed anywhere under the project's assets/ directory — there is no required directory structure. The IDE automatically compiles scripts with @IEditor.* or @IEditorEnv.* decorators into the corresponding bundles.
One convention: place editor-only resources (icons, widgets, locales) in an editorResources/ folder — files there are excluded from the game build.
Step-by-Step: Creating a Plugin
1. Ask the user what type of plugin they need
Common plugin types:
- Panel plugin: Custom editor panel (most common)
- Menu plugin: Add menu items to the editor
- Inspector plugin: Custom property fields in Inspector
- Build plugin: Extend the build pipeline
- Asset plugin: Custom asset types with import/export/preview
- Scene hook plugin: React to scene events (node creation, save, etc.)
- Gizmo plugin: Custom scene view drawing (2D/3D)
2. Create the plugin following these patterns
Read references/api-patterns.md for the complete API reference with code examples for each plugin type.
Key Rules
- Decorator placement matters:
@IEditor.* = UI process only, @IEditorEnv.* = Scene process only
- Panel class must extend
IEditor.EditorPanel and implement async create() returning this._panel
- Dialog class must extend
IEditor.Dialog and set this.contentPane
- Inspector field must extend
IEditor.PropertyField and implement create() + refresh()
- Build plugin must implement
IEditorEnv.IBuildPlugin interface
- Settings location:
"project" (shared), "local" (gitignored), "application" (global), "memory" (transient)
- editorResources/ directory: assets here are NOT published to the game build
- Cross-process calls: UI calls Scene via
Editor.scene.runScript("ClassName.method", ...args), Scene calls UI via EditorEnv.sendMessageToPanel("PanelName", "method")
- React panels: React is built-in to the IDE — just
import and use, no npm install needed. Use IEditor.ReactDOM, call adoptStyles() for CSS, makeFullSize() to fill parent, render(<App/>) to mount. The IDE also provides ready-made editor-integrated React components via IEditor.React: EditorImage, TextInput, NumericInput, NumericInputWithSlider, SelectInput, SearchInput, ResourceInput, NodeRefInput, ColorInput, GradientInput, CurveInput, TooltipTarget, Popup, LocalizedText, ResizeHandle. See api-patterns.md §2 "Built-in React Components" for full API. Only prerequisite: ensure "jsx": "react-jsx" is set in tsconfig (see rule 11)
- CSS workflow: ReactDOM auto-injects a base dark-theme stylesheet with CSS variables and styled HTML elements (
<button>, <input>, <select>, etc.). Available component classes: button.primary, button.icon/.btn-icon, .toolbar-icon-button, .tab, .search-input, .editor-slider, .text-muted, .editor-list/.editor-list-row, etc. No built-in layout utility classes exist — use inline style props for layout. Always prefer the built-in theme first — most panels need zero custom CSS. Only create a custom CSS file when the built-in classes are insufficient. import styles from './Foo.css' returns CSS as a string (via built-in esbuild css-text plugin), pass to reactDOM.adoptStyles(styles). See api-patterns.md §2 "Built-in Theme Reference" for the full variable/class list.
- TypeScript config: Must have
"experimentalDecorators": true and "jsx": "react-jsx" (for React). React runtime is built-in — import { useState } from "react" works directly with no npm install react. However, TypeScript needs type definitions to compile: add "@types/react" and "@types/react-dom" to devDependencies in package.json (npm install --save-dev @types/react @types/react-dom).
- Images: Two approaches depending on UI mode. React panels:
import icon from './icon.png' returns an absolute file:// URL string, use in JSX <img src={icon} />; CSS url(./icon.png) also auto-resolved (supported: png, jpg, gif, svg, webp, ico, bmp). Built-in UI (FairyGUI): use editorResources/ paths directly, e.g. "editorResources/my-plugin/icon.svg". Editor-only images should always go in editorResources/ to exclude from game build.
- IFrame: Never use raw
<iframe> HTML element. Always use IEditor.WebIFrame instead. In React, create the instance once via useRef + useCallback, append its .element to a container div. When hiding, use display:none — do NOT remove from DOM (avoids reload/state loss).
- Node.js modules: Node built-in modules (
fs, path, child_process, etc.) are available in the IDE — just import and use, no install needed.
- Renaming scripts: When renaming a script file, always rename the corresponding
.meta file as well (e.g. rename Foo.ts → Bar.ts, must also rename Foo.ts.meta → Bar.ts.meta). The .meta file stores the asset UUID and must stay paired with its file.
- Type name uniqueness:
Editor.typeRegistry.addTypes 和 InspectorPanel.inspect 中传入的类型名(name 字段)在全局类型注册表中必须唯一,否则会与其他插件冲突。命名时加上插件专属前缀,例如 "MyPlugin_SettingsType" 而非 "SettingsType"。
- Panel ID uniqueness:
@IEditor.panel(id, ...) 的 id 是全局唯一标识符,简短通用的名字(如 "MyPanel"、"Settings")容易与其他插件冲突。建议使用带插件/公司前缀的复杂名字,例如 "MyCompany.ProjectManager.MainPanel" 而非 "MainPanel"。
Full API Reference
For the complete API beyond what references/api-patterns.md covers, read the type declaration files in the project's engine/types directory:
- editor.d.ts — UI process API (
IEditor namespace, global Editor object)
- editor-env.d.ts — Scene process API (
IEditorEnv namespace, global EditorEnv object)
- editor-ui.d.ts — Editor UI library (
IEditorUI namespace, FairyGUI components)
Output Format
When creating a plugin, always:
- Ask the user where to place the plugin files (anywhere under project
assets/ is valid)
- Include proper decorators and type annotations
- Put editor-only resources (icons, widgets) in
editorResources/ directory
- Add i18n support if the plugin has user-visible strings
- Explain which process each file runs in (UI vs Scene)