Market Stall

showcase/market-stall/

A procedural timber market stall 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: 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

blender --background --python showcase/market-stall/market_stall.py --

A showcase piece, not an example. Procedural timber stall (corner posts with wrap plinths, slatted counter and shelf, back-wall planks, side braces that run post to post, striped awning with a front roller and hanging valance) then the shipped pipeline: unique-cell UVs, Cycles high-to-low normal bake, LOD chain, convex collider, Unity glTF export.

The old piece used capped foot cubes coplanar with the post bottoms and counter-leg pads coplanar with the legs, which z-fought at Z=0. Wrap plates stand off the post; counter legs go to Z=0 without a second bottom face.

The side braces used to start at the back post and stop at mid-depth, 0.43 m short of the front post, nearly level and joined to nothing at the front: in the side elevation they read as pegs hanging in the air. The audit that should have caught it never did, because a level brace fails its brace shape test and was never measured. Each brace now runs from the front post, just above the counter, up to the back post under the header, so the side bay is triangulated; the brace-in-post seat below asserts both ends. Wood carries grain and a tone per piece (PlankTone / GrainDir face attributes), and the awning is a matte canvas with faint dirt, not two flat paints.

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

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

Joint fit and seat#

AxisDeclaredMeasured (all three)
Brace-vs-counter overlap≤ 1e-6 m³0.000000
Brace-in-post seat: 2 side braces, each end past the post's inner face≥ 0.020 m0.0418
Header-post tenon engage≥ 0.4 × tenon0.0595
Awning-on-header seat−0.002–0.010 m0.00378
Post plumb (XY drift)≤ 0.008 m0.00000

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 uses no RNG; the per-piece wood tone is drawn from a seeded random.Random(TONE_SEED), the same every run. Export byte counts differ by series (glTF serializer), not a gated axis.

Falsifiers#

Each violates one named budget. Every falsifier was 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 wrap-foot supports at Z=016
--low-bracebrace-vs-counter overlap17
--short-bracebrace-in-post seat (front end stops at mid-depth, -0.4181 m)17
--float-awningawning-on-header seat18
--rake-postspost plumb19

Run#

blender --background --python market_stall.py --
blender --background --python market_stall.py -- --skip-decimate
blender --background --python market_stall.py -- --stray-vert
blender --background --python market_stall.py -- --lift-z
blender --background --python market_stall.py -- --short-feet
blender --background --python market_stall.py -- --low-brace
blender --background --python market_stall.py -- --short-brace
blender --background --python market_stall.py -- --float-awning
blender --background --python market_stall.py -- --rake-posts
blender --background --python market_stall.py -- --output stall.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 ≠ 3 distinct slots, or stripe 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
15Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight
16Not grounded: bounding box zmin off 0, or a named wrap foot floats
17Joint fit: brace occupying the counter volume, or a side brace not seated in both posts
18Seat: awning-on-header gap
19Post plumb or frame plan off the stated real-world size
20Gallery asset-quality violation (render path; the floors' 11 is remapped here)

Source

showcase/market-stall/market_stall.py View the script on GitHub →
A grained timber market stall with diagonal side braces, a red and cream striped canvas awning and a counter with shelves.