<!-- RUBY-BACKUP · part 317 -->
thout a camera */
            var _safeTargets = [];
            scene.traverse(function(o){
              if(!o.isMesh) return;
              if(o.isSprite) return;
              _safeTargets.push(o);
            });
            _hits = rayc.intersectObjects(_safeTargets, false);
          }catch(e){ _hits = []; }
          if(_hits.length > 0){
            var _top = _hits[0].point.y;
            /* Landing on an object — its layer holds firm */
            if(mePos.y < _top + 0.1 && meVel.y <= 0 && !FLYM){
              mePos.y = _top + 0.1;
              meVel.y = 0;
              onGround = true;
            }
            /* Can't pass through from the side — push out */
            if(!FLYM){
              for(var _hi = 0; _hi < Math.min(_hits.length, 3); _hi++){
                var _hp = _hits[_hi].point;
                var _dx = mePos.x - _hp.x, _dz = mePos.z - _hp.z;
                var _dh = Math.sqrt(_dx*_dx + _dz*_dz);
                if(_dh < 0.3 && _dh > 0.001){
                  var _push = (0.3 - _dh);
                  mePos.x += (_dx/_dh) * _push;
                  mePos.z += (_dz/_dh) * _push;
                }
              }
            }
          }
        }
      /* Impassable solid blocks — none shall pass */
      try{
        if(window._solidBlocks && window._solidBlocks.length > 0 && typeof mePos !== 'undefined'){
          for(var _bi = window._solidBlocks.length - 1; _bi >= 0; _bi--){
            var _blk = window._solidBlocks[_bi];
            /* PURGE GHOSTS — if the mesh is gone from the scene, drop the collision (King's order) */
            if(!_blk || !_blk.parent){ window._solidBlocks.splice(_bi, 1); continue; }
            if(!_blk.userData.solidBox) continue;
            var _box = _blk.userData.solidBox;
            /* Expand box slightly for player radius */
            var _px = mePos.x, _py = mePos.y, _pz = mePos.z;
            var _pr = 0.3; /* player radius */
            if(_px + _pr > _box.min.x && _px - _pr < _box.max.x &&
               _py + _pr > _box.min.y && _py - _pr < _box.max.y &&
               _pz + _pr > _box.min.z && _pz - _pr < _box.max.z){
              /* Inside the block — push out to nearest face */
              var _dx1 = (_px + _pr) - _box.min.x, _dx2 = _box.max.x - (_px - _pr);
              var _dy1 = (_py + _pr) - _box.min.y, _dy2 = _box.max.y - (_py - _pr);
              var _dz1 = (_pz + _pr) - _box.min.z, _dz2 = _box.max.z - (_pz - _pr);
              var _min = Math.min(_dx1, _dx2, _dy1, _dy2, _dz1, _dz2);
              if(_min === _dx1) mePos.x = _box.min.x - _pr;
              else if(_min === _dx2) mePos.x = _box.max.x + _pr;
              else if(_min === _dy1) mePos.y = _box.min.y - _pr;
              else if(_min === _dy2) mePos.y = _box.max.y + _pr;
              else if(_min === _dz1) mePos.z = _box.min.z - _pr;
              else mePos.z = _box.max.z + _pr;
            }
          }
        }
      }catch(e){}
      /* Solid's avatar spins gently */
      try{
        if(window._solidAvatar && window._solidAvatar.userData.spin){
          window._solidAvatar.rotation.y += dt * 0.5;
          window._solidAvatar.position.y += Math.sin(Date.now() * 0.002) * 0.002;
        }
      }catch(e){}
      /* Surface feel — not blocks. The body senses where things are. */
      try{
        if((window._crawling || window._crouching) && typeof rayc !== 'undefined' && typeof mePos !== 'undefined'){
          var joyMoving = Math.abs(joyX) > 0.15 || Math.abs(joyY) > 0.15;
          if(joyMoving || window._crouching){
            var fwd = new THREE.Vector3(Math.sin(faceYaw), 0, Math.cos(faceYaw));
            var hh = window._crawling ? mePos.y + 0.3 : mePos.y + 0.5;
            rayc.set(new THREE.Vector3(mePos.x, hh, mePos.z), fwd);
            rayc.far = window._crawling ? 0.8 : 1.2;
            var hits = rayc.intersectObjects(scene.children, true);
            if(hits.length > 0 && hits[0].distance < rayc.far){
              var pt = hits[0].point;
              /* Align to intaglio — the hand lands on the linework, not between */
              var snapped = snapToIntaglio(pt);
              if(window._crawling){
                /* Tuck: ease into the space, don't snap to a face */
                window._tuckPoint = snapped;
              }
              if(window._crouching){
                window._handPlant = snapped;
              }
            }else{
              window._tuckPoint = null;
              window._handPlant = null;
            }
          }
        }
      }catch(e){}
      /* Hand rests — body eases so the hand meets the intaglio point */
      try{
        if(window._handPlant && typeof myAvatar !== 'undefined' && myAvatar){
          var hp = window._handPlant;
          var hx = mePos.x + Math.sin(faceYaw) * 0.4;
          var hz = mePos.z + Math.cos(faceYaw) * 0.4;
          var dx = hp.x - hx, dz = hp.z - hz;
          var dist = Math.abs(dx) + Math.abs(dz);
          if(dis