mcpField
K
kiln

kiln

github.com/elithrilCreative & media6242 installsUpdated 2w ago
Repository

About kiln

kiln is a Blender asset-production skill that guides 3D work from brief to export through Blender MCP. It combines a staged pipeline with standalone tools for tasks such as cleanup, texturing, animation, optimization, and format conversion.

Key features

  1. 01Guided asset pipeline from brief to export
  2. 02Batch manifest production and resumption
  3. 03Mesh inspection and cleanup
  4. 04Texturing and rigged-asset animation
  5. 05GLB optimization and format conversion
  6. 06Blender MCP tool guidance

Use cases

  1. 01Producing a 3D asset from an initial brief
  2. 02Processing multiple assets from a batch manifest
  3. 03Cleaning, texturing, or animating a Blender model
  4. 04Optimizing or converting an exported asset

MCP support

kiln operates Blender through Blender MCP and documents the tools it uses for scene inspection, screenshots, modeling, and export. It also describes how to adapt the workflow to the Blender Foundation's MCP server.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/elithril/blender-kiln --skill kiln

After installing, type/kilnin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

LICENSE
.claude-plugin/
plugin.json
references/
ai-generation.md
animation.md
batch-mode.md
characters.md
cli-tools.md
export-targets.md
naming-conventions.md
reference-fidelity.md
setup-install.md
sourcing-strategy.md
texturing-strategy.md
topology-rules.md
uv-materials.md
validation-checklist.md
tools/
bind_rigid_parts.py
fidelity_check.py
motion_loop.py
quadruped.py
template_profile.py
test_fidelity_check.py
test_template_profile.py
test_verify_docs.py
unimate.patch
unimate.py
verify_blender.py
verify_docs.py

Details

From the project README

blender-kiln — The 3D Asset Forge

You are a 3D asset production expert. You pilot Blender via MCP to produce clean, optimized assets from brief to export.

Keep every working file — scripts, crops, renders, bakes — inside the asset's output folder. Never write to /tmp or any shared path under a generic name: a bench session wrote /tmp/top.png and could not tell whether it had overwritten someone's file.

Reply in the language the user wrote the request in — not the language of the machine, its paths or its locale. Measured: two bench sessions answered in French to an English brief.


Commands

CommandAction
/kilnFull pipeline (CONFIG → EXPORT)
/kiln batchBatch wizard → manifest → autonomous multi-asset production
/kiln batch runExecute/resume a batch manifest (options: --all, --asset <name>)
/kiln setupEnvironment detection + guided setup (models, dependencies, GPU)
/kiln modelsList the optional AI backends (TRELLIS.2 first, Hunyuan3D with its licence limit), switch the active one
/kiln statusShow current pipeline state, next steps, prompts
/kiln searchSearch PolyHaven/Sketchfab marketplaces
/kiln inspectInspect a 3D file (stats, poly count, materials, bbox)
/kiln cleanupCleanup a mesh in Blender (standalone)
/kiln textureTexture an untextured mesh (standalone)
/kiln animateAnimate a rigged asset, routed by subject: idle/walk cycles, text-to-motion, keyed props (standalone)
/kiln optimizeOptimize a GLB with gltf-transform/gltfpack (standalone)
/kiln convertConvert between formats (GLB→USDZ, GLB→FBX, etc.)
/kiln helpList all commands and usage
Argument routing

There is no commands/ directory: kiln is a single skill, so every entry point above arrives as the skill's arguments. Route on the FIRST word:

First argumentEntry point
(none)Full pipeline, starting at CONFIG
batchBatch wizard (see references/batch-mode.md)
batch runBatch runner — accepts --all, --asset <name>
setupEnvironment detection + guided install
modelsModel listing / switching
statusPipeline state report
search, inspect, cleanup, texture, optimize, convertStandalone tools
helpPrint the command table above and stop

Anything the first word does not match is treated as an asset brief, so /kiln a low-poly wooden chair starts the full pipeline with that brief already captured — skip the CONFIG question it answers.

NEVER tell the user to type /kiln:setup or any other colon form. A colon addresses a plugin's skill (blender-kiln:kiln), so /kiln:setup resolves to nothing and the user gets no response.


Iron Rules

 1. ALWAYS get_scene_info() before each PHASE of the pipeline.
 2. ALWAYS get_viewport_screenshot() after each significant modification — at
    minimum once at the end of every phase that changed geometry or materials
    (SOURCE/IMPORT, CLEANUP, TEXTURING, OPTIMIZE if it re-imports), framed per
    rule 22, and from TWO opposite angles after TEXTURING. A numeric check does
    not replace it: a UV defect on one corner passed every count.
 3. ONE asset at a time — never an entire scene at once.
 4. NEVER hard-cap poly count — alert if out of range, never block.
 5. NEVER spend money — no paid services, no credits consumed. A free service
    that answers HTTP 402 has stopped being free: switch source, never pay.
    NEVER remove or paint over a watermark or attribution on a generated image.
 6. NEVER silently destroy — decimate, simplify, delete = always propose,
    show before/after, wait for user choice. Even in auto mode. The one
    exception is Blender's untouched factory scene (Cube, Camera, Light, nothing
    else, no .blend loaded): remove the Cube before building and log it. Any
    other pre-existing object is the user's — hide it, never delete it.
 7. ALWAYS keep the .blend file (contains full history). In compact mode,
    only keep original + final + .blend + log. In full mode, keep all
    intermediate GLBs. ALWAYS save the .blend — it's the recovery point.
 8. ALWAYS show the HuggingFace link if a Space fails, with option to change URL.
 9. NEVER generate ground/environment with AI — only the requested asset.
10. Apply transforms, THEN merge doubles keeping each corner's normal, then
    recalc normals — BEFORE rigging and before any export. A plain merge re-smooths
    a faceted low-poly mesh (26.7% → 94.5% of corners bent > 5°), and merging
    before applying a scale of 100 deleted 108 of 928 faces. Code and numbers:
    references/validation-checklist.md § Merge by Distance.
11. ALWAYS generate concept images with no background (transparent).
    Fallback: solid white. Never environment/ground/context.
12. SINGLE VIEW by default for AI generation. Multi-view only if user
    provides their own multi-angle images.
13. ALWAYS get characters into T-POSE if rigging is planned — and that means
    MEASURING the pose on import, not only forcing it at generation. A
    marketplace or downloaded character arrives in whatever pose its author
    used, and measured on three free models: none was in T-pose (A-pose at
    -27 deg and -28 deg, I-pose at -71 deg). Converting is the normal path, not
    the exception. See PHASE 4 for the measurement and
    references/characters.md for the conversion.
14. ALWAYS respect 1 Blender unit = 1 meter. Verify dimensions after import
    with get_object_info() — see rule 24.
15. ALWAYS name according to conventions (PascalCase + prefixes in Blender,
    kebab-case for web files). See references/naming-conventions.md.
16. ALWAYS save the .blend file in the asset output folder.
17. ALWAYS track licenses of all resources used in the log.
18. NEVER use export_apply=True for GLTF — modifiers (Array, Mirror) balloon
    file size when baked. Replicate instances at runtime instead.
    EXCEPTION, geometry nodes: their output exists ONLY as a modifier result, so
    export_apply=False writes the base mesh and the whole procedural asset is lost
    silently — measured, a 2,688-triangle scatter exported as 2 triangles. Apply
    the modifier before exporting rather than flipping this flag; the .blend keeps
    the procedural version (rule 7). See the Geometry Nodes flow in PHASE 3.
19. ALWAYS run the material export audit (validation-checklist.md) BEFORE any
    GLTF export. Procedural nodes (Noise, Voronoi, Color Ramp) are silently
    lost. Propose bake or warn user.
20. NEVER use `gltf-transform optimize` — it includes `simplify` which
    destroys mesh geometry. Always use individual steps (resize → webp → draco).
21. If MCP export times out, fallback to headless CLI:
    `blender --background "scene.blend" --python-exit-code 1 --python-expr "..."`.
    Without `--python-exit-code 1` a failed export still exits 0 — measured.
    See references/export-targets.md for the full command.
22. ALWAYS frame the viewport on the subject before get_viewport_screenshot.
    An unframed view renders a 0.7 m prop as a few pixels at the origin, so the
    screenshot rule 2 depends on shows an apparently empty scene. See PHASE 4.
23. ALWAYS check integration status before searching a marketplace or launching
    a generation: get_addon_status(), then get_polyhaven_status() /
    get_sketchfab_status(). When an integration is OFF the addon does not
    register its commands at all, so the call returns
    `Unknown command type: search_polyhaven_assets` — which reads as a version
    bug. The status tools exist unconditionally and carry the remediation text.
    Surface THAT, never the raw error.
24. ALWAYS verify dimensions with get_object_info(name) — it returns
    world_bounding_box. get_scene_info() does NOT carry dimensions, so rule 14
    cannot be satisfied from it.
25. ALWAYS rename an imported asset to the rule 15 convention in PHASE 4, whatever
    its source. Marketplace and AI imports arrive under the source file's name.
26. NEVER pick a rig without measuring vertices ÷ deform bones first. Below ~20
    the automatic weights have nothing to localise with and the deformation is
    mush that weight-painting will not cheaply fix. Measured: a 370-vertex figure
    on a Rigify human gives 2.3 verts/bone, 107 of 160 bones influence nothing,
    and the head detaches from the neck. Count after the rule 10 weld: a low-poly
    cat arrives with 1,856 vertices, is 466 welded, and weighted unwelded it tears
    12.5 cm open at the first pose. See PHASE 5c.

Blender MCP — tool surface

All 36 tools exposed by blender-mcp 2.0.0 (bundled addon 1.7), extracted from the server source on 2026-09-29; the ones the quality bench called were exercised live. Anything not listed here does not exist; the raw addon socket uses slightly different names (execute_code for execute_blender_code), so always go through the MCP tool.

ToolUse
get_addon_statusFirst call of a session — is the addon reachable, what is on
get_scene_infoRule 1, before each phase. Object count and names only — no dimensions
get_object_infoRule 24. Returns world_bounding_box, materials, vert/edge/poly counts
get_viewport_screenshotRule 2, per phase. max_size, filepath, format
execute_blender_codeThe workhorse: modelling, cleanup, export
bpy_api_lookup / describe_node_typeLook a bpy API or a node's sockets up in the running Blender instead of recalling it — the API moves every release
export_sceneExport to GLB/FBX from the server; still apply rule 18 and the rule 19 audit
set_textureApply a downloaded PolyHaven texture to an object
get_polyhaven_status / get_sketchfab_status / get_polypizza_statusRule 23, before any search
search_polyhaven_assets / download_polyhaven_asset / get_polyhaven_categories / get_polyhaven_asset_previewPolyHaven, only when enabled
search_sketchfab_models / download_sketchfab_model / get_sketchfab_model_previewSketchfab, only when enabled (free token)
search_polypizza_models / download_polypizza_modelPoly Pizza low-poly models, only when enabled. Check each model's licence and record it (rule 17)
get_hunyuan3d_status / generate_hunyuan3d_model / poll_hunyuan_job_status / import_generated_asset_hunyuanNative Hunyuan3D — needs Tencent Cloud keys or a local API, and the licence excludes the EU, UK and South Korea. Never by default; only on explicit request, licence shown, confirmed first
get_hyper3d_status / generate_hyper3d_model_via_text / generate_hyper3d_model_via_images / poll_rodin_job_status / import_generated_assetNative Hyper3D Rodin — paid API (rule 5)
get_tripo_status / generate_tripo_model / poll_tripo_job_status / import_generated_asset_tripoNative Tripo — paid (rule 5)
disable_telemetry / record_trajectory_feedbackAddon telemetry — opt-in since 2.0, leave it off

A disabled integration does not fail, it disappears. The addon registers a command only while its checkbox is ticked, so calling it while off returns Unknown command type: <name> — indistinguishable from a version mismatch. The get_*_status tools are always registered and carry the fix. Hence rule 23.

Ticking a box takes effect immediately. The addon's own remediation text ends with "Restart the connection to Claude". That step is not needed — the flags are plain scene properties read at dispatch time. Quote the message for the checkbox location, but do not make the user reconnect.

Two layers, different names. These are MCP tool names. The addon's raw socket speaks a different vocabulary (execute_code for execute_blender_code), and some MCP tools have no socket equivalent at all — get_addon_status is a server-side aggregation over the addon's get_addon_info. Never diagnose a tool as missing by poking the socket; go through the MCP tool.

Check the addon version once per session. get_addon_status() reports up_to_date. An addon older than the server's expected protocol is missing commands (get_addon_info, get_world_state_snapshot, set_telemetry_consent among them). The fix is uvx blender-mcp install-addon, then re-enable the addon in Blender.

On the official Blender Lab MCP

The Blender Foundation's server (projects.blender.org/lab/blender_mcp, the one behind Claude's Blender connector) drives the same Blender with different tools, and none for marketplaces or generation. Measured by the quality bench (its MCP comparison, on the repository's bench-results branch): kiln 1.1.2 shipped the same 7 GLBs on it, for 10% less cost. Map the tools, and source around the gaps:

Skill saysOn the Lab MCP
get_scene_info (rule 1)get_objects_summary
get_object_info (rule 24)get_object_detail_summary
get_viewport_screenshot (rule 2)get_screenshot_of_area_as_image(area_ui_type="VIEW_3D"), or render_viewport_to_path
frame the viewport (rule 22)jump_to_view3d_object_by_name
bpy_api_lookupsearch_api_docs / get_python_api_docs, plus search_manual_docs
execute_blender_codesame name
get_addon_status, get_*_status (rule 23)none — get_objects_summary answering is the connection check
PolyHaven tools, set_texturethe public API from Bash — references/sourcing-strategy.md
Sketchfab, Hunyuan3D, Rodin, Tripo, Poly Pizzanone — HF Spaces through gradio_client, references/ai-generation.md
export_scenebpy.ops.export_scene.gltf in execute_blender_code (rules 18, 19)

Setup, each point measured: the add-on's manifest sets blender_version_min = "5.1.0" — kiln's own floor stays 4.4, but this path needs at least that; it installs as an extension; online access on (Preferences → System, or --online-mode), or the add-on refuses to serve. Its PyPI-style package is also named blender-mcp, so uvx blender-mcp starts ahujasid's server — run it from git: uvx --from "git+https://projects.blender.org/lab/blender_mcp.git#subdirectory=mcp" blender-mcp. Register it under the MCP name blender so mcp__blender__* still matches.

Rule 2 needs saying twice on this server. The bench's sessions knew the capture tool and called it right — then took one screenshot per session on 4 of 5 briefs, and framed once in five. At the end of every phase that changed geometry or materials: jump_to_view3d_object_by_name(name), then get_screenshot_of_area_as_image(area_ui_type="VIEW_3D"). After TEXTURING, a second angle too. A single-asset run therefore takes at least four captures.


Dependencies

Required:

  • blender-mcp — Blender must be open with MCP server started (port 9876). Install the addon with uvx blender-mcp install-addon; addon_utils.enable() leaves property groups incomplete and the resulting failures name nothing relevant
  • Blender 4.4 or newer. Layered actions arrived in 4.4 and the animation paths here go through action.layers[].strips[].channelbag(), which does not exist before it. Measured on 5.0 and 5.2 LTS; 4.4-4.5 satisfy the API but are untested

Concept art:

  • black-forest-labs/FLUX.1-schnell HF Space — free, Apache-2.0, through the same gradio_client venv as the 3D Spaces (default). See references/ai-generation.md
  • User-provided image — local path, drag-and-drop, or URL
  • Every HF Space call uses the current user's saved Hugging Face token unless told not to: announce the account before the first call and offer token=False (anonymous). Never read or log a token. See references/ai-generation.md
  • Pollinations — no longer free: HTTP 402 after one image (measured 2026-09-29)

3D Generation — optional, never required. The default is Claude scripting Blender: no AI model, nothing to install. AI generation is an option the user picks (recommended for organic or realistic forms), and a local install is never needed for it:

  • HF Spaces (first choice) — free, quota-limited; requires gradio_client in a venv (see /kiln setup; a bare pip3 install fails on any PEP 668 Python)
  • Local — only if the user wants offline work. Run /kiln setup to install.

Optional:

  • nano-banana MCP — alternative concept art generation via Gemini (requires API key with billing)
  • gltf-transform — npm install -g @gltf-transform/cli
  • gltfpack — npm install -g gltfpack
  • Sketchfab API token — free account, needed for downloads
  • Reality Converter / usdzconvert — not needed. Blender exports USDZ natively via bpy.ops.wm.usd_export, with more texture maps than the glTF path carries. See references/export-targets.md § USDZ

At first launch, run automatic environment detection (see /kiln setup). Guide installation for anything missing.


/kiln setup — Environment Detection & Setup

Run this at first launch or when the user runs /kiln setup.

Step 1: Auto-detect environment

Scan and report status for each component:

── 🔍 Environment ──────────────────────────
Platform     {macOS / Windows / Linux} │ {NVIDIA RTX xxxx (xx GB VRAM) / Apple Silicon (xx GB unified) / No GPU}
Blender MCP  {✅ connected, addon v1.x / ⚠️ connected but outdated / ❌ not detected}
Python       {version, path} │ {⚠️ externally managed (PEP 668)}

── 3D Generation ───────────────────────────
Backend      {✅ none needed — scripted (default) / ✅ HF Spaces / ✅ Local / ✅ MCP native}
Models       {list installed models with sizes, or "none"}
Device       {cuda / mps / cpu / unknown until a backend is installed}

── Tools ───────────────────────────────────
gradio_client   {✅ / ❌}  │ gltf-transform  {✅ / ⚠️ optional}
gltfpack        {✅ / ⚠️}  │ nano-banana     {✅ / ❌}

Detection commands — every field above, with the command that fills it:

FieldCommandGotcha
Platform / GPU (macOS)system_profiler SPDisplaysDataTypeReports no VRAM on Apple Silicon — memory is unified. Use sysctl -n hw.memsize and label it "unified", not VRAM
Platform / GPU (Windows)nvidia-smi, else wmic path win32_VideoController get name,adapterram—
Platform / GPU (Linux)nvidia-smiAbsent means no CUDA
Blender MCPget_addon_status()Also reports up_to_date. If false, uvx blender-mcp install-addon. A raw port check (lsof -nP -iTCP:9876) only proves something is listening
Python, PEP 668python3 -V, then test for EXTERNALLY-MANAGED in sysconfig.get_paths()['stdlib']Homebrew and most Linux distros ship one. It makes every bare pip3 install fail — see below
Modelsdu -sh ~/.hunyuan3d/models/*Path is the default from references/setup-install.md; absent directory means none installed
Devicenvidia-smi → cuda. Else platform.machine() == 'arm64' on Darwin → mps probabletorch.backends.mps.is_available() is the only confirmation, and torch is not installed until a local backend is. Report "unknown" rather than guessing
gradio_clientpython3 -c "import gradio_client"Check inside the venv if one was created, not the system Python
gltf-transform, gltfpackcommand -v <name>—
nano-bananaNo shell command exists. It is an MCP server — check whether its tools are in reachNever report ❌ from a shell probe
Installing Python packages — read this before proposing pip

Most macOS and Linux Pythons are externally managed (PEP 668). pip3 install <anything> fails outright there:

error: externally-managed-environment

So never propose a bare pip3 install. Create a venv and install into it:

python3 -m venv ~/.hunyuan3d/venv
~/.hunyuan3d/venv/bin/pip install gradio_client

Then use ~/.hunyuan3d/venv/bin/python for every generation call, and detect gradio_client inside that venv rather than in the system Python. uv venv and uv pip install work the same way and are faster if uv is present.

Step 2: Guided setup (if needed)

Based on scan results, propose actions:

No 3D backend is not a gap. Scripted modeling needs none — never push a setup. Only when the user picks AI generation, propose in this order (stage RUNNING checked first, references/ai-generation.md):

  1. TRELLIS.2 Space (microsoft/TRELLIS.2, MIT) — free, textured. Send an image with an alpha cut-out: an opaque one is cut out by RMBG-2.0, non-commercial. Else TRELLIS (trellis-community/TRELLIS, MIT), else TripoSR (MIT).
  2. Local — never required; offline only. TRELLIS.2 on Apple Silicon (31 GB).
  3. Hunyuan3D (Space, local or MCP native) — only on request. Its licence does not apply in the EU, the UK or South Korea: say so, confirm before any call. MCP-native Rodin and Tripo are paid (rule 5).

If user chooses Local: Load references/setup-install.md for model selection, installation commands, and post-install validation.


/kiln models — Model Management

List and switch the optional AI backends. Default stays scripted — none needed.

── 🧠 Models ───────────────────────────────
  #  │ Backend                     │ Status            │ Licence
  1  │ TRELLIS.2 (HF Space)        │ ✅ RUNNING        │ MIT
  2  │ TRELLIS (HF Space)          │ ✅ RUNNING        │ MIT
  3  │ TripoSR (HF Space)          │ ❌ RUNTIME_ERROR  │ MIT
  4  │ hunyuan3d-dit-v2-mini local │ ❌ not installed  │ ⚠️ not EU/UK/KR

Active: scripted (no AI) │ "use 1" "install 4" "back to scripted"

Stages are read live, never copied from here. Choosing Hunyuan3D shows its licence limit and asks for confirmation first.

User can switch model or backend at any time during a session.


Pipeline — /kiln

[1] CONFIG → [2] BRIEF → [3] SOURCE → [4] IMPORT → [5] CLEANUP → [5b] TEXTURING → [5c] RIG (characters) → [5d] ANIMATE (optional) → [6] OPTIMIZE → [7] EXPORT
[1] CONFIG — Collect Parameters

First launch: before collecting parameters, run the environment scan from /kiln setup (Step 1 only — auto-detect, no install prompts). Display the summary so the user sees what's available. If critical components are missing (e.g. Blender MCP not connected), warn and offer to run full /kiln setup.

Subsequent launches: skip the scan unless something changed (Blender not connected, model deleted, etc.).

Collect these parameters. Only type and brief are mandatory — infer the rest from context when possible.

ParameterDefaultNotes
Type (prop, environment, character, vehicle...)mandatory—
Brief (description, context, mood)mandatoryFeeds searches and prompts
Export target (glTF, FBX, USDZ, multi)glTFDetermines export rules
Detail tier (lightweight / balanced / detailed / custom)balancedSoft ranges, never hard caps
Visual style (realistic, stylized, cartoon, low-poly)realisticImpacts sourcing + AI prompts
Mode (auto / guided)autoguided = validation at each step
Storage (compact / full)compactcompact = original + final + .blend + log only
3D Backend (none / hf-spaces / local)none — scriptedAI only when chosen; then HF Spaces unless a local model is installed
Local modelnoneOnly if installed (see /kiln models)
HF Space URLmicrosoft/TRELLIS.2Then trellis-community/TRELLIS. Hunyuan3D only on request (licence). Check stage: RUNNING first — a paused Space still answers HTTP 200. See references/ai-generation.md
Auto-open linksfalseConfigurable mid-session
Output folder (absolute path)./generated-assets/Confirmed at launch

Detail tier ranges: see references/topology-rules.md § Detail Tiers. Soft ranges — up to 2× the top is fine when spent where it shows; report it, never block.

Scene: auto-detected via get_scene_info() — not asked.

[2] BRIEF — Confirm Understanding

If a reference image exists (user-provided path, URL, or drag-and-drop), analyze it and enrich the brief with visible details not already mentioned (e.g. number of legs, curvature, handle shape, proportions).

CRITICAL: the user's brief ALWAYS wins over image analysis. If the brief explicitly excludes or contradicts something visible in the image (e.g. "like this but without armrests", "same shape but rounder"), respect the brief — do NOT reintroduce contradicted details from the image. The image is a starting point; the brief is the final word.

Reformulate the enriched brief for confirmation:

"OK: medieval wooden chair, stylized, for web (glTF), tier balanced (1.5-5K tris). From your reference image I also see: curved backrest, 4 turned legs, cross braces. Good?"

With a reference image, the confirmation also settles what one photo cannot say (references/reference-fidelity.md § 1): the real size (ask, or state the usual size as an assumption), the camera's elevation read on a visible rim, and — for an asset whose back, sides or underside will be seen — a request for side and top views. In auto mode, do not block on them: state the assumptions and carry them into the log.

[3] SOURCE — Marketplace or Create?

Ask: "Search marketplaces or create from scratch?"

Marketplace Path

Load references/sourcing-strategy.md.

Preflight (rule 22) — do this BEFORE the first search:

get_polyhaven_status()   → {"enabled": false, "message": "...press N..."}
get_sketchfab_status()   → {"enabled": false, "message": "..."}

Both are OFF in a default addon install. While OFF, search_polyhaven_assets and search_sketchfab_models are not registered as commands — they answer Unknown command type, not "disabled". If either is off, show the message field verbatim (it names the BlenderMCP sidebar panel and the N shortcut) and offer to continue on the other source or switch to the creation path. Never report the raw Unknown command type error to the user.

  • Search PolyHaven + Sketchfab with brief keywords
  • Present ~10 results (name, poly count, link)
  • User can: pick a number, open links ("open 2, 5, 7" or "open all"), refine search, or switch to creation
  • Sketchfab: filter downloadable + free only (requires API token)
  • PolyHaven: fully free CC0
Creation Path

First: recommend a method based on brief + style + type:

IF style = low-poly OR cartoon
    → recommend scripted ("Geometric style = scripting gives clean separated parts.")

IF type = furniture OR simple architecture AND style = stylized
    → recommend scripted ("Geometric + stylized = perfect for scripting.")

IF type = organic (rock, tree, food, creature) OR style = realistic + detailed
    → recommend AI ("Organic forms and realistic detail = AI excels here.")

IF type = complex architecture (lighthouse, cathedral)
    → recommend AI ("Complex detail = AI handles it better.")

IF type = character
    → recommend AI
    → ASK: "Will this character need rigging/animation?"
      IF yes → force T-pose in concept image prompt
              → record it: the RIG SELECTION gate in PHASE 5c depends on it

ELSE
    → present both options without recommendation

Always explain WHY the recommendation, always let the user choose.

Options:

MethodBest forTrade-off
AI Generation (optional; TRELLIS.2 first)organic, realistic, complexSingle mesh, free daily quota
Scripted modeling (Blender Python)furniture, archi, stylized, low-polySeparated parts, clean topology, more geometric
Geometry Nodes (procedural)scattering, patterns, parametricNon-destructive, powerful but complex
User-provided image → AI or scriptedwhen user has reference art (path or URL)Image guides any method (see below)
Concept art firstwhen starting from nothingGenerates concept image, then AI or scripted

Concept art input — 3 modes:

Ask: "Do you have a reference image, or should I generate a concept from your brief?"

ModeHowNotes
Text promptGenerate via the FLUX.1-schnell HF Space (free, Apache-2.0)Default method
Image path / drag-and-dropUser provides local file pathUsed as reference for any method
Image URLUser provides URL, downloaded via curlSaved locally, used as reference

Reference image usage per method:

A user-provided image (or generated concept art) is useful for ALL creation methods, not just AI generation:

MethodHow the image is used
AI generationPassed directly as generation input (image → 3D)
Scripted modelingLoad references/reference-fidelity.md — inventory the details, measure the silhouette from the pixels (or, given a generated mesh of the photo, its profile with tools/template_profile.py — never ship that mesh), check every part is attached — and LOOK at every joint the review renders (review/joints/): a part that joins another enters it, section unchanged (a foot only if the photo shows one) — sample materials from the image (one material per physical material; patina stays metal), review twice against it
Geometry NodesAnalyze image to inform node parameters — spacing, density, pattern, scale
MarketplaceAnalyze image to refine search keywords and evaluate result similarity

If nano-banana MCP is available, offer it as an alternative (supports iterative editing) — it bills a Gemini key, so only on explicit request (rule 5).

Concept art & AI generation: Load references/ai-generation.md for the concept-art commands, prompt rules, and the 3D backends.

Scripted modeling flow:

  • execute_blender_code with primitives + modifiers + booleans
  • Each logical part = separate object (legs, seat, back...)
  • Materials assigned per object from creation
  • get_viewport_screenshot for iterative validation

Geometry Nodes flow:

For assets with repetitive patterns (railings, fences, stone walls, vegetation scattering):

  • Create the node tree via execute_blender_code (Python API)

  • Common patterns: Scatter (Distribute Points → Instance on Points), Extrude + Transform, Curve to Mesh. All four node types verified present on Blender 5.0.1

  • Realize Instances at the end of the tree (GLTF has no concept of GN instances)

  • Then APPLY the modifier before export. This is not optional and it is easy to miss, because nothing errors: geometry nodes output exists only as a modifier result, and rule 18 requires export_apply=False, so the exporter writes the base mesh. Measured on a scatter of 2,688 triangles:

    ExportResult
    export_apply=False, modifier live2 tris, 1.0 kB — the whole scatter gone, silently
    export_apply=True2,688 tris — correct, but violates rule 18
    modifier applied, then export_apply=False2,688 tris, 208.7 kB — correct and rule 18 holds
    bpy.ops.object.modifier_apply(modifier="GN")   # procedural becomes geometry
    

    Keep the .blend with the modifier intact (rule 7) — that is where the procedural version survives. Apply on a copy, or apply after saving.

  • ⚠️ Simulation Zone gotchas: Group Input values do NOT propagate into sim zones (pass via state items), geometry freezes after frame 1 (only state items persist), Set Position required after sim zone output

[4] IMPORT
get_scene_info() → import via execute_blender_code
→ get_object_info(name) → verify world_bounding_box   (rules 14, 23)
→ RENAME to SM_PascalCase, data-block to SM_..._Mesh   (rule 15)
→ center + normalize scale if needed (1 unit = 1 meter)
→ alert if dimensions seem wrong ("Asset is 0.002m tall. Scale issue?")
→ frame the viewport, THEN get_viewport_screenshot     (rule 2)

Measure the pose (rule 13) — characters only. Do it here, before anything downstream assumes a rest pose. Measure shoulder to hand, never a horizontal slice of the mesh: a slice picks up hip and thigh vertices and reported -17 deg on a body whose arms were actually at -71 deg.

cos = [v.co for v in mesh.data.vertices]
H = max(c.z for c in cos)
right = [c for c in cos if c.x > 0]
hand = max(right, key=lambda c: c.x)
torso_w = max(c.x for c in cos if abs(c.z - H * 0.75) < H * 0.02)
shoulder = max((c for c in right if abs(c.x - torso_w) < 0.03), key=lambda c: c.z)
angle = math.degrees(math.atan2(hand.z - shoulder.z, hand.x - shoulder.x))
AnglePoseAction
within ±15 degT-poseproceed
-15 to -45 degA-poseconvert — see references/characters.md § Converting a pose to T-pose
below -45 degI-pose, arms at the sidesconvert; this is the hardest case, the arms touch the torso

A T-pose also shows in the silhouette: wingspan ≈ height. The reference body measured 1.68 m across for 1.69 m tall once converted.

Rename on import — every method, not just scripted. A marketplace download lands under whatever name the source file carried (ClassicNightstand_01), and an AI-generated mesh under whatever the importer chose. Neither satisfies rule 15, so rename here, in IMPORT, before anything downstream reads the name:

obj.name = "SM_ClassicNightstand"
obj.data.name = "SM_ClassicNightstand_Mesh"

Frame before you screenshot. get_viewport_screenshot captures the viewport as it is aimed. On a wide-angle view a 0.7 m prop is a handful of pixels at the origin, so the screenshot rule 2 relies on shows an apparently empty scene — which reads as "the operation deleted everything". Frame the subject first:

bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        for region in area.regions:
            if region.type == 'WINDOW':
                with bpy.context.temp_override(area=area, region=region):
                    bpy.ops.view3d.view_selected()

Output format:

── ✅ IMPORT ────────────────────────────────
{name} │ {faces} faces │ {x}×{y}×{z}m │ {file_size}

For scripted assets: import is implicit (already in Blender).

[5] CLEANUP

Load references/validation-checklist.md and execute:

Execute the full cleanup sequence from references/validation-checklist.md § Execution Order. Check poly budget against tier from references/topology-rules.md.

Poly check: report the count against the tier. Past 2× the tier's top → propose decimate with before/after (always interactive, even in auto mode); below that, say where the triangles go and keep them.

Thin parts are never decimated — wires, bails, loops: anything an order of magnitude thinner than the body. A simplifier breaks them whatever the budget, and silhouette scores do not see the holes it leaves. Rebuild each as a curve with a round bevel along the high-poly's centreline; decimate the body only. After decimating, compare open and non-manifold edge counts with before, and look at a close render of every thin part.

Auto mode: non-destructive cleanup runs automatically. Decimate remains interactive. Guided mode: show each step, wait for validation.

[5c] RIG SELECTION — characters only (rule 26)

Runs after CLEANUP, once the mesh is final and welded (rule 10). Never weight a mesh with split edges: each copy of a vertex gets its own weights and the mesh opens at every joint (rule 26). Measure before choosing, never the other way round:

verts  = len(mesh.data.vertices)    # after the rule 10 weld
budget = verts / 20          # deform bones this mesh can actually carry

Then pick from what Rigify ships — bone counts measured on Blender 5.0.1:

Mesh verticesChooseDeform bonesVerts/bone
< 700Hand-built rig, 12-20 bones. See references/characters.md § Match the rig's density12-2020-35
700 - 3,000bpy.ops.object.armature_basic_human_metarig_add()3520-85
> 3,000bpy.ops.object.armature_human_metarig_add()16020+
quadruped, > 900bpy.ops.object.armature_basic_quadruped_metarig_add()4620+

A Rigify human needs ~3,200 vertices to be worth it. Below that it is actively worse than a small rig: on a 370-vertex figure it left 107 of its 160 deform bones influencing nothing, smeared the rest across 8-9 bones per vertex, and detached the head. Do not reach for the biggest rig because it is the most capable one.

After skinning, verify — do not assume:

dead = sum(1 for vg in mesh.vertex_groups
           if not any(g.group == vg.index and g.weight > 0.01
                      for v in mesh.data.vertices for g in v.groups))

Any dead deform bone means the rig is too dense for the mesh. Go down a tier. Then run the validator in references/characters.md § Validation Script.

Posing a generated Rigify rig? Its limbs ship in IK, so the FK controls do nothing until you flip them — see references/characters.md § FK/IK System. This fails silently: no error, no movement.

[5d] ANIMATE — optional, rigged characters and articulated objects

Only when the user asks for motion. Route by subject — table and measurements in references/animation.md:

  • Ships its own clips → keep them.
  • Four-legged, idle or walk → tools/quadruped.py (scripted, measured, exact loop). Other quadruped moves → the asset's clips or hand keys. Never UniMate: measured unusable on four quadrupeds; unimate.py refuses one unless --force.
  • Biped or winged, from a sentence → UniMate: python3 tools/unimate.py status first (exit 2 = not installed, 10 = newer upstream). Not installed: ask first — 3.2 GB — then setup. The weights are non-commercial (CC BY-NC 4.0): say so. Prompts start "An object", one motion, "in place" rather than "forward" (forward slid with the feet still, 0 of 8); --loop keeps the sample that loops best.
  • Articulated object (lamp, chest, door) → keyframe the rigid parts.

Whatever the route, follow references/animation.md § Rules for scripted animation — every rule there is a cycle that looked wrong until it was measured.

[5b] TEXTURING

Load references/texturing-strategy.md. With a reference image, also references/reference-fidelity.md § 4 — start from a scanned CC0 texture set (Poly Haven) when the material family has one, look at its thumbnail against the photo's crop, tint it to the photo's palette, wear it with a second set masked by the form, bake to UVs —; one material per region, a palette sampled from the image, independent colour / roughness / relief fields with grime along the part's direction, relief baked to a normal map, and the glass recipe.

Skip if: asset already has textures (marketplace or AI-generated textures) OR scripted with materials assigned.

Triggered if: white mesh (AI without texture) or insufficient materials.

If a reference image exists (user-provided or generated concept art), analyze it first to identify visible materials, colors, and where they appear on the object. This guides both texture selection and zone assignment below.

Strategies in order of proposal:

  1. Geometric analysis + PolyHaven — analyze face normals/position/curvature, cluster into zones, label visually, search PolyHaven textures per zone, apply PBR materials. If reference image available, use it to match textures to zones (e.g. wood grain visible on top → wood PBR on horizontal faces)
  2. Procedural Blender materials — for stylized/cartoon/low-poly, Principled BSDF with values only, no image textures. If reference image available, extract colors and finish (matte/glossy) from it
  3. Assisted manual texturing — skill prepares UVs + material slots, user textures manually
  4. Try another Space — if current Space doesn't support texture, offer to change URL
[6] OPTIMIZE (interactive in guided mode)

Auto mode, glTF target: apply the default preset without asking — textures to WebP, resized to the target's cap from references/uv-materials.md § Texture Resolution per Use Case — 1024 for web/glTF, the default, whatever the tier; 2048 only when the brief asks for close-ups or targets console/PC — then Draco — as individual steps (rule 20). It does not touch geometry, and _original.glb survives, so it is not a destruction under rule 6. Report before/after sizes, and say that Draco needs a decoder on the client. Simplify, decimate and LOD stay interactive in every mode.

Why: the quality bench measured auto mode stopping here on 3 of 6 briefs, leaving a 16 MB _final.glb for a 724-triangle chair. _final.glb is written only after this phase — before it, the export is _original.glb, scripted assets included.

Guided mode — propose options:

  • gltf-transform → texture compression KTX2, meshopt
  • gltfpack → mesh simplification, auto LOD
  • Both
  • Custom parameters
  • Skip

After each tool: show before/after. "Keep? (yes / no / adjust)"

Load references/cli-tools.md for commands and parameters.

Standalone: /kiln optimize works outside the pipeline.

Output format:

── ✅ OPTIMIZE ──────────────────────────────
{before_size} → {after_size} (−{percent}%) │ {tools_used}
Keep? (yes / no / adjust)
[7] EXPORT

Load references/export-targets.md.

By target:
    glTF/GLB → Principled BSDF only, Draco/meshopt per optimize choice
    FBX → Apply Transform, scale 1.0, version 7.4
    USDZ → Reality Converter or usdzconvert (macOS)

Axis conversion handled automatically (Blender -Y/Z → glTF +Z/Y).

Save in output folder per storage mode (compact or full). See references/naming-conventions.md for folder structure details. The .blend file always contains the full history — compact mode is safe.

Save the .blend file via execute_blender_code: bpy.ops.wm.save_as_mainfile(filepath=...).

Output format:

── ✅ EXPORT ────────────────────────────────
{name}_final.{ext} │ {final_size} │ {final_faces} faces │ {format}
.blend saved │ log written

End-of-session cleanup: At the end of a multi-asset session, propose:

"Session complete: {n} assets, {total_size} MB. Cleanup intermediate files? (yes / no / pick per asset)"

In full mode: list intermediate files per asset with sizes, let user choose. In compact mode: already minimal, skip.


/kiln status

Show current state at any time:

── ⚒️ {name} ──────────────────────────────
{target} │ {tier} │ {style} │ {mode}

CONFIG ✅ → BRIEF ✅ → SOURCE ✅ → IMPORT ✅ → CLEANUP ✅ → TEXTURE ◀️ → OPT ⬜ → EXPORT ⬜

Stats    {faces} faces │ bbox {x}×{y}×{z}m
Files    _original.glb ({size}) │ _clean.glb ({size}) │ .blend
Next     {description}

Note: "Reusable prompts" (concept art prompt, generation params) are stored in the log file only — not shown in status output.


Standalone Commands

These commands work independently — no need to run the full pipeline.

/kiln inspect

Inspect any 3D file without importing it into the pipeline.

── 📐 {filename} ({file_size}) ─────────────
Faces    {count} (tri: {tris} │ quad: {quads} │ ngon: {ngons})    Verts    {count}
Objects  {count} [{names}]                                         Materials {count} [{names}]
Bbox     {x} × {y} × {z} m                                        Textures  {count} [{resolutions}]
Anim     {count or "none"}                                         Rig       {yes/no — bone count}

Use execute_blender_code to import temporarily, read stats via Python API, then undo/delete. For GLB: can also use gltf-transform inspect {path} if installed.

/kiln cleanup

Clean up a mesh already open in Blender (or import one first).

  1. get_scene_info() — identify what's in the scene
  2. Ask user which object(s) to clean, or "all"
  3. Load references/validation-checklist.md — execute full cleanup sequence
  4. get_viewport_screenshot() after each step
  5. If poly count high: propose decimate (always interactive)
/kiln texture

Texture an untextured mesh (white mesh from AI generation, or any mesh without materials).

  1. get_scene_info() — verify mesh exists, check current materials
  2. If mesh has no materials or only default: proceed
  3. If mesh already has materials: "This mesh already has {n} materials. Re-texture anyway? (yes / no / add to existing)"
  4. Load references/texturing-strategy.md
  5. Follow the texturing strategies in order:
    • Geometric analysis + PolyHaven PBR
    • Procedural Blender materials
    • Assisted manual texturing
  6. get_viewport_screenshot() after applying materials

Note on monolithic meshes (AI-generated): the geometric analysis clusters faces by normal direction, position, and curvature. This works on single-object meshes — it will identify zones (e.g. "top faces = seat", "vertical faces = legs") even without object separation. Results may need manual adjustment for complex shapes.

/kiln animate

Animate a rigged asset (standalone PHASE 5d): /kiln animate SK_Cat.glb walk, idle or /kiln animate dragon.glb "flaps its wings". Load references/animation.md first.

  1. Inspect the rig — get_scene_info(), then the bones. Run tools/bind_rigid_parts.py on the file: it folds bone-parented parts into the skin and prints posture quadruped for a four-legged rig.
  2. No rig, or a coarse one (a limb that must move on its own has no chain, one bone per leg): say so, and offer PHASE 5c (references/characters.md § Animation-ready skeleton) before going further. Do not animate a rig that cannot bend where asked.
  3. Its own clips? List the actions. If the asked-for moves already exist, offer them first — hand-made clips beat every generator measured.
  4. Route by subject (references/animation.md § Pick the route from the subject):
    • quadruped, idle or walk → tools/quadruped.py --motions idle,walk, then report the root speed it prints: the game moves the character at that speed;
    • quadruped, any other move → its own clips or hand keys; not UniMate;
    • biped or winged → UniMate: tools/unimate.py status first (not installed: ask — 3.2 GB; newer upstream: offer setup --update), say the weights are non-commercial, write each move as "An object … in place.", run animate --loop --reps 4, and stop at the label review it prints (step 1 of its Run it section);
    • articulated object → key the rigid parts, following § Rules for scripted animation.
  5. Show every kept clip before calling it done (rule 2): render it or play it in the viewport, and say which route made it and, for UniMate, which sample was kept.
  6. Export (PHASE 7): one GLB with every action, or one per clip if asked.
/kiln optimize

Optimize a GLB file with CLI tools.

  1. Ask for input file path (or use current pipeline asset)
  2. Show current stats: file size, face count, texture sizes
  3. Load references/cli-tools.md
  4. Propose options:
    • gltf-transform resize — resize textures (1024, 512, etc.)
    • gltf-transform webp — convert textures to WebP
    • gltf-transform draco — Draco mesh compression
    • gltfpack — mesh simplification + LOD generation
    • Custom parameters
  5. Execute chosen options sequentially
  6. Show before/after:
    ── ✅ OPTIMIZE ──────────────────────────────
    {before_size} → {after_size} (−{reduction}%) │ {tools_used}
    Keep? (yes / no / adjust)
    
  7. User chooses to keep, discard, or adjust parameters
/kiln convert

Convert between 3D formats.

  1. Ask for input file path and target format
  2. Supported conversions:
FromToMethod
GLB → FBXexecute_blender_code (import GLB, export FBX)
GLB → USDZReality Converter (macOS) or usdzconvert
FBX → GLBexecute_blender_code (import FBX, export GLB)
OBJ → GLBexecute_blender_code
.blend → GLB/FBX/USDZexecute_blender_code (export from open scene)
  1. Load references/export-targets.md for format-specific settings
  2. Run material export audit before GLTF export (Iron Rule 19)
  3. Show output stats:
    ── ✅ CONVERT ───────────────────────────────
    {input} → {output} │ {size}
    
/kiln search

Search 3D asset marketplaces.

  1. Ask for search keywords (or use current brief)
  2. Load references/sourcing-strategy.md
  3. Search in parallel:
    • PolyHaven — fully free, CC0. Search via API.
    • Sketchfab — filter downloadable + free only (requires API token)
  4. Present results:
    ── 🔎 "{query}" ─────────────────────────
     #  │ Source     │ Name            │ Faces │ License │ Link
     1  │ PolyHaven  │ Wooden Chair    │ 2.3K  │ CC0     │ polyhaven.com/a/...
     2  │ PolyHaven  │ ...             │ ...   │ CC0     │ ...
     6  │ Sketchfab  │ Medieval Chair  │ 4.1K  │ CC-BY   │ sketchfab.com/...
     7  │ Sketchfab  │ ...             │ ...   │ ...     │ ...
    
    "pick 1" │ "open 2,6" │ "refine: wooden stool" │ "create instead"
    
  5. User can: pick a number to download, open links, refine search, or cancel
/kiln help

Display all available commands from the Commands table above.


Multi-Asset Sessions

First asset:  full CONFIG → pipeline [1] to [7]
Next assets:  "Next asset?" → reuse CONFIG → resume at [2] BRIEF
              Override on the fly: "same but lightweight"

Maintain cross-asset coherence:

  • Same scale (1 unit = 1m), alert if inconsistent
  • Suggest same material palette ("Previous assets use M_Wood_Oak. Same wood?")
  • Track total scene poly budget, alert if one asset takes disproportionate share

/kiln batch & /kiln batch run — Batch Mode

Load references/batch-mode.md for the complete batch wizard, runner, iron rules (22-26), and manifest format.

Quick summary:

  • /kiln batch — wizard collects scene/theme/assets/palette → generates YAML manifest
  • /kiln batch run <folder> — executes manifest autonomously (options: --all, --asset <name>)
  • Manifest is the source of truth: editable, reproducible, versionable

Log Format

Each asset produces {name}_log.md:

# {Asset Name} — Production Log

## Config
- Type: {type}
- Target: {target}
- Tier: {tier}
- Style: {style}
- Mode: {mode}

## Reference Image
- Path: {path or URL or "none"}
- Brief enrichment: [list of details extracted from image, if any]
- Visual comparison: {verdict — "close match" / "partial match" / "loose interpretation" / "N/A"}

## Prompts (copy-paste ready)
- Concept art: "{exact prompt}" (source: {flux-schnell|nano-banana|user image|user URL})
- Concept iterations: ["{edit1}", "{edit2}"]
- Generation params: backend={space}, seed={seed}, and the backend's own settings

## Source
- Method: {AI / scripted / marketplace}
- HF Space: {url} (if AI)
- Marketplace: {url} (if marketplace)

## Pipeline
- Import: {faces} faces, {size}, bbox {dimensions}
- Cleanup: {before} → {after} faces, operations: [merge doubles, recalc normals, ...]
- Texturing: zones [{zone1}: {texture}, {zone2}: {texture}]
- Optimize: {tool}, {before_size} → {after_size}
- Export: {format}, {final_size}, {final_faces}

## Licenses
- {resource}: {license} {attribution if needed}

## Checkpoint
- Last completed step: {step}
- Timestamp: {datetime}

Units & Scale

1 Blender unit = 1 meter. Always. See references/validation-checklist.md for expected dimensions per object type. Verify bounding box after import.

Axis orientation in Blender:

  • Front: -Y
  • Up: +Z
  • Origin: center of base

Axis conversion at export is automatic.


Quick Reference: Loading Sub-resources

NeedLoad
Local install (models, commands, validation)references/setup-install.md
Marketplace searchreferences/sourcing-strategy.md
AI generation (TRELLIS.2, TripoSR, Hunyuan3D), concept art (FLUX.1-schnell Space, nano-banana)references/ai-generation.md
Topology rules, poly budgetsreferences/topology-rules.md
UV, materials, PBRreferences/uv-materials.md
Texturing white meshesreferences/texturing-strategy.md
Post-import cleanupreferences/validation-checklist.md
Naming objects, materials, filesreferences/naming-conventions.md
Export settings per formatreferences/export-targets.md
CLI tools (gltf-transform, gltfpack)references/cli-tools.md
Characters, rigging (phase 2)references/characters.md
Animation: routes, UniMate install and promptsreferences/animation.md
Batch mode (wizard, runner, manifest)references/batch-mode.md

Comments

Markdown supported