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
17 changes: 11 additions & 6 deletions docs/gallery/anvil/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,13 @@
.md h1, .md h2, .md h3 { letter-spacing: -0.01em; margin: 1.4rem 0 0.6rem; line-height: 1.25; }
.md h1 { font-size: 1.35rem; } .md h2 { font-size: 1.15rem; } .md h3 { font-size: 1rem; }
.md p { margin: 0.7rem 0; }
.md ul { margin: 0.7rem 0 0.7rem 1.4rem; }
.md ul, .md ol { margin: 0.7rem 0 0.7rem 1.4rem; }
.md li { margin: 0.3rem 0; }
.md .table-wrap { overflow-x: auto; margin: 0.9rem 0; }
.md table { border-collapse: collapse; font-size: 0.86rem; min-width: 100%; }
.md th, .md td { text-align: left; vertical-align: top; padding: 0.4rem 0.75rem 0.4rem 0;
border-bottom: 1px solid var(--border); }
.md th { color: var(--text-dim); font-weight: 600; white-space: nowrap; }
.md code { background: var(--surface-2); border: 1px solid var(--border); padding: 0.08rem 0.35rem;
border-radius: 4px; font-family: var(--font-mono); font-size: 0.84em; }
.md pre { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
Expand Down Expand Up @@ -265,17 +270,17 @@ <h1>anvil</h1>
<p><strong>Composes</strong> skills <code>mesh-editing-and-bmesh</code>, <code>bake-high-to-low</code>, <code>depsgraph-and-evaluated-data</code>, <code>engine-export-presets</code>, and snippets <code>bake_normal_high_to_low.py</code>, <code>setup_bake_target_image.py</code>, <code>lod_chain.py</code> / <code>decimate_to_budget.py</code>, <code>convex_hull_collider.py</code>, <code>export_preset_unity.py</code> (helpers copied, not imported as a package).</p>
<h2>Budgets</h2>
<p>Declared as named constants; every gate <strong>recomputes</strong> from the mesh, materials, UVs, evaluated LOD, collider, or export file.</p>
<p>| Axis | Declared | Measured (4.5.11 / 5.1.2 / 5.2.1) | | --- | --- | --- | | Base triangles | 2500–4500 | 2988 / 2988 / 2988 | | LOD1 ratio | 0.32–0.62 of base | 0.5000 / 0.5000 / 0.5000 | | LOD2 ratio | 0.10–0.35 of base | 0.2195 / 0.2195 / 0.2195 | | Materials | exactly 2 distinct; ≥400 wood, ≥400 metal faces | 2 slots; 1040 / 822 | | UVs | in <code>0..1</code>, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.621, 0.414, 0.489) m ± 0.015 | (0.6210, 0.4137, 0.4890), zmin 0 | | Collider tris | ≤ 280 | 134 | | Export | written, size &gt; 0 | 244052 / 244052 / 244036 bytes |</p>
<div class="table-wrap"><table><thead><tr><th scope="col">Axis</th><th scope="col">Declared</th><th scope="col">Measured (4.5.11 / 5.1.2 / 5.2.1)</th></tr></thead><tbody><tr><td>Base triangles</td><td>2500–4500</td><td>2988 / 2988 / 2988</td></tr><tr><td>LOD1 ratio</td><td>0.32–0.62 of base</td><td>0.5000 / 0.5000 / 0.5000</td></tr><tr><td>LOD2 ratio</td><td>0.10–0.35 of base</td><td>0.2195 / 0.2195 / 0.2195</td></tr><tr><td>Materials</td><td>exactly 2 distinct; ≥400 wood, ≥400 metal faces</td><td>2 slots; 1040 / 822</td></tr><tr><td>UVs</td><td>in <code>0..1</code>, AABB overlap ≤ 1e-5</td><td>in range, overlap 0</td></tr><tr><td>Outer AABB</td><td>(0.621, 0.414, 0.489) m ± 0.015</td><td>(0.6210, 0.4137, 0.4890), zmin 0</td></tr><tr><td>Collider tris</td><td>≤ 280</td><td>134</td></tr><tr><td>Export</td><td>written, size &gt; 0</td><td>244052 / 244052 / 244036 bytes</td></tr></tbody></table></div>
<p>Base triangles dropped from <strong>6616 to 2988</strong> in the quality pass: overlapping face boxes and a beveled superellipse horn became one slotted slab plus a circular oval loft. Hidden coincident faces were the waste.</p>
<p>DECIMATE COLLAPSE triangle counts are <strong>not</strong> identical across series — the gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is <code>has_data</code> plus operator <code>FINISHED</code>, not byte-identity. Stave-width jitter uses fixed seed 17. Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.</p>
<h3>Hygiene</h3>
<p>Recomputed from the generated mesh, not asserted about the script.</p>
<p>| Axis | Declared | Measured (all three) | | --- | --- | --- | | Non-manifold edges | 0 | 0 | | Loose verts / edges | 0 / 0 | 0 / 0 | | Doubles merged at 1e-5 | 0 | 0 | | Zero-area faces | 0 | 0 | | N-gons | 0 | 0 | | Coplanar disjoint face pairs | 0 | 0 | | Grounded: <code>zmin</code> | within 1e-4 of 0 | 0.0000 | | Named supports: 16 staves | each <code>zmin</code> ≤ 0.001 | 16, stave_z 0.00000 | | Body plan | 0.621 m long × 0.180 m high ± 0.05 | 0.6210 × 0.1800 |</p>
<div class="table-wrap"><table><thead><tr><th scope="col">Axis</th><th scope="col">Declared</th><th scope="col">Measured (all three)</th></tr></thead><tbody><tr><td>Non-manifold edges</td><td>0</td><td>0</td></tr><tr><td>Loose verts / edges</td><td>0 / 0</td><td>0 / 0</td></tr><tr><td>Doubles merged at 1e-5</td><td>0</td><td>0</td></tr><tr><td>Zero-area faces</td><td>0</td><td>0</td></tr><tr><td>N-gons</td><td>0</td><td>0</td></tr><tr><td>Coplanar disjoint face pairs</td><td>0</td><td>0</td></tr><tr><td>Grounded: <code>zmin</code></td><td>within 1e-4 of 0</td><td>0.0000</td></tr><tr><td>Named supports: 16 staves</td><td>each <code>zmin</code> ≤ 0.001</td><td>16, stave_z 0.00000</td></tr><tr><td>Body plan</td><td>0.621 m long × 0.180 m high ± 0.05</td><td>0.6210 × 0.1800</td></tr></tbody></table></div>
<h3>Joint fit and seat</h3>
<p>| Axis | Declared | Measured (all three) | | --- | --- | --- | | Foot-on-head BVH gap | ≤ 0.006 m | 0.00300 | | Hoop bite (host r − inner hoop r) | 0.0012–0.008 m | 0.00300 |</p>
<div class="table-wrap"><table><thead><tr><th scope="col">Axis</th><th scope="col">Declared</th><th scope="col">Measured (all three)</th></tr></thead><tbody><tr><td>Foot-on-head BVH gap</td><td>≤ 0.006 m</td><td>0.00300</td></tr><tr><td>Hoop bite (host r − inner hoop r)</td><td>0.0012–0.008 m</td><td>0.00300</td></tr></tbody></table></div>
<h3>Falsifiers</h3>
<p>Each violates one named budget. All six were run on 4.5.11, 5.1.2 and 5.2.1 and returned the same code on each.</p>
<p>| Flag | Budget violated | Exit | | --- | --- | --- | | <code>--skip-decimate</code> | LOD1 ratio band | 9 | | <code>--stray-vert</code> | loose vertex count is 0 | 15 | | <code>--lift-z</code> | bounding box <code>zmin</code> is 0 | 16 | | <code>--short-staves</code> | named stave supports at Z=0 | 16 | | <code>--float-anvil</code> | foot-on-head gap | 17 | | <code>--round-band</code> | hoop bite band | 18 |</p>
<div class="table-wrap"><table><thead><tr><th scope="col">Flag</th><th scope="col">Budget violated</th><th scope="col">Exit</th></tr></thead><tbody><tr><td><code>--skip-decimate</code></td><td>LOD1 ratio band</td><td>9</td></tr><tr><td><code>--stray-vert</code></td><td>loose vertex count is 0</td><td>15</td></tr><tr><td><code>--lift-z</code></td><td>bounding box <code>zmin</code> is 0</td><td>16</td></tr><tr><td><code>--short-staves</code></td><td>named stave supports at Z=0</td><td>16</td></tr><tr><td><code>--float-anvil</code></td><td>foot-on-head gap</td><td>17</td></tr><tr><td><code>--round-band</code></td><td>hoop bite band</td><td>18</td></tr></tbody></table></div>
<h2>Run</h2>
<pre><code>blender --background --python anvil.py --
blender --background --python anvil.py -- --skip-decimate
Expand All @@ -288,7 +293,7 @@ <h2>Run</h2>
<p>Smoke passes no flags.</p>
<h2>Exit codes</h2>
<p>File-local. <code>9</code> is a valid check code. <code>10</code> is reserved for <code>gallery_framing.check_framing</code> on the <code>--output</code> path. <code>15</code>–<code>19</code> are the hygiene and joint-fit family.</p>
<p>| Code | Meaning | | --- | --- | | 0 | Success | | 1 | Uncaught exception (FATAL wrapper) | | 2 | argparse / usage | | 3 | Mesh did not build / no UV layer | | 4 | Base triangle count outside range | | 5 | Material count ≠ 2 distinct slots, or a face-count floor missed | | 6 | UVs outside 0..1 | | 7 | UV AABB overlap above tolerance | | 8 | World AABB off declared outer size | | 9 | LOD ratio band (<code>--skip-decimate</code> lands here) | | 10 | Framing gate (render path only) | | 11 | Collider triangle count above ceiling | | 12 | Bake did not finish or image has no data | | 13 | Export file missing or empty | | 14 | <code>--output</code> produced no file | | 15 | Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight | | 16 | Not grounded: bounding box <code>zmin</code> off 0, or a named stave floats | | 17 | Joint fit: foot-on-head gap (<code>--float-anvil</code>) | | 18 | Seat: hoop bite band (<code>--round-band</code>) | | 19 | Body length or height off the stated real-world size |</p>
<div class="table-wrap"><table><thead><tr><th scope="col">Code</th><th scope="col">Meaning</th></tr></thead><tbody><tr><td>0</td><td>Success</td></tr><tr><td>1</td><td>Uncaught exception (FATAL wrapper)</td></tr><tr><td>2</td><td>argparse / usage</td></tr><tr><td>3</td><td>Mesh did not build / no UV layer</td></tr><tr><td>4</td><td>Base triangle count outside range</td></tr><tr><td>5</td><td>Material count ≠ 2 distinct slots, or a face-count floor missed</td></tr><tr><td>6</td><td>UVs outside 0..1</td></tr><tr><td>7</td><td>UV AABB overlap above tolerance</td></tr><tr><td>8</td><td>World AABB off declared outer size</td></tr><tr><td>9</td><td>LOD ratio band (<code>--skip-decimate</code> lands here)</td></tr><tr><td>10</td><td>Framing gate (render path only)</td></tr><tr><td>11</td><td>Collider triangle count above ceiling</td></tr><tr><td>12</td><td>Bake did not finish or image has no data</td></tr><tr><td>13</td><td>Export file missing or empty</td></tr><tr><td>14</td><td><code>--output</code> produced no file</td></tr><tr><td>15</td><td>Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight</td></tr><tr><td>16</td><td>Not grounded: bounding box <code>zmin</code> off 0, or a named stave floats</td></tr><tr><td>17</td><td>Joint fit: foot-on-head gap (<code>--float-anvil</code>)</td></tr><tr><td>18</td><td>Seat: hoop bite band (<code>--round-band</code>)</td></tr><tr><td>19</td><td>Body length or height off the stated real-world size</td></tr></tbody></table></div>
</section>
<section class="detail-section src">
<h2>Source</h2>
Expand Down
11 changes: 8 additions & 3 deletions docs/gallery/armature-bend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,13 @@
.md h1, .md h2, .md h3 { letter-spacing: -0.01em; margin: 1.4rem 0 0.6rem; line-height: 1.25; }
.md h1 { font-size: 1.35rem; } .md h2 { font-size: 1.15rem; } .md h3 { font-size: 1rem; }
.md p { margin: 0.7rem 0; }
.md ul { margin: 0.7rem 0 0.7rem 1.4rem; }
.md ul, .md ol { margin: 0.7rem 0 0.7rem 1.4rem; }
.md li { margin: 0.3rem 0; }
.md .table-wrap { overflow-x: auto; margin: 0.9rem 0; }
.md table { border-collapse: collapse; font-size: 0.86rem; min-width: 100%; }
.md th, .md td { text-align: left; vertical-align: top; padding: 0.4rem 0.75rem 0.4rem 0;
border-bottom: 1px solid var(--border); }
.md th { color: var(--text-dim); font-weight: 600; white-space: nowrap; }
.md code { background: var(--surface-2); border: 1px solid var(--border); padding: 0.08rem 0.35rem;
border-radius: 4px; font-family: var(--font-mono); font-size: 0.84em; }
.md pre { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
Expand Down Expand Up @@ -261,7 +266,7 @@ <h1>armature-bend</h1>
<section class="detail-section md">
<p>A runnable example that rigs a tapered, segmented tube with a four-bone armature chain — <code>edit_bones</code> construction, name-bound vertex groups with smoothstep blend zones, a posed curl — and checks the depsgraph-evaluated result against closed-form linear blend skinning, following <a href="https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/skills/mesh-editing-and-bmesh/SKILL.md"><code>mesh-editing-and-bmesh</code></a> and <a href="https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/skills/depsgraph-and-evaluated-data/SKILL.md"><code>depsgraph-and-evaluated-data</code></a>.</p>
<p><strong>What it witnesses:</strong> the three contracts AI-generated rigging code most often gets wrong.</p>
<p>1. <code>edit_bones</code> only exists in edit mode — the collection is asserted empty in object mode and holding the full chain (heads/tails at closed-form positions) inside <code>mode_set(mode=&#x27;EDIT&#x27;)</code>. Outside edit mode, reads silently return nothing. 2. Vertex groups bind to bones <strong>by name</strong>; a typo deforms nothing without erroring. Every group here is named after its bone and the deform proves the binding. 3. The armature modifier is exactly linear blend skinning: for *every* vertex, <code>evaluated == Σ wᵢ · (pose_bone.matrix @ bone.matrix_local.inverted()) @ rest</code>. The check re-implements LBS from the pose matrices and compares the whole evaluated mesh (max error ~5e-7). The root ring must stay pinned and the tip must deflect — a straight tube is a failure.</p>
<ol><li><code>edit_bones</code> only exists in edit mode — the collection is asserted empty in object mode and holding the full chain (heads/tails at closed-form positions) inside <code>mode_set(mode=&#x27;EDIT&#x27;)</code>. Outside edit mode, reads silently return nothing.</li><li>Vertex groups bind to bones <strong>by name</strong>; a typo deforms nothing without erroring. Every group here is named after its bone and the deform proves the binding.</li><li>The armature modifier is exactly linear blend skinning: for <em>every</em> vertex, <code>evaluated == Σ wᵢ · (pose_bone.matrix @ bone.matrix_local.inverted()) @ rest</code>. The check re-implements LBS from the pose matrices and compares the whole evaluated mesh (max error ~5e-7). The root ring must stay pinned and the tip must deflect — a straight tube is a failure.</li></ol>
<p>The armature API is identical on Blender 4.5 LTS and 5.1 — no version gate needed. One portability hazard is baked in as a comment: interleaving <code>color_attributes</code> writes with <code>VertexGroup.add()</code> dangles the attribute reference when the deform layer is allocated (hard crash on 4.5, silent luck on 5.1), so the script finishes all weight writes before creating the color attribute.</p>
<p>The render shows rest → half curl → full curl left to right, with per-bone weight bands visualized through a <code>BoneTint</code> color attribute — the smooth color blends at the joints are the same weights the LBS check asserts.</p>
<h2>Run</h2>
Expand All @@ -276,7 +281,7 @@ <h2>Run</h2>
blender --background --python armature_bend.py -- --output bend.png --engine cycles</code></pre>
<h2>Exit codes</h2>
<p>Per-script sequential checks. <code>9</code> is a valid check code; there is no rule against it.</p>
<p>| Code | Meaning | | --- | --- | | 0 | Success | | 1 | Uncaught exception (FATAL wrapper) | | 2 | argparse / usage | | 3 | <code>edit_bones</code> populated in object mode | | 4 | Edit-mode bone chain off closed form | | 5 | Evaluated vertex count changed | | 6 | Evaluated mesh off closed-form LBS | | 7 | Root ring moved | | 8 | Tip did not deflect (<code>--zero-curl</code> lands here) | | 9 | <code>--output</code> produced no file |</p>
<div class="table-wrap"><table><thead><tr><th scope="col">Code</th><th scope="col">Meaning</th></tr></thead><tbody><tr><td>0</td><td>Success</td></tr><tr><td>1</td><td>Uncaught exception (FATAL wrapper)</td></tr><tr><td>2</td><td>argparse / usage</td></tr><tr><td>3</td><td><code>edit_bones</code> populated in object mode</td></tr><tr><td>4</td><td>Edit-mode bone chain off closed form</td></tr><tr><td>5</td><td>Evaluated vertex count changed</td></tr><tr><td>6</td><td>Evaluated mesh off closed-form LBS</td></tr><tr><td>7</td><td>Root ring moved</td></tr><tr><td>8</td><td>Tip did not deflect (<code>--zero-curl</code> lands here)</td></tr><tr><td>9</td><td><code>--output</code> produced no file</td></tr></tbody></table></div>
<p>The <code>blender-smoke</code> workflow runs the check on Blender 5.2 LTS and 4.5 LTS (5.1 on the weekly cron, the <code>needs-5.1</code> PR label, or manual dispatch). Smoke does not pass <code>--output</code> or <code>--zero-curl</code>.</p>
</section>
<section class="detail-section src">
Expand Down
Loading
Loading