You are seat S2 (layout + render). Build:
1. omg/kit/building/layout.mjs (pure JS, no THREE; tiny local mat4 helpers): `layout(spec, kitInfo) -> Layout` (TYPES.md)
   where kitInfo = { kit: kit.json, style: style.json } (kits-src/breton/style.json is being written by seat S1 in
   parallel: until it exists use the v1 role map in this brief: window.std -> window_ground, window.std.shutters ->
   window_ground_shutters, window.small -> window_small, door.main/door.back/door.double -> door, dormer -> dormer,
   chimney -> chimney_stack, roof.unit.{a,b,c} -> slate_{a,b,c}, roof.ridge -> ridge_tile, roof.verge -> verge_board_1m,
   eaves.fascia -> eaves_board_1m, eaves.gutter -> gutter_1m, downpipe -> downpipe_1m, corner.long/short ->
   quoin_long/short, lantern -> lantern; put that default map in layout.mjs). Port from houses.mjs houseInto(): facades,
   openings (+ shutters as the shutters variant atom on v1, a separate shutters atom when the kit has `shutters_std`),
   quoins (corner zone), downpipes, dormers, chimneys, lantern/sign, verges, ridge. CHANGE per BLUEPRINT v2 rules 8-11:
   roof laid FROM THE EAVES UP with headlap (gauge (0.42-0.075)/2 = 0.1725, course lift 0.014 along the roof normal),
   starter course at the drip line 0.05 beyond the fascia, last course dropped when it would pass the ridge (ridge cap
   covers), rows flush on both verges, seeded jitter (yaw +-1 deg, slide +-6 mm) on singles, strips (role
   roof.strip.*) for the middle of each course when the kit has them, and an underlay panel (kind 'underlay') under
   each slope. Gutter law: top 20-40 mm below the lowest point of the PLACED starter course, centre under the drip,
   full eaves length (1 m pieces + one last piece scaled on X within +-15 %), end caps/outlets/brackets when the kit has
   them, a downpipe from each end down to the ground. Wall panels: one per facade (rect, or gable pentagon), holes = the
   clear openings, kind from spec volume wall.kind, `shade` from spec.look.
   `checkLayout(layout, kitInfo) -> Finding[]`: gutter clearance vs the placed starter course units (no gutter bbox
   corner inside any starter-course unit's oriented box; gutter top below their lowest point), gutter run continuity
   (no gap > 5 mm), roof coverage (no course past the ridge cap, rows reach both verges within 10 mm), opening surrounds
   not inside the quoin zone, generic overlap among gutters/dormers/chimneys/openings/signs (roof units excluded).
2. omg/kit/building/render.mjs: `loadStyleKit(THREE, { base, renderer, GLTFLoader, KTX2Loader, DRACOLoader, basisPath })`
   (port loadHouseKit: shelf, wall material with displacement, atoms split by material) returning
   `{ kit, style, materials, atoms, build(placements), sharedBytes() }` with `build([{ layout, x, z, yaw }])`: one
   InstancedMesh per (atom part, material) for the whole batch, instance tints with setColorAt on paint-slot materials
   (v1 kit: Breton_blue_timber gets the spec's shutter/door colour as a multiplier close to white so blue stays blue,
   Aged_ivory_frames the joinery colour; kit v2: materials listed in kit.json paint_slots), underlay panels, wall panels
   (port wallInto: 0.118 m grid, displacement, UV (u+half)/tile, -y/tile, holes; generalise to the outline polygon) and a
   per-building shade as vertex colour on walls. Returns stats like houses.mjs (buildings, instances, drawCalls, tris,
   perBuildingBytes).
3. omg/kit/building/test/layout.test.mjs: on the fixture and on 50 synthetic specs (vary w 6-12, d 6-8, storeys 1-2,
   built by small helper code in the test, not by spec.mjs): checkLayout returns 0 errors; and a test that today's
   houses.mjs roof+gutter placement (reproduce its numbers: courses from the ridge, gauge 0.21, gutter at eaves-0.02)
   FAILS your gutter clearance check (proves the check can fail). Count instances per house and print them.
V3 ADDITIONS (BLUEPRINT rules 8, 9, 11, 12): eaves comes from the spec (`volume.eaves`, it already includes the
kneewall); gutter = 1 m pieces + one last piece scaled on X 0.3-1.0, a fall of 3 mm per metre from the middle toward each
end, an outlet + downpipe at each end with a swan-neck offset from the outlet back to the wall (kit v1: a tilted
downpipe_1m segment scaled on its length); if dropping the last course leaves a gap larger than the ridge cap's cover
(0.185 - 0.03 m along the slope), add a short top course (units scaled on their length axis); joints stagger by half a
unit on alternate courses; allowed penetrations (named pairs) in checkLayout: opening atom into its wall, chimney base
into the roof (<= 0.6 m), dormer into the roof, bracket into fascia/wall. Tints: kit v1 uses style.json
`paint_slots_v1` (Breton_blue_timber -> spec.look.paint.shutters/door, Aged_ivory_frames -> joinery); test (in node,
no GPU) that two specs with different paint give different instance tint values for the same atom part. A longhouse
fixture will appear from S1; also build your own synthetic attic case (kneewall 0.6, dormers).
V3.1 (Fable pass 2, these override anything above): gutter pieces n = round(L), each scaled to L / n on X; course
lift = 0.02 + 0.014 * (course % 2) along the roof normal, NEVER cumulative; on staggered courses the verge unit is a
HALF unit (kit v1: end single scaled X 0.5) so no slate is doubled at the verge; downpipes: one per eaves run, two when
the run > 8 m, never within 1.2 m of the main door; checkLayout also tests no roof unit centre inside a dormer's roof
cut polygon (kit.json dormer roof_cut_polygon_XZ) or inside a chimney footprint + 0.05 m; report triangles per house
(kit v1 is ~90k, that is expected). The fixture is now 8.33 m wide.
Files you own: omg/kit/building/layout.mjs, omg/kit/building/render.mjs, omg/kit/building/test/layout.test.mjs.
