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
Binary file modified docs/gallery/assets/wooden-ladder-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/gallery/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1151,12 +1151,12 @@ <h2><a href="iron-cauldron/">iron-cauldron</a></h2>
</article>
<article class="card" data-tags="mesh export showcase">
<a class="card-media" href="wooden-ladder/" aria-label="wooden-ladder example detail page">
<img src="assets/wooden-ladder-hero.webp" alt="wooden-ladder — A procedural timber ladder with raked stiles, six rungs, and iron shoes through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather…" loading="lazy" decoding="async" />
<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" />
</a>
<div class="card-body">
<h2><a href="wooden-ladder/">wooden-ladder</a></h2>
<p class="teaches">A procedural timber ladder with raked stiles, six rungs, and iron shoes through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 2184 tris, two materials with 1008 wood and 48 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.474×0.361×1.482 m, LOD ratios in band, convex collider 52 tris, non-empty glTF. --skip-decimate exits 9 on the LOD1 ratio budget.</p>
<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>
<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>
<a class="card-link" href="wooden-ladder/">View example <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
Expand Down
441 changes: 373 additions & 68 deletions docs/gallery/wooden-ladder/index.html

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion showcase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ entry in `showcase/gallery.json`, and a rendered still.
- **Falsifier** breaks one pipeline stage so a **named** budget fails and
the piece exits its documented code. Prove default and falsifier on
4.5.11, 5.1.2, and 5.2.1. `--skip-decimate` is the LOD-ratio
falsifier (exit 9). `--lift-z` is the grounded-zmin falsifier (exit 16).
falsifier (exit 9), `--stray-vert` the mesh-hygiene falsifier (exit
15), `--lift-z` the grounded-zmin falsifier (exit 16), and
`--fat-rungs` (or the piece's equivalent) the joint-fit falsifier
(exit 17). A budget with no falsifier witnesses nothing: prove each
one fails once, and check the exit code, not just non-zero.
- **Hygiene budgets.** Copied combinatorics from
`examples/mesh-hygiene-audit` (do not import the example). Every piece
asserts on the generated mesh: non-manifold edges 0, loose verts 0,
Expand All @@ -43,6 +47,17 @@ entry in `showcase/gallery.json`, and a rendered still.
characteristic 2 — that is a single-shell contract. Pairs of parts
meant to touch assert a BVH surface gap below a named epsilon
(vert-vert is the wrong metric for thin straps and collars).
- **Joint-fit budgets.** Parts that interpenetrate on purpose — a tenon
in a mortise, a peg in a hub — assert how deep the overlap goes, not
just that it exists. Split the mesh into shells by edge connectivity,
assert the expected shell count, and for each joint assert three
named minima recomputed from vertex positions: the inserted part stays
clear of the host's chamfer, it seats far enough past the host's near
face, and it stops short of the host's far face. A part exactly as
thick as its host passes a "parts overlap" test while erupting through
the host's chamfer as a spike — that is the class this catches.
Measure in the construction frame (un-rotate by any rake) so a tilted
host does not inflate its own AABB.
- **Material face floors.** Every declared material asserts a named
minimum face count on the finished mesh, recomputed from
`polygon.material_index`. This catches the slot-assignment wipe class:
Expand Down
4 changes: 2 additions & 2 deletions showcase/gallery.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@
{
"name": "wooden-ladder",
"dir": "showcase/wooden-ladder",
"teaches": "A procedural timber ladder with raked stiles, six rungs, and iron shoes through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.",
"witnessesFix": "Recomputed: 2184 tris, two materials with 1008 wood and 48 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.474×0.361×1.482 m, LOD ratios in band, convex collider 52 tris, non-empty glTF. --skip-decimate exits 9 on the LOD1 ratio budget.",
"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.",
"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.",
"hero": "docs/gallery/assets/wooden-ladder-hero.webp",
"preview": "showcase/wooden-ladder/preview.webp",
"tags": [
Expand Down
60 changes: 48 additions & 12 deletions showcase/wooden-ladder/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Wooden ladder

A showcase piece, not an example. Procedural timber ladder (raked
stiles, six rungs, iron shoes and straps) then the shipped pipeline:
unique-cell UVs, Cycles high-to-low normal bake, LOD chain, convex
collider, Unity glTF export.
stiles, six 26 mm dowel rungs tenoned into the stiles, iron shoes and
top caps) then the shipped pipeline: unique-cell UVs, Cycles
high-to-low normal bake, LOD chain, convex collider, Unity glTF export.

It asserts **budget conformance** of the generated result. It does not
witness an API contract. "It rendered without error" is not a check.
Expand All @@ -21,14 +21,34 @@ materials, UVs, evaluated LOD, collider, or export file.

| Axis | Declared | Measured (4.5.11 / 5.1.2 / 5.2.1) |
| --- | --- | --- |
| Base triangles | 2100–2280 | 2184 / 2184 / 2184 |
| Base triangles | 900–975 | 936 / 936 / 936 |
| LOD1 ratio | 0.32–0.62 of base | 0.5000 / 0.5000 / 0.5000 |
| LOD2 ratio | 0.10–0.35 of base | 0.2198 / 0.2198 / 0.2198 |
| Materials | exactly 2 distinct, ≥24 wood, ≥24 metal | 2 slots, 1008 wood, 48 metal |
| LOD2 ratio | 0.10–0.35 of base | 0.2179 / 0.2179 / 0.2179 |
| Materials | exactly 2 distinct, ≥280 wood, ≥180 metal | 2 slots, 324 wood, 216 metal |
| UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 |
| Outer AABB | (0.474, 0.361, 1.482) m ± 0.01 | (0.4740, 0.3612, 1.4823), zmin 0 |
| Collider tris | ≤ 120 | 52 |
| Export | written, size > 0 | 158256 / 158256 / 158240 bytes |
| Outer AABB | (0.472, 0.365, 1.460) m ± 0.01 | (0.4720, 0.3649, 1.4597) |
| Grounded | `abs(zmin)` ≤ 1e-4 | 0.0000 |
| Mesh hygiene | non-manifold, loose v/e, doubles at 1e-5, zero-area, n-gons all 0 | all 0 |
| Parts | exactly 12 shells (2 stiles, 6 rungs, 2 caps, 2 shoes) | 12 (2 / 6) |
| Rung depth clearance | ≥ 0.003 m inside the stile faces | 0.00361 |
| Tenon engagement | ≥ 0.006 m past the stile inner face | 0.01200 |
| Tenon breakout margin | ≥ 0.005 m short of the stile outer face | 0.04600 |
| Collider tris | ≤ 120 | 24 |
| Export | written, size > 0 | 75140 / 75140 / 75128 bytes |

Base triangles fell from **2184 to 936** in the quality pass: four iron
fittings per stile collapsed to one shoe and one top cap, and the
redundant top block came out. No hidden-face removal was involved.

The rung rims are capped and buried in the stile rather than left open.
That costs 144 tris nobody sees, but an open rim is a non-manifold
boundary and the hygiene budget forbids it.

The joint budgets are measured per rung against each stile, from vertex
positions in the un-raked construction frame, and the reported value is
the worst case over all twelve rung ends. `clearance` is how far the
widest dowel stays inside the stile's front and back faces; it must
exceed the 2.5 mm chamfer or the dowel erupts through it as a spike.

DECIMATE COLLAPSE triangle counts are **not** identical across series —
the gate is a ratio band, not an exact count. On this mesh the three
Expand All @@ -37,18 +57,31 @@ binaries agreed on LOD ratios. Bake pixels are stochastic; the gate is
uses no RNG. Export byte counts differ by 16 B on 5.2.1 (glTF
serializer), not a gated axis.

`--skip-decimate` skips the LOD DECIMATE stage so LOD1 ratio is 1.0 and
exit 9 fires. That is the named budget the falsifier violates.
Each falsifier violates exactly one named budget, and each was proven to
fire on all three binaries:

| Falsifier | Budget violated | Exit | Measured failure |
| --- | --- | --- | --- |
| `--skip-decimate` | LOD1 ratio band | 9 | ratio 1.0000 |
| `--stray-vert` | Mesh hygiene, loose verts | 15 | `loose_v=1` |
| `--lift-z` | Grounded zmin | 16 | zmin 0.050000 |
| `--fat-rungs` | Rung depth clearance | 17 | clearance −0.00051 |

`--fat-rungs` widens the dowels to the full 34 mm stile depth, which is
the proportion this piece shipped with before the quality pass.

## Run

```bash
blender --background --python wooden_ladder.py --
blender --background --python wooden_ladder.py -- --skip-decimate
blender --background --python wooden_ladder.py -- --stray-vert
blender --background --python wooden_ladder.py -- --lift-z
blender --background --python wooden_ladder.py -- --fat-rungs
blender --background --python wooden_ladder.py -- --output ladder.png
```

Smoke does not pass `--output` or `--skip-decimate`.
Smoke passes no flags: no `--output`, no falsifier.

## Exit codes

Expand All @@ -72,3 +105,6 @@ File-local. `9` is a valid check code. `10` is reserved for
| 12 | Bake did not finish or image has no data |
| 13 | Export file missing or empty |
| 14 | `--output` produced no file |
| 15 | Mesh hygiene (`--stray-vert` lands here) |
| 16 | World AABB min Z off the floor (`--lift-z` lands here) |
| 17 | Part count or rung-to-stile joint fit (`--fat-rungs` lands here) |
Binary file modified showcase/wooden-ladder/preview.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading