<!-- SOLID CITY · part 2709 -->
nk);
    sph(solid, 2.9 * s, 0, 4.6 * s, 0, C.leafLight, 0.75);
    sph(solid, 2.1 * s, 1.6 * s, 3.9 * s, 0.8 * s, C.leaf, 0.7);
    sph(solid, 0.34, 0.9 * s, 3.6 * s, 0.9 * s, 0xa8c86a, 1);   // fruit
    sph(solid, 0.34, -1.1 * s, 3.9 * s, -0.6 * s, 0xa8c86a, 1);
  }
  function ohia(s) {
    cyl(solid, 0.34 * s, 0.55 * s, 3.2 * s, 7, 0, 1.6 * s, 0, C.trunk);
    sph(solid, 3 * s, 0, 4.9 * s, 0, C.leaf, 0.72);
    sph(solid, 2.2 * s, 1.7 * s, 4.2 * s, 0.7 * s, C.leafDeep, 0.68);
    sph(glowB, 0.5, 1.2 * s, 4.6 * s, 0.6 * s, C.flower3, 0.7);   // lehua blossom hint
  }
  function shrub(fl) {              // flowering shrub against the walls (Hilo photos)
    sph(solid, 0.9 + R() * 0.5, 0, 0.75, 0, R() < 0.5 ? C.leaf : C.leafDeep, 0.78);
    sph(glowB, 0.3, 0.4, 1.15, 0.25, fl, 0.8);
    sph(glowB, 0.24, -0.45, 1.0, -0.2, fl, 0.8);
  }
  function taroPatch(w, d) {        // lo'i kalo: soil bed, water, taro leaves (compound image)
    box(solid, w, 0.5, d, 0, 0.25, 0, C.soil);
    box(glassB, w - 0.8, 0.1, d - 0.8, 0, 0.56, 0, C.water);
    var n = Math.floor(w * d / 3.2);
    for (var i = 0; i < n; i++) {
      var px = (R() - 0.5) * (w - 1.4), pz = (R() - 0.5) * (d - 1.4);
      cone(solid, 0.42, 0.9, 5, px, 1.0, pz, C.taro);
      sph(solid, 0.3, px, 1.25, pz, C.taro, 0.5);
    }
  }
  function lavaWall(len, ry) {       // low dry-stack lava rock wall edging yards (building stone, not terrain)
    var n = Math.max(2, Math.round(len / 1.6));
    for (var i = 0; i < n; i++) {
      var off = -len / 2 + (i + 0.5) * (len / n);
      var lx = Math.cos(ry) * off, lz = -Math.sin(ry) * off;
      rock(solid, 0.85, lx, 0.42, lz, i % 2 ? C.stone : C.stoneDark);
    }
  }
  function yellowStones(n, spacing) {  // the King's yellow-painted path stones, in a line along +z
    for (var i = 0; i < n; i++) rock(solid, 0.32, (i % 2 ? 0.3 : -0.3), 0.16, i * spacing, C.yellowStone);
  }
  function car(color) {              // a parked car on the parking pad
    box(solid, 1.8, 0.55, 4.3, 0, 0.55, 0, color);
    box(solid, 1.6, 0.5, 2.2, 0, 1.05, -0.2, color);
    box(glassB, 1.5, 0.34, 1.1, 0, 1.08, 0.45, C.glass);
    [[-0.85, 1.4], [0.85, 1.4], [-0.85, -1.4], [0.85, -1.4]].forEach(function (w) {
      cyl(solid, 0.34, 0.34, 0.24, 8, w[0], 0.34, w[1], 0x1c1c1e, 0, 0, Math.PI / 2);
    });
  }
  function streetLight() {           // road light: pole + warm lamp (no PointLight — perf)
    cyl(solid, 0.09, 0.13, 5.2, 6, 0, 2.6, 0, C.stoneDark);
    box(solid, 1.4, 0.12, 0.12, 0.6, 5.2, 0, C.stoneDark);
    sph(glowB, 0.26, 1.25, 5.05, 0, C.warm, 0.8);
  }

  /* ================= STAND / COLLISION REGISTRATION (local frame helpers) ================= */
  // All home builders work in a local frame (origin at pad center, +z = front/door side)
  // with BASE set to the home's world matrix. Footprints + stand rects are recorded in
  // WORLD coordinates by transforming the local rect corners.
  var HOME = null;  // {x, z, y, cos, sin} of the home being built
  function wpt(lx, lz) { return [HOME.x + lx * HOME.cos + lz * HOME.sin, HOME.z - lx * HOME.sin + lz * HOME.cos]; }
  function footprint(lx, lz, w, d, y0, y1) {
    var p = wpt(lx, lz);
    foot.push([p[0], p[1], w, d, HOME.y + y0, HOME.y + y1, HOME.ry]);
  }
  function stand(lx, lz, w, d, y) {
    standRects.push({ cx: HOME.x, cz: HOME.z, cos: HOME.cos, sin: HOME.sin, lx: lx, lz: lz, hw: w / 2, hd: d / 2, y: HOME.y + y });
  }
  function setHome(x, z, y, ry) {
    HOME = { x: x, z: z, y: y, ry: ry, cos: Math.cos(ry), sin: Math.sin(ry) };
    BASE = M4(x, y, z, ry, 0, 0);
  }
  function clearHome() { HOME = null; BASE = new T.Matrix4(); }

  /* ================= THE HOME FACTORY =================
   * Local frame: origin at pad top center, +z = front (door/lanai side), floor at y=0.
   * Styles (King's verified guide):
   *   waa        — Hale Wa'a: A-FRAME steep thatch-look roof, stone foundation, door centered in side wall
   *   noa        — Hale Noa: enclosed traditional, steep thatch gable, low wood walls
   *   plantation — gable roof, single-wall siding, front porch, post-and-pier foundation
   *   dickey     — DICKEY double-pitch hip roof, lava-rock piers/columns, board-and-batten, enclosed lanai
   *   mission    — high-pitched gable, clapboard, plain form
   */
  function gableEnds(w, d, wh, rise, color) {
    var g1 = prismGeo(d / 2, rise, 0.34), g2 = prismGeo(d / 2, rise, 0.34);
    put(solid, g1, -(w / 2 - 0.17), wh, 0, 0, 0, 0, color);
    put(solid, g2, (w / 2 - 0.17), wh, 0, 0, 0, 0, color);
  }
  function gableRoof(w, d, wh, rise, color, ov) {
    ov = ov == null ? 0.9 : ov;
    var hd = d / 2 + ov, sl = Math.hypot(hd, rise), th = Math.atan2(rise, hd);
    box(solid, w + 2 * ov, 0.18, sl, 0, wh + rise / 2 + 0.1, hd / 2, color, 0, th, 0);
    box(solid, w + 2 * ov, 0.18, sl, 0, wh + rise / 2 + 0.1, -hd / 2, color, 0, -th, 0);
    box(solid, w + 2 * ov + 0.3, 0.22, 0.5, 0, wh + rise + 0.14, 0, C.woodDark);   // ridge cap
  }
  fu