<!-- SOLID CITY · part 2514 -->
contained ES module:
 *   import { createMountainHomes } from '/city/mountain-homes.js';
 *   const g = createMountainHomes({ THREE, groundAt });
 *   // g.userData: footprint [x,z,w,d,y0,y1,rot] (world), standRects, homes, update(t)
 */
import { createRoadSmith } from './roads.js?v=20261014l';

function mulberry(a) { return function () { a |= 0; a = a + 0x6D2B79F5 | 0; var t = Math.imul(a ^ a >>> 15, 1 | a); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; }; }

export function createMountainHomes(o) {
  var T = o.THREE, groundAt = o.groundAt;
  var R = mulberry(20261012);
  var root = new T.Group(); root.name = 'mountain-homes';
  var foot = [];        // collision footprints, world coords: [x, z, w, d, y0, y1, rotY]
  var driveMouths = []; // where driveways meet the road — the rail keeps a gap there
  var PLANTBODY = false; // set while a planter holds a tree: the tree takes a body
  var standRects = [];  // walkable floors: {cx, cz, cos, sin, hw, hd, y} (rotated rect, world)
  var standTris = [];   // pitched surfaces that STAND (world tris, 9 numbers each): road slabs, driveway stones, paths, parking pads — what you see is what you stand on (2026-10-13)
  var homes = [];       // {x, z, y, kind, name} for narration / POI

  /* ---------------- palette (from the King's photos) ---------------- */
  var C = {
    stucco: 0xb3a184,      // earth-tone walls, Hilo photos
    stucco2: 0xc0b096,
    woodWall: 0x6e5136,     // weathered dark wood, compound image
    woodDark: 0x4a3520,
    white: 0xe8e2d4,        // plantation board-and-batten
    shingle: 0x4c4238,      // dark shingle roofs, Hilo photos
    shingle2: 0x5a4c3c,
    corrugated: 0xaeb6ba,   // silvered tin roof, compound main hale
    stone: 0x55504c,        // lava-rock foundation / walls
    stoneDark: 0x3c3835,
    lanaiWood: 0x7a5c38,
    doorFrame: 0x3d2b1a,    // dark wood door frames
    glass: 0xbfe0ea,
    warm: 0xffc06a,         // window glow
    leaf: 0x2a5c2e, leafDeep: 0x1d4523, leafLight: 0x3f7a38,
    banana: 0x4c9440, taro: 0x3e8a4c,
    trunk: 0x5a4630, palmTrunk: 0x8a7a68,
    lawn: 0x4d7d33, soil: 0x4a3826, water: 0x7fc4d8,
    mtn: 0x1d3515,          // THE MOUNTAIN DARK GREEN (the King's word, 2026-10-14 ~00:47; deepened ~01:38 — "Fix the color to dark green": the first green read LIGHT on his phone because the fixed noon sun + sky light together strike a slope at better than twice strength; the colour is chosen for the light it will actually stand in, deep forest that stays dark at noon)
    road: 0x6b6259, drive: 0x8a8078, conc: 0xa89e90,   // warm paved tones, Hilo photos
    yellowStone: 0xd8b93a,  // the King's yellow path stones
    flower1: 0xe86a9a, flower2: 0xf2f0e6, flower3: 0xd84a3a,
    carA: 0xb8bcc2, carB: 0x7a3a30, carC: 0x3a5a7a, carD: 0xd8d4c8
  };

  /* ---------------- geometry batcher (indexed merge, vertex colors) ---------------- */
  function Batch() { this.pos = []; this.nor = []; this.col = []; this.idx = []; this.n = 0; }
  Batch.prototype.add = function (geo, mtx, color) {
    var p = geo.attributes.position, nr = geo.attributes.normal, ix = geo.index;
    var col = new T.Color(color);
    var nm = new T.Matrix3().getNormalMatrix(mtx);
    var v = new T.Vector3(), nv = new T.Vector3();
    var i, base = this.n;
    for (i = 0; i < p.count; i++) {
      v.fromBufferAttribute(p, i).applyMatrix4(mtx);
      this.pos.push(v.x, v.y, v.z);
      nv.fromBufferAttribute(nr, i).applyMatrix3(nm).normalize();
      this.nor.push(nv.x, nv.y, nv.z);
      this.col.push(col.r, col.g, col.b);
    }
    if (ix) { for (i = 0; i < ix.count; i++) this.idx.push(base + ix.getX(i)); }
    else { for (i = 0; i < p.count; i++) this.idx.push(base + i); }
    this.n += p.count;
    if (geo.dispose) geo.dispose();
  };
  Batch.prototype.build = function (mat) {
    var g = new T.BufferGeometry();
    g.setAttribute('position', new T.Float32BufferAttribute(this.pos, 3));
    g.setAttribute('normal', new T.Float32BufferAttribute(this.nor, 3));
    g.setAttribute('color', new T.Float32BufferAttribute(this.col, 3));
    g.setIndex(this.idx);
    var mesh = new T.Mesh(g, mat);
    mesh.frustumCulled = false;
    return mesh;
  };
  var solid = new Batch(), glowB = new Batch(), glassB = new Batch();

  var _e = new T.Euler(), _m = new T.Matrix4(), _q = new T.Quaternion();
  function M4(x, y, z, ry, rx, rz) {
    _e.set(rx || 0, ry || 0, rz || 0, 'YXZ'); _q.setFromEuler(_e);
    return new T.Matrix4().compose(new T.Vector3(x, y, z), _q.clone(), new T.Vector3(1, 1, 1));
  }
  // batched primitives — all coordinates in each home's LOCAL frame, baked to world by the caller via a base matrix
  var BASE = new T.Matrix4();
  function put(batch, geo, x, y, z, ry, rx, rz, color) {
    var m = M4(x, y, z, ry || 0, rx || 0, rz || 0);
    if (BASE) m.premultiply(BASE);
    batch.add(geo, m, color);
  }
  function box(batch, w, h, d, x, y, z, color, ry, rx, rz) { put(ba