<!-- RUBY-BACKUP · part 472 -->
*Math.PI*2;
    var rad = 3+Math.random()*4;
    soul.position.set(Math.cos(ang)*rad, 4+Math.random()*8, Math.sin(ang)*rad);
    soul.userData = {ang: ang, rad: rad, speed: 0.005+Math.random()*0.01, yBase: soul.position.y};
    g.add(soul);
    souls.push(soul);
  }
  var t = 0;
  var soulAnim = setInterval(function(){
    t += 0.02;
    souls.forEach(function(sl){
      sl.userData.ang += sl.userData.speed;
      sl.position.x = Math.cos(sl.userData.ang)*sl.userData.rad;
      sl.position.z = Math.sin(sl.userData.ang)*sl.userData.rad;
      sl.position.y = sl.userData.yBase + Math.sin(t*2+sl.userData.ang)*0.5;
      sl.material.opacity = 0.4 + Math.sin(t*3+sl.userData.ang)*0.25;
    });
  }, 50);
  g.userData.anim = soulAnim;
  var sign = buildStreetSign('LOST SOULS PEAK', 0, 10, 0);
  g.add(sign);
  g.position.set(x*0.13, 0, z*0.13);
  return g;
}
function buildUnderworldFallacy(x, z){
  var g = new THREE.Group();
  /* impossible geometry — Penrose-like */
  var darkRed = new THREE.MeshStandardMaterial({color: 0x4a0a0a, roughness: 0.8});
  var glowRed = new THREE.MeshStandardMaterial({color: 0xff2222, emissive: 0xff2222, emissiveIntensity: 1});
  /* floating paradox cubes — rotating impossibly */
  var cubes = [];
  for(var i=0; i<5; i++){
    var cube = new THREE.Mesh(new THREE.BoxGeometry(1.5, 1.5, 1.5), darkRed);
    cube.position.set((Math.random()-0.5)*10, 2+Math.random()*4, (Math.random()-0.5)*10);
    /* edges glow */
    var edges = new THREE.LineSegments(
      new THREE.EdgesGeometry(cube.geometry),
      new THREE.LineBasicMaterial({color: 0xff4444})
    );
    cube.add(edges);
    g.add(cube);
    cubes.push(cube);
  }
  var t = 0;
  var paradoxAnim = setInterval(function(){
    t += 0.02;
    cubes.forEach(function(cb, idx){
      cb.rotation.x = t*(0.5+idx*0.1);
      cb.rotation.y = t*(0.3+idx*0.15);
      cb.position.y += Math.sin(t*2+idx)*0.01;
    });
  }, 50);
  g.userData.anim = paradoxAnim;
  /* ground — cracked */
  var ground = new THREE.Mesh(new THREE.CircleGeometry(8, 24),
    new THREE.MeshStandardMaterial({color: 0x1a0a0a, roughness: 1}));
  ground.rotation.x = -Math.PI/2; ground.position.y = 0.05;
  g.add(ground);
  /* fallacy text — floating */
  var fallacies = ['AD HOMINEM', 'STRAW MAN', 'FALSE DILEMMA', 'CIRCULAR'];
  fallacies.forEach(function(fal, fi){
    var cv = document.createElement('canvas');
    cv.width = 256; cv.height = 48;
    var ctx = cv.getContext('2d');
    ctx.fillStyle = '#ff4444'; ctx.font = 'bold 22px Arial';
    ctx.textAlign = 'center'; ctx.fillText(fal, 128, 32);
    var tex = new THREE.CanvasTexture(cv);
    var label = new THREE.Mesh(new THREE.PlaneGeometry(2.5, 0.47),
      new THREE.MeshBasicMaterial({map: tex, transparent: true}));
    var fa = fi*(Math.PI*2/4);
    label.position.set(Math.cos(fa)*5, 3, Math.sin(fa)*5);
    label.rotation.y = -fa + Math.PI/2;
    g.add(label);
  });
  var sign = buildStreetSign('UNDERWORLD FALLACY', 0, 10, 0);
  g.add(sign);
  g.position.set(x*0.13, 0, z*0.13);
  return g;
}
function buildParadoxWormholes(x, z){
  var g = new THREE.Group();
  var wormholes = [];
  var colors = [0xff00ff, 0x00ffff, 0xffff00];
  colors.forEach(function(col, i){
    var wg = new THREE.Group();
    /* swirling portal */
    var portal = new THREE.Mesh(new THREE.TorusGeometry(1.5, 0.3, 12, 32),
      new THREE.MeshStandardMaterial({
        color: col, emissive: col, emissiveIntensity: 1.5,
        transparent: true, opacity: 0.85
      }));
    wg.add(portal);
    /* inner void */
    var void_ = new THREE.Mesh(new THREE.CircleGeometry(1.3, 24),
      new THREE.MeshBasicMaterial({color: 0x000000}));
    wg.add(void_);
    /* event horizon shimmer */
    var shimmer = new THREE.Mesh(new THREE.TorusGeometry(1.1, 0.1, 8, 24),
      new THREE.MeshBasicMaterial({color: 0xffffff, transparent: true, opacity: 0.5}));
    wg.add(shimmer);
    var ang = i*(Math.PI*2/3);
    wg.position.set(Math.cos(ang)*8, 2.5, Math.sin(ang)*8);
    wg.rotation.y = -ang + Math.PI/2;
    g.add(wg);
    wormholes.push({group: wg, portal: portal, shimmer: shimmer, speed: 0.02+i*0.01});
  });
  var t = 0;
  var wormAnim = setInterval(function(){
    t += 0.02;
    wormholes.forEach(function(wh){
      wh.portal.rotation.z += wh.speed;
      wh.shimmer.rotation.z -= wh.speed*1.5;
      wh.shimmer.material.opacity = 0.3 + Math.sin(t*4)*0.25;
    });
  }, 50);
  g.userData.anim = wormAnim;
  var sign = buildStreetSign('PARADOX WORMHOLES', 0, 12, 0);
  g.add(sign);
  g.position.set(x*0.13, 0, z*0.13);
  return g;
}
function buildFunnyHomeless(x, y, z){
  /* funny-looking, not scary — a gentle soul */
  var g = new THREE.Group();
  var skin = new THREE.MeshStandardMaterial({color: 0xc89868, roughness: 0.8});
  var coat = new THREE.MeshStandardMaterial({color: 0x6a5a4a, roughness: 1});
  /* head — big nose, kind eyes */
  var head = new THREE.Mesh(new THREE.SphereGeometry(0.16, 14, 14), skin);
  head.position.y = 1.1; g.add(head);
  va