<!-- SOLID CITY · part 2967 -->
olid = new Batch(), glow = new Batch(), glassB = new Batch();

  /* ---------- frames: local X = tangent, local Z = radial (outward) ---------- */
  function frame(radius, angle) {
    var rx = Math.cos(angle), rz = Math.sin(angle);
    return { r: radius, a: angle, rx: rx, rz: rz, tx: -rz, tz: rx, x: CX + rx * radius, z: CZ + rz * radius };
  }
  function localMatrix(f, lx, ly, lz, ex, ey, ez, sx, sy, sz) {
    var basis = new T.Matrix4().makeBasis(
      new T.Vector3(f.tx, 0, f.tz), new T.Vector3(0, 1, 0), new T.Vector3(f.rx, 0, f.rz));
    basis.setPosition(f.x, BASE, f.z);
    var local = new T.Matrix4().compose(
      new T.Vector3(lx, ly, lz),
      new T.Quaternion().setFromEuler(new T.Euler(ex || 0, ey || 0, ez || 0)),
      new T.Vector3(sx == null ? 1 : sx, sy == null ? 1 : sy, sz == null ? 1 : sz));
    return basis.multiply(local);
  }
  function box(batch, f, w, h, d, lx, ly, lz, color, ex, ey, ez) {
    batch.add(new T.BoxGeometry(w, h, d), localMatrix(f, lx, ly, lz, ex, ey, ez), color);
  }
  function cyl(batch, f, rt, rb, h, seg, lx, ly, lz, color, ex, ey, ez) {
    batch.add(new T.CylinderGeometry(rt, rb, h, seg), localMatrix(f, lx, ly, lz, ex, ey, ez), color);
  }
  function sph(batch, f, r, lx, ly, lz, color, sx, sy, sz) {
    batch.add(new T.SphereGeometry(r, 10, 7), localMatrix(f, lx, ly, lz, 0, 0, 0, sx, sy, sz), color);
  }
  function disc(batch, f, r, ly, color) {
    batch.add(new T.CircleGeometry(r, 36), localMatrix(f, 0, ly, 0, -Math.PI / 2, 0, 0), color);
  }

  var buildings = [], footprints = [], standRects = [], trees = [];
  function footprint(f, w, d, y0, y1) { footprints.push({ x: f.x, z: f.z, w: w, d: d, a: f.a, y0: y0, y1: y1 }); }
  function standRect(f, w, d, y, lx, lz) {
    standRects.push({ cx: f.x + f.tx * (lx || 0) + f.rx * (lz || 0), cz: f.z + f.tz * (lx || 0) + f.rz * (lz || 0), hw: w / 2, hd: d / 2, tx: f.tx, tz: f.tz, rx: f.rx, rz: f.rz, y: y });
  }
  function record(name, kind, f, district) {
    var rec = { name: name, kind: kind, x: Math.round(f.x * 10) / 10, z: Math.round(f.z * 10) / 10, y: BASE, ring: Math.round(f.r), district: district };
    buildings.push(rec); return rec;
  }

  /* ---------- the builders ---------- */
  var STYLES = [
    { wall: C.cream, roof: C.slate, trim: C.woodDark, form: 'pitched' },
    { wall: C.cream2, roof: C.roofRed, trim: C.wood, form: 'dickey' },
    { wall: C.titanium, roof: C.silver, trim: C.gold, form: 'flat' },
    { wall: C.cream, roof: C.wood, trim: C.woodDark, form: 'pitched' },
    { wall: C.cream2, roof: C.slate, trim: C.gold, form: 'dickey' }
  ];
  function buildHouse(f, district, styleIdx, floors) {
    var st = STYLES[styleIdx % STYLES.length];
    var w = 13 + R() * 4, d = 10.5 + R() * 2.5, wallH = floors === 2 ? 6.4 : 3.4;
    box(solid, f, w + 3.4, 0.35, d + 4.6, 0, 0.18, -0.6, C.conc);
    standRect(f, w + 3.4, d + 4.6, BASE + 0.35, 0, -0.6);
    box(solid, f, w, wallH, d, 0, 0.35 + wallH / 2, 0, st.wall);
    box(solid, f, w + 1.2, 0.16, 3.0, 0, 0.43, -d / 2 - 1.5, C.conc);            // the lanai floor, toward the ring road
    for (var px = -1; px <= 1; px += 2) box(solid, f, 0.26, 2.6, 0.26, px * (w / 2 - 0.4), 1.7, -d / 2 - 2.7, st.trim);
    box(solid, f, 1.9, 2.3, 0.24, 0, 1.5, -d / 2 - 0.13, C.woodDark);           // the door, facing the road
    box(glassB, f, w * 0.62, 1.0, 0.12, 0, 2.2, -d / 2 - 0.07, C.glass);
    box(glow, f, 0.5, 0.5, 0.12, w / 4, 2.3, -d / 2 - 0.1, C.gold);              // a lamp of welcome beside the door
    if (floors === 2) {
      box(solid, f, w * 0.8, 0.14, d * 0.8, 0, 3.55, 0, st.trim);
      box(glassB, f, w * 0.55, 0.9, 0.12, 0, 5.2, -d / 2 - 0.07, C.glass);
    }
    var topY = 0.35 + wallH;
    if (st.form === 'pitched') {
      box(solid, f, w + 1.6, 0.18, d / 2 + 1.1, 0, topY + 1.05, -d / 4 - 0.2, st.roof, 0.5, 0, 0);
      box(solid, f, w + 1.6, 0.18, d / 2 + 1.1, 0, topY + 1.05, d / 4 + 0.2, st.roof, -0.5, 0, 0);
      box(solid, f, w + 1.2, 0.22, 0.5, 0, topY + 1.95, 0, st.trim);
    } else if (st.form === 'dickey') {
      box(solid, f, w + 2.2, 0.16, d + 2.2, 0, topY + 0.35, 0, st.roof, 0, 0, 0);
      box(solid, f, w * 0.62, 0.16, d * 0.55, 0, topY + 1.15, -d * 0.14, st.roof, 0.48, 0, 0);
      box(solid, f, w * 0.62, 0.16, d * 0.55, 0, topY + 1.15, d * 0.14, st.roof, -0.48, 0, 0);
    } else {
      box(solid, f, w + 1.0, 0.28, d + 1.0, 0, topY + 0.14, 0, st.roof);
      box(glow, f, w + 1.04, 0.1, d + 1.04, 0, topY + 0.3, 0, C.gold);
    }
    footprint(f, w, d, BASE, BASE + topY + 2.1);
    return record('', 'house', f, district);
  }
  function buildPavilion(f, district, big) {
    var w = big ? 17 : 12, d = big ? 13 : 9.5;
    box(solid, f, w + 2, 0.3, d + 2, 0, 0.15, 0, C.stone);
    standRect(f, w + 2, d + 2, BASE + 0.3, 0, 0);
    for (var px = -1; px <= 1; px += 2) for (var pz = -1; pz <= 1; pz += 2) {
      box(solid, f, 0.42, 3.1, 0.42, px * (w / 2 - 0.5), 1.85, pz * (d / 2 - 0.5), C.woodDark);
      footprin