TouchDesigner Node Alignment: Automated Layout & Python Scripts
TouchDesigner Node Alignment: Automated Layout & Python Scripts
Quick answer: Use a small Python routine (run via a Text DAT or DAT Execute DAT) to iterate operator children, calculate grid/column coordinates, and assign each OP’s position—this standardizes layout, reduces manual tweaks, and improves readability in large networks.
Why automate node alignment in TouchDesigner?
Manual positioning is fine for small networks, but as projects scale you spend more time nudging operators than building logic. Automated alignment makes the structure visible: consistent X/Y spacing, aligned groups, and column-based flows instantly reveal data paths and bottlenecks.
Automation also reduces human error. When you refactor a network, rename operators, or replace blocks, a repeatable script guarantees consistent placement and avoids overlapping OPs that break wiring clarity. That reliability matters when handing projects between artists and developers.
Finally, an automated layout integrates well with source control and build processes. Positioning logic in a script or DAT means you can run an alignment as part of an export or initialization routine, ensuring every instance of the project presents the same topology.
Automated layout strategies that actually help
There are three practical strategies: grid snapping, column/row stacking, and group-based anchoring. Grid snapping forces positions to multiples of X/Y spacing. Column stacking places nodes in logical columns (input → processing → output). Group anchoring aligns node clusters relative to a container’s origin.
Grid systems are fast and consistent. Column stacking provides semantic clarity—e.g., all TOPs in column 1, CHOPs in column 2, and COMP outputs in column 3. Group anchoring is great for reusable modules: align internals relative to a module’s left edge so the module can be dropped anywhere and keep internal geometry.
Choose a hybrid approach: use columns for high-level flow, grid snapping for micro-adjustments, and group anchoring for self-contained sub-networks. This reduces visual noise while keeping the network readable and maintainable.
- When to automate: large node counts, frequent refactors, collaboration, or production hand-offs.
Python script: a reliable node alignment routine
Below is a compact and adaptable Python routine written for TouchDesigner. It uses the common OP attributes for node placement and supports both grid and column modes. Adapt spacing and sorting as needed for your topology.
Notes before running: paste this into a Text DAT (or a Python IDE inside TD). Many TD builds expose OP.nodeX and OP.nodeY attributes for layout; the script sets these directly. Always test on a copy of your network or inside a parent container.
def align_nodes(container_op, mode='grid', cols=3, spacing_x=240, spacing_y=140):
"""
Align children of container_op.
mode: 'grid' or 'columns'
cols: number of columns when mode=='columns'
spacing_x, spacing_y: pixel spacing
"""
# collect visible children (filter comments, containers you don't want, etc.)
nodes = [n for n in container_op.children if not getattr(n, 'isComment', False)]
# deterministic order
nodes.sort(key=lambda n: n.name.lower())
if mode == 'grid':
# simple NxM grid
import math
cols = max(1, cols)
for i, n in enumerate(nodes):
row = i // cols
col = i % cols
n.nodeX = col * spacing_x
n.nodeY = row * spacing_y
else:
# column stacking left-to-right
for i, n in enumerate(nodes):
col = i % cols
row = i // cols
n.nodeX = col * spacing_x
n.nodeY = row * spacing_y
# Example usage:
# align_nodes(op('/project1'), mode='columns', cols=2, spacing_x=300, spacing_y=160)
Call the function with the container that holds the nodes you want to arrange. For example, run align_nodes(op('/project1')) or replace /project1 with a referenced network like op('base1').
Small refinements: sort by node type (TOP, CHOP, DAT) before applying positions if you want type-based columns. You can also use regex on node.name to group related operators together.
Creating and triggering with a DAT Execute DAT
To make layout automatic, use a DAT Execute DAT that calls your alignment routine when the network changes (or on project start). The pattern: (1) create a Text DAT for the scripts, (2) create a DAT Execute DAT, (3) point the DAT Execute to call your function on the desired trigger (onStart, onTableChange, onPulse).
Step-by-step: create a Text DAT named layout_tools and paste the align_nodes routine. Then create a DAT Execute DAT; set its parameter DAT to a small trigger table (or the same Text DAT) and edit the callback to call layout_tools.run() or directly import the function and call it.
Example DAT Execute callback (pseudo):
# inside the DAT Execute DAT's onStart or onTableChange callback
import layout_tools
layout_tools.align_nodes(op('base1'), mode='columns', cols=2)
If you prefer a manual trigger, add a Button COMP and set its Pulse to run a script that calls align_nodes. This gives quick control without auto-running on every tiny edit.
Optimizing node workflow: conventions and tips
Naming conventions are crucial. When sorting nodes alphabetically to drive layout, use prefixes like in_, proc_, out_ or numeric indices. This ensures the auto-layout groups nodes semantically without additional code complexity.
Use container COMP anchors. If you align internals relative to a container, moving or duplicating the container preserves internal layout. This is essential for building reusable modules and templates that remain tidy when instantiated multiple times.
Finally, add lightweight metadata to nodes using custom parameters or text DATs for grouping hints. The script can read these hints to place a node in a specific column or row, giving you programmatic control without hardcoding names.
Implementation examples and troubleshooting
Case: nodes overlapping after alignment. Solution: increase spacing_x or spacing_y, or pre-calculate each node’s bounding width/height if your script needs to handle varying node sizes. TouchDesigner’s node visuals can differ; generous spacing avoids collisions.
Case: you need type-based columns. Modify the collection step to bucket by type: TOPs first, CHOPs next, DATs last. Sorting by n.type (or n.opType depending on version) implements this reliably.
Case: want to exclude helper nodes. Add a small rule: skip nodes whose name starts with _ or whose custom parameter excludeFromLayout is True. This keeps noise out of your layout algorithm.
Semantic core (keyword clusters)
| Cluster | Keywords & phrases |
|---|---|
| Primary | TouchDesigner node alignment; automatic node placement TouchDesigner; automatic layout scripting TouchDesigner; node positioning automation TouchDesigner; Python script for node alignment |
| Secondary | DAT Execute node creation; scripting node alignment TouchDesigner; optimizing node workflow TouchDesigner; align nodes by grid TouchDesigner; column layout TouchDesigner |
| Clarifying / LSI | auto layout TD; TouchDesigner automation; OP positioning script; Text DAT alignment; network tidy TouchDesigner; node spacing; align operators TD |
This semantic core groups intent-based queries: primary clusters target immediate how-to needs, secondary help refine implementation, and clarifying terms cover synonyms and LSI phrases to use naturally in copy and code comments.
Popular user questions (sample)
- How do I automatically lay out nodes in TouchDesigner?
- Can I align nodes with a Python script in TouchDesigner?
- How to trigger layout on network change using DAT Execute?
- What’s the best spacing for readable operator graphs?
- How to group and align specific operator types (TOP/CHOP/DAT)?
FAQ
1. How do I run the alignment script automatically when a network changes?
Use a DAT Execute DAT to call your align routine on events such as onStart or onTableChange. Put the Python function in a Text DAT and have the DAT Execute invoke it. Optionally, restrict triggers to a light-weight table change or a button pulse to avoid running on every small edit.
2. Will moving nodes after auto-alignment break future automated layouts?
No—if your script is deterministic and based on name, type, or metadata, re-running it will re-align nodes to the same rules. If you want manual exceptions, mark nodes with a custom flag (e.g., prefix names with _ or set an excludeFromLayout parameter) so the script skips them.
3. Can I align nodes by operator type (TOP, CHOP, DAT) into columns?
Yes. Bucket nodes by n.type or by a simple classification function in your script, then assign X positions per bucket (columns) and stagger Y positions per node. This creates clear vertical lanes for each operator family.
Backlinks & further reading
For a compact reference and a downloadable example, see this TouchDesigner node alignment walkthrough: TouchDesigner node alignment
For automatic layout scripting and DAT Execute examples, check this guide: automatic layout scripting TouchDesigner and a sample Python script for node alignment.