Current: v0.46.1
Themes are listed in order. Shipped themes note the release they landed in (for reference, not a commitment); upcoming themes are intentionally not pinned to a version number, so shipping another example or skill never forces a roadmap renumber. The release pipeline derives the actual version from conventional-commit types.
| Theme | Skills | Rules | Templates | Snippets | Status |
|---|---|---|---|---|---|
| Foundation | 8 | 4 | 1 | 10 | Shipped (v0.1.0) |
| Materials, drivers, migration | 12 | 6 | 2 | 17 | Shipped (v0.2.0) |
| Examples and demos (smoke-gated) | 12 | 6 | 2 | 17 | Shipped (v0.3.0) |
| More examples (turntable, SDF remesh) | 12 | 6 | 2 | 17 | Shipped (v0.4.0) |
| 5.2 LTS sweep, modal operators, USD | — | — | — | — | Upcoming |
| Stable | — | — | — | — | Upcoming |
The 8 skills:
addon-scaffolding-- Extensions Platform manifest, file layout, register/unregister symmetryoperators--bpy.types.Operatorlifecycle,bl_idname, redo, defensive context handlingui-panels--bpy.types.Paneldeclarativedraw(), layout primitives, conditional UIcustom-properties--bpy.propsannotations, PropertyGroup, PointerProperty, storage tradeoffsmesh-editing-and-bmesh-- when to use bpy.data vs bpy.ops vs bmesh, foreach_set, depsgraph evalheadless-batch-scripting--blender --background --python, temp_override, argparse after--slotted-actions-animation-- Blender 5.x Slotted Actions, channelbag, 4.5 LTS fallback bridgegeometry-nodes-python-- programmatic GN tree construction, interface sockets, NODES modifier
The 4 rules:
prefer-data-over-ops-in-loopsalways-free-bmeshtarget-extensions-platform-formattype-annotate-props-and-defend-context
The 1 template:
extension-addon-template-- Extensions Platform format, register_classes_factory, PointerProperty binding, symmetric register/unregister
The 10 snippets:
canonical-object-creation.pycanonical-object-deletion.pydepsgraph-evaluated-mesh.pybmesh-load-edit-free.pytemp-override-context.pyforeach-set-vertices.pyregister-classes-factory.pypointerproperty-binding.pycross-version-property-delete.pyaction-ensure-channelbag-for-slot.py
The 4 new skills:
procedural-materials-and-shaders-- node tree construction for Principled BSDF, emissive, node groups; cross-version socket-name handling forSpecular IOR Leveldepsgraph-and-evaluated-data--evaluated_getplusto_meshplusto_mesh_clearlifetime contract, OBJ-style exporter worked exampledrivers-and-app-handlers-- driver expressions,bpy.app.driver_namespaceescape hatch, application handler pattern with@persistent, the new 5.1exit_prehandlerbl-info-migration-- three-step migration from legacybl_infoto Extensions Platform, before-and-after diff, dual-format pattern
The 2 new rules:
prefer-temp-override-over-context-copy--bpy.context.copy()deprecation in 4.x, removal in 5.x,temp_overridereplacementuse-foreach-set-for-bulk-data-- per-element Python loops over mesh data versusforeach_setandforeach_get
The 1 new template:
headless-batch-script-template-- argparse after--, mesh iteration, modifier apply via temp_override, glTF export, explicit exit codes
The 7 new snippets:
principled-bsdf-material.pydriver-with-custom-function.pyapp-handler-registration.pyshader-node-group.py(cross-versioninterfacevsinputs/outputs)foreach-get-vertices.pyversion-branch-skeleton.pyusd-export-evaluation-mode.py
Audit pass on v0.1.0 content: standards-version markers bumped from 1.9.1 to 1.9.4 across all skills, rules, AGENTS.md, CLAUDE.md, and ROADMAP.md. Verified the bpy_extras.anim_utils.action_ensure_channelbag_for_slot import path against the current Blender 5.1 API reference and removed the stale "verify before production" caveat in slotted-actions-animation/SKILL.md.
Not committed; target list for the next content version. (v0.3.0 shipped the smoke-gated examples/ track.)
-
Fleet Pages facelift + examples supportRESOLVED differently (2026-07-03): the meta-repo migration was dropped — the fleet template only scaffolds new tools, and each tool's site evolves independently after that. This repo vendored the site build intoscripts/site/, redesigned landing + gallery as the Blender-viewport system (seedocs/gallery/DESIGN_NOTES.md), added the examples grid, nav link, and full hero stats locally.scripts/build_gallery.pyandexamples/gallery.jsonare now permanent, not a prototype awaiting lift-and-shift. -
modal-operatorsskill --invokereturningRUNNING_MODAL, themodal()event handler, modal cancellation patterns -
usd-pipelinesskill -- USD export options,evaluation_mode, instancing, the USD vs glTF tradeoffs -
mathutils-patternsskill --mathutils.Vector,Matrix,Quaternion, common transforms, the@operator -
Blender 5.2 LTS sweep (after the 5.2 LTS release in mid-2026)
-
Refresh the
slotted-actions-animationskill against any 5.2 changes -
Bump
blender_version_minin the templates if 5.2 APIs are used -
Additional snippets for asset library scripting, EXR baking, multi-file extensions
-
UV-layer authoring witnessSHIPPED asexamples/uv-layer-grid/—create_grid(..., calc_uvs=True)silent no-op without a pre-existing UV layer; closed-form UV fill + explicit assignment fallback; dual-panel render (flat texel (0,0) vs neon checker) -
Image save-format witnessSHIPPED asexamples/png-exr-alpha/— float→PNG is RGBA16 and false-unpremultiplies as if associated-alpha (closed-form err 0.98 at RGB 0.02 / a=1/255); OpenEXR preserves float RGBA; byte→PNG is straight RGBA8;EXR color_mode='RGB'drops alpha -
Attribute domain witnessSHIPPED asexamples/attribute-domain-shear/— POINT vs CORNER semantics on an 8-wedge pinwheel with one shared hub: CORNER authoring exact (hub corners disagree by face, err ≤ 1e-6), naive per-wedge POINT loop shears to the last write at hub + ring verts, measured deviation == palette closed form (0.751031); byte-identical on 4.5.11 and 5.1.2; crisp-vs-smeared dual pinwheel still — companion tocolor-attribute-wheel -
Light-linking collection witnessSHIPPED asexamples/light-link-studio/— the API isobj.light_linkingon the light OBJECT (ld.light_linkingis an AttributeError on both versions); linked ratio 4.0x at projected-center luminance samples, unlink raises the decoy 244–251% with 0.0% hero drift in the same two-render check; EEVEE Next honors linking too (5.5x on 4.5.11, 5.9x on 5.1.2), Cycles pinned for deterministic samples -
VSE sequences-to-strips witnessSHIPPED asexamples/vse-cut-list/—.sequencesremoved on 5.x (4.5 bridges to.strips),new_effectend kwargframe_end=(4.5) vslength=(5.x),frame_final_*deprecated in favor ofleft_handle/right_handle/duration, TRANSFORM effect type removed, GAMMA_CROSS clamps to the source overlap, effect strips consume inputs only when stacked above them, same-scene scene strips render transparent; save/reload round-trip + tiny-render pixel witness -
glTF export round-trip witnessSHIPPED asexamples/gltf-export-roundtrip/—export_yupbakes(x,y,z)→(x,z,−y)into vertex data with no node rotation (probed identical on 4.5.11 and 5.1.2),export_applyships the evaluated mesh (one disk vertex per evaluated loop), TEXCOORD_0 is V-flipped on disk, per-triangle material bindings survive; exporter/importer RNA signatures byte-identical between 4.5.11 and 5.1.2 (guarded against future renames);Mesh.calc_normals()removal on 5.x surfaced during authoring -
LOD decimate chain witnessSHIPPED asexamples/lod-decimate-chain/— Decimate COLLAPSE evaluated through the depsgraph is non-destructive (obj.data keeps closed-form counts), evaluated tris hitratio × basewithin 5% (measured 0.0–0.44%), silhouette bbox survives within 1e-3 (measured 7.7e-6); a stacked Decimate halves the effective ratio, an aggressive 0.02 ratio collapses the nose tip — both caught failure modes -
Vertex weight limit witnessSHIPPED asexamples/vertex-weight-limit/— the 4-influence engine cap enforced via the data API (v.groups+VertexGroup.remove+ renormalize); unit sums (measured 3e-8), pose preserved (4.9e-3), exact LBS from the mesh's own deform layer (2.7e-7), Root mount pinned -
Triangulate + tangent-space witnessSHIPPED asexamples/triangulate-tangents/—calc_tangentsaborts on any ngon (back cap must be an explicit fan); mikktspace matches the edge/UV-delta formula within welding tolerance on smooth fields (2.3e-6 measured); planar UVs on a cylindrical wall collapse tangents onto normals (dot 0.998);MeshUVLoopLayerhandle dangles acrosscalc_tangents()on 4.5 (471 phantom flips, silent exit 0) while the mikktspace math is byte-identical on 4.5.11 and 5.1.2 -
UV-handle lifetime snippet: re-fetch attribute/UV layers by name after any CustomData-reallocating call (
calc_tangents,VertexGroup.add, modifier edits) — held handles dangle silently on 4.5, survive by luck on 5.1 (found authoringtriangulate-tangents; confirmed harder authoringlightmap-uv-channel: iterating a heldMeshUVLoopLayer.dataafter edit-mode UV ops segfaults 4.5.11 headless, EXCEPTION_ACCESS_VIOLATION 5/5, survives on 5.1.2) -
glTF skinned-mesh export witness: follow-up toSHIPPED asgltf-export-roundtrip+vertex-weight-limitexamples/gltf-skin-roundtrip/—skins[0].jointsnames every bone, JOINTS_0/WEIGHTS_0 with unit sums (3e-8), weights bit-exact, rest matrices to 2.4e-07, deformation to 4.8e-07; exporter welds duplicate loops (sorted-multiset comparisons mispair — compare by rest-key); unparented skinned meshes make the exporter bind an armature by name -
Degenerate-bevel weld hazardSHIPPED asexamples/degenerate-bevel-weld/— atoffset == min_dim/2the bevel band collapses to exactly 12 zero-area faces (4 min-axis edges × 3 segments) with 16 coincident verts (4 × (segments+1)) and min_area down 3.2e5×; a stdlib GLB re-parse counts 32 degenerate triangles crossing the export boundary (MEASURED regression constant) versus 0 for the safe mesh — the loops an engine merge-by-distance welds; byte-identical on 4.5.11 and 5.1.2 -
Modular kit snap witnessSHIPPED asexamples/modular-kit-snap/— tiling corridor segment: 16 boundary verts onx ∈ {0, TILE}within 1e-6 m, end rings coincident under the tile offset (nearest-key match), linked-duplicate joint deviation 0.0, shell bbox == declared tile (dev 0.0), manifold except the 16 open-end edges, 20 detail parts contained inside the tile; unsnapped probe (3 mm skew, 2 mm nudge) fails at exits 3/4 with measured errors; sorted-zip ring matching mispairs displaced verts — match by nearest key (authoring hazard, fixed); byte-identical on 4.5.11 and 5.1.2 -
Lightmap UV channel witnessSHIPPED asexamples/lightmap-uv-channel/— two-channel UV contract on a market cart: per-partUVMap/UVLightwithactive/active_renderre-asserted after the ops (edit-mode UV ops clear both flags;uv_layers.new()never moves them), UV0 drift 0.0 (clobber trap measured 2.068), every UV1 loop in [0,1], 0 overlapping islands via independent binned strict-SAT (15 hits when falsified), min island distance 0.00401 vs nominal margin 0.002 (MARGIN_DIV × 0.01semantics measured live); heldMeshUVLoopLayer.dataafter edit-mode UV ops segfaults 4.5.11 (5/5, EXCEPTION_ACCESS_VIOLATION), silent no-op pack without prior unwrap; byte-identical on 4.5.11 and 5.1.2 (3680 islands) -
Socket attach-point witnessSHIPPED asexamples/socket-attach-points/— namedSKT_empties as the spawn contract on a survey drone: 7 socket world matrices within 1.788e-07 of the authored transform with orthonormal right-handed bases (Gram 3.576e-07, det err 2.980e-07), socket +Z == the mount pad's Newell normal (1.794e-07) by a quaternion-swing construction independent of the Gram-Schmidt basis, origin on the mount-face centroid (6.687e-08), documented up-axis fallback for the +Z/−Z mounts, module seating offset exactly 0.0 with strictly identity local matrices, rigid invariance under a re-pose (2.384e-07);transform_applyon an Empty root preserves world matrices (2.235e-07) but clears 7/7matrix_parent_inverseand pushes the root scale down into every child (0.35 for an applied 1.35) — both halves asserted; a child left selected during the apply drifts sockets 2.335 m;bm.normal_update()does not fix inward winding (recalc_face_normalsdoes — the lofted fuselage rendered as a flat white panel); no-parent-inverse probe jumps 0.690128 m; byte-identical on 4.5.11 and 5.1.2 -
Vertex-colour AO witnessSHIPPED asexamples/vertex-color-ao/— baked occlusion in a colour attribute on a stone village well, checked against a closed form rather than a captured value: the cosine-weighted hemisphere integral for an infinitely wide wall of height H at distance d isAO = 1 − ½(1 − 1/√(1+k²)),k = H/d, matched to 6.760e-04 across k = 60.0…0.60 (gate 2.5e-03, QMC noise ~1/√n at 4096 samples); unoccluded plate bakes to exactly 1.0; strictly monotone 0.508301 → 0.928467; asset values in [0,1] with spread 1.0;BYTE_COLORis sRGB-encoded 8-bit, not linear (0.735 → 0.7379107, peak round-trip error 3.782e-03, matching an independent encode/quantise/decode model to 3.189e-07) whileFLOAT_COLORis exact; both survive depsgraph evaluation at deviation 0.0;bmesh.ops.beveloffsets along cached face normals and flips outward past 90° of staleness (12 mm below ground on a ring of boxes, fixed bynormal_update()); point-domain AO needs subdivision or the crevice gradient never reaches the attribute;color_attributesenumeration order differs between 4.5.11 and 5.1.2 — look up by name; byte-identical on 4.5.11 and 5.1.2 (6966 verts) -
UV atlas utilization witness — coverage/wasted-texel closed forms for a packed lightmap atlas (the non-overlap, unit-square, margin, and active/active_render contracts shipped in
lightmap-uv-channel; utilization is the remaining unbuilt slice of the old "UV atlas pack" candidate) -
GAMMA_CROSS blend-curve witnessSHIPPED asexamples/vse-gamma-cross/— the cross blends in a gamma-0.5 space:((1-t)·√A + t·√B)²witht = (frame − start)/duration, never 1 inside the effect; mid-cross dips 0.115 below the sRGB lerp from crimson/teal (closed form (0.341, 0.349, 0.463) confirmed per frame); AgX-default sampling poisons the fit (0.146 red-channel error,view_transform='Standard'mandatory); deleting a consumed input orphans-and-deletes the effect — follow-up tovse-cut-list -
Falsy
bpy_prop_collectiontrap snippet: an empty collection is falsy, soeditor.strips or editor.sequencessilently falls through to the legacy accessor on an empty timeline — always branch onhasattr; likely generalizes across the API (found authoringvse-cut-list) -
Collision compound witnessSHIPPED asexamples/collision-hull-proxy/— game-prop collision as a compound of convex pieces, each abmesh.ops.convex_hullof a coarsesec(π/n)-inflated cage (containment 4.4e-08, watertight, positive signed volume, Euler 2, per-piece 255-face budget: body 70, caps 60×3, compound 250); a hull of the dense render mesh measures 380 faces — over budget — which is why pipelines hull cages; proud details cost cage rows, concave grooves are free; byte-identical on 4.5.11 and 5.1.2 -
Custom-normals / shade-by-angle witnessSHIPPED asexamples/custom-normals-shade/— the post-4.1 shading contract:use_auto_smooth/use_custom_normals/calc_normalsare AttributeError on BOTH 4.5.11 and 5.1.2;set_sharp_from_anglesharp sets match an independent dihedral recompute exactly (188/388 edges, 3 meshes); evaluated normal welds/splits exact (0.0 dev); custom split normals survive depsgraph evaluation within int16 quantization (1.407e-04, not float-exact); divergence: the legacyshade_auto_smoothoperator CANCELS headless on 4.5 ("Asset loading is unfinished", mesh untouched, no exception) while 5.1 FINISHES with the Smooth-by-Angle NODES modifier — the data API is the portable path -
Sky Texture / sun_elevation witnessSHIPPED asexamples/sky-texture-sun-elevation/— WorldShaderNodeTexSky→ Background;sky_typeisNISHITAon 4.5 andMULTIPLE_SCATTERINGon 5.1 (NISHITAgone);dust_densityis 4.5-only (aerosol_densityon 5.1); zenith EXR rise 8°→55° measured 2.25x (5.1.2) / 1.50x (4.5.11), gate ≥ 1.25; dual-elevation gallery diptych -
Grease Pencil Line Art contour witnessSHIPPED asexamples/gp-lineart-contour/— GPv3 +modifiers.new(..., "LINEART");source_objectclear → 0 strokes; contour+crease off → 0; restore recovers 10 strokes / 34 points on 4.5.11 and 5.1.2;thicknessis 4.5-only (AttributeErroron 5.1; portableradius) -
Camera DOF + focus_distance witness:
cam.dof.use_dof, focus plane vs defocus variance on high-freq cards (Stage deviation — depth needs background content) -
Volumetric scatter optical-depth witness: Volume Scatter density → Beer–Lambert transmittance along a known path (Cycles; Stage deviation)
-
Freestyle SVG / line-set witness: Freestyle line set on a silhouette (full render pass; prefer Line Art first)
-
prop-origin-transform witnessSHIPPED asexamples/prop-origin-transform/— origin to base center + data-API scale apply +matrix_parent_inversefor a bolted accessory; scale(1,1,1), localmin.z==0, world AABB delta 0, bare jump ~0.43 m, MPI err ~3e-8; stalematrix_worlduntilview_layer.update(); byte-identical on 4.5.11 and 5.1.2 -
Goldberg polyhedron topology witnessSHIPPED asexamples/soccer-ball-goldberg/— soccer ball as a truncated icosahedron: bmesh icosphere cut at 1/3 per edge, faces ordered by link-topology walks; closed forms 60/90/32 + Euler 2, census 12×5+20×6, uniform degree 3, edge dev 6.5e-06, planarity 1.9e-06 (independent Newell normal), circumsphere dev 9.0e-06, panels bound by face vertex count (enumeration-order probes exit 13); float32 noise floor ~9e-6 → 3e-5 gates; byte-identical on 4.5.11 and 5.1.2 -
Mirror-modifier symmetry witness: half-model completed by Mirror evaluated through the depsgraphSHIPPED asexamples/car-mirror-symmetry/— generic hatchback loft (14 stations × 9-point half-rings); datablock keeps the half (126/231/106, 28 centerline), evaluated is exactly 2n−c (224/434/212), watertight Euler 2, ±X partner dev 0.0; wheels/lamps mirror about origins parked on the plane; probes: merge off → 252 (exit 5), centerline off-plane → 27≠28 (exit 4), axis off → 126 half-car (exit 5), applied → exit 3; byte-identical on 4.5.11 and 5.1.2 -
Chess-piece lathe witness: a turned piece (rook/pawn) via Screw modifier or bmesh spin from an authored profile — evaluated verts == profile × steps (minus pole merges), ring radii match the profile closed form, axis of revolution exact
-
Dice-pair per-face witness: material/attribute assignment driven by face normal direction, opposite-faces-sum-to-7 as an independently computed invariant, pip placement from a closed-form lattice
-
Bicycle-wheel radial witness: spokes via radial Array with object offset — exact angular spacing, spoke count, hub/rim concentricity, every evaluated spoke endpoint on its computed rim coordinate
-
mesh-hygiene-audit witnessSHIPPED asexamples/mesh-hygiene-audit/— engine-ingest topology checklist on a stepped street electrical pedestal: no ngons, no loose verts, manifold edges (exactly 2 faces), no zero-area faces (min_areaprinted), positive signed volume, EulerV−E+F==2(24/44/22, volume 0.989248); byte-identical on 4.5.11 and 5.1.2; dual-panel dirty vs clean still -
Gallery framing recomposition worklistDRAINED: all four recomposition cases restaged and gated withcheck_framing— depsgraph-export (0.984x/touch→0.812x; cube+dome recentered, aim-based camera), vertex-weight-limit (touch B→0.867y; more frontal camera, lower aim, base in frame), triangulate-tangents (0.334x→0.833y; 2x-class move-in plus Key/Glint trim that also cleared a pre-existing dome blowout), text-version-stamp (0.663x→0.719x; moved in with aim on the stamp center, dead third gone). The seven marginal cases were camera-nudged in the preceding sweep; deviations documented in #108 (damped-track-aim, wave-displace); sky-texture-sun-elevation is a measurement artifact (world subject — report-only if wired). Remaining: nothing on the framing worklist — future examples inherit the gate at authoring time.
The neutral asset-sheet harness sized its camera from the subject's bounding
box diagonal, which cropped tall subjects and shrank wide ones, so panels
in one sheet were at different effective scales. It now solves the required
distance from the real field of view on both axes. Sheets committed before
this fix (modular-kit-snap, lightmap-uv-channel) show mis-scaled panels
and must not be cited as evidence for or against an asset; re-render them if
that comparison is ever needed.
Full-gallery floor survey after the gate landed (feat/asset-quality-gate).
26 of 42 examples pass all floors. The 14 below-floor entries, with
measured numbers — every one is a contract-vehicle or display subject
(testcard TV, VSE monitors, text bars, swatch/display rigs, single honest
primitives), not a game asset meant for reuse, so none is a remodeling
mandate; the floors exist to catch future asset-type examples at authoring
time. Two non-mesh subjects (curve-bevel-arc, grease-pencil-rosette) are
not measurable by the floors (curve/GP data, no mesh hero). Re-survey after
any example remodel.
- naming (default datablock names): gltf-skin-roundtrip (3 parts), gn-sdf-remesh (
Torus), turntable (Suzanne) - materials (multi-part, single material): armature-bend (3 parts/1 mat — vertex-color weight bands are the honest display), degenerate-bevel-weld (2/1), driver-wave (16/1, also edge90 1.0), shape-key-blend (3/1, also edge90 1.0)
- edge90 (raw right angles, 1.0): depsgraph-export (also naming + materials), image-pixels-testcard, png-exr-alpha, temp-override-join, text-version-stamp, vse-cut-list; vse-gamma-cross at 0.92
- reference: gallery best-modeled measure collision-hull-proxy 0.044, custom-normals-shade 0.288, vertex-weight-limit 0.150, lod-decimate-chain 0.019; calibration details in
docs/VISUAL-STYLE.md§ Asset quality
- Asset library and asset browser scripting skill
- Cycles vs EEVEE Next render API skill
- Geometry Nodes 5.x feature parity (volumes, fields)
- Animation rigging from Python (constraints, drivers across bones)