Plugin Development Overview

Getting started with Orbis plugin development

What Are Plugins?

Plugins are self-contained modules that extend Orbis functionality. They can:

  • Add new pages to the application
  • Define custom API routes
  • Execute backend logic in WASM
  • Store and retrieve data
  • Communicate with other plugins

Plugin Types

1. Manifest-Only Plugins

The simplest plugin type. Just a manifest file defining UI pages:

text
my-plugin/
└── manifest.json

Best for:

  • Dashboard pages
  • Static content
  • Simple interactive UIs
  • Prototyping

2. WASM Plugins

Full-featured plugins with backend execution:

text
my-plugin/
├── manifest.json
├── Cargo.toml
├── src/lib.rs
└── target/wasm32-unknown-unknown/release/my_plugin.wasm

Best for:

  • Complex business logic
  • Data processing
  • External API integration
  • Custom algorithms

Quick Start

Orbis supports two types of plugins:

  1. Manifest-only plugins - Pure UI with no server logic (simple dashboards, reports)
  2. WASM plugins - Full-featured with server-side logic using the Orbis SDK

Option 1: Minimal Manifest Plugin

For simple UI-only plugins, create plugins/hello/manifest.json:

json
{
  "name": "hello",
  "version": "1.0.0",
  "description": "Hello World plugin",
  "pages": [
    {
      "route": "/hello",
      "title": "Hello World",
      "icon": "Hand",
      "sections": [
        {
          "type": "Container",
          "className": "p-6",
          "children": [
            {
              "type": "Heading",
              "level": 1,
              "text": "Hello, World!"
            },
            {
              "type": "Text",
              "content": "This is my first Orbis plugin."
            }
          ]
        }
      ]
    }
  ]
}

Option 2: WASM Plugin with SDK

For plugins with server logic, API routes, state management, etc., use the Orbis SDK:

1. Create Project:

bash
cargo new --lib my-plugin
cd my-plugin

2. Add Dependencies (Cargo.toml):

toml
[package]
name = "my-plugin"
version = "1.0.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
orbis-plugin-api = { path = "../../crates/orbis-plugin-api" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[profile.release]
opt-level = "s"
lto = true

3. Write Plugin (src/lib.rs):

rust
use orbis_plugin_api::sdk::prelude::*;
use serde_json::json;

orbis_plugin!();

pub fn get_greeting_impl(ctx: Context) -> Result<Response> {
    let name = ctx.query_param("name").unwrap_or("World");
    Ok(Response::json(&json!({
        "message": format!("Hello, {}!", name)
    })))
}

wrap_handler!(get_greeting, get_greeting_impl);

4. Create Manifest:

json
{
  "name": "my-plugin",
  "version": "1.0.0",
  "wasm_entry": "my_plugin.wasm",
  "routes": [
    { "path": "/greeting", "handler": "get_greeting" }
  ],
  "pages": [
    {
      "route": "/my-plugin",
      "title": "My Plugin",
      "sections": [
        {
          "type": "Container",
          "children": [
            { "type": "Text", "content": "{{state.message}}" }
          ]
        }
      ]
    }
  ]
}

5. Build:

bash
cargo build --target wasm32-unknown-unknown --release
# Output: target/wasm32-unknown-unknown/release/my_plugin.wasm

See the WASM Plugins guide for the complete SDK reference.

That’s it! Place it in the plugins/ directory and restart Orbis.

Plugin File Structure

text
my-plugin/
├── manifest.json          # Required: plugin metadata and config
├── README.md              # Recommended: documentation
├── CHANGELOG.md           # Recommended: version history

├── src/                   # WASM plugin source (if applicable)
│   └── lib.rs
├── Cargo.toml             # WASM plugin dependencies

├── assets/                # Static assets (optional)
│   ├── icon.svg
│   └── styles.css

└── tests/                 # Plugin tests (optional)
    └── integration.rs

Development Workflow

1. Create Plugin Directory

bash
mkdir -p plugins/my-plugin
cd plugins/my-plugin

2. Write Manifest

Create manifest.json with your plugin configuration.

3. Test Iteratively

Run Orbis in development mode for hot reload:

bash
cd orbis
bun run tauri dev

Changes to manifest files are picked up automatically.

4. Add WASM (Optional)

If you need backend logic:

bash
cargo init --lib
# Edit Cargo.toml for WASM target
cargo build --target wasm32-unknown-unknown --release

5. Build for Distribution

Package your plugin:

bash
# As a ZIP
zip -r my-plugin.zip manifest.json my_plugin.wasm

# Or with embedded manifest
python3 add_custom_section.py my_plugin.wasm -s manifest < manifest.json

Key Concepts

Pages

Pages are the UI entry points. Each page has:

  • A unique route in the application
  • Its own state store
  • A layout defined by component schemas

See Page Definitions.

State

Each page has reactive state that drives the UI:

json
{
  "state": {
    "count": { "type": "number", "default": 0 }
  }
}

State is accessed via expressions: {{state.count}}

Actions

Actions respond to user events:

json
{
  "events": {
    "on_click": [
      { "type": "update_state", "path": "count", "from": "{{state.count + 1}}" }
    ]
  }
}

Components

35+ built-in components for building UIs:

  • Layout: Container, Flex, Grid
  • Typography: Text, Heading
  • Forms: Form, Field
  • Data: Table, List, Card
  • Navigation: Button, Link, Tabs
  • And more…

Example Plugins

Counter Plugin

json
{
  "name": "counter",
  "version": "1.0.0",
  "pages": [
    {
      "route": "/counter",
      "title": "Counter",
      "icon": "Hash",
      "state": {
        "count": { "type": "number", "default": 0 }
      },
      "sections": [
        {
          "type": "Flex",
          "direction": "column",
          "align": "center",
          "gap": "1rem",
          "className": "p-6",
          "children": [
            {
              "type": "Heading",
              "level": 1,
              "text": "Count: {{state.count}}"
            },
            {
              "type": "Flex",
              "gap": "0.5rem",
              "children": [
                {
                  "type": "Button",
                  "label": "-",
                  "variant": "outline",
                  "events": {
                    "on_click": [
                      { "type": "update_state", "path": "count", "from": "{{state.count - 1}}" }
                    ]
                  }
                },
                {
                  "type": "Button",
                  "label": "+",
                  "events": {
                    "on_click": [
                      { "type": "update_state", "path": "count", "from": "{{state.count + 1}}" }
                    ]
                  }
                }
              ]
            },
            {
              "type": "Button",
              "label": "Reset",
              "variant": "ghost",
              "events": {
                "on_click": [
                  { "type": "update_state", "path": "count", "value": 0 }
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}

Todo List Plugin

See the full example in the repository.

Next Steps