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 @@ -80,6 +80,7 @@
"examples/swatch-grid",
"examples/temp-override-join",
"examples/text-version-stamp",
"examples/triangulate-tangents",
"examples/turntable",
"examples/uv-layer-grid",
"examples/vertex-weight-limit",
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/blender-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,15 @@ jobs:
# deform layer, and a pinned Root mount. Exits non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/vertex-weight-limit/vertex_weight_limit.py --

- name: Shipped example - triangulate + tangents (mikktspace contract)
run: |
set -euo pipefail
# Check only (no render): a lathed buckler with polar/strip/planar
# UV charts; asserts closed-form loop-triangle count, unit and
# orthogonal tangent frames, bitangent == sign*(n x t), tangents
# matching the independent edge/UV-delta formula on smooth-field
# triangles, zero flips off seams, and the re-fetched UV layer
# surviving calc_tangents. Exits non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/triangulate-tangents/triangulate_tangents.py --
23 changes: 20 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>26 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>27 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 26 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 27 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 @@ -472,7 +472,7 @@ round-trips through the raw `POINT` buffer.
</details>

<details>
<summary><strong>Game asset pipeline</strong> — 3 examples</summary>
<summary><strong>Game asset pipeline</strong> — 4 examples</summary>

<table>
<tr>
Expand Down Expand Up @@ -525,6 +525,23 @@ boots really carry five influences, no vertex ends over the cap, weights still
sum to one, the pose survives pruning, and the modifier is still exact linear
blend skinning read back from the mesh's own deform layer.

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<a href="examples/triangulate-tangents/"><img src="examples/triangulate-tangents/preview.webp" alt="Triangulate and tangents: a machined steel buckler on a dark cradle - brushed grooves circulating the boss with an anisotropic sweep - proving the mikktspace tangent field a normal map depends on" /></a>
</td>
<td valign="middle">

### [triangulate-tangents](examples/triangulate-tangents/)

The normal-mapping tangent-space contract: deterministic triangulation
(`calc_tangents` aborts on any ngon), unit orthogonal tangent frames,
`bitangent == sign * (n x t)`, and mikktspace matching the independent
edge/UV-delta formula on smooth fields. Documents the planar-on-cylinder UV
degeneracy (tangent collapses onto the normal) and the stale layer-handle
hazard that silently corrupts measurements on 4.5.

</td>
</tr>
</table>
Expand Down
3 changes: 2 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- ~~glTF export round-trip witness~~ **SHIPPED** as `examples/gltf-export-roundtrip/` — `export_yup` bakes `(x,y,z)→(x,z,−y)` into vertex data with no node rotation (probed identical on 4.5.11 and 5.1.2), `export_apply` ships 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 witness~~ **SHIPPED** as `examples/lod-decimate-chain/` — Decimate COLLAPSE evaluated through the depsgraph is non-destructive (obj.data keeps closed-form counts), evaluated tris hit `ratio × base` within 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 witness~~ **SHIPPED** as `examples/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 witness: `mesh.calc_loop_triangles` + `calc_tangents` producing the deterministic loop topology and orthonormal tangent basis a game engine's normal mapping depends on — the fourth direction of the game-pipeline arc, identified but not built
- ~~Triangulate + tangent-space witness~~ **SHIPPED** as `examples/triangulate-tangents/` — `calc_tangents` aborts 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); `MeshUVLoopLayer` handle dangles across `calc_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 authoring `triangulate-tangents`)
- glTF skinned-mesh export witness: follow-up to `gltf-export-roundtrip` + `vertex-weight-limit` — export a rigged mesh (weights + joints) to glTF and round-trip the skin, asserting influence counts and joint bindings survive the format
- Degenerate-bevel weld hazard (snippet or rule): bevel width ≥ half a box dimension creates zero-area faces whose loops weld on glTF export (found authoring `gltf-export-roundtrip`, where the count check caught a 36-vertex weld)
- GAMMA_CROSS blend-curve witness: the cross blend is not the naive linear mix (mid-cross measured (0.341, 0.349, 0.463) from crimson (0.85, 0.10, 0.22) and teal (0.06, 0.75, 0.80)) — derive and assert the gamma-space closed form per frame; follow-up to `vse-cut-list`
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.
11 changes: 11 additions & 0 deletions docs/gallery/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,17 @@ <h2><a href="vertex-weight-limit/">vertex-weight-limit</a></h2>
<a class="card-link" href="vertex-weight-limit/">View example <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
<article class="card" data-tags="mesh uv">
<a class="card-media" href="triangulate-tangents/" aria-label="triangulate-tangents example detail page">
<img src="assets/triangulate-tangents-hero.webp" alt="triangulate-tangents — A machined buckler verifying the tangent-space contract a game engine&#x27;s normal mapping depends on." loading="lazy" decoding="async" />
</a>
<div class="card-body">
<h2><a href="triangulate-tangents/">triangulate-tangents</a></h2>
<p class="teaches">A machined buckler verifying the tangent-space contract a game engine&#x27;s normal mapping depends on. Deterministic triangulation, unit orthogonal tangent frames, and the edge/UV-delta formula matching mikktspace within welding tolerance.</p>
<p class="witnesses"><span class="tag">witnesses</span> calc_tangents aborts on any ngon; planar UVs on a cylindrical wall collapse tangents onto normals; a MeshUVLoopLayer handle held across calc_tangents dangles on 4.5 (471 phantom flips, silent exit 0) while the mikktspace math is byte-identical on both versions.</p>
<a class="card-link" href="triangulate-tangents/">View example <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
</div>
</main>
<footer>
Expand Down
Loading
Loading