<!-- RUBY-BACKUP · part 293 -->
) m.position.x = -62;
  }
  if(AURORA_ON){
    var at = clock.elapsedTime;
    for(var axi=0; axi<auroras.length; axi++){
      var am2 = auroras[axi], ap = am2.geometry.attributes.position, ab = am2.userData.base, aph = am2.userData.ph;
      for(var axj=0; axj<ap.count; axj++){
        var bx0 = ab[axj*3];
        ap.setY(axj, ab[axj*3+1] + Math.sin(bx0*0.09 + at*1.8 + aph)*2.2);
        ap.setZ(axj, ab[axj*3+2] + Math.cos(bx0*0.07 + at*1.3 + aph)*1.4);
      }
      ap.needsUpdate = true;
    }
  }
  if(EMBER_ON && emberPts.visible){
    var epos2 = emberPts.geometry.attributes.position, en = epos2.count;
    for(i=0;i<en;i++){
      var ey = epos2.getY(i) + emberVel[i]*dt;
      if(ey > 32){ ey = 0; epos2.setX(i, Math.random()*110-55); epos2.setZ(i, Math.random()*110-55); }
      epos2.setY(i, ey);
      epos2.setX(i, epos2.getX(i) + Math.sin(ey*0.5 + i)*dt*0.8);
    }
    epos2.needsUpdate = true;
  }
  if(RAIN_ON && rainPts.visible){
    var pos = rainPts.geometry.attributes.position, n = pos.count;
    for(i=0;i<n;i++){
      rainVel[i] += 32*dt;  /* gravity — the drops accelerate as they fall */
      var y = pos.getY(i) - rainVel[i]*dt;
      if(y < 0){ y = 40; rainVel[i] = 6+Math.random()*6; pos.setX(i, Math.random()*110-55); pos.setZ(i, Math.random()*110-55); }
      pos.setY(i, y);
    }
    pos.needsUpdate = true;
  }
  /* lightning strikes while the Rain Law holds */
  if(RAIN_ON){
    boltT += dt;
    if(boltT > nextBolt){
      boltT = 0; nextBolt = 6 + Math.random()*10;
      fireBolt(false);
      var br = Math.random();
      if(br < 0.25) setTimeout(function(){ fireBolt(true); }, 350 + Math.random()*450);
      else if(br < 0.35){ setTimeout(function(){ fireBolt(true); }, 350 + Math.random()*450); setTimeout(function(){ fireBolt(true); }, 800 + Math.random()*700); }
    }
    if(boltLight.intensity > 0) boltLight.intensity = Math.max(0, boltLight.intensity - dt*10);
  }
  /* the whiteout: every frame decides — white while flashing or held, true sky after */
  if(WHITEOUT_HELD){ scene.background.set(0xffffff); }
  else if(flashT > 0){ flashT -= dt; scene.background.set(0xffffff); if(flashT <= 0) scene.background.set(skyBgHex); }
  if(!RAIN_ON){
    boltLine.visible = false; boltBranch.visible = false; boltGlow.visible = false; boltLight.intensity = 0;
  }
}
/* his sky on arrival — dawn by default, ?sky=day|night|storm|cosmic|cave|dawn|ember to choose.
   placed here, after the sky's own variables are born. */
(function(){
  var sm = location.search.match(/[?&]sky=([a-z]+)/);
  var skn = sm ? sm[1] : 'night'; /* night by default — King's order 2026-10-03 */
  if(['day','night','storm','cosmic','cave','dawn','ember','aurora'].indexOf(skn) >= 0) skyState(skn);
})();


/* COLLAPSED BUTTON MENU — one button holds them all */
var _menuOpen = false;
var _menuBtn = null;
var _menuPanel = null;
/* GRAB MODE — pick up, twist, turn */
var GRAB_MODE = false;
var _grabbed = null;
var _grabPanel = null;
function toggleGrabMode(){
  GRAB_MODE = !GRAB_MODE;
  if(GRAB_MODE){
    codeStatus('grab mode — tap something to pick it up');
    showGrabHint();
  }else{
    codeStatus('grab mode off');
    dropGrabbed();
    hideGrabPanel();
    hideGrabHint();
  }
}
function showGrabHint(){
  var h = document.createElement('div');
  h.id = 'grabhint';
  h.textContent = 'Tap a block to pick it up';
  h.style.cssText = 'position:fixed;top:80px;left:50%;transform:translateX(-50%);z-index:10001;background:#d8a920;color:#111;padding:10px 20px;border-radius:20px;font-size:14px;font-weight:bold;';
  document.body.appendChild(h);
}
function hideGrabHint(){
  var h = document.getElementById('grabhint');
  if(h) h.remove();
}
function pickUp(obj){
  _grabbed = obj;
  hideGrabHint();
  // gold glow on grabbed
  if(obj.material && obj.material.emissive){
    obj.userData._oldEmissive = obj.material.emissive.getHex();
    obj.material.emissive.setHex(0x664400);
  }
  showGrabPanel();
  codeStatus('picked up — twist and turn');
}
function dropGrabbed(){
  if(_grabbed){
    if(_grabbed.material && _grabbed.material.emissive && _grabbed.userData._oldEmissive!==undefined){
      _grabbed.material.emissive.setHex(_grabbed.userData._oldEmissive);
    }
    _grabbed = null;
  }
}
var INSTALL_MODE = false;
function startInstall(){
  if(!_grabbed){ codeStatus('pick something up first'); return; }
  INSTALL_MODE = true;
  hideGrabPanel();
  var h = document.createElement('div');
  h.id = 'installhint';
  h.textContent = 'Tap the thing to install into';
  h.style.cssText = 'position:fixed;top:80px;left:50%;transform:translateX(-50%);z-index:10001;background:#d8a920;color:#111;padding:10px 20px;border-radius:20px;font-size:14px;font-weight:bold;';
  document.body.appendChild(h);
  codeStatus('tap the target');
}
function doInstall(target){
  if(!_grabbed || !target) return;
  try{
    // attach grabbed as child of target, keeping world position
    var worldPos = new THREE.Vector3();
    _grabbed.getWorl