Making Plugins
Author your own sources, effects, system plugins, and feeds for Lightpath as TouchDesigner .tox files.
Plugins are how you extend Lightpath with content and behavior that
isn't in the box. They're regular TouchDesigner .tox files that
follow a small contract: expose the right parameters, plug into the
right slot in your project, and Lightpath will load them and surface
them in the UI.
The four types
| Type | What it does | Look params | Config params | Status params | Feed params |
|---|---|---|---|---|---|
| Source | Produces a look's visual signal — a texture, or a colour for each LED or pixel | ✓ | ✓ | — | — |
| Effect | Transforms a texture source's output | ✓ | ✓ | — | — |
| System | A singleton that reads, computes, or holds data other plugins can use | — | ✓ | ✓ | — |
| Feed | Streams video that operators watch in the browser | — | ✓ | — | ✓ |
Sources and effects are the visual building blocks of every look. System plugins are the supporting cast — they don't render anything themselves, but they make data available (sensor reads, audio analysis, MIDI input, computed state) for sources and effects to react to. Feeds don't touch looks at all; they exist to put live video in front of an operator.
See Making an Output for the per-output equivalent. Outputs follow the same parameter contract; they just sit at the end of the chain rather than inside it.
Sources
There are two kinds, and they are built differently.
A texture source is a .tox whose output is a texture — generative
patterns, audio-reactive visuals, media playback, camera feeds. If it
produces pixels, it is a texture source. It runs through the look's palette
and effects like any image.
A shader source produces a colour for a point rather than an image: you write one GLSL function and Lightpath runs it at each LED or pixel of the output, with no texture in between. That is what lets it read where a fixture actually is. It applies the palette itself, and the only effect it takes is Color.
The rest of this section is for texture sources. Shader sources have their own contract, palette handling and parameters — see Shader Sources.
The texture source contract
A texture source takes in a palette (as a texture input) and outputs a texture. That's the shape Lightpath expects:
- Input 1: a palette texture. Lightpath wires the active look's palette TOP into this input automatically. When the operator hasn't picked a palette, Lightpath leaves the input disconnected.
- Output 1: the source's rendered texture — whatever your component produces, colorized however it likes with the palette.
Don't depend on anything outside the project folder — see the accessing project files note in the outputs guide; it applies here too.
Working with the palette
The palette is a horizontal gradient TOP: pixel x-coordinate maps to the position along the palette, RGB at that x is the color at that stop. Most sources sample it via a Lookup TOP, using the luminance of some internally-generated pattern as the lookup index — white in your pattern picks the rightmost palette color, black picks the leftmost, mids pick the in-between gradient.
You don't have to use a Lookup TOP, though. The palette is just a texture — multiply with it, sample at specific x positions, drive a particle recolor, feed it to a shader. What you do with it inside the source is up to you.
Set a default palette as the second fallback input to your
In TOP, pointing it at a built-in fallback (a ramp TOP, a
hand-tuned gradient, whatever you like). When Lightpath disconnects
the external input — because the operator hasn't picked a palette in
the look — TouchDesigner uses this default automatically.
Custom parameters
Texture sources support Look, Config, and Managed parameter
pages. Use Look for things operators dial in per-look (pattern
speed, scale, density, audio reactivity threshold, style toggles).
Use Config for install-level settings (an expensive post-process
toggle, a path to an external LUT). Use Managed for the params
Lightpath drives rather than the operator — and always put your
source's resolution there as Resolution1 and Resolution2 Int
parameters. Add a Thumbnail Toggle on Managed too if your source
needs special parameter values to look good in the source picker. See
TouchDesigner Overview → Custom parameters
for the full rules.
Effects
An effect is a .tox that takes one texture in and emits a (usually
different) texture out. Color shifts, blurs, mirrors, masks,
geometric distortions, time-warps — anything that transforms an
incoming signal.
Effects apply to texture sources. A shader source has no texture to transform, so the one effect it accepts is the built-in Color, whose adjustments the shader applies directly; an effect you author never reaches it.
The contract
- Accept the incoming texture on the component's first input.
- Output the transformed texture on the first output.
- Effects should be self-contained — Lightpath stacks multiple effects on one source, so each effect must work standalone.
Custom parameters
Effects support Look, Config, and Managed parameter
pages. Look is the bread and butter — strength, blend amount, hue
shift, blur radius, mask threshold — every per-look knob an operator
expects. Config is rarer on effects (quality preset, mask image path,
expensive-feature toggle) but available when you need it. Managed
holds the params Lightpath drives rather than the operator; in
particular, expose a Thumbnail Toggle there if your effect is
pass-through at default
values (most are) so the picker thumbnail shows something
interesting. See
TouchDesigner Overview → Custom parameters
for the full rules.
Category tags
Effects can declare one or more category tags that surface as filter chips in the effect picker. The built-in categories are color, distort, mask, and transform; you can use these or declare your own. Group several effects under the same tag and an operator can find them all in one click in a long list.
Tags are optional — an untagged effect still works, it just lands in the "all" bucket in the picker.
System plugins
System plugins are singletons — one instance per type, mounted at a known op shortcut so other plugins can find them. They don't participate in the render chain. Instead, they hold and expose data that sources, effects, outputs, and actions can read.
When to author one
- Reading external data — lidar, depth cameras, audio analysis, MIDI controllers, OSC ingestion, MQTT subscriptions.
- Computing shared state — beat tracking from audio, presence detection from a sensor stack, smoothing filters on noisy input.
- Coordinating between plugins — a "show clock" that multiple visuals reference, a global tempo, an environmental mode flag.
If two sources want to react to the same audio analysis, that analysis belongs in a system plugin — not duplicated inside each source.
The contract
- No render input or output. The plugin doesn't sit in the texture chain.
- Expose data via custom parameters, CHOPs, DATs, or your preferred TouchDesigner mechanism.
- Set up a global op shortcut on the COMP so other plugins can resolve it from anywhere in the project — see below.
Surfacing status to Lightpath
System plugins (alongside outputs) support a Status parameter
page. Any parameter you put on a page named Status shows up live
in the TouchDesigner device on the Integrations page, and is available as
a target in the Alerts rule editor. See
TouchDesigner Overview → Status parameters
for the full rules.
This is what makes system plugins observable from the rest of Lightpath — operators can see connection state, error counts, and last-message timestamps without ever opening TouchDesigner.
The op shortcut
The op shortcut is what makes a system plugin reachable from
elsewhere. Set the COMP's Common → Global OP Shortcut parameter
to a name, and op.NAME resolves to the COMP from anywhere in the
project — no path traversal, no parent() walks, no fragile
relative references.
Convention: ALL_CAPS_UNDERSCORE. Lightpath's system plugins use
this form (AUDIO_ANALYSIS, PRESENCE_TRACKER, SHOW_CLOCK) so
they read as constants at the call site and don't collide with
component or extension names. Stick to it for any plugin you author.
From a source's, effect's, or output's Python:
# Read a custom parameter
bpm = op.AUDIO_ANALYSIS.par.Bpm.eval()
# Read a CHOP / DAT / TOP inside the plugin
beat = op.AUDIO_ANALYSIS.op('out1')['beat'].eval()Or wire it into a parameter expression in the editor:
op.AUDIO_ANALYSIS.par.BpmSystem plugins are the only TD components in Lightpath that other plugins should reach into directly. Sources and effects must stay self-contained — referencing one source or effect from another makes the look editor unpredictable when the referenced plugin isn't loaded. If two visual plugins need shared data, put the data in a system plugin and have each reach into it from there.
Feeds
A feed plugin is a .tox that streams video to operators in the browser. Lightpath ingests NDI on its own; anything else — a capture
card, video from another application, a commissioning test pattern, a
generative patch that isn't a look — is a feed plugin.
The contract
Output a texture on the component's first output. There's no input to accept, no extension to write, and no naming convention. Put an Out TOP inside the component and wire your video into it.
Creating one
On the TD Plugins page: New Plugin, type Feed, name it, Create
plugin. Lightpath copies a template into the project's plugins/feeds/
folder and loads it — open it in TouchDesigner and replace the placeholder.
Dropping a .tox into plugins/feeds/ works too (see
Registering a plugin). Deleting the .tox deletes
the feed.
Where it shows up
Feed plugins appear on the Feeds page alongside NDI feeds. Scope decides where else, and is set from either the Feeds page or the plugin's row on the TD Plugins page:
- An output — that output's monitor gains an entry, so an operator can switch its tile between the output's previs and your video.
- All outputs — shows wherever all outputs are in view.
- An area — stored, but areas don't surface feeds yet.
- Not scoped — still pickable for a kiosk or panel monitor, but won't appear anywhere on its own.
Size and framing
A feed plugin publishes whatever it renders, at whatever size it renders it. Do framing, cropping, and scaling in TouchDesigner — nothing on the Lightpath side will resize the video for you.
Parameters
Config params are install-time setup — which device to open, a network address — and appear on the TD Plugins page.
Feed params appear beside the stream, on the expanded view of a monitor tile: camera choice, zoom, an overlay toggle. Operator changes are saved and restored, so give each one a sensible default. See Feed parameters for the full rules.
Look and Status params don't apply to feeds.
A feed only encodes while somebody is watching it. Lightpath handles that — you don't need a start/stop control of your own.
Registering a plugin
Plugins are discovered from the project's plugins/ folder. Drop a
.tox into the subfolder for its type — sources, effects,
system, or feeds — and Lightpath picks it up on the next project
load, or immediately when you click Rescan on the TD Plugins page.
The folder is the categorization; there is no separate "add plugin"
step and no type to declare.
Deleting a .tox removes the plugin. Moving or renaming one is a
delete plus an add — any settings attached to the old entry
(associated output, saved parameter defaults, feed scope) don't
follow it.
Accessing project files
Same pattern as outputs — see TouchDesigner Overview → Accessing project files
for the project/... shortcut.
Lifecycle hooks (advanced)
Sources, effects, and system plugins can react to being loaded or torn down — either with a capitalized extension method or a pulse parameter. See TouchDesigner Overview → Lifecycle hooks for more information.

