<!-- RUBY-BACKUP · part 189 -->
 h: height, hue: hue}));
  }catch(e){}
  return g;
}

/* ANCESTRAL STREETS — signs for the last names of his lineage */
var ANCESTOR_STREETS = [
  'UENUKU', 'LILOA', 'UMI', 'KEAWE', 'KUKOHOU', 'KUAIWA',
  'HAKAU', 'KAHOUKAPU', 'MOKULANI', 'ULULANI',
  'KAIWAOKALANI', 'KANAKAOLE', 'WILCOX', 'KAILIWAI', 'KAMAILE',
  /* first names of those who have only one */
  'POTIKI', 'HIHIRIOTU', 'TARANGA', 'TAHARAWA', 'HEKAPONGA',
  'RAKAU', 'WHATOMA', 'POUTIRIAO', 'TANE', 'KAMEA',
  'POHUKAINA', 'HUA', 'PAU', 'PAUMAKUA', 'HAHO',
  'PALENA', 'LANAKAWAI', 'PILI', 'KANIUIHI', 'KANIPAHU',
  'KALAPANA', 'KAHAIMOELEA', 'KALAUNUIOHUA', 'KAUHOLANUIMAHU',
  'KIHA', 'KEALIIOKALOA', 'KUKAILANI', 'KAPUKAMOLA',
  'MAKAKAUalii', 'IWIKAWIKAUA', 'KANEIKAIWILANI',
  'KEAWEMAUHILI', 'NIAU', 'NAHOLOWAA', 'MUKOI',
  'KALUA', 'KAIKIOEWA', 'MAIKAI', 'PAOKALANI',
  'KAPIHA', 'NALIPOEPOE', 'KAPIHANUI', 'LELEKU',
  /* Hawaiian royal family — no titles */
  'KALANIKAULELEIAWI', 'KALANINUIAMAMAO', 'KEAWEKAHIALII',
  'KAIMAMAO', 'LONAAKEAWE',
  /* Hawaiian words for extinct animals — gone but remembered */
  'MOANALO', 'MAMO', 'OO', 'POOULI',
  'AKIALOA', 'NUKUPUU', 'KAKAWAHIE', 'OU'
];
var STREET_SIGNS = [];
function makeIntaglioSignTexture(name){
  /* canvas — ultra-dense intaglio linework + future symbols */
  var cv = document.createElement('canvas');
  cv.width = 512; cv.height = 128;
  var ctx = cv.getContext('2d');
  /* dark background */
  ctx.fillStyle = '#0a0a12';
  ctx.fillRect(0, 0, 512, 128);
  /* intaglio — dense fine lines */
  ctx.strokeStyle = 'rgba(200,170,100,0.25)';
  ctx.lineWidth = 0.5;
  for(var i=0; i<40; i++){
    ctx.beginPath();
    ctx.moveTo(0, i*3.2);
    ctx.bezierCurveTo(170, i*3.2+8, 340, i*3.2-8, 512, i*3.2);
    ctx.stroke();
  }
  /* border — double line */
  ctx.strokeStyle = '#c8aa64';
  ctx.lineWidth = 3;
  ctx.strokeRect(6, 6, 500, 116);
  ctx.lineWidth = 1;
  ctx.strokeRect(12, 12, 488, 104);
  /* future symbols — geometric accents */
  ctx.fillStyle = 'rgba(100,200,255,0.6)';
  [[20,64],[492,64]].forEach(function(p){
    ctx.beginPath();
    ctx.moveTo(p[0], p[1]-12);
    ctx.lineTo(p[0]+8, p[1]);
    ctx.lineTo(p[0], p[1]+12);
    ctx.lineTo(p[0]-8, p[1]);
    ctx.closePath();
    ctx.fill();
  });
  /* the name — last name only */
  ctx.fillStyle = '#f0e0c0';
  ctx.font = 'bold 44px Georgia, serif';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  /* letterpress shadow for depth */
  ctx.fillStyle = 'rgba(0,0,0,0.7)';
  ctx.fillText(name, 258, 66);
  ctx.fillStyle = '#f0e0c0';
  ctx.fillText(name, 256, 64);
  var tex = new THREE.CanvasTexture(cv);
  tex.anisotropy = 4;
  return tex;
}
function buildStreetSign(name, x, z, rotationY){
  var g = new THREE.Group();
  /* post — dark metal */
  var post = new THREE.Mesh(
    new THREE.CylinderGeometry(0.06, 0.08, 2.2, 12),
    new THREE.MeshStandardMaterial({color: 0x2a2a3a, metalness: 0.8, roughness: 0.4})
  );
  post.position.y = 1.1;
  g.add(post);
  /* sign plate — double-sided */
  var tex = makeIntaglioSignTexture(name);
  var plateMat = new THREE.MeshStandardMaterial({
    map: tex, metalness: 0.3, roughness: 0.6,
    emissive: 0xffffff, emissiveMap: tex, emissiveIntensity: 0.15
  });
  var plate = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.45, 0.06), plateMat);
  plate.position.y = 2.0;
  g.add(plate);
  /* future glow — underlight */
  var glow = new THREE.Mesh(new THREE.SphereGeometry(0.04, 10, 10),
    new THREE.MeshStandardMaterial({color: 0x64c8ff, emissive: 0x64c8ff, emissiveIntensity: 2}));
  glow.position.y = 1.75;
  g.add(glow);
  g.position.set(x*0.13, 0, z*0.13);
  g.rotation.y = rotationY || 0;
  return g;
}
function placeAncestorStreets(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  STREET_SIGNS.forEach(function(s){ try{ scene.remove(s); }catch(e){} });
  STREET_SIGNS = [];
  var px = mePos.x, pz = mePos.z;
  /* place along the street grid */
  ANCESTOR_STREETS.forEach(function(name, i){
    var side = i % 4;
    var idx = Math.floor(i/4);
    var x, z, rot;
    var spread = 24; /* expanded */
    if(side===0){ x = px + (idx-8)*spread; z = pz - 8; rot = 0; }
    else if(side===1){ x = px + (idx-8)*spread; z = pz + 8; rot = Math.PI; }
    else if(side===2){ x = px - 8; z = pz + (idx-8)*spread; rot = Math.PI/2; }
    else { x = px + 8; z = pz + (idx-8)*spread; rot = -Math.PI/2; }
    var sign = buildStreetSign(name, x, z, rot);
    scene.add(sign);
    STREET_SIGNS.push(sign);
  });
  /* save the names as the street list */
  setStreetNames(ANCESTOR_STREETS.map(function(n){
    return n.charAt(0)+n.slice(1).toLowerCase();
  }));
  codeStatus('ancestral streets — 15 signs, last names only. Intaglio and future.');
}
function clearAncestorStreets(){
  STREET_SIGNS.forEach(function(s){ try{ scene.remove(s); }catch(e){} });
  STREET_SIGNS = [];
  codeStatus('ancestor streets cleared');
}
function buildCity(){
  if(typeof scene==='undefined' || typeof mePos==='undefined')