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 the pane-bar drag-drop hijack and path-cell injection, and four stock-TouchDesigner shortcuts for opening parameters and the COMP editor.
◎ Parameters
Pane bar button
Toolbar button
Where it appears
Read off the registry hosts in the component, so this is where the tool puts itself in a default install; every one of these can be reordered or hidden from Hub.
- Pane bar buttonas PathCellClickInject · right side
Pane bar buttonas CustomParTools · right side · position 1- Pane bar buttonas HijackDragdrop · right side
Toolbar buttonposition 34
Shortcuts
Global: they fire anywhere in TouchDesigner. Shortcuts scoped to a single panel are a local control scheme and stay off this list.
- 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 import statements (complicated looking at first sight) for the utility packages. You can just ignore them, but don't remove them!
Each line is a fancy import statement that avoids any conflicts when having multiple extension classes with ExtUtils attached. It finds the ExtUtils docked to your extension, or the one beside it when the dock is missing, which is what keeps a cloned component working.
CustomParHelper: CustomParHelper = (next((d for d in me.docked if 'ExtUtils' in d.tags), None) or next((c for c in me.parent().children if 'ExtUtils' in c.tags), None)).mod('CustomParHelper').CustomParHelper # import
NoNode: NoNode = (next((d for d in me.docked if 'ExtUtils' in d.tags), None) or next((c for c in me.parent().children if 'ExtUtils' in c.tags), None)).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
- Declare parameters on the class and have them created
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), None) or next((c for c in me.parent().children if 'ExtUtils' in c.tags), None)).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, enable_parfields: 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: No longer does anything from here (default: False). Stub generation was removed fromExtUtils; the Stubser it carried was ~19 operators in every instance and nothing enabled it. The argument is kept so existing calls keep working. Generate stubs through VSCodeTools or QuickExt, which carry their own (thanks to AlphaMoonbase.berlin for Stubser)general_callback_enable: If True, enables general callbacks that catch all parameter changes (default: True)enable_parfields: If True, creates any parameters the class DECLARES before reflection runs (default: True). Harmless for a class that declares none
-
Optionally declare your parameters in code, and they get created:
class MyToolExt: def __init__(self, ownerComp): self.ownerComp = ownerComp self.Speed = CustomParHelper.Float(ownerComp, 'Speed', default=1.0, min=0, max=10, page='Settings', help='Playback speed multiplier.') self.Mode = CustomParHelper.Menu(ownerComp, 'Mode', ['fast', 'slow'], page='Settings', help='Which way the thing runs.') if ownerComp.par.Advanced.eval(): # conditionals work CustomParHelper.Int(ownerComp, 'Depth', default=3, page='Settings', help='Recursion depth.') for name in ('Alpha', 'Beta'): # so do loops CustomParHelper.Toggle(ownerComp, name, page='Flags', help='Flag %s.' % name) CustomParHelper.Init(self, ownerComp)Each call creates the parameter and returns it, so you can use it on the next line:
self.Speed.val = 5. Declaring inside__init__is what makes conditionals, loops and computed defaults ordinary Python, since the COMP exists by then.One helper per style:
FloatIntStrTogglePulseMenuStrMenuFileFolderHeaderXYZRGBRGBAOPCOMPTOPCHOPSOPDATMAT. The multi-member ones (XYZ,RGB,RGBA) return a ParGroup and take either one value for every member or a sequence:default=(0.2, 0.4, 0.6).This is additive: CustomParHelper still reflects whatever parameters it finds, so a tool that declares nothing behaves exactly as before, and you can mix declared and hand-made parameters freely. There is no base class to inherit.
Declare before
CustomParHelper.Init, so the new parameters get properties and callbacks in the same pass. A parameter added by hand afterInithas no property until something refreshes it; a declared one cannot drift.Which page? The
pagekeyword,page='Settings'above. It is the page NAME, created if it does not exist, and it defaults to'Custom'.Every other keyword is a TouchDesigner
Parmember, set straight through:default,label,help,readOnly,startSection,min,max,clampMin,clampMax,normMin,normMax,menuNames,menuLabels,order. They keep TouchDesigner's own names: see Par Class for what each does and which styles honour it.A static alternative. If the parameter set never varies you can declare on the class body instead, and
Initcreates them:class MyToolExt: Speed = CustomParHelper.ParFloat(default=1.0, page='Settings', help='Playback speed multiplier.') def __init__(self, ownerComp): CustomParHelper.Init(self, ownerComp)It cannot do conditionals or loops and it cannot hand you the parameter, because a class body runs before there is any COMP to create one on.
self.Speedstill resolves to the real Par onceInithas run, and raises a message explaining itself if you touch it before that. Both forms use the same code underneath, so they behave identically once the parameter exists.Three things worth knowing:
- A new parameter is seeded with its default; an existing one keeps its value.
The first time a declaration creates a parameter it is set to the declared
default. After that, re-initializing refreshes label, help, range and menu entries and leaves the value alone, whatever you or the saved project put there. - A style change is applied for you. Declaring
ParStrover an existing Float rebuilds the parameter and carries across its value, expression, bind expression and position on the page. The one thing that cannot survive is an export: that link belongs to the exporting CHOP and lives outside the parameter, so it is reported in the textport and you re-export it. helpis strongly expected but not enforced. Omitting it logs a warning and your extension keeps working. Fill it in: it is the tooltip your users get when they hover the parameter name.
- A new parameter is seeded with its default; an existing one keeps its value.
The first time a declaration creates a parameter it is set to the declared
-
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
-
Naming the handler yourself
Every callback above is found by its NAME. If you would rather name the method for what it does, declare which parameter it handles:
class MyToolExt:
def __init__(self, ownerComp):
self.ownerComp = ownerComp
CustomParHelper.Init(self, ownerComp) # harvests the declarations
@CustomParHelper.onPar('Speed')
def playbackSpeedChanged(self, _par, _val, _prev):
...
@CustomParHelper.onPar('Reset') # a Pulse parameter
def clearEverything(self, _par):
...
@CustomParHelper.onParGroup('Translate')
def moved(self, _parGroup, _val):
...
Six decorators, one per callback kind: onPar (value change, or pulse for a
Pulse parameter), onParGroup, onSeq(sequence, par), onSeqBlock(sequence),
onAnyValueChange() and onAnyPulse() for the two general callbacks.
Init harvests them, so there is no extra call and no change to your Init
signature. Signatures and arity are exactly as documented above; the
decorator records which parameter the method handles and returns the method
untouched, so you can still omit _val and _prev from the right.
Two things the naming convention cannot do:
- A declaration that names a parameter you do not have is reported. With
the convention a mistyped
onParSpeeedis simply a method that never runs and never complains. It is logged, so one bad declaration should not stop a tool loading. - A collision is reported too. If the class already defines
onParSpeedand something else declares@onPar('Speed'), the real method wins and the declaration is reported as ignored, so nothing silently shadows working code.
Declared and conventionally-named callbacks work side by side on the same extension; use whichever reads better per parameter.
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), None) or next((c for c in me.parent().children if 'ExtUtils' in c.tags), None)).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))
Declaring callbacks on the method
The Register* calls above are one way to wire a callback. The other is to
declare it on the method itself and let NoNode collect them:
class MyToolExt:
def __init__(self, ownerComp):
self.ownerComp = ownerComp
NoNode.Init(ownerComp, enable_chopexec=True, enable_parexec=True)
NoNode.HarvestCallbacks(self) # registers everything below
@NoNode.onChopExec(NoNode.ChopExecType.ValueChange, 'null_audio', 'chan1')
def audioMoved(self, channel, sampleIndex, val, prev):
...
@NoNode.onParExec(NoNode.ParExecType.ValueChange, 'null_hk', 'Shift')
def shiftChanged(self, par, val, prev):
...
@NoNode.onKeyboardShortcut('ctrl.k')
def quickAction(self):
...
@NoNode.onChopExec, @NoNode.onDatExec, @NoNode.onParExec and
@NoNode.onKeyboardShortcut take the same arguments as their Register*
counterparts, minus the callback itself. Signatures are unchanged; arity is
still inferred, so you can still drop arguments off the right.
Targets are strings, resolved when HarvestCallbacks runs, relative to the
extension's COMP. They cannot be op() calls: a class body is executed while
the class is being defined, long before any COMP exists to resolve against.
Omit the owner on onParExec to watch your own COMP's parameter.
What this buys over the imperative form:
- The binding is visible at the callback itself, right where you read the handler, and the method name is free.
- A target that does not resolve is reported. A mistyped operator or parameter name currently produces a callback that simply never fires; harvest logs it, and nothing is raised, so one bad declaration should not stop a tool from loading.
- Re-harvesting rebuilds from scratch, so a callback deleted from the code disappears with it and there is nothing stale to deregister.
Both styles work on the same extension, and neither needs the other:
NoNode.Init + HarvestCallbacks is enough on its own, with no CustomParHelper
involved.
It also works alongside CustomParHelper. The two watch through separate
exec DATs and do not read each other's state, so a COMP can use CustomParHelper
for its parameters and decorators for its callbacks. Note that on the same
parameter both fire: an onParSpeed method and an @onParExec decorator for
Speed give you two callbacks, so pick one style per parameter. Use the
decorator when you want the handler's name to be free of the onPar<Name>
convention.
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 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, with the promotion made as an Expression |
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 HotkeyManager.
It was a separate package until 2026-08-24, though it always depended on this
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.
Path Bar mods
Dragging an operator onto one of the parents in the Path Bar, and holding Ctrl+Alt (or Ctrl+Cmd) will promote the operator as an iop (internal operator). The root / cell counts as a parent, so a shortcut can be added to the root too.
Dragging a parameter onto one of the parents in the Path Bar will promote it to that parent.
- ‼️
MiddleClickingon a parent will open its parameter window. - ‼️‼️
Long-MiddleClickingon a parent will open its customize window.
Modules
Everything above is a separate sub-module, and the Modules page on the CustomParTools component switches each one on or off independently. All nine default to on, and the settings persist through FNS_ConfigRegistry like the rest of the tool's parameters.
| Toggle | Turns off |
|---|---|
| Parameter Promotion | Dropping a parameter, COMP or table on the button or on the path bar |
| QuickExt | Extension creation from the button |
| QuickParent | Setting a parent shortcut from the button |
| ClearPars | Alt-LeftClick parameter clearing |
| IOP Promoter | Ctrl+Alt drop as an internal operator |
| Navbar Drag/Drop | Drops anywhere on the pane bar |
| Navbar Path Cell Click | MiddleClick on a path-bar parent |
| QuickParCustom | The rollover hotkeys (bound to QuickParCustom's own Active switch) |
| Parameter/Editor Hotkeys | The four stock-TouchDesigner shortcuts |
Switching a module off withdraws whatever surface it owns, so that surface goes away with it:
- Navbar Drag/Drop and Navbar Path Cell Click each own their own navbar registration, so turning one off unregisters that widget and it disappears from every pane bar.
- The other five in the top group share one surface, the CustomParTools button. It leaves the navbar and the toolbar only when all five are off, since any one of them still gives the button something to do.
- The settings registration is never withdrawn. It carries no surface, and it is what stores these toggles, so dropping it would discard the setting that asked for the drop.
Parameters
Its Registry page comes from FNS_ConfigRegistry, FNS_NavbarRegistry and FNS_ToolbarRegistry.
Custom
| Control | Type / default | What it does |
|---|---|---|
Ref/BindRefbind |
on / offoff | How a promoted parameter is linked back to the original. On binds the two (either end can be edited and both follow); off leaves the original in expression mode pointing at the promoted one. Holding the modifier while promoting inverts this for that one action. |
Promote AllPromote |
button | Promote every custom parameter on the current page of the referenced COMP to the target COMP at once, linked according to Ref/Bind. |
Params: SelectedShortcutcurrentpars |
textshift.alt.q | Hotkey that opens the parameter dialog for the SELECTED operator. Rebindable here or in FNS_HotkeyManager. |
Params: Current COMPShortcutparentpars |
textctrl.alt.q | Hotkey that opens the parameter dialog for the COMP whose network is showing. |
Editor: SelectedShortcutcurrentcomp |
textshift.alt.w | Hotkey that opens the component editor for the SELECTED operator. |
Editor: Current COMPShortcutparentcomp |
textctrl.alt.w | Hotkey that opens the component editor for the COMP whose network is showing. |
Modules
| Control | Type / default | What it does |
|---|---|---|
Parameter PromotionActiveparpromote |
on / offon | Drop a parameter onto the CustomParTools button to promote it onto the current network COMP. The core action of the tool. |
QuickExtActivequickext |
on / offon | Create an extension on the current COMP from the button. |
QuickParentActivequickparent |
on / offon | Set a parent shortcut on the current COMP from the button. |
ClearParsActiveclearpars |
on / offon | Alt-click (Cmd on macOS) the button to clear the custom parameters of the current child. |
IOP PromoterActiveioppromoter |
on / offon | Hold the modifier while dropping an operator on the button to promote it as an Internal OP instead of promoting parameters. |
Navbar Drag/DropActivehijackdragdrop |
on / offon | Accept operator and parameter drops anywhere on the pane navigation bar. Off UNREGISTERS the widget, removing it from every bar. |
Navbar Path Cell ClickActivepathcellclickinject |
on / offon | Open parameters for the operator whose path cell you click in the pane bar. Off UNREGISTERS the widget, removing it from every bar. |
QuickParCustomActivequickparcustom |
on / offon | Rollover hotkeys for promoting and customizing the parameter under the mouse. Bound to QuickParCustom's own Active switch. |
Parameter/Editor HotkeysActivetdshortcuts |
on / offon | The four stock-TouchDesigner hotkeys on the Custom page (open parameters, open component editor). Off deactivates the keyboardins; the matching quick-launch commands stay available. |