<!-- SAGA2 · part 90 -->
(0.55, 0.55, 0.55);
  avatarGrp.position.set(0, 0, -490);
  avatarGrp.visible = false; // hidden — King: soldiers in the way
  avatarGrp.rotation.set(0,0,0);
  scene.add(camera);
}
var weaponMode = false;
var lasers = [];
var cannonL = null, cannonR = null;
var scorchMarks = [];
var sparkles = [];
function animate(){
  requestAnimationFrame(animate);
  var dt=Math.min(clock.getDelta(),0.05), t=clock.elapsedTime;
  auroras.forEach(function(a){
    a.material.opacity=0.14+Math.sin(t*0.5+a.userData.phase)*0.08;
    a.rotation.y+=dt*0.006;
  });
  if(window._crown){
    window._crown.rotation.y+=dt*0.8;
    window._crown.position.y=300+Math.sin(t*0.8)*12;
  }
  (window._rings||[]).forEach(function(r){
    r.rotation.z+=dt*r.userData.s;
  });
  blimps.forEach(function(b){
    var u=b.userData; u.a+=dt*u.s;
    b.position.set(500+Math.cos(u.a)*u.r,u.h+Math.sin(t*0.4+u.a)*14,500+Math.sin(u.a)*u.r);
    b.rotation.y=-u.a+Math.PI/2;
  });
  heart.intensity=1.6+Math.sin(t*1.2)*0.5;
  if(avatarGrp){
    if(avatarGrp.userData.reactor){
      var rp = 1+Math.sin(t*4)*0.08;
      avatarGrp.userData.reactor.scale.set(rp,rp,rp);
    }
    // lights breathe with power
    if(avatarGrp.userData.lights){
      var lp = 2.5+Math.sin(t*4)*0.6;
      if(avatarGrp.userData.lights[1]) avatarGrp.userData.lights[1].intensity = lp+0.5;
      if(avatarGrp.userData.lights[0]) avatarGrp.userData.lights[0].intensity = 2.2+Math.sin(t*2.3)*0.4;
      // cannons blaze when firing
      var cf = weaponMode ? 2.5 : 1.2;
      if(avatarGrp.userData.lights[2]) avatarGrp.userData.lights[2].intensity += (cf - avatarGrp.userData.lights[2].intensity)*0.1;
      if(avatarGrp.userData.lights[3]) avatarGrp.userData.lights[3].intensity += (cf - avatarGrp.userData.lights[3].intensity)*0.1;
    }
    if(avatarGrp.userData.antT){
      avatarGrp.userData.antT.material.color.setHex(Math.sin(t*6)>0?0x55ddff:0x1a5a77);
    }
    // energy pulses
    if(avatarGrp.userData.pulses){
      avatarGrp.userData.pulses.forEach(function(p){
        p.userData.t += 0.016*0.5;
        if(p.userData.t>1) p.userData.t = 0;
        p.position.y = -16 + p.userData.t*14;
        var f = Math.sin(p.userData.t*Math.PI);
        p.scale.set(f+0.3, f+0.3, f+0.3);
      });
    }
    // cannon heat
    [avatarCannonL, avatarCannonR].forEach(function(ac){
      if(ac && ac.userData.heats){
        ac.userData.heats.forEach(function(h){
          var tgt = weaponMode ? 0.4 : 0;
          h.material.opacity += (tgt - h.material.opacity)*0.07;
        });
      }
    });
    // head alive — subtle, human
    if(avatarGrp.userData.head){
      avatarGrp.userData.head.rotation.y = Math.sin(t*0.5)*0.06;
      avatarGrp.userData.head.rotation.x = Math.sin(t*0.7)*0.03;
    }
    // BREATHING — the whole being breathes
    var breath = 1+Math.sin(t*1.2)*0.015;
    avatarGrp.scale.set(0.55*breath, 0.55*breath, 0.55*breath);
    // ENERGY PULSE — brightness waves through lines
    if(avatarGrp.userData.pulseT === undefined) avatarGrp.userData.pulseT = 0;
    avatarGrp.userData.pulseT += 0.016;
    var pulse = 0.75+Math.sin(avatarGrp.userData.pulseT*2.5)*0.25;
    if(avatarGrp.userData.lineMats){
      avatarGrp.userData.lineMats[1].opacity = 0.7+pulse*0.3; // gold breathes
      avatarGrp.userData.lineMats[0].opacity = 0.65+pulse*0.25; // cyan follows
    }
    // mandala — the pure linework breathes
    // (halo removed)
    if(avatarGrp.userData.reticle){
      avatarGrp.userData.reticle.rotation.z = t*0.3;
      var rs = 1+Math.sin(t*2)*0.05;
      avatarGrp.userData.reticle.scale.set(rs, rs, 1);
    }

    if(avatarGrp.userData.antTip){
      avatarGrp.userData.antTip.material.color.setHex(Math.sin(t*5)>0?0x44ccff:0x226688);
    }
    // subtle breathing
    avatarGrp.position.y = -16 + Math.sin(t*1.5)*0.35;
  }

  var sp=40*dt, fx=-Math.sin(yaw), fz=-Math.cos(yaw), rx=Math.cos(yaw), rz=-Math.sin(yaw); // 6x slower
  if(keys['w']){camera.position.x+=fx*sp;camera.position.z+=fz*sp;}
  if(keys['s']){camera.position.x-=fx*sp;camera.position.z-=fz*sp;}
  if(keys['a']){camera.position.x-=rx*sp;camera.position.z-=rz*sp;}
  if(keys['d']){camera.position.x+=rx*sp;camera.position.z+=rz*sp;}
  if(keys[' '])camera.position.y+=sp;
  if(stickL.active){
    camera.position.x+=(fx*-stickL.dy+rx*stickL.dx)*sp;
    camera.position.z+=(fz*-stickL.dy+rz*stickL.dx)*sp;
  }
  camera.rotation.order='YXZ'; camera.rotation.y=yaw; camera.rotation.x=pitch; camera.rotation.z=0;
  // CONTINUOUS FIRE: CANNONS button toggles, lasers never stop while live
  if(weaponMode){
    if(!window._lastAuto) window._lastAuto = 0;
    if(t - window._lastAuto > 0.22){
      window._lastAuto = t;
      fireLaser();
    }
  }
  // laser fade
  for(var li=lasers.length-1; li>=0; li--){
    lasers[li].life -= dt;
    lasers[li].mesh.children.forEach(function(c){ c.material.opacity = Math.max(0, lasers[li].life*5); });
    if(lasers[li].life<=0){ scene.remove(lasers[li].mesh); lasers.splice(li,1); }
  }
  