Skip to content

Creating Custom Modules ​

Debby's modular architecture allows you to create custom debugging modules that integrate seamlessly with the built-in modules. Custom modules can display any information or provide any functionality you need during development and testing.

Overview ​

A custom module is a class that extends DebbyModule and provides its own UI and functionality. Custom modules:

  • Appear in the Debby sidebar alongside built-in modules
  • Can use all Debby UI controls for consistent styling (or build your own!)
  • Can be registered any time after Debby initialization
  • Support both Desktop and Mobile layout modes
    • Note: It's up to you to make sure your layout is responsive and works across all screen sizes you need to support.

Creating a Custom Module ​

Basic Structure ​

To create a custom module, extend the DebbyModule class and implement the required abstract members:

csharp
using Debology.Debby.Modules;
using Debology.Debby.Elements;
using UnityEngine;
using UnityEngine.UIElements;

public class MyCustomModule : DebbyModule
{
    // Required: The name displayed in the sidebar
    public override string Name => "My Module";

    // Required: USS class for the button icon (use "module-button--custom" for custom modules)
    public override string ButtonClass => "module-button--custom";

    // Required: Create and return the module's UI
    protected override VisualElement OnModuleCreate()
    {
        var root = new ScrollView();

        // Add your UI elements here
        var category = new DebbyCategory("MY CATEGORY");
        root.Add(category);

        var button = new DebbyButton("Click Me", DebbyIcon.Play);
        button.clicked += () => Debug.Log("Button clicked!");
        category.Add(button);

        return root;
    }
}

Registering Your Module ​

Register your custom module after Debby has been initialized:

csharp
using UnityEngine;
using Debology.Debby;

public class GameManager : MonoBehaviour
{
    void Start()
    {
        // Ensure Debby is initialized first
        if (!Debby.IsInitialized)
        {
            Debby.Initialize();
        }

        // Register your custom module
        Debby.RegisterCustomModule<MyCustomModule>();

        // Or register with an instance
        var myModule = new MyCustomModule();
        Debby.RegisterCustomModule(myModule);
    }
}

Module Lifecycle ​

The DebbyModule base class provides several lifecycle methods you can override:

OnModuleCreate() ​

csharp
protected abstract VisualElement OnModuleCreate();

Called: Once, the first time the module window is opened.

Purpose: Create and return the root visual element for your module's UI. This is where you build your module's interface.

Important: This method is only called once. The returned element is cached and reused.

csharp
protected override VisualElement OnModuleCreate()
{
    var root = new VisualElement();
    root.AddToClassList("my-module-root");

    // Build your UI
    _scrollView = new ScrollView();
    root.Add(_scrollView);

    return root;
}

OnModuleOpen() ​

csharp
protected virtual void OnModuleOpen();

Called: Every time the module window is opened.

Purpose: Refresh data, update UI, or perform any actions needed when the module becomes visible.

csharp
protected override void OnModuleOpen()
{
    // Refresh data display
    UpdateStatistics();

    // Log analytics
    Debug.Log("My module was opened");
}

OnModuleClose() ​

csharp
protected virtual void OnModuleClose();

Called: Every time the module window is closed.

Purpose: Clean up temporary resources, pause expensive operations, or save state.

csharp
protected override void OnModuleClose()
{
    // Stop expensive operations
    _isMonitoring = false;

    // Save state
    SaveModulePreferences();
}

OnModuleDestroy() ​

csharp
protected virtual void OnModuleDestroy();

Called: When Debby is destroyed via Debby.Destroy().

Purpose: Clean up resources, unregister callbacks, or perform final cleanup.

Note: Only needed if you call Debby.Destroy() explicitly.

csharp
protected override void OnModuleDestroy()
{
    // Unregister callbacks
    Application.logMessageReceived -= HandleLog;

    // Clean up resources
    _customResource?.Dispose();
}

OnLiveReload() ​

csharp
protected internal virtual void OnLiveReload();

Called: When USS/UXML files are modified during runtime (development only).

Purpose: Reload your custom UI if you're working with custom USS/UXML files.

Note: Only needed if you have custom USS/UXML assets and want hot-reloading during development.

csharp
protected internal override void OnLiveReload()
{
    // Rebuild UI with updated styles
    if (IsCreated)
    {
        Root.Clear();
        BuildUI();
    }
}

Module Properties ​

Name (Required) ​

csharp
public override string Name => "My Module";

The display name shown in the sidebar and module title.

ButtonClass (Required) ​

csharp
public override DebbyIcon Icon => DebbyIcon.Fire;

The icon displayed in the sidebar button.

DesktopDefaultSize ​

csharp
protected internal override Vector2Int DesktopDefaultSize => new(1200, 800);

The starting size when the module is opened in Desktop layout mode.

Default: (1920, 1080)

DesktopMinSize ​

csharp
protected internal override Vector2Int DesktopMinSize => new(600, 400);

The minimum size the module window can be resized to in Desktop layout mode.

Default: (960, 540)

IsOpened ​

csharp
public bool IsOpened { get; }

Returns true if the module is currently opened and showing. Read-only.

IsCreated ​

csharp
public bool IsCreated { get; }

Returns true if OnModuleCreate() has been called. Read-only.

Root ​

csharp
internal VisualElement Root { get; }

The root visual element returned by OnModuleCreate(). Available after the module is created.

Building the UI ​

Using Debby Elements ​

Debby provides a comprehensive set of UI elements designed for debugging interfaces. These elements maintain visual consistency and follow Debby's design language.

See Elements for complete documentation of all available elements.

Organizational Elements ​

csharp
// Category - top-level horizontal container with title
var category = new DebbyCategory("PLAYER STATS");
root.Add(category);

// Group - vertical container within a category
var group = new DebbyGroup("Health");
category.Add(group);

Control Elements ​

csharp
// Button with icon
var button = new DebbyButton("Respawn Player", DebbyIcon.Refresh);
button.clicked += () => RespawnPlayer();
category.Add(button);

// Toggle switch
// You can optionally use an AdjustableValue<T> to avoid manually registering callbacks.
var godMode = new AdjustableValue<bool>();

var toggle = new DebbyToggle("God Mode");
godMode.BindTwoWay(toggle);
category.Add(toggle);

// Text field
var textField = new DebbyTextField("Player Name");
textField.RegisterValueChangedCallback(evt => SetPlayerName(evt.newValue));
category.Add(textField);

// Int slider
var healthSlider = new DebbyIntSlider("Health", 0, 100);
healthSlider.RegisterValueChangedCallback(evt => SetHealth(evt.newValue));
category.Add(healthSlider);

// Float slider
var speedSlider = new DebbyFloatSlider("Speed", 0f, 10f, 0.1f);
speedSlider.RegisterValueChangedCallback(evt => SetSpeed(evt.newValue));
category.Add(speedSlider);

Using UXML ​

For complex layouts, you can use UXML files:

csharp
protected override VisualElement OnModuleCreate()
{
    var asset = Resources.Load<VisualTreeAsset>("MyModule/MyModuleLayout");
    var root = asset.CloneTree();

    // Query elements
    _container = root.Q<ScrollView>("Container");
    _statusLabel = root.Q<Label>("StatusLabel");

    return root;
}

Accessing Other Modules ​

You can access other Debby modules from your custom module:

csharp
public class MyCustomModule : DebbyModule
{
    private IAdjustModule _adjustModule;
    private IConsoleModule _consoleModule;

    protected override VisualElement OnModuleCreate()
    {
        // Get references to other modules
        _adjustModule = Debby.Adjust;
        _consoleModule = Debby.Console;

        var root = new ScrollView();

        var button = new DebbyButton("Log Message", DebbyIcon.Console);
        button.clicked += () =>
        {
            _consoleModule.PushLogMessage("Custom module message", LogType.Log);
        };

        root.Add(button);
        return root;
    }
}

Example ​

See the Notepad Example for a working example of a custom module.