[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6GAZMDFFAQTZTZWYECHBA4T":3,"skill-same:01M6GAZMDFFAQTZTZWYECHBA4T":88},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":26,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":66,"commitSha":67,"skillDirectory":68,"forksCount":69,"repositoryHtmlUrl":70,"repositoryHomepageUrl":6,"ownerHtmlUrl":71,"ownerBlogUrl":6,"ownerDescription":72,"updatedAt":73,"install":74,"resources":87},"01M6GAZMDFFAQTZTZWYECHBA4T","touchdesigner-mcp",null,"Control TouchDesigner via twozero MCP.","zapabob\u002FSkills","zapabob","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F130830376?v=4","01M6DBMYZAGRTFQDSQYW3W764P","峯岸 亮","01M6DBMZ3GKDSJ01NZ9XTZD7JD",2,"MIT","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Farchive\u002Fskill-md-reviewed\u002Fsha256\u002F92\u002F925c387c16a3a0752e4670d48ab9bde94f930cd3dd27fe08cefda2e05c0765e9\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"touchdesigner mcp","MCP","Art","vj","creative-coding","generative-art","GLSL","via","ascii","control","installation","time","coding","Audio","Video","real-time","visuals","windows","linux","macos","2026-11-10 10:12:30",false,"---\nname: touchdesigner-mcp\ndescription: Control TouchDesigner via twozero MCP.\nversion: 1.1.0\nauthor: kshitijk4poor\nlicense: MIT\nplatforms: [linux, macos, windows]\nmetadata:\n  hermes:\n    tags: [TouchDesigner, MCP, twozero, creative-coding, real-time-visuals, generative-art, audio-reactive, VJ, installation, GLSL]\n    related_skills: [ascii-video, manim-video]\n\n---\n\n# TouchDesigner Integration (twozero MCP)\n\n## CRITICAL RULES\n\n1. **NEVER guess parameter names.** Call `td_get_par_info` for the op type FIRST. Your training data is wrong for TD 2025.32.\n2. **If `tdAttributeError` fires, STOP.** Call `td_get_operator_info` on the failing node before continuing.\n3. **NEVER hardcode absolute paths** in script callbacks. Use `me.parent()` \u002F `scriptOp.parent()`.\n4. **Prefer native MCP tools over td_execute_python.** Use `td_create_operator`, `td_set_operator_pars`, `td_get_errors` etc. Only fall back to `td_execute_python` for complex multi-step logic.\n5. **Call `td_get_hints` before building.** It returns patterns specific to the op type you're working with.\n\n## Architecture\n\n```\nHermes Agent -> MCP (Streamable HTTP) -> twozero.tox (port 40404) -> TD Python\n```\n\n36 native tools. Free plugin (no payment\u002Flicense — confirmed April 2026).\nContext-aware (knows selected OP, current network).\nHub health check: `GET http:\u002F\u002Flocalhost:40404\u002Fmcp` returns JSON with instance PID, project name, TD version.\n\n## Setup (Automated)\n\nRun the setup script to handle everything:\n\n```bash\nbash \"${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fcreative\u002Ftouchdesigner-mcp\u002Fscripts\u002Fsetup.sh\"\n```\n\nThe script will:\n1. Check if TD is running\n2. Download twozero.tox if not already cached\n3. Add `twozero_td` MCP server to Hermes config (if missing)\n4. Test the MCP connection on port 40404\n5. Report what manual steps remain (drag .tox into TD, enable MCP toggle)\n\n### Manual steps (one-time, cannot be automated)\n\n1. **Drag `~\u002FDownloads\u002Ftwozero.tox` into the TD network editor** → click Install\n2. **Enable MCP:** click twozero icon → Settings → mcp → \"auto start MCP\" → Yes\n3. **Restart Hermes session** to pick up the new MCP server\n\nAfter setup, verify:\n```bash\nnc -z 127.0.0.1 40404 && echo \"twozero MCP: READY\"\n```\n\n## Environment Notes\n\n- **Non-Commercial TD** caps resolution at 1280×1280. Use `outputresolution = 'custom'` and set width\u002Fheight explicitly.\n- **Codecs:** `prores` (preferred on macOS) or `mjpa` as fallback. H.264\u002FH.265\u002FAV1 require a Commercial license.\n- Always call `td_get_par_info` before setting params — names vary by TD version (see CRITICAL RULES #1).\n\n## Workflow\n\n### Step 0: Discover (before building anything)\n\n```\nCall td_get_par_info with op_type for each type you plan to use.\nCall td_get_hints with the topic you're building (e.g. \"glsl\", \"audio reactive\", \"feedback\").\nCall td_get_focus to see where the user is and what's selected.\nCall td_get_network to see what already exists.\n```\n\nNo temp nodes, no cleanup. This replaces the old discovery dance entirely.\n\n### Step 1: Clean + Build\n\n**IMPORTANT: Split cleanup and creation into SEPARATE MCP calls.** Destroying and recreating same-named nodes in one `td_execute_python` script causes \"Invalid OP object\" errors. See pitfalls #11b.\n\nUse `td_create_operator` for each node (handles viewport positioning automatically):\n\n```\ntd_create_operator(type=\"noiseTOP\", parent=\"\u002Fproject1\", name=\"bg\", parameters={\"resolutionw\": 1280, \"resolutionh\": 720})\ntd_create_operator(type=\"levelTOP\", parent=\"\u002Fproject1\", name=\"brightness\")\ntd_create_operator(type=\"nullTOP\", parent=\"\u002Fproject1\", name=\"out\")\n```\n\nFor bulk creation or wiring, use `td_execute_python`:\n\n```python\n# td_execute_python script:\nroot = op('\u002Fproject1')\nnodes = []\nfor name, optype in [('bg', noiseTOP), ('fx', levelTOP), ('out', nullTOP)]:\n    n = root.create(optype, name)\n    nodes.append(n.path)\n# Wire chain\nfor i in range(len(nodes)-1):\n    op(nodes[i]).outputConnectors[0].connect(op(nodes[i+1]).inputConnectors[0])\nresult = {'created': nodes}\n```\n\n### Step 2: Set Parameters\n\nPrefer the native tool (validates params, won't crash):\n\n```\ntd_set_operator_pars(path=\"\u002Fproject1\u002Fbg\", parameters={\"roughness\": 0.6, \"monochrome\": true})\n```\n\nFor expressions or modes, use `td_execute_python`:\n\n```python\nop('\u002Fproject1\u002Ftime_driver').par.colorr.expr = \"absTime.seconds % 1000.0\"\n```\n\n### Step 3: Wire\n\nUse `td_execute_python` — no native wire tool exists:\n\n```python\nop('\u002Fproject1\u002Fbg').outputConnectors[0].connect(op('\u002Fproject1\u002Ffx').inputConnectors[0])\n```\n\n### Step 4: Verify\n\n```\ntd_get_errors(path=\"\u002Fproject1\", recursive=true)\ntd_get_perf()\ntd_get_operator_info(path=\"\u002Fproject1\u002Fout\", detail=\"full\")\n```\n\n### Step 5: Display \u002F Capture\n\n```\ntd_get_screenshot(path=\"\u002Fproject1\u002Fout\")\n```\n\nOr open a window via script:\n\n```python\nwin = op('\u002Fproject1').create(windowCOMP, 'display')\nwin.par.winop = op('\u002Fproject1\u002Fout').path\nwin.par.winw = 1280; win.par.winh = 720\nwin.par.winopen.pulse()\n```\n\n## MCP Tool Quick Reference\n\n**Core (use these most):**\n| Tool | What |\n|------|------|\n| `td_execute_python` | Run arbitrary Python in TD. Full API access. |\n| `td_create_operator` | Create node with params + auto-positioning |\n| `td_set_operator_pars` | Set params safely (validates, won't crash) |\n| `td_get_operator_info` | Inspect one node: connections, params, errors |\n| `td_get_operators_info` | Inspect multiple nodes in one call |\n| `td_get_network` | See network structure at a path |\n| `td_get_errors` | Find errors\u002Fwarnings recursively |\n| `td_get_par_info` | Get param names for an OP type (replaces discovery) |\n| `td_get_hints` | Get patterns\u002Ftips before building |\n| `td_get_focus` | What network is open, what's selected |\n\n**Read\u002FWrite:**\n| Tool | What |\n|------|------|\n| `td_read_dat` | Read DAT text content |\n| `td_write_dat` | Write\u002Fpatch DAT content |\n| `td_read_chop` | Read CHOP channel values |\n| `td_read_textport` | Read TD console output |\n\n**Visual:**\n| Tool | What |\n|------|------|\n| `td_get_screenshot` | Capture one OP viewer to file |\n| `td_get_screenshots` | Capture multiple OPs at once |\n| `td_get_screen_screenshot` | Capture actual screen via TD |\n| `td_navigate_to` | Jump network editor to an OP |\n\n**Search:**\n| Tool | What |\n|------|------|\n| `td_find_op` | Find ops by name\u002Ftype across project |\n| `td_search` | Search code, expressions, string params |\n\n**System:**\n| Tool | What |\n|------|------|\n| `td_get_perf` | Performance profiling (FPS, slow ops) |\n| `td_list_instances` | List all running TD instances |\n| `td_get_docs` | In-depth docs on a TD topic |\n| `td_agents_md` | Read\u002Fwrite per-COMP markdown docs |\n| `td_reinit_extension` | Reload extension after code edit |\n| `td_clear_textport` | Clear console before debug session |\n\n**Input Automation:**\n| Tool | What |\n|------|------|\n| `td_input_execute` | Send mouse\u002Fkeyboard to TD |\n| `td_input_status` | Poll input queue status |\n| `td_input_clear` | Stop input automation |\n| `td_op_screen_rect` | Get screen coords of a node |\n| `td_click_screen_point` | Click a point in a screenshot |\n| `td_screen_point_to_global` | Convert screenshot pixel to absolute screen coords |\n\nThe table above covers the 32 tools used in typical creative workflows. The remaining 4 tools (`td_project_quit`, `td_test_session`, `td_dev_log`, `td_clear_dev_log`) are admin\u002Fdev-mode utilities — see `references\u002Fmcp-tools.md` for the full 36-tool reference with complete parameter schemas.\n\n## Key Implementation Rules\n\n**GLSL time:** No `uTDCurrentTime` in GLSL TOP. Use the Values page:\n```python\n# Call td_get_par_info(op_type=\"glslTOP\") first to confirm param names\ntd_set_operator_pars(path=\"\u002Fproject1\u002Fshader\", parameters={\"value0name\": \"uTime\"})\n# Then set expression via script:\n# op('\u002Fproject1\u002Fshader').par.value0.expr = \"absTime.seconds\"\n# In GLSL: uniform float uTime;\n```\n\nFallback: Constant TOP in `rgba32float` format (8-bit clamps to 0-1, freezing the shader).\n\n**Feedback TOP:** Use `top` parameter reference, not direct input wire. \"Not enough sources\" resolves after first cook. \"Cook dependency loop\" warning is expected.\n\n**Resolution:** Non-Commercial caps at 1280×1280. Use `outputresolution = 'custom'`.\n\n**Large shaders:** Write GLSL to `\u002Ftmp\u002Ffile.glsl`, then use `td_write_dat` or `td_execute_python` to load.\n\n**Vertex\u002FPoint access (TD 2025.32):** `point.P[0]`, `point.P[1]`, `point.P[2]` — NOT `.x`, `.y`, `.z`.\n\n**Extensions:** `ext0object` format is `\"op('.\u002FdatName').module.ClassName(me)\"` in CONSTANT mode. After editing extension code with `td_write_dat`, call `td_reinit_extension`.\n\n**Script callbacks:** ALWAYS use relative paths via `me.parent()` \u002F `scriptOp.parent()`.\n\n**Cleaning nodes:** Always `list(root.children)` before iterating + `child.valid` check.\n\n## Recording \u002F Exporting Video\n\n```python\n# via td_execute_python:\nroot = op('\u002Fproject1')\nrec = root.create(moviefileoutTOP, 'recorder')\nop('\u002Fproject1\u002Fout').outputConnectors[0].connect(rec.inputConnectors[0])\nrec.par.type = 'movie'\nrec.par.file = '\u002Ftmp\u002Foutput.mov'\nrec.par.videocodec = 'prores'  # Apple ProRes — NOT license-restricted on macOS\nrec.par.record = True   # start\n# rec.par.record = False  # stop (call separately later)\n```\n\nH.264\u002FH.265\u002FAV1 need Commercial license. Use `prores` on macOS or `mjpa` as fallback.\nExtract frames: `ffmpeg -i \u002Ftmp\u002Foutput.mov -vframes 120 \u002Ftmp\u002Fframes\u002Fframe_%06d.png`\n\n**TOP.save() is useless for animation** — captures same GPU texture every time. Always use MovieFileOut.\n\n### Before Recording: Checklist\n\n1. **Verify FPS > 0** via `td_get_perf`. If FPS=0 the recording will be empty. See pitfalls #38-39.\n2. **Verify shader output is not black** via `td_get_screenshot`. Black output = shader error or missing input. See pitfalls #8, #40.\n3. **If recording with audio:** cue audio to start first, then delay recording by 3 frames. See pitfalls #19.\n4. **Set output path before starting record** — setting both in the same script can race.\n\n## Audio-Reactive GLSL (Proven Recipe)\n\n### Correct signal chain (tested April 2026)\n\n```\nAudioFileIn CHOP (playmode=sequential)\n  → AudioSpectrum CHOP (FFT=512, outputmenu=setmanually, outlength=256, timeslice=ON)\n  → Math CHOP (gain=10)\n  → CHOP to TOP (dataformat=r, layout=rowscropped)\n  → GLSL TOP input 1 (spectrum texture, 256x2)\n\nConstant TOP (rgba32float, time) → GLSL TOP input 0\nGLSL TOP → Null TOP → MovieFileOut\n```\n\n### Critical audio-reactive rules (empirically verified)\n\n1. **TimeSlice must stay ON** for AudioSpectrum. OFF = processes entire audio file → 24000+ samples → CHOP to TOP overflow.\n2. **Set Output Length manually** to 256 via `outputmenu='setmanually'` and `outlength=256`. Default outputs 22050 samples.\n3. **DO NOT use Lag CHOP for spectrum smoothing.** Lag CHOP operates in timeslice mode and expands 256 samples to 2400+, averaging all values to near-zero (~1e-06). The shader receives no usable data. This was the #1 audio sync failure in testing.\n4. **DO NOT use Filter CHOP either** — same timeslice expansion problem with spectrum data.\n5. **Smoothing belongs in the GLSL shader** if needed, via temporal lerp with a feedback texture: `mix(prevValue, newValue, 0.3)`. This gives frame-perfect sync with zero pipeline latency.\n6. **CHOP to TOP dataformat = 'r'**, layout = 'rowscropped'. Spectrum output is 256x2 (stereo). Sample at y=0.25 for first channel.\n7. **Math gain = 10** (not 5). Raw spectrum values are ~0.19 in bass range. Gain of 10 gives usable ~5.0 for the shader.\n8. **No Resample CHOP needed.** Control output size via AudioSpectrum's `outlength` param directly.\n\n### GLSL spectrum sampling\n\n```glsl\n\u002F\u002F Input 0 = time (1x1 rgba32float), Input 1 = spectrum (256x2)\nfloat iTime = texture(sTD2DInputs[0], vec2(0.5)).r;\n\n\u002F\u002F Sample multiple points per band and average for stability:\n\u002F\u002F NOTE: y=0.25 for first channel (stereo texture is 256x2, first row center is 0.25)\nfloat bass = (texture(sTD2DInputs[1], vec2(0.02, 0.25)).r +\n              texture(sTD2DInputs[1], vec2(0.05, 0.25)).r) \u002F 2.0;\nfloat mid  = (texture(sTD2DInputs[1], vec2(0.2, 0.25)).r +\n              texture(sTD2DInputs[1], vec2(0.35, 0.25)).r) \u002F 2.0;\nfloat hi   = (texture(sTD2DInputs[1], vec2(0.6, 0.25)).r +\n              texture(sTD2DInputs[1], vec2(0.8, 0.25)).r) \u002F 2.0;\n```\n\nSee `references\u002Fnetwork-patterns.md` for complete build scripts + shader code.\n\n## Operator Quick Reference\n\n| Family | Color | Python class \u002F MCP type | Suffix |\n|--------|-------|-------------|--------|\n| TOP | Purple | noiseTOP, glslTOP, compositeTOP, levelTop, blurTOP, textTOP, nullTOP | TOP |\n| CHOP | Green | audiofileinCHOP, audiospectrumCHOP, mathCHOP, lfoCHOP, constantCHOP | CHOP |\n| SOP | Blue | gridSOP, sphereSOP, transformSOP, noiseSOP | SOP |\n| DAT | White | textDAT, tableDAT, scriptDAT, webserverDAT | DAT |\n| MAT | Yellow | phongMAT, pbrMAT, glslMAT, constMAT | MAT |\n| COMP | Gray | geometryCOMP, containerCOMP, cameraCOMP, lightCOMP, windowCOMP | COMP |\n\n## Security Notes\n\n- MCP runs on localhost only (port 40404). No authentication — any local process can send commands.\n- `td_execute_python` has unrestricted access to the TD Python environment and filesystem as the TD process user.\n- `setup.sh` downloads twozero.tox from the official 404zero.com URL. Verify the download if concerned.\n- The skill never sends data outside localhost. All MCP communication is local.\n\n## References\n\n| File | What |\n|------|------|\n| `references\u002Fpitfalls.md` | Hard-won lessons from real sessions |\n| `references\u002Foperators.md` | All operator families with params and use cases |\n| `references\u002Fnetwork-patterns.md` | Recipes: audio-reactive, generative, GLSL, instancing |\n| `references\u002Fmcp-tools.md` | Full twozero MCP tool parameter schemas |\n| `references\u002Fpython-api.md` | TD Python: op(), scripting, extensions |\n| `references\u002Ftroubleshooting.md` | Connection diagnostics, debugging |\n| `references\u002Fglsl.md` | GLSL uniforms, built-in functions, shader templates |\n| `references\u002Fpostfx.md` | Post-FX: bloom, CRT, chromatic aberration, feedback glow |\n| `references\u002Flayout-compositor.md` | HUD layout patterns, panel grids, BSP-style layouts |\n| `references\u002Foperator-tips.md` | Wireframe rendering, feedback TOP setup |\n| `references\u002Fgeometry-comp.md` | Geometry COMP: instancing, POP vs SOP, morphing |\n| `references\u002Faudio-reactive.md` | Audio band extraction, beat detection, envelope following |\n| `references\u002Fanimation.md` | LFOs, timers, keyframes, easing, expression-driven motion |\n| `references\u002Fmidi-osc.md` | MIDI\u002FOSC controllers, TouchOSC, multi-machine sync |\n| `references\u002Fparticles.md` | POPs and legacy particleSOP — emission, forces, collisions |\n| `references\u002Fprojection-mapping.md` | Multi-window output, corner pin, mesh warp, edge blending |\n| `references\u002Fexternal-data.md` | HTTP, WebSocket, MQTT, Serial, TCP, webserverDAT |\n| `references\u002Fpanel-ui.md` | Custom params, panel COMPs, button\u002Fslider\u002Ffield, panelExecuteDAT |\n| `references\u002Freplicator.md` | replicatorCOMP — data-driven cloning, layouts, callbacks |\n| `references\u002Fdat-scripting.md` | Execute DAT family — chop\u002Fdat\u002Fparameter\u002Fpanel\u002Fop\u002FexecuteDAT |\n| `references\u002F3d-scene.md` | Lighting rigs, shadows, IBL\u002Fcubemaps, multi-camera, PBR |\n| `scripts\u002Fsetup.sh` | Automated setup script |\n\n---\n\n> You're not writing code. You're conducting light.\n","# TouchDesigner Integration (twozero MCP)\n\n## CRITICAL RULES\n\n1. **NEVER guess parameter names.** Call `td_get_par_info` for the op type FIRST. Your training data is wrong for TD 2025.32.\n2. **If `tdAttributeError` fires, STOP.** Call `td_get_operator_info` on the failing node before continuing.\n3. **NEVER hardcode absolute paths** in script callbacks. Use `me.parent()` \u002F `scriptOp.parent()`.\n4. **Prefer native MCP tools over td_execute_python.** Use `td_create_operator`, `td_set_operator_pars`, `td_get_errors` etc. Only fall back to `td_execute_python` for complex multi-step logic.\n5. **Call `td_get_hints` before building.** It returns patterns specific to the op type you're working with.\n\n## Architecture\n\n```\nHermes Agent -> MCP (Streamable HTTP) -> twozero.tox (port 40404) -> TD Python\n```\n\n36 native tools. Free plugin (no payment\u002Flicense — confirmed April 2026).\nContext-aware (knows selected OP, current network).\nHub health check: `GET http:\u002F\u002Flocalhost:40404\u002Fmcp` returns JSON with instance PID, project name, TD version.\n\n## Setup (Automated)\n\nRun the setup script to handle everything:\n\n```bash\nbash \"${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fcreative\u002Ftouchdesigner-mcp\u002Fscripts\u002Fsetup.sh\"\n```\n\nThe script will:\n1. Check if TD is running\n2. Download twozero.tox if not already cached\n3. Add `twozero_td` MCP server to Hermes config (if missing)\n4. Test the MCP connection on port 40404\n5. Report what manual steps remain (drag .tox into TD, enable MCP toggle)\n\n### Manual steps (one-time, cannot be automated)\n\n1. **Drag `~\u002FDownloads\u002Ftwozero.tox` into the TD network editor** → click Install\n2. **Enable MCP:** click twozero icon → Settings → mcp → \"auto start MCP\" → Yes\n3. **Restart Hermes session** to pick up the new MCP server\n\nAfter setup, verify:\n```bash\nnc -z 127.0.0.1 40404 && echo \"twozero MCP: READY\"\n```\n\n## Environment Notes\n\n- **Non-Commercial TD** caps resolution at 1280×1280. Use `outputresolution = 'custom'` and set width\u002Fheight explicitly.\n- **Codecs:** `prores` (preferred on macOS) or `mjpa` as fallback. H.264\u002FH.265\u002FAV1 require a Commercial license.\n- Always call `td_get_par_info` before setting params — names vary by TD version (see CRITICAL RULES #1).\n\n## Workflow\n\n### Step 0: Discover (before building anything)\n\n```\nCall td_get_par_info with op_type for each type you plan to use.\nCall td_get_hints with the topic you're building (e.g. \"glsl\", \"audio reactive\", \"feedback\").\nCall td_get_focus to see where the user is and what's selected.\nCall td_get_network to see what already exists.\n```\n\nNo temp nodes, no cleanup. This replaces the old discovery dance entirely.\n\n### Step 1: Clean + Build\n\n**IMPORTANT: Split cleanup and creation into SEPARATE MCP calls.** Destroying and recreating same-named nodes in one `td_execute_python` script causes \"Invalid OP object\" errors. See pitfalls #11b.\n\nUse `td_create_operator` for each node (handles viewport positioning automatically):\n\n```\ntd_create_operator(type=\"noiseTOP\", parent=\"\u002Fproject1\", name=\"bg\", parameters={\"resolutionw\": 1280, \"resolutionh\": 720})\ntd_create_operator(type=\"levelTOP\", parent=\"\u002Fproject1\", name=\"brightness\")\ntd_create_operator(type=\"nullTOP\", parent=\"\u002Fproject1\", name=\"out\")\n```\n\nFor bulk creation or wiring, use `td_execute_python`:\n\n```python\n# td_execute_python script:\nroot = op('\u002Fproject1')\nnodes = []\nfor name, optype in [('bg', noiseTOP), ('fx', levelTOP), ('out', nullTOP)]:\n    n = root.create(optype, name)\n    nodes.append(n.path)\n# Wire chain\nfor i in range(len(nodes)-1):\n    op(nodes[i]).outputConnectors[0].connect(op(nodes[i+1]).inputConnectors[0])\nresult = {'created': nodes}\n```\n\n### Step 2: Set Parameters\n\nPrefer the native tool (validates params, won't crash):\n\n```\ntd_set_operator_pars(path=\"\u002Fproject1\u002Fbg\", parameters={\"roughness\": 0.6, \"monochrome\": true})\n```\n\nFor expressions or modes, use `td_execute_python`:\n\n```python\nop('\u002Fproject1\u002Ftime_driver').par.colorr.expr = \"absTime.seconds % 1000.0\"\n```\n\n### Step 3: Wire\n\nUse `td_execute_python` — no native wire tool exists:\n\n```python\nop('\u002Fproject1\u002Fbg').outputConnectors[0].connect(op('\u002Fproject1\u002Ffx').inputConnectors[0])\n```\n\n### Step 4: Verify\n\n```\ntd_get_errors(path=\"\u002Fproject1\", recursive=true)\ntd_get_perf()\ntd_get_operator_info(path=\"\u002Fproject1\u002Fout\", detail=\"full\")\n```\n\n### Step 5: Display \u002F Capture\n\n```\ntd_get_screenshot(path=\"\u002Fproject1\u002Fout\")\n```\n\nOr open a window via script:\n\n```python\nwin = op('\u002Fproject1').create(windowCOMP, 'display')\nwin.par.winop = op('\u002Fproject1\u002Fout').path\nwin.par.winw = 1280; win.par.winh = 720\nwin.par.winopen.pulse()\n```\n\n## MCP Tool Quick Reference\n\n**Core (use these most):**\n| Tool | What |\n|------|------|\n| `td_execute_python` | Run arbitrary Python in TD. Full API access. |\n| `td_create_operator` | Create node with params + auto-positioning |\n| `td_set_operator_pars` | Set params safely (validates, won't crash) |\n| `td_get_operator_info` | Inspect one node: connections, params, errors |\n| `td_get_operators_info` | Inspect multiple nodes in one call |\n| `td_get_network` | See network structure at a path |\n| `td_get_errors` | Find errors\u002Fwarnings recursively |\n| `td_get_par_info` | Get param names for an OP type (replaces discovery) |\n| `td_get_hints` | Get patterns\u002Ftips before building |\n| `td_get_focus` | What network is open, what's selected |\n\n**Read\u002FWrite:**\n| Tool | What |\n|------|------|\n| `td_read_dat` | Read DAT text content |\n| `td_write_dat` | Write\u002Fpatch DAT content |\n| `td_read_chop` | Read CHOP channel values |\n| `td_read_textport` | Read TD console output |\n\n**Visual:**\n| Tool | What |\n|------|------|\n| `td_get_screenshot` | Capture one OP viewer to file |\n| `td_get_screenshots` | Capture multiple OPs at once |\n| `td_get_screen_screenshot` | Capture actual screen via TD |\n| `td_navigate_to` | Jump network editor to an OP |\n\n**Search:**\n| Tool | What |\n|------|------|\n| `td_find_op` | Find ops by name\u002Ftype across project |\n| `td_search` | Search code, expressions, string params |\n\n**System:**\n| Tool | What |\n|------|------|\n| `td_get_perf` | Performance profiling (FPS, slow ops) |\n| `td_list_instances` | List all running TD instances |\n| `td_get_docs` | In-depth docs on a TD topic |\n| `td_agents_md` | Read\u002Fwrite per-COMP markdown docs |\n| `td_reinit_extension` | Reload extension after code edit |\n| `td_clear_textport` | Clear console before debug session |\n\n**Input Automation:**\n| Tool | What |\n|------|------|\n| `td_input_execute` | Send mouse\u002Fkeyboard to TD |\n| `td_input_status` | Poll input queue status |\n| `td_input_clear` | Stop input automation |\n| `td_op_screen_rect` | Get screen coords of a node |\n| `td_click_screen_point` | Click a point in a screenshot |\n| `td_screen_point_to_global` | Convert screenshot pixel to absolute screen coords |\n\nThe table above covers the 32 tools used in typical creative workflows. The remaining 4 tools (`td_project_quit`, `td_test_session`, `td_dev_log`, `td_clear_dev_log`) are admin\u002Fdev-mode utilities — see `references\u002Fmcp-tools.md` for the full 36-tool reference with complete parameter schemas.\n\n## Key Implementation Rules\n\n**GLSL time:** No `uTDCurrentTime` in GLSL TOP. Use the Values page:\n```python\n# Call td_get_par_info(op_type=\"glslTOP\") first to confirm param names\ntd_set_operator_pars(path=\"\u002Fproject1\u002Fshader\", parameters={\"value0name\": \"uTime\"})\n# Then set expression via script:\n# op('\u002Fproject1\u002Fshader').par.value0.expr = \"absTime.seconds\"\n# In GLSL: uniform float uTime;\n```\n\nFallback: Constant TOP in `rgba32float` format (8-bit clamps to 0-1, freezing the shader).\n\n**Feedback TOP:** Use `top` parameter reference, not direct input wire. \"Not enough sources\" resolves after first cook. \"Cook dependency loop\" warning is expected.\n\n**Resolution:** Non-Commercial caps at 1280×1280. Use `outputresolution = 'custom'`.\n\n**Large shaders:** Write GLSL to `\u002Ftmp\u002Ffile.glsl`, then use `td_write_dat` or `td_execute_python` to load.\n\n**Vertex\u002FPoint access (TD 2025.32):** `point.P[0]`, `point.P[1]`, `point.P[2]` — NOT `.x`, `.y`, `.z`.\n\n**Extensions:** `ext0object` format is `\"op('.\u002FdatName').module.ClassName(me)\"` in CONSTANT mode. After editing extension code with `td_write_dat`, call `td_reinit_extension`.\n\n**Script callbacks:** ALWAYS use relative paths via `me.parent()` \u002F `scriptOp.parent()`.\n\n**Cleaning nodes:** Always `list(root.children)` before iterating + `child.valid` check.\n\n## Recording \u002F Exporting Video\n\n```python\n# via td_execute_python:\nroot = op('\u002Fproject1')\nrec = root.create(moviefileoutTOP, 'recorder')\nop('\u002Fproject1\u002Fout').outputConnectors[0].connect(rec.inputConnectors[0])\nrec.par.type = 'movie'\nrec.par.file = '\u002Ftmp\u002Foutput.mov'\nrec.par.videocodec = 'prores'  # Apple ProRes — NOT license-restricted on macOS\nrec.par.record = True   # start\n# rec.par.record = False  # stop (call separately later)\n```\n\nH.264\u002FH.265\u002FAV1 need Commercial license. Use `prores` on macOS or `mjpa` as fallback.\nExtract frames: `ffmpeg -i \u002Ftmp\u002Foutput.mov -vframes 120 \u002Ftmp\u002Fframes\u002Fframe_%06d.png`\n\n**TOP.save() is useless for animation** — captures same GPU texture every time. Always use MovieFileOut.\n\n### Before Recording: Checklist\n\n1. **Verify FPS > 0** via `td_get_perf`. If FPS=0 the recording will be empty. See pitfalls #38-39.\n2. **Verify shader output is not black** via `td_get_screenshot`. Black output = shader error or missing input. See pitfalls #8, #40.\n3. **If recording with audio:** cue audio to start first, then delay recording by 3 frames. See pitfalls #19.\n4. **Set output path before starting record** — setting both in the same script can race.\n\n## Audio-Reactive GLSL (Proven Recipe)\n\n### Correct signal chain (tested April 2026)\n\n```\nAudioFileIn CHOP (playmode=sequential)\n  → AudioSpectrum CHOP (FFT=512, outputmenu=setmanually, outlength=256, timeslice=ON)\n  → Math CHOP (gain=10)\n  → CHOP to TOP (dataformat=r, layout=rowscropped)\n  → GLSL TOP input 1 (spectrum texture, 256x2)\n\nConstant TOP (rgba32float, time) → GLSL TOP input 0\nGLSL TOP → Null TOP → MovieFileOut\n```\n\n### Critical audio-reactive rules (empirically verified)\n\n1. **TimeSlice must stay ON** for AudioSpectrum. OFF = processes entire audio file → 24000+ samples → CHOP to TOP overflow.\n2. **Set Output Length manually** to 256 via `outputmenu='setmanually'` and `outlength=256`. Default outputs 22050 samples.\n3. **DO NOT use Lag CHOP for spectrum smoothing.** Lag CHOP operates in timeslice mode and expands 256 samples to 2400+, averaging all values to near-zero (~1e-06). The shader receives no usable data. This was the #1 audio sync failure in testing.\n4. **DO NOT use Filter CHOP either** — same timeslice expansion problem with spectrum data.\n5. **Smoothing belongs in the GLSL shader** if needed, via temporal lerp with a feedback texture: `mix(prevValue, newValue, 0.3)`. This gives frame-perfect sync with zero pipeline latency.\n6. **CHOP to TOP dataformat = 'r'**, layout = 'rowscropped'. Spectrum output is 256x2 (stereo). Sample at y=0.25 for first channel.\n7. **Math gain = 10** (not 5). Raw spectrum values are ~0.19 in bass range. Gain of 10 gives usable ~5.0 for the shader.\n8. **No Resample CHOP needed.** Control output size via AudioSpectrum's `outlength` param directly.\n\n### GLSL spectrum sampling\n\n```glsl\n\u002F\u002F Input 0 = time (1x1 rgba32float), Input 1 = spectrum (256x2)\nfloat iTime = texture(sTD2DInputs[0], vec2(0.5)).r;\n\n\u002F\u002F Sample multiple points per band and average for stability:\n\u002F\u002F NOTE: y=0.25 for first channel (stereo texture is 256x2, first row center is 0.25)\nfloat bass = (texture(sTD2DInputs[1], vec2(0.02, 0.25)).r +\n              texture(sTD2DInputs[1], vec2(0.05, 0.25)).r) \u002F 2.0;\nfloat mid  = (texture(sTD2DInputs[1], vec2(0.2, 0.25)).r +\n              texture(sTD2DInputs[1], vec2(0.35, 0.25)).r) \u002F 2.0;\nfloat hi   = (texture(sTD2DInputs[1], vec2(0.6, 0.25)).r +\n              texture(sTD2DInputs[1], vec2(0.8, 0.25)).r) \u002F 2.0;\n```\n\nSee `references\u002Fnetwork-patterns.md` for complete build scripts + shader code.\n\n## Operator Quick Reference\n\n| Family | Color | Python class \u002F MCP type | Suffix |\n|--------|-------|-------------|--------|\n| TOP | Purple | noiseTOP, glslTOP, compositeTOP, levelTop, blurTOP, textTOP, nullTOP | TOP |\n| CHOP | Green | audiofileinCHOP, audiospectrumCHOP, mathCHOP, lfoCHOP, constantCHOP | CHOP |\n| SOP | Blue | gridSOP, sphereSOP, transformSOP, noiseSOP | SOP |\n| DAT | White | textDAT, tableDAT, scriptDAT, webserverDAT | DAT |\n| MAT | Yellow | phongMAT, pbrMAT, glslMAT, constMAT | MAT |\n| COMP | Gray | geometryCOMP, containerCOMP, cameraCOMP, lightCOMP, windowCOMP | COMP |\n\n## Security Notes\n\n- MCP runs on localhost only (port 40404). No authentication — any local process can send commands.\n- `td_execute_python` has unrestricted access to the TD Python environment and filesystem as the TD process user.\n- `setup.sh` downloads twozero.tox from the official 404zero.com URL. Verify the download if concerned.\n- The skill never sends data outside localhost. All MCP communication is local.\n\n## References\n\n| File | What |\n|------|------|\n| `references\u002Fpitfalls.md` | Hard-won lessons from real sessions |\n| `references\u002Foperators.md` | All operator families with params and use cases |\n| `references\u002Fnetwork-patterns.md` | Recipes: audio-reactive, generative, GLSL, instancing |\n| `references\u002Fmcp-tools.md` | Full twozero MCP tool parameter schemas |\n| `references\u002Fpython-api.md` | TD Python: op(), scripting, extensions |\n| `references\u002Ftroubleshooting.md` | Connection diagnostics, debugging |\n| `references\u002Fglsl.md` | GLSL uniforms, built-in functions, shader templates |\n| `references\u002Fpostfx.md` | Post-FX: bloom, CRT, chromatic aberration, feedback glow |\n| `references\u002Flayout-compositor.md` | HUD layout patterns, panel grids, BSP-style layouts |\n| `references\u002Foperator-tips.md` | Wireframe rendering, feedback TOP setup |\n| `references\u002Fgeometry-comp.md` | Geometry COMP: instancing, POP vs SOP, morphing |\n| `references\u002Faudio-reactive.md` | Audio band extraction, beat detection, envelope following |\n| `references\u002Fanimation.md` | LFOs, timers, keyframes, easing, expression-driven motion |\n| `references\u002Fmidi-osc.md` | MIDI\u002FOSC controllers, TouchOSC, multi-machine sync |\n| `references\u002Fparticles.md` | POPs and legacy particleSOP — emission, forces, collisions |\n| `references\u002Fprojection-mapping.md` | Multi-window output, corner pin, mesh warp, edge blending |\n| `references\u002Fexternal-data.md` | HTTP, WebSocket, MQTT, Serial, TCP, webserverDAT |\n| `references\u002Fpanel-ui.md` | Custom params, panel COMPs, button\u002Fslider\u002Ffield, panelExecuteDAT |\n| `references\u002Freplicator.md` | replicatorCOMP — data-driven cloning, layouts, callbacks |\n| `references\u002Fdat-scripting.md` | Execute DAT family — chop\u002Fdat\u002Fparameter\u002Fpanel\u002Fop\u002FexecuteDAT |\n| `references\u002F3d-scene.md` | Lighting rigs, shadows, IBL\u002Fcubemaps, multi-camera, PBR |\n| `scripts\u002Fsetup.sh` | Automated setup script |\n\n---\n\n> You're not writing code. You're conducting light.\n",{"name":5,"author":52,"license":15,"version":53,"metadata":54,"platforms":65,"description":7},"kshitijk4poor","1.1.0",{"hermes":55},{"tags":56,"related_skills":62},[57,28,58,31,59,32,60,61,37,33],"TouchDesigner","twozero","real-time-visuals","audio-reactive","VJ",[63,64],"ascii-video","manim-video",[45,46,44],"main","0d1434f89f4bc6b07e9d272accd8c1013768820f","archive\u002Fskill-md-reviewed\u002Fsha256\u002F92\u002F925c387c16a3a0752e4670d48ab9bde94f930cd3dd27fe08cefda2e05c0765e9",0,"https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills","https:\u002F\u002Fgithub.com\u002Fzapabob","The Open University of JAPAN　2019-now\r\n\r\nTokyo University of Science　2007-2010","2026-10-26 16:29:01",{"source":8,"skillName":5,"commands":75,"prompt":85,"zipAvailable":86},[76,79,82],{"tool":77,"command":78},"npx","npx skills add zapabob\u002FSkills --skill touchdesigner-mcp",{"tool":80,"command":81},"bunx","bunx skills add zapabob\u002FSkills --skill touchdesigner-mcp",{"tool":83,"command":84},"pnpm","pnpm dlx skills add zapabob\u002FSkills --skill touchdesigner-mcp","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Farchive\u002Fskill-md-reviewed\u002Fsha256\u002F92\u002F925c387c16a3a0752e4670d48ab9bde94f930cd3dd27fe08cefda2e05c0765e9\u002FSKILL.md",true,[],[89,119,154,178,203,220],{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":104,"publishedAt":47},"01M6GJTE1GESGGF9K028Y7753E","xurl","X\u002FTwitter via xurl CLI: post, search, DM, media, v2 API.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fxurl\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[95,98,99],{"categoryNo":96,"categoryName":97,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":100,"categoryName":101,"taxonomyType":102,"taxonomyTypeDesc":103},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[91,105,46,106,107,45,44,108,109,110,111,112,113,114,115,116,66,117,34,118],"openclaw","cli","github","official","search","https","social-media","api","Media","hermes","hermes agent","twitter","social","post",{"skillNo":120,"name":121,"nameZh":6,"description":122,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":136,"publishedAt":47},"01M6GJT8S1PXQ8WPXT1HSNBWH2","writing-plans","Write implementation plans: bite-sized tasks, paths, code.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fwriting-plans\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[125,128,131,132,133],{"categoryNo":126,"categoryName":127,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":129,"categoryName":130,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":100,"categoryName":101,"taxonomyType":102,"taxonomyTypeDesc":103},{"categoryNo":134,"categoryName":135,"taxonomyType":102,"taxonomyTypeDesc":103},"01JBSEEDCAT000000000000036","内容创作者",[137,138,139,140,46,141,45,142,44,143,144,145,146,147,148,149,150,151,152,153],"writing","writing plans","plans","design","review","workflow","documentation","tasks","development","code","planning","code-review","subagent","write","superpowers","paths","test-driven-development",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":161,"publishedAt":47},"01M6GJST0H5X7WHBJ3BZK0DVKH","whisper","OpenAI's general-purpose speech recognition model. Supports 99 languages, transcription, translation to English, and language identification. Six model sizes from tiny (39M params) to large (1550M params). Use for speech-to-text, podcast transcription, or multilingual audio processing. Best for robust, multilingual ASR.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fwhisper\u002Fvariants\u002Fhermes-agent-optional\u002FSKILL.md",[160],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[156,46,45,162,163,164,165,166,40,167,168,169,170,171,172,173,174,175,176,177],"openai","speech","multimodal","Transformers","ASR","text","model","speech recognition","use","general","multilingual","translation","english","identification","processing","Audio Processing",{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":187,"publishedAt":47},"01M6GJSMRQ8EETZTYMG72P70EA","weights-and-biases","W&B: log ML experiments, sweeps, model registry, dashboards.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fweights-and-biases\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[184],{"categoryNo":185,"categoryName":186,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化",[188,46,189,190,44,191,192,193,42,194,195,168,196,197,38,198,199,200,201,202],"weights and biases","tensorflow","experiments","pytorch","visualization","registry","tuning","dashboards","experiment","log","Experiment Tracking","Model Registry","Hyperparameter Tuning","WandB","Real-Time Visualization",{"skillNo":204,"name":205,"nameZh":6,"description":206,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":207,"categories":208,"keywords":210,"publishedAt":47},"01M6GJS19KDPRY112JTR326S06","watchers","Poll RSS, JSON APIs, and GitHub with watermark dedup.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fwatchers\u002Fvariants\u002Fhermes-agent-optional\u002FSKILL.md",[209],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[205,46,211,107,45,212,213,214,215,216,217,114,115,218,219],"terminal","automation","http","monitoring","cron","json","rss","devops","with",{"skillNo":221,"name":222,"nameZh":6,"description":223,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":224,"categories":225,"keywords":228,"publishedAt":47},"01M6GJRHJD2A6Q830SWF9W48BC","serving-llms-vllm","vLLM: high-throughput LLM serving, OpenAI API, quantization.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fvllm\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[226,227],{"categoryNo":96,"categoryName":97,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":100,"categoryName":101,"taxonomyType":102,"taxonomyTypeDesc":103},[229,230,231,45,232,162,233,234,235,165,236,112,237,238,239,240,241,242,243,244],"llms","vLLM","serving llms vllm","research","openai api","tensor","Inference Serving","Production","llm serving","High Throughput","PagedAttention","Continuous Batching","Quantization","Tensor Parallelism","high-throughput","throughput"]