Modeling
Read blender-scene for the local session contract.
Tool names below use its capability mapping when the named interface is absent;
read only the relevant rows in blender-volatile.
Model from the Scene Passport, in metres, Z-up. Typed tools first —
bl_build_blockout, bl_batch, bl_create_collection, bl_parent_objects,
bl_add_modifier, the narrow primitive/transform tools; bl_execute is for
mesh editing, curves, Geometry Nodes, and whatever else typed tools cannot
express.
Blockout passes
Coarse to fine, and each pass locks one class of spatial constraints before
more detail is allowed:
- Silhouette — primitives set footprint, height, dominant contour.
Judged from the active camera plus one orthographic side view.
- Proportion — dimensions and relative scale checked against the
passport in explicit metre values, not by eye.
- Depth — foreground/midground/background, overlap, negative space,
camera-visible thickness.
- Contact — nothing floats, nothing interpenetrates; support surfaces,
pivots, and believable contact exist.
- Camera read — viewed camera render with simple diagnostic materials:
subject, focal
hierarchy, and major forms must read before bevels, topology, or
generated replacements are allowed.
- Detail — every visible asset is brought to its passport
fidelity
tier by role:
- hero — full detail: silhouette, surface features, material response;
- midground prop — a recognizable species/type silhouette (a cactus
must read as a saguaro — ribs, tapered curved arms, rounded caps — not
as a cylinder; a rock needs facet variation, not a uniform sphere);
- background — blockout primitives are acceptable.
A
commercial, ad, or deliverable intent in the passport raises every
camera-visible tier by one. The build is unfinished while any visible
asset sits below its tier.
A failed gate stops the line: fix the largest silhouette or placement error
before touching anything downstream.
On a connector exposing bl_build_blockout with a documented dry-run and
pass contract, validate its schema before committing a manifest, then rerun
idempotently with pass_id in this locked order: bounds, primary_masses,
secondary_masses, silhouette_proportions, pivots_attachments,
camera_review. View each pass render/screenshot, then call
bl_review_blockout_pass — only decision:"continue" with viewed evidence
unlocks the next pass; when continuing is not justified, the decision is
refine-spec, refine-code, request-input, or stop. Confirm via
bl_scene_diff against the checkpoint that only the intended semantic
objects changed. On a connector without these interfaces, use the core local
fallbacks: perform the same spatial passes, view the evidence and record the
continue/refine decision before progressing, and compare fresh snapshots.
Do not pretend that a missing dry-run or review tool was executed.
Editable construction
- Distinct semantic parts stay separate named objects or collections.
- Origins sit where manipulation and animation need them.
- Modifiers over destructive edits; the base mesh survives until finalize.
- Repeated assets are instances.
- Scale gets applied only when a modifier, export, or simulation demands it —
and the destructive application is recorded.
- Mesh-level scale hits every user of the datablock at once. Count the users
before scaling shared data; an object
scale of exactly 1 beside resized
geometry means the factor already lives in the mesh and is not reapplied.
- Proxies for generated assets stay until the import passes audit.
- No single fused mesh where the scene needs per-part materials or motion.
Transform and parenting traps
- Scaled object + Bevel modifier makes pillows. Bevel works in local
space, so a chamfer set on a unit cube gets stretched by
o.scale.
bpy.ops.object.transform_apply(scale=True) first.
- Parent inverse compensates the initial parent transform; it does not
disable later inheritance. For a child authored in the parent's local
space, use an identity parent inverse. To preserve an existing world pose
when assigning a parent, retain and restore the child's
matrix_world.
A fixed inverse still allows subsequent parent motion to move the child.
If motion disappears, inspect constraints and evaluated world transforms;
do not diagnose it from a non-identity inverse alone.
- A rotation about the wrong axis silently does nothing visible. A panel
whose normal is +X does not change facing when rotated about X. Measure the
world normal against the view vector rather than reasoning about it.
Measurement traps
bound_box is not a radius. The bounding box of a rotated body of
revolution is smaller than its diameter, and reading one as a radius
oversizes every part derived from it. Measure from the mesh: the axis is
the direction of least vertex spread (covariance), the radius is the
maximum distance in the perpendicular plane.
- Quaternion difference carries no sign.
rotation_difference().angle
returns an unsigned magnitude and cannot separate a rotation from its
complement. Take the signed angle:
atan2(dot(axis, cross(v1, v2)), dot(v1, v2)).
Destructive edit traps
- Never select geometry by coordinate box. A box takes everything inside
it, far side included, and thousands of polygons from unrelated parts leave
silently. Select by material, island, normal, or attribute, and compare
polygon counts before and after.
- Decimate:
COLLAPSE deforms flat panels; DISSOLVE (planar) moves no
vertices at all. 5° is the safe ceiling (about -43% polygons), 8° tears UV
islands, 12° facets the surface.
bl_execute discipline
Data API first. When operators are unavoidable:
- set object mode explicitly;
- deselect all, select the target, make it active;
- establish collection/view-layer context;
- restore relevant state afterwards;
- return created names, dimensions, modifier names, and mesh counts in
result.
Batch one coherent object or modifier stack per call — not the whole scene in
one opaque script.
Hard-surface techniques
For man-made rigid objects (vehicles, machines, buildings, devices):
- Loft cross-sections; never stack primitives. Primitive assembly has a
hard ceiling no lighting or framing gets past. Define a profile whose
width/height/chamfer vary along the length, sweep it through stations, and
bridge into one continuous skin. A stepped profile (parallel midbody,
shoulder, blunt end) reads better than a smooth taper — steps are what the
eye measures scale against.
- Cut detail into the skin. Panel recesses, trenches, and openings are
bmesh.ops.inset_region on selected faces translated inward along the face
normal, with a different material index in the recess. Boxes glued onto a
surface always look glued on.
- Detail hierarchy with restraint. Three tiers: primary masses, medium
panel features, fine detail at roughly 1/60 of the object's length. Zone
the fine detail and deliberately leave clean areas — detail only registers
against something undetailed; covering every face reads as noise.
- A flat plate never sits flush on a curved host. The standoff varies
across the seat and no amount of translation closes it. Sweep the plate's
profile along the host surface, or cut the recess into the skin.
- Flat-shade hard-surface plate rather than smooth-shading everything.
Engine export
When the user requests export to a game engine or external renderer:
- Join by material first. Draw calls scale with glTF primitives, one per
material per mesh; joining single-material objects collapses a loose export
of dozens of draws into a handful.
- Procedural node materials do not survive glTF — export flat base colors
(bake if the look must travel).
KHR_materials_emissive_strength does
survive, so authored emissive intensities keep.
- Apply transforms on export (
export_apply=True) and mind the unit scale of
the target engine; model in metres and scale once at a root object.
Geometry checks
For hero and exported meshes:
- dimensions and transform;
- non-manifold/open boundaries where the surface should be closed;
- flipped normals;
- duplicate or internal geometry;
- unapplied scale breaking shading or modifiers;
- density out of proportion to silhouette benefit;
- naming, parenting, collection membership, material slots.
bl_get_object and additional read-only bpy checks supply structural
evidence; viewed camera renders supply the
visual one. A script finishing is not approval.
1---2name: blender-modeling3description: Procedural, camera-aware blockout-first geometry — silhouette/proportion/depth/contact/camera-read/detail gates, typed tools before bl_execute, and topology/parenting/measurement/destructive-edit traps.4---56# Modeling78Read [blender-scene](../blender-scene/SKILL.md) for the local session contract.9Tool names below use its capability mapping when the named interface is absent;10read only the relevant rows in [blender-volatile](../blender-volatile/SKILL.md).1112Model from the Scene Passport, in metres, Z-up. Typed tools first —13`bl_build_blockout`, `bl_batch`, `bl_create_collection`, `bl_parent_objects`,14`bl_add_modifier`, the narrow primitive/transform tools; `bl_execute` is for15mesh editing, curves, Geometry Nodes, and whatever else typed tools cannot16express.1718## Blockout passes1920Coarse to fine, and each pass locks one class of spatial constraints before21more detail is allowed:22231. **Silhouette** — primitives set footprint, height, dominant contour.24 Judged from the active camera plus one orthographic side view.252. **Proportion** — dimensions and relative scale checked against the26 passport in explicit metre values, not by eye.273. **Depth** — foreground/midground/background, overlap, negative space,28 camera-visible thickness.294. **Contact** — nothing floats, nothing interpenetrates; support surfaces,30 pivots, and believable contact exist.315. **Camera read** — viewed camera render with simple diagnostic materials:32 subject, focal33 hierarchy, and major forms must read before bevels, topology, or34 generated replacements are allowed.356. **Detail** — every visible asset is brought to its passport `fidelity`36 tier by role:37 - **hero** — full detail: silhouette, surface features, material response;38 - **midground prop** — a recognizable species/type silhouette (a cactus39 must read as a saguaro — ribs, tapered curved arms, rounded caps — not40 as a cylinder; a rock needs facet variation, not a uniform sphere);41 - **background** — blockout primitives are acceptable.42 A `commercial`, `ad`, or `deliverable` intent in the passport raises every43 camera-visible tier by one. The build is unfinished while any visible44 asset sits below its tier.4546A failed gate stops the line: fix the largest silhouette or placement error47before touching anything downstream.4849On a connector exposing `bl_build_blockout` with a documented dry-run and50pass contract, validate its schema before committing a manifest, then rerun51idempotently with `pass_id` in this locked order: `bounds`, `primary_masses`,52`secondary_masses`, `silhouette_proportions`, `pivots_attachments`,53`camera_review`. View each pass render/screenshot, then call54`bl_review_blockout_pass` — only `decision:"continue"` with viewed evidence55unlocks the next pass; when continuing is not justified, the decision is56`refine-spec`, `refine-code`, `request-input`, or `stop`. Confirm via57`bl_scene_diff` against the checkpoint that only the intended semantic58objects changed. On a connector without these interfaces, use the core local59fallbacks: perform the same spatial passes, view the evidence and record the60continue/refine decision before progressing, and compare fresh snapshots.61Do not pretend that a missing dry-run or review tool was executed.6263## Editable construction6465- Distinct semantic parts stay separate named objects or collections.66- Origins sit where manipulation and animation need them.67- Modifiers over destructive edits; the base mesh survives until finalize.68- Repeated assets are instances.69- Scale gets applied only when a modifier, export, or simulation demands it —70 and the destructive application is recorded.71- Mesh-level scale hits every user of the datablock at once. Count the users72 before scaling shared data; an object `scale` of exactly 1 beside resized73 geometry means the factor already lives in the mesh and is not reapplied.74- Proxies for generated assets stay until the import passes audit.75- No single fused mesh where the scene needs per-part materials or motion.7677## Transform and parenting traps7879- **Scaled object + Bevel modifier makes pillows.** Bevel works in local80 space, so a chamfer set on a unit cube gets stretched by `o.scale`.81 `bpy.ops.object.transform_apply(scale=True)` first.82- **Parent inverse compensates the initial parent transform; it does not83 disable later inheritance.** For a child authored in the parent's local84 space, use an identity parent inverse. To preserve an existing world pose85 when assigning a parent, retain and restore the child's `matrix_world`.86 A fixed inverse still allows subsequent parent motion to move the child.87 If motion disappears, inspect constraints and evaluated world transforms;88 do not diagnose it from a non-identity inverse alone.89- **A rotation about the wrong axis silently does nothing visible.** A panel90 whose normal is +X does not change facing when rotated about X. Measure the91 world normal against the view vector rather than reasoning about it.9293## Measurement traps9495- **`bound_box` is not a radius.** The bounding box of a rotated body of96 revolution is smaller than its diameter, and reading one as a radius97 oversizes every part derived from it. Measure from the mesh: the axis is98 the direction of least vertex spread (covariance), the radius is the99 maximum distance in the perpendicular plane.100- **Quaternion difference carries no sign.** `rotation_difference().angle`101 returns an unsigned magnitude and cannot separate a rotation from its102 complement. Take the signed angle:103 `atan2(dot(axis, cross(v1, v2)), dot(v1, v2))`.104105## Destructive edit traps106107- **Never select geometry by coordinate box.** A box takes everything inside108 it, far side included, and thousands of polygons from unrelated parts leave109 silently. Select by material, island, normal, or attribute, and compare110 polygon counts before and after.111- **Decimate:** `COLLAPSE` deforms flat panels; `DISSOLVE` (planar) moves no112 vertices at all. 5° is the safe ceiling (about -43% polygons), 8° tears UV113 islands, 12° facets the surface.114115## `bl_execute` discipline116117Data API first. When operators are unavoidable:118119- set object mode explicitly;120- deselect all, select the target, make it active;121- establish collection/view-layer context;122- restore relevant state afterwards;123- return created names, dimensions, modifier names, and mesh counts in124 `result`.125126Batch one coherent object or modifier stack per call — not the whole scene in127one opaque script.128129## Hard-surface techniques130131For man-made rigid objects (vehicles, machines, buildings, devices):132133- **Loft cross-sections; never stack primitives.** Primitive assembly has a134 hard ceiling no lighting or framing gets past. Define a profile whose135 width/height/chamfer vary along the length, sweep it through stations, and136 bridge into one continuous skin. A stepped profile (parallel midbody,137 shoulder, blunt end) reads better than a smooth taper — steps are what the138 eye measures scale against.139- **Cut detail into the skin.** Panel recesses, trenches, and openings are140 `bmesh.ops.inset_region` on selected faces translated inward along the face141 normal, with a different material index in the recess. Boxes glued onto a142 surface always look glued on.143- **Detail hierarchy with restraint.** Three tiers: primary masses, medium144 panel features, fine detail at roughly 1/60 of the object's length. Zone145 the fine detail and deliberately leave clean areas — detail only registers146 against something undetailed; covering every face reads as noise.147- **A flat plate never sits flush on a curved host.** The standoff varies148 across the seat and no amount of translation closes it. Sweep the plate's149 profile along the host surface, or cut the recess into the skin.150- Flat-shade hard-surface plate rather than smooth-shading everything.151152## Engine export153154When the user requests export to a game engine or external renderer:155156- **Join by material first.** Draw calls scale with glTF primitives, one per157 material per mesh; joining single-material objects collapses a loose export158 of dozens of draws into a handful.159- Procedural node materials do **not** survive glTF — export flat base colors160 (bake if the look must travel). `KHR_materials_emissive_strength` does161 survive, so authored emissive intensities keep.162- Apply transforms on export (`export_apply=True`) and mind the unit scale of163 the target engine; model in metres and scale once at a root object.164165## Geometry checks166167For hero and exported meshes:168169- dimensions and transform;170- non-manifold/open boundaries where the surface should be closed;171- flipped normals;172- duplicate or internal geometry;173- unapplied scale breaking shading or modifiers;174- density out of proportion to silhouette benefit;175- naming, parenting, collection membership, material slots.176177`bl_get_object` and additional read-only bpy checks supply structural178evidence; viewed camera renders supply the179visual one. A script finishing is not approval.