Skip to content

Commit 2b6f401

Browse files
fix(showcase): hitching post visual quality pass
Hang the rings through eyes under one rail and seat the post in a closed shoe, with centerline and cup budgets so a clipped torus cannot pass again. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 3bc587f commit 2b6f401

7 files changed

Lines changed: 1081 additions & 275 deletions

File tree

7.25 KB
Loading

‎docs/gallery/hitching-post/index.html‎

Lines changed: 519 additions & 125 deletions
Large diffs are not rendered by default.

‎docs/gallery/index.html‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,12 +1052,12 @@ <h2><a href="water-trough/">water-trough</a></h2>
10521052
</article>
10531053
<article class="card" data-tags="mesh export showcase">
10541054
<a class="card-media" href="hitching-post/" aria-label="hitching-post example detail page">
1055-
<img src="assets/hitching-post-hero.webp" alt="hitching-post — A procedural hitching post (corner-aligned cap, stub-and-tenon arm, collar shoe, eye-threaded rings) through UVs, bake, LOD, collider, and Unity glTF…" loading="lazy" decoding="async" />
1055+
<img src="assets/hitching-post-hero.webp" alt="hitching-post — A procedural hitching post (eaved cap, one rail, cup shoe, rings hung through eyes) through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed…" loading="lazy" decoding="async" />
10561056
</a>
10571057
<div class="card-body">
10581058
<h2><a href="hitching-post/">hitching-post</a></h2>
1059-
<p class="teaches">A procedural hitching post (corner-aligned cap, stub-and-tenon arm, collar shoe, eye-threaded rings) through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
1060-
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 1598 tris, two materials with 269 wood and 532 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.460×0.191×1.258 m, zmin 0, hygiene 0, wood-metal BVH gap 0.45 mm, LOD ratios in band, convex collider 78 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --lift-z exits 16 on grounded zmin.</p>
1059+
<p class="teaches">A procedural hitching post (eaved cap, one rail, cup shoe, rings hung through eyes) through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
1060+
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 1680 tris, two materials with 114 wood and 742 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.500×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, LOD ratios in band, convex collider 80 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring exits 18; --short-post exits 19.</p>
10611061
<a class="card-link" href="hitching-post/">View example <span aria-hidden="true">&rarr;</span></a>
10621062
</div>
10631063
</article>
@@ -1151,12 +1151,12 @@ <h2><a href="iron-cauldron/">iron-cauldron</a></h2>
11511151
</article>
11521152
<article class="card" data-tags="mesh export showcase">
11531153
<a class="card-media" href="wooden-ladder/" aria-label="wooden-ladder example detail page">
1154-
<img src="assets/wooden-ladder-hero.webp" alt="wooden-ladder — A procedural timber ladder with raked stiles, six dowel rungs tenoned into the stiles, and iron shoes and top caps through UVs, bake, LOD, collider, and Unity…" loading="lazy" decoding="async" />
1154+
<img src="assets/wooden-ladder-hero.webp" alt="wooden-ladder — A procedural timber ladder with raked tapered stiles, six turned rungs, ferrule caps, and level shoe plates through UVs, bake, LOD, collider, and Unity glTF…" loading="lazy" decoding="async" />
11551155
</a>
11561156
<div class="card-body">
11571157
<h2><a href="wooden-ladder/">wooden-ladder</a></h2>
1158-
<p class="teaches">A procedural timber ladder with raked stiles, six dowel rungs tenoned into the stiles, and iron shoes and top caps through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
1159-
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 936 tris, two materials with 324 wood and 216 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.472×0.365×1.460 m, grounded at zmin 0, mesh hygiene all zero, 12 shells with every rung clearing the stile chamfer by 3.61 mm, convex collider 24 tris, non-empty glTF. Four falsifiers exit 9, 15, 16, and 17 on the LOD, hygiene, grounded, and joint-fit budgets.</p>
1158+
<p class="teaches">A procedural timber ladder with raked tapered stiles, six turned rungs, ferrule caps, and level shoe plates through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
1159+
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 2536 tris, two materials with 612 wood and 736 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.490×0.376×1.487 m, zmin 0, hygiene and coplanar pairs 0, tenon clearance 8 mm, shoe bite 20 mm, LOD ratios in band, convex collider 24 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --fat-rungs exits 17; --short-stile exits 18.</p>
11601160
<a class="card-link" href="wooden-ladder/">View example <span aria-hidden="true">&rarr;</span></a>
11611161
</div>
11621162
</article>

‎showcase/gallery.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@
188188
{
189189
"name": "hitching-post",
190190
"dir": "showcase/hitching-post",
191-
"teaches": "A procedural hitching post (corner-aligned cap, stub-and-tenon arm, collar shoe, eye-threaded rings) through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.",
192-
"witnessesFix": "Recomputed: 1598 tris, two materials with 269 wood and 532 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.460×0.191×1.258 m, zmin 0, hygiene 0, wood-metal BVH gap 0.45 mm, LOD ratios in band, convex collider 78 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --lift-z exits 16 on grounded zmin.",
191+
"teaches": "A procedural hitching post (eaved cap, one rail, cup shoe, rings hung through eyes) through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.",
192+
"witnessesFix": "Recomputed: 1680 tris, two materials with 114 wood and 742 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.500×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, LOD ratios in band, convex collider 80 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring exits 18; --short-post exits 19.",
193193
"hero": "docs/gallery/assets/hitching-post-hero.webp",
194194
"preview": "showcase/hitching-post/preview.webp",
195195
"tags": [
@@ -296,8 +296,8 @@
296296
{
297297
"name": "wooden-ladder",
298298
"dir": "showcase/wooden-ladder",
299-
"teaches": "A procedural timber ladder with raked stiles, six dowel rungs tenoned into the stiles, and iron shoes and top caps through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.",
300-
"witnessesFix": "Recomputed: 936 tris, two materials with 324 wood and 216 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.472×0.365×1.460 m, grounded at zmin 0, mesh hygiene all zero, 12 shells with every rung clearing the stile chamfer by 3.61 mm, convex collider 24 tris, non-empty glTF. Four falsifiers exit 9, 15, 16, and 17 on the LOD, hygiene, grounded, and joint-fit budgets.",
299+
"teaches": "A procedural timber ladder with raked tapered stiles, six turned rungs, ferrule caps, and level shoe plates through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.",
300+
"witnessesFix": "Recomputed: 2536 tris, two materials with 612 wood and 736 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.490×0.376×1.487 m, zmin 0, hygiene and coplanar pairs 0, tenon clearance 8 mm, shoe bite 20 mm, LOD ratios in band, convex collider 24 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --fat-rungs exits 17; --short-stile exits 18.",
301301
"hero": "docs/gallery/assets/wooden-ladder-hero.webp",
302302
"preview": "showcase/wooden-ladder/preview.webp",
303303
"tags": [

‎showcase/hitching-post/README.md‎

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
# Hitching post
22

3-
A showcase piece, not an example. Procedural timber hitching post
4-
(square post, pyramid cap on the post corners, stub-and-tenon
5-
cross-arm, iron collar shoe and bands, eye-threaded hitching rings)
6-
then the shipped pipeline: unique-cell UVs, Cycles high-to-low normal
7-
bake, LOD chain, convex collider, Unity glTF export.
3+
A showcase piece, not an example. Procedural timber hitching post: a
4+
125 mm square post seated in a closed iron shoe, one cross-rail through
5+
the post, a pyramidal cap with eaves, and two rings hung through eyes
6+
under the rail. Then the shipped pipeline: unique-cell UVs, Cycles
7+
high-to-low normal bake, LOD chain, convex collider, Unity glTF export.
88

99
It asserts **budget conformance** of the generated result. It does not
1010
witness an API contract. "It rendered without error" is not a check.
1111

12+
Intended size: post 0.125 m square and 1.16 m of timber, cap 0.096 m,
13+
cross-rail 0.50 m. Outer AABB 0.500 × 0.149 × 1.246 m.
14+
1215
**Composes** skills `mesh-editing-and-bmesh`, `bake-high-to-low`,
1316
`depsgraph-and-evaluated-data`, `engine-export-presets`, and snippets
1417
`bake_normal_high_to_low.py`, `setup_bake_target_image.py`,
1518
`lod_chain.py` / `decimate_to_budget.py`, `convex_hull_collider.py`,
1619
`export_preset_unity.py` (helpers copied, not imported as a package).
1720
Hygiene combinatorics match `examples/mesh-hygiene-audit` (copied, not
18-
imported).
19-
20-
Intended size: 0.125 m square post, 1.16 m timber plus 0.10 m cap;
21-
cross-arm 0.46 m; outer AABB 0.460 × 0.191 × 1.258 m.
21+
imported). Coplanar-pair counting matches `showcase/signpost`.
2222

2323
## Budgets
2424

@@ -27,39 +27,62 @@ materials, UVs, evaluated LOD, collider, or export file.
2727

2828
| Axis | Declared | Measured (4.5.11 / 5.1.2 / 5.2.1) |
2929
| --- | --- | --- |
30-
| Base triangles | 900–1800 | 1598 / 1598 / 1598 |
31-
| LOD1 ratio | 0.32–0.62 of base | 0.4994 / 0.4994 / 0.4994 |
30+
| Base triangles | 1400–2400 | 1680 / 1680 / 1680 |
31+
| LOD1 ratio | 0.32–0.62 of base | 0.5000 / 0.5000 / 0.5000 |
3232
| LOD2 ratio | 0.10–0.35 of base | 0.2190 / 0.2190 / 0.2190 |
33-
| Materials | exactly 2 distinct, ≥12 wood, ≥24 metal | 2 slots, 269 wood, 532 metal |
33+
| Materials | exactly 2 distinct, ≥70 wood, ≥560 metal | 2 slots, 114 wood, 742 metal |
3434
| UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 |
35-
| Outer AABB | (0.460, 0.191, 1.258) m ± 0.01 | (0.4600, 0.1912, 1.2580) |
35+
| Outer AABB | (0.500, 0.149, 1.246) m ± 0.01 | (0.5000, 0.1490, 1.2460) |
3636
| Grounded zmin | within 1e-4 of 0 | 0 / 0 / 0 |
37-
| Hygiene | loose/nonman/zero-area/doubles/ngons = 0 | 0 / 0 / 0 |
38-
| Wood–metal gap | BVH surface < 0.008 m | 0.00045 / 0.00045 / 0.00045 |
39-
| Collider tris | ≤ 280 | 78 |
40-
| Export | written, size > 0 | 121496 / 121496 / 121480 bytes |
37+
| Hygiene | loose/nonman/zero-area/doubles/n-gons/coplanar pairs = 0 | all 0 |
38+
| Post seat | world zmin in (0.004, 0.014), XY centroid within 0.010 of origin, arm axis cos ≥ cos(0.5°) | 0.01000, 0, 1.000 |
39+
| Hung ring | centerline error ≤ 0.008 m, ring–wood overlap 0, eye–wood overlap 0, shank–ring overlap 0, shank bites the eye | 0, 0, 0, 0, 40 |
40+
| Shoe | each band overlaps the post, shoe overlaps the sole | band gap 0, sole–shoe 8 |
41+
| Wood–metal gap | BVH surface < 0.008 m | 0.00075 |
42+
| Collider tris | ≤ 280 | 80 |
43+
| Export | written, size > 0 | 127428 / 127428 / 127412 bytes |
44+
45+
Base triangles rose from **1598 to 1680**. The old rings were faceted
46+
tori clipped into the arm; the new eyes, shanks, and 24-segment hung
47+
rings replace that mesh. Cylinder caps are triangulated so the n-gon
48+
budget stays at 0.
4149

4250
DECIMATE COLLAPSE triangle counts are **not** identical across series —
43-
the gate is a ratio band, not an exact count. Bake pixels are
44-
stochastic; the gate is `has_data` plus operator `FINISHED`, not
45-
byte-identity. Construction uses no RNG. Export byte counts differ by
46-
16 B on 5.2.1 (glTF serializer), not a gated axis. Euler characteristic
47-
is 10 (multi-body: timber, collars, eyes, rings) — not gated to 2.
51+
the gate is a ratio band, not an exact count. On this mesh the three
52+
binaries agreed. Bake pixels are stochastic; the gate is `has_data`
53+
plus operator `FINISHED`, not byte-identity. Construction uses no RNG.
54+
Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a
55+
gated axis. Euler is 12 (six balls and seven tori) and is not gated to 2.
56+
57+
Each falsifier violates exactly one named budget. Proven on Blender
58+
4.5.11 LTS, 5.1.2, and 5.2.1 LTS (the binaries' own `--version`):
59+
60+
| Falsifier | Budget violated | Exit | Measured failure |
61+
| --- | --- | --- | --- |
62+
| `--skip-decimate` | LOD1 ratio band | 9 | ratio 1.0000 |
63+
| `--stray-vert` | Mesh hygiene, loose verts | 15 | `loose_v=1` |
64+
| `--twin-sole` | Coplanar face pairs | 15 | `zfight=6` |
65+
| `--lift-z` | Grounded zmin | 16 | zmin 0.050000 |
66+
| `--clip-ring` | Hung-ring centerline | 18 | ring_err 0.024, ring–wood overlap 32 |
67+
| `--short-post` | Seated post | 19 | post zmin 0.030 |
4868

49-
`--skip-decimate` skips the LOD DECIMATE stage so LOD1 ratio is 1.0 and
50-
exit 9 fires. `--lift-z` raises the mesh 5 cm so the grounded-zmin
51-
hygiene budget fails and exit 16 fires.
69+
Default exit is 0 on all three. `--clip-ring` also overlaps the rail;
70+
the centerline gate is the one that fires.
5271

5372
## Run
5473

5574
```bash
5675
blender --background --python hitching_post.py --
5776
blender --background --python hitching_post.py -- --skip-decimate
77+
blender --background --python hitching_post.py -- --stray-vert
78+
blender --background --python hitching_post.py -- --twin-sole
5879
blender --background --python hitching_post.py -- --lift-z
59-
blender --background --python hitching_post.py -- --output hitching-post.png
80+
blender --background --python hitching_post.py -- --clip-ring
81+
blender --background --python hitching_post.py -- --short-post
82+
blender --background --python hitching_post.py -- --output preview.webp --engine cycles
6083
```
6184

62-
Smoke does not pass `--output`, `--skip-decimate`, or `--lift-z`.
85+
Smoke does not pass `--output` or a falsifier.
6386

6487
## Exit codes
6588

@@ -83,6 +106,8 @@ File-local. `9` is a valid check code. `10` is reserved for
83106
| 12 | Bake did not finish or image has no data |
84107
| 13 | Export file missing or empty |
85108
| 14 | `--output` produced no file |
86-
| 15 | Hygiene: loose verts/edges, non-manifold, zero-area, doubles, or n-gons |
87-
| 16 | Grounded zmin (`--lift-z` lands here) |
109+
| 15 | Hygiene, including coplanar pairs (`--stray-vert`, `--twin-sole`) |
110+
| 16 | Grounded zmin (`--lift-z`) |
88111
| 17 | Wood–metal BVH gap above 8 mm |
112+
| 18 | Hung ring or shoe seat (`--clip-ring`) |
113+
| 19 | Post plumb, origin, and cup seat (`--short-post`) |

0 commit comments

Comments
 (0)