@nodetool-ai/manimgx-nodes 0.0.0-stage → 0.8.3

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 CHANGED
@@ -1,3 +1,43 @@
1
- # Temporary Holding Version
1
+ # @nodetool-ai/manimgx-nodes
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [ManimGX](https://github.com/academa-labs/manimgx) nodes for NodeTool: math and
4
+ 3D animations written in Manim Community Edition's Python API, rendered to
5
+ video by a Rust GPU engine.
6
+
7
+ The nodes shell out to the `manimgx` command, resolved from the `MANIMGX_PATH`
8
+ setting, `MANIMGX_PATH`, PATH, or `~/.local/bin`. In the desktop app, install
9
+ ManimGX from the Package Manager: it runs `uv tool install manimgx` on a Python
10
+ 3.13 that uv downloads into the app's data directory, which is on the server's
11
+ PATH. A node run without it asks for that install. Elsewhere, install it with:
12
+
13
+ ```bash
14
+ uv tool install manimgx # or: pip install manimgx (Python 3.13+)
15
+ ```
16
+
17
+ They do not run in the hosted cloud, because a scene is a Python program that
18
+ runs with the server's permissions.
19
+
20
+ ## Nodes
21
+
22
+ | Node | Does |
23
+ |---|---|
24
+ | `RenderScene` | Scene code → MP4, with the storyboard, layout report and subtitles |
25
+ | `InspectScene` | Storyboard, timeline and 2D layout checks, without video |
26
+ | `GenerateScene` | A language model writes the scene, fixes it from the inspection, then renders |
27
+
28
+ Each node takes dynamic inputs. The scene reads them with
29
+ `from nodetool_inputs import inputs`; image, audio and video inputs arrive as
30
+ file paths.
31
+
32
+ ## Tests
33
+
34
+ ```bash
35
+ npm run test --workspace=packages/manimgx-nodes
36
+ npm run test:real --workspace=packages/manimgx-nodes
37
+ ```
38
+
39
+ The first runs against a fake `manimgx` and skips the real renders when none is
40
+ installed. The second fails without a real install and renders through it.
41
+
42
+ The authoring guide agents load is the
43
+ [`manimgx` system skill](../system-skills/manimgx/SKILL.md).
@@ -0,0 +1 @@
1
+ 2026-10-12T12:30:25.449Z
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `@nodetool-ai/manimgx-nodes` — ManimGX scenes as workflow nodes.
3
+ *
4
+ * ManimGX renders math and 3D animations written with Manim Community
5
+ * Edition's Python API on a Rust GPU engine. These nodes run its command
6
+ * line: `RenderScene` (scene → MP4), `InspectScene` (storyboard, timeline and
7
+ * layout checks without video) and `GenerateScene` (a language model writes
8
+ * the scene and fixes it from the inspection). `MANIMGX_NODES` is registered
9
+ * in `@nodetool-ai/base-nodes` alongside the other node arrays.
10
+ */
11
+ export { RenderSceneNode, MANIMGX_RENDER_NODES } from "./nodes/render-scene.js";
12
+ export { InspectSceneNode, MANIMGX_INSPECT_NODES } from "./nodes/inspect-scene.js";
13
+ export { GenerateSceneNode, MANIMGX_GENERATE_NODES, SCENE_AUTHOR_SYSTEM_PROMPT, extractSceneCode } from "./nodes/generate-scene.js";
14
+ export { MANIMGX_INSTALL_HINT, resolveManimgxBinary, resetManimgxBinaryCache } from "./manimgx-binary.js";
15
+ export type { ManimgxBinary } from "./manimgx-binary.js";
16
+ export { MANIMGX_DISABLED_ERROR, MANIMGX_PRESETS, ManimgxError, childEnv, isManimgxEnabled, manimgxArgs, runManimgx } from "./run-manimgx.js";
17
+ export type { ManimgxPreset, ManimgxRenderSettings, ManimgxResult, ManimgxRun, ManimgxRunOptions, ManimgxScene } from "./run-manimgx.js";
18
+ export declare const MANIMGX_NODES: (typeof import("./nodes/render-scene.js").RenderSceneNode | typeof import("./nodes/inspect-scene.js").InspectSceneNode | typeof import("./nodes/generate-scene.js").GenerateSceneNode)[];
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACnF,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,0BAA0B,EAC1B,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,UAAU,EACX,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,YAAY,EACb,MAAM,kBAAkB,CAAC;AAM1B,eAAO,MAAM,aAAa,0LAIzB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `@nodetool-ai/manimgx-nodes` — ManimGX scenes as workflow nodes.
3
+ *
4
+ * ManimGX renders math and 3D animations written with Manim Community
5
+ * Edition's Python API on a Rust GPU engine. These nodes run its command
6
+ * line: `RenderScene` (scene → MP4), `InspectScene` (storyboard, timeline and
7
+ * layout checks without video) and `GenerateScene` (a language model writes
8
+ * the scene and fixes it from the inspection). `MANIMGX_NODES` is registered
9
+ * in `@nodetool-ai/base-nodes` alongside the other node arrays.
10
+ */
11
+ export { RenderSceneNode, MANIMGX_RENDER_NODES } from "./nodes/render-scene.js";
12
+ export { InspectSceneNode, MANIMGX_INSPECT_NODES } from "./nodes/inspect-scene.js";
13
+ export { GenerateSceneNode, MANIMGX_GENERATE_NODES, SCENE_AUTHOR_SYSTEM_PROMPT, extractSceneCode } from "./nodes/generate-scene.js";
14
+ export { MANIMGX_INSTALL_HINT, resolveManimgxBinary, resetManimgxBinaryCache } from "./manimgx-binary.js";
15
+ export { MANIMGX_DISABLED_ERROR, MANIMGX_PRESETS, ManimgxError, childEnv, isManimgxEnabled, manimgxArgs, runManimgx } from "./run-manimgx.js";
16
+ import { MANIMGX_RENDER_NODES } from "./nodes/render-scene.js";
17
+ import { MANIMGX_INSPECT_NODES } from "./nodes/inspect-scene.js";
18
+ import { MANIMGX_GENERATE_NODES } from "./nodes/generate-scene.js";
19
+ export const MANIMGX_NODES = [
20
+ ...MANIMGX_RENDER_NODES,
21
+ ...MANIMGX_INSPECT_NODES,
22
+ ...MANIMGX_GENERATE_NODES
23
+ ];
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACnF,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,0BAA0B,EAC1B,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,UAAU,EACX,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,GAAG,oBAAoB;IACvB,GAAG,qBAAqB;IACxB,GAAG,sBAAsB;CAC1B,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * ManimGX executable discovery.
3
+ *
4
+ * Order: the user's `MANIMGX_PATH` setting, the process `MANIMGX_PATH`, then
5
+ * `manimgx` on PATH, then `~/.local/bin/manimgx` (where `uv tool install`
6
+ * and `pip install --user` put it, which an app started from the desktop
7
+ * often lacks on PATH). The desktop Package Manager installs it into a
8
+ * directory the server's PATH already holds. The first candidate whose
9
+ * `--version` runs wins. Nothing found throws a `MissingRuntimePackageError`
10
+ * for `manimgx`, so the editor offers the install.
11
+ *
12
+ * The result is cached per process and invalidated when the configured path
13
+ * changes, so tests pointing `MANIMGX_PATH` at a fake re-resolve.
14
+ */
15
+ export interface ManimgxBinary {
16
+ path: string;
17
+ version: string;
18
+ }
19
+ /** What to do when no ManimGX is found. */
20
+ export declare const MANIMGX_INSTALL_HINT: string;
21
+ /**
22
+ * Resolve the ManimGX executable. `configuredPath` is the user's
23
+ * `MANIMGX_PATH` setting; callers pass null under the cloud profile.
24
+ */
25
+ export declare function resolveManimgxBinary(options?: {
26
+ configuredPath?: string | null;
27
+ }): Promise<ManimgxBinary>;
28
+ /** Forget the cached resolution. Tests use this after mutating the environment. */
29
+ export declare function resetManimgxBinaryCache(): void;
30
+ //# sourceMappingURL=manimgx-binary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manimgx-binary.d.ts","sourceRoot":"","sources":["../src/manimgx-binary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,QAGiB,CAAC;AA2CnD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAC/C,OAAO,CAAC,aAAa,CAAC,CAoBxB;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * ManimGX executable discovery.
3
+ *
4
+ * Order: the user's `MANIMGX_PATH` setting, the process `MANIMGX_PATH`, then
5
+ * `manimgx` on PATH, then `~/.local/bin/manimgx` (where `uv tool install`
6
+ * and `pip install --user` put it, which an app started from the desktop
7
+ * often lacks on PATH). The desktop Package Manager installs it into a
8
+ * directory the server's PATH already holds. The first candidate whose
9
+ * `--version` runs wins. Nothing found throws a `MissingRuntimePackageError`
10
+ * for `manimgx`, so the editor offers the install.
11
+ *
12
+ * The result is cached per process and invalidated when the configured path
13
+ * changes, so tests pointing `MANIMGX_PATH` at a fake re-resolve.
14
+ */
15
+ import { execFile } from "node:child_process";
16
+ import os from "node:os";
17
+ import path from "node:path";
18
+ import { promisify } from "node:util";
19
+ import { MissingRuntimePackageError } from "@nodetool-ai/protocol";
20
+ import { HostBinaryMissingError } from "@nodetool-ai/runtime";
21
+ const execFileAsync = promisify(execFile);
22
+ /** What to do when no ManimGX is found. */
23
+ export const MANIMGX_INSTALL_HINT = "Install ManimGX from the Package Manager in the desktop app. Elsewhere, run " +
24
+ "`uv tool install manimgx` or `pip install manimgx` (Python 3.13 or newer), " +
25
+ "or set MANIMGX_PATH to the manimgx executable.";
26
+ function parseVersion(output) {
27
+ const match = /manimgx\s+(\S+)/i.exec(output);
28
+ return match ? match[1] : null;
29
+ }
30
+ function firstLine(text) {
31
+ const line = text.trim().split("\n", 1)[0] ?? "";
32
+ return line.length > 200 ? `${line.slice(0, 200)}…` : line;
33
+ }
34
+ async function probe(candidate) {
35
+ try {
36
+ const { stdout, stderr } = await execFileAsync(candidate, ["--version"], {
37
+ timeout: 30000,
38
+ windowsHide: true
39
+ });
40
+ const version = parseVersion(`${stdout}\n${stderr}`);
41
+ if (version === null)
42
+ return { failure: firstLine(`${stdout}\n${stderr}`) };
43
+ return { binary: { path: candidate, version } };
44
+ }
45
+ catch (err) {
46
+ return {
47
+ failure: firstLine(err instanceof Error ? err.message : String(err))
48
+ };
49
+ }
50
+ }
51
+ function candidates(configuredPath) {
52
+ const list = [];
53
+ if (configuredPath)
54
+ list.push(configuredPath);
55
+ const envPath = process.env["MANIMGX_PATH"];
56
+ if (envPath !== undefined && envPath !== "")
57
+ list.push(envPath);
58
+ list.push("manimgx");
59
+ const exe = process.platform === "win32" ? "manimgx.exe" : "manimgx";
60
+ list.push(path.join(os.homedir(), ".local", "bin", exe));
61
+ return [...new Set(list)];
62
+ }
63
+ let cached = null;
64
+ /**
65
+ * Resolve the ManimGX executable. `configuredPath` is the user's
66
+ * `MANIMGX_PATH` setting; callers pass null under the cloud profile.
67
+ */
68
+ export async function resolveManimgxBinary(options = {}) {
69
+ const key = `${options.configuredPath ?? ""}\0${process.env["MANIMGX_PATH"] ?? ""}`;
70
+ if (cached && cached.key === key)
71
+ return cached.binary;
72
+ const failures = [];
73
+ for (const candidate of candidates(options.configuredPath)) {
74
+ const result = await probe(candidate);
75
+ if ("binary" in result) {
76
+ cached = { key, binary: result.binary };
77
+ return result.binary;
78
+ }
79
+ if (candidate === options.configuredPath || candidate === process.env["MANIMGX_PATH"]) {
80
+ failures.push(` MANIMGX_PATH=${JSON.stringify(candidate)} failed: ${result.failure}`);
81
+ }
82
+ }
83
+ throw new MissingRuntimePackageError(`manimgx was not found. ${MANIMGX_INSTALL_HINT}${failures.join("")}`, "manimgx", { cause: new HostBinaryMissingError("manimgx") });
84
+ }
85
+ /** Forget the cached resolution. Tests use this after mutating the environment. */
86
+ export function resetManimgxBinaryCache() {
87
+ cached = null;
88
+ }
89
+ //# sourceMappingURL=manimgx-binary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manimgx-binary.js","sourceRoot":"","sources":["../src/manimgx-binary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `nodetool.manimgx.GenerateScene` — a prompt → a ManimGX scene → video.
3
+ *
4
+ * A language model writes the scene; `manimgx inspect` checks it; the
5
+ * traceback or the layout report (and, by default, the storyboard pictures)
6
+ * go back to the model until the scene runs clean or the attempts run out.
7
+ * Then `manimgx render` makes the video. The code comes out with the video,
8
+ * so a person or a RenderScene node can take it from there.
9
+ *
10
+ * Layout problems are advisory: a scene that still has some after the last
11
+ * attempt renders anyway, with them in `report`. A scene that never runs
12
+ * throws its last traceback.
13
+ */
14
+ import { BaseNode } from "@nodetool-ai/node-sdk";
15
+ import type { LanguageModel } from "@nodetool-ai/protocol";
16
+ import { type ProcessingContext } from "@nodetool-ai/runtime";
17
+ import { type ImageOutput, type VideoOutput } from "./scene-base.js";
18
+ export declare const SCENE_AUTHOR_SYSTEM_PROMPT = "You write ManimGX scenes. ManimGX is a Rust GPU animation engine with Manim Community Edition's Python API.\n\nWrite one Python module:\n- `import manimgx as m`, then exactly one class deriving m.Scene (or m.ThreeDScene for a 3D camera) with `def construct(self) -> None`.\n- Time advances only through self.play(...) and self.wait(...). self.add(...) adds without animating.\n- Place with VGroup, arrange, next_to, to_edge and center so labels follow their subjects. The frame is about 14.2 units wide and 8 tall, centred on the origin; keep everything inside it.\n- Text for prose, MathTex(r\"...\") with raw strings for LaTeX mathematics. No LaTeX installation is needed.\n- For changing values, animate a ValueTracker and derive geometry from it with always_redraw or updaters. Updaters use elapsed time or state, never frame counts.\n- For 3D: m.ThreeDScene, self.set_camera_orientation(phi=..., theta=...), Surface, Sphere, Cube, ThreeDAxes, self.begin_ambient_camera_rotation(rate=...).\n- Values from the workflow are `from nodetool_inputs import inputs` (a dict). Media inputs are file paths: m.ImageMobject(path) for images, self.add_sound(path) for audio.\n- Read no other files and touch no network: the scene runs headless.\n\nReply with the complete module in a single ```python code block, nothing after it. When told about an error or layout problems, reply with the whole corrected module.";
19
+ /** The longest fenced code block, or the whole reply when it is bare code. */
20
+ export declare function extractSceneCode(reply: string): string;
21
+ type GenerateSceneOutputs = {
22
+ video: VideoOutput;
23
+ code: string;
24
+ storyboard: ImageOutput[];
25
+ report: string;
26
+ attempts: number;
27
+ };
28
+ export declare class GenerateSceneNode extends BaseNode {
29
+ static readonly nodeType = "nodetool.manimgx.GenerateScene";
30
+ static readonly title = "Generate ManimGX Scene";
31
+ static readonly description = "Describe a math or 3D animation and get a video: a language model writes a ManimGX scene, ManimGX inspects it, and the model fixes errors and layout problems from the report and storyboard before the final render.\n manim, manimgx, animation, math, explainer, generate, llm, agent, 3d, video, python\n\n Use cases:\n - Explain a formula, theorem or algorithm as a short animation\n - Make a 3D visualization from a sentence\n - Draft a scene to refine in a RenderScene node";
32
+ static readonly metadataOutputTypes: {
33
+ video: string;
34
+ code: string;
35
+ storyboard: string;
36
+ report: string;
37
+ attempts: string;
38
+ };
39
+ static readonly inputFields: string[];
40
+ static readonly supportsDynamicInputs = true;
41
+ static readonly requiredRuntimes: string[];
42
+ model: LanguageModel;
43
+ prompt: string;
44
+ max_attempts: number;
45
+ send_storyboard: boolean;
46
+ width: number;
47
+ height: number;
48
+ fps: number;
49
+ timeout: number;
50
+ process(context?: ProcessingContext): Promise<GenerateSceneOutputs>;
51
+ }
52
+ export declare const MANIMGX_GENERATE_NODES: readonly [typeof GenerateSceneNode];
53
+ export {};
54
+ //# sourceMappingURL=generate-scene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-scene.d.ts","sourceRoot":"","sources":["../../src/nodes/generate-scene.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAQ,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAUzB,eAAO,MAAM,0BAA0B,m4CAYmI,CAAC;AAE3K,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAoBtD;AAoCD,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,iBAAkB,SAAQ,QAAQ;IAC7C,MAAM,CAAC,QAAQ,CAAC,QAAQ,oCAAoC;IAC5D,MAAM,CAAC,QAAQ,CAAC,KAAK,4BAA4B;IACjD,MAAM,CAAC,QAAQ,CAAC,WAAW,8eACkd;IAC7e,MAAM,CAAC,QAAQ,CAAC,mBAAmB;QACjC,KAAK;QACL,IAAI;QACJ,UAAU;QACV,MAAM;QACN,QAAQ;MACR;IACF,MAAM,CAAC,QAAQ,CAAC,WAAW,WAAc;IACzC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,QAAQ;IAC7C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,WAAe;IAQvC,KAAK,EAAE,aAAa,CAAC;IAQrB,MAAM,EAAE,MAAM,CAAC;IAGf,YAAY,EAAE,MAAM,CAAC;IAQrB,eAAe,EAAE,OAAO,CAAC;IAGzB,KAAK,EAAE,MAAM,CAAC;IAGd,MAAM,EAAE,MAAM,CAAC;IAGf,GAAG,EAAE,MAAM,CAAC;IAGZ,OAAO,EAAE,MAAM,CAAC;IAElB,OAAO,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA4FxE;CACF;AAED,eAAO,MAAM,sBAAsB,qCAA+B,CAAC"}
@@ -0,0 +1,242 @@
1
+ /**
2
+ * `nodetool.manimgx.GenerateScene` — a prompt → a ManimGX scene → video.
3
+ *
4
+ * A language model writes the scene; `manimgx inspect` checks it; the
5
+ * traceback or the layout report (and, by default, the storyboard pictures)
6
+ * go back to the model until the scene runs clean or the attempts run out.
7
+ * Then `manimgx render` makes the video. The code comes out with the video,
8
+ * so a person or a RenderScene node can take it from there.
9
+ *
10
+ * Layout problems are advisory: a scene that still has some after the last
11
+ * attempt renders anyway, with them in `report`. A scene that never runs
12
+ * throws its last traceback.
13
+ */
14
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
15
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
18
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
19
+ };
20
+ import { BaseNode, prop } from "@nodetool-ai/node-sdk";
21
+ import { meterProviderSpend } from "@nodetool-ai/llm-nodes/nodes/provider-spend";
22
+ import { messageText } from "@nodetool-ai/runtime";
23
+ import { ManimgxError, runManimgx } from "../run-manimgx.js";
24
+ import { imageOutput, runNodeStep, videoOutput } from "./scene-base.js";
25
+ const NODE_NAME = "nodetool.manimgx.GenerateScene";
26
+ /** Tokens one scene may take. Long films run a few hundred lines. */
27
+ const MAX_SCENE_TOKENS = 12000;
28
+ /** Storyboard sheets sent back per attempt: each holds up to six frames. */
29
+ const MAX_FEEDBACK_SHEETS = 2;
30
+ export const SCENE_AUTHOR_SYSTEM_PROMPT = `You write ManimGX scenes. ManimGX is a Rust GPU animation engine with Manim Community Edition's Python API.
31
+
32
+ Write one Python module:
33
+ - \`import manimgx as m\`, then exactly one class deriving m.Scene (or m.ThreeDScene for a 3D camera) with \`def construct(self) -> None\`.
34
+ - Time advances only through self.play(...) and self.wait(...). self.add(...) adds without animating.
35
+ - Place with VGroup, arrange, next_to, to_edge and center so labels follow their subjects. The frame is about 14.2 units wide and 8 tall, centred on the origin; keep everything inside it.
36
+ - Text for prose, MathTex(r"...") with raw strings for LaTeX mathematics. No LaTeX installation is needed.
37
+ - For changing values, animate a ValueTracker and derive geometry from it with always_redraw or updaters. Updaters use elapsed time or state, never frame counts.
38
+ - For 3D: m.ThreeDScene, self.set_camera_orientation(phi=..., theta=...), Surface, Sphere, Cube, ThreeDAxes, self.begin_ambient_camera_rotation(rate=...).
39
+ - Values from the workflow are \`from nodetool_inputs import inputs\` (a dict). Media inputs are file paths: m.ImageMobject(path) for images, self.add_sound(path) for audio.
40
+ - Read no other files and touch no network: the scene runs headless.
41
+
42
+ Reply with the complete module in a single \`\`\`python code block, nothing after it. When told about an error or layout problems, reply with the whole corrected module.`;
43
+ /** The longest fenced code block, or the whole reply when it is bare code. */
44
+ export function extractSceneCode(reply) {
45
+ // A line scan, not a regex: the reply is model output of any shape.
46
+ const blocks = [];
47
+ let open = null;
48
+ for (const line of reply.split("\n")) {
49
+ if (line.trimStart().startsWith("```")) {
50
+ if (open) {
51
+ blocks.push(open.join("\n"));
52
+ open = null;
53
+ }
54
+ else {
55
+ open = [];
56
+ }
57
+ }
58
+ else if (open) {
59
+ open.push(line);
60
+ }
61
+ }
62
+ if (blocks.length > 0) {
63
+ return blocks.reduce((a, b) => (b.length > a.length ? b : a)).trim();
64
+ }
65
+ return /\bimport manimgx\b/.test(reply) ? reply.trim() : "";
66
+ }
67
+ function describeInputs(inputs) {
68
+ const names = Object.keys(inputs);
69
+ if (names.length === 0)
70
+ return "";
71
+ const lines = names.map((name) => {
72
+ const value = inputs[name];
73
+ const kind = value && typeof value === "object" && "type" in value
74
+ ? `${String(value.type)} file path`
75
+ : JSON.stringify(value)?.slice(0, 200) ?? "null";
76
+ return `- inputs[${JSON.stringify(name)}]: ${kind}`;
77
+ });
78
+ return `\n\nThe scene can read these values:\n${lines.join("\n")}`;
79
+ }
80
+ function feedbackMessage(result, sendStoryboard) {
81
+ if (!result.ok) {
82
+ return {
83
+ role: "user",
84
+ content: `The scene failed:\n\n${result.report}\n\nFix it and reply with the whole module.`
85
+ };
86
+ }
87
+ const text = `The scene runs, but inspection found layout problems:\n\n${result.report}\n\n` +
88
+ "Fix them (the storyboard numbers each one) and reply with the whole module.";
89
+ if (!sendStoryboard || result.storyboards.length === 0) {
90
+ return { role: "user", content: text };
91
+ }
92
+ const content = [{ type: "text", text }];
93
+ for (const sheet of result.storyboards.slice(0, MAX_FEEDBACK_SHEETS)) {
94
+ content.push({ type: "image_url", image: { data: sheet, mimeType: "image/png" } });
95
+ }
96
+ return { role: "user", content };
97
+ }
98
+ export class GenerateSceneNode extends BaseNode {
99
+ static nodeType = "nodetool.manimgx.GenerateScene";
100
+ static title = "Generate ManimGX Scene";
101
+ static description = "Describe a math or 3D animation and get a video: a language model writes a ManimGX scene, ManimGX inspects it, and the model fixes errors and layout problems from the report and storyboard before the final render.\n manim, manimgx, animation, math, explainer, generate, llm, agent, 3d, video, python\n\n Use cases:\n - Explain a formula, theorem or algorithm as a short animation\n - Make a 3D visualization from a sentence\n - Draft a scene to refine in a RenderScene node";
102
+ static metadataOutputTypes = {
103
+ video: "video",
104
+ code: "str",
105
+ storyboard: "list[image]",
106
+ report: "str",
107
+ attempts: "int"
108
+ };
109
+ static inputFields = ["prompt"];
110
+ static supportsDynamicInputs = true;
111
+ static requiredRuntimes = ["manimgx"];
112
+ async process(context) {
113
+ if (!context)
114
+ throw new Error(`${NODE_NAME} requires a processing context`);
115
+ const prompt = this.prompt?.trim() ?? "";
116
+ if (!prompt)
117
+ throw new Error(`${NODE_NAME}: prompt is empty — describe the animation`);
118
+ const providerId = this.model?.provider ?? "";
119
+ const modelId = this.model?.id ?? "";
120
+ if (!providerId || providerId === "empty" || !modelId) {
121
+ throw new Error(`${NODE_NAME}: pick a model — the scene needs a writer`);
122
+ }
123
+ const inputs = Object.fromEntries([...this.dynamicProps.entries()].filter(([name]) => !name.startsWith("_")));
124
+ const timeoutMs = Math.max(1, Math.round(Number(this.timeout ?? 300))) * 1000;
125
+ const maxAttempts = Math.min(8, Math.max(1, Math.round(Number(this.max_attempts ?? 3))));
126
+ const signal = context.signal;
127
+ return runNodeStep(NODE_NAME, signal, async () => {
128
+ const provider = await context.getProvider(providerId);
129
+ const spend = meterProviderSpend(context, provider, modelId);
130
+ try {
131
+ const messages = [
132
+ { role: "system", content: SCENE_AUTHOR_SYSTEM_PROMPT },
133
+ { role: "user", content: `${prompt}${describeInputs(inputs)}` }
134
+ ];
135
+ let scene = null;
136
+ let inspected = null;
137
+ let attempts = 0;
138
+ while (attempts < maxAttempts) {
139
+ signal?.throwIfAborted();
140
+ attempts += 1;
141
+ const reply = await provider.generateMessage({
142
+ messages: [...messages],
143
+ model: modelId,
144
+ maxTokens: MAX_SCENE_TOKENS
145
+ });
146
+ const text = messageText(reply.content);
147
+ messages.push({ role: "assistant", content: text });
148
+ const code = extractSceneCode(text);
149
+ if (!code) {
150
+ messages.push({
151
+ role: "user",
152
+ content: "Reply with the complete scene module in a single ```python code block."
153
+ });
154
+ continue;
155
+ }
156
+ scene = { code, inputs };
157
+ inspected = await runManimgx(context, scene, { command: "inspect" }, { timeoutMs, signal });
158
+ context.postMessage?.({
159
+ type: "log_update",
160
+ node_id: this.__node_id,
161
+ node_name: NODE_NAME,
162
+ content: `Attempt ${attempts}: ${inspected.ok ? (inspected.problems ? "layout problems" : "clean") : "scene failed"}`,
163
+ severity: inspected.ok ? "info" : "warning"
164
+ });
165
+ if (inspected.ok && !inspected.problems)
166
+ break;
167
+ messages.push(feedbackMessage(inspected, this.send_storyboard !== false));
168
+ }
169
+ if (!scene || !inspected) {
170
+ throw new ManimgxError(`the model wrote no scene code in ${attempts} attempts`);
171
+ }
172
+ if (!inspected.ok) {
173
+ throw new ManimgxError(`the scene still fails after ${attempts} attempts:\n${inspected.report}`);
174
+ }
175
+ const rendered = await runManimgx(context, scene, {
176
+ command: "render",
177
+ settings: {
178
+ width: Number(this.width ?? 1920),
179
+ height: Number(this.height ?? 1080),
180
+ fps: Number(this.fps ?? 30),
181
+ preset: "medium",
182
+ crf: 23
183
+ }
184
+ }, { timeoutMs, signal });
185
+ if (!rendered.ok || !rendered.video) {
186
+ throw new ManimgxError(`the scene failed to render:\n${rendered.report}`);
187
+ }
188
+ return {
189
+ video: videoOutput(rendered.video),
190
+ code: scene.code,
191
+ storyboard: rendered.storyboards.map(imageOutput),
192
+ report: rendered.report,
193
+ attempts
194
+ };
195
+ }
196
+ finally {
197
+ spend.report();
198
+ }
199
+ });
200
+ }
201
+ }
202
+ __decorate([
203
+ prop({
204
+ type: "language_model",
205
+ default: { type: "language_model", provider: "empty", id: "", name: "", path: null, supported_tasks: [] },
206
+ title: "Model",
207
+ description: "Model that writes the scene. A vision model also reads the storyboard."
208
+ })
209
+ ], GenerateSceneNode.prototype, "model", void 0);
210
+ __decorate([
211
+ prop({
212
+ type: "str",
213
+ default: "",
214
+ title: "Prompt",
215
+ description: "What to animate. Wired dynamic inputs reach the scene as `inputs`."
216
+ })
217
+ ], GenerateSceneNode.prototype, "prompt", void 0);
218
+ __decorate([
219
+ prop({ type: "int", default: 3, title: "Max Attempts", description: "Write-and-inspect rounds before rendering", min: 1, max: 8 })
220
+ ], GenerateSceneNode.prototype, "max_attempts", void 0);
221
+ __decorate([
222
+ prop({
223
+ type: "bool",
224
+ default: true,
225
+ title: "Send Storyboard",
226
+ description: "Show the model the storyboard pictures with layout problems (needs a vision model)"
227
+ })
228
+ ], GenerateSceneNode.prototype, "send_storyboard", void 0);
229
+ __decorate([
230
+ prop({ type: "int", default: 1920, title: "Width", description: "Video width in pixels", min: 16, max: 7680 })
231
+ ], GenerateSceneNode.prototype, "width", void 0);
232
+ __decorate([
233
+ prop({ type: "int", default: 1080, title: "Height", description: "Video height in pixels", min: 16, max: 4320 })
234
+ ], GenerateSceneNode.prototype, "height", void 0);
235
+ __decorate([
236
+ prop({ type: "int", default: 30, title: "FPS", description: "Frames per second", min: 1, max: 120 })
237
+ ], GenerateSceneNode.prototype, "fps", void 0);
238
+ __decorate([
239
+ prop({ type: "int", default: 300, title: "Timeout", description: "Maximum seconds for each ManimGX run", min: 1, max: 3600 })
240
+ ], GenerateSceneNode.prototype, "timeout", void 0);
241
+ export const MANIMGX_GENERATE_NODES = [GenerateSceneNode];
242
+ //# sourceMappingURL=generate-scene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-scene.js","sourceRoot":"","sources":["../../src/nodes/generate-scene.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `nodetool.manimgx.InspectScene` — check a ManimGX scene without video.
3
+ *
4
+ * Runs `manimgx inspect`: the storyboard (the frame at each play's end, or at
5
+ * the times asked for, layout problems outlined and numbered), the timeline
6
+ * of plays with their source lines, and 2D layout checks (clipped content,
7
+ * overlapping text, small labels). This is the feedback half of an authoring
8
+ * loop, so a scene that fails is a result here, not an error: `ok` is false
9
+ * and `report` carries the traceback with ManimGX's hint.
10
+ */
11
+ import type { ProcessingContext } from "@nodetool-ai/runtime";
12
+ import { ManimgxSceneNode, type ImageOutput } from "./scene-base.js";
13
+ type InspectSceneOutputs = {
14
+ ok: boolean;
15
+ problems: boolean;
16
+ report: string;
17
+ storyboard: ImageOutput[];
18
+ duration: number;
19
+ };
20
+ export declare class InspectSceneNode extends ManimgxSceneNode {
21
+ static readonly nodeType = "nodetool.manimgx.InspectScene";
22
+ static readonly title = "Inspect ManimGX Scene";
23
+ static readonly description = "Check a ManimGX scene without rendering video: a storyboard of key frames, the timeline of plays, and 2D layout problems such as clipped content or overlapping text.\n manim, manimgx, inspect, storyboard, layout, check, preview, animation, python\n\n Use cases:\n - Preview a scene's key frames before a full render\n - Feed layout problems and tracebacks back to an LLM that writes the scene\n - Grab stills at chosen times";
24
+ static readonly metadataOutputTypes: {
25
+ ok: string;
26
+ problems: string;
27
+ report: string;
28
+ storyboard: string;
29
+ duration: string;
30
+ };
31
+ times: string;
32
+ process(context?: ProcessingContext): Promise<InspectSceneOutputs>;
33
+ }
34
+ export declare const MANIMGX_INSPECT_NODES: readonly [typeof InspectSceneNode];
35
+ export {};
36
+ //# sourceMappingURL=inspect-scene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect-scene.d.ts","sourceRoot":"","sources":["../../src/nodes/inspect-scene.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,OAAO,EACL,gBAAgB,EAGhB,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAIzB,KAAK,mBAAmB,GAAG;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,gBAAiB,SAAQ,gBAAgB;IACpD,MAAM,CAAC,QAAQ,CAAC,QAAQ,mCAAmC;IAC3D,MAAM,CAAC,QAAQ,CAAC,KAAK,2BAA2B;IAChD,MAAM,CAAC,QAAQ,CAAC,WAAW,6bACia;IAC5b,MAAM,CAAC,QAAQ,CAAC,mBAAmB;QACjC,EAAE;QACF,QAAQ;QACR,MAAM;QACN,UAAU;QACV,QAAQ;MACR;IAQM,KAAK,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgBvE;CACF;AAED,eAAO,MAAM,qBAAqB,oCAA8B,CAAC"}