<!-- RUBY-BACKUP · part 565 -->
 nid;
    }catch(e){ return 'stand failed: ' + e.message; }
  };

  // List all nodes with their solidify codes
  window.solidCodes = function(){
    try{
      if(typeof window.listNodes !== 'function') return 'nodes not ready';
      var ns = window.listNodes();
      var out = [];
      for(var i=0;i<ns.length;i++){
        out.push({node: ns[i].id, at: ns[i].x + ',' + ns[i].z, code: 'stand ' + ns[i].id});
      }
      return out;
    }catch(e){ return 'list failed'; }
  };

  // Expose the node map for solidify (bridge to touch-nodes)
  // touch-nodes.js keeps nodeMap private — patch it to expose
  try{
    if(typeof window.stampNode === 'function'){
      var origStamp = window.stampNode;
      window.stampNode = function(obj, stone){
        var nid = origStamp(obj, stone);
        try{
          if(nid && obj){
            window.__nodeMap = window.__nodeMap || {};
            window.__nodeMap[nid] = {obj: obj, stone: stone};
          }
        }catch(e){}
        return nid;
      };
    }
  }catch(e){}


  /* ADJUSTABLE MODES — each node can be SOLID (platform) or LATCH (grabber).
     The King: "Make them adjustable to latch or be solid." */

  // Set a node's mode
  window.setNodeMode = function(nid, mode){
    try{
      var sn = solidNodes[nid];
      if(!sn) return 'solidify it first: solidify ' + nid;
      sn.mode = mode;
      // Visual: gold platform = solid, cyan claws = latch
      if(sn.platform){
        if(mode === 'latch'){
          sn.platform.material.color.setHex(0x00d4ff);
          sn.platform.material.emissive = new THREE.Color(0x004455);
        } else {
          sn.platform.material.color.setHex(0xc9a227);
          if(sn.platform.material.emissive) sn.platform.material.emissive.setHex(0x000000);
        }
      }
      if(typeof codeStatus === 'function') codeStatus(nid + ' → ' + mode.toUpperCase());
      return nid + ' is now ' + mode;
    }catch(e){ return 'mode failed: ' + e.message; }
  };

  window.latchNode = function(nid){ return window.setNodeMode(nid, 'latch'); };
  window.solidNode = function(nid){ return window.setNodeMode(nid, 'solid'); };

  // Latch behavior: in latch mode, the node grabs the nearest loose object within 3 units
  setInterval(function(){
    try{
      for(var nid in solidNodes){
        var sn = solidNodes[nid];
        if(!sn || sn.mode !== 'latch' || !window.__nodeMap) continue;
        // Find nearest non-solid object within latch range
        var best = null, bd = 9; // 3 units squared
        for(var k in window.__nodeMap){
          if(k === nid) continue;
          var rec = window.__nodeMap[k];
          if(!rec || !rec.obj || !rec.obj.parent) continue;
          if(solidNodes[k]) continue; // skip other solid nodes
          var p = new THREE.Vector3(); rec.obj.getWorldPosition(p);
          var d = (p.x-sn.x)*(p.x-sn.x) + (p.z-sn.z)*(p.z-sn.z);
          if(d < bd){ bd = d; best = rec.obj; }
        }
        if(best){
          // Pull it to the latch
          var bp = new THREE.Vector3(); best.getWorldPosition(bp);
          var dir = new THREE.Vector3(sn.x-bp.x, 0, sn.z-bp.z).normalize().multiplyScalar(0.1);
          best.position.add(dir);
        }
      }
    }catch(e){}
  }, 100);

  /* ================= FIVE NODE MODES =================
     PORTAL SWITCH SENSOR SPRING ANCHOR — the King's five.
     Each mode has its visual identity, its code, its nature. */

  function nodePos(nid){
    var sn = solidNodes[nid];
    return sn ? {x: sn.x, y: sn.y, z: sn.z} : null;
  }
  function playerPos(){
    try{
      if(window.camera) return {x: camera.position.x, y: camera.position.y, z: camera.position.z};
    }catch(e){}
    return null;
  }
  function dist2D(a, b){ return Math.hypot(a.x-b.x, a.z-b.z); }

  /* ---- PORTAL: pair two nodes, step through ---- */
  var portals = {}; // nid -> paired nid
  window.portalPair = function(a, b){
    try{
      if(!solidNodes[a]) window.solidifyNode(a);
      if(!solidNodes[b]) window.solidifyNode(b);
      if(!solidNodes[a] || !solidNodes[b]) return 'solidify both nodes first';
      portals[a] = b; portals[b] = a;
      solidNodes[a].mode = 'portal'; solidNodes[b].mode = 'portal';
      paintMode(a); paintMode(b);
      // violet swirl rings
      ringMode(a, 0x9b30ff); ringMode(b, 0x9b30ff);
      if(typeof codeStatus==='function') codeStatus('PORTAL ' + a + ' <-> ' + b);
      return 'portal linked';
    }catch(e){ return 'portal failed: ' + e.message; }
  };
  function portalTick(){
    try{
      var pp = playerPos();
      if(!pp) return;
      for(var a in portals){
        var sn = solidNodes[a];
        if(!sn || sn.cool > Date.now()) continue;
        if(dist2D(pp, sn) < 1.5){
          var b = portals[a], sb = solidNodes[b];
          if(!sb) continue;
          // step through — the portal's nature is to move you
          camera.position.set(sb.x, sb.y + 1.2, sb.z);
          sn.cool = Date.now() + 2000; sb.cool = Date.now() + 2000;
      