Launch OpenGPEX

OpenGPEX 1.x documentation (legacy editor).

v2 Docs

Slots & UI

Plugins render into predefined slot regions within the editor workspace. This page details all available slots, visibility policies, Z-index conventions, and the contribution system.


Available Slots

Slot Constant Location / Context Typical Plugins / Purpose
SIDE_BAR Sidebar drawers (left & right sides) Crop, Adjustment, Brush, Text, Image Info, AI Bridge
OPTION_BAR Top strip (below header) Tool-specific option panels (aspect ratio, zoom)
DOCK Bottom tab panel area Layer panel, History panel, Timeline
TL / TR / BL / BR Viewport corner widgets Anchored viewport HUD actions and status widgets
VIEWPORT_OVERLAY Over the canvas (pointer-interactive) Crop handles, selection outline, interactive frames
STAGE_OVERLAY Stage-level layer (non-interactive) Pixel grid, rulers, snapping guides
STAGE_GIZMOS Interactive transform & crop tools Free transform handles, crop boundaries
ROOT_OVERLAY App-level absolute layers Global notifications, dialogs, loading spinner overlays
TOOL_MENU Left vertical toolbar Cursor interaction tools selection menu
HIDDEN No visual UI TimeTraveler, Clipboard service, background hooks

Show Policies

The show property determines when a plugin's UI is rendered:

Policy Behavior
'always-show' Visible whenever the editor is open (regardless of document state)
'frame-required' Visible only when at least one frame/document is loaded

Most tools use 'frame-required' because they operate on layer data that doesn't exist without a document.


Z-Index Protocol

The workspace defines a strict Z-index map in EDITOR_Z_INDEX (@opengpex/editor/core/helpers/config) to prevent overlap conflicts:

Z-Index Layer Content
0 STAGE.BACKDROP Stage backdrop
100 STAGE.CONTENT Layer stack starting level
1000 STAGE.GIZMOS Basic interactive entities (guide lines, anchor points)
2000 STAGE.SYSTEM_TOOLS Core tools (selection box, crop box)
3000 STAGE.DEVELOPER_ZONE Third-party safety zone for plugin gizmos
2000 UI.WORKSPACE_BASE Sidebar, top bar, action bar
4000 UI.OVERLAY Global overlay plugins
5000 UI.POPOVER Popover, dropdown (requires Portal)
6000 UI.MODAL Modal dialogs and warnings
10100 UI.TOOLTIP Tooltips — must float above Popover

Within each slot, plugins are ordered by the order property (lower = rendered first / further back).


Sidebar Drawer Behavior

For SIDE_BAR plugins:

  • Clicking a sidebar icon toggles its drawer panel; double-clicking isolates the drawer (closes all others)
  • Multiple drawers can be open concurrently across Left/Right columns
  • The side property ('left' | 'right') determines default placement
  • Users can drag-and-drop sidebar icons to reorder or swap between columns
  • Drawer panel width is set via initialConfig.preferredWidth (in pixels); it defaults to 320 when unset

Drawer Auto-Reveal

SIDE_BAR plugins may declare an autoReveal rule to open automatically when editor state matches a condition:

export const plugin: EditorPlugin = {
  // ...
  autoReveal: {
    // Pure, O(1) predicate — expansion triggers only on the false → true edge
    when: (state) => !!state.activeFrameId,
    // What happens when `when` becomes false:
    // 'sticky' (default) — stay open until the user closes it
    // 'restore'          — restore the open state from before activation
    // 'collapse'         — always collapse
    collapseWhenFalse: 'restore',
    priority: 0, // higher wins when multiple drawers reveal simultaneously
  },
};

Contributions System

Contributions System

Plugins can donate additional UI to external slots via the contributions array:

export const plugin: EditorPlugin = {
  // ...
  contributions: [
    {
      slot: 'OPTION_BAR',
      component: MyOptionsBarWidget,
    },
  ],
};

This allows a SIDE_BAR plugin to also contribute an options strip to the top bar without creating a separate plugin.

Each UIContribution accepts slot, component, plus optional order, group, title, and icon. Rendering conventions handled automatically by PluginSlot:

  • OPTION_BAR entries are wrapped in a pill-shaped container (h-[34px] px-3.5, panel background with backdrop blur, rounded on first/last siblings) — keep your component content-only and let the wrapper provide the chrome
  • A divider is rendered automatically whenever order crosses a multiple of 100 (full-width line in SIDE_BAR, short centered line in TOOL_MENU, none in OPTION_BAR)

Next Steps


Last updated: 2026-07-30