Skip to content

Commit a09254c

Browse files
fix(showcase): street-lantern and water-trough visual quality pass (#181)
* fix(showcase): street-lantern visual quality pass Seat the hanger on a closed square pyramid and lock brace/hanger contact as BVH budgets so a welded cone stack cannot regress. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * fix(showcase): water-trough visual quality pass Rebuild the hull as U-staves and U-caps on one radius so box-slab ends and through-leg stretchers cannot pass. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * docs(showcase): designed-overlap hygiene convention Record coplanar-vs-weld seating so future pieces inherit a named overlap or rebate instead of coincident faces. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> --------- Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 18c83df commit a09254c

14 files changed

Lines changed: 2645 additions & 662 deletions

File tree

-790 Bytes
Loading
5.25 KB
Loading

docs/gallery/grindstone/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ <h2>Source</h2>
10221022
<span class="k">for</span> p <span class="k">in</span> me.polygons:
10231023
<span class="k">if</span> all(i <span class="k">in</span> member <span class="k">for</span> i <span class="k">in</span> p.vertices):
10241024
<span class="k">return</span> p.material_index
1025-
<span class="k">return</span> -<span class="n">1</span>
1025+
<span class="k">return</span> <span class="k">None</span>
10261026

10271027

10281028
<span class="k">def</span> support_audit(me):

docs/gallery/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ <h2><a href="market-stall/">market-stall</a></h2>
947947
<div class="card-body">
948948
<h2><a href="street-lantern/">street-lantern</a></h2>
949949
<p class="teaches">A procedural hanging street lantern through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
950-
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 3520 tris, three materials with 24 glass and 94 brass faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.403×0.892×1.404 m, LOD ratios in band, convex collider 84 tris, non-empty glTF. --skip-decimate exits 9 on the LOD1 ratio budget.</p>
950+
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 3338 tris, three materials with 1530 metal, 24 glass and 209 brass faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.300×0.786×1.287 m, zmin 0, hygiene 0, brace BVH gap 0, hanger-roof gap −1 mm, post 0.100×1.120 m plumb 0, LOD ratios in band (5.2 COLLAPSE 2 tris leaner on LOD2), convex collider 78 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19.</p>
951951
<a class="card-link" href="street-lantern/">View example <span aria-hidden="true">&rarr;</span></a>
952952
</div>
953953
</article>
@@ -1046,7 +1046,7 @@ <h2><a href="anvil/">anvil</a></h2>
10461046
<div class="card-body">
10471047
<h2><a href="water-trough/">water-trough</a></h2>
10481048
<p class="teaches">A procedural watertight water trough through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
1049-
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 2484 tris, three materials with 192 metal and 6 water faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.152×0.568×0.509 m, LOD ratios in band (5.2 COLLAPSE 8 tris leaner on LOD2), convex collider 32 tris, non-empty glTF. --skip-decimate exits 9 on the LOD1 ratio budget.</p>
1049+
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 3700 tris, three materials with 1674 wood, 156 metal and 29 water faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.093×0.552×0.504 m, zmin 0, four shoes planted, U end-cap rim span 5 mm, strap BVH gap 0, water-hull gap 2.6 mm, hull 1.045×0.466 m, LOD ratios in band, convex collider 64 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --box-ends 17; --float-strap 18; --narrow-hull 19.</p>
10501050
<a class="card-link" href="water-trough/">View example <span aria-hidden="true">&rarr;</span></a>
10511051
</div>
10521052
</article>

docs/gallery/street-lantern/index.html

Lines changed: 650 additions & 182 deletions
Large diffs are not rendered by default.

docs/gallery/water-trough/index.html

Lines changed: 605 additions & 137 deletions
Large diffs are not rendered by default.

showcase/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ entry in `showcase/gallery.json`, and a rendered still.
5050
flat fan cap are coplanar and close-centred by construction, and
5151
counting those makes the budget unsatisfiable rather than meaningful.
5252
Multi-body props do **not** require Euler characteristic 2 — that is a
53-
single-shell contract. Pairs of parts meant to touch assert a BVH
53+
single-shell contract. Two boxes that share a coplanar face z-fight;
54+
two that share a vertex weld into one shell. Seat a joint with a named
55+
overlap or rebate computed from the host (a cage post into its rail, a
56+
glass pane behind its muntin, a plinth step into its base) rather than
57+
hoping the numbers happen not to coincide. A hang-station versus
58+
arm-station split lets a contact falsifier move one member without
59+
dragging the rest of the assembly. Pairs of parts meant to touch assert a BVH
5460
surface gap below a named epsilon (vert-vert is the wrong metric for
5561
thin straps and collars). A spanning board whose only vertices sit at
5662
the far ends will report a false gap to a mid-span knuckle; put a

showcase/gallery.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"name": "street-lantern",
7070
"dir": "showcase/street-lantern",
7171
"teaches": "A procedural hanging street lantern through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.",
72-
"witnessesFix": "Recomputed: 3520 tris, three materials with 24 glass and 94 brass faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.403×0.892×1.404 m, LOD ratios in band, convex collider 84 tris, non-empty glTF. --skip-decimate exits 9 on the LOD1 ratio budget.",
72+
"witnessesFix": "Recomputed: 3338 tris, three materials with 1530 metal, 24 glass and 209 brass faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.300×0.786×1.287 m, zmin 0, hygiene 0, brace BVH gap 0, hanger-roof gap −1 mm, post 0.100×1.120 m plumb 0, LOD ratios in band (5.2 COLLAPSE 2 tris leaner on LOD2), convex collider 78 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19.",
7373
"hero": "docs/gallery/assets/street-lantern-hero.webp",
7474
"preview": "showcase/street-lantern/preview.webp",
7575
"tags": [
@@ -177,7 +177,7 @@
177177
"name": "water-trough",
178178
"dir": "showcase/water-trough",
179179
"teaches": "A procedural watertight water trough through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.",
180-
"witnessesFix": "Recomputed: 2484 tris, three materials with 192 metal and 6 water faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.152×0.568×0.509 m, LOD ratios in band (5.2 COLLAPSE 8 tris leaner on LOD2), convex collider 32 tris, non-empty glTF. --skip-decimate exits 9 on the LOD1 ratio budget.",
180+
"witnessesFix": "Recomputed: 3700 tris, three materials with 1674 wood, 156 metal and 29 water faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.093×0.552×0.504 m, zmin 0, four shoes planted, U end-cap rim span 5 mm, strap BVH gap 0, water-hull gap 2.6 mm, hull 1.045×0.466 m, LOD ratios in band, convex collider 64 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --box-ends 17; --float-strap 18; --narrow-hull 19.",
181181
"hero": "docs/gallery/assets/water-trough-hero.webp",
182182
"preview": "showcase/water-trough/preview.webp",
183183
"tags": [

showcase/street-lantern/README.md

Lines changed: 88 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,17 @@
22

33
A showcase piece, not an example. Procedural hanging street lantern
44
(stepped iron foot, tapered octagonal post, brass collars, braced arm,
5-
muntined cage with amber panes, pyramidal brass roof and finial) then
6-
the shipped pipeline: unique-cell UVs, Cycles high-to-low normal bake,
7-
LOD chain, convex collider, Unity glTF export.
5+
muntined cage with amber panes, square pyramidal brass roof and finial)
6+
then the shipped pipeline: unique-cell UVs, Cycles high-to-low normal
7+
bake, LOD chain, convex collider, Unity glTF export.
8+
9+
The arm axis, drop length, and roof stack are one closed-form chain: the
10+
roof peak stays below the arm, the hanger is the arm's far station, and
11+
the brace is an oriented box between a post-radius station and an arm
12+
station. The square pyramid is lofted on the cage axes, not a 4-gon cone.
13+
Cage posts and rails share a named overlap (`CAGE_JOINT`); glass sits
14+
behind the muntins by `PANE_REBATE`. Collars and the arm root evaluate
15+
`post_radius_at(z)`.
816

917
It asserts **budget conformance** of the generated result. It does not
1018
witness an API contract. "It rendered without error" is not a check.
@@ -14,6 +22,12 @@ witness an API contract. "It rendered without error" is not a check.
1422
`bake_normal_high_to_low.py`, `setup_bake_target_image.py`,
1523
`lod_chain.py` / `decimate_to_budget.py`, `convex_hull_collider.py`,
1624
`export_preset_unity.py` (helpers copied, not imported as a package).
25+
Hygiene combinatorics match `examples/mesh-hygiene-audit` (copied, not
26+
imported).
27+
28+
Intended size: 0.30 m square foot, 1.12 m octagonal post (0.10 m across
29+
at the base), 0.50 m arm, 0.24 × 0.30 m cage; outer AABB
30+
0.300 × 0.786 × 1.287 m.
1731

1832
## Budgets
1933

@@ -22,38 +36,87 @@ materials, UVs, evaluated LOD, collider, or export file.
2236

2337
| Axis | Declared | Measured (4.5.11 / 5.1.2 / 5.2.1) |
2438
| --- | --- | --- |
25-
| Base triangles | 3400–3650 | 3520 / 3520 / 3520 |
26-
| LOD1 ratio | 0.32–0.62 of base | 0.5000 / 0.5000 / 0.5000 |
27-
| LOD2 ratio | 0.10–0.35 of base | 0.2199 / 0.2199 / 0.2199 |
28-
| Materials | exactly 3 distinct, ≥8 glass faces, ≥8 brass faces | 3 slots, 24 glass, 94 brass |
39+
| Base triangles | 3000–3800 | 3338 / 3338 / 3338 |
40+
| LOD1 ratio | 0.32–0.62 of base | 0.4997 / 0.4997 / 0.4997 |
41+
| LOD2 ratio | 0.10–0.35 of base | 0.2199 / 0.2199 / 0.2193 |
42+
| Materials | exactly 3 distinct; ≥200 metal, ≥8 glass, ≥24 brass | 3 slots; 1530 / 24 / 209 |
2943
| UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 |
30-
| Outer AABB | (0.403, 0.892, 1.404) m ± 0.01 | (0.4032, 0.8916, 1.4041), zmin 0 |
31-
| Collider tris | ≤ 110 | 84 |
32-
| Export | written, size > 0 | 254552 / 254552 / 254536 bytes |
44+
| Outer AABB | (0.300, 0.786, 1.287) m ± 0.01 | (0.3000, 0.7860, 1.2874), zmin 0 |
45+
| Collider tris | ≤ 120 | 78 |
46+
| Export | written, size > 0 | 250980 / 250980 / 250964 bytes |
47+
48+
Base triangles dropped from **3520 to 3338** in the quality pass: the
49+
open 4-gon cone roof became a closed square pyramid, cage crossings
50+
stopped sharing vertices, and a pane rebate replaced coplanar glass.
51+
52+
DECIMATE COLLAPSE triangle counts are **not** identical across series —
53+
5.2.1 is 2 tris leaner on LOD2. The gate is a ratio band, not an exact
54+
count. Bake pixels are stochastic; the gate is `has_data` plus operator
55+
`FINISHED`, not byte-identity. Construction uses no RNG. Export byte
56+
counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.
57+
58+
### Hygiene
59+
60+
Recomputed from the generated mesh, not asserted about the script.
61+
62+
| Axis | Declared | Measured (all three) |
63+
| --- | --- | --- |
64+
| Non-manifold edges | 0 | 0 |
65+
| Loose verts / edges | 0 / 0 | 0 / 0 |
66+
| Doubles merged at 1e-5 | 0 | 0 |
67+
| Zero-area faces | 0 | 0 |
68+
| N-gons | 0 | 0 |
69+
| Coplanar disjoint face pairs | 0 | 0 |
70+
| Grounded: `zmin` | within 1e-4 of 0 | 0.0000 |
71+
| Post plan | 0.100 m across × 1.120 m high ± (0.02, 0.04) | 0.1000 × 1.1200 |
72+
| Post plumb (top vs bottom XY) | ≤ 0.008 m | 0.00000 |
73+
74+
### Joint fit and seat
75+
76+
| Axis | Declared | Measured (all three) |
77+
| --- | --- | --- |
78+
| Brace-to-arm BVH gap | ≤ 0.006 m | 0.00000 |
79+
| Arm underside vs roof peak | ≥ 0.008 m clearance | 0.05300 |
80+
| Hanger-to-roof BVH gap | ≤ 0.004 m | −0.00100 |
3381

34-
DECIMATE COLLAPSE triangle counts are **not** guaranteed identical across
35-
series — the gate is a ratio band, not an exact count. This mesh happened
36-
to match on 4.5.11 / 5.1.2 / 5.2.1. Bake pixels are stochastic; the gate
37-
is `has_data` plus operator `FINISHED`, not byte-identity. Construction
38-
uses no RNG. glTF byte size differs by a few bytes across series.
82+
### Falsifiers
83+
84+
Each violates one named budget. All six were run on 4.5.11, 5.1.2 and
85+
5.2.1 and returned the same code on each.
86+
87+
| Flag | Budget violated | Exit |
88+
| --- | --- | --- |
89+
| `--skip-decimate` | LOD1 ratio band | 9 |
90+
| `--stray-vert` | loose vertex count is 0 | 15 |
91+
| `--lift-z` | bounding box `zmin` is 0 | 16 |
92+
| `--float-brace` | brace-to-arm BVH gap | 17 |
93+
| `--sink-arm` | arm-over-roof clearance | 18 |
94+
| `--rake-post` | post plumb | 19 |
3995

40-
`--skip-decimate` skips the LOD DECIMATE stage so LOD1 ratio is 1.0 and
41-
exit 9 fires. That is the named budget the falsifier violates.
96+
`--sink-arm` lowers only the arm. Hang-station `hang_z` stays at post
97+
top so the cage does not follow, which is what lets the clearance budget
98+
fire.
4299

43100
## Run
44101

45102
```bash
46103
blender --background --python street_lantern.py --
47104
blender --background --python street_lantern.py -- --skip-decimate
105+
blender --background --python street_lantern.py -- --stray-vert
106+
blender --background --python street_lantern.py -- --lift-z
107+
blender --background --python street_lantern.py -- --float-brace
108+
blender --background --python street_lantern.py -- --sink-arm
109+
blender --background --python street_lantern.py -- --rake-post
48110
blender --background --python street_lantern.py -- --output lantern.png
49111
```
50112

51-
Smoke does not pass `--output` or `--skip-decimate`.
113+
Smoke passes no flags.
52114

53115
## Exit codes
54116

55117
File-local. `9` is a valid check code. `10` is reserved for
56-
`gallery_framing.check_framing` on the `--output` path.
118+
`gallery_framing.check_framing` on the `--output` path. `15``19` are the
119+
hygiene and joint-fit family.
57120

58121
| Code | Meaning |
59122
| --- | --- |
@@ -62,7 +125,7 @@ File-local. `9` is a valid check code. `10` is reserved for
62125
| 2 | argparse / usage |
63126
| 3 | Mesh did not build / no UV layer |
64127
| 4 | Base triangle count outside range |
65-
| 5 | Material count ≠ 3 distinct slots, or glass/brass faces missing |
128+
| 5 | Material count ≠ 3 distinct slots, or a face-count floor missed |
66129
| 6 | UVs outside 0..1 |
67130
| 7 | UV AABB overlap above tolerance |
68131
| 8 | World AABB off declared outer size |
@@ -72,3 +135,8 @@ File-local. `9` is a valid check code. `10` is reserved for
72135
| 12 | Bake did not finish or image has no data |
73136
| 13 | Export file missing or empty |
74137
| 14 | `--output` produced no file |
138+
| 15 | Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight |
139+
| 16 | Not grounded: bounding box `zmin` off 0 |
140+
| 17 | Joint fit: brace-to-arm gap (`--float-brace`) |
141+
| 18 | Seat: arm-roof clearance or hanger-roof gap (`--sink-arm`) |
142+
| 19 | Post plumb or post size off the stated real-world size (`--rake-post`) |
3.11 KB
Loading

0 commit comments

Comments
 (0)