Custom Actions

Pulse comes with a default set of built-in actions, which are the building blocks that run modular rigging code. Adding custom actions is easy and essential to custom rigging functionality.

Registering Action Packages

Actions are found by recursively searching a python package for BuildAction subclasses. Beyond the default pulse.builtin_actions, you can add other action packages to search using the BuildActionPackageRegistry:

from pulse.core import BuildActionPackageRegistry
import my_pulse_actions

BuildActionPackageRegistry.get().add_package(my_pulse_actions)

In the above example, my_pulse_actions is a package with as many subpackages and submodules as you want. An example structure might include sub-packages for organization, and one module per action:

my_pulse_actions/
  __init__.py
  first_group/
    __init__.py
    my_action_a.py
    my_action_b.py
  second_group/
    __init__.py
    my_action_c.py
    my_action_d.py

As long as all modules are at least imported in the package, they and all BuildAction subclasses inside them will be found. You can import all actions recursively to the root of the package with import_all_submodules(). This allows any new actions to automatically be picked up without having to individually import them:

# my_pulse_actions/__init__.py
from pulse.core import import_all_submodules

# equivalent to:
#   import first_group.my_action_a
#   import first_group.my_action_b
#   import second_group.my_action_c
#   import second_group.my_action_d
import_all_submodules(__name__)

Implementing Actions

Actions are as simple as executing a single function when it’s their turn. Each action can expose as many attributes as needed for the user to custom how individual action instances behave, such as what nodes to affect or which settings to use for an operation.

Subclass BuildAction, set an id, and implement the run() method:

from pulse.core import BuildAction, BuildActionError
from pulse.core import BuildActionAttributeType as AttrType


class MyAction(BuildAction):
    """
    An example action that logs some info.
    """

    id = 'MyStudio.MyAction'
    display_name = 'My Action'
    color = [.8, .4, .6]
    category = 'Custom'
    attr_definitions = [
        dict(name='myName', type=AttrType.STRING, value='Hello World'),
        dict(name='myNode', type=AttrType.NODE, description="A node attribute."),
        dict(name='myOption', type=AttrType.OPTION, value=1, options=['A', 'B', 'C']),
    ]

    def run(self):
        self.logger.info(f'My Name: {self.myName}')
        self.logger.info(f'My Node: {self.myNode}')
        self.logger.info(f'My Option: {self.myOption}')

Custom Action Editor Forms

TODO