Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"examples/collision-hull-proxy",
"examples/compositor-glare",
"examples/curve-bevel-arc",
"examples/custom-normals-shade",
"examples/damped-track-aim",
"examples/depsgraph-export",
"examples/driver-wave",
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/blender-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,17 @@ jobs:
# the 255-face per-piece engine budget. Exits non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/collision-hull-proxy/collision_hull_proxy.py --

- name: Shipped example - custom normals + shade by angle (post-4.1 shading contract)
run: |
set -euo pipefail
# Check only (no render): a jerry can prop; asserts the legacy
# shading API stays removed (use_auto_smooth/use_custom_normals/
# calc_normals), set_sharp_from_angle sharp sets matching an
# independent dihedral recompute exactly, evaluated normal welds/
# splits, custom split normals surviving depsgraph evaluation
# within int16 quantization, and the version-gated shade_auto_smooth
# operator divergence (CANCELLED headless on 4.5, FINISHED on 5.1).
# Exits non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/custom-normals-shade/custom_normals_shade.py --
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</p>

<p align="center">
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>31 examples</strong>
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>32 examples</strong>
</p>

<p align="center">
Expand All @@ -36,7 +36,7 @@

## Overview

This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 31 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.
This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 32 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.

The content is consumed by AI coding agents (Cursor, Claude Code, any MCP-capable client) when working on Blender add-ons, geometry nodes scripts, batch pipelines, or animation tooling. There is no build step. Edit the markdown and Python files directly.

Expand Down Expand Up @@ -504,7 +504,7 @@ round-trips through the raw `POINT` buffer.
</details>

<details>
<summary><strong>Game asset pipeline</strong> — 6 examples</summary>
<summary><strong>Game asset pipeline</strong> — 7 examples</summary>

<table>
<tr>
Expand Down Expand Up @@ -610,6 +610,27 @@ tests prove containment (5.9e-08), convexity, watertightness, outward
winding, and Euler characteristic 2 per piece. Proud details cost cage rows;
concave grooves are free.

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<a href="examples/custom-normals-shade/"><img src="examples/custom-normals-shade/preview.webp" alt="Custom normals and shade by angle: three olive-drab jerry can props with pressed X ribs and red spout rings on a dark studio floor - one faceted flat, one smeared by smooth-everything, one crisp with correct hard edges - proving the post-4.1 shading contract" /></a>
</td>
<td valign="middle">

### [custom-normals-shade](examples/custom-normals-shade/)

The shading contract a prop's silhouette depends on: since Blender 4.1,
hard edges are mesh data (face smooth flags + `sharp_edge` attribute), and
`use_auto_smooth` / `use_custom_normals` / `calc_normals` are AttributeError
on **both** 4.5 LTS and 5.1. `set_sharp_from_angle` marks sharp exactly the
edges an independent dihedral recompute predicts; evaluated loop normals
weld across smooth edges and split by the dihedral across sharp ones;
custom split normals survive depsgraph evaluation within their int16
quantization (1.407e-04, not float-exact). Documents the legacy
`shade_auto_smooth` operator trap: CANCELLED headless on 4.5, FINISHED
with the Smooth-by-Angle modifier on 5.1.

</td>
</tr>
</table>
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- ~~GAMMA_CROSS blend-curve witness~~ **SHIPPED** as `examples/vse-gamma-cross/` — the cross blends in a gamma-0.5 space: `((1-t)·√A + t·√B)²` with `t = (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 to `vse-cut-list`
- Falsy `bpy_prop_collection` trap snippet: an empty collection is falsy, so `editor.strips or editor.sequences` silently falls through to the legacy accessor on an empty timeline — always branch on `hasattr`; likely generalizes across the API (found authoring `vse-cut-list`)
- ~~Collision compound witness~~ **SHIPPED** as `examples/collision-hull-proxy/` — game-prop collision as a compound of convex pieces, each a `bmesh.ops.convex_hull` of a coarse `sec(π/n)`-inflated cage (containment 5.9e-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 374 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 witness (game prop shading) — `use_auto_smooth` removed in 4.1; assert what 4.5 vs 5.1 actually expose (`shade_smooth_by_angle` operator / Smooth-by-Angle node group), per-loop custom normals surviving depsgraph evaluation, unit-length basis, hard edges landing exactly where an independently recomputed dihedral angle crosses the threshold
- ~~Custom-normals / shade-by-angle witness~~ **SHIPPED** as `examples/custom-normals-shade/` — the post-4.1 shading contract: `use_auto_smooth`/`use_custom_normals`/`calc_normals` are AttributeError on BOTH 4.5.11 and 5.1.2; `set_sharp_from_angle` sharp 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 legacy `shade_auto_smooth` operator 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
- prop-origin-transform witness — origin to base center, `transform_apply` through the data API, delta transforms, `matrix_parent_inverse` so parented children do not teleport; closed forms: post-apply scale exactly (1,1,1), local bbox min Z == 0, world bbox unchanged (builds on `parent-inverse-orrery`, does not duplicate it)
- mesh-hygiene-audit witness — the engine-ingest checklist as executable contract: no ngons, no loose vertices, no non-manifold edges, no zero-area faces, consistent outward winding; closed forms via Euler characteristic and exact edge-face incidence counts

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading