<!-- RUBY-BACKUP · part 192 -->
6);
  g.add(namePlate);
  var namePlate2 = namePlate.clone();
  namePlate2.position.set(0, 3, -3.6);
  namePlate2.rotation.y = Math.PI;
  g.add(namePlate2);
  /* star of gladness — golden beacon on top */
  var star = new THREE.Mesh(new THREE.SphereGeometry(0.25, 16, 16), glowGold);
  star.position.y = 6.2; g.add(star);
  var spire = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.08, 1.0, 8), hull);
  spire.position.y = 5.7; g.add(spire);
  g.userData.name = 'Hokulea';
  return g;
}
function summonHokulea(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  if(MOTHERSHIP){
    try{ scene.remove(MOTHERSHIP.mesh); }catch(e){}
    if(MOTHERSHIP.anim) clearInterval(MOTHERSHIP.anim);
  }
  var ship = buildMothership();
  var cx = mePos.x*0.13, cz = mePos.z*0.13;
  var orbitRadius = 25;
  var orbitHeight = 35; /* high orbit */
  ship.position.set(cx + orbitRadius, orbitHeight, cz);
  scene.add(ship);
  /* stays in orbit — circles above, never lands */
  var t = 0;
  var anim = setInterval(function(){
    t += 0.008; /* slow, majestic */
    ship.position.x = cx + Math.cos(t)*orbitRadius;
    ship.position.z = cz + Math.sin(t)*orbitRadius;
    ship.position.y = orbitHeight + Math.sin(t*2)*1.0;
    /* face direction of travel */
    ship.rotation.y = -t;
  }, 50);
  MOTHERSHIP = {mesh: ship, anim: anim};
  codeStatus('HOKULEA — in orbit. She stays above, watching.');
}
function dismissHokulea(){
  if(MOTHERSHIP){
    try{ scene.remove(MOTHERSHIP.mesh); }catch(e){}
    if(MOTHERSHIP.anim) clearInterval(MOTHERSHIP.anim);
    MOTHERSHIP = null;
    codeStatus('Hokulea departs');
  }
}
function buildSpaceport(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  SPACESHIPS.forEach(function(s){ try{ scene.remove(s.mesh); }catch(e){} if(s.anim) clearInterval(s.anim); });
  LANDING_PADS.forEach(function(p){ try{ scene.remove(p); }catch(e){} });
  SPACESHIPS = []; LANDING_PADS = [];
  var px = mePos.x, pz = mePos.z;
  /* spaceport — 3 landing pads */
  for(var i=0; i<3; i++){
    var x = px + 30 + i*10, z = pz + 30;
    var pad = buildLandingPad(x, z);
    scene.add(pad);
    LANDING_PADS.push(pad);
    /* ship on pad */
    if(i < 2){
      var ship = buildSpaceship();
      ship.position.set(x*0.13, 0, z*0.13);
      scene.add(ship);
      pad.userData.occupied = true;
      /* hover animation */
      (function(sh, pd){
        var t = Math.random()*10;
        var anim = setInterval(function(){
          t += 0.03;
          if(sh.userData.state==='landed'){
            sh.position.y = Math.sin(t*2)*0.05;
          }else if(sh.userData.state==='takingoff'){
            sh.position.y += 0.05;
            if(sh.position.y > 8) sh.userData.state = 'hover';
          }else if(sh.userData.state==='hover'){
            sh.position.y = 8 + Math.sin(t)*0.3;
            sh.rotation.y += 0.01;
          }
        }, 50);
        SPACESHIPS.push({mesh: sh, anim: anim, pad: pd});
      })(ship, pad);
    }
  }
  codeStatus('spaceport — 3 landing pads, 2 ships. The future lands here.');
}
function launchShip(idx){
  idx = idx || 0;
  if(SPACESHIPS[idx]){
    SPACESHIPS[idx].mesh.userData.state = 'takingoff';
    codeStatus('ship launching');
  }else{
    codeStatus('no ship at index '+idx);
  }
}
function landShip(idx){
  idx = idx || 0;
  if(SPACESHIPS[idx]){
    SPACESHIPS[idx].mesh.userData.state = 'landed';
    SPACESHIPS[idx].mesh.position.y = 0;
    codeStatus('ship landed');
  }
}
function clearSpaceport(){
  SPACESHIPS.forEach(function(s){ try{ scene.remove(s.mesh); }catch(e){} if(s.anim) clearInterval(s.anim); });
  LANDING_PADS.forEach(function(p){ try{ scene.remove(p); }catch(e){} });
  SPACESHIPS = []; LANDING_PADS = [];
  codeStatus('spaceport cleared');
}

/* THE OFFICER AND THE FIREFIGHTER */
var OFFICER_GROUP = null;
function buildPoliceOfficer(x, y, z){
  var g = new THREE.Group();
  var skin = new THREE.MeshStandardMaterial({color: 0xc89868, roughness: 0.7});
  var uniform = new THREE.MeshStandardMaterial({color: 0x1a2a5a, roughness: 0.7});
  /* head */
  var head = new THREE.Mesh(new THREE.SphereGeometry(0.15, 18, 18), skin);
  head.position.y = 1.55; g.add(head);
  /* police cap */
  var cap = new THREE.Mesh(new THREE.CylinderGeometry(0.16, 0.17, 0.1, 12), uniform);
  cap.position.y = 1.68; g.add(cap);
  var badge = new THREE.Mesh(new THREE.CircleGeometry(0.04, 8),
    new THREE.MeshStandardMaterial({color: 0xffcc00, metalness: 0.8, roughness: 0.3}));
  badge.position.set(0, 1.68, 0.16); g.add(badge);
  /* concerned eyes — looking for the pad */
  [-1,1].forEach(function(s){
    var eye = new THREE.Mesh(new THREE.SphereGeometry(0.025, 10, 10),
      new THREE.MeshStandardMaterial({color: 0x222222}));
    eye.position.set(0.08, 1.57, s*0.06); g.add(eye);
  });
  /* uniform body */
  var body = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.22, 0.9, 12), uniform);
  body.position.y = 1.0; g.add(body);
  /* badge on chest */
  var 