# medieval-town-v2

Eleven add-on atoms and seven aged PBR materials for the medieval shelf. Built from the supplied historical sheet and the existing medieval kit contracts. **11,000 triangles total**. No source shelf files were changed.

Open `kit_sheet.png` for the parts, `test_house.png` for the assembled demonstration, and `roof_closeup.png` for the 45° roof view at 4 m. `kit.blend` is editable with packed textures. `kit.glb` is the lightweight runtime geometry; load its external materials through `materials.json` (textures are intentionally not embedded).

## Frozen interfaces

Metres, +Y up, facade +Z, exterior wall Z=0. Names are exact glTF node names. Ground props sit at Y=0 with X/Z footprint centred. Door origins are bottom centre of their clear openings; actual bounds and openings are in `kit.json`. Door surrounds stand proud of the wall; backing boards extend behind it. Cut the host wall at door/vent openings.

| Atom | Triangles | Placement |
|---|---:|---|
| barn_door_double | 1572 | Clear opening 3.0 × 3.5 m; exterior Z=0 |
| barn_loft_door | 996 | Clear opening 1.1 × 1.3 m; hoist above hatch |
| barn_vent_slit | 224 | Clear slit .14 × .90 m; sill extends .05 m below origin |
| tile_strip_aged_a | 288 | Exact tile_strip_a bounds; eight tiles |
| tile_strip_aged_b | 288 | Exact tile_strip_b bounds; eight tiles |
| ridge_tile_aged | 140 | Exact ridge_tile_round bounds and lap |
| grime_skirt | 2 | 1 × 1.2 m decal; face Z=.001 m |
| hay_cart | 3590 | 1.8 × 1.9 × 3.2 m; long axis Z; shafts +Z |
| trough | 1220 | 1.8 × .6 × .6 m; hollow chamfered basin |
| barrel_stack | 1404 | Three horizontal coopered casks on rack |
| trestle_table | 1276 | 2 × .8 × 1.8 m including two separate benches |

Roof strips: X width **1.32 m**, +Z downslope, heads at Z=0, **.10 m course gauge**. Rotate about X by positive roof pitch. Built-in lap tilt separates courses; do not stack them vertically. Bounds are exactly `[-.66,0,0] .. [.66,.0548,.265]`. New strips use 1.286× the original 224 triangles, below the 1.5× cap. Keep COLOR_0 enabled for per-tile tints. Choose A/B with a seeded sequence. Use `weathering.tile_style` for spatial colour clusters and edge-aware UV lanes: clean tiles use the right lane, damp tiles the left. Arbitrary full-range UV offsets would spread moss everywhere again.

Ridge: along X, repeat **.255 m**, length .30 m, overlap .045 m. Bounds `[-.15,-.231,-.15] .. [.15,.071,.15]`. Mortar shoulders use Dressed_limestone.

## Material binding

All seven new sets are 1024² PNG: BaseColor sRGB, tangent Normal OpenGL (+Y), and ORM linear (R occlusion, G roughness, B metalness). UV0 already contains physical scaling: texture repeat stays 1. Set roughness and metalness factors to 1 when binding ORM. For glTF UVs in Three.js, set `flipY=false`. Use the exact material names.

| Material | Physical repeat U × V |
|---|---|
| Clay_tile_aged | .65 × .65 m; per-tile UV offsets and vertex tints |
| Barn_plank | 1 × 2 m; V vertical, five irregular boards across U |
| Plaster_aged_white | 1.5 × 1.5 m, same as Plaster_white |
| Plaster_aged_ochre | 1.5 × 1.5 m |
| Oak_frame_aged | 1 × 1 m; U along timber |
| Grime_skirt | 1 × 1.2 m; U repeats, V clamps |
| Thatch_reed_light | 1 × 1 m; original town-v1 Normal/ORM unchanged |

Grime uses BaseColor alpha, alpha blending, depthWrite=false and double-sided display. It fades clear upward. Place just proud of the infill, behind raised timbers. The decal should repeat only along the wall, not vertically.

Thatch BaseColor average changed from RGB 78/70/58 to 154/144/119; Normal and ORM are byte-identical to town-v1. Reused shelf sets are included, including Clay_tile_dark for the original-roof comparison. Provenance and source licenses are in `materials.json`; derivatives retain registered CC0 scan maps, plus deterministic weathering. No painted lighting or generated render substitutes.

## Demonstration and verification

`test_house.glb` is a proof assembly: barn footprint 10 × 6 m, walls 4.5 m, roof 50°, long-side double door, gable hatch, two cut vent openings, and cart. The middle and right three-bay house corners share aged plaster, oak and grime; only their roofs differ. Middle uses aged A/B; right uses original tile_strip_a with original clay materials. Props stand in front. This deliberately isolates the roof comparison.

`render_kit.py` builds the proof from reimported delivered GLBs. `assembly_contract.json` records cameras/placement. `renders/` has front and rear-clay per-atom captures; `kit_sheet.png`, `clay_sheet.png`, `assembly_clay.png` collect them. `materials/material_sheet.png` displays the seven new sets.

Strict independent GLB audits: `audit_glb.json` and `audit_assembly.json`. Actual Three.js/Chromium evidence: `runtime_check.json` and `runtime_*.png`. The viewer keeps vertex colours and decal alpha and measures transformed bounds, triangles and instancing draws. The assembly builder preserves imported triangle winding. Recalculating normals on the disconnected glTF vertex soup had flipped individual triangles and caused browser gaps/pepper; this is fixed in `geometry.py`. Shadow normalBias=.03 m / bias=-.0002 remains unchanged.

The assembly repeats hundreds of real strips; its triangle/draw cost is not the eleven-atom kit budget. It is a visual integration fixture, not a production instancing implementation. No town generator or production game was modified.

## Rebuild

On gex44, working directory `/root/fal-author/medieval-town-v2`. Blender is `/root/blender-spike/blender-5.2.0-linux-x64/blender`.

```sh
python3 prepare_materials.py --shelf ../medieval-atom-kit-v1 --town ../medieval-town-v1
blender -b --factory-startup --python-exit-code 1 --python build_kit.py
blender -b --factory-startup --python-exit-code 1 --python render_kit.py
blender -b --factory-startup --python-exit-code 1 --python bind_materials.py
blender -b --factory-startup --python-exit-code 1 --python material_proof.py
python3 make_sheets.py
python3 browser_check.py
python3 proof_browser.py
python3 validate_delivery.py
```

`render_kit.py --export-only` exports just the assembly. Material preparation needs Pillow, NumPy and SciPy; browser verification needs Playwright/Chromium. The viewer vendors Three.js; run `python3 -m http.server 8765` here and open `/viewer/`. The read-only source kits must be adjacent for a full material/comparison rebuild. Geometry rebuild uses the included frozen `source_contract.json`.

## Weathering revision

Clay now uses prefiltered ceramic colour, sparse soft moss masks, irregular orange/red/brown clusters and occasional replacement tiles. Edge-aware UV selection gathers weathering near eaves and verges; the overlapping geometry provides real toe shadows. `runtime_roof_15m.png` and `runtime_roof_4m.png` are actual Three.js captures.

Plaster uses restrained tileable scan detail plus continuous wall-scale colour variation, irregular vertical streaks, and a darker bottom half-metre. `weathering.wall_tone` and `wall_uv` supply the exported vertex tint and gentle UV warp used by both the houses and the 6 × 5 m material fixtures. Preserve COLOR_0. This placement layer is necessary for large nonrepeating age patterns; repeating the 1.5 m maps alone cannot encode wall position. `corner_cracks` adds sparse 1.5 mm settlement hairlines at infill corners, joined into the existing material draw. Grime skirts remain separate reusable decals. White and ochre fixtures are captured at 15 m, white also at 4 m.

Oak retains the registered grain, with more grey bleaching and fine longitudinal splits. `runtime_proof_oak_10m.png` compares original oak on the left with aged oak on the right.

Kit interfaces and budgets remain unchanged: eleven atoms, 11,000 triangles, 23 measured draws. The proof assembly has extra wall subdivisions for continuous tint and fine corner cracks; its cost is recorded in `runtime_check.json`. It is not part of the eleven-atom budget. Current strict export, material, browser and freshness checks are recorded in `delivery_validation.json`, `audit_glb.json`, `audit_assembly.json`, and `material_proof_check.json`.

The original `critic_review_r*.txt` files describe the superseded delivery. The user rejection reopened that acceptance. Current visual findings are in `revision_critic_final.txt`; original matched captures and source parameters are retained under `revision_weathering_before/`. Close-up limits include the frozen straight strip boundary and repeated barn plank knots, neither of which changed in this material revision.
