<!-- RUBY-BACKUP · part 473 -->
r nose = new THREE.Mesh(new THREE.SphereGeometry(0.04, 8, 8), skin);
  nose.position.set(0.14, 1.08, 0); g.add(nose);
  [-1,1].forEach(function(s){
    var eye = new THREE.Mesh(new THREE.SphereGeometry(0.025, 8, 8),
      new THREE.MeshStandardMaterial({color: 0x222222}));
    eye.position.set(0.1, 1.15, s*0.06); g.add(eye);
  });
  /* smile */
  var smile = new THREE.Mesh(new THREE.TorusGeometry(0.06, 0.012, 6, 12, Math.PI),
    new THREE.MeshStandardMaterial({color: 0x6a3a2a}));
  smile.position.set(0.12, 1.02, 0); smile.rotation.z = -Math.PI/2; smile.rotation.y = Math.PI/2;
  g.add(smile);
  /* scruffy beard */
  var beard = new THREE.Mesh(new THREE.ConeGeometry(0.1, 0.2, 8),
    new THREE.MeshStandardMaterial({color: 0x888888, roughness: 1}));
  beard.position.set(0.08, 0.92, 0); beard.rotation.z = Math.PI/2;
  g.add(beard);
  /* patched coat */
  var body = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.22, 0.7, 10), coat);
  body.position.y = 0.6; g.add(body);
  /* patch */
  var patch = new THREE.Mesh(new THREE.PlaneGeometry(0.12, 0.12),
    new THREE.MeshStandardMaterial({color: 0xaa4444, roughness: 1}));
  patch.position.set(0, 0.65, 0.21); g.add(patch);
  /* bindle — stick with bag */
  var stick = new THREE.Mesh(new THREE.CylinderGeometry(0.02, 0.02, 1.2, 6),
    new THREE.MeshStandardMaterial({color: 0x6a4a2a}));
  stick.position.set(-0.3, 1.0, 0.25); stick.rotation.z = 0.4;
  g.add(stick);
  var bag = new THREE.Mesh(new THREE.SphereGeometry(0.12, 10, 10), coat);
  bag.position.set(-0.5, 1.35, 0.25); bag.scale.y = 0.8;
  g.add(bag);
  /* legs */
  [-1,1].forEach(function(s){
    var leg = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.05, 0.4, 8), coat);
    leg.position.set(0, 0.2, s*0.09); g.add(leg);
  });
  g.position.set(x, y, z);
  /* gentle sway — content, not sad */
  var t = Math.random()*10;
  var anim = setInterval(function(){
    t += 0.03;
    g.rotation.y = Math.sin(t*0.5)*0.3;
    g.position.y = y + Math.abs(Math.sin(t))*0.02;
  }, 50);
  g.userData.anim = anim;
  return g;
}

/* THREE MORE SOULS — broken robot, tree beggar, unanswerable questions */
function buildBrokenRobot(x, y, z){
  var g = new THREE.Group();
  var rusty = new THREE.MeshStandardMaterial({color: 0x8a6a4a, metalness: 0.5, roughness: 0.8});
  var dark = new THREE.MeshStandardMaterial({color: 0x3a3a3a, roughness: 0.7});
  /* lopsided head */
  var head = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.25, 0.28), rusty);
  head.position.y = 1.3; head.rotation.z = 0.2; /* tilted */
  g.add(head);
  /* one eye working, one flickering */
  var eyeGood = new THREE.Mesh(new THREE.SphereGeometry(0.04, 8, 8),
    new THREE.MeshStandardMaterial({color: 0x00ff00, emissive: 0x00ff00, emissiveIntensity: 1}));
  eyeGood.position.set(0.1, 1.32, 0.15);
  g.add(eyeGood);
  var eyeBad = new THREE.Mesh(new THREE.SphereGeometry(0.04, 8, 8), dark);
  eyeBad.position.set(0.1, 1.32, -0.05);
  g.add(eyeBad);
  /* body — dented */
  var body = new THREE.Mesh(new THREE.BoxGeometry(0.4, 0.6, 0.3), rusty);
  body.position.y = 0.85; body.rotation.x = 0.08;
  g.add(body);
  /* one arm longer than the other */
  var armL = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.5, 8), rusty);
  armL.position.set(0, 0.85, 0.25); g.add(armL);
  var armR = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.35, 8), rusty);
  armR.position.set(0, 0.9, -0.25); g.add(armR);
  /* legs — one bent */
  var legL = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.06, 0.5, 8), rusty);
  legL.position.set(0, 0.25, 0.12); g.add(legL);
  var legR = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.06, 0.5, 8), rusty);
  legR.position.set(0, 0.25, -0.12); legR.rotation.x = 0.3; /* bent */
  g.add(legR);
  /* antenna — sparking */
  var spark = new THREE.Mesh(new THREE.SphereGeometry(0.03, 6, 6),
    new THREE.MeshBasicMaterial({color: 0xffff00}));
  spark.position.set(-0.1, 1.55, 0);
  g.add(spark);
  g.position.set(x, y, z);
  var t = 0;
  var anim = setInterval(function(){
    t += 0.05;
    /* twitchy, malfunctioning */
    head.rotation.z = 0.2 + Math.sin(t*7)*0.05;
    armL.rotation.x = Math.sin(t*3)*0.2;
    spark.material.color.setHex(Math.random()<0.5 ? 0xffff00 : 0xff8800);
    /* occasional hop */
    if(Math.random() < 0.02) g.position.y = y + 0.15;
    else g.position.y += (y - g.position.y)*0.2;
  }, 50);
  g.userData.anim = anim;
  return g;
}
function buildTreeBeggar(x, y, z){
  var g = new THREE.Group();
  /* tree */
  var trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.45, 3, 10),
    new THREE.MeshStandardMaterial({color: 0x5a3a1a, roughness: 0.95}));
  trunk.position.y = 1.5;
  g.add(trunk);
  for(var b=0; b<6; b++){
    var branch = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.12, 1.5, 6),
      new THREE.MeshStandardMaterial({color: 0x5a3a1a, roughness: 0.95}));
    var ba = b*(Math.PI*2/6);
    branch.position.set(Math.cos(ba)*0.7, 2.8, Math.sin(ba)*0.7);
    branch.rotation.z = Mat