Wheelbarrow

showcase/wheelbarrow/

A procedural wooden wheelbarrow 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: 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

blender --background --python showcase/wheelbarrow/wheelbarrow.py --

A showcase piece, not an example. Procedural wooden wheelbarrow (two shafts that are the handles, each one timber from grip to axle; a flared hopper tray with overlapping floor slats and walls of stacked boards; iron straps; a single flat-tread spoked wheel; rear legs) then the shipped pipeline: unique-cell UVs, Cycles high-to-low normal bake, LOD chain, convex collider, Unity glTF export.

The tray walls seat into the floor rather than sitting on top of it, so a wood bevel cannot open daylight at the joint. The tyre is a flat felloe wrap, not a torus.

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

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

Joint fit and seat#

AxisDeclaredMeasured (all three)
Spoke clearance (hub − spoke)≥ 0.010 m0.05210
Wall-floor seat (inner bottom edge, lowest board of each wall)≥ 0.005 m0.00800
Metal-wood BVH gap≤ 0.010 m0.00000
Tread aspect (tyre width / radial)≥ 2.55.111
Wall boards2 boards per side wall and in the front wall; every seam 0.001–0.004 m, measured up the wall's own plane2 / 2 / 2; 0.00207–0.00231

Form#

AxisDeclaredMeasured (all three)
Shaft runs: wood shells unbroken from behind the tray to past its frontexactly 22
Tray flare / rake, from the boards' own facesside ≥ 10°, front ≥ 20°15.00° / 30.00°

DECIMATE COLLAPSE triangle counts are not identical across series, so LOD2 ratios differ slightly. 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-board 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.

Why the frame is two timbers and the tray a hopper#

The second pass found the barrow read as a crate on legs. The frame was three boxes per side: a handle that stopped at the tray's rear corner, a level run hidden exactly under the side wall (both at 0.255 m from the centreline), and a fork that started at the front corner and turned in a 50° V to the hub. From outside, the tray carried everything. The tray itself was a square box, and a spreader between the forks stood inside the wheel, touching neither fork. The iron straps ran 12 mm above the wall tops.

WALL_SEAT went from 12 mm to 8 mm: a raked board's outer bottom edge sits WALL_T·sin(RAKE) below its inner one, and at 12 mm it would have broken through the underside of the 22 mm floor. The handle-join budget is gone, because the handle no longer joins anything: it is the shaft. The shaft-run budget replaces it. Base triangles went from 2536 to 2440, and the collider from 90 to 80.

Walls, wood and iron#

Side and front walls are two boards stacked with a 2 mm seam, held by the straps; the low rear wall stays one board. Wall boards asserts the count and the seam; --wide-seams opens the seams to 8 mm (same boards, same triangles) and exits 17. Faces nobody sees get no bevel: wall bottoms buried in the floor and slat undersides. Wood has a tone and grain per board and shaft; the iron is dark and rusted. The temp .glb is removed after its size is measured.

Falsifiers#

Each violates one named budget. All eleven 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-legsnamed shoe supports at Z=016
--fat-spokesspoke clearance inside the hub17
--float-wallswall-floor seat (measures −0.00691 m)17
--pipe-rimtread aspect (torus on a flat felloe)18
--wide-seamswall boards (seam band)17
--split-shaftstwo unbroken shaft runs (measures 0)20
--box-traytray flare / rake (measures 0° / 0°)21

--box-tray stands every wall vertical on the flared tray's top outline, so the envelope and the tray-size budget stay put and only the flare gate can fail.

Run#

blender --background --python wheelbarrow.py --
blender --background --python wheelbarrow.py -- --skip-decimate
blender --background --python wheelbarrow.py -- --stray-vert
blender --background --python wheelbarrow.py -- --lift-z
blender --background --python wheelbarrow.py -- --short-legs
blender --background --python wheelbarrow.py -- --fat-spokes
blender --background --python wheelbarrow.py -- --float-walls
blender --background --python wheelbarrow.py -- --pipe-rim
blender --background --python wheelbarrow.py -- --wide-seams
blender --background --python wheelbarrow.py -- --split-shafts
blender --background --python wheelbarrow.py -- --box-tray
blender --background --python wheelbarrow.py -- --output barrow.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.

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 a face-count floor missed
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
15Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight
16Not grounded: bounding box zmin off 0, or a named shoe/tyre floats
17Joint fit: spoke clearance, wall-floor seat, metal-wood gap, or wall boards and seams
18Seat: tread aspect of the tyre
19Tray size off the stated real-world dimensions
20A shaft is not one timber from grip to axle (--split-shafts)
21Tray flare or front rake under its floor (--box-tray)
22Gallery asset-quality violation (render path; the floors' 11 is remapped here)

Source

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