<!-- SAGA-STAGING · part 109 -->
'function') say('Lab UPDATE: cube moved +10x, y=10. Type eyeshot to capture.');
    } catch(e){ if(typeof say==='function') say('Lab UPDATE failed: ' + e.message); }
  },
  remove: function(){
    try {
      if(!this.cube){ if(typeof say==='function') say('Lab: no cube to remove.'); return; }
      var id = this.testId;
      var ok = window.WORLD_REGISTRY.unregister(id);
      var count = window.WORLD_REGISTRY.countByType('lab-test');
      var inScene = this.cube.parent ? 'STILL_IN_SCENE_FAIL' : 'REMOVED_FROM_SCENE_OK';
      // Check Foundation for stale entries
      var wfClean = true;
      if(window.WF && window.WF.colliders){
        for(var i=0; i<window.WF.colliders.length; i++){
          if(window.WF.colliders[i].mesh === this.cube){ wfClean = false; break; }
        }
      }
      this.cube = null;
      this.testId = null;
      if(typeof say==='function') say('Lab REMOVE: unregister=' + ok + ', count=' + count + ', ' + inScene + ', WF_clean=' + wfClean + '. Type eyeshot to verify empty.');
    } catch(e){ if(typeof say==='function') say('Lab REMOVE failed: ' + e.message); }
  }
};
CODES['labtest'] = {cat:'Lab', desc:'Create test cube', fn:function(){ window.LAB.create(); }};
CODES['labmove'] = {cat:'Lab', desc:'Move test cube', fn:function(){ window.LAB.move(); }};
CODES['labremove'] = {cat:'Lab', desc:'Remove test cube', fn:function(){ window.LAB.remove(); }};

/* Automated full lifecycle: create → eyeshot → move → eyeshot → remove → eyeshot → verify */
CODES['labauto'] = {cat:'Lab', desc:'Automated lifecycle test', fn:function(){
  if(typeof say==='function') say('Lab AUTO: starting...');
  var steps = [];
  // Stage 1: Create
  window.LAB.create();
  steps.push('create');
  setTimeout(function(){
    // Stage 2: Eyeshot after create
    if(CODES['eyeshot']) CODES['eyeshot'].fn();
    steps.push('eyeshot1');
    setTimeout(function(){
      // Stage 3: Move
      window.LAB.move();
      steps.push('move');
      setTimeout(function(){
        // Stage 4: Eyeshot after move
        if(CODES['eyeshot']) CODES['eyeshot'].fn();
        steps.push('eyeshot2');
        setTimeout(function(){
          // Stage 5: Remove
          window.LAB.remove();
          steps.push('remove');
          setTimeout(function(){
            // Stage 6: Final eyeshot
            if(CODES['eyeshot']) CODES['eyeshot'].fn();
            steps.push('eyeshot3');
            if(typeof say==='function') say('Lab AUTO complete: ' + steps.join(' → '));
          }, 2000);
        }, 2000);
      }, 2000);
    }, 2000);
  }, 2000);
}};


===== FILE: public/saga-staging/three.min.js =====
/**
 * @license
 * Copyright 2010-2021 Three.js Authors
 * SPDX-License-Identifier: MIT
 */
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).THREE={})}(this,(function(t){"use strict";const e="128",n=100,i=300,r=301,s=302,a=303,o=304,l=306,c=307,h=1e3,u=1001,d=1002,p=1003,m=1004,f=1005,g=1006,v=1007,y=1008,x=1009,_=1012,w=1014,b=1015,M=1016,S=1020,T=1022,E=1023,A=1026,L=1027,R=33776,C=33777,P=33778,D=33779,I=35840,N=35841,B=35842,z=35843,F=37492,O=37496,H=2300,G=2301,U=2302,k=2400,V=2401,W=2402,j=2500,q=2501,X=3e3,Y=3001,Z=3007,J=3002,Q=3004,K=3005,$=3006,tt=7680,et=35044,nt=35048,it="300 es";class rt{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e<i;e++)n[e].call(this,t);t.target=null}}}const st=[];for(let t=0;t<256;t++)st[t]=(t<16?"0":"")+t.toString(16);let at=1234567;const ot=Math.PI/180,lt=180/Math.PI;function ct(){const t=4294967295*Math.random()|0,e=4294967295*Math.random()|0,n=4294967295*Math.random()|0,i=4294967295*Math.random()|0;return(st[255&t]+st[t>>8&255]+st[t>>16&255]+st[t>>24&255]+"-"+st[255&e]+st[e>>8&255]+"-"+st[e>>16&15|64]+st[e>>24&255]+"-"+st[63&n|128]+st[n>>8&255]+"-"+st[n>>16&255]+st[n>>24&255]+st[255&i]+st[i>>8&255]+st[i>>16&255]+st[i>>24&255]).toUpperCase()}function ht(t,e,n){return Math.max(e,Math.min(n,t))}function ut(t,e){return(t%e+e)%e}function dt(t,e,n){return(1-n)*t+n*e}function pt(t){return 0==(t&t-1)&&0!==t}function mt(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))}function ft(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))}var gt=Object.freeze({__proto__:null,DEG2RAD:ot,RAD2DEG:lt,generateUUID:ct,clamp:ht,euclideanModulo:ut,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverse