Park Bench

showcase/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.

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 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

blender --background --python showcase/park-bench/park_bench.py --

A showcase piece, not an example. A procedural wrought-iron park bench (round-bar legs bent in one piece from scroll toe to post, with the rear pair bending again into a reclined back; a slatted seat and back; armrests on quarter-round brackets), then the shipped pipeline: unique-cell UVs, a Cycles high-to-low normal bake, an LOD chain, a convex collider and a Unity glTF export.

Every leg is one bar swept along one path: a quarter-circle toe about (hy ± R, R), tangent to the post where it meets it, then the post, and at the back a 12° bend into the upright that carries the back slats. The seat slats bear on the side rails, the back slats on the uprights, and each armrest on its arm bar and the front leg's tenon, each by a named bite. The H-stretcher meets the legs at the shared stations (HX, HY, SEAT_Z, ARM_Z, SCROLL_R, BACK_TOP).

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, not imported as a package). Hygiene combinatorics match examples/mesh-hygiene-audit (copied, not imported).

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≤ 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#

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 toes4, each zmin ≤ 0.0024, 0.00000

Joint fit, bearing and form#

AxisDeclaredMeasured (all three)
Stretcher-to-leg BVH gap≤ 0.008 m0.00111
Slat-to-leg BVH gap≤ 0.008 m0.00016
Seat span vs 2·hx± 0.08 m1.2720 vs 1.260
Bearing bite (exit 20): 7 seat slats × 2 side rails, 5 back slats × 2 uprights, 2 armrests × (front leg + arm bar), overlap depth either way round28 bites, each ≥ 0.0015 m28, min 0.00201
Legs in one piece (exit 21): the shell under each toe station is a leg reaching the seat44
Back recline (exit 19): each upright, from a low and a high slab centroid9°–16°12.00° / 12.00°

The bearing bite takes the overlap either way round. A round rail has vertices only at its end rings, so under a mid-span slat it is the slat's corner that sits in the rail, not a rail vertex in the slat.

Falsifiers#

Each violates one named budget. All were run on 4.5.11, 5.1.2 and 5.2.1 and returned the same code on each.

FlagBudget violatedExit
--skip-decimateLOD1 ratio band9
--stray-vertloose vertex count is 015
--lift-zbounding box zmin is 016
--short-feetnamed toes plant at z=016
--float-stretcherstretcher-to-leg BVH gap17
--gap-slatsslat-to-leg BVH gap18
--narrow-seatseat span vs 2·hx19
--upright-backback recline band (measured 0.00°)19
--float-slatsbearing bite (seat slats 6 mm up; measured −0.00354)20
--split-feetlegs in one piece (measured 0 of 4)21

--short-feet lifts only the outward toe verts. After recentring, the bottom of the scroll is the AABB zmin, so the AABB gate would still pass. The named-toe stations fail. --split-feet restores the first build: each foot is an arc stopped short of its post, and each post starts at the arc's top. The toes still ground and every gap budget still passes. Only the one-piece budget sees the 14 mm of daylight. --upright-back keeps the back top where it was, so the envelope does not move.

Run#

blender --background --python park_bench.py --
blender --background --python park_bench.py -- --skip-decimate
blender --background --python park_bench.py -- --stray-vert
blender --background --python park_bench.py -- --lift-z
blender --background --python park_bench.py -- --short-feet
blender --background --python park_bench.py -- --float-stretcher
blender --background --python park_bench.py -- --gap-slats
blender --background --python park_bench.py -- --narrow-seat
blender --background --python park_bench.py -- --upright-back
blender --background --python park_bench.py -- --float-slats
blender --background --python park_bench.py -- --split-feet
blender --background --python park_bench.py -- --output bench.png

Smoke passes no flags.

Exit codes#

File-local. 9 is a valid check code. 10 is reserved for gallery_framing.check_framing on the --output path. 15–19 are the hygiene and joint-fit family. 20 and 21 are this piece's own.

CodeMeaning
0Success
1Uncaught exception (FATAL wrapper)
2argparse / usage
3Mesh did not build / no UV layer
4Base triangle count outside range
5Material count ≠ 2 distinct slots, or wood/metal faces missing
6UVs outside 0..1
7UV AABB overlap above tolerance
8World AABB off declared outer size
9LOD ratio band (--skip-decimate lands here)
10Framing gate (render path only)
11Collider triangle count above ceiling
12Bake did not finish or image has no data
13Export file missing or empty
14--output produced no file
15Hygiene (--stray-vert lands here)
16Grounded zmin / named toes (--lift-z, --short-feet)
17Stretcher-to-leg gap (--float-stretcher)
18Slat-to-leg gap (--gap-slats)
19Seat span (--narrow-seat) or back recline (--upright-back)
20Bearing bite on slats and armrests (--float-slats)
21Legs not bent in one piece from toe to seat (--split-feet)
22Gallery asset-quality violation (render path; the floors' 11 is remapped here)

Source

showcase/park-bench/park_bench.py View the script on GitHub →
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.