TouchDesigner via td-atlas
Перевод английской документации от 29.09·English
TouchDesigner is a node-based visual programming environment. td-atlas gives you an offline index of the installed build (operators, parameters, documentation, palette) plus a live bridge into a running instance.
#The one thing that will waste your time
TouchDesigner reports almost nothing when work silently does nothing. A network that never cooks raises no error. Nor does a flag left off, an output device switched off, a CPU-bound operator holding the frame rate down, or a resolution silently halved by the licence. Three separate hours have been lost to exactly this.
Run td_health after building anything, and whenever something "looks fine but does nothing". It is the tool that catches these. When it says nothing is cooking, td_flags says which flag is the reason. The keys are the ones TouchDesigner uses, so cooking is allowCooking, not cooking; the full set is display, render, bypass, lock, expose, viewer, activeViewer, cloneImmune, allowCooking, selected, pickable. td_set_flags reads every write back, so a flag a family will not take comes back as a refusal, and so does a name that is not one of these.
Two more questions have their own tool. Why is the output black, or darker than its parameters say: td_trace walks up the TOP's inputs and marks the node where the image was lost, went below zero or turned NaN. Who spends the frame when the frame rate drops: td_timeline_profile times each operator on real timeline frames with the GPU waited for.
#Order of work
- Search the index first. It is offline and free, with no round trip to TouchDesigner. Never guess a parameter name. The index is not there until
td-atlas buildhas run once;references/tools.mdhas that command and the rest of the setup. - Read the schema of any operator before creating it.
- Build with
td_build, not a series of single calls. - Look at the result with
td_render, and at motion with a contact sheet. - Run
td_health.
Working from a reference video or image, measure the reference before you choose how to build it — the motion from consecutive frames (a dozen, a few apart; frames a second apart do not show motion), the shape from a few numbers you can take from your own output the same way. In three agent sessions the model chosen from memory cost more rounds than anything this index lacked, and what turned each one was a number taken from the reference.
td_log(failures=True) is your own trail, every bridge call this host made, with the text each refusal came back with. Reach for it when a call refuses and you do not know why, or when the artist says something broke while you were working. td_log(summary=True) says which method has been failing repeatedly, which is the signal that the approach is wrong. It outlives the TouchDesigner session, so it also answers "what happened yesterday". A call that changed the project carries what it changed: tx = 0.5 (was 0.2), each step of a batch, the first lines of a td_exec's code. A secret in it, found by pattern, reads [redacted].
#Finding the right operator
Ask for what the operator does, in plain language, with td_search_operators("displace an image with noise").
Two things it cannot do, and the way round each:
- Artist slang is not TouchDesigner vocabulary. There is no "strobe" or "melt" operator; those are techniques built from several nodes. Search for the mechanism ("brightness over time", "displace by a texture"), or use
td_docs, which reaches 2,060 wiki pages of concepts and techniques, not just operator help. - Check the palette before building.
td_palette("projection mapping")searches 277 finished components that ship with TouchDesigner, among them mappers, corner-pinners, colour pickers and audio analysers. Install one withtd_palette_load(name, parent), which checks the .tox is on disk first and reports the name TouchDesigner actually gave the node.
td_glossary("cook") defines the vocabulary the documentation assumes.
#Parameter names
td_operator_schema("noiseTOP") always gives exact names. Defaults, menu options and ranges appear once td-atlas probe has run against a live TouchDesigner; without that run the schema says so itself, in place of the values. Two traps:
- *The documentation describes parameter groups; you must set the members.* The docs say
t(Translate); the settable parameters aretx,ty,tz. The schema returns the members, and settingtfails. - Menu labels carry information the value does not. The schema prints them as
value — Label: the Noise TOP'stypemenu readssimplex3d — Simplex 3D (GPU)against a plainsparse — Sparse, and the second one runs on the CPU at ~96 ms per cook at 1280×720. Read the labels, not just the values.
A sequence (a Constant CHOP's channels, a GLSL TOP's arrays and uniforms) shows its first block in the schema: const0name, array0name. Later blocks are written the same way with the next number — const1name, array3type — and td_build adds the blocks they need. To set the count outright, give the sequence's own parameter a number: "const": 4. Setting it by hand in TouchDesigner (par.const = 4) does nothing; seq.const.numBlocks = 4 does.
td_build validates parameter names against the index before sending anything, resolving each target's type itself, so a mistake comes back as t: is a parameter group, not a settable parameter (try: tx, ty, tz). The check is a convenience, not a guarantee: with no index built, and for an existing node whose type the bridge cannot report, the batch goes out unchecked. td_set_params does the same, asking the bridge for the node's type when you do not pass op_type.
#Building
Use td_build for anything multi-step:
[
{"method": "op_create", "params": {
"parent": "/project1", "type": "noiseTOP", "name": "n1",
"position": [-600, 0],
"pars": {"type": "simplex3d", "period": 3.5,
"tx": {"expr": "absTime.seconds * 0.1"}}}},
{"method": "op_create", "params": {
"parent": "/project1", "type": "blurTOP", "name": "b1",
"pars": {"size": 6},
"connect": [{"from": "/project1/n1", "index": 0}]}}
]
The whole batch lands in one ui.undo block. If any step fails everything rolls back, and a successful batch is a single Ctrl+Z for the person using TouchDesigner. Parameter values may be a constant, {"expr": "..."} for an expression, {"bind": "..."}, or {"pulse": true}.
A DAT's contents are not a parameter, so they go in their own text key on op_create. That covers shader source, script bodies and callbacks. Doing it there puts the text in the same rollback and the same Ctrl+Z, and saves a follow-up td_exec:
{"method": "op_create", "params": {
"parent": "/project1", "type": "textDAT", "name": "frag",
"text": "out vec4 fragColor;\nvoid main() { fragColor = vec4(1.0); }"}}
A DAT whose text is an output (Select, Null, Info, the script generators) is refused, since it would overwrite the assignment on its next cook.
This was measured live on 2026-08-30, against build 2025.32460. A fragment shader delivered this way to a textDAT, with a glslTOP created in the next step pointing its pixeldat at it, compiled. compileResult read Compiled Successfully, and the TOP's first pixel came back as the colour the shader writes. A shader that does not compile is a warning, not an error, and compileResult is where the line number lives, which td_health reads for you.
The methods are op_create, op_delete, op_connect, op_disconnect and par_set. undo is not one of them, since it walks the history the batch is being recorded into. Call td_undo on its own, after.
If another agent or session may be in the same project, claim your subtree with td_claim_scope(path, owner) first. Then pass that same owner into every tool that writes: td_build, td_set_params, td_set_flags, td_annotate, td_palette_load and td_extension_add, or your own claim refuses your own writes. td_release_scope hands it back, and td_scopes says what is already held.
td_annotate leaves the reason for what you built beside the nodes, as a box the artist can read. td_annotations reads notes back, including a brief a person left for you, which no other tool here shows.
#Seeing what you made
td_render("/project1/b1") returns the image. Use it, since inferring appearance from parameter values does not work. save_to writes the PNG to a path instead, and a file already there is refused unless overwrite=True. Right after an edit pass settle_frames=2 or 3, or the render can be the frame from before it.
For a strobe or any other simple animation, a single frame is a coin toss. Use a contact sheet:
from td_atlas.bridge.client import BridgeClient
from td_atlas.bridge.filmstrip import contact_sheet
contact_sheet(BridgeClient.discover(), "/project1/b1", "sheet.png",
frames=9, interval=0.13, columns=3)
A contact sheet samples wall-clock time. When a frame depends on the ones before it, as with a Feedback TOP, a trail or live audio, use td_timeline_run instead: it walks the timeline frame by frame and saves the frames you pick.
#Reading projects from disk
None of this needs TouchDesigner running, and td_project_read gives the tree. td_project_text gives the whole network as JSON, every parameter, wire, flag and DAT line. td_project_grep reaches the Python and GLSL inside DATs, which no file search can, since that code lives inside the .toe container. A network too big for one result is refused, and never truncated. Narrow it with path, or write it out with td-atlas project text FILE -o network.json.
td_project_write is the return leg, an edited dump into a new file. It is a patcher, so it needs the original file too, and it lists what it could not write, so read those gaps before assuming.
Before trying a direction, td_variant_save(file, label) keeps the current state, and td_variant_list/_restore/_diff branch, restore and compare.
On a live instance, to keep a branch's parameters before changing them, do not dump them to text by hand:
td_snapshot("before", path="/project1/branch")writes that COMP to a.toxand replies with the file path.- Make the edits.
td_snapshot("after", path="/project1/branch"). The label must differ, because a reused label replaces the file you meant to compare against.td_project_diff(before=<before.tox>, after=<after.tox>)lists each changed parameter asname: old -> new, expressions and custom parameters included.- To roll back, use
td_undowhile the edits are still on its stack. Otherwise take the old values fromtd_project_text(<before.tox>)intotd_set_params. The diff shows an expression's text without saying it is one, and the text keeps it as{"expr": ...}. Paths in a snapshot start at the COMP's own name, so/branch/blur1in the file is/project1/branch/blur1live. Put the COMP's parent path in front.
Never save the artist's project. project.save() is Save As in disguise and moves the file they have open. Nothing here needs it; TouchDesigner writes the network text beside the .toe when they save.
#Things that will bite you
Detail in references/gotchas.md, and the short list follows:
- A branch nothing displays or records never cooks. Terminal nodes (Movie File Out, and any chain not feeding a viewer) are not pulled. Add a
cacheTOPwithalwayscookon to keep a chain live. - A Script CHOP or SOP that reads the time inside
onCookcooks once and freezes. Put the clock on a parameter or on an input. - A Python class attached the way the wiki shows it fails in total silence. Use
td_extension_add, which uses the form that works and reads it back. - TouchDesigner throttles rendering when its window is in the background.
- Colour operations inside a feedback loop accumulate. A hue rotation in the loop drives everything to grey; an additive composite drives it to white. Feed back from before the grade, and prefer
maximumoveradd. - Non-Commercial caps resolution at 1280×1280, silently, with only a warning, so asking for 1920×1080 gives 1280×720.
execblocks TouchDesigner's main thread, so do not poll during a recording.- A playing timeline cooks live CHOPs between your calls. The
timelineline oftd_statussaysplayingorpaused, and marks with(!)a playback range that stops beforeend.
#Command line
td-atlas status # install, index and bridge state
td-atlas doctor # every link, with the command that fixes it
td-atlas search "blur an image"
td-atlas op noiseTOP --page Noise
td-atlas render /project1/n1 -o out.png
td-atlas project diff a.toe b.toe
td-atlas project variant save a.toe --label try1 # branch, restore, compare
td-atlas log --failures # the same trail as td_log
td-atlas reload # upgrade the bridge in place
#If the bridge is unreachable
td-atlas install prints a one-line bootstrap to paste into TouchDesigner's textport. The textport opens from the menu, Dialogs → Textport and DATs. Do not reach for the keyboard shortcut. A blind key combination lands in the network editor when the window is not focused, and creates operators in the artist's project. Re-running the bootstrap upgrades in place. td_instances says which running TouchDesigner these tools actually reach. Check it before believing an edit landed in the project you meant.