1. What we can actually do
These are capabilities reached in the source workflow, not a promise that every reader’s installation already supports them.
| Capability | What was reached | Important boundary |
|---|---|---|
| Natural-language control of Blender | Scene queries, Python execution, documentation searches, screenshots, rendering, and saved-file/background work through an MCP bridge | Discover the actual tools; different servers expose different surfaces |
| Parametric production | Named, reproducible models, families of assets, automated measurements, exports, and manifests | A script finishing does not prove the asset looks right |
| Whole-house scenes | Multiple house concepts with room volumes, furnishings, native scenes, room schedules, plans, exterior views, and browser exports | Visualization is not structural design, a permit set, a cost estimate, or a buildability determination |
| Architectural realism studies | Controlled work on sofas, cushions, pillow bodies and piping, bedding, wood floors, plaster, glass, furniture supports, and practical lighting | Scoped stills can pass while other rooms remain unfinished |
| Evidence-driven correction | Source/candidate geometry guards, material and lighting comparisons, sampled support checks, target-aware cameras, and deliberately broken test fixtures | Each checker has a declared scope; there is no universal “realism PASS” button |
| Native-frame house tours | A roughly eight-minute, native-30-fps tour covering 35 named spaces was produced with reusable route/capture logic | That film used an earlier furnished scene; later realism stills do not upgrade it retroactively. Framing and motion review remained separate gates |
| Animated fire studies | Gas/wood-fire volumes, 200-file sequences, and consecutive native-frame probes including sequence wrap checks | These were local experiments, not proof that a new final whole-house film was finished |
| Portable delivery | Shared texture packaging, reopen checks, native scenes, GLB candidates, images, chapter data, and website handoff packages | Geometry/import checks do not establish browser material fidelity or mobile acceptance |
| Large asset batches | Hundreds of exported assets with disk-based counts/hashes and staged delivery | Exported assets can still lack placement data or working application integration |
The strongest transferable capability is a loop: describe a defect → make a bounded change → save → measure → inspect the real image → retain or reject → reuse the improvement.
This is how you move past attractive one-off demos. Better prompting helps, but project organization, evidence, and persistent iteration do much of the work.
2. The operating principles
- Use Blender as the source of visual truth. A generated illustration of a room does not prove your
.blendscene contains that room. - Prove access with execution. A tool list, a connected badge, a running local add-on, and a passing configuration check are different pieces of evidence.
- Save before expensive work. Keep scripts and checkpoints outside conversation history.
- Serialize edits to one scene. One active writer owns an interactive Blender session. Independent workers use separate files and output folders.
- Use short orchestration calls and durable jobs. A short tool timeout should not define how ambitious a render can be.
- Measure actual bytes. Audit the saved/exported file, not only the live scene or a claimed manifest.
- Inspect what you intend to deliver. Check browser exports in the browser; check films as motion; reopen portable native scenes.
- Keep a reviewed parent. A pending candidate is not automatically the next approved baseline.
- Record failures. Rejected images and negative tests prevent the same mistake from returning.
- Continue within the assignment. Do not ask “shall I continue?” between already-authorized steps. Stop for a real blocker, a requested checkpoint, a scope decision, or an actual platform limit.
3. Identify the right Blender MCP
“Blender MCP” names several different projects. This matters more than it first appears.
The setup behind our tuned workflow
Our recorded setup used Blender Lab MCP, with an add-on running inside Blender and a separate blender-mcp MCP process. Its public starting points are:
- Blender Lab: https://www.blender.org/lab/mcp-server/
- Source and setup documentation: https://projects.blender.org/lab/blender_mcp
- Lab extension repository: https://lab.blender.org/
The Lab page currently describes Blender 5.1 or newer as a prerequisite. Our historical connection evidence reported a 5.2.0 LTS build; that is an observation, not a requirement to obtain that exact build. Record the versions actually installed. [S1]
The similarly named community project
The separate project at https://github.com/ahujasid/mcp-for-blender was formerly widely linked as ahujasid/blender-mcp. Its current package name and setup commands differ from the Lab project. It has its own add-on, bridge, and optional integrations. [S2]
Do not install one project’s add-on and the other project’s bridge merely because both mention Blender and port 9876. A matching port does not establish a matching wire protocol.
For a new setup following this guide, start with the Lab route. If a working community installation is already present, keep its components matched and adapt the tests rather than replacing it casually. The artistic and project-management lessons still apply.
Capture a compatibility record
Record these locally, without secrets:
{
"blender_version": "RECORD_ACTUAL",
"blender_binary": "RECORD_LOCAL_ABSOLUTE_PATH",
"addon_project": "Blender Lab MCP",
"addon_version": "RECORD_ACTUAL",
"addon_source_revision": null,
"mcp_server_command": "RECORD_VERIFIED_LOCAL_COMMAND",
"mcp_server_version_or_revision": "RECORD_ACTUAL",
"client_surface": "ChatGPT web or local Codex",
"transport": "stdio or private tunnel",
"addon_host": "127.0.0.1",
"addon_port": 9876,
"tunnel_health_port_if_used": 8081,
"last_successful_execution_utc": null
}
Unknown fields stay null or explicitly unknown. Do not make up an exact version lockfile: our historical setup evolved, and this document is not a redistribution of its binaries.
4. Choose your connection route
| Route | Where the assistant/tool runtime lives | How it reaches Blender | Extra pieces |
|---|---|---|---|
| A: local Codex | On the computer running Blender, or an explicitly configured executor | Local MCP process → local Blender add-on | No OpenAI tunnel needed for a same-host stdio connection |
| B: ChatGPT with a private tunnel | Chat orchestration is hosted; a local tunnel client runs beside the MCP server | ChatGPT → private tunnel → local MCP process → Blender add-on | Tunnel permissions, runtime credentials, and a configured custom MCP connection |
| C: a separate render/build host | A local or remote job runner on a known machine | Saved .blend + scripts → isolated background Blender | Explicitly authorized file transfer/job access; separate from proving interactive MCP |
For a hosted chat, localhost normally refers to the machine where a particular tool executes, not automatically to your laptop. A terminal in a hosted sandbox does not imply a route into your personal computer.
A .mcpb bundle supported by one application does not automatically install into every OpenAI surface. A local Codex configuration does not automatically become a ChatGPT web plugin. Treat those as different setup tasks. [S3]
Default simplification: keep the add-on, bridge, tunnel client if needed, and project files on one machine until the first end-to-end test succeeds. Add remote machines only for an actual reason.
5. Discover the environment
The receiving assistant should first determine:
- Which surface is this: hosted ChatGPT, local Codex, or another client?
- What computer will actually run Blender, and what access is available to it?
- Is there already an installed add-on, bridge command, tunnel profile, or managed service?
Inspect what you can. Ask only for missing facts. Do not invent shell access, claim to click UI you cannot control, or repeatedly ask the user to reconfirm evidence they just supplied.
Useful non-secret local checks on macOS/Linux:
command -v blender
command -v uv
command -v codex
command -v tunnel-client
An empty result can mean “not on PATH,” not “not installed.” On macOS a common Blender binary is:
/Applications/Blender.app/Contents/MacOS/Blender
Verify that file on the intended machine. Do not hard-code a username or assume an application bundle lives in the standard location.
For GUI-launched apps and background services, use verified absolute executable paths. They may not inherit the PATH or environment variables of your Terminal.
Create a small local connection record with host roles, executable paths, profile name, ports, service label, log locations, and a restart command. Keep credentials elsewhere. That record eliminates much repeated diagnosis.
6. Install the Blender-side pieces
6.1 The add-on inside Blender
Use the current Blender Lab page and its download/setup links. The documented drag-and-drop installation has two stages: adding the Lab extension repository, then installing the add-on. Installing from disk is another path. Enable the extension and start its server in its preferences. [S1]
If Blender reports that networking/online access is disabled, inspect the relevant preference and the extension’s current documentation. A local socket can still be governed by Blender’s networking permissions. Change the necessary setting intentionally; do not disable unrelated security controls.
Start with a new empty project or a disposable copy. A Blender execution tool can run powerful Python code. Keep the bridge on loopback and use a trusted client. The Lab project explicitly warns that its code-execution facility is not a sandbox. [S1]
6.2 The separate MCP bridge
Installing the add-on is only half the job. Your MCP client needs a command that starts the matching server process.
Use the Lab project’s current Setup documentation. Obtain its server from the official project/release, or reuse a verified installation. Avoid assuming that an unrelated package with the same short name is the right server.
Two common launcher forms to inspect against the installed release are:
/absolute/path/to/a/managed/environment/bin/blender-mcp
and a source checkout launched with uv:
/absolute/path/to/uv --directory /absolute/path/to/blender_mcp/mcp run blender-mcp
These are launcher patterns, not a promise about the layout of an arbitrary downloaded archive. Confirm the actual entry point and installed help. If reusing a server that another client installed, use its real executable; do not assume it is under a particular application’s private directories.
The official source host was not fully retrievable during preparation of this guide. Follow its live Setup page for installation details rather than treating a guessed package-install command as validated here.
6.3 Check the Blender listener
On macOS:
lsof -nP -iTCP:9876 -sTCP:LISTEN
On Linux, if installed:
ss -ltnp 'sport = :9876'
On Windows PowerShell:
Get-NetTCPConnection -LocalPort 9876 -State Listen |
Select-Object LocalAddress,LocalPort,OwningProcess
Identify the process. A random process on 9876 is not Blender. If a different port is deliberately configured, use that port throughout.
Do not curl the add-on socket expecting an HTTP response. It is not the tunnel health server or necessarily an HTTP MCP endpoint.
7. The settings we actually used
The following values came from a recorded working setup and its add-on screenshot. They are a starting profile for the same family of add-on, not universal defaults or a benchmark result.
| Setting | Recorded value | Why we retained it |
|---|---|---|
| Host | localhost, with loopback expected | Keep the local code-execution bridge local |
| Port | 9876 | Consistent add-on/bridge pairing |
| Auto Start | Enabled | Reduce missed manual starts after opening Blender |
| Auto Start Delay | 1 second | Defer bridge start briefly during application startup |
| Active timer interval | 250 ms / 0.25 s | Responsive queue polling in this workflow |
| Idle timer interval | 250 ms / 0.25 s | Avoid the slower idle polling behavior in that profile |
| Idle delay | 1 minute / 60 s | Recorded transition setting; not a socket-timeout cure |
| Logging | Enabled during setup/recovery | Observe requests and failures locally |
| Tunnel health/admin address | 127.0.0.1:8081 | Avoided an observed collision on 8080; this is a separate process/port |
Historical add-on records mention different version labels on different dates. Do not call the table the default settings of every release. If your installed version omits a control, do not invent it or patch the add-on without a reason.
What the timer tuning did not fix
We encountered an idle connection failure around a minute of inactivity. The timer changes were not demonstrated to eliminate it. The operational response was to:
- Prepare a short sequence of meaningful calls before beginning.
- Save scripts and files, so the connection is not the only copy of the work.
- After a pause, test the connection with a tiny read-only request before an expensive action.
- If the idle path wedges, stop repeated retries and recover the relevant add-on/bridge.
- Move long work to an isolated, durable job where possible.
Do not replace thoughtful recovery with endless keepalive calls. Reducing a polling interval does not turn Blender’s main-thread operations into parallel work, solve every network timeout, or keep a sleeping laptop reachable.
A sensible tuning experiment
Keep a baseline. Change one timing setting, record its old/new values, perform a few small real operations, deliberately pause, then test recovery. Record latency, failures, and machine load. Restore the baseline if the change is worse.
Our exact values are useful historical evidence; an improvement on your hardware should be measured rather than assumed.
8. Local Codex setup
This route does not require tunneling a same-machine stdio server to the public internet.
After verifying the actual executable, a registration pattern is:
codex mcp add blender -- /absolute/path/to/blender-mcp
codex mcp list
For a verified source-checkout launcher:
codex mcp add blender -- /absolute/path/to/uv --directory /absolute/path/to/blender_mcp/mcp run blender-mcp
Choose one matching registration, not both for the same instance. Local Codex supports stdio entries; its current documentation describes CLI registration and [mcp_servers.NAME] configuration. ChatGPT web does not read that file. [S3]
An equivalent illustrative TOML entry is:
[mcp_servers.blender]
command = "/absolute/path/to/blender-mcp"
startup_timeout_sec = 30
tool_timeout_sec = 120
The 30/120-second values above are proposed starting allowances, not our measured optimum. Check the installed client’s help and actual upstream deadlines. Increasing a client timeout cannot extend a shorter limit in an intervening service.
Use the client’s supported refresh/restart mechanism after configuration changes. Then enumerate the real tool names and perform the probe in Section 11. A saved configuration entry is not yet a successful connection.
Do not automatically add powerful filesystem/process permissions just because the agent requests them. If the current execution policy cannot support background subprocesses, use the supported saved-file tools or a separately authorized local runner instead.
9. ChatGPT through a private tunnel
9.1 Understand the layers
There are separate components:
| Component | Job | What it does not prove |
|---|---|---|
| Blender add-on | Executes operations in Blender | Hosted chat can reach the machine |
| Matching MCP bridge | Translates MCP tools into Blender operations | OpenAI’s tunnel is connected |
Local tunnel-client | Carries requests between OpenAI and the private MCP target | Every request reached Blender |
| ChatGPT custom MCP plugin/connection | Makes configured tools available in the conversation | The local process is still running |
The OpenAI private tunnel uses an outbound client near the MCP server. Availability depends on the supported product surface and organization/workspace permissions; this guide does not grant them. [S4]
9.2 Prepare the account and runtime
Use the current official tunnel guide and Platform UI. Reuse a suitable existing tunnel. Obtain its identifier and an appropriate runtime key locally. The tunnel and intended ChatGPT workspace must be correctly associated. Managing tunnels and running them require different permissions. [S4, S5]
Keep these concepts separate:
- Tunnel identifier: identifies a routing resource; it is not an API key.
- Runtime credential: authenticates the local client; keep it out of chat.
- MCP server authentication: a separate question from tunnel runtime authentication.
Do not solve discovery errors by randomly switching OAuth settings. Select the authentication scheme your actual MCP server supports.
9.3 Discover the installed CLI before using old flags
tunnel-client help quickstart
tunnel-client help doctor
Use the verified absolute binary path if it is not on PATH. A historical failure in our setup was simply that a bare command was not discoverable.
9.4 Create a named stdio profile
The following is a template for a new profile, using the current documented command family. Replace values before running; inspect/reuse existing profiles instead of overwriting them.
tunnel-client init \
--profile blender-local \
--sample sample_mcp_stdio_local \
--tunnel-id YOUR_ACTUAL_TUNNEL_ID \
--mcp-command '/absolute/path/to/blender-mcp'
The target is the MCP bridge command, not the Blender application and not http://localhost:9876. If the launcher has arguments, preserve them using the installed CLI’s documented command parsing. An executable-only wrapper around a verified command can avoid nested quoting mistakes. [S6]
Do not hand-author a YAML schema from memory. Let the installed CLI generate its supported profile, then inspect non-secret target/port fields.
9.5 Load a credential without sharing it
Our historical working path sourced an existing local environment file. A file is convenient, but it is plaintext, not a password vault. Prefer an appropriate OS-backed secret store for unattended deployments when supported. Never put a secret in this public guide, a command argument, a transcript, or a shared .blend text block.
If you intentionally choose a local environment file, this optional Python snippet prompts locally and refuses to overwrite an existing file:
import getpass
import os
import shlex
from pathlib import Path
target = Path.home() / ".config/tunnel-client/blender-local.env"
target.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
if target.exists():
raise SystemExit("Existing credential file kept; use its established loader.")
key = getpass.getpass("Runtime tunnel key, entered locally: ").strip()
if not key:
raise SystemExit("No key entered; no file created.")
fd = os.open(target, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, "w", encoding="utf-8") as handle:
handle.write("CONTROL_PLANE_API_KEY=" + shlex.quote(key) + "\n")
print("Created the local credential file; its contents were not printed.")
Save/run that code locally as a Python script. If using a heredoc, the secure prompt still needs a usable local terminal. Do not run it through a remote chat tool that will capture the key.
9.6 First successful foreground run
Use Bash for this snippet, and substitute the actual verified binary path. The 8081 choice is an example retained from our working recovery, not a reserved port.
(
set +x
set -a
source "$HOME/.config/tunnel-client/blender-local.env" || exit
set +a
/absolute/path/to/tunnel-client doctor \
--profile blender-local \
--health.listen-addr 127.0.0.1:8081 --explain &&
/absolute/path/to/tunnel-client run \
--profile blender-local \
--health.listen-addr 127.0.0.1:8081
)
This is intentionally the foreground test, not a persistent installation. Keep its Terminal attached while testing. Do not start it if a healthy managed runtime for the same target already exists.
In another terminal:
curl --noproxy '*' --max-time 5 -sS -i http://127.0.0.1:8081/readyz
Check the local admin UI if supplied by your version. A stdio readiness check can succeed before protocol discovery is observed; end-to-end tool execution remains the final connection test. [S5]
9.7 Add the custom MCP connection in ChatGPT
Current official instructions describe adding a custom MCP server from ChatGPT’s Plugins UI, choosing a server URL or a tunnel, configuring authentication, and installing the resulting plugin before use. UI labels can change; consult the linked page rather than searching indefinitely for an older “developer mode” toggle. Workspace policy still applies. [S7]
Select the same tunnel the local runtime uses. Refresh/discover its tools and enable the needed tools in the intended conversation. Run Section 11’s read-only probe. Do not publish a private tunnel as a public plugin listing: private testing and public distribution have different endpoint requirements. [S4]
10. Persistent startup and correct restarts
10.1 First inventory, then repair
Before creating anything persistent, identify the executable, arguments, profile, service label, credentials loader, logs, and health listener of existing jobs.
The name “tunnel” is weak evidence. In one real incident, a supposedly relevant persistent tunnel job was actually /usr/bin/ssh, forwarding unrelated application ports. Blender was listening, but no local OpenAI tunnel client was running. Restarting the SSH job would not start that missing process.
10.2 Prefer the current client’s supported lifecycle
Newer tunnel-client documentation describes managed runtimes operations. If your installed version supports them, inspect runtimes connect --help, configure the verified target and credential reference, and use its status output. Do not improvise nohup/disown or add another supervisor over an already-managed instance. [S6]
Useful discovery/status patterns:
tunnel-client runtimes list
tunnel-client runtimes connect --help
tunnel-client runtimes status blender-local --json
Do not assume these commands exist in an older binary. A process being launched, healthy, ready, and able to execute Blender are four distinct states.
10.3 Existing macOS launchd installations
Our workflow also used launchd-based supervision in related infrastructure. A Mac-specific repair installer for the Blender client was prepared and locally logic-tested during one incident; its installation on that Mac was not confirmed in the evidence used for this guide. This guide therefore does not call that proposed repair a proven permanent Blender fix.
For an intentionally configured user LaunchAgent, use your own label and current user ID:
launchctl print "gui/$(id -u)/org.example.blender-tunnel"
launchctl kickstart -k "gui/$(id -u)/org.example.blender-tunnel"
org.example.blender-tunnel is a placeholder. Run the restart only after confirming that exact job is the Blender tunnel you intend to restart. A restart is not needed on every session.
For an installed job not yet registered, the relevant operation can be:
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/org.example.blender-tunnel.plist"
An agent’s usual design is RunAtLoad, KeepAlive, a measured restart throttle, absolute paths, private logs, and an exec wrapper that loads its credential locally. User agents run in a login session; they do not make a sleeping or logged-out laptop an always-on render server. [S8]
If an assistant prepares a new service, require it to inspect conflicts, avoid duplicate clients, preserve existing files, validate the target, provide uninstall instructions, and verify after Terminal closes and after a normal login/restart. Do not add persistence until the foreground path works.
10.4 Inspect an SSH alias without guessing
On a system that actually uses an SSH bridge, this read-only pattern shows resolved non-secret forwarding settings:
ssh -G YOUR_HOST_ALIAS |
grep -E '^(hostname|user|port|localforward|remoteforward|serveraliveinterval|serveralivecountmax) '
Review the output locally before sharing host/user details. ExitOnForwardFailure does not make SSH exit merely because a later forwarded destination refuses a connection. A running SSH process is not proof that an application behind it works. [S9]
On Linux or Windows, use the platform’s intended service manager/task mechanism if needed. Do not paste macOS launchctl commands into another OS, and do not claim this guide provides a tested installer for all three platforms.
11. Prove the connection
Ask the client to discover the actual Blender tools. In the Lab tool surface used here, the interactive execution tool is named execute_blender_code; a saved-file/background counterpart may be named execute_blender_code_for_cli. Tool names can be namespaced by the host product.
11.1 One read-only execution probe
Supply a fresh harmless probe label in the request so an old pasted result cannot be confused with a new execution:
import bpy
import json
result = {
"ready": True,
"probe": "REPLACE_WITH_A_FRESH_TEST_LABEL",
"blender_version": bpy.app.version_string,
"background": bpy.app.background,
"scene_count": len(bpy.data.scenes),
"object_count": len(bpy.data.objects),
"saved_file": bool(bpy.data.filepath),
}
print(json.dumps(result))
Our Lab wrapper returned a JSON-serializable result. Other bridges may capture stdout instead; that is why the example also prints it. Follow the installed tool’s schema rather than insisting all forks have the same return convention.
The test does not create or delete objects. An empty file path on a newly opened file means “not yet saved,” not “all old projects disappeared.”
11.2 Report the right evidence
| Observation | Honest statement |
|---|---|
| Blender add-on says running | “The local add-on reports running.” |
| Port 9876 is listening | “The local socket has a listener; owner checked separately.” |
doctor passes | “Configuration/startup checks passed within that doctor’s scope.” |
/readyz returns 200 | “The tunnel runtime’s readiness policy passed.” |
| Tools are listed | “Discovery returned these tools.” |
| The fresh probe returns through ChatGPT | “This conversation executed this read-only code in Blender at this time.” |
| A native file is saved and reopened | “This saved artifact was verified from disk.” |
Do not collapse the rows into one “connected” claim.
11.3 The first writable proof
Once the user has authorized a new scratch project, create a small object in that isolated scene, save .blend, export GLB, render a PNG, and inspect all three. That tests a much more useful path than a text-only health response.
Keep existing user work intact. Section 16 provides an isolated background exercise; it does not require clearing the interactive scene.
12. Troubleshooting without making it worse
12.1 The decision table
| Symptom | First interpretation to check | Useful next action | Avoid |
|---|---|---|---|
| Command not found | Wrong PATH or executable location | Locate the real executable; use its absolute path | Reinstalling everything immediately |
| Missing runtime key | Service/shell did not load the local secret | Fix the established credential loader locally | Pasting the key into chat |
| Address already in use | Another process owns that exact port | Identify owner; select a deliberate free loopback health port or restart the confirmed relevant service | Killing a random listener |
| Blender listens on 9876, health port absent | Add-on and tunnel client have different states | Check the actual tunnel process/service | Repeatedly toggling Blender |
| Tools list, execution fails | Discovery and execution paths differ | Read error; inspect bridge target and Blender listener | Declaring success from the tool list |
| Error immediately after a long idle | Possible idle socket issue | One tiny probe; recover the known relevant add-on/bridge if it wedges | Repeated full build attempts |
| Timeout during render/export | Blender may still be busy | Inspect job/process and output receipts before retrying | Launching a duplicate job |
| Tunnel HTTP 429/404 before execution | Upstream routing, rate, association, or availability issue may be involved | Preserve exact response, observe supplied retry delay, inspect the client, make a bounded retry after recovery/cooldown | Calling it scene corruption or claiming an exact cause without evidence |
| Black render | Wrong camera, occluder, missing light/texture, or real dark room | Verify evaluated camera pose and first-hit geometry; inspect actual image | Immediately multiplying all light powers |
| Missing local screenshot path | File does not exist where the reader tried to open it | Re-render/recover and transfer the actual image into the reader’s environment | Calling it an MCP failure solely from the file error |
| Blender process crash | Application/build/scene-specific failure | Preserve crash log and minimal reproducer; recover from saved parent | Assuming transport tuning will fix the renderer |
| Access/approval refusal | An actual execution boundary | Report action/reason; use a genuinely narrower permitted alternative | Encoding or rerouting the same prohibited action |
12.2 Busy Blender versus a dead connection
This distinction saved a great deal of wasted work.
- Idle wedge: a tiny request fails after a pause; no known render/build is running. Stop retrying the heavy action. Recover the affected connection component and prove it with one small test.
- Busy operation: a render, remesh, large import, or export is in progress. Blender’s main thread may not answer another request. Check the durable job record and exact process. Wait for completion or a real failure.
- Crash: the process exited or there is an application crash record. Preserve evidence and open a saved checkpoint.
Neither “every timeout means dead” nor “every timeout means still working” is safe. We saw timed-out operations leave real rendered files, and other timed-out writes whose outcome was uncertain. Inspect the intended result; do not assume either outcome.
12.3 A small macOS diagnostic bundle
Run on the computer that should host the client and Blender:
pgrep -l tunnel-client
lsof -nP -iTCP:9876 -iTCP:8081 -sTCP:LISTEN
curl --noproxy '*' --max-time 5 -sS -i http://127.0.0.1:8081/readyz
Substitute your actual ports. Port ownership visibility can be limited by user permissions; no lsof output from another account is not proof that no other user’s listener exists.
Do not dump all environment variables, full secret-bearing configurations, or command arguments that might contain credentials. Prefer narrowly selected fields and reviewed/redacted logs.
12.4 The missing-image trap
An error like:
Could not read local image at /workspace/session/upload/frame.png:
No such file or directory
means a file read failed at that path. Possible causes include transient workspace cleanup, a stale attachment reference, a file created only on the Blender host, or a screenshot that was never transferred.
If a tool returns an actual image, inspect that returned image. If it returns only a remote path, transfer the bytes through an authorized route before using a local image viewer. Regenerate a missing disposable proof; recover an important saved artifact from durable storage. Never invent a successful visual review of an unread image.
An error recurring every few minutes can be a repeated attempt to read the same missing file. That timing alone does not prove an automation, a tunnel failure, or a Blender crash.
12.5 A naming crash we encountered
One recorded Blender build crashed during an integer/name-suffix parsing path (stoi/name-number splitting). Simplifying generated names and replacing period separators was part of the successful recovery in that case.
Transferable practice: use short semantic names, stable IDs in custom properties, and conservative separators such as underscores. Keep a minimal reproducer for a crash. Do not claim every period-containing name is invalid or that every Blender release shares the defect.
13. Organize a project for reliable execution
Suggested structure, using a fictional project:
studio-project/
START-HERE.md
brief.md
environment.json
contracts.json
state.json
NEXT.md
manifest.jsonl
reviewed-scenes.json
scripts/
sources/
scenes/
exports/
proofs/
experiments/
jobs/
packages/
assets/
asset-register.csv
textures/
licenses/
This is an example directory list, not a required tool installation layout.
Minimum durable state
{
"project": "fictional-study-room",
"status": "IN_PROGRESS",
"active_assignment": "Build and review one furnished study room",
"reviewed_parent": {
"path": "scenes/room-r003.blend",
"sha256": "REPLACE_WITH_MEASURED_HASH"
},
"pending_candidate": null,
"active_job": null,
"completed": [],
"ready_next": "Render the existing material candidate from the fixed review camera",
"blocked": [],
"last_verified_connection_utc": null,
"current_usage_reading": null
}
Use a consistent schema and update it after meaningful work. A state file should explain the next action to a fresh assistant without a transcript archaeology project.
Keep work status precise
Use statuses such as:
PLANNED: scoped but not built.BUILT: output exists.RENDERED_AWAITING_REVIEW: images exist, visual decision pending.REJECTED: evidence retained; do not promote.REVIEWED_WORKING_COPY: passed its stated scope.EXPORTED: an export was written.VERIFIED: specified disk/import checks passed.DELIVERED: destination bytes were confirmed.INTEGRATED: consumer references/configuration were changed and checked.RELEASED: the required final acceptance happened.
Do not let a filename such as final-final.blend substitute for status evidence.
14. The production loop
Before modeling
- Convert the brief into a complete output roster: filenames, units, dimensions, camera views, performance constraints, dependencies, and destination.
- Inspect actual references. If a required host/socket/reference is missing, mark affected work blocked rather than inventing a substitute.
- Identify protected geometry, existing objects, and the reviewed parent.
- Make the smallest saved proof that exercises the intended delivery path.
For each meaningful change
- State the defect or design goal.
- Save or confirm the parent checkpoint.
- Run one coherent modeling operation or isolated job.
- Save a new candidate.
- Check dimensions, identities, dependencies, and required technical invariants.
- Render or capture the relevant views.
- Open the actual image and describe the defect if one remains.
- Correct and repeat.
- Record the acceptance scope, artifact hashes, and next step.
For a substantial layout, do at least three review-and-correct rounds. Do not satisfy this by generating three nearly identical screenshots without decisions.
Keep calls efficient
- Return compact measurements and paths, not enormous scene dumps.
- Filter by explicit collections/roles/names before requesting object details.
- Separate a quick status call from a large render.
- Persist a long script first; do not repeatedly transmit and re-execute an unfinished giant program.
- Older fragile sessions benefited from writing scripts in small verified chunks. That was a transport workaround, not a universal 25-line artistic limit.
- Prefer direct data API operations when context-sensitive
bpy.opswould be brittle. When operators are needed, set the intended context explicitly.
What “keep working” should mean
An assistant should finish the already-authorized ready work, then proceed to the next ready item. It should not voluntarily stop after the first pass, impose an arbitrary two-item limit, or pause merely to ask for the same authorization again.
It should also not pretend a chat turn is a guaranteed unattended service. Real background work requires a real running job with saved state. Account usage, resets, and platform limits are not controllable by writing “run forever” into a prompt.
15. Run long jobs safely
The preferred division of labor
Use MCP for discovery, small edits, launching supported work, and inspecting results. Use isolated background Blender for expensive builds, controlled renders, audits, and batch exports when the available execution policy supports it.
Typical job command after checking the installed Blender’s help:
"$BLENDER_BIN" --background "$SOURCE_BLEND" --disable-autoexec \
--python-exit-code 2 --python "$JOB_SCRIPT" -- \
--config "$JOB_CONFIG"
--disable-autoexec is not a sandbox: the explicitly supplied job script still executes. Use files and scripts you intend to run. Command ordering matters; the script should apply and record settings after loading its intended source.
On macOS, set BLENDER_BIN to the verified app binary. On other systems use the actual installed executable. Do not infer a background binary path from the fact that the GUI is open.
A durable job should record
- Job ID and UTC start time.
- Machine role and exact process ID.
- Source file path and SHA-256.
- Script/config hashes.
- Command structure with secrets omitted.
- Expected outputs and log path.
- Exit code, completion timestamp, and artifact hashes.
- Technical checks and a separate visual-review status.
Write a final receipt only after outputs are closed. An atomic temporary-file replacement helps avoid truncated JSON, but does not make a collection of many files transactional.
Keep the scene and the job independent
Do not reset another person’s interactive scene to create a private worker. Do not run two writers against the same candidate file. Give each candidate a new filename and each render recipe a new output directory.
For an unresponsive job, check its exact process and receipt. A PID alone can be reused later, and an old image file may predate the current attempt. Do not “recover” by killing every Blender process.
Laptop sleep
Long jobs need an awake, powered host. On macOS, a time-bounded caffeinate invocation can help an intentionally supervised run, for example:
caffeinate -dimsu -t 14400
That is a four-hour example, not an always-on deployment. Lid/power/thermal behavior and OS policy still matter. Save work even when sleep prevention is active.
Deferred tools are implementation-specific
The Lab interactive surface used here supported a deferred-completion mechanism for some requests. Its background mode did not support the same mechanism. Do not assume every tool accepts a check_is_finished pattern, and do not assume a background saved-file call automatically saves changes.
Inspect the schema and explicitly save required changes. A tool returning success with no save_mainfile operation may leave the original disk file unchanged.
16. A complete first-project exercise
This exercise is deliberately modest: create a furnished test room, render it, save it, and export it. It demonstrates a reliable pipeline, not the final realism standard.
Ask the assistant to save the following as first_room.py on the intended Blender host. Run it only in a new background worker. It refuses interactive use and refuses a nonempty output folder.
import hashlib
import json
import os
from pathlib import Path
import bpy
from mathutils import Vector
if not bpy.app.background:
raise RuntimeError("This exercise requires a private background Blender process.")
out = Path(os.environ["BLENDER_MCP_DEMO_DIR"]).expanduser().resolve()
out.mkdir(parents=True, exist_ok=True)
if any(out.iterdir()):
raise RuntimeError("Choose a new empty output directory; existing files are kept.")
bpy.ops.wm.read_factory_settings(use_empty=True)
scene = bpy.context.scene
scene.unit_settings.system = "METRIC"
scene.unit_settings.scale_length = 1.0
scene.render.engine = "CYCLES"
scene.cycles.device = "CPU"
scene.cycles.samples = 32
scene.render.resolution_x = 960
scene.render.resolution_y = 720
scene.render.resolution_percentage = 100
scene.render.image_settings.file_format = "PNG"
scene.view_settings.view_transform = "AgX"
def material(name, color, roughness):
mat = bpy.data.materials.new(name)
mat.use_nodes = True
shader = mat.node_tree.nodes.get("Principled BSDF")
shader.inputs["Base Color"].default_value = (*color, 1.0)
shader.inputs["Roughness"].default_value = roughness
return mat
plaster = material("Wall_Plaster", (0.72, 0.69, 0.62), 0.8)
wood = material("Floor_Wood_Proxy", (0.22, 0.105, 0.045), 0.42)
fabric = material("Sofa_Fabric_Proxy", (0.12, 0.19, 0.18), 0.85)
dark = material("Furniture_Dark", (0.025, 0.028, 0.025), 0.4)
def box(name, center, size, mat, bevel=0.0):
bpy.ops.mesh.primitive_cube_add(size=1, location=center)
obj = bpy.context.object
obj.name = name
obj.dimensions = size
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
obj.data.materials.append(mat)
obj["role"] = "furniture" if "Sofa" in name or "Table" in name else "architecture"
if bevel:
mod = obj.modifiers.new("Edge_Bevel", "BEVEL")
mod.width = bevel
mod.segments = 3
return obj
# Coordinates are metres; the room is 5 by 4 metres with a 3-metre ceiling.
box("F00_Study_Floor", (0, 0, -0.06), (5.3, 4.3, 0.12), wood)
box("F00_Study_LeftWall", (-2.575, 0, 1.5), (0.15, 4.3, 3), plaster)
box("F00_Study_RightWall", (2.575, 0, 1.5), (0.15, 4.3, 3), plaster)
box("F00_Study_Ceiling", (0, 0, 3.075), (5.3, 4.3, 0.15), plaster)
# Back wall has a real opening, not a glass object embedded in a solid wall.
box("F00_Study_BackLeft", (-1.85, 2.075, 1.5), (1.3, 0.15, 3), plaster)
box("F00_Study_BackRight", (1.85, 2.075, 1.5), (1.3, 0.15, 3), plaster)
box("F00_Study_WindowSillWall", (0, 2.075, 0.45), (2.4, 0.15, 0.9), plaster)
box("F00_Study_WindowHeader", (0, 2.075, 2.75), (2.4, 0.15, 0.5), plaster)
# Front wall leaves an unobstructed entrance.
box("F00_Study_FrontLeft", (-1.525, -2.075, 1.5), (1.95, 0.15, 3), plaster)
box("F00_Study_FrontRight", (1.525, -2.075, 1.5), (1.95, 0.15, 3), plaster)
box("F00_Study_DoorHeader", (0, -2.075, 2.55), (1.1, 0.15, 0.9), plaster)
# Obvious furniture-scale proxies, intentionally ready for a second modeling pass.
box("F00_Study_SofaSeat", (-1.72, 0.25, 0.48), (0.95, 1.95, 0.24), fabric, 0.045)
box("F00_Study_SofaBack", (-2.15, 0.25, 0.85), (0.18, 1.95, 0.68), fabric, 0.04)
for y in (-0.62, 1.12):
box("F00_Study_SofaArm", (-1.72, y, 0.68), (0.95, 0.2, 0.5), fabric, 0.04)
for x in (-2.05, -1.4):
for y in (-0.45, 0.95):
box("F00_Study_SofaFoot", (x, y, 0.18), (0.07, 0.07, 0.36), dark, 0.005)
box("F00_Study_TableTop", (-0.2, 0.25, 0.48), (0.8, 1.1, 0.06), wood, 0.015)
for x in (-0.5, 0.1):
for y in (-0.18, 0.68):
box("F00_Study_TableLeg", (x, y, 0.225), (0.05, 0.05, 0.45), dark, 0.004)
world = bpy.data.worlds.new("World_Test")
world.use_nodes = True
world.node_tree.nodes["Background"].inputs["Color"].default_value = (0.7, 0.8, 1.0, 1.0)
world.node_tree.nodes["Background"].inputs["Strength"].default_value = 0.25
scene.world = world
def aim(obj, target):
obj.rotation_euler = (Vector(target) - obj.location).to_track_quat("-Z", "Y").to_euler()
light_data = bpy.data.lights.new("Window_SoftLight", "AREA")
light_data.energy = 600
light_data.shape = "RECTANGLE"
light_data.size = 2.2
light_data.size_y = 1.5
light = bpy.data.objects.new("Window_SoftLight", light_data)
scene.collection.objects.link(light)
light.location = (0, 3.1, 2.1)
aim(light, (0, 0, 1.0))
camera_data = bpy.data.cameras.new("F00_Study_EntranceCamera")
camera = bpy.data.objects.new("F00_Study_EntranceCamera", camera_data)
scene.collection.objects.link(camera)
camera.location = (0.25, -1.8, 1.55)
camera_data.lens = 22
camera_data.clip_start = 0.02
aim(camera, (-0.4, 0.65, 1.3))
scene.camera = camera
bpy.context.view_layer.update()
scene.render.filepath = str(out / "entrance.png")
bpy.ops.wm.save_as_mainfile(filepath=str(out / "study-room-r001.blend"))
bpy.ops.render.render(write_still=True)
bpy.ops.export_scene.gltf(filepath=str(out / "study-room-r001.glb"),
export_format="GLB", export_cameras=False,
export_lights=False, export_animations=False)
artifacts = []
for name in ("study-room-r001.blend", "study-room-r001.glb", "entrance.png"):
path = out / name
if not path.is_file() or path.stat().st_size == 0:
raise RuntimeError("Required output missing or empty: " + name)
artifacts.append({"file": name, "bytes": path.stat().st_size,
"sha256": hashlib.sha256(path.read_bytes()).hexdigest()})
(out / "receipt.json").write_text(json.dumps({
"status": "BUILT_AND_RENDERED_AWAITING_VISUAL_REVIEW",
"blender_version": bpy.app.version_string,
"unit_scale_metres_per_bu": scene.unit_settings.scale_length,
"artifacts": artifacts,
}, indent=2), encoding="utf-8")
print("Saved exercise outputs to", out)
Example Bash invocation after saving the script at the indicated local path:
BLENDER_BIN="/Applications/Blender.app/Contents/MacOS/Blender"
BLENDER_MCP_DEMO_DIR="$HOME/BlenderProjects/mcp-first-room" \
"$BLENDER_BIN" --background --factory-startup --disable-autoexec \
--python-exit-code 2 --python "$HOME/BlenderProjects/first_room.py"
Use the correct binary on your OS. This script targets the contemporary Lab-era Blender API and has been syntax-checked for this guide; it was not rendered on every recipient platform during preparation.
Review it in three rounds
- Round 1 — spatial: inspect the entrance view, a top view, and an opposite corner. Check wall openings, furniture scale, floor contact, camera pose, and missing geometry. Save corrections as a new revision.
- Round 2 — form/material: improve the proxy sofa geometry, choose plausible fabric and wood scale, add window/frame detail, and compare the same cameras. Save and reopen.
- Round 3 — presentation: fix lighting and composition, inspect a close view and wide view, then reopen/export the selected revision and view the GLB in its consumer.
The receipt intentionally says “awaiting visual review.” Its existence is not a claim the image was seen or the room is photorealistic.
17. Units, naming, and scene contracts
17.1 Choose one coordinate convention
Two conventions worked in different projects:
| Convention | scale_length | One coordinate unit represents |
|---|---|---|
| Metre geometry | 1.0 | One metre |
| Foot geometry | 0.3048 | One foot |
Setting a units label is not the same as rescaling existing mesh coordinates. Importers, exporters, modifiers, lights, and scripts need to agree on the convention.
For a scene whose scale is established:
import bpy
metres_per_bu = bpy.context.scene.unit_settings.scale_length
if metres_per_bu <= 0:
raise RuntimeError("Invalid scene unit scale")
def metres_to_bu(value):
return value / metres_per_bu
def bu_to_metres(value):
return value * metres_per_bu
def square_bu_to_square_feet(area):
return area * metres_per_bu ** 2 / 0.3048 ** 2
Measure an imported known-size object and an exported/reimported known-size object. Do not accept a visually similar miniature as a successful unit conversion.
17.2 Name semantically
Examples:
F00_Living_Wall_North
F00_Living_Window_W01
F00_Living_Sofa_Seat_01
F01_BedroomA_RoomVolume
F01_BedroomA_Pillow_Piping_01
SITE_Terrain_Main
CAM_F00_Entry_To_Rear
Use custom properties such as room_id, floor_id, role, assembly_id, and source_asset_id. A name is useful for discovery but is not a reliable substitute for explicit roles.
One bad census treated walls containing “Bedroom” and suspended curtains as unsupported furniture. Classification needs more than substring matching and low bounding-box heights.
17.3 Protect what must not change
Before a material or furniture pass, retain:
- Source scene hash and expected parent identity.
- Unit scale and origin convention.
- Room identity and required dimensions.
- Protected walls, floors, roofs, openings, and site geometry.
- Required cameras or explicit camera recipes.
- Existing material graphs/images/bindings when not part of the experiment.
- Lighting, display transform, exposure, and relevant render visibility.
Check both raw geometry and evaluated geometry where modifiers or transforms matter. A static frame-1 audit does not protect an entire animated route.
18. Whole-house modeling
18.1 Build the spatial program first
Start with exterior massing, floor plates, roof forms, and named room volumes. Add openings and furniture-scale blocks after the layout makes sense. Then develop realistic detail.
Choose floor count and total area based on the brief. Explain the tradeoff in plain language. A larger house is not automatically a more efficient design.
Translate requirements into measurable checks:
- Room dimensions and usable areas.
- Bedroom floor grouping and attached-bath adjacency.
- Office separation and actual exterior windows.
- Kitchen work-zone clearance and structural-placeholder exclusions.
- Hall sizes, total circulation, and the denominator used.
- Clear sightlines and usable path widths.
- Window/roof/skylight placement.
- Floor-to-ceiling heights and model unit scale.
18.2 Room schedules must reconcile
Specify whether totals are net room area, gross conditioned area, garage area, covered exterior area, or an all-inclusive footprint. Do not double-count overlapping room volumes. Keep walls, shafts, stairs, and voids explicit.
Our reviews exposed a circulation result that passed against a gross denominator and failed against net area. Report both where relevant; do not quietly choose the larger denominator to improve a percentage.
A useful schedule row is:
{
"room_id": "F00_STUDY",
"floor": "F00",
"name": "Study",
"dimensions_basis": "clear interior",
"length_ft": 12,
"width_ft": 10,
"area_sq_ft": 120,
"area_method": "rectangle",
"circulation_category": "room",
"review_status": "PENDING"
}
For irregular rooms, measure the actual boundary rather than multiplying bounding-box dimensions.
18.3 Inspect the right views
For each major stage, review a top view per floor, four exterior corners, and key interior sightlines. A tall foyer or impressive roof can look good from one angle while concealing a missing wall on the opposite side.
For a front-to-back sightline, check the actual path corridor and objects that can obstruct it. A clear mathematical centerline is weaker than a usable corridor of declared width. Door leaves, furniture, glazing bars, and level changes may matter.
Place skylight glazing in the actual roof plane with plausible visual framing. Floating a rectangle above the roof is not a completed roof opening.
18.4 Construction-looking detail without engineering claims
Model visible thickness, reveals, trim, sill depth, roof edges, flashings as appropriate to the visualization, baseboards, and openings. Keep any dimension estimates labeled.
If working from drawings, distinguish authoritative dimensions from inferred photo-based appearance. If the drawings are incomplete, keep the unknowns visible in the report.
Do not infer structural adequacy, code compliance, cost, weather-tightness, or buildability from a convincing image.
19. The realism improvement order
Work in this order unless a particular defect is more urgent:
- Correct scale, proportions, layout, and missing/penetrating geometry.
- Correct the major silhouettes and assembly relationships.
- Establish believable support/contact and useful light paths.
- Set a coherent camera and display/exposure baseline.
- Give the major surfaces plausible finish and texture scale.
- Develop furniture form, upholstery, joinery, glazing, trim, and hardware.
- Add coherent outdoor depth and context.
- Add small lived-in details with restraint.
- Increase samples/resolution to resolve a specific remaining question.
- Review motion and browser delivery separately.
More polygons and more samples did not fix our oversized sofa seats, periodic cushion ridges, floating supports, or blocked cameras. Texture quality did not make flat pillow slabs look full.
Suggested release rubric
This is a proposed review framework, not a scientific realism probability:
| Dimension | Weight | What to inspect |
|---|---|---|
| Form/construction appearance | 25% | Scale, silhouette, thickness, believable joins, complete surfaces |
| Materials | 25% | Mapping, finish, color, roughness, repetition, geometry interaction |
| Light | 20% | Readable rooms, plausible sources, glare, window behavior, shadow quality |
| Contact | 10% | Feet, bedding, trims, fixtures, props, support hierarchy |
| Environment | 10% | Near-ground depth, context, parallax, vegetation and horizon coherence |
| Camera/composition/temporal | 10% | Framing, distortion, clearance, transitions, motion stability |
Score 0 broken, 1 placeholder, 2 developed CG with obvious giveaways, 3 credible for the target view, 4 convincing under demanding comparison. One proposed gate is every applicable category at least 3, weighted mean at least 3.5, and zero critical defects. Keep unreviewed categories null. The user makes final acceptance decisions.
20. Materials and texture lessons
20.1 Material realism is not a download count
For each important finish, inspect a wide view and close view. A map can look impressive on a shader ball and be wrong across a whole room.
Record texture provenance, intended physical scale, mapping source, image color spaces, material graph, and material-level render settings that affect appearance. Color textures and data maps serve different roles; inspect the asset’s own documentation and the installed Blender shader interface.
Do not blindly overwrite a material because uv_layers is empty. We imported vegetation whose shader read a named CORNER/FLOAT_VECTOR attribute called UVMap; its usable mapping was not in the conventional UV-layer list. Inspect shader Attribute nodes and named geometry attributes before regenerating mapping.
20.2 Specific lessons from actual reviews
- Plaster: broad color blotches looked dirty. Narrower color variation with subtle relief worked better. Review the entire wall.
- Wood floors: veneer images alone did not define the finish. Board identity, believable scale, edge detail, roughness, and reflection behavior mattered together.
- Fabric: full cushions, seams, and support were needed before textures could help. Avoid repeated procedural ridges that read as manufactured stripes.
- Glass: a dark interior behind a pane can come from a real exterior obstruction. Diagnose the whole light path before declaring the glass shader broken.
- Metal/enamel/ceramic: test curved and planar surfaces. One flat crop is insufficient for judging the material family.
- Repetition: variation should be purposeful. Repeated identical logs or regularly gridded media can remain visibly artificial even after contact is correct.
- Dirt/wear: small variation should reinforce use and construction; noise everywhere is not realism.
20.3 Preserve shader meaning
A shader digest should identify socket indices/identifiers, not only display names, because repeated names can lose information. Include images and their color spaces, world state, material bindings, and display settings.
Node-tree equality alone is incomplete. Material-level Cycles settings can change volume appearance while the node graph remains identical. A clean digest means only that the properties in that digest matched.
20.4 Portable textures
Deduplicate by exact file hashes, not names. Keep paths and licenses in an asset register. Reopen the portable copy on its intended path and test missing dependencies.
One tested save correction assigned destination-relative paths and saved with relative_remap=False, followed by reopening each scene. Do not apply that flag blindly to every project: verify the intended relative-path behavior for the actual source and destination.
Packed images may be available even when an old external path no longer exists. Conversely, packed textures do not imply that VDB caches, image sequences, linked libraries, fonts, sounds, or movies are all embedded. Audit each dependency class.
21. Furniture, assemblies, and contact
21.1 Treat assemblies as assemblies
A sofa can include frame, feet, seat, cushions, piping, and pillows. A pillow body and its separate welt curve must move and deform coherently.
We once corrected pillow bodies while leaving the piping behind. A later geometric midpoint-based seam adjustment passed contact measurements but produced a visible kink. Geometry checks and sewing plausibility were different requirements.
Keep explicit assembly IDs and enumerate constituent objects before a correction. Preserve the intended upper silhouette when correcting a lower bearing surface.
21.2 Support is a declared relationship
For each object, identify what it actually rests on:
- Chair foot → finished plank, not a lower substrate in a joint.
- Stove → hearth, not the room floor under it.
- Bowl → tray, then tray → floor.
- Upper log → a lower log or container base.
- Pillow → mattress/duvet, with the actual upper-floor elevation.
- Ceiling fixture → ceiling or mounting plate.
Names and bounding boxes help find candidates; they do not prove a support failure.
21.3 Sample contact carefully
Use evaluated world-space geometry. Record sample coordinates, upper/support object identities, query counts, missing-ray categories, and gaps in physical units.
For a hard foot, start with a small central flat sole patch. Wider rectangular samples can fall outside rounded corners or hit bevels. Preserve that distinction instead of reshaping a plausible rounded foot to satisfy the wrong sampling pattern.
Separate:
- No upper geometry at the sample.
- No sampled support geometry.
- A true positive gap.
- Intentional joint/recess depth.
- A rounded/beveled edge.
- Penetration.
A missing query is not automatically a missing floor. We obtained false failures from a support search that did not extend down to the actual substrate.
21.4 Correct without destroying the design
Bound a hard-foot adjustment and preserve its upper join and XY footprint where appropriate. A soft rug may need a different treatment; moving an entire table to satisfy a rug intersection is not a universal solution.
For stacked props, derive expected movement from the original support chain independently, not only from the builder’s claimed translation.
Reopen the candidate and inspect a close view, context view, and if needed an underside/grazing diagnostic. A static diagnostic camera below furniture is not proof that a human-height tour camera can travel there.
21.5 Use a negative control
Deliberately raise a copied test foot in an isolated worker. The checker should report the gap. If it still passes, the checker is not measuring what you think.
Never save deliberate fault injection into the reviewed scene. Passing contact tests does not establish structural load capacity or finish the object’s material realism.
22. Lighting and camera lessons
22.1 Diagnose geometry before adding light
We found an office whose room-to-window rays were clear, but the continued rays hit an exterior garage/roof obstruction. Removing glazing and changing transport settings did not solve the underlying darkness.
Test the complete path toward the environment, record exceptions for glass, and inspect actual openings. A clear segment ending just beyond a pane does not establish daylight access, and straight rays do not measure irradiance or full refracted transport.
22.2 Bracket practical lights
Use a few fixed-camera intensity variants at the same exposure. Select the lowest useful setting and compare neighboring control rooms. Inspect the fixture’s actual attachment and its appearance, not just the average brightness of the image.
Our experiments found that making a room readable could expose appliance/support gaps previously hidden in darkness. Close the lighting defect and record the newly visible geometry defect separately.
An emitting mesh changes lighting even if the list of light objects and the world digest do not change. Clone shared materials before modifying emission, and protect original bindings.
22.3 Units and light calibration
Do not label artistic emission strength as watts, lumens, or lux. Geometry units alone do not establish a calibrated lighting setup.
An isolated native area-light fixture compared metre coordinates and foot-scaled coordinates at equal physical dimensions. It measured a scale-squared response difference, while a constant-world test was invariant. Compensation restored that fixture’s reference response. This was a relative test, not a general electrical/photometric calibration.
The lesson is to run a tiny linear-EXR calibration experiment when physically interpreting light values. Do not multiply a visually balanced scene’s lights by a guessed conversion factor.
22.4 Cameras need three different checks
- Origin clearance: is the camera inside or too close to geometry?
- Target/sightline coverage: does it see the intended body or room?
- Composition: does the actual image communicate the space well?
A camera can pass the first test and face a blank shower wall. A bed target mask including the headboard can pass while the camera sees only its back. Declare the intended body, such as front bedding, rather than the whole assembly.
Update the view layer after setting camera transforms and inspect its evaluated pose. We encountered stale matrices that produced plausible-looking but wrong ray tests.
22.5 Practical camera recipes
Some successful room studies used approximately 22–24 mm lenses and camera heights around 1.45–1.52 m. These are project choices, not universal values or a reason to distort every room with a wide lens.
Keep verticals deliberate. Use shift/composition adjustments where appropriate, test projected geometry, and inspect actual views. A narrowly framed single bed does not prove a two-bed room’s full coverage.
Model role and actual first-hit geometry matter more than naming conventions: a screen that recognized one door suffix missed doors carrying another suffix.
22.6 Render engines and hardware
Use a fast preview to inspect layout and a declared production engine for appearance decisions. Switching between Eevee and Cycles can change illumination and reflections; a preview-engine pass is not universal material acceptance.
On Apple hardware, explicitly detect/select an available Metal device if using it. On other hardware, use the installed Blender’s supported backend. Record the backend actually applied, and make a CPU fallback explicit rather than silently relabeling a failed GPU render.
Keep hardware-specific settings scoped. A shadow-memory adjustment that helped one Eevee scene is not a universal recommended pool size.
23. Controlled experiments and regression tests
23.1 Keep the comparison controlled
Hold camera, resolution, samples, seed, engine, lights, exposure, world, and display transform fixed unless one is the stated variable.
Our early comparisons sometimes changed resolution and samples between revisions. They were useful qualitative evidence, not clean A/B measurements. Better evidence came from fixed recipes and fresh output directories.
23.2 Experiment template
{
"experiment_id": "E001",
"hypothesis": "Reducing periodic cushion ridges improves the sofa close view",
"parent_scene": "scenes/room-r003.blend",
"parent_sha256": "MEASURE_ACTUAL_PARENT",
"candidate_scene": "scenes/room-r004-candidate.blend",
"change_scope": ["sofa seat geometry"],
"protected": ["room layout", "camera", "lighting", "materials"],
"proof_views": ["living-wide", "sofa-close", "sofa-grazing"],
"technical_tests": ["unit scale unchanged", "protected geometry unchanged"],
"visual_acceptance": "Ridges removed without flattening the cushion silhouette",
"technical_verdict": null,
"visual_verdict": null,
"promotion_status": "PENDING"
}
23.3 What an image receipt should include
- Source scene, renderer script, and recipe hashes.
- Exact frame/timebase if animated.
- Named or explicit camera pose, evaluated pose, lens, sensor, clipping, and shift.
- Requested and actually applied engine, device, resolution, samples, seed, exposure, and display settings.
- Image filename, dimensions, size, and hash.
- Technical status and separate visual-review status.
Record applied settings, not merely requested settings. We caught a wrapper using an older renderer that ignored a new exposure field; all input hashes were valid, but the intended override was never applied.
23.4 Negative tests make verification useful
Use tiny isolated fixtures to inject faults such as:
- Wrong source hash or wrong reviewed parent.
- Missing image/volume file.
- Modified protected wall.
- Hidden light or excluded collection.
- Camera inside a wall or aimed away from the target.
- Raised support foot.
- Wrong VDB offset or native FPS.
- Requested exposure override not applied.
Verify the fault actually exists. An early camera fault test moved an animated camera before evaluating the frame; animation reset the move, so it had not tested the intended failure.
A valid PNG is not necessarily a good image. Decode/integrity checks, nearly-black-image screening, visual composition review, realism review, and release acceptance answer different questions.
23.5 Evidence reuse and scene lineage
Reuse a baseline only when source, renderer, recipe, view set, and image hashes match. Do not relabel an old image as a new proof.
After editing a Python helper, run a fresh process or explicitly reload the module. A cached import once left an older lineage rule active even though the file on disk had changed.
Keep one canonical reviewed-scene index. Derive duplicated current_scene/next_action fields from it, and assert the expected parent before a new build. Hash consistency alone does not say the chosen parent was visually accepted.
24. Walkthroughs and motion
24.1 Make a room-coverage plan
Write a route table with room IDs, entry/exit anchors, door state, floor elevation, camera height, target, transition, and required detail holds.
A full-house tour should cover the requested spaces. Do not silently replace it with a short highlights reel. Duration follows coverage and pacing unless the user supplies a duration cap.
24.2 Smooth motion comes from the route
- Plan continuous positional and rotational motion with eased transitions.
- Keep walking speed and turn speed coherent.
- Set required doors open in the intended scene revision.
- Check camera and near-plane clearance through doorways, stairs, and narrow passages.
- Check the forward view, not just the camera center.
- Avoid long blank-wall passages and sudden light/exposure jumps.
- Evaluate the actual frame timebase:
fps / fps_base.
One early film used low rendered cadence plus synthesized frames and had reported turn glitches. A later native-30-fps approach improved the capture basis. Frame interpolation did not repair a poorly designed camera path.
Do not impose 30 fps on every scene without checking it: a later fire/room scene in the same program was saved at 24 fps. The source and intended delivery must agree.
24.3 Render a short native-frame test first
Test the hardest doorway, tight turn, glass passage, stair, dark-to-light transition, moving flame, and foliage. Inspect consecutive native frames and, where possible, actual playback at the intended cadence.
A sparse selection of pretty frames cannot establish smooth motion. A file decoding successfully cannot establish smooth camera motion either.
24.4 Save frames before encoding
Render numbered frames with resumable receipts. Missing frames, wrong frames, and changed settings should be detected before encoding. Preserve the image sequence as a recovery point when feasible.
An illustrative encoding command is:
ffmpeg -framerate 30 -i 'frame_%06d.png' -c:v libx264 -crf 18 -pix_fmt yuv420p tour.mp4
This is not a universal mastering recipe: substitute the actual frame rate and declare color management. Compare decoded video frames against the source frames before attributing brightness/flicker to the renderer.
24.5 Keep revisions honest
Label the source scene and review status of every movie. An earlier stylized tour remains an earlier stylized tour even when new realism stills look much better.
Browser chapters, route coverage, technical decode, motion appearance, and user acceptance belong in separate fields.
25. Volumes, fire, and advanced experiments
This is the frontier section: concrete lessons from scoped experiments, not a plug-and-play promise of physically correct combustion.
25.1 VDB file mapping
In a tested 200-file sequence numbered 0000–0199, default offset behavior skipped the intended first file and later requested a nonexistent file. An offset of -1 worked for that specific start-frame-1, duration-200, repeat setup.
Do not copy -1 universally. Verify the evaluated loaded filename and file hash at the first, last, next/wrapped, and representative interior frames. Record source numbering, start frame, duration, offset, mode, and actual playback FPS.
25.2 Fit the visible field, not only the domain box
A volume’s density domain can be much larger than its visible flame field. Measure the relevant grids across the sequence, retain source transforms, and distinguish object-space from world-space values.
We found a gas-flame field entirely inside its cavity that still appeared to float over the media. Sequence-wide bounds did not establish the visible emission’s contact at a particular frame. Matched renders revealed the gap and a color fringe.
If no temperature grid exists, do not describe an artistic color ramp as measured blackbody temperature.
25.3 Judge appearance and spill together
An auxiliary point light placed inside a stove produced a bright disc through the glass. Actual paired renders caught it; removing that light improved the tested view while the volume/embers provided emission.
Low-resolution uniformly glowing coals exposed polygon faces in a close-up. Correct stacking/contact did not make their glow believable. A regular grid of stones remained artificial even with valid support; constrained variation helped the arrangement.
25.4 Material settings can matter outside the node tree
In a tested 5.2-era Cycles scene, interpolation and step-rate controls relevant to the volume were on the material’s Cycles settings, not only on volume.render. Cubic interpolation plus a smaller step rate softened voxel stair steps in the tested close view. It did not create source detail that was absent.
Inspect the actual installed API and record these settings explicitly.
25.5 A renderer crash workaround with narrow scope
A tiny fixture reproduced a Cycles crash in a legacy RGB mix operation feeding a volume material, including on CPU. This did not support calling it Metal-only.
For the specific unclamped RGB MIX contract tested, replacing the operation with explicit cool * (1 - factor) + warm * factor rendered successfully on CPU and Metal and in the full room. Preserve the failing fixture and check the exact factor/alpha/blend contract before adapting it. This is not a blanket workaround for arbitrary mix modes, materials, or Blender versions.
25.6 Motion acceptance remains separate
Source simulation timestamps and preview FPS can differ. A small last-to-first grid difference is useful evidence, not proof of a seamless-looking loop. Inspect consecutive frames, including the wrap, and record which actual volume file each render loaded.
26. External assets and Geometry Nodes
26.1 Reuse good work where it helps
Evaluate whether an existing licensed asset will get you farther than building from primitives. Useful public starting points include Poly Haven, Kenney, and Sketchfab, subject to each asset’s actual license and download terms.
Do not confuse “available to view” with “permitted to redistribute.” Record creator, source URL, license, attribution, downloaded file hash, unit scale, modifications, and dependency paths. A source-site-wide reputation is not an asset-specific license receipt.
26.2 Asset intake sequence
- Confirm license and intended use.
- Save the original source bytes and provenance.
- Import into an isolated intake scene.
- Measure individual object bounds and units; a catalog collection’s bounds may describe an entire group.
- Inspect UV layers and named attributes/material mapping.
- Inspect geometry, texture resolution, materials, dependencies, and likely target-view cost.
- Normalize only what the consumer actually needs.
- Place in a candidate scene, render, reopen, and export/reimport if relevant.
An asset library does not automatically provide scale, coherent art direction, correct placement, or believable contact.
26.3 Geometry Nodes
Use node systems when a repeated family or distribution genuinely benefits: floorboards, trim families, scatter, foliage variation, facade components, or controlled layout variants.
Keep the input contract explicit, seed deterministic, and realized/evaluated export behavior checked. Save a small representative fixture before scaling to thousands of instances.
General Blender Python access can build Geometry Nodes graphs, but this guide does not claim a complete audited node library is bundled or that every sophisticated node workflow was proven in the source projects. Apply the same visual and export tests as with ordinary objects.
27. Exports, game assets, and browser delivery
27.1 Keep deliverable types separate
| Deliverable | Priorities |
|---|---|
Editable .blend master | Full materials, dependencies, cameras, lighting, source organization, future changes |
| Offline still/film | Actual render appearance, declared scene revision, image quality and motion |
| Browser GLB | Supported materials, texture/geometry budgets, predictable scale, viewer behavior |
| Game asset | Consumer-specific topology, sockets, pivots, LODs, normals, textures/material contract |
Do not impose game-lane “no materials, flat shading, tiny triangle budget” rules on an architectural realism master. Those were specific export contracts for particular consumers.
27.2 Useful game-lane lessons
Our specialized game exports sometimes used POSITION+NORMAL, no UV/tangents/materials/cameras/lights/animation, and flat normals, because the consumer supplied the intended look. These are not universal glTF defaults.
Triangle limits are ceilings, not artistic targets. Spend geometry on silhouette, readable shape, joins, and expected camera distance. Conversely, an absurdly small asset that reads as a few boxes can be a quality failure despite being below budget.
A low-detail tier should provide a meaningful reduction or a declared consumer-supported alias. Delivering identical “hi” and “lo” files does not establish a useful LOD strategy.
Quantized attributes can reduce bytes, but only use extensions the target loader actually supports. Do not assume compression/quantization preserves every consumer’s behavior. Audit exported bytes, reimport, and inspect the real target.
27.3 Socket and placement contracts
Before building a host-dependent asset, verify required socket names and transforms in the actual reference file. Keep protected host digests. A socket-only repair should not silently remesh or re-shade the host.
Ship placement/assembly data if needed: transforms, parent/instance identity, pivot, forward/up axes, units, socket usage, collisions, animation expectations, materials, and example application code.
Hundreds of correct GLBs can still fail intake if nobody knows where or how to place them. “Delivered assets” and “working level” are different outcomes.
27.4 Browser appearance is a new test
Native Blender shaders can use nodes and effects a glTF viewer does not reproduce. Bake or simplify deliberately where needed. Preserve the native master.
Test actual geometry, scale, textures, transparency, metallic/roughness behavior, environment/exposure, supported extensions, and default camera behavior in the intended viewer. Then test a representative phone if mobile is part of the brief.
Opening a GLB without an exception is not a material-fidelity pass. A nice Cycles PNG is not evidence that the browser GLB looks the same.
27.5 A small independent GLB container audit
Save this as inspect_glb.py and run it with a file path. It uses only standard Python and reads the exported file. It checks the container and summarizes metadata; it does not decode every vertex, certify bounds, count rendered instances, or validate visual quality.
import hashlib
import json
import struct
import sys
from pathlib import Path
path = Path(sys.argv[1])
raw = path.read_bytes()
if len(raw) < 12:
raise SystemExit("Too short for a GLB header")
magic, version, declared_length = struct.unpack_from("<4sII", raw, 0)
if magic != b"glTF" or version != 2 or declared_length != len(raw):
raise SystemExit("Invalid GLB header/version/length")
offset = 12
chunks = []
doc = None
while offset < len(raw):
if offset + 8 > len(raw):
raise SystemExit("Truncated chunk header")
length, kind = struct.unpack_from("<II", raw, offset)
offset += 8
if length % 4 or offset + length > len(raw):
raise SystemExit("Misaligned or truncated chunk")
payload = raw[offset:offset + length]
chunks.append({"type": kind, "bytes": length})
if kind == 0x4E4F534A:
if doc is not None or len(chunks) != 1:
raise SystemExit("Unexpected JSON chunk placement/count")
doc = json.loads(payload.decode("utf-8").rstrip(" \x00"))
offset += length
if doc is None:
raise SystemExit("Missing JSON chunk")
accessors = doc.get("accessors", [])
triangles = 0
nontriangle_primitives = 0
for mesh in doc.get("meshes", []):
for primitive in mesh.get("primitives", []):
if primitive.get("mode", 4) != 4:
nontriangle_primitives += 1
continue
accessor_id = primitive.get("indices")
if accessor_id is None:
accessor_id = primitive.get("attributes", {}).get("POSITION")
if not isinstance(accessor_id, int) or not 0 <= accessor_id < len(accessors):
raise SystemExit("Missing/invalid primitive accessor")
count = accessors[accessor_id]["count"]
if count % 3:
raise SystemExit("Triangle-list count is not divisible by 3")
triangles += count // 3
external = []
for category in ("buffers", "images"):
for item in doc.get(category, []):
uri = item.get("uri")
if uri and not uri.startswith("data:"):
external.append({"category": category, "uri": uri})
print(json.dumps({
"file": path.name,
"bytes": len(raw),
"sha256": hashlib.sha256(raw).hexdigest(),
"chunks": chunks,
"nodes": len(doc.get("nodes", [])),
"meshes": len(doc.get("meshes", [])),
"triangle_list_resource_triangles": triangles,
"other_primitive_modes_not_counted": nontriangle_primitives,
"materials": len(doc.get("materials", [])),
"images": len(doc.get("images", [])),
"extensions_used": doc.get("extensionsUsed", []),
"external_dependencies": external,
"scope": "container and metadata only; reimport and view separately",
}, indent=2))
For instancing, strips/fans, compressed data, skinning, actual world bounds, or flat-normal invariants, add a real decoded geometry audit or consumer-side test. A resource triangle count is not an instance-expanded scene count.
28. Portable projects and dependable handoffs
28.1 A minimal useful delivery package
Include:
START-HERE.md: what this is and how to open it.- Editable scene(s) with exact revision/status.
- Needed dependencies and asset/license register.
- Export(s) for the intended consumer.
- Actual reviewed proof images and, where applicable, film/chapters.
- Scripts/recipes needed to reproduce the work.
- Manifest with filenames, byte sizes, SHA-256, units, and appropriate counts.
- Known flaws, unverified checks, integration instructions, and exact next action.
Use relative paths inside a portable bundle. Keep machine-specific connection records and credentials out of it.
28.2 Delivery is a separate verification
Check that the destination has the actual bytes and matching hashes. A file in the Blender host’s Downloads folder is not automatically a file in the chat sandbox, staging machine, Git repository, or website build.
Do not say “uploaded” because a local export exists. Do not say “live” because a ZIP was handed to the integrator.
28.3 A fresh-session handoff
ASSIGNMENT
What the user authorized; complete output roster; latest amendments.
ENVIRONMENT
Machine roles; versions; executable/connection details without secrets.
LAST VERIFIED ACCESS
Timestamp, actual probe result or error; what has not been retested.
REVIEWED PARENT
Exact file and measured hash; accepted scope; protected objects/contracts.
PENDING WORK
Candidate files, active job identity, receipts/logs, uncertain write outcomes.
DELIVERED
Destination, filenames, sizes/hashes, export/visual/integration status separately.
READY NEXT
One precise next operation; independent work that can proceed.
HOLDS AND FLAWS
Missing references, failed checks, unreviewed rooms/frames/exports.
A fresh assistant should inspect this state and continue, not rebuild everything or revive an old queue. If the assignment is present and authorized, connection verification and real work should follow promptly.
29. Copyable operating prompts
Setup coach
Guide me through the Blender Lab MCP route using current official docs and this field guide. First inspect whether I already have a compatible setup. Identify my client surface, operating system, and the machine hosting Blender. Give me two or three steps at a time. Keep keys local. Prove the add-on, bridge, tunnel if used, tool discovery, and a fresh read-only Blender execution separately. Do not call setup complete from a screenshot or configuration doctor alone. Then help me run the isolated first-project exercise.
First production assignment
Build one furnished study-room visualization in a new project. Use real-world units, named objects, reproducible scripts, and saved revisions. Start with room geometry/openings/furniture scale, then improve form, materials, light, and presentation. Save an editable
.blend, GLB, three actual rendered views, a manifest, and a concise flaws list. Perform at least three meaningful review-and-correct rounds. Inspect every proof image you claim to review. Continue through the authorized work without asking permission between ordinary steps.
Whole-house assignment
Convert my attached room program into a measurable layout contract. Propose floor count and area, explain the tradeoffs, and build a named whole-house scene in real-world units. Reconcile net/gross/garage/exterior areas explicitly. Review floor plans, four corners, entry sightlines, openings, and furniture clearance before styling. Preserve unknowns. Deliver editable scenes, exports, schedules, actual renders, and honest PASS/FAIL/NOT MEASURED checks. Make no structure, code, cost, or buildability claims.
Realism pass
Refine the existing scene without changing its protected layout. First inspect the actual file, units, camera, materials, lighting, and reviewed parent. Rank the largest visible realism defects. Choose one bounded experiment, declare acceptance, render matched before/after wide and close views, measure applicable contracts, inspect actual images, and accept or reject it. Save failures. Reuse a successful improvement on a second relevant scene before calling it transferable. Keep technical and visual verdicts separate.
Camera-tour assignment
Produce a full POV tour of the requested spaces using the actual selected scene revision. Build a room-coverage route and declared native timebase. Open required doors, check clearance and forward framing, render short native-frame tests of difficult transitions, inspect motion, and then render a resumable frame sequence. Deliver the video, chapters, source route/capture scripts, scene hash, technical checks, and remaining visual flaws. Do not substitute a highlights reel or label an older movie as a new realism revision.
Connection recovery
Diagnose the existing connection without reinstalling or disturbing the current scene. Map the add-on, bridge, tunnel client, and custom MCP connection. Identify each relevant process by executable/arguments and actual port ownership. Read narrow non-secret diagnostics. Distinguish idle timeout, busy operation, crash, missing local file, and upstream transport error. Preserve active job evidence before restarting. Make one read-only execution test after a real recovery step and report the exact observed result.
Continue an interrupted project
Read START-HERE, NEXT, state, reviewed-scene index, and the latest user amendments. Verify file hashes and inspect active-job receipts/liveness before starting anything. Resolve pending versus reviewed branches. Preserve holds and do not rebuild accepted work. Continue the next ready authorized item, saving state and reporting concrete progress as you go.
Improve the workflow itself
Identify one recurring defect and turn the fix into a small reusable tool or documented recipe. Define its input/output contract, test a positive case and a deliberately failing case, record limits, and apply it to a second representative project. Keep the tool version separate from scene versions. Do not claim broad automation from one successful example.
30. Readiness and release checklists
Connection readiness
- ☐ Intended machine and client surface identified.
- ☐ Add-on and matching MCP bridge identified; versions recorded.
- ☐ Actual listener/port ownership confirmed.
- ☐ Runtime environment/paths verified.
- ☐ Tunnel target/profile/health checked if this route uses a tunnel.
- ☐ Workspace association/authentication checked where required.
- ☐ Actual tools discovered in this conversation.
- ☐ Fresh read-only code returned from Blender.
- ☐ Test save/export/render verified in an isolated project.
- ☐ Restart/credential/log record saved without secrets.
Per-experiment readiness
- ☐ Parent identity and source hash verified.
- ☐ Defect/hypothesis and acceptance criteria written.
- ☐ Scope/protected objects specified.
- ☐ Units and evaluated geometry understood.
- ☐ Fixed camera and render recipe recorded.
- ☐ Candidate saved separately.
- ☐ Applicable technical checks passed, with checker limits stated.
- ☐ Actual wide/close/context images inspected.
- ☐ Negative test used where a new checker could otherwise give false confidence.
- ☐ Verdict and next action recorded; rejected evidence retained.
Delivery readiness
- ☐ Native scene reopened; required dependencies available.
- ☐ Export inspected from disk and in the intended consumer.
- ☐ Units, names, sizes, counts, and hashes measured as applicable.
- ☐ Named views/spaces covered; unreviewed parts marked honestly.
- ☐ Motion reviewed if delivering motion.
- ☐ Master, browser, and film revisions labeled independently.
- ☐ Licenses/provenance included for redistributed assets.
- ☐ Destination bytes verified.
- ☐ Integration instructions are sufficient for another person to use the work.
- ☐ Known flaws and exact next action included.
31. What this guide does not promise
- A Markdown attachment cannot grant tool access, provision an account, override a permission refusal, or keep a computer online.
- Our 250-ms timer profile is an observed configuration, not a universal cure or a scientifically optimized setting.
- The prepared macOS Blender LaunchAgent repair was not proven installed in the referenced recovery incident.
- No current connection is claimed merely because a historical test succeeded.
- A valid file, complete manifest, or clean audit does not prove visual quality.
- Scoped still/frame success does not establish a final realistic whole-house film, all-room completion, or browser/mobile acceptance.
- General Python access does not mean a complete rigging, simulation, Geometry Nodes, or asset-library pipeline is already installed.
- This one file contains operating knowledge and small example recipes, not every historical production script, private source file, model, or paid asset.
- Render time and language-model usage are separate resources. Do not estimate remaining account quota from a render’s duration or pretend the assistant can read a usage meter it has not been given.
- Strong visualization does not establish engineering correctness or construction readiness.
The practical advantage is starting with a process that keeps producing inspectable, recoverable improvements. There is no requirement to repeat the same months of setup confusion, lost state, false passes, or export-versus-integration mistakes.
32. Public references and provenance
Public setup references
The product pages below were consulted during preparation. Some source/manual pages were blocked by the retrieval service; they are included as the authoritative places for the receiving assistant/user to check, not falsely described as fully retrieved here. Software and UI labels change: inspect live docs and installed help before applying version-specific installation commands.
- [S1] Blender Lab MCP: https://www.blender.org/lab/mcp-server/; source https://projects.blender.org/lab/blender_mcp; setup https://projects.blender.org/lab/blender_mcp/wiki/Setup. Official Lab-page content was retrieved through search; direct source/setup retrieval was unavailable.
- [S2] Community MCP for Blender, a different project: https://github.com/ahujasid/mcp-for-blender. Consulted to distinguish implementations, not to claim its current package matches our historical Lab setup.
- [S3] OpenAI MCP configuration: https://learn.chatgpt.com/docs/extend/mcp. Local Codex configuration, hosted-chat distinction, registration and timeout controls.
- [S4] OpenAI Secure MCP Tunnel: https://developers.openai.com/api/docs/guides/secure-mcp-tunnels. Private connectivity, permissions/workspace association, supported surfaces, and distribution boundary.
- [S5] OpenAI tunnel-client end-user guide: https://github.com/openai/tunnel-client/blob/master/docs/end-user-guide.md. Credential roles, readiness/discovery distinction, and operator checks.
- [S6] OpenAI tunnel-client onboarding: https://github.com/openai/tunnel-client/blob/master/docs/onboarding.md. CLI/profile examples and current managed-runtime lifecycle. Check the installed version’s help.
- [S7] Add a custom MCP server in ChatGPT: https://developers.openai.com/api/docs/guides/custom-mcp-server. Current connection UI, authentication, installation, and tool management.
- [S8] Apple launchd background jobs: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html. User-agent lifecycle and job design. For modern command details consult the local
man launchctl. - [S9] OpenSSH configuration: https://man.openbsd.org/ssh_config.5; command reference https://man.openbsd.org/ssh.1. Effective configuration and forwarding-failure semantics.
Additional authoritative starting points
- Blender command-line reference: https://docs.blender.org/manual/en/latest/advanced/command_line/arguments.html
- Blender glTF exporter: https://docs.blender.org/manual/en/latest/addons/import_export/scene_gltf2.html
- Blender Python API: https://docs.blender.org/api/current/
- Blender packed data: https://docs.blender.org/manual/en/latest/files/blend/packed_data.html
- glTF specification: https://registry.khronos.org/glTF/
- Poly Haven: https://polyhaven.com/
- Kenney: https://kenney.nl/
- Sketchfab license guidance: https://sketchfab.com/licenses
Blender’s direct manual/API pages were not retrievable during this guide’s preparation. Prefer the installed Lab server’s bundled documentation-search tools where available, or open the official manual locally. The examples here are original illustrative recipes and are not claimed to be an exhaustive API reference.
Where the experience-based advice came from
The exact tuning table and recovery distinctions came from recorded local settings, actual connection errors, and a successful historical tunneled execution. Production lessons came from saved project/handoff records and the architectural-realism workflow’s evidence-backed lessons, including rejected experiments. The frontier capability summary also uses retrieved historical project reports; those reports were not all independently rerun for this document.
The public text omits personal names, household information, private hostnames, account identifiers, real local usernames, live tunnel IDs, secret values, private repository links, and proprietary project files. Fictional room names and org.example labels are examples.
Receiving assistant: start at Section 5, test what is actually available, and then help the user make something worth keeping.