Custom parameters let you expose a clean control surface on a COMP. Instead of digging into a nested network to tweak a noise frequency or a blur radius, you wrap the network in a Base COMP and expose just the settings that matter as new parameters on the wrapper. Most reusable TouchDesigner modules are built this way.

Why

  • A clean “Master Control” surface for a project, with no internal noise.
  • Reusable modules: drop the COMP into another project and the same controls come along.
  • A natural binding target for UI sliders, OSC, MIDI, or external automation.
  • A versionable interface: the inner network can change without breaking callers.

Creating via the Component Editor

The simplest path:

  1. RMB the COMP → Customize Component… to open the Component Editor Dialog.
  2. Name a page (e.g. Settings) and click Add Page.
  3. Type a parameter label, pick the style (Float, Int, Toggle, Menu, RGB, …), set the size (1-4), click Add Par.

Naming rule: the label gets converted to a valid parameter name automatically: first letter capitalized, no spaces or special characters. So a label Speed factor becomes the parameter Speedfactor accessed as op.par.Speedfactor.

In the dialog you can also drag to reorder, drag between pages, double-click to rename, and x to delete. RMB or Ctrl+C / Ctrl+V copies parameters between components.

Parameter Types

Every type listed under Parameters is creatable. The most common:

TypeMethodNotes
FloatappendFloatsize=1..4 for multi-value
IntappendIntsize=1..4
ToggleappendToggleOn/off
MenuappendMenuFixed menu options
Str MenuappendStrMenuDynamic menu populated from a callback
PulseappendPulseButton, fires once
MomentaryappendMomentaryTrue while held, False on release
StringappendStrText
File / FolderappendFile, appendFolderFile/dir picker
RGB / RGBAappendRGB, appendRGBAColor (size 3 / 4)
XYZ / XY / WH / UVappendXYZ, etc.Named multi-value with preset sizing
OP / TOP / CHOP / SOP / COMPappendOP, appendTOP, …Path picker constrained to a family

Creating in Python

Sometimes you want to script parameter creation (templating, generating from a config, etc.).

comp = op('myEffect')
page = comp.appendCustomPage('Settings')
page.appendFloat('Speed', size=1)
page.appendInt('Iterations', size=1)
page.appendToggle('Active')
page.appendRGB('Tint')                  # auto sizes to 3
page.appendPulse('Reset')
page.appendStrMenu('Mode')              # populate menuNames/menuLabels separately

All append* methods return a ParGroup (the row of related parameters, e.g. R/G/B for an RGB).

Modifying Parameters

Once a parameter exists, every attribute of it is editable from script:

p = op('myEffect').par.Speed
p.label = 'Speed (Hz)'
p.default = 1.0
p.normMin = 0.0
p.normMax = 5.0          # slider range
p.clampMin = True
p.enable = False         # grey out
p.expr = 'absTime.frame * 0.01'
p.mode = ParMode.EXPRESSION

Delete with p.destroy(). Wipe everything with comp.destroyCustomPars().

Pulse Parameters and Callbacks

Pulse parameters do nothing on their own. Wire them to a Parameter Execute DAT:

# Parameter Execute DAT, watching myEffect.par.Reset
def onPulse(par):
    op('feedback1').par.reset.pulse()
    return

This is the standard pattern for a “Reset” or “Reload” button on a COMP.

Internal Wiring: Bind vs Expression

Two common ways to make an internal node respond to a custom param:

Bind (preferred for one-to-one): click the internal parameter’s mode button to purple, set the bound parameter to parent.MyEffect.par.Speed. The internal value tracks the wrapper’s value bidirectionally.

Expression: click the mode to blue, type parent.MyEffect.par.Speed * 2. Read-only but lets you transform the value.

Inside the COMP, the shorthand is even cleaner: if you set the COMP’s Parent Shortcut to Effect, all internal expressions can use parent.Effect.par.Speed regardless of how the COMP gets nested later. See The op and me objects for parent shortcuts.

What’s Next



(y) Return to Scripting & Architecture | (y) Return to TouchDesigner | (y) Return to Home