<!-- SOLID CITY · part 21 -->
 'px Georgia, serif'; }
  g.fillText(name, 256, 66);
  var t = new T.CanvasTexture(c); t.encoding = T.sRGBEncoding; t.anisotropy = 4; return t;
}
export function createAncestorRoads(o) {
  var T = o.THREE, P = o.position || { x: 0, y: 0, z: 0 };
  var root = new T.Group(); root.name = 'ancestor-roads'; root.position.set(P.x, P.y, P.z);
  var foot = [];
  var C = { gold: 0xd8aa48, basalt: 0x141114, stone: 0x2a242a };
  // Platform: a great circular terrace; the roads rest on it.
  var plat = new T.Mesh(new T.CylinderGeometry(540, 560, 100, 64), new T.MeshLambertMaterial({ color: C.stone }));
  plat.position.y = -50; root.add(plat);
  var platTop = new T.Mesh(new T.CylinderGeometry(540, 540, 2, 64), new T.MeshLambertMaterial({ color: 0x3a3230 }));
  platTop.position.y = 1; root.add(platTop);
  var brick = brickTexture(T);
  var brickMat = new T.MeshLambertMaterial({ map: brick });
  var goldMat = new T.MeshLambertMaterial({ color: C.gold, emissive: 0x2a1a04 });
  var postGeo = new T.CylinderGeometry(0.35, 0.45, 5, 8);
  // 5 rings x 11 roads
  var RINGS = [130, 210, 290, 370, 450], ni = 0, r, i, a, x, z, segLen, seg;
  var signs = [];
  for (r = 0; r < 5; r++) {
    var rad = RINGS[r], circ = 2 * Math.PI * rad, arc = circ / 11;
    for (i = 0; i < 11; i++) {
      var name = NAMES[ni++];
      a = (i / 11) * Math.PI * 2;
      x = Math.cos(a) * rad; z = Math.sin(a) * rad;
      // road segment: brick box laid tangent to the ring
      segLen = arc * 0.92;
      seg = new T.Mesh(new T.BoxGeometry(segLen, 0.6, 16), brickMat);
      seg.position.set(x, 2.3, z); seg.rotation.y = -a + Math.PI / 2;
      root.add(seg);
      // THE ONE ROAD (2026-10-12): a flush brick paver fills the gap to the
      // next ancestor's road — same height, same brick, butt joint — so each
      // ring runs as one continuous smooth circle. The named segments stay
      // distinct by their signs; the surface no longer steps down to bare
      // terrace and back up between them.
      var ga2 = a + Math.PI / 11;
      var pav = new T.Mesh(new T.BoxGeometry(arc * 0.08, 0.6, 16), brickMat);
      pav.position.set(Math.cos(ga2) * rad, 2.3, Math.sin(ga2) * rad);
      pav.rotation.y = -ga2 + Math.PI / 2;
      root.add(pav);
      // gold sign post at the segment's start, name plate facing outward.
      // THE ONE ROAD: the post stands at the road's OUTER EDGE now, not on
      // its centreline — it names the road without standing in the traveller.
      var sa = a - (Math.PI / 11) * 0.92;
      var sx = Math.cos(sa) * (rad + 9.6), sz = Math.sin(sa) * (rad + 9.6);
      var post = new T.Mesh(postGeo, goldMat);
      post.position.set(sx, 4.5, sz); root.add(post);
      var plate = new T.Mesh(new T.PlaneGeometry(10, 2.5),
        new T.MeshBasicMaterial({ map: namePlate(T, name), side: T.DoubleSide }));
      plate.position.set(sx, 6.4, sz);
      plate.rotation.y = -sa + Math.PI / 2;
      root.add(plate); signs.push(plate);
      foot.push([sx, sz, 1.2, 1.2, 0, 7, 0]);
    }
    // thin gold ring marking the circle
    var ring = new T.Mesh(new T.TorusGeometry(rad, 0.25, 4, 96), new T.MeshBasicMaterial({ color: C.gold }));
    ring.rotation.x = Math.PI / 2; ring.position.y = 2.65; root.add(ring);
  }
  // Centre: the fire — a stone circle with an eternal flame for the ancestors
  var fireBase = new T.Mesh(new T.CylinderGeometry(14, 16, 3, 24), new T.MeshLambertMaterial({ color: C.basalt }));
  fireBase.position.y = 3.5; root.add(fireBase);
  var flame = new T.Mesh(new T.ConeGeometry(4, 12, 12),
    new T.MeshBasicMaterial({ color: 0xff9a30, transparent: true, opacity: 0.85 }));
  flame.position.y = 14; root.add(flame);
  var flameGlow = new T.PointLight(0xff9a30, 1.4, 120);
  flameGlow.position.y = 14; root.add(flameGlow);
  foot.push([0, 0, 32, 32, 0, 9, 0]);
  // North ramp: a stair from the terrace down toward the city
  var ramp = new T.Mesh(new T.BoxGeometry(40, 2, 120), brickMat);
  ramp.position.set(0, -18, 595); ramp.rotation.x = 0.32; root.add(ramp);
  // stepped collision for the ramp (AABBs cannot slope)
  foot.push([0, 550, 40, 30, -9, 1, 0]);
  foot.push([0, 580, 40, 30, -19, -9, 0]);
  foot.push([0, 610, 40, 30, -29, -19, 0]);
  foot.push([0, 640, 40, 30, -37, -29, 0]);
  root.userData = {
    footprint: foot, center: { x: 0, z: 0 }, radius: 560, height: 30,
    update: function (t) {
      flame.scale.y = 1 + Math.sin(t * 3.1) * 0.12;
      flameGlow.intensity = 1.3 + Math.sin(t * 3.1) * 0.25;
    }
  };
  return root;
}
export default createAncestorRoads;


===== FILE: public/city/ancestor-roads.js.bak-oneroad-20261012 =====
/* SOLID CITY — THE ANCESTRAL ROADS (2026-10-11, by order of the King)
 * "Give retry the road system of a Hawaiian Ancestry."
 * 55 brick roads for 55 ancestors, Maui-Potiki to Kamaile, in 5 rings.
 * Ring 0 (innermost) = the oldest; Ring 4 (outermost) = the newest, ending with
 * Wilcox, Kailiwai, Kamaile — his family, closest to the city and the future.
 * Self-