<!-- RUBY-BACKUP · part 571 -->

    var dur = 1500, t0 = Date.now();
    var dir = end.clone().sub(start);
    (function glide(){
      try{
        var t = Math.min(1, (Date.now()-t0)/dur);
        var e = t<0.5 ? 2*t*t : -1+(4-2*t)*t; /* ease in-out, like a real pull */
        var p = start.clone().add(dir.clone().multiplyScalar(e));
        wheel.position.copy(p);
        tire.rotation.z += 0.22; hub.rotation.z += 0.22;
        car.position.y = -1.35 + Math.sin(Date.now()/180)*0.07; /* the car sways */
        /* carry the rider on the thread */
        if(typeof mePos !== 'undefined' && mePos){
          mePos.x = p.x; mePos.z = p.z; mePos.y = p.y + 1.4;
        }
        if(t < 1){ requestAnimationFrame(glide); return; }
        /* arrival — set the rider down on the ground, like tp does */
        if(typeof mePos !== 'undefined' && mePos){
          mePos.x = end.x; mePos.z = end.z;
          try{
            if(typeof fortifiedGroundY === 'function') mePos.y = fortifiedGroundY(end.x, end.z) + 5;
            else mePos.y = end.y + 1.4;
          }catch(e2){ mePos.y = end.y + 1.4; }
        }
        try{
          wheel.traverse(function(o){
            if(o.geometry) o.geometry.dispose();
            if(o.material && o.material.dispose) o.material.dispose();
          });
          if(window.scene) window.scene.remove(wheel);
        }catch(e3){}
        status('warped — rode the thread home');
      }catch(e4){}
    })();
  }
  window.__rideThread = rideThread;
  window.__weaveAt = function(pos){
    try{
      var meshes = [];
      if(typeof window.__nodeMap !== 'undefined'){
        var map = window.__nodeMap;
        for(var k in map){
          try{
            var p = new THREE.Vector3(); map[k].obj.getWorldPosition(p);
            if(p.distanceToSquared(pos) < 2500) meshes.push(map[k].obj);
          }catch(e){}
          if(meshes.length >= 40) break;
        }
      }
      if(meshes.length) return spinWeb(meshes);
    }catch(e){}
    return null;
  };

  window.warpThread = function(n){
    if(!webs.length){ status('weave a web first — spider'); return 'no webs'; }
    var web = webs[webs.length-1];
    n = parseInt(n, 10);
    if(isNaN(n) || n < 1 || n > web.pairs.length){
      status(web.name+' has '+web.pairs.length+' threads — warp 1..'+web.pairs.length);
      return 'pick 1..'+web.pairs.length;
    }
    var pr = web.pairs[n-1];
    rideThread(pr[0], pr[1]);
    return 'warping thread '+n;
  };

  /* ---------- tap hook: armed spider steals the next structure tap ---------- */
  function hookTaps(){
    if(window.__spiderTapHooked) return;
    window.__spiderTapHooked = true;
    var tries = 0;
    var iv = setInterval(function(){
      tries++;
      try{
        if(typeof dDown === 'function' && !dDown.__spiderWrapped){
          var orig = dDown;
          var mine = function(id, sx, sy){
            try{
              /* yield to pyramid install/uninstall flows */
              if(window.__installArmed || window.__uninstallArmed)
                return orig.apply(this, arguments);
              if(warpArmed && typeof rayPick === 'function'){
                warpArmed = false;
                var hitW = rayPick(sx, sy);
                if(hitW && hitW.point){
                  var th = nearestThread(hitW.point, 3.5);
                  if(th) rideThread(th.a, th.b);
                  else status('no thread there — tap closer to a gold thread');
                } else {
                  status('no thread there');
                }
                return true;
              }
              if(spiderArmed && typeof rayPick === 'function'){
                spiderArmed = false;
                if(hit && hit.object){
                  var meshes = structureOf(hit.object);
                  var web = spinWeb(meshes);
                  if(web) status('spider spun — '+web.conns+' threads, '+web.pts+
                    ' points @ '+web.dist+'u latch');
                } else {
                  status('no structure there');
                }
                return true;
              }
            }catch(e){}
            return orig.apply(this, arguments);
          };
          mine.__spiderWrapped = true;
          dDown = mine;
          clearInterval(iv);
        }
      }catch(e){}
      if(tries > 40) clearInterval(iv);
    }, 500);
  }

  /* ---------- runLine chain ---------- */
  (function(){
    var __triesspiderHooked=0;
    function __hookspiderHooked(){
      __triesspiderHooked++;
      try{
        if(typeof window.runLine === 'function' && !window.runLine.__spiderHooked){
      var prevRL = window.runLine;
      window.runLine = function(line){
        try{
          var raw = String(line == null ? '' : line).trim();
          var tl = raw.toLowerCase();
          if(tl === 'spider'){
            spiderArmed = true;
            status('spider armed — tap a structure ('+latchDist+'u latch)');
            return;
          }
          if(tl.indexOf('spider ') === 0){
   