disguise developers

Designer Plugins

Plugins for Disguise Designer software.

Python Plugin

The designer-plugin library lets you execute Python code remotely on Disguise Designer. Define your plugin methods locally, connect to a Designer instance, and call those methods as if they were running on your machine. The library handles all the HTTP communication, sending your code to Designer’s Python API and returning the results.

Since Designer’s runtime uses Python 2.7, the library also converts your Python 3 code automatically, transforming f-strings, type hints, and other modern syntax so you can write clean, modern Python without worrying about compatibility.

Code executed on Designer runs under Python 2.7. While the library converts common Python 3 syntax automatically, some features may not be supported. Write and test your plugin code with this in mind.


Installation

Install the designer-plugin package before running any examples.

pip install designer-plugin

Requires Python 3.11 or later on the client (local) machine.

Python Stub for Designer Object (Optional)

To enable IDE autocomplete and type checking for Designer’s Python API, install the stub file package:

pip install designer-plugin-pystub

Once installed, import the stubs in your local (client-side) code:

from designer_plugin.pystub import *

The wildcard import makes all Designer type hints available at once, which is the intended usage for a stub package.

This provides type hints for Designer objects like resourceManager, Screen2, Path, and more. See the Python API for the full list of available classes and methods.

The pystub package provides type hints only. These objects are client-side proxies that hold no data. They only exist in Designer’s runtime. See Limitation for details.


How It Works

Here’s a simple example that prints “Hello World!” to the Designer console:

Using the Client API, you define a class that inherits from D3PluginClient:

from designer_plugin.d3sdk import D3PluginClient

class MyPlugin(D3PluginClient):
    def hello_world(self):
        print("Hello World!")

plugin = MyPlugin()

with plugin.session('localhost'):
    plugin.hello_world()

When you call a method on your plugin, the library sends your code to Designer via HTTP. Designer executes the code using its Python API and returns any output or return values back to your local session.

From your perspective, you’re just calling Python methods. The HTTP communication, serialisation, and response handling are all managed behind the scenes.

Two Ways to Write Plugins

APIDescriptionBest For
Client APIClass-based approach. Inherit from D3PluginClient and all methods become remotely executable. Supports function chaining.Related methods that share state, OOP-style plugins
Functional APIDecorator-based approach using @d3function and @d3pythonscript. Explicit control over what gets sent and when.Standalone scripts, mixing plugin code with other logic

Both approaches support synchronous and asynchronous execution.


Limitation

Object types imported from designer_plugin.pystub (such as Screen2, Camera, Path) only live in Designer’s runtime. They cannot be used directly on the client side. You cannot receive one of these objects as a return value and call methods on it in your local Python script.

with my_plugin.session('localhost'):
    surface = my_plugin.get_surface("surface 1")  # Returns a Screen2 on Designer
    surface.rename(...)  # This will fail. Surface is not a real object on the client

To work around this, use function chaining: define a method that calls another method within the same D3PluginClient class. Because all chained methods execute on the Designer side, Designer objects can be passed between them freely.

class MyPlugin(D3PluginClient):
    def get_surface(self, surface_name: str) -> Screen2:
        return resourceManager.load(Path(f'objects/screen2/{surface_name}.apx'), Screen2)

    def rename_surface(self, surface_name: str, new_name: str) -> None:
        surface: Screen2 = self.get_surface(surface_name)  # Chained. Runs on Designer
        surface.rename(surface.path.replaceFilename(new_name))

If you need data from a Designer object on the client side, return a serializable value (e.g. a string or number) instead of the object itself:

def get_surface_uid(self, surface_name: str) -> str:
    surface: Screen2 = resourceManager.load(...)
    return str(surface.uid)  # Returns a plain string to the client

Enable Logging

By default, designer_plugin logging is disabled. To enable it:

import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger('designer_plugin').setLevel(logging.DEBUG)

Next Steps

When you need detailed API information, the Client API, Functional API, and Reference pages cover everything in depth. For worked examples, see the Examples in the Client API reference.