<!-- LIVE · part 67 -->
window.applyMinimum(roof); scene.add(roof);
});
dOrder.push('practice');

/* ===== LOOP ===== */

/* 1. AUTO-SWIM — water zones, auto-enter/exit like Genshin */
var waterBodies = [
  {x: 100, z: 100, r: 30, surfaceY: 0.5},
  {x: -80, z: 60, r: 25, surfaceY: 0.5}
];
function waterAt(x, z){
  for(var i=0; i<waterBodies.length; i++){
    var w = waterBodies[i];
    var dx = x - w.x, dz = z - w.z;
    if(dx*dx + dz*dz < w.r*w.r) return w;
  }
  return null;
}

  var animPhase = {walk:0, swim:0};
  var animAmp = {walk:0, swim:0};
function animate(){
  requestAnimationFrame(animate);
  /* body movement — left stick rules here */
  /* Body follows kingPos — STATE-GATED animations with BLEND */
  if(typeof playerBody !== 'undefined' && playerBody){
    playerBody.position.set(kingPos.x, kingPos.y, kingPos.z);
    /* 2. FACE TRAVEL DIRECTION */
    var mdx = lastDX, mdz = lastDZ;
    if(Math.abs(mdx) > 0.01 || Math.abs(mdz) > 0.01){
      var targetYaw = Math.atan2(mdx, mdz);
      var dyaw = targetYaw - playerBody.rotation.y;
      dyaw = Math.atan2(Math.sin(dyaw), Math.cos(dyaw));
      playerBody.rotation.y += dyaw * 0.15;
    }
    /* 6. SEPARATE clocks, 7. BLEND amplitudes, 4. STATE-GATED */
    var moving = Math.abs(lastDX) > 0.1 || Math.abs(lastDZ) > 0.1;
    var tWalk = (moveMode==='walk' && moving) ? 0.5 : 0;
    var tSwim = (moveMode==='swim') ? 0.8 : 0;
    animAmp.walk += (tWalk - animAmp.walk) * 0.15;
    animAmp.swim += (tSwim - animAmp.swim) * 0.15;
    if(moveMode==='walk' && moving){
      animPhase.walk += 0.15;
      if(playerBody.userData.legL) playerBody.userData.legL.rotation.x = Math.sin(animPhase.walk) * animAmp.walk;
      if(playerBody.userData.legR) playerBody.userData.legR.rotation.x = -Math.sin(animPhase.walk) * animAmp.walk;
      if(playerBody.userData.armL) playerBody.userData.armL.rotation.x = -Math.sin(animPhase.walk) * animAmp.walk * 0.8;
      if(playerBody.userData.armR) playerBody.userData.armR.rotation.x = Math.sin(animPhase.walk) * animAmp.walk * 0.8;
      playerBody.rotation.x = 0;
    } else if(moveMode==='swim'){
      animPhase.swim += 0.1;
      if(playerBody.userData.armL) playerBody.userData.armL.rotation.x = Math.sin(animPhase.swim) * animAmp.swim;
      if(playerBody.userData.armR) playerBody.userData.armR.rotation.x = -Math.sin(animPhase.swim) * animAmp.swim;
      playerBody.rotation.x = -Math.PI/2 + 0.3;
    } else if(moveMode==='fly'){
      /* Fly: tilt only, limbs ease to neutral */
      if(playerBody.userData.legL) playerBody.userData.legL.rotation.x *= 0.9;
      if(playerBody.userData.legR) playerBody.userData.legR.rotation.x *= 0.9;
    }
  }
  /* 1. AUTO-SWIM check */
  if(typeof waterAt !== 'undefined'){
    var wtr = waterAt(kingPos.x, kingPos.z);
    if(wtr && kingPos.y <= wtr.surfaceY + 0.3 && moveMode !== 'swim' && moveMode !== 'fly'){
      moveMode = 'swim';
    } else if(!wtr && moveMode === 'swim'){
      moveMode = 'walk';
    }
  }
  updateCamera();
  renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', function(){
  camera.aspect=window.innerWidth/window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});
document.getElementById('boot').style.display='none';
say('Coders100 — all codes organized. Type or tap \u2630.');


/* ===== v190 CORE SCOPE BRIDGE =====
 * Legacy systems below this IIFE depend on CODERS100 internals.
 * Export references only; do not alter world state.
 */
window.SAGA_CORE = window.SAGA_CORE || {};

window.SAGA_CORE.CODES = CODES;
window.SAGA_CORE.runCode = runCode;
window.SAGA_CORE.kingPos = kingPos;
window.SAGA_CORE.scene = scene;
window.SAGA_CORE.camera = camera;
window.SAGA_CORE.renderer = renderer;
window.SAGA_CORE.sfx = sfx;
window.SAGA_CORE.say = say;
window.SAGA_CORE.spawnNewBody = spawnNewBody;

window.SAGA_CORE.getGroundY = function(){ return groundY; };
window.SAGA_CORE.getMoveMode = function(){ return moveMode; };
window.SAGA_CORE.getCamYaw = function(){ return camYaw; };
window.SAGA_CORE.getCamPitch = function(){ return camPitch; };
window.SAGA_CORE.getCamDist = function(){ return camDist; };
window.SAGA_CORE.getPlayerBody = function(){ return playerBody; };

/* Legacy aliases used by existing post-IIFE code. */
window.CODES = CODES;
window.runCode = runCode;
window.kingPos = kingPos;
window.scene = scene;
window.camera = camera;
window.renderer = renderer;
window.sfx = sfx;
window.say = say;
window.spawnNewBody = spawnNewBody;

})();


/* Wire click sound to all UI buttons */
document.addEventListener('touchstart', function(e){
  var t = e.target;
  if(t && (t.tagName === 'BUTTON' || t.closest('button'))){
    sfx('click');
  }
}, {passive:true});


/* PLAYA 2.0 TOGGLE — top-right, menu with Chat, Mic, Playa 2.0 */
(function(){
  if(document.getElementById('playa2-btn')) return;
  var b = document.createElement('button');
  b.id = 'playa2-btn';
  b.innerHTML = '◆';
  b.title = 'Menu';
  b.style.cssT