<!-- SOLID CITY · part 2834 -->
(0, p.ry, 0); d.scale.set(p.cr, p.cr * 0.34, p.cr); },
    function (c) { greens(c, 0.17, 0.09); });
  var props = [], hangers = [];
  banyans.forEach(function (p) {
    var n = 6 + Math.floor(R() * 3);
    for (var i = 0; i < n; i++) {
      var a = (i / n) * 6.283 + R() * 0.5, rr = p.cr * (0.55 + R() * 0.38);
      var rx = p.x + Math.cos(a) * rr, rz = p.z + Math.sin(a) * rr;
      var gy = H(rx, rz), topY = p.y + p.ch - 0.4, len = topY - gy;
      if (len > 2) props.push({ x: rx, z: rz, yMid: gy + len / 2, len: len, s: 0.30 + R() * 0.16 });
    }
    for (var j = 0; j < 4; j++) {
      var a2 = R() * 6.283, rr2 = p.cr * (0.3 + R() * 0.5), hl = 1.8 + R() * 2.4;
      hangers.push({ x: p.x + Math.cos(a2) * rr2, z: p.z + Math.sin(a2) * rr2, yMid: p.y + p.ch - 0.6 - hl / 2, len: hl, s: 0.055 });
    }
  });
  counts.props = props.length; counts.hangers = hangers.length;
  var propGeo = new T.CylinderGeometry(0.5, 0.68, 1, 6);
  var propMat = lambert(0x5d4630);
  instanced('banyan-props', propGeo, propMat, props,
    function (d, p) { d.position.set(p.x, p.yMid, p.z); d.rotation.set(0, 0, 0); d.scale.set(p.s, p.len, p.s); }, null);
  instanced('banyan-hangers', propGeo, propMat, hangers,
    function (d, p) { d.position.set(p.x, p.yMid, p.z); d.rotation.set(0, 0, 0); d.scale.set(p.s, p.len, p.s); }, null);

  group.userData = { counts: counts, samples: samples, tier: opts.tier || 'hi', tick: function (t) { uTime.value = t; } };
  return group;
}


===== FILE: public/city/nature.js.bak-natureoff-20261014 =====
/* ============================================================
 * EPISTLE — THE NATURE LAYER
 * To the King, from his General —
 *
 * His word: "create stones now and lace the whole map with
 * them — we need grasses too — flows and bushes and trees
 * of all kinds. Make huge trees: look up monkey pod and
 * banyan."
 *
 * So the wild things come, and they come the way the whole
 * world is now built: measured first (the land is scanned —
 * slope, height, and the paved places refused), instanced
 * (each kind is ONE draw for ten thousand bodies), woven in
 * the two cloths (the strong phone gets the full lace, the
 * struggling phone a lighter weave of the same design), and
 * ALIVE in time — the grass and the flower stems carry a
 * wind in their vertex shader, one uniform, no per-frame
 * cost on the CPU.
 *
 * The giants are true to their study: the MONKEY POD is a
 * short massive trunk under a symmetrical UMBRELLA crown
 * (the books say 15–25 m tall, 30 m across; Humboldt
 * measured one near 60 m wide). The BANYAN sends AERIAL
 * ROOTS down from its branches; where they ground they
 * thicken into PILLAR trunks, and the tree walks outward
 * forever — a forest of one body.
 *
 * Nature is decor: it carries no collision and no standing
 * — feet pass through grass as they should. The paved
 * hearts (plaza, terrace, first city, spaceport, the
 * village green, and the Servitude's own digging) are
 * refused by the scatter, by measurement.
 * ============================================================ */
function mulberry(seed) { var a = seed >>> 0; 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 createNature(opts) {
  var T = opts.THREE, H = opts.heightAt;
  var hiTier = opts.tier !== 'lo';
  var group = new T.Group(); group.name = 'nature-layer';
  var R = mulberry(20261021), CR = mulberry(424242);
  var counts = {}, samples = {};
  var uTime = { value: 0 };

  var EXC = [[0, 0, 150], [0, -1600, 600], [-1300, -1000, 280], [-390, 300, 130], [-900, -760, 110], [2035, 1995, 130]];
  function excluded(x, z) {
    if (x > 2130 && x < 3070 && z > 830 && z < 2070) return true;
    for (var i = 0; i < EXC.length; i++) { var dx = x - EXC[i][0], dz = z - EXC[i][1]; if (dx * dx + dz * dz < EXC[i][2] * EXC[i][2]) return true; }
    return false;
  }
  function slope(x, z, h) { var d = 2.5; return Math.max(Math.abs(H(x + d, z) - h), Math.abs(H(x - d, z) - h), Math.abs(H(x, z + d) - h), Math.abs(H(x, z - d) - h)) / d; }
  /* THE GROUNDING LAW (the Battening, 2026-10-14 — the
   * Examiner's grounding census convicted 9 perched trees
   * and 207 crest-perched stones): a thing is seated by the
   * LOWEST land under its own footprint, not by the land at
   * its center. ringLow samples the footprint's rim; the
   * seat settles the body DOWN toward that low ground —
   * never up, never sideways: (x, z) and the seeded stream
   * are untouched, so the layer's map does not churn; only
   * heights settle, the way a stone settles into a slope.
   * The census re-measures after: perched must fall. */
  function ringLow(x, z, r) { var lo = Infinity; for (var k = 0; k < 8; k++) { var a = k / 8 * 6.2832; var v = H(x + Math.cos(a) * r, z + Math.sin(a) * r); if (v < lo) lo = v; } return lo; }
  function seatSettle(x, z, h,