KIT CONTRACT v2 (same for every style; the code assembler depends on it exactly)
- ONE file kit.glb; each atom a separate TOP-LEVEL mesh node named exactly as listed; transforms applied; Y up; +Z = outward
  from the facade (toward the street); X along the facade; metres. No images inside the GLB: the game binds the shared
  material shelf by MATERIAL NAME. UVs world-scale: u, v = metres along the surface / that material's tile size.
- Openings (windows, doors, shopfronts): origin at the bottom centre of the CLEAR opening on the wall's outer face plane
  (z = 0). The wall generator cuts exactly that clear opening. Every opening atom carries its own reveal faces lining the
  hole back to z = -wall_thickness AND an outer trim/surround that OVERLAPS the cut wall by at least 30 mm on all four
  sides (so a 5 mm mismatch never shows sky).
- Window family: ONE clear opening size per style for every full storey (the assembler uses the same window on the
  ground and upper floors). Shutters are SEPARATE atoms (a left+right pair as one node) placed on the same origin, so they
  can be toggled and tinted.
- Paint slots: joinery, doors and shutters that should change colour per building use a material whose BaseColor is a
  NEUTRAL light version (the game multiplies it by a tint). Name these materials with the suffix _paint and list them
  in kit.json "paint_slots".
- Roof cover (laid with POSITIVE HEADLAP, e.g. slate 0.42 long, 75 mm headlap, gauge 0.1725; give unit size, headlap and gauge in kit.json): 4 single units (variants a-d: real thickness, chipped/irregular edges, slight warps) AND 2 STRIP atoms
  (a row of 4 units already offset/jittered, one node) so the assembler lays most of a roof with strips (phones) and
  uses singles at the ends; a roof_underlay atom (1 x 1 m dark membrane/boarding, the assembler scales it on X/Z only).
- Eaves system on ONE socket line: fascia_1m, gutter_1m (half-round or box, open ends), gutter_bracket, gutter_end_cap,
  gutter_outlet, downpipe_1m, downpipe_shoe. kit.json gives for the gutter: "drip_to_gutter_top" (the gutter top sits
  this far BELOW the roof's drip line, 0.02-0.04) and "drip_to_gutter_centre_out" (horizontal offset). Fascia origin:
  middle of its top OUTER edge; gutter origin: middle of its back top edge (fixed to the fascia face).
- kit.json schema "forge.atom-kit.v2": per atom: node_name, role, bounding_box, clearance_box (bbox + what must stay free),
  triangles, materials, opening {width, height, wall_thickness} for openings, sockets {name: [x,y,z]} where useful,
  variants. Plus top level: style, unit sizes (roof unit width/length/gauge/lap), pitch it was built for, paint_slots.
- materials.json "forge.material-shelf.v1" (as the Breton kit): per material maps BaseColor/Normal/ORM (TILEABLE, 1024,
  glass/metal 512), tile_size_metres, roughness/metalness factors; wall materials also a Height map + displacement scale
  and bias in metres. Material VARIANTS: give the listed variant materials as separate shelf entries (same tile size).
- No coplanar faces between different materials: quoins, jambs, string courses and any trim stand at least 15 mm PROUD
  of the wall face they sit on (flush trim z-fights into hatched streaks in the game; seen on the church tower, 8 Oct 2026).
- Triangle budget: whole kit <= 45k triangles; any single atom <= 3,500 (strips <= 160, single units <= 40).
- Deliver also: kit_sheet.png (1920x1080 Cycles render of every atom in a row with names, shelf textures on, light grey
  floor), a test_house.png (Cycles render of a small house YOU assemble in Blender from the atoms with a generated wall,
  to prove they fit: eaves close-up must show the gutter BELOW the roof edge, not through it), build_kit.py (ONE script that
  builds kit.glb + materials from scratch; the delivered files must come from a clean run), NOTES.md (8 lines).
- Textures: CC0 only (Poly Haven / ambientCG downloads, or procedural bakes). Record the ids in NOTES.md.
- Blender 5.2 is headless on another machine. Write bpy scripts here and run them with:
  ssh gex44 /root/blender-spike/blender-5.2.0-linux-x64/blender -b --python-exit-code 1 --python /root/fal-author/__SLUG__/<script>.py
  (first `ssh gex44 mkdir -p /root/fal-author/__SLUG__`, scp scripts there, scp results back here, LOOK at every render with
  your image tool and fix what looks wrong). Only one Blender job at a time from you. Other Astra seats use other dirs:
  never touch /root/fal-author/ dirs that are not yours. Do not deploy anything.
- Stop when every atom looks as good as the reference, test_house.png has no clipping, and the shelf tiles seamlessly.
  Time box: 75 minutes of work.
