<!-- SAGA2 · part 91 -->
// sparkles drift + fade
  for(var si=sparkles.length-1; si>=0; si--){
    var spk=sparkles[si], u=spk.userData;
    u.life-=dt;
    spk.position.x+=u.vx*dt; spk.position.y+=u.vy*dt; spk.position.z+=u.vz*dt;
    spk.rotation.x+=dt*5; spk.rotation.y+=dt*7;
    spk.material.opacity=Math.max(0,u.life*2);
    if(u.life<=0){ scene.remove(spk); sparkles.splice(si,1); }
  }
  // scorch marks fade shortly
  for(var mi=scorchMarks.length-1; mi>=0; mi--){
    var sm=scorchMarks[mi];
    sm.life-=dt;
    if(sm.life<1.5) sm.m.material.opacity=Math.max(0, sm.life/1.5*0.85);
    if(sm.life<=0){ scene.remove(sm.m); scorchMarks.splice(mi,1); }
  }
  renderer.render(scene,camera);
}
// BLACKOUT — only avatars and h=10 remain
//buildSentinel();
//buildScout();
//buildHuman();
buildAvatar();
// BLACK WALL behind the winning face (King's order)
(function(){
  var wall = new THREE.Mesh(
    new THREE.PlaneGeometry(60, 40),
    new THREE.MeshBasicMaterial({color:0x080808})
  );
  wall.position.set(0, 14, 132);
  // face the soldiers/camera (toward -Z)
  wall.rotation.y = Math.PI;
  scene.add(wall);
})();

// MANNEQUIN HEAD — winner's face (index 0), clean 3D form (King's order)
(function(){ return; // BLACKOUT
  var mg = new THREE.Group();
  var mCyan = new THREE.LineBasicMaterial({color:0x66eeff, transparent:true, opacity:0.85});
  var mGold = new THREE.LineBasicMaterial({color:0xffcc44, transparent:true, opacity:0.85});
  function mline(pts, mat){
    mg.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(pts.map(function(p){
      return new THREE.Vector3(p[0],p[1],p[2]); })), mat));
  }
  function mellipse(cx,cy,cz,rx,ry,mat,rz){
    var pts=[];
    for(var i=0;i<=24;i++){ var a=(i/24)*Math.PI*2;
      pts.push(new THREE.Vector3(cx+Math.cos(a)*rx, cy+Math.sin(a)*ry, (rz||0)+cz*0.1));
      // Actually 3D: vary z with angle for form
      pts[pts.length-1].z = cz + Math.sin(a)*ry*0.3;
    }
    mline(pts, mat);
  }
  // CRANIUM — clean sphere meridians (8)
  for(var mi=0; mi<8; mi++){
    var ma = (mi/8)*Math.PI*2, mpts=[];
    for(var mh=0; mh<=12; mh++){
      var phi = (mh/12)*Math.PI; // 0 to PI
      var mr = 5.0*Math.sin(phi);
      mpts.push([Math.cos(ma)*mr, 5.0*Math.cos(phi)+2, Math.sin(ma)*mr*0.92]);
    }
    mline(mpts, mi%2?mGold:mCyan);
  }
  // CRANIUM — latitudinal (5)
  for(var la=0; la<5; la++){
    var ly = 6.5 - la*2.2, lr = 5.0*Math.sqrt(Math.max(0,1-Math.pow((ly-2)/5.0,2)));
    var lpts=[];
    for(var la2=0; la2<=24; la2++){ var ang=(la2/24)*Math.PI*2;
      lpts.push([Math.cos(ang)*lr, ly, Math.sin(ang)*lr*0.92]);
    }
    mline(lpts, la%2?mCyan:mGold);
  }
  // FACE — sculptural relief (King: indented eyes, protruding nose, lip work)
  var eDX = 1.9, eSZ = 1.15;
  // center line
  mline([[0,7,4.6],[0,3,5.0],[0,0,5.2],[0,-2.5,5.0]], mGold);
  // brows (on surface)
  mline([[-3.2,3.2,4.2],[-eDX,3.5,4.6],[-0.8,3.2,4.7]], mGold);
  mline([[0.8,3.2,4.7],[eDX,3.5,4.6],[3.2,3.2,4.2]], mGold);
  // EYE SOCKETS — indented (concave bowl, z dips in)
  function eyeSocket(cx){
    // socket rim (surface)
    mellipse(cx, 2.0, 4.9, eSZ+0.5, eSZ*0.5+0.4, mGold);
    // socket bowl — lines curving INWARD (z decreases toward center)
    for(var sb=0; sb<3; sb++){
      var sr = eSZ+0.3-sb*0.25, sz = 4.9-sb*0.25;
      mellipse(cx, 2.0, sz, sr, sr*0.5, mCyan);
    }
    // eyeball (recessed, z=4.1)
    mellipse(cx, 2.0, 4.1, eSZ*0.7, eSZ*0.35, mCyan);
    mellipse(cx, 2.0, 4.15, 0.3, 0.3, mGold); // pupil
  }
  eyeSocket(-eDX); eyeSocket(eDX);
  // NOSE — protruding (convex, z pushes OUT)
  // bridge (rises from face)
  mline([[0,2.5,4.9],[0,1.5,5.3],[0,0.5,5.6],[0,-0.5,5.9]], mGold);
  // nose sides (showing protrusion)
  mline([[-0.4,2.0,4.95],[-0.5,1.0,5.4],[-0.6,0,5.7],[-0.7,-1.0,5.8]], mCyan);
  mline([[0.4,2.0,4.95],[0.5,1.0,5.4],[0.6,0,5.7],[0.7,-1.0,5.8]], mCyan);
  // tip (most protruding, z=6.0)
  mellipse(0, -1.2, 5.95, 0.6, 0.4, mGold);
  // nostrils (under tip, recessed)
  mellipse(-0.45, -1.5, 5.7, 0.22, 0.15, mCyan);
  mellipse(0.45, -1.5, 5.7, 0.22, 0.15, mCyan);
  // nostril wings
  mline([[-0.7,-1.0,5.8],[-0.85,-1.5,5.6],[-0.7,-1.9,5.4]], mCyan);
  mline([[0.7,-1.0,5.8],[0.85,-1.5,5.6],[0.7,-1.9,5.4]], mCyan);
  // LIPS — volume (upper protrudes, mouth recessed, lower protrudes)
  // upper lip (z=5.4, full)
  mline([[-1.6,-2.6,5.2],[-1.0,-2.4,5.35],[-0.3,-2.3,5.4],[0,-2.35,5.42],[0.3,-2.3,5.4],[1.0,-2.4,5.35],[1.6,-2.6,5.2]], mGold);
  // mouth line (recessed, z=5.0)
  mline([[-1.5,-2.9,5.0],[-0.8,-3.05,5.05],[0,-3.0,5.08],[0.8,-3.05,5.05],[1.5,-2.9,5.0]], mCyan);
  // lower lip (z=5.5, fullest)
  mline([[-1.3,-3.2,5.3],[-0.7,-3.5,5.5],[0,-3.6,5.55],[0.7,-3.5,5.5],[1.3,-3.2,5.3]], mGold);
  // chin (recessed below lip, then jaw)
  mline([[-1.0,-4.2,5.2],[-0.4,-4.6,5.3],[0,-4.7,5.35],[0.4,-4.6,5.3],[1.0,-4.2,5.2]], mCyan);
  // jaw — mannequin smooth
  mline([[-4.5,1.5,3.5],[-3.8,-1,4.2],[-2.5,-3.5,4.6],[-1,-4.5,4.8],[0,-4.8,4.9]], mCyan);
  mline([[0,-4.8,4.9],[1,