<!-- RUBY-BACKUP · part 166 -->
(spawnMarker && spawnMarker.parent) spawnMarker.parent.remove(spawnMarker);
  /* glowing cyan ring at spawn point */
  var geo = new THREE.RingGeometry(0.8, 1.0, 32);
  var mat = new THREE.MeshBasicMaterial({color: 0x00ffff, transparent: true, opacity: 0.8, side: THREE.DoubleSide});
  spawnMarker = new THREE.Mesh(geo, mat);
  spawnMarker.rotation.x = -Math.PI/2;
  var gy = 0;
  if(typeof fortifiedGroundY==='function') gy = fortifiedGroundY(sp.x, sp.z);
  spawnMarker.position.set(sp.x*0.13, gy+0.05, sp.z*0.13);
  if(typeof scene!=='undefined') scene.add(spawnMarker);
  /* pulse */
  var s = 1;
  setInterval(function(){
    if(spawnMarker){
      s = 1 + Math.sin(Date.now()/300)*0.1;
      spawnMarker.scale.set(s,s,1);
    }
  }, 50);
}
function moveSpawnTo(x, z){
  /* SPAWN LAW: never land at lat 0 — no zero lines */
  if(Math.round(x) === 0 || Math.round(z) === 0){
    if(typeof codeStatus === 'function') codeStatus('spawn law: never at lat 0');
    return;
  }
  SPAWN_PT = {x: Math.round(x), z: Math.round(z)};
  try{ localStorage.setItem('ruby-spawnpt', JSON.stringify(SPAWN_PT)); }catch(e){}
  showSpawnMarker();
  codeStatus('spawn point moved to '+SPAWN_PT.x+', '+SPAWN_PT.z);
}
/* show marker on load */
setTimeout(function(){ showSpawnMarker(); }, 5000);
function getSpawnPoint(){
  if(SPAWN_PT) return SPAWN_PT;
  try{
    var s = JSON.parse(localStorage.getItem('ruby-spawnpt')||'null');
    if(s){ SPAWN_PT = s; return s; }
  }catch(e){}
  var sp = {x: 8, z: 9}; /* Cloud 9 — the default */
  /* Spawn ON the grass if the platform exists */
  if(window._cloud9GrassY) sp.y = window._cloud9GrassY;
  return sp;
}
function toggleMoveMode(){
  MOVE_MODE = !MOVE_MODE;
  if(!MOVE_MODE && MOVE_HELD){
    /* drop held */
    MOVE_HELD = null;
  }
  codeStatus(MOVE_MODE ? 'MOVE MODE — tap an object to pick up, tap destination to place' : 'move mode off');
  updateMoveToggle();
}
function updateMoveToggle(){
  var btn = document.getElementById('movetogglebtn');
  if(btn){
    btn.textContent = '\u2725';
    btn.style.background = MOVE_MODE ? '#fff2aa' : '#d8a920';
    btn.style.boxShadow = MOVE_MODE ? '0 0 12px #d8a920' : 'none';
  }
}
/* move toggle button */
setTimeout(function(){
  if(!document.getElementById('movetogglebtn')){
    var b = document.createElement('button');
    b.id = 'movetogglebtn';
    b.textContent = '\u2725';
    b.title = 'MOVE';
    b.style.cssText = 'position:fixed;bottom:246px;right:14px;z-index:9999;width:46px;height:46px;background:#d8a920;color:#111;border:1px solid #d8a920;border-radius:50%;font-size:24px;line-height:1;padding:0;cursor:pointer;-webkit-tap-highlight-color:transparent;';
    b.onclick = toggleMoveMode;
    document.body.appendChild(b);
    updateMoveToggle();
  }
}, 3000);
/* gap filling — merge open spaces between objects */

/* CONNECTION COLOR + TEXTURE EDITING */
var CONN_COLOR = '#00ffcc'; /* default connection color */
var CONN_TEX = 'chrome'; /* default texture */
var CONN_LIST = []; /* tracks connection stones {x,z,y} */

function setConnColor(col){
  CONN_COLOR = col;
  try{ localStorage.setItem('ruby-conncolor', col); }catch(e){}
  codeStatus('connection color set to '+col+' — new connections use it');
}
function setConnTex(tex){
  CONN_TEX = tex;
  try{ localStorage.setItem('ruby-conntex', tex); }catch(e){}
  codeStatus('connection texture set to '+tex+' — new connections use it');
}
function getConnColor(){
  try{ return localStorage.getItem('ruby-conncolor')||CONN_COLOR; }catch(e){ return CONN_COLOR; }
}
function getConnTex(){
  try{ return localStorage.getItem('ruby-conntex')||CONN_TEX; }catch(e){ return CONN_TEX; }
}
/* apply color/tex to a connection stone */
function styleConnection(stone){
  if(!stone) return;
  var col = getConnColor();
  var tex = getConnTex();
  /* set material color */
  if(stone.material && stone.material.color){
    /* parse hex */
    var hex = col.replace('#','');
    if(hex.length===6){
      var r = parseInt(hex.substr(0,2),16)/255;
      var g = parseInt(hex.substr(2,2),16)/255;
      var b = parseInt(hex.substr(4,2),16)/255;
      stone.material.color.setRGB(r,g,b);
    }
  }
  /* texture name stored for reference */
  stone.userData.connTex = tex;
  stone.userData.isConnection = true;
}
/* recolor all existing connections */
function recolorConnections(){
  var count = 0;
  CONN_LIST.forEach(function(pos){
    if(typeof getStoneMesh==='function'){
      var mesh = getStoneMesh(pos.x, pos.z, pos.y);
      if(mesh){ styleConnection(mesh); count++; }
    }
  });
  codeStatus(count ? 'recolored '+count+' connections to '+getConnColor()+' / '+getConnTex() : 'no connections to recolor yet — build some first');
}
/* hook: when fillGaps creates a stone, mark as connection */
var origFillGaps = fillGaps;
function fillGaps(){
  if(typeof stones==='undefined' || typeof stoneAt==='undefined') return;
  var filled = 0;
  /* scan a 20x20 area around player */
  var px = Math.round(mePos.x), pz = Math.round