@dpantani/tdmcp 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -7
- package/dist/cli/agent.d.ts +13 -0
- package/dist/cli/agent.js +12324 -1726
- package/dist/cli/agent.js.map +1 -1
- package/dist/index.js +27930 -14302
- package/dist/index.js.map +1 -1
- package/dist/recipes/animus_rings_visualizer.json +37 -0
- package/dist/recipes/body_tracking_reactive.json +127 -0
- package/dist/recipes/mediapipe_body_dots.json +86 -0
- package/dist/recipes/pose_skeleton_mediapipe.json +67 -0
- package/package.json +16 -5
- package/recipes/animus_rings_visualizer.json +37 -0
- package/recipes/body_tracking_reactive.json +127 -0
- package/recipes/mediapipe_body_dots.json +86 -0
- package/recipes/pose_skeleton_mediapipe.json +67 -0
- package/scripts/fetch-shader-park-td.mjs +79 -0
- package/scripts/tdmcp-lops.mjs +52 -0
- package/td/modules/utils/version.py +1 -1
- package/td/tests/test_api_controller.py +0 -307
- package/td/tests/test_services.py +0 -209
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "animus_rings_visualizer",
|
|
3
|
+
"name": "Animus Rings Visualizer",
|
|
4
|
+
"description": "A native TouchDesigner audio rings visualizer inspired by codygibb/animus-visualizer. It uses a synthetic oscillator by default, so it previews without microphone permissions or any Processing/Java runtime.",
|
|
5
|
+
"tags": ["audio-reactive", "rings", "music", "animus", "native-td"],
|
|
6
|
+
"difficulty": "beginner",
|
|
7
|
+
"td_version_min": "2022",
|
|
8
|
+
"nodes": [
|
|
9
|
+
{
|
|
10
|
+
"name": "osc",
|
|
11
|
+
"type": "audiooscillatorCHOP",
|
|
12
|
+
"parameters": { "freq": 96, "amp": 0.85 },
|
|
13
|
+
"comment": "Synthetic audio driver; swap for Audio Device In or Audio File In for a live set"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "audio_tex",
|
|
17
|
+
"type": "choptoTOP",
|
|
18
|
+
"comment": "Converts the audio channel into a tiny texture the shader can sample"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "rings",
|
|
22
|
+
"type": "glslTOP",
|
|
23
|
+
"parameters": { "outputresolution": "custom", "resolutionw": 1280, "resolutionh": 720 },
|
|
24
|
+
"comment": "Draws radial rings and droplets from the audio texture"
|
|
25
|
+
},
|
|
26
|
+
{ "name": "out1", "type": "nullTOP" }
|
|
27
|
+
],
|
|
28
|
+
"connections": [
|
|
29
|
+
{ "from": "osc", "to": "audio_tex" },
|
|
30
|
+
{ "from": "audio_tex", "to": "rings" },
|
|
31
|
+
{ "from": "rings", "to": "out1" }
|
|
32
|
+
],
|
|
33
|
+
"glsl_code": {
|
|
34
|
+
"rings": "out vec4 fragColor;\nvoid main(){\n vec2 uv = vUV.st;\n vec2 p = (uv - 0.5) * vec2(1.777, 1.0) * 2.0;\n float radius = length(p);\n float angle = atan(p.y, p.x);\n float amp = abs(texture(sTD2DInputs[0], vec2(fract(radius * 0.35), 0.5)).r);\n float ringPhase = fract(radius * 9.0 - amp * 2.5);\n float ring = 1.0 - smoothstep(0.035, 0.09, abs(ringPhase - 0.5));\n float droplets = smoothstep(0.96, 1.0, sin(angle * 18.0 + amp * 12.0) * 0.5 + 0.5);\n float core = smoothstep(0.55 + amp * 0.25, 0.0, radius);\n vec3 ink = vec3(0.025, 0.015, 0.045);\n vec3 cyan = vec3(0.10, 0.92, 1.0);\n vec3 magenta = vec3(1.0, 0.15, 0.55);\n vec3 col = ink + cyan * ring * (0.45 + amp * 1.8);\n col += magenta * droplets * ring * (0.2 + amp * 1.4);\n col += vec3(1.0, 0.75, 0.35) * core * (0.3 + amp);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n"
|
|
35
|
+
},
|
|
36
|
+
"preview_description": "Concentric neon rings pulse from a warm center, with small radial droplet accents reacting to the audio signal."
|
|
37
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "body_tracking_reactive",
|
|
3
|
+
"name": "Body Tracking Reactive",
|
|
4
|
+
"description": "A camera-reactive performance look: the 33 MediaPipe body landmarks become glowing dots that leave luminous motion trails as the performer moves, via a feedback loop. Point the 'posein' Select CHOP at the pose-landmarks CHOP from the free torinmb/mediapipe-touchdesigner plugin (33 samples, tx/ty/tz) — webcam only, no Kinect or extra hardware. Run setup_body_tracking first to load the engine and emit that CHOP, or use create_body_reactive for a self-contained synthetic preview.",
|
|
5
|
+
"tags": ["mediapipe", "pose", "body-tracking", "reactive", "feedback", "camera", "performance"],
|
|
6
|
+
"difficulty": "advanced",
|
|
7
|
+
"td_version_min": "2022",
|
|
8
|
+
"nodes": [
|
|
9
|
+
{
|
|
10
|
+
"name": "posein",
|
|
11
|
+
"type": "selectCHOP",
|
|
12
|
+
"comment": "Set 'chop' to the MediaPipe plugin's pose-landmarks CHOP (33 samples, tx/ty/tz)"
|
|
13
|
+
},
|
|
14
|
+
{ "name": "geo", "type": "geometryCOMP" },
|
|
15
|
+
{
|
|
16
|
+
"name": "dot",
|
|
17
|
+
"type": "sphereSOP",
|
|
18
|
+
"parameters": { "radx": 0.035, "rady": 0.035, "radz": 0.035 },
|
|
19
|
+
"parent": "geo",
|
|
20
|
+
"comment": "The mark stamped on each landmark"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "pts",
|
|
24
|
+
"type": "choptoSOP",
|
|
25
|
+
"parent": "geo",
|
|
26
|
+
"comment": "33 landmark samples become 33 points (tx/ty/tz map to position)"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "copy",
|
|
30
|
+
"type": "copySOP",
|
|
31
|
+
"parent": "geo",
|
|
32
|
+
"render": true,
|
|
33
|
+
"comment": "Stamp the dot on every landmark point"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "dotmat",
|
|
37
|
+
"type": "constantMAT",
|
|
38
|
+
"parameters": { "colorr": 0.2, "colorg": 1, "colorb": 0.9 }
|
|
39
|
+
},
|
|
40
|
+
{ "name": "cam", "type": "cameraCOMP", "parameters": { "tz": 4.6 } },
|
|
41
|
+
{
|
|
42
|
+
"name": "render",
|
|
43
|
+
"type": "renderTOP",
|
|
44
|
+
"parameters": {
|
|
45
|
+
"outputresolution": "custom",
|
|
46
|
+
"resolutionw": 1280,
|
|
47
|
+
"resolutionh": 720,
|
|
48
|
+
"antialias": "3"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "feedback1",
|
|
53
|
+
"type": "feedbackTOP",
|
|
54
|
+
"comment": "Holds the previous (decayed) frame — the motion trail"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "comp1",
|
|
58
|
+
"type": "compositeTOP",
|
|
59
|
+
"parameters": { "operand": "add" },
|
|
60
|
+
"comment": "Add the live dots over the fed-back trail"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "decay",
|
|
64
|
+
"type": "levelTOP",
|
|
65
|
+
"parameters": { "brightness1": 0.92 },
|
|
66
|
+
"comment": "Trail decay / feedback gain — higher = longer trails"
|
|
67
|
+
},
|
|
68
|
+
{ "name": "bloom", "type": "blurTOP", "parameters": { "size": 12 } },
|
|
69
|
+
{
|
|
70
|
+
"name": "glow",
|
|
71
|
+
"type": "compositeTOP",
|
|
72
|
+
"parameters": { "operand": "add" },
|
|
73
|
+
"comment": "Add a bloom of the trail for the luminous glow"
|
|
74
|
+
},
|
|
75
|
+
{ "name": "out1", "type": "nullTOP", "comment": "Output of the system" }
|
|
76
|
+
],
|
|
77
|
+
"connections": [
|
|
78
|
+
{ "from": "dot", "to": "copy", "to_input": 0 },
|
|
79
|
+
{ "from": "pts", "to": "copy", "to_input": 1 },
|
|
80
|
+
{ "from": "render", "to": "feedback1" },
|
|
81
|
+
{ "from": "render", "to": "comp1", "to_input": 0 },
|
|
82
|
+
{ "from": "feedback1", "to": "comp1", "to_input": 1 },
|
|
83
|
+
{ "from": "comp1", "to": "decay" },
|
|
84
|
+
{ "from": "decay", "to": "bloom" },
|
|
85
|
+
{ "from": "decay", "to": "glow", "to_input": 0 },
|
|
86
|
+
{ "from": "bloom", "to": "glow", "to_input": 1 },
|
|
87
|
+
{ "from": "glow", "to": "out1" }
|
|
88
|
+
],
|
|
89
|
+
"parameters": [
|
|
90
|
+
{
|
|
91
|
+
"name": "landmarks_chop",
|
|
92
|
+
"node": "pts",
|
|
93
|
+
"param": "chop",
|
|
94
|
+
"value": "posein",
|
|
95
|
+
"label": "Landmarks CHOP"
|
|
96
|
+
},
|
|
97
|
+
{ "name": "material", "node": "geo", "param": "material", "value": "dotmat" },
|
|
98
|
+
{ "name": "geometry", "node": "render", "param": "geometry", "value": "geo" },
|
|
99
|
+
{ "name": "camera", "node": "render", "param": "camera", "value": "cam" },
|
|
100
|
+
{
|
|
101
|
+
"name": "feedback_target",
|
|
102
|
+
"node": "feedback1",
|
|
103
|
+
"param": "top",
|
|
104
|
+
"value": "decay",
|
|
105
|
+
"description": "feedbackTOP samples the decayed composite (decay), forming the trail loop. Value resolves to the created node path."
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"controls": [
|
|
109
|
+
{
|
|
110
|
+
"name": "TrailLength",
|
|
111
|
+
"type": "float",
|
|
112
|
+
"min": 0,
|
|
113
|
+
"max": 1,
|
|
114
|
+
"default": 0.92,
|
|
115
|
+
"bind_to": ["decay.brightness1"]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "GlowAmount",
|
|
119
|
+
"type": "float",
|
|
120
|
+
"min": 0,
|
|
121
|
+
"max": 48,
|
|
122
|
+
"default": 12,
|
|
123
|
+
"bind_to": ["bloom.size"]
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"preview_description": "Cyan glowing dots tracing a person's joints, smearing into luminous trails as they move in front of the webcam — a hands-free reactive performance look."
|
|
127
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mediapipe_body_dots",
|
|
3
|
+
"name": "MediaPipe Body Dots",
|
|
4
|
+
"description": "Glowing dots that track the 33 MediaPipe body landmarks. Point the 'posein' Select CHOP at the pose-landmarks CHOP from the free torinmb/mediapipe-touchdesigner plugin (33 samples, tx/ty/tz). Webcam only — no Kinect or extra hardware. Or use create_body_reactive for a self-contained synthetic preview.",
|
|
5
|
+
"tags": ["mediapipe", "pose", "body-tracking", "interactive", "camera"],
|
|
6
|
+
"difficulty": "intermediate",
|
|
7
|
+
"td_version_min": "2022",
|
|
8
|
+
"nodes": [
|
|
9
|
+
{
|
|
10
|
+
"name": "posein",
|
|
11
|
+
"type": "selectCHOP",
|
|
12
|
+
"comment": "Set 'chops' to the MediaPipe plugin's pose-landmarks CHOP (33 samples, tx/ty/tz)"
|
|
13
|
+
},
|
|
14
|
+
{ "name": "geo", "type": "geometryCOMP" },
|
|
15
|
+
{
|
|
16
|
+
"name": "dot",
|
|
17
|
+
"type": "sphereSOP",
|
|
18
|
+
"parameters": { "radx": 0.03, "rady": 0.03, "radz": 0.03 },
|
|
19
|
+
"parent": "geo",
|
|
20
|
+
"comment": "The mark stamped on each landmark"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "pts",
|
|
24
|
+
"type": "choptoSOP",
|
|
25
|
+
"parent": "geo",
|
|
26
|
+
"comment": "33 landmark samples become 33 points (tx/ty/tz map to position)"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "copy",
|
|
30
|
+
"type": "copySOP",
|
|
31
|
+
"parent": "geo",
|
|
32
|
+
"render": true,
|
|
33
|
+
"comment": "Stamp the dot on every landmark point"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "dotmat",
|
|
37
|
+
"type": "constantMAT",
|
|
38
|
+
"parameters": { "colorr": 1, "colorg": 0.25, "colorb": 0.8 }
|
|
39
|
+
},
|
|
40
|
+
{ "name": "cam", "type": "cameraCOMP", "parameters": { "tz": 4.6 } },
|
|
41
|
+
{
|
|
42
|
+
"name": "render",
|
|
43
|
+
"type": "renderTOP",
|
|
44
|
+
"parameters": {
|
|
45
|
+
"outputresolution": "custom",
|
|
46
|
+
"resolutionw": 1280,
|
|
47
|
+
"resolutionh": 720,
|
|
48
|
+
"antialias": "3"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{ "name": "bloom", "type": "blurTOP", "parameters": { "size": 16 } },
|
|
52
|
+
{ "name": "glow", "type": "compositeTOP", "parameters": { "operand": "add" } },
|
|
53
|
+
{ "name": "out1", "type": "nullTOP" }
|
|
54
|
+
],
|
|
55
|
+
"connections": [
|
|
56
|
+
{ "from": "dot", "to": "copy", "to_input": 0 },
|
|
57
|
+
{ "from": "pts", "to": "copy", "to_input": 1 },
|
|
58
|
+
{ "from": "render", "to": "bloom" },
|
|
59
|
+
{ "from": "render", "to": "glow", "to_input": 0 },
|
|
60
|
+
{ "from": "bloom", "to": "glow", "to_input": 1 },
|
|
61
|
+
{ "from": "glow", "to": "out1" }
|
|
62
|
+
],
|
|
63
|
+
"parameters": [
|
|
64
|
+
{
|
|
65
|
+
"name": "landmarks_chop",
|
|
66
|
+
"node": "pts",
|
|
67
|
+
"param": "chop",
|
|
68
|
+
"value": "posein",
|
|
69
|
+
"label": "Landmarks CHOP"
|
|
70
|
+
},
|
|
71
|
+
{ "name": "material", "node": "geo", "param": "material", "value": "dotmat" },
|
|
72
|
+
{ "name": "geometry", "node": "render", "param": "geometry", "value": "geo" },
|
|
73
|
+
{ "name": "camera", "node": "render", "param": "camera", "value": "cam" }
|
|
74
|
+
],
|
|
75
|
+
"controls": [
|
|
76
|
+
{
|
|
77
|
+
"name": "GlowAmount",
|
|
78
|
+
"type": "float",
|
|
79
|
+
"min": 0,
|
|
80
|
+
"max": 64,
|
|
81
|
+
"default": 16,
|
|
82
|
+
"bind_to": ["bloom.size"]
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"preview_description": "Hot-pink glowing dots tracing a person's joints — head, hands, elbows, hips, knees, feet — as they move in front of the webcam."
|
|
86
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "pose_skeleton_mediapipe",
|
|
3
|
+
"name": "Pose Skeleton (MediaPipe)",
|
|
4
|
+
"description": "A live stick-figure skeleton drawn from the 33 MediaPipe body landmarks (the classic body-tracking look). Point the 'posein' Select CHOP at the pose-landmarks CHOP from the free torinmb/mediapipe-touchdesigner plugin. Webcam only — no Kinect or extra hardware. Or use create_pose_skeleton for a self-contained synthetic preview.",
|
|
5
|
+
"tags": ["mediapipe", "pose", "skeleton", "body-tracking", "camera"],
|
|
6
|
+
"difficulty": "advanced",
|
|
7
|
+
"td_version_min": "2022",
|
|
8
|
+
"nodes": [
|
|
9
|
+
{
|
|
10
|
+
"name": "posein",
|
|
11
|
+
"type": "selectCHOP",
|
|
12
|
+
"comment": "Set 'chops' to the MediaPipe plugin's pose-landmarks CHOP (33 samples, tx/ty/tz)"
|
|
13
|
+
},
|
|
14
|
+
{ "name": "geo", "type": "geometryCOMP" },
|
|
15
|
+
{
|
|
16
|
+
"name": "skeleton",
|
|
17
|
+
"type": "scriptSOP",
|
|
18
|
+
"parent": "geo",
|
|
19
|
+
"render": true,
|
|
20
|
+
"comment": "onCook builds a point per landmark + a polyline per bone"
|
|
21
|
+
},
|
|
22
|
+
{ "name": "skel_cb", "type": "textDAT", "parent": "geo", "comment": "Script SOP callbacks" },
|
|
23
|
+
{
|
|
24
|
+
"name": "wire",
|
|
25
|
+
"type": "lineMAT",
|
|
26
|
+
"parameters": {
|
|
27
|
+
"linenearcolorr": 0.2,
|
|
28
|
+
"linenearcolorg": 1.0,
|
|
29
|
+
"linenearcolorb": 0.9,
|
|
30
|
+
"widthnear": 3
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{ "name": "cam", "type": "cameraCOMP", "parameters": { "tz": 4.6 } },
|
|
34
|
+
{
|
|
35
|
+
"name": "render",
|
|
36
|
+
"type": "renderTOP",
|
|
37
|
+
"parameters": {
|
|
38
|
+
"outputresolution": "custom",
|
|
39
|
+
"resolutionw": 1280,
|
|
40
|
+
"resolutionh": 720,
|
|
41
|
+
"antialias": "3"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{ "name": "out1", "type": "nullTOP" }
|
|
45
|
+
],
|
|
46
|
+
"connections": [{ "from": "render", "to": "out1" }],
|
|
47
|
+
"parameters": [
|
|
48
|
+
{ "name": "callbacks", "node": "skeleton", "param": "callbacks", "value": "skel_cb" },
|
|
49
|
+
{ "name": "material", "node": "geo", "param": "material", "value": "wire" },
|
|
50
|
+
{ "name": "geometry", "node": "render", "param": "geometry", "value": "geo" },
|
|
51
|
+
{ "name": "camera", "node": "render", "param": "camera", "value": "cam" }
|
|
52
|
+
],
|
|
53
|
+
"python_code": {
|
|
54
|
+
"skel_cb": "BONES = [[0,1],[1,2],[2,3],[3,7],[0,4],[4,5],[5,6],[6,8],[9,10],[11,12],[11,13],[13,15],[15,17],[15,19],[15,21],[17,19],[12,14],[14,16],[16,18],[16,20],[16,22],[18,20],[11,23],[12,24],[23,24],[23,25],[25,27],[27,29],[27,31],[29,31],[24,26],[26,28],[28,30],[28,32],[30,32]]\n\ndef onCook(scriptOp):\n scriptOp.clear()\n pose = op('../posein')\n if pose is None or pose.numChans < 3 or pose.numSamples < 1:\n return\n tx = pose['tx']; ty = pose['ty']; tz = pose['tz']\n if tx is None or ty is None or tz is None:\n return\n n = pose.numSamples\n pts = []\n for i in range(n):\n p = scriptOp.appendPoint()\n p.x = float(tx[i]); p.y = float(ty[i]); p.z = float(tz[i])\n pts.append(p)\n for a, b in BONES:\n if a < n and b < n:\n poly = scriptOp.appendPoly(2, closed=False, addPoints=False)\n poly[0].point = pts[a]\n poly[1].point = pts[b]\n return\n"
|
|
55
|
+
},
|
|
56
|
+
"controls": [
|
|
57
|
+
{
|
|
58
|
+
"name": "LineWidth",
|
|
59
|
+
"type": "float",
|
|
60
|
+
"min": 0,
|
|
61
|
+
"max": 20,
|
|
62
|
+
"default": 3,
|
|
63
|
+
"bind_to": ["wire.widthnear"]
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"preview_description": "A glowing cyan skeleton mirroring the performer's body in real time against black."
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dpantani/tdmcp",
|
|
3
3
|
"mcpName": "io.github.Pantani/tdmcp",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"description": "tdmcp — the TouchDesigner MCP server. Build real TouchDesigner visual systems from plain language with Claude, Cursor, or Codex (Model Context Protocol).",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -23,8 +23,14 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
|
+
"scripts/fetch-shader-park-td.mjs",
|
|
27
|
+
"scripts/tdmcp-lops.mjs",
|
|
26
28
|
"recipes",
|
|
27
|
-
"td",
|
|
29
|
+
"td/bootstrap.py",
|
|
30
|
+
"td/modules",
|
|
31
|
+
"td/README.md",
|
|
32
|
+
"td/startup.py",
|
|
33
|
+
"td/templates",
|
|
28
34
|
"README.md",
|
|
29
35
|
"LICENSE"
|
|
30
36
|
],
|
|
@@ -35,14 +41,18 @@
|
|
|
35
41
|
"start": "node dist/index.js",
|
|
36
42
|
"lint": "biome check .",
|
|
37
43
|
"format": "biome format --write .",
|
|
38
|
-
"test": "vitest run",
|
|
39
|
-
"test:
|
|
44
|
+
"test": "node scripts/run-vitest.mjs run",
|
|
45
|
+
"test:coverage": "node scripts/run-vitest.mjs run --coverage",
|
|
46
|
+
"test:watch": "node scripts/run-vitest.mjs",
|
|
47
|
+
"coverage:harness": "node scripts/coverage-harness.mjs",
|
|
40
48
|
"test:bridge": "python3 -m unittest discover -s td/tests",
|
|
41
49
|
"typecheck": "tsc --noEmit",
|
|
42
50
|
"import:bottobot": "tsx scripts/import-bottobot-data.ts",
|
|
43
51
|
"validate:recipes": "tsx scripts/validate-recipes.ts",
|
|
44
52
|
"smoke:live": "tsx scripts/smoke-live.ts",
|
|
45
|
-
"
|
|
53
|
+
"shader-park:tox": "node scripts/fetch-shader-park-td.mjs",
|
|
54
|
+
"smoke:packages": "tsx scripts/smoke-packages.ts",
|
|
55
|
+
"build:mcpb": "node scripts/build-dxt.mjs",
|
|
46
56
|
"docs:gen": "tsx scripts/gen-tool-docs.ts",
|
|
47
57
|
"docs:dev": "npm run docs:gen && vitepress dev docs",
|
|
48
58
|
"docs:build": "npm run docs:gen && vitepress build docs",
|
|
@@ -75,6 +85,7 @@
|
|
|
75
85
|
"dependencies": {
|
|
76
86
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
77
87
|
"gray-matter": "^4.0.3",
|
|
88
|
+
"shader-park-core": "^0.2.8",
|
|
78
89
|
"zod": "^4.4.3"
|
|
79
90
|
},
|
|
80
91
|
"devDependencies": {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "animus_rings_visualizer",
|
|
3
|
+
"name": "Animus Rings Visualizer",
|
|
4
|
+
"description": "A native TouchDesigner audio rings visualizer inspired by codygibb/animus-visualizer. It uses a synthetic oscillator by default, so it previews without microphone permissions or any Processing/Java runtime.",
|
|
5
|
+
"tags": ["audio-reactive", "rings", "music", "animus", "native-td"],
|
|
6
|
+
"difficulty": "beginner",
|
|
7
|
+
"td_version_min": "2022",
|
|
8
|
+
"nodes": [
|
|
9
|
+
{
|
|
10
|
+
"name": "osc",
|
|
11
|
+
"type": "audiooscillatorCHOP",
|
|
12
|
+
"parameters": { "freq": 96, "amp": 0.85 },
|
|
13
|
+
"comment": "Synthetic audio driver; swap for Audio Device In or Audio File In for a live set"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "audio_tex",
|
|
17
|
+
"type": "choptoTOP",
|
|
18
|
+
"comment": "Converts the audio channel into a tiny texture the shader can sample"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "rings",
|
|
22
|
+
"type": "glslTOP",
|
|
23
|
+
"parameters": { "outputresolution": "custom", "resolutionw": 1280, "resolutionh": 720 },
|
|
24
|
+
"comment": "Draws radial rings and droplets from the audio texture"
|
|
25
|
+
},
|
|
26
|
+
{ "name": "out1", "type": "nullTOP" }
|
|
27
|
+
],
|
|
28
|
+
"connections": [
|
|
29
|
+
{ "from": "osc", "to": "audio_tex" },
|
|
30
|
+
{ "from": "audio_tex", "to": "rings" },
|
|
31
|
+
{ "from": "rings", "to": "out1" }
|
|
32
|
+
],
|
|
33
|
+
"glsl_code": {
|
|
34
|
+
"rings": "out vec4 fragColor;\nvoid main(){\n vec2 uv = vUV.st;\n vec2 p = (uv - 0.5) * vec2(1.777, 1.0) * 2.0;\n float radius = length(p);\n float angle = atan(p.y, p.x);\n float amp = abs(texture(sTD2DInputs[0], vec2(fract(radius * 0.35), 0.5)).r);\n float ringPhase = fract(radius * 9.0 - amp * 2.5);\n float ring = 1.0 - smoothstep(0.035, 0.09, abs(ringPhase - 0.5));\n float droplets = smoothstep(0.96, 1.0, sin(angle * 18.0 + amp * 12.0) * 0.5 + 0.5);\n float core = smoothstep(0.55 + amp * 0.25, 0.0, radius);\n vec3 ink = vec3(0.025, 0.015, 0.045);\n vec3 cyan = vec3(0.10, 0.92, 1.0);\n vec3 magenta = vec3(1.0, 0.15, 0.55);\n vec3 col = ink + cyan * ring * (0.45 + amp * 1.8);\n col += magenta * droplets * ring * (0.2 + amp * 1.4);\n col += vec3(1.0, 0.75, 0.35) * core * (0.3 + amp);\n fragColor = TDOutputSwizzle(vec4(col, 1.0));\n}\n"
|
|
35
|
+
},
|
|
36
|
+
"preview_description": "Concentric neon rings pulse from a warm center, with small radial droplet accents reacting to the audio signal."
|
|
37
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "body_tracking_reactive",
|
|
3
|
+
"name": "Body Tracking Reactive",
|
|
4
|
+
"description": "A camera-reactive performance look: the 33 MediaPipe body landmarks become glowing dots that leave luminous motion trails as the performer moves, via a feedback loop. Point the 'posein' Select CHOP at the pose-landmarks CHOP from the free torinmb/mediapipe-touchdesigner plugin (33 samples, tx/ty/tz) — webcam only, no Kinect or extra hardware. Run setup_body_tracking first to load the engine and emit that CHOP, or use create_body_reactive for a self-contained synthetic preview.",
|
|
5
|
+
"tags": ["mediapipe", "pose", "body-tracking", "reactive", "feedback", "camera", "performance"],
|
|
6
|
+
"difficulty": "advanced",
|
|
7
|
+
"td_version_min": "2022",
|
|
8
|
+
"nodes": [
|
|
9
|
+
{
|
|
10
|
+
"name": "posein",
|
|
11
|
+
"type": "selectCHOP",
|
|
12
|
+
"comment": "Set 'chop' to the MediaPipe plugin's pose-landmarks CHOP (33 samples, tx/ty/tz)"
|
|
13
|
+
},
|
|
14
|
+
{ "name": "geo", "type": "geometryCOMP" },
|
|
15
|
+
{
|
|
16
|
+
"name": "dot",
|
|
17
|
+
"type": "sphereSOP",
|
|
18
|
+
"parameters": { "radx": 0.035, "rady": 0.035, "radz": 0.035 },
|
|
19
|
+
"parent": "geo",
|
|
20
|
+
"comment": "The mark stamped on each landmark"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "pts",
|
|
24
|
+
"type": "choptoSOP",
|
|
25
|
+
"parent": "geo",
|
|
26
|
+
"comment": "33 landmark samples become 33 points (tx/ty/tz map to position)"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "copy",
|
|
30
|
+
"type": "copySOP",
|
|
31
|
+
"parent": "geo",
|
|
32
|
+
"render": true,
|
|
33
|
+
"comment": "Stamp the dot on every landmark point"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "dotmat",
|
|
37
|
+
"type": "constantMAT",
|
|
38
|
+
"parameters": { "colorr": 0.2, "colorg": 1, "colorb": 0.9 }
|
|
39
|
+
},
|
|
40
|
+
{ "name": "cam", "type": "cameraCOMP", "parameters": { "tz": 4.6 } },
|
|
41
|
+
{
|
|
42
|
+
"name": "render",
|
|
43
|
+
"type": "renderTOP",
|
|
44
|
+
"parameters": {
|
|
45
|
+
"outputresolution": "custom",
|
|
46
|
+
"resolutionw": 1280,
|
|
47
|
+
"resolutionh": 720,
|
|
48
|
+
"antialias": "3"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "feedback1",
|
|
53
|
+
"type": "feedbackTOP",
|
|
54
|
+
"comment": "Holds the previous (decayed) frame — the motion trail"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "comp1",
|
|
58
|
+
"type": "compositeTOP",
|
|
59
|
+
"parameters": { "operand": "add" },
|
|
60
|
+
"comment": "Add the live dots over the fed-back trail"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "decay",
|
|
64
|
+
"type": "levelTOP",
|
|
65
|
+
"parameters": { "brightness1": 0.92 },
|
|
66
|
+
"comment": "Trail decay / feedback gain — higher = longer trails"
|
|
67
|
+
},
|
|
68
|
+
{ "name": "bloom", "type": "blurTOP", "parameters": { "size": 12 } },
|
|
69
|
+
{
|
|
70
|
+
"name": "glow",
|
|
71
|
+
"type": "compositeTOP",
|
|
72
|
+
"parameters": { "operand": "add" },
|
|
73
|
+
"comment": "Add a bloom of the trail for the luminous glow"
|
|
74
|
+
},
|
|
75
|
+
{ "name": "out1", "type": "nullTOP", "comment": "Output of the system" }
|
|
76
|
+
],
|
|
77
|
+
"connections": [
|
|
78
|
+
{ "from": "dot", "to": "copy", "to_input": 0 },
|
|
79
|
+
{ "from": "pts", "to": "copy", "to_input": 1 },
|
|
80
|
+
{ "from": "render", "to": "feedback1" },
|
|
81
|
+
{ "from": "render", "to": "comp1", "to_input": 0 },
|
|
82
|
+
{ "from": "feedback1", "to": "comp1", "to_input": 1 },
|
|
83
|
+
{ "from": "comp1", "to": "decay" },
|
|
84
|
+
{ "from": "decay", "to": "bloom" },
|
|
85
|
+
{ "from": "decay", "to": "glow", "to_input": 0 },
|
|
86
|
+
{ "from": "bloom", "to": "glow", "to_input": 1 },
|
|
87
|
+
{ "from": "glow", "to": "out1" }
|
|
88
|
+
],
|
|
89
|
+
"parameters": [
|
|
90
|
+
{
|
|
91
|
+
"name": "landmarks_chop",
|
|
92
|
+
"node": "pts",
|
|
93
|
+
"param": "chop",
|
|
94
|
+
"value": "posein",
|
|
95
|
+
"label": "Landmarks CHOP"
|
|
96
|
+
},
|
|
97
|
+
{ "name": "material", "node": "geo", "param": "material", "value": "dotmat" },
|
|
98
|
+
{ "name": "geometry", "node": "render", "param": "geometry", "value": "geo" },
|
|
99
|
+
{ "name": "camera", "node": "render", "param": "camera", "value": "cam" },
|
|
100
|
+
{
|
|
101
|
+
"name": "feedback_target",
|
|
102
|
+
"node": "feedback1",
|
|
103
|
+
"param": "top",
|
|
104
|
+
"value": "decay",
|
|
105
|
+
"description": "feedbackTOP samples the decayed composite (decay), forming the trail loop. Value resolves to the created node path."
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"controls": [
|
|
109
|
+
{
|
|
110
|
+
"name": "TrailLength",
|
|
111
|
+
"type": "float",
|
|
112
|
+
"min": 0,
|
|
113
|
+
"max": 1,
|
|
114
|
+
"default": 0.92,
|
|
115
|
+
"bind_to": ["decay.brightness1"]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "GlowAmount",
|
|
119
|
+
"type": "float",
|
|
120
|
+
"min": 0,
|
|
121
|
+
"max": 48,
|
|
122
|
+
"default": 12,
|
|
123
|
+
"bind_to": ["bloom.size"]
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"preview_description": "Cyan glowing dots tracing a person's joints, smearing into luminous trails as they move in front of the webcam — a hands-free reactive performance look."
|
|
127
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mediapipe_body_dots",
|
|
3
|
+
"name": "MediaPipe Body Dots",
|
|
4
|
+
"description": "Glowing dots that track the 33 MediaPipe body landmarks. Point the 'posein' Select CHOP at the pose-landmarks CHOP from the free torinmb/mediapipe-touchdesigner plugin (33 samples, tx/ty/tz). Webcam only — no Kinect or extra hardware. Or use create_body_reactive for a self-contained synthetic preview.",
|
|
5
|
+
"tags": ["mediapipe", "pose", "body-tracking", "interactive", "camera"],
|
|
6
|
+
"difficulty": "intermediate",
|
|
7
|
+
"td_version_min": "2022",
|
|
8
|
+
"nodes": [
|
|
9
|
+
{
|
|
10
|
+
"name": "posein",
|
|
11
|
+
"type": "selectCHOP",
|
|
12
|
+
"comment": "Set 'chops' to the MediaPipe plugin's pose-landmarks CHOP (33 samples, tx/ty/tz)"
|
|
13
|
+
},
|
|
14
|
+
{ "name": "geo", "type": "geometryCOMP" },
|
|
15
|
+
{
|
|
16
|
+
"name": "dot",
|
|
17
|
+
"type": "sphereSOP",
|
|
18
|
+
"parameters": { "radx": 0.03, "rady": 0.03, "radz": 0.03 },
|
|
19
|
+
"parent": "geo",
|
|
20
|
+
"comment": "The mark stamped on each landmark"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "pts",
|
|
24
|
+
"type": "choptoSOP",
|
|
25
|
+
"parent": "geo",
|
|
26
|
+
"comment": "33 landmark samples become 33 points (tx/ty/tz map to position)"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "copy",
|
|
30
|
+
"type": "copySOP",
|
|
31
|
+
"parent": "geo",
|
|
32
|
+
"render": true,
|
|
33
|
+
"comment": "Stamp the dot on every landmark point"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "dotmat",
|
|
37
|
+
"type": "constantMAT",
|
|
38
|
+
"parameters": { "colorr": 1, "colorg": 0.25, "colorb": 0.8 }
|
|
39
|
+
},
|
|
40
|
+
{ "name": "cam", "type": "cameraCOMP", "parameters": { "tz": 4.6 } },
|
|
41
|
+
{
|
|
42
|
+
"name": "render",
|
|
43
|
+
"type": "renderTOP",
|
|
44
|
+
"parameters": {
|
|
45
|
+
"outputresolution": "custom",
|
|
46
|
+
"resolutionw": 1280,
|
|
47
|
+
"resolutionh": 720,
|
|
48
|
+
"antialias": "3"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{ "name": "bloom", "type": "blurTOP", "parameters": { "size": 16 } },
|
|
52
|
+
{ "name": "glow", "type": "compositeTOP", "parameters": { "operand": "add" } },
|
|
53
|
+
{ "name": "out1", "type": "nullTOP" }
|
|
54
|
+
],
|
|
55
|
+
"connections": [
|
|
56
|
+
{ "from": "dot", "to": "copy", "to_input": 0 },
|
|
57
|
+
{ "from": "pts", "to": "copy", "to_input": 1 },
|
|
58
|
+
{ "from": "render", "to": "bloom" },
|
|
59
|
+
{ "from": "render", "to": "glow", "to_input": 0 },
|
|
60
|
+
{ "from": "bloom", "to": "glow", "to_input": 1 },
|
|
61
|
+
{ "from": "glow", "to": "out1" }
|
|
62
|
+
],
|
|
63
|
+
"parameters": [
|
|
64
|
+
{
|
|
65
|
+
"name": "landmarks_chop",
|
|
66
|
+
"node": "pts",
|
|
67
|
+
"param": "chop",
|
|
68
|
+
"value": "posein",
|
|
69
|
+
"label": "Landmarks CHOP"
|
|
70
|
+
},
|
|
71
|
+
{ "name": "material", "node": "geo", "param": "material", "value": "dotmat" },
|
|
72
|
+
{ "name": "geometry", "node": "render", "param": "geometry", "value": "geo" },
|
|
73
|
+
{ "name": "camera", "node": "render", "param": "camera", "value": "cam" }
|
|
74
|
+
],
|
|
75
|
+
"controls": [
|
|
76
|
+
{
|
|
77
|
+
"name": "GlowAmount",
|
|
78
|
+
"type": "float",
|
|
79
|
+
"min": 0,
|
|
80
|
+
"max": 64,
|
|
81
|
+
"default": 16,
|
|
82
|
+
"bind_to": ["bloom.size"]
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"preview_description": "Hot-pink glowing dots tracing a person's joints — head, hands, elbows, hips, knees, feet — as they move in front of the webcam."
|
|
86
|
+
}
|