@multisetai/vps 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -276,6 +276,7 @@ new ThreeAdapter(options: IThreeAdapterOptions)
276
276
  | `buttonContainer?` | `HTMLElement` | Where to append the built-in button. Defaults to `overlayRoot` or `document.body`. |
277
277
  | `onButtonCreated?` | `(button: HTMLButtonElement) => void` | Called after the built-in button is created. |
278
278
  | `onXRFrame?` | `(event: IXRFrameEvent) => void` | Called every XR frame after camera matrices are synced, before the scene is rendered. Use this to update scene objects each frame. |
279
+ | `onLocalizationSuccess?` | `(result: ILocalizeAndMapDetails, worldFromMap: THREE.Matrix4) => void` | Called after a successful localization. `worldFromMap` transforms any point from VPS map space into Three.js world space — use it to place scene objects at known physical locations in the scanned map. |
279
280
 
280
281
  #### Static methods
281
282
 
@@ -297,6 +298,32 @@ new ThreeAdapter(options: IThreeAdapterOptions)
297
298
 
298
299
  ---
299
300
 
301
+ ## Placing Content at Map Coordinates
302
+
303
+ After localization, the `onLocalizationSuccess` callback on `ThreeAdapter` provides a `worldFromMap` matrix that converts any point from VPS map space into Three.js world space. Use this to anchor scene objects to specific physical locations in the scanned map — independently of where the user started the AR session.
304
+
305
+ ```typescript
306
+ const adapter = new ThreeAdapter({
307
+ session,
308
+ renderer, scene, camera,
309
+ onLocalizationSuccess: (result, worldFromMap) => {
310
+ // mapPoint is a position you measured from the scanned map (in metres)
311
+ const mapPoint = new THREE.Vector3(1.5, 0, -2.0);
312
+
313
+ const marker = new THREE.Mesh(
314
+ new THREE.SphereGeometry(0.05),
315
+ new THREE.MeshBasicMaterial({ color: 0x00ff88 })
316
+ );
317
+ marker.position.copy(mapPoint.applyMatrix4(worldFromMap));
318
+ scene.add(marker);
319
+ },
320
+ });
321
+ ```
322
+
323
+ > **Note** — `worldFromMap` is recomputed on every successful localization. If you re-localize, update or re-add your objects so they stay in sync with the latest result.
324
+
325
+ ---
326
+
300
327
  ## Styling the AR Button
301
328
 
302
329
  The built-in button ships with minimal inline styles. Use these CSS classes to override appearance from your own stylesheet:
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import D from'axios';import*as m from'three';import {DRACOLoader}from'three/examples/jsm/loaders/DRACOLoader.js';import {GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';import {TransformControls}from'three/examples/jsm/controls/TransformControls.js';var X={authUrl:"https://api.multiset.ai/v1/m2m/token",queryUrl:"https://api.multiset.ai/v1/vps/map/query-form",mapDetailsUrl:"https://api.multiset.ai/v1/vps/map/",mapSetDetailsUrl:"https://api.multiset.ai/v1/vps/map-set/",fileDownloadUrl:"https://api.multiset.ai/v1/file"};var B=class{constructor(e){this.accessToken=null;this.mapDetailsCache={};let{clientId:t,clientSecret:i,...o}=e;this.credentials={clientId:t,clientSecret:i},this.config=o,this.endpoints={...X,...o.endpoints};}get token(){return this.accessToken}async authorize(){var i,o,r;let e=await D.post(this.endpoints.authUrl,{},{auth:{username:this.credentials.clientId,password:this.credentials.clientSecret}}),t=(r=(i=e.data)==null?void 0:i.token)!=null?r:(o=e.data)==null?void 0:o.access_token;if(!t)throw new Error("Authorization succeeded but no token was returned.");return this.accessToken=t,t}async downloadFile(e){if(!this.accessToken||!e)return "";try{let t=await D.get(`${this.endpoints.fileDownloadUrl}?key=${encodeURIComponent(e)}`,{headers:{Authorization:`Bearer ${this.accessToken}`}});return t.status===200?t.data.url:""}catch{return ""}}async localizeWithFrame(e,t,i){var o;if(!this.accessToken)throw new Error("Access token is missing. Call authorize() first.");return this.queryLocalization(e,t,(o=i==null?void 0:i.fetchMapDetails)!=null?o:false)}async fetchMapDetails(e){if(!this.accessToken)return null;let t=this.mapDetailsCache[e];if(t)return t;try{let i=await D.get(`${this.endpoints.mapDetailsUrl}${e}`,{headers:{Authorization:`Bearer ${this.accessToken}`}});return this.mapDetailsCache[e]=i.data,i.data}catch{return null}}async getGeoPoseComponents(){if(typeof navigator=="undefined"||!("geolocation"in navigator)||!navigator.geolocation)return null;try{let e=await new Promise((a,l)=>{navigator.geolocation.getCurrentPosition(a,l,{enableHighAccuracy:!0,timeout:1e4,maximumAge:0});}),{latitude:t,longitude:i,altitude:o}=e.coords,r=typeof o=="number"&&!Number.isNaN(o)?o:0;return {latitude:t,longitude:i,altitude:r}}catch{return null}}async queryLocalization(e,t,i){var d,u,h;let o=new FormData;this.config.mapType==="map"?o.append("mapCode",this.config.code):o.append("mapSetCode",this.config.code);let r=(d=this.config.isRightHanded)!=null?d:true;o.append("isRightHanded",`${r}`),o.append("fx",`${t.fx}`),o.append("fy",`${t.fy}`),o.append("px",`${t.px}`),o.append("py",`${t.py}`),o.append("width",`${e.width}`),o.append("height",`${e.height}`),o.append("queryImage",e.blob),this.config.convertToGeoCoordinates!==void 0&&o.append("convertToGeoCoordinates",`${this.config.convertToGeoCoordinates}`),"hintMapCodes"in this.config&&((u=this.config.hintMapCodes)!=null&&u.length)&&this.config.hintMapCodes.forEach(p=>{o.append("hintMapCodes",p);}),this.config.hintPosition&&o.append("hintPosition",this.config.hintPosition);let a;if(this.config.passGeoPose){let p=await this.getGeoPoseComponents();if(p){let{latitude:f,longitude:v,altitude:E}=p;a=`${f},${v},${E}`;}}if(a&&o.append("geoHint",a),this.config.hintRadius!==void 0){let p=Number(this.config.hintRadius);if(Number.isNaN(p)||p<1||p>100)throw new Error("hintRadius must be a number between 1 and 100.");if(!this.config.hintPosition&&!a)throw new Error("hintRadius requires hintPosition, or passGeoPose with available geolocation to generate geoHint.");o.append("hintRadius",`${p}`);}"use2DFiltering"in this.config&&this.config.use2DFiltering!==void 0&&o.append("use2DFiltering",`${this.config.use2DFiltering}`);let n=(await D.post(this.endpoints.queryUrl,o,{headers:{Authorization:`Bearer ${this.accessToken}`}})).data;if(!n.poseFound)return null;let c={localizeData:n};if(i&&((h=n.mapCodes)!=null&&h.length)){let p=await this.fetchMapDetails(n.mapCodes[0]);p&&(c.mapDetails=p);}return c}};async function q(s,e,t,i=.8,o=e,r=t){let a=document.createElement("canvas");a.width=e,a.height=t;let l=a.getContext("2d");if(!l)return new Blob;l.putImageData(new ImageData(new Uint8ClampedArray(s),e,t),0,0);let n=document.createElement("canvas");n.width=o,n.height=r;let c=n.getContext("2d");return c?(c.drawImage(a,0,0,o,r),new Promise(d=>{n.toBlob(u=>d(u!=null?u:new Blob),"image/jpeg",i);})):new Blob}async function U(s,e,t,i){let o=s.createFramebuffer();if(!o)return null;let r;try{s.bindFramebuffer(s.FRAMEBUFFER,o),s.framebufferTexture2D(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,e,0),r=new Uint8Array(t*i*4),s.readPixels(0,0,t,i,s.RGBA,s.UNSIGNED_BYTE,r);}finally{s.bindFramebuffer(s.FRAMEBUFFER,null),s.deleteFramebuffer(o);}let a=new Uint8ClampedArray(r.length);for(let u=0;u<i;u+=1){let h=u*t*4,p=(i-u-1)*t*4;a.set(r.subarray(h,h+t*4),p);}let l=Math.min(1,1280/Math.max(t,i)),n=Math.round(t*l),c=Math.round(i*l),d=await q(a.buffer,t,i,.7,n,c);return d.size?{blob:d,width:n,height:c}:null}function _(s,e){let t=s,i=(1-t[8])*e.width/2+e.x,o=(1-t[9])*e.height/2+e.y,r=e.width/2*t[0],a=e.height/2*t[5];return {fx:r,fy:a,px:i,py:o,width:e.width,height:e.height}}function $(s){return new Float32Array(s)}var j=.2,K=.8,Q=60,J=1e4,Y=300,Z=10,A=class{constructor(e,t){this.gl=e;this.options=t;this.session=null;this.referenceSpace=null;this.baseLayer=null;this.xrBinding=null;this.lastFrameTime=0;this.trackingLossFrames=0;this.hadTrackingLoss=false;this._isLocalizing=false;this.trackerSpace=null;this.arButton=null;this.xrFrameHandler=null;this.adapterResultHandler=null;this.adapterSessionStartHandler=null;this.adapterSessionEndHandler=null;this.handleContextLost=e=>{var t,i;if(e.preventDefault(),this.session)try{this.session.end();}catch{}(i=(t=this.options).onContextLost)==null||i.call(t);};this.handleContextRestored=()=>{var e,t;(t=(e=this.options).onContextRestored)==null||t.call(e);};let i=e.canvas;i instanceof HTMLCanvasElement&&(i.addEventListener("webglcontextlost",this.handleContextLost),i.addEventListener("webglcontextrestored",this.handleContextRestored));}static async isSupported(){if(!navigator.xr)return false;try{return await navigator.xr.isSessionSupported("immersive-ar")}catch{return false}}setXRFrameHandler(e){this.xrFrameHandler=e;}setAdapterResultHandler(e){this.adapterResultHandler=e;}setAdapterSessionHandlers(e,t){this.adapterSessionStartHandler=e,this.adapterSessionEndHandler=t;}getClient(){return this.options.client}getOverlayRoot(){return this.options.overlayRoot}isActive(){return this.session!==null}get isLocalizing(){return this._isLocalizing}stopSession(){this.session&&this.session.end();}getBaseLayer(){return this.baseLayer}createButton(){let e=document.createElement("button");return e.textContent="START AR",e.className="multiset-ar-button multiset-ar-inactive",e.style.cssText=["position:fixed","bottom:20px","left:50%","transform:translateX(-50%)","padding:12px 24px","border:1px solid #fff","border-radius:4px","background:rgba(0,0,0,0.1)","color:#fff","font-size:13px","cursor:pointer","z-index:999"].join(";"),e.addEventListener("click",()=>{this.session?this.session.end():this.startSession();}),this.arButton=e,e}async startSession(){var e,t,i;try{if(!navigator.xr)throw new Error("WebXR not supported on this device.");let o=await navigator.xr.requestSession("immersive-ar",{requiredFeatures:["local"],optionalFeatures:["camera-access","dom-overlay"],domOverlay:{root:(e=this.options.overlayRoot)!=null?e:document.body}});await this.initSession(o);}catch(o){(i=(t=this.options).onError)==null||i.call(t,o);}}async initSession(e){var a,l,n,c;await this.gl.makeXRCompatible();let t={};this.options.framebufferScaleFactor!==void 0&&(t.framebufferScaleFactor=this.options.framebufferScaleFactor);let i=new XRWebGLLayer(e,this.gl,t);await e.updateRenderState({baseLayer:i});let o=await e.requestReferenceSpace((a=this.options.referenceSpaceType)!=null?a:"local");this.session=e,this.baseLayer=i,this.referenceSpace=o;let r=XRWebGLBinding;this.xrBinding=new r(e,this.gl),e.addEventListener("end",()=>this.handleSessionEnd()),e.requestAnimationFrame((d,u)=>this.xrLoop(d,u)),this.arButton&&(this.arButton.textContent="STOP AR",this.arButton.classList.replace("multiset-ar-inactive","multiset-ar-active")),(l=this.adapterSessionStartHandler)==null||l.call(this),(c=(n=this.options).onSessionStart)==null||c.call(n),this.options.autoLocalize&&e.requestAnimationFrame(()=>{this.localizeFrame();});}handleSessionEnd(){var e,t,i;this.arButton&&(this.arButton.textContent="START AR",this.arButton.classList.replace("multiset-ar-active","multiset-ar-inactive")),this.session=null,this.baseLayer=null,this.referenceSpace=null,this.xrBinding=null,this.lastFrameTime=0,this.trackingLossFrames=0,this.hadTrackingLoss=false,this._isLocalizing=false,this.trackerSpace=null,(e=this.adapterSessionEndHandler)==null||e.call(this),(i=(t=this.options).onSessionEnd)==null||i.call(t);}xrLoop(e,t){var l;this.session.requestAnimationFrame((n,c)=>this.xrLoop(n,c));let i=this.lastFrameTime===0?0:(e-this.lastFrameTime)/1e3;this.lastFrameTime=e;let o=t.getViewerPose(this.referenceSpace);if(!o){this.options.relocalization&&(this.trackingLossFrames+=1,this.trackingLossFrames>=Q&&(this.hadTrackingLoss=true));return}this.hadTrackingLoss&&!this._isLocalizing&&this.options.relocalization?(this.hadTrackingLoss=false,this.trackingLossFrames=0,this.localizeFrame()):this.trackingLossFrames=0;let r=o.views[0],a=this.baseLayer.getViewport(r);(l=this.xrFrameHandler)==null||l.call(this,{time:e,frame:t,pose:o,view:r,viewport:a,baseLayer:this.baseLayer,referenceSpace:this.referenceSpace,deltaSeconds:i});}async localizeFrame(){var l,n,c,d,u,h,p,f,v,E,y,C,x;if(!this.session)throw new Error("No active XR session. Start AR before calling localizeFrame().");let e=(l=this.options.confidenceCheck)!=null?l:false,t=Math.max(j,Math.min((n=this.options.confidenceThreshold)!=null?n:.5,K));(d=(c=this.options).onLocalizationInit)==null||d.call(c),this._isLocalizing=true;let i=null,o;try{let w=await this.captureFrame();i=w.result,o=w.failureReason;}catch(w){return (h=(u=this.options).onError)==null||h.call(u,w),null}finally{this._isLocalizing=false;}if(i&&(!e||((p=i.localizeData.confidence)!=null?p:0)>=t)&&i)return (v=(f=this.options).onLocalizationSuccess)==null||v.call(f,i),this.trackerSpace&&((E=this.adapterResultHandler)==null||E.call(this,i,this.trackerSpace)),i;let a=o!=null?o:i?e?`Best confidence ${(y=i.localizeData.confidence)!=null?y:0} below threshold ${t}.`:void 0:"All attempts failed to produce a pose.";return (x=(C=this.options).onLocalizationFailure)==null||x.call(C,a),null}async captureFrame(){var o;let e=this.session,t=this.referenceSpace,i=(o=this.options.localizationTrackingTimeoutMs)!=null?o:J;return new Promise((r,a)=>{let l=Date.now(),n=(c,d)=>{e.requestAnimationFrame(async(u,h)=>{var p,f,v,E,y,C,x,w,z;try{let L=Date.now()-l,F=h.getViewerPose(t);if(!F){if(L>=i||c+1>=Y){let b=(i/1e3).toFixed(1);r({result:null,failureReason:`Tracking unavailable: no viewer pose within ${b}s. Try moving the device or ensuring good lighting.`});}else n(c+1,d);return}let G=F.views;for(let b of G){let T=b.camera;if(!T)continue;let I=(v=(f=(p=this.xrBinding)==null?void 0:p.getCameraImage)==null?void 0:f.call(p,T))!=null?v:null;if(!I)continue;let{width:S,height:V}=T;if(!S||!V)continue;let H=await U(this.gl,I,S,V);if(!H)continue;let k=_(b.projectionMatrix,{width:H.width,height:H.height,x:0,y:0});if(k){(y=(E=this.options).onFrameCaptured)==null||y.call(E,H),(x=(C=this.options).onCameraIntrinsics)==null||x.call(C,k),this.trackerSpace=$(b.transform.matrix);let R=await this.options.client.localizeWithFrame(H,k);R!=null&&R.localizeData&&((z=(w=this.options).onPoseResult)==null||z.call(w,{poseFound:R.localizeData.poseFound,position:R.localizeData.position,rotation:R.localizeData.rotation,mapIds:R.localizeData.mapIds,confidence:R.localizeData.confidence})),r({result:R});return}}d+1>=Z?r({result:null,failureReason:"Camera image not available. The device or browser may not support camera access in AR."}):n(c+1,d+1);}catch(L){a(L);}});};n(0,0);})}dispose(){if(this.session)try{this.session.end();}catch{}let e=this.gl.canvas;e instanceof HTMLCanvasElement&&(e.removeEventListener("webglcontextlost",this.handleContextLost),e.removeEventListener("webglcontextrestored",this.handleContextRestored)),this.arButton=null;}};var ee=`
1
+ import D from'axios';import*as g from'three';import {DRACOLoader}from'three/examples/jsm/loaders/DRACOLoader.js';import {GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';import {TransformControls}from'three/examples/jsm/controls/TransformControls.js';var B={authUrl:"https://api.multiset.ai/v1/m2m/token",queryUrl:"https://api.multiset.ai/v1/vps/map/query-form",mapDetailsUrl:"https://api.multiset.ai/v1/vps/map/",mapSetDetailsUrl:"https://api.multiset.ai/v1/vps/map-set/",fileDownloadUrl:"https://api.multiset.ai/v1/file"};var X=class{constructor(e){this.accessToken=null;this.mapDetailsCache={};let{clientId:t,clientSecret:i,...o}=e;this.credentials={clientId:t,clientSecret:i},this.config=o,this.endpoints={...B,...o.endpoints};}get token(){return this.accessToken}async authorize(){var i,o,r;let e=await D.post(this.endpoints.authUrl,{},{auth:{username:this.credentials.clientId,password:this.credentials.clientSecret}}),t=(r=(i=e.data)==null?void 0:i.token)!=null?r:(o=e.data)==null?void 0:o.access_token;if(!t)throw new Error("Authorization succeeded but no token was returned.");return this.accessToken=t,t}async downloadFile(e){if(!this.accessToken||!e)return "";try{let t=await D.get(`${this.endpoints.fileDownloadUrl}?key=${encodeURIComponent(e)}`,{headers:{Authorization:`Bearer ${this.accessToken}`}});return t.status===200?t.data.url:""}catch{return ""}}async localizeWithFrame(e,t,i){var o;if(!this.accessToken)throw new Error("Access token is missing. Call authorize() first.");return this.queryLocalization(e,t,(o=i==null?void 0:i.fetchMapDetails)!=null?o:false)}async fetchMapDetails(e){if(!this.accessToken)return null;let t=this.mapDetailsCache[e];if(t)return t;try{let i=await D.get(`${this.endpoints.mapDetailsUrl}${e}`,{headers:{Authorization:`Bearer ${this.accessToken}`}});return this.mapDetailsCache[e]=i.data,i.data}catch{return null}}async getGeoPoseComponents(){if(typeof navigator=="undefined"||!("geolocation"in navigator)||!navigator.geolocation)return null;try{let e=await new Promise((n,l)=>{navigator.geolocation.getCurrentPosition(n,l,{enableHighAccuracy:!0,timeout:1e4,maximumAge:0});}),{latitude:t,longitude:i,altitude:o}=e.coords,r=typeof o=="number"&&!Number.isNaN(o)?o:0;return {latitude:t,longitude:i,altitude:r}}catch{return null}}async queryLocalization(e,t,i){var u,p,m;let o=new FormData;this.config.mapType==="map"?o.append("mapCode",this.config.code):o.append("mapSetCode",this.config.code);let r=(u=this.config.isRightHanded)!=null?u:true;o.append("isRightHanded",`${r}`),o.append("fx",`${t.fx}`),o.append("fy",`${t.fy}`),o.append("px",`${t.px}`),o.append("py",`${t.py}`),o.append("width",`${e.width}`),o.append("height",`${e.height}`),o.append("queryImage",e.blob),this.config.convertToGeoCoordinates!==void 0&&o.append("convertToGeoCoordinates",`${this.config.convertToGeoCoordinates}`),"hintMapCodes"in this.config&&((p=this.config.hintMapCodes)!=null&&p.length)&&this.config.hintMapCodes.forEach(d=>{o.append("hintMapCodes",d);}),this.config.hintPosition&&o.append("hintPosition",this.config.hintPosition);let n;if(this.config.passGeoPose){let d=await this.getGeoPoseComponents();if(d){let{latitude:h,longitude:f,altitude:w}=d;n=`${h},${f},${w}`;}}if(n&&o.append("geoHint",n),this.config.hintRadius!==void 0){let d=Number(this.config.hintRadius);if(Number.isNaN(d)||d<1||d>100)throw new Error("hintRadius must be a number between 1 and 100.");if(!this.config.hintPosition&&!n)throw new Error("hintRadius requires hintPosition, or passGeoPose with available geolocation to generate geoHint.");o.append("hintRadius",`${d}`);}"use2DFiltering"in this.config&&this.config.use2DFiltering!==void 0&&o.append("use2DFiltering",`${this.config.use2DFiltering}`);let a=(await D.post(this.endpoints.queryUrl,o,{headers:{Authorization:`Bearer ${this.accessToken}`}})).data;if(!a.poseFound)return null;let c={localizeData:a};if(i&&((m=a.mapCodes)!=null&&m.length)){let d=await this.fetchMapDetails(a.mapCodes[0]);d&&(c.mapDetails=d);}return c}};async function q(s,e,t,i=.8,o=e,r=t){let n=document.createElement("canvas");n.width=e,n.height=t;let l=n.getContext("2d");if(!l)return new Blob;l.putImageData(new ImageData(new Uint8ClampedArray(s),e,t),0,0);let a=document.createElement("canvas");a.width=o,a.height=r;let c=a.getContext("2d");return c?(c.drawImage(n,0,0,o,r),new Promise(u=>{a.toBlob(p=>u(p!=null?p:new Blob),"image/jpeg",i);})):new Blob}async function V(s,e,t,i){let o=s.createFramebuffer();if(!o)return null;let r;try{s.bindFramebuffer(s.FRAMEBUFFER,o),s.framebufferTexture2D(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,e,0),r=new Uint8Array(t*i*4),s.readPixels(0,0,t,i,s.RGBA,s.UNSIGNED_BYTE,r);}finally{s.bindFramebuffer(s.FRAMEBUFFER,null),s.deleteFramebuffer(o);}let n=new Uint8ClampedArray(r.length);for(let p=0;p<i;p+=1){let m=p*t*4,d=(i-p-1)*t*4;n.set(r.subarray(m,m+t*4),d);}let l=Math.min(1,1280/Math.max(t,i)),a=Math.round(t*l),c=Math.round(i*l),u=await q(n.buffer,t,i,.7,a,c);return u.size?{blob:u,width:a,height:c}:null}function _(s,e){let t=s,i=(1-t[8])*e.width/2+e.x,o=(1-t[9])*e.height/2+e.y,r=e.width/2*t[0],n=e.height/2*t[5];return {fx:r,fy:n,px:i,py:o,width:e.width,height:e.height}}function O(s){return new Float32Array(s)}var j=.2,K=.8,Q=60,J=1e4,Y=300,Z=10,G=class{constructor(e,t){this.gl=e;this.options=t;this.session=null;this.referenceSpace=null;this.baseLayer=null;this.xrBinding=null;this.lastFrameTime=0;this.trackingLossFrames=0;this.hadTrackingLoss=false;this._isLocalizing=false;this.trackerSpace=null;this.arButton=null;this.xrFrameHandler=null;this.adapterResultHandler=null;this.adapterSessionStartHandler=null;this.adapterSessionEndHandler=null;this.handleContextLost=e=>{var t,i;if(e.preventDefault(),this.session)try{this.session.end();}catch{}(i=(t=this.options).onContextLost)==null||i.call(t);};this.handleContextRestored=()=>{var e,t;(t=(e=this.options).onContextRestored)==null||t.call(e);};let i=e.canvas;i instanceof HTMLCanvasElement&&(i.addEventListener("webglcontextlost",this.handleContextLost),i.addEventListener("webglcontextrestored",this.handleContextRestored));}static async isSupported(){if(!navigator.xr)return false;try{return await navigator.xr.isSessionSupported("immersive-ar")}catch{return false}}setXRFrameHandler(e){this.xrFrameHandler=e;}setAdapterResultHandler(e){this.adapterResultHandler=e;}setAdapterSessionHandlers(e,t){this.adapterSessionStartHandler=e,this.adapterSessionEndHandler=t;}getClient(){return this.options.client}getOverlayRoot(){return this.options.overlayRoot}isActive(){return this.session!==null}get isLocalizing(){return this._isLocalizing}stopSession(){this.session&&this.session.end();}getBaseLayer(){return this.baseLayer}createButton(){let e=document.createElement("button");return e.textContent="START AR",e.className="multiset-ar-button multiset-ar-inactive",e.style.cssText=["position:fixed","bottom:20px","left:50%","transform:translateX(-50%)","padding:12px 24px","border:1px solid #fff","border-radius:4px","background:rgba(0,0,0,0.1)","color:#fff","font-size:13px","cursor:pointer","z-index:999"].join(";"),e.addEventListener("click",()=>{this.session?this.session.end():this.startSession();}),this.arButton=e,e}async startSession(){var e,t,i;try{if(!navigator.xr)throw new Error("WebXR not supported on this device.");let o=await navigator.xr.requestSession("immersive-ar",{requiredFeatures:["local"],optionalFeatures:["camera-access","dom-overlay"],domOverlay:{root:(e=this.options.overlayRoot)!=null?e:document.body}});await this.initSession(o);}catch(o){(i=(t=this.options).onError)==null||i.call(t,o);}}async initSession(e){var n,l,a,c;await this.gl.makeXRCompatible();let t={};this.options.framebufferScaleFactor!==void 0&&(t.framebufferScaleFactor=this.options.framebufferScaleFactor);let i=new XRWebGLLayer(e,this.gl,t);await e.updateRenderState({baseLayer:i});let o=await e.requestReferenceSpace((n=this.options.referenceSpaceType)!=null?n:"local");this.session=e,this.baseLayer=i,this.referenceSpace=o;let r=XRWebGLBinding;this.xrBinding=new r(e,this.gl),e.addEventListener("end",()=>this.handleSessionEnd()),e.requestAnimationFrame((u,p)=>this.xrLoop(u,p)),this.arButton&&(this.arButton.textContent="STOP AR",this.arButton.classList.replace("multiset-ar-inactive","multiset-ar-active")),(l=this.adapterSessionStartHandler)==null||l.call(this),(c=(a=this.options).onSessionStart)==null||c.call(a),this.options.autoLocalize&&e.requestAnimationFrame(()=>{this.localizeFrame();});}handleSessionEnd(){var e,t,i;this.arButton&&(this.arButton.textContent="START AR",this.arButton.classList.replace("multiset-ar-active","multiset-ar-inactive")),this.session=null,this.baseLayer=null,this.referenceSpace=null,this.xrBinding=null,this.lastFrameTime=0,this.trackingLossFrames=0,this.hadTrackingLoss=false,this._isLocalizing=false,this.trackerSpace=null,(e=this.adapterSessionEndHandler)==null||e.call(this),(i=(t=this.options).onSessionEnd)==null||i.call(t);}xrLoop(e,t){var l;this.session.requestAnimationFrame((a,c)=>this.xrLoop(a,c));let i=this.lastFrameTime===0?0:(e-this.lastFrameTime)/1e3;this.lastFrameTime=e;let o=t.getViewerPose(this.referenceSpace);if(!o){this.options.relocalization&&(this.trackingLossFrames+=1,this.trackingLossFrames>=Q&&(this.hadTrackingLoss=true));return}this.hadTrackingLoss&&!this._isLocalizing&&this.options.relocalization?(this.hadTrackingLoss=false,this.trackingLossFrames=0,this.localizeFrame()):this.trackingLossFrames=0;let r=o.views[0],n=this.baseLayer.getViewport(r);(l=this.xrFrameHandler)==null||l.call(this,{time:e,frame:t,pose:o,view:r,viewport:n,baseLayer:this.baseLayer,referenceSpace:this.referenceSpace,deltaSeconds:i});}async localizeFrame(){var l,a,c,u,p,m,d,h,f,w,C,M,b;if(!this.session)throw new Error("No active XR session. Start AR before calling localizeFrame().");let e=(l=this.options.confidenceCheck)!=null?l:false,t=Math.max(j,Math.min((a=this.options.confidenceThreshold)!=null?a:.5,K));(u=(c=this.options).onLocalizationInit)==null||u.call(c),this._isLocalizing=true;let i=null,o;try{let R=await this.captureFrame();i=R.result,o=R.failureReason;}catch(R){return (m=(p=this.options).onError)==null||m.call(p,R),null}finally{this._isLocalizing=false;}if(i&&(!e||((d=i.localizeData.confidence)!=null?d:0)>=t)&&i)return (f=(h=this.options).onLocalizationSuccess)==null||f.call(h,i),this.trackerSpace&&((w=this.adapterResultHandler)==null||w.call(this,i,this.trackerSpace)),i;let n=o!=null?o:i?e?`Best confidence ${(C=i.localizeData.confidence)!=null?C:0} below threshold ${t}.`:void 0:"All attempts failed to produce a pose.";return (b=(M=this.options).onLocalizationFailure)==null||b.call(M,n),null}async captureFrame(){var o;let e=this.session,t=this.referenceSpace,i=(o=this.options.localizationTrackingTimeoutMs)!=null?o:J;return new Promise((r,n)=>{let l=Date.now(),a=(c,u)=>{e.requestAnimationFrame(async(p,m)=>{var d,h,f,w,C,M,b,R,z;try{let T=Date.now()-l,I=m.getViewerPose(t);if(!I){if(T>=i||c+1>=Y){let L=(i/1e3).toFixed(1);r({result:null,failureReason:`Tracking unavailable: no viewer pose within ${L}s. Try moving the device or ensuring good lighting.`});}else a(c+1,u);return}let A=I.views;for(let L of A){let x=L.camera;if(!x)continue;let F=(f=(h=(d=this.xrBinding)==null?void 0:d.getCameraImage)==null?void 0:h.call(d,x))!=null?f:null;if(!F)continue;let{width:S,height:U}=x;if(!S||!U)continue;let H=await V(this.gl,F,S,U);if(!H)continue;let k=_(L.projectionMatrix,{width:H.width,height:H.height,x:0,y:0});if(k){(C=(w=this.options).onFrameCaptured)==null||C.call(w,H),(b=(M=this.options).onCameraIntrinsics)==null||b.call(M,k),this.trackerSpace=O(L.transform.matrix);let y=await this.options.client.localizeWithFrame(H,k);y!=null&&y.localizeData&&((z=(R=this.options).onPoseResult)==null||z.call(R,{poseFound:y.localizeData.poseFound,position:y.localizeData.position,rotation:y.localizeData.rotation,mapIds:y.localizeData.mapIds,confidence:y.localizeData.confidence})),r({result:y});return}}u+1>=Z?r({result:null,failureReason:"Camera image not available. The device or browser may not support camera access in AR."}):a(c+1,u+1);}catch(T){n(T);}});};a(0,0);})}dispose(){if(this.session)try{this.session.end();}catch{}let e=this.gl.canvas;e instanceof HTMLCanvasElement&&(e.removeEventListener("webglcontextlost",this.handleContextLost),e.removeEventListener("webglcontextrestored",this.handleContextRestored)),this.arButton=null;}};var ee=`
2
2
  varying vec3 vWorldPosition;
3
3
  varying vec3 vWorldNormal;
4
4
 
@@ -90,4 +90,4 @@ void main() {
90
90
 
91
91
  gl_FragColor = vec4(finalColor, alphaWithGlow);
92
92
  }
93
- `;function O(s={}){var v,E,y,C,x,w,z,L,F,G,b,T,I,S;let e=(v=s.color)!=null?v:"#7B2CBF",t=(E=s.opacity)!=null?E:150/255,i=(y=s.gridColor)!=null?y:"#ffeb3b",o=(C=s.gridScale)!=null?C:2,r=(x=s.gridLineWidth)!=null?x:.02,a=(w=s.showGrid)!=null?w:1,l=(z=s.center)!=null?z:new m.Vector3(0,0,0),n=(L=s.radius)!=null?L:1,c=(F=s.progress)!=null?F:1,d=(G=s.glowColor)!=null?G:"#FF3A00",u=(b=s.glowWidth)!=null?b:.05,h=(T=s.glowIntensity)!=null?T:2,p=(I=s.lightColor)!=null?I:"#ffffff",f=(S=s.lightDirection)!=null?S:new m.Vector3(.3,1,.3).normalize();return new m.ShaderMaterial({vertexShader:ee,fragmentShader:te,transparent:true,side:m.DoubleSide,uniforms:{uColor:{value:typeof e=="string"?new m.Color(e):e},uOpacity:{value:t},uGridColor:{value:typeof i=="string"?new m.Color(i):i},uGridSize:{value:o},uGridLineWidth:{value:r},uShowGrid:{value:a},uCenter:{value:l.clone()},uRadius:{value:n},uProgress:{value:c},uGlowColor:{value:typeof d=="string"?new m.Color(d):d},uGlowWidth:{value:u},uGlowIntensity:{value:h},uLightColor:{value:typeof p=="string"?new m.Color(p):p},uLightDirection:{value:f.clone()}}})}var P=class{constructor(e,t,i,o){this.scene=e;this.client=t;this.renderer=i;this.camera=o;this.gizmoControl=null;this.gizmoHelper=null;this.meshMaterial=null;this.localCenter=new m.Vector3;this.localRadius=0;this.radialDuration=4;this.meshGroup=new m.Group,this.meshGroup.visible=false,this.scene.add(this.meshGroup),this.dracoLoader=new DRACOLoader,this.dracoLoader.setDecoderPath("/draco/"),this.gltfLoader=new GLTFLoader,this.gltfLoader.setDRACOLoader(this.dracoLoader);}getMeshGroup(){return this.meshGroup}async ensureGizmoLoaded(){if(!this.gizmoControl){let e=new TransformControls(this.camera,this.renderer.domElement);e.setMode("translate"),e.setSpace("local"),e.enabled=false;let t=e.getHelper();this.scene.add(t),e.attach(this.meshGroup),this.gizmoControl=e,this.gizmoHelper=t;}this.gizmoHelper.visible=true;}async ensureMeshLoaded(e){var o,r;if(this.scene.getObjectByName(e._id))return;let t=(r=(o=e.mapMesh)==null?void 0:o.rawMesh)==null?void 0:r.meshLink;if(!t)return;let i=await this.client.downloadFile(t);i&&await new Promise((a,l)=>{this.gltfLoader.load(i,n=>{let c=new m.Box3().setFromObject(n.scene),d=c.getSize(new m.Vector3),u=c.getCenter(new m.Vector3);this.localCenter.copy(u),this.localRadius=Math.max(d.length()/2*1.1,.001);let h=O({color:"#7B2CBF",opacity:.58,gridColor:"#ffeb3b",gridScale:2,gridLineWidth:.02,showGrid:1,center:this.localCenter.clone(),radius:this.localRadius,progress:0,glowColor:"#FF3A00",glowWidth:.05,glowIntensity:2});this.meshMaterial=h,n.scene.traverse(p=>{let f=p;f.isMesh&&(f.material=h,f.frustumCulled=false);}),n.scene.name=e._id,this.meshGroup.add(n.scene),a();},void 0,n=>{l(n instanceof Error?n:new Error(String(n)));});});}applyMeshTransform(e,t){let i=e.localizeData,o=new m.Vector3(i.position.x,i.position.y,i.position.z),r=new m.Quaternion(i.rotation.x,i.rotation.y,i.rotation.z,i.rotation.w),a=new m.Matrix4;a.compose(o,r,new m.Vector3(1,1,1));let l=a.clone().invert(),n=new m.Matrix4;n.multiplyMatrices(t,l);let c=new m.Vector3,d=new m.Quaternion,u=new m.Vector3;n.decompose(c,d,u),this.meshGroup.position.copy(c),this.meshGroup.quaternion.copy(d),this.meshGroup.scale.set(1,1,1),this.meshGroup.visible=true,this.meshGroup.updateMatrixWorld(true),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0,this.meshMaterial.uniforms.uCenter.value.copy(this.localCenter).applyMatrix4(this.meshGroup.matrixWorld));}update(e,t){if(!this.meshMaterial)return;let i=this.meshMaterial.uniforms.uProgress;i&&(i.value>=1||(i.value=Math.min(i.value+e/this.radialDuration,1)));}hideUntilNextLocalization(){this.meshGroup.visible=false,this.gizmoHelper&&(this.gizmoHelper.visible=false),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0);}dispose(){this.meshMaterial=null,this.meshGroup.traverse(e=>{let t=e;t.isMesh&&(t.geometry.dispose(),Array.isArray(t.material)?t.material.forEach(i=>i.dispose()):t.material.dispose());}),this.scene.remove(this.meshGroup),this.dracoLoader.dispose(),this.gizmoHelper&&this.scene.remove(this.gizmoHelper),this.gizmoControl&&this.gizmoControl.dispose();}};var W=class{constructor(e,t,i,o){this.meshVisualizer=new P(e,t,i,o);}async ensureGizmoLoaded(){await this.meshVisualizer.ensureGizmoLoaded();}async ensureMeshLoaded(e){await this.meshVisualizer.ensureMeshLoaded(e);}applyMeshTransform(e,t){this.meshVisualizer.applyMeshTransform(e,t);}update(e,t){this.meshVisualizer.update(e,t);}hideUntilNextLocalization(){this.meshVisualizer.hideUntilNextLocalization();}dispose(){this.meshVisualizer.dispose();}};var N=class{constructor(e){this.options=e;this.world=null;this.previewRAFHandle=null;this.resizeHandler=null;this.xrFrameCount=0;this.xrRenderTarget=null;let{session:t,renderer:i,camera:o}=e;i.xr.enabled=false,o.matrixAutoUpdate=false,t.setXRFrameHandler(r=>this.onXRFrame(r)),t.setAdapterResultHandler((r,a)=>{this.handleLocalizationResult(r,a);}),t.setAdapterSessionHandlers(()=>{o.matrixAutoUpdate=false;let r=t.getBaseLayer();r&&(this.xrRenderTarget=new m.WebGLRenderTarget(r.framebufferWidth,r.framebufferHeight)),this.stopPreviewLoop();},()=>{var r,a;i.setRenderTarget(null),this.xrRenderTarget&&(i.setRenderTargetFramebuffer(this.xrRenderTarget,null),this.xrRenderTarget.dispose(),this.xrRenderTarget=null),(r=this.world)==null||r.hideUntilNextLocalization(),o.matrixAutoUpdate=true,o.position.set(0,0,0),o.quaternion.identity(),(a=this.resizeHandler)==null||a.call(this),this.startPreviewLoop();}),(e.showMesh||e.showGizmo!==false)&&(this.world=new W(e.scene,t.getClient(),i,o));}static isSupported(){return A.isSupported()}initialize(e){var n,c;let{options:t}=this,{session:i}=t,o=null;if(t.useDefaultButton!==false){o=i.createButton();let d=e instanceof HTMLElement?e:t.buttonContainer instanceof HTMLElement?t.buttonContainer:(n=i.getOverlayRoot())!=null?n:document.body;d.contains(o)||d.appendChild(o),(c=t.onButtonCreated)==null||c.call(t,o);}let{renderer:r,camera:a}=t;this.resizeHandler=()=>{a.aspect=window.innerWidth/window.innerHeight,a.updateProjectionMatrix(),r.setSize(window.innerWidth,window.innerHeight);},window.addEventListener("resize",this.resizeHandler),this.resizeHandler();let l=r.domElement;return console.log(`[ThreeAdapter] initialize \u2014 canvas size: ${l.width}x${l.height}, window: ${window.innerWidth}x${window.innerHeight}`),this.startPreviewLoop(),o}isActive(){return this.options.session.isActive()}get isLocalizing(){return this.options.session.isLocalizing}startSession(){return this.options.session.startSession()}stopSession(){this.options.session.stopSession();}async localizeFrame(){return this.options.session.localizeFrame()}onXRFrame(e){var r,a;let{renderer:t,scene:i,camera:o}=this.options;if(this.xrRenderTarget&&(t.setRenderTargetFramebuffer(this.xrRenderTarget,e.baseLayer.framebuffer),t.setRenderTarget(this.xrRenderTarget)),this.syncCameraMatrices(e.view),this.xrFrameCount+=1,this.xrFrameCount<=5){let l=e.pose.transform.position,n=new m.Vector3().setFromMatrixPosition(o.matrixWorld),d=new m.Vector3(0,0,-0.4).clone().applyMatrix4(o.matrixWorldInverse);console.log(`[ThreeAdapter] XR frame #${this.xrFrameCount} | rt: ${this.xrRenderTarget?"OK":"NULL"}`),console.log(`[ThreeAdapter] XR pose: x=${l.x.toFixed(3)} y=${l.y.toFixed(3)} z=${l.z.toFixed(3)}`),console.log(`[ThreeAdapter] camera.matrixWorld: x=${n.x.toFixed(3)} y=${n.y.toFixed(3)} z=${n.z.toFixed(3)}`),console.log(`[ThreeAdapter] cube cam-space z=${d.z.toFixed(3)} (negative = in front)`),console.log(`[ThreeAdapter] scene children: ${i.children.length}`);}if(this.world&&e.deltaSeconds>0){let l=e.pose.transform.position;this.world.update(e.deltaSeconds,new m.Vector3(l.x,l.y,l.z));}(a=(r=this.options).onXRFrame)==null||a.call(r,e),t.render(i,o);}syncCameraMatrices(e){let{camera:t}=this.options;t.projectionMatrix.fromArray(e.projectionMatrix),t.projectionMatrixInverse.copy(t.projectionMatrix).invert(),t.matrixWorld.fromArray(e.transform.matrix),t.matrixWorldInverse.fromArray(e.transform.inverse.matrix),t.matrix.copy(t.matrixWorld);}startPreviewLoop(){let{renderer:e,scene:t,camera:i}=this.options;console.log(`[ThreeAdapter] preview loop started \u2014 scene has ${t.children.length} objects`);let o=()=>{this.previewRAFHandle=window.requestAnimationFrame(o),e.render(t,i);};this.previewRAFHandle=window.requestAnimationFrame(o);}stopPreviewLoop(){this.previewRAFHandle!==null&&(cancelAnimationFrame(this.previewRAFHandle),this.previewRAFHandle=null,this.xrFrameCount=0,console.log("[ThreeAdapter] preview loop stopped \u2014 XR session starting"));}async handleLocalizationResult(e,t){var n;if(!this.world)return;let{showMesh:i,showGizmo:o,session:r}=this.options,a=o!==false;if(i&&((n=e.localizeData.mapCodes)!=null&&n[0]))try{let c=await r.getClient().fetchMapDetails(e.localizeData.mapCodes[0]);c&&(e.mapDetails=c);}catch{}let l=i&&!!e.mapDetails;if(!(!l&&!a))try{if(a&&await this.world.ensureGizmoLoaded(),l&&await this.world.ensureMeshLoaded(e.mapDetails),!r.isActive())return;this.world.applyMeshTransform(e,new m.Matrix4().fromArray(t));}catch{}}dispose(){var e;this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null),this.stopPreviewLoop(),(e=this.world)==null||e.dispose(),this.world=null,this.options.session.dispose();}};export{X as DEFAULT_ENDPOINTS,B as MultisetClient,N as ThreeAdapter,A as XRSessionManager};
93
+ `;function $(s={}){var f,w,C,M,b,R,z,T,I,A,L,x,F,S;let e=(f=s.color)!=null?f:"#7B2CBF",t=(w=s.opacity)!=null?w:150/255,i=(C=s.gridColor)!=null?C:"#ffeb3b",o=(M=s.gridScale)!=null?M:2,r=(b=s.gridLineWidth)!=null?b:.02,n=(R=s.showGrid)!=null?R:1,l=(z=s.center)!=null?z:new g.Vector3(0,0,0),a=(T=s.radius)!=null?T:1,c=(I=s.progress)!=null?I:1,u=(A=s.glowColor)!=null?A:"#FF3A00",p=(L=s.glowWidth)!=null?L:.05,m=(x=s.glowIntensity)!=null?x:2,d=(F=s.lightColor)!=null?F:"#ffffff",h=(S=s.lightDirection)!=null?S:new g.Vector3(.3,1,.3).normalize();return new g.ShaderMaterial({vertexShader:ee,fragmentShader:te,transparent:true,side:g.DoubleSide,uniforms:{uColor:{value:typeof e=="string"?new g.Color(e):e},uOpacity:{value:t},uGridColor:{value:typeof i=="string"?new g.Color(i):i},uGridSize:{value:o},uGridLineWidth:{value:r},uShowGrid:{value:n},uCenter:{value:l.clone()},uRadius:{value:a},uProgress:{value:c},uGlowColor:{value:typeof u=="string"?new g.Color(u):u},uGlowWidth:{value:p},uGlowIntensity:{value:m},uLightColor:{value:typeof d=="string"?new g.Color(d):d},uLightDirection:{value:h.clone()}}})}var P=class{constructor(e,t,i,o){this.scene=e;this.client=t;this.renderer=i;this.camera=o;this.gizmoControl=null;this.gizmoHelper=null;this.meshMaterial=null;this.localCenter=new g.Vector3;this.localRadius=0;this.radialDuration=4;this.meshGroup=new g.Group,this.meshGroup.visible=false,this.scene.add(this.meshGroup),this.dracoLoader=new DRACOLoader,this.dracoLoader.setDecoderPath("/draco/"),this.gltfLoader=new GLTFLoader,this.gltfLoader.setDRACOLoader(this.dracoLoader);}getMeshGroup(){return this.meshGroup}async ensureGizmoLoaded(){if(!this.gizmoControl){let e=new TransformControls(this.camera,this.renderer.domElement);e.setMode("translate"),e.setSpace("local"),e.enabled=false;let t=e.getHelper();this.scene.add(t),e.attach(this.meshGroup),this.gizmoControl=e,this.gizmoHelper=t;}this.gizmoHelper.visible=true;}async ensureMeshLoaded(e){var o,r;if(this.scene.getObjectByName(e._id))return;let t=(r=(o=e.mapMesh)==null?void 0:o.rawMesh)==null?void 0:r.meshLink;if(!t)return;let i=await this.client.downloadFile(t);i&&await new Promise((n,l)=>{this.gltfLoader.load(i,a=>{let c=new g.Box3().setFromObject(a.scene),u=c.getSize(new g.Vector3),p=c.getCenter(new g.Vector3);this.localCenter.copy(p),this.localRadius=Math.max(u.length()/2*1.1,.001);let m=$({color:"#7B2CBF",opacity:.58,gridColor:"#ffeb3b",gridScale:2,gridLineWidth:.02,showGrid:1,center:this.localCenter.clone(),radius:this.localRadius,progress:0,glowColor:"#FF3A00",glowWidth:.05,glowIntensity:2});this.meshMaterial=m,a.scene.traverse(d=>{let h=d;h.isMesh&&(h.material=m,h.frustumCulled=false);}),a.scene.name=e._id,this.meshGroup.add(a.scene),n();},void 0,a=>{l(a instanceof Error?a:new Error(String(a)));});});}applyMeshTransform(e){let t=new g.Vector3,i=new g.Quaternion,o=new g.Vector3;e.decompose(t,i,o),this.meshGroup.position.copy(t),this.meshGroup.quaternion.copy(i),this.meshGroup.scale.set(1,1,1),this.meshGroup.visible=true,this.meshGroup.updateMatrixWorld(true),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0,this.meshMaterial.uniforms.uCenter.value.copy(this.localCenter).applyMatrix4(this.meshGroup.matrixWorld));}update(e,t){if(!this.meshMaterial)return;let i=this.meshMaterial.uniforms.uProgress;i&&(i.value>=1||(i.value=Math.min(i.value+e/this.radialDuration,1)));}hideUntilNextLocalization(){this.meshGroup.visible=false,this.gizmoHelper&&(this.gizmoHelper.visible=false),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0);}dispose(){this.meshMaterial=null,this.meshGroup.traverse(e=>{let t=e;t.isMesh&&(t.geometry.dispose(),Array.isArray(t.material)?t.material.forEach(i=>i.dispose()):t.material.dispose());}),this.scene.remove(this.meshGroup),this.dracoLoader.dispose(),this.gizmoHelper&&this.scene.remove(this.gizmoHelper),this.gizmoControl&&this.gizmoControl.dispose();}};var W=class{constructor(e,t,i,o){this.meshVisualizer=new P(e,t,i,o);}async ensureGizmoLoaded(){await this.meshVisualizer.ensureGizmoLoaded();}async ensureMeshLoaded(e){await this.meshVisualizer.ensureMeshLoaded(e);}applyMeshTransform(e){this.meshVisualizer.applyMeshTransform(e);}update(e,t){this.meshVisualizer.update(e,t);}hideUntilNextLocalization(){this.meshVisualizer.hideUntilNextLocalization();}dispose(){this.meshVisualizer.dispose();}};var N=class{constructor(e){this.options=e;this.world=null;this.previewRAFHandle=null;this.resizeHandler=null;this.xrRenderTarget=null;let{session:t,renderer:i,camera:o}=e;i.xr.enabled=false,o.matrixAutoUpdate=false,t.setXRFrameHandler(r=>this.onXRFrame(r)),t.setAdapterResultHandler((r,n)=>{this.handleLocalizationResult(r,n);}),t.setAdapterSessionHandlers(()=>{o.matrixAutoUpdate=false;let r=t.getBaseLayer();r&&(this.xrRenderTarget=new g.WebGLRenderTarget(r.framebufferWidth,r.framebufferHeight)),this.stopPreviewLoop();},()=>{var r,n;i.setRenderTarget(null),this.xrRenderTarget&&(i.setRenderTargetFramebuffer(this.xrRenderTarget,null),this.xrRenderTarget.dispose(),this.xrRenderTarget=null),(r=this.world)==null||r.hideUntilNextLocalization(),o.matrixAutoUpdate=true,o.position.set(0,0,0),o.quaternion.identity(),(n=this.resizeHandler)==null||n.call(this),this.startPreviewLoop();}),(e.showMesh||e.showGizmo!==false)&&(this.world=new W(e.scene,t.getClient(),i,o));}static isSupported(){return G.isSupported()}initialize(e){var l,a;let{options:t}=this,{session:i}=t,o=null;if(t.useDefaultButton!==false){o=i.createButton();let c=e instanceof HTMLElement?e:t.buttonContainer instanceof HTMLElement?t.buttonContainer:(l=i.getOverlayRoot())!=null?l:document.body;c.contains(o)||c.appendChild(o),(a=t.onButtonCreated)==null||a.call(t,o);}let{renderer:r,camera:n}=t;return this.resizeHandler=()=>{n.aspect=window.innerWidth/window.innerHeight,n.updateProjectionMatrix(),r.setSize(window.innerWidth,window.innerHeight);},window.addEventListener("resize",this.resizeHandler),this.resizeHandler(),this.startPreviewLoop(),o}isActive(){return this.options.session.isActive()}get isLocalizing(){return this.options.session.isLocalizing}startSession(){return this.options.session.startSession()}stopSession(){this.options.session.stopSession();}async localizeFrame(){return this.options.session.localizeFrame()}onXRFrame(e){var r,n;let{renderer:t,scene:i,camera:o}=this.options;if(this.xrRenderTarget&&(t.setRenderTargetFramebuffer(this.xrRenderTarget,e.baseLayer.framebuffer),t.setRenderTarget(this.xrRenderTarget)),this.syncCameraMatrices(e.view),this.world&&e.deltaSeconds>0){let l=e.pose.transform.position;this.world.update(e.deltaSeconds,new g.Vector3(l.x,l.y,l.z));}(n=(r=this.options).onXRFrame)==null||n.call(r,e),t.render(i,o);}syncCameraMatrices(e){let{camera:t}=this.options;t.projectionMatrix.fromArray(e.projectionMatrix),t.projectionMatrixInverse.copy(t.projectionMatrix).invert(),t.matrixWorld.fromArray(e.transform.matrix),t.matrixWorldInverse.fromArray(e.transform.inverse.matrix),t.matrix.copy(t.matrixWorld);}startPreviewLoop(){let{renderer:e,scene:t,camera:i}=this.options,o=()=>{this.previewRAFHandle=window.requestAnimationFrame(o),e.render(t,i);};this.previewRAFHandle=window.requestAnimationFrame(o);}stopPreviewLoop(){this.previewRAFHandle!==null&&(cancelAnimationFrame(this.previewRAFHandle),this.previewRAFHandle=null);}async handleLocalizationResult(e,t){var m,d,h;let{position:i,rotation:o}=e.localizeData,r=new g.Matrix4().compose(new g.Vector3(i.x,i.y,i.z),new g.Quaternion(o.x,o.y,o.z,o.w),new g.Vector3(1,1,1)),n=new g.Matrix4().multiplyMatrices(new g.Matrix4().fromArray(t),r.invert());if((d=(m=this.options).onLocalizationSuccess)==null||d.call(m,e,n),!this.world)return;let{showMesh:l,showGizmo:a,session:c}=this.options,u=a!==false;if(l&&((h=e.localizeData.mapCodes)!=null&&h[0]))try{let f=await c.getClient().fetchMapDetails(e.localizeData.mapCodes[0]);f&&(e.mapDetails=f);}catch{}let p=l&&!!e.mapDetails;if(!(!p&&!u))try{if(u&&await this.world.ensureGizmoLoaded(),p&&await this.world.ensureMeshLoaded(e.mapDetails),!c.isActive())return;this.world.applyMeshTransform(n);}catch{}}dispose(){var e;this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null),this.stopPreviewLoop(),(e=this.world)==null||e.dispose(),this.world=null,this.options.session.dispose();}};export{B as DEFAULT_ENDPOINTS,X as MultisetClient,N as ThreeAdapter,G as XRSessionManager};
@@ -25,6 +25,24 @@ interface IThreeAdapterOptions {
25
25
  * in response to the current device pose.
26
26
  */
27
27
  onXRFrame?: (event: IXRFrameEvent) => void;
28
+ /**
29
+ * Called after a successful localization.
30
+ *
31
+ * `worldFromMap` is a THREE.Matrix4 that transforms any point from VPS map
32
+ * space into Three.js world space (the XR reference space). Use it to place
33
+ * scene objects at known physical locations inside the scanned map:
34
+ *
35
+ * ```ts
36
+ * onLocalizationSuccess: (result, worldFromMap) => {
37
+ * const marker = new THREE.Mesh(geometry, material);
38
+ * // mapPoint is a position you know from the scanned map (in metres)
39
+ * const mapPoint = new THREE.Vector3(1.5, 0, -2.0);
40
+ * marker.position.copy(mapPoint.applyMatrix4(worldFromMap));
41
+ * scene.add(marker);
42
+ * }
43
+ * ```
44
+ */
45
+ onLocalizationSuccess?: (result: ILocalizeAndMapDetails, worldFromMap: THREE.Matrix4) => void;
28
46
  }
29
47
  declare class ThreeAdapter {
30
48
  private readonly options;
@@ -33,7 +51,6 @@ declare class ThreeAdapter {
33
51
  private world;
34
52
  private previewRAFHandle;
35
53
  private resizeHandler;
36
- private xrFrameCount;
37
54
  private xrRenderTarget;
38
55
  constructor(options: IThreeAdapterOptions);
39
56
  initialize(buttonContainer?: HTMLElement): HTMLButtonElement | null;
@@ -1,4 +1,4 @@
1
- import*as m from'three';import {DRACOLoader}from'three/examples/jsm/loaders/DRACOLoader.js';import {GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';import {TransformControls}from'three/examples/jsm/controls/TransformControls.js';async function O(s,e,t,i=.8,r=e,o=t){let n=document.createElement("canvas");n.width=e,n.height=t;let l=n.getContext("2d");if(!l)return new Blob;l.putImageData(new ImageData(new Uint8ClampedArray(s),e,t),0,0);let a=document.createElement("canvas");a.width=r,a.height=o;let c=a.getContext("2d");return c?(c.drawImage(n,0,0,r,o),new Promise(d=>{a.toBlob(u=>d(u!=null?u:new Blob),"image/jpeg",i);})):new Blob}async function N(s,e,t,i){let r=s.createFramebuffer();if(!r)return null;let o;try{s.bindFramebuffer(s.FRAMEBUFFER,r),s.framebufferTexture2D(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,e,0),o=new Uint8Array(t*i*4),s.readPixels(0,0,t,i,s.RGBA,s.UNSIGNED_BYTE,o);}finally{s.bindFramebuffer(s.FRAMEBUFFER,null),s.deleteFramebuffer(r);}let n=new Uint8ClampedArray(o.length);for(let u=0;u<i;u+=1){let p=u*t*4,h=(i-u-1)*t*4;n.set(o.subarray(p,p+t*4),h);}let l=Math.min(1,1280/Math.max(t,i)),a=Math.round(t*l),c=Math.round(i*l),d=await O(n.buffer,t,i,.7,a,c);return d.size?{blob:d,width:a,height:c}:null}function V(s,e){let t=s,i=(1-t[8])*e.width/2+e.x,r=(1-t[9])*e.height/2+e.y,o=e.width/2*t[0],n=e.height/2*t[5];return {fx:o,fy:n,px:i,py:r,width:e.width,height:e.height}}function k(s){return new Float32Array(s)}var U=.2,$=.8,j=60,q=1e4,K=300,Q=10,I=class{constructor(e,t){this.gl=e;this.options=t;this.session=null;this.referenceSpace=null;this.baseLayer=null;this.xrBinding=null;this.lastFrameTime=0;this.trackingLossFrames=0;this.hadTrackingLoss=false;this._isLocalizing=false;this.trackerSpace=null;this.arButton=null;this.xrFrameHandler=null;this.adapterResultHandler=null;this.adapterSessionStartHandler=null;this.adapterSessionEndHandler=null;this.handleContextLost=e=>{var t,i;if(e.preventDefault(),this.session)try{this.session.end();}catch{}(i=(t=this.options).onContextLost)==null||i.call(t);};this.handleContextRestored=()=>{var e,t;(t=(e=this.options).onContextRestored)==null||t.call(e);};let i=e.canvas;i instanceof HTMLCanvasElement&&(i.addEventListener("webglcontextlost",this.handleContextLost),i.addEventListener("webglcontextrestored",this.handleContextRestored));}static async isSupported(){if(!navigator.xr)return false;try{return await navigator.xr.isSessionSupported("immersive-ar")}catch{return false}}setXRFrameHandler(e){this.xrFrameHandler=e;}setAdapterResultHandler(e){this.adapterResultHandler=e;}setAdapterSessionHandlers(e,t){this.adapterSessionStartHandler=e,this.adapterSessionEndHandler=t;}getClient(){return this.options.client}getOverlayRoot(){return this.options.overlayRoot}isActive(){return this.session!==null}get isLocalizing(){return this._isLocalizing}stopSession(){this.session&&this.session.end();}getBaseLayer(){return this.baseLayer}createButton(){let e=document.createElement("button");return e.textContent="START AR",e.className="multiset-ar-button multiset-ar-inactive",e.style.cssText=["position:fixed","bottom:20px","left:50%","transform:translateX(-50%)","padding:12px 24px","border:1px solid #fff","border-radius:4px","background:rgba(0,0,0,0.1)","color:#fff","font-size:13px","cursor:pointer","z-index:999"].join(";"),e.addEventListener("click",()=>{this.session?this.session.end():this.startSession();}),this.arButton=e,e}async startSession(){var e,t,i;try{if(!navigator.xr)throw new Error("WebXR not supported on this device.");let r=await navigator.xr.requestSession("immersive-ar",{requiredFeatures:["local"],optionalFeatures:["camera-access","dom-overlay"],domOverlay:{root:(e=this.options.overlayRoot)!=null?e:document.body}});await this.initSession(r);}catch(r){(i=(t=this.options).onError)==null||i.call(t,r);}}async initSession(e){var n,l,a,c;await this.gl.makeXRCompatible();let t={};this.options.framebufferScaleFactor!==void 0&&(t.framebufferScaleFactor=this.options.framebufferScaleFactor);let i=new XRWebGLLayer(e,this.gl,t);await e.updateRenderState({baseLayer:i});let r=await e.requestReferenceSpace((n=this.options.referenceSpaceType)!=null?n:"local");this.session=e,this.baseLayer=i,this.referenceSpace=r;let o=XRWebGLBinding;this.xrBinding=new o(e,this.gl),e.addEventListener("end",()=>this.handleSessionEnd()),e.requestAnimationFrame((d,u)=>this.xrLoop(d,u)),this.arButton&&(this.arButton.textContent="STOP AR",this.arButton.classList.replace("multiset-ar-inactive","multiset-ar-active")),(l=this.adapterSessionStartHandler)==null||l.call(this),(c=(a=this.options).onSessionStart)==null||c.call(a),this.options.autoLocalize&&e.requestAnimationFrame(()=>{this.localizeFrame();});}handleSessionEnd(){var e,t,i;this.arButton&&(this.arButton.textContent="START AR",this.arButton.classList.replace("multiset-ar-active","multiset-ar-inactive")),this.session=null,this.baseLayer=null,this.referenceSpace=null,this.xrBinding=null,this.lastFrameTime=0,this.trackingLossFrames=0,this.hadTrackingLoss=false,this._isLocalizing=false,this.trackerSpace=null,(e=this.adapterSessionEndHandler)==null||e.call(this),(i=(t=this.options).onSessionEnd)==null||i.call(t);}xrLoop(e,t){var l;this.session.requestAnimationFrame((a,c)=>this.xrLoop(a,c));let i=this.lastFrameTime===0?0:(e-this.lastFrameTime)/1e3;this.lastFrameTime=e;let r=t.getViewerPose(this.referenceSpace);if(!r){this.options.relocalization&&(this.trackingLossFrames+=1,this.trackingLossFrames>=j&&(this.hadTrackingLoss=true));return}this.hadTrackingLoss&&!this._isLocalizing&&this.options.relocalization?(this.hadTrackingLoss=false,this.trackingLossFrames=0,this.localizeFrame()):this.trackingLossFrames=0;let o=r.views[0],n=this.baseLayer.getViewport(o);(l=this.xrFrameHandler)==null||l.call(this,{time:e,frame:t,pose:r,view:o,viewport:n,baseLayer:this.baseLayer,referenceSpace:this.referenceSpace,deltaSeconds:i});}async localizeFrame(){var l,a,c,d,u,p,h,v,E,R,L,x,y;if(!this.session)throw new Error("No active XR session. Start AR before calling localizeFrame().");let e=(l=this.options.confidenceCheck)!=null?l:false,t=Math.max(U,Math.min((a=this.options.confidenceThreshold)!=null?a:.5,$));(d=(c=this.options).onLocalizationInit)==null||d.call(c),this._isLocalizing=true;let i=null,r;try{let g=await this.captureFrame();i=g.result,r=g.failureReason;}catch(g){return (p=(u=this.options).onError)==null||p.call(u,g),null}finally{this._isLocalizing=false;}if(i&&(!e||((h=i.localizeData.confidence)!=null?h:0)>=t)&&i)return (E=(v=this.options).onLocalizationSuccess)==null||E.call(v,i),this.trackerSpace&&((R=this.adapterResultHandler)==null||R.call(this,i,this.trackerSpace)),i;let n=r!=null?r:i?e?`Best confidence ${(L=i.localizeData.confidence)!=null?L:0} below threshold ${t}.`:void 0:"All attempts failed to produce a pose.";return (y=(x=this.options).onLocalizationFailure)==null||y.call(x,n),null}async captureFrame(){var r;let e=this.session,t=this.referenceSpace,i=(r=this.options.localizationTrackingTimeoutMs)!=null?r:q;return new Promise((o,n)=>{let l=Date.now(),a=(c,d)=>{e.requestAnimationFrame(async(u,p)=>{var h,v,E,R,L,x,y,g,z;try{let b=Date.now()-l,F=p.getViewerPose(t);if(!F){if(b>=i||c+1>=K){let T=(i/1e3).toFixed(1);o({result:null,failureReason:`Tracking unavailable: no viewer pose within ${T}s. Try moving the device or ensuring good lighting.`});}else a(c+1,d);return}let G=F.views;for(let T of G){let M=T.camera;if(!M)continue;let S=(E=(v=(h=this.xrBinding)==null?void 0:h.getCameraImage)==null?void 0:v.call(h,M))!=null?E:null;if(!S)continue;let{width:H,height:B}=M;if(!H||!B)continue;let A=await N(this.gl,S,H,B);if(!A)continue;let P=V(T.projectionMatrix,{width:A.width,height:A.height,x:0,y:0});if(P){(L=(R=this.options).onFrameCaptured)==null||L.call(R,A),(y=(x=this.options).onCameraIntrinsics)==null||y.call(x,P),this.trackerSpace=k(T.transform.matrix);let w=await this.options.client.localizeWithFrame(A,P);w!=null&&w.localizeData&&((z=(g=this.options).onPoseResult)==null||z.call(g,{poseFound:w.localizeData.poseFound,position:w.localizeData.position,rotation:w.localizeData.rotation,mapIds:w.localizeData.mapIds,confidence:w.localizeData.confidence})),o({result:w});return}}d+1>=Q?o({result:null,failureReason:"Camera image not available. The device or browser may not support camera access in AR."}):a(c+1,d+1);}catch(b){n(b);}});};a(0,0);})}dispose(){if(this.session)try{this.session.end();}catch{}let e=this.gl.canvas;e instanceof HTMLCanvasElement&&(e.removeEventListener("webglcontextlost",this.handleContextLost),e.removeEventListener("webglcontextrestored",this.handleContextRestored)),this.arButton=null;}};var J=`
1
+ import*as f from'three';import {DRACOLoader}from'three/examples/jsm/loaders/DRACOLoader.js';import {GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';import {TransformControls}from'three/examples/jsm/controls/TransformControls.js';async function O(a,e,t,i=.8,r=e,o=t){let n=document.createElement("canvas");n.width=e,n.height=t;let l=n.getContext("2d");if(!l)return new Blob;l.putImageData(new ImageData(new Uint8ClampedArray(a),e,t),0,0);let s=document.createElement("canvas");s.width=r,s.height=o;let c=s.getContext("2d");return c?(c.drawImage(n,0,0,r,o),new Promise(d=>{s.toBlob(u=>d(u!=null?u:new Blob),"image/jpeg",i);})):new Blob}async function N(a,e,t,i){let r=a.createFramebuffer();if(!r)return null;let o;try{a.bindFramebuffer(a.FRAMEBUFFER,r),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,e,0),o=new Uint8Array(t*i*4),a.readPixels(0,0,t,i,a.RGBA,a.UNSIGNED_BYTE,o);}finally{a.bindFramebuffer(a.FRAMEBUFFER,null),a.deleteFramebuffer(r);}let n=new Uint8ClampedArray(o.length);for(let u=0;u<i;u+=1){let h=u*t*4,m=(i-u-1)*t*4;n.set(o.subarray(h,h+t*4),m);}let l=Math.min(1,1280/Math.max(t,i)),s=Math.round(t*l),c=Math.round(i*l),d=await O(n.buffer,t,i,.7,s,c);return d.size?{blob:d,width:s,height:c}:null}function V(a,e){let t=a,i=(1-t[8])*e.width/2+e.x,r=(1-t[9])*e.height/2+e.y,o=e.width/2*t[0],n=e.height/2*t[5];return {fx:o,fy:n,px:i,py:r,width:e.width,height:e.height}}function k(a){return new Float32Array(a)}var U=.2,j=.8,q=60,K=1e4,$=300,Q=10,I=class{constructor(e,t){this.gl=e;this.options=t;this.session=null;this.referenceSpace=null;this.baseLayer=null;this.xrBinding=null;this.lastFrameTime=0;this.trackingLossFrames=0;this.hadTrackingLoss=false;this._isLocalizing=false;this.trackerSpace=null;this.arButton=null;this.xrFrameHandler=null;this.adapterResultHandler=null;this.adapterSessionStartHandler=null;this.adapterSessionEndHandler=null;this.handleContextLost=e=>{var t,i;if(e.preventDefault(),this.session)try{this.session.end();}catch{}(i=(t=this.options).onContextLost)==null||i.call(t);};this.handleContextRestored=()=>{var e,t;(t=(e=this.options).onContextRestored)==null||t.call(e);};let i=e.canvas;i instanceof HTMLCanvasElement&&(i.addEventListener("webglcontextlost",this.handleContextLost),i.addEventListener("webglcontextrestored",this.handleContextRestored));}static async isSupported(){if(!navigator.xr)return false;try{return await navigator.xr.isSessionSupported("immersive-ar")}catch{return false}}setXRFrameHandler(e){this.xrFrameHandler=e;}setAdapterResultHandler(e){this.adapterResultHandler=e;}setAdapterSessionHandlers(e,t){this.adapterSessionStartHandler=e,this.adapterSessionEndHandler=t;}getClient(){return this.options.client}getOverlayRoot(){return this.options.overlayRoot}isActive(){return this.session!==null}get isLocalizing(){return this._isLocalizing}stopSession(){this.session&&this.session.end();}getBaseLayer(){return this.baseLayer}createButton(){let e=document.createElement("button");return e.textContent="START AR",e.className="multiset-ar-button multiset-ar-inactive",e.style.cssText=["position:fixed","bottom:20px","left:50%","transform:translateX(-50%)","padding:12px 24px","border:1px solid #fff","border-radius:4px","background:rgba(0,0,0,0.1)","color:#fff","font-size:13px","cursor:pointer","z-index:999"].join(";"),e.addEventListener("click",()=>{this.session?this.session.end():this.startSession();}),this.arButton=e,e}async startSession(){var e,t,i;try{if(!navigator.xr)throw new Error("WebXR not supported on this device.");let r=await navigator.xr.requestSession("immersive-ar",{requiredFeatures:["local"],optionalFeatures:["camera-access","dom-overlay"],domOverlay:{root:(e=this.options.overlayRoot)!=null?e:document.body}});await this.initSession(r);}catch(r){(i=(t=this.options).onError)==null||i.call(t,r);}}async initSession(e){var n,l,s,c;await this.gl.makeXRCompatible();let t={};this.options.framebufferScaleFactor!==void 0&&(t.framebufferScaleFactor=this.options.framebufferScaleFactor);let i=new XRWebGLLayer(e,this.gl,t);await e.updateRenderState({baseLayer:i});let r=await e.requestReferenceSpace((n=this.options.referenceSpaceType)!=null?n:"local");this.session=e,this.baseLayer=i,this.referenceSpace=r;let o=XRWebGLBinding;this.xrBinding=new o(e,this.gl),e.addEventListener("end",()=>this.handleSessionEnd()),e.requestAnimationFrame((d,u)=>this.xrLoop(d,u)),this.arButton&&(this.arButton.textContent="STOP AR",this.arButton.classList.replace("multiset-ar-inactive","multiset-ar-active")),(l=this.adapterSessionStartHandler)==null||l.call(this),(c=(s=this.options).onSessionStart)==null||c.call(s),this.options.autoLocalize&&e.requestAnimationFrame(()=>{this.localizeFrame();});}handleSessionEnd(){var e,t,i;this.arButton&&(this.arButton.textContent="START AR",this.arButton.classList.replace("multiset-ar-active","multiset-ar-inactive")),this.session=null,this.baseLayer=null,this.referenceSpace=null,this.xrBinding=null,this.lastFrameTime=0,this.trackingLossFrames=0,this.hadTrackingLoss=false,this._isLocalizing=false,this.trackerSpace=null,(e=this.adapterSessionEndHandler)==null||e.call(this),(i=(t=this.options).onSessionEnd)==null||i.call(t);}xrLoop(e,t){var l;this.session.requestAnimationFrame((s,c)=>this.xrLoop(s,c));let i=this.lastFrameTime===0?0:(e-this.lastFrameTime)/1e3;this.lastFrameTime=e;let r=t.getViewerPose(this.referenceSpace);if(!r){this.options.relocalization&&(this.trackingLossFrames+=1,this.trackingLossFrames>=q&&(this.hadTrackingLoss=true));return}this.hadTrackingLoss&&!this._isLocalizing&&this.options.relocalization?(this.hadTrackingLoss=false,this.trackingLossFrames=0,this.localizeFrame()):this.trackingLossFrames=0;let o=r.views[0],n=this.baseLayer.getViewport(o);(l=this.xrFrameHandler)==null||l.call(this,{time:e,frame:t,pose:r,view:o,viewport:n,baseLayer:this.baseLayer,referenceSpace:this.referenceSpace,deltaSeconds:i});}async localizeFrame(){var l,s,c,d,u,h,m,p,E,L,y,T,C;if(!this.session)throw new Error("No active XR session. Start AR before calling localizeFrame().");let e=(l=this.options.confidenceCheck)!=null?l:false,t=Math.max(U,Math.min((s=this.options.confidenceThreshold)!=null?s:.5,j));(d=(c=this.options).onLocalizationInit)==null||d.call(c),this._isLocalizing=true;let i=null,r;try{let w=await this.captureFrame();i=w.result,r=w.failureReason;}catch(w){return (h=(u=this.options).onError)==null||h.call(u,w),null}finally{this._isLocalizing=false;}if(i&&(!e||((m=i.localizeData.confidence)!=null?m:0)>=t)&&i)return (E=(p=this.options).onLocalizationSuccess)==null||E.call(p,i),this.trackerSpace&&((L=this.adapterResultHandler)==null||L.call(this,i,this.trackerSpace)),i;let n=r!=null?r:i?e?`Best confidence ${(y=i.localizeData.confidence)!=null?y:0} below threshold ${t}.`:void 0:"All attempts failed to produce a pose.";return (C=(T=this.options).onLocalizationFailure)==null||C.call(T,n),null}async captureFrame(){var r;let e=this.session,t=this.referenceSpace,i=(r=this.options.localizationTrackingTimeoutMs)!=null?r:K;return new Promise((o,n)=>{let l=Date.now(),s=(c,d)=>{e.requestAnimationFrame(async(u,h)=>{var m,p,E,L,y,T,C,w,z;try{let x=Date.now()-l,F=h.getViewerPose(t);if(!F){if(x>=i||c+1>=$){let b=(i/1e3).toFixed(1);o({result:null,failureReason:`Tracking unavailable: no viewer pose within ${b}s. Try moving the device or ensuring good lighting.`});}else s(c+1,d);return}let A=F.views;for(let b of A){let M=b.camera;if(!M)continue;let S=(E=(p=(m=this.xrBinding)==null?void 0:m.getCameraImage)==null?void 0:p.call(m,M))!=null?E:null;if(!S)continue;let{width:H,height:B}=M;if(!H||!B)continue;let G=await N(this.gl,S,H,B);if(!G)continue;let P=V(b.projectionMatrix,{width:G.width,height:G.height,x:0,y:0});if(P){(y=(L=this.options).onFrameCaptured)==null||y.call(L,G),(C=(T=this.options).onCameraIntrinsics)==null||C.call(T,P),this.trackerSpace=k(b.transform.matrix);let R=await this.options.client.localizeWithFrame(G,P);R!=null&&R.localizeData&&((z=(w=this.options).onPoseResult)==null||z.call(w,{poseFound:R.localizeData.poseFound,position:R.localizeData.position,rotation:R.localizeData.rotation,mapIds:R.localizeData.mapIds,confidence:R.localizeData.confidence})),o({result:R});return}}d+1>=Q?o({result:null,failureReason:"Camera image not available. The device or browser may not support camera access in AR."}):s(c+1,d+1);}catch(x){n(x);}});};s(0,0);})}dispose(){if(this.session)try{this.session.end();}catch{}let e=this.gl.canvas;e instanceof HTMLCanvasElement&&(e.removeEventListener("webglcontextlost",this.handleContextLost),e.removeEventListener("webglcontextrestored",this.handleContextRestored)),this.arButton=null;}};var J=`
2
2
  varying vec3 vWorldPosition;
3
3
  varying vec3 vWorldNormal;
4
4
 
@@ -90,4 +90,4 @@ void main() {
90
90
 
91
91
  gl_FragColor = vec4(finalColor, alphaWithGlow);
92
92
  }
93
- `;function _(s={}){var E,R,L,x,y,g,z,b,F,G,T,M,S,H;let e=(E=s.color)!=null?E:"#7B2CBF",t=(R=s.opacity)!=null?R:150/255,i=(L=s.gridColor)!=null?L:"#ffeb3b",r=(x=s.gridScale)!=null?x:2,o=(y=s.gridLineWidth)!=null?y:.02,n=(g=s.showGrid)!=null?g:1,l=(z=s.center)!=null?z:new m.Vector3(0,0,0),a=(b=s.radius)!=null?b:1,c=(F=s.progress)!=null?F:1,d=(G=s.glowColor)!=null?G:"#FF3A00",u=(T=s.glowWidth)!=null?T:.05,p=(M=s.glowIntensity)!=null?M:2,h=(S=s.lightColor)!=null?S:"#ffffff",v=(H=s.lightDirection)!=null?H:new m.Vector3(.3,1,.3).normalize();return new m.ShaderMaterial({vertexShader:J,fragmentShader:Y,transparent:true,side:m.DoubleSide,uniforms:{uColor:{value:typeof e=="string"?new m.Color(e):e},uOpacity:{value:t},uGridColor:{value:typeof i=="string"?new m.Color(i):i},uGridSize:{value:r},uGridLineWidth:{value:o},uShowGrid:{value:n},uCenter:{value:l.clone()},uRadius:{value:a},uProgress:{value:c},uGlowColor:{value:typeof d=="string"?new m.Color(d):d},uGlowWidth:{value:u},uGlowIntensity:{value:p},uLightColor:{value:typeof h=="string"?new m.Color(h):h},uLightDirection:{value:v.clone()}}})}var D=class{constructor(e,t,i,r){this.scene=e;this.client=t;this.renderer=i;this.camera=r;this.gizmoControl=null;this.gizmoHelper=null;this.meshMaterial=null;this.localCenter=new m.Vector3;this.localRadius=0;this.radialDuration=4;this.meshGroup=new m.Group,this.meshGroup.visible=false,this.scene.add(this.meshGroup),this.dracoLoader=new DRACOLoader,this.dracoLoader.setDecoderPath("/draco/"),this.gltfLoader=new GLTFLoader,this.gltfLoader.setDRACOLoader(this.dracoLoader);}getMeshGroup(){return this.meshGroup}async ensureGizmoLoaded(){if(!this.gizmoControl){let e=new TransformControls(this.camera,this.renderer.domElement);e.setMode("translate"),e.setSpace("local"),e.enabled=false;let t=e.getHelper();this.scene.add(t),e.attach(this.meshGroup),this.gizmoControl=e,this.gizmoHelper=t;}this.gizmoHelper.visible=true;}async ensureMeshLoaded(e){var r,o;if(this.scene.getObjectByName(e._id))return;let t=(o=(r=e.mapMesh)==null?void 0:r.rawMesh)==null?void 0:o.meshLink;if(!t)return;let i=await this.client.downloadFile(t);i&&await new Promise((n,l)=>{this.gltfLoader.load(i,a=>{let c=new m.Box3().setFromObject(a.scene),d=c.getSize(new m.Vector3),u=c.getCenter(new m.Vector3);this.localCenter.copy(u),this.localRadius=Math.max(d.length()/2*1.1,.001);let p=_({color:"#7B2CBF",opacity:.58,gridColor:"#ffeb3b",gridScale:2,gridLineWidth:.02,showGrid:1,center:this.localCenter.clone(),radius:this.localRadius,progress:0,glowColor:"#FF3A00",glowWidth:.05,glowIntensity:2});this.meshMaterial=p,a.scene.traverse(h=>{let v=h;v.isMesh&&(v.material=p,v.frustumCulled=false);}),a.scene.name=e._id,this.meshGroup.add(a.scene),n();},void 0,a=>{l(a instanceof Error?a:new Error(String(a)));});});}applyMeshTransform(e,t){let i=e.localizeData,r=new m.Vector3(i.position.x,i.position.y,i.position.z),o=new m.Quaternion(i.rotation.x,i.rotation.y,i.rotation.z,i.rotation.w),n=new m.Matrix4;n.compose(r,o,new m.Vector3(1,1,1));let l=n.clone().invert(),a=new m.Matrix4;a.multiplyMatrices(t,l);let c=new m.Vector3,d=new m.Quaternion,u=new m.Vector3;a.decompose(c,d,u),this.meshGroup.position.copy(c),this.meshGroup.quaternion.copy(d),this.meshGroup.scale.set(1,1,1),this.meshGroup.visible=true,this.meshGroup.updateMatrixWorld(true),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0,this.meshMaterial.uniforms.uCenter.value.copy(this.localCenter).applyMatrix4(this.meshGroup.matrixWorld));}update(e,t){if(!this.meshMaterial)return;let i=this.meshMaterial.uniforms.uProgress;i&&(i.value>=1||(i.value=Math.min(i.value+e/this.radialDuration,1)));}hideUntilNextLocalization(){this.meshGroup.visible=false,this.gizmoHelper&&(this.gizmoHelper.visible=false),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0);}dispose(){this.meshMaterial=null,this.meshGroup.traverse(e=>{let t=e;t.isMesh&&(t.geometry.dispose(),Array.isArray(t.material)?t.material.forEach(i=>i.dispose()):t.material.dispose());}),this.scene.remove(this.meshGroup),this.dracoLoader.dispose(),this.gizmoHelper&&this.scene.remove(this.gizmoHelper),this.gizmoControl&&this.gizmoControl.dispose();}};var W=class{constructor(e,t,i,r){this.meshVisualizer=new D(e,t,i,r);}async ensureGizmoLoaded(){await this.meshVisualizer.ensureGizmoLoaded();}async ensureMeshLoaded(e){await this.meshVisualizer.ensureMeshLoaded(e);}applyMeshTransform(e,t){this.meshVisualizer.applyMeshTransform(e,t);}update(e,t){this.meshVisualizer.update(e,t);}hideUntilNextLocalization(){this.meshVisualizer.hideUntilNextLocalization();}dispose(){this.meshVisualizer.dispose();}};var X=class{constructor(e){this.options=e;this.world=null;this.previewRAFHandle=null;this.resizeHandler=null;this.xrFrameCount=0;this.xrRenderTarget=null;let{session:t,renderer:i,camera:r}=e;i.xr.enabled=false,r.matrixAutoUpdate=false,t.setXRFrameHandler(o=>this.onXRFrame(o)),t.setAdapterResultHandler((o,n)=>{this.handleLocalizationResult(o,n);}),t.setAdapterSessionHandlers(()=>{r.matrixAutoUpdate=false;let o=t.getBaseLayer();o&&(this.xrRenderTarget=new m.WebGLRenderTarget(o.framebufferWidth,o.framebufferHeight)),this.stopPreviewLoop();},()=>{var o,n;i.setRenderTarget(null),this.xrRenderTarget&&(i.setRenderTargetFramebuffer(this.xrRenderTarget,null),this.xrRenderTarget.dispose(),this.xrRenderTarget=null),(o=this.world)==null||o.hideUntilNextLocalization(),r.matrixAutoUpdate=true,r.position.set(0,0,0),r.quaternion.identity(),(n=this.resizeHandler)==null||n.call(this),this.startPreviewLoop();}),(e.showMesh||e.showGizmo!==false)&&(this.world=new W(e.scene,t.getClient(),i,r));}static isSupported(){return I.isSupported()}initialize(e){var a,c;let{options:t}=this,{session:i}=t,r=null;if(t.useDefaultButton!==false){r=i.createButton();let d=e instanceof HTMLElement?e:t.buttonContainer instanceof HTMLElement?t.buttonContainer:(a=i.getOverlayRoot())!=null?a:document.body;d.contains(r)||d.appendChild(r),(c=t.onButtonCreated)==null||c.call(t,r);}let{renderer:o,camera:n}=t;this.resizeHandler=()=>{n.aspect=window.innerWidth/window.innerHeight,n.updateProjectionMatrix(),o.setSize(window.innerWidth,window.innerHeight);},window.addEventListener("resize",this.resizeHandler),this.resizeHandler();let l=o.domElement;return console.log(`[ThreeAdapter] initialize \u2014 canvas size: ${l.width}x${l.height}, window: ${window.innerWidth}x${window.innerHeight}`),this.startPreviewLoop(),r}isActive(){return this.options.session.isActive()}get isLocalizing(){return this.options.session.isLocalizing}startSession(){return this.options.session.startSession()}stopSession(){this.options.session.stopSession();}async localizeFrame(){return this.options.session.localizeFrame()}onXRFrame(e){var o,n;let{renderer:t,scene:i,camera:r}=this.options;if(this.xrRenderTarget&&(t.setRenderTargetFramebuffer(this.xrRenderTarget,e.baseLayer.framebuffer),t.setRenderTarget(this.xrRenderTarget)),this.syncCameraMatrices(e.view),this.xrFrameCount+=1,this.xrFrameCount<=5){let l=e.pose.transform.position,a=new m.Vector3().setFromMatrixPosition(r.matrixWorld),d=new m.Vector3(0,0,-0.4).clone().applyMatrix4(r.matrixWorldInverse);console.log(`[ThreeAdapter] XR frame #${this.xrFrameCount} | rt: ${this.xrRenderTarget?"OK":"NULL"}`),console.log(`[ThreeAdapter] XR pose: x=${l.x.toFixed(3)} y=${l.y.toFixed(3)} z=${l.z.toFixed(3)}`),console.log(`[ThreeAdapter] camera.matrixWorld: x=${a.x.toFixed(3)} y=${a.y.toFixed(3)} z=${a.z.toFixed(3)}`),console.log(`[ThreeAdapter] cube cam-space z=${d.z.toFixed(3)} (negative = in front)`),console.log(`[ThreeAdapter] scene children: ${i.children.length}`);}if(this.world&&e.deltaSeconds>0){let l=e.pose.transform.position;this.world.update(e.deltaSeconds,new m.Vector3(l.x,l.y,l.z));}(n=(o=this.options).onXRFrame)==null||n.call(o,e),t.render(i,r);}syncCameraMatrices(e){let{camera:t}=this.options;t.projectionMatrix.fromArray(e.projectionMatrix),t.projectionMatrixInverse.copy(t.projectionMatrix).invert(),t.matrixWorld.fromArray(e.transform.matrix),t.matrixWorldInverse.fromArray(e.transform.inverse.matrix),t.matrix.copy(t.matrixWorld);}startPreviewLoop(){let{renderer:e,scene:t,camera:i}=this.options;console.log(`[ThreeAdapter] preview loop started \u2014 scene has ${t.children.length} objects`);let r=()=>{this.previewRAFHandle=window.requestAnimationFrame(r),e.render(t,i);};this.previewRAFHandle=window.requestAnimationFrame(r);}stopPreviewLoop(){this.previewRAFHandle!==null&&(cancelAnimationFrame(this.previewRAFHandle),this.previewRAFHandle=null,this.xrFrameCount=0,console.log("[ThreeAdapter] preview loop stopped \u2014 XR session starting"));}async handleLocalizationResult(e,t){var a;if(!this.world)return;let{showMesh:i,showGizmo:r,session:o}=this.options,n=r!==false;if(i&&((a=e.localizeData.mapCodes)!=null&&a[0]))try{let c=await o.getClient().fetchMapDetails(e.localizeData.mapCodes[0]);c&&(e.mapDetails=c);}catch{}let l=i&&!!e.mapDetails;if(!(!l&&!n))try{if(n&&await this.world.ensureGizmoLoaded(),l&&await this.world.ensureMeshLoaded(e.mapDetails),!o.isActive())return;this.world.applyMeshTransform(e,new m.Matrix4().fromArray(t));}catch{}}dispose(){var e;this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null),this.stopPreviewLoop(),(e=this.world)==null||e.dispose(),this.world=null,this.options.session.dispose();}};export{X as ThreeAdapter};
93
+ `;function _(a={}){var E,L,y,T,C,w,z,x,F,A,b,M,S,H;let e=(E=a.color)!=null?E:"#7B2CBF",t=(L=a.opacity)!=null?L:150/255,i=(y=a.gridColor)!=null?y:"#ffeb3b",r=(T=a.gridScale)!=null?T:2,o=(C=a.gridLineWidth)!=null?C:.02,n=(w=a.showGrid)!=null?w:1,l=(z=a.center)!=null?z:new f.Vector3(0,0,0),s=(x=a.radius)!=null?x:1,c=(F=a.progress)!=null?F:1,d=(A=a.glowColor)!=null?A:"#FF3A00",u=(b=a.glowWidth)!=null?b:.05,h=(M=a.glowIntensity)!=null?M:2,m=(S=a.lightColor)!=null?S:"#ffffff",p=(H=a.lightDirection)!=null?H:new f.Vector3(.3,1,.3).normalize();return new f.ShaderMaterial({vertexShader:J,fragmentShader:Y,transparent:true,side:f.DoubleSide,uniforms:{uColor:{value:typeof e=="string"?new f.Color(e):e},uOpacity:{value:t},uGridColor:{value:typeof i=="string"?new f.Color(i):i},uGridSize:{value:r},uGridLineWidth:{value:o},uShowGrid:{value:n},uCenter:{value:l.clone()},uRadius:{value:s},uProgress:{value:c},uGlowColor:{value:typeof d=="string"?new f.Color(d):d},uGlowWidth:{value:u},uGlowIntensity:{value:h},uLightColor:{value:typeof m=="string"?new f.Color(m):m},uLightDirection:{value:p.clone()}}})}var D=class{constructor(e,t,i,r){this.scene=e;this.client=t;this.renderer=i;this.camera=r;this.gizmoControl=null;this.gizmoHelper=null;this.meshMaterial=null;this.localCenter=new f.Vector3;this.localRadius=0;this.radialDuration=4;this.meshGroup=new f.Group,this.meshGroup.visible=false,this.scene.add(this.meshGroup),this.dracoLoader=new DRACOLoader,this.dracoLoader.setDecoderPath("/draco/"),this.gltfLoader=new GLTFLoader,this.gltfLoader.setDRACOLoader(this.dracoLoader);}getMeshGroup(){return this.meshGroup}async ensureGizmoLoaded(){if(!this.gizmoControl){let e=new TransformControls(this.camera,this.renderer.domElement);e.setMode("translate"),e.setSpace("local"),e.enabled=false;let t=e.getHelper();this.scene.add(t),e.attach(this.meshGroup),this.gizmoControl=e,this.gizmoHelper=t;}this.gizmoHelper.visible=true;}async ensureMeshLoaded(e){var r,o;if(this.scene.getObjectByName(e._id))return;let t=(o=(r=e.mapMesh)==null?void 0:r.rawMesh)==null?void 0:o.meshLink;if(!t)return;let i=await this.client.downloadFile(t);i&&await new Promise((n,l)=>{this.gltfLoader.load(i,s=>{let c=new f.Box3().setFromObject(s.scene),d=c.getSize(new f.Vector3),u=c.getCenter(new f.Vector3);this.localCenter.copy(u),this.localRadius=Math.max(d.length()/2*1.1,.001);let h=_({color:"#7B2CBF",opacity:.58,gridColor:"#ffeb3b",gridScale:2,gridLineWidth:.02,showGrid:1,center:this.localCenter.clone(),radius:this.localRadius,progress:0,glowColor:"#FF3A00",glowWidth:.05,glowIntensity:2});this.meshMaterial=h,s.scene.traverse(m=>{let p=m;p.isMesh&&(p.material=h,p.frustumCulled=false);}),s.scene.name=e._id,this.meshGroup.add(s.scene),n();},void 0,s=>{l(s instanceof Error?s:new Error(String(s)));});});}applyMeshTransform(e){let t=new f.Vector3,i=new f.Quaternion,r=new f.Vector3;e.decompose(t,i,r),this.meshGroup.position.copy(t),this.meshGroup.quaternion.copy(i),this.meshGroup.scale.set(1,1,1),this.meshGroup.visible=true,this.meshGroup.updateMatrixWorld(true),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0,this.meshMaterial.uniforms.uCenter.value.copy(this.localCenter).applyMatrix4(this.meshGroup.matrixWorld));}update(e,t){if(!this.meshMaterial)return;let i=this.meshMaterial.uniforms.uProgress;i&&(i.value>=1||(i.value=Math.min(i.value+e/this.radialDuration,1)));}hideUntilNextLocalization(){this.meshGroup.visible=false,this.gizmoHelper&&(this.gizmoHelper.visible=false),this.meshMaterial&&(this.meshMaterial.uniforms.uProgress.value=0);}dispose(){this.meshMaterial=null,this.meshGroup.traverse(e=>{let t=e;t.isMesh&&(t.geometry.dispose(),Array.isArray(t.material)?t.material.forEach(i=>i.dispose()):t.material.dispose());}),this.scene.remove(this.meshGroup),this.dracoLoader.dispose(),this.gizmoHelper&&this.scene.remove(this.gizmoHelper),this.gizmoControl&&this.gizmoControl.dispose();}};var W=class{constructor(e,t,i,r){this.meshVisualizer=new D(e,t,i,r);}async ensureGizmoLoaded(){await this.meshVisualizer.ensureGizmoLoaded();}async ensureMeshLoaded(e){await this.meshVisualizer.ensureMeshLoaded(e);}applyMeshTransform(e){this.meshVisualizer.applyMeshTransform(e);}update(e,t){this.meshVisualizer.update(e,t);}hideUntilNextLocalization(){this.meshVisualizer.hideUntilNextLocalization();}dispose(){this.meshVisualizer.dispose();}};var X=class{constructor(e){this.options=e;this.world=null;this.previewRAFHandle=null;this.resizeHandler=null;this.xrRenderTarget=null;let{session:t,renderer:i,camera:r}=e;i.xr.enabled=false,r.matrixAutoUpdate=false,t.setXRFrameHandler(o=>this.onXRFrame(o)),t.setAdapterResultHandler((o,n)=>{this.handleLocalizationResult(o,n);}),t.setAdapterSessionHandlers(()=>{r.matrixAutoUpdate=false;let o=t.getBaseLayer();o&&(this.xrRenderTarget=new f.WebGLRenderTarget(o.framebufferWidth,o.framebufferHeight)),this.stopPreviewLoop();},()=>{var o,n;i.setRenderTarget(null),this.xrRenderTarget&&(i.setRenderTargetFramebuffer(this.xrRenderTarget,null),this.xrRenderTarget.dispose(),this.xrRenderTarget=null),(o=this.world)==null||o.hideUntilNextLocalization(),r.matrixAutoUpdate=true,r.position.set(0,0,0),r.quaternion.identity(),(n=this.resizeHandler)==null||n.call(this),this.startPreviewLoop();}),(e.showMesh||e.showGizmo!==false)&&(this.world=new W(e.scene,t.getClient(),i,r));}static isSupported(){return I.isSupported()}initialize(e){var l,s;let{options:t}=this,{session:i}=t,r=null;if(t.useDefaultButton!==false){r=i.createButton();let c=e instanceof HTMLElement?e:t.buttonContainer instanceof HTMLElement?t.buttonContainer:(l=i.getOverlayRoot())!=null?l:document.body;c.contains(r)||c.appendChild(r),(s=t.onButtonCreated)==null||s.call(t,r);}let{renderer:o,camera:n}=t;return this.resizeHandler=()=>{n.aspect=window.innerWidth/window.innerHeight,n.updateProjectionMatrix(),o.setSize(window.innerWidth,window.innerHeight);},window.addEventListener("resize",this.resizeHandler),this.resizeHandler(),this.startPreviewLoop(),r}isActive(){return this.options.session.isActive()}get isLocalizing(){return this.options.session.isLocalizing}startSession(){return this.options.session.startSession()}stopSession(){this.options.session.stopSession();}async localizeFrame(){return this.options.session.localizeFrame()}onXRFrame(e){var o,n;let{renderer:t,scene:i,camera:r}=this.options;if(this.xrRenderTarget&&(t.setRenderTargetFramebuffer(this.xrRenderTarget,e.baseLayer.framebuffer),t.setRenderTarget(this.xrRenderTarget)),this.syncCameraMatrices(e.view),this.world&&e.deltaSeconds>0){let l=e.pose.transform.position;this.world.update(e.deltaSeconds,new f.Vector3(l.x,l.y,l.z));}(n=(o=this.options).onXRFrame)==null||n.call(o,e),t.render(i,r);}syncCameraMatrices(e){let{camera:t}=this.options;t.projectionMatrix.fromArray(e.projectionMatrix),t.projectionMatrixInverse.copy(t.projectionMatrix).invert(),t.matrixWorld.fromArray(e.transform.matrix),t.matrixWorldInverse.fromArray(e.transform.inverse.matrix),t.matrix.copy(t.matrixWorld);}startPreviewLoop(){let{renderer:e,scene:t,camera:i}=this.options,r=()=>{this.previewRAFHandle=window.requestAnimationFrame(r),e.render(t,i);};this.previewRAFHandle=window.requestAnimationFrame(r);}stopPreviewLoop(){this.previewRAFHandle!==null&&(cancelAnimationFrame(this.previewRAFHandle),this.previewRAFHandle=null);}async handleLocalizationResult(e,t){var h,m,p;let{position:i,rotation:r}=e.localizeData,o=new f.Matrix4().compose(new f.Vector3(i.x,i.y,i.z),new f.Quaternion(r.x,r.y,r.z,r.w),new f.Vector3(1,1,1)),n=new f.Matrix4().multiplyMatrices(new f.Matrix4().fromArray(t),o.invert());if((m=(h=this.options).onLocalizationSuccess)==null||m.call(h,e,n),!this.world)return;let{showMesh:l,showGizmo:s,session:c}=this.options,d=s!==false;if(l&&((p=e.localizeData.mapCodes)!=null&&p[0]))try{let E=await c.getClient().fetchMapDetails(e.localizeData.mapCodes[0]);E&&(e.mapDetails=E);}catch{}let u=l&&!!e.mapDetails;if(!(!u&&!d))try{if(d&&await this.world.ensureGizmoLoaded(),u&&await this.world.ensureMeshLoaded(e.mapDetails),!c.isActive())return;this.world.applyMeshTransform(n);}catch{}}dispose(){var e;this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null),this.stopPreviewLoop(),(e=this.world)==null||e.dispose(),this.world=null,this.options.session.dispose();}};export{X as ThreeAdapter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multisetai/vps",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Multiset VPS WebXR SDK - Core client and WebXR controller.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",