Docs Parameters
CustomParTools
Promote parameters to a parent with binds or expressions, customize name/label/range on drop, plus extension creation, parent shortcuts, parameter clearing and IOP promotion. Also carries four stock-TouchDesigner shortcuts for opening parameters and the COMP editor.
◎ Parameters
Shortcuts
Global — they fire anywhere in TouchDesigner. Shortcuts scoped to a single panel are a local control scheme and are not listed here.
- Alt+\
- Alt+X
- Ctrl+Alt+\
- Ctrl+Alt+Q
- Ctrl+Alt+W
- Shift+Alt+Q
- Shift+Alt+W
- Shift+Alt+X
CustomPar Tools
This button is a quick way to manipulate Custom Parameters of a parent component. It is also added for each pane!
- Drag-and-Drop onto the icon:
- A Parameter: Promote that Parameter to the Parent Custom Params and Bind/Reference automatically (always to the currently active/selected page).
- Hold
Ctrlto customize parameter promotion—name it, set min/max values, and tweak clamping.LabelandParNamefor all params, and for slider-type params:min,maxvalues,clampingtickboxes, anddefaultvalue- Quickly jump between text fields by pressing
TabandShift+Tab
- Hold
- A Table DAT: adds a new ParMenu and sets the table as a menu source
- A COMP: Promote all Custom Parameters of the dragged COMP to the Parent Custom Params and Bind/Reference automatically.
- A Parameter: Promote that Parameter to the Parent Custom Params and Bind/Reference automatically (always to the currently active/selected page).
- LeftClick: Opens Parent Parameters.
- Shift-LeftClick: Opens Selected OP Parameters.
- RightClick: Opens Parent Component Editor.
- Shift-RightClick: Opens Selected OP Component Editor.
- Alt-LeftClick (Cmd+LeftClick for Mac): Runs ClearPars on the selected COMP — any parameter left in
Bindmode with no valid bind master, or inExpressionmode whose expression currently raises, is switched toConstantmode (dropping the dangling bind/expression), and the COMP's script errors are cleared too. Recursive into the COMP's immediate children (excluding annotations) — usually useful after copying a COMP from another project - Ctrl+Alt+Drag an OP (Ctrl+Cmd+Drag on Mac): Promote as
iopto parent - Ctrl+Shift+Click: Add Parent shortcut
- Shift+Alt+LeftClick (Shift+Cmd+LeftClick for Mac): Add QuickExt to parent for a streamlined python Extension workflow - see QuickExt
- MiddleClick: Collapses the selected nodes via QuickCollapse (if installed). Hold
CtrlorShiftto pop the naming dialog first.
QuickExt
See the extensive description of QuickExt.
CustomParCustomize
A fast way to customize parameter promotion—name it, set min/max values, and tweak clamping. Related to CustomParTools
LabelandParNamefor all params, and for slider-type params:min,maxvalues,clampingtickboxes, anddefaultvalue- Invoked by holding
Ctrlwhile drag-and-dropping a parameter onto thediamondbutton or a parent in the path bar - Quickly jump between text fields by pressing
TabandShift+Tab
When adding an extension using CustomParTools
Shift+Alt+LeftClick, the created default Extension will have the following available:
- Simplified default extension code
- Includes
ExtUtilswhich contains CustomParHelper and NoNode, which are also initialized in the default extension code
You can also add QuickExt to your Base COMP via the
Component Editor->Extensionsection by long-clicking onAddand selectingQuickExt
It is important that
ExtUtilsstays docked to your extension code!
By leveraging [NoNode] and [CustomParHelper], TouchDesigner developers can create more efficient, organized, and maintainable extensions, ultimately leading to smoother workflow and improved project scalability.
Pro Tip: Set your IDE's Python interpreter to that of TouchDesigner's to utilize stubs/code suggestion - ExtUtils will deploy its definition automatically!
Importing
The default extension code will contain the following - at first sight complicated looking - import statements for the utility packages. You can just ignore them, but don't remove them!
This might look complicated at first but it's just a fancy import statement to avoid any conflicts when having multiple extension classes with ExtUtils attached.
CustomParHelper: CustomParHelper = next(d for d in me.docked if 'ExtUtils' in d.tags).mod('CustomParHelper').CustomParHelper # import
NoNode: NoNode = next(d for d in me.docked if 'ExtUtils' in d.tags).mod('NoNode').NoNode # import
CustomParHelper
CustomParHelper simplifies the management of custom parameters in TouchDesigner extensions, providing an intuitive interface for accessing and manipulating parameters, implementing callbacks, and handling parameter groups.
Key Features:
- Easy parameter access as properties
- Simplified custom parameter callbacks
- Support for sequence parameters and blocks
- Parameter group (parGroups) management
- Flexible configuration for inclusion/exclusion of properties and callbacks
- Optional public/private naming conventions
- Automatic stub generation for improved IDE support
Usage examples in your extension class:
-
Make sure ExtUtils is docked to your extension
-
Import the CustomParHelper class:
CustomParHelper: CustomParHelper = next(d for d in me.docked if 'ExtUtils' in d.tags).mod('CustomParHelper').CustomParHelper # import -
Initialize in your extension's init method as follows:
CustomParHelper.Init(self, ownerComp)Full signature and optional parameters:
CustomParHelper.Init(self, ownerComp, enable_properties: bool = True, enable_callbacks: bool = True, enable_parGroups: bool = True, enable_seq: bool = True, expose_public: bool = False, par_properties: list[str] = ['*'], par_callbacks: list[str] = ['*'], except_properties: list[str] = [], except_sequences: list[str] = [], except_callbacks: list[str] = [], except_pages: list[str] = [], enable_stubs: bool = False, general_callback_enable: bool = True)Additional options:
enable_properties: If True, creates properties for custom parameters (default: True)enable_callbacks: If True, creates callbacks for custom parameters (default: True)enable_parGroups: If True, creates properties and methods for parGroups (default: True)enable_seq: If True, creates properties and methods for sequence parameters (default: True)expose_public: If True, uses capitalized property and method names (e.g., Par, Eval instead of par, eval)par_properties: List of parameter names to include in property creation, by default all parameters are includedpar_callbacks: List of parameter names to include in callback handling, by default all parameters are includedexcept_properties: List of parameter names to exclude from property creationexcept_callbacks: List of parameter names to exclude from callback handlingexcept_pages: List of parameter pages to exclude from property and callback handlingexcept_sequences: List of sequence names to exclude from property and callback handlingenable_stubs: If True, automatically creates and updates stubs for the extension (default: False) (thanks to AlphaMoonbase.berlin for Stubser)general_callback_enable: If True, enables general callbacks that catch all parameter changes (default: True)
-
Access and set custom parameters as properties (if enable_properties=True (default)):
There are two ways to access and set parameter values:
a) Using Eval properties (recommended for simple value setting):
self.eval<ParamName>: Get/set the evaluated value of the parameter# Get value value = self.evalMyparam # Set value (always sets .val regardless of parameter mode) self.evalMyparam = 5self.evalGroup<GroupName>: Get/set the evaluated value of the parameter group# Get values values = self.evalGroupXyz # Set values (always sets .val for each parameter) self.evalGroupXyz = [1, 2, 3]
b) Using Par properties (for advanced parameter control):
self.par<ParamName>: Access/set the parameter object# Get parameter object for advanced operations self.parMyparam.expr = "op('something').par.value" self.parMyparam.bindExpr = "op('other').par.value" # Set value (only works in CONSTANT or BIND modes) self.parMyparam = 5 # Ignored if parameter is in EXPRESSION modeself.parGroup<GroupName>: Access/set the parameter group object# Get parameter group for advanced operations myGroup = self.parGroupXyz # Set values (only works for parameters in CONSTANT or BIND modes) self.parGroupXyz = [1, 2, 3] # Only affects non-expression parameters
NOTE: to expose public properties, eg. self.Par
instead of self.par , set expose_public=True in the Init function -
Implement callbacks (if enable_callbacks=True (default)): a) Parameter-specific callbacks:
-
For regular parameters:
def onPar<Parname>(self, _par, _val, _prev): # _par and _prev can be omitted if not needed -
For pulse parameters:
def onPar<PulseParname>(self, _par): # _par can be omitted if not needed -
For sequence blocks:
def onSeq<SeqName>N(self, idx): -
For sequence parameters:
def onSeq<SeqName>N<Parname>(self, _par, idx, _val, _prev): # _par and _prev can be omitted if not needed -
For parameter groups if enable_parGroups=True (default):
def onParGroup<Groupname>(self, _parGroup, _val): # _parGroup can be omitted if not needed
b) General callbacks (if general_callback_enable=True (default)): These catch all parameter changes that aren't handled by specific callbacks:
-
For value changes:
def onValueChange(self, _par, _val, _prev): # Called when any parameter value changes that doesn't have a specific callback # _val and _prev can be omitted if not needed -
For pulse parameters:
def onPulse(self, _par): # Called when any pulse parameter is triggered that doesn't have a specific callback # _par can be omitted if not needed
-
NoNode
NoNode is a versatile utility class that centralizes the management of various types of executions and callbacks in TouchDesigner, eliminating the need for dedicated nodes.
Usage examples:
-
Make sure ExtUtils is docked to your extension
-
Import the NoNode class:
NoNode: NoNode = next(d for d in me.docked if 'ExtUtils' in d.tags).mod('NoNode').NoNode # import -
Initialize the NoNode system in your extension:
NoNode.Init(enable_chopexec=True, enable_datexec=True, enable_parexec=True, enable_keyboard_shortcuts=True) -
CHOP executions:
- Register a callback for CHOP value changes:
NoNode.RegisterChopExec(NoNode.ChopExecType.ValueChange, chop_op, channel_name(s), self.on_value_change_function) # callback signature: def on_value_change_function(self, channel: Channel, sampleIndex: int, val: float, prev: float): # can omit parameters from the right side of the signature if not needed - Handle CHOP state changes:
NoNode.RegisterChopExec(NoNode.ChopExecType.OffToOn, chop_op, channel_name(s), self.on_activate_function) # callback signature: def on_activate_function(self, channel: Channel, sampleIndex: int, val: float, prev: float): # can omit parameters from the right side of the signature if not needed
- Register a callback for CHOP value changes:
-
DAT executions:
- React to table changes in a DAT:
NoNode.RegisterDatExec(NoNode.DatExecType.TableChange, dat_op, self.on_table_change_function) # callback signature depends on the event type, eg.: def on_table_change_function(self, dat: DAT): - Handle cell value changes:
NoNode.RegisterDatExec(NoNode.DatExecType.CellChange, dat_op, self.on_cell_change_function) # callback signature depends on the event type, eg.: def on_cell_change_function(self, dat: DAT, cells: list[Cell], prev: Cell):
- React to table changes in a DAT:
-
Parameter executions:
- Register a callback for parameter value changes:
NoNode.RegisterParExec(NoNode.ParExecType.ValueChange, par_op, par_name, self.on_value_change_function) # callback signature depends on the event type, eg.: def on_value_change_function(self, par: Par, val: float, prev: float): # can omit prev, or use val only - Handle pulse parameters:
NoNode.RegisterParExec(NoNode.ParExecType.OnPulse, par_op, par_name, self.on_pulse_function) # callback signature: def on_pulse_function(self,par: Par): # can omit par if not needed
- Register a callback for parameter value changes:
-
Keyboard shortcuts:
- Register a keyboard shortcut:
NoNode.RegisterKeyboardShortcut('ctrl.k', self.onKeyboardShortcut) # callback signature: def onKeyboardShortcut(self):
- Register a keyboard shortcut:
-
Deregister callbacks:
- Deregister a CHOP execution:
NoNode.DeregisterChopExec(NoNode.ChopExecType.ValueChange, chop_op, channel_name(s)) - Deregister a DAT execution:
NoNode.DeregisterDatExec(NoNode.DatExecType.TableChange, dat_op) - Deregister a parameter execution:
NoNode.DeregisterParExec(NoNode.ParExecType.ValueChange, par_op, par_name) - Deregister a keyboard shortcut:
NoNode.DeregisterKeyboardShortcut('ctrl.k')
- Deregister a CHOP execution:
-
Visual indication:
- Operators with registered callbacks are marked with a color for easy identification
- Customize the mark color:
NoNode.SetMarkColor((r, g, b))
To demo all the features you can download QuickExtTest.tox and run it or just check its extension code.
TouchDesigner shortcuts
Four conveniences over TouchDesigner's own UI, by keyboard or from the command palette:
| Shortcut | Action |
|---|---|
| Shift+Alt+Q | Open the parameter dialog for the selected operator |
| Ctrl+Alt+Q | Open the parameter dialog for the current network's COMP |
| Shift+Alt+W | Open the component editor for the selected operator |
| Ctrl+Alt+W | Open the component editor for the current network's COMP |
(On macOS, Alt is Option.)
They call nothing but TouchDesigner itself, so they work regardless of which other packages are installed, and each is rebindable in FNS_HotkeyManager. Keyboard and palette share one implementation: the keyboardin callbacks invoke the same promoted methods the commands do.
These arrived from the retired MY_HOTKEYS package. Their command ids are
unchanged (opencurrentparameters, openparentparameters,
customizecurrentcomp, customizeparentcomp) but the owning tool is now
CustomParTools — so launcher history, curation and presets that referenced
MY_HOTKEYS#… need re-pointing once.
QuickParCustom
Promote and customize the parameter under the cursor, without selecting anything. Its Active toggle turns the whole feature off.
| Shortcut | On the hovered parameter |
|---|---|
alt+x |
Promote to parent (Bind). If it is already promoted, opens the promoted parameter's customization instead |
shift+alt+x |
Same, but promotes with an Expression rather than a Bind |
alt+\ |
Customize the parameter (a custom par customizes its owner COMP; otherwise the promoted owner) |
ctrl+alt+\ |
Toggle that parameter between Bind and Expression |
All four are rebindable on the Custom page of QuickParCustom, and listed in FNS_HotkeyManager.
It was a separate package until 2026-08-24. It never really was one: it drove
promotion by calling this package's promoter through the FNS_CPP global, so
installing it without CustomParTools gave you hotkeys that could not promote.
As a child it calls its parent directly.