<!-- SOLID CITY · part 2467 -->
.MeshLambertMaterial({ color: C.stone })),
    gold: curve(new T.MeshLambertMaterial({ color: C.gold, emissive: 0x1a1004 })),
    red: curve(new T.MeshBasicMaterial({ color: C.red })),
    names: curve(new T.MeshBasicMaterial({ map: namesTex })),
    stele: curve(new T.MeshBasicMaterial({ map: steleTex }))
  };
  const group = new T.Group(); group.name = 'MONUMENT TO THE FALLEN WORLDS';
  const pieces = [];
  [['black', black], ['stone', stone], ['gold', gold], ['red', red], ['names', names], ['stele', stele]].forEach(function (e) {
    const mesh = new T.Mesh(e[1].build(), mats[e[0]]); mesh.name = 'fallen-' + e[0];
    mesh.matrixAutoUpdate = false; mesh.updateMatrix(); group.add(mesh);
    e[1].pieces.forEach(function (p) { p.material = e[0]; pieces.push(p); });
  });
  group.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
  group.rotation.y = opts.rotationY || 0;

  const redMat = mats.red, base = new T.Color(C.red), dim = new T.Color(0x9a1020);
  group.userData = {
    kind: 'monument', name: 'Monument to the Fallen Worlds', worlds: FALLEN_WORLDS.slice(),
    plaque: 'The Fallen Worlds, taken by the Twin Lightnings',
    height: TOP + OB_H + 6,   // obelisk apex, ~73 m
    boltTop: TOP + BH,
    pieces: pieces,
    // solid boxes in LOCAL coords (before position/rotation): [cx, cz, w, d, y0, y1]
    footprint: [[0, 0, 18, 18, 0, TOP], [0, 0, 6.8, 6.8, TOP, TOP + OB_H + 6], [-5.2, GZ, 1.8, 1.8, 0, 12.6], [5.2, GZ, 1.8, 1.8, 0, 8.4], [0, GZ, 8.2, 1.6, 0, 7.6]],
    checkLaw: function (min) { min = min || MINIMUM; return pieces.filter(function (p) { return p.min < min - 1e-6; }); },
    update: function (t) { redMat.color.copy(dim).lerp(base, 0.75 + 0.25 * Math.sin(t * 2.2)); },
    dispose: function () { group.traverse(function (o) { if (o.geometry) o.geometry.dispose(); }); Object.keys(mats).forEach(function (k) { mats[k].dispose(); }); steleTex.dispose(); namesTex.dispose(); }
  };
  return group;
}
export default createFallenWorldsMonument;


===== FILE: public/city/monument-place.js =====
/* Solid City — places King Playa's MONUMENT TO THE FALLEN WORLDS (public/city/monument-fallen.js, not edited here).
   Lazy: imported ~1.5 s after you enter the city; any import/build error is caught and the city carries on.
   Adds: collision (userData.footprint + the stone ring and fallen lintel), a radar marker (no-build zone: forge-core.js),
   a Hyper Controller stop with narration, a Watch (GRAND TOUR) fly-by caption, and the bolt pulse (userData.update). */
(function () {
'use strict';
if (!window.SC || !SC.api) return;
var A = SC.api, S = A.S, Y0 = A.CITY_Y;
var POS = { x: 176, z: 120 }, RY = Math.atan2(-176, -120), NAME = 'Fallen Worlds Monument';
var M = { state: 'idle', group: null, t0: 0, said: false, wait: 1.5 };
var cs = Math.cos(RY), sn = Math.sin(RY);
function toWorld(lx, lz) { return { x: POS.x + lx * cs + lz * sn, z: POS.z - lx * sn + lz * cs }; }   // three.js Y-rotation
function addBox(cx, cz, w, d, rot, y0, y1) { // rotated local box -> small axis-aligned cells (city solids are AABBs)
  var nx = Math.max(1, Math.ceil(w / 2.5)), nz = Math.max(1, Math.ceil(d / 2.5)), cw = w / nx, cd = d / nz, c = Math.cos(rot), s = Math.sin(rot);
  var a = RY + rot, hx = cw / 2 * Math.abs(Math.cos(a)) + cd / 2 * Math.abs(Math.sin(a)), hz = cw / 2 * Math.abs(Math.sin(a)) + cd / 2 * Math.abs(Math.cos(a));
  for (var i = 0; i < nx; i++) for (var j = 0; j < nz; j++) {
    var ox = -w / 2 + cw * (i + 0.5), oz = -d / 2 + cd * (j + 0.5), lx = cx + ox * c + oz * s, lz = cz - ox * s + oz * c, p = toWorld(lx, lz);
    A.solids.push({ x0: p.x - hx, x1: p.x + hx, z0: p.z - hz, z1: p.z + hz, y0: Y0 + y0, y1: Y0 + y1, monument: true });
  }
}
function collide(ud) {
  (ud.footprint || []).forEach(function (b) { addBox(b[0], b[1], b[2], b[3], 0, b[4], b[5]); });
  // the footprint leaves the nine world-stones and the fallen lintel walk-through; make them solid too (same layout as the file)
  var H = [2.6, 3.2, 2.3, 3.4, 2.8, 2.4, 3.1, 2.7, 2.5];
  for (var i = 0; i < 9; i++) { var a = (i + 1) * (Math.PI * 2 / 10); addBox(Math.sin(a) * 15.4, Math.cos(a) * 15.4, 2.2, 1.5, a, 0, 0.2 + H[i] + 0.9); }
  addBox(6.0, 12.6 + 3.8, 4.4, 1.9, 0.9, 0, 1.5);
}
/* no-build zone: listed in forge-core.js ZONES (shared with the server's build checks) */
function hyperStop() {
  var H = window.CityHyper; if (!H || !H.pois || H.pois.some(function (p) { return p.id === 'fallen'; })) return;
  var st = toWorld(0, 30);
  H.pois.push({ id: 'fallen', name: NAME, short: 'FALLEN WORLDS', x: POS.x, z: POS.z, stand: { x: st.x, z: st.z },
    alias: 'fallen worlds monument memorial obelisk lightning lightnings twin nine worlds',
    text: 'A 73 m black obelisk struck by the Twin Lightnings, a broken gate and nine world-stones: /saga, /saga-solid, /saga-staging, /ruby, /ruby2, /live, /playaspace, /playa and /soluv. They stay shut down; the monument only remembers them. The Soul Print Tower stands behind it.' });
  if (H.regr