From 5934ac4001c73c325f8a4b19ca9093379377aa25 Mon Sep 17 00:00:00 2001 From: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:39:14 -0400 Subject: [PATCH] fix(showcase): hull only the points so showcase colliders come out closed The 58 showcase copies of convex_hull_collider ran bmesh.ops.convex_hull over a copy of the full source mesh. The source edges survived the hull and left wire edges and interior vertices in the collider, so the "closed" collider was not closed and its triangle count was inflated. Remove the source edges before the hull and delete any vertex the hull left without a face, matching the snippet and template fix in #407. Measured on 4.5.11, 5.1.2 and 5.2.1: 174/174 runs exit 0 and collider triangle counts are identical across versions. 46 of 58 counts changed (e.g. archery-target 1083 -> 634, anvil 134 -> 130). README collider and export rows and the gallery witness callouts carry the new numbers. Closes #386 Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 --- docs/gallery/anvil/index.html | 4 +- docs/gallery/archery-target/index.html | 4 +- docs/gallery/bamboo-clump/index.html | 2 +- docs/gallery/basketball-hoop/index.html | 6 +- docs/gallery/boulder-cluster/index.html | 2 +- docs/gallery/bowling-pins/index.html | 4 +- docs/gallery/broadleaf-oak/index.html | 2 +- docs/gallery/cactus-garden/index.html | 2 +- docs/gallery/campfire/index.html | 2 +- docs/gallery/cargo-loader/index.html | 4 +- docs/gallery/cart/index.html | 4 +- docs/gallery/chopping-block/index.html | 4 +- docs/gallery/crate-stack/index.html | 6 +- docs/gallery/desk-lamp/index.html | 4 +- docs/gallery/espresso-machine/index.html | 4 +- docs/gallery/fallen-log/index.html | 4 +- docs/gallery/fence-kit/index.html | 4 +- docs/gallery/fern-mossy-rock/index.html | 2 +- docs/gallery/floor-fan/index.html | 4 +- docs/gallery/go-kart/index.html | 4 +- docs/gallery/grindstone/index.html | 4 +- docs/gallery/hand-pump/index.html | 4 +- docs/gallery/hay-bale/index.html | 2 +- docs/gallery/hitching-post/index.html | 4 +- docs/gallery/hover-bike/index.html | 4 +- docs/gallery/index.html | 90 +++++++++---------- docs/gallery/iron-cauldron/index.html | 4 +- docs/gallery/market-stall/index.html | 4 +- docs/gallery/motor-scooter/index.html | 4 +- docs/gallery/mushroom-stump/index.html | 4 +- docs/gallery/office-chair/index.html | 4 +- docs/gallery/palm-tree/index.html | 2 +- docs/gallery/park-bench/index.html | 4 +- docs/gallery/pine-tree/index.html | 4 +- docs/gallery/planet-rover/index.html | 4 +- docs/gallery/pond-edge/index.html | 2 +- docs/gallery/quad-drone/index.html | 4 +- docs/gallery/road-bicycle/index.html | 4 +- docs/gallery/shipping-crate/index.html | 4 +- docs/gallery/signpost/index.html | 4 +- docs/gallery/skate-ramp/index.html | 4 +- docs/gallery/soccer-goal/index.html | 4 +- docs/gallery/stand-mixer/index.html | 4 +- docs/gallery/stone-archway/index.html | 4 +- docs/gallery/stone-well/index.html | 4 +- docs/gallery/street-lantern/index.html | 4 +- docs/gallery/tavern-stool/index.html | 4 +- docs/gallery/terrain-scatter/index.html | 2 +- docs/gallery/traffic-cones/index.html | 4 +- docs/gallery/treasure-chest/index.html | 4 +- docs/gallery/wall-torch/index.html | 4 +- docs/gallery/watchtower/index.html | 4 +- docs/gallery/water-trough/index.html | 2 +- docs/gallery/weight-rack/index.html | 4 +- docs/gallery/wheelbarrow/index.html | 4 +- docs/gallery/wingback-armchair/index.html | 4 +- docs/gallery/wooden-barrel/index.html | 4 +- docs/gallery/wooden-bucket/index.html | 2 +- docs/gallery/wooden-ladder/index.html | 4 +- showcase/anvil/README.md | 4 +- showcase/anvil/anvil.py | 7 ++ showcase/archery-target/README.md | 4 +- showcase/archery-target/archery_target.py | 7 ++ showcase/bamboo-clump/README.md | 2 +- showcase/bamboo-clump/bamboo_clump.py | 7 ++ showcase/basketball-hoop/README.md | 6 +- showcase/basketball-hoop/basketball_hoop.py | 7 ++ showcase/boulder-cluster/README.md | 2 +- showcase/boulder-cluster/boulder_cluster.py | 7 ++ showcase/bowling-pins/README.md | 4 +- showcase/bowling-pins/bowling_pins.py | 7 ++ showcase/broadleaf-oak/README.md | 2 +- showcase/broadleaf-oak/broadleaf_oak.py | 7 ++ showcase/cactus-garden/README.md | 2 +- showcase/cactus-garden/cactus_garden.py | 7 ++ showcase/campfire/README.md | 2 +- showcase/campfire/campfire.py | 7 ++ showcase/cargo-loader/README.md | 4 +- showcase/cargo-loader/cargo_loader.py | 7 ++ showcase/cart/README.md | 4 +- showcase/cart/cart.py | 7 ++ showcase/chopping-block/README.md | 4 +- showcase/chopping-block/chopping_block.py | 7 ++ showcase/crate-stack/README.md | 4 +- showcase/crate-stack/crate_stack.py | 7 ++ showcase/desk-lamp/README.md | 4 +- showcase/desk-lamp/desk_lamp.py | 7 ++ showcase/espresso-machine/README.md | 4 +- showcase/espresso-machine/espresso_machine.py | 7 ++ showcase/fallen-log/README.md | 4 +- showcase/fallen-log/fallen_log.py | 7 ++ showcase/fence-kit/README.md | 4 +- showcase/fence-kit/fence_kit.py | 7 ++ showcase/fern-mossy-rock/README.md | 2 +- showcase/fern-mossy-rock/fern_mossy_rock.py | 7 ++ showcase/floor-fan/README.md | 4 +- showcase/floor-fan/floor_fan.py | 7 ++ showcase/gallery.json | 90 +++++++++---------- showcase/go-kart/README.md | 4 +- showcase/go-kart/go_kart.py | 7 ++ showcase/grindstone/README.md | 4 +- showcase/grindstone/grindstone.py | 7 ++ showcase/hand-pump/README.md | 4 +- showcase/hand-pump/hand_pump.py | 7 ++ showcase/hay-bale/README.md | 2 +- showcase/hay-bale/hay_bale.py | 7 ++ showcase/hitching-post/README.md | 4 +- showcase/hitching-post/hitching_post.py | 7 ++ showcase/hover-bike/README.md | 4 +- showcase/hover-bike/hover_bike.py | 7 ++ showcase/iron-cauldron/README.md | 4 +- showcase/iron-cauldron/iron_cauldron.py | 7 ++ showcase/market-stall/README.md | 4 +- showcase/market-stall/market_stall.py | 7 ++ showcase/motor-scooter/README.md | 4 +- showcase/motor-scooter/motor_scooter.py | 7 ++ showcase/mushroom-stump/README.md | 4 +- showcase/mushroom-stump/mushroom_stump.py | 7 ++ showcase/office-chair/README.md | 4 +- showcase/office-chair/office_chair.py | 7 ++ showcase/palm-tree/README.md | 2 +- showcase/palm-tree/palm_tree.py | 7 ++ showcase/park-bench/README.md | 4 +- showcase/park-bench/park_bench.py | 7 ++ showcase/pine-tree/README.md | 4 +- showcase/pine-tree/pine_tree.py | 7 ++ showcase/planet-rover/README.md | 4 +- showcase/planet-rover/planet_rover.py | 7 ++ showcase/pond-edge/README.md | 2 +- showcase/pond-edge/pond_edge.py | 7 ++ showcase/quad-drone/README.md | 4 +- showcase/quad-drone/quad_drone.py | 7 ++ showcase/road-bicycle/README.md | 4 +- showcase/road-bicycle/road_bicycle.py | 7 ++ showcase/shipping-crate/README.md | 4 +- showcase/shipping-crate/shipping_crate.py | 7 ++ showcase/signpost/README.md | 4 +- showcase/signpost/signpost.py | 7 ++ showcase/skate-ramp/README.md | 4 +- showcase/skate-ramp/skate_ramp.py | 7 ++ showcase/soccer-goal/README.md | 4 +- showcase/soccer-goal/soccer_goal.py | 7 ++ showcase/stand-mixer/README.md | 4 +- showcase/stand-mixer/stand_mixer.py | 7 ++ showcase/stone-archway/README.md | 4 +- showcase/stone-archway/stone_archway.py | 7 ++ showcase/stone-well/README.md | 4 +- showcase/stone-well/stone_well.py | 7 ++ showcase/street-lantern/README.md | 4 +- showcase/street-lantern/street_lantern.py | 7 ++ showcase/tavern-stool/README.md | 4 +- showcase/tavern-stool/tavern_stool.py | 7 ++ showcase/terrain-scatter/README.md | 2 +- showcase/terrain-scatter/terrain_scatter.py | 7 ++ showcase/traffic-cones/README.md | 4 +- showcase/traffic-cones/traffic_cones.py | 7 ++ showcase/treasure-chest/README.md | 4 +- showcase/treasure-chest/treasure_chest.py | 7 ++ showcase/wall-torch/README.md | 4 +- showcase/wall-torch/wall_torch.py | 7 ++ showcase/watchtower/README.md | 4 +- showcase/watchtower/watchtower.py | 7 ++ showcase/water-trough/README.md | 2 +- showcase/water-trough/water_trough.py | 7 ++ showcase/weight-rack/README.md | 4 +- showcase/weight-rack/weight_rack.py | 7 ++ showcase/wheelbarrow/README.md | 4 +- showcase/wheelbarrow/wheelbarrow.py | 7 ++ showcase/wingback-armchair/README.md | 4 +- .../wingback-armchair/wingback_armchair.py | 7 ++ showcase/wooden-barrel/README.md | 4 +- showcase/wooden-barrel/wooden_barrel.py | 7 ++ showcase/wooden-bucket/README.md | 2 +- showcase/wooden-bucket/wooden_bucket.py | 7 ++ showcase/wooden-ladder/README.md | 4 +- showcase/wooden-ladder/wooden_ladder.py | 7 ++ 176 files changed, 707 insertions(+), 301 deletions(-) diff --git a/docs/gallery/anvil/index.html b/docs/gallery/anvil/index.html index 894e5549..75891137 100644 --- a/docs/gallery/anvil/index.html +++ b/docs/gallery/anvil/index.html @@ -53,7 +53,7 @@

Anvil

A London-pattern forged anvil with a thick face block, tapered horn and broad flared foot on a hooped oak stand, a cross-peen hammer on the floor beside it.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 3168 tris, two materials with 1040 wood and 912 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.621×0.414×0.569 m, LOD ratios in band, convex collider 134 tris, hygiene 0, 16 grounded staves, hoop bite 0.003 m, foot-on-head gap 0.003 m, waist corner reach 0.8572, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-staves 16; --float-anvil 17; --round-band 18; --round-waist 19.
+
witnesses Recomputed: 3168 tris, two materials with 1040 wood and 912 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.621×0.414×0.569 m, LOD ratios in band, convex collider 130 tris, hygiene 0, 16 grounded staves, hoop bite 0.003 m, foot-on-head gap 0.003 m, waist corner reach 0.8572, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-staves 16; --float-anvil 17; --round-band 18; --round-waist 19.

category Village

tags mesh export showcase

@@ -68,7 +68,7 @@

Anvil

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2500–45003168 / 3168 / 3168
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2197
Materialsexactly 2 distinct; ≥400 wood, ≥400 metal faces2 slots; 1040 / 912
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.621, 0.414, 0.569) m ± 0.015(0.6210, 0.4137, 0.5690), zmin 0
Collider tris≤ 280134
Exportwritten, size > 0257068 / 257068 / 257052 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2500–45003168 / 3168 / 3168
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2197
Materialsexactly 2 distinct; ≥400 wood, ≥400 metal faces2 slots; 1040 / 912
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.621, 0.414, 0.569) m ± 0.015(0.6210, 0.4137, 0.5690), zmin 0
Collider tris≤ 280130
Exportwritten, size > 0258408 / 258408 / 258400 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles dropped from 6616 to 2988 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.

DECIMATE COLLAPSE triangle counts are not identical across series — the gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Stave-width jitter uses fixed seed 17, and the per-piece wood tone its own seed. Export byte counts differ on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

diff --git a/docs/gallery/archery-target/index.html b/docs/gallery/archery-target/index.html index e7c60fcb..f7c075ce 100644 --- a/docs/gallery/archery-target/index.html +++ b/docs/gallery/archery-target/index.html @@ -53,7 +53,7 @@

Archery Target

A straw archery boss with a gold, red, blue, black and white face and five arrows, leaning on a timber easel numbered 12, a quiver on the grass patch below.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 42908 tris, sixteen materials with 4732 straw, 1856 twine, 1086 pine, 6288 steel, 522 white, 816 black, 128 blue, 128 red, 254 gold, 326 carbon, 500 vane, 300 cock-vane, 1076 nock, 5230 grass, 286 soil and 768 leather faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.007×2.689×2.054 m, zmin 0 with both skids and the rear tread bedded 2.0 mm into the turf (band 1–4 mm), hygiene 0 including zero coplanar cross-shell pairs, the hinge pin 0.000 mm off the axis of all three knuckles (tol 0.3 mm), the boss seated 2.5 mm into its ledge and leaning 2.0 mm on both legs (bands 1–4 mm), the gold centre 1.3000 m above the turf (World Archery 1.30 ± 0.05) on a 1.100 × 0.280 m boss and a 0.800 m face tilted 12.000° (band 10–15°), seven points buried 0.119–0.149 m in the straw (band 0.08–0.20) with straw left ahead, every vane at least 0.419 m clear of the boss (min 0.25), ten fletched shafts with three vanes each within 0.002° of 120° (tol 1°), all ten ring lines on the 4 cm scoring table (0.000 mm off, tol 0.5 mm) in the right inks, a 73.85 kg stand and boss whose mass centre is 0.349 m inside its supports with a forward tip angle of 27.83° (min 20°), one connected assembly of 722 shells, LOD ratios in band, collider 1083 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --lift-boss 18; --high-boss 19; --shallow-arrow 20; --short-arrow 21; --skew-vane 22; --wide-gold 23; --short-skids 24; --loose-pin 25.
+
witnesses Recomputed: 42908 tris, sixteen materials with 4732 straw, 1856 twine, 1086 pine, 6288 steel, 522 white, 816 black, 128 blue, 128 red, 254 gold, 326 carbon, 500 vane, 300 cock-vane, 1076 nock, 5230 grass, 286 soil and 768 leather faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.007×2.689×2.054 m, zmin 0 with both skids and the rear tread bedded 2.0 mm into the turf (band 1–4 mm), hygiene 0 including zero coplanar cross-shell pairs, the hinge pin 0.000 mm off the axis of all three knuckles (tol 0.3 mm), the boss seated 2.5 mm into its ledge and leaning 2.0 mm on both legs (bands 1–4 mm), the gold centre 1.3000 m above the turf (World Archery 1.30 ± 0.05) on a 1.100 × 0.280 m boss and a 0.800 m face tilted 12.000° (band 10–15°), seven points buried 0.119–0.149 m in the straw (band 0.08–0.20) with straw left ahead, every vane at least 0.419 m clear of the boss (min 0.25), ten fletched shafts with three vanes each within 0.002° of 120° (tol 1°), all ten ring lines on the 4 cm scoring table (0.000 mm off, tol 0.5 mm) in the right inks, a 73.85 kg stand and boss whose mass centre is 0.349 m inside its supports with a forward tip angle of 27.83° (min 20°), one connected assembly of 722 shells, LOD ratios in band, collider 634 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --lift-boss 18; --high-boss 19; --shallow-arrow 20; --short-arrow 21; --skew-vane 22; --wide-gold 23; --short-skids 24; --loose-pin 25.

category Sports

tags mesh export showcase

@@ -70,7 +70,7 @@

Archery Target

Intended size: 2.01 m across the turf patch, 2.69 m front to back, 2.05 m to the top of the front legs. The turf sets the width and depth, the leg tops the height. The centre of the gold stands 1.30 m above the turf, the World Archery height.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles42000–4400042908
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 16 distinct; ≥4490 straw, ≥1760 twine, ≥1030 pine, ≥5970 steel, ≥495 white, ≥775 black, ≥120 blue, ≥120 red, ≥240 gold, ≥310 carbon, ≥475 vane, ≥285 cock vane, ≥1020 nock, ≥4960 grass, ≥270 soil, ≥730 leather faces16 slots; 4732 / 1856 / 1086 / 6288 / 522 / 816 / 128 / 128 / 254 / 326 / 500 / 300 / 1076 / 5230 / 286 / 768
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.0071, 2.6887, 2.0538) m ± 0.01(2.0071, 2.6887, 2.0538), zmin 0
Collider tris≤ 11501083
Exportwritten, size > 0, removed after measuring3288248 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles42000–4400042908
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 16 distinct; ≥4490 straw, ≥1760 twine, ≥1030 pine, ≥5970 steel, ≥495 white, ≥775 black, ≥120 blue, ≥120 red, ≥240 gold, ≥310 carbon, ≥475 vane, ≥285 cock vane, ≥1020 nock, ≥4960 grass, ≥270 soil, ≥730 leather faces16 slots; 4732 / 1856 / 1086 / 6288 / 522 / 816 / 128 / 128 / 254 / 326 / 500 / 300 / 1076 / 5230 / 286 / 768
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.0071, 2.6887, 2.0538) m ± 0.01(2.0071, 2.6887, 2.0538), zmin 0
Collider tris≤ 1150634
Exportwritten, size > 0, removed after measuring3259388 / 3259388 / 3259380 bytes (4.5.11 / 5.1.2 / 5.2.1)

The collider is the convex hull of the whole piece; its count is carried by the 96-segment turf outline.

Every falsifier leaves the triangle count at 42908 and the AABB unchanged: they move parts or change a length, never add or remove geometry.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses only seeded random.Random streams; two default runs print identical measurements.

diff --git a/docs/gallery/bamboo-clump/index.html b/docs/gallery/bamboo-clump/index.html index b284dafe..da027a34 100644 --- a/docs/gallery/bamboo-clump/index.html +++ b/docs/gallery/bamboo-clump/index.html @@ -72,7 +72,7 @@

Bamboo Clump

Intended size: a clump 3.82 × 3.55 m across its leaves and 4.83 m to the highest leaf. The outer AABB is 3.8168 × 3.5512 × 4.8254 m, read off the vertices: the leaning culms and their branches set X and Y, a leaf on the tallest culm's top plume sets the top; the soil's underside is the ground. The collider is the convex hull of the lower 1.25 m of the clump, coarse: a player walks the litter and brushes through the leaves, but not through the culms.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles72800–7480073804
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 5 distinct; ≥2680 soil, ≥16600 culm, ≥16770 leaf, ≥2920 sheath, ≥740 dry-leaf faces5 slots; 2734 / 16944 / 17115 / 2979 / 756
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(3.8168, 3.5512, 4.8254) m ± 0.01(3.8168, 3.5512, 4.8254), zmin 0
Collider tris (lower 1.25 m hull)≤ 9688
Exportwritten, size > 0, removed after measuring5606968 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles72800–7480073804
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 5 distinct; ≥2680 soil, ≥16600 culm, ≥16770 leaf, ≥2920 sheath, ≥740 dry-leaf faces5 slots; 2734 / 16944 / 17115 / 2979 / 756
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(3.8168, 3.5512, 4.8254) m ± 0.01(3.8168, 3.5512, 4.8254), zmin 0
Collider tris (lower 1.25 m hull)≤ 9688
Exportwritten, size > 0, removed after measuring5606976 / 5606976 / 5606968 bytes (4.5.11 / 5.1.2 / 5.2.1)

The quality pass re-fitted four of these around the new measurements, each for a stated reason. The triangle band moved from 51500–53500 to 72800–74800, paying for a fuller crown (815 leaves on 107 branches against 567 on 63), 21 culm sheaths, five knuckles and a wax-band row under every node. The face floors follow the same counts. The collider ceiling went from 80 to 96: the culms now rise from a 0.6 m footprint and splay from the soil, so the hull of the lower 1.25 m has more facets (88). The AABB is a new shape.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; the geometry is pure Python math. Two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/basketball-hoop/index.html b/docs/gallery/basketball-hoop/index.html index 97000f04..5ddbf70b 100644 --- a/docs/gallery/basketball-hoop/index.html +++ b/docs/gallery/basketball-hoop/index.html @@ -53,7 +53,7 @@

Basketball Hoop

A basketball goal on a concrete court pad: padded square gooseneck pole, framed backboard, orange rim and white net over a faded green key and arc, two basketballs on the concrete.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 19564 tris, twelve materials with 2546 steel, 54 board, 32 board-paint, 970 rim, 2784 net, 382 pad, 144 aluminium, 108 concrete, 504 court-line, 12 key, 1024 ball and 2310 seam faces, UVs in 0..1 with zero AABB overlap, outer AABB 5.200×6.600×4.050 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both braces 9.5 mm into the collar and 21.0 mm into the lower rail, all 12 net loops threaded through their hook eyes (worst 7.0 mm from the eye centre against a 9 mm clear radius), rim top 3.050 m over the court, inside diameter 0.457 m, inner edge 0.151 m off the board, tilt 0.000°, both balls radius 0.1194 m bearing 2.0 mm into their slabs, all four anchor bolts 70 mm into the slab and 62 mm over the plate, all 18 paint shells 1.0–2.2 mm proud and 1.4–3.0 mm sunk into their slabs, one connected assembly of 209 shells, LOD ratios in band, convex collider 58 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --short-brace 17; --drop-net 18; --tilt-rim 19; --loose-pad 20; --float-ball 21; --short-bolts 22; --float-paint 23.
+
witnesses Recomputed: 19564 tris, twelve materials with 2546 steel, 54 board, 32 board-paint, 970 rim, 2784 net, 382 pad, 144 aluminium, 108 concrete, 504 court-line, 12 key, 1024 ball and 2310 seam faces, UVs in 0..1 with zero AABB overlap, outer AABB 5.200×6.600×4.050 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both braces 9.5 mm into the collar and 21.0 mm into the lower rail, all 12 net loops threaded through their hook eyes (worst 7.0 mm from the eye centre against a 9 mm clear radius), rim top 3.050 m over the court, inside diameter 0.457 m, inner edge 0.151 m off the board, tilt 0.000°, both balls radius 0.1194 m bearing 2.0 mm into their slabs, all four anchor bolts 70 mm into the slab and 62 mm over the plate, all 18 paint shells 1.0–2.2 mm proud and 1.4–3.0 mm sunk into their slabs, one connected assembly of 209 shells, LOD ratios in band, convex collider 44 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --short-brace 17; --drop-net 18; --tilt-rim 19; --loose-pad 20; --float-ball 21; --short-bolts 22; --float-paint 23.

category Sports

tags mesh export showcase

@@ -73,10 +73,10 @@

Basketball Hoop

Shading follows what each part is. Round stock (ring, cord, balls, braces) is smooth-shaded. Chamfers, material boundaries and bends over 35° stay sharp, and so does a flat face meeting a much narrower facet, so the pole's flats read flat and its corner fillets read round. The steel is near-black satin powder coat and the frame satin aluminium, each with a studio reflection term in the material (after espresso-machine), so neither reads as grey plastic on the dark stage.

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

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied inline, not imported).

-

Intended size: 5.2 × 6.6 m court pad; 1.83 × 1.05 m board with its bottom 2.90 m above the court; pole axis 1.22 m behind the board face. The outer AABB is 5.200 × 6.600 × 4.050 m; the pad sets the footprint, and the pole cap on the 100 mm slab sets the height. The convex collider wraps the pad and the hoop together (58 tris).

+

Intended size: 5.2 × 6.6 m court pad; 1.83 × 1.05 m board with its bottom 2.90 m above the court; pole axis 1.22 m behind the board face. The outer AABB is 5.200 × 6.600 × 4.050 m; the pad sets the footprint, and the pole cap on the 100 mm slab sets the height. The convex collider wraps the pad and the hoop together (44 tris).

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles18500–2050019564
LOD1 ratio0.32–0.62 of base0.4984
LOD2 ratio0.10–0.35 of base0.2183
Materialsexactly 12 distinct; face floors ≥2200 steel, ≥45 board, ≥28 board paint, ≥850 rim, ≥2400 net, ≥330 pad, ≥120 aluminium, ≥90 concrete, ≥440 court line, ≥12 key, ≥900 ball, ≥2000 seam12 slots; 2546 / 54 / 32 / 970 / 2784 / 382 / 144 / 108 / 504 / 12 / 1024 / 2310
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(5.200, 6.600, 4.050) m ± 0.01(5.2000, 6.6000, 4.0500), zmin 0
Collider tris≤ 22058
Exportwritten, size > 0, removed after measuring1456228 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles18500–2050019564
LOD1 ratio0.32–0.62 of base0.4984
LOD2 ratio0.10–0.35 of base0.2183
Materialsexactly 12 distinct; face floors ≥2200 steel, ≥45 board, ≥28 board paint, ≥850 rim, ≥2400 net, ≥330 pad, ≥120 aluminium, ≥90 concrete, ≥440 court line, ≥12 key, ≥900 ball, ≥2000 seam12 slots; 2546 / 54 / 32 / 970 / 2784 / 382 / 144 / 108 / 504 / 12 / 1024 / 2310
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(5.200, 6.600, 4.050) m ± 0.01(5.2000, 6.6000, 4.0500), zmin 0
Collider tris≤ 22044
Exportwritten, size > 0, removed after measuring1454192 / 1454192 / 1454180 bytes (4.5.11 / 5.1.2 / 5.2.1)

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/boulder-cluster/index.html b/docs/gallery/boulder-cluster/index.html index c84889c0..a0daad31 100644 --- a/docs/gallery/boulder-cluster/index.html +++ b/docs/gallery/boulder-cluster/index.html @@ -71,7 +71,7 @@

Boulder Cluster

Intended size: a mound 4.44 × 3.22 m, the granite block's top 1.37 m off the ground. The outer AABB is 4.444 × 3.215 × 1.366 m. The soil sets X and Y, a moss cushion on the block's crown the top. The soil's underside is the ground. The collider is the convex hull of the five rocks alone, coarse: players walk through grass.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles39600–4090040244
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥4000 granite, ≥3400 sandstone, ≥1960 lichen, ≥1580 moss, ≥4700 grass, ≥2460 soil, ≥1750 gravel, ≥1260 flower faces8 slots; 4440 / 3798 / 2184 / 1760 / 5251 / 2734 / 1944 / 1400
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(4.4442, 3.2153, 1.3657) m ± 0.01(4.4442, 3.2153, 1.3657), zmin 0
Collider tris (rock hull)≤ 320292
Exportwritten, size > 0, removed after measuring3064548 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles39600–4090040244
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥4000 granite, ≥3400 sandstone, ≥1960 lichen, ≥1580 moss, ≥4700 grass, ≥2460 soil, ≥1750 gravel, ≥1260 flower faces8 slots; 4440 / 3798 / 2184 / 1760 / 5251 / 2734 / 1944 / 1400
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(4.4442, 3.2153, 1.3657) m ± 0.01(4.4442, 3.2153, 1.3657), zmin 0
Collider tris (rock hull)≤ 320292
Exportwritten, size > 0, removed after measuring3064552 / 3064552 / 3064548 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the triangle count or the envelope: every falsifier run measured 40244 tris and the default's outer AABB to the tenth of a millimetre.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; the geometry is pure Python math. Two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/bowling-pins/index.html b/docs/gallery/bowling-pins/index.html index 11fd696c..a9e9d0a2 100644 --- a/docs/gallery/bowling-pins/index.html +++ b/docs/gallery/bowling-pins/index.html @@ -53,7 +53,7 @@

Bowling Pins

Ten white pins with red neck stripes racked on a dark pin deck at the end of a glossy maple lane with arrows and dots, a marbled violet ball resting on the approach.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 37078 tris, eleven materials with 358 maple, 358 pin-deck, 13720 pin-white, 1280 pin-red, 1649 ball, 562 bore, 254 phenolic, 142 laminate, 176 aluminium, 1197 inlay and 380 sleeper faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.640×2.301×0.523 m read off the vertices, zmin 0 with all five sleepers on the floor, hygiene 0 including zero coplanar cross-shell pairs, every pin's base centre 0.000 mm off its spot (tol 0.5) and 0.6 mm below the deck face (band 0.3–1.0), every pin plumb (0.000°), 0.3810 m tall with a 0.12106 m belly, its radius on all 15 profile-table stations to 0.000 mm (tol 0.2), the ten spots on an exact 12 in lattice (18 edges, rows 1-2-3-4, row pitch 0.26396 m, head spot on the centre line), the ball 0.21590 m across resting 0.60 mm into the lane (band 0.3–0.9), its thumb hole 63.5 mm and finger holes 50.8 mm deep with 25.40 and 20.32 mm bores, a 112.2 mm span and a 26.67 mm bridge, 39 boards flush and straight to 0.000 mm, one connected assembly of 55 shells, LOD ratios in band, collider 277 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sleeper 16; --offset-pin 17; --float-pin 18; --lean-pin 19; --wide-rack 20; --fat-neck 21; --float-ball 22; --shallow-holes 23; --proud-board 24; --lift-arrows 25.
+
witnesses Recomputed: 37078 tris, eleven materials with 358 maple, 358 pin-deck, 13720 pin-white, 1280 pin-red, 1649 ball, 562 bore, 254 phenolic, 142 laminate, 176 aluminium, 1197 inlay and 380 sleeper faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.640×2.301×0.523 m read off the vertices, zmin 0 with all five sleepers on the floor, hygiene 0 including zero coplanar cross-shell pairs, every pin's base centre 0.000 mm off its spot (tol 0.5) and 0.6 mm below the deck face (band 0.3–1.0), every pin plumb (0.000°), 0.3810 m tall with a 0.12106 m belly, its radius on all 15 profile-table stations to 0.000 mm (tol 0.2), the ten spots on an exact 12 in lattice (18 edges, rows 1-2-3-4, row pitch 0.26396 m, head spot on the centre line), the ball 0.21590 m across resting 0.60 mm into the lane (band 0.3–0.9), its thumb hole 63.5 mm and finger holes 50.8 mm deep with 25.40 and 20.32 mm bores, a 112.2 mm span and a 26.67 mm bridge, 39 boards flush and straight to 0.000 mm, one connected assembly of 55 shells, LOD ratios in band, collider 200 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sleeper 16; --offset-pin 17; --float-pin 18; --lean-pin 19; --wide-rack 20; --fat-neck 21; --float-ball 22; --shallow-holes 23; --proud-board 24; --lift-arrows 25.

category Sports

tags mesh export showcase

@@ -70,7 +70,7 @@

Bowling Pins

Intended size: 1.64 m across the sleepers, 2.30 m from the lane's near end to the kickbacks' aluminium caps behind the pit edge, 0.52 m to the top of the caps. The origin is under the head spot at floor level.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles36400–3770037078
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 11 distinct; ≥330 maple, ≥330 pin deck, ≥12800 pin white, ≥1190 pin red, ≥1450 ball, ≥480 bore, ≥235 gutter/kick plate, ≥130 kickback laminate, ≥160 aluminium/steel, ≥1110 inlay, ≥350 sleeper faces11 slots; 358 / 358 / 13720 / 1280 / 1649 / 562 / 254 / 142 / 176 / 1197 / 380
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.640, 2.301, 0.523) m ± 0.01, read off the vertices(1.6400, 2.3014, 0.5234), zmin 0
Collider tris≤ 300277
Exportwritten, size > 0, removed after measuring2730012 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles36400–3770037078
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 11 distinct; ≥330 maple, ≥330 pin deck, ≥12800 pin white, ≥1190 pin red, ≥1450 ball, ≥480 bore, ≥235 gutter/kick plate, ≥130 kickback laminate, ≥160 aluminium/steel, ≥1110 inlay, ≥350 sleeper faces11 slots; 358 / 358 / 13720 / 1280 / 1649 / 562 / 254 / 142 / 176 / 1197 / 380
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.640, 2.301, 0.523) m ± 0.01, read off the vertices(1.6400, 2.3014, 0.5234), zmin 0
Collider tris≤ 300200
Exportwritten, size > 0, removed after measuring2722544 / 2722544 / 2722540 bytes (4.5.11 / 5.1.2 / 5.2.1)

Every falsifier leaves the triangle count at 37078 and the envelope at (1.6400, 2.3014, 0.5234): they move or resize parts, never add or remove geometry.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. The ball's Boolean may cut its sphere into a slightly different set of faces on another series; the triangle band and the ball and bore floors leave room for it. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/broadleaf-oak/index.html b/docs/gallery/broadleaf-oak/index.html index 4357efd0..271a6530 100644 --- a/docs/gallery/broadleaf-oak/index.html +++ b/docs/gallery/broadleaf-oak/index.html @@ -76,7 +76,7 @@

Foliage: why cushions, not only le

The collider is the convex hull of the bole alone: a 14-sided frustum from under the soil to the fork and a point over the dome, without flutes, buttresses or roots, because players walk under the crown. The hull is built from points only; handed faces as well, it keeps them alongside its own.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles86250–8715086700
LOD1 ratio0.32–0.62 of base0.4995
LOD2 ratio0.10–0.35 of base0.2167
Materialsexactly 9 distinct; face floors bark ≥7110, leaf ≥14090, deadwood ≥240, nut ≥1480, cup ≥1210, soil ≥2600, grass ≥2730, litter ≥1590, canopy ≥411009 slots; 7481 / 14832 / 256 / 1566 / 1276 / 2734 / 2880 / 1680 / 43270
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(11.529, 11.716, 8.958) m ± 0.01(11.5288, 11.7164, 8.9575), zmin 0
Collider tris (bole hull)≤ 6054
Exportwritten, size > 0, removed after measuring10351880 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles86250–8715086700
LOD1 ratio0.32–0.62 of base0.4995
LOD2 ratio0.10–0.35 of base0.2167
Materialsexactly 9 distinct; face floors bark ≥7110, leaf ≥14090, deadwood ≥240, nut ≥1480, cup ≥1210, soil ≥2600, grass ≥2730, litter ≥1590, canopy ≥411009 slots; 7481 / 14832 / 256 / 1566 / 1276 / 2734 / 2880 / 1680 / 43270
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(11.529, 11.716, 8.958) m ± 0.01(11.5288, 11.7164, 8.9575), zmin 0
Collider tris (bole hull)≤ 6054
Exportwritten, size > 0, removed after measuring10351900 / 10351900 / 10351880 bytes (4.5.11 / 5.1.2 / 5.2.1)

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count (4.5.11 and 5.1.2 decimate to 0.5000 / 0.2200). Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; two default runs print identical measurements, and 4.5.11 and 5.1.2 print the same measurements as 5.2.1 apart from the LOD counts (the glTF differs by 20 bytes).

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/cactus-garden/index.html b/docs/gallery/cactus-garden/index.html index a324bc88..2a461692 100644 --- a/docs/gallery/cactus-garden/index.html +++ b/docs/gallery/cactus-garden/index.html @@ -71,7 +71,7 @@

Cactus Garden

Intended size: a disc 3.00 × 2.61 m, its mound 0.14 m high, the saguaro's crown flowers 2.38 m off the floor. The outer AABB is 2.9950 × 2.6077 × 2.3754 m, read off the vertices. The sand sets X and Y, a crown flower the top; the sand's underside is the ground. The collider is the convex hull of the sand disc alone, coarse: players brush through the plants.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles44700–4600045364
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 10 distinct; ≥3400 sand, ≥8400 skin, ≥12100 spine, ≥420 fruit, ≥900 flower, ≥440 agave, ≥990 rock, ≥550 gravel, ≥610 wood, ≥1120 grass faces10 slots; 3694 / 9332 / 13254 / 432 / 976 / 481 / 1080 / 600 / 666 / 1222
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.9950, 2.6077, 2.3754) m ± 0.01(2.9950, 2.6077, 2.3754), zmin 0
Collider tris (sand hull)≤ 120112
Exportwritten, size > 0, removed after measuring3772220 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles44700–4600045364
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 10 distinct; ≥3400 sand, ≥8400 skin, ≥12100 spine, ≥420 fruit, ≥900 flower, ≥440 agave, ≥990 rock, ≥550 gravel, ≥610 wood, ≥1120 grass faces10 slots; 3694 / 9332 / 13254 / 432 / 976 / 481 / 1080 / 600 / 666 / 1222
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.9950, 2.6077, 2.3754) m ± 0.01(2.9950, 2.6077, 2.3754), zmin 0
Collider tris (sand hull)≤ 120112
Exportwritten, size > 0, removed after measuring3772228 / 3772228 / 3772220 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the triangle count: every falsifier run measured 45364 tris. Only --lean-saguaro moves the envelope, by 6.5 mm in Z against a 10 mm tolerance, because it tips the flowers that set the top.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; the geometry is pure Python math. Two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/campfire/index.html b/docs/gallery/campfire/index.html index 27ddaf6c..6f53778e 100644 --- a/docs/gallery/campfire/index.html +++ b/docs/gallery/campfire/index.html @@ -68,7 +68,7 @@

Campfire

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1400–36002760 / 2760 / 2760
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.4993
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 3 distinct; ≥80 wood, ≥24 ash, ≥200 stone3 slots; 216 / 48 / 1416
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.807, 0.808, 0.404) m ± 0.015(0.8024, 0.8022, 0.4037), zmin 0
Collider tris≤ 360162
Exportwritten, size > 0231952 / 231952 / 231944 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1400–36002760 / 2760 / 2760
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.4993
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 3 distinct; ≥80 wood, ≥24 ash, ≥200 stone3 slots; 216 / 48 / 1416
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.807, 0.808, 0.404) m ± 0.015(0.8024, 0.8022, 0.4037), zmin 0
Collider tris≤ 360162
Exportwritten, size > 0231712 / 231712 / 231708 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles dropped from 3616 to 2200 in the quality pass: the old piece stacked identical boxes with a mortar gap and a teepee that met at one point. The rebuild is two seated courses plus crossing sticks; hidden overlapping volume went away. The second pass took it to 2760: each stone is now a lofted, chamfered lump instead of a four-sided wedge.

DECIMATE COLLAPSE triangle counts are not guaranteed identical across series — the gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Stone-width jitter uses fixed seed 17; each stone's shape draws from its own seeded generator. glTF byte size differs on 5.2.1.

Hygiene#

diff --git a/docs/gallery/cargo-loader/index.html b/docs/gallery/cargo-loader/index.html index eea40f53..6aa0d8db 100644 --- a/docs/gallery/cargo-loader/index.html +++ b/docs/gallery/cargo-loader/index.html @@ -53,7 +53,7 @@

Cargo Loader

A yellow bipedal cargo loader in a crouch, hydraulic rams on its legs and arms, an open roll-cage cockpit with an amber beacon, holding a blue-grey crate on its forks.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 44600 tris, ten materials with 2736 paint, 608 hazard, 3128 chrome, 15328 steel, 2740 rubber, 480 seat-vinyl, 640 harness, 256 beacon, 152 work-light and 516 crate-paint faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.827×1.689×2.974 m, zmin 0 with both soles on the floor, hygiene 0 including zero coplanar cross-shell pairs, all 28 clevis pins 0.000 mm off the axis of each of their three bushings and 0.000° to them (caps 0.3 mm, 0.3°), the crate's base biting both tines by 0.0020 m at every station along a 0.74 m run (band 0.0010–0.0040, run ≥ 0.50), both soles flat and level to 0.000 mm and 0.000° (caps 0.5 mm, 0.2°), all 8 ram rods 0.000 mm off their cylinders' axes and 0.0096° to them (caps 0.3 mm, 0.3°) with 0.1591–0.2858 m of rod exposed (band 0.080–0.340) and 0.060 m engaged (floor 0.040), a 2380.6 kg loader and crate whose mass centre stands 0.4473 m inside the soles' support polygon (floor 0.200), one connected assembly of 414 shells, LOD ratios in band, collider 710 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --lift-crate 18; --tilt-sole 19; --skew-rod 20; --bottom-ram 21; --overload 22; --loose-light 23.
+
witnesses Recomputed: 44600 tris, ten materials with 2736 paint, 608 hazard, 3128 chrome, 15328 steel, 2740 rubber, 480 seat-vinyl, 640 harness, 256 beacon, 152 work-light and 516 crate-paint faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.827×1.689×2.974 m, zmin 0 with both soles on the floor, hygiene 0 including zero coplanar cross-shell pairs, all 28 clevis pins 0.000 mm off the axis of each of their three bushings and 0.000° to them (caps 0.3 mm, 0.3°), the crate's base biting both tines by 0.0020 m at every station along a 0.74 m run (band 0.0010–0.0040, run ≥ 0.50), both soles flat and level to 0.000 mm and 0.000° (caps 0.5 mm, 0.2°), all 8 ram rods 0.000 mm off their cylinders' axes and 0.0096° to them (caps 0.3 mm, 0.3°) with 0.1591–0.2858 m of rod exposed (band 0.080–0.340) and 0.060 m engaged (floor 0.040), a 2380.6 kg loader and crate whose mass centre stands 0.4473 m inside the soles' support polygon (floor 0.200), one connected assembly of 414 shells, LOD ratios in band, collider 532 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --lift-crate 18; --tilt-sole 19; --skew-rod 20; --bottom-ram 21; --overload 22; --loose-light 23.

category Vehicles

tags mesh export showcase

@@ -70,7 +70,7 @@

Cargo Loader

Intended size: 2.97 m to the top of the beacon, 1.69 m across the pin heads of the arm joints, 2.83 m from the power pack's grille to the tine tips. The crate is 0.78 × 1.12 × 0.62 m, its base 1.00 m off the ground. The origin is under the loader's centre, so it lands on its soles.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles44000–4500044600
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2190
Materialsexactly 10 distinct; ≥2550 paint, ≥560 hazard, ≥2900 chrome, ≥14300 steel, ≥2550 rubber, ≥440 seat vinyl, ≥590 harness webbing, ≥235 beacon, ≥140 work-light, ≥480 crate paint faces10 slots; 2736 / 608 / 3128 / 15328 / 2740 / 480 / 640 / 256 / 152 / 516
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.827, 1.689, 2.974) m ± 0.01(2.8272, 1.6890, 2.9740), zmin 0
Collider tris≤ 760710
Exportwritten, size > 0, removed after measuring3461604 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles44000–4500044600
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2190
Materialsexactly 10 distinct; ≥2550 paint, ≥560 hazard, ≥2900 chrome, ≥14300 steel, ≥2550 rubber, ≥440 seat vinyl, ≥590 harness webbing, ≥235 beacon, ≥140 work-light, ≥480 crate paint faces10 slots; 2736 / 608 / 3128 / 15328 / 2740 / 480 / 640 / 256 / 152 / 516
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.827, 1.689, 2.974) m ± 0.01(2.8272, 1.6890, 2.9740), zmin 0
Collider tris≤ 760532
Exportwritten, size > 0, removed after measuring3450636 / 3450636 / 3450628 bytes (4.5.11 / 5.1.2 / 5.2.1)

The collider is the convex hull of the whole loader; the power pack, the beacon, the shoulder pins and the tine tips carry its outline.

Every falsifier leaves the triangle count at 44600 and the outer AABB unchanged: they move, turn or reweigh parts, never add or remove them.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

diff --git a/docs/gallery/cart/index.html b/docs/gallery/cart/index.html index 4069e11a..fce49de0 100644 --- a/docs/gallery/cart/index.html +++ b/docs/gallery/cart/index.html @@ -53,7 +53,7 @@

Cart

A wooden handcart with a planked box bed and iron corner straps on two spoked wheels, standing level on two prop legs with its shafts joined by a pull bar.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 5284 tris, two materials with metal and wood face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.580×0.842×0.640 m, LOD ratios in band, convex collider 192 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, both tyres and both prop legs grounded, two wall boards per side with 3 mm seams, tyre seat depth in band over 48 angular stations, every shell in one BVH-contact assembly, the two wheels mirrored within 5e-5 m, no unchamfered right-angle edge, 17.45 bake texels per UV cell, non-empty glTF. --flush-tyre exits 15 on the z-fight budget; --float-wheel and --short-props exit 16 on the named-support budget; --wide-seams exits 17 on the board seams; --sink-tyre exits 18 on the tyre seat band; --lift-bed exits 18 on the one-assembly budget; --skew-wheel exits 19 on the wheel mirror; --sharp-bar exits 20 on edge treatment; --low-bake exits 21 on texel density; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.
+
witnesses Recomputed: 5284 tris, two materials with metal and wood face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.580×0.842×0.640 m, LOD ratios in band, convex collider 164 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, both tyres and both prop legs grounded, two wall boards per side with 3 mm seams, tyre seat depth in band over 48 angular stations, every shell in one BVH-contact assembly, the two wheels mirrored within 5e-5 m, no unchamfered right-angle edge, 17.45 bake texels per UV cell, non-empty glTF. --flush-tyre exits 15 on the z-fight budget; --float-wheel and --short-props exit 16 on the named-support budget; --wide-seams exits 17 on the board seams; --sink-tyre exits 18 on the tyre seat band; --lift-bed exits 18 on the one-assembly budget; --skew-wheel exits 19 on the wheel mirror; --sharp-bar exits 20 on edge treatment; --low-bake exits 21 on texel density; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.

category Village

tags mesh export showcase

@@ -68,7 +68,7 @@

Cart

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles5160–54105284 / 5284 / 5284
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2146
Materialsexactly 2 distinct, metal ≥ 800, wood ≥ 1200 faces2 slots; 1196 metal, 1694 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.580, 0.842, 0.640) m ± 0.01(1.5800, 0.8420, 0.6400)
Collider tris≤ 360192
Bake texelssmallest UV cell ≥ 12 px at the baked resolution17.45 px at 1024 px
Exportwritten, size > 0, removed after measuring403176 / 403176 / 403160 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles5160–54105284 / 5284 / 5284
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2146
Materialsexactly 2 distinct, metal ≥ 800, wood ≥ 1200 faces2 slots; 1196 metal, 1694 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.580, 0.842, 0.640) m ± 0.01(1.5800, 0.8420, 0.6400)
Collider tris≤ 360164
Bake texelssmallest UV cell ≥ 12 px at the baked resolution17.45 px at 1024 px
Exportwritten, size > 0, removed after measuring402904 / 402904 / 402900 bytes (4.5.11 / 5.1.2 / 5.2.1)

Hygiene, supports and joints#

Recomputed from the generated mesh on all three binaries, identical on each.

AxisDeclaredMeasured
Loose V/E, non-manifold, zero-area, doubles @1e-5, n-gonsall 0all 0
Z-fightingcoplanar cross-shell face pairs = 00
Groundedbbox min Z within 1e-4 of 00.0000
Named supports2 legs found; each tyre and leg zmin within 1e-4 of the floor2 legs; all four 0.000000
Material-island gapmetal↔wood min distance ≤ 0.008 m0.00023
Wall boards2 boards per side wall, seams 0.0015–0.005 m(2, 2), seams 0.00300
Tyre seat0.0030–0.0055 m interference, per angular station[0.00400, 0.00400] over 48 stations
One assemblythe shells' BVH-overlap graph is 1 component1 component, 59 shells
Wheel mirrorthe two wheels match in X, Z and extent within 5e-5 m0.00000 mm
Edge treatmentmanifold edges within 5° of 90° = 00 wood, 0 iron
diff --git a/docs/gallery/chopping-block/index.html b/docs/gallery/chopping-block/index.html index ebb6b702..28cffadb 100644 --- a/docs/gallery/chopping-block/index.html +++ b/docs/gallery/chopping-block/index.html @@ -53,7 +53,7 @@

Chopping Block

A log-round chopping block bound with a riveted iron hoop, a felling axe buried in its ringed top, split billets and wood chips scattered at its foot.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 1816 tris, four materials with 180 bark / 216 grain / 412 metal / 176 haft faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.526 x 0.526 x 1.006 m, LOD ratios in band, convex collider 538 tris, non-empty glTF. Hygiene: zero non-manifold edges, loose geometry, doubles, zero-area faces, n-gons and coplanar disjoint face pairs, grounded at zmin 0, log plumb to 1e-7, oval haft 1.35 wide-to-thick. Joint fit: six shells, 13.5 mm haft clearance in the eye, 78.7 mm bit bury, hoop biting 3.7-4.2 mm into the log on every segment, two lap rivets seated 1.50 and 1.54 mm. --fat-haft exits 17 on eye clearance; --round-band and --float-rivets exit 18 on their seats; --round-haft exits 19 on the haft section.
+
witnesses Recomputed: 1816 tris, four materials with 180 bark / 216 grain / 412 metal / 176 haft faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.526 x 0.526 x 1.006 m, LOD ratios in band, convex collider 398 tris, non-empty glTF. Hygiene: zero non-manifold edges, loose geometry, doubles, zero-area faces, n-gons and coplanar disjoint face pairs, grounded at zmin 0, log plumb to 1e-7, oval haft 1.35 wide-to-thick. Joint fit: six shells, 13.5 mm haft clearance in the eye, 78.7 mm bit bury, hoop biting 3.7-4.2 mm into the log on every segment, two lap rivets seated 1.50 and 1.54 mm. --fat-haft exits 17 on eye clearance; --round-band and --float-rivets exit 18 on their seats; --round-haft exits 19 on the haft section.

category Village

tags mesh export showcase

@@ -70,7 +70,7 @@

Chopping Block

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1730–18701816 / 1816 / 1816
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2192 / 0.2192 / 0.2192
Materialsexactly 4 distinct; ≥160 bark, ≥90 grain, ≥170 metal, ≥150 haft faces4 slots; 180 / 216 / 412 / 176
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.526, 0.526, 1.006) m ± 0.012(0.5264, 0.5264, 1.0064)
Collider tris≤ 560538
Exportwritten, size > 0181676 / 181676 / 181660 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1730–18701816 / 1816 / 1816
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2192 / 0.2192 / 0.2192
Materialsexactly 4 distinct; ≥160 bark, ≥90 grain, ≥170 metal, ≥150 haft faces4 slots; 180 / 216 / 412 / 176
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.526, 0.526, 1.006) m ± 0.012(0.5264, 0.5264, 1.0064)
Collider tris≤ 560398
Exportwritten, size > 0174020 / 174020 / 174020 bytes (4.5.11 / 5.1.2 / 5.2.1)

The triangle band, the outer AABB and the collider ceiling were re-fitted in the quality pass that added the lap, the rivets and the 16-segment oval haft (1472 → 1800 triangles, collider 434 → 538). The triangle band is centred on that measurement, ± 4 %. The axe-head reprofile (a waist behind the eye) added one head section: 1800 → 1816.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/crate-stack/index.html b/docs/gallery/crate-stack/index.html index 604300b6..3d9b0d52 100644 --- a/docs/gallery/crate-stack/index.html +++ b/docs/gallery/crate-stack/index.html @@ -53,7 +53,7 @@

Crate Stack

Three grained wooden shipping crates stacked, each turned slightly differently, with nailed iron corner straps.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 6060 tris, two materials with 1344 iron and 2418 timber faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.658×0.524×0.704 m, zmin 0, hygiene 0 including zero coplanar disjoint pairs, three ground runners at z=0, both crate-to-crate seats overlapping, each crate's own footprint 0.588×0.428 m measured in its own frame, yaw spread 0.026 rad and plank spread 2.05 mm across instances, LOD ratios in band, convex collider 230 tris, non-empty glTF. --float-stack exits 18 on the seat; --same-seed exits 20 on per-instance variation.
+
witnesses Recomputed: 6060 tris, two materials with 1344 iron and 2418 timber faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.658×0.524×0.704 m, zmin 0, hygiene 0 including zero coplanar disjoint pairs, three ground runners at z=0, both crate-to-crate seats overlapping, each crate's own footprint 0.588×0.428 m measured in its own frame, yaw spread 0.026 rad and plank spread 2.05 mm across instances, LOD ratios in band, convex collider 204 tris, non-empty glTF. --float-stack exits 18 on the seat; --same-seed exits 20 on per-instance variation.

category Village

tags mesh export showcase

@@ -72,7 +72,7 @@

Reuse with variationBudgets#

Declared in the script as named constants, recomputed from the generated mesh. Measured values below are from Blender 5.2.1; see the table at the end for the 4.5.11 / 5.1.2 figures.

-
BudgetBandMeasured
Base triangles5200–70006060
LOD1 ratio0.32–0.620.5000
LOD2 ratio0.10–0.350.2198
Material slotsexactly 2, distinct2
Iron faces≥ 9001344
Timber faces≥ 18002418
UV boundsinside 0..1(0.0006, 0.0007)–(0.9994, 0.9993)
UV AABB overlap≤ 1e-50.000000
Outer AABB0.658 × 0.524 × 0.704 m ± 0.0200.6583 × 0.5235 × 0.7040
Crate body footprint0.588 × 0.428 m ± 0.015, in the crate's own frame0.5882 × 0.4282 (all three)
Collider triangles≤ 260230
Normal bake{'FINISHED'} with image data{'FINISHED'}, has_data=True
glTF exportfile written, non-empty~490 kB
Hygieneall zeroloose 0/0, non-manifold 0, zero-area 0, doubles 0, n-gons 0, coplanar disjoint pairs 0
Grounded AABB\zmin\≤ 1e-40.00000
Ground runners3 named supports, each zmin ≤ 1e-33 at 0.00000
Crate-to-crate seatboth seats, surface gap ≤ 0.0015 m0.00000 (overlapping)
Yaw bandeach \yaw\in 0.040–0.192 rad0.0681, 0.0943, 0.1093
Per-instance variationyaw spread ≥ 0.020 rad, plank spread ≥ 0.0008 m0.0262 rad, 0.00205 m
Nail seat48 nails; bite 0.3–1.0 mm into the strap, head ≥ 1.0 mm proud48; bite 0.60 mm, proud 1.80 mm
Edge treatmentmanifold edges within 5° of a right angle: 0timber 0, iron 0
+
BudgetBandMeasured
Base triangles5200–70006060
LOD1 ratio0.32–0.620.5000
LOD2 ratio0.10–0.350.2198
Material slotsexactly 2, distinct2
Iron faces≥ 9001344
Timber faces≥ 18002418
UV boundsinside 0..1(0.0006, 0.0007)–(0.9994, 0.9993)
UV AABB overlap≤ 1e-50.000000
Outer AABB0.658 × 0.524 × 0.704 m ± 0.0200.6583 × 0.5235 × 0.7040
Crate body footprint0.588 × 0.428 m ± 0.015, in the crate's own frame0.5882 × 0.4282 (all three)
Collider triangles≤ 260204
Normal bake{'FINISHED'} with image data{'FINISHED'}, has_data=True
glTF exportfile written, non-empty~490 kB
Hygieneall zeroloose 0/0, non-manifold 0, zero-area 0, doubles 0, n-gons 0, coplanar disjoint pairs 0
Grounded AABB\zmin\≤ 1e-40.00000
Ground runners3 named supports, each zmin ≤ 1e-33 at 0.00000
Crate-to-crate seatboth seats, surface gap ≤ 0.0015 m0.00000 (overlapping)
Yaw bandeach \yaw\in 0.040–0.192 rad0.0681, 0.0943, 0.1093
Per-instance variationyaw spread ≥ 0.020 rad, plank spread ≥ 0.0008 m0.0262 rad, 0.00205 m
Nail seat48 nails; bite 0.3–1.0 mm into the strap, head ≥ 1.0 mm proud48; bite 0.60 mm, proud 1.80 mm
Edge treatmentmanifold edges within 5° of a right angle: 0timber 0, iron 0

Real-world size: each crate is 0.58 × 0.42 m at the timber and 0.588 × 0.428 m over the corner iron and its nail heads, 0.244 m tall including runners and lid. Three stacked come to 0.70 m — knee height, wider than tall.

Why the footprint is measured in the crate's own frame#

The stack AABB is the union of three yawed boxes, so a crate could drift to any size underneath it and the outer budget would not notice. Each crate's footprint is therefore measured after un-rotating by the yaw that crate was measured to have, not the yaw it was built with. All three land on 0.5882 × 0.4282 m exactly, which is what makes the un-rotation trustworthy.

@@ -109,7 +109,7 @@

Run itCross-version measurements#

-
Value4.5.115.1.25.2.1
Base triangles606060606060
LOD1 tris / ratio3030 / 0.50003030 / 0.50003030 / 0.5000
LOD2 tris / ratio1332 / 0.21981332 / 0.21981332 / 0.2198
Outer AABB0.6583 × 0.5235 × 0.7040samesame
Collider tris230230230
Yaws (rad)0.0943, −0.1093, 0.0681samesame
Seat gap0.000000.000000.00000
Nails / bite / proud48 / 0.60 mm / 1.80 mmsamesame
Right-angle edges000
Check wall-clock~1.59 s~1.41 s~1.65 s
+
Value4.5.115.1.25.2.1
Base triangles606060606060
LOD1 tris / ratio3030 / 0.50003030 / 0.50003030 / 0.5000
LOD2 tris / ratio1332 / 0.21981332 / 0.21981332 / 0.2198
Outer AABB0.6583 × 0.5235 × 0.7040samesame
Collider tris204204204
Yaws (rad)0.0943, −0.1093, 0.0681samesame
Seat gap0.000000.000000.00000
Nails / bite / proud48 / 0.60 mm / 1.80 mmsamesame
Right-angle edges000
Check wall-clock~1.59 s~1.41 s~1.65 s

Source

diff --git a/docs/gallery/desk-lamp/index.html b/docs/gallery/desk-lamp/index.html index 896c19b5..fec39ee4 100644 --- a/docs/gallery/desk-lamp/index.html +++ b/docs/gallery/desk-lamp/index.html @@ -53,7 +53,7 @@

Desk Lamp

A red balanced-arm desk lamp on a dark studio floor: stepped base, parallel-rod arms with chrome springs and knobs, and a domed shade whose white reflector frames a glowing bulb.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 30110 tris, six materials with 3972 enamel, 9210 steel, 348 bulb, 1508 rubber, 622 reflector and 384 bakelite faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.725×0.361×0.442 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 7 joint pins coaxial with the 23 eyes and bosses they pass through (offset 0.000 mm, band 0.3 mm), all 6 spring loops centred on their bars' axes (band 0.6 mm), mass centre 39.6 mm inside the base footprint (floor 25 mm), base 0.180 m square, arm sections 0.320 and 0.360 m pin to pin, one connected assembly of 78 shells, LOD ratios in band, collider 713 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-pin 17; --unhook-spring 18; --hollow-base 19; --unscrew-bulb 20.
+
witnesses Recomputed: 30110 tris, six materials with 3972 enamel, 9210 steel, 348 bulb, 1508 rubber, 622 reflector and 384 bakelite faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.725×0.361×0.442 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 7 joint pins coaxial with the 23 eyes and bosses they pass through (offset 0.000 mm, band 0.3 mm), all 6 spring loops centred on their bars' axes (band 0.6 mm), mass centre 39.6 mm inside the base footprint (floor 25 mm), base 0.180 m square, arm sections 0.320 and 0.360 m pin to pin, one connected assembly of 78 shells, LOD ratios in band, collider 472 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-pin 17; --unhook-spring 18; --hollow-base 19; --unscrew-bulb 20.

category Household

tags mesh export showcase

@@ -74,7 +74,7 @@

Desk Lamp

Intended size: a 0.18 m square base, 0.32 m and 0.36 m arm sections, and a shade 0.17 m across the rim. The outer AABB is 0.725 × 0.361 × 0.442 m. The shade rim sets +X, the plug sets −X and −Y, and the elbow knuckle sets the top. The origin is under the base centre, so the lamp drops onto a desk by its base.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles29000–3150030110
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 6 distinct; ≥3600 enamel, ≥8300 steel, ≥310 bulb, ≥1350 rubber, ≥560 reflector, ≥340 bakelite faces6 slots; 3972 / 9210 / 348 / 1508 / 622 / 384
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.725, 0.361, 0.442) m ± 0.01(0.7252, 0.3606, 0.4421), zmin 0
Collider tris≤ 760713
Exportwritten, size > 0, removed after measuring2229360 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles29000–3150030110
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 6 distinct; ≥3600 enamel, ≥8300 steel, ≥310 bulb, ≥1350 rubber, ≥560 reflector, ≥340 bakelite faces6 slots; 3972 / 9210 / 348 / 1508 / 622 / 384
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.725, 0.361, 0.442) m ± 0.01(0.7252, 0.3606, 0.4421), zmin 0
Collider tris≤ 760472
Exportwritten, size > 0, removed after measuring2217452 / 2217452 / 2217444 bytes (4.5.11 / 5.1.2 / 5.2.1)

The triangle band is wide enough to hold --hollow-base (30974) and --unhook-spring (29790), so those falsifiers exit on their own budgets rather than on the triangle count.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/espresso-machine/index.html b/docs/gallery/espresso-machine/index.html index 4e0c2e17..8fb925a6 100644 --- a/docs/gallery/espresso-machine/index.html +++ b/docs/gallery/espresso-machine/index.html @@ -53,7 +53,7 @@

Espresso Machine

A brushed stainless E61 espresso machine with twin gauges, a chrome group head and a walnut-handled portafilter over a shot cup, cups on its warmer tray, beside a tamper, milk pitcher and knock box.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 43636 tris, fourteen materials with 4788 stainless, 7284 chrome, 948 bakelite, 632 wood, 5800 ceramic, 1244 rubber, 632 glass, 1642 dial, 64 ink, 36 needle, 91 stone, 26 paint, 452 coffee and 116 lamp faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.670×0.655×0.4755 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the lever pin 0.000000 m off the axis of both bosses and the hub (cap 0.0003) and spanning all three, all five cups seated 0.00020–0.00074 m on the warmer tray or the grate (band 0.0001–0.0009), the body 0.30000 m wide (0.300 ± 0.004) and its warmer tray 0.39070 m above the counter (0.3907 ± 0.004), the portafilter and gasket 0.000000 m off the group's axis (cap 0.0003) and the rim pressed 0.00040 m into the gasket (band 0.0001–0.0008), both gauge glasses 0.0034 m behind their bezels' lips (band 0.0015–0.0050), the drip tray 0.0250 m inside the side panels (floor 0.010) and tucked 0.0170 m behind the front panel (floor 0.005), the mass centre 0.1064 m inside the feet's support polygon (floor 0.060) at 39.83 kg, one connected assembly of 94 shells, LOD ratios in band, collider 447 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --sink-cup 18; --narrow-body 19; --offset-pf 20; --drop-pf 21; --proud-gauge 22; --shift-tray 23; --bunch-feet 24; --loose-knob 25.
+
witnesses Recomputed: 43636 tris, fourteen materials with 4788 stainless, 7284 chrome, 948 bakelite, 632 wood, 5800 ceramic, 1244 rubber, 632 glass, 1642 dial, 64 ink, 36 needle, 91 stone, 26 paint, 452 coffee and 116 lamp faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.670×0.655×0.4755 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the lever pin 0.000000 m off the axis of both bosses and the hub (cap 0.0003) and spanning all three, all five cups seated 0.00020–0.00074 m on the warmer tray or the grate (band 0.0001–0.0009), the body 0.30000 m wide (0.300 ± 0.004) and its warmer tray 0.39070 m above the counter (0.3907 ± 0.004), the portafilter and gasket 0.000000 m off the group's axis (cap 0.0003) and the rim pressed 0.00040 m into the gasket (band 0.0001–0.0008), both gauge glasses 0.0034 m behind their bezels' lips (band 0.0015–0.0050), the drip tray 0.0250 m inside the side panels (floor 0.010) and tucked 0.0170 m behind the front panel (floor 0.005), the mass centre 0.1064 m inside the feet's support polygon (floor 0.060) at 39.83 kg, one connected assembly of 94 shells, LOD ratios in band, collider 346 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --sink-cup 18; --narrow-body 19; --offset-pf 20; --drop-pf 21; --proud-gauge 22; --shift-tray 23; --bunch-feet 24; --loose-knob 25.

category Household

tags mesh export showcase

@@ -75,7 +75,7 @@

Espresso Machine

Intended size: a machine 0.300 m wide and 0.391 m to its warmer tray on a 0.03 m counter, 0.376 m deep plus a 0.12 m drip tray, with a 0.064 m cappuccino cup setting the top. The outer AABB is 0.670 × 0.655 × 0.4755 m: the counter sets the plan and the cup the top. The origin is under the counter.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles43000–4430043636
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 14 distinct; face floors ≥4400 stainless, ≥6700 chrome, ≥870 bakelite, ≥580 wood, ≥5330 ceramic, ≥1140 rubber, ≥580 glass, ≥1510 dial, ≥58 ink, ≥32 needle, ≥84 stone, ≥24 paint, ≥415 coffee, ≥106 lamp14 slots; 4788 / 7284 / 948 / 632 / 5800 / 1244 / 632 / 1642 / 64 / 36 / 91 / 26 / 452 / 116
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.670, 0.655, 0.4755) m ± 0.01(0.6700, 0.6550, 0.4755), zmin 0
Collider tris≤ 520447
Exportwritten, size > 0, removed after measuring3229536 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles43000–4430043636
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 14 distinct; face floors ≥4400 stainless, ≥6700 chrome, ≥870 bakelite, ≥580 wood, ≥5330 ceramic, ≥1140 rubber, ≥580 glass, ≥1510 dial, ≥58 ink, ≥32 needle, ≥84 stone, ≥24 paint, ≥415 coffee, ≥106 lamp14 slots; 4788 / 7284 / 948 / 632 / 5800 / 1244 / 632 / 1642 / 64 / 36 / 91 / 26 / 452 / 116
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.670, 0.655, 0.4755) m ± 0.01(0.6700, 0.6550, 0.4755), zmin 0
Collider tris≤ 520346
Exportwritten, size > 0, removed after measuring3222244 / 3222244 / 3222236 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the topology, so every one of them measures the default's 43636 triangles. Every one keeps the default's AABB except --sink-cup, which sinks the cup that sets the top 3 mm and measures 0.4725 m, inside the 10 mm tolerance.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/fallen-log/index.html b/docs/gallery/fallen-log/index.html index 03793bf3..645cca5c 100644 --- a/docs/gallery/fallen-log/index.html +++ b/docs/gallery/fallen-log/index.html @@ -53,7 +53,7 @@

Fallen Log

A mossy fallen log settled into a soil mound: furrowed dark bark peeled in patches, a hollow ringed butt, a splintered top, shelf fungi, toadstools, ferns and fallen leaves.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 36374 tris, nine materials with 5144 bark, 892 wood, 384 rot, 2400 moss, 2448 bracket, 1296 toadstool, 2494 soil, 2080 litter and 5090 fern faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.119×2.189×1.027 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the log bedded in the soil at 0.889 of its stations (floor 0.75, depth band 0.020–0.090 m), all 12 bracket shelves rooted 0.021–0.029 m into the bark (band 0.008–0.050), the log's mass centre 0.149 m inside the plan hull of its buried vertices (floor 0.06), 0.992 of the moss top area facing up or north (floor 0.85), all 436 ground-cover shells joined to the soil, LOD ratios in band, log collider 215 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --hump-ground 17; --float-fungi 18; --tilt-ground 19; --sunny-moss 20; --float-litter 21.
+
witnesses Recomputed: 36374 tris, nine materials with 5144 bark, 892 wood, 384 rot, 2400 moss, 2448 bracket, 1296 toadstool, 2494 soil, 2080 litter and 5090 fern faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.119×2.189×1.027 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the log bedded in the soil at 0.889 of its stations (floor 0.75, depth band 0.020–0.090 m), all 12 bracket shelves rooted 0.021–0.029 m into the bark (band 0.008–0.050), the log's mass centre 0.149 m inside the plan hull of its buried vertices (floor 0.06), 0.992 of the moss top area facing up or north (floor 0.85), all 436 ground-cover shells joined to the soil, LOD ratios in band, log collider 142 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --hump-ground 17; --float-fungi 18; --tilt-ground 19; --sunny-moss 20; --float-litter 21.

category Nature

tags mesh export showcase

@@ -71,7 +71,7 @@

Fallen Log

Intended size: a log 3.60 m long to the tip of its longest splinter, its top 0.67 m off the ground, on a soil mound 4.12 × 2.17 m. The outer AABB is 4.119 × 2.189 × 1.027 m. The soil sets X and the south edge, the tip of one fern frond the north edge, and the upright stub's broken tip the top. The soil's underside is the ground. The collider is the convex hull of the log alone, round and unfurrowed: players walk through ferns.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles35600–3720036374
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥4600 bark, ≥800 wood, ≥340 rot, ≥2150 moss, ≥2200 bracket, ≥1160 toadstool, ≥2240 soil, ≥1870 litter, ≥4580 fern faces9 slots; 5144 / 892 / 384 / 2400 / 2448 / 1296 / 2494 / 2080 / 5090
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(4.1189, 2.1885, 1.0267) m ± 0.01(4.1189, 2.1885, 1.0267), zmin 0
Collider tris (log hull)≤ 240215
Exportwritten, size > 0, removed after measuring2826044 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles35600–3720036374
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥4600 bark, ≥800 wood, ≥340 rot, ≥2150 moss, ≥2200 bracket, ≥1160 toadstool, ≥2240 soil, ≥1870 litter, ≥4580 fern faces9 slots; 5144 / 892 / 384 / 2400 / 2448 / 1296 / 2494 / 2080 / 5090
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(4.1189, 2.1885, 1.0267) m ± 0.01(4.1189, 2.1885, 1.0267), zmin 0
Collider tris (log hull)≤ 240142
Exportwritten, size > 0, removed after measuring2823404 / 2823404 / 2823392 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the triangle count: they move parts or the soil, never add or remove them.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/fence-kit/index.html b/docs/gallery/fence-kit/index.html index 286edf04..e319d1be 100644 --- a/docs/gallery/fence-kit/index.html +++ b/docs/gallery/fence-kit/index.html @@ -53,7 +53,7 @@

Fence Kit

A weathered post-and-rail fence run of three sections on a packed-earth strip, one capped post at each joint, each bay with a diagonal board brace and dark iron bands.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 1012 tris, two materials with 116 metal and 390 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.596×0.134×1.232 m inside the 1.60 m tile, grounded zmin, 2 iron shoes, brace housed 12 mm in both posts and bearing 2 mm on the middle rail, rail-to-post gap 0.93 mm, rail span 1.362 m, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 24 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-brace 17; --gap-rails 18; --long-rails 19; --float-brace 20; --wide-tile 21.
+
witnesses Recomputed: 1012 tris, two materials with 116 metal and 390 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.596×0.134×1.232 m inside the 1.60 m tile, grounded zmin, 2 iron shoes, brace housed 12 mm in both posts and bearing 2 mm on the middle rail, rail-to-post gap 0.93 mm, rail span 1.362 m, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 20 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-brace 17; --gap-rails 18; --long-rails 19; --float-brace 20; --wide-tile 21.

category Village

tags mesh export showcase

@@ -70,7 +70,7 @@

Fence Kit

Intended size: 1.60 m tile, 1.14 m posts, 0.11 m post stock. Outer AABB 1.596 × 0.134 × 1.232 m.

Budgets#

Declared as named constants. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles850–12001012 / 1012 / 1012
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2194 / 0.2194 / 0.2174
Materialsexactly 2 distinct, ≥48 metal, ≥48 wood2 slots, 116 metal / 390 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.596, 0.134, 1.232) m ± 0.015(1.5960, 0.1340, 1.2320), zmin 0
Collider tris≤ 18024
Exportwritten, size > 075900 / 75900 / 75888 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles850–12001012 / 1012 / 1012
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2194 / 0.2194 / 0.2174
Materialsexactly 2 distinct, ≥48 metal, ≥48 wood2 slots, 116 metal / 390 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.596, 0.134, 1.232) m ± 0.015(1.5960, 0.1340, 1.2320), zmin 0
Collider tris≤ 18020
Exportwritten, size > 074952 / 74952 / 74944 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles dropped from 1092 to 1012 in the second quality pass. Each band became one mitred shell instead of three or four separate plates, and the brace became a six-face board. The band was re-fitted around the measurement and narrowed from 1000–1400.

DECIMATE COLLAPSE triangle counts are not identical across series: 5.2.1 is more aggressive on LOD2. The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction is closed-form and plank tones are seeded, so repeated runs on one binary print identical measurements. Export byte counts differ by 12 B on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

diff --git a/docs/gallery/fern-mossy-rock/index.html b/docs/gallery/fern-mossy-rock/index.html index 8e538939..11ae3676 100644 --- a/docs/gallery/fern-mossy-rock/index.html +++ b/docs/gallery/fern-mossy-rock/index.html @@ -74,7 +74,7 @@

Fern Mossy Rock

The piece is 86,740 triangles, 58% of them pinnae; the boulder's lattice went from 28 to 36 cells a side (16,224 stone faces) so its arrises are resolved at a 16–20 mm weathering radius instead of hidden in 40–110 mm bevels. A fern is its pinnae, and the whole point of this one is pinnule detail that holds up at hero size.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles86300–8720086740
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 10 distinct; face floors stone ≥15600, moss ≥4360, frond ≥48400, stipe ≥1480, crozier ≥750, rootstock ≥290, soil ≥2350, litter ≥1660, twig ≥64, sorrel ≥206010 slots; 16224 / 4548 / 50428 / 1545 / 780 / 303 / 2446 / 1728 / 66 / 2150
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.2872, 1.9008, 1.1111) m ± 0.01(2.2872, 1.9008, 1.1111), zmin 0
Collider tris (boulder hull)≤ 200130
Exportwritten, size > 0, removed after measuring10731436 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles86300–8720086740
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 10 distinct; face floors stone ≥15600, moss ≥4360, frond ≥48400, stipe ≥1480, crozier ≥750, rootstock ≥290, soil ≥2350, litter ≥1660, twig ≥64, sorrel ≥206010 slots; 16224 / 4548 / 50428 / 1545 / 780 / 303 / 2446 / 1728 / 66 / 2150
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.2872, 1.9008, 1.1111) m ± 0.01(2.2872, 1.9008, 1.1111), zmin 0
Collider tris (boulder hull)≤ 200130
Exportwritten, size > 0, removed after measuring10731448 / 10731448 / 10731436 bytes (4.5.11 / 5.1.2 / 5.2.1)

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; two default runs print identical measurements, and 4.5.11 and 5.1.2 print the same measurements as 5.2.1 (the glTF differs by 12 bytes).

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/floor-fan/index.html b/docs/gallery/floor-fan/index.html index ae7e6079..7da47403 100644 --- a/docs/gallery/floor-fan/index.html +++ b/docs/gallery/floor-fan/index.html @@ -53,7 +53,7 @@

Floor Fan

A sage-green 1950s pedestal fan, head turned on a tilt yoke: chrome wire guard over four brass blades, telescoping column, round cast base with a speed knob, cord to a plug.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 41460 tris, six materials with 4732 enamel, 13960 chrome, 584 brass, 1216 rubber, 810 bakelite and 440 badge faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.761×0.704×1.229 m, zmin 0 with the gasket on the floor, hygiene 0 including zero coplanar cross-shell pairs, hub, spinner, shaft, badge, rear mount and motor housing on the axis the rim rings define (worst 0.000001 m, cap 0.0005), all 48 spokes ending inside their rim rings (worst 0.0007 m from the ring's centreline, cap 0.0026) and each of 7 rings crossing all 24 spokes of its half, both column tubes plumb (0.000°, cap 0.2°) and on the base's axis (0.0000 m, cap 0.001), guard 0.452 m and base 0.400 m across, blade tips 0.0195 m inside the rim rings (band 0.012–0.030) and 0.0140 m from the nearest wire (floor 0.006), four blades 90° apart within 0.0002° (cap 0.3°), a 28.4 kg fan that stands on a 19.06° incline before it tips (floor 16°), one connected assembly of 109 shells, LOD ratios in band, collider 1997 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-hub 17; --short-spoke 18; --lean-column 19; --long-blades 20; --skew-blade 21; --hollow-base 22; --loose-spinner 23.
+
witnesses Recomputed: 41460 tris, six materials with 4732 enamel, 13960 chrome, 584 brass, 1216 rubber, 810 bakelite and 440 badge faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.761×0.704×1.229 m, zmin 0 with the gasket on the floor, hygiene 0 including zero coplanar cross-shell pairs, hub, spinner, shaft, badge, rear mount and motor housing on the axis the rim rings define (worst 0.000001 m, cap 0.0005), all 48 spokes ending inside their rim rings (worst 0.0007 m from the ring's centreline, cap 0.0026) and each of 7 rings crossing all 24 spokes of its half, both column tubes plumb (0.000°, cap 0.2°) and on the base's axis (0.0000 m, cap 0.001), guard 0.452 m and base 0.400 m across, blade tips 0.0195 m inside the rim rings (band 0.012–0.030) and 0.0140 m from the nearest wire (floor 0.006), four blades 90° apart within 0.0002° (cap 0.3°), a 28.4 kg fan that stands on a 19.06° incline before it tips (floor 16°), one connected assembly of 109 shells, LOD ratios in band, collider 1560 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-hub 17; --short-spoke 18; --lean-column 19; --long-blades 20; --skew-blade 21; --hollow-base 22; --loose-spinner 23.

category Household

tags mesh export showcase

@@ -76,7 +76,7 @@

Floor Fan

Intended size: a 0.40 m base, a guard 0.452 m across its rim, and 1.23 m overall. The outer AABB is 0.761 × 0.704 × 1.229 m. The guard's rim sets the top, the guard and the cord's loop set the plan. The origin is under the base centre, so the fan drops onto a floor by its gasket.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles40600–4190041460
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 6 distinct; ≥4350 enamel, ≥12800 chrome, ≥540 brass, ≥1120 rubber, ≥740 bakelite, ≥400 badge faces6 slots; 4732 / 13960 / 584 / 1216 / 810 / 440
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.761, 0.704, 1.230) m ± 0.01(0.7614, 0.7039, 1.2286), zmin 0
Collider tris≤ 22001997
Exportwritten, size > 0, removed after measuring3114936 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles40600–4190041460
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 6 distinct; ≥4350 enamel, ≥12800 chrome, ≥540 brass, ≥1120 rubber, ≥740 bakelite, ≥400 badge faces6 slots; 4732 / 13960 / 584 / 1216 / 810 / 440
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.761, 0.704, 1.230) m ± 0.01(0.7614, 0.7039, 1.2286), zmin 0
Collider tris≤ 22001560
Exportwritten, size > 0, removed after measuring3119064 / 3119064 / 3119060 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the topology, so every one of them measures the default's 41460 triangles and the default's AABB.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/go-kart/index.html b/docs/gallery/go-kart/index.html index 557854db..b55fd3ce 100644 --- a/docs/gallery/go-kart/index.html +++ b/docs/gallery/go-kart/index.html @@ -53,7 +53,7 @@

Go Kart

Blue go-kart on a patch of track asphalt before a red and white kerb: moulded nose, side pods and a front panel with a white plate, red tube chassis, black seat, finned engine.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 81854 tris, fourteen materials with 3168 frame paint, 6994 chrome, 8188 rubber, 3708 bodywork, 1548 seat, 12666 aluminium, 1920 engine casting, 4130 steel, 1686 black plastic, 172 fuel tank, 168 lead, 646 asphalt, 126 kerb paint and 124 number plate faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.895×1.774×0.640 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 tyres pressed 1.5 mm into the asphalt with their patches in one plane (band 0.8–3.0 mm), 4 hubs and 2 bearings 0.0 mm off their axles (≤ 0.3 mm), 4 tie-rod eyes on their pins and biting their plates 0.3–0.5 mm, tyre beads seated 0.864–1.000 mm on the rims (band 0.4–2.0 mm), the chain's inner edge 1.911–1.946 mm under both tooth-root circles (band 0.8–3.0 mm), frame and bodywork mirrored within 0.043 mm and the wheels within 0.0001 mm, wheelbase 1.040 m and tracks 1.100 / 1.200 m, caster 14.0°, the mass centre 0.374 m inside the tyres' support polygon (≥ 0.312 m), one connected assembly of 330 shells, 10 bodywork brackets each biting its tube 0.90–1.99 mm and its moulding 1.00–1.47 mm (band 0.5–2.5 mm), LOD ratios in band, collider 816 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --cock-hub 17; --drop-bearing 17; --short-tierod 17; --sink-tyre 18; --lift-chain 18; --toe-wheel 19; --wide-track 19; --odd-frame 19; --no-caster 19; --aft-ballast 20; --loose-ballast 21; --float-nose 23.
+
witnesses Recomputed: 81854 tris, fourteen materials with 3168 frame paint, 6994 chrome, 8188 rubber, 3708 bodywork, 1548 seat, 12666 aluminium, 1920 engine casting, 4130 steel, 1686 black plastic, 172 fuel tank, 168 lead, 646 asphalt, 126 kerb paint and 124 number plate faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.895×1.774×0.640 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 tyres pressed 1.5 mm into the asphalt with their patches in one plane (band 0.8–3.0 mm), 4 hubs and 2 bearings 0.0 mm off their axles (≤ 0.3 mm), 4 tie-rod eyes on their pins and biting their plates 0.3–0.5 mm, tyre beads seated 0.864–1.000 mm on the rims (band 0.4–2.0 mm), the chain's inner edge 1.911–1.946 mm under both tooth-root circles (band 0.8–3.0 mm), frame and bodywork mirrored within 0.043 mm and the wheels within 0.0001 mm, wheelbase 1.040 m and tracks 1.100 / 1.200 m, caster 14.0°, the mass centre 0.374 m inside the tyres' support polygon (≥ 0.312 m), one connected assembly of 330 shells, 10 bodywork brackets each biting its tube 0.90–1.99 mm and its moulding 1.00–1.47 mm (band 0.5–2.5 mm), LOD ratios in band, collider 598 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --cock-hub 17; --drop-bearing 17; --short-tierod 17; --sink-tyre 18; --lift-chain 18; --toe-wheel 19; --wide-track 19; --odd-frame 19; --no-caster 19; --aft-ballast 20; --loose-ballast 21; --float-nose 23.

category Vehicles

tags mesh export showcase

@@ -69,7 +69,7 @@

Go Kart

Intended size: wheelbase 1.040 m, front track 1.100 m and rear track 1.200 m (tyre centre to tyre centre); overall 1.75 × 1.40 m, the seat back 0.47 m over the asphalt. The patch with its kerb is 1.90 × 1.77 m; the top of the envelope is the seat back at 0.64 m. The origin is under the patch centre at the slab's underside.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file. Shells are found by a part face attribute; every measured value is read from their vertices.

-
AxisDeclaredMeasured (5.2.1)
Base triangles81000–8270081854
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 14 distinct; ≥2910 frame paint, ≥6430 chrome, ≥7530 rubber, ≥3410 bodywork, ≥1420 seat, ≥11650 aluminium, ≥1760 engine casting, ≥3790 steel, ≥1550 black plastic, ≥158 fuel tank, ≥154 lead, ≥590 asphalt, ≥115 kerb paint, ≥114 number plate faces14 slots; 3168 / 6994 / 8188 / 3708 / 1548 / 12666 / 1920 / 4130 / 1686 / 172 / 168 / 646 / 126 / 124
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.8950, 1.7738, 0.6397) m ± 0.01, read off the vertices(1.8950, 1.7738, 0.6397), zmin 0
Collider tris≤ 900816
Exportwritten, size > 0, removed after measuring6084452 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles81000–8270081854
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 14 distinct; ≥2910 frame paint, ≥6430 chrome, ≥7530 rubber, ≥3410 bodywork, ≥1420 seat, ≥11650 aluminium, ≥1760 engine casting, ≥3790 steel, ≥1550 black plastic, ≥158 fuel tank, ≥154 lead, ≥590 asphalt, ≥115 kerb paint, ≥114 number plate faces14 slots; 3168 / 6994 / 8188 / 3708 / 1548 / 12666 / 1920 / 4130 / 1686 / 172 / 168 / 646 / 126 / 124
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.8950, 1.7738, 0.6397) m ± 0.01, read off the vertices(1.8950, 1.7738, 0.6397), zmin 0
Collider tris≤ 900598
Exportwritten, size > 0, removed after measuring6072672 / 6072672 / 6072664 bytes (4.5.11 / 5.1.2 / 5.2.1)

Every falsifier leaves the triangle count at 81854 and the envelope at (1.8950, 1.7738, 0.6397): they move parts, never add or remove them.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements, and 4.5.11 and 5.1.2 print the same measurements as 5.2.1 (the export differs by 76 bytes).

Hygiene and grounding#

diff --git a/docs/gallery/grindstone/index.html b/docs/gallery/grindstone/index.html index d5f3bfa6..3cb0a80f 100644 --- a/docs/gallery/grindstone/index.html +++ b/docs/gallery/grindstone/index.html @@ -53,7 +53,7 @@

Grindstone

A sandstone grindstone wheel dipping into a water-filled trough, turning in a chamfered timber A-frame with its iron crank toward the viewer, the sills capped by iron shoes.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 1668 tris, three materials with 400 wood / 240 stone / 364 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.419×0.610 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, four shoes planted, trough seated in the sills and biting both stretchers 4 mm, stone dip 24 mm, no unchamfered right-angle edge, 29.44 bake texels per UV cell, LOD ratios in band, convex collider 304 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert / --flush-shoes exit 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --float-crank / --float-legs exit 17 on joint fit; --no-dip / --narrow-trough / --low-stretchers exit 18 on seat; --sharp-handle exits 20 on edge treatment; --low-bake exits 21 on texel density.
+
witnesses Recomputed: 1668 tris, three materials with 400 wood / 240 stone / 364 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.419×0.610 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, four shoes planted, trough seated in the sills and biting both stretchers 4 mm, stone dip 24 mm, no unchamfered right-angle edge, 29.44 bake texels per UV cell, LOD ratios in band, convex collider 202 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert / --flush-shoes exit 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --float-crank / --float-legs exit 17 on joint fit; --no-dip / --narrow-trough / --low-stretchers exit 18 on seat; --sharp-handle exits 20 on edge treatment; --low-bake exits 21 on texel density.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Grindstone

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1560–17801668 / 1668 / 1668
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2194 / 0.2194 / 0.2194
Materialsexactly 3 distinct; ≥ 280 wood, ≥ 190 stone, ≥ 260 metal faces3 slots; 400 / 240 / 364
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.722, 0.419, 0.610) m ± 0.015(0.7220, 0.4185, 0.6100), zmin 0
Collider tris≤ 320304
Bake texelssmallest UV cell ≥ 12 px at the baked resolution29.44 px at 1024 px
Exportwritten, size > 0152272 / 152272 / 152260 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1560–17801668 / 1668 / 1668
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2194 / 0.2194 / 0.2194
Materialsexactly 3 distinct; ≥ 280 wood, ≥ 190 stone, ≥ 260 metal faces3 slots; 400 / 240 / 364
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.722, 0.419, 0.610) m ± 0.015(0.7220, 0.4185, 0.6100), zmin 0
Collider tris≤ 320202
Bake texelssmallest UV cell ≥ 12 px at the baked resolution29.44 px at 1024 px
Exportwritten, size > 0147532 / 147532 / 147528 bytes (4.5.11 / 5.1.2 / 5.2.1)

The collider ceiling moved from 240 to 320 with the stone. 48 segments put more of its rim on the hull (198 → 304 triangles).

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/hand-pump/index.html b/docs/gallery/hand-pump/index.html index 8ed75d80..8fcece23 100644 --- a/docs/gallery/hand-pump/index.html +++ b/docs/gallery/hand-pump/index.html @@ -53,7 +53,7 @@

Hand Pump

A green-enamelled cast-iron village pump with a fluted barrel, ball finial and counterweighted handle on a wooden plinth, a hooped bucket under its spout.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 2412 tris, two materials with 1134 metal and 332 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.610×0.521×1.055 m, grounded zmin, spout-to-column gap 2.4 mm, flange-to-plinth gap 6.0 mm, column radius 68 mm, LOD ratios in band, convex collider 205 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-spout 17; --float-flange 18; --skinny-col 19.
+
witnesses Recomputed: 2412 tris, two materials with 1134 metal and 332 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.610×0.521×1.055 m, grounded zmin, spout-to-column gap 2.4 mm, flange-to-plinth gap 6.0 mm, column radius 68 mm, LOD ratios in band, convex collider 146 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-spout 17; --float-flange 18; --skinny-col 19.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Hand Pump

Intended size: ~1.05 m village pump, 0.34 m plinth, 0.76 m column, 0.15 m bucket; outer AABB 0.610 × 0.521 × 1.055 m.

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.2.1; 5.1.2 not re-run after the model pass)
Base triangles900–26002412 / 2412
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2181
Materialsexactly 2 distinct, ≥48 metal, ≥24 wood2 slots, 1134 metal / 332 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.610, 0.521, 1.055) m ± 0.015(0.6100, 0.5210, 1.0545), zmin 0
Collider tris≤ 220 (source turns the bucket at 8 staves, no hoops)205
Exportwritten, size > 0202576 bytes (5.2.1)
+
AxisDeclaredMeasured (4.5.11 / 5.2.1; 5.1.2 not re-run after the model pass)
Base triangles900–26002412 / 2412
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2181
Materialsexactly 2 distinct, ≥48 metal, ≥24 wood2 slots, 1134 metal / 332 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.610, 0.521, 1.055) m ± 0.015(0.6100, 0.5210, 1.0545), zmin 0
Collider tris≤ 220 (source turns the bucket at 8 staves, no hoops)146
Exportwritten, size > 0200352 / 200352 / 200348 bytes (4.5.11 / 5.1.2 / 5.2.1)

The model pass took the pump from 1064 to 2412 triangles and raised the ceiling 2200 → 2600. Two lighting-and-paint passes had left it the plainest object in its asset sheet: a smooth two-step column on a box. It now carries the cast detail a village pump has: a turned lower barrel with a moulded foot and a spout boss, eight flutes on the upper barrel, a moulded collar at the socket, a domed cap and ball finial on the head, a rolled drip lip on the nozzle, a counterweighted tail on the handle, and a turned grip. A coopered bucket with two iron hoops stands under the spout, clear of the plinth. The spout's reach grew 0.13 → 0.17 m (SPOUT_R) so the nozzle clears the plinth and falls inside the bucket mouth. The outer AABB grew in y (0.382 → 0.521 m) for the bucket and in z (1.052 → 1.055 m) for the finial. The collider stays under its 220 ceiling because its source turns the bucket at 8 staves without hoops (BUCKET_PROXY_SEGS); at 16 staves the hull ran to 267, past Unity's 255 convex-collider limit. The foot (0.068 m) and spout boss (0.067 m) stay within COL_R_TOL of COL_R_LO, so the column-radius budget still reads the barrel. The flange classifier now also requires a shell centred on the column axis: the bucket's lower hoop is as wide and as low as the flange, and would otherwise mask --float-flange. The new bucket budget gets its own falsifier, --shift-bucket (exit 20).

Earlier, base triangles dropped from 1164 to 1064 in the quality pass: seven sausage cylinders became one gooseneck tube, and the wood grip is no longer beveled with the plinth. Outer AABB is 0.610 × 0.382 × 1.052 m (was 0.610 × 0.364 × 1.049 m).

DECIMATE COLLAPSE triangle counts are not identical across series — 5.2.1 is slightly leaner on LOD2. The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction is closed-form; the only RNG is the seeded per-piece wood tone. Bevel inputs are sorted by edge index, so the face order is the same on every run; a Python set of edges handed to the bevel had made it vary. Export byte counts differ on 5.2.1 (glTF serializer), not a gated axis.

diff --git a/docs/gallery/hay-bale/index.html b/docs/gallery/hay-bale/index.html index 1cb87ef1..73b2338b 100644 --- a/docs/gallery/hay-bale/index.html +++ b/docs/gallery/hay-bale/index.html @@ -72,7 +72,7 @@

How the belts are builtBudgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file. Measurements below are identical on 4.5.11, 5.1.2 and 5.2.1 — construction uses no RNG and no version-dependent operator.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1700–24002044 on all three
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2192
Materialsexactly 2 distinct, ≥24 hay, ≥24 twine2 slots, 1436 hay, 304 twine
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.921, 0.508, 0.417) m ± 0.01(0.9208, 0.5075, 0.4165)
Grounded zminwithin 1e-4 of 00.000000
Hygieneloose/nonman/zero-area/doubles/n-gons/z-fight = 0all 0
Shell countexactly 5 (loaf, 2 belts, 2 loops)5
Belt wrap zmineach belt shell ≤ 0.006 m0.001460 both
Belt seat depthevery station in [0.002, 0.020] m0.00400..0.01114 over 20/20 stations, both belts
Mirror symmetrybelts and loops matched within 5e-4 m0.000000
Loaf mirrorevery loaf vertex has an X-mirror partner within 2e-4 m0.000093
Cinch depthmid-span minus waist in [0.006, 0.020] m0.01053
Loaf X × Z(0.921, 0.393) m ± 0.02(0.9208, 0.3931)
Hay–twine gapBVH surface < 0.008 m0.00009
Collider tris≤ 400100
Bake texelssmallest UV cell ≥ 12 px at the baked resolution22.43 px at 1024 px
Exportwritten, size > 0203508 / 203508 / 203496 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1700–24002044 on all three
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2192
Materialsexactly 2 distinct, ≥24 hay, ≥24 twine2 slots, 1436 hay, 304 twine
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.921, 0.508, 0.417) m ± 0.01(0.9208, 0.5075, 0.4165)
Grounded zminwithin 1e-4 of 00.000000
Hygieneloose/nonman/zero-area/doubles/n-gons/z-fight = 0all 0
Shell countexactly 5 (loaf, 2 belts, 2 loops)5
Belt wrap zmineach belt shell ≤ 0.006 m0.001460 both
Belt seat depthevery station in [0.002, 0.020] m0.00400..0.01114 over 20/20 stations, both belts
Mirror symmetrybelts and loops matched within 5e-4 m0.000000
Loaf mirrorevery loaf vertex has an X-mirror partner within 2e-4 m0.000093
Cinch depthmid-span minus waist in [0.006, 0.020] m0.01053
Loaf X × Z(0.921, 0.393) m ± 0.02(0.9208, 0.3931)
Hay–twine gapBVH surface < 0.008 m0.00009
Collider tris≤ 400100
Bake texelssmallest UV cell ≥ 12 px at the baked resolution22.43 px at 1024 px
Exportwritten, size > 0200356 / 200356 / 200348 bytes (4.5.11 / 5.1.2 / 5.2.1)

DECIMATE COLLAPSE triangle counts are not guaranteed identical across series — the gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity, plus the texel floor. The bake was 256 px, which left 5.6 texels per UV cell and smeared neighbouring cells' normals into streaks across the straw; at 1024 px with a 0.02 m cage (was 0.04, which reached the twine standing proud of the loaf) every cell gets 22. Export byte counts differ by 12 B on 5.2.1 (glTF serializer), which is not a gated axis; every geometric figure above is identical on all three binaries.

The export is deleted once its size is measured. Blender sets TMPDIR from its own preference, which resolves to the working directory on a stock portable build, so tempfile.gettempdir() is the repo root under CI and every run used to leave a .glb behind.

Why these budgets and not an AABB#

diff --git a/docs/gallery/hitching-post/index.html b/docs/gallery/hitching-post/index.html index 038d409c..c5a6f9f2 100644 --- a/docs/gallery/hitching-post/index.html +++ b/docs/gallery/hitching-post/index.html @@ -53,7 +53,7 @@

Hitching Post

A tall wooden hitching post with a pointed cap, a cross-rail on two knee braces with iron end caps and two hung rings, iron bands, and a horseshoe nailed to its face.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 2156 tris, two materials with 222 wood and 880 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.506×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, bands 6.5 mm proud of the post, horseshoe biting 1.5 mm and 7.5 mm proud, LOD ratios in band, convex collider 72 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring, --sunk-bands and --float-horseshoe exit 18; --short-post exits 19.
+
witnesses Recomputed: 2156 tris, two materials with 222 wood and 880 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.506×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, bands 6.5 mm proud of the post, horseshoe biting 1.5 mm and 7.5 mm proud, LOD ratios in band, convex collider 44 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring, --sunk-bands and --float-horseshoe exit 18; --short-post exits 19.

category Village

tags mesh export showcase

@@ -68,7 +68,7 @@

Hitching Post

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package). Hygiene combinatorics match examples/mesh-hygiene-audit (copied, not imported). Coplanar-pair counting matches showcase/signpost.

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles1400–24002156 / 2156
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199
Materialsexactly 2 distinct, ≥70 wood, ≥560 metal2 slots, 222 wood, 880 metal
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.506, 0.149, 1.246) m ± 0.01(0.5060, 0.1490, 1.2460)
Grounded zminwithin 1e-4 of 00 / 0 / 0
Hygieneloose/nonman/zero-area/doubles/n-gons/coplanar pairs = 0all 0
Post seatworld zmin in (0.004, 0.014), XY centroid within 0.010 of origin, arm axis cos ≥ cos(0.5°)0.01000, 0, 1.000
Hung ringcenterline error ≤ 0.008 m, ring–wood overlap 0, eye–wood overlap 0, shank–ring overlap 0, shank bites the eye0, 0, 0, 0, 40
Shoeeach band overlaps the post, shoe overlaps the soleband gap 0, sole–shoe 8
Band seateach band above the shoe stands ≥ 0.004 m proud of the post faces0.00650
Horseshoe seatexactly 1; back bites the post face 0.0005–0.004 m, face ≥ 0.004 m proud1, 0.00150, 0.00750
Brace seatexactly 2 knee braces, each housed in the post and in the rail (triangle overlap ≥ 1 with each); exactly 2 end caps, each gripping the rail2 braces, worst post 12 / rail 16; 2 caps, worst 12
Wood–metal gapBVH surface < 0.008 m0.00075
Collider tris≤ 28072
Exportwritten, size > 0160548 / 160532 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles1400–24002156 / 2156
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199
Materialsexactly 2 distinct, ≥70 wood, ≥560 metal2 slots, 222 wood, 880 metal
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.506, 0.149, 1.246) m ± 0.01(0.5060, 0.1490, 1.2460)
Grounded zminwithin 1e-4 of 00 / 0 / 0
Hygieneloose/nonman/zero-area/doubles/n-gons/coplanar pairs = 0all 0
Post seatworld zmin in (0.004, 0.014), XY centroid within 0.010 of origin, arm axis cos ≥ cos(0.5°)0.01000, 0, 1.000
Hung ringcenterline error ≤ 0.008 m, ring–wood overlap 0, eye–wood overlap 0, shank–ring overlap 0, shank bites the eye0, 0, 0, 0, 40
Shoeeach band overlaps the post, shoe overlaps the soleband gap 0, sole–shoe 8
Band seateach band above the shoe stands ≥ 0.004 m proud of the post faces0.00650
Horseshoe seatexactly 1; back bites the post face 0.0005–0.004 m, face ≥ 0.004 m proud1, 0.00150, 0.00750
Brace seatexactly 2 knee braces, each housed in the post and in the rail (triangle overlap ≥ 1 with each); exactly 2 end caps, each gripping the rail2 braces, worst post 12 / rail 16; 2 caps, worst 12
Wood–metal gapBVH surface < 0.008 m0.00075
Collider tris≤ 28044
Exportwritten, size > 0158568 / 158568 / 158560 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 1598 to 1680. The old rings were faceted tori clipped into the arm; the new eyes, shanks, and 24-segment hung rings replace that mesh. Cylinder caps are triangulated so the n-gon budget stays at 0.

DECIMATE COLLAPSE triangle counts are not identical across series — the gate is a ratio band, not an exact count. On this mesh the three binaries agreed. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction is closed-form; the only RNG is the seeded per-piece wood tone. Bevel inputs are sorted by edge index, so the face order is the same on every run; a Python set of edges handed to the bevel had made it vary. Export byte counts differ on 5.2.1 (glTF serializer), not a gated axis. Euler is 14 (12 before the horseshoe added one more closed shell) and is not gated to 2.

Horseshoe#

diff --git a/docs/gallery/hover-bike/index.html b/docs/gallery/hover-bike/index.html index 7115e3d9..7cf598c5 100644 --- a/docs/gallery/hover-bike/index.html +++ b/docs/gallery/hover-bike/index.html @@ -53,7 +53,7 @@

Hover Bike

A muted-teal hover bike with panelled flanks, a stitched saddle and two ducted fans, standing on pinned landing gear with orange shock absorbers and teal skis on a dark studio floor.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 45796 tris, ten materials with 3796 livery, 5832 composite, 6008 gunmetal, 1304 rubber, 1760 leather, 532 light, 476 glass, 2788 anodised, 1344 carbon and 1320 chrome faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.234×0.660×1.112 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both wear strips on the floor, both rotor hubs and motor cans on their shroud axes (0.001 mm) with level shrouds 1.600 m apart, blade-tip clearance 9.8 mm on both fans (band 6–14 mm), the fuselage mirror-symmetric to 0.000 mm at 1.033×0.344 m with the saddle at 0.852 m, seven blades per rotor with gaps within 0.0001° of 360/7°, the mass centre 0.252 m inside the skids' contact polygon (floor 0.200), one connected assembly of 322 shells, all 16 pins coaxial with their three bushings (0.000 mm), all 4 shock rods on their barrels' axes with 0.123 m of rod out of the gland (band 0.100–0.140) and 0.065 m engaged (floor 0.045), LOD ratios in band, collider 1890 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-skid 16; --offset-hub 17; --long-blades 18; --odd-hull 19; --skew-blade 20; --narrow-skids 21; --pop-lens 22; --offset-pin 24; --skew-rod 25; --short-rod 25.
+
witnesses Recomputed: 45796 tris, ten materials with 3796 livery, 5832 composite, 6008 gunmetal, 1304 rubber, 1760 leather, 532 light, 476 glass, 2788 anodised, 1344 carbon and 1320 chrome faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.234×0.660×1.112 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both wear strips on the floor, both rotor hubs and motor cans on their shroud axes (0.001 mm) with level shrouds 1.600 m apart, blade-tip clearance 9.8 mm on both fans (band 6–14 mm), the fuselage mirror-symmetric to 0.000 mm at 1.033×0.344 m with the saddle at 0.852 m, seven blades per rotor with gaps within 0.0001° of 360/7°, the mass centre 0.252 m inside the skids' contact polygon (floor 0.200), one connected assembly of 322 shells, all 16 pins coaxial with their three bushings (0.000 mm), all 4 shock rods on their barrels' axes with 0.123 m of rod out of the gland (band 0.100–0.140) and 0.065 m engaged (floor 0.045), LOD ratios in band, collider 1246 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-skid 16; --offset-hub 17; --long-blades 18; --odd-hull 19; --skew-blade 20; --narrow-skids 21; --pop-lens 22; --offset-pin 24; --skew-rod 25; --short-rod 25.

category Vehicles

tags mesh export showcase

@@ -70,7 +70,7 @@

Hover Bike

Intended size: 2.23 m long, 0.66 m across the bar ends, 1.11 m to the top of the cluster's visor, with the saddle's top at 0.852 m. The shrouds set the length, the bar-end weights the width and the visor the top. The fuselage is 1.033 × 0.344 m. The origin is under the bike's centre, so it lands on the soles of its wear strips.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles45000–4600045796
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2197
Materialsexactly 10 distinct; ≥3490 livery, ≥5365 composite, ≥5525 gunmetal, ≥1200 rubber, ≥1620 leather, ≥490 light, ≥460 glass, ≥2565 anodised, ≥1235 carbon, ≥1215 chrome faces10 slots; 3796 / 5832 / 6008 / 1304 / 1760 / 532 / 476 / 2788 / 1344 / 1320
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.234, 0.660, 1.112) m ± 0.01(2.2338, 0.6598, 1.1124), zmin 0
Collider tris≤ 19901890
Exportwritten, size > 0, removed after measuring3504016 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles45000–4600045796
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2197
Materialsexactly 10 distinct; ≥3490 livery, ≥5365 composite, ≥5525 gunmetal, ≥1200 rubber, ≥1620 leather, ≥490 light, ≥460 glass, ≥2565 anodised, ≥1235 carbon, ≥1215 chrome faces10 slots; 3796 / 5832 / 6008 / 1304 / 1760 / 532 / 476 / 2788 / 1344 / 1320
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.234, 0.660, 1.112) m ± 0.01(2.2338, 0.6598, 1.1124), zmin 0
Collider tris≤ 19901246
Exportwritten, size > 0, removed after measuring3472164 / 3472164 / 3472160 bytes (4.5.11 / 5.1.2 / 5.2.1)

The collider is the convex hull of the whole bike. Its count is carried by the two 72-segment shroud lips, which are the hull's outline in plan.

Every falsifier leaves the triangle count at 45796: they move, scale or bend parts, never add or remove them.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

diff --git a/docs/gallery/index.html b/docs/gallery/index.html index 6a0f68f7..1bc7f7ea 100644 --- a/docs/gallery/index.html +++ b/docs/gallery/index.html @@ -829,7 +829,7 @@

Boolean Exact Volume

Shipping Crate

shipping-crate

A procedural shipping crate through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 3388 tris, two materials with 1170 wood and 904 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.146×0.726×0.612 m, grounded zmin, 3 skids, handle-end and slat-post join 0, mesh hygiene all zero, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 116 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-skids 16; --float-handle 17; --omit-slats 18.

+

witnesses Recomputed: 3388 tris, two materials with 1170 wood and 904 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.146×0.726×0.612 m, grounded zmin, 3 skids, handle-end and slat-post join 0, mesh hygiene all zero, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 100 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-skids 16; --float-handle 17; --omit-slats 18.

@@ -841,7 +841,7 @@

Shipping Crate

Stone Well

stone-well

A procedural stone well through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 9380 tris, three materials with face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.312×1.312×1.761 m, LOD ratios in band, convex collider 346 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, all 12 bottom-course stones on the floor, each post tenoned 18 mm into the measured coping and standing under a roof hip corner, the bucket hanging 0.10 m clear of the coping, grounded zmin, non-empty glTF. --stand-posts exits 15 on the z-fight budget; --float-stone exits 16 on the named-support budget; --shallow-tenon and --drop-bucket exit 18; --turn-posts exits 19 on post placement; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.

+

witnesses Recomputed: 9380 tris, three materials with face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.312×1.312×1.761 m, LOD ratios in band, convex collider 258 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, all 12 bottom-course stones on the floor, each post tenoned 18 mm into the measured coping and standing under a roof hip corner, the bucket hanging 0.10 m clear of the coping, grounded zmin, non-empty glTF. --stand-posts exits 15 on the z-fight budget; --float-stone exits 16 on the named-support budget; --shallow-tenon and --drop-bucket exit 18; --turn-posts exits 19 on post placement; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.

@@ -853,7 +853,7 @@

Stone Well

Wooden Barrel

wooden-barrel

A procedural wine-cask with boarded, croze-seated heads and chord-lofted hoops through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 7312 tris, two materials with 2584 wood and 1440 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.714×0.880 m, 20 grounded staves, hoop bite 0.003 m, head-croze gap 0.007 m, four boards per head with 1.5 mm seams, LOD ratios in band, convex collider 238 tris, non-empty glTF. --skip-decimate exits 9; --round-band exits 18 on the hoop-seat budget; --one-piece-head exits 17 on the head-board budget.

+

witnesses Recomputed: 7312 tris, two materials with 2584 wood and 1440 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.714×0.880 m, 20 grounded staves, hoop bite 0.003 m, head-croze gap 0.007 m, four boards per head with 1.5 mm seams, LOD ratios in band, convex collider 226 tris, non-empty glTF. --skip-decimate exits 9; --round-band exits 18 on the hoop-seat budget; --one-piece-head exits 17 on the head-board budget.

@@ -877,7 +877,7 @@

Campfire

Market Stall

market-stall

A procedural timber market stall through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 4324 tris, three materials with 34 faces per awning stripe slot, UVs in 0..1 with zero AABB overlap, outer AABB 1.389×1.011×1.740 m, grounded zmin, 4 wrap feet, brace-counter overlap 0, both side braces seated 0.0418 m into their posts, awning seat 4 mm, post plumb 0, LOD ratios in band, convex collider 58 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --low-brace/--short-brace 17; --float-awning 18; --rake-posts 19.

+

witnesses Recomputed: 4324 tris, three materials with 34 faces per awning stripe slot, UVs in 0..1 with zero AABB overlap, outer AABB 1.389×1.011×1.740 m, grounded zmin, 4 wrap feet, brace-counter overlap 0, both side braces seated 0.0418 m into their posts, awning seat 4 mm, post plumb 0, LOD ratios in band, convex collider 56 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --low-brace/--short-brace 17; --float-awning 18; --rake-posts 19.

@@ -889,7 +889,7 @@

Market Stall

Street Lantern

street-lantern

A procedural hanging street lantern through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 4726 tris, three materials with 2162 metal, 24 glass and 341 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, brace ends 13 mm into the post and the arm, 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 108 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19; --shallow-brace 20.

+

witnesses Recomputed: 4726 tris, three materials with 2162 metal, 24 glass and 341 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, brace ends 13 mm into the post and the arm, 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 86 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19; --shallow-brace 20.

@@ -901,7 +901,7 @@

Street Lantern

Treasure Chest

treasure-chest

A procedural iron-bound chest with a lofted barrel-vault lid, U-wrap bands, and hinge knuckles through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 3816 tris, two materials with 1608 wood and 300 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.764×0.524×0.696 m, LOD ratios in band, convex collider 180 tris, non-empty glTF. Hygiene all zero, four feet at zmin 0, lid-knuckle to hinge barrel 7 mm, band-wall gap 0. --float-hinge exits 17 on the hinge join; --narrow-bands exits 18 on the band seat.

+

witnesses Recomputed: 3816 tris, two materials with 1608 wood and 300 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.764×0.524×0.696 m, LOD ratios in band, convex collider 156 tris, non-empty glTF. Hygiene all zero, four feet at zmin 0, lid-knuckle to hinge barrel 7 mm, band-wall gap 0. --float-hinge exits 17 on the hinge join; --narrow-bands exits 18 on the band seat.

@@ -925,7 +925,7 @@

Terrain Scatter

Fence Kit

fence-kit

A procedural post-and-rail fence section that fits its 1.60 m tile, with one-shell iron bands and a board brace housed in both posts, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 1012 tris, two materials with 116 metal and 390 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.596×0.134×1.232 m inside the 1.60 m tile, grounded zmin, 2 iron shoes, brace housed 12 mm in both posts and bearing 2 mm on the middle rail, rail-to-post gap 0.93 mm, rail span 1.362 m, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 24 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-brace 17; --gap-rails 18; --long-rails 19; --float-brace 20; --wide-tile 21.

+

witnesses Recomputed: 1012 tris, two materials with 116 metal and 390 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.596×0.134×1.232 m inside the 1.60 m tile, grounded zmin, 2 iron shoes, brace housed 12 mm in both posts and bearing 2 mm on the middle rail, rail-to-post gap 0.93 mm, rail span 1.362 m, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 20 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-brace 17; --gap-rails 18; --long-rails 19; --float-brace 20; --wide-tile 21.

@@ -937,7 +937,7 @@

Fence Kit

Watchtower

watchtower

A procedural timber watchtower through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 6840 tris, three materials with 300 metal and 126 roof faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.594×1.594×2.973 m, grounded zmin, 4 iron shoes, rail engage 18 mm, all four side rails tenoned at both ends, both joists bearing 31 mm into deck girts, collar standoff 2 mm, post plumb 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 150 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-rails/--open-sides/--short-joists 17; --float-band 18; --rake-posts 19.

+

witnesses Recomputed: 6840 tris, three materials with 300 metal and 126 roof faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.594×1.594×2.973 m, grounded zmin, 4 iron shoes, rail engage 18 mm, all four side rails tenoned at both ends, both joists bearing 31 mm into deck girts, collar standoff 2 mm, post plumb 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 122 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-rails/--open-sides/--short-joists 17; --float-band 18; --rake-posts 19.

@@ -949,7 +949,7 @@

Watchtower

Cart

cart

A procedural two-wheel handcart through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 5284 tris, two materials with metal and wood face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.580×0.842×0.640 m, LOD ratios in band, convex collider 192 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, both tyres and both prop legs grounded, two wall boards per side with 3 mm seams, tyre seat depth in band over 48 angular stations, every shell in one BVH-contact assembly, the two wheels mirrored within 5e-5 m, no unchamfered right-angle edge, 17.45 bake texels per UV cell, non-empty glTF. --flush-tyre exits 15 on the z-fight budget; --float-wheel and --short-props exit 16 on the named-support budget; --wide-seams exits 17 on the board seams; --sink-tyre exits 18 on the tyre seat band; --lift-bed exits 18 on the one-assembly budget; --skew-wheel exits 19 on the wheel mirror; --sharp-bar exits 20 on edge treatment; --low-bake exits 21 on texel density; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.

+

witnesses Recomputed: 5284 tris, two materials with metal and wood face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.580×0.842×0.640 m, LOD ratios in band, convex collider 164 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, both tyres and both prop legs grounded, two wall boards per side with 3 mm seams, tyre seat depth in band over 48 angular stations, every shell in one BVH-contact assembly, the two wheels mirrored within 5e-5 m, no unchamfered right-angle edge, 17.45 bake texels per UV cell, non-empty glTF. --flush-tyre exits 15 on the z-fight budget; --float-wheel and --short-props exit 16 on the named-support budget; --wide-seams exits 17 on the board seams; --sink-tyre exits 18 on the tyre seat band; --lift-bed exits 18 on the one-assembly budget; --skew-wheel exits 19 on the wheel mirror; --sharp-bar exits 20 on edge treatment; --low-bake exits 21 on texel density; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.

@@ -961,7 +961,7 @@

Cart

Park Bench

park-bench

A procedural wrought-iron park bench whose legs are each one bent bar from scroll toe to reclined back, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 3272 tris, two materials with 1008 metal and 756 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.295×0.632×0.887 m, grounded zmin, 4 named toes, 4 legs each one bar from toe to seat, back reclined 12°, 28 slat and armrest bites of at least 2.0 mm, stretcher gap 1.1 mm, seat span 1.272 m, LOD ratios in band, convex collider 64 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --float-stretcher 17; --gap-slats 18; --narrow-seat/--upright-back 19; --float-slats 20; --split-feet 21.

+

witnesses Recomputed: 3272 tris, two materials with 1008 metal and 756 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.295×0.632×0.887 m, grounded zmin, 4 named toes, 4 legs each one bar from toe to seat, back reclined 12°, 28 slat and armrest bites of at least 2.0 mm, stretcher gap 1.1 mm, seat span 1.272 m, LOD ratios in band, convex collider 60 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --float-stretcher 17; --gap-slats 18; --narrow-seat/--upright-back 19; --float-slats 20; --split-feet 21.

@@ -973,7 +973,7 @@

Park Bench

Wheelbarrow

wheelbarrow

A procedural wooden wheelbarrow through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 2440 tris, two materials with 1085 wood and 214 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.563x0.594x0.577 m, zmin 0, hygiene 0, both shafts one timber from grip to axle, tray flared 15 deg and raked 30 deg, wall-floor seat 8 mm, spoke clearance 52 mm, two boards per side and front wall with 2 mm seams measured in the wall's plane, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 80 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert exits 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --fat-spokes / --float-walls / --wide-seams exit 17 on joint fit; --pipe-rim exits 18 on tread aspect; --split-shafts exits 20 on shaft runs; --box-tray exits 21 on tray flare.

+

witnesses Recomputed: 2440 tris, two materials with 1085 wood and 214 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.563x0.594x0.577 m, zmin 0, hygiene 0, both shafts one timber from grip to axle, tray flared 15 deg and raked 30 deg, wall-floor seat 8 mm, spoke clearance 52 mm, two boards per side and front wall with 2 mm seams measured in the wall's plane, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 64 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert exits 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --fat-spokes / --float-walls / --wide-seams exit 17 on joint fit; --pipe-rim exits 18 on tread aspect; --split-shafts exits 20 on shaft runs; --box-tray exits 21 on tray flare.

@@ -985,7 +985,7 @@

Wheelbarrow

Anvil

anvil

A procedural blacksmith anvil on a timber stump through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 3168 tris, two materials with 1040 wood and 912 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.621×0.414×0.569 m, LOD ratios in band, convex collider 134 tris, hygiene 0, 16 grounded staves, hoop bite 0.003 m, foot-on-head gap 0.003 m, waist corner reach 0.8572, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-staves 16; --float-anvil 17; --round-band 18; --round-waist 19.

+

witnesses Recomputed: 3168 tris, two materials with 1040 wood and 912 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.621×0.414×0.569 m, LOD ratios in band, convex collider 130 tris, hygiene 0, 16 grounded staves, hoop bite 0.003 m, foot-on-head gap 0.003 m, waist corner reach 0.8572, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-staves 16; --float-anvil 17; --round-band 18; --round-waist 19.

@@ -1009,7 +1009,7 @@

Water Trough

Hitching Post

hitching-post

A procedural hitching post (eaved cap, one rail, cup shoe, rings hung through eyes, a face-nailed horseshoe) through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 2156 tris, two materials with 222 wood and 880 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.506×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, bands 6.5 mm proud of the post, horseshoe biting 1.5 mm and 7.5 mm proud, LOD ratios in band, convex collider 72 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring, --sunk-bands and --float-horseshoe exit 18; --short-post exits 19.

+

witnesses Recomputed: 2156 tris, two materials with 222 wood and 880 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.506×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, bands 6.5 mm proud of the post, horseshoe biting 1.5 mm and 7.5 mm proud, LOD ratios in band, convex collider 44 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring, --sunk-bands and --float-horseshoe exit 18; --short-post exits 19.

@@ -1021,7 +1021,7 @@

Hitching Post

Grindstone

grindstone

A procedural grindstone on a timber trestle through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 1668 tris, three materials with 400 wood / 240 stone / 364 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.419×0.610 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, four shoes planted, trough seated in the sills and biting both stretchers 4 mm, stone dip 24 mm, no unchamfered right-angle edge, 29.44 bake texels per UV cell, LOD ratios in band, convex collider 304 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert / --flush-shoes exit 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --float-crank / --float-legs exit 17 on joint fit; --no-dip / --narrow-trough / --low-stretchers exit 18 on seat; --sharp-handle exits 20 on edge treatment; --low-bake exits 21 on texel density.

+

witnesses Recomputed: 1668 tris, three materials with 400 wood / 240 stone / 364 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.419×0.610 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, four shoes planted, trough seated in the sills and biting both stretchers 4 mm, stone dip 24 mm, no unchamfered right-angle edge, 29.44 bake texels per UV cell, LOD ratios in band, convex collider 202 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert / --flush-shoes exit 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --float-crank / --float-legs exit 17 on joint fit; --no-dip / --narrow-trough / --low-stretchers exit 18 on seat; --sharp-handle exits 20 on edge treatment; --low-bake exits 21 on texel density.

@@ -1033,7 +1033,7 @@

Grindstone

Hand Pump

hand-pump

A procedural village hand pump whose gooseneck is a 6-gon tube from the lower-column radius, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 2412 tris, two materials with 1134 metal and 332 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.610×0.521×1.055 m, grounded zmin, spout-to-column gap 2.4 mm, flange-to-plinth gap 6.0 mm, column radius 68 mm, LOD ratios in band, convex collider 205 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-spout 17; --float-flange 18; --skinny-col 19.

+

witnesses Recomputed: 2412 tris, two materials with 1134 metal and 332 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.610×0.521×1.055 m, grounded zmin, spout-to-column gap 2.4 mm, flange-to-plinth gap 6.0 mm, column radius 68 mm, LOD ratios in band, convex collider 146 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-spout 17; --float-flange 18; --skinny-col 19.

@@ -1045,7 +1045,7 @@

Hand Pump

Signpost

signpost

A procedural timber fingerboard signpost through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 432 tris, three materials with 126 metal, 33 board and 60 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.260×0.142×1.551 m at zmin 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD1/LOD2), convex collider 56 tris, non-empty glTF. Hygiene all zero. Board-to-post gap 5 mm, strap gap 3 mm, board AABB Y 28 mm. --skip-decimate exits 9; --stray-vert 15; --lift-z / --short-shoe 16; --gap-board 17; --float-strap 18; --yaw-boards 19.

+

witnesses Recomputed: 432 tris, three materials with 126 metal, 33 board and 60 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.260×0.142×1.551 m at zmin 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD1/LOD2), convex collider 44 tris, non-empty glTF. Hygiene all zero. Board-to-post gap 5 mm, strap gap 3 mm, board AABB Y 28 mm. --skip-decimate exits 9; --stray-vert 15; --lift-z / --short-shoe 16; --gap-board 17; --float-strap 18; --yaw-boards 19.

@@ -1057,7 +1057,7 @@

Signpost

Chopping Block

chopping-block

A procedural log-round chopping block with a riveted iron hoop and a felling axe buried in the sawn face, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 1816 tris, four materials with 180 bark / 216 grain / 412 metal / 176 haft faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.526 x 0.526 x 1.006 m, LOD ratios in band, convex collider 538 tris, non-empty glTF. Hygiene: zero non-manifold edges, loose geometry, doubles, zero-area faces, n-gons and coplanar disjoint face pairs, grounded at zmin 0, log plumb to 1e-7, oval haft 1.35 wide-to-thick. Joint fit: six shells, 13.5 mm haft clearance in the eye, 78.7 mm bit bury, hoop biting 3.7-4.2 mm into the log on every segment, two lap rivets seated 1.50 and 1.54 mm. --fat-haft exits 17 on eye clearance; --round-band and --float-rivets exit 18 on their seats; --round-haft exits 19 on the haft section.

+

witnesses Recomputed: 1816 tris, four materials with 180 bark / 216 grain / 412 metal / 176 haft faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.526 x 0.526 x 1.006 m, LOD ratios in band, convex collider 398 tris, non-empty glTF. Hygiene: zero non-manifold edges, loose geometry, doubles, zero-area faces, n-gons and coplanar disjoint face pairs, grounded at zmin 0, log plumb to 1e-7, oval haft 1.35 wide-to-thick. Joint fit: six shells, 13.5 mm haft clearance in the eye, 78.7 mm bit bury, hoop biting 3.7-4.2 mm into the log on every segment, two lap rivets seated 1.50 and 1.54 mm. --fat-haft exits 17 on eye clearance; --round-band and --float-rivets exit 18 on their seats; --round-haft exits 19 on the haft section.

@@ -1081,7 +1081,7 @@

Wooden Bucket

Wall Torch

wall-torch

A procedural wall-mounted torch sconce: an iron plate bolted to the stone face, a level arm, an open cup holding a leaning haft with a pitch wrap and upright flames, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 2004 tris, five materials with 540 stone, 318 metal, 50 wood, 180 flame and 60 pitch faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.304×0.322×0.485 m at zmin 0, LOD ratios in band, convex collider 116 tris, non-empty glTF. Hygiene all zero. Arm level 0.000°, plate 13 mm proud of the stones and 3 mm into them, arm-to-cup gap 0.07 mm, plaque width 0.280 m, bake 27.7 texels per UV cell. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-arm 17; --float-plate 18; --skinny-plaque 19; --droop-arm 20; --sink-plate 21; --low-bake 22.

+

witnesses Recomputed: 2004 tris, five materials with 540 stone, 318 metal, 50 wood, 180 flame and 60 pitch faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.304×0.322×0.485 m at zmin 0, LOD ratios in band, convex collider 90 tris, non-empty glTF. Hygiene all zero. Arm level 0.000°, plate 13 mm proud of the stones and 3 mm into them, arm-to-cup gap 0.07 mm, plaque width 0.280 m, bake 27.7 texels per UV cell. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-arm 17; --float-plate 18; --skinny-plaque 19; --droop-arm 20; --sink-plate 21; --low-bake 22.

@@ -1093,7 +1093,7 @@

Wall Torch

Tavern Stool

tavern-stool

A procedural tavern stool with a lathed seat, turned splayed legs, staggered stretchers, and iron ferrules gripping each leg on its own axis over a level tread, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 3040 tris, two materials with 1168 wood and 576 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.341×0.341×0.470 m, LOD ratios in band, convex collider 468 tris, non-empty glTF. Hygiene all zero, four treads at zmin 0, stretcher-leg gap 0, ferrule grip 1.20 mm on each leg's axis, leg ends 1.1 mm above their treads, bake 22.4 texels per UV cell. --float-stretchers exits 17; --pipe-ferrule 18; --sink-legs 20; --low-bake 21.

+

witnesses Recomputed: 3040 tris, two materials with 1168 wood and 576 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.341×0.341×0.470 m, LOD ratios in band, convex collider 308 tris, non-empty glTF. Hygiene all zero, four treads at zmin 0, stretcher-leg gap 0, ferrule grip 1.20 mm on each leg's axis, leg ends 1.1 mm above their treads, bake 22.4 texels per UV cell. --float-stretchers exits 17; --pipe-ferrule 18; --sink-legs 20; --low-bake 21.

@@ -1105,7 +1105,7 @@

Tavern Stool

Iron Cauldron

iron-cauldron

A procedural hanging iron cauldron with a round-bellied pot, a bail threaded through flat ear rings, and a timber tripod through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 4180 tris, two materials with 144 wood and 2116 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.987×0.961×0.860 m, pot–leg clearance 0.053 m, pot base radius 0.075 m, 3 coaxial ferrules at zmin 0, ferrule bite −0.00185 m, hook-bail join 0 under a five-link chain, bail threads both ear rings, mesh hygiene all zero, LOD ratios in band, convex collider 252 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --float-hook/--edge-on-ears 17; --pipe-ferrule 18; --pointed-pot 19.

+

witnesses Recomputed: 4180 tris, two materials with 144 wood and 2116 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.987×0.961×0.860 m, pot–leg clearance 0.053 m, pot base radius 0.075 m, 3 coaxial ferrules at zmin 0, ferrule bite −0.00185 m, hook-bail join 0 under a five-link chain, bail threads both ear rings, mesh hygiene all zero, LOD ratios in band, convex collider 196 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --float-hook/--edge-on-ears 17; --pipe-ferrule 18; --pointed-pot 19.

@@ -1117,7 +1117,7 @@

Iron Cauldron

Wooden Ladder

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, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 3000 tris, two materials with 684 wood and 976 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, rung pitch even to 0.002 m, LOD ratios in band, convex collider 92 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; --drift-rungs exits 19.

+

witnesses Recomputed: 3000 tris, two materials with 684 wood and 976 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, rung pitch even to 0.002 m, LOD ratios in band, convex collider 68 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; --drift-rungs exits 19.

@@ -1141,7 +1141,7 @@

Hay Bale

Crate Stack

crate-stack

A stack of three procedural shipping crates built by one generator called three times with a per-instance seed, carried through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 6060 tris, two materials with 1344 iron and 2418 timber faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.658×0.524×0.704 m, zmin 0, hygiene 0 including zero coplanar disjoint pairs, three ground runners at z=0, both crate-to-crate seats overlapping, each crate's own footprint 0.588×0.428 m measured in its own frame, yaw spread 0.026 rad and plank spread 2.05 mm across instances, LOD ratios in band, convex collider 230 tris, non-empty glTF. --float-stack exits 18 on the seat; --same-seed exits 20 on per-instance variation.

+

witnesses Recomputed: 6060 tris, two materials with 1344 iron and 2418 timber faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.658×0.524×0.704 m, zmin 0, hygiene 0 including zero coplanar disjoint pairs, three ground runners at z=0, both crate-to-crate seats overlapping, each crate's own footprint 0.588×0.428 m measured in its own frame, yaw spread 0.026 rad and plank spread 2.05 mm across instances, LOD ratios in band, convex collider 204 tris, non-empty glTF. --float-stack exits 18 on the seat; --same-seed exits 20 on per-instance variation.

@@ -1261,7 +1261,7 @@

Book Trolley

Basketball Hoop

basketball-hoop

A procedural in-ground basketball goal on a patch of driveway court — a square gooseneck pole swept in one piece with welded bend webs, its plate sunk and bolted into a two-pour concrete pad with a sealed expansion joint, a braced board in an aluminium frame, a breakaway regulation rim, a knotted twelve-loop net hung on the rim hooks, faded court paint set into the slabs and two pebbled basketballs resting on the concrete — through UVs, bake, LOD, convex collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 19564 tris, twelve materials with 2546 steel, 54 board, 32 board-paint, 970 rim, 2784 net, 382 pad, 144 aluminium, 108 concrete, 504 court-line, 12 key, 1024 ball and 2310 seam faces, UVs in 0..1 with zero AABB overlap, outer AABB 5.200×6.600×4.050 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both braces 9.5 mm into the collar and 21.0 mm into the lower rail, all 12 net loops threaded through their hook eyes (worst 7.0 mm from the eye centre against a 9 mm clear radius), rim top 3.050 m over the court, inside diameter 0.457 m, inner edge 0.151 m off the board, tilt 0.000°, both balls radius 0.1194 m bearing 2.0 mm into their slabs, all four anchor bolts 70 mm into the slab and 62 mm over the plate, all 18 paint shells 1.0–2.2 mm proud and 1.4–3.0 mm sunk into their slabs, one connected assembly of 209 shells, LOD ratios in band, convex collider 58 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --short-brace 17; --drop-net 18; --tilt-rim 19; --loose-pad 20; --float-ball 21; --short-bolts 22; --float-paint 23.

+

witnesses Recomputed: 19564 tris, twelve materials with 2546 steel, 54 board, 32 board-paint, 970 rim, 2784 net, 382 pad, 144 aluminium, 108 concrete, 504 court-line, 12 key, 1024 ball and 2310 seam faces, UVs in 0..1 with zero AABB overlap, outer AABB 5.200×6.600×4.050 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both braces 9.5 mm into the collar and 21.0 mm into the lower rail, all 12 net loops threaded through their hook eyes (worst 7.0 mm from the eye centre against a 9 mm clear radius), rim top 3.050 m over the court, inside diameter 0.457 m, inner edge 0.151 m off the board, tilt 0.000°, both balls radius 0.1194 m bearing 2.0 mm into their slabs, all four anchor bolts 70 mm into the slab and 62 mm over the plate, all 18 paint shells 1.0–2.2 mm proud and 1.4–3.0 mm sunk into their slabs, one connected assembly of 209 shells, LOD ratios in band, convex collider 44 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --short-brace 17; --drop-net 18; --tilt-rim 19; --loose-pad 20; --float-ball 21; --short-bolts 22; --float-paint 23.

@@ -1273,7 +1273,7 @@

Basketball Hoop

Pine Tree

pine-tree

A procedural mature Scots pine — a buttressed trunk with plated lower bark bedded in a needle-litter soil disc, eight seeded whorls of heavy limbs seated in the bark, 113 overlapping brushes of long thin needle strands each on its own twig, dead limbs, hanging cones, fallen cones, mossy stones and sticks — through UVs, bake, LOD, trunk collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 45852 tris, six materials with 3026 bark, 36612 needle, 1024 cone, 274 deadwood, 878 soil and 192 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 9.284×7.932×7.659 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 33 limbs and 7 dead members seated in the trunk (base 0.43–0.47 of the bark radius from the axis, band 0.25–0.75), 8 whorls of 3–5 limbs with gaps 0.40–0.45 m (band 0.32–0.60), trunk lean 0.489°, needle mass 0.047 m off the base axis, breast-height diameter 0.3768 m, every one of 113 needle brushes holding its own carrier at least 0.059 m deep (min 0.040), fallen cones and sticks 0.010 m and stones 0.045 m into the soil, roots at least 0.091 m under it, one connected assembly of 266 shells, LOD ratios in band, trunk collider 56 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-branches 17; --lean-crown 19; --bunch-whorls 20; --drop-cones 21; --short-twigs 22; --float-litter 23.

+

witnesses Recomputed: 45852 tris, six materials with 3026 bark, 36612 needle, 1024 cone, 274 deadwood, 878 soil and 192 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 9.284×7.932×7.659 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 33 limbs and 7 dead members seated in the trunk (base 0.43–0.47 of the bark radius from the axis, band 0.25–0.75), 8 whorls of 3–5 limbs with gaps 0.40–0.45 m (band 0.32–0.60), trunk lean 0.489°, needle mass 0.047 m off the base axis, breast-height diameter 0.3768 m, every one of 113 needle brushes holding its own carrier at least 0.059 m deep (min 0.040), fallen cones and sticks 0.010 m and stones 0.045 m into the soil, roots at least 0.091 m under it, one connected assembly of 266 shells, LOD ratios in band, trunk collider 54 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-branches 17; --lean-crown 19; --bunch-whorls 20; --drop-cones 21; --short-twigs 22; --float-litter 23.

@@ -1285,7 +1285,7 @@

Pine Tree

Desk Lamp

desk-lamp

A procedural balanced-arm desk lamp — stepped cast base, swivel turret, two parallelogram arm sections pinned through knuckle bosses with knurled tension knobs, three extension springs hung on cross bars, a domed enamel shade with a rolled rim, reflector and glowing lamp, a draped flex and a cable to a plug — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 30110 tris, six materials with 3972 enamel, 9210 steel, 348 bulb, 1508 rubber, 622 reflector and 384 bakelite faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.725×0.361×0.442 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 7 joint pins coaxial with the 23 eyes and bosses they pass through (offset 0.000 mm, band 0.3 mm), all 6 spring loops centred on their bars' axes (band 0.6 mm), mass centre 39.6 mm inside the base footprint (floor 25 mm), base 0.180 m square, arm sections 0.320 and 0.360 m pin to pin, one connected assembly of 78 shells, LOD ratios in band, collider 713 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-pin 17; --unhook-spring 18; --hollow-base 19; --unscrew-bulb 20.

+

witnesses Recomputed: 30110 tris, six materials with 3972 enamel, 9210 steel, 348 bulb, 1508 rubber, 622 reflector and 384 bakelite faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.725×0.361×0.442 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 7 joint pins coaxial with the 23 eyes and bosses they pass through (offset 0.000 mm, band 0.3 mm), all 6 spring loops centred on their bars' axes (band 0.6 mm), mass centre 39.6 mm inside the base footprint (floor 25 mm), base 0.180 m square, arm sections 0.320 and 0.360 m pin to pin, one connected assembly of 78 shells, LOD ratios in band, collider 472 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-pin 17; --unhook-spring 18; --hollow-base 19; --unscrew-bulb 20.

@@ -1297,7 +1297,7 @@

Desk Lamp

Quad Drone

quad-drone

A procedural camera quadcopter — a two-tone moulded shell with panel lines, grilles, a sensor visor, a battery pack and a GPS puck, four folding arms hinged on pinned clevises with lock rings, slotted brushless motors carrying twisted, swept two-blade propellers, rubber-footed skids and a three-axis gimbal camera — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 41048 tris, eight materials with 1720 shell, 2304 carbon, 6472 gunmetal, 524 glass, 760 light, 1296 rubber, 8464 graphite and 2184 anodised faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.692×0.569×0.243 m, zmin 0 and all 4 feet grounded, hygiene 0 including zero coplanar cross-shell pairs, the 4 motor axes on an exact X about the body centre (gaps 90.000°, diagonals 0.52000 m, axes vertical, hubs level), every neighbouring prop disc cleared by 0.0365 m (band 0.028–0.050), mass centre 0.115 m inside the feet's footprint (floor 0.090), wheelbase 0.520 m, one connected assembly of 171 shells, LOD ratios in band, collider 499 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --unlock-arm 17; --long-blades 18; --narrow-skids 19; --drop-lens 20.

+

witnesses Recomputed: 41048 tris, eight materials with 1720 shell, 2304 carbon, 6472 gunmetal, 524 glass, 760 light, 1296 rubber, 8464 graphite and 2184 anodised faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.692×0.569×0.243 m, zmin 0 and all 4 feet grounded, hygiene 0 including zero coplanar cross-shell pairs, the 4 motor axes on an exact X about the body centre (gaps 90.000°, diagonals 0.52000 m, axes vertical, hubs level), every neighbouring prop disc cleared by 0.0365 m (band 0.028–0.050), mass centre 0.115 m inside the feet's footprint (floor 0.090), wheelbase 0.520 m, one connected assembly of 171 shells, LOD ratios in band, collider 374 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --unlock-arm 17; --long-blades 18; --narrow-skids 19; --drop-lens 20.

@@ -1309,7 +1309,7 @@

Quad Drone

Soccer Goal

soccer-goal

A procedural freestanding 5 × 2 m youth soccer goal — posts and crossbar in one oval aluminium extrusion with a net channel, mitred and welded at the corners, cast corner brackets, foot connectors and rear hubs, sloped supports and a steel ground frame pinned by staples and spikes, and a sagging diamond-mesh net whose red head rope runs through 53 nylon clips — on a turf patch with a painted goal line, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 34804 tris, ten materials with 2514 paint, 9028 cord, 160 rope, 340 steel, 1464 cast, 3604 nylon, 1000 galvanised, 196 turf, 16 line-paint and 102 soil faces, UVs in 0..1 with zero AABB overlap, outer AABB 6.220×2.640×2.153 m, zmin 0 and all 3 ground bars bedded 2.5 mm into the turf, hygiene 0 including zero coplanar cross-shell pairs, both sloped supports 65 mm into their bracket sockets and 80 mm into their hubs, the head rope through all 53 clip loops (axis offset 0.000 m, ceiling 0.0012), a clear mouth of 5.0002 × 2.0001 m with the posts plumb and the crossbar level, the back panel sagging 0.148 m below its chord (band 0.110–0.180), LOD ratios in band, collider 168 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-bar 16; --short-support 17; --unclip-net 18; --wide-mouth 19; --taut-net 20.

+

witnesses Recomputed: 34804 tris, ten materials with 2514 paint, 9028 cord, 160 rope, 340 steel, 1464 cast, 3604 nylon, 1000 galvanised, 196 turf, 16 line-paint and 102 soil faces, UVs in 0..1 with zero AABB overlap, outer AABB 6.220×2.640×2.153 m, zmin 0 and all 3 ground bars bedded 2.5 mm into the turf, hygiene 0 including zero coplanar cross-shell pairs, both sloped supports 65 mm into their bracket sockets and 80 mm into their hubs, the head rope through all 53 clip loops (axis offset 0.000 m, ceiling 0.0012), a clear mouth of 5.0002 × 2.0001 m with the posts plumb and the crossbar level, the back panel sagging 0.148 m below its chord (band 0.110–0.180), LOD ratios in band, collider 126 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-bar 16; --short-support 17; --unclip-net 18; --wide-mouth 19; --taut-net 20.

@@ -1321,7 +1321,7 @@

Soccer Goal

Fallen Log

fallen-log

A procedural fallen forest log — one furrowed lathe along a bowed axis with bark peeled to galleried sapwood, a rotted hollow saw-cut butt, a splintered snapped top, broken branch stubs, moss cushions on its top and shaded side and three tiers of bracket fungi rooted in the bark — settled into a soil mound with toadstools, ferns and fallen leaves, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 36374 tris, nine materials with 5144 bark, 892 wood, 384 rot, 2400 moss, 2448 bracket, 1296 toadstool, 2494 soil, 2080 litter and 5090 fern faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.119×2.189×1.027 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the log bedded in the soil at 0.889 of its stations (floor 0.75, depth band 0.020–0.090 m), all 12 bracket shelves rooted 0.021–0.029 m into the bark (band 0.008–0.050), the log's mass centre 0.149 m inside the plan hull of its buried vertices (floor 0.06), 0.992 of the moss top area facing up or north (floor 0.85), all 436 ground-cover shells joined to the soil, LOD ratios in band, log collider 215 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --hump-ground 17; --float-fungi 18; --tilt-ground 19; --sunny-moss 20; --float-litter 21.

+

witnesses Recomputed: 36374 tris, nine materials with 5144 bark, 892 wood, 384 rot, 2400 moss, 2448 bracket, 1296 toadstool, 2494 soil, 2080 litter and 5090 fern faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.119×2.189×1.027 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the log bedded in the soil at 0.889 of its stations (floor 0.75, depth band 0.020–0.090 m), all 12 bracket shelves rooted 0.021–0.029 m into the bark (band 0.008–0.050), the log's mass centre 0.149 m inside the plan hull of its buried vertices (floor 0.06), 0.992 of the moss top area facing up or north (floor 0.85), all 436 ground-cover shells joined to the soil, LOD ratios in band, log collider 142 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --hump-ground 17; --float-fungi 18; --tilt-ground 19; --sunny-moss 20; --float-litter 21.

@@ -1333,7 +1333,7 @@

Fallen Log

Office Chair

office-chair

A procedural ergonomic task chair on a chair mat at a desk corner — a polished aluminium five-star base with ribbed spokes and five swivelled hooded twin-wheel casters pressed into a smoked polycarbonate mat, a chrome gas lift in a telescoping cover under a synchro-tilt mechanism with tension knob and paddles, a moulded shell cupping a two-tone sculpted cushion with thigh channels, a waterfall front and two piped welts, an elastomeric mesh back on a graphite frame with an S-curved lumbar pad on sliders, a mesh headrest, 4D armrests, and a snake plant in a stone planter — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 44440 tris, fourteen materials each above its face floor, UVs in 0..1 with zero AABB overlap, outer AABB 1.635×1.480×1.317 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the mat flat on the floor, all 10 wheels pressed 0.6 mm into the mat, the pot on the floor, spokes and bosses 72° apart (worst 0.00001°), bosses and swivel stems on one 0.305 m circle, stems plumb, coaxial and seated 34 mm, the gas-lift column coaxial with hub and socket (0.0 mm) and seated 52 and 28 mm, seven armrest part pairs mirrored and level within 0.5 mm, seat 0.497 m high, armrests 0.197 m over it, a 0.660 m star, the mass centre 0.215 m inside the caster contact hull (floor 0.12), one connected chair of 89 shells, both lumbar sliders 3.5–5.2 mm off the frame tube, nine leaves rooted 24.5–31.6 mm in the soil, LOD ratios in band, collider 551 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-caster 16; --curl-mat 16; --skew-spoke 17; --offset-column 18; --uneven-arms 19; --loose-wheel 20; --float-lumbar 21; --float-leaves 22.

+

witnesses Recomputed: 44440 tris, fourteen materials each above its face floor, UVs in 0..1 with zero AABB overlap, outer AABB 1.635×1.480×1.317 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the mat flat on the floor, all 10 wheels pressed 0.6 mm into the mat, the pot on the floor, spokes and bosses 72° apart (worst 0.00001°), bosses and swivel stems on one 0.305 m circle, stems plumb, coaxial and seated 34 mm, the gas-lift column coaxial with hub and socket (0.0 mm) and seated 52 and 28 mm, seven armrest part pairs mirrored and level within 0.5 mm, seat 0.497 m high, armrests 0.197 m over it, a 0.660 m star, the mass centre 0.215 m inside the caster contact hull (floor 0.12), one connected chair of 89 shells, both lumbar sliders 3.5–5.2 mm off the frame tube, nine leaves rooted 24.5–31.6 mm in the soil, LOD ratios in band, collider 374 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-caster 16; --curl-mat 16; --skew-spoke 17; --offset-column 18; --uneven-arms 19; --loose-wheel 20; --float-lumbar 21; --float-leaves 22.

@@ -1345,7 +1345,7 @@

Office Chair

Hover Bike

hover-bike

A procedural sci-fi hover bike — a sculpted two-tone fuselage with panel seams, gasketed access panels with hex fasteners, a belly service plate, decal plate, hinged charge-port door, heat sink, intake grilles, grab rail and tail light, a stitched pleated saddle, a twin-stanchion fork through sculpted triple clamps with clip-ons, switch pods, pivoted levers and a visored instrument cluster, two glowing exhaust nozzles, two ducted fans with canted stator vanes and handed seven-blade rotors, aerofoil pylons flared into the shrouds with fastener rows and a conduit, and landing gear of twin-plate pressed links and oleo shocks on sixteen pinned joints carrying ski-section skids on wear strips — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 45796 tris, ten materials with 3796 livery, 5832 composite, 6008 gunmetal, 1304 rubber, 1760 leather, 532 light, 476 glass, 2788 anodised, 1344 carbon and 1320 chrome faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.234×0.660×1.112 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both wear strips on the floor, both rotor hubs and motor cans on their shroud axes (0.001 mm) with level shrouds 1.600 m apart, blade-tip clearance 9.8 mm on both fans (band 6–14 mm), the fuselage mirror-symmetric to 0.000 mm at 1.033×0.344 m with the saddle at 0.852 m, seven blades per rotor with gaps within 0.0001° of 360/7°, the mass centre 0.252 m inside the skids' contact polygon (floor 0.200), one connected assembly of 322 shells, all 16 pins coaxial with their three bushings (0.000 mm), all 4 shock rods on their barrels' axes with 0.123 m of rod out of the gland (band 0.100–0.140) and 0.065 m engaged (floor 0.045), LOD ratios in band, collider 1890 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-skid 16; --offset-hub 17; --long-blades 18; --odd-hull 19; --skew-blade 20; --narrow-skids 21; --pop-lens 22; --offset-pin 24; --skew-rod 25; --short-rod 25.

+

witnesses Recomputed: 45796 tris, ten materials with 3796 livery, 5832 composite, 6008 gunmetal, 1304 rubber, 1760 leather, 532 light, 476 glass, 2788 anodised, 1344 carbon and 1320 chrome faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.234×0.660×1.112 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both wear strips on the floor, both rotor hubs and motor cans on their shroud axes (0.001 mm) with level shrouds 1.600 m apart, blade-tip clearance 9.8 mm on both fans (band 6–14 mm), the fuselage mirror-symmetric to 0.000 mm at 1.033×0.344 m with the saddle at 0.852 m, seven blades per rotor with gaps within 0.0001° of 360/7°, the mass centre 0.252 m inside the skids' contact polygon (floor 0.200), one connected assembly of 322 shells, all 16 pins coaxial with their three bushings (0.000 mm), all 4 shock rods on their barrels' axes with 0.123 m of rod out of the gland (band 0.100–0.140) and 0.065 m engaged (floor 0.045), LOD ratios in band, collider 1246 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-skid 16; --offset-hub 17; --long-blades 18; --odd-hull 19; --skew-blade 20; --narrow-skids 21; --pop-lens 22; --offset-pin 24; --skew-rod 25; --short-rod 25.

@@ -1357,7 +1357,7 @@

Hover Bike

Weight Rack

weight-rack

A procedural home-gym strength set — a half rack of punched, numbered square uprights on bolted feet with rubber pads, side rails on bolted flanges, a pull-up bar, J-hooks with UHMW saddles and spotter arms on pull pins seated in the holes, plate-storage horns, an Olympic barbell with a knurled shaft, collars and sleeves loaded with bumpers (steel hubs, raised rims and numerals) and cast-iron change plates behind coiled spring clips, and two hex dumbbells — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 44264 tris, twelve materials with 4758 powder-coat, 3036 bore, 4196 zinc, 3348 chrome, 256 knurl, 1328 rubber, 104 UHMW, 3112 numeral, 864 blue, 576 yellow, 576 green and 2240 cast-iron faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.200×1.636×2.092 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads and four dumbbell heads on the floor, all four pull pins on their holes' axes (0.000 mm) 7.0 mm deep, the bar seated in both J-hook saddles (−0.20 mm) and level (0.0000°) at 2.200 m, 0.450 m bumpers, twelve plates on six sleeves within 0.80 mm of their axes with every gap −0.50 mm (band −0.8 to −0.2 mm), the loaded bar's mass centre 0.002 mm off its midpoint (tol 2 mm), one connected rack plus two dumbbells, LOD ratios in band, collider 598 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --float-bar 18; --hook-high 19; --gap-plate 20; --odd-load 21; --loose-horn 22.

+

witnesses Recomputed: 44264 tris, twelve materials with 4758 powder-coat, 3036 bore, 4196 zinc, 3348 chrome, 256 knurl, 1328 rubber, 104 UHMW, 3112 numeral, 864 blue, 576 yellow, 576 green and 2240 cast-iron faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.200×1.636×2.092 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads and four dumbbell heads on the floor, all four pull pins on their holes' axes (0.000 mm) 7.0 mm deep, the bar seated in both J-hook saddles (−0.20 mm) and level (0.0000°) at 2.200 m, 0.450 m bumpers, twelve plates on six sleeves within 0.80 mm of their axes with every gap −0.50 mm (band −0.8 to −0.2 mm), the loaded bar's mass centre 0.002 mm off its midpoint (tol 2 mm), one connected rack plus two dumbbells, LOD ratios in band, collider 472 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --float-bar 18; --hook-high 19; --gap-plate 20; --odd-load 21; --loose-horn 22.

@@ -1381,7 +1381,7 @@

Boulder Cluster

Floor Fan

floor-fan

A procedural 1950s oscillating pedestal fan — a hollow two-tier cast base on a rubber gasket with a rotary speed switch and badge, a telescoping enamel and chrome column with a knurled height-lock collar, a strap yoke with a knurled tilt knob, a slotted motor housing with a trim band and an oscillation knob, a two-half wire guard of radial spokes and concentric rings welded to clipped rim rings with a centre badge, four swept brass blades on a hub with a hex spinner nut, and a cord to a plug — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 41460 tris, six materials with 4732 enamel, 13960 chrome, 584 brass, 1216 rubber, 810 bakelite and 440 badge faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.761×0.704×1.229 m, zmin 0 with the gasket on the floor, hygiene 0 including zero coplanar cross-shell pairs, hub, spinner, shaft, badge, rear mount and motor housing on the axis the rim rings define (worst 0.000001 m, cap 0.0005), all 48 spokes ending inside their rim rings (worst 0.0007 m from the ring's centreline, cap 0.0026) and each of 7 rings crossing all 24 spokes of its half, both column tubes plumb (0.000°, cap 0.2°) and on the base's axis (0.0000 m, cap 0.001), guard 0.452 m and base 0.400 m across, blade tips 0.0195 m inside the rim rings (band 0.012–0.030) and 0.0140 m from the nearest wire (floor 0.006), four blades 90° apart within 0.0002° (cap 0.3°), a 28.4 kg fan that stands on a 19.06° incline before it tips (floor 16°), one connected assembly of 109 shells, LOD ratios in band, collider 1997 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-hub 17; --short-spoke 18; --lean-column 19; --long-blades 20; --skew-blade 21; --hollow-base 22; --loose-spinner 23.

+

witnesses Recomputed: 41460 tris, six materials with 4732 enamel, 13960 chrome, 584 brass, 1216 rubber, 810 bakelite and 440 badge faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.761×0.704×1.229 m, zmin 0 with the gasket on the floor, hygiene 0 including zero coplanar cross-shell pairs, hub, spinner, shaft, badge, rear mount and motor housing on the axis the rim rings define (worst 0.000001 m, cap 0.0005), all 48 spokes ending inside their rim rings (worst 0.0007 m from the ring's centreline, cap 0.0026) and each of 7 rings crossing all 24 spokes of its half, both column tubes plumb (0.000°, cap 0.2°) and on the base's axis (0.0000 m, cap 0.001), guard 0.452 m and base 0.400 m across, blade tips 0.0195 m inside the rim rings (band 0.012–0.030) and 0.0140 m from the nearest wire (floor 0.006), four blades 90° apart within 0.0002° (cap 0.3°), a 28.4 kg fan that stands on a 19.06° incline before it tips (floor 16°), one connected assembly of 109 shells, LOD ratios in band, collider 1560 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-hub 17; --short-spoke 18; --lean-column 19; --long-blades 20; --skew-blade 21; --hollow-base 22; --loose-spinner 23.

@@ -1393,7 +1393,7 @@

Floor Fan

Motor Scooter

motor-scooter

A procedural 1960s Italian step-through motor scooter — a pressed-steel tail lofted from superellipse sections with two bulbous side cowls (pressed louvres on the engine side, chrome belt trims), a floorboard with rubber runner strips and chrome edge trims pressed up into the tail and into a leg shield convex in plan, arched up into the headset and rimmed in a rolled chrome trim, with a horn cast and grille, a single-sided front end (a column raked 26 degrees, crown, fork leg, trailing link and coil spring) under a crested mudguard, a headset carrying the headlamp, speedometer, ribbed grips, levers and two mirrors, a two-tone dual saddle with piping and a grab strap, 10-inch split rims with five nuts and finned drums in block-tread tyres, an alloy engine case with a finned cylinder, header, silencer and kick-start, a luggage rack, tail lamp and plate, and a centre stand with rubber feet — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 45060 tris, nine materials with 7156 paint, 4638 chrome, 3608 rubber, 1147 oxblood vinyl, 297 cream vinyl, 550 glass, 188 tail-lens, 4020 alloy and 2292 black-enamel faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.790×0.730×1.244 m, zmin 0 with both tyres and both stand feet on the floor, hygiene 0 including zero coplanar cross-shell pairs, both axles level and parallel (camber 0.000°, toe 0.000°, cap 0.3°), the steering column raked 26.000° meeting the ground 0.0750 m ahead of the front contact (band 0.055–0.090) and on its line, the body mirror-symmetric to 0.000 mm (cap 0.5, engine side excluded by construction), tail 0.862 m and saddle top 0.807 m, a 1.20000 m wheelbase (±0.004), a 101.6 kg scooter whose mass centre stands 0.1284 m inside its tyres-and-stand support polygon (floor 0.080), one connected assembly of 105 shells, the leg shield's foot 0.0320 m deep in the floorboard (band 0.020–0.040), LOD ratios in band, collider 1678 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --toe-wheel 17; --steep-head 18; --odd-body 19; --short-wheelbase 20; --narrow-stand 21; --pop-speedo 22; --lift-shield 23.

+

witnesses Recomputed: 45060 tris, nine materials with 7156 paint, 4638 chrome, 3608 rubber, 1147 oxblood vinyl, 297 cream vinyl, 550 glass, 188 tail-lens, 4020 alloy and 2292 black-enamel faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.790×0.730×1.244 m, zmin 0 with both tyres and both stand feet on the floor, hygiene 0 including zero coplanar cross-shell pairs, both axles level and parallel (camber 0.000°, toe 0.000°, cap 0.3°), the steering column raked 26.000° meeting the ground 0.0750 m ahead of the front contact (band 0.055–0.090) and on its line, the body mirror-symmetric to 0.000 mm (cap 0.5, engine side excluded by construction), tail 0.862 m and saddle top 0.807 m, a 1.20000 m wheelbase (±0.004), a 101.6 kg scooter whose mass centre stands 0.1284 m inside its tyres-and-stand support polygon (floor 0.080), one connected assembly of 105 shells, the leg shield's foot 0.0320 m deep in the floorboard (band 0.020–0.040), LOD ratios in band, collider 1132 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --toe-wheel 17; --steep-head 18; --odd-body 19; --short-wheelbase 20; --narrow-stand 21; --pop-speedo 22; --lift-shield 23.

@@ -1405,7 +1405,7 @@

Motor Scooter

Bowling Pins

bowling-pins

A procedural pin deck end of a ten-pin bowling lane — one laminated slab of 39 maple boards, 41.5 in across, each board's top edges chamfered into a V seam and crossed by the joint to a dark pin deck, ten pin spots inlaid on a 12 in equilateral triangle 34 3/16 in from the pit edge, a chevron of targeting arrows and a row of range dots, channel-profile gutters, cappings, kickbacks with sloped noses under mitred aluminium caps and phenolic kick plates, a steel pit-edge bullnose and five sleepers; ten pins lathe-turned from the regulation profile table (15 in tall, 4.766 in belly) with two red neck stripes and a crown band of red teeth; and an 8.5 in marbled resin ball drilled by an exact Boolean with a countersunk thumb hole and two parallel finger holes — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 37078 tris, eleven materials with 358 maple, 358 pin-deck, 13720 pin-white, 1280 pin-red, 1649 ball, 562 bore, 254 phenolic, 142 laminate, 176 aluminium, 1197 inlay and 380 sleeper faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.640×2.301×0.523 m read off the vertices, zmin 0 with all five sleepers on the floor, hygiene 0 including zero coplanar cross-shell pairs, every pin's base centre 0.000 mm off its spot (tol 0.5) and 0.6 mm below the deck face (band 0.3–1.0), every pin plumb (0.000°), 0.3810 m tall with a 0.12106 m belly, its radius on all 15 profile-table stations to 0.000 mm (tol 0.2), the ten spots on an exact 12 in lattice (18 edges, rows 1-2-3-4, row pitch 0.26396 m, head spot on the centre line), the ball 0.21590 m across resting 0.60 mm into the lane (band 0.3–0.9), its thumb hole 63.5 mm and finger holes 50.8 mm deep with 25.40 and 20.32 mm bores, a 112.2 mm span and a 26.67 mm bridge, 39 boards flush and straight to 0.000 mm, one connected assembly of 55 shells, LOD ratios in band, collider 277 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sleeper 16; --offset-pin 17; --float-pin 18; --lean-pin 19; --wide-rack 20; --fat-neck 21; --float-ball 22; --shallow-holes 23; --proud-board 24; --lift-arrows 25.

+

witnesses Recomputed: 37078 tris, eleven materials with 358 maple, 358 pin-deck, 13720 pin-white, 1280 pin-red, 1649 ball, 562 bore, 254 phenolic, 142 laminate, 176 aluminium, 1197 inlay and 380 sleeper faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.640×2.301×0.523 m read off the vertices, zmin 0 with all five sleepers on the floor, hygiene 0 including zero coplanar cross-shell pairs, every pin's base centre 0.000 mm off its spot (tol 0.5) and 0.6 mm below the deck face (band 0.3–1.0), every pin plumb (0.000°), 0.3810 m tall with a 0.12106 m belly, its radius on all 15 profile-table stations to 0.000 mm (tol 0.2), the ten spots on an exact 12 in lattice (18 edges, rows 1-2-3-4, row pitch 0.26396 m, head spot on the centre line), the ball 0.21590 m across resting 0.60 mm into the lane (band 0.3–0.9), its thumb hole 63.5 mm and finger holes 50.8 mm deep with 25.40 and 20.32 mm bores, a 112.2 mm span and a 26.67 mm bridge, 39 boards flush and straight to 0.000 mm, one connected assembly of 55 shells, LOD ratios in band, collider 200 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sleeper 16; --offset-pin 17; --float-pin 18; --lean-pin 19; --wide-rack 20; --fat-neck 21; --float-ball 22; --shallow-holes 23; --proud-board 24; --lift-arrows 25.

@@ -1429,7 +1429,7 @@

Pond Edge

Stand Mixer

stand-mixer

A procedural retro tilt-head kitchen stand mixer on a honed limestone countertop section — a cast enamel body lofted from superellipse sections (a pebble-shaped base foot on four rubber feet, a neck leaning back as it rises, a streamlined motor head) hinged at the back on a pin through two neck knuckles; a chrome trim band wrapped on the head's own sections, a blank badge, a speed lever and a tilt-lock lever; an attachment hub with its cap and thumb screw on the nose; a planetary socket carrying a flat beater whose frame follows the bowl's wall into a 4.5 L brushed stainless bowl with a rolled rim and strap handle, clamped under three bayonet lugs; a cord to a plug; and a balloon whisk, a measuring cup and two brown eggs in a glazed dish — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 29620 tris, eight materials with 4328 enamel, 2626 chrome, 5560 stainless, 91 stone, 1174 rubber, 812 ceramic, 760 egg and 562 beater faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.470×0.570×0.389 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four feet sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the hinge pin 0.000000 m off the axis of both neck knuckles and the head knuckle (cap 0.0003) and spanning all three, the bowl seated 0.00050 m into its plate (band 0.0002–0.0010) and 0.000000 m off its axis (cap 0.0003) with all three lugs engaged, the mixer 0.35899 m tall (0.360 ± 0.006) and the bowl holding 4.5465 L to the brim (4.5 ± 0.35), the beater shaft 0.000000 m off the planetary socket's axis (cap 0.0003) and clearing the bowl's wall by 0.00245 m and its floor by 0.00250 m (band 0.0012–0.0040), the mass centre 0.0658 m inside the feet's support polygon (floor 0.040) at 13.94 kg, one connected assembly of 52 shells, LOD ratios in band, collider 2329 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --offset-bowl 18; --shallow-bowl 19; --offset-beater 20; --long-beater 21; --bunch-feet 22; --loose-cap 23.

+

witnesses Recomputed: 29620 tris, eight materials with 4328 enamel, 2626 chrome, 5560 stainless, 91 stone, 1174 rubber, 812 ceramic, 760 egg and 562 beater faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.470×0.570×0.389 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four feet sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the hinge pin 0.000000 m off the axis of both neck knuckles and the head knuckle (cap 0.0003) and spanning all three, the bowl seated 0.00050 m into its plate (band 0.0002–0.0010) and 0.000000 m off its axis (cap 0.0003) with all three lugs engaged, the mixer 0.35899 m tall (0.360 ± 0.006) and the bowl holding 4.5465 L to the brim (4.5 ± 0.35), the beater shaft 0.000000 m off the planetary socket's axis (cap 0.0003) and clearing the bowl's wall by 0.00245 m and its floor by 0.00250 m (band 0.0012–0.0040), the mass centre 0.0658 m inside the feet's support polygon (floor 0.040) at 13.94 kg, one connected assembly of 52 shells, LOD ratios in band, collider 1308 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --offset-bowl 18; --shallow-bowl 19; --offset-beater 20; --long-beater 21; --bunch-feet 22; --loose-cap 23.

@@ -1441,7 +1441,7 @@

Stand Mixer

Cargo Loader

cargo-loader

A procedural sci-fi industrial cargo loader, a bipedal powered-lift exoframe standing in a crouch and holding a corrugated cargo crate off the ground on two forged L-tines — broad flat feet with rubber soles, grip cleats and toe bumpers; hydraulic legs of lofted box-section shins and thighs pinned at the ankle, knee and hip; arms hung from shoulder yokes, each joint a clevis of two lug bushings straddling an eye bushing with a chrome pin through all three; eight rams (hip and knee, shoulder and elbow), each a collared steel cylinder with a chromed rod, a pinned clevis bracket at each end and a hose from its port; fork carriages with hazard-striped faces; an open roll-cage cockpit with a bucket seat, four-point harness, joystick consoles, amber beacon and work lights; a power pack with a slatted grille, cooling fins, hazard bands, exhaust stacks and cable looms — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 44600 tris, ten materials with 2736 paint, 608 hazard, 3128 chrome, 15328 steel, 2740 rubber, 480 seat-vinyl, 640 harness, 256 beacon, 152 work-light and 516 crate-paint faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.827×1.689×2.974 m, zmin 0 with both soles on the floor, hygiene 0 including zero coplanar cross-shell pairs, all 28 clevis pins 0.000 mm off the axis of each of their three bushings and 0.000° to them (caps 0.3 mm, 0.3°), the crate's base biting both tines by 0.0020 m at every station along a 0.74 m run (band 0.0010–0.0040, run ≥ 0.50), both soles flat and level to 0.000 mm and 0.000° (caps 0.5 mm, 0.2°), all 8 ram rods 0.000 mm off their cylinders' axes and 0.0096° to them (caps 0.3 mm, 0.3°) with 0.1591–0.2858 m of rod exposed (band 0.080–0.340) and 0.060 m engaged (floor 0.040), a 2380.6 kg loader and crate whose mass centre stands 0.4473 m inside the soles' support polygon (floor 0.200), one connected assembly of 414 shells, LOD ratios in band, collider 710 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --lift-crate 18; --tilt-sole 19; --skew-rod 20; --bottom-ram 21; --overload 22; --loose-light 23.

+

witnesses Recomputed: 44600 tris, ten materials with 2736 paint, 608 hazard, 3128 chrome, 15328 steel, 2740 rubber, 480 seat-vinyl, 640 harness, 256 beacon, 152 work-light and 516 crate-paint faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.827×1.689×2.974 m, zmin 0 with both soles on the floor, hygiene 0 including zero coplanar cross-shell pairs, all 28 clevis pins 0.000 mm off the axis of each of their three bushings and 0.000° to them (caps 0.3 mm, 0.3°), the crate's base biting both tines by 0.0020 m at every station along a 0.74 m run (band 0.0010–0.0040, run ≥ 0.50), both soles flat and level to 0.000 mm and 0.000° (caps 0.5 mm, 0.2°), all 8 ram rods 0.000 mm off their cylinders' axes and 0.0096° to them (caps 0.3 mm, 0.3°) with 0.1591–0.2858 m of rod exposed (band 0.080–0.340) and 0.060 m engaged (floor 0.040), a 2380.6 kg loader and crate whose mass centre stands 0.4473 m inside the soles' support polygon (floor 0.200), one connected assembly of 414 shells, LOD ratios in band, collider 532 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --lift-crate 18; --tilt-sole 19; --skew-rod 20; --bottom-ram 21; --overload 22; --loose-light 23.

@@ -1453,7 +1453,7 @@

Cargo Loader

Archery Target

archery-target

A procedural archery range target on a turf patch — a 1.10 m compressed-straw boss coiled from rope courses that show on its back and round its edge, bound with doubled jute twine drawn tight over the crests; an 80 cm ten-zone World Archery face in aged inks with ring lines, an X ring and a printed X, held by four target pins; a timber easel leaning it back 12° on toe skids with knee braces, a ledge with a stop lip on a bolted rail and gussets, a numbered butt board, a strap hinge pinned to a rear leg in a steel ferrule and foot, and a splay chain between eye bolts; five carbon arrows in the face with cresting, nocks and three vanes, one glancing into the straw edge, one snapped with its fletched half on the grass, and a leather quiver of arrows lying among grass tufts — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 42908 tris, sixteen materials with 4732 straw, 1856 twine, 1086 pine, 6288 steel, 522 white, 816 black, 128 blue, 128 red, 254 gold, 326 carbon, 500 vane, 300 cock-vane, 1076 nock, 5230 grass, 286 soil and 768 leather faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.007×2.689×2.054 m, zmin 0 with both skids and the rear tread bedded 2.0 mm into the turf (band 1–4 mm), hygiene 0 including zero coplanar cross-shell pairs, the hinge pin 0.000 mm off the axis of all three knuckles (tol 0.3 mm), the boss seated 2.5 mm into its ledge and leaning 2.0 mm on both legs (bands 1–4 mm), the gold centre 1.3000 m above the turf (World Archery 1.30 ± 0.05) on a 1.100 × 0.280 m boss and a 0.800 m face tilted 12.000° (band 10–15°), seven points buried 0.119–0.149 m in the straw (band 0.08–0.20) with straw left ahead, every vane at least 0.419 m clear of the boss (min 0.25), ten fletched shafts with three vanes each within 0.002° of 120° (tol 1°), all ten ring lines on the 4 cm scoring table (0.000 mm off, tol 0.5 mm) in the right inks, a 73.85 kg stand and boss whose mass centre is 0.349 m inside its supports with a forward tip angle of 27.83° (min 20°), one connected assembly of 722 shells, LOD ratios in band, collider 1083 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --lift-boss 18; --high-boss 19; --shallow-arrow 20; --short-arrow 21; --skew-vane 22; --wide-gold 23; --short-skids 24; --loose-pin 25.

+

witnesses Recomputed: 42908 tris, sixteen materials with 4732 straw, 1856 twine, 1086 pine, 6288 steel, 522 white, 816 black, 128 blue, 128 red, 254 gold, 326 carbon, 500 vane, 300 cock-vane, 1076 nock, 5230 grass, 286 soil and 768 leather faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.007×2.689×2.054 m, zmin 0 with both skids and the rear tread bedded 2.0 mm into the turf (band 1–4 mm), hygiene 0 including zero coplanar cross-shell pairs, the hinge pin 0.000 mm off the axis of all three knuckles (tol 0.3 mm), the boss seated 2.5 mm into its ledge and leaning 2.0 mm on both legs (bands 1–4 mm), the gold centre 1.3000 m above the turf (World Archery 1.30 ± 0.05) on a 1.100 × 0.280 m boss and a 0.800 m face tilted 12.000° (band 10–15°), seven points buried 0.119–0.149 m in the straw (band 0.08–0.20) with straw left ahead, every vane at least 0.419 m clear of the boss (min 0.25), ten fletched shafts with three vanes each within 0.002° of 120° (tol 1°), all ten ring lines on the 4 cm scoring table (0.000 mm off, tol 0.5 mm) in the right inks, a 73.85 kg stand and boss whose mass centre is 0.349 m inside its supports with a forward tip angle of 27.83° (min 20°), one connected assembly of 722 shells, LOD ratios in band, collider 634 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --lift-boss 18; --high-boss 19; --shallow-arrow 20; --short-arrow 21; --skew-vane 22; --wide-gold 23; --short-skids 24; --loose-pin 25.

@@ -1477,7 +1477,7 @@

Cactus Garden

Espresso Machine

espresso-machine

A procedural prosumer E61 semi-automatic espresso machine on a honed limestone countertop section — a black chassis behind a brushed stainless front panel, two side panels folded round the front and back edges, each one sheet with louvred vent slots cut through it, a warmer tray with a rail bent from one bar and four upturned cups, on adjustable feet; the chromed E61 group with its neck, thermosiphon pipe, gasket, mushroom cap and a lever pinned through two bosses; a spouted portafilter with a walnut handle locked against the gasket; steam and hot-water valves with fluted bakelite knobs and wands on ball joints; twin gauges with printed dials in chrome bezels; a toggle and pilot lamp; a drip tray whose slotted grate carries a shot cup of espresso; and a knock box, tamper and milk pitcher — with a studio carried in the metals' material so stainless reads as metal on a dark stage, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 43636 tris, fourteen materials with 4788 stainless, 7284 chrome, 948 bakelite, 632 wood, 5800 ceramic, 1244 rubber, 632 glass, 1642 dial, 64 ink, 36 needle, 91 stone, 26 paint, 452 coffee and 116 lamp faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.670×0.655×0.4755 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the lever pin 0.000000 m off the axis of both bosses and the hub (cap 0.0003) and spanning all three, all five cups seated 0.00020–0.00074 m on the warmer tray or the grate (band 0.0001–0.0009), the body 0.30000 m wide (0.300 ± 0.004) and its warmer tray 0.39070 m above the counter (0.3907 ± 0.004), the portafilter and gasket 0.000000 m off the group's axis (cap 0.0003) and the rim pressed 0.00040 m into the gasket (band 0.0001–0.0008), both gauge glasses 0.0034 m behind their bezels' lips (band 0.0015–0.0050), the drip tray 0.0250 m inside the side panels (floor 0.010) and tucked 0.0170 m behind the front panel (floor 0.005), the mass centre 0.1064 m inside the feet's support polygon (floor 0.060) at 39.83 kg, one connected assembly of 94 shells, LOD ratios in band, collider 447 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --sink-cup 18; --narrow-body 19; --offset-pf 20; --drop-pf 21; --proud-gauge 22; --shift-tray 23; --bunch-feet 24; --loose-knob 25.

+

witnesses Recomputed: 43636 tris, fourteen materials with 4788 stainless, 7284 chrome, 948 bakelite, 632 wood, 5800 ceramic, 1244 rubber, 632 glass, 1642 dial, 64 ink, 36 needle, 91 stone, 26 paint, 452 coffee and 116 lamp faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.670×0.655×0.4755 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the lever pin 0.000000 m off the axis of both bosses and the hub (cap 0.0003) and spanning all three, all five cups seated 0.00020–0.00074 m on the warmer tray or the grate (band 0.0001–0.0009), the body 0.30000 m wide (0.300 ± 0.004) and its warmer tray 0.39070 m above the counter (0.3907 ± 0.004), the portafilter and gasket 0.000000 m off the group's axis (cap 0.0003) and the rim pressed 0.00040 m into the gasket (band 0.0001–0.0008), both gauge glasses 0.0034 m behind their bezels' lips (band 0.0015–0.0050), the drip tray 0.0250 m inside the side panels (floor 0.010) and tucked 0.0170 m behind the front panel (floor 0.005), the mass centre 0.1064 m inside the feet's support polygon (floor 0.060) at 39.83 kg, one connected assembly of 94 shells, LOD ratios in band, collider 346 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --sink-cup 18; --narrow-body 19; --offset-pf 20; --drop-pf 21; --proud-gauge 22; --shift-tray 23; --bunch-feet 24; --loose-knob 25.

@@ -1489,7 +1489,7 @@

Espresso Machine

Road Bicycle

road-bicycle

A procedural 1970s lugged-steel road bicycle standing on its side kickstand — a 56 cm diamond frame of round tubes joined in chromed, spear-pointed lugs at the head tube, seat cluster and bottom bracket, tapered stays in chromed tips, a fork with a chromed sloping crown and socks; two 700c wheels, each a box-section rim with 36 spokes laced three-cross from both flanges of a small-flange hub to nipples through the rim, quick-release skewers and tan-wall tyres with a black file-tread crown; a 52/42 crankset with quill pedals, toe clips and straps, a six-speed freewheel, a roller chain of 112 individual links solved round the ring, the cog and both jockey wheels, front and rear derailleurs, down-tube shifters, side-pull calipers with pads a millimetre off the rims, levers under gum hoods on cotton-taped drop bars, a quill stem, a leather saddle on rails and a bottle in a bolted wire cage — leaned 5° onto its stand, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 46092 tris, ten materials with 1048 paint, 6438 chrome, 6950 alloy, 8239 steel, 540 tread, 952 gum, 356 leather, 1080 tape, 1810 black and 176 bottle faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.670×0.438×0.997 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs across 112 chain links, both tyres and the stand foot on the ground, both hubs 0.000000 m off their dropout eyes (cap 0.0005), every one of 72 spokes 3.00 mm deep in its flange (band 2.0–4.0 mm) and 4.50 mm inside its nipple on its axis, both rims 0.000 mm off the frame's plane (cap 1.0 mm), seat tube 0.5800 m, wheelbase 0.99982 m, trail 0.05536 m (band 0.045–0.065), lacing 36/36 with 18 per flange, pitch 0.000° off and every spoke three-cross (60.000°), 30 rollers seated on the ring and 10 on the cog 1.20–3.40 mm above the root (band 0.5–6.5 mm), every roller and the cog 0.000 mm off the chain line (cap 1.0 mm), the mass centre 0.0393 m inside the support triangle (floor 0.020) at 11.80 kg, one connected assembly of 685 shells, LOD ratios in band, collider 880 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --slip-wheel 17; --short-spoke 18; --dish-wheel 19; --steep-head 20; --bunch-spokes 21; --lift-chain 22; --shift-rollers 23; --tuck-stand 24; --pop-bottle 25.

+

witnesses Recomputed: 46092 tris, ten materials with 1048 paint, 6438 chrome, 6950 alloy, 8239 steel, 540 tread, 952 gum, 356 leather, 1080 tape, 1810 black and 176 bottle faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.670×0.438×0.997 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs across 112 chain links, both tyres and the stand foot on the ground, both hubs 0.000000 m off their dropout eyes (cap 0.0005), every one of 72 spokes 3.00 mm deep in its flange (band 2.0–4.0 mm) and 4.50 mm inside its nipple on its axis, both rims 0.000 mm off the frame's plane (cap 1.0 mm), seat tube 0.5800 m, wheelbase 0.99982 m, trail 0.05536 m (band 0.045–0.065), lacing 36/36 with 18 per flange, pitch 0.000° off and every spoke three-cross (60.000°), 30 rollers seated on the ring and 10 on the cog 1.20–3.40 mm above the root (band 0.5–6.5 mm), every roller and the cog 0.000 mm off the chain line (cap 1.0 mm), the mass centre 0.0393 m inside the support triangle (floor 0.020) at 11.80 kg, one connected assembly of 685 shells, LOD ratios in band, collider 574 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --slip-wheel 17; --short-spoke 18; --dish-wheel 19; --steep-head 20; --bunch-spokes 21; --lift-chain 22; --shift-rollers 23; --tuck-stand 24; --pop-bottle 25.

@@ -1501,7 +1501,7 @@

Road Bicycle

Skate Ramp

skate-ramp

A procedural backyard quarter-pipe, 1.2 m high on a 1.8 m transition and 2.44 m wide, with a skateboard on its deck — five plywood transition templates (curved bands with a solid toe and an arm under the deck) on 2x4 sills with studs and a back post sistered to their faces, nine 2x4 stringers under a two-layer 12 mm plywood skin whose joints are offset between layers and land on stringers, 143 screws in rows over the stringers, a 60 mm steel coping pipe standing proud of the transition on five welded, bolted tabs, a steel kicker plate ground to a lip at the toe on a timber toe block, a worn stencilled roundel and wheel marks on the riding face; the skateboard a seven-ply maple deck with concave and kicktails under grip tape, two trucks (baseplate, raked kingpin, bushings, hanger, pivot arm, axle) and four urethane wheels on bearings — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 31164 tris, nine materials with 3268 plywood, 1479 framing, 1086 steel, 7304 hardware, 1100 maple, 900 grip, 1536 urethane, 892 alloy and 464 bushing faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.529×2.440×1.339 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all five sills, the toe block and the plate on the floor, the riding face a circle of radius 1.80000 m (98 samples, 0.000 mm deviation, cap 1.0 mm) tangent to the ground, deck at 1.20000 m, five templates each 2.00 mm into its sill (band 1–6 mm) and 0.90–0.91 mm into the skin (band 0.3–2.5 mm), the coping straight and square to the width with a 5.00 mm reveal (band 2–8 mm) and 3.86 mm above the deck, the kicker plate 0.01 mm off flush (cap 0.6 mm) with a 0.80 mm toe, top seams at 0.84 and 1.84 m and the inner at 1.24 m (stagger 0.400 m, floor 0.30) each 43.9 mm inside its stringer, 143 screws 17.4 mm inside a stringer and 17.0 mm inside a sheet, four wheels 0.50 mm into the deck (band 0.2–1.2 mm), every wheel 0.000 mm off its axle, one connected assembly of 309 shells, LOD ratios in band, collider 350 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sill 16; --short-rib 17; --small-wheel 18; --sag-skin 19; --sink-coping 20; --proud-plate 21; --stack-seams 22; --miss-screws 23; --skew-wheel 24; --lift-grip 25.

+

witnesses Recomputed: 31164 tris, nine materials with 3268 plywood, 1479 framing, 1086 steel, 7304 hardware, 1100 maple, 900 grip, 1536 urethane, 892 alloy and 464 bushing faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.529×2.440×1.339 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all five sills, the toe block and the plate on the floor, the riding face a circle of radius 1.80000 m (98 samples, 0.000 mm deviation, cap 1.0 mm) tangent to the ground, deck at 1.20000 m, five templates each 2.00 mm into its sill (band 1–6 mm) and 0.90–0.91 mm into the skin (band 0.3–2.5 mm), the coping straight and square to the width with a 5.00 mm reveal (band 2–8 mm) and 3.86 mm above the deck, the kicker plate 0.01 mm off flush (cap 0.6 mm) with a 0.80 mm toe, top seams at 0.84 and 1.84 m and the inner at 1.24 m (stagger 0.400 m, floor 0.30) each 43.9 mm inside its stringer, 143 screws 17.4 mm inside a stringer and 17.0 mm inside a sheet, four wheels 0.50 mm into the deck (band 0.2–1.2 mm), every wheel 0.000 mm off its axle, one connected assembly of 309 shells, LOD ratios in band, collider 306 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sill 16; --short-rib 17; --small-wheel 18; --sag-skin 19; --sink-coping 20; --proud-plate 21; --stack-seams 22; --miss-screws 23; --skew-wheel 24; --lift-grip 25.

@@ -1525,7 +1525,7 @@

Palm Tree

Wingback Armchair

wingback-armchair

A procedural reading corner on a fringed wool rug — a Queen Anne / Chesterfield wingback armchair in oxblood leather whose tall reclined back is deep-button tufted, thirteen buttons on a diamond lattice each seated in a funnelled dimple with the leather puffed into pillows between them and folded into sharp pleats along every line that joins two buttons; two wings sweeping forward from the back into rolled arms, each arm one lofted scroll section with an English roll tucked under on the outside, a crowned front, a piped welt round the front seam and a row of brass nailheads following the scroll; a nailed front rail, a loose cushion with a crowned top and piped welts on both seams, cabriole front legs on pad feet and square rear legs splayed into brass ferrules; beside it a walnut tripod side table with a brass reading lamp (knopped stem, harp, finial, linen shade) and two cloth-bound books — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 44324 tris, nine materials with 15712 leather, 3628 wood, 4825 brass, 672 shade, 668 rug, 1512 fringe, 124 cloth, 12 paper and 212 bulb faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.030×1.400×1.160 m read off the vertices, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 chair feet and 3 table feet sunk 0.0020 m into the rug (band 0.0008–0.0040), all 4 legs tenoned 0.0288–0.0319 m into the body (band 0.012–0.045), all 13 buttons seated 0.0025 m (band 0.0012–0.0045) and 0.0074 m proud in dimples 0.0169–0.0185 m deep (min 0.008), the body mirror-symmetric to 0.000000 m over 10620 vertices (max 0.0005) with the seat 0.4531 m, the back 1.1113 m and the width 0.8683 m, 16 diagonal button pairs at 0.1617–0.1626 m (spread 0.00089, cap 0.004), the mass centre of table, lamp and books 0.0922 m inside the feet's triangle (min 0.045), the cushion pressed 0.0020 m into the deck (band 0.0008–0.0040), 28 + 28 + 19 nailheads at a 0.03000 m pitch with zero spread, seated 0.0010–0.0013 m, LOD ratios in band, collider 802 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --short-legs 17; --sink-buttons 18; --odd-wing 19; --drift-buttons 20; --narrow-tripod 21; --lift-cushion 22; --bunch-nails 23.

+

witnesses Recomputed: 44324 tris, nine materials with 15712 leather, 3628 wood, 4825 brass, 672 shade, 668 rug, 1512 fringe, 124 cloth, 12 paper and 212 bulb faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.030×1.400×1.160 m read off the vertices, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 chair feet and 3 table feet sunk 0.0020 m into the rug (band 0.0008–0.0040), all 4 legs tenoned 0.0288–0.0319 m into the body (band 0.012–0.045), all 13 buttons seated 0.0025 m (band 0.0012–0.0045) and 0.0074 m proud in dimples 0.0169–0.0185 m deep (min 0.008), the body mirror-symmetric to 0.000000 m over 10620 vertices (max 0.0005) with the seat 0.4531 m, the back 1.1113 m and the width 0.8683 m, 16 diagonal button pairs at 0.1617–0.1626 m (spread 0.00089, cap 0.004), the mass centre of table, lamp and books 0.0922 m inside the feet's triangle (min 0.045), the cushion pressed 0.0020 m into the deck (band 0.0008–0.0040), 28 + 28 + 19 nailheads at a 0.03000 m pitch with zero spread, seated 0.0010–0.0013 m, LOD ratios in band, collider 640 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --short-legs 17; --sink-buttons 18; --odd-wing 19; --drift-buttons 20; --narrow-tripod 21; --lift-cushion 22; --bunch-nails 23.

@@ -1537,7 +1537,7 @@

Wingback Armchair

Planet Rover

planet-rover

A procedural six-wheeled planetary science rover in the rocker-bogie tradition on a patch of rocky red-grey regolith — a cream warm-electronics body with gold-foil insulation blankets quilted into puffed cells, anodised corner posts and a trimmed deck carrying instrument boxes, sample inlets, a calibration target, a UHF can and a whip; a finned radioisotope power unit on struts between two radiator fin banks; on each side a rocker pivoting on a boss in the body side through its eye and pin, and a bogie pinned in a clevis on its front end, the two rockers linked through cranks and links to a differential bar on the deck so they turn equal and opposite; six 0.50 m aluminium drum wheels with 24 chevron grousers, six curved titanium flexure spokes and a drive actuator each, the four corners hanging from steering actuators through C-brackets; a camera mast with a laser telescope window, two camera barrels and navigation cameras; a high-gain dish on a two-axis gimbal; a 5-DOF arm whose turret drills a boulder; cable harnesses along every leg, the mast and the arm; ruts trailing behind both wheel lines and 19 broken rocks, the regolith fitted so every wheel sinks into it — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 46096 tris, nine materials with 2512 paint, 1276 foil, 6476 aluminium, 9330 anodised, 2392 titanium, 672 glass, 970 harness, 2516 regolith and 620 rock faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.857×3.709×2.200 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all six wheels sunk 0.0115–0.0189 m into the regolith (band 0.006–0.025), all 4 rocker and bogie pivots' 10 bushings 0.000000 m off their pins' axes (cap 0.0005), 144 grousers rooted 1.00 mm inside the drum skin (band 0.5–2.5 mm) and 7.50 mm proud, the mast 0.0000° off plumb with the track 2.7000 m, the length 3.3509 m and the height 2.1004 m, the rockers deflected +4.0000° and −4.0000° (residual 0, cap 0.10°) with both link eyes on their crank pins, all 4 steering axes 0.000000 m off their wheel centres (cap 0.001), every axle 0.0000° off the lateral (cap 0.20°), grouser pitch within 0.0148° of 15° (cap 0.30°), the mass centre of the 750.0 kg rover 1.0480 m inside the six wheels' contact polygon against a 0.8170 m 45° tip margin, one connected assembly of 441 shells, LOD ratios in band, collider 1120 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-wheel 16; --offset-pin 17; --sink-grousers 18; --lean-mast 19; --jam-rocker 20; --offset-steer 21; --camber-wheel 22; --bunch-grousers 23; --overload-turret 24; --loose-dish 25.

+

witnesses Recomputed: 46096 tris, nine materials with 2512 paint, 1276 foil, 6476 aluminium, 9330 anodised, 2392 titanium, 672 glass, 970 harness, 2516 regolith and 620 rock faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.857×3.709×2.200 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all six wheels sunk 0.0115–0.0189 m into the regolith (band 0.006–0.025), all 4 rocker and bogie pivots' 10 bushings 0.000000 m off their pins' axes (cap 0.0005), 144 grousers rooted 1.00 mm inside the drum skin (band 0.5–2.5 mm) and 7.50 mm proud, the mast 0.0000° off plumb with the track 2.7000 m, the length 3.3509 m and the height 2.1004 m, the rockers deflected +4.0000° and −4.0000° (residual 0, cap 0.10°) with both link eyes on their crank pins, all 4 steering axes 0.000000 m off their wheel centres (cap 0.001), every axle 0.0000° off the lateral (cap 0.20°), grouser pitch within 0.0148° of 15° (cap 0.30°), the mass centre of the 750.0 kg rover 1.0480 m inside the six wheels' contact polygon against a 0.8170 m 45° tip margin, one connected assembly of 441 shells, LOD ratios in band, collider 742 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-wheel 16; --offset-pin 17; --sink-grousers 18; --lean-mast 19; --jam-rocker 20; --offset-steer 21; --camber-wheel 22; --bunch-grousers 23; --overload-turret 24; --loose-dish 25.

@@ -1549,7 +1549,7 @@

Planet Rover

Traffic Cones

traffic-cones

A procedural roadworks set on a cut-out patch of asphalt — a broken-edged asphalt slab with a worn white road line and two sealed tar cracks; seven 720 mm PVC traffic cones, each a hollow lathed body with a moulded bead and a rolled lip round an open tip, bonded into a square rubber base with chamfered corners, a raked top, a collar, four moulded lugs and a recess underneath, and hooped with 4 in and 6 in retroreflective collars; three standing in a taper line, three nested in a stack whose wall thickness sets the nesting pitch, and one knocked over onto the edge of its base and the lip of its tip, its roll solved so both touch; a folding A-frame barricade of four square steel legs hinged in pairs on pivot bolts, spread by pinned straps on spacers, each foot in a rubber pad, carrying two boards on each face split on 45-degree lines into orange and white retroreflective stripes and bolted to the legs; and a warning lamp with amber fresnel lenses on a bracket bolted to the top board — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 45816 tris, eleven materials with 6048 cone PVC, 4088 reflective, 8096 rubber, 596 asphalt, 56 road paint, 496 tar, 64 orange sheeting, 384 board, 2912 steel, 720 black plastic and 696 lens faces, UVs in 0..1 with zero AABB overlap, outer AABB 3.037×2.037×1.335 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 10 supports (five cone bases, the fallen cone's body and four barricade pads) 1.5 mm into the slab (band 0.8–3.0 mm), 4 boards biting their legs 1.5 mm at all 8 joints (band 0.8–3.0 mm), 14 collars seated 0.600 mm into their bodies and 1.400 mm proud, 6 upright cones 0.0000° off plumb at 0.720 m on bases 0.356 m across the flats, the barricade's 4 legs mirrored within 0.0001 mm, one stack of 3 at a 0.036 m pitch with each inner wall bearing 0.847–1.105 mm on the wall below (band 0.4–2.0 mm), one connected assembly of 125 shells, LOD ratios in band, collider 493 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-cone 16; --gap-board 17; --float-band 18; --lean-cone 19; --skew-leg 19; --loose-stack 20; --loose-lamp 21.

+

witnesses Recomputed: 45816 tris, eleven materials with 6048 cone PVC, 4088 reflective, 8096 rubber, 596 asphalt, 56 road paint, 496 tar, 64 orange sheeting, 384 board, 2912 steel, 720 black plastic and 696 lens faces, UVs in 0..1 with zero AABB overlap, outer AABB 3.037×2.037×1.335 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 10 supports (five cone bases, the fallen cone's body and four barricade pads) 1.5 mm into the slab (band 0.8–3.0 mm), 4 boards biting their legs 1.5 mm at all 8 joints (band 0.8–3.0 mm), 14 collars seated 0.600 mm into their bodies and 1.400 mm proud, 6 upright cones 0.0000° off plumb at 0.720 m on bases 0.356 m across the flats, the barricade's 4 legs mirrored within 0.0001 mm, one stack of 3 at a 0.036 m pitch with each inner wall bearing 0.847–1.105 mm on the wall below (band 0.4–2.0 mm), one connected assembly of 125 shells, LOD ratios in band, collider 342 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-cone 16; --gap-board 17; --float-band 18; --lean-cone 19; --skew-leg 19; --loose-stack 20; --loose-lamp 21.

@@ -1561,7 +1561,7 @@

Traffic Cones

Mushroom Stump

mushroom-stump

A procedural felled-tree stump on a sloping forest-floor soil disc — one furrowed lathe about a plumb axis flaring through five buttresses into the ground, its bark peeled in two patches to grey sapwood a bark's thickness under a ragged torn lip with curling flakes, a felling top with weathered growth rings, radial drying checks, the undercut floor a step under the back cut and a low band of torn hinge fibres along the step, five surface roots bedded along their run, thin moss cushions laid on the furrowed bark with tufted rims, two tiers of turkey-tail brackets rooted in the bark, three fly agarics with warted caps, pleated gills, volva and skirt, and two clusters of ringed honey fungus out of a root and the stump's foot — with fallen leaves, bipinnate ferns, twigs and pebbles, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 56710 tris, twelve materials with 4441 bark, 1702 wood, 3080 moss, 1596 bracket, 672 fly-agaric, 1820 honey-cap, 4050 flesh, 1758 soil, 1232 litter, 17884 fern, 384 pebble and 210 twig faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.935×1.628×0.689 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the stump sealed in the soil in 8 of 8 sectors, all 16 caps seated on their stipes 0.0052–0.0137 m (band 0.003–0.030), the back cut 0.089° off level (max 1.0°), the stump 0.621 m across and 0.497 m tall (stated 0.62 and 0.50 ± 0.015 m), 5 roots bedded at every station, shallowest 0.055 m under the soil (min 0.006), all 16 stipes rooted 0.025–0.038 m in their soil, root or stump (band 0.008–0.070), all 6 bracket shelves 0.018–0.021 m into the bark (band 0.006–0.050), 0.946 of the moss top area facing up or north (floor 0.85), all 339 ground-cover shells joined to the soil, the undercut floor 0.035 m under the back cut (band 0.028–0.041) with the hinge band's tallest fibre 0.029 m over it (band 0.018–0.034), the torn bark 0.027 and 0.025 m over the sapwood at the two peels (band 0.020–0.034) with 12 flakes rooted 0.004–0.015 m in the bark (band 0.002–0.020), the moss at most 0.010 m over the bark (band 0.006–0.016), LOD ratios in band, stump collider 66 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --perch-stump 17; --float-caps 18; --tilt-cut 19; --fat-stump 19; --arch-roots 20; --float-mushrooms 21; --float-brackets 22; --sunny-moss 23; --float-cover 24; --flat-felling 25; --tall-hinge 25; --flush-peel 26; --float-flakes 26; --slab-moss 27.

+

witnesses Recomputed: 56710 tris, twelve materials with 4441 bark, 1702 wood, 3080 moss, 1596 bracket, 672 fly-agaric, 1820 honey-cap, 4050 flesh, 1758 soil, 1232 litter, 17884 fern, 384 pebble and 210 twig faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.935×1.628×0.689 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the stump sealed in the soil in 8 of 8 sectors, all 16 caps seated on their stipes 0.0052–0.0137 m (band 0.003–0.030), the back cut 0.089° off level (max 1.0°), the stump 0.621 m across and 0.497 m tall (stated 0.62 and 0.50 ± 0.015 m), 5 roots bedded at every station, shallowest 0.055 m under the soil (min 0.006), all 16 stipes rooted 0.025–0.038 m in their soil, root or stump (band 0.008–0.070), all 6 bracket shelves 0.018–0.021 m into the bark (band 0.006–0.050), 0.946 of the moss top area facing up or north (floor 0.85), all 339 ground-cover shells joined to the soil, the undercut floor 0.035 m under the back cut (band 0.028–0.041) with the hinge band's tallest fibre 0.029 m over it (band 0.018–0.034), the torn bark 0.027 and 0.025 m over the sapwood at the two peels (band 0.020–0.034) with 12 flakes rooted 0.004–0.015 m in the bark (band 0.002–0.020), the moss at most 0.010 m over the bark (band 0.006–0.016), LOD ratios in band, stump collider 52 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --perch-stump 17; --float-caps 18; --tilt-cut 19; --fat-stump 19; --arch-roots 20; --float-mushrooms 21; --float-brackets 22; --sunny-moss 23; --float-cover 24; --flat-felling 25; --tall-hinge 25; --flush-peel 26; --float-flakes 26; --slab-moss 27.

@@ -1573,7 +1573,7 @@

Mushroom Stump

Go Kart

go-kart

A procedural rental go-kart on a patch of kart-track asphalt against a red and white kerb — a 30 mm tube chassis whose main loop is one bar swept round every bend, cross tubes ending inside the rails with welded gussets, bearing hangers and kingpin C-brackets; spindles on kingpin bolts with 14° caster, a raked column in a bushing, a steering plate and two tie rods on rod-end eyes; blue moulded bodywork — a nose cone with a raised hump and lipped shoulders, pods with a crest, a ribbed deck and a groove, a front panel leaning back from the hump with a white number plate — on ten strap brackets welded to the tubes and bolted to the mouldings; a moulded seat on stays, a floor tray, pedals, a brake master cylinder with its hose to the caliper, a throttle cable, a strapped fuel tank and a lead ballast block; a finned four-stroke clamped to the rail driving the live rear axle through a clutch, an 88-link chain solved to a whole number of pitches and a 60-tooth sprocket, bearing carriers, a brake disc and caliper; and four loaded slicks on split rims with valve stems, the fronts narrower than the rears — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

-

witnesses Recomputed: 81854 tris, fourteen materials with 3168 frame paint, 6994 chrome, 8188 rubber, 3708 bodywork, 1548 seat, 12666 aluminium, 1920 engine casting, 4130 steel, 1686 black plastic, 172 fuel tank, 168 lead, 646 asphalt, 126 kerb paint and 124 number plate faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.895×1.774×0.640 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 tyres pressed 1.5 mm into the asphalt with their patches in one plane (band 0.8–3.0 mm), 4 hubs and 2 bearings 0.0 mm off their axles (≤ 0.3 mm), 4 tie-rod eyes on their pins and biting their plates 0.3–0.5 mm, tyre beads seated 0.864–1.000 mm on the rims (band 0.4–2.0 mm), the chain's inner edge 1.911–1.946 mm under both tooth-root circles (band 0.8–3.0 mm), frame and bodywork mirrored within 0.043 mm and the wheels within 0.0001 mm, wheelbase 1.040 m and tracks 1.100 / 1.200 m, caster 14.0°, the mass centre 0.374 m inside the tyres' support polygon (≥ 0.312 m), one connected assembly of 330 shells, 10 bodywork brackets each biting its tube 0.90–1.99 mm and its moulding 1.00–1.47 mm (band 0.5–2.5 mm), LOD ratios in band, collider 816 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --cock-hub 17; --drop-bearing 17; --short-tierod 17; --sink-tyre 18; --lift-chain 18; --toe-wheel 19; --wide-track 19; --odd-frame 19; --no-caster 19; --aft-ballast 20; --loose-ballast 21; --float-nose 23.

+

witnesses Recomputed: 81854 tris, fourteen materials with 3168 frame paint, 6994 chrome, 8188 rubber, 3708 bodywork, 1548 seat, 12666 aluminium, 1920 engine casting, 4130 steel, 1686 black plastic, 172 fuel tank, 168 lead, 646 asphalt, 126 kerb paint and 124 number plate faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.895×1.774×0.640 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 tyres pressed 1.5 mm into the asphalt with their patches in one plane (band 0.8–3.0 mm), 4 hubs and 2 bearings 0.0 mm off their axles (≤ 0.3 mm), 4 tie-rod eyes on their pins and biting their plates 0.3–0.5 mm, tyre beads seated 0.864–1.000 mm on the rims (band 0.4–2.0 mm), the chain's inner edge 1.911–1.946 mm under both tooth-root circles (band 0.8–3.0 mm), frame and bodywork mirrored within 0.043 mm and the wheels within 0.0001 mm, wheelbase 1.040 m and tracks 1.100 / 1.200 m, caster 14.0°, the mass centre 0.374 m inside the tyres' support polygon (≥ 0.312 m), one connected assembly of 330 shells, 10 bodywork brackets each biting its tube 0.90–1.99 mm and its moulding 1.00–1.47 mm (band 0.5–2.5 mm), LOD ratios in band, collider 598 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --cock-hub 17; --drop-bearing 17; --short-tierod 17; --sink-tyre 18; --lift-chain 18; --toe-wheel 19; --wide-track 19; --odd-frame 19; --no-caster 19; --aft-ballast 20; --loose-ballast 21; --float-nose 23.

diff --git a/docs/gallery/iron-cauldron/index.html b/docs/gallery/iron-cauldron/index.html index 15ba424a..bc05e66b 100644 --- a/docs/gallery/iron-cauldron/index.html +++ b/docs/gallery/iron-cauldron/index.html @@ -53,7 +53,7 @@

Iron Cauldron

A rust-blotched cast-iron cauldron with a raised belly band, hanging by its bail and a short chain from a forged iron head atop a tripod of wooden poles.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 4180 tris, two materials with 144 wood and 2116 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.987×0.961×0.860 m, pot–leg clearance 0.053 m, pot base radius 0.075 m, 3 coaxial ferrules at zmin 0, ferrule bite −0.00185 m, hook-bail join 0 under a five-link chain, bail threads both ear rings, mesh hygiene all zero, LOD ratios in band, convex collider 252 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --float-hook/--edge-on-ears 17; --pipe-ferrule 18; --pointed-pot 19.
+
witnesses Recomputed: 4180 tris, two materials with 144 wood and 2116 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.987×0.961×0.860 m, pot–leg clearance 0.053 m, pot base radius 0.075 m, 3 coaxial ferrules at zmin 0, ferrule bite −0.00185 m, hook-bail join 0 under a five-link chain, bail threads both ear rings, mesh hygiene all zero, LOD ratios in band, convex collider 196 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --float-hook/--edge-on-ears 17; --pipe-ferrule 18; --pointed-pot 19.

category Village

tags mesh export showcase

@@ -68,7 +68,7 @@

Iron Cauldron

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2800–42004180 / 4180 / 4180
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 2 distinct; ≥80 wood, ≥200 metal faces2 slots; 144 / 2116
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.987, 0.961, 0.860) m ± 0.015(0.9866, 0.9605, 0.8600), zmin 0
Collider tris≤ 280252
Exportwritten, size > 0324056 / 324056 / 324044 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2800–42004180 / 4180 / 4180
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 2 distinct; ≥80 wood, ≥200 metal faces2 slots; 144 / 2116
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.987, 0.961, 0.860) m ± 0.015(0.9866, 0.9605, 0.8600), zmin 0
Collider tris≤ 280196
Exportwritten, size > 0320368 / 320368 / 320364 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 3388 to 3664 in the quality pass: coaxial ferrule cups and a dual-wall lathe with a rolled rim replaced the old cone-tripod / overlapping-torus construction. The #345 remodel (the asset sheet read it as the least-designed object in the lineup) took it to 4180: a five-link chain replaced the bare hanging rod, a forged iron head replaced the turned wooden crown, and the pot gained a casting band and three stub feet. The iron material breaks its rust into blotches and adds fine sand-cast pitting. 4180 leaves 20 triangles under the ceiling, enough for --short-legs's 12-triangle shim to still land on the support check (16), not the triangle budget (4).

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/market-stall/index.html b/docs/gallery/market-stall/index.html index f178257a..7e829aee 100644 --- a/docs/gallery/market-stall/index.html +++ b/docs/gallery/market-stall/index.html @@ -53,7 +53,7 @@

Market Stall

A grained timber market stall with diagonal side braces, a red and cream striped canvas awning and a counter with shelves.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 4324 tris, three materials with 34 faces per awning stripe slot, UVs in 0..1 with zero AABB overlap, outer AABB 1.389×1.011×1.740 m, grounded zmin, 4 wrap feet, brace-counter overlap 0, both side braces seated 0.0418 m into their posts, awning seat 4 mm, post plumb 0, LOD ratios in band, convex collider 58 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --low-brace/--short-brace 17; --float-awning 18; --rake-posts 19.
+
witnesses Recomputed: 4324 tris, three materials with 34 faces per awning stripe slot, UVs in 0..1 with zero AABB overlap, outer AABB 1.389×1.011×1.740 m, grounded zmin, 4 wrap feet, brace-counter overlap 0, both side braces seated 0.0418 m into their posts, awning seat 4 mm, post plumb 0, LOD ratios in band, convex collider 56 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --low-brace/--short-brace 17; --float-awning 18; --rake-posts 19.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Market Stall

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles3900–52004324 / 4324 / 4324
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2197
Materialsexactly 3 distinct; ≥16 faces per stripe slot3 slots; 34 / 34 stripe faces
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.389, 1.011, 1.740) m ± 0.01(1.3892, 1.0107, 1.7402), zmin 0
Collider tris≤ 8058
Exportwritten, size > 0, removed after measuring312400 / 312400 / 312376 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles3900–52004324 / 4324 / 4324
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2197
Materialsexactly 3 distinct; ≥16 faces per stripe slot3 slots; 34 / 34 stripe faces
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.389, 1.011, 1.740) m ± 0.01(1.3892, 1.0107, 1.7402), zmin 0
Collider tris≤ 8056
Exportwritten, size > 0, removed after measuring310792 / 310792 / 310784 bytes (4.5.11 / 5.1.2 / 5.2.1)

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

AxisDeclaredMeasured (all three)
Non-manifold edges00
Loose verts / edges0 / 00 / 0
Doubles merged at 1e-500
Zero-area faces00
N-gons00
Coplanar disjoint face pairs00
Grounded: zminwithin 1e-4 of 00.0000
Named supports: 4 wrap feeteach zmin ≤ 1e-34, foot_z 0.00000
Frame plan1.36 × 0.92 m ± 0.041.3600 × 0.9200
diff --git a/docs/gallery/motor-scooter/index.html b/docs/gallery/motor-scooter/index.html index 352af538..9f1a8197 100644 --- a/docs/gallery/motor-scooter/index.html +++ b/docs/gallery/motor-scooter/index.html @@ -53,7 +53,7 @@

Motor Scooter

A pastel sea-green 1960s scooter on its centre stand: cream and oxblood saddle, louvred side cowl, curved chrome-rimmed leg shield, split-rim front wheel, black silencer.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 45060 tris, nine materials with 7156 paint, 4638 chrome, 3608 rubber, 1147 oxblood vinyl, 297 cream vinyl, 550 glass, 188 tail-lens, 4020 alloy and 2292 black-enamel faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.790×0.730×1.244 m, zmin 0 with both tyres and both stand feet on the floor, hygiene 0 including zero coplanar cross-shell pairs, both axles level and parallel (camber 0.000°, toe 0.000°, cap 0.3°), the steering column raked 26.000° meeting the ground 0.0750 m ahead of the front contact (band 0.055–0.090) and on its line, the body mirror-symmetric to 0.000 mm (cap 0.5, engine side excluded by construction), tail 0.862 m and saddle top 0.807 m, a 1.20000 m wheelbase (±0.004), a 101.6 kg scooter whose mass centre stands 0.1284 m inside its tyres-and-stand support polygon (floor 0.080), one connected assembly of 105 shells, the leg shield's foot 0.0320 m deep in the floorboard (band 0.020–0.040), LOD ratios in band, collider 1678 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --toe-wheel 17; --steep-head 18; --odd-body 19; --short-wheelbase 20; --narrow-stand 21; --pop-speedo 22; --lift-shield 23.
+
witnesses Recomputed: 45060 tris, nine materials with 7156 paint, 4638 chrome, 3608 rubber, 1147 oxblood vinyl, 297 cream vinyl, 550 glass, 188 tail-lens, 4020 alloy and 2292 black-enamel faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.790×0.730×1.244 m, zmin 0 with both tyres and both stand feet on the floor, hygiene 0 including zero coplanar cross-shell pairs, both axles level and parallel (camber 0.000°, toe 0.000°, cap 0.3°), the steering column raked 26.000° meeting the ground 0.0750 m ahead of the front contact (band 0.055–0.090) and on its line, the body mirror-symmetric to 0.000 mm (cap 0.5, engine side excluded by construction), tail 0.862 m and saddle top 0.807 m, a 1.20000 m wheelbase (±0.004), a 101.6 kg scooter whose mass centre stands 0.1284 m inside its tyres-and-stand support polygon (floor 0.080), one connected assembly of 105 shells, the leg shield's foot 0.0320 m deep in the floorboard (band 0.020–0.040), LOD ratios in band, collider 1132 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --toe-wheel 17; --steep-head 18; --odd-body 19; --short-wheelbase 20; --narrow-stand 21; --pop-speedo 22; --lift-shield 23.

category Vehicles

tags mesh export showcase

@@ -70,7 +70,7 @@

Motor Scooter

Intended size: 1.79 m from the mudguard's nose to the number plate, 0.73 m across the bar-end caps, 1.24 m to the mirror tops, with the saddle's top at 0.807 m and a 1.20 m wheelbase. The body's tail is 0.862 m long. The origin is under the scooter's centre, so it lands on its tyres and stand.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles44400–4570045060
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥6440 paint, ≥4350 chrome, ≥3250 rubber, ≥1030 oxblood vinyl, ≥265 cream vinyl, ≥495 glass, ≥170 tail lens, ≥3620 alloy, ≥2060 black enamel faces9 slots; 7156 / 4638 / 3608 / 1147 / 297 / 550 / 188 / 4020 / 2292
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.790, 0.730, 1.244) m ± 0.01(1.7901, 0.7300, 1.2435), zmin 0
Collider tris≤ 18501678
Exportwritten, size > 0, removed after measuring3374040 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles44400–4570045060
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥6440 paint, ≥4350 chrome, ≥3250 rubber, ≥1030 oxblood vinyl, ≥265 cream vinyl, ≥495 glass, ≥170 tail lens, ≥3620 alloy, ≥2060 black enamel faces9 slots; 7156 / 4638 / 3608 / 1147 / 297 / 550 / 188 / 4020 / 2292
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.790, 0.730, 1.244) m ± 0.01(1.7901, 0.7300, 1.2435), zmin 0
Collider tris≤ 18501132
Exportwritten, size > 0, removed after measuring3347780 / 3347780 / 3347776 bytes (4.5.11 / 5.1.2 / 5.2.1)

The collider is the convex hull of the whole scooter; the mudguard, the mirrors and the tail carry its outline.

Every falsifier leaves the triangle count at 45060 and the outer AABB unchanged: they move, turn or bend parts, never add or remove them.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

diff --git a/docs/gallery/mushroom-stump/index.html b/docs/gallery/mushroom-stump/index.html index 936ac892..96589f92 100644 --- a/docs/gallery/mushroom-stump/index.html +++ b/docs/gallery/mushroom-stump/index.html @@ -53,7 +53,7 @@

Mushroom Stump

A sawn tree stump with a stepped felling cut and torn hinge fibres, peeled bark, moss, shelf fungi, honey mushrooms, red fly agarics, ferns and fallen leaves on soil.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 56710 tris, twelve materials with 4441 bark, 1702 wood, 3080 moss, 1596 bracket, 672 fly-agaric, 1820 honey-cap, 4050 flesh, 1758 soil, 1232 litter, 17884 fern, 384 pebble and 210 twig faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.935×1.628×0.689 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the stump sealed in the soil in 8 of 8 sectors, all 16 caps seated on their stipes 0.0052–0.0137 m (band 0.003–0.030), the back cut 0.089° off level (max 1.0°), the stump 0.621 m across and 0.497 m tall (stated 0.62 and 0.50 ± 0.015 m), 5 roots bedded at every station, shallowest 0.055 m under the soil (min 0.006), all 16 stipes rooted 0.025–0.038 m in their soil, root or stump (band 0.008–0.070), all 6 bracket shelves 0.018–0.021 m into the bark (band 0.006–0.050), 0.946 of the moss top area facing up or north (floor 0.85), all 339 ground-cover shells joined to the soil, the undercut floor 0.035 m under the back cut (band 0.028–0.041) with the hinge band's tallest fibre 0.029 m over it (band 0.018–0.034), the torn bark 0.027 and 0.025 m over the sapwood at the two peels (band 0.020–0.034) with 12 flakes rooted 0.004–0.015 m in the bark (band 0.002–0.020), the moss at most 0.010 m over the bark (band 0.006–0.016), LOD ratios in band, stump collider 66 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --perch-stump 17; --float-caps 18; --tilt-cut 19; --fat-stump 19; --arch-roots 20; --float-mushrooms 21; --float-brackets 22; --sunny-moss 23; --float-cover 24; --flat-felling 25; --tall-hinge 25; --flush-peel 26; --float-flakes 26; --slab-moss 27.
+
witnesses Recomputed: 56710 tris, twelve materials with 4441 bark, 1702 wood, 3080 moss, 1596 bracket, 672 fly-agaric, 1820 honey-cap, 4050 flesh, 1758 soil, 1232 litter, 17884 fern, 384 pebble and 210 twig faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.935×1.628×0.689 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the stump sealed in the soil in 8 of 8 sectors, all 16 caps seated on their stipes 0.0052–0.0137 m (band 0.003–0.030), the back cut 0.089° off level (max 1.0°), the stump 0.621 m across and 0.497 m tall (stated 0.62 and 0.50 ± 0.015 m), 5 roots bedded at every station, shallowest 0.055 m under the soil (min 0.006), all 16 stipes rooted 0.025–0.038 m in their soil, root or stump (band 0.008–0.070), all 6 bracket shelves 0.018–0.021 m into the bark (band 0.006–0.050), 0.946 of the moss top area facing up or north (floor 0.85), all 339 ground-cover shells joined to the soil, the undercut floor 0.035 m under the back cut (band 0.028–0.041) with the hinge band's tallest fibre 0.029 m over it (band 0.018–0.034), the torn bark 0.027 and 0.025 m over the sapwood at the two peels (band 0.020–0.034) with 12 flakes rooted 0.004–0.015 m in the bark (band 0.002–0.020), the moss at most 0.010 m over the bark (band 0.006–0.016), LOD ratios in band, stump collider 52 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --perch-stump 17; --float-caps 18; --tilt-cut 19; --fat-stump 19; --arch-roots 20; --float-mushrooms 21; --float-brackets 22; --sunny-moss 23; --float-cover 24; --flat-felling 25; --tall-hinge 25; --flush-peel 26; --float-flakes 26; --slab-moss 27.

category Nature

tags mesh export showcase

@@ -71,7 +71,7 @@

Mushroom Stump

Intended size: a stump 0.62 m across the bark at the cut, sawn 0.50 m above the soil at its axis, on a soil disc 1.7 × 1.6 m. The outer AABB is 1.935 × 1.628 × 0.689 m. Two fern fronds set X, the soil sets Y, and the tallest hinge fibre the top. The soil's underside is the ground. The collider is the convex hull of the stump alone, round and unfurrowed, down to the soil: players walk through ferns and step over roots.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles56150–5725056710
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 12 distinct; ≥4000 bark, ≥1530 wood, ≥2770 moss, ≥1440 bracket, ≥600 agaric, ≥1640 honey, ≥3640 flesh, ≥1580 soil, ≥1100 litter, ≥16100 fern, ≥345 stone, ≥190 twig faces12 slots; 4441 / 1702 / 3080 / 1596 / 672 / 1820 / 4050 / 1758 / 1232 / 17884 / 384 / 210
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.9351, 1.6283, 0.6888) m ± 0.01(1.9351, 1.6283, 0.6888), zmin 0
Collider tris (stump hull)≤ 7566
Exportwritten, size > 0, removed after measuring5733424 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles56150–5725056710
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 12 distinct; ≥4000 bark, ≥1530 wood, ≥2770 moss, ≥1440 bracket, ≥600 agaric, ≥1640 honey, ≥3640 flesh, ≥1580 soil, ≥1100 litter, ≥16100 fern, ≥345 stone, ≥190 twig faces12 slots; 4441 / 1702 / 3080 / 1596 / 672 / 1820 / 4050 / 1758 / 1232 / 17884 / 384 / 210
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.9351, 1.6283, 0.6888) m ± 0.01(1.9351, 1.6283, 0.6888), zmin 0
Collider tris (stump hull)≤ 7552
Exportwritten, size > 0, removed after measuring5733356 / 5733356 / 5733340 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the triangle count, and only --tall-hinge moves the envelope, 7.2 mm up against the 10 mm tolerance: they move parts or reshape the foot, never add or remove faces. The upper lathe carries a fixed ring count, so moving the foot keeps the topology; the step's chord scales with --fat-stump, so the cuts along it cross the same edges.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; two default runs print identical measurements, and 4.5.11 and 5.1.2 print the same measurements as 5.2.1 (the glTF differs by 16 bytes).

Hygiene#

diff --git a/docs/gallery/office-chair/index.html b/docs/gallery/office-chair/index.html index 68e00217..43c0f77c 100644 --- a/docs/gallery/office-chair/index.html +++ b/docs/gallery/office-chair/index.html @@ -53,7 +53,7 @@

Office Chair

A graphite mesh-back office chair with a muted-teal two-tone seat, mesh headrest and polished five-star base, on a smoked chair mat beside a snake plant in a stone planter.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 44440 tris, fourteen materials each above its face floor, UVs in 0..1 with zero AABB overlap, outer AABB 1.635×1.480×1.317 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the mat flat on the floor, all 10 wheels pressed 0.6 mm into the mat, the pot on the floor, spokes and bosses 72° apart (worst 0.00001°), bosses and swivel stems on one 0.305 m circle, stems plumb, coaxial and seated 34 mm, the gas-lift column coaxial with hub and socket (0.0 mm) and seated 52 and 28 mm, seven armrest part pairs mirrored and level within 0.5 mm, seat 0.497 m high, armrests 0.197 m over it, a 0.660 m star, the mass centre 0.215 m inside the caster contact hull (floor 0.12), one connected chair of 89 shells, both lumbar sliders 3.5–5.2 mm off the frame tube, nine leaves rooted 24.5–31.6 mm in the soil, LOD ratios in band, collider 551 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-caster 16; --curl-mat 16; --skew-spoke 17; --offset-column 18; --uneven-arms 19; --loose-wheel 20; --float-lumbar 21; --float-leaves 22.
+
witnesses Recomputed: 44440 tris, fourteen materials each above its face floor, UVs in 0..1 with zero AABB overlap, outer AABB 1.635×1.480×1.317 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the mat flat on the floor, all 10 wheels pressed 0.6 mm into the mat, the pot on the floor, spokes and bosses 72° apart (worst 0.00001°), bosses and swivel stems on one 0.305 m circle, stems plumb, coaxial and seated 34 mm, the gas-lift column coaxial with hub and socket (0.0 mm) and seated 52 and 28 mm, seven armrest part pairs mirrored and level within 0.5 mm, seat 0.497 m high, armrests 0.197 m over it, a 0.660 m star, the mass centre 0.215 m inside the caster contact hull (floor 0.12), one connected chair of 89 shells, both lumbar sliders 3.5–5.2 mm off the frame tube, nine leaves rooted 24.5–31.6 mm in the soil, LOD ratios in band, collider 374 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-caster 16; --curl-mat 16; --skew-spoke 17; --offset-column 18; --uneven-arms 19; --loose-wheel 20; --float-lumbar 21; --float-leaves 22.

category Household

tags mesh export showcase

@@ -73,7 +73,7 @@

Office Chair

Intended size: seat 0.50 m high, a 0.66 m star, armrests 0.20 m over the seat, headrest top 1.32 m; a 1.20 × 1.28 m mat plus its 0.20 m lip; a planter 0.29 m tall with leaves to 0.96 m. The outer AABB is 1.635 × 1.480 × 1.317 m. The mat sets −X and ±Y, the plant sets +X, the headrest sets the top. The origin is under the hub, so the chair and its mat drop onto a floor together.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file. Parts are told apart by a part face attribute written at build time; every position, depth, angle and mass is read off the mesh.

-
AxisDeclaredMeasured (5.2.1)
Base triangles43700–4520044440
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 14 distinct; ≥1330 fabric, ≥1450 mesh, ≥3260 shell, ≥4100 nylon, ≥3950 aluminium, ≥1370 chrome, ≥1820 tread, ≥1600 leatherette, ≥510 steel, ≥1060 border, ≥790 mat, ≥750 ceramic, ≥220 soil, ≥715 leaf faces14 slots; 1402 / 1534 / 3440 / 4322 / 4167 / 1450 / 1920 / 1688 / 538 / 1118 / 836 / 796 / 236 / 756
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.635, 1.480, 1.317) m ± 0.01(1.6350, 1.4800, 1.3169), zmin 0
Collider tris≤ 580551
Exportwritten, size > 0, removed after measuring3294736 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles43700–4520044440
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 14 distinct; ≥1330 fabric, ≥1450 mesh, ≥3260 shell, ≥4100 nylon, ≥3950 aluminium, ≥1370 chrome, ≥1820 tread, ≥1600 leatherette, ≥510 steel, ≥1060 border, ≥790 mat, ≥750 ceramic, ≥220 soil, ≥715 leaf faces14 slots; 1402 / 1534 / 3440 / 4322 / 4167 / 1450 / 1920 / 1688 / 538 / 1118 / 836 / 796 / 236 / 756
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.635, 1.480, 1.317) m ± 0.01(1.6350, 1.4800, 1.3169), zmin 0
Collider tris≤ 580374
Exportwritten, size > 0, removed after measuring3283660 / 3283660 / 3283652 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the triangle count, so the band is narrow and centred on the measurement. DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; the plant's per-blade variation is closed-form from the blade index. Two default runs print identical measurements.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/palm-tree/index.html b/docs/gallery/palm-tree/index.html index 3d2b080a..8087f3bf 100644 --- a/docs/gallery/palm-tree/index.html +++ b/docs/gallery/palm-tree/index.html @@ -71,7 +71,7 @@

Palm Tree

Intended size: a disc 3.1 × 2.8 m, the palm 6.03 m to the tip of its highest frond. The outer AABB is 5.2645 × 5.1503 × 6.0258 m, read off the vertices: the fronds set X, Y and the top; the sand's underside is the ground. The collider is the convex hull of the lower 2.4 m of the trunk, coarse: players walk the sand and brush through the fronds, but not through the bole.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles44600–4580045196
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥3400 sand, ≥4370 bark, ≥13640 frond, ≥1140 dead frond, ≥1230 husk, ≥780 shell, ≥134 driftwood, ≥1030 grass faces8 slots; 3694 / 4752 / 14828 / 1243 / 1344 / 846 / 146 / 1118
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(5.2645, 5.1503, 6.0258) m ± 0.01(5.2645, 5.1503, 6.0258), zmin 0
Collider tris (lower trunk hull)≤ 6044
Exportwritten, size > 0, removed after measuring3518252 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles44600–4580045196
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥3400 sand, ≥4370 bark, ≥13640 frond, ≥1140 dead frond, ≥1230 husk, ≥780 shell, ≥134 driftwood, ≥1030 grass faces8 slots; 3694 / 4752 / 14828 / 1243 / 1344 / 846 / 146 / 1118
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(5.2645, 5.1503, 6.0258) m ± 0.01(5.2645, 5.1503, 6.0258), zmin 0
Collider tris (lower trunk hull)≤ 6044
Exportwritten, size > 0, removed after measuring3518264 / 3518264 / 3518252 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the triangle count: every falsifier run measured 45196 tris. None moves the envelope by more than 0.1 mm.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; the geometry is pure Python math. Two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/park-bench/index.html b/docs/gallery/park-bench/index.html index 20e19821..9bd97ec7 100644 --- a/docs/gallery/park-bench/index.html +++ b/docs/gallery/park-bench/index.html @@ -53,7 +53,7 @@

Park Bench

A park bench of grained wooden slats with a reclined back, on a dark wrought-iron frame whose round-bar legs curl into scrolled feet, with armrests on curved brackets.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 3272 tris, two materials with 1008 metal and 756 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.295×0.632×0.887 m, grounded zmin, 4 named toes, 4 legs each one bar from toe to seat, back reclined 12°, 28 slat and armrest bites of at least 2.0 mm, stretcher gap 1.1 mm, seat span 1.272 m, LOD ratios in band, convex collider 64 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --float-stretcher 17; --gap-slats 18; --narrow-seat/--upright-back 19; --float-slats 20; --split-feet 21.
+
witnesses Recomputed: 3272 tris, two materials with 1008 metal and 756 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.295×0.632×0.887 m, grounded zmin, 4 named toes, 4 legs each one bar from toe to seat, back reclined 12°, 28 slat and armrest bites of at least 2.0 mm, stretcher gap 1.1 mm, seat span 1.272 m, LOD ratios in band, convex collider 60 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --float-stretcher 17; --gap-slats 18; --narrow-seat/--upright-back 19; --float-slats 20; --split-feet 21.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Park Bench

Intended size: 1.40 m sitting width, 0.50 m seat depth, 0.43 m seat height, 0.64 m arm height, back reclined 12°. Outer AABB 1.295 × 0.632 × 0.887 m.

Budgets#

Declared as named constants. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2900–37003272 / 3272 / 3272
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2194 / 0.2194 / 0.2194
Materialsexactly 2 distinct, ≥48 metal, ≥24 wood2 slots, 1008 metal / 756 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.295, 0.632, 0.887) m ± 0.015(1.2945, 0.6316, 0.8870), zmin 0
Collider tris≤ 18064
Exportwritten, size > 0245620 / 245620 / 245604 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2900–37003272 / 3272 / 3272
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2194 / 0.2194 / 0.2194
Materialsexactly 2 distinct, ≥48 metal, ≥24 wood2 slots, 1008 metal / 756 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.295, 0.632, 0.887) m ± 0.015(1.2945, 0.6316, 0.8870), zmin 0
Collider tris≤ 18060
Exportwritten, size > 0244056 / 244056 / 244048 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 2520 to 3272 in the second quality pass. The square posts and 6-gon scroll tubes became 8-gon round bar swept along each leg, the back gained its bend, and armrest brackets were added. The band was re-fitted around the measurement and narrowed from 2200–4200.

DECIMATE COLLAPSE triangle counts are not guaranteed identical across series — the gate is a ratio band, not an exact count. This mesh matched on 4.5.11 / 5.1.2 / 5.2.1. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Slat widths are closed-form and plank tones are seeded, so repeated runs on one binary print identical measurements. Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

diff --git a/docs/gallery/pine-tree/index.html b/docs/gallery/pine-tree/index.html index 4206772f..2b8aa437 100644 --- a/docs/gallery/pine-tree/index.html +++ b/docs/gallery/pine-tree/index.html @@ -53,7 +53,7 @@

Pine Tree

A mature Scots pine on a dark studio floor: a bare grey-plated bole with dead lower limbs under a broad crown of soft blue-green needle brushes, on a soil disc with mossy stones.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 45852 tris, six materials with 3026 bark, 36612 needle, 1024 cone, 274 deadwood, 878 soil and 192 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 9.284×7.932×7.659 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 33 limbs and 7 dead members seated in the trunk (base 0.43–0.47 of the bark radius from the axis, band 0.25–0.75), 8 whorls of 3–5 limbs with gaps 0.40–0.45 m (band 0.32–0.60), trunk lean 0.489°, needle mass 0.047 m off the base axis, breast-height diameter 0.3768 m, every one of 113 needle brushes holding its own carrier at least 0.059 m deep (min 0.040), fallen cones and sticks 0.010 m and stones 0.045 m into the soil, roots at least 0.091 m under it, one connected assembly of 266 shells, LOD ratios in band, trunk collider 56 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-branches 17; --lean-crown 19; --bunch-whorls 20; --drop-cones 21; --short-twigs 22; --float-litter 23.
+
witnesses Recomputed: 45852 tris, six materials with 3026 bark, 36612 needle, 1024 cone, 274 deadwood, 878 soil and 192 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 9.284×7.932×7.659 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 33 limbs and 7 dead members seated in the trunk (base 0.43–0.47 of the bark radius from the axis, band 0.25–0.75), 8 whorls of 3–5 limbs with gaps 0.40–0.45 m (band 0.32–0.60), trunk lean 0.489°, needle mass 0.047 m off the base axis, breast-height diameter 0.3768 m, every one of 113 needle brushes holding its own carrier at least 0.059 m deep (min 0.040), fallen cones and sticks 0.010 m and stones 0.045 m into the soil, roots at least 0.091 m under it, one connected assembly of 266 shells, LOD ratios in band, trunk collider 54 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-branches 17; --lean-crown 19; --bunch-whorls 20; --drop-cones 21; --short-twigs 22; --float-litter 23.

category Nature

tags mesh export showcase

@@ -74,7 +74,7 @@

Pine Tree

The collider is the convex hull of a 14-sided trunk alone, without ridges or roots, because players walk under the branches. The side count is chosen for the ceiling: a 20-sided hull measured 58 triangles and a 10-sided one 80, while 14 sides give 56.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles43500–4600045852
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 6 distinct; face floors bark ≥2850, needle ≥35000, cone ≥950, deadwood ≥250, soil ≥820, stone ≥1706 slots; 3026 / 36612 / 1024 / 274 / 878 / 192
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(9.284, 7.932, 7.659) m ± 0.01(9.2837, 7.9318, 7.6586), zmin 0
Collider tris (trunk hull)≤ 6056
Exportwritten, size > 0, removed after measuring5703388 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles43500–4600045852
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 6 distinct; face floors bark ≥2850, needle ≥35000, cone ≥950, deadwood ≥250, soil ≥820, stone ≥1706 slots; 3026 / 36612 / 1024 / 274 / 878 / 192
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(9.284, 7.932, 7.659) m ± 0.01(9.2837, 7.9318, 7.6586), zmin 0
Collider tris (trunk hull)≤ 6054
Exportwritten, size > 0, removed after measuring5703232 / 5703232 / 5703216 bytes (4.5.11 / 5.1.2 / 5.2.1)

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; two default runs print identical measurements.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/planet-rover/index.html b/docs/gallery/planet-rover/index.html index 4877767c..8ff0511c 100644 --- a/docs/gallery/planet-rover/index.html +++ b/docs/gallery/planet-rover/index.html @@ -53,7 +53,7 @@

Planet Rover

A six-wheeled rocker-bogie rover with gold-foil sides, a camera mast, a dish antenna and a finned power unit, its arm drilling a boulder on red-grey regolith.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 46096 tris, nine materials with 2512 paint, 1276 foil, 6476 aluminium, 9330 anodised, 2392 titanium, 672 glass, 970 harness, 2516 regolith and 620 rock faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.857×3.709×2.200 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all six wheels sunk 0.0115–0.0189 m into the regolith (band 0.006–0.025), all 4 rocker and bogie pivots' 10 bushings 0.000000 m off their pins' axes (cap 0.0005), 144 grousers rooted 1.00 mm inside the drum skin (band 0.5–2.5 mm) and 7.50 mm proud, the mast 0.0000° off plumb with the track 2.7000 m, the length 3.3509 m and the height 2.1004 m, the rockers deflected +4.0000° and −4.0000° (residual 0, cap 0.10°) with both link eyes on their crank pins, all 4 steering axes 0.000000 m off their wheel centres (cap 0.001), every axle 0.0000° off the lateral (cap 0.20°), grouser pitch within 0.0148° of 15° (cap 0.30°), the mass centre of the 750.0 kg rover 1.0480 m inside the six wheels' contact polygon against a 0.8170 m 45° tip margin, one connected assembly of 441 shells, LOD ratios in band, collider 1120 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-wheel 16; --offset-pin 17; --sink-grousers 18; --lean-mast 19; --jam-rocker 20; --offset-steer 21; --camber-wheel 22; --bunch-grousers 23; --overload-turret 24; --loose-dish 25.
+
witnesses Recomputed: 46096 tris, nine materials with 2512 paint, 1276 foil, 6476 aluminium, 9330 anodised, 2392 titanium, 672 glass, 970 harness, 2516 regolith and 620 rock faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.857×3.709×2.200 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all six wheels sunk 0.0115–0.0189 m into the regolith (band 0.006–0.025), all 4 rocker and bogie pivots' 10 bushings 0.000000 m off their pins' axes (cap 0.0005), 144 grousers rooted 1.00 mm inside the drum skin (band 0.5–2.5 mm) and 7.50 mm proud, the mast 0.0000° off plumb with the track 2.7000 m, the length 3.3509 m and the height 2.1004 m, the rockers deflected +4.0000° and −4.0000° (residual 0, cap 0.10°) with both link eyes on their crank pins, all 4 steering axes 0.000000 m off their wheel centres (cap 0.001), every axle 0.0000° off the lateral (cap 0.20°), grouser pitch within 0.0148° of 15° (cap 0.30°), the mass centre of the 750.0 kg rover 1.0480 m inside the six wheels' contact polygon against a 0.8170 m 45° tip margin, one connected assembly of 441 shells, LOD ratios in band, collider 742 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-wheel 16; --offset-pin 17; --sink-grousers 18; --lean-mast 19; --jam-rocker 20; --offset-steer 21; --camber-wheel 22; --bunch-grousers 23; --overload-turret 24; --loose-dish 25.

category Vehicles

tags mesh export showcase

@@ -70,7 +70,7 @@

Planet Rover

Intended size: 2.70 m across the wheels' outer faces, 3.35 m from the power unit's fins to the turret, 2.10 m from the wheels' contact plane to the top of the mast head; a 2.05 m wheelbase on 0.51 m wheels. The regolith patch is 4.86 × 3.71 m. The origin is under the patch, so it lands on its base.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles45600–4660046096
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2189
Materialsexactly 9 distinct; ≥2260 paint, ≥1140 foil, ≥5820 aluminium, ≥8390 anodised, ≥2150 titanium, ≥600 glass, ≥870 harness, ≥2260 regolith, ≥550 rock faces9 slots; 2512 / 1276 / 6476 / 9330 / 2392 / 672 / 970 / 2516 / 620
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(4.857, 3.709, 2.200) m ± 0.01(4.8568, 3.7091, 2.1999), zmin 0
Collider tris≤ 11601120
Exportwritten, size > 0, removed after measuring3563808 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles45600–4660046096
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2189
Materialsexactly 9 distinct; ≥2260 paint, ≥1140 foil, ≥5820 aluminium, ≥8390 anodised, ≥2150 titanium, ≥600 glass, ≥870 harness, ≥2260 regolith, ≥550 rock faces9 slots; 2512 / 1276 / 6476 / 9330 / 2392 / 672 / 970 / 2516 / 620
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(4.857, 3.709, 2.200) m ± 0.01(4.8568, 3.7091, 2.1999), zmin 0
Collider tris≤ 1160742
Exportwritten, size > 0, removed after measuring3541092 / 3541092 / 3541084 bytes (4.5.11 / 5.1.2 / 5.2.1)

Every falsifier leaves the triangle count at 46096: they move parts, never add or remove them. DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The low mesh is baked against a high copy whose edges over 35° are bevelled in three segments. The rocks' shapes come from a seeded random.Random; everything else is closed-form, and two default runs print identical measurements (and an identical export size).

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/pond-edge/index.html b/docs/gallery/pond-edge/index.html index 57870747..25f3dafd 100644 --- a/docs/gallery/pond-edge/index.html +++ b/docs/gallery/pond-edge/index.html @@ -71,7 +71,7 @@

Pond Edge

Intended size: a disc 3.20 × 2.63 m with its bank 0.17–0.25 m high, the tallest cattail spike 1.51 m off the floor. The outer AABB is 3.204 × 2.634 × 1.507 m, read off the vertices. The soil sets X and Y, a cattail spike the top; the soil's underside is the ground. The collider is the convex hull of the soil disc alone, coarse: the water is a trigger volume, and players walk through reeds.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles36900–3830037602
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥5240 water, ≥5050 soil, ≥7340 reed, ≥1260 seed head, ≥1250 pad, ≥1290 flower, ≥1840 stone, ≥210 wood, ≥360 litter faces9 slots; 5824 / 5614 / 8162 / 1400 / 1390 / 1440 / 2046 / 234 / 400
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(3.2040, 2.6342, 1.5071) m ± 0.01(3.2040, 2.6342, 1.5071), zmin 0
Collider tris (soil hull)≤ 12096
Exportwritten, size > 0, removed after measuring3140704 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles36900–3830037602
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥5240 water, ≥5050 soil, ≥7340 reed, ≥1260 seed head, ≥1250 pad, ≥1290 flower, ≥1840 stone, ≥210 wood, ≥360 litter faces9 slots; 5824 / 5614 / 8162 / 1400 / 1390 / 1440 / 2046 / 234 / 400
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(3.2040, 2.6342, 1.5071) m ± 0.01(3.2040, 2.6342, 1.5071), zmin 0
Collider tris (soil hull)≤ 12096
Exportwritten, size > 0, removed after measuring3140712 / 3140712 / 3140704 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the triangle count or the envelope: every falsifier run measured 37602 tris and the default's outer AABB to the tenth of a millimetre.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. The plan is seeded and nothing else is random; the geometry is pure Python math. Two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/quad-drone/index.html b/docs/gallery/quad-drone/index.html index 85d9fdbb..b57a3f14 100644 --- a/docs/gallery/quad-drone/index.html +++ b/docs/gallery/quad-drone/index.html @@ -53,7 +53,7 @@

Quad Drone

A white-and-graphite camera drone seen from above on a dark studio floor: four carbon arms with red lock rings, two-blade props on slotted motors, skids, and a gimbal camera under the nose.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 41048 tris, eight materials with 1720 shell, 2304 carbon, 6472 gunmetal, 524 glass, 760 light, 1296 rubber, 8464 graphite and 2184 anodised faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.692×0.569×0.243 m, zmin 0 and all 4 feet grounded, hygiene 0 including zero coplanar cross-shell pairs, the 4 motor axes on an exact X about the body centre (gaps 90.000°, diagonals 0.52000 m, axes vertical, hubs level), every neighbouring prop disc cleared by 0.0365 m (band 0.028–0.050), mass centre 0.115 m inside the feet's footprint (floor 0.090), wheelbase 0.520 m, one connected assembly of 171 shells, LOD ratios in band, collider 499 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --unlock-arm 17; --long-blades 18; --narrow-skids 19; --drop-lens 20.
+
witnesses Recomputed: 41048 tris, eight materials with 1720 shell, 2304 carbon, 6472 gunmetal, 524 glass, 760 light, 1296 rubber, 8464 graphite and 2184 anodised faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.692×0.569×0.243 m, zmin 0 and all 4 feet grounded, hygiene 0 including zero coplanar cross-shell pairs, the 4 motor axes on an exact X about the body centre (gaps 90.000°, diagonals 0.52000 m, axes vertical, hubs level), every neighbouring prop disc cleared by 0.0365 m (band 0.028–0.050), mass centre 0.115 m inside the feet's footprint (floor 0.090), wheelbase 0.520 m, one connected assembly of 171 shells, LOD ratios in band, collider 374 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --unlock-arm 17; --long-blades 18; --narrow-skids 19; --drop-lens 20.

category Vehicles

tags mesh export showcase

@@ -73,7 +73,7 @@

Quad Drone

Intended size: a 0.52 m motor-to-motor diagonal, 0.33 m propellers, and a body shell 0.255 m long and 0.136 m wide. The outer AABB is 0.692 × 0.569 × 0.243 m. The props, as parked, set X and Y; the battery and spinners set the top. The origin is under the body centre, so the drone lands on its feet.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles40000–4200041048
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥1580 shell, ≥2120 carbon, ≥5950 gunmetal, ≥480 glass, ≥700 light, ≥1190 rubber, ≥7800 graphite, ≥2000 anodised faces8 slots; 1720 / 2304 / 6472 / 524 / 760 / 1296 / 8464 / 2184
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.692, 0.569, 0.243) m ± 0.01(0.6924, 0.5693, 0.2433), zmin 0
Collider tris≤ 540499
Exportwritten, size > 0, removed after measuring3128864 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles40000–4200041048
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥1580 shell, ≥2120 carbon, ≥5950 gunmetal, ≥480 glass, ≥700 light, ≥1190 rubber, ≥7800 graphite, ≥2000 anodised faces8 slots; 1720 / 2304 / 6472 / 524 / 760 / 1296 / 8464 / 2184
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.692, 0.569, 0.243) m ± 0.01(0.6924, 0.5693, 0.2433), zmin 0
Collider tris≤ 540374
Exportwritten, size > 0, removed after measuring3121080 / 3121080 / 3121072 bytes (4.5.11 / 5.1.2 / 5.2.1)

Every falsifier leaves the triangle count at 41048: they move, scale or narrow parts, never add or remove them.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/road-bicycle/index.html b/docs/gallery/road-bicycle/index.html index 5fd2f93b..2a1d268c 100644 --- a/docs/gallery/road-bicycle/index.html +++ b/docs/gallery/road-bicycle/index.html @@ -53,7 +53,7 @@

Road Bicycle

A deep red lugged-steel road bicycle leaning on its kickstand: chromed lugs and fork socks, tan-wall 700c wheels, a honey leather saddle, cream-taped drop bars and a chain over a double crankset.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 46092 tris, ten materials with 1048 paint, 6438 chrome, 6950 alloy, 8239 steel, 540 tread, 952 gum, 356 leather, 1080 tape, 1810 black and 176 bottle faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.670×0.438×0.997 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs across 112 chain links, both tyres and the stand foot on the ground, both hubs 0.000000 m off their dropout eyes (cap 0.0005), every one of 72 spokes 3.00 mm deep in its flange (band 2.0–4.0 mm) and 4.50 mm inside its nipple on its axis, both rims 0.000 mm off the frame's plane (cap 1.0 mm), seat tube 0.5800 m, wheelbase 0.99982 m, trail 0.05536 m (band 0.045–0.065), lacing 36/36 with 18 per flange, pitch 0.000° off and every spoke three-cross (60.000°), 30 rollers seated on the ring and 10 on the cog 1.20–3.40 mm above the root (band 0.5–6.5 mm), every roller and the cog 0.000 mm off the chain line (cap 1.0 mm), the mass centre 0.0393 m inside the support triangle (floor 0.020) at 11.80 kg, one connected assembly of 685 shells, LOD ratios in band, collider 880 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --slip-wheel 17; --short-spoke 18; --dish-wheel 19; --steep-head 20; --bunch-spokes 21; --lift-chain 22; --shift-rollers 23; --tuck-stand 24; --pop-bottle 25.
+
witnesses Recomputed: 46092 tris, ten materials with 1048 paint, 6438 chrome, 6950 alloy, 8239 steel, 540 tread, 952 gum, 356 leather, 1080 tape, 1810 black and 176 bottle faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.670×0.438×0.997 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs across 112 chain links, both tyres and the stand foot on the ground, both hubs 0.000000 m off their dropout eyes (cap 0.0005), every one of 72 spokes 3.00 mm deep in its flange (band 2.0–4.0 mm) and 4.50 mm inside its nipple on its axis, both rims 0.000 mm off the frame's plane (cap 1.0 mm), seat tube 0.5800 m, wheelbase 0.99982 m, trail 0.05536 m (band 0.045–0.065), lacing 36/36 with 18 per flange, pitch 0.000° off and every spoke three-cross (60.000°), 30 rollers seated on the ring and 10 on the cog 1.20–3.40 mm above the root (band 0.5–6.5 mm), every roller and the cog 0.000 mm off the chain line (cap 1.0 mm), the mass centre 0.0393 m inside the support triangle (floor 0.020) at 11.80 kg, one connected assembly of 685 shells, LOD ratios in band, collider 574 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --slip-wheel 17; --short-spoke 18; --dish-wheel 19; --steep-head 20; --bunch-spokes 21; --lift-chain 22; --shift-rollers 23; --tuck-stand 24; --pop-bottle 25.

category Vehicles

tags mesh export showcase

@@ -70,7 +70,7 @@

Road Bicycle

Intended size: 1.67 m from tyre to tyre, a 1.000 m wheelbase, 0.44 m across the bars and pedals, 1.00 m to the saddle's top. The seat tube is 0.580 m from the bottom-bracket centre to its top. The origin is under the bike, so it lands on its tyres and stand.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles45600–4660046092
LOD1 ratio0.32–0.62 of base0.4995
LOD2 ratio0.10–0.35 of base0.2198
Materialsexactly 10 distinct; ≥940 paint, ≥5650 chrome, ≥6250 alloy, ≥7410 steel, ≥480 tread rubber, ≥850 gum, ≥320 leather, ≥970 tape, ≥1620 black, ≥158 bottle faces10 slots; 1048 / 6438 / 6950 / 8239 / 540 / 952 / 356 / 1080 / 1810 / 176
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.670, 0.438, 0.997) m ± 0.01(1.6698, 0.4376, 0.9969), zmin 0
Collider tris≤ 970880
Exportwritten, size > 0, removed after measuring3598060 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles45600–4660046092
LOD1 ratio0.32–0.62 of base0.4995
LOD2 ratio0.10–0.35 of base0.2198
Materialsexactly 10 distinct; ≥940 paint, ≥5650 chrome, ≥6250 alloy, ≥7410 steel, ≥480 tread rubber, ≥850 gum, ≥320 leather, ≥970 tape, ≥1620 black, ≥158 bottle faces10 slots; 1048 / 6438 / 6950 / 8239 / 540 / 952 / 356 / 1080 / 1810 / 176
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.670, 0.438, 0.997) m ± 0.01(1.6698, 0.4376, 0.9969), zmin 0
Collider tris≤ 970574
Exportwritten, size > 0, removed after measuring3579436 / 3579436 / 3579428 bytes (4.5.11 / 5.1.2 / 5.2.1)

Every falsifier leaves the triangle count at 46092: they move parts, never add or remove them. --lift-chain keeps the default chain's link count and lets the derailleur cage take up the longer loop. DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/shipping-crate/index.html b/docs/gallery/shipping-crate/index.html index 874b8519..2c29d653 100644 --- a/docs/gallery/shipping-crate/index.html +++ b/docs/gallery/shipping-crate/index.html @@ -53,7 +53,7 @@

Shipping Crate

A grained wooden shipping crate in three-quarter view, PORT ROYAL and NO 17 stencilled along its side slats, with nailed iron corner straps and a bail handle on one end.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 3388 tris, two materials with 1170 wood and 904 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.146×0.726×0.612 m, grounded zmin, 3 skids, handle-end and slat-post join 0, mesh hygiene all zero, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 116 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-skids 16; --float-handle 17; --omit-slats 18.
+
witnesses Recomputed: 3388 tris, two materials with 1170 wood and 904 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.146×0.726×0.612 m, grounded zmin, 3 skids, handle-end and slat-post join 0, mesh hygiene all zero, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 100 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-skids 16; --float-handle 17; --omit-slats 18.

category Village

tags mesh export showcase

@@ -68,7 +68,7 @@

Shipping Crate

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2900–39003388 / 3388 / 3388
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 2 distinct; ≥900 wood, ≥600 metal faces2 slots; 1170 / 904
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.146, 0.726, 0.612) m ± 0.015(1.1460, 0.7260, 0.6120), zmin 0
Collider tris≤ 220116
Exportwritten, size > 0274624 (4.5.11) / 274680 (5.2.1) bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2900–39003388 / 3388 / 3388
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 2 distinct; ≥900 wood, ≥600 metal faces2 slots; 1170 / 904
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.146, 0.726, 0.612) m ± 0.015(1.1460, 0.7260, 0.6120), zmin 0
Collider tris≤ 220100
Exportwritten, size > 0273124 / 273196 / 273188 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 624 to 2508 in the quality pass: the old beveled cube with glued-on slats became a post-and-slat crate with tenons, sills, L-straps, and pipe handles. The second pass took them to 3388: single-shell chamfered straps, 24 nails, chamfered mounting plates.

DECIMATE COLLAPSE triangle counts are not guaranteed identical across series; on this mesh they happen to match (LOD2 744 on all three). The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Slat-width jitter uses fixed seed 17. Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

diff --git a/docs/gallery/signpost/index.html b/docs/gallery/signpost/index.html index 3437e7ec..7b7f093c 100644 --- a/docs/gallery/signpost/index.html +++ b/docs/gallery/signpost/index.html @@ -53,7 +53,7 @@

Signpost

A wooden crossroads signpost with three pointed cream finger boards painted MILLBROOK 2, OAKHAM 5 and FORD 1, rusted iron collars and bands on the post.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 432 tris, three materials with 126 metal, 33 board and 60 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.260×0.142×1.551 m at zmin 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD1/LOD2), convex collider 56 tris, non-empty glTF. Hygiene all zero. Board-to-post gap 5 mm, strap gap 3 mm, board AABB Y 28 mm. --skip-decimate exits 9; --stray-vert 15; --lift-z / --short-shoe 16; --gap-board 17; --float-strap 18; --yaw-boards 19.
+
witnesses Recomputed: 432 tris, three materials with 126 metal, 33 board and 60 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.260×0.142×1.551 m at zmin 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD1/LOD2), convex collider 44 tris, non-empty glTF. Hygiene all zero. Board-to-post gap 5 mm, strap gap 3 mm, board AABB Y 28 mm. --skip-decimate exits 9; --stray-vert 15; --lift-z / --short-shoe 16; --gap-board 17; --float-strap 18; --yaw-boards 19.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Signpost

Intended size: 1.48 m post, boards 0.62 m, 0.54 m and 0.46 m, 0.118 m post stock; outer AABB 1.260 × 0.142 × 1.551 m.

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles320–480432 / 432
LOD1 ratio0.32–0.62 of base0.5000 / 0.4537
LOD2 ratio0.10–0.35 of base0.2176 / 0.1620
Materialsexactly 3 distinct, ≥24 metal, ≥12 board, ≥12 wood3 slots, 126 metal, 33 board, 60 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.260, 0.142, 1.551) m ± 0.015(1.2600, 0.1420, 1.5510), zmin 0
Collider tris≤ 18056
Exportwritten, size > 041168 / 41232 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles320–480432 / 432
LOD1 ratio0.32–0.62 of base0.5000 / 0.4537
LOD2 ratio0.10–0.35 of base0.2176 / 0.1620
Materialsexactly 3 distinct, ≥24 metal, ≥12 board, ≥12 wood3 slots, 126 metal, 33 board, 60 wood
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.260, 0.142, 1.551) m ± 0.015(1.2600, 0.1420, 1.5510), zmin 0
Collider tris≤ 18044
Exportwritten, size > 038668 / 38740 / 38740 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles dropped from 504 to 376 in the quality pass: glued diamond cubes and a solid shoe block became wedges and a four-plate collar. Outer AABB tightened from 1.368 × 0.201 × 1.566 m.

DECIMATE COLLAPSE triangle counts are not identical across series — 5.2.1 is leaner on LOD1 and LOD2. The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction is closed-form; the only RNG is the seeded per-piece wood tone. Bevel inputs are sorted by edge index, so the face order is the same on every run. Export byte counts differ on 5.2.1 (glTF serializer), not a gated axis.

Surface and stage#

diff --git a/docs/gallery/skate-ramp/index.html b/docs/gallery/skate-ramp/index.html index 89fe9af2..40e609a0 100644 --- a/docs/gallery/skate-ramp/index.html +++ b/docs/gallery/skate-ramp/index.html @@ -53,7 +53,7 @@

Skate Ramp

A plywood quarter-pipe with a steel coping and kicker plate, screw rows, sheet seams and a red stencilled roundel, its open side showing studs and sills, a skateboard on the deck.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 31164 tris, nine materials with 3268 plywood, 1479 framing, 1086 steel, 7304 hardware, 1100 maple, 900 grip, 1536 urethane, 892 alloy and 464 bushing faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.529×2.440×1.339 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all five sills, the toe block and the plate on the floor, the riding face a circle of radius 1.80000 m (98 samples, 0.000 mm deviation, cap 1.0 mm) tangent to the ground, deck at 1.20000 m, five templates each 2.00 mm into its sill (band 1–6 mm) and 0.90–0.91 mm into the skin (band 0.3–2.5 mm), the coping straight and square to the width with a 5.00 mm reveal (band 2–8 mm) and 3.86 mm above the deck, the kicker plate 0.01 mm off flush (cap 0.6 mm) with a 0.80 mm toe, top seams at 0.84 and 1.84 m and the inner at 1.24 m (stagger 0.400 m, floor 0.30) each 43.9 mm inside its stringer, 143 screws 17.4 mm inside a stringer and 17.0 mm inside a sheet, four wheels 0.50 mm into the deck (band 0.2–1.2 mm), every wheel 0.000 mm off its axle, one connected assembly of 309 shells, LOD ratios in band, collider 350 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sill 16; --short-rib 17; --small-wheel 18; --sag-skin 19; --sink-coping 20; --proud-plate 21; --stack-seams 22; --miss-screws 23; --skew-wheel 24; --lift-grip 25.
+
witnesses Recomputed: 31164 tris, nine materials with 3268 plywood, 1479 framing, 1086 steel, 7304 hardware, 1100 maple, 900 grip, 1536 urethane, 892 alloy and 464 bushing faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.529×2.440×1.339 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all five sills, the toe block and the plate on the floor, the riding face a circle of radius 1.80000 m (98 samples, 0.000 mm deviation, cap 1.0 mm) tangent to the ground, deck at 1.20000 m, five templates each 2.00 mm into its sill (band 1–6 mm) and 0.90–0.91 mm into the skin (band 0.3–2.5 mm), the coping straight and square to the width with a 5.00 mm reveal (band 2–8 mm) and 3.86 mm above the deck, the kicker plate 0.01 mm off flush (cap 0.6 mm) with a 0.80 mm toe, top seams at 0.84 and 1.84 m and the inner at 1.24 m (stagger 0.400 m, floor 0.30) each 43.9 mm inside its stringer, 143 screws 17.4 mm inside a stringer and 17.0 mm inside a sheet, four wheels 0.50 mm into the deck (band 0.2–1.2 mm), every wheel 0.000 mm off its axle, one connected assembly of 309 shells, LOD ratios in band, collider 306 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sill 16; --short-rib 17; --small-wheel 18; --sag-skin 19; --sink-coping 20; --proud-plate 21; --stack-seams 22; --miss-screws 23; --skew-wheel 24; --lift-grip 25.

category Sports

tags mesh export showcase

@@ -70,7 +70,7 @@

Skate Ramp

Intended size: 2.53 m from the kicker plate's toe to the back of the deck, 2.44 m across, 1.34 m to the top of the skateboard's kicktail (the deck is at 1.20 m). The origin is under the transition's toe at floor level.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles30600–3170031164
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥3100 plywood, ≥1400 framing, ≥1030 steel, ≥6940 hardware, ≥1045 maple, ≥855 grip, ≥1460 urethane, ≥850 alloy, ≥440 bushing faces9 slots; 3268 / 1479 / 1086 / 7304 / 1100 / 900 / 1536 / 892 / 464
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.529, 2.440, 1.339) m ± 0.01, read off the vertices(2.5293, 2.4400, 1.3389), zmin 0
Collider tris≤ 380350
Exportwritten, size > 0, removed after measuring2376604 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles30600–3170031164
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; ≥3100 plywood, ≥1400 framing, ≥1030 steel, ≥6940 hardware, ≥1045 maple, ≥855 grip, ≥1460 urethane, ≥850 alloy, ≥440 bushing faces9 slots; 3268 / 1479 / 1086 / 7304 / 1100 / 900 / 1536 / 892 / 464
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.529, 2.440, 1.339) m ± 0.01, read off the vertices(2.5293, 2.4400, 1.3389), zmin 0
Collider tris≤ 380306
Exportwritten, size > 0, removed after measuring2373684 / 2373684 / 2373676 bytes (4.5.11 / 5.1.2 / 5.2.1)

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/soccer-goal/index.html b/docs/gallery/soccer-goal/index.html index fb2719b6..e3ef29f1 100644 --- a/docs/gallery/soccer-goal/index.html +++ b/docs/gallery/soccer-goal/index.html @@ -53,7 +53,7 @@

Soccer Goal

A white youth soccer goal on a turf patch with a painted goal line, seen at three-quarter: mitred posts and crossbar, sloped rear supports and a sagging diamond-mesh net edged in red rope.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 34804 tris, ten materials with 2514 paint, 9028 cord, 160 rope, 340 steel, 1464 cast, 3604 nylon, 1000 galvanised, 196 turf, 16 line-paint and 102 soil faces, UVs in 0..1 with zero AABB overlap, outer AABB 6.220×2.640×2.153 m, zmin 0 and all 3 ground bars bedded 2.5 mm into the turf, hygiene 0 including zero coplanar cross-shell pairs, both sloped supports 65 mm into their bracket sockets and 80 mm into their hubs, the head rope through all 53 clip loops (axis offset 0.000 m, ceiling 0.0012), a clear mouth of 5.0002 × 2.0001 m with the posts plumb and the crossbar level, the back panel sagging 0.148 m below its chord (band 0.110–0.180), LOD ratios in band, collider 168 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-bar 16; --short-support 17; --unclip-net 18; --wide-mouth 19; --taut-net 20.
+
witnesses Recomputed: 34804 tris, ten materials with 2514 paint, 9028 cord, 160 rope, 340 steel, 1464 cast, 3604 nylon, 1000 galvanised, 196 turf, 16 line-paint and 102 soil faces, UVs in 0..1 with zero AABB overlap, outer AABB 6.220×2.640×2.153 m, zmin 0 and all 3 ground bars bedded 2.5 mm into the turf, hygiene 0 including zero coplanar cross-shell pairs, both sloped supports 65 mm into their bracket sockets and 80 mm into their hubs, the head rope through all 53 clip loops (axis offset 0.000 m, ceiling 0.0012), a clear mouth of 5.0002 × 2.0001 m with the posts plumb and the crossbar level, the back panel sagging 0.148 m below its chord (band 0.110–0.180), LOD ratios in band, collider 126 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-bar 16; --short-support 17; --unclip-net 18; --wide-mouth 19; --taut-net 20.

category Sports

tags mesh export showcase

@@ -73,7 +73,7 @@

Soccer Goal

Intended size: a 5.000 × 2.000 m clear mouth, 1.5 m deep at the ground, on a turf patch 6.22 × 2.64 m. The outer AABB is 6.220 × 2.640 × 2.153 m. The turf sets X and Y; the weld beads on the crossbar's outer corners set the top. The origin is under the goal line's centre, so the turf's underside is the ground.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles34000–3560034804
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 10 distinct; ≥2300 paint, ≥8300 cord, ≥150 rope, ≥310 steel, ≥1350 cast, ≥3300 nylon, ≥920 galvanised, ≥180 turf, ≥16 line paint, ≥95 soil faces10 slots; 2514 / 9028 / 160 / 340 / 1464 / 3604 / 1000 / 196 / 16 / 102
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(6.220, 2.640, 2.153) m ± 0.01(6.2200, 2.6400, 2.1527), zmin 0
Collider tris≤ 190168
Exportwritten, size > 0, removed after measuring2525996 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles34000–3560034804
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 10 distinct; ≥2300 paint, ≥8300 cord, ≥150 rope, ≥310 steel, ≥1350 cast, ≥3300 nylon, ≥920 galvanised, ≥180 turf, ≥16 line paint, ≥95 soil faces10 slots; 2514 / 9028 / 160 / 340 / 1464 / 3604 / 1000 / 196 / 16 / 102
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(6.220, 2.640, 2.153) m ± 0.01(6.2200, 2.6400, 2.1527), zmin 0
Collider tris≤ 190126
Exportwritten, size > 0, removed after measuring2523792 / 2523792 / 2523784 bytes (4.5.11 / 5.1.2 / 5.2.1)

Every falsifier but one leaves the triangle count at 34804: they move or shorten parts, never add or remove them. --wide-mouth measures 34816, because a 30 mm wider back panel holds one more strand.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/stand-mixer/index.html b/docs/gallery/stand-mixer/index.html index 95d850a7..9e5d1511 100644 --- a/docs/gallery/stand-mixer/index.html +++ b/docs/gallery/stand-mixer/index.html @@ -53,7 +53,7 @@

Stand Mixer

A slate-blue retro stand mixer with a chrome band and a brushed steel bowl on a stone countertop, beside a wire whisk, a steel measuring cup and two brown eggs in a terracotta dish.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 29620 tris, eight materials with 4328 enamel, 2626 chrome, 5560 stainless, 91 stone, 1174 rubber, 812 ceramic, 760 egg and 562 beater faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.470×0.570×0.389 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four feet sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the hinge pin 0.000000 m off the axis of both neck knuckles and the head knuckle (cap 0.0003) and spanning all three, the bowl seated 0.00050 m into its plate (band 0.0002–0.0010) and 0.000000 m off its axis (cap 0.0003) with all three lugs engaged, the mixer 0.35899 m tall (0.360 ± 0.006) and the bowl holding 4.5465 L to the brim (4.5 ± 0.35), the beater shaft 0.000000 m off the planetary socket's axis (cap 0.0003) and clearing the bowl's wall by 0.00245 m and its floor by 0.00250 m (band 0.0012–0.0040), the mass centre 0.0658 m inside the feet's support polygon (floor 0.040) at 13.94 kg, one connected assembly of 52 shells, LOD ratios in band, collider 2329 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --offset-bowl 18; --shallow-bowl 19; --offset-beater 20; --long-beater 21; --bunch-feet 22; --loose-cap 23.
+
witnesses Recomputed: 29620 tris, eight materials with 4328 enamel, 2626 chrome, 5560 stainless, 91 stone, 1174 rubber, 812 ceramic, 760 egg and 562 beater faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.470×0.570×0.389 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four feet sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the hinge pin 0.000000 m off the axis of both neck knuckles and the head knuckle (cap 0.0003) and spanning all three, the bowl seated 0.00050 m into its plate (band 0.0002–0.0010) and 0.000000 m off its axis (cap 0.0003) with all three lugs engaged, the mixer 0.35899 m tall (0.360 ± 0.006) and the bowl holding 4.5465 L to the brim (4.5 ± 0.35), the beater shaft 0.000000 m off the planetary socket's axis (cap 0.0003) and clearing the bowl's wall by 0.00245 m and its floor by 0.00250 m (band 0.0012–0.0040), the mass centre 0.0658 m inside the feet's support polygon (floor 0.040) at 13.94 kg, one connected assembly of 52 shells, LOD ratios in band, collider 1308 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --offset-bowl 18; --shallow-bowl 19; --offset-beater 20; --long-beater 21; --bunch-feet 22; --loose-cap 23.

category Household

tags mesh export showcase

@@ -74,7 +74,7 @@

Stand Mixer

Intended size: a mixer 0.36 m tall on a 0.03 m counter, a 0.296 × 0.196 m base foot, a 0.34 m head, and a 4.5 L bowl. The outer AABB is 0.470 × 0.570 × 0.389 m. The counter sets the plan and the head's crown sets the top. The origin is under the counter.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles29000–3030029620
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥3980 enamel, ≥2410 chrome, ≥5110 stainless, ≥84 stone, ≥1080 rubber, ≥745 ceramic, ≥700 egg, ≥515 beater faces8 slots; 4328 / 2626 / 5560 / 91 / 1174 / 812 / 760 / 562
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.470, 0.570, 0.389) m ± 0.01(0.4700, 0.5700, 0.3890), zmin 0
Collider tris≤ 24502329
Exportwritten, size > 0, removed after measuring2337532 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles29000–3030029620
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 8 distinct; ≥3980 enamel, ≥2410 chrome, ≥5110 stainless, ≥84 stone, ≥1080 rubber, ≥745 ceramic, ≥700 egg, ≥515 beater faces8 slots; 4328 / 2626 / 5560 / 91 / 1174 / 812 / 760 / 562
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.470, 0.570, 0.389) m ± 0.01(0.4700, 0.5700, 0.3890), zmin 0
Collider tris≤ 24501308
Exportwritten, size > 0, removed after measuring2283036 / 2283036 / 2283032 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the topology, so every one of them measures the default's 29620 triangles and the default's AABB. --shallow-bowl keeps the bowl's four wall stations, spread up to the lower rim, and the beater follows the full-height wall's r(z), which is the same function.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/stone-archway/index.html b/docs/gallery/stone-archway/index.html index 5a016db0..a4d3d415 100644 --- a/docs/gallery/stone-archway/index.html +++ b/docs/gallery/stone-archway/index.html @@ -72,7 +72,7 @@

Measuring it took two correctionsThe first attempt selected intrados vertices by radius. That swept in the chamfer vertices sitting one bevel-width out on each radial face and reported a 5.1 mm error on a true arch. The fit now runs over the vertices of faces that actually face the springing centre — normal inward in XZ and with a small Y component, which is what excludes the chamfer strips running along the intrados edges.

Budgets#

Declared in the script as named constants, recomputed from the generated mesh. Measured values are from Blender 5.2.1; the cross-version table is at the end.

-
BudgetBandMeasured
Base triangles950–14501140
LOD1 ratio0.32–0.620.5000
LOD2 ratio0.10–0.350.2140 (5.2) / 0.2193 (4.5, 5.1)
Material slotsexactly 3, distinct3
Dressed faces (keystone, imposts, plinth and head courses)≥ 100182
Ashlar faces≥ 280364
Mortar faces≥ 100108
UV boundsinside 0..1(0.0015, 0.0015)–(0.9985, 0.9985)
UV AABB overlap≤ 1e-50.000000
Outer AABB1.644 × 0.510 × 2.057 m ± 0.0201.6440 × 0.5100 × 2.0568
Clear opening1.200 m ± 0.015, measured between the pier faces1.2033
Collider triangles≤ 260168
Normal bake{'FINISHED'} with image data{'FINISHED'}, has_data=True
glTF exportfile written, non-empty~100 kB
Hygieneall zeroloose 0/0, non-manifold 0, zero-area 0, doubles 0, n-gons 0, coplanar disjoint pairs 0
Grounded AABB\zmin\≤ 1e-40.00000
Pier supports2 piers, each base course zmin ≤ 1e-32 at 0.00000
Keystone proud of the wall face≥ 0.020 m0.03500
Springing jointoverlap, surface gap ≤ 1e-40.00000
Mortar jointsevery adjacent pair in 0.006–0.017 mall eight at 0.00970
Intrados circle fitevery vertex within 0.004 m of R = 0.600.00097
Intrados arc span≥ 168°178.0°
Mortar contact18 joints, each overlapping exactly 2 stones18, all 2
+
BudgetBandMeasured
Base triangles950–14501140
LOD1 ratio0.32–0.620.5000
LOD2 ratio0.10–0.350.2140 (5.2) / 0.2193 (4.5, 5.1)
Material slotsexactly 3, distinct3
Dressed faces (keystone, imposts, plinth and head courses)≥ 100182
Ashlar faces≥ 280364
Mortar faces≥ 100108
UV boundsinside 0..1(0.0015, 0.0015)–(0.9985, 0.9985)
UV AABB overlap≤ 1e-50.000000
Outer AABB1.644 × 0.510 × 2.057 m ± 0.0201.6440 × 0.5100 × 2.0568
Clear opening1.200 m ± 0.015, measured between the pier faces1.2033
Collider triangles≤ 260132
Normal bake{'FINISHED'} with image data{'FINISHED'}, has_data=True
glTF exportfile written, non-empty~100 kB
Hygieneall zeroloose 0/0, non-manifold 0, zero-area 0, doubles 0, n-gons 0, coplanar disjoint pairs 0
Grounded AABB\zmin\≤ 1e-40.00000
Pier supports2 piers, each base course zmin ≤ 1e-32 at 0.00000
Keystone proud of the wall face≥ 0.020 m0.03500
Springing jointoverlap, surface gap ≤ 1e-40.00000
Mortar jointsevery adjacent pair in 0.006–0.017 mall eight at 0.00970
Intrados circle fitevery vertex within 0.004 m of R = 0.600.00097
Intrados arc span≥ 168°178.0°
Mortar contact18 joints, each overlapping exactly 2 stones18, all 2

Real-world size: a 1.20 m clear opening under a semicircular head, 1.64 m across the piers and 2.06 m to the top of the keystone — a garden gate arch.

Mortar#

Every joint used to be air. The pier courses stood 7 mm apart and the voussoirs 9.7 mm apart, none of them touching: each pier was a stack of floating blocks, with daylight through every joint in the ground-contact and joint close-ups. The mortar-band budget measured the gaps and passed, because the gaps were the right width. Nothing asked what was in them.

@@ -106,7 +106,7 @@

Run itCross-version measurements#

-
Value4.5.115.1.25.2.1
Base triangles114011401140
LOD1 tris / ratio570 / 0.5000570 / 0.5000570 / 0.5000
LOD2 tris / ratio250 / 0.2193250 / 0.2193244 / 0.2140
Face counts (ashlar / dressed / mortar)364 / 182 / 108samesame
Outer AABB1.6440 × 0.5100 × 2.0568samesame
Collider tris168168168
Intrados deviation0.000970.000970.00097
Mortar jointsall 0.00970all 0.00970all 0.00970
Mortar contact18 × 2 stonessamesame
Check wall-clock~1.11 s~1.18 s~1.37 s
+
Value4.5.115.1.25.2.1
Base triangles114011401140
LOD1 tris / ratio570 / 0.5000570 / 0.5000570 / 0.5000
LOD2 tris / ratio250 / 0.2193250 / 0.2193244 / 0.2140
Face counts (ashlar / dressed / mortar)364 / 182 / 108samesame
Outer AABB1.6440 × 0.5100 × 2.0568samesame
Collider tris132132132
Intrados deviation0.000970.000970.00097
Mortar jointsall 0.00970all 0.00970all 0.00970
Mortar contact18 × 2 stonessamesame
Check wall-clock~1.11 s~1.18 s~1.37 s

Source

diff --git a/docs/gallery/stone-well/index.html b/docs/gallery/stone-well/index.html index b3f12f49..603a4c7d 100644 --- a/docs/gallery/stone-well/index.html +++ b/docs/gallery/stone-well/index.html @@ -53,7 +53,7 @@

Stone Well

A round well of grey stones, each a slightly different shade, under a four-post grained wooden roof, with a bucket on rusted iron hoops hanging inside.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 9380 tris, three materials with face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.312×1.312×1.761 m, LOD ratios in band, convex collider 346 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, all 12 bottom-course stones on the floor, each post tenoned 18 mm into the measured coping and standing under a roof hip corner, the bucket hanging 0.10 m clear of the coping, grounded zmin, non-empty glTF. --stand-posts exits 15 on the z-fight budget; --float-stone exits 16 on the named-support budget; --shallow-tenon and --drop-bucket exit 18; --turn-posts exits 19 on post placement; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.
+
witnesses Recomputed: 9380 tris, three materials with face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.312×1.312×1.761 m, LOD ratios in band, convex collider 258 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, all 12 bottom-course stones on the floor, each post tenoned 18 mm into the measured coping and standing under a roof hip corner, the bucket hanging 0.10 m clear of the coping, grounded zmin, non-empty glTF. --stand-posts exits 15 on the z-fight budget; --float-stone exits 16 on the named-support budget; --shallow-tenon and --drop-bucket exit 18; --turn-posts exits 19 on post placement; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.

category Village

tags mesh export showcase

@@ -67,7 +67,7 @@

Stone Well

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles8280–95009380 / 9380 / 9380
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2198 / 0.2198 / 0.2198
Materialsexactly 3 distinct3
Material facesstone ≥ 3000, wood ≥ 600, metal ≥ 100all above
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.312, 1.312, 1.761) m ± 0.01(1.3120, 1.3120, 1.7606)
Groundedbbox min Z within 1e-4 of 00.0000 / 0.0000 / 0.0000
Named supportsall 12 bottom-course stones on the floor within 1e-412/12, worst 0.000000
Hygieneloose V/E, non-manifold, zero-area, doubles @1e-5, n-gons: all 00 / 0 / 0 on every axis
Z-fightingcoplanar cross-shell face pairs = 00 / 0 / 0
Post tenoneach post seats 0.015–0.022 m into the measured coping top0.01800 / 0.01800 / 0.01800
Post placementeach post within 0.02 rad, in plan, of a roof hip corner recomputed from the mesh0.00000
Bucket clearancehangs 0.085–0.115 m clear of the measured coping top0.10000
Material-island gapstone↔wood and metal↔wood min distance ≤ 0.008 m0.00000 / 0.00000 / 0.00000
Collider tris≤ 380346
Exportwritten, size > 0, removed after measuring690216 bytes on 5.2.1
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles8280–95009380 / 9380 / 9380
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2198 / 0.2198 / 0.2198
Materialsexactly 3 distinct3
Material facesstone ≥ 3000, wood ≥ 600, metal ≥ 100all above
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.312, 1.312, 1.761) m ± 0.01(1.3120, 1.3120, 1.7606)
Groundedbbox min Z within 1e-4 of 00.0000 / 0.0000 / 0.0000
Named supportsall 12 bottom-course stones on the floor within 1e-412/12, worst 0.000000
Hygieneloose V/E, non-manifold, zero-area, doubles @1e-5, n-gons: all 00 / 0 / 0 on every axis
Z-fightingcoplanar cross-shell face pairs = 00 / 0 / 0
Post tenoneach post seats 0.015–0.022 m into the measured coping top0.01800 / 0.01800 / 0.01800
Post placementeach post within 0.02 rad, in plan, of a roof hip corner recomputed from the mesh0.00000
Bucket clearancehangs 0.085–0.115 m clear of the measured coping top0.10000
Material-island gapstone↔wood and metal↔wood min distance ≤ 0.008 m0.00000 / 0.00000 / 0.00000
Collider tris≤ 380258
Exportwritten, size > 0, removed after measuring686472 / 686472 / 686468 bytes (4.5.11 / 5.1.2 / 5.2.1)

DECIMATE COLLAPSE triangle counts are not guaranteed identical across series — the gate is a ratio band, not an exact count. This mesh happened to match on 4.5.11 / 5.1.2 / 5.2.1. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; the per-piece material tone is drawn from a seeded random.Random(TONE_SEED), the same every run. glTF byte size differs by a few hundred bytes across series; the gate is "written and non-empty", not a byte count, and the file is removed once measured.

Falsifiers#

Each flag breaks one stage so a named budget fails and the piece exits that code.

diff --git a/docs/gallery/street-lantern/index.html b/docs/gallery/street-lantern/index.html index 35829b34..44e6cb50 100644 --- a/docs/gallery/street-lantern/index.html +++ b/docs/gallery/street-lantern/index.html @@ -53,7 +53,7 @@

Street Lantern

A cast-iron street lamp: fluted post with brass collars and a ladder bar, a braced arm with wrought scrolls, and a banded brass lantern lit amber from inside.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 4726 tris, three materials with 2162 metal, 24 glass and 341 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, brace ends 13 mm into the post and the arm, 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 108 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19; --shallow-brace 20.
+
witnesses Recomputed: 4726 tris, three materials with 2162 metal, 24 glass and 341 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, brace ends 13 mm into the post and the arm, 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 86 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19; --shallow-brace 20.

category Village

tags mesh export showcase

@@ -72,7 +72,7 @@

Street Lantern

Intended size: 0.30 m square foot, 1.12 m fluted post (0.10 m across the lands at the base), 0.50 m arm, 0.24 × 0.30 m cage; outer AABB 0.300 × 0.786 × 1.287 m.

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles4200–52004726 / 4726
LOD1 ratio0.32–0.62 of base0.4998 / 0.4998
LOD2 ratio0.10–0.35 of base0.2196 / 0.2179
Materialsexactly 3 distinct; ≥200 metal, ≥8 glass, ≥24 brass3 slots; 2162 / 24 / 341
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.300, 0.786, 1.287) m ± 0.01(0.3000, 0.7860, 1.2874), zmin 0
Collider tris≤ 120108
Exportwritten, size > 0, removed after measuring355288 / 355272 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles4200–52004726 / 4726
LOD1 ratio0.32–0.62 of base0.4998 / 0.4998
LOD2 ratio0.10–0.35 of base0.2196 / 0.2179
Materialsexactly 3 distinct; ≥200 metal, ≥8 glass, ≥24 brass3 slots; 2162 / 24 / 341
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.300, 0.786, 1.287) m ± 0.01(0.3000, 0.7860, 1.2874), zmin 0
Collider tris≤ 12086
Exportwritten, size > 0, removed after measuring353488 / 353488 / 353480 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles dropped from 3520 to 3338 in the first quality pass (closed square-pyramid roof, unshared cage crossings, pane rebate), then rose to 4726 when the model gained its column flutes, second collar, ladder bar, arm scrolls, hook ring, eave band, base tray and drip. The band moved from 3000–3800 to 4200–5200, the same ~±10 % slack around the measured count. The 5.1.2 column was dropped with this change: the new model was measured on 4.5.11 and 5.2.1 only.

DECIMATE COLLAPSE triangle counts are not identical across series — 5.2.1 is 8 tris leaner on LOD2. The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG. Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

diff --git a/docs/gallery/tavern-stool/index.html b/docs/gallery/tavern-stool/index.html index e2d088df..629b3353 100644 --- a/docs/gallery/tavern-stool/index.html +++ b/docs/gallery/tavern-stool/index.html @@ -53,7 +53,7 @@

Tavern Stool

A wooden tavern stool with a grained, dished round seat holding a pewter tankard, turned splayed legs, stretcher rungs at two heights, and dark iron ferrules on flat treads.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 3040 tris, two materials with 1168 wood and 576 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.341×0.341×0.470 m, LOD ratios in band, convex collider 468 tris, non-empty glTF. Hygiene all zero, four treads at zmin 0, stretcher-leg gap 0, ferrule grip 1.20 mm on each leg's axis, leg ends 1.1 mm above their treads, bake 22.4 texels per UV cell. --float-stretchers exits 17; --pipe-ferrule 18; --sink-legs 20; --low-bake 21.
+
witnesses Recomputed: 3040 tris, two materials with 1168 wood and 576 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.341×0.341×0.470 m, LOD ratios in band, convex collider 308 tris, non-empty glTF. Hygiene all zero, four treads at zmin 0, stretcher-leg gap 0, ferrule grip 1.20 mm on each leg's axis, leg ends 1.1 mm above their treads, bake 22.4 texels per UV cell. --float-stretchers exits 17; --pipe-ferrule 18; --sink-legs 20; --low-bake 21.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Tavern Stool

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2750–33503040 / 3040 / 3040
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2197
Materialsexactly 2 distinct; ≥200 wood, ≥48 metal faces2 slots; 1168 / 576
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.341, 0.341, 0.470) m ± 0.015(0.3406, 0.3406, 0.4700), zmin 0
Collider tris≤ 640468
Exportwritten, size > 0259676 / 259676 / 259668 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2750–33503040 / 3040 / 3040
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2197
Materialsexactly 2 distinct; ≥200 wood, ≥48 metal faces2 slots; 1168 / 576
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.341, 0.341, 0.470) m ± 0.015(0.3406, 0.3406, 0.4700), zmin 0
Collider tris≤ 640308
Exportwritten, size > 0251188 / 251188 / 251184 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 2528 to 3040 in the second quality pass, and the band moved from 2300–3200 to 2750–3350. Each foot gained a tread, and the sleeves are walled on both ends. The bake went from 256 px to 1024 px, and its cage extrusion from 60 mm to 10 mm. See the bake texel budget below.

DECIMATE COLLAPSE triangle counts are not identical across series. The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction is closed-form and member tones are seeded, so repeated runs on one binary print identical measurements. Export byte counts may differ by a few bytes across series.

Hygiene#

diff --git a/docs/gallery/terrain-scatter/index.html b/docs/gallery/terrain-scatter/index.html index a984c691..a0243804 100644 --- a/docs/gallery/terrain-scatter/index.html +++ b/docs/gallery/terrain-scatter/index.html @@ -70,7 +70,7 @@

Terrain Scatter

Hero. On the render path, grass is blended into the dirt shader where the ground faces up (geometry normal Z), broken by a coarse patch noise so bare soil shows through. The rounded rim and the cut sides tip past the band, so the section still reads as topsoil over subsoil. A render-only dressing, drawn with a fixed seed from the up-facing dirt faces, adds 120 clumped grass tufts and 40 sunk pebbles in the stone material. The dressing is staging, parented to the tile, and is not part of the asset, its budgets or its export. The asset sheet judges TerrainLow alone.

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1400–28002398 / 2398 / 2398
LOD1 ratio0.32–0.62 of base0.4996 / 0.4996 / 0.4996
LOD2 ratio0.10–0.35 of base0.2193 / 0.2193 / 0.2193
Materialsexactly 2 distinct, ≥24 stone faces2 slots, 720 stone
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.800, 1.800, 0.570) m ± 0.015(1.8000, 1.8008, 0.5700), zmin 0
Collider tris≤ 12036
Exportwritten, size > 0199496 / 199496 / 199480 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1400–28002398 / 2398 / 2398
LOD1 ratio0.32–0.62 of base0.4996 / 0.4996 / 0.4996
LOD2 ratio0.10–0.35 of base0.2193 / 0.2193 / 0.2193
Materialsexactly 2 distinct, ≥24 stone faces2 slots, 720 stone
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.800, 1.800, 0.570) m ± 0.015(1.8000, 1.8008, 0.5700), zmin 0
Collider tris≤ 12036
Exportwritten, size > 0198908 / 198908 / 198900 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 1194 to 1758 in the first quality pass: 9-vert hill became a 21-vert grid, and bevelled cubes became subdiv-2 icospheres. Outer Z dropped from 0.655 m (crate corners swinging through the slab) to 0.552 m of seated stone on the hill.

The second pass took them from 1758 to 2398: the four-segment rim bevel adds 640. The outer Z moved from 0.584 m to 0.570 m, because the stones now sink into the ground rather than perch on it, and the declared size was re-fitted to match. The collider fell from 72 to 36 triangles because it now hulls a coarse, unbevelled 9-vertex tile (COLLIDER_GRID): the chamfer and micro-relief are visual, and on the full-resolution tile they pushed the hull to 178, over its ceiling.

DECIMATE COLLAPSE triangle counts are not guaranteed identical across series — the gate is a ratio band, not an exact count. This mesh matched on 4.5.11 / 5.1.2 / 5.2.1. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG: jitter, cleave planes and relaxation are all closed form or fixed iteration. Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.

diff --git a/docs/gallery/traffic-cones/index.html b/docs/gallery/traffic-cones/index.html index 8f83ea23..1c8fcb95 100644 --- a/docs/gallery/traffic-cones/index.html +++ b/docs/gallery/traffic-cones/index.html @@ -53,7 +53,7 @@

Traffic Cones

Scuffed orange cones on a patch of asphalt, three in a row, three stacked and one knocked over showing its open base, before a striped A-frame barricade with an amber lamp.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 45816 tris, eleven materials with 6048 cone PVC, 4088 reflective, 8096 rubber, 596 asphalt, 56 road paint, 496 tar, 64 orange sheeting, 384 board, 2912 steel, 720 black plastic and 696 lens faces, UVs in 0..1 with zero AABB overlap, outer AABB 3.037×2.037×1.335 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 10 supports (five cone bases, the fallen cone's body and four barricade pads) 1.5 mm into the slab (band 0.8–3.0 mm), 4 boards biting their legs 1.5 mm at all 8 joints (band 0.8–3.0 mm), 14 collars seated 0.600 mm into their bodies and 1.400 mm proud, 6 upright cones 0.0000° off plumb at 0.720 m on bases 0.356 m across the flats, the barricade's 4 legs mirrored within 0.0001 mm, one stack of 3 at a 0.036 m pitch with each inner wall bearing 0.847–1.105 mm on the wall below (band 0.4–2.0 mm), one connected assembly of 125 shells, LOD ratios in band, collider 493 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-cone 16; --gap-board 17; --float-band 18; --lean-cone 19; --skew-leg 19; --loose-stack 20; --loose-lamp 21.
+
witnesses Recomputed: 45816 tris, eleven materials with 6048 cone PVC, 4088 reflective, 8096 rubber, 596 asphalt, 56 road paint, 496 tar, 64 orange sheeting, 384 board, 2912 steel, 720 black plastic and 696 lens faces, UVs in 0..1 with zero AABB overlap, outer AABB 3.037×2.037×1.335 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 10 supports (five cone bases, the fallen cone's body and four barricade pads) 1.5 mm into the slab (band 0.8–3.0 mm), 4 boards biting their legs 1.5 mm at all 8 joints (band 0.8–3.0 mm), 14 collars seated 0.600 mm into their bodies and 1.400 mm proud, 6 upright cones 0.0000° off plumb at 0.720 m on bases 0.356 m across the flats, the barricade's 4 legs mirrored within 0.0001 mm, one stack of 3 at a 0.036 m pitch with each inner wall bearing 0.847–1.105 mm on the wall below (band 0.4–2.0 mm), one connected assembly of 125 shells, LOD ratios in band, collider 342 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-cone 16; --gap-board 17; --float-band 18; --lean-cone 19; --skew-leg 19; --loose-stack 20; --loose-lamp 21.

category Vehicles

tags mesh export showcase

@@ -71,7 +71,7 @@

Traffic Cones

Intended size: the patch is 3.04 × 2.04 m with its jittered edge; the lamp housing sets the top at 1.335 m. A cone is 0.720 m tall on a base 0.356 m across the flats; the barricade's hinges stand 1.0 m over the slab. The origin is under the patch centre at the slab's underside.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles45300–4640045816
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 11 distinct; ≥5560 cone PVC, ≥3760 reflective, ≥7440 rubber, ≥540 asphalt, ≥50 road paint, ≥450 tar, ≥58 orange sheeting, ≥350 board plastic, ≥2670 steel, ≥660 black plastic, ≥640 lens faces11 slots; 6048 / 4088 / 8096 / 596 / 56 / 496 / 64 / 384 / 2912 / 720 / 696
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(3.0365, 2.0374, 1.3354) m ± 0.01, read off the vertices(3.0365, 2.0374, 1.3354), zmin 0
Collider tris≤ 540493
Exportwritten, size > 0, removed after measuring3335792 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles45300–4640045816
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 11 distinct; ≥5560 cone PVC, ≥3760 reflective, ≥7440 rubber, ≥540 asphalt, ≥50 road paint, ≥450 tar, ≥58 orange sheeting, ≥350 board plastic, ≥2670 steel, ≥660 black plastic, ≥640 lens faces11 slots; 6048 / 4088 / 8096 / 596 / 56 / 496 / 64 / 384 / 2912 / 720 / 696
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(3.0365, 2.0374, 1.3354) m ± 0.01, read off the vertices(3.0365, 2.0374, 1.3354), zmin 0
Collider tris≤ 540342
Exportwritten, size > 0, removed after measuring3327800 / 3327800 / 3327792 bytes (4.5.11 / 5.1.2 / 5.2.1)

Every falsifier leaves the triangle count at 45816 and the envelope at (3.0365, 2.0374, 1.3354): they move parts, never add or remove them.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements, and 4.5.11 and 5.1.2 print the same measurements as 5.2.1 (the export differs by 28 bytes).

Hygiene#

diff --git a/docs/gallery/treasure-chest/index.html b/docs/gallery/treasure-chest/index.html index dc7279d3..a8ebd63b 100644 --- a/docs/gallery/treasure-chest/index.html +++ b/docs/gallery/treasure-chest/index.html @@ -53,7 +53,7 @@

Treasure Chest

An open grained wooden treasure chest with iron bands following its barrel-vaulted lid.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 3816 tris, two materials with 1608 wood and 300 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.764×0.524×0.696 m, LOD ratios in band, convex collider 180 tris, non-empty glTF. Hygiene all zero, four feet at zmin 0, lid-knuckle to hinge barrel 7 mm, band-wall gap 0. --float-hinge exits 17 on the hinge join; --narrow-bands exits 18 on the band seat.
+
witnesses Recomputed: 3816 tris, two materials with 1608 wood and 300 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.764×0.524×0.696 m, LOD ratios in band, convex collider 156 tris, non-empty glTF. Hygiene all zero, four feet at zmin 0, lid-knuckle to hinge barrel 7 mm, band-wall gap 0. --float-hinge exits 17 on the hinge join; --narrow-bands exits 18 on the band seat.

category Village

tags mesh export showcase

@@ -68,7 +68,7 @@

Treasure Chest

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles3600–45003816 / 3816 / 3816
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2129
Materialsexactly 2 distinct; ≥200 wood, ≥80 metal faces2 slots; 1608 / 300
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.764, 0.524, 0.696) m ± 0.015(0.7640, 0.5237, 0.6958), zmin 0
Lid bands on the vault3 bands spanning the lid; every vertex radius within 1e-4 m of the band's inner/outer radius3; 0.000000
Collider tris≤ 200180
Exportwritten, size > 0285980 / 285980 / 285972 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles3600–45003816 / 3816 / 3816
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2129
Materialsexactly 2 distinct; ≥200 wood, ≥80 metal faces2 slots; 1608 / 300
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.764, 0.524, 0.696) m ± 0.015(0.7640, 0.5237, 0.6958), zmin 0
Lid bands on the vault3 bands spanning the lid; every vertex radius within 1e-4 m of the band's inner/outer radius3; 0.000000
Collider tris≤ 200156
Exportwritten, size > 0283028 / 283028 / 283024 bytes (4.5.11 / 5.1.2 / 5.2.1)

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

AxisDeclaredMeasured (all three)
Non-manifold edges00
Loose verts / edges0 / 00 / 0
Doubles merged at 1e-500
Zero-area faces00
N-gons00
Coplanar disjoint face pairs00
Grounded: zminwithin 1e-4 of 00.0000
Named supports: 4 feeteach zmin ≤ 1e-34, foot_z 0.00000
Body plan0.74 × 0.46 m ± 0.040.7400 × 0.4600
diff --git a/docs/gallery/wall-torch/index.html b/docs/gallery/wall-torch/index.html index f0f558d8..403c3ddd 100644 --- a/docs/gallery/wall-torch/index.html +++ b/docs/gallery/wall-torch/index.html @@ -53,7 +53,7 @@

Wall Torch

A wall torch: a dark-jointed stone plaque with a round iron plate and level arm holding a cup, from which a leaning wooden torch with a pitch-wrapped head burns above the cornice.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 2004 tris, five materials with 540 stone, 318 metal, 50 wood, 180 flame and 60 pitch faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.304×0.322×0.485 m at zmin 0, LOD ratios in band, convex collider 116 tris, non-empty glTF. Hygiene all zero. Arm level 0.000°, plate 13 mm proud of the stones and 3 mm into them, arm-to-cup gap 0.07 mm, plaque width 0.280 m, bake 27.7 texels per UV cell. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-arm 17; --float-plate 18; --skinny-plaque 19; --droop-arm 20; --sink-plate 21; --low-bake 22.
+
witnesses Recomputed: 2004 tris, five materials with 540 stone, 318 metal, 50 wood, 180 flame and 60 pitch faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.304×0.322×0.485 m at zmin 0, LOD ratios in band, convex collider 90 tris, non-empty glTF. Hygiene all zero. Arm level 0.000°, plate 13 mm proud of the stones and 3 mm into them, arm-to-cup gap 0.07 mm, plaque width 0.280 m, bake 27.7 texels per UV cell. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-arm 17; --float-plate 18; --skinny-plaque 19; --droop-arm 20; --sink-plate 21; --low-bake 22.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Wall Torch

Intended size: a 0.28 m wide, 0.40 m tall plaque; the cup centre 0.24 m out from the wall; the flame tip 0.48 m above the floor. Outer AABB 0.304 × 0.322 × 0.485 m.

Budgets#

Declared as named constants. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1800–22502004 / 2004 / 2004
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 5 distinct; ≥24 stone, ≥24 metal, ≥8 flame, ≥10 pitch5 slots; 540 stone, 318 metal, 50 wood, 180 flame, 60 pitch
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.304, 0.322, 0.485) m ± 0.015(0.3040, 0.3218, 0.4845), zmin 0
Collider tris≤ 180116
Exportwritten, size > 0164408 / 164408 / 164384 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles1800–22502004 / 2004 / 2004
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2196 / 0.2196 / 0.2196
Materialsexactly 5 distinct; ≥24 stone, ≥24 metal, ≥8 flame, ≥10 pitch5 slots; 540 stone, 318 metal, 50 wood, 180 flame, 60 pitch
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.304, 0.322, 0.485) m ± 0.015(0.3040, 0.3218, 0.4845), zmin 0
Collider tris≤ 18090
Exportwritten, size > 0163468 / 163468 / 163460 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 1528 to 2004 in the second quality pass, and the band moved from 1400–1700 to 1800–2250. The solid cup became an open, walled cup with a drip boss. The 26 mm haft stub became a 0.20 m haft with a wrap. The three flame cones became lathed teardrops. The envelope grew from 0.293 m to 0.322 m in depth and from 0.424 m to 0.485 m in height, because the torch now stands up out of its cup.

DECIMATE COLLAPSE triangle counts are not identical across series. The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Construction is closed-form and stone tones are seeded, so repeated runs on one binary print identical measurements. Export byte counts differ by 24 B on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

diff --git a/docs/gallery/watchtower/index.html b/docs/gallery/watchtower/index.html index 45157331..1f23dff4 100644 --- a/docs/gallery/watchtower/index.html +++ b/docs/gallery/watchtower/index.html @@ -53,7 +53,7 @@

Watchtower

A grained timber watchtower on braced legs, seen from low and close, with a ladder, a railed platform on deck girts, rusted iron collars and a weathered cedar shake roof.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 6840 tris, three materials with 300 metal and 126 roof faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.594×1.594×2.973 m, grounded zmin, 4 iron shoes, rail engage 18 mm, all four side rails tenoned at both ends, both joists bearing 31 mm into deck girts, collar standoff 2 mm, post plumb 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 150 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-rails/--open-sides/--short-joists 17; --float-band 18; --rake-posts 19.
+
witnesses Recomputed: 6840 tris, three materials with 300 metal and 126 roof faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.594×1.594×2.973 m, grounded zmin, 4 iron shoes, rail engage 18 mm, all four side rails tenoned at both ends, both joists bearing 31 mm into deck girts, collar standoff 2 mm, post plumb 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 122 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-rails/--open-sides/--short-joists 17; --float-band 18; --rake-posts 19.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Watchtower

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles6200–82006840 / 6840 / 6840
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2187
Materialsexactly 3 distinct; ≥80 metal, ≥40 roof faces3 slots; 300 metal, 126 roof
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.594, 1.594, 2.973) m ± 0.01(1.5940, 1.5940, 2.9731), zmin 0
Collider tris≤ 180150
Exportwritten, size > 0, removed after measuring494508 / 494508 / 494492 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles6200–82006840 / 6840 / 6840
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2187
Materialsexactly 3 distinct; ≥80 metal, ≥40 roof faces3 slots; 300 metal, 126 roof
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.594, 1.594, 2.973) m ± 0.01(1.5940, 1.5940, 2.9731), zmin 0
Collider tris≤ 180122
Exportwritten, size > 0, removed after measuring492624 / 492624 / 492616 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 5220 to 6408 in the first quality pass (a taller eave-true roof and coursed shakes) and to 6840 in the second (four deck girts), not hidden interior faces.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

diff --git a/docs/gallery/water-trough/index.html b/docs/gallery/water-trough/index.html index f80e1e24..00afea62 100644 --- a/docs/gallery/water-trough/index.html +++ b/docs/gallery/water-trough/index.html @@ -69,7 +69,7 @@

Water Trough

Intended size: 1.08 m tray length, 0.44 m across the U, 0.51 m overall height; outer AABB 1.111 × 0.552 × 0.512 m (the bung adds 18 mm in X, the rim clips 7 mm in Z).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles4300–52004792 / 4792
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199
Materialsexactly 3 distinct; ≥24 wood, ≥24 metal, ≥6 water3 slots; 1656 / 420 / 476
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.111, 0.552, 0.512) m ± 0.01(1.1112, 0.5520, 0.5123), zmin 0
Collider tris≤ 8076
Exportwritten, size > 0355404 / 355388 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.2.1)
Base triangles4300–52004792 / 4792
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199
Materialsexactly 3 distinct; ≥24 wood, ≥24 metal, ≥6 water3 slots; 1656 / 420 / 476
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.111, 0.552, 0.512) m ± 0.01(1.1112, 0.5520, 0.5123), zmin 0
Collider tris≤ 8076
Exportwritten, size > 0354444 / 354444 / 354436 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 2484 to 3700 in the first quality pass: box end slabs and a single extruded U became ten jittered staves, U end-caps, continuous straps offset from the legs, and stretchers that meet the inner faces. The second pass took them to 3124: the open U-band ends became solid end boards, which close the section with fewer faces. The third pass took them to 3316: each end became three boards. The fifth pass took them to 4792: the water became a lofted, rippled volume (~900 triangles; it was one flat quad on a U prism), and the straps gained ten bolt heads and four rim clips, the trestles six pegs, and the right end a bung. The band moved from 2800–3500 to 4300–5200, the same ~±10 % slack around the measured count. The collider hulls the trough without the sub-2 cm hardware (bolts, pegs, bung): detail that small carries no collision meaning. The rim clips are 47 mm wide and stay in it. The 5.1.2 column was dropped with this change: the new model was measured on 4.5.11 and 5.2.1 only.

DECIMATE COLLAPSE triangle counts are not identical across series — the gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Stave-width jitter uses closed-form sin(i); plank tone is the only RNG, seeded (TONE_SEED). Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.

The hull-size budget (exit 19) runs before the outer AABB budget (exit 8) so --narrow-hull is not swallowed by a moved bounding box.

diff --git a/docs/gallery/weight-rack/index.html b/docs/gallery/weight-rack/index.html index a84d2138..c133a5d6 100644 --- a/docs/gallery/weight-rack/index.html +++ b/docs/gallery/weight-rack/index.html @@ -53,7 +53,7 @@

Weight Rack

A red home-gym half rack holding an Olympic barbell loaded with blue and yellow bumpers on J-hooks, plates on storage horns and two hex dumbbells, on a dark studio floor.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 44264 tris, twelve materials with 4758 powder-coat, 3036 bore, 4196 zinc, 3348 chrome, 256 knurl, 1328 rubber, 104 UHMW, 3112 numeral, 864 blue, 576 yellow, 576 green and 2240 cast-iron faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.200×1.636×2.092 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads and four dumbbell heads on the floor, all four pull pins on their holes' axes (0.000 mm) 7.0 mm deep, the bar seated in both J-hook saddles (−0.20 mm) and level (0.0000°) at 2.200 m, 0.450 m bumpers, twelve plates on six sleeves within 0.80 mm of their axes with every gap −0.50 mm (band −0.8 to −0.2 mm), the loaded bar's mass centre 0.002 mm off its midpoint (tol 2 mm), one connected rack plus two dumbbells, LOD ratios in band, collider 598 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --float-bar 18; --hook-high 19; --gap-plate 20; --odd-load 21; --loose-horn 22.
+
witnesses Recomputed: 44264 tris, twelve materials with 4758 powder-coat, 3036 bore, 4196 zinc, 3348 chrome, 256 knurl, 1328 rubber, 104 UHMW, 3112 numeral, 864 blue, 576 yellow, 576 green and 2240 cast-iron faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.200×1.636×2.092 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads and four dumbbell heads on the floor, all four pull pins on their holes' axes (0.000 mm) 7.0 mm deep, the bar seated in both J-hook saddles (−0.20 mm) and level (0.0000°) at 2.200 m, 0.450 m bumpers, twelve plates on six sleeves within 0.80 mm of their axes with every gap −0.50 mm (band −0.8 to −0.2 mm), the loaded bar's mass centre 0.002 mm off its midpoint (tol 2 mm), one connected rack plus two dumbbells, LOD ratios in band, collider 472 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --float-bar 18; --hook-high 19; --gap-plate 20; --odd-load 21; --loose-horn 22.

category Sports

tags mesh export showcase

@@ -70,7 +70,7 @@

Weight Rack

Intended size: 2.20 m across the bar, 1.64 m from the dumbbells to the rear foot caps, 2.09 m to the top of the upright caps. The bar sets the width, the dumbbells and the rear feet the depth, and the caps the height. The origin is under the rack, so it lands on its pads.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles43500–4500044264
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2197
Materialsexactly 12 distinct; ≥4420 powder coat, ≥2820 bore, ≥3900 zinc, ≥3110 chrome, ≥235 knurl, ≥1230 rubber, ≥96 UHMW, ≥2890 numeral, ≥800 blue, ≥530 yellow, ≥530 green, ≥2080 cast-iron faces12 slots; 4758 / 3036 / 4196 / 3348 / 256 / 1328 / 104 / 3112 / 864 / 576 / 576 / 2240
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.200, 1.636, 2.092) m ± 0.01(2.2000, 1.6364, 2.0920), zmin 0
Collider tris≤ 640598
Exportwritten, size > 0, removed after measuring3303420 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles43500–4500044264
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2197
Materialsexactly 12 distinct; ≥4420 powder coat, ≥2820 bore, ≥3900 zinc, ≥3110 chrome, ≥235 knurl, ≥1230 rubber, ≥96 UHMW, ≥2890 numeral, ≥800 blue, ≥530 yellow, ≥530 green, ≥2080 cast-iron faces12 slots; 4758 / 3036 / 4196 / 3348 / 256 / 1328 / 104 / 3112 / 864 / 576 / 576 / 2240
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.200, 1.636, 2.092) m ± 0.01(2.2000, 1.6364, 2.0920), zmin 0
Collider tris≤ 640472
Exportwritten, size > 0, removed after measuring3295024 / 3295024 / 3295016 bytes (4.5.11 / 5.1.2 / 5.2.1)

The collider is the convex hull of the whole set. Its count is carried by the plates' rims and the dumbbell heads, which are the hull's outline.

Every falsifier leaves the triangle count at 44264: they move parts or swap a plate for one of the same topology, never add or remove geometry.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

diff --git a/docs/gallery/wheelbarrow/index.html b/docs/gallery/wheelbarrow/index.html index 8536a3a7..3319df5b 100644 --- a/docs/gallery/wheelbarrow/index.html +++ b/docs/gallery/wheelbarrow/index.html @@ -53,7 +53,7 @@

Wheelbarrow

A wooden wheelbarrow with a flared tray of stacked boards held by iron straps, its front raked out over a spoked wheel, and two long shafts running from the handles under the tray to the axle.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 2440 tris, two materials with 1085 wood and 214 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.563x0.594x0.577 m, zmin 0, hygiene 0, both shafts one timber from grip to axle, tray flared 15 deg and raked 30 deg, wall-floor seat 8 mm, spoke clearance 52 mm, two boards per side and front wall with 2 mm seams measured in the wall's plane, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 80 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert exits 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --fat-spokes / --float-walls / --wide-seams exit 17 on joint fit; --pipe-rim exits 18 on tread aspect; --split-shafts exits 20 on shaft runs; --box-tray exits 21 on tray flare.
+
witnesses Recomputed: 2440 tris, two materials with 1085 wood and 214 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.563x0.594x0.577 m, zmin 0, hygiene 0, both shafts one timber from grip to axle, tray flared 15 deg and raked 30 deg, wall-floor seat 8 mm, spoke clearance 52 mm, two boards per side and front wall with 2 mm seams measured in the wall's plane, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 64 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert exits 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --fat-spokes / --float-walls / --wide-seams exit 17 on joint fit; --pipe-rim exits 18 on tread aspect; --split-shafts exits 20 on shaft runs; --box-tray exits 21 on tray flare.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Wheelbarrow

Intended size: a 1.56 m long barrow, 0.59 m across the tray top, 0.58 m to the top of the raked front board; the tray is 0.94 m long at its top edge and 0.22 m deep.

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2300–28002440 / 2440 / 2440
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2057
Materialsexactly 2 distinct; ≥700 wood, ≥180 metal faces2 slots; 1085 / 214
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.563, 0.594, 0.577) m ± 0.015(1.5630, 0.5938, 0.5773), zmin 0
Collider tris≤ 22080
Exportwritten, size > 0185652 / 185652 / 185636 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles2300–28002440 / 2440 / 2440
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2197 / 0.2197 / 0.2057
Materialsexactly 2 distinct; ≥700 wood, ≥180 metal faces2 slots; 1085 / 214
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(1.563, 0.594, 0.577) m ± 0.015(1.5630, 0.5938, 0.5773), zmin 0
Collider tris≤ 22064
Exportwritten, size > 0183984 / 183984 / 183976 bytes (4.5.11 / 5.1.2 / 5.2.1)

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

AxisDeclaredMeasured (all three)
Non-manifold edges00
Loose verts / edges0 / 00 / 0
Doubles merged at 1e-500
Zero-area faces00
N-gons00
Coplanar disjoint face pairs00
Grounded: zminwithin 1e-4 of 00.0000
Named supports: 2 shoes + tyreeach zmin ≤ 1e-3shoe_z 0.00000, tyre_z 0.00000
Tray size(0.939, 0.578, 0.225) m ± 0.02(0.9393, 0.5783, 0.2247)
diff --git a/docs/gallery/wingback-armchair/index.html b/docs/gallery/wingback-armchair/index.html index d94b0fab..a44911af 100644 --- a/docs/gallery/wingback-armchair/index.html +++ b/docs/gallery/wingback-armchair/index.html @@ -53,7 +53,7 @@

Wingback Armchair

An oxblood leather wingback armchair with a deep-button tufted back and brass-nailed rolled arms, beside a tripod side table with a brass reading lamp and books, on a fringed rug.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 44324 tris, nine materials with 15712 leather, 3628 wood, 4825 brass, 672 shade, 668 rug, 1512 fringe, 124 cloth, 12 paper and 212 bulb faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.030×1.400×1.160 m read off the vertices, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 chair feet and 3 table feet sunk 0.0020 m into the rug (band 0.0008–0.0040), all 4 legs tenoned 0.0288–0.0319 m into the body (band 0.012–0.045), all 13 buttons seated 0.0025 m (band 0.0012–0.0045) and 0.0074 m proud in dimples 0.0169–0.0185 m deep (min 0.008), the body mirror-symmetric to 0.000000 m over 10620 vertices (max 0.0005) with the seat 0.4531 m, the back 1.1113 m and the width 0.8683 m, 16 diagonal button pairs at 0.1617–0.1626 m (spread 0.00089, cap 0.004), the mass centre of table, lamp and books 0.0922 m inside the feet's triangle (min 0.045), the cushion pressed 0.0020 m into the deck (band 0.0008–0.0040), 28 + 28 + 19 nailheads at a 0.03000 m pitch with zero spread, seated 0.0010–0.0013 m, LOD ratios in band, collider 802 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --short-legs 17; --sink-buttons 18; --odd-wing 19; --drift-buttons 20; --narrow-tripod 21; --lift-cushion 22; --bunch-nails 23.
+
witnesses Recomputed: 44324 tris, nine materials with 15712 leather, 3628 wood, 4825 brass, 672 shade, 668 rug, 1512 fringe, 124 cloth, 12 paper and 212 bulb faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.030×1.400×1.160 m read off the vertices, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 chair feet and 3 table feet sunk 0.0020 m into the rug (band 0.0008–0.0040), all 4 legs tenoned 0.0288–0.0319 m into the body (band 0.012–0.045), all 13 buttons seated 0.0025 m (band 0.0012–0.0045) and 0.0074 m proud in dimples 0.0169–0.0185 m deep (min 0.008), the body mirror-symmetric to 0.000000 m over 10620 vertices (max 0.0005) with the seat 0.4531 m, the back 1.1113 m and the width 0.8683 m, 16 diagonal button pairs at 0.1617–0.1626 m (spread 0.00089, cap 0.004), the mass centre of table, lamp and books 0.0922 m inside the feet's triangle (min 0.045), the cushion pressed 0.0020 m into the deck (band 0.0008–0.0040), 28 + 28 + 19 nailheads at a 0.03000 m pitch with zero spread, seated 0.0010–0.0013 m, LOD ratios in band, collider 640 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --short-legs 17; --sink-buttons 18; --odd-wing 19; --drift-buttons 20; --narrow-tripod 21; --lift-cushion 22; --bunch-nails 23.

category Household

tags mesh export showcase

@@ -74,7 +74,7 @@

Wingback Armchair

Intended size: a chair 0.868 m wide, its seat 0.453 m and its back 1.111 m above the rug; a side table 0.575 m high and 0.47 m across. The outer AABB is 2.0304 × 1.400 × 1.160 m: the tassels set the width, the rug the depth and the lamp's finial the top. The origin is under the rug.

Budgets#

Every budget is declared as a named constant. Every gate recomputes its value from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (5.2.1)
Base triangles43700–4490044324
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; face floors ≥14500 leather, ≥3350 wood, ≥4450 brass, ≥620 shade, ≥615 rug, ≥1390 fringe, ≥114 cloth, ≥11 paper, ≥195 bulb9 slots; 15712 / 3628 / 4825 / 672 / 668 / 1512 / 124 / 12 / 212
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.0304, 1.400, 1.160) m ± 0.01(2.0304, 1.4000, 1.1600), zmin 0
Collider tris≤ 820802
Exportwritten, size > 0, removed after measuring3509556 bytes
+
AxisDeclaredMeasured (5.2.1)
Base triangles43700–4490044324
LOD1 ratio0.32–0.62 of base0.5000
LOD2 ratio0.10–0.35 of base0.2200
Materialsexactly 9 distinct; face floors ≥14500 leather, ≥3350 wood, ≥4450 brass, ≥620 shade, ≥615 rug, ≥1390 fringe, ≥114 cloth, ≥11 paper, ≥195 bulb9 slots; 15712 / 3628 / 4825 / 672 / 668 / 1512 / 124 / 12 / 212
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(2.0304, 1.400, 1.160) m ± 0.01(2.0304, 1.4000, 1.1600), zmin 0
Collider tris≤ 820640
Exportwritten, size > 0, removed after measuring3503360 / 3503360 / 3503352 bytes (4.5.11 / 5.1.2 / 5.2.1)

No falsifier changes the topology or the envelope: every run measures the default's 44324 triangles and AABB.

DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels are stochastic, so the bake gate is has_data plus operator FINISHED, not byte-identity. Construction uses no RNG; two default runs print identical measurements.

Hygiene#

diff --git a/docs/gallery/wooden-barrel/index.html b/docs/gallery/wooden-barrel/index.html index 26128b49..c1dcad11 100644 --- a/docs/gallery/wooden-barrel/index.html +++ b/docs/gallery/wooden-barrel/index.html @@ -53,7 +53,7 @@

Wooden Barrel

A wooden stave barrel bound by four iron hoops, its head made of boards.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 7312 tris, two materials with 2584 wood and 1440 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.714×0.880 m, 20 grounded staves, hoop bite 0.003 m, head-croze gap 0.007 m, four boards per head with 1.5 mm seams, LOD ratios in band, convex collider 238 tris, non-empty glTF. --skip-decimate exits 9; --round-band exits 18 on the hoop-seat budget; --one-piece-head exits 17 on the head-board budget.
+
witnesses Recomputed: 7312 tris, two materials with 2584 wood and 1440 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.714×0.880 m, 20 grounded staves, hoop bite 0.003 m, head-croze gap 0.007 m, four boards per head with 1.5 mm seams, LOD ratios in band, convex collider 226 tris, non-empty glTF. --skip-decimate exits 9; --round-band exits 18 on the hoop-seat budget; --one-piece-head exits 17 on the head-board budget.

category Village

tags mesh export showcase

@@ -68,7 +68,7 @@

Wooden Barrel

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles6000–85007312 / 7312 / 7312
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2199
Materialsexactly 2 distinct; ≥400 wood, ≥200 metal faces2 slots; 2584 / 1440
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.722, 0.714, 0.880) m ± 0.015(0.7220, 0.7142, 0.8800), zmin 0
Collider tris≤ 400238
Exportwritten, size > 0552456 / 552456 / 552440 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles6000–85007312 / 7312 / 7312
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2199
Materialsexactly 2 distinct; ≥400 wood, ≥200 metal faces2 slots; 2584 / 1440
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.722, 0.714, 0.880) m ± 0.015(0.7220, 0.7142, 0.8800), zmin 0
Collider tris≤ 400226
Exportwritten, size > 0555344 / 555344 / 555340 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 4312 to 7216 in the quality pass: 12 identical staves with 5 mm daylight and circular hoops became 20 jittered staves, 8-ring bulge, chord-seated hoops, polygonal croze heads, and a bung. Cutting each head into four boards added 96 more (7312).

DECIMATE COLLAPSE triangle counts are not identical across series — the gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, 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.

Hygiene#

diff --git a/docs/gallery/wooden-bucket/index.html b/docs/gallery/wooden-bucket/index.html index 09771eaf..a61b0df0 100644 --- a/docs/gallery/wooden-bucket/index.html +++ b/docs/gallery/wooden-bucket/index.html @@ -68,7 +68,7 @@

Wooden Bucket

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles4000–58005458 / 5458 / 5458
LOD1 ratio0.32–0.62 of base0.4998 / 0.4998 / 0.4998
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2191
Materialsexactly 3 distinct; ≥350 wood, ≥180 metal, ≥40 rope3 slots; 1448 / 1020 / 486
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.396, 0.346, 0.534) m ± 0.015(0.3957, 0.3462, 0.5338), zmin 0
Collider tris≤ 420276
Exportwritten, size > 0420984 / 420984 / 420976 bytes
+
AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles4000–58005458 / 5458 / 5458
LOD1 ratio0.32–0.62 of base0.4998 / 0.4998 / 0.4998
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2191
Materialsexactly 3 distinct; ≥350 wood, ≥180 metal, ≥40 rope3 slots; 1448 / 1020 / 486
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.396, 0.346, 0.534) m ± 0.015(0.3957, 0.3462, 0.5338), zmin 0
Collider tris≤ 420276
Exportwritten, size > 0422992 / 422992 / 422984 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 4272 to 4872 in the quality pass: overlapping identical staves, circular hoops, and a 12-box bail became 16 jittered staves, chord-seated hoops, a polygonal croze floor, and a round bail through the ear rings. The second pass took it to 5458: the bail became three-strand rope (48 segments of a nine-vertex lobed section, running on through the rings) and the floor three boards.

DECIMATE COLLAPSE triangle counts are not identical across series, so LOD2 ratios differ slightly between versions. The gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Stave-width jitter uses fixed seed 17. Export byte counts differ on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

diff --git a/docs/gallery/wooden-ladder/index.html b/docs/gallery/wooden-ladder/index.html index 6326a911..a6066505 100644 --- a/docs/gallery/wooden-ladder/index.html +++ b/docs/gallery/wooden-ladder/index.html @@ -53,7 +53,7 @@

Wooden Ladder

An oak ladder with six pale turned hickory rungs through-tenoned into its rails, iron tie-rods under the end rungs, leaning on a board wall with a rope coil on a rung.

Rendered headless by the showcase piece itself. Select it to enlarge.

-
witnesses Recomputed: 3000 tris, two materials with 684 wood and 976 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, rung pitch even to 0.002 m, LOD ratios in band, convex collider 92 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; --drift-rungs exits 19.
+
witnesses Recomputed: 3000 tris, two materials with 684 wood and 976 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, rung pitch even to 0.002 m, LOD ratios in band, convex collider 68 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; --drift-rungs exits 19.

category Village

tags mesh export showcase

@@ -69,7 +69,7 @@

Wooden Ladder

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package). Hygiene combinatorics match examples/mesh-hygiene-audit (copied, not imported). Coplanar-pair counting matches showcase/signpost.

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

-
AxisDeclaredMeasured (4.5.11 / 5.2.1; 5.1.2 not re-run after the tie-rod pass)
Base triangles1800–31003000 / 3000
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2200 / 0.2200
Materialsexactly 2 distinct, ≥280 wood, ≥180 metal2 slots, 684 wood, 976 metal
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.490, 0.376, 1.487) m ± 0.01(0.4903, 0.3760, 1.4870)
Groundedabs(zmin) ≤ 1e-4, each sole at 0, rail end ≥ 0.012 mzmin 0, sole 0, rail 0.02037
Mesh hygienenon-manifold, loose v/e, doubles at 1e-5, zero-area, n-gons, coplanar pairs all 0all 0
Parts26 shells (2 stiles, 6 rungs, 2 sleeves, 2 cap sleeves, 2 plates, 2 soles, 2 tie-rods, 4 washers, 4 nuts)26 (2 / 6 / 2 / 2)
Rung depth clearance≥ 0.003 m inside the stile faces0.00800
Tenon engagement≥ 0.008 m past the stile inner face0.05387 (through)
Through-tenon proudtenon end 0.001–0.004 m past the stile outer face0.00199
Shoe bite / coverbite ≥ 0.010 m, cover ≥ 0.016 m0.02000 / 0.03800
Rung pitch6 rungs; every rung-to-rung gap within 0.002 m of the mean6; 0.00000
Tie-rod seat2 rods, 4 washers, 4 nuts; washer into stile and nut into washer 0.0002–0.002 m; on the rod axis within 0.0015 m; thread ≥ 0.003 m proud of each nut2 / 4 / 4; bite 0.00049–0.00051; axis 0; thread 0.00450
Collider tris≤ 18092
Exportwritten, size > 0230268 bytes (5.2.1)
+
AxisDeclaredMeasured (4.5.11 / 5.2.1; 5.1.2 not re-run after the tie-rod pass)
Base triangles1800–31003000 / 3000
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2200 / 0.2200
Materialsexactly 2 distinct, ≥280 wood, ≥180 metal2 slots, 684 wood, 976 metal
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.490, 0.376, 1.487) m ± 0.01(0.4903, 0.3760, 1.4870)
Groundedabs(zmin) ≤ 1e-4, each sole at 0, rail end ≥ 0.012 mzmin 0, sole 0, rail 0.02037
Mesh hygienenon-manifold, loose v/e, doubles at 1e-5, zero-area, n-gons, coplanar pairs all 0all 0
Parts26 shells (2 stiles, 6 rungs, 2 sleeves, 2 cap sleeves, 2 plates, 2 soles, 2 tie-rods, 4 washers, 4 nuts)26 (2 / 6 / 2 / 2)
Rung depth clearance≥ 0.003 m inside the stile faces0.00800
Tenon engagement≥ 0.008 m past the stile inner face0.05387 (through)
Through-tenon proudtenon end 0.001–0.004 m past the stile outer face0.00199
Shoe bite / coverbite ≥ 0.010 m, cover ≥ 0.016 m0.02000 / 0.03800
Rung pitch6 rungs; every rung-to-rung gap within 0.002 m of the mean6; 0.00000
Tie-rod seat2 rods, 4 washers, 4 nuts; washer into stile and nut into washer 0.0002–0.002 m; on the rod axis within 0.0015 m; thread ≥ 0.003 m proud of each nut2 / 4 / 4; bite 0.00049–0.00051; axis 0; thread 0.00450
Collider tris≤ 18068
Exportwritten, size > 0228568 / 228568 / 228560 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 936 to 2536. The previous mesh was two boxes, six cloned dowels, and four chrome cubes. Turned rungs (tenon and barrel in one shell) plus ferrule collars and chamfered soles added the triangles. Nothing was removed as a hidden face.

A later pass took them to 2680. The bare ladder was still the plainest object in its asset-sheet lineup, and the parts budget is exact (16 shells), so the detail had to live inside existing shells. Each rung gained one ring at mid-span (+24 triangles per rung): the barrel shoulders in at 0.90 × its radius (RUNG_SHOULDER) and swells to 1.14 × (RUNG_SWELL). That turns a dowel into a lathe-turned round. The tenons are unchanged, so clearance, engagement and pitch read the same. The breakout margin moved 0.07 mm (0.03780 → 0.03787) because the shell's worst vertex is now measured across seven rings. The wood shader also changed. The grain noise runs across the stile's 50 mm width at a readable scale (WOOD_GRAIN_SCALE 34 → 95, streak stretch 0.94 → 0.985); before, about one noise period spanned a stile, so it rendered as flat tan. A short-range AO term darkens the rung housings and the wood under the iron sleeves.

A third pass changed the model itself. The bare ladder was still the plainest object in its asset sheet, because the exact parts budget left every detail inside the existing shells. The parts budget is now 26: two iron tie-rods run through both rails under the bottom and top rungs, each end clamped by a square nut over a round washer bedded on the rail's outer face. That is the rod a wooden ladder carries to stop the rails spreading off the rungs. The triangle ceiling rose 2800 → 3100 for the hardware (+320 triangles; the old ceiling had 120 to spare). The rungs are now through-tenoned: each tenon runs right through its rail and stands 2 mm proud, so the old breakout margin (a blind tenon stopping short of the outer face) became a through-tenon proud band, and the tenon's inboard ring moved to 4 mm inside the rail so the joint audit always samples tenon section in the wood. The shader reads a per-shell Species attribute: rungs are pale hickory against darker oak rails, and end grain (the tenon ends, the rail tops) takes the finish darker. The rung finders now require the wood material, because the tie-rods are as wide as a rung. The new tie-rod seat budget gets its own falsifier, --float-nuts (exit 20).

diff --git a/showcase/anvil/README.md b/showcase/anvil/README.md index d550123d..296b6767 100644 --- a/showcase/anvil/README.md +++ b/showcase/anvil/README.md @@ -34,8 +34,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 2 distinct; ≥400 wood, ≥400 metal faces | 2 slots; 1040 / 912 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.621, 0.414, 0.569) m ± 0.015 | (0.6210, 0.4137, 0.5690), zmin 0 | -| Collider tris | ≤ 280 | 134 | -| Export | written, size > 0 | 257068 / 257068 / 257052 bytes | +| Collider tris | ≤ 280 | 130 | +| Export | written, size > 0 | 258408 / 258408 / 258400 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles dropped from **6616 to 2988** in the quality pass: overlapping face boxes and a beveled superellipse horn became one diff --git a/showcase/anvil/anvil.py b/showcase/anvil/anvil.py index 3cc759c2..affbe38a 100644 --- a/showcase/anvil/anvil.py +++ b/showcase/anvil/anvil.py @@ -1171,6 +1171,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1178,6 +1182,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bmesh.ops.dissolve_limit(bm, angle_limit=math.radians(10.0), verts=list(bm.verts), edges=list(bm.edges), delimit={"NORMAL"}) bmesh.ops.triangulate(bm, faces=list(bm.faces)) diff --git a/showcase/archery-target/README.md b/showcase/archery-target/README.md index 38f59bef..3fa4c309 100644 --- a/showcase/archery-target/README.md +++ b/showcase/archery-target/README.md @@ -61,8 +61,8 @@ export file. | Materials | exactly 16 distinct; ≥4490 straw, ≥1760 twine, ≥1030 pine, ≥5970 steel, ≥495 white, ≥775 black, ≥120 blue, ≥120 red, ≥240 gold, ≥310 carbon, ≥475 vane, ≥285 cock vane, ≥1020 nock, ≥4960 grass, ≥270 soil, ≥730 leather faces | 16 slots; 4732 / 1856 / 1086 / 6288 / 522 / 816 / 128 / 128 / 254 / 326 / 500 / 300 / 1076 / 5230 / 286 / 768 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.0071, 2.6887, 2.0538) m ± 0.01 | (2.0071, 2.6887, 2.0538), zmin 0 | -| Collider tris | ≤ 1150 | 1083 | -| Export | written, size > 0, removed after measuring | 3288248 bytes | +| Collider tris | ≤ 1150 | 634 | +| Export | written, size > 0, removed after measuring | 3259388 / 3259388 / 3259380 bytes (4.5.11 / 5.1.2 / 5.2.1) | The collider is the convex hull of the whole piece; its count is carried by the 96-segment turf outline. diff --git a/showcase/archery-target/archery_target.py b/showcase/archery-target/archery_target.py index 4e7e4eb2..977ee9b8 100644 --- a/showcase/archery-target/archery_target.py +++ b/showcase/archery-target/archery_target.py @@ -2131,6 +2131,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2138,6 +2142,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/bamboo-clump/README.md b/showcase/bamboo-clump/README.md index 88188804..87e6137f 100644 --- a/showcase/bamboo-clump/README.md +++ b/showcase/bamboo-clump/README.md @@ -104,7 +104,7 @@ export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (3.8168, 3.5512, 4.8254) m ± 0.01 | (3.8168, 3.5512, 4.8254), zmin 0 | | Collider tris (lower 1.25 m hull) | ≤ 96 | 88 | -| Export | written, size > 0, removed after measuring | 5606968 bytes | +| Export | written, size > 0, removed after measuring | 5606976 / 5606976 / 5606968 bytes (4.5.11 / 5.1.2 / 5.2.1) | The quality pass re-fitted four of these around the new measurements, each for a stated reason. The triangle band moved from 51500–53500 to 72800–74800, diff --git a/showcase/bamboo-clump/bamboo_clump.py b/showcase/bamboo-clump/bamboo_clump.py index e33977bc..d596e885 100644 --- a/showcase/bamboo-clump/bamboo_clump.py +++ b/showcase/bamboo-clump/bamboo_clump.py @@ -1585,6 +1585,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1592,6 +1596,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/basketball-hoop/README.md b/showcase/basketball-hoop/README.md index 7d885ea1..9976949f 100644 --- a/showcase/basketball-hoop/README.md +++ b/showcase/basketball-hoop/README.md @@ -94,7 +94,7 @@ Intended size: 5.2 × 6.6 m court pad; 1.83 × 1.05 m board with its bottom 2.90 m above the court; pole axis 1.22 m behind the board face. The outer AABB is 5.200 × 6.600 × 4.050 m; the pad sets the footprint, and the pole cap on the 100 mm slab sets the height. The convex collider wraps the pad -and the hoop together (58 tris). +and the hoop together (44 tris). ## Budgets @@ -110,8 +110,8 @@ export file. | Materials | exactly 12 distinct; face floors ≥2200 steel, ≥45 board, ≥28 board paint, ≥850 rim, ≥2400 net, ≥330 pad, ≥120 aluminium, ≥90 concrete, ≥440 court line, ≥12 key, ≥900 ball, ≥2000 seam | 12 slots; 2546 / 54 / 32 / 970 / 2784 / 382 / 144 / 108 / 504 / 12 / 1024 / 2310 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (5.200, 6.600, 4.050) m ± 0.01 | (5.2000, 6.6000, 4.0500), zmin 0 | -| Collider tris | ≤ 220 | 58 | -| Export | written, size > 0, removed after measuring | 1456228 bytes | +| Collider tris | ≤ 220 | 44 | +| Export | written, size > 0, removed after measuring | 1454192 / 1454192 / 1454180 bytes (4.5.11 / 5.1.2 / 5.2.1) | DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels diff --git a/showcase/basketball-hoop/basketball_hoop.py b/showcase/basketball-hoop/basketball_hoop.py index 44d2511e..1efd928e 100644 --- a/showcase/basketball-hoop/basketball_hoop.py +++ b/showcase/basketball-hoop/basketball_hoop.py @@ -1644,6 +1644,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1651,6 +1655,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/boulder-cluster/README.md b/showcase/boulder-cluster/README.md index 513433c0..50bbd0ce 100644 --- a/showcase/boulder-cluster/README.md +++ b/showcase/boulder-cluster/README.md @@ -73,7 +73,7 @@ export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (4.4442, 3.2153, 1.3657) m ± 0.01 | (4.4442, 3.2153, 1.3657), zmin 0 | | Collider tris (rock hull) | ≤ 320 | 292 | -| Export | written, size > 0, removed after measuring | 3064548 bytes | +| Export | written, size > 0, removed after measuring | 3064552 / 3064552 / 3064548 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the triangle count or the envelope: every falsifier run measured 40244 tris and the default's outer AABB to the tenth of a diff --git a/showcase/boulder-cluster/boulder_cluster.py b/showcase/boulder-cluster/boulder_cluster.py index cbb1515e..9d84bf35 100644 --- a/showcase/boulder-cluster/boulder_cluster.py +++ b/showcase/boulder-cluster/boulder_cluster.py @@ -1922,6 +1922,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1929,6 +1933,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/bowling-pins/README.md b/showcase/bowling-pins/README.md index 3a57779a..9d2f5b65 100644 --- a/showcase/bowling-pins/README.md +++ b/showcase/bowling-pins/README.md @@ -65,8 +65,8 @@ export file. | Materials | exactly 11 distinct; ≥330 maple, ≥330 pin deck, ≥12800 pin white, ≥1190 pin red, ≥1450 ball, ≥480 bore, ≥235 gutter/kick plate, ≥130 kickback laminate, ≥160 aluminium/steel, ≥1110 inlay, ≥350 sleeper faces | 11 slots; 358 / 358 / 13720 / 1280 / 1649 / 562 / 254 / 142 / 176 / 1197 / 380 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.640, 2.301, 0.523) m ± 0.01, read off the vertices | (1.6400, 2.3014, 0.5234), zmin 0 | -| Collider tris | ≤ 300 | 277 | -| Export | written, size > 0, removed after measuring | 2730012 bytes | +| Collider tris | ≤ 300 | 200 | +| Export | written, size > 0, removed after measuring | 2722544 / 2722544 / 2722540 bytes (4.5.11 / 5.1.2 / 5.2.1) | Every falsifier leaves the triangle count at 37078 and the envelope at (1.6400, 2.3014, 0.5234): they move or resize parts, never add or remove diff --git a/showcase/bowling-pins/bowling_pins.py b/showcase/bowling-pins/bowling_pins.py index 157eec11..aa866371 100644 --- a/showcase/bowling-pins/bowling_pins.py +++ b/showcase/bowling-pins/bowling_pins.py @@ -1615,6 +1615,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1622,6 +1626,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/broadleaf-oak/README.md b/showcase/broadleaf-oak/README.md index 4ff8c868..6ad5748f 100644 --- a/showcase/broadleaf-oak/README.md +++ b/showcase/broadleaf-oak/README.md @@ -118,7 +118,7 @@ export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (11.529, 11.716, 8.958) m ± 0.01 | (11.5288, 11.7164, 8.9575), zmin 0 | | Collider tris (bole hull) | ≤ 60 | 54 | -| Export | written, size > 0, removed after measuring | 10351880 bytes | +| Export | written, size > 0, removed after measuring | 10351900 / 10351900 / 10351880 bytes (4.5.11 / 5.1.2 / 5.2.1) | DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count (4.5.11 and diff --git a/showcase/broadleaf-oak/broadleaf_oak.py b/showcase/broadleaf-oak/broadleaf_oak.py index 197d8544..05efecd3 100644 --- a/showcase/broadleaf-oak/broadleaf_oak.py +++ b/showcase/broadleaf-oak/broadleaf_oak.py @@ -2464,6 +2464,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2471,6 +2475,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/cactus-garden/README.md b/showcase/cactus-garden/README.md index cb9ce533..fb92f1d0 100644 --- a/showcase/cactus-garden/README.md +++ b/showcase/cactus-garden/README.md @@ -89,7 +89,7 @@ export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.9950, 2.6077, 2.3754) m ± 0.01 | (2.9950, 2.6077, 2.3754), zmin 0 | | Collider tris (sand hull) | ≤ 120 | 112 | -| Export | written, size > 0, removed after measuring | 3772220 bytes | +| Export | written, size > 0, removed after measuring | 3772228 / 3772228 / 3772220 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the triangle count: every falsifier run measured 45364 tris. Only `--lean-saguaro` moves the envelope, by 6.5 mm in Z diff --git a/showcase/cactus-garden/cactus_garden.py b/showcase/cactus-garden/cactus_garden.py index 5c1f912c..ea58c485 100644 --- a/showcase/cactus-garden/cactus_garden.py +++ b/showcase/cactus-garden/cactus_garden.py @@ -2367,6 +2367,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2374,6 +2378,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/campfire/README.md b/showcase/campfire/README.md index 7be27020..bb180816 100644 --- a/showcase/campfire/README.md +++ b/showcase/campfire/README.md @@ -34,7 +34,7 @@ materials, UVs, evaluated LOD, collider, or export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.807, 0.808, 0.404) m ± 0.015 | (0.8024, 0.8022, 0.4037), zmin 0 | | Collider tris | ≤ 360 | 162 | -| Export | written, size > 0 | 231952 / 231952 / 231944 bytes | +| Export | written, size > 0 | 231712 / 231712 / 231708 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles dropped from **3616 to 2200** in the quality pass: the old piece stacked identical boxes with a mortar gap and a teepee that diff --git a/showcase/campfire/campfire.py b/showcase/campfire/campfire.py index 033cf418..cf0b633d 100644 --- a/showcase/campfire/campfire.py +++ b/showcase/campfire/campfire.py @@ -1083,6 +1083,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1090,6 +1094,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bmesh.ops.dissolve_limit(bm, angle_limit=math.radians(10.0), verts=list(bm.verts), edges=list(bm.edges), delimit={"NORMAL"}) bmesh.ops.triangulate(bm, faces=list(bm.faces)) diff --git a/showcase/cargo-loader/README.md b/showcase/cargo-loader/README.md index 0e38612d..bbf8fdeb 100644 --- a/showcase/cargo-loader/README.md +++ b/showcase/cargo-loader/README.md @@ -81,8 +81,8 @@ export file. | Materials | exactly 10 distinct; ≥2550 paint, ≥560 hazard, ≥2900 chrome, ≥14300 steel, ≥2550 rubber, ≥440 seat vinyl, ≥590 harness webbing, ≥235 beacon, ≥140 work-light, ≥480 crate paint faces | 10 slots; 2736 / 608 / 3128 / 15328 / 2740 / 480 / 640 / 256 / 152 / 516 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.827, 1.689, 2.974) m ± 0.01 | (2.8272, 1.6890, 2.9740), zmin 0 | -| Collider tris | ≤ 760 | 710 | -| Export | written, size > 0, removed after measuring | 3461604 bytes | +| Collider tris | ≤ 760 | 532 | +| Export | written, size > 0, removed after measuring | 3450636 / 3450636 / 3450628 bytes (4.5.11 / 5.1.2 / 5.2.1) | The collider is the convex hull of the whole loader; the power pack, the beacon, the shoulder pins and the tine tips carry its outline. diff --git a/showcase/cargo-loader/cargo_loader.py b/showcase/cargo-loader/cargo_loader.py index b1cae469..98810115 100644 --- a/showcase/cargo-loader/cargo_loader.py +++ b/showcase/cargo-loader/cargo_loader.py @@ -1829,6 +1829,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1836,6 +1840,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/cart/README.md b/showcase/cart/README.md index bfb84c2b..0bd2b243 100644 --- a/showcase/cart/README.md +++ b/showcase/cart/README.md @@ -36,9 +36,9 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 2 distinct, metal ≥ 800, wood ≥ 1200 faces | 2 slots; 1196 metal, 1694 wood | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.580, 0.842, 0.640) m ± 0.01 | (1.5800, 0.8420, 0.6400) | -| Collider tris | ≤ 360 | 192 | +| Collider tris | ≤ 360 | 164 | | Bake texels | smallest UV cell ≥ 12 px at the baked resolution | 17.45 px at 1024 px | -| Export | written, size > 0, removed after measuring | 403176 / 403176 / 403160 bytes | +| Export | written, size > 0, removed after measuring | 402904 / 402904 / 402900 bytes (4.5.11 / 5.1.2 / 5.2.1) | ### Hygiene, supports and joints diff --git a/showcase/cart/cart.py b/showcase/cart/cart.py index 4e28a665..60c6231d 100644 --- a/showcase/cart/cart.py +++ b/showcase/cart/cart.py @@ -1352,6 +1352,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1359,6 +1363,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/chopping-block/README.md b/showcase/chopping-block/README.md index a5471ba0..03968c0f 100644 --- a/showcase/chopping-block/README.md +++ b/showcase/chopping-block/README.md @@ -54,8 +54,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 4 distinct; ≥160 bark, ≥90 grain, ≥170 metal, ≥150 haft faces | 4 slots; 180 / 216 / 412 / 176 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.526, 0.526, 1.006) m ± 0.012 | (0.5264, 0.5264, 1.0064) | -| Collider tris | ≤ 560 | 538 | -| Export | written, size > 0 | 181676 / 181676 / 181660 bytes | +| Collider tris | ≤ 560 | 398 | +| Export | written, size > 0 | 174020 / 174020 / 174020 bytes (4.5.11 / 5.1.2 / 5.2.1) | The triangle band, the outer AABB and the collider ceiling were re-fitted in the quality pass that added the lap, the rivets and the 16-segment diff --git a/showcase/chopping-block/chopping_block.py b/showcase/chopping-block/chopping_block.py index 4156fe83..ea3f11a2 100644 --- a/showcase/chopping-block/chopping_block.py +++ b/showcase/chopping-block/chopping_block.py @@ -1416,6 +1416,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1423,6 +1427,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/crate-stack/README.md b/showcase/crate-stack/README.md index 9b1af888..a3aa3bbc 100644 --- a/showcase/crate-stack/README.md +++ b/showcase/crate-stack/README.md @@ -59,7 +59,7 @@ for the 4.5.11 / 5.1.2 figures. | UV AABB overlap | ≤ 1e-5 | 0.000000 | | Outer AABB | 0.658 × 0.524 × 0.704 m ± 0.020 | 0.6583 × 0.5235 × 0.7040 | | Crate body footprint | 0.588 × 0.428 m ± 0.015, in the crate's own frame | 0.5882 × 0.4282 (all three) | -| Collider triangles | ≤ 260 | 230 | +| Collider triangles | ≤ 260 | 204 | | Normal bake | `{'FINISHED'}` with image data | `{'FINISHED'}`, `has_data=True` | | glTF export | file written, non-empty | ~490 kB | | Hygiene | all zero | loose 0/0, non-manifold 0, zero-area 0, doubles 0, n-gons 0, coplanar disjoint pairs 0 | @@ -215,7 +215,7 @@ Smoke runs the check-only path. It does not pass `--output` or any falsifier. | LOD1 tris / ratio | 3030 / 0.5000 | 3030 / 0.5000 | 3030 / 0.5000 | | LOD2 tris / ratio | 1332 / 0.2198 | 1332 / 0.2198 | 1332 / 0.2198 | | Outer AABB | 0.6583 × 0.5235 × 0.7040 | same | same | -| Collider tris | 230 | 230 | 230 | +| Collider tris | 204 | 204 | 204 | | Yaws (rad) | 0.0943, −0.1093, 0.0681 | same | same | | Seat gap | 0.00000 | 0.00000 | 0.00000 | | Nails / bite / proud | 48 / 0.60 mm / 1.80 mm | same | same | diff --git a/showcase/crate-stack/crate_stack.py b/showcase/crate-stack/crate_stack.py index 9669d708..3a27698e 100644 --- a/showcase/crate-stack/crate_stack.py +++ b/showcase/crate-stack/crate_stack.py @@ -1293,6 +1293,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1300,6 +1304,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/desk-lamp/README.md b/showcase/desk-lamp/README.md index f9c2da2d..42dc3cc1 100644 --- a/showcase/desk-lamp/README.md +++ b/showcase/desk-lamp/README.md @@ -84,8 +84,8 @@ export file. | Materials | exactly 6 distinct; ≥3600 enamel, ≥8300 steel, ≥310 bulb, ≥1350 rubber, ≥560 reflector, ≥340 bakelite faces | 6 slots; 3972 / 9210 / 348 / 1508 / 622 / 384 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.725, 0.361, 0.442) m ± 0.01 | (0.7252, 0.3606, 0.4421), zmin 0 | -| Collider tris | ≤ 760 | 713 | -| Export | written, size > 0, removed after measuring | 2229360 bytes | +| Collider tris | ≤ 760 | 472 | +| Export | written, size > 0, removed after measuring | 2217452 / 2217452 / 2217444 bytes (4.5.11 / 5.1.2 / 5.2.1) | The triangle band is wide enough to hold `--hollow-base` (30974) and `--unhook-spring` (29790), so those falsifiers exit on their own budgets diff --git a/showcase/desk-lamp/desk_lamp.py b/showcase/desk-lamp/desk_lamp.py index d61fe129..06d3c13c 100644 --- a/showcase/desk-lamp/desk_lamp.py +++ b/showcase/desk-lamp/desk_lamp.py @@ -1360,6 +1360,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1367,6 +1371,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/espresso-machine/README.md b/showcase/espresso-machine/README.md index 943b191e..972140b0 100644 --- a/showcase/espresso-machine/README.md +++ b/showcase/espresso-machine/README.md @@ -110,8 +110,8 @@ export file. | Materials | exactly 14 distinct; face floors ≥4400 stainless, ≥6700 chrome, ≥870 bakelite, ≥580 wood, ≥5330 ceramic, ≥1140 rubber, ≥580 glass, ≥1510 dial, ≥58 ink, ≥32 needle, ≥84 stone, ≥24 paint, ≥415 coffee, ≥106 lamp | 14 slots; 4788 / 7284 / 948 / 632 / 5800 / 1244 / 632 / 1642 / 64 / 36 / 91 / 26 / 452 / 116 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.670, 0.655, 0.4755) m ± 0.01 | (0.6700, 0.6550, 0.4755), zmin 0 | -| Collider tris | ≤ 520 | 447 | -| Export | written, size > 0, removed after measuring | 3229536 bytes | +| Collider tris | ≤ 520 | 346 | +| Export | written, size > 0, removed after measuring | 3222244 / 3222244 / 3222236 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the topology, so every one of them measures the default's 43636 triangles. Every one keeps the default's AABB except diff --git a/showcase/espresso-machine/espresso_machine.py b/showcase/espresso-machine/espresso_machine.py index b1ba6a11..a074a623 100644 --- a/showcase/espresso-machine/espresso_machine.py +++ b/showcase/espresso-machine/espresso_machine.py @@ -1797,6 +1797,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1804,6 +1808,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/fallen-log/README.md b/showcase/fallen-log/README.md index 68fb0c2f..82cb981b 100644 --- a/showcase/fallen-log/README.md +++ b/showcase/fallen-log/README.md @@ -74,8 +74,8 @@ export file. | Materials | exactly 9 distinct; ≥4600 bark, ≥800 wood, ≥340 rot, ≥2150 moss, ≥2200 bracket, ≥1160 toadstool, ≥2240 soil, ≥1870 litter, ≥4580 fern faces | 9 slots; 5144 / 892 / 384 / 2400 / 2448 / 1296 / 2494 / 2080 / 5090 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (4.1189, 2.1885, 1.0267) m ± 0.01 | (4.1189, 2.1885, 1.0267), zmin 0 | -| Collider tris (log hull) | ≤ 240 | 215 | -| Export | written, size > 0, removed after measuring | 2826044 bytes | +| Collider tris (log hull) | ≤ 240 | 142 | +| Export | written, size > 0, removed after measuring | 2823404 / 2823404 / 2823392 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the triangle count: they move parts or the soil, never add or remove them. diff --git a/showcase/fallen-log/fallen_log.py b/showcase/fallen-log/fallen_log.py index 65bc9ce4..73006d51 100644 --- a/showcase/fallen-log/fallen_log.py +++ b/showcase/fallen-log/fallen_log.py @@ -1705,6 +1705,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1712,6 +1716,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/fence-kit/README.md b/showcase/fence-kit/README.md index ae3e45a9..05e944c7 100644 --- a/showcase/fence-kit/README.md +++ b/showcase/fence-kit/README.md @@ -58,8 +58,8 @@ mesh, materials, UVs, evaluated LOD, collider or export file. | Materials | exactly 2 distinct, ≥48 metal, ≥48 wood | 2 slots, 116 metal / 390 wood | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.596, 0.134, 1.232) m ± 0.015 | (1.5960, 0.1340, 1.2320), zmin 0 | -| Collider tris | ≤ 180 | 24 | -| Export | written, size > 0 | 75900 / 75900 / 75888 bytes | +| Collider tris | ≤ 180 | 20 | +| Export | written, size > 0 | 74952 / 74952 / 74944 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles dropped from **1092 to 1012** in the second quality pass. Each band became one mitred shell instead of three or four separate plates, and diff --git a/showcase/fence-kit/fence_kit.py b/showcase/fence-kit/fence_kit.py index 4b855166..fdfcd003 100644 --- a/showcase/fence-kit/fence_kit.py +++ b/showcase/fence-kit/fence_kit.py @@ -711,6 +711,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -718,6 +722,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/fern-mossy-rock/README.md b/showcase/fern-mossy-rock/README.md index 25a4dd47..05f172db 100644 --- a/showcase/fern-mossy-rock/README.md +++ b/showcase/fern-mossy-rock/README.md @@ -120,7 +120,7 @@ export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.2872, 1.9008, 1.1111) m ± 0.01 | (2.2872, 1.9008, 1.1111), zmin 0 | | Collider tris (boulder hull) | ≤ 200 | 130 | -| Export | written, size > 0, removed after measuring | 10731436 bytes | +| Export | written, size > 0, removed after measuring | 10731448 / 10731448 / 10731436 bytes (4.5.11 / 5.1.2 / 5.2.1) | DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels diff --git a/showcase/fern-mossy-rock/fern_mossy_rock.py b/showcase/fern-mossy-rock/fern_mossy_rock.py index 754dd4bc..15bff7ab 100644 --- a/showcase/fern-mossy-rock/fern_mossy_rock.py +++ b/showcase/fern-mossy-rock/fern_mossy_rock.py @@ -2881,6 +2881,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2888,6 +2892,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/floor-fan/README.md b/showcase/floor-fan/README.md index 364fb40f..e44c68bb 100644 --- a/showcase/floor-fan/README.md +++ b/showcase/floor-fan/README.md @@ -91,8 +91,8 @@ export file. | Materials | exactly 6 distinct; ≥4350 enamel, ≥12800 chrome, ≥540 brass, ≥1120 rubber, ≥740 bakelite, ≥400 badge faces | 6 slots; 4732 / 13960 / 584 / 1216 / 810 / 440 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.761, 0.704, 1.230) m ± 0.01 | (0.7614, 0.7039, 1.2286), zmin 0 | -| Collider tris | ≤ 2200 | 1997 | -| Export | written, size > 0, removed after measuring | 3114936 bytes | +| Collider tris | ≤ 2200 | 1560 | +| Export | written, size > 0, removed after measuring | 3119064 / 3119064 / 3119060 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the topology, so every one of them measures the default's 41460 triangles and the default's AABB. diff --git a/showcase/floor-fan/floor_fan.py b/showcase/floor-fan/floor_fan.py index 100a418d..88c6aa6f 100644 --- a/showcase/floor-fan/floor_fan.py +++ b/showcase/floor-fan/floor_fan.py @@ -1451,6 +1451,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1458,6 +1462,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/gallery.json b/showcase/gallery.json index ab132fbb..317140f7 100644 --- a/showcase/gallery.json +++ b/showcase/gallery.json @@ -11,7 +11,7 @@ "category": "village", "teaches": "A procedural shipping crate through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A grained wooden shipping crate in three-quarter view, PORT ROYAL and NO 17 stencilled along its side slats, with nailed iron corner straps and a bail handle on one end.", - "witnessesFix": "Recomputed: 3388 tris, two materials with 1170 wood and 904 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.146×0.726×0.612 m, grounded zmin, 3 skids, handle-end and slat-post join 0, mesh hygiene all zero, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 116 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-skids 16; --float-handle 17; --omit-slats 18.", + "witnessesFix": "Recomputed: 3388 tris, two materials with 1170 wood and 904 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.146×0.726×0.612 m, grounded zmin, 3 skids, handle-end and slat-post join 0, mesh hygiene all zero, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 100 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-skids 16; --float-handle 17; --omit-slats 18.", "hero": "docs/gallery/assets/shipping-crate-hero.webp", "preview": "showcase/shipping-crate/preview.webp", "tags": [ @@ -25,7 +25,7 @@ "category": "village", "teaches": "A procedural stone well through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A round well of grey stones, each a slightly different shade, under a four-post grained wooden roof, with a bucket on rusted iron hoops hanging inside.", - "witnessesFix": "Recomputed: 9380 tris, three materials with face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.312×1.312×1.761 m, LOD ratios in band, convex collider 346 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, all 12 bottom-course stones on the floor, each post tenoned 18 mm into the measured coping and standing under a roof hip corner, the bucket hanging 0.10 m clear of the coping, grounded zmin, non-empty glTF. --stand-posts exits 15 on the z-fight budget; --float-stone exits 16 on the named-support budget; --shallow-tenon and --drop-bucket exit 18; --turn-posts exits 19 on post placement; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.", + "witnessesFix": "Recomputed: 9380 tris, three materials with face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.312×1.312×1.761 m, LOD ratios in band, convex collider 258 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, all 12 bottom-course stones on the floor, each post tenoned 18 mm into the measured coping and standing under a roof hip corner, the bucket hanging 0.10 m clear of the coping, grounded zmin, non-empty glTF. --stand-posts exits 15 on the z-fight budget; --float-stone exits 16 on the named-support budget; --shallow-tenon and --drop-bucket exit 18; --turn-posts exits 19 on post placement; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.", "hero": "docs/gallery/assets/stone-well-hero.webp", "preview": "showcase/stone-well/preview.webp", "tags": [ @@ -40,7 +40,7 @@ "category": "village", "teaches": "A procedural wine-cask with boarded, croze-seated heads and chord-lofted hoops through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A wooden stave barrel bound by four iron hoops, its head made of boards.", - "witnessesFix": "Recomputed: 7312 tris, two materials with 2584 wood and 1440 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.714×0.880 m, 20 grounded staves, hoop bite 0.003 m, head-croze gap 0.007 m, four boards per head with 1.5 mm seams, LOD ratios in band, convex collider 238 tris, non-empty glTF. --skip-decimate exits 9; --round-band exits 18 on the hoop-seat budget; --one-piece-head exits 17 on the head-board budget.", + "witnessesFix": "Recomputed: 7312 tris, two materials with 2584 wood and 1440 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.714×0.880 m, 20 grounded staves, hoop bite 0.003 m, head-croze gap 0.007 m, four boards per head with 1.5 mm seams, LOD ratios in band, convex collider 226 tris, non-empty glTF. --skip-decimate exits 9; --round-band exits 18 on the hoop-seat budget; --one-piece-head exits 17 on the head-board budget.", "hero": "docs/gallery/assets/wooden-barrel-hero.webp", "preview": "showcase/wooden-barrel/preview.webp", "tags": [ @@ -68,7 +68,7 @@ "category": "village", "teaches": "A procedural timber market stall through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A grained timber market stall with diagonal side braces, a red and cream striped canvas awning and a counter with shelves.", - "witnessesFix": "Recomputed: 4324 tris, three materials with 34 faces per awning stripe slot, UVs in 0..1 with zero AABB overlap, outer AABB 1.389×1.011×1.740 m, grounded zmin, 4 wrap feet, brace-counter overlap 0, both side braces seated 0.0418 m into their posts, awning seat 4 mm, post plumb 0, LOD ratios in band, convex collider 58 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --low-brace/--short-brace 17; --float-awning 18; --rake-posts 19.", + "witnessesFix": "Recomputed: 4324 tris, three materials with 34 faces per awning stripe slot, UVs in 0..1 with zero AABB overlap, outer AABB 1.389×1.011×1.740 m, grounded zmin, 4 wrap feet, brace-counter overlap 0, both side braces seated 0.0418 m into their posts, awning seat 4 mm, post plumb 0, LOD ratios in band, convex collider 56 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --low-brace/--short-brace 17; --float-awning 18; --rake-posts 19.", "hero": "docs/gallery/assets/market-stall-hero.webp", "preview": "showcase/market-stall/preview.webp", "tags": [ @@ -83,7 +83,7 @@ "category": "village", "teaches": "A procedural hanging street lantern through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A cast-iron street lamp: fluted post with brass collars and a ladder bar, a braced arm with wrought scrolls, and a banded brass lantern lit amber from inside.", - "witnessesFix": "Recomputed: 4726 tris, three materials with 2162 metal, 24 glass and 341 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, brace ends 13 mm into the post and the arm, 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 108 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19; --shallow-brace 20.", + "witnessesFix": "Recomputed: 4726 tris, three materials with 2162 metal, 24 glass and 341 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, brace ends 13 mm into the post and the arm, 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 86 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-brace 17; --sink-arm 18; --rake-post 19; --shallow-brace 20.", "hero": "docs/gallery/assets/street-lantern-hero.webp", "preview": "showcase/street-lantern/preview.webp", "tags": [ @@ -97,7 +97,7 @@ "category": "village", "teaches": "A procedural iron-bound chest with a lofted barrel-vault lid, U-wrap bands, and hinge knuckles through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "An open grained wooden treasure chest with iron bands following its barrel-vaulted lid.", - "witnessesFix": "Recomputed: 3816 tris, two materials with 1608 wood and 300 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.764×0.524×0.696 m, LOD ratios in band, convex collider 180 tris, non-empty glTF. Hygiene all zero, four feet at zmin 0, lid-knuckle to hinge barrel 7 mm, band-wall gap 0. --float-hinge exits 17 on the hinge join; --narrow-bands exits 18 on the band seat.", + "witnessesFix": "Recomputed: 3816 tris, two materials with 1608 wood and 300 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.764×0.524×0.696 m, LOD ratios in band, convex collider 156 tris, non-empty glTF. Hygiene all zero, four feet at zmin 0, lid-knuckle to hinge barrel 7 mm, band-wall gap 0. --float-hinge exits 17 on the hinge join; --narrow-bands exits 18 on the band seat.", "hero": "docs/gallery/assets/treasure-chest-hero.webp", "preview": "showcase/treasure-chest/preview.webp", "tags": [ @@ -125,7 +125,7 @@ "category": "village", "teaches": "A procedural post-and-rail fence section that fits its 1.60 m tile, with one-shell iron bands and a board brace housed in both posts, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A weathered post-and-rail fence run of three sections on a packed-earth strip, one capped post at each joint, each bay with a diagonal board brace and dark iron bands.", - "witnessesFix": "Recomputed: 1012 tris, two materials with 116 metal and 390 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.596×0.134×1.232 m inside the 1.60 m tile, grounded zmin, 2 iron shoes, brace housed 12 mm in both posts and bearing 2 mm on the middle rail, rail-to-post gap 0.93 mm, rail span 1.362 m, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 24 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-brace 17; --gap-rails 18; --long-rails 19; --float-brace 20; --wide-tile 21.", + "witnessesFix": "Recomputed: 1012 tris, two materials with 116 metal and 390 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.596×0.134×1.232 m inside the 1.60 m tile, grounded zmin, 2 iron shoes, brace housed 12 mm in both posts and bearing 2 mm on the middle rail, rail-to-post gap 0.93 mm, rail span 1.362 m, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 20 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-brace 17; --gap-rails 18; --long-rails 19; --float-brace 20; --wide-tile 21.", "hero": "docs/gallery/assets/fence-kit-hero.webp", "preview": "showcase/fence-kit/preview.webp", "tags": [ @@ -139,7 +139,7 @@ "category": "village", "teaches": "A procedural timber watchtower through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A grained timber watchtower on braced legs, seen from low and close, with a ladder, a railed platform on deck girts, rusted iron collars and a weathered cedar shake roof.", - "witnessesFix": "Recomputed: 6840 tris, three materials with 300 metal and 126 roof faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.594×1.594×2.973 m, grounded zmin, 4 iron shoes, rail engage 18 mm, all four side rails tenoned at both ends, both joists bearing 31 mm into deck girts, collar standoff 2 mm, post plumb 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 150 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-rails/--open-sides/--short-joists 17; --float-band 18; --rake-posts 19.", + "witnessesFix": "Recomputed: 6840 tris, three materials with 300 metal and 126 roof faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.594×1.594×2.973 m, grounded zmin, 4 iron shoes, rail engage 18 mm, all four side rails tenoned at both ends, both joists bearing 31 mm into deck girts, collar standoff 2 mm, post plumb 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 122 tris, non-empty glTF. Hygiene all zero. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-shoes 16; --short-rails/--open-sides/--short-joists 17; --float-band 18; --rake-posts 19.", "hero": "docs/gallery/assets/watchtower-hero.webp", "preview": "showcase/watchtower/preview.webp", "tags": [ @@ -153,7 +153,7 @@ "category": "village", "teaches": "A procedural two-wheel handcart through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A wooden handcart with a planked box bed and iron corner straps on two spoked wheels, standing level on two prop legs with its shafts joined by a pull bar.", - "witnessesFix": "Recomputed: 5284 tris, two materials with metal and wood face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.580×0.842×0.640 m, LOD ratios in band, convex collider 192 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, both tyres and both prop legs grounded, two wall boards per side with 3 mm seams, tyre seat depth in band over 48 angular stations, every shell in one BVH-contact assembly, the two wheels mirrored within 5e-5 m, no unchamfered right-angle edge, 17.45 bake texels per UV cell, non-empty glTF. --flush-tyre exits 15 on the z-fight budget; --float-wheel and --short-props exit 16 on the named-support budget; --wide-seams exits 17 on the board seams; --sink-tyre exits 18 on the tyre seat band; --lift-bed exits 18 on the one-assembly budget; --skew-wheel exits 19 on the wheel mirror; --sharp-bar exits 20 on edge treatment; --low-bake exits 21 on texel density; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.", + "witnessesFix": "Recomputed: 5284 tris, two materials with metal and wood face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.580×0.842×0.640 m, LOD ratios in band, convex collider 164 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, both tyres and both prop legs grounded, two wall boards per side with 3 mm seams, tyre seat depth in band over 48 angular stations, every shell in one BVH-contact assembly, the two wheels mirrored within 5e-5 m, no unchamfered right-angle edge, 17.45 bake texels per UV cell, non-empty glTF. --flush-tyre exits 15 on the z-fight budget; --float-wheel and --short-props exit 16 on the named-support budget; --wide-seams exits 17 on the board seams; --sink-tyre exits 18 on the tyre seat band; --lift-bed exits 18 on the one-assembly budget; --skew-wheel exits 19 on the wheel mirror; --sharp-bar exits 20 on edge treatment; --low-bake exits 21 on texel density; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.", "hero": "docs/gallery/assets/cart-hero.webp", "preview": "showcase/cart/preview.webp", "tags": [ @@ -168,7 +168,7 @@ "category": "village", "teaches": "A procedural wrought-iron park bench whose legs are each one bent bar from scroll toe to reclined back, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A park bench of grained wooden slats with a reclined back, on a dark wrought-iron frame whose round-bar legs curl into scrolled feet, with armrests on curved brackets.", - "witnessesFix": "Recomputed: 3272 tris, two materials with 1008 metal and 756 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.295×0.632×0.887 m, grounded zmin, 4 named toes, 4 legs each one bar from toe to seat, back reclined 12°, 28 slat and armrest bites of at least 2.0 mm, stretcher gap 1.1 mm, seat span 1.272 m, LOD ratios in band, convex collider 64 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --float-stretcher 17; --gap-slats 18; --narrow-seat/--upright-back 19; --float-slats 20; --split-feet 21.", + "witnessesFix": "Recomputed: 3272 tris, two materials with 1008 metal and 756 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.295×0.632×0.887 m, grounded zmin, 4 named toes, 4 legs each one bar from toe to seat, back reclined 12°, 28 slat and armrest bites of at least 2.0 mm, stretcher gap 1.1 mm, seat span 1.272 m, LOD ratios in band, convex collider 60 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-feet 16; --float-stretcher 17; --gap-slats 18; --narrow-seat/--upright-back 19; --float-slats 20; --split-feet 21.", "hero": "docs/gallery/assets/park-bench-hero.webp", "preview": "showcase/park-bench/preview.webp", "tags": [ @@ -183,7 +183,7 @@ "category": "village", "teaches": "A procedural wooden wheelbarrow through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A wooden wheelbarrow with a flared tray of stacked boards held by iron straps, its front raked out over a spoked wheel, and two long shafts running from the handles under the tray to the axle.", - "witnessesFix": "Recomputed: 2440 tris, two materials with 1085 wood and 214 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.563x0.594x0.577 m, zmin 0, hygiene 0, both shafts one timber from grip to axle, tray flared 15 deg and raked 30 deg, wall-floor seat 8 mm, spoke clearance 52 mm, two boards per side and front wall with 2 mm seams measured in the wall's plane, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 80 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert exits 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --fat-spokes / --float-walls / --wide-seams exit 17 on joint fit; --pipe-rim exits 18 on tread aspect; --split-shafts exits 20 on shaft runs; --box-tray exits 21 on tray flare.", + "witnessesFix": "Recomputed: 2440 tris, two materials with 1085 wood and 214 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.563x0.594x0.577 m, zmin 0, hygiene 0, both shafts one timber from grip to axle, tray flared 15 deg and raked 30 deg, wall-floor seat 8 mm, spoke clearance 52 mm, two boards per side and front wall with 2 mm seams measured in the wall's plane, LOD ratios in band (5.2 COLLAPSE leaner on LOD2), convex collider 64 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert exits 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --fat-spokes / --float-walls / --wide-seams exit 17 on joint fit; --pipe-rim exits 18 on tread aspect; --split-shafts exits 20 on shaft runs; --box-tray exits 21 on tray flare.", "hero": "docs/gallery/assets/wheelbarrow-hero.webp", "preview": "showcase/wheelbarrow/preview.webp", "tags": [ @@ -197,7 +197,7 @@ "category": "village", "teaches": "A procedural blacksmith anvil on a timber stump through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A London-pattern forged anvil with a thick face block, tapered horn and broad flared foot on a hooped oak stand, a cross-peen hammer on the floor beside it.", - "witnessesFix": "Recomputed: 3168 tris, two materials with 1040 wood and 912 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.621×0.414×0.569 m, LOD ratios in band, convex collider 134 tris, hygiene 0, 16 grounded staves, hoop bite 0.003 m, foot-on-head gap 0.003 m, waist corner reach 0.8572, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-staves 16; --float-anvil 17; --round-band 18; --round-waist 19.", + "witnessesFix": "Recomputed: 3168 tris, two materials with 1040 wood and 912 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.621×0.414×0.569 m, LOD ratios in band, convex collider 130 tris, hygiene 0, 16 grounded staves, hoop bite 0.003 m, foot-on-head gap 0.003 m, waist corner reach 0.8572, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-staves 16; --float-anvil 17; --round-band 18; --round-waist 19.", "hero": "docs/gallery/assets/anvil-hero.webp", "preview": "showcase/anvil/preview.webp", "tags": [ @@ -225,7 +225,7 @@ "category": "village", "teaches": "A procedural hitching post (eaved cap, one rail, cup shoe, rings hung through eyes, a face-nailed horseshoe) through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A tall wooden hitching post with a pointed cap, a cross-rail on two knee braces with iron end caps and two hung rings, iron bands, and a horseshoe nailed to its face.", - "witnessesFix": "Recomputed: 2156 tris, two materials with 222 wood and 880 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.506×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, bands 6.5 mm proud of the post, horseshoe biting 1.5 mm and 7.5 mm proud, LOD ratios in band, convex collider 72 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring, --sunk-bands and --float-horseshoe exit 18; --short-post exits 19.", + "witnessesFix": "Recomputed: 2156 tris, two materials with 222 wood and 880 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.506×0.149×1.246 m, zmin 0, hygiene and coplanar pairs 0, post seated at z 0.010, ring centerline error 0, bands 6.5 mm proud of the post, horseshoe biting 1.5 mm and 7.5 mm proud, LOD ratios in band, convex collider 44 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert and --twin-sole exit 15; --lift-z exits 16; --clip-ring, --sunk-bands and --float-horseshoe exit 18; --short-post exits 19.", "hero": "docs/gallery/assets/hitching-post-hero.webp", "preview": "showcase/hitching-post/preview.webp", "tags": [ @@ -239,7 +239,7 @@ "category": "village", "teaches": "A procedural grindstone on a timber trestle through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A sandstone grindstone wheel dipping into a water-filled trough, turning in a chamfered timber A-frame with its iron crank toward the viewer, the sills capped by iron shoes.", - "witnessesFix": "Recomputed: 1668 tris, three materials with 400 wood / 240 stone / 364 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.419×0.610 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, four shoes planted, trough seated in the sills and biting both stretchers 4 mm, stone dip 24 mm, no unchamfered right-angle edge, 29.44 bake texels per UV cell, LOD ratios in band, convex collider 304 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert / --flush-shoes exit 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --float-crank / --float-legs exit 17 on joint fit; --no-dip / --narrow-trough / --low-stretchers exit 18 on seat; --sharp-handle exits 20 on edge treatment; --low-bake exits 21 on texel density.", + "witnessesFix": "Recomputed: 1668 tris, three materials with 400 wood / 240 stone / 364 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.419×0.610 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, four shoes planted, trough seated in the sills and biting both stretchers 4 mm, stone dip 24 mm, no unchamfered right-angle edge, 29.44 bake texels per UV cell, LOD ratios in band, convex collider 202 tris, non-empty glTF. --skip-decimate exits 9 on LOD1; --stray-vert / --flush-shoes exit 15 on hygiene; --lift-z / --short-legs exit 16 on grounded; --float-crank / --float-legs exit 17 on joint fit; --no-dip / --narrow-trough / --low-stretchers exit 18 on seat; --sharp-handle exits 20 on edge treatment; --low-bake exits 21 on texel density.", "hero": "docs/gallery/assets/grindstone-hero.webp", "preview": "showcase/grindstone/preview.webp", "tags": [ @@ -253,7 +253,7 @@ "category": "village", "teaches": "A procedural village hand pump whose gooseneck is a 6-gon tube from the lower-column radius, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A green-enamelled cast-iron village pump with a fluted barrel, ball finial and counterweighted handle on a wooden plinth, a hooped bucket under its spout.", - "witnessesFix": "Recomputed: 2412 tris, two materials with 1134 metal and 332 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.610×0.521×1.055 m, grounded zmin, spout-to-column gap 2.4 mm, flange-to-plinth gap 6.0 mm, column radius 68 mm, LOD ratios in band, convex collider 205 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-spout 17; --float-flange 18; --skinny-col 19.", + "witnessesFix": "Recomputed: 2412 tris, two materials with 1134 metal and 332 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.610×0.521×1.055 m, grounded zmin, spout-to-column gap 2.4 mm, flange-to-plinth gap 6.0 mm, column radius 68 mm, LOD ratios in band, convex collider 146 tris, hygiene all zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-spout 17; --float-flange 18; --skinny-col 19.", "hero": "docs/gallery/assets/hand-pump-hero.webp", "preview": "showcase/hand-pump/preview.webp", "tags": [ @@ -267,7 +267,7 @@ "category": "village", "teaches": "A procedural timber fingerboard signpost through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A wooden crossroads signpost with three pointed cream finger boards painted MILLBROOK 2, OAKHAM 5 and FORD 1, rusted iron collars and bands on the post.", - "witnessesFix": "Recomputed: 432 tris, three materials with 126 metal, 33 board and 60 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.260×0.142×1.551 m at zmin 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD1/LOD2), convex collider 56 tris, non-empty glTF. Hygiene all zero. Board-to-post gap 5 mm, strap gap 3 mm, board AABB Y 28 mm. --skip-decimate exits 9; --stray-vert 15; --lift-z / --short-shoe 16; --gap-board 17; --float-strap 18; --yaw-boards 19.", + "witnessesFix": "Recomputed: 432 tris, three materials with 126 metal, 33 board and 60 wood faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.260×0.142×1.551 m at zmin 0, LOD ratios in band (5.2 COLLAPSE leaner on LOD1/LOD2), convex collider 44 tris, non-empty glTF. Hygiene all zero. Board-to-post gap 5 mm, strap gap 3 mm, board AABB Y 28 mm. --skip-decimate exits 9; --stray-vert 15; --lift-z / --short-shoe 16; --gap-board 17; --float-strap 18; --yaw-boards 19.", "hero": "docs/gallery/assets/signpost-hero.webp", "preview": "showcase/signpost/preview.webp", "tags": [ @@ -281,7 +281,7 @@ "category": "village", "teaches": "A procedural log-round chopping block with a riveted iron hoop and a felling axe buried in the sawn face, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A log-round chopping block bound with a riveted iron hoop, a felling axe buried in its ringed top, split billets and wood chips scattered at its foot.", - "witnessesFix": "Recomputed: 1816 tris, four materials with 180 bark / 216 grain / 412 metal / 176 haft faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.526 x 0.526 x 1.006 m, LOD ratios in band, convex collider 538 tris, non-empty glTF. Hygiene: zero non-manifold edges, loose geometry, doubles, zero-area faces, n-gons and coplanar disjoint face pairs, grounded at zmin 0, log plumb to 1e-7, oval haft 1.35 wide-to-thick. Joint fit: six shells, 13.5 mm haft clearance in the eye, 78.7 mm bit bury, hoop biting 3.7-4.2 mm into the log on every segment, two lap rivets seated 1.50 and 1.54 mm. --fat-haft exits 17 on eye clearance; --round-band and --float-rivets exit 18 on their seats; --round-haft exits 19 on the haft section.", + "witnessesFix": "Recomputed: 1816 tris, four materials with 180 bark / 216 grain / 412 metal / 176 haft faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.526 x 0.526 x 1.006 m, LOD ratios in band, convex collider 398 tris, non-empty glTF. Hygiene: zero non-manifold edges, loose geometry, doubles, zero-area faces, n-gons and coplanar disjoint face pairs, grounded at zmin 0, log plumb to 1e-7, oval haft 1.35 wide-to-thick. Joint fit: six shells, 13.5 mm haft clearance in the eye, 78.7 mm bit bury, hoop biting 3.7-4.2 mm into the log on every segment, two lap rivets seated 1.50 and 1.54 mm. --fat-haft exits 17 on eye clearance; --round-band and --float-rivets exit 18 on their seats; --round-haft exits 19 on the haft section.", "hero": "docs/gallery/assets/chopping-block-hero.webp", "preview": "showcase/chopping-block/preview.webp", "tags": [ @@ -309,7 +309,7 @@ "category": "village", "teaches": "A procedural wall-mounted torch sconce: an iron plate bolted to the stone face, a level arm, an open cup holding a leaning haft with a pitch wrap and upright flames, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A wall torch: a dark-jointed stone plaque with a round iron plate and level arm holding a cup, from which a leaning wooden torch with a pitch-wrapped head burns above the cornice.", - "witnessesFix": "Recomputed: 2004 tris, five materials with 540 stone, 318 metal, 50 wood, 180 flame and 60 pitch faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.304×0.322×0.485 m at zmin 0, LOD ratios in band, convex collider 116 tris, non-empty glTF. Hygiene all zero. Arm level 0.000°, plate 13 mm proud of the stones and 3 mm into them, arm-to-cup gap 0.07 mm, plaque width 0.280 m, bake 27.7 texels per UV cell. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-arm 17; --float-plate 18; --skinny-plaque 19; --droop-arm 20; --sink-plate 21; --low-bake 22.", + "witnessesFix": "Recomputed: 2004 tris, five materials with 540 stone, 318 metal, 50 wood, 180 flame and 60 pitch faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.304×0.322×0.485 m at zmin 0, LOD ratios in band, convex collider 90 tris, non-empty glTF. Hygiene all zero. Arm level 0.000°, plate 13 mm proud of the stones and 3 mm into them, arm-to-cup gap 0.07 mm, plaque width 0.280 m, bake 27.7 texels per UV cell. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-arm 17; --float-plate 18; --skinny-plaque 19; --droop-arm 20; --sink-plate 21; --low-bake 22.", "hero": "docs/gallery/assets/wall-torch-hero.webp", "preview": "showcase/wall-torch/preview.webp", "tags": [ @@ -324,7 +324,7 @@ "category": "village", "teaches": "A procedural tavern stool with a lathed seat, turned splayed legs, staggered stretchers, and iron ferrules gripping each leg on its own axis over a level tread, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A wooden tavern stool with a grained, dished round seat holding a pewter tankard, turned splayed legs, stretcher rungs at two heights, and dark iron ferrules on flat treads.", - "witnessesFix": "Recomputed: 3040 tris, two materials with 1168 wood and 576 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.341×0.341×0.470 m, LOD ratios in band, convex collider 468 tris, non-empty glTF. Hygiene all zero, four treads at zmin 0, stretcher-leg gap 0, ferrule grip 1.20 mm on each leg's axis, leg ends 1.1 mm above their treads, bake 22.4 texels per UV cell. --float-stretchers exits 17; --pipe-ferrule 18; --sink-legs 20; --low-bake 21.", + "witnessesFix": "Recomputed: 3040 tris, two materials with 1168 wood and 576 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.341×0.341×0.470 m, LOD ratios in band, convex collider 308 tris, non-empty glTF. Hygiene all zero, four treads at zmin 0, stretcher-leg gap 0, ferrule grip 1.20 mm on each leg's axis, leg ends 1.1 mm above their treads, bake 22.4 texels per UV cell. --float-stretchers exits 17; --pipe-ferrule 18; --sink-legs 20; --low-bake 21.", "hero": "docs/gallery/assets/tavern-stool-hero.webp", "preview": "showcase/tavern-stool/preview.webp", "tags": [ @@ -338,7 +338,7 @@ "category": "village", "teaches": "A procedural hanging iron cauldron with a round-bellied pot, a bail threaded through flat ear rings, and a timber tripod through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A rust-blotched cast-iron cauldron with a raised belly band, hanging by its bail and a short chain from a forged iron head atop a tripod of wooden poles.", - "witnessesFix": "Recomputed: 4180 tris, two materials with 144 wood and 2116 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.987×0.961×0.860 m, pot–leg clearance 0.053 m, pot base radius 0.075 m, 3 coaxial ferrules at zmin 0, ferrule bite −0.00185 m, hook-bail join 0 under a five-link chain, bail threads both ear rings, mesh hygiene all zero, LOD ratios in band, convex collider 252 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --float-hook/--edge-on-ears 17; --pipe-ferrule 18; --pointed-pot 19.", + "witnessesFix": "Recomputed: 4180 tris, two materials with 144 wood and 2116 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.987×0.961×0.860 m, pot–leg clearance 0.053 m, pot base radius 0.075 m, 3 coaxial ferrules at zmin 0, ferrule bite −0.00185 m, hook-bail join 0 under a five-link chain, bail threads both ear rings, mesh hygiene all zero, LOD ratios in band, convex collider 196 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-legs 16; --float-hook/--edge-on-ears 17; --pipe-ferrule 18; --pointed-pot 19.", "hero": "docs/gallery/assets/iron-cauldron-hero.webp", "preview": "showcase/iron-cauldron/preview.webp", "tags": [ @@ -352,7 +352,7 @@ "category": "village", "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.", "alt": "An oak ladder with six pale turned hickory rungs through-tenoned into its rails, iron tie-rods under the end rungs, leaning on a board wall with a rope coil on a rung.", - "witnessesFix": "Recomputed: 3000 tris, two materials with 684 wood and 976 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, rung pitch even to 0.002 m, LOD ratios in band, convex collider 92 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; --drift-rungs exits 19.", + "witnessesFix": "Recomputed: 3000 tris, two materials with 684 wood and 976 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, rung pitch even to 0.002 m, LOD ratios in band, convex collider 68 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; --drift-rungs exits 19.", "hero": "docs/gallery/assets/wooden-ladder-hero.webp", "preview": "showcase/wooden-ladder/preview.webp", "tags": [ @@ -380,7 +380,7 @@ "category": "village", "teaches": "A stack of three procedural shipping crates built by one generator called three times with a per-instance seed, carried through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "Three grained wooden shipping crates stacked, each turned slightly differently, with nailed iron corner straps.", - "witnessesFix": "Recomputed: 6060 tris, two materials with 1344 iron and 2418 timber faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.658×0.524×0.704 m, zmin 0, hygiene 0 including zero coplanar disjoint pairs, three ground runners at z=0, both crate-to-crate seats overlapping, each crate's own footprint 0.588×0.428 m measured in its own frame, yaw spread 0.026 rad and plank spread 2.05 mm across instances, LOD ratios in band, convex collider 230 tris, non-empty glTF. --float-stack exits 18 on the seat; --same-seed exits 20 on per-instance variation.", + "witnessesFix": "Recomputed: 6060 tris, two materials with 1344 iron and 2418 timber faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.658×0.524×0.704 m, zmin 0, hygiene 0 including zero coplanar disjoint pairs, three ground runners at z=0, both crate-to-crate seats overlapping, each crate's own footprint 0.588×0.428 m measured in its own frame, yaw spread 0.026 rad and plank spread 2.05 mm across instances, LOD ratios in band, convex collider 204 tris, non-empty glTF. --float-stack exits 18 on the seat; --same-seed exits 20 on per-instance variation.", "hero": "docs/gallery/assets/crate-stack-hero.webp", "preview": "showcase/crate-stack/preview.webp", "tags": [ @@ -521,7 +521,7 @@ "category": "sports", "teaches": "A procedural in-ground basketball goal on a patch of driveway court — a square gooseneck pole swept in one piece with welded bend webs, its plate sunk and bolted into a two-pour concrete pad with a sealed expansion joint, a braced board in an aluminium frame, a breakaway regulation rim, a knotted twelve-loop net hung on the rim hooks, faded court paint set into the slabs and two pebbled basketballs resting on the concrete — through UVs, bake, LOD, convex collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A basketball goal on a concrete court pad: padded square gooseneck pole, framed backboard, orange rim and white net over a faded green key and arc, two basketballs on the concrete.", - "witnessesFix": "Recomputed: 19564 tris, twelve materials with 2546 steel, 54 board, 32 board-paint, 970 rim, 2784 net, 382 pad, 144 aluminium, 108 concrete, 504 court-line, 12 key, 1024 ball and 2310 seam faces, UVs in 0..1 with zero AABB overlap, outer AABB 5.200×6.600×4.050 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both braces 9.5 mm into the collar and 21.0 mm into the lower rail, all 12 net loops threaded through their hook eyes (worst 7.0 mm from the eye centre against a 9 mm clear radius), rim top 3.050 m over the court, inside diameter 0.457 m, inner edge 0.151 m off the board, tilt 0.000°, both balls radius 0.1194 m bearing 2.0 mm into their slabs, all four anchor bolts 70 mm into the slab and 62 mm over the plate, all 18 paint shells 1.0–2.2 mm proud and 1.4–3.0 mm sunk into their slabs, one connected assembly of 209 shells, LOD ratios in band, convex collider 58 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --short-brace 17; --drop-net 18; --tilt-rim 19; --loose-pad 20; --float-ball 21; --short-bolts 22; --float-paint 23.", + "witnessesFix": "Recomputed: 19564 tris, twelve materials with 2546 steel, 54 board, 32 board-paint, 970 rim, 2784 net, 382 pad, 144 aluminium, 108 concrete, 504 court-line, 12 key, 1024 ball and 2310 seam faces, UVs in 0..1 with zero AABB overlap, outer AABB 5.200×6.600×4.050 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both braces 9.5 mm into the collar and 21.0 mm into the lower rail, all 12 net loops threaded through their hook eyes (worst 7.0 mm from the eye centre against a 9 mm clear radius), rim top 3.050 m over the court, inside diameter 0.457 m, inner edge 0.151 m off the board, tilt 0.000°, both balls radius 0.1194 m bearing 2.0 mm into their slabs, all four anchor bolts 70 mm into the slab and 62 mm over the plate, all 18 paint shells 1.0–2.2 mm proud and 1.4–3.0 mm sunk into their slabs, one connected assembly of 209 shells, LOD ratios in band, convex collider 44 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --short-brace 17; --drop-net 18; --tilt-rim 19; --loose-pad 20; --float-ball 21; --short-bolts 22; --float-paint 23.", "hero": "docs/gallery/assets/basketball-hoop-hero.webp", "preview": "showcase/basketball-hoop/preview.webp", "tags": [ @@ -535,7 +535,7 @@ "category": "nature", "teaches": "A procedural mature Scots pine — a buttressed trunk with plated lower bark bedded in a needle-litter soil disc, eight seeded whorls of heavy limbs seated in the bark, 113 overlapping brushes of long thin needle strands each on its own twig, dead limbs, hanging cones, fallen cones, mossy stones and sticks — through UVs, bake, LOD, trunk collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A mature Scots pine on a dark studio floor: a bare grey-plated bole with dead lower limbs under a broad crown of soft blue-green needle brushes, on a soil disc with mossy stones.", - "witnessesFix": "Recomputed: 45852 tris, six materials with 3026 bark, 36612 needle, 1024 cone, 274 deadwood, 878 soil and 192 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 9.284×7.932×7.659 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 33 limbs and 7 dead members seated in the trunk (base 0.43–0.47 of the bark radius from the axis, band 0.25–0.75), 8 whorls of 3–5 limbs with gaps 0.40–0.45 m (band 0.32–0.60), trunk lean 0.489°, needle mass 0.047 m off the base axis, breast-height diameter 0.3768 m, every one of 113 needle brushes holding its own carrier at least 0.059 m deep (min 0.040), fallen cones and sticks 0.010 m and stones 0.045 m into the soil, roots at least 0.091 m under it, one connected assembly of 266 shells, LOD ratios in band, trunk collider 56 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-branches 17; --lean-crown 19; --bunch-whorls 20; --drop-cones 21; --short-twigs 22; --float-litter 23.", + "witnessesFix": "Recomputed: 45852 tris, six materials with 3026 bark, 36612 needle, 1024 cone, 274 deadwood, 878 soil and 192 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 9.284×7.932×7.659 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 33 limbs and 7 dead members seated in the trunk (base 0.43–0.47 of the bark radius from the axis, band 0.25–0.75), 8 whorls of 3–5 limbs with gaps 0.40–0.45 m (band 0.32–0.60), trunk lean 0.489°, needle mass 0.047 m off the base axis, breast-height diameter 0.3768 m, every one of 113 needle brushes holding its own carrier at least 0.059 m deep (min 0.040), fallen cones and sticks 0.010 m and stones 0.045 m into the soil, roots at least 0.091 m under it, one connected assembly of 266 shells, LOD ratios in band, trunk collider 54 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-branches 17; --lean-crown 19; --bunch-whorls 20; --drop-cones 21; --short-twigs 22; --float-litter 23.", "hero": "docs/gallery/assets/pine-tree-hero.webp", "preview": "showcase/pine-tree/preview.webp", "tags": [ @@ -549,7 +549,7 @@ "category": "household", "teaches": "A procedural balanced-arm desk lamp — stepped cast base, swivel turret, two parallelogram arm sections pinned through knuckle bosses with knurled tension knobs, three extension springs hung on cross bars, a domed enamel shade with a rolled rim, reflector and glowing lamp, a draped flex and a cable to a plug — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A red balanced-arm desk lamp on a dark studio floor: stepped base, parallel-rod arms with chrome springs and knobs, and a domed shade whose white reflector frames a glowing bulb.", - "witnessesFix": "Recomputed: 30110 tris, six materials with 3972 enamel, 9210 steel, 348 bulb, 1508 rubber, 622 reflector and 384 bakelite faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.725×0.361×0.442 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 7 joint pins coaxial with the 23 eyes and bosses they pass through (offset 0.000 mm, band 0.3 mm), all 6 spring loops centred on their bars' axes (band 0.6 mm), mass centre 39.6 mm inside the base footprint (floor 25 mm), base 0.180 m square, arm sections 0.320 and 0.360 m pin to pin, one connected assembly of 78 shells, LOD ratios in band, collider 713 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-pin 17; --unhook-spring 18; --hollow-base 19; --unscrew-bulb 20.", + "witnessesFix": "Recomputed: 30110 tris, six materials with 3972 enamel, 9210 steel, 348 bulb, 1508 rubber, 622 reflector and 384 bakelite faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.725×0.361×0.442 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 7 joint pins coaxial with the 23 eyes and bosses they pass through (offset 0.000 mm, band 0.3 mm), all 6 spring loops centred on their bars' axes (band 0.6 mm), mass centre 39.6 mm inside the base footprint (floor 25 mm), base 0.180 m square, arm sections 0.320 and 0.360 m pin to pin, one connected assembly of 78 shells, LOD ratios in band, collider 472 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-pin 17; --unhook-spring 18; --hollow-base 19; --unscrew-bulb 20.", "hero": "docs/gallery/assets/desk-lamp-hero.webp", "preview": "showcase/desk-lamp/preview.webp", "tags": [ @@ -563,7 +563,7 @@ "category": "vehicles", "teaches": "A procedural camera quadcopter — a two-tone moulded shell with panel lines, grilles, a sensor visor, a battery pack and a GPS puck, four folding arms hinged on pinned clevises with lock rings, slotted brushless motors carrying twisted, swept two-blade propellers, rubber-footed skids and a three-axis gimbal camera — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A white-and-graphite camera drone seen from above on a dark studio floor: four carbon arms with red lock rings, two-blade props on slotted motors, skids, and a gimbal camera under the nose.", - "witnessesFix": "Recomputed: 41048 tris, eight materials with 1720 shell, 2304 carbon, 6472 gunmetal, 524 glass, 760 light, 1296 rubber, 8464 graphite and 2184 anodised faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.692×0.569×0.243 m, zmin 0 and all 4 feet grounded, hygiene 0 including zero coplanar cross-shell pairs, the 4 motor axes on an exact X about the body centre (gaps 90.000°, diagonals 0.52000 m, axes vertical, hubs level), every neighbouring prop disc cleared by 0.0365 m (band 0.028–0.050), mass centre 0.115 m inside the feet's footprint (floor 0.090), wheelbase 0.520 m, one connected assembly of 171 shells, LOD ratios in band, collider 499 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --unlock-arm 17; --long-blades 18; --narrow-skids 19; --drop-lens 20.", + "witnessesFix": "Recomputed: 41048 tris, eight materials with 1720 shell, 2304 carbon, 6472 gunmetal, 524 glass, 760 light, 1296 rubber, 8464 graphite and 2184 anodised faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.692×0.569×0.243 m, zmin 0 and all 4 feet grounded, hygiene 0 including zero coplanar cross-shell pairs, the 4 motor axes on an exact X about the body centre (gaps 90.000°, diagonals 0.52000 m, axes vertical, hubs level), every neighbouring prop disc cleared by 0.0365 m (band 0.028–0.050), mass centre 0.115 m inside the feet's footprint (floor 0.090), wheelbase 0.520 m, one connected assembly of 171 shells, LOD ratios in band, collider 374 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --unlock-arm 17; --long-blades 18; --narrow-skids 19; --drop-lens 20.", "hero": "docs/gallery/assets/quad-drone-hero.webp", "preview": "showcase/quad-drone/preview.webp", "tags": [ @@ -577,7 +577,7 @@ "category": "sports", "teaches": "A procedural freestanding 5 × 2 m youth soccer goal — posts and crossbar in one oval aluminium extrusion with a net channel, mitred and welded at the corners, cast corner brackets, foot connectors and rear hubs, sloped supports and a steel ground frame pinned by staples and spikes, and a sagging diamond-mesh net whose red head rope runs through 53 nylon clips — on a turf patch with a painted goal line, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A white youth soccer goal on a turf patch with a painted goal line, seen at three-quarter: mitred posts and crossbar, sloped rear supports and a sagging diamond-mesh net edged in red rope.", - "witnessesFix": "Recomputed: 34804 tris, ten materials with 2514 paint, 9028 cord, 160 rope, 340 steel, 1464 cast, 3604 nylon, 1000 galvanised, 196 turf, 16 line-paint and 102 soil faces, UVs in 0..1 with zero AABB overlap, outer AABB 6.220×2.640×2.153 m, zmin 0 and all 3 ground bars bedded 2.5 mm into the turf, hygiene 0 including zero coplanar cross-shell pairs, both sloped supports 65 mm into their bracket sockets and 80 mm into their hubs, the head rope through all 53 clip loops (axis offset 0.000 m, ceiling 0.0012), a clear mouth of 5.0002 × 2.0001 m with the posts plumb and the crossbar level, the back panel sagging 0.148 m below its chord (band 0.110–0.180), LOD ratios in band, collider 168 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-bar 16; --short-support 17; --unclip-net 18; --wide-mouth 19; --taut-net 20.", + "witnessesFix": "Recomputed: 34804 tris, ten materials with 2514 paint, 9028 cord, 160 rope, 340 steel, 1464 cast, 3604 nylon, 1000 galvanised, 196 turf, 16 line-paint and 102 soil faces, UVs in 0..1 with zero AABB overlap, outer AABB 6.220×2.640×2.153 m, zmin 0 and all 3 ground bars bedded 2.5 mm into the turf, hygiene 0 including zero coplanar cross-shell pairs, both sloped supports 65 mm into their bracket sockets and 80 mm into their hubs, the head rope through all 53 clip loops (axis offset 0.000 m, ceiling 0.0012), a clear mouth of 5.0002 × 2.0001 m with the posts plumb and the crossbar level, the back panel sagging 0.148 m below its chord (band 0.110–0.180), LOD ratios in band, collider 126 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-bar 16; --short-support 17; --unclip-net 18; --wide-mouth 19; --taut-net 20.", "hero": "docs/gallery/assets/soccer-goal-hero.webp", "preview": "showcase/soccer-goal/preview.webp", "tags": [ @@ -591,7 +591,7 @@ "category": "nature", "teaches": "A procedural fallen forest log — one furrowed lathe along a bowed axis with bark peeled to galleried sapwood, a rotted hollow saw-cut butt, a splintered snapped top, broken branch stubs, moss cushions on its top and shaded side and three tiers of bracket fungi rooted in the bark — settled into a soil mound with toadstools, ferns and fallen leaves, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A mossy fallen log settled into a soil mound: furrowed dark bark peeled in patches, a hollow ringed butt, a splintered top, shelf fungi, toadstools, ferns and fallen leaves.", - "witnessesFix": "Recomputed: 36374 tris, nine materials with 5144 bark, 892 wood, 384 rot, 2400 moss, 2448 bracket, 1296 toadstool, 2494 soil, 2080 litter and 5090 fern faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.119×2.189×1.027 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the log bedded in the soil at 0.889 of its stations (floor 0.75, depth band 0.020–0.090 m), all 12 bracket shelves rooted 0.021–0.029 m into the bark (band 0.008–0.050), the log's mass centre 0.149 m inside the plan hull of its buried vertices (floor 0.06), 0.992 of the moss top area facing up or north (floor 0.85), all 436 ground-cover shells joined to the soil, LOD ratios in band, log collider 215 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --hump-ground 17; --float-fungi 18; --tilt-ground 19; --sunny-moss 20; --float-litter 21.", + "witnessesFix": "Recomputed: 36374 tris, nine materials with 5144 bark, 892 wood, 384 rot, 2400 moss, 2448 bracket, 1296 toadstool, 2494 soil, 2080 litter and 5090 fern faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.119×2.189×1.027 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the log bedded in the soil at 0.889 of its stations (floor 0.75, depth band 0.020–0.090 m), all 12 bracket shelves rooted 0.021–0.029 m into the bark (band 0.008–0.050), the log's mass centre 0.149 m inside the plan hull of its buried vertices (floor 0.06), 0.992 of the moss top area facing up or north (floor 0.85), all 436 ground-cover shells joined to the soil, LOD ratios in band, log collider 142 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --hump-ground 17; --float-fungi 18; --tilt-ground 19; --sunny-moss 20; --float-litter 21.", "hero": "docs/gallery/assets/fallen-log-hero.webp", "preview": "showcase/fallen-log/preview.webp", "tags": [ @@ -605,7 +605,7 @@ "category": "household", "teaches": "A procedural ergonomic task chair on a chair mat at a desk corner — a polished aluminium five-star base with ribbed spokes and five swivelled hooded twin-wheel casters pressed into a smoked polycarbonate mat, a chrome gas lift in a telescoping cover under a synchro-tilt mechanism with tension knob and paddles, a moulded shell cupping a two-tone sculpted cushion with thigh channels, a waterfall front and two piped welts, an elastomeric mesh back on a graphite frame with an S-curved lumbar pad on sliders, a mesh headrest, 4D armrests, and a snake plant in a stone planter — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A graphite mesh-back office chair with a muted-teal two-tone seat, mesh headrest and polished five-star base, on a smoked chair mat beside a snake plant in a stone planter.", - "witnessesFix": "Recomputed: 44440 tris, fourteen materials each above its face floor, UVs in 0..1 with zero AABB overlap, outer AABB 1.635×1.480×1.317 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the mat flat on the floor, all 10 wheels pressed 0.6 mm into the mat, the pot on the floor, spokes and bosses 72° apart (worst 0.00001°), bosses and swivel stems on one 0.305 m circle, stems plumb, coaxial and seated 34 mm, the gas-lift column coaxial with hub and socket (0.0 mm) and seated 52 and 28 mm, seven armrest part pairs mirrored and level within 0.5 mm, seat 0.497 m high, armrests 0.197 m over it, a 0.660 m star, the mass centre 0.215 m inside the caster contact hull (floor 0.12), one connected chair of 89 shells, both lumbar sliders 3.5–5.2 mm off the frame tube, nine leaves rooted 24.5–31.6 mm in the soil, LOD ratios in band, collider 551 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-caster 16; --curl-mat 16; --skew-spoke 17; --offset-column 18; --uneven-arms 19; --loose-wheel 20; --float-lumbar 21; --float-leaves 22.", + "witnessesFix": "Recomputed: 44440 tris, fourteen materials each above its face floor, UVs in 0..1 with zero AABB overlap, outer AABB 1.635×1.480×1.317 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the mat flat on the floor, all 10 wheels pressed 0.6 mm into the mat, the pot on the floor, spokes and bosses 72° apart (worst 0.00001°), bosses and swivel stems on one 0.305 m circle, stems plumb, coaxial and seated 34 mm, the gas-lift column coaxial with hub and socket (0.0 mm) and seated 52 and 28 mm, seven armrest part pairs mirrored and level within 0.5 mm, seat 0.497 m high, armrests 0.197 m over it, a 0.660 m star, the mass centre 0.215 m inside the caster contact hull (floor 0.12), one connected chair of 89 shells, both lumbar sliders 3.5–5.2 mm off the frame tube, nine leaves rooted 24.5–31.6 mm in the soil, LOD ratios in band, collider 374 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-caster 16; --curl-mat 16; --skew-spoke 17; --offset-column 18; --uneven-arms 19; --loose-wheel 20; --float-lumbar 21; --float-leaves 22.", "hero": "docs/gallery/assets/office-chair-hero.webp", "preview": "showcase/office-chair/preview.webp", "tags": [ @@ -619,7 +619,7 @@ "category": "vehicles", "teaches": "A procedural sci-fi hover bike — a sculpted two-tone fuselage with panel seams, gasketed access panels with hex fasteners, a belly service plate, decal plate, hinged charge-port door, heat sink, intake grilles, grab rail and tail light, a stitched pleated saddle, a twin-stanchion fork through sculpted triple clamps with clip-ons, switch pods, pivoted levers and a visored instrument cluster, two glowing exhaust nozzles, two ducted fans with canted stator vanes and handed seven-blade rotors, aerofoil pylons flared into the shrouds with fastener rows and a conduit, and landing gear of twin-plate pressed links and oleo shocks on sixteen pinned joints carrying ski-section skids on wear strips — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A muted-teal hover bike with panelled flanks, a stitched saddle and two ducted fans, standing on pinned landing gear with orange shock absorbers and teal skis on a dark studio floor.", - "witnessesFix": "Recomputed: 45796 tris, ten materials with 3796 livery, 5832 composite, 6008 gunmetal, 1304 rubber, 1760 leather, 532 light, 476 glass, 2788 anodised, 1344 carbon and 1320 chrome faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.234×0.660×1.112 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both wear strips on the floor, both rotor hubs and motor cans on their shroud axes (0.001 mm) with level shrouds 1.600 m apart, blade-tip clearance 9.8 mm on both fans (band 6–14 mm), the fuselage mirror-symmetric to 0.000 mm at 1.033×0.344 m with the saddle at 0.852 m, seven blades per rotor with gaps within 0.0001° of 360/7°, the mass centre 0.252 m inside the skids' contact polygon (floor 0.200), one connected assembly of 322 shells, all 16 pins coaxial with their three bushings (0.000 mm), all 4 shock rods on their barrels' axes with 0.123 m of rod out of the gland (band 0.100–0.140) and 0.065 m engaged (floor 0.045), LOD ratios in band, collider 1890 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-skid 16; --offset-hub 17; --long-blades 18; --odd-hull 19; --skew-blade 20; --narrow-skids 21; --pop-lens 22; --offset-pin 24; --skew-rod 25; --short-rod 25.", + "witnessesFix": "Recomputed: 45796 tris, ten materials with 3796 livery, 5832 composite, 6008 gunmetal, 1304 rubber, 1760 leather, 532 light, 476 glass, 2788 anodised, 1344 carbon and 1320 chrome faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.234×0.660×1.112 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, both wear strips on the floor, both rotor hubs and motor cans on their shroud axes (0.001 mm) with level shrouds 1.600 m apart, blade-tip clearance 9.8 mm on both fans (band 6–14 mm), the fuselage mirror-symmetric to 0.000 mm at 1.033×0.344 m with the saddle at 0.852 m, seven blades per rotor with gaps within 0.0001° of 360/7°, the mass centre 0.252 m inside the skids' contact polygon (floor 0.200), one connected assembly of 322 shells, all 16 pins coaxial with their three bushings (0.000 mm), all 4 shock rods on their barrels' axes with 0.123 m of rod out of the gland (band 0.100–0.140) and 0.065 m engaged (floor 0.045), LOD ratios in band, collider 1246 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-skid 16; --offset-hub 17; --long-blades 18; --odd-hull 19; --skew-blade 20; --narrow-skids 21; --pop-lens 22; --offset-pin 24; --skew-rod 25; --short-rod 25.", "hero": "docs/gallery/assets/hover-bike-hero.webp", "preview": "showcase/hover-bike/preview.webp", "tags": [ @@ -633,7 +633,7 @@ "category": "sports", "teaches": "A procedural home-gym strength set — a half rack of punched, numbered square uprights on bolted feet with rubber pads, side rails on bolted flanges, a pull-up bar, J-hooks with UHMW saddles and spotter arms on pull pins seated in the holes, plate-storage horns, an Olympic barbell with a knurled shaft, collars and sleeves loaded with bumpers (steel hubs, raised rims and numerals) and cast-iron change plates behind coiled spring clips, and two hex dumbbells — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A red home-gym half rack holding an Olympic barbell loaded with blue and yellow bumpers on J-hooks, plates on storage horns and two hex dumbbells, on a dark studio floor.", - "witnessesFix": "Recomputed: 44264 tris, twelve materials with 4758 powder-coat, 3036 bore, 4196 zinc, 3348 chrome, 256 knurl, 1328 rubber, 104 UHMW, 3112 numeral, 864 blue, 576 yellow, 576 green and 2240 cast-iron faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.200×1.636×2.092 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads and four dumbbell heads on the floor, all four pull pins on their holes' axes (0.000 mm) 7.0 mm deep, the bar seated in both J-hook saddles (−0.20 mm) and level (0.0000°) at 2.200 m, 0.450 m bumpers, twelve plates on six sleeves within 0.80 mm of their axes with every gap −0.50 mm (band −0.8 to −0.2 mm), the loaded bar's mass centre 0.002 mm off its midpoint (tol 2 mm), one connected rack plus two dumbbells, LOD ratios in band, collider 598 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --float-bar 18; --hook-high 19; --gap-plate 20; --odd-load 21; --loose-horn 22.", + "witnessesFix": "Recomputed: 44264 tris, twelve materials with 4758 powder-coat, 3036 bore, 4196 zinc, 3348 chrome, 256 knurl, 1328 rubber, 104 UHMW, 3112 numeral, 864 blue, 576 yellow, 576 green and 2240 cast-iron faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.200×1.636×2.092 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads and four dumbbell heads on the floor, all four pull pins on their holes' axes (0.000 mm) 7.0 mm deep, the bar seated in both J-hook saddles (−0.20 mm) and level (0.0000°) at 2.200 m, 0.450 m bumpers, twelve plates on six sleeves within 0.80 mm of their axes with every gap −0.50 mm (band −0.8 to −0.2 mm), the loaded bar's mass centre 0.002 mm off its midpoint (tol 2 mm), one connected rack plus two dumbbells, LOD ratios in band, collider 472 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --float-bar 18; --hook-high 19; --gap-plate 20; --odd-load 21; --loose-horn 22.", "hero": "docs/gallery/assets/weight-rack-hero.webp", "preview": "showcase/weight-rack/preview.webp", "tags": [ @@ -661,7 +661,7 @@ "category": "household", "teaches": "A procedural 1950s oscillating pedestal fan — a hollow two-tier cast base on a rubber gasket with a rotary speed switch and badge, a telescoping enamel and chrome column with a knurled height-lock collar, a strap yoke with a knurled tilt knob, a slotted motor housing with a trim band and an oscillation knob, a two-half wire guard of radial spokes and concentric rings welded to clipped rim rings with a centre badge, four swept brass blades on a hub with a hex spinner nut, and a cord to a plug — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A sage-green 1950s pedestal fan, head turned on a tilt yoke: chrome wire guard over four brass blades, telescoping column, round cast base with a speed knob, cord to a plug.", - "witnessesFix": "Recomputed: 41460 tris, six materials with 4732 enamel, 13960 chrome, 584 brass, 1216 rubber, 810 bakelite and 440 badge faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.761×0.704×1.229 m, zmin 0 with the gasket on the floor, hygiene 0 including zero coplanar cross-shell pairs, hub, spinner, shaft, badge, rear mount and motor housing on the axis the rim rings define (worst 0.000001 m, cap 0.0005), all 48 spokes ending inside their rim rings (worst 0.0007 m from the ring's centreline, cap 0.0026) and each of 7 rings crossing all 24 spokes of its half, both column tubes plumb (0.000°, cap 0.2°) and on the base's axis (0.0000 m, cap 0.001), guard 0.452 m and base 0.400 m across, blade tips 0.0195 m inside the rim rings (band 0.012–0.030) and 0.0140 m from the nearest wire (floor 0.006), four blades 90° apart within 0.0002° (cap 0.3°), a 28.4 kg fan that stands on a 19.06° incline before it tips (floor 16°), one connected assembly of 109 shells, LOD ratios in band, collider 1997 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-hub 17; --short-spoke 18; --lean-column 19; --long-blades 20; --skew-blade 21; --hollow-base 22; --loose-spinner 23.", + "witnessesFix": "Recomputed: 41460 tris, six materials with 4732 enamel, 13960 chrome, 584 brass, 1216 rubber, 810 bakelite and 440 badge faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.761×0.704×1.229 m, zmin 0 with the gasket on the floor, hygiene 0 including zero coplanar cross-shell pairs, hub, spinner, shaft, badge, rear mount and motor housing on the axis the rim rings define (worst 0.000001 m, cap 0.0005), all 48 spokes ending inside their rim rings (worst 0.0007 m from the ring's centreline, cap 0.0026) and each of 7 rings crossing all 24 spokes of its half, both column tubes plumb (0.000°, cap 0.2°) and on the base's axis (0.0000 m, cap 0.001), guard 0.452 m and base 0.400 m across, blade tips 0.0195 m inside the rim rings (band 0.012–0.030) and 0.0140 m from the nearest wire (floor 0.006), four blades 90° apart within 0.0002° (cap 0.3°), a 28.4 kg fan that stands on a 19.06° incline before it tips (floor 16°), one connected assembly of 109 shells, LOD ratios in band, collider 1560 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --offset-hub 17; --short-spoke 18; --lean-column 19; --long-blades 20; --skew-blade 21; --hollow-base 22; --loose-spinner 23.", "hero": "docs/gallery/assets/floor-fan-hero.webp", "preview": "showcase/floor-fan/preview.webp", "tags": [ @@ -675,7 +675,7 @@ "category": "vehicles", "teaches": "A procedural 1960s Italian step-through motor scooter — a pressed-steel tail lofted from superellipse sections with two bulbous side cowls (pressed louvres on the engine side, chrome belt trims), a floorboard with rubber runner strips and chrome edge trims pressed up into the tail and into a leg shield convex in plan, arched up into the headset and rimmed in a rolled chrome trim, with a horn cast and grille, a single-sided front end (a column raked 26 degrees, crown, fork leg, trailing link and coil spring) under a crested mudguard, a headset carrying the headlamp, speedometer, ribbed grips, levers and two mirrors, a two-tone dual saddle with piping and a grab strap, 10-inch split rims with five nuts and finned drums in block-tread tyres, an alloy engine case with a finned cylinder, header, silencer and kick-start, a luggage rack, tail lamp and plate, and a centre stand with rubber feet — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A pastel sea-green 1960s scooter on its centre stand: cream and oxblood saddle, louvred side cowl, curved chrome-rimmed leg shield, split-rim front wheel, black silencer.", - "witnessesFix": "Recomputed: 45060 tris, nine materials with 7156 paint, 4638 chrome, 3608 rubber, 1147 oxblood vinyl, 297 cream vinyl, 550 glass, 188 tail-lens, 4020 alloy and 2292 black-enamel faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.790×0.730×1.244 m, zmin 0 with both tyres and both stand feet on the floor, hygiene 0 including zero coplanar cross-shell pairs, both axles level and parallel (camber 0.000°, toe 0.000°, cap 0.3°), the steering column raked 26.000° meeting the ground 0.0750 m ahead of the front contact (band 0.055–0.090) and on its line, the body mirror-symmetric to 0.000 mm (cap 0.5, engine side excluded by construction), tail 0.862 m and saddle top 0.807 m, a 1.20000 m wheelbase (±0.004), a 101.6 kg scooter whose mass centre stands 0.1284 m inside its tyres-and-stand support polygon (floor 0.080), one connected assembly of 105 shells, the leg shield's foot 0.0320 m deep in the floorboard (band 0.020–0.040), LOD ratios in band, collider 1678 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --toe-wheel 17; --steep-head 18; --odd-body 19; --short-wheelbase 20; --narrow-stand 21; --pop-speedo 22; --lift-shield 23.", + "witnessesFix": "Recomputed: 45060 tris, nine materials with 7156 paint, 4638 chrome, 3608 rubber, 1147 oxblood vinyl, 297 cream vinyl, 550 glass, 188 tail-lens, 4020 alloy and 2292 black-enamel faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.790×0.730×1.244 m, zmin 0 with both tyres and both stand feet on the floor, hygiene 0 including zero coplanar cross-shell pairs, both axles level and parallel (camber 0.000°, toe 0.000°, cap 0.3°), the steering column raked 26.000° meeting the ground 0.0750 m ahead of the front contact (band 0.055–0.090) and on its line, the body mirror-symmetric to 0.000 mm (cap 0.5, engine side excluded by construction), tail 0.862 m and saddle top 0.807 m, a 1.20000 m wheelbase (±0.004), a 101.6 kg scooter whose mass centre stands 0.1284 m inside its tyres-and-stand support polygon (floor 0.080), one connected assembly of 105 shells, the leg shield's foot 0.0320 m deep in the floorboard (band 0.020–0.040), LOD ratios in band, collider 1132 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --toe-wheel 17; --steep-head 18; --odd-body 19; --short-wheelbase 20; --narrow-stand 21; --pop-speedo 22; --lift-shield 23.", "hero": "docs/gallery/assets/motor-scooter-hero.webp", "preview": "showcase/motor-scooter/preview.webp", "tags": [ @@ -689,7 +689,7 @@ "category": "sports", "teaches": "A procedural pin deck end of a ten-pin bowling lane — one laminated slab of 39 maple boards, 41.5 in across, each board's top edges chamfered into a V seam and crossed by the joint to a dark pin deck, ten pin spots inlaid on a 12 in equilateral triangle 34 3/16 in from the pit edge, a chevron of targeting arrows and a row of range dots, channel-profile gutters, cappings, kickbacks with sloped noses under mitred aluminium caps and phenolic kick plates, a steel pit-edge bullnose and five sleepers; ten pins lathe-turned from the regulation profile table (15 in tall, 4.766 in belly) with two red neck stripes and a crown band of red teeth; and an 8.5 in marbled resin ball drilled by an exact Boolean with a countersunk thumb hole and two parallel finger holes — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "Ten white pins with red neck stripes racked on a dark pin deck at the end of a glossy maple lane with arrows and dots, a marbled violet ball resting on the approach.", - "witnessesFix": "Recomputed: 37078 tris, eleven materials with 358 maple, 358 pin-deck, 13720 pin-white, 1280 pin-red, 1649 ball, 562 bore, 254 phenolic, 142 laminate, 176 aluminium, 1197 inlay and 380 sleeper faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.640×2.301×0.523 m read off the vertices, zmin 0 with all five sleepers on the floor, hygiene 0 including zero coplanar cross-shell pairs, every pin's base centre 0.000 mm off its spot (tol 0.5) and 0.6 mm below the deck face (band 0.3–1.0), every pin plumb (0.000°), 0.3810 m tall with a 0.12106 m belly, its radius on all 15 profile-table stations to 0.000 mm (tol 0.2), the ten spots on an exact 12 in lattice (18 edges, rows 1-2-3-4, row pitch 0.26396 m, head spot on the centre line), the ball 0.21590 m across resting 0.60 mm into the lane (band 0.3–0.9), its thumb hole 63.5 mm and finger holes 50.8 mm deep with 25.40 and 20.32 mm bores, a 112.2 mm span and a 26.67 mm bridge, 39 boards flush and straight to 0.000 mm, one connected assembly of 55 shells, LOD ratios in band, collider 277 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sleeper 16; --offset-pin 17; --float-pin 18; --lean-pin 19; --wide-rack 20; --fat-neck 21; --float-ball 22; --shallow-holes 23; --proud-board 24; --lift-arrows 25.", + "witnessesFix": "Recomputed: 37078 tris, eleven materials with 358 maple, 358 pin-deck, 13720 pin-white, 1280 pin-red, 1649 ball, 562 bore, 254 phenolic, 142 laminate, 176 aluminium, 1197 inlay and 380 sleeper faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.640×2.301×0.523 m read off the vertices, zmin 0 with all five sleepers on the floor, hygiene 0 including zero coplanar cross-shell pairs, every pin's base centre 0.000 mm off its spot (tol 0.5) and 0.6 mm below the deck face (band 0.3–1.0), every pin plumb (0.000°), 0.3810 m tall with a 0.12106 m belly, its radius on all 15 profile-table stations to 0.000 mm (tol 0.2), the ten spots on an exact 12 in lattice (18 edges, rows 1-2-3-4, row pitch 0.26396 m, head spot on the centre line), the ball 0.21590 m across resting 0.60 mm into the lane (band 0.3–0.9), its thumb hole 63.5 mm and finger holes 50.8 mm deep with 25.40 and 20.32 mm bores, a 112.2 mm span and a 26.67 mm bridge, 39 boards flush and straight to 0.000 mm, one connected assembly of 55 shells, LOD ratios in band, collider 200 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sleeper 16; --offset-pin 17; --float-pin 18; --lean-pin 19; --wide-rack 20; --fat-neck 21; --float-ball 22; --shallow-holes 23; --proud-board 24; --lift-arrows 25.", "hero": "docs/gallery/assets/bowling-pins-hero.webp", "preview": "showcase/bowling-pins/preview.webp", "tags": [ @@ -717,7 +717,7 @@ "category": "household", "teaches": "A procedural retro tilt-head kitchen stand mixer on a honed limestone countertop section — a cast enamel body lofted from superellipse sections (a pebble-shaped base foot on four rubber feet, a neck leaning back as it rises, a streamlined motor head) hinged at the back on a pin through two neck knuckles; a chrome trim band wrapped on the head's own sections, a blank badge, a speed lever and a tilt-lock lever; an attachment hub with its cap and thumb screw on the nose; a planetary socket carrying a flat beater whose frame follows the bowl's wall into a 4.5 L brushed stainless bowl with a rolled rim and strap handle, clamped under three bayonet lugs; a cord to a plug; and a balloon whisk, a measuring cup and two brown eggs in a glazed dish — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A slate-blue retro stand mixer with a chrome band and a brushed steel bowl on a stone countertop, beside a wire whisk, a steel measuring cup and two brown eggs in a terracotta dish.", - "witnessesFix": "Recomputed: 29620 tris, eight materials with 4328 enamel, 2626 chrome, 5560 stainless, 91 stone, 1174 rubber, 812 ceramic, 760 egg and 562 beater faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.470×0.570×0.389 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four feet sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the hinge pin 0.000000 m off the axis of both neck knuckles and the head knuckle (cap 0.0003) and spanning all three, the bowl seated 0.00050 m into its plate (band 0.0002–0.0010) and 0.000000 m off its axis (cap 0.0003) with all three lugs engaged, the mixer 0.35899 m tall (0.360 ± 0.006) and the bowl holding 4.5465 L to the brim (4.5 ± 0.35), the beater shaft 0.000000 m off the planetary socket's axis (cap 0.0003) and clearing the bowl's wall by 0.00245 m and its floor by 0.00250 m (band 0.0012–0.0040), the mass centre 0.0658 m inside the feet's support polygon (floor 0.040) at 13.94 kg, one connected assembly of 52 shells, LOD ratios in band, collider 2329 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --offset-bowl 18; --shallow-bowl 19; --offset-beater 20; --long-beater 21; --bunch-feet 22; --loose-cap 23.", + "witnessesFix": "Recomputed: 29620 tris, eight materials with 4328 enamel, 2626 chrome, 5560 stainless, 91 stone, 1174 rubber, 812 ceramic, 760 egg and 562 beater faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.470×0.570×0.389 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four feet sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the hinge pin 0.000000 m off the axis of both neck knuckles and the head knuckle (cap 0.0003) and spanning all three, the bowl seated 0.00050 m into its plate (band 0.0002–0.0010) and 0.000000 m off its axis (cap 0.0003) with all three lugs engaged, the mixer 0.35899 m tall (0.360 ± 0.006) and the bowl holding 4.5465 L to the brim (4.5 ± 0.35), the beater shaft 0.000000 m off the planetary socket's axis (cap 0.0003) and clearing the bowl's wall by 0.00245 m and its floor by 0.00250 m (band 0.0012–0.0040), the mass centre 0.0658 m inside the feet's support polygon (floor 0.040) at 13.94 kg, one connected assembly of 52 shells, LOD ratios in band, collider 1308 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --offset-bowl 18; --shallow-bowl 19; --offset-beater 20; --long-beater 21; --bunch-feet 22; --loose-cap 23.", "hero": "docs/gallery/assets/stand-mixer-hero.webp", "preview": "showcase/stand-mixer/preview.webp", "tags": [ @@ -731,7 +731,7 @@ "category": "vehicles", "teaches": "A procedural sci-fi industrial cargo loader, a bipedal powered-lift exoframe standing in a crouch and holding a corrugated cargo crate off the ground on two forged L-tines — broad flat feet with rubber soles, grip cleats and toe bumpers; hydraulic legs of lofted box-section shins and thighs pinned at the ankle, knee and hip; arms hung from shoulder yokes, each joint a clevis of two lug bushings straddling an eye bushing with a chrome pin through all three; eight rams (hip and knee, shoulder and elbow), each a collared steel cylinder with a chromed rod, a pinned clevis bracket at each end and a hose from its port; fork carriages with hazard-striped faces; an open roll-cage cockpit with a bucket seat, four-point harness, joystick consoles, amber beacon and work lights; a power pack with a slatted grille, cooling fins, hazard bands, exhaust stacks and cable looms — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A yellow bipedal cargo loader in a crouch, hydraulic rams on its legs and arms, an open roll-cage cockpit with an amber beacon, holding a blue-grey crate on its forks.", - "witnessesFix": "Recomputed: 44600 tris, ten materials with 2736 paint, 608 hazard, 3128 chrome, 15328 steel, 2740 rubber, 480 seat-vinyl, 640 harness, 256 beacon, 152 work-light and 516 crate-paint faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.827×1.689×2.974 m, zmin 0 with both soles on the floor, hygiene 0 including zero coplanar cross-shell pairs, all 28 clevis pins 0.000 mm off the axis of each of their three bushings and 0.000° to them (caps 0.3 mm, 0.3°), the crate's base biting both tines by 0.0020 m at every station along a 0.74 m run (band 0.0010–0.0040, run ≥ 0.50), both soles flat and level to 0.000 mm and 0.000° (caps 0.5 mm, 0.2°), all 8 ram rods 0.000 mm off their cylinders' axes and 0.0096° to them (caps 0.3 mm, 0.3°) with 0.1591–0.2858 m of rod exposed (band 0.080–0.340) and 0.060 m engaged (floor 0.040), a 2380.6 kg loader and crate whose mass centre stands 0.4473 m inside the soles' support polygon (floor 0.200), one connected assembly of 414 shells, LOD ratios in band, collider 710 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --lift-crate 18; --tilt-sole 19; --skew-rod 20; --bottom-ram 21; --overload 22; --loose-light 23.", + "witnessesFix": "Recomputed: 44600 tris, ten materials with 2736 paint, 608 hazard, 3128 chrome, 15328 steel, 2740 rubber, 480 seat-vinyl, 640 harness, 256 beacon, 152 work-light and 516 crate-paint faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.827×1.689×2.974 m, zmin 0 with both soles on the floor, hygiene 0 including zero coplanar cross-shell pairs, all 28 clevis pins 0.000 mm off the axis of each of their three bushings and 0.000° to them (caps 0.3 mm, 0.3°), the crate's base biting both tines by 0.0020 m at every station along a 0.74 m run (band 0.0010–0.0040, run ≥ 0.50), both soles flat and level to 0.000 mm and 0.000° (caps 0.5 mm, 0.2°), all 8 ram rods 0.000 mm off their cylinders' axes and 0.0096° to them (caps 0.3 mm, 0.3°) with 0.1591–0.2858 m of rod exposed (band 0.080–0.340) and 0.060 m engaged (floor 0.040), a 2380.6 kg loader and crate whose mass centre stands 0.4473 m inside the soles' support polygon (floor 0.200), one connected assembly of 414 shells, LOD ratios in band, collider 532 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --lift-crate 18; --tilt-sole 19; --skew-rod 20; --bottom-ram 21; --overload 22; --loose-light 23.", "hero": "docs/gallery/assets/cargo-loader-hero.webp", "preview": "showcase/cargo-loader/preview.webp", "tags": [ @@ -745,7 +745,7 @@ "category": "sports", "teaches": "A procedural archery range target on a turf patch — a 1.10 m compressed-straw boss coiled from rope courses that show on its back and round its edge, bound with doubled jute twine drawn tight over the crests; an 80 cm ten-zone World Archery face in aged inks with ring lines, an X ring and a printed X, held by four target pins; a timber easel leaning it back 12° on toe skids with knee braces, a ledge with a stop lip on a bolted rail and gussets, a numbered butt board, a strap hinge pinned to a rear leg in a steel ferrule and foot, and a splay chain between eye bolts; five carbon arrows in the face with cresting, nocks and three vanes, one glancing into the straw edge, one snapped with its fletched half on the grass, and a leather quiver of arrows lying among grass tufts — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A straw archery boss with a gold, red, blue, black and white face and five arrows, leaning on a timber easel numbered 12, a quiver on the grass patch below.", - "witnessesFix": "Recomputed: 42908 tris, sixteen materials with 4732 straw, 1856 twine, 1086 pine, 6288 steel, 522 white, 816 black, 128 blue, 128 red, 254 gold, 326 carbon, 500 vane, 300 cock-vane, 1076 nock, 5230 grass, 286 soil and 768 leather faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.007×2.689×2.054 m, zmin 0 with both skids and the rear tread bedded 2.0 mm into the turf (band 1–4 mm), hygiene 0 including zero coplanar cross-shell pairs, the hinge pin 0.000 mm off the axis of all three knuckles (tol 0.3 mm), the boss seated 2.5 mm into its ledge and leaning 2.0 mm on both legs (bands 1–4 mm), the gold centre 1.3000 m above the turf (World Archery 1.30 ± 0.05) on a 1.100 × 0.280 m boss and a 0.800 m face tilted 12.000° (band 10–15°), seven points buried 0.119–0.149 m in the straw (band 0.08–0.20) with straw left ahead, every vane at least 0.419 m clear of the boss (min 0.25), ten fletched shafts with three vanes each within 0.002° of 120° (tol 1°), all ten ring lines on the 4 cm scoring table (0.000 mm off, tol 0.5 mm) in the right inks, a 73.85 kg stand and boss whose mass centre is 0.349 m inside its supports with a forward tip angle of 27.83° (min 20°), one connected assembly of 722 shells, LOD ratios in band, collider 1083 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --lift-boss 18; --high-boss 19; --shallow-arrow 20; --short-arrow 21; --skew-vane 22; --wide-gold 23; --short-skids 24; --loose-pin 25.", + "witnessesFix": "Recomputed: 42908 tris, sixteen materials with 4732 straw, 1856 twine, 1086 pine, 6288 steel, 522 white, 816 black, 128 blue, 128 red, 254 gold, 326 carbon, 500 vane, 300 cock-vane, 1076 nock, 5230 grass, 286 soil and 768 leather faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.007×2.689×2.054 m, zmin 0 with both skids and the rear tread bedded 2.0 mm into the turf (band 1–4 mm), hygiene 0 including zero coplanar cross-shell pairs, the hinge pin 0.000 mm off the axis of all three knuckles (tol 0.3 mm), the boss seated 2.5 mm into its ledge and leaning 2.0 mm on both legs (bands 1–4 mm), the gold centre 1.3000 m above the turf (World Archery 1.30 ± 0.05) on a 1.100 × 0.280 m boss and a 0.800 m face tilted 12.000° (band 10–15°), seven points buried 0.119–0.149 m in the straw (band 0.08–0.20) with straw left ahead, every vane at least 0.419 m clear of the boss (min 0.25), ten fletched shafts with three vanes each within 0.002° of 120° (tol 1°), all ten ring lines on the 4 cm scoring table (0.000 mm off, tol 0.5 mm) in the right inks, a 73.85 kg stand and boss whose mass centre is 0.349 m inside its supports with a forward tip angle of 27.83° (min 20°), one connected assembly of 722 shells, LOD ratios in band, collider 634 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-hinge 17; --lift-boss 18; --high-boss 19; --shallow-arrow 20; --short-arrow 21; --skew-vane 22; --wide-gold 23; --short-skids 24; --loose-pin 25.", "hero": "docs/gallery/assets/archery-target-hero.webp", "preview": "showcase/archery-target/preview.webp", "tags": [ @@ -773,7 +773,7 @@ "category": "household", "teaches": "A procedural prosumer E61 semi-automatic espresso machine on a honed limestone countertop section — a black chassis behind a brushed stainless front panel, two side panels folded round the front and back edges, each one sheet with louvred vent slots cut through it, a warmer tray with a rail bent from one bar and four upturned cups, on adjustable feet; the chromed E61 group with its neck, thermosiphon pipe, gasket, mushroom cap and a lever pinned through two bosses; a spouted portafilter with a walnut handle locked against the gasket; steam and hot-water valves with fluted bakelite knobs and wands on ball joints; twin gauges with printed dials in chrome bezels; a toggle and pilot lamp; a drip tray whose slotted grate carries a shot cup of espresso; and a knock box, tamper and milk pitcher — with a studio carried in the metals' material so stainless reads as metal on a dark stage, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A brushed stainless E61 espresso machine with twin gauges, a chrome group head and a walnut-handled portafilter over a shot cup, cups on its warmer tray, beside a tamper, milk pitcher and knock box.", - "witnessesFix": "Recomputed: 43636 tris, fourteen materials with 4788 stainless, 7284 chrome, 948 bakelite, 632 wood, 5800 ceramic, 1244 rubber, 632 glass, 1642 dial, 64 ink, 36 needle, 91 stone, 26 paint, 452 coffee and 116 lamp faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.670×0.655×0.4755 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the lever pin 0.000000 m off the axis of both bosses and the hub (cap 0.0003) and spanning all three, all five cups seated 0.00020–0.00074 m on the warmer tray or the grate (band 0.0001–0.0009), the body 0.30000 m wide (0.300 ± 0.004) and its warmer tray 0.39070 m above the counter (0.3907 ± 0.004), the portafilter and gasket 0.000000 m off the group's axis (cap 0.0003) and the rim pressed 0.00040 m into the gasket (band 0.0001–0.0008), both gauge glasses 0.0034 m behind their bezels' lips (band 0.0015–0.0050), the drip tray 0.0250 m inside the side panels (floor 0.010) and tucked 0.0170 m behind the front panel (floor 0.005), the mass centre 0.1064 m inside the feet's support polygon (floor 0.060) at 39.83 kg, one connected assembly of 94 shells, LOD ratios in band, collider 447 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --sink-cup 18; --narrow-body 19; --offset-pf 20; --drop-pf 21; --proud-gauge 22; --shift-tray 23; --bunch-feet 24; --loose-knob 25.", + "witnessesFix": "Recomputed: 43636 tris, fourteen materials with 4788 stainless, 7284 chrome, 948 bakelite, 632 wood, 5800 ceramic, 1244 rubber, 632 glass, 1642 dial, 64 ink, 36 needle, 91 stone, 26 paint, 452 coffee and 116 lamp faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.670×0.655×0.4755 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all four pads sunk 0.00025–0.00070 m into the counter (band 0.0001–0.0008), the lever pin 0.000000 m off the axis of both bosses and the hub (cap 0.0003) and spanning all three, all five cups seated 0.00020–0.00074 m on the warmer tray or the grate (band 0.0001–0.0009), the body 0.30000 m wide (0.300 ± 0.004) and its warmer tray 0.39070 m above the counter (0.3907 ± 0.004), the portafilter and gasket 0.000000 m off the group's axis (cap 0.0003) and the rim pressed 0.00040 m into the gasket (band 0.0001–0.0008), both gauge glasses 0.0034 m behind their bezels' lips (band 0.0015–0.0050), the drip tray 0.0250 m inside the side panels (floor 0.010) and tucked 0.0170 m behind the front panel (floor 0.005), the mass centre 0.1064 m inside the feet's support polygon (floor 0.060) at 39.83 kg, one connected assembly of 94 shells, LOD ratios in band, collider 346 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --offset-pin 17; --sink-cup 18; --narrow-body 19; --offset-pf 20; --drop-pf 21; --proud-gauge 22; --shift-tray 23; --bunch-feet 24; --loose-knob 25.", "hero": "docs/gallery/assets/espresso-machine-hero.webp", "preview": "showcase/espresso-machine/preview.webp", "tags": [ @@ -787,7 +787,7 @@ "category": "vehicles", "teaches": "A procedural 1970s lugged-steel road bicycle standing on its side kickstand — a 56 cm diamond frame of round tubes joined in chromed, spear-pointed lugs at the head tube, seat cluster and bottom bracket, tapered stays in chromed tips, a fork with a chromed sloping crown and socks; two 700c wheels, each a box-section rim with 36 spokes laced three-cross from both flanges of a small-flange hub to nipples through the rim, quick-release skewers and tan-wall tyres with a black file-tread crown; a 52/42 crankset with quill pedals, toe clips and straps, a six-speed freewheel, a roller chain of 112 individual links solved round the ring, the cog and both jockey wheels, front and rear derailleurs, down-tube shifters, side-pull calipers with pads a millimetre off the rims, levers under gum hoods on cotton-taped drop bars, a quill stem, a leather saddle on rails and a bottle in a bolted wire cage — leaned 5° onto its stand, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A deep red lugged-steel road bicycle leaning on its kickstand: chromed lugs and fork socks, tan-wall 700c wheels, a honey leather saddle, cream-taped drop bars and a chain over a double crankset.", - "witnessesFix": "Recomputed: 46092 tris, ten materials with 1048 paint, 6438 chrome, 6950 alloy, 8239 steel, 540 tread, 952 gum, 356 leather, 1080 tape, 1810 black and 176 bottle faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.670×0.438×0.997 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs across 112 chain links, both tyres and the stand foot on the ground, both hubs 0.000000 m off their dropout eyes (cap 0.0005), every one of 72 spokes 3.00 mm deep in its flange (band 2.0–4.0 mm) and 4.50 mm inside its nipple on its axis, both rims 0.000 mm off the frame's plane (cap 1.0 mm), seat tube 0.5800 m, wheelbase 0.99982 m, trail 0.05536 m (band 0.045–0.065), lacing 36/36 with 18 per flange, pitch 0.000° off and every spoke three-cross (60.000°), 30 rollers seated on the ring and 10 on the cog 1.20–3.40 mm above the root (band 0.5–6.5 mm), every roller and the cog 0.000 mm off the chain line (cap 1.0 mm), the mass centre 0.0393 m inside the support triangle (floor 0.020) at 11.80 kg, one connected assembly of 685 shells, LOD ratios in band, collider 880 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --slip-wheel 17; --short-spoke 18; --dish-wheel 19; --steep-head 20; --bunch-spokes 21; --lift-chain 22; --shift-rollers 23; --tuck-stand 24; --pop-bottle 25.", + "witnessesFix": "Recomputed: 46092 tris, ten materials with 1048 paint, 6438 chrome, 6950 alloy, 8239 steel, 540 tread, 952 gum, 356 leather, 1080 tape, 1810 black and 176 bottle faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.670×0.438×0.997 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs across 112 chain links, both tyres and the stand foot on the ground, both hubs 0.000000 m off their dropout eyes (cap 0.0005), every one of 72 spokes 3.00 mm deep in its flange (band 2.0–4.0 mm) and 4.50 mm inside its nipple on its axis, both rims 0.000 mm off the frame's plane (cap 1.0 mm), seat tube 0.5800 m, wheelbase 0.99982 m, trail 0.05536 m (band 0.045–0.065), lacing 36/36 with 18 per flange, pitch 0.000° off and every spoke three-cross (60.000°), 30 rollers seated on the ring and 10 on the cog 1.20–3.40 mm above the root (band 0.5–6.5 mm), every roller and the cog 0.000 mm off the chain line (cap 1.0 mm), the mass centre 0.0393 m inside the support triangle (floor 0.020) at 11.80 kg, one connected assembly of 685 shells, LOD ratios in band, collider 574 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --slip-wheel 17; --short-spoke 18; --dish-wheel 19; --steep-head 20; --bunch-spokes 21; --lift-chain 22; --shift-rollers 23; --tuck-stand 24; --pop-bottle 25.", "hero": "docs/gallery/assets/road-bicycle-hero.webp", "preview": "showcase/road-bicycle/preview.webp", "tags": [ @@ -801,7 +801,7 @@ "category": "sports", "teaches": "A procedural backyard quarter-pipe, 1.2 m high on a 1.8 m transition and 2.44 m wide, with a skateboard on its deck — five plywood transition templates (curved bands with a solid toe and an arm under the deck) on 2x4 sills with studs and a back post sistered to their faces, nine 2x4 stringers under a two-layer 12 mm plywood skin whose joints are offset between layers and land on stringers, 143 screws in rows over the stringers, a 60 mm steel coping pipe standing proud of the transition on five welded, bolted tabs, a steel kicker plate ground to a lip at the toe on a timber toe block, a worn stencilled roundel and wheel marks on the riding face; the skateboard a seven-ply maple deck with concave and kicktails under grip tape, two trucks (baseplate, raked kingpin, bushings, hanger, pivot arm, axle) and four urethane wheels on bearings — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A plywood quarter-pipe with a steel coping and kicker plate, screw rows, sheet seams and a red stencilled roundel, its open side showing studs and sills, a skateboard on the deck.", - "witnessesFix": "Recomputed: 31164 tris, nine materials with 3268 plywood, 1479 framing, 1086 steel, 7304 hardware, 1100 maple, 900 grip, 1536 urethane, 892 alloy and 464 bushing faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.529×2.440×1.339 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all five sills, the toe block and the plate on the floor, the riding face a circle of radius 1.80000 m (98 samples, 0.000 mm deviation, cap 1.0 mm) tangent to the ground, deck at 1.20000 m, five templates each 2.00 mm into its sill (band 1–6 mm) and 0.90–0.91 mm into the skin (band 0.3–2.5 mm), the coping straight and square to the width with a 5.00 mm reveal (band 2–8 mm) and 3.86 mm above the deck, the kicker plate 0.01 mm off flush (cap 0.6 mm) with a 0.80 mm toe, top seams at 0.84 and 1.84 m and the inner at 1.24 m (stagger 0.400 m, floor 0.30) each 43.9 mm inside its stringer, 143 screws 17.4 mm inside a stringer and 17.0 mm inside a sheet, four wheels 0.50 mm into the deck (band 0.2–1.2 mm), every wheel 0.000 mm off its axle, one connected assembly of 309 shells, LOD ratios in band, collider 350 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sill 16; --short-rib 17; --small-wheel 18; --sag-skin 19; --sink-coping 20; --proud-plate 21; --stack-seams 22; --miss-screws 23; --skew-wheel 24; --lift-grip 25.", + "witnessesFix": "Recomputed: 31164 tris, nine materials with 3268 plywood, 1479 framing, 1086 steel, 7304 hardware, 1100 maple, 900 grip, 1536 urethane, 892 alloy and 464 bushing faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.529×2.440×1.339 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all five sills, the toe block and the plate on the floor, the riding face a circle of radius 1.80000 m (98 samples, 0.000 mm deviation, cap 1.0 mm) tangent to the ground, deck at 1.20000 m, five templates each 2.00 mm into its sill (band 1–6 mm) and 0.90–0.91 mm into the skin (band 0.3–2.5 mm), the coping straight and square to the width with a 5.00 mm reveal (band 2–8 mm) and 3.86 mm above the deck, the kicker plate 0.01 mm off flush (cap 0.6 mm) with a 0.80 mm toe, top seams at 0.84 and 1.84 m and the inner at 1.24 m (stagger 0.400 m, floor 0.30) each 43.9 mm inside its stringer, 143 screws 17.4 mm inside a stringer and 17.0 mm inside a sheet, four wheels 0.50 mm into the deck (band 0.2–1.2 mm), every wheel 0.000 mm off its axle, one connected assembly of 309 shells, LOD ratios in band, collider 306 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-sill 16; --short-rib 17; --small-wheel 18; --sag-skin 19; --sink-coping 20; --proud-plate 21; --stack-seams 22; --miss-screws 23; --skew-wheel 24; --lift-grip 25.", "hero": "docs/gallery/assets/skate-ramp-hero.webp", "preview": "showcase/skate-ramp/preview.webp", "tags": [ @@ -829,7 +829,7 @@ "category": "household", "teaches": "A procedural reading corner on a fringed wool rug — a Queen Anne / Chesterfield wingback armchair in oxblood leather whose tall reclined back is deep-button tufted, thirteen buttons on a diamond lattice each seated in a funnelled dimple with the leather puffed into pillows between them and folded into sharp pleats along every line that joins two buttons; two wings sweeping forward from the back into rolled arms, each arm one lofted scroll section with an English roll tucked under on the outside, a crowned front, a piped welt round the front seam and a row of brass nailheads following the scroll; a nailed front rail, a loose cushion with a crowned top and piped welts on both seams, cabriole front legs on pad feet and square rear legs splayed into brass ferrules; beside it a walnut tripod side table with a brass reading lamp (knopped stem, harp, finial, linen shade) and two cloth-bound books — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "An oxblood leather wingback armchair with a deep-button tufted back and brass-nailed rolled arms, beside a tripod side table with a brass reading lamp and books, on a fringed rug.", - "witnessesFix": "Recomputed: 44324 tris, nine materials with 15712 leather, 3628 wood, 4825 brass, 672 shade, 668 rug, 1512 fringe, 124 cloth, 12 paper and 212 bulb faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.030×1.400×1.160 m read off the vertices, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 chair feet and 3 table feet sunk 0.0020 m into the rug (band 0.0008–0.0040), all 4 legs tenoned 0.0288–0.0319 m into the body (band 0.012–0.045), all 13 buttons seated 0.0025 m (band 0.0012–0.0045) and 0.0074 m proud in dimples 0.0169–0.0185 m deep (min 0.008), the body mirror-symmetric to 0.000000 m over 10620 vertices (max 0.0005) with the seat 0.4531 m, the back 1.1113 m and the width 0.8683 m, 16 diagonal button pairs at 0.1617–0.1626 m (spread 0.00089, cap 0.004), the mass centre of table, lamp and books 0.0922 m inside the feet's triangle (min 0.045), the cushion pressed 0.0020 m into the deck (band 0.0008–0.0040), 28 + 28 + 19 nailheads at a 0.03000 m pitch with zero spread, seated 0.0010–0.0013 m, LOD ratios in band, collider 802 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --short-legs 17; --sink-buttons 18; --odd-wing 19; --drift-buttons 20; --narrow-tripod 21; --lift-cushion 22; --bunch-nails 23.", + "witnessesFix": "Recomputed: 44324 tris, nine materials with 15712 leather, 3628 wood, 4825 brass, 672 shade, 668 rug, 1512 fringe, 124 cloth, 12 paper and 212 bulb faces, UVs in 0..1 with zero AABB overlap, outer AABB 2.030×1.400×1.160 m read off the vertices, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 chair feet and 3 table feet sunk 0.0020 m into the rug (band 0.0008–0.0040), all 4 legs tenoned 0.0288–0.0319 m into the body (band 0.012–0.045), all 13 buttons seated 0.0025 m (band 0.0012–0.0045) and 0.0074 m proud in dimples 0.0169–0.0185 m deep (min 0.008), the body mirror-symmetric to 0.000000 m over 10620 vertices (max 0.0005) with the seat 0.4531 m, the back 1.1113 m and the width 0.8683 m, 16 diagonal button pairs at 0.1617–0.1626 m (spread 0.00089, cap 0.004), the mass centre of table, lamp and books 0.0922 m inside the feet's triangle (min 0.045), the cushion pressed 0.0020 m into the deck (band 0.0008–0.0040), 28 + 28 + 19 nailheads at a 0.03000 m pitch with zero spread, seated 0.0010–0.0013 m, LOD ratios in band, collider 640 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-foot 16; --short-legs 17; --sink-buttons 18; --odd-wing 19; --drift-buttons 20; --narrow-tripod 21; --lift-cushion 22; --bunch-nails 23.", "hero": "docs/gallery/assets/wingback-armchair-hero.webp", "preview": "showcase/wingback-armchair/preview.webp", "tags": [ @@ -843,7 +843,7 @@ "category": "vehicles", "teaches": "A procedural six-wheeled planetary science rover in the rocker-bogie tradition on a patch of rocky red-grey regolith — a cream warm-electronics body with gold-foil insulation blankets quilted into puffed cells, anodised corner posts and a trimmed deck carrying instrument boxes, sample inlets, a calibration target, a UHF can and a whip; a finned radioisotope power unit on struts between two radiator fin banks; on each side a rocker pivoting on a boss in the body side through its eye and pin, and a bogie pinned in a clevis on its front end, the two rockers linked through cranks and links to a differential bar on the deck so they turn equal and opposite; six 0.50 m aluminium drum wheels with 24 chevron grousers, six curved titanium flexure spokes and a drive actuator each, the four corners hanging from steering actuators through C-brackets; a camera mast with a laser telescope window, two camera barrels and navigation cameras; a high-gain dish on a two-axis gimbal; a 5-DOF arm whose turret drills a boulder; cable harnesses along every leg, the mast and the arm; ruts trailing behind both wheel lines and 19 broken rocks, the regolith fitted so every wheel sinks into it — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A six-wheeled rocker-bogie rover with gold-foil sides, a camera mast, a dish antenna and a finned power unit, its arm drilling a boulder on red-grey regolith.", - "witnessesFix": "Recomputed: 46096 tris, nine materials with 2512 paint, 1276 foil, 6476 aluminium, 9330 anodised, 2392 titanium, 672 glass, 970 harness, 2516 regolith and 620 rock faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.857×3.709×2.200 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all six wheels sunk 0.0115–0.0189 m into the regolith (band 0.006–0.025), all 4 rocker and bogie pivots' 10 bushings 0.000000 m off their pins' axes (cap 0.0005), 144 grousers rooted 1.00 mm inside the drum skin (band 0.5–2.5 mm) and 7.50 mm proud, the mast 0.0000° off plumb with the track 2.7000 m, the length 3.3509 m and the height 2.1004 m, the rockers deflected +4.0000° and −4.0000° (residual 0, cap 0.10°) with both link eyes on their crank pins, all 4 steering axes 0.000000 m off their wheel centres (cap 0.001), every axle 0.0000° off the lateral (cap 0.20°), grouser pitch within 0.0148° of 15° (cap 0.30°), the mass centre of the 750.0 kg rover 1.0480 m inside the six wheels' contact polygon against a 0.8170 m 45° tip margin, one connected assembly of 441 shells, LOD ratios in band, collider 1120 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-wheel 16; --offset-pin 17; --sink-grousers 18; --lean-mast 19; --jam-rocker 20; --offset-steer 21; --camber-wheel 22; --bunch-grousers 23; --overload-turret 24; --loose-dish 25.", + "witnessesFix": "Recomputed: 46096 tris, nine materials with 2512 paint, 1276 foil, 6476 aluminium, 9330 anodised, 2392 titanium, 672 glass, 970 harness, 2516 regolith and 620 rock faces, UVs in 0..1 with zero AABB overlap, outer AABB 4.857×3.709×2.200 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all six wheels sunk 0.0115–0.0189 m into the regolith (band 0.006–0.025), all 4 rocker and bogie pivots' 10 bushings 0.000000 m off their pins' axes (cap 0.0005), 144 grousers rooted 1.00 mm inside the drum skin (band 0.5–2.5 mm) and 7.50 mm proud, the mast 0.0000° off plumb with the track 2.7000 m, the length 3.3509 m and the height 2.1004 m, the rockers deflected +4.0000° and −4.0000° (residual 0, cap 0.10°) with both link eyes on their crank pins, all 4 steering axes 0.000000 m off their wheel centres (cap 0.001), every axle 0.0000° off the lateral (cap 0.20°), grouser pitch within 0.0148° of 15° (cap 0.30°), the mass centre of the 750.0 kg rover 1.0480 m inside the six wheels' contact polygon against a 0.8170 m 45° tip margin, one connected assembly of 441 shells, LOD ratios in band, collider 742 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-wheel 16; --offset-pin 17; --sink-grousers 18; --lean-mast 19; --jam-rocker 20; --offset-steer 21; --camber-wheel 22; --bunch-grousers 23; --overload-turret 24; --loose-dish 25.", "hero": "docs/gallery/assets/planet-rover-hero.webp", "preview": "showcase/planet-rover/preview.webp", "tags": [ @@ -857,7 +857,7 @@ "category": "vehicles", "teaches": "A procedural roadworks set on a cut-out patch of asphalt — a broken-edged asphalt slab with a worn white road line and two sealed tar cracks; seven 720 mm PVC traffic cones, each a hollow lathed body with a moulded bead and a rolled lip round an open tip, bonded into a square rubber base with chamfered corners, a raked top, a collar, four moulded lugs and a recess underneath, and hooped with 4 in and 6 in retroreflective collars; three standing in a taper line, three nested in a stack whose wall thickness sets the nesting pitch, and one knocked over onto the edge of its base and the lip of its tip, its roll solved so both touch; a folding A-frame barricade of four square steel legs hinged in pairs on pivot bolts, spread by pinned straps on spacers, each foot in a rubber pad, carrying two boards on each face split on 45-degree lines into orange and white retroreflective stripes and bolted to the legs; and a warning lamp with amber fresnel lenses on a bracket bolted to the top board — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "Scuffed orange cones on a patch of asphalt, three in a row, three stacked and one knocked over showing its open base, before a striped A-frame barricade with an amber lamp.", - "witnessesFix": "Recomputed: 45816 tris, eleven materials with 6048 cone PVC, 4088 reflective, 8096 rubber, 596 asphalt, 56 road paint, 496 tar, 64 orange sheeting, 384 board, 2912 steel, 720 black plastic and 696 lens faces, UVs in 0..1 with zero AABB overlap, outer AABB 3.037×2.037×1.335 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 10 supports (five cone bases, the fallen cone's body and four barricade pads) 1.5 mm into the slab (band 0.8–3.0 mm), 4 boards biting their legs 1.5 mm at all 8 joints (band 0.8–3.0 mm), 14 collars seated 0.600 mm into their bodies and 1.400 mm proud, 6 upright cones 0.0000° off plumb at 0.720 m on bases 0.356 m across the flats, the barricade's 4 legs mirrored within 0.0001 mm, one stack of 3 at a 0.036 m pitch with each inner wall bearing 0.847–1.105 mm on the wall below (band 0.4–2.0 mm), one connected assembly of 125 shells, LOD ratios in band, collider 493 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-cone 16; --gap-board 17; --float-band 18; --lean-cone 19; --skew-leg 19; --loose-stack 20; --loose-lamp 21.", + "witnessesFix": "Recomputed: 45816 tris, eleven materials with 6048 cone PVC, 4088 reflective, 8096 rubber, 596 asphalt, 56 road paint, 496 tar, 64 orange sheeting, 384 board, 2912 steel, 720 black plastic and 696 lens faces, UVs in 0..1 with zero AABB overlap, outer AABB 3.037×2.037×1.335 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 10 supports (five cone bases, the fallen cone's body and four barricade pads) 1.5 mm into the slab (band 0.8–3.0 mm), 4 boards biting their legs 1.5 mm at all 8 joints (band 0.8–3.0 mm), 14 collars seated 0.600 mm into their bodies and 1.400 mm proud, 6 upright cones 0.0000° off plumb at 0.720 m on bases 0.356 m across the flats, the barricade's 4 legs mirrored within 0.0001 mm, one stack of 3 at a 0.036 m pitch with each inner wall bearing 0.847–1.105 mm on the wall below (band 0.4–2.0 mm), one connected assembly of 125 shells, LOD ratios in band, collider 342 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-cone 16; --gap-board 17; --float-band 18; --lean-cone 19; --skew-leg 19; --loose-stack 20; --loose-lamp 21.", "hero": "docs/gallery/assets/traffic-cones-hero.webp", "preview": "showcase/traffic-cones/preview.webp", "tags": [ @@ -871,7 +871,7 @@ "category": "nature", "teaches": "A procedural felled-tree stump on a sloping forest-floor soil disc — one furrowed lathe about a plumb axis flaring through five buttresses into the ground, its bark peeled in two patches to grey sapwood a bark's thickness under a ragged torn lip with curling flakes, a felling top with weathered growth rings, radial drying checks, the undercut floor a step under the back cut and a low band of torn hinge fibres along the step, five surface roots bedded along their run, thin moss cushions laid on the furrowed bark with tufted rims, two tiers of turkey-tail brackets rooted in the bark, three fly agarics with warted caps, pleated gills, volva and skirt, and two clusters of ringed honey fungus out of a root and the stump's foot — with fallen leaves, bipinnate ferns, twigs and pebbles, through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "A sawn tree stump with a stepped felling cut and torn hinge fibres, peeled bark, moss, shelf fungi, honey mushrooms, red fly agarics, ferns and fallen leaves on soil.", - "witnessesFix": "Recomputed: 56710 tris, twelve materials with 4441 bark, 1702 wood, 3080 moss, 1596 bracket, 672 fly-agaric, 1820 honey-cap, 4050 flesh, 1758 soil, 1232 litter, 17884 fern, 384 pebble and 210 twig faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.935×1.628×0.689 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the stump sealed in the soil in 8 of 8 sectors, all 16 caps seated on their stipes 0.0052–0.0137 m (band 0.003–0.030), the back cut 0.089° off level (max 1.0°), the stump 0.621 m across and 0.497 m tall (stated 0.62 and 0.50 ± 0.015 m), 5 roots bedded at every station, shallowest 0.055 m under the soil (min 0.006), all 16 stipes rooted 0.025–0.038 m in their soil, root or stump (band 0.008–0.070), all 6 bracket shelves 0.018–0.021 m into the bark (band 0.006–0.050), 0.946 of the moss top area facing up or north (floor 0.85), all 339 ground-cover shells joined to the soil, the undercut floor 0.035 m under the back cut (band 0.028–0.041) with the hinge band's tallest fibre 0.029 m over it (band 0.018–0.034), the torn bark 0.027 and 0.025 m over the sapwood at the two peels (band 0.020–0.034) with 12 flakes rooted 0.004–0.015 m in the bark (band 0.002–0.020), the moss at most 0.010 m over the bark (band 0.006–0.016), LOD ratios in band, stump collider 66 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --perch-stump 17; --float-caps 18; --tilt-cut 19; --fat-stump 19; --arch-roots 20; --float-mushrooms 21; --float-brackets 22; --sunny-moss 23; --float-cover 24; --flat-felling 25; --tall-hinge 25; --flush-peel 26; --float-flakes 26; --slab-moss 27.", + "witnessesFix": "Recomputed: 56710 tris, twelve materials with 4441 bark, 1702 wood, 3080 moss, 1596 bracket, 672 fly-agaric, 1820 honey-cap, 4050 flesh, 1758 soil, 1232 litter, 17884 fern, 384 pebble and 210 twig faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.935×1.628×0.689 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, the stump sealed in the soil in 8 of 8 sectors, all 16 caps seated on their stipes 0.0052–0.0137 m (band 0.003–0.030), the back cut 0.089° off level (max 1.0°), the stump 0.621 m across and 0.497 m tall (stated 0.62 and 0.50 ± 0.015 m), 5 roots bedded at every station, shallowest 0.055 m under the soil (min 0.006), all 16 stipes rooted 0.025–0.038 m in their soil, root or stump (band 0.008–0.070), all 6 bracket shelves 0.018–0.021 m into the bark (band 0.006–0.050), 0.946 of the moss top area facing up or north (floor 0.85), all 339 ground-cover shells joined to the soil, the undercut floor 0.035 m under the back cut (band 0.028–0.041) with the hinge band's tallest fibre 0.029 m over it (band 0.018–0.034), the torn bark 0.027 and 0.025 m over the sapwood at the two peels (band 0.020–0.034) with 12 flakes rooted 0.004–0.015 m in the bark (band 0.002–0.020), the moss at most 0.010 m over the bark (band 0.006–0.016), LOD ratios in band, stump collider 52 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --perch-stump 17; --float-caps 18; --tilt-cut 19; --fat-stump 19; --arch-roots 20; --float-mushrooms 21; --float-brackets 22; --sunny-moss 23; --float-cover 24; --flat-felling 25; --tall-hinge 25; --flush-peel 26; --float-flakes 26; --slab-moss 27.", "hero": "docs/gallery/assets/mushroom-stump-hero.webp", "preview": "showcase/mushroom-stump/preview.webp", "tags": [ @@ -885,7 +885,7 @@ "category": "vehicles", "teaches": "A procedural rental go-kart on a patch of kart-track asphalt against a red and white kerb — a 30 mm tube chassis whose main loop is one bar swept round every bend, cross tubes ending inside the rails with welded gussets, bearing hangers and kingpin C-brackets; spindles on kingpin bolts with 14° caster, a raked column in a bushing, a steering plate and two tie rods on rod-end eyes; blue moulded bodywork — a nose cone with a raised hump and lipped shoulders, pods with a crest, a ribbed deck and a groove, a front panel leaning back from the hump with a white number plate — on ten strap brackets welded to the tubes and bolted to the mouldings; a moulded seat on stays, a floor tray, pedals, a brake master cylinder with its hose to the caliper, a throttle cable, a strapped fuel tank and a lead ballast block; a finned four-stroke clamped to the rail driving the live rear axle through a clutch, an 88-link chain solved to a whole number of pitches and a 60-tooth sprocket, bearing carriers, a brake disc and caliper; and four loaded slicks on split rims with valve stems, the fronts narrower than the rears — through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.", "alt": "Blue go-kart on a patch of track asphalt before a red and white kerb: moulded nose, side pods and a front panel with a white plate, red tube chassis, black seat, finned engine.", - "witnessesFix": "Recomputed: 81854 tris, fourteen materials with 3168 frame paint, 6994 chrome, 8188 rubber, 3708 bodywork, 1548 seat, 12666 aluminium, 1920 engine casting, 4130 steel, 1686 black plastic, 172 fuel tank, 168 lead, 646 asphalt, 126 kerb paint and 124 number plate faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.895×1.774×0.640 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 tyres pressed 1.5 mm into the asphalt with their patches in one plane (band 0.8–3.0 mm), 4 hubs and 2 bearings 0.0 mm off their axles (≤ 0.3 mm), 4 tie-rod eyes on their pins and biting their plates 0.3–0.5 mm, tyre beads seated 0.864–1.000 mm on the rims (band 0.4–2.0 mm), the chain's inner edge 1.911–1.946 mm under both tooth-root circles (band 0.8–3.0 mm), frame and bodywork mirrored within 0.043 mm and the wheels within 0.0001 mm, wheelbase 1.040 m and tracks 1.100 / 1.200 m, caster 14.0°, the mass centre 0.374 m inside the tyres' support polygon (≥ 0.312 m), one connected assembly of 330 shells, 10 bodywork brackets each biting its tube 0.90–1.99 mm and its moulding 1.00–1.47 mm (band 0.5–2.5 mm), LOD ratios in band, collider 816 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --cock-hub 17; --drop-bearing 17; --short-tierod 17; --sink-tyre 18; --lift-chain 18; --toe-wheel 19; --wide-track 19; --odd-frame 19; --no-caster 19; --aft-ballast 20; --loose-ballast 21; --float-nose 23.", + "witnessesFix": "Recomputed: 81854 tris, fourteen materials with 3168 frame paint, 6994 chrome, 8188 rubber, 3708 bodywork, 1548 seat, 12666 aluminium, 1920 engine casting, 4130 steel, 1686 black plastic, 172 fuel tank, 168 lead, 646 asphalt, 126 kerb paint and 124 number plate faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.895×1.774×0.640 m, zmin 0, hygiene 0 including zero coplanar cross-shell pairs, all 4 tyres pressed 1.5 mm into the asphalt with their patches in one plane (band 0.8–3.0 mm), 4 hubs and 2 bearings 0.0 mm off their axles (≤ 0.3 mm), 4 tie-rod eyes on their pins and biting their plates 0.3–0.5 mm, tyre beads seated 0.864–1.000 mm on the rims (band 0.4–2.0 mm), the chain's inner edge 1.911–1.946 mm under both tooth-root circles (band 0.8–3.0 mm), frame and bodywork mirrored within 0.043 mm and the wheels within 0.0001 mm, wheelbase 1.040 m and tracks 1.100 / 1.200 m, caster 14.0°, the mass centre 0.374 m inside the tyres' support polygon (≥ 0.312 m), one connected assembly of 330 shells, 10 bodywork brackets each biting its tube 0.90–1.99 mm and its moulding 1.00–1.47 mm (band 0.5–2.5 mm), LOD ratios in band, collider 598 tris, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --float-tyre 16; --cock-hub 17; --drop-bearing 17; --short-tierod 17; --sink-tyre 18; --lift-chain 18; --toe-wheel 19; --wide-track 19; --odd-frame 19; --no-caster 19; --aft-ballast 20; --loose-ballast 21; --float-nose 23.", "hero": "docs/gallery/assets/go-kart-hero.webp", "preview": "showcase/go-kart/preview.webp", "tags": [ diff --git a/showcase/go-kart/README.md b/showcase/go-kart/README.md index 55837a0b..b23f1e40 100644 --- a/showcase/go-kart/README.md +++ b/showcase/go-kart/README.md @@ -85,8 +85,8 @@ value is read from their vertices. | Materials | exactly 14 distinct; ≥2910 frame paint, ≥6430 chrome, ≥7530 rubber, ≥3410 bodywork, ≥1420 seat, ≥11650 aluminium, ≥1760 engine casting, ≥3790 steel, ≥1550 black plastic, ≥158 fuel tank, ≥154 lead, ≥590 asphalt, ≥115 kerb paint, ≥114 number plate faces | 14 slots; 3168 / 6994 / 8188 / 3708 / 1548 / 12666 / 1920 / 4130 / 1686 / 172 / 168 / 646 / 126 / 124 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.8950, 1.7738, 0.6397) m ± 0.01, read off the vertices | (1.8950, 1.7738, 0.6397), zmin 0 | -| Collider tris | ≤ 900 | 816 | -| Export | written, size > 0, removed after measuring | 6084452 bytes | +| Collider tris | ≤ 900 | 598 | +| Export | written, size > 0, removed after measuring | 6072672 / 6072672 / 6072664 bytes (4.5.11 / 5.1.2 / 5.2.1) | Every falsifier leaves the triangle count at 81854 and the envelope at (1.8950, 1.7738, 0.6397): they move parts, never add or remove them. diff --git a/showcase/go-kart/go_kart.py b/showcase/go-kart/go_kart.py index 635dd54c..76f92678 100644 --- a/showcase/go-kart/go_kart.py +++ b/showcase/go-kart/go_kart.py @@ -3386,6 +3386,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -3393,6 +3397,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/grindstone/README.md b/showcase/grindstone/README.md index c3bb88d8..b7f8f3bb 100644 --- a/showcase/grindstone/README.md +++ b/showcase/grindstone/README.md @@ -45,9 +45,9 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 3 distinct; ≥ 280 wood, ≥ 190 stone, ≥ 260 metal faces | 3 slots; 400 / 240 / 364 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.722, 0.419, 0.610) m ± 0.015 | (0.7220, 0.4185, 0.6100), zmin 0 | -| Collider tris | ≤ 320 | 304 | +| Collider tris | ≤ 320 | 202 | | Bake texels | smallest UV cell ≥ 12 px at the baked resolution | 29.44 px at 1024 px | -| Export | written, size > 0 | 152272 / 152272 / 152260 bytes | +| Export | written, size > 0 | 147532 / 147532 / 147528 bytes (4.5.11 / 5.1.2 / 5.2.1) | The collider ceiling moved from 240 to 320 with the stone. 48 segments put more of its rim on the hull (198 → 304 triangles). diff --git a/showcase/grindstone/grindstone.py b/showcase/grindstone/grindstone.py index 19c0ba04..93b182f2 100644 --- a/showcase/grindstone/grindstone.py +++ b/showcase/grindstone/grindstone.py @@ -1295,6 +1295,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1302,6 +1306,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/hand-pump/README.md b/showcase/hand-pump/README.md index 38b5cbf3..fa53aec2 100644 --- a/showcase/hand-pump/README.md +++ b/showcase/hand-pump/README.md @@ -42,8 +42,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 2 distinct, ≥48 metal, ≥24 wood | 2 slots, 1134 metal / 332 wood | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.610, 0.521, 1.055) m ± 0.015 | (0.6100, 0.5210, 1.0545), zmin 0 | -| Collider tris | ≤ 220 (source turns the bucket at 8 staves, no hoops) | 205 | -| Export | written, size > 0 | 202576 bytes (5.2.1) | +| Collider tris | ≤ 220 (source turns the bucket at 8 staves, no hoops) | 146 | +| Export | written, size > 0 | 200352 / 200352 / 200348 bytes (4.5.11 / 5.1.2 / 5.2.1) | The model pass took the pump from **1064 to 2412** triangles and raised the ceiling **2200 → 2600**. Two lighting-and-paint passes had left it the diff --git a/showcase/hand-pump/hand_pump.py b/showcase/hand-pump/hand_pump.py index 2f19cddf..9ab4ac7f 100644 --- a/showcase/hand-pump/hand_pump.py +++ b/showcase/hand-pump/hand_pump.py @@ -957,6 +957,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -964,6 +968,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/hay-bale/README.md b/showcase/hay-bale/README.md index 24050672..fd003aad 100644 --- a/showcase/hay-bale/README.md +++ b/showcase/hay-bale/README.md @@ -67,7 +67,7 @@ RNG and no version-dependent operator. | Hay–twine gap | BVH surface < 0.008 m | 0.00009 | | Collider tris | ≤ 400 | 100 | | Bake texels | smallest UV cell ≥ 12 px at the baked resolution | 22.43 px at 1024 px | -| Export | written, size > 0 | 203508 / 203508 / 203496 bytes | +| Export | written, size > 0 | 200356 / 200356 / 200348 bytes (4.5.11 / 5.1.2 / 5.2.1) | DECIMATE COLLAPSE triangle counts are **not** guaranteed identical across series — the gate is a ratio band, not an exact count. Bake diff --git a/showcase/hay-bale/hay_bale.py b/showcase/hay-bale/hay_bale.py index e261cb2a..4934617b 100644 --- a/showcase/hay-bale/hay_bale.py +++ b/showcase/hay-bale/hay_bale.py @@ -1034,6 +1034,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1041,6 +1045,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/hitching-post/README.md b/showcase/hitching-post/README.md index e7d64359..fc4e1ad9 100644 --- a/showcase/hitching-post/README.md +++ b/showcase/hitching-post/README.md @@ -45,8 +45,8 @@ materials, UVs, evaluated LOD, collider, or export file. | **Horseshoe seat** | exactly 1; back bites the post face 0.0005–0.004 m, face ≥ 0.004 m proud | 1, 0.00150, 0.00750 | | **Brace seat** | exactly 2 knee braces, each housed in the post and in the rail (triangle overlap ≥ 1 with each); exactly 2 end caps, each gripping the rail | 2 braces, worst post 12 / rail 16; 2 caps, worst 12 | | Wood–metal gap | BVH surface < 0.008 m | 0.00075 | -| Collider tris | ≤ 280 | 72 | -| Export | written, size > 0 | 160548 / 160532 bytes | +| Collider tris | ≤ 280 | 44 | +| Export | written, size > 0 | 158568 / 158568 / 158560 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **1598 to 1680**. The old rings were faceted tori clipped into the arm; the new eyes, shanks, and 24-segment hung diff --git a/showcase/hitching-post/hitching_post.py b/showcase/hitching-post/hitching_post.py index f0d85901..ab7bbe60 100644 --- a/showcase/hitching-post/hitching_post.py +++ b/showcase/hitching-post/hitching_post.py @@ -1207,6 +1207,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1214,6 +1218,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/hover-bike/README.md b/showcase/hover-bike/README.md index 096c59f6..7f84e78f 100644 --- a/showcase/hover-bike/README.md +++ b/showcase/hover-bike/README.md @@ -91,8 +91,8 @@ export file. | Materials | exactly 10 distinct; ≥3490 livery, ≥5365 composite, ≥5525 gunmetal, ≥1200 rubber, ≥1620 leather, ≥490 light, ≥460 glass, ≥2565 anodised, ≥1235 carbon, ≥1215 chrome faces | 10 slots; 3796 / 5832 / 6008 / 1304 / 1760 / 532 / 476 / 2788 / 1344 / 1320 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.234, 0.660, 1.112) m ± 0.01 | (2.2338, 0.6598, 1.1124), zmin 0 | -| Collider tris | ≤ 1990 | 1890 | -| Export | written, size > 0, removed after measuring | 3504016 bytes | +| Collider tris | ≤ 1990 | 1246 | +| Export | written, size > 0, removed after measuring | 3472164 / 3472164 / 3472160 bytes (4.5.11 / 5.1.2 / 5.2.1) | The collider is the convex hull of the whole bike. Its count is carried by the two 72-segment shroud lips, which are the hull's outline in plan. diff --git a/showcase/hover-bike/hover_bike.py b/showcase/hover-bike/hover_bike.py index a9d7db40..9a3fc5aa 100644 --- a/showcase/hover-bike/hover_bike.py +++ b/showcase/hover-bike/hover_bike.py @@ -2293,6 +2293,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2300,6 +2304,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/iron-cauldron/README.md b/showcase/iron-cauldron/README.md index 123b170c..0ebc1957 100644 --- a/showcase/iron-cauldron/README.md +++ b/showcase/iron-cauldron/README.md @@ -35,8 +35,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 2 distinct; ≥80 wood, ≥200 metal faces | 2 slots; 144 / 2116 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.987, 0.961, 0.860) m ± 0.015 | (0.9866, 0.9605, 0.8600), zmin 0 | -| Collider tris | ≤ 280 | 252 | -| Export | written, size > 0 | 324056 / 324056 / 324044 bytes | +| Collider tris | ≤ 280 | 196 | +| Export | written, size > 0 | 320368 / 320368 / 320364 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **3388 to 3664** in the quality pass: coaxial ferrule cups and a dual-wall lathe with a rolled rim replaced the old diff --git a/showcase/iron-cauldron/iron_cauldron.py b/showcase/iron-cauldron/iron_cauldron.py index 3f198fd2..a09b43dd 100644 --- a/showcase/iron-cauldron/iron_cauldron.py +++ b/showcase/iron-cauldron/iron_cauldron.py @@ -1295,6 +1295,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1302,6 +1306,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/market-stall/README.md b/showcase/market-stall/README.md index 435dbd0d..d0241ee0 100644 --- a/showcase/market-stall/README.md +++ b/showcase/market-stall/README.md @@ -44,8 +44,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 3 distinct; ≥16 faces per stripe slot | 3 slots; 34 / 34 stripe faces | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.389, 1.011, 1.740) m ± 0.01 | (1.3892, 1.0107, 1.7402), zmin 0 | -| Collider tris | ≤ 80 | 58 | -| Export | written, size > 0, removed after measuring | 312400 / 312400 / 312376 bytes | +| Collider tris | ≤ 80 | 56 | +| Export | written, size > 0, removed after measuring | 310792 / 310792 / 310784 bytes (4.5.11 / 5.1.2 / 5.2.1) | ### Hygiene diff --git a/showcase/market-stall/market_stall.py b/showcase/market-stall/market_stall.py index 4da379a6..44145c36 100644 --- a/showcase/market-stall/market_stall.py +++ b/showcase/market-stall/market_stall.py @@ -1045,6 +1045,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1052,6 +1056,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/motor-scooter/README.md b/showcase/motor-scooter/README.md index 80eb38e0..069621cd 100644 --- a/showcase/motor-scooter/README.md +++ b/showcase/motor-scooter/README.md @@ -85,8 +85,8 @@ export file. | Materials | exactly 9 distinct; ≥6440 paint, ≥4350 chrome, ≥3250 rubber, ≥1030 oxblood vinyl, ≥265 cream vinyl, ≥495 glass, ≥170 tail lens, ≥3620 alloy, ≥2060 black enamel faces | 9 slots; 7156 / 4638 / 3608 / 1147 / 297 / 550 / 188 / 4020 / 2292 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.790, 0.730, 1.244) m ± 0.01 | (1.7901, 0.7300, 1.2435), zmin 0 | -| Collider tris | ≤ 1850 | 1678 | -| Export | written, size > 0, removed after measuring | 3374040 bytes | +| Collider tris | ≤ 1850 | 1132 | +| Export | written, size > 0, removed after measuring | 3347780 / 3347780 / 3347776 bytes (4.5.11 / 5.1.2 / 5.2.1) | The collider is the convex hull of the whole scooter; the mudguard, the mirrors and the tail carry its outline. diff --git a/showcase/motor-scooter/motor_scooter.py b/showcase/motor-scooter/motor_scooter.py index 8669f28c..1dcfc2cc 100644 --- a/showcase/motor-scooter/motor_scooter.py +++ b/showcase/motor-scooter/motor_scooter.py @@ -1903,6 +1903,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1910,6 +1914,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/mushroom-stump/README.md b/showcase/mushroom-stump/README.md index bfadd105..3e886575 100644 --- a/showcase/mushroom-stump/README.md +++ b/showcase/mushroom-stump/README.md @@ -109,8 +109,8 @@ export file. | Materials | exactly 12 distinct; ≥4000 bark, ≥1530 wood, ≥2770 moss, ≥1440 bracket, ≥600 agaric, ≥1640 honey, ≥3640 flesh, ≥1580 soil, ≥1100 litter, ≥16100 fern, ≥345 stone, ≥190 twig faces | 12 slots; 4441 / 1702 / 3080 / 1596 / 672 / 1820 / 4050 / 1758 / 1232 / 17884 / 384 / 210 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.9351, 1.6283, 0.6888) m ± 0.01 | (1.9351, 1.6283, 0.6888), zmin 0 | -| Collider tris (stump hull) | ≤ 75 | 66 | -| Export | written, size > 0, removed after measuring | 5733424 bytes | +| Collider tris (stump hull) | ≤ 75 | 52 | +| Export | written, size > 0, removed after measuring | 5733356 / 5733356 / 5733340 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the triangle count, and only `--tall-hinge` moves the envelope, 7.2 mm up against the 10 mm tolerance: they move parts or diff --git a/showcase/mushroom-stump/mushroom_stump.py b/showcase/mushroom-stump/mushroom_stump.py index b9934445..6fbd0db0 100644 --- a/showcase/mushroom-stump/mushroom_stump.py +++ b/showcase/mushroom-stump/mushroom_stump.py @@ -2938,6 +2938,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2945,6 +2949,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/office-chair/README.md b/showcase/office-chair/README.md index 5a71e070..e2567671 100644 --- a/showcase/office-chair/README.md +++ b/showcase/office-chair/README.md @@ -110,8 +110,8 @@ build time; every position, depth, angle and mass is read off the mesh. | Materials | exactly 14 distinct; ≥1330 fabric, ≥1450 mesh, ≥3260 shell, ≥4100 nylon, ≥3950 aluminium, ≥1370 chrome, ≥1820 tread, ≥1600 leatherette, ≥510 steel, ≥1060 border, ≥790 mat, ≥750 ceramic, ≥220 soil, ≥715 leaf faces | 14 slots; 1402 / 1534 / 3440 / 4322 / 4167 / 1450 / 1920 / 1688 / 538 / 1118 / 836 / 796 / 236 / 756 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.635, 1.480, 1.317) m ± 0.01 | (1.6350, 1.4800, 1.3169), zmin 0 | -| Collider tris | ≤ 580 | 551 | -| Export | written, size > 0, removed after measuring | 3294736 bytes | +| Collider tris | ≤ 580 | 374 | +| Export | written, size > 0, removed after measuring | 3283660 / 3283660 / 3283652 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the triangle count, so the band is narrow and centred on the measurement. DECIMATE COLLAPSE triangle counts are not diff --git a/showcase/office-chair/office_chair.py b/showcase/office-chair/office_chair.py index 2d0c6601..67510140 100644 --- a/showcase/office-chair/office_chair.py +++ b/showcase/office-chair/office_chair.py @@ -1891,6 +1891,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1898,6 +1902,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/palm-tree/README.md b/showcase/palm-tree/README.md index 1be1a847..0d788c90 100644 --- a/showcase/palm-tree/README.md +++ b/showcase/palm-tree/README.md @@ -84,7 +84,7 @@ export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (5.2645, 5.1503, 6.0258) m ± 0.01 | (5.2645, 5.1503, 6.0258), zmin 0 | | Collider tris (lower trunk hull) | ≤ 60 | 44 | -| Export | written, size > 0, removed after measuring | 3518252 bytes | +| Export | written, size > 0, removed after measuring | 3518264 / 3518264 / 3518252 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the triangle count: every falsifier run measured 45196 tris. None moves the envelope by more than 0.1 mm. diff --git a/showcase/palm-tree/palm_tree.py b/showcase/palm-tree/palm_tree.py index 2e88dd65..c2f2c519 100644 --- a/showcase/palm-tree/palm_tree.py +++ b/showcase/palm-tree/palm_tree.py @@ -2061,6 +2061,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2068,6 +2072,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/park-bench/README.md b/showcase/park-bench/README.md index 19c7d4d5..cb102b74 100644 --- a/showcase/park-bench/README.md +++ b/showcase/park-bench/README.md @@ -43,8 +43,8 @@ mesh, materials, UVs, evaluated LOD, collider or export file. | Materials | exactly 2 distinct, ≥48 metal, ≥24 wood | 2 slots, 1008 metal / 756 wood | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.295, 0.632, 0.887) m ± 0.015 | (1.2945, 0.6316, 0.8870), zmin 0 | -| Collider tris | ≤ 180 | 64 | -| Export | written, size > 0 | 245620 / 245620 / 245604 bytes | +| Collider tris | ≤ 180 | 60 | +| Export | written, size > 0 | 244056 / 244056 / 244048 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **2520 to 3272** in the second quality pass. The square posts and 6-gon scroll tubes became 8-gon round bar swept along each diff --git a/showcase/park-bench/park_bench.py b/showcase/park-bench/park_bench.py index 4fd32bea..59ef15a0 100644 --- a/showcase/park-bench/park_bench.py +++ b/showcase/park-bench/park_bench.py @@ -743,6 +743,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -750,6 +754,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/pine-tree/README.md b/showcase/pine-tree/README.md index bfa9c9ed..7a84dcfd 100644 --- a/showcase/pine-tree/README.md +++ b/showcase/pine-tree/README.md @@ -93,8 +93,8 @@ export file. | Materials | exactly 6 distinct; face floors bark ≥2850, needle ≥35000, cone ≥950, deadwood ≥250, soil ≥820, stone ≥170 | 6 slots; 3026 / 36612 / 1024 / 274 / 878 / 192 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (9.284, 7.932, 7.659) m ± 0.01 | (9.2837, 7.9318, 7.6586), zmin 0 | -| Collider tris (trunk hull) | ≤ 60 | 56 | -| Export | written, size > 0, removed after measuring | 5703388 bytes | +| Collider tris (trunk hull) | ≤ 60 | 54 | +| Export | written, size > 0, removed after measuring | 5703232 / 5703232 / 5703216 bytes (4.5.11 / 5.1.2 / 5.2.1) | DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels diff --git a/showcase/pine-tree/pine_tree.py b/showcase/pine-tree/pine_tree.py index a7e92a5a..7636a6de 100644 --- a/showcase/pine-tree/pine_tree.py +++ b/showcase/pine-tree/pine_tree.py @@ -1696,6 +1696,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1703,6 +1707,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/planet-rover/README.md b/showcase/planet-rover/README.md index b2681893..37ab5d3e 100644 --- a/showcase/planet-rover/README.md +++ b/showcase/planet-rover/README.md @@ -84,8 +84,8 @@ export file. | Materials | exactly 9 distinct; ≥2260 paint, ≥1140 foil, ≥5820 aluminium, ≥8390 anodised, ≥2150 titanium, ≥600 glass, ≥870 harness, ≥2260 regolith, ≥550 rock faces | 9 slots; 2512 / 1276 / 6476 / 9330 / 2392 / 672 / 970 / 2516 / 620 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (4.857, 3.709, 2.200) m ± 0.01 | (4.8568, 3.7091, 2.1999), zmin 0 | -| Collider tris | ≤ 1160 | 1120 | -| Export | written, size > 0, removed after measuring | 3563808 bytes | +| Collider tris | ≤ 1160 | 742 | +| Export | written, size > 0, removed after measuring | 3541092 / 3541092 / 3541084 bytes (4.5.11 / 5.1.2 / 5.2.1) | Every falsifier leaves the triangle count at 46096: they move parts, never add or remove them. DECIMATE COLLAPSE triangle counts are not identical diff --git a/showcase/planet-rover/planet_rover.py b/showcase/planet-rover/planet_rover.py index 6add7d30..c13dc656 100644 --- a/showcase/planet-rover/planet_rover.py +++ b/showcase/planet-rover/planet_rover.py @@ -2405,6 +2405,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2412,6 +2416,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/pond-edge/README.md b/showcase/pond-edge/README.md index 45728a48..03c37c77 100644 --- a/showcase/pond-edge/README.md +++ b/showcase/pond-edge/README.md @@ -79,7 +79,7 @@ export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (3.2040, 2.6342, 1.5071) m ± 0.01 | (3.2040, 2.6342, 1.5071), zmin 0 | | Collider tris (soil hull) | ≤ 120 | 96 | -| Export | written, size > 0, removed after measuring | 3140704 bytes | +| Export | written, size > 0, removed after measuring | 3140712 / 3140712 / 3140704 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the triangle count or the envelope: every falsifier run measured 37602 tris and the default's outer AABB to the tenth of a diff --git a/showcase/pond-edge/pond_edge.py b/showcase/pond-edge/pond_edge.py index 02e26a2b..7b4afb54 100644 --- a/showcase/pond-edge/pond_edge.py +++ b/showcase/pond-edge/pond_edge.py @@ -2070,6 +2070,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2077,6 +2081,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/quad-drone/README.md b/showcase/quad-drone/README.md index 925c16e8..f24e8b9e 100644 --- a/showcase/quad-drone/README.md +++ b/showcase/quad-drone/README.md @@ -83,8 +83,8 @@ export file. | Materials | exactly 8 distinct; ≥1580 shell, ≥2120 carbon, ≥5950 gunmetal, ≥480 glass, ≥700 light, ≥1190 rubber, ≥7800 graphite, ≥2000 anodised faces | 8 slots; 1720 / 2304 / 6472 / 524 / 760 / 1296 / 8464 / 2184 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.692, 0.569, 0.243) m ± 0.01 | (0.6924, 0.5693, 0.2433), zmin 0 | -| Collider tris | ≤ 540 | 499 | -| Export | written, size > 0, removed after measuring | 3128864 bytes | +| Collider tris | ≤ 540 | 374 | +| Export | written, size > 0, removed after measuring | 3121080 / 3121080 / 3121072 bytes (4.5.11 / 5.1.2 / 5.2.1) | Every falsifier leaves the triangle count at 41048: they move, scale or narrow parts, never add or remove them. diff --git a/showcase/quad-drone/quad_drone.py b/showcase/quad-drone/quad_drone.py index f88620fb..4ba6c7d6 100644 --- a/showcase/quad-drone/quad_drone.py +++ b/showcase/quad-drone/quad_drone.py @@ -1533,6 +1533,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1540,6 +1544,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/road-bicycle/README.md b/showcase/road-bicycle/README.md index a97f0be4..75558733 100644 --- a/showcase/road-bicycle/README.md +++ b/showcase/road-bicycle/README.md @@ -85,8 +85,8 @@ export file. | Materials | exactly 10 distinct; ≥940 paint, ≥5650 chrome, ≥6250 alloy, ≥7410 steel, ≥480 tread rubber, ≥850 gum, ≥320 leather, ≥970 tape, ≥1620 black, ≥158 bottle faces | 10 slots; 1048 / 6438 / 6950 / 8239 / 540 / 952 / 356 / 1080 / 1810 / 176 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.670, 0.438, 0.997) m ± 0.01 | (1.6698, 0.4376, 0.9969), zmin 0 | -| Collider tris | ≤ 970 | 880 | -| Export | written, size > 0, removed after measuring | 3598060 bytes | +| Collider tris | ≤ 970 | 574 | +| Export | written, size > 0, removed after measuring | 3579436 / 3579436 / 3579428 bytes (4.5.11 / 5.1.2 / 5.2.1) | Every falsifier leaves the triangle count at 46092: they move parts, never add or remove them. `--lift-chain` keeps the default chain's link diff --git a/showcase/road-bicycle/road_bicycle.py b/showcase/road-bicycle/road_bicycle.py index fbd5f695..31569727 100644 --- a/showcase/road-bicycle/road_bicycle.py +++ b/showcase/road-bicycle/road_bicycle.py @@ -2683,6 +2683,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -2690,6 +2694,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/shipping-crate/README.md b/showcase/shipping-crate/README.md index e57c318d..d082f412 100644 --- a/showcase/shipping-crate/README.md +++ b/showcase/shipping-crate/README.md @@ -33,8 +33,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 2 distinct; ≥900 wood, ≥600 metal faces | 2 slots; 1170 / 904 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.146, 0.726, 0.612) m ± 0.015 | (1.1460, 0.7260, 0.6120), zmin 0 | -| Collider tris | ≤ 220 | 116 | -| Export | written, size > 0 | 274624 (4.5.11) / 274680 (5.2.1) bytes | +| Collider tris | ≤ 220 | 100 | +| Export | written, size > 0 | 273124 / 273196 / 273188 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **624 to 2508** in the quality pass: the old beveled cube with glued-on slats became a post-and-slat crate with diff --git a/showcase/shipping-crate/shipping_crate.py b/showcase/shipping-crate/shipping_crate.py index 0ea8e04d..2d28982d 100644 --- a/showcase/shipping-crate/shipping_crate.py +++ b/showcase/shipping-crate/shipping_crate.py @@ -1239,6 +1239,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1246,6 +1250,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/signpost/README.md b/showcase/signpost/README.md index f67be22b..15d34690 100644 --- a/showcase/signpost/README.md +++ b/showcase/signpost/README.md @@ -40,8 +40,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 3 distinct, ≥24 metal, ≥12 board, ≥12 wood | 3 slots, 126 metal, 33 board, 60 wood | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.260, 0.142, 1.551) m ± 0.015 | (1.2600, 0.1420, 1.5510), zmin 0 | -| Collider tris | ≤ 180 | 56 | -| Export | written, size > 0 | 41168 / 41232 bytes | +| Collider tris | ≤ 180 | 44 | +| Export | written, size > 0 | 38668 / 38740 / 38740 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles dropped from **504 to 376** in the quality pass: glued diamond cubes and a solid shoe block became wedges and a four-plate diff --git a/showcase/signpost/signpost.py b/showcase/signpost/signpost.py index 231db518..28c836dc 100644 --- a/showcase/signpost/signpost.py +++ b/showcase/signpost/signpost.py @@ -736,6 +736,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -743,6 +747,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/skate-ramp/README.md b/showcase/skate-ramp/README.md index 68b12c60..3e036008 100644 --- a/showcase/skate-ramp/README.md +++ b/showcase/skate-ramp/README.md @@ -69,8 +69,8 @@ export file. | Materials | exactly 9 distinct; ≥3100 plywood, ≥1400 framing, ≥1030 steel, ≥6940 hardware, ≥1045 maple, ≥855 grip, ≥1460 urethane, ≥850 alloy, ≥440 bushing faces | 9 slots; 3268 / 1479 / 1086 / 7304 / 1100 / 900 / 1536 / 892 / 464 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.529, 2.440, 1.339) m ± 0.01, read off the vertices | (2.5293, 2.4400, 1.3389), zmin 0 | -| Collider tris | ≤ 380 | 350 | -| Export | written, size > 0, removed after measuring | 2376604 bytes | +| Collider tris | ≤ 380 | 306 | +| Export | written, size > 0, removed after measuring | 2373684 / 2373684 / 2373676 bytes (4.5.11 / 5.1.2 / 5.2.1) | DECIMATE COLLAPSE triangle counts are not identical across Blender series, so the LOD gate is a ratio band, not an exact count. Bake pixels diff --git a/showcase/skate-ramp/skate_ramp.py b/showcase/skate-ramp/skate_ramp.py index 69e9f3e4..682aa44f 100644 --- a/showcase/skate-ramp/skate_ramp.py +++ b/showcase/skate-ramp/skate_ramp.py @@ -1830,6 +1830,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1837,6 +1841,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/soccer-goal/README.md b/showcase/soccer-goal/README.md index 1f13ffdf..c4d43477 100644 --- a/showcase/soccer-goal/README.md +++ b/showcase/soccer-goal/README.md @@ -80,8 +80,8 @@ export file. | Materials | exactly 10 distinct; ≥2300 paint, ≥8300 cord, ≥150 rope, ≥310 steel, ≥1350 cast, ≥3300 nylon, ≥920 galvanised, ≥180 turf, ≥16 line paint, ≥95 soil faces | 10 slots; 2514 / 9028 / 160 / 340 / 1464 / 3604 / 1000 / 196 / 16 / 102 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (6.220, 2.640, 2.153) m ± 0.01 | (6.2200, 2.6400, 2.1527), zmin 0 | -| Collider tris | ≤ 190 | 168 | -| Export | written, size > 0, removed after measuring | 2525996 bytes | +| Collider tris | ≤ 190 | 126 | +| Export | written, size > 0, removed after measuring | 2523792 / 2523792 / 2523784 bytes (4.5.11 / 5.1.2 / 5.2.1) | Every falsifier but one leaves the triangle count at 34804: they move or shorten parts, never add or remove them. `--wide-mouth` measures 34816, diff --git a/showcase/soccer-goal/soccer_goal.py b/showcase/soccer-goal/soccer_goal.py index 4fefdfb3..71c6f812 100644 --- a/showcase/soccer-goal/soccer_goal.py +++ b/showcase/soccer-goal/soccer_goal.py @@ -1379,6 +1379,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1386,6 +1390,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/stand-mixer/README.md b/showcase/stand-mixer/README.md index b50b8410..7fa8915f 100644 --- a/showcase/stand-mixer/README.md +++ b/showcase/stand-mixer/README.md @@ -98,8 +98,8 @@ export file. | Materials | exactly 8 distinct; ≥3980 enamel, ≥2410 chrome, ≥5110 stainless, ≥84 stone, ≥1080 rubber, ≥745 ceramic, ≥700 egg, ≥515 beater faces | 8 slots; 4328 / 2626 / 5560 / 91 / 1174 / 812 / 760 / 562 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.470, 0.570, 0.389) m ± 0.01 | (0.4700, 0.5700, 0.3890), zmin 0 | -| Collider tris | ≤ 2450 | 2329 | -| Export | written, size > 0, removed after measuring | 2337532 bytes | +| Collider tris | ≤ 2450 | 1308 | +| Export | written, size > 0, removed after measuring | 2283036 / 2283036 / 2283032 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the topology, so every one of them measures the default's 29620 triangles and the default's AABB. `--shallow-bowl` keeps diff --git a/showcase/stand-mixer/stand_mixer.py b/showcase/stand-mixer/stand_mixer.py index ef282298..c932cd09 100644 --- a/showcase/stand-mixer/stand_mixer.py +++ b/showcase/stand-mixer/stand_mixer.py @@ -1765,6 +1765,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1772,6 +1776,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/stone-archway/README.md b/showcase/stone-archway/README.md index 3580a241..3d29c664 100644 --- a/showcase/stone-archway/README.md +++ b/showcase/stone-archway/README.md @@ -65,7 +65,7 @@ the end. | UV AABB overlap | ≤ 1e-5 | 0.000000 | | Outer AABB | 1.644 × 0.510 × 2.057 m ± 0.020 | 1.6440 × 0.5100 × 2.0568 | | Clear opening | 1.200 m ± 0.015, measured between the pier faces | 1.2033 | -| Collider triangles | ≤ 260 | 168 | +| Collider triangles | ≤ 260 | 132 | | Normal bake | `{'FINISHED'}` with image data | `{'FINISHED'}`, `has_data=True` | | glTF export | file written, non-empty | ~100 kB | | Hygiene | all zero | loose 0/0, non-manifold 0, zero-area 0, doubles 0, n-gons 0, coplanar disjoint pairs 0 | @@ -229,7 +229,7 @@ Smoke runs the check-only path. It does not pass `--output` or any falsifier. | LOD2 tris / ratio | 250 / 0.2193 | 250 / 0.2193 | 244 / 0.2140 | | Face counts (ashlar / dressed / mortar) | 364 / 182 / 108 | same | same | | Outer AABB | 1.6440 × 0.5100 × 2.0568 | same | same | -| Collider tris | 168 | 168 | 168 | +| Collider tris | 132 | 132 | 132 | | Intrados deviation | 0.00097 | 0.00097 | 0.00097 | | Mortar joints | all 0.00970 | all 0.00970 | all 0.00970 | | Mortar contact | 18 × 2 stones | same | same | diff --git a/showcase/stone-archway/stone_archway.py b/showcase/stone-archway/stone_archway.py index 2d8daaad..457f0416 100644 --- a/showcase/stone-archway/stone_archway.py +++ b/showcase/stone-archway/stone_archway.py @@ -986,6 +986,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -993,6 +997,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/stone-well/README.md b/showcase/stone-well/README.md index 4517c0fd..c9875ff0 100644 --- a/showcase/stone-well/README.md +++ b/showcase/stone-well/README.md @@ -36,8 +36,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Post placement | each post within 0.02 rad, in plan, of a roof hip corner recomputed from the mesh | 0.00000 | | Bucket clearance | hangs 0.085–0.115 m clear of the measured coping top | 0.10000 | | Material-island gap | stone↔wood and metal↔wood min distance ≤ 0.008 m | 0.00000 / 0.00000 / 0.00000 | -| Collider tris | ≤ 380 | 346 | -| Export | written, size > 0, removed after measuring | 690216 bytes on 5.2.1 | +| Collider tris | ≤ 380 | 258 | +| Export | written, size > 0, removed after measuring | 686472 / 686472 / 686468 bytes (4.5.11 / 5.1.2 / 5.2.1) | DECIMATE COLLAPSE triangle counts are **not** guaranteed identical across series — the gate is a ratio band, not an exact count. This mesh happened diff --git a/showcase/stone-well/stone_well.py b/showcase/stone-well/stone_well.py index 40063c71..33e68670 100644 --- a/showcase/stone-well/stone_well.py +++ b/showcase/stone-well/stone_well.py @@ -1148,6 +1148,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1155,6 +1159,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/street-lantern/README.md b/showcase/street-lantern/README.md index e01634ee..f235f0e1 100644 --- a/showcase/street-lantern/README.md +++ b/showcase/street-lantern/README.md @@ -76,8 +76,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 3 distinct; ≥200 metal, ≥8 glass, ≥24 brass | 3 slots; 2162 / 24 / 341 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.300, 0.786, 1.287) m ± 0.01 | (0.3000, 0.7860, 1.2874), zmin 0 | -| Collider tris | ≤ 120 | 108 | -| Export | written, size > 0, removed after measuring | 355288 / 355272 bytes | +| Collider tris | ≤ 120 | 86 | +| Export | written, size > 0, removed after measuring | 353488 / 353488 / 353480 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles dropped from **3520 to 3338** in the first quality pass (closed square-pyramid roof, unshared cage crossings, pane rebate), then diff --git a/showcase/street-lantern/street_lantern.py b/showcase/street-lantern/street_lantern.py index a920d208..b27d97d3 100644 --- a/showcase/street-lantern/street_lantern.py +++ b/showcase/street-lantern/street_lantern.py @@ -1213,6 +1213,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1220,6 +1224,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/tavern-stool/README.md b/showcase/tavern-stool/README.md index f84ea1da..6e554229 100644 --- a/showcase/tavern-stool/README.md +++ b/showcase/tavern-stool/README.md @@ -46,8 +46,8 @@ mesh, materials, UVs, evaluated LOD, collider or export file. | Materials | exactly 2 distinct; ≥200 wood, ≥48 metal faces | 2 slots; 1168 / 576 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.341, 0.341, 0.470) m ± 0.015 | (0.3406, 0.3406, 0.4700), zmin 0 | -| Collider tris | ≤ 640 | 468 | -| Export | written, size > 0 | 259676 / 259676 / 259668 bytes | +| Collider tris | ≤ 640 | 308 | +| Export | written, size > 0 | 251188 / 251188 / 251184 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **2528 to 3040** in the second quality pass, and the band moved from 2300–3200 to 2750–3350. Each foot gained a tread, and the diff --git a/showcase/tavern-stool/tavern_stool.py b/showcase/tavern-stool/tavern_stool.py index 96f1c375..4da65a73 100644 --- a/showcase/tavern-stool/tavern_stool.py +++ b/showcase/tavern-stool/tavern_stool.py @@ -1051,6 +1051,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1058,6 +1062,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/terrain-scatter/README.md b/showcase/terrain-scatter/README.md index d807f484..6f280a62 100644 --- a/showcase/terrain-scatter/README.md +++ b/showcase/terrain-scatter/README.md @@ -50,7 +50,7 @@ materials, UVs, evaluated LOD, collider, or export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.800, 1.800, 0.570) m ± 0.015 | (1.8000, 1.8008, 0.5700), zmin 0 | | Collider tris | ≤ 120 | 36 | -| Export | written, size > 0 | 199496 / 199496 / 199480 bytes | +| Export | written, size > 0 | 198908 / 198908 / 198900 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **1194 to 1758** in the first quality pass: 9-vert hill became a 21-vert grid, and bevelled cubes became subdiv-2 icospheres. diff --git a/showcase/terrain-scatter/terrain_scatter.py b/showcase/terrain-scatter/terrain_scatter.py index 433c9f6e..65b082f8 100644 --- a/showcase/terrain-scatter/terrain_scatter.py +++ b/showcase/terrain-scatter/terrain_scatter.py @@ -904,6 +904,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -911,6 +915,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/traffic-cones/README.md b/showcase/traffic-cones/README.md index 3fc54459..495fc5f0 100644 --- a/showcase/traffic-cones/README.md +++ b/showcase/traffic-cones/README.md @@ -73,8 +73,8 @@ export file. | Materials | exactly 11 distinct; ≥5560 cone PVC, ≥3760 reflective, ≥7440 rubber, ≥540 asphalt, ≥50 road paint, ≥450 tar, ≥58 orange sheeting, ≥350 board plastic, ≥2670 steel, ≥660 black plastic, ≥640 lens faces | 11 slots; 6048 / 4088 / 8096 / 596 / 56 / 496 / 64 / 384 / 2912 / 720 / 696 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (3.0365, 2.0374, 1.3354) m ± 0.01, read off the vertices | (3.0365, 2.0374, 1.3354), zmin 0 | -| Collider tris | ≤ 540 | 493 | -| Export | written, size > 0, removed after measuring | 3335792 bytes | +| Collider tris | ≤ 540 | 342 | +| Export | written, size > 0, removed after measuring | 3327800 / 3327800 / 3327792 bytes (4.5.11 / 5.1.2 / 5.2.1) | Every falsifier leaves the triangle count at 45816 and the envelope at (3.0365, 2.0374, 1.3354): they move parts, never add or remove them. diff --git a/showcase/traffic-cones/traffic_cones.py b/showcase/traffic-cones/traffic_cones.py index 638b48ad..6e316b31 100644 --- a/showcase/traffic-cones/traffic_cones.py +++ b/showcase/traffic-cones/traffic_cones.py @@ -1855,6 +1855,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1862,6 +1866,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/treasure-chest/README.md b/showcase/treasure-chest/README.md index ccb2e7e1..1cbbcf97 100644 --- a/showcase/treasure-chest/README.md +++ b/showcase/treasure-chest/README.md @@ -34,8 +34,8 @@ materials, UVs, evaluated LOD, collider, or export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.764, 0.524, 0.696) m ± 0.015 | (0.7640, 0.5237, 0.6958), zmin 0 | | Lid bands on the vault | 3 bands spanning the lid; every vertex radius within 1e-4 m of the band's inner/outer radius | 3; 0.000000 | -| Collider tris | ≤ 200 | 180 | -| Export | written, size > 0 | 285980 / 285980 / 285972 bytes | +| Collider tris | ≤ 200 | 156 | +| Export | written, size > 0 | 283028 / 283028 / 283024 bytes (4.5.11 / 5.1.2 / 5.2.1) | ### Hygiene diff --git a/showcase/treasure-chest/treasure_chest.py b/showcase/treasure-chest/treasure_chest.py index 1dc80bab..fbf6be19 100644 --- a/showcase/treasure-chest/treasure_chest.py +++ b/showcase/treasure-chest/treasure_chest.py @@ -1069,6 +1069,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1076,6 +1080,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/wall-torch/README.md b/showcase/wall-torch/README.md index 3263fdea..3d154f60 100644 --- a/showcase/wall-torch/README.md +++ b/showcase/wall-torch/README.md @@ -44,8 +44,8 @@ mesh, materials, UVs, evaluated LOD, collider or export file. | Materials | exactly 5 distinct; ≥24 stone, ≥24 metal, ≥8 flame, ≥10 pitch | 5 slots; 540 stone, 318 metal, 50 wood, 180 flame, 60 pitch | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.304, 0.322, 0.485) m ± 0.015 | (0.3040, 0.3218, 0.4845), zmin 0 | -| Collider tris | ≤ 180 | 116 | -| Export | written, size > 0 | 164408 / 164408 / 164384 bytes | +| Collider tris | ≤ 180 | 90 | +| Export | written, size > 0 | 163468 / 163468 / 163460 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **1528 to 2004** in the second quality pass, and the band moved from 1400–1700 to 1800–2250. The solid cup became an open, walled diff --git a/showcase/wall-torch/wall_torch.py b/showcase/wall-torch/wall_torch.py index 86f0bb05..ad1a6ea8 100644 --- a/showcase/wall-torch/wall_torch.py +++ b/showcase/wall-torch/wall_torch.py @@ -781,6 +781,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -788,6 +792,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/watchtower/README.md b/showcase/watchtower/README.md index 8edc2e48..eb2a7401 100644 --- a/showcase/watchtower/README.md +++ b/showcase/watchtower/README.md @@ -45,8 +45,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 3 distinct; ≥80 metal, ≥40 roof faces | 3 slots; 300 metal, 126 roof | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.594, 1.594, 2.973) m ± 0.01 | (1.5940, 1.5940, 2.9731), zmin 0 | -| Collider tris | ≤ 180 | 150 | -| Export | written, size > 0, removed after measuring | 494508 / 494508 / 494492 bytes | +| Collider tris | ≤ 180 | 122 | +| Export | written, size > 0, removed after measuring | 492624 / 492624 / 492616 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **5220 to 6408** in the first quality pass (a taller eave-true roof and coursed shakes) and to **6840** in the second diff --git a/showcase/watchtower/watchtower.py b/showcase/watchtower/watchtower.py index 748e3fc2..09483610 100644 --- a/showcase/watchtower/watchtower.py +++ b/showcase/watchtower/watchtower.py @@ -1169,6 +1169,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1176,6 +1180,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/water-trough/README.md b/showcase/water-trough/README.md index 6bb4bc37..6a25c0a0 100644 --- a/showcase/water-trough/README.md +++ b/showcase/water-trough/README.md @@ -42,7 +42,7 @@ materials, UVs, evaluated LOD, collider, or export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.111, 0.552, 0.512) m ± 0.01 | (1.1112, 0.5520, 0.5123), zmin 0 | | Collider tris | ≤ 80 | 76 | -| Export | written, size > 0 | 355404 / 355388 bytes | +| Export | written, size > 0 | 354444 / 354444 / 354436 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **2484 to 3700** in the first quality pass: box end slabs and a single extruded U became ten jittered staves, U end-caps, diff --git a/showcase/water-trough/water_trough.py b/showcase/water-trough/water_trough.py index fe6d765d..c470f3ca 100644 --- a/showcase/water-trough/water_trough.py +++ b/showcase/water-trough/water_trough.py @@ -1355,6 +1355,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1362,6 +1366,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/weight-rack/README.md b/showcase/weight-rack/README.md index 1135a013..c5765e46 100644 --- a/showcase/weight-rack/README.md +++ b/showcase/weight-rack/README.md @@ -70,8 +70,8 @@ export file. | Materials | exactly 12 distinct; ≥4420 powder coat, ≥2820 bore, ≥3900 zinc, ≥3110 chrome, ≥235 knurl, ≥1230 rubber, ≥96 UHMW, ≥2890 numeral, ≥800 blue, ≥530 yellow, ≥530 green, ≥2080 cast-iron faces | 12 slots; 4758 / 3036 / 4196 / 3348 / 256 / 1328 / 104 / 3112 / 864 / 576 / 576 / 2240 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.200, 1.636, 2.092) m ± 0.01 | (2.2000, 1.6364, 2.0920), zmin 0 | -| Collider tris | ≤ 640 | 598 | -| Export | written, size > 0, removed after measuring | 3303420 bytes | +| Collider tris | ≤ 640 | 472 | +| Export | written, size > 0, removed after measuring | 3295024 / 3295024 / 3295016 bytes (4.5.11 / 5.1.2 / 5.2.1) | The collider is the convex hull of the whole set. Its count is carried by the plates' rims and the dumbbell heads, which are the hull's outline. diff --git a/showcase/weight-rack/weight_rack.py b/showcase/weight-rack/weight_rack.py index bc5d53f6..fbd261f5 100644 --- a/showcase/weight-rack/weight_rack.py +++ b/showcase/weight-rack/weight_rack.py @@ -1545,6 +1545,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1552,6 +1556,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/wheelbarrow/README.md b/showcase/wheelbarrow/README.md index 29c0157e..5c28b6b6 100644 --- a/showcase/wheelbarrow/README.md +++ b/showcase/wheelbarrow/README.md @@ -37,8 +37,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 2 distinct; ≥700 wood, ≥180 metal faces | 2 slots; 1085 / 214 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (1.563, 0.594, 0.577) m ± 0.015 | (1.5630, 0.5938, 0.5773), zmin 0 | -| Collider tris | ≤ 220 | 80 | -| Export | written, size > 0 | 185652 / 185652 / 185636 bytes | +| Collider tris | ≤ 220 | 64 | +| Export | written, size > 0 | 183984 / 183984 / 183976 bytes (4.5.11 / 5.1.2 / 5.2.1) | ### Hygiene diff --git a/showcase/wheelbarrow/wheelbarrow.py b/showcase/wheelbarrow/wheelbarrow.py index 036ead11..ab688b6c 100644 --- a/showcase/wheelbarrow/wheelbarrow.py +++ b/showcase/wheelbarrow/wheelbarrow.py @@ -1349,6 +1349,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1356,6 +1360,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/wingback-armchair/README.md b/showcase/wingback-armchair/README.md index 6dcf2654..865d1679 100644 --- a/showcase/wingback-armchair/README.md +++ b/showcase/wingback-armchair/README.md @@ -97,8 +97,8 @@ export file. | Materials | exactly 9 distinct; face floors ≥14500 leather, ≥3350 wood, ≥4450 brass, ≥620 shade, ≥615 rug, ≥1390 fringe, ≥114 cloth, ≥11 paper, ≥195 bulb | 9 slots; 15712 / 3628 / 4825 / 672 / 668 / 1512 / 124 / 12 / 212 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (2.0304, 1.400, 1.160) m ± 0.01 | (2.0304, 1.4000, 1.1600), zmin 0 | -| Collider tris | ≤ 820 | 802 | -| Export | written, size > 0, removed after measuring | 3509556 bytes | +| Collider tris | ≤ 820 | 640 | +| Export | written, size > 0, removed after measuring | 3503360 / 3503360 / 3503352 bytes (4.5.11 / 5.1.2 / 5.2.1) | No falsifier changes the topology or the envelope: every run measures the default's 44324 triangles and AABB. diff --git a/showcase/wingback-armchair/wingback_armchair.py b/showcase/wingback-armchair/wingback_armchair.py index 30bc1f73..9d516068 100644 --- a/showcase/wingback-armchair/wingback_armchair.py +++ b/showcase/wingback-armchair/wingback_armchair.py @@ -1973,6 +1973,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1980,6 +1984,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: diff --git a/showcase/wooden-barrel/README.md b/showcase/wooden-barrel/README.md index c5269cba..0b5e0a8e 100644 --- a/showcase/wooden-barrel/README.md +++ b/showcase/wooden-barrel/README.md @@ -36,8 +36,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Materials | exactly 2 distinct; ≥400 wood, ≥200 metal faces | 2 slots; 2584 / 1440 | | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.722, 0.714, 0.880) m ± 0.015 | (0.7220, 0.7142, 0.8800), zmin 0 | -| Collider tris | ≤ 400 | 238 | -| Export | written, size > 0 | 552456 / 552456 / 552440 bytes | +| Collider tris | ≤ 400 | 226 | +| Export | written, size > 0 | 555344 / 555344 / 555340 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **4312 to 7216** in the quality pass: 12 identical staves with 5 mm daylight and circular hoops became 20 jittered staves, diff --git a/showcase/wooden-barrel/wooden_barrel.py b/showcase/wooden-barrel/wooden_barrel.py index 59fca4f2..eacf747b 100644 --- a/showcase/wooden-barrel/wooden_barrel.py +++ b/showcase/wooden-barrel/wooden_barrel.py @@ -954,6 +954,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -961,6 +965,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bmesh.ops.dissolve_limit(bm, angle_limit=math.radians(10.0), verts=list(bm.verts), edges=list(bm.edges), delimit={"NORMAL"}) bmesh.ops.triangulate(bm, faces=list(bm.faces)) diff --git a/showcase/wooden-bucket/README.md b/showcase/wooden-bucket/README.md index 90f21d64..ac44c186 100644 --- a/showcase/wooden-bucket/README.md +++ b/showcase/wooden-bucket/README.md @@ -39,7 +39,7 @@ materials, UVs, evaluated LOD, collider, or export file. | UVs | in `0..1`, AABB overlap ≤ 1e-5 | in range, overlap 0 | | Outer AABB | (0.396, 0.346, 0.534) m ± 0.015 | (0.3957, 0.3462, 0.5338), zmin 0 | | Collider tris | ≤ 420 | 276 | -| Export | written, size > 0 | 420984 / 420984 / 420976 bytes | +| Export | written, size > 0 | 422992 / 422992 / 422984 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **4272 to 4872** in the quality pass: overlapping identical staves, circular hoops, and a 12-box bail became 16 jittered diff --git a/showcase/wooden-bucket/wooden_bucket.py b/showcase/wooden-bucket/wooden_bucket.py index 47e0051d..286ebe7f 100644 --- a/showcase/wooden-bucket/wooden_bucket.py +++ b/showcase/wooden-bucket/wooden_bucket.py @@ -1135,6 +1135,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1142,6 +1146,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bmesh.ops.dissolve_limit(bm, angle_limit=math.radians(10.0), verts=list(bm.verts), edges=list(bm.edges), delimit={"NORMAL"}) bmesh.ops.triangulate(bm, faces=list(bm.faces)) diff --git a/showcase/wooden-ladder/README.md b/showcase/wooden-ladder/README.md index f467433c..bf747c9d 100644 --- a/showcase/wooden-ladder/README.md +++ b/showcase/wooden-ladder/README.md @@ -57,8 +57,8 @@ materials, UVs, evaluated LOD, collider, or export file. | Shoe bite / cover | bite ≥ 0.010 m, cover ≥ 0.016 m | 0.02000 / 0.03800 | | **Rung pitch** | 6 rungs; every rung-to-rung gap within 0.002 m of the mean | 6; 0.00000 | | **Tie-rod seat** | 2 rods, 4 washers, 4 nuts; washer into stile and nut into washer 0.0002–0.002 m; on the rod axis within 0.0015 m; thread ≥ 0.003 m proud of each nut | 2 / 4 / 4; bite 0.00049–0.00051; axis 0; thread 0.00450 | -| Collider tris | ≤ 180 | 92 | -| Export | written, size > 0 | 230268 bytes (5.2.1) | +| Collider tris | ≤ 180 | 68 | +| Export | written, size > 0 | 228568 / 228568 / 228560 bytes (4.5.11 / 5.1.2 / 5.2.1) | Base triangles rose from **936 to 2536**. The previous mesh was two boxes, six cloned dowels, and four chrome cubes. Turned rungs (tenon diff --git a/showcase/wooden-ladder/wooden_ladder.py b/showcase/wooden-ladder/wooden_ladder.py index a228bbb7..89fd2f30 100644 --- a/showcase/wooden-ladder/wooden_ladder.py +++ b/showcase/wooden-ladder/wooden_ladder.py @@ -1297,6 +1297,10 @@ def convex_hull_collider(obj, name): bm = bmesh.new() try: bm.from_mesh(obj.data) + # Hull the points, not the surface: convex_hull keeps source faces + # lying on the hull, which made colliders non-manifold (#386). + for edge in list(bm.edges): + bm.edges.remove(edge) result = bmesh.ops.convex_hull(bm, input=list(bm.verts)) interior = [g for g in result.get("geom_interior") or [] if g.is_valid] if interior: @@ -1304,6 +1308,9 @@ def convex_hull_collider(obj, name): unused = [g for g in result.get("geom_unused") or [] if g.is_valid] if unused: bmesh.ops.delete(bm, geom=unused, context="VERTS") + loose = [v for v in bm.verts if v.is_valid and not v.link_faces] + if loose: + bmesh.ops.delete(bm, geom=loose, context="VERTS") bm.to_mesh(mesh) mesh.update() finally: