Windows, buttons, and menus
Parameters for windows, iframes, buttons, and import and export menu actions in editorAPI.
The methods on this page create UI inside BDEngine. The examples assume that the editor UI is ready. When a plugin loads together with the editor, wait for the bde:started event. Import and export actions can be registered earlier: they appear once the menus have been created.
createWindow
editorAPI.createWindow( name = 'Window', name_id = 'default', icon = 'icon-layout-grid', width = 1100, height = 550, minWidth = 500, minHeight = 400, closeFunc = () => {});Synchronously creates and opens a movable window. Returns a window instance,
not a DOM element. Add content to its container.
| Parameter | Meaning |
|---|---|
name |
Window title. Use your own string without untrusted HTML |
name_id |
Window identifier. Use a prefix for your plugin, such as my-plugin-preview |
icon |
Icon class. Also accepts { type: 'image', src, fallback }, where fallback is a fallback icon class |
width, height |
Initial size in CSS pixels |
minWidth, minHeight |
Minimum size when the user resizes the window |
closeFunc |
Function with no arguments, called when the close icon is clicked |
closeFunc must be a function; otherwise, the call throws an API error.
Reusing the same name_id does not reuse an existing window: keep your own
reference to the instance.
const panel = editorAPI.createWindow( 'Preview', 'my-plugin-preview', 'icon-eye', 700, 450, 400, 300);const text = document.createElement('p');text.textContent = 'The plugin preview will appear here.';panel.container.append(text);The returned object provides these members:
| Member | Action |
|---|---|
container |
DOM container for the plugin’s content |
headerAdd |
DOM container for additional elements in the window header |
focus() |
Brings the window to the front; restores it if minimized |
minimize() / restore() |
Minimizes / restores the window |
setName(name) |
Changes the title; the string is interpreted as HTML |
setIcon(icon, updateManager = true) |
Changes the icon and updates the window manager by default |
close() |
Starts closing the window and removing its DOM |
These methods are synchronous and do not return a result. After the closing
animation, windowDiv and container become null. Create a new window
instance to open it again. Calling close() directly does not call
closeFunc. If both closing paths need cleanup, invoke it explicitly
and make it safe to run more than once.
createWindowIFrame
editorAPI.createWindowIFrame( url = 'https://www.block-display.com/', name = 'Window', name_id = 'default', icon = 'icon-layout-grid', width = 1100, height = 550, minWidth = 500, minHeight = 400, closeFunc = () => {}, iframeAttributes = {});Creates the same kind of window with an iframe inside. Returns a window
object with an additional iframe property; the padding of container
is set to 0. url specifies the page address. The other window parameters
have the same meaning.
iframeAttributes is an object of HTML attributes for the iframe. Values
of null, undefined, and false are skipped; true creates an empty
attribute; other values are converted to strings. Attributes are set before
src is assigned.
const help = editorAPI.createWindowIFrame( 'https://docs.bde.gg/en/plugins/', 'Plugin documentation', 'my-plugin-help', 'icon-book-open', 900, 600, 400, 300, () => {}, { title: 'BDEngine Manual', referrerpolicy: 'no-referrer' });Browser restrictions still apply: a site may prohibit embedding, and access
to the DOM of a page on another origin is restricted. The plugin chooses
sandbox, allow, and any other required attributes; they are not added
automatically.
createModalWindow
const modal = editorAPI.createModalWindow(name = 'Window');Synchronously creates a hidden modal window and returns a ModalGUI object.
name is the title; add content elements to modal.container. The window
is already in the DOM, but displaying it requires a separate call.
const modal = editorAPI.createModalWindow('Plugin settings');const close = document.createElement('button');close.type = 'button';close.textContent = 'Done';close.addEventListener('click', () => modal.hideModal());modal.container.append(close);modal.showModal();showModal
modal.showModal() displays an existing window. Returns undefined.
The method hides other modal components in editor.gui, releases interactive
camera input, and exits Pointer Lock when necessary. It is not a shared
manager for every modal created by third-party plugins: manage switching
between your own windows yourself.
hideModal
modal.hideModal() hides the window while retaining its DOM, content, and
event handlers. Returns undefined. You can show the window again without
recreating it. Clicking the backdrop calls the same method. In immersion mode,
hiding may be deferred while the editor is dragging an object.
addButtonDockMenu
editorAPI.addButtonDockMenu( icon = 'icon-box', name = 'New button', func = () => {}, sound = true);Adds an item to the dock menu and synchronously returns an HTMLAnchorElement.
icon is the icon class, name is the item label, and func is a callback
with no arguments. After the callback, the menu closes and a sound plays.
The label is inserted into markup, so use trusted text.
const button = editorAPI.addButtonDockMenu( 'icon-settings', 'Plugin settings', () => modal.showModal());// When the item is no longer needed:// button.remove();The current wrapper always passes sound = true: setting this parameter
to false does not currently disable sound for this method. An asynchronous
func is not awaited and does not prevent repeated clicks. For a long-running
operation, manage its state yourself, for example with the disabled class
on the returned element.
addButtonTool
editorAPI.addButtonTool(icon, func, right = false, sound = true);Adds a button to the left (right = false) or right (right = true)
toolbar. Synchronously returns an HTMLButtonElement.
icon is required: one nonempty CSS class string without whitespace.
func is required and must be a function; it is called with no arguments.
Invalid values throw an API error. sound = false does disable the click
sound for this button.
const button = editorAPI.addButtonTool('icon-info', () => { console.log('Selected objects:', editorAPI.getSelectedObjects().length);}, true, false);button.title = 'Number of selected objects';button.setAttribute('aria-label', button.title);Use button.disabled to disable the button and button.remove() to remove it.
The callback’s Promise is not awaited: the plugin must prevent repeated
execution and handle errors from asynchronous operations.
addButtonImportMenu
const action = editorAPI.addButtonImportMenu({ id: 'my-plugin-import', title: 'Plugin import', icon: 'icon-upload', enabled: true, onClick(event) { /* open a file picker */ }});Registers an item in File > Import, after the built-in actions and a separator. Synchronously returns a handle for managing the action. File > Export uses the same contract.
| options field | Contract |
|---|---|
id |
Required nonempty string. Unique within the import or export menu; use a plugin prefix |
title |
Required nonempty string, displayed as text |
icon |
Optional single CSS class without whitespace; defaults to '', with no icon |
onClick |
Required function. Receives the click event and may return a Promise |
enabled |
Optional boolean. Defaults to true for a new item |
Invalid types or missing required fields throw an API error. Registering the
same id again updates the existing item’s title, icon, and callback. If
enabled is omitted during that update, its current value is retained.
The repeated call returns the same handle.
| Handle method | Return value and action |
|---|---|
action.setEnabled(boolean) |
Changes availability and returns action for chaining |
action.remove() |
Removes the registration and button. Returns true on the first removal, or false if the registration no longer exists |
action.setEnabled(false);action.setEnabled(true);// action.remove();The item is disabled while its callback runs, including the entire time spent
awaiting a Promise. The menu closes before the callback starts. The callback
is invoked before the first await, so a file picker can use the user’s
activation. Exceptions and rejected Promises are logged to the console with
the action’s context, and the temporary disabled state is then cleared.
The plugin is responsible for displaying an error message to the user.
addButtonExportMenu
editorAPI.addButtonExportMenu(options) adds an action to File > Export.
Its parameters, return value, replacement by id, and Promise handling are
the same as for import. The method itself does not define an export format
or retrieve project data.
const exportAction = editorAPI.addButtonExportMenu({ id: 'my-plugin-inspect-export', title: 'Get JSON for the plugin', icon: 'icon-download', async onClick() { const data = await editorAPI.exportToJSON(false); if (data === false) return; console.log(data); }});For details about the result and changes to the export window, see exportToJSON.
State and repeated execution
A file menu action is reused by id. Dock buttons, toolbar buttons, regular
windows, and modal windows are created anew on every call. Keep them in your
plugin’s state to avoid duplicating UI when it is opened again.
Removing a button does not remove handlers attached to window or document,
nor does it stop intervals, observers, or network requests. Closing a window
does not automatically unload the plugin either. Implement your own resource
cleanup and check it using
Debugging and repeated execution.