Quickstart
Build your first Orbis plugin in 5 minutes
Quickstart
Build your first Orbis plugin in 5 minutes using the Orbis SDK. This tutorial walks you through creating a simple “Hello World” plugin with interactive UI and server-side logic.
What You’ll Build
A plugin that:
- Displays a greeting message with customizable name
- Has server-side state management
- Counts button clicks using API routes
- Shows dynamic UI updates
Prerequisites
Ensure you have completed the Installation guide and have the Orbis development environment set up.
Step 1: Create the Project
# Create a new Rust library project
cargo new --lib quick-start-plugin
cd quick-start-plugin Step 2: Configure Cargo.toml
[package]
name = "quick-start-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" # Optimize for size
lto = true # Link-time optimization
strip = true # Strip symbols
codegen-units = 1 # Single codegen unit
panic = "abort" # Abort on panic Step 3: Write the Plugin Code
Create src/lib.rs:
use orbis_plugin_api::sdk::prelude::*;
use serde_json::json;
// Initialize the plugin with zero boilerplate
orbis_plugin!();
/// Get personalized greeting
fn get_greeting_impl(ctx: Context) -> Result<Response> {
// Get name from query parameter or use "World"
let name = ctx.query_param("name").unwrap_or("World");
log::info!("Greeting requested for: {}", name);
Response::json(&json!({
"message": format!("Hello, {}!", name),
}))
}
/// Increment click counter
fn increment_count_impl(_ctx: Context) -> Result<Response> {
// Get current count
let count: i32 = state::get("count")?.unwrap_or(0);
let new_count = count + 1;
// Save new count
state::set("count", &new_count)?;
log::info!("Count incremented to: {}", new_count);
Response::json(&json!({
"count": new_count,
"message": format!("Clicked {} times!", new_count)
}))
}
// Export handlers for FFI
wrap_handler!(get_greeting, get_greeting_impl);
wrap_handler!(increment_count, increment_count_impl); Step 4: Create the Manifest
Create manifest.json:
{
"name": "quick-start-plugin",
"version": "1.0.0",
"description": "A simple greeting plugin with click counter",
"author": "You",
"license": "MIT",
"min_orbis_version": "1.0.0",
"wasm_entry": "quick_start_plugin.wasm",
"routes": [
{
"path": "/greeting",
"method": "GET",
"handler": "get_greeting"
},
{
"path": "/increment",
"method": "POST",
"handler": "increment_count"
}
],
"pages": [
{
"id": "greeting-page",
"title": "Quick Start",
"icon": "waves",
"route": "/hello",
"state": {
"name": {
"type": "string",
"default": "World"
},
"count": {
"type": "number",
"default": 0
},
"message": {
"type": "string",
"default": ""
}
},
"sections": [
{
"type": "Container",
"className": "flex items-center justify-center bg-gradient-to-br from-purple-500 to-pink-500",
"children": [
{
"type": "Card",
"className": "p-8 shadow-2xl max-w-md w-full",
"content": {
"type": "Container",
"className": "flex flex-col space-y-4",
"children": [
{
"type": "Text",
"content": "Hello, {{state.name}}!",
"className": "text-4xl font-bold text-center mb-2"
},
{
"type": "Text",
"content": "Clicks: {{state.count}}",
"className": "text-center text-gray-600 mb-6"
},
{
"type": "Field",
"fieldType": "text",
"placeholder": "Enter your name",
"defaultValue": "{{state.name}}",
"bindTo": "name"
},
{
"type": "Button",
"label": "Click Me!",
"className": "w-full",
"events": {
"on_click": [
{
"type": "call_api",
"api": "plugin.increment_count",
"method": "POST",
"on_success": [
{
"type": "update_state",
"path": "count",
"from": "$response.body.count"
},
{
"type": "show_toast",
"message": "{{$response.body.message}}",
"level": "success",
"title": "Counter Updated",
"duration": 3000
}
]
}
]
}
}
]
}
}
]
}
]
}
]
}
Step 5: Build the Plugin
# Build WASM binary
cargo build --target wasm32-unknown-unknown --release
# Output will be at:
# target/wasm32-unknown-unknown/release/quick_start_plugin.wasm Build optimization: The [profile.release] settings reduce binary size from ~2MB to ~200KB.
Step 6: Install the Plugin
# Create the plugin directory
mkdir -p ./orbis/src-tauri/plugins/quick-start-plugin
# Copy WASM binary and manifest
cp target/wasm32-unknown-unknown/release/quick_start_plugin.wasm ./orbis/src-tauri/plugins/quick-start-plugin/
cp manifest.json ./orbis/src-tauri/plugins/quick-start-plugin/
# Or use custom plugin directory
export ORBIS_PLUGINS_DIR=/path/to/plugins
cp target/wasm32-unknown-unknown/release/quick_start_plugin.wasm $ORBIS_PLUGINS_DIR/quick-start-plugin/
cp manifest.json $ORBIS_PLUGINS_DIR/quick-start-plugin/ Step 7: Run Orbis
# From the orbis project root
cd orbis
bun run tauri dev Navigate to the “Quick Start” page in the sidebar. You should see:
- A greeting with your custom name
- An input to change the name
- A button that increments the counter
- Toast notifications on each click
Understanding the Code
Zero-Boilerplate Initialization
The orbis_plugin!() macro handles all FFI (Foreign Function Interface) setup:
orbis_plugin!(); // Expands to:
// - init() function
// - allocate/deallocate memory management
// - execute() dispatcher
// - All extern declarations for host functions Type-Safe Handler Wrapping
The wrap_handler! macro eliminates manual FFI:
pub fn get_greeting_impl(ctx: Context) -> Result<Response> {
// Your business logic here
}
wrap_handler!(get_greeting, get_greeting_impl);
// Expands to FFI-compatible export with:
// - Request parsing from memory
// - Error handling
// - Response serialization Context API
The Context provides request data:
ctx.query_param("name") // Get query parameter
ctx.query_param_as::<i32>("id") // Parse as type
ctx.body_as::<MyStruct>() // Deserialize body Response Builders
Convenient response creation:
Response::json(&data) // JSON response
Response::text("Hello") // Plain text
Response::new(200, "OK", json!({})) // Custom response State Management
Type-safe persistent state:
state::get::<i32>("count") // Get typed value
state::set("count", 42) // Set value
state::delete("count") // Remove value Next Steps
Now that you’ve built your first plugin, explore:
Plugin Development
- WASM Plugins - Full SDK reference with advanced examples
- Building Plugins - Build optimization and packaging
- Testing Plugins - Testing strategies
SDK Features
- Database Access - Query and execute SQL
- HTTP Requests - Make external API calls
- Logging - Debug and monitoring
- Permissions - Security and access control
UI Development
- Schema System - Deep dive into UI schemas
- Components - All available components
- Actions - All action types
- State & Expressions - Dynamic UI patterns
Complete Example
For a production-ready example with database access and HTTP requests, see the TODO Plugin in the repository.
On This Page
- What You’ll Build
- Prerequisites
- Step 1: Create the Project
- Step 2: Configure Cargo.toml
- Step 3: Write the Plugin Code
- Step 4: Create the Manifest
- Step 5: Build the Plugin
- Step 6: Install the Plugin
- Step 7: Run Orbis
- Understanding the Code
- Zero-Boilerplate Initialization
- Type-Safe Handler Wrapping
- Context API
- Response Builders
- State Management
- Next Steps
- Plugin Development
- SDK Features
- UI Development
- Complete Example