# Blender Web 3d

> Work with Blender from Claude — headless CLI scripting or the Blender MCP — to build, modify, render, and publish any 3D model, including shipping it online as an interactive Three.js/Next.js web app (GLB export with Draco+WebP, orbit viewer, bloom, animated parts, Vercel deploy). Use this whenever the user wants to create, improve, fix, render, or iterate on any Blender model or scene — phrases like "improve the model", "fix this part", "render this", "make a 3D web demo", "export to glTF/GLB", "use blender", "the model looks wrong in the browser", "optimize the 3D scene", or any screenshot-driven feedback loop on a 3D asset. Also use it when debugging a Three.js viewer that renders black, glows wrong, or has detached/floating parts, and when deciding between Blender MCP and headless CLI. Proven on the Aurora colony-ship project.

- Skill: `czlonkowski/blender-web-3d` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add czlonkowski/blender-web-3d`
- Raw SKILL.md: https://api.skillmd.com/api/skills/czlonkowski/blender-web-3d/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: czlonkowski (https://skillmd.com/u/czlonkowski)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/czlonkowski/blender-web-3d

---


# Blender → Web 3D publishing pipeline

Build detailed 3D models with scripted, reproducible Blender edits, export them
as compressed GLB, and serve them in a Next.js/Three.js viewer. The whole loop
runs headless — no Blender GUI needed — so every change is a reviewable script
and every state is a versioned file.

Every pattern here is project-agnostic — it applies to any model (product
viz, architecture, vehicles, characters, props). The patterns were extracted
from a real shipped project (the Aurora colony ship: a ~2 km vessel with two
counter-rotating habitat rings, ~30 versioned edit scripts, deployed on
Vercel). A typical project layout:

```
my-project/
├── app/                  # Next.js + Three.js viewer (one client component)
├── public/models/        # versioned runtime GLBs (model-vNNN.glb)
├── public/draco/         # Draco decoder files
├── scripts/              # versioned Blender edit scripts + export pipeline
└── ../blend-output/      # versioned .blend chain + textures + beauty renders
```

## Two ways to drive Blender: MCP vs headless CLI

Both exist on this machine; choose per task.

- **Headless CLI** (`blender --background file.blend --python script.py`) —
  the default for this skill. Reproducible, versionable, runs without a GUI,
  works in CI. All the pipeline patterns below assume it.
- **Blender MCP** — the community BlenderMCP addon (`blender_mcp_addon.py`,
  installed in Blender's addons; stock v1.2 from the ahujasid/blender-mcp
  project, not modified) plus its paired MCP server (`uvx blender-mcp`,
  registered with `claude mcp add blender -- uvx blender-mcp` when wanted).
  The addon runs a socket server **only inside a live GUI session** (the user
  opens Blender, sidebar → "Connect to MCP server"); in `--background` mode it
  prints a warning and stays inert. Use MCP when the user is watching the
  viewport and wants live iteration, viewport screenshots, or quick
  interactive queries.
- **Write scripts that work in both modes**: guard on `bpy.data.filepath`
  (not GUI state), avoid operators needing a 3D-view context (convert text
  via `bpy.data.meshes.new_from_object(obj.evaluated_get(depsgraph))`), and
  keep everything idempotent — then the same script runs via CLI or pasted
  through MCP's execute-code tool. Docstrings saying "run in the GUI" usually
  just mean the file-path guard must match; headless still works.

## The iteration loop (one model change, end to end)

1. **Copy forward**: `cp <previous>.blend <next-version>.blend` — never edit a
   previous version in place. One version per meaningful change.
2. **Write a versioned edit script** (`scripts/blender_<change>_vNNN.py`)
   following the managed-script pattern → read
   `references/blender-scripting.md` before writing it.
3. **Run headless**: `blender --background <blend> --python <script>`. The
   script validates itself and saves.
4. **Verify with renders**: headless EEVEE renders from 2-4 camera angles
   (recipe in `references/blender-scripting.md`). Look at them — geometry bugs
   are obvious in pictures and invisible in logs.
5. **Export**: bump the export-pipeline constants to the new version, run the
   raw + runtime GLB exports → `references/export-pipeline.md`.
6. **Wire the app**: copy runtime GLB into `public/models/`, bump the model
   path in the viewer component, update README asset notes.
7. **Verify in the browser**, then deploy (`npx vercel deploy --prod --yes`
   from the app directory — the user may need to run this themselves if the
   permission classifier blocks it).

Keep every version of scripts and blends. The chain is the project's history
and lets any state be rebuilt or bisected.

## Reference files — read before the relevant phase

- `references/blender-scripting.md` — the managed-script pattern (guards,
  markers, validation), bmesh geometry construction, headless verification
  renders, BVH cleanup/reseating of orphaned parts, and draw-call
  consolidation (with the animated-ancestor rule). Read before writing any
  Blender script.
- `references/export-pipeline.md` — glTF/GLB export settings (Draco, WebP,
  transmission), what needs baking vs what exports natively, and the export
  gotchas (drivers, collection instances, normal-map chains). Read before
  exporting or when the GLB looks wrong.
- `references/threejs-viewer.md` — the viewer app: loading, driving rotations
  in JS, postprocessing with the mandatory NaN-scrub pass, light strobes,
  performance knobs, the occluded-window RAF trap, and the debug-frame hook.
  Read before touching the web app or debugging rendering.

## Design lessons that shape good results

- **Enclosed volumes beat skeletons.** Thin rods, hoops, and trusses with
  nothing behind them read as "cage" from any distance. Structures read as
  solid when they enclose a lit volume: continuous hull bands, glazed surfaces
  with visible chunky mullions (not hairline rods), and interior content
  (terraces, plants, lights) visible through glass. Glass needs presence —
  alpha ≈ 0.45 and a slight emissive tint, not alpha 0.2.
- **Attach everything.** Floating greebles (caps, markers, rings) read as
  bugs. When a pass removes geometry, sweep for now-orphaned small parts that
  used to sit on it (BVH proximity test — see blender-scripting reference).
- **Scale detail to the camera.** At kilometre scale, 2 m mullions every 20 m
  read correctly; 0.3 m rods disappear or alias.
- **Give each zone a light signature** (e.g. warm amber residential vs green
  agricultural glow) — it makes the model legible at a glance and gives bloom
  something meaningful to do.

## When the user reports a visual bug from a screenshot

Locate the object first, guess never. Headless probe scripts that dump object
names, world-space bounds, radii, and angular positions (grouped by name
pattern) identify what the user photographed in one run. Then fix by script,
re-render the same view, and compare. The screenshot's background often
identifies which assembly you're looking at (e.g. a ring interior visible
behind the hub pinpoints the camera position).

