Creating Your First Plugin

This walkthrough builds a complete Spark plugin from scratch. By the end, you will have a working plugin with a database entry, a scene entity, a command, an event, and a tab in the Spark Editor.

We will build a generic plugin called MyPlugin that you can adapt to any purpose.

Step 1: Create the Folder Structure

Inside your project, create the following folder structure:

Assets/MyPlugins/MyPlugin/
    Editor/
        Scripts/
    Runtime/
        Scripts/
            API/
            Data/
            Components/
            Events/
            Commands/
            Persistence/
        Resources/
            MyPluginData/

This follows the standard Spark plugin layout. Runtime/ holds gameplay code, Editor/ holds editor-only code, and Resources/MyPluginData/ is where database entries will be stored.

Step 2: Create Assembly Definitions

Create two assembly definition files:

Runtime/Spark.MyPlugin.asmdef

Editor/Spark.MyPlugin.Editor.asmdef

Step 3: Define the Plugin Interface

Create the interface that other plugins will use to access your plugin's functionality.

Runtime/Scripts/API/IMyPlugin.cs

Keep the interface focused on read operations. Actions that modify state should go through commands.

Step 4: Create the Database Entry

This is the data type that appears in the Spark Editor.

Runtime/Scripts/Data/MyPluginEntry.cs

The [Section] attribute creates collapsible groups in the Spark Editor's inspector. The [SerializeField] private pattern with public getters is the standard Spark convention for entry fields.

Step 5: Define Events

Events notify other systems when something happens in your plugin.

Runtime/Scripts/Events/MyPluginValueChangedEvent.cs

Step 6: Define Commands and Handlers

Commands are the actions your plugin supports. Handlers contain the logic.

Runtime/Scripts/Commands/ModifyMyPluginValueCommand.cs

Runtime/Scripts/Commands/ModifyMyPluginValueCommandHandler.cs

The handler follows the standard pattern: validate inputs, apply state changes, publish events.

Step 7: Create the Scene Entity

This MonoBehaviour goes on a character's GameObject to track plugin data at runtime.

Runtime/Scripts/Components/MyPluginTrackerEntity.cs

Step 8: Implement the Plugin Class

This ties everything together. The plugin class registers itself with Spark and registers its command handlers with the network provider.

Runtime/Scripts/API/MyPluginImplementation.cs

Step 9: Create the Plugin Manifest

The manifest tells the Spark Editor about your plugin. Create a ScriptableObject asset:

  1. In Unity, right-click in your Editor folder.

  2. Select Create > Spark > Plugin Manifest (or create a PluginManifest ScriptableObject).

  3. Fill in the fields:

    • Plugin Name: MyPlugin

    • Unique ID: myplugin

    • Version: 1.0.0

    • Author: Your Name

    • Folder Name: MyPlugin

  4. Add a Category called "My Plugin" with a tab:

    • Tab ID: myplugin_tab

    • Display Name: My Plugin

    • Asset Type: Select MyPluginEntry

    • Path: The Resources path where entries are stored

    • Tab Type: Database

This creates a "My Plugin" tab in the Spark Editor where users can create and manage entries.

Step 10: Using Your Plugin

Once everything is set up, here is how you use the plugin from other code:

What You Have Built

Your plugin now has:

  • A plugin interface (IMyPlugin) for other plugins to access

  • A database entry type (MyPluginEntry) editable in the Spark Editor

  • An event (MyPluginValueChangedEvent) that fires on data changes

  • A command (ModifyMyPluginValueCommand) for modifying values

  • A command handler that validates, applies changes, and publishes events

  • A scene entity (MyPluginTrackerEntity) that stores data per character

  • A plugin class that registers everything at startup

  • A manifest that adds a tab to the Spark Editor

This follows the exact same patterns used by Spark's built-in plugins. From here, you could add save data persistence, custom trigger types, requirement types, and extensions to other plugins' entries.

Next Steps

Last updated

Was this helpful?