@mcptoolshop/armature-studio 0.0.0 → 0.2.1
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/LICENSE +21 -0
- package/README.md +67 -4
- package/bin/armature.mjs +103 -0
- package/package.json +30 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mcp-tool-shop
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
|
-
#
|
|
1
|
+
# armature-studio
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
**You block the shot. The model shoots it.**
|
|
4
|
+
|
|
5
|
+
Node launcher for [`armature-studio`](https://pypi.org/project/armature-studio/) — GLB-authored
|
|
6
|
+
previz, control sequences and gates for video-diffusion generation.
|
|
7
|
+
|
|
8
|
+
A video model can produce motion, light and life that no renderer can. It cannot be told
|
|
9
|
+
*who is on screen and where they are standing*. armature supplies exactly that: a canonical
|
|
10
|
+
character mesh is staged and animated in headless Blender, and the render becomes a per-frame
|
|
11
|
+
**control sequence** the video model must obey — so AI-generated video can carry one
|
|
12
|
+
persistent main character whose position and pose are known every frame.
|
|
13
|
+
|
|
14
|
+
**armature is image-to-video with a GLB instead of an image.**
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @mcptoolshop/armature-studio
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The toolkit itself is Python, so install that too:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install armature-studio
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
armature check
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Why a launcher and not a port
|
|
33
|
+
|
|
34
|
+
armature's measured pieces — the gates, the framing solves, the channel maths — are Python.
|
|
35
|
+
Re-implementing any of them in Node would create a second copy of a threshold, which is how a
|
|
36
|
+
threshold drifts. This package installs the `armature` command and forwards it, verbatim, to
|
|
37
|
+
the Python that holds the truth.
|
|
38
|
+
|
|
39
|
+
**It will not install Python for you and will not `pip install` anything behind your back.**
|
|
40
|
+
When the toolkit is missing it says which of the two things is wrong — no interpreter, or an
|
|
41
|
+
interpreter without the package — prints the one command that fixes it, and exits non-zero.
|
|
42
|
+
|
|
43
|
+
Point it at a specific interpreter with `ARMATURE_PYTHON` if you keep several.
|
|
44
|
+
|
|
45
|
+
## Commands
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
armature check # import every module and report what resolved
|
|
49
|
+
armature modules # what each module is for (--json for machine output)
|
|
50
|
+
armature where # where the docs and the Blender-side scripts live
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## The rendering scripts are not here, deliberately
|
|
54
|
+
|
|
55
|
+
`render_turnaround.py` and its siblings run inside **Blender's own interpreter**:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
blender -b -P tools/render_turnaround.py -- --glb subject.glb --out renders --ortho
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
They live in the repository, where the invocation that works is the one written down.
|
|
62
|
+
|
|
63
|
+
- **Docs and handbook:** https://mcp-tool-shop-org.github.io/armature/
|
|
64
|
+
- **Repository and the full record:** https://github.com/mcp-tool-shop-org/armature
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
MIT.
|
package/bin/armature.mjs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* armature — the Node launcher for the `armature-studio` Python toolkit.
|
|
4
|
+
*
|
|
5
|
+
* WHY A LAUNCHER AND NOT A PORT. armature's measured pieces are Python: the gates, the
|
|
6
|
+
* framing solves, the channel maths. Re-implementing any of them in Node would create a
|
|
7
|
+
* second copy of a threshold, which is how a threshold drifts — the exact failure the
|
|
8
|
+
* repository's own record was written to prevent. So this package installs a command and
|
|
9
|
+
* forwards it, verbatim, to the Python that holds the truth.
|
|
10
|
+
*
|
|
11
|
+
* WHAT IT WILL NOT DO. It does not install Python, does not pip-install anything behind
|
|
12
|
+
* your back, and does not guess at a substitute when the toolkit is absent. A launcher
|
|
13
|
+
* that silently installed things would make `npx` a package manager pointed at your
|
|
14
|
+
* machine. When the toolkit is missing it says so, prints the one command that fixes it,
|
|
15
|
+
* and exits non-zero.
|
|
16
|
+
*/
|
|
17
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
18
|
+
import process from "node:process";
|
|
19
|
+
|
|
20
|
+
const PYPI = "armature-studio";
|
|
21
|
+
const DOCS = "https://mcp-tool-shop-org.github.io/armature/";
|
|
22
|
+
|
|
23
|
+
/** Interpreter candidates, in the order worth trying on each platform. */
|
|
24
|
+
function candidates() {
|
|
25
|
+
const fromEnv = process.env.ARMATURE_PYTHON;
|
|
26
|
+
const list = fromEnv ? [fromEnv] : [];
|
|
27
|
+
// `py -3` is the Windows launcher and resolves when `python3` is only the Store stub.
|
|
28
|
+
return process.platform === "win32"
|
|
29
|
+
? [...list, "python", "py", "python3"]
|
|
30
|
+
: [...list, "python3", "python"];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Args that turn a bare candidate into a working interpreter invocation. */
|
|
34
|
+
function argsFor(exe) {
|
|
35
|
+
return exe === "py" ? ["-3"] : [];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Find an interpreter that can actually import the toolkit.
|
|
40
|
+
*
|
|
41
|
+
* Deliberately two questions, not one: an interpreter that exists but lacks the package
|
|
42
|
+
* is a DIFFERENT problem from no interpreter at all, and telling them apart is the whole
|
|
43
|
+
* value of this check. Reporting "python not found" to someone who has three Pythons and
|
|
44
|
+
* no package would send them fixing the wrong thing.
|
|
45
|
+
*/
|
|
46
|
+
function locate() {
|
|
47
|
+
let sawInterpreter = false;
|
|
48
|
+
for (const exe of candidates()) {
|
|
49
|
+
const pre = argsFor(exe);
|
|
50
|
+
const probe = spawnSync(exe, [...pre, "-c", "import armature_core"], {
|
|
51
|
+
stdio: "ignore",
|
|
52
|
+
shell: false,
|
|
53
|
+
});
|
|
54
|
+
if (probe.error) continue; // this candidate is not on PATH at all
|
|
55
|
+
sawInterpreter = true;
|
|
56
|
+
if (probe.status === 0) return { exe, pre };
|
|
57
|
+
}
|
|
58
|
+
return { exe: null, pre: null, sawInterpreter };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function fail(found) {
|
|
62
|
+
const what = found.sawInterpreter
|
|
63
|
+
? `Python is installed, but the ${PYPI} toolkit is not importable from it.`
|
|
64
|
+
: "No Python interpreter was found on PATH.";
|
|
65
|
+
process.stderr.write(
|
|
66
|
+
`armature: ${what}\n\n` +
|
|
67
|
+
` This package is a launcher. The toolkit itself is Python:\n\n` +
|
|
68
|
+
` pip install ${PYPI}\n\n` +
|
|
69
|
+
` Point at a specific interpreter with ARMATURE_PYTHON if you use one.\n` +
|
|
70
|
+
` Docs: ${DOCS}\n`
|
|
71
|
+
);
|
|
72
|
+
process.exit(127);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const argv = process.argv.slice(2);
|
|
76
|
+
|
|
77
|
+
// A self-test that does not need Python present: it proves this file parses, resolves its
|
|
78
|
+
// candidate list and reports honestly. `npm test` runs it in CI where Python may be absent.
|
|
79
|
+
if (argv[0] === "--node-selftest") {
|
|
80
|
+
const list = candidates();
|
|
81
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
82
|
+
process.stderr.write("selftest: no interpreter candidates\n");
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
if (argsFor("py")[0] !== "-3") {
|
|
86
|
+
process.stderr.write("selftest: the Windows launcher lost its -3\n");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
process.stdout.write(`armature launcher ok — candidates: ${list.join(", ")}\n`);
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const found = locate();
|
|
94
|
+
if (!found.exe) fail(found);
|
|
95
|
+
|
|
96
|
+
// Forward everything verbatim and inherit the child's exit code, so a gate that raises in
|
|
97
|
+
// Python still fails the shell that called this launcher.
|
|
98
|
+
const child = spawn(found.exe, [...found.pre, "-m", "armature_core.cli", ...argv], {
|
|
99
|
+
stdio: "inherit",
|
|
100
|
+
shell: false,
|
|
101
|
+
});
|
|
102
|
+
child.on("exit", (code, signal) => process.exit(signal ? 1 : code ?? 0));
|
|
103
|
+
child.on("error", () => fail(found));
|
package/package.json
CHANGED
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcptoolshop/armature-studio",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "You block the shot; the model shoots it — GLB-authored previz, control sequences and gates for video-diffusion generation. Node launcher for the armature-studio Python toolkit.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"previz",
|
|
7
|
+
"blender",
|
|
8
|
+
"video-diffusion",
|
|
9
|
+
"controlnet",
|
|
10
|
+
"turnaround",
|
|
11
|
+
"glb",
|
|
12
|
+
"character",
|
|
13
|
+
"animation",
|
|
14
|
+
"comfyui",
|
|
15
|
+
"sprite"
|
|
16
|
+
],
|
|
7
17
|
"homepage": "https://mcp-tool-shop-org.github.io/armature/",
|
|
18
|
+
"bugs": "https://github.com/mcp-tool-shop-org/armature/issues",
|
|
8
19
|
"repository": {
|
|
9
20
|
"type": "git",
|
|
10
21
|
"url": "git+https://github.com/mcp-tool-shop-org/armature.git",
|
|
11
22
|
"directory": "npm"
|
|
12
23
|
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "mcp-tool-shop <64996768+mcp-tool-shop@users.noreply.github.com>",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"armature": "bin/armature.mjs"
|
|
29
|
+
},
|
|
13
30
|
"files": [
|
|
14
|
-
"
|
|
31
|
+
"bin/"
|
|
15
32
|
],
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"test": "node bin/armature.mjs --node-selftest"
|
|
38
|
+
},
|
|
16
39
|
"publishConfig": {
|
|
17
|
-
"access": "public"
|
|
40
|
+
"access": "public",
|
|
41
|
+
"provenance": true
|
|
18
42
|
}
|
|
19
43
|
}
|