graphite-editor-mcp
Provides programmatic rendering and document validation for the Graphite node-graph graphics engine, allowing agents to author documents as data (templates or inline .graphite JSON), render them to PNG, SVG, JPG, or GIF via a pinned CLI, list available node identifiers, and validate document structure and compilability.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@graphite-editor-mcpRender a 800x600 PNG of a procedural gradient using the 'gradient' template."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
graphite-editor-mcp
A programmatic graphics engine boundary for AI agents. Deterministic, node-graph-based, agent-drivable: agents author documents as data, a headless CLI renders them, assets are reproducible and versionable. The MCP server is the stable boundary that makes this usable by agents and automation: it wraps data-driving, never GUI-driving, and it exists to be boring — every call returns a validated artifact or a precise error. Print/DTP finishing is deliberately out of scope; Graphite owns procedural/generative asset production.
What this is — and is not
It is: an MCP server (stdio) exposing four tools over the pinned graphene-cli binary. Agents author documents as data — either template + parameters or inline legacy .graphite JSON — and receive validated, hashed artifacts with full provenance. Nothing here drives a GUI.
It is not: a print pipeline. graphene-cli writes .png, .jpg, .jpeg, .gif and .svg only — PDF is explicitly rejected upstream. It is also not an upstream Graphite fork: the engine is pinned at a verified commit with zero source modifications (see docs/ENGINE-PIN.md).
Related MCP server: starlight-creator-mcp
Architecture (one paragraph)
Tools → builder/templates → runner → pinned CLI: each MCP tool validates its inputs, produces a complete legacy .graphite document (via the template factories in src/templates.ts or an inline document materialized under tmp/mcp-inline/), and hands a render spec to GraphiteRunner (src/runner.ts), which spawns the pinned graphene-cli binary, captures its output tails, enforces a per-render timeout, and — because every successful export writes a valid artifact and THEN dies with SIGSEGV — validates the artifact unconditionally (src/validator.ts: magic bytes + structure + size floors) and quarantines the abnormal exit instead of trusting exit codes. Failures are typed (src/errors.ts) with stable codes and precise diagnostics; the MCP layer turns every failure into an isError result carrying the code.
Quickstart
Prerequisites:
Node ≥ 22 (see
package.jsonengines).Rust toolchain (
cargoon PATH, or at~/.cargo/bin) — for building the pinned engine.git — for the shallow engine fetch.
git clone https://github.com/ktheunlikedoll/graphite-editor-mcp.git
cd graphite-editor-mcp
npm install
bash scripts/fetch-engine.sh # shallow-fetch the pinned upstream SHA into engine/ and build graphene-cli
npm run build # tsc → dist/src/*.js
npm test # optional; the real-CLI test tiers run when the binary is presentscripts/fetch-engine.sh shallow-fetches the exact pinned upstream commit into engine/Graphite/ (gitignored — never committed) and builds the debug graphene-cli. It is idempotent: if engine/Graphite is already at the pinned commit, it skips the fetch. First build takes a while. Reference build facts — commit SHA, binary sha256, toolchain — are recorded in docs/ENGINE-PIN.md.
The CLI path: GRAPHITE_CLI_PATH
Resolution order (src/paths.ts):
GRAPHITE_CLI_PATHenv var — used exclusively when set. A broken value fails precisely on that value; it never silently falls back.Default:
<projectRoot>/engine/Graphite/target/debug/graphene-cli(the pinned debug build).Otherwise:
CLI_NOT_FOUNDerror listing exactly what was searched.
Tool contracts
Four tools, stdio transport, official MCP SDK, zod-validated inputs. Every result is one JSON text block. Every failure is an isError: true result whose text is a JSON error envelope:
{
"code": "SPEC_INVALID",
"message": "output format \"png\" requires an explicit size: provide width AND height with BOTH dimensions (got width=800, height=undefined). Rationale: graphene-cli silently falls back to a 1x1 default viewport when a dimension is missing, so Graphite rejects incomplete sizes outright. (SVG is the only format that may omit size.)",
"name": "SpecInvalidError"
}Error codes
Code | Class | When |
|
| No usable binary (missing, not a file, not executable). Carries |
|
| The engine refused the document (compile failed) or it cannot be read. Carries |
|
| The CLI failed in a way that is NOT the SIGSEGV-after-write case. Carries |
|
| The CLI produced (or claimed to produce) an artifact that failed validation. Carries |
|
| Render exceeded its time budget (default 120 s) and was killed. Carries |
|
| Malformed request before/without any process run: unknown template id, bad params, incomplete raster size, unsupported GIF timing, bad |
| — | Any non-Graphite error; message only, never a stack trace. |
graphite_render
Renders a document to a validated artifact.
Input | Type | Notes |
|
| One of the four template ids. Either |
|
| Template parameters; defaults to the template's |
|
| Inline legacy |
|
| Required. |
|
| Both required together for raster formats (png/jpg/gif); a width-only request is rejected with |
|
| Base name WITHOUT extension — the format extension is appended ( |
|
| Required for |
Output path: <projectRoot>/exports/<name> (directory created on demand; the runner deletes stale artifacts of the same path before rendering so validation is always about THIS render).
Successful result (real output, template-driven duotone with default params):
{
"artifactPath": "<project-root>/exports/readme-example.png",
"format": "png",
"byteSize": 1154138,
"sha256": "93ef9b199f1e166cb95d26ba584f7038745a701ff18c9195e4ffc3eb23060b75",
"width": 1000,
"height": 500,
"validation": {
"valid": true,
"format": "png",
"byteSize": 1154138,
"path": "<project-root>/exports/readme-example.png",
"width": 1000,
"height": 500
},
"quarantine": {
"exitCode": null,
"signal": "SIGSEGV",
"quarantinedAfterWrite": true,
"stderrTail": ""
},
"renderMs": 1502,
"exitCode": null,
"signal": "SIGSEGV",
"command": "graphene-cli export …/tmp/mcp-inline/render-….graphite --output …/exports/readme-example.png --width 1000 --height 500",
"documentPath": "<project-root>/tmp/mcp-inline/render-….graphite",
"templateId": "duotone-image",
"params": { "width": 1000, "height": 500, "seed": 0, "scale": 35, "dark": { "red": 0.02, "green": 0.02, "blue": 0.12, "alpha": 1 }, "light": { "red": 1, "green": 0.3, "blue": 0.03, "alpha": 1 }, "reverse": false }
}templateId/params echo only on template-driven renders (echoing the parameters actually used — defaults included). The render is NOT compiled separately first: the export itself surfaces compile errors (DOC_INVALID), so every call spawns exactly one CLI process.
graphite_list_nodes
No required inputs; optional filter (case-sensitive substring). Returns { "count": <n>, "nodes": ["…", …] } from graphene-cli list-node-identifiers — 324 identifiers on the pinned build. The unfiltered list is cached in memory after the first success (process lifetime; the pin cannot change under a running server).
{
"count": 1,
"nodes": ["raster_nodes::adjustments::GradientMapNode"]
}graphite_validate_doc
Structural validation of a document WITHOUT rendering. Pass either document (inline object or JSON string) or documentPath (existing file) — never both. Optional compileCheck: true adds the engine's own compile verdict (default false — fast and offline). Validation results are data: an invalid document returns valid: false with precise reasons; it is not an error result.
{
"valid": false,
"structural": {
"checks": {
"parsed": true, "hasNetworkInterface": true, "hasNetwork": true,
"hasNodesArray": true, "hasExportsArray": true,
"nodeEntriesWellFormed": true, "exportsResolveToNodes": false
},
"nodeCount": 4,
"reasons": ["export references node id 999999, which does not exist in network.nodes"]
}
}With compileCheck: true on a structurally-valid document:
{
"valid": true,
"structural": { "checks": { "parsed": true, "hasNetworkInterface": true, "hasNetwork": true, "hasNodesArray": true, "hasExportsArray": true, "nodeEntriesWellFormed": true, "exportsResolveToNodes": true }, "nodeCount": 4, "reasons": [] },
"compile": { "ok": true, "stderrTail": "" },
"documentPath": "<project-root>/tmp/mcp-inline/validate-….graphite"
}Compile runs only after structural validation passes; when structural validation fails, compile is reported as { "ok": false, "reason": "not run: structural validation failed" } (no wasted spawn). documentPath echoes the on-disk path (the materialized copy for inline documents). A failed engine compile sets compile.ok: false with the engine's stderrTail.
graphite_render_variants
Sequential batch renderer (v1 doctrine: never parallel — one GPU-heavy child at a time).
Input | Type | Notes |
|
| Required. |
|
| 2..20 full parameter objects; each validated independently. |
|
| Required. |
|
| Required — the render size for every variant (pass the same values inside each variant's params). |
|
| Default |
Outputs: <templateId>-<index>.<format> (index = position in variants, 0-based) under the output dir. Each variant goes through the full render + validate pipeline; a failing variant is reported per-item and does NOT abort the batch — the call is isError only when every variant fails.
Result: { "count": 3, "results": [ …same shape as graphite_render results… ] }; a failed item looks like { "templateId": "duotone-image", "params": { … }, "error": { "code": "SPEC_INVALID", "message": "…" } }.
Templates
Id | Produces | Params | Provenance |
| Full-bleed solid color (EmptyImage route) or two-color linear gradient (proven Rectangle→Fill vector route) |
| working demo gradient route |
| Procedural noise-pattern background (NoisePatternNode, clip disabled → full-bleed) |
| working demo — full 16-input serialization |
| Fallback-font text (TextNode → TextToVector → Fill) over a solid background |
| executed TextNode chain with proven placement transform |
| Procedural noise mapped through a two-color gradient ramp (GradientMap duotone) |
| demo-proven NoisePattern → GradientMap chain |
Default parameters per template live in src/templates.ts (DEFAULT_PARAMS) and are exactly the committed sample outputs in templates/*.graphite. Agents never hand-write wrapper JSON.
The SIGSEGV quarantine — why every render reports quarantinedAfterWrite
Ground truth on the pinned engine build: every successful graphene-cli export writes a complete, valid artifact and THEN dies with SIGSEGV (exit 139) — reproducibly (likely the detached GPU-poll thread in graphene-cli/src/main.rs).
The runner therefore never trusts exit codes: it validates the artifact unconditionally (existence, non-trivial size, magic bytes + structure). When the CLI crashed after writing a valid artifact, the render succeeds and carries quarantine metadata { exitCode, signal, quarantinedAfterWrite: true, stderrTail }. This is normal and expected — a successful tool result with quarantine.quarantinedAfterWrite: true is the pinned engine behaving exactly as measured. If a future engine build stops crashing, the field flips to false (exit 0 + valid artifact). A crash that left a broken artifact is NOT quarantined: it is an ARTIFACT_INVALID error.
Determinism
Same spec rendered twice → byte-identical output. Evidence: the Phase-3 suite asserts pixel-identical renders for all four templates (tests/templates-e2e.test.ts, determinism: … pixel-identical), and every tool result carries the artifact sha256, so any two renders of the same document can be compared by hash. Assets are reproducible and diffable — the point of the whole boundary.
Engine pin & support statement
Pinned engine: upstream Graphite (
GraphiteEditor/Graphite) at commitd7ae6029e0c1818d81a13b0389ef1808496a715b, fetched shallowly and built byscripts/fetch-engine.sh. Build facts and the reference binary sha256:docs/ENGINE-PIN.md.Why a pin: upstream is a fast-churning alpha. The pin exists for reproducibility — the node registry (324 identifiers on this build), document serialization shapes, and rendered output are only stable against one exact engine commit. Deterministic tooling requires a deterministic engine.
Zero modifications: the engine source is never modified; the clone stays pristine (
git status --porcelainempty after build — asserted byscripts/fetch-engine.sh).Upgrading is a deliberate re-pin: choose a new upstream commit, update the pinned SHA in
scripts/fetch-engine.shanddocs/ENGINE-PIN.md, rebuild, and re-run the full test suite (including the real-CLI e2e tiers) before relying on the new build. Node-registry content and serialization shapes can change between upstream versions.Support boundary: bugs in this repository (the MCP server, builder, runner, validator) belong here; questions about engine behavior belong upstream at
GraphiteEditor/Graphite— this wrapper changes no engine code. The SIGSEGV-after-write quirk is an upstream behavior, absorbed by the quarantine contract above.
Integration
Register the server with your MCP client (Claude Desktop, Cursor, or any client supporting the Model Context Protocol). Give it the absolute path to the built entrypoint:
{
"mcpServers": {
"graphite-editor-mcp": {
"command": "node",
"args": ["/absolute/path/to/graphite-editor-mcp/dist/src/index.js"]
}
}
}To explore the server interactively:
npx @modelcontextprotocol/inspector node dist/src/index.jsA scripted non-interactive stdio handshake lives at scripts/stdio-probe.mjs (node scripts/stdio-probe.mjs dist/src/index.js graphite_list_nodes '{"filter":"GradientMap"}').
Limitations
No PDF / no print pipeline — the CLI rejects PDF.
Fallback-font text only — the text template uses the engine's embedded fallback font. The raw-
TextNoderesource failure is fully decoded and the authoring-shape fix is execution-verified; seedocs/font-resource-investigation.md— embedded brand fonts would need the.gddresource route (future work, not this build).Sequential renders in v1 — one graphene-cli child at a time;
graphite_render_variantsruns its variants in a plain loop.Debug-binary latency — the pinned debug build spends ~1–1.5 s per spawn (startup + render); a release build (
cargo build --release -p graphene-cli, then pointGRAPHITE_CLI_PATHat it) cuts that substantially.Inline documents are materialized and kept under
tmp/mcp-inline/(small JSON files; gitignored) so error messages always point at a real document on disk.graphite_list_nodescaches the registry per process lifetime.Strictly a wrapper: no upstream source modifications, no GUI driving.
Development
npm run typecheck # tsc --noEmit
npm run build # tsc -p tsconfig.json → dist/src/*.js
npm test # vitest run — 122 tests, 5 filesTest layout (tests/):
runner.test.ts/validator.test.ts— process-runner and artifact-validation units against synthetic fake CLIs intests/synthetic/*.mjs(crash-after-write, clean exits, hangs, garbage writes) — the real binary is never required.builder.test.ts/ fixtures — builder + template round-trips against committed proven documents intests/fixtures/.templates-e2e.test.ts— real-CLI renders of all four templates, parametric pixel checks, determinism. Skipped as a whole when the binary is absent (describe.skipIf).mcp-e2e.test.ts— the MCP surface over the SDK'sInMemoryTransport: a protocol tier (no binary needed: tool advertisement,SPEC_INVALIDenvelopes, structural validation) and a real-CLI tier (template/inline renders, list-nodes, compile check, variants batch).
Engine pin: docs/ENGINE-PIN.md records the pinned commit, the reproducible scripts/fetch-engine.sh, and the reference binary sha256; the clone (engine/) is gitignored and never modified.
Built by The Native Creative.
Licensed under the MIT License — Copyright (c) 2026 The Native Creative.
Available Tools
4 toolsgraphite_list_nodesGraphite node registryA
List every node identifier the pinned graphene-cli understands (exits cleanly; cached in memory after the first call). Optional filter: case-sensitive substring match.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden. It discloses that the command exits cleanly and is cached in memory after the first call, and explains the filter behavior (case-sensitive substring). However, it does not mention return format, error handling, or permission requirements. These gaps are moderate for a read-only list operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence states the core purpose first, then adds behavioral details and parameter info without redundancy. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list tool with one optional parameter and no output schema, the description covers purpose, parameter behavior, and some operational characteristics. It lacks return type details, but these are not essential for a basic enumeration tool. Overall it is adequately complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must explain the parameter. It does so effectively: 'Optional filter: case-sensitive substring match' clarifies the parameter's name, optionality, and matching semantics. This adds substantial value beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'List' and the resource 'every node identifier the pinned graphene-cli understands'. It distinguishes itself from sibling tools (render, validate, render_variants) by describing a listing operation, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance on when to use this tool versus alternatives. It does not mention when not to use it or suggest a sibling for other needs. Usage is only implied by the description's content, not stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
graphite_renderGraphite renderA
Render a Graphite document to a validated artifact. Pass EITHER { templateId, params? } (params default to the template defaults; known templates: duotone-image, pattern-background, solid-background, text-on-background) OR { document } (inline legacy .graphite JSON, materialized under tmp/mcp-inline/). output: { format: png|svg|jpg|gif, width?, height?, outputName? } — raster formats require BOTH width and height; SVG may omit size; outputName is a base name (extension appended automatically). Artifacts land in /exports/. Every success reports sha256, artifact validation, and quarantine metadata: the pinned CLI always exits SIGSEGV after writing, so quarantinedAfterWrite: true is normal and expected.
| Name | Required | Description | Default |
|---|---|---|---|
| output | Yes | ||
| params | No | ||
| document | No | ||
| templateId | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full transparency burden and succeeds: it warns that the pinned CLI exits SIGSEGV after writing, that quarantinedAfterWrite: true is normal, that artifacts land in <projectRoot>/exports/, and that outputName gets an extension appended automatically. This is exactly the kind of non-obvious behavior an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every clause carries operational weight, and it is front-loaded with the core purpose and the either/or input decision. The SIGSEGV warning is unusual but necessary, not filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no annotations and no output schema, the description covers the full invocation path: inputs, output format constraints, artifact location, and success metadata (sha256, validation, quarantine). It is sufficient for an agent to call the tool correctly, with only minor gaps around error behavior and gif sub-options.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the prose must compensate. It does: templateId vs document, params defaulting behavior, known templates, output format enum, raster requiring both width/height, and outputName semantics are all explained. The only substantive gap is the gif animation object (mode/fps/frames/duration), which is left to the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence identifies a specific operation: 'Render a Graphite document to a validated artifact,' which clearly separates it from list/validate operations. It does not explicitly mention graphite_render_variants, so sibling differentiation is mostly implicit rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit input routing: pass either templateId/params or an inline document, lists known template IDs, and states output size rules. This is clear when-to-use context, but it never tells the agent when to prefer graphite_render_variants or graphite_validate_doc, so exclusions are absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
graphite_render_variantsGraphite batch rendererA
Render 2..20 parametric variants of ONE template sequentially (one GPU-heavy child at a time). Each variant is a full params object; artifacts land as -. under outputDir (default /exports/). A failing variant is reported per-item and does NOT abort the batch; the call is an error only when every variant fails.
| Name | Required | Description | Default |
|---|---|---|---|
| width | Yes | ||
| format | Yes | ||
| height | Yes | ||
| variants | Yes | ||
| outputDir | No | ||
| templateId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so richly: it discloses sequential execution, GPU-heavy resource behavior, per-item failure isolation, the fact that the call only errors if all variants fail, artifact naming, and outputDir defaulting. This is well beyond a mere 'renders variants' statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: the first states the core operation and constraints, the second covers artifact output, and the third covers failure semantics. No wasted words or repetition of schema details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no annotations and no output schema, the description provides a strong operational contract: limits, ordering, failure behavior, output location, and error condition. The exact per-item report structure is not specified, but the essential information needed to call and interpret the outcome is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It adds meaning for variants ('full params object'), templateId/index artifact naming, format in the filename, and outputDir default. Width and height are left implicit, but their purpose is reasonably inferable from the render context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('render') and resource ('parametric variants of ONE template') and clearly marks this as a batch operation distinct from the single-render sibling. The '2..20' range and 'ONE template' scope prevent confusion with graphite_render, graphite_list_nodes, and graphite_validate_doc.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description conveys when to use the tool: when rendering multiple parametric variants of a single template sequentially. It does not explicitly name the sibling alternatives or state when not to use it, but the batch/one-template framing gives clear context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
graphite_validate_docGraphite document validator
Structurally validate a Graphite document WITHOUT rendering: JSON parse, network_interface shape, node-entry tuples, and export references. Pass EITHER { document } (inline) OR { documentPath }. Optional compileCheck: true adds the engine's own compile verdict (default false). Validation results are data: an invalid document returns valid: false with precise reasons instead of an error.
| Name | Required | Description | Default |
|---|---|---|---|
| document | No | ||
| compileCheck | No | ||
| documentPath | No |
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
graphite_list_nodes - First observed
graphite_render - First observed
graphite_render_variants - First observed
graphite_validate_doc
Related MCP Connectors
Build and run visual creative-production workflows from your AI agent.
Deterministic image rendering for agents: JSON template in, on-brand PNG out.
Generate reproducible image, video, and audio assets with leading models and your own provider keys.
Design, save, and run outcome-aligned AI workflows and verifiers, with reliable image output.
Related MCP Servers
- AlicenseAqualityDmaintenanceA deterministic video rendering engine that enables AI agents to create programmable, reproducible videos via MCP protocol.149 npm2MIT
- AlicenseNot gradedqualityCmaintenanceEnables agentic creators to generate images, videos, and audio, run taste-based scoring, and publish through human-gated signed manifests using their own keys and local provenance.MIT
- AlicenseAqualityCmaintenanceEnables AI agents to generate game-ready 3D assets from reference images with PBR textures, and to retexture meshes the user already owns, while recording full provenance for every generated file.2010MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to create Material Maker node graphs from natural language, validate them against the node catalog, and render them headlessly to PBR texture maps and editable .ptex files.5MIT