Launch OpenGPEX

Packaging & Distribution

How to build, package, and distribute OpenGPEX plugins for installation by other users.


Build Tool

Use the built-in packaging script:

pnpm pack-plugin <PluginFolderName>           # Standard build
pnpm pack-plugin <PluginFolderName> --minify  # Minified production build

Example:

pnpm pack-plugin ColorPickerDrawer
# Output: dist/user-plugin-colorpickerdrawer-1.0.0.zip

ZIP Structure

The packaged ZIP contains:

user-plugin-colorpickerdrawer-1.0.0.zip
├── plugin.json         # Plugin metadata (auto-generated from manifest)
├── dist/
│   ├── index.js        # ESM bundle (compiled from TypeScript)
│   └── index.css       # Extracted CSS (if any)
└── visuals/            # Static assets (auto-copied from source)
    └── logo.svg

plugin.json Requirements

The plugin.json must include:

{
  "id": "drawers.color_picker",
  "displayName": "Color Picker",
  "version": "1.0.0",
  "description": "A simple color picker tool",
  "author": "my-username",
  "category": "drawers"
}

Both id and author are required — the packager will refuse to build if either is missing.


External Dependencies (Mandatory)

The following packages are always externalized — they are provided by the host runtime and must NOT be bundled:

Package Reason
react Shared single React instance (prevents "Invalid hook call")
react-dom Same as above
lucide-react Shared icon library
@opengpex/editor/* Editor framework APIs

The pack-plugin script handles this automatically. If your plugin tries to bundle React, it will cause runtime crashes.


Asset Bundling

All subdirectories in your plugin source (excluding node_modules, dist, .git) are automatically copied into the ZIP. Directory naming is not restricted — use assets/, visuals/, icons/, media/, or any name you prefer.

Reference assets in your code via usePluginResource():

const logo = usePluginResource('visuals/logo.svg');

Namespace Protection

  • ❌ Plugin id starting with base. → packager refuses to build
  • ❌ Plugin id starting with com.gpex.plugins.base. → upload rejected
  • ✅ Dynamic loader forces sourceType: 'user' on all uploaded plugins

Distribution Channels

Channel Method
GPEX Hub Upload ZIP via the Hub interface (coming soon)
Direct share Send ZIP file; recipient uploads via Settings > Plugins
Git repository Clone and place in plugins/user/ for static development

Installation (User Side)

  1. Download the .zip file
  2. Open the editor → GPEX Hub panel → Installed tab → Upload Plugin
  3. Select the ZIP file
  4. Plugin appears in the appropriate slot after page reload

Style Isolation

  • Custom styles go in index.css (automatically extracted by packager)
  • Must use scoped class names or CSS modules — global tag selectors are forbidden
  • The plugin inherits the editor's dark/light theme via CSS custom properties

Next Steps


Last updated: 2026-07-30