<!-- SAGA-SOLID · part 44 -->
 bird = new THREE.Group();
          var body = new THREE.Mesh(new THREE.ConeGeometry(0.5, 2, 4), birdMat);
          body.rotation.x = Math.PI/2;
          bird.add(body);
          var wingL = new THREE.Mesh(new THREE.PlaneGeometry(3, 1), birdMat);
          wingL.position.x = -1.5;
          bird.add(wingL);
          var wingR = new THREE.Mesh(new THREE.PlaneGeometry(3, 1), birdMat);
          wingR.position.x = 1.5;
          bird.add(wingR);
          bird.position.set(cx + (Math.random()-0.5)*30, cy + (Math.random()-0.5)*10, cz + (Math.random()-0.5)*30);
          scene.add(bird);
          flock.push({mesh: bird, wingL: wingL, wingR: wingR, off: Math.random()*10});
        }
        var flockT = Math.random() * 100;
        window._dynamics.push(function(t, dt){
          flockT += (dt || 0.016) * 0.3;
          /* Flock moves in a circle */
          var fx = cx + Math.cos(flockT) * 150;
          var fz = cz + Math.sin(flockT) * 150;
          for(var i = 0; i < flock.length; i++){
            var brd = flock[i];
            /* Follow flock center with offset */
            var tx = fx + Math.sin(brd.off + flockT*2) * 15;
            var tz = fz + Math.cos(brd.off + flockT*2) * 15;
            var ty = cy + Math.sin(brd.off*2 + t) * 5;
            brd.mesh.position.lerp(new THREE.Vector3(tx, ty, tz), 0.05);
            brd.mesh.rotation.y = Math.atan2(tx - brd.mesh.position.x, tz - brd.mesh.position.z);
            /* Flap */
            var flap = Math.sin(t*10 + brd.off) * 0.6;
            brd.wingL.rotation.z = flap;
            brd.wingR.rotation.z = -flap;
          }
        });
      })();
    }
  }catch(e){ console.error(e); }
}
if(typeof buildBirds === 'function'){ try{ buildBirds(); }catch(e){ console.error(e); } }

/* DAY/NIGHT CYCLE — the world breathes. 2026-10-04. */
(function(){
  window._dynamics = window._dynamics || [];
  var cycleTime = 0;
  var dayLength = 300; /* 5 minutes per day */
  window._dynamics.push(function(t, dt){
    try{
      cycleTime += (dt || 0.016);
      var phase = (cycleTime % dayLength) / dayLength; /* 0-1 */
      var sunAngle = phase * Math.PI * 2;
      /* Sun position */
      var sunX = Math.cos(sunAngle) * 800;
      var sunY = Math.sin(sunAngle) * 500 + 100;
      /* Find the key light and move it */
      /* (We can't easily reference it, so we adjust fog and sky) */
      var dayness = Math.max(0, Math.sin(sunAngle));
      /* Fog color shifts: gold day, dark blue night */
      if(scene.fog){
        var r = 0.1 + dayness * 0.7;
        var g = 0.1 + dayness * 0.5;
        var b = 0.2 + dayness * 0.1;
        scene.fog.color.setRGB(r, g, b);
      }
    }catch(e){ console.error(e); }
  });
})();




/* DYNAMIC FOV — widens with speed. Academic: FOV kick is the cheapest feel-of-speed.
   Base 72, +8 running, +12 flying. */
var _baseFOV = 72;
var _targetFOV = 72;
window._dynamics = window._dynamics || [];
window._dynamics.push(function(t, dt){
  try{
    var speed = 0;
    if(typeof lastDX !== 'undefined'){
      speed = Math.sqrt(lastDX*lastDX + lastDZ*lastDZ);
    }
    if(typeof moveMode !== 'undefined' && moveMode === 'fly'){
      _targetFOV = 84; /* Flying: wide */
    } else if(speed > 1.5){
      _targetFOV = 80; /* Running: kick */
    } else if(speed > 0.3){
      _targetFOV = 76; /* Walking */
    } else {
      _targetFOV = _baseFOV; /* Still */
    }
    /* Smooth lerp */
    var cur = camera.fov;
    var next = cur + (_targetFOV - cur) * 0.08;
    if(Math.abs(next - cur) > 0.01){
      camera.fov = next;
      camera.updateProjectionMatrix();
    }
  }catch(e){ console.error(e); }
});





/* FLYING SWORD — directional flight, like the old game. 2026-10-04. */
var _flySword = null;
function ensureFlySword(){
  if(_flySword) return;
  _flySword = new THREE.Group();
  /* Blade */
  var blade = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.1, 4),
    new THREE.MeshStandardMaterial({color: 0xcccccc, metalness: 0.9, roughness: 0.2}));
  blade.position.z = 2;
  _flySword.add(blade);
  /* Tip */
  var tip = new THREE.Mesh(new THREE.ConeGeometry(0.2, 1, 4),
    new THREE.MeshStandardMaterial({color: 0xffffff, metalness: 0.9, roughness: 0.1}));
  tip.rotation.x = Math.PI/2;
  tip.position.z = 4.5;
  _flySword.add(tip);
  /* Guard */
  var guard = new THREE.Mesh(new THREE.BoxGeometry(1, 0.2, 0.3),
    new THREE.MeshStandardMaterial({color: 0xd4a017, metalness: 0.8}));
  _flySword.add(guard);
  /* Hilt */
  var hilt = new THREE.Mesh(new THREE.CylinderGeometry(0.15, 0.15, 1.2, 8),
    new THREE.MeshStandardMaterial({color: 0x5a3a1a, roughness: 0.8}));
  hilt.rotation.x = Math.PI/2;
  hilt.position.z = -0.7;
  _flySword.add(hilt);
  /* Glow */
  var glow = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.3, 5),
    new THREE.MeshBasicMaterial({color: 0x00ffff, transparent: true, opacity: 0.3}));
  glow.position.z = 2;
  _flySword.add(glow);
  _flySword.visible = false;
  scene.add(_flySword);
}
/* Show/hide sword based on