<!-- RUBY-BACKUP · part 234 -->
3; /* lounging */
  g.add(beggar);
  g.position.set(x, y, z);
  var t = Math.random()*10;
  var anim = setInterval(function(){
    t += 0.03;
    /* swinging legs, content */
    beggar.rotation.z = -0.3 + Math.sin(t)*0.08;
    cup.position.y = 0.3 + Math.sin(t*2)*0.03; /* jingling cup */
  }, 50);
  g.userData.anim = anim;
  return g;
}
function buildQuestionGuy(x, y, z){
  var g = new THREE.Group();
  var skin = new THREE.MeshStandardMaterial({color: 0xd4a574, roughness: 0.7});
  var robe = new THREE.MeshStandardMaterial({color: 0x4a4a6a, roughness: 0.85});
  /* thoughtful pose — hand on chin */
  var head = new THREE.Mesh(new THREE.SphereGeometry(0.15, 16, 16), skin);
  head.position.y = 1.45; head.rotation.x = -0.15; /* looking up, thinking */
  g.add(head);
  /* furrowed brow */
  var brow = new THREE.Mesh(new THREE.BoxGeometry(0.02, 0.02, 0.12),
    new THREE.MeshStandardMaterial({color: 0x2a1a0a}));
  brow.position.set(0.12, 1.5, 0);
  g.add(brow);
  var body = new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0.28, 1.0, 12), robe);
  body.position.y = 0.8; g.add(body);
  /* hand on chin */
  var arm = new THREE.Mesh(new THREE.CylinderGeometry(0.045, 0.04, 0.4, 8), robe);
  arm.position.set(0.15, 1.15, 0.15); arm.rotation.z = -0.8;
  g.add(arm);
  var hand = new THREE.Mesh(new THREE.SphereGeometry(0.05, 10, 10), skin);
  hand.position.set(0.1, 1.35, 0.08);
  g.add(hand);
  /* question marks — floating */
  var questions = [
    'Why is the sky?',
    'What is a thought?',
    'Where does lost go?',
    'Who asks the asker?'
  ];
  var qIdx = 0;
  var qCv = document.createElement('canvas');
  qCv.width = 512; qCv.height = 64;
  var qCtx = qCv.getContext('2d');
  var qTex = new THREE.CanvasTexture(qCv);
  var qLabel = new THREE.Mesh(new THREE.PlaneGeometry(2.5, 0.31),
    new THREE.MeshBasicMaterial({map: qTex, transparent: true}));
  qLabel.position.set(0, 2.0, 0);
  g.add(qLabel);
  function drawQuestion(){
    qCtx.clearRect(0, 0, 512, 64);
    qCtx.fillStyle = '#aaccff';
    qCtx.font = 'italic 28px Georgia';
    qCtx.textAlign = 'center';
    qCtx.fillText(questions[qIdx], 256, 42);
    qTex.needsUpdate = true;
    qIdx = (qIdx+1) % questions.length;
  }
  drawQuestion();
  var qTimer = setInterval(drawQuestion, 4000);
  g.userData.qTimer = qTimer;
  g.position.set(x, y, z);
  var t = 0;
  var anim = setInterval(function(){
    t += 0.02;
    /* pacing — back and forth, thinking */
    g.position.x = x + Math.sin(t*0.5)*1.5;
    g.rotation.y = Math.cos(t*0.5) > 0 ? Math.PI/2 : -Math.PI/2;
    head.rotation.x = -0.15 + Math.sin(t*2)*0.05;
  }, 50);
  g.userData.anim = anim;
  return g;
}
function placeThreeSouls(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  var px = mePos.x, pz = mePos.z;
  /* broken robot — near the underworld */
  var br = buildBrokenRobot((px-175)*0.13, 0, (pz+125)*0.13);
  scene.add(br);
  /* beggar in tree — near storm beach */
  var tb = buildTreeBeggar((px-175)*0.13, 0, (pz-115)*0.13);
  scene.add(tb);
  /* question guy — near wormholes */
  var qg = buildQuestionGuy((px+175)*0.13, 0, (pz+125)*0.13);
  scene.add(qg);
  if(!DARK_PLACES) DARK_PLACES = [];
  DARK_PLACES.push(br, tb, qg);
  codeStatus('three more souls — broken robot, tree beggar, question guy.');
}

/* GOOD SOULS — they come by and give missions */
var MISSION_GIVERS = [];
var MISSIONS = [
  {giver: 'Kai', soul: 'broken robot', text: 'Find three gears to fix my arm'},
  {giver: 'Leilani', soul: 'tree beggar', text: 'Share your cup with someone thirsty'},
  {giver: 'Makoa', soul: 'question guy', text: 'Find one answer, any answer'},
  {giver: 'Nalani', soul: 'homeless', text: 'Sing a song for the valley'},
  {giver: 'Keala', soul: 'broken robot', text: 'Learn to dance with your bent leg'}
];
function buildMissionGiver(name, colorHex, x, y, z, targetX, targetZ){
  var g = new THREE.Group();
  var skin = new THREE.MeshStandardMaterial({color: 0xd4a574, roughness: 0.6});
  var cloth = new THREE.MeshStandardMaterial({color: colorHex, roughness: 0.7});
  /* kind face */
  var head = new THREE.Mesh(new THREE.SphereGeometry(0.15, 18, 18), skin);
  head.position.y = 1.5; g.add(head);
  /* warm smile */
  var smile = new THREE.Mesh(new THREE.TorusGeometry(0.06, 0.012, 6, 12, Math.PI),
    new THREE.MeshStandardMaterial({color: 0x8a4a3a}));
  smile.position.set(0.11, 1.45, 0); smile.rotation.y = Math.PI/2; smile.rotation.z = Math.PI;
  g.add(smile);
  /* bright eyes */
  [-1,1].forEach(function(s){
    var eye = new THREE.Mesh(new THREE.SphereGeometry(0.022, 10, 10),
      new THREE.MeshStandardMaterial({color: 0x222222}));
    eye.position.set(0.12, 1.53, s*0.06); g.add(eye);
  });
  /* glowing heart — they are good */
  var heart = new THREE.Mesh(new THREE.SphereGeometry(0.06, 10, 10),
    new THREE.MeshStandardMaterial({color: 0xff6699, emissive: 0xff6699, emissiveIntensity: 1.5}));
  heart.position.set(0, 1.15, 0.16); heart.scale.set(1, 1.2, 0.6);
  g.add(he