embody tdn

TDN / TOUCHDESIGNER NETWORK FORMAT

your network,
as text.

TDN exports any TouchDesigner network as clean, human-readable JSON — only the parameters you actually changed, structured so any tool can understand it. Your AI agent can read it. Your team can review it. Git can diff it line by line.

THE CONTRAST

binary vs. text.

TDN gives your TouchDesigner networks a second representation — one designed for diffing, reviewing, and reading. A format where every change is visible, every version is comparable, and every operator is text your tools can work with.

binary .toe / .tox

  • Opaque — requires TouchDesigner to inspect
  • Binary diff — "file changed"
  • Invisible to AI agents
  • Revert = restore entire binary file
  • Merge conflicts are unresolvable
  • Fixed size regardless of complexity

text .tdn

  • Readable in any text editor
  • Line-by-line diff — "noise frequency changed from 1 to 2.5"
  • Full network context in a single JSON document
  • Revert = git checkout a specific change
  • Merge conflicts are readable and fixable
  • Non-default only — a simple network is a small file

COMPLETE REPRESENTATION

everything that matters.

TDN captures the complete state of a network. Everything that defines the network is in the file; everything that doesn't is left out.

operators

Name, type, position, size, color, comment, tags — the full identity of every node.

parameters

Only non-default values. Constants, expressions (=), and binds (~) — nothing else.

connections

Input wiring as arrays. Position equals input index. No wrappers, no ceremony.

custom parameters

Complete definitions — pages, styles, ranges, menus, defaults, help text. Ready to rebuild.

flags

Viewer, display, render, bypass, lock, expose — compact arrays with - prefix for negation.

DAT content

Text and table data embedded directly in the JSON. Scripts, lookup tables, configuration — all in one file.

operator storage

Dicts, lists, tuples, sets, and bytes. Python types round-tripped with $type wrappers.

annotations

Annotate, comment, and network box modes — position, size, color, opacity. Your documentation, preserved.

hierarchy & nesting

Recursive children, COMP inputs, docking relationships, and tdn_ref pointers for independently externalized COMPs.

palette clones

Clone relationships preserved. Children excluded — TD recreates them from the clone source automatically.

parameter sequences

Resizable parameter blocks — GLSL uniforms, Combine blocks, channel constants — round-tripped with portable base names.

FORMAT DESIGN

designed to be small.

Every design decision serves a single goal: the smallest possible output that remains fully readable. A network with 50 operators where you only changed a few parameters produces a file measured in kilobytes, not megabytes.

// expression — just prefix with =
"period": "=absTime.frame * 0.1"

// bind — just prefix with ~
"tx": "~op('ctrl').par.x"

// negated flag — just prefix with -
"flags": ["viewer", "-expose"]

// connections — position = input index
"inputs": ["noise1", null, "level1"]

// constant — no wrapper needed
"amp": 0.8
  • Non-default only — parameters at their default values are omitted entirely, often eliminating 90%+ of the parameter space.
  • Type defaults — properties shared across all operators of a given type are hoisted into a top-level section and removed from each operator.
  • Parameter templates — identical custom parameter pages appearing on 2+ operators are extracted into par_templates and referenced via $t. Definitions stored once, values per-operator.
  • Compact shorthands — prefix characters instead of verbose wrapper objects. = for expressions, ~ for binds, - for negated flags.
  • Simplified connections["noise1"] instead of [{"index": 0, "source": "noise1"}]. Array position equals input index.

Round-trip safe. Export a network, edit the JSON, import it back. Same network. Every time.

RELIABILITY

built for safety.

TDN is the source of truth for externalized networks. Every write must be bulletproof.

atomic writes

Every save writes to a temp file first, calls fsync, then uses os.replace to swap it in. No partial writes. Ever.

backup rotation

A .tdn_backup/ directory keeps two generations of previous versions. Recover from any bad export instantly.

post-write validation

After every write, the file is read back and JSON-parsed to confirm integrity. If validation fails, the backup is restored automatically.

content comparison

If the new export matches the existing file, the write is skipped entirely — preserving git timestamps and avoiding noise commits.

best-effort import

The importer runs 8 ordered phases. A single failed operator never aborts the entire import — partial results are more useful than total failure.

VERSION DURABILITY

survives TD upgrades.

Some TouchDesigner operators reset certain parameters during initialization — a camera's tz is reported as 0 by default, but TD actually creates it at 5. A non-default comparison that trusts the reported value will silently omit your intended setting. TDN catches this.

The first time you open a project on a new TD build, Embody scans every creatable operator type in the background, samples the actual creation values, and writes a per-build catalog. TDN exports compare against those real values instead of the reported defaults. When you upgrade TD, the catalog detects which creation values shifted between builds and automatically patches your operators to preserve your intent. An elegant solution to a very obscure problem — but the kind that would otherwise cost you hours of debugging a parameter that "just changed" after an update.

Upgrade-proof. Export on one build, open on another. Every parameter value survives.

THE WORKFLOW

part of the loop.

TDN is not a standalone format. It's the substrate that connects the other two layers of Embody — the format that makes both forward and lateral velocity possible.

Envoy

forward velocity.

Your AI agent exports the current network as TDN to see what's on screen. It generates or modifies the JSON, then imports it back — changes appear instantly in your live session.

Embody

lateral velocity.

Tag a COMP, choose TDN as its externalization strategy, and every save writes the network to a .tdn file. On project open, children rebuild themselves from text automatically.

Git

the record.

Commit the .tdn file. Every change is a clean diff. Review network modifications in pull requests. Branch off working versions. Revert broken experiments.

The substrate. Tag a COMP. Save it as TDN. Commit the file. Let your agent read it, modify it, import the result. All without touching a binary.

SPECIFICATION

format details.

extension .tdn
encoding UTF-8
MIME type application/json
current version 1.3
backward compatible v1.0 through v1.3
JSON Schema tdn.schema.json

A REAL FILE

this is what it looks like.

{
  "format": "tdn",
  "version": "1.3",
  "generator": "Embody/5.0.351",
  "td_build": "2025.33020",
  "exported_at": "2026-04-10T08:15:00Z",
  "network_path": "/project1",
  "type": "containerCOMP",
  "options": { "include_dat_content": true },

  "operators": [
    {
      "name": "noise1",
      "type": "noiseTOP",
      "parameters": {
        "amp": 0.8,
        "period": "=absTime.frame * 0.1",
        "harmons": 4
      },
      "flags": ["viewer"]
    },
    {
      "name": "blur1",
      "type": "blurTOP",
      "parameters": { "size": 8 },
      "inputs": ["noise1"],
      "position": [400, 0]
    },
    {
      "name": "level1",
      "type": "levelTOP",
      "parameters": {
        "opacity": "~op('ctrl').par.Fade",
        "brightness1": 1.2
      },
      "inputs": ["blur1"],
      "flags": ["display", "render"],
      "position": [800, 0]
    }
  ],

  "annotations": [
    {
      "name": "annot1",
      "mode": "annotate",
      "title": "noise pipeline",
      "position": [-100, -200],
      "size": [1100, 400]
    }
  ]
}

Three operators, one annotation, one expression, one bind. Every required field present, every value spec-accurate — readable, diffable, importable.