@multisetai/vps 2.1.0 → 2.1.1

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.
@@ -1,2 +1,2 @@
1
- import E from'axios';var F={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 w=class{constructor(e){this.accessToken=null;this.mapDetailsCache={};let{clientId:t,clientSecret:n,...i}=e;this.credentials={clientId:t,clientSecret:n},this.config=i,this.endpoints={...F,...i.endpoints};}get token(){return this.accessToken}async authorize(){var n,i,a;let e=await E.post(this.endpoints.authUrl,{},{auth:{username:this.credentials.clientId,password:this.credentials.clientSecret}}),t=(a=(n=e.data)==null?void 0:n.token)!=null?a:(i=e.data)==null?void 0:i.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 E.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,n){var i;if(!this.accessToken)throw new Error("Access token is missing. Call authorize() first.");return this.queryLocalization(e,t,(i=n==null?void 0:n.fetchMapDetails)!=null?i:false)}async fetchMapDetails(e){if(!this.accessToken)return null;let t=this.mapDetailsCache[e];if(t)return t;try{let n=await E.get(`${this.endpoints.mapDetailsUrl}${e}`,{headers:{Authorization:`Bearer ${this.accessToken}`}});return this.mapDetailsCache[e]=n.data,n.data}catch{return null}}async getGeoPoseComponents(){if(typeof navigator=="undefined"||!("geolocation"in navigator)||!navigator.geolocation)return null;try{let e=await new Promise((s,p)=>{navigator.geolocation.getCurrentPosition(s,p,{enableHighAccuracy:!0,timeout:1e4,maximumAge:0});}),{latitude:t,longitude:n,altitude:i}=e.coords,a=typeof i=="number"&&!Number.isNaN(i)?i:0;return {latitude:t,longitude:n,altitude:a}}catch{return null}}async queryLocalization(e,t,n){var d,u,m;let i=new FormData;this.config.mapType==="map"?i.append("mapCode",this.config.code):i.append("mapSetCode",this.config.code);let a=(d=this.config.isRightHanded)!=null?d:true;i.append("isRightHanded",`${a}`),i.append("fx",`${t.fx}`),i.append("fy",`${t.fy}`),i.append("px",`${t.px}`),i.append("py",`${t.py}`),i.append("width",`${e.width}`),i.append("height",`${e.height}`),i.append("queryImage",e.blob),this.config.convertToGeoCoordinates!==void 0&&i.append("convertToGeoCoordinates",`${this.config.convertToGeoCoordinates}`),"hintMapCodes"in this.config&&((u=this.config.hintMapCodes)!=null&&u.length)&&this.config.hintMapCodes.forEach(r=>{i.append("hintMapCodes",r);}),this.config.hintPosition&&i.append("hintPosition",this.config.hintPosition);let s;if(this.config.passGeoPose){let r=await this.getGeoPoseComponents();if(r){let{latitude:f,longitude:g,altitude:v}=r;s=`${f},${g},${v}`;}}if(s&&i.append("geoHint",s),this.config.hintRadius!==void 0){let r=Number(this.config.hintRadius);if(Number.isNaN(r)||r<1||r>100)throw new Error("hintRadius must be a number between 1 and 100.");if(!this.config.hintPosition&&!s)throw new Error("hintRadius requires hintPosition, or passGeoPose with available geolocation to generate geoHint.");i.append("hintRadius",`${r}`);}"use2DFiltering"in this.config&&this.config.use2DFiltering!==void 0&&i.append("use2DFiltering",`${this.config.use2DFiltering}`);let o=(await E.post(this.endpoints.queryUrl,i,{headers:{Authorization:`Bearer ${this.accessToken}`}})).data;if(!o.poseFound)return null;let c={localizeData:o};if(n&&((m=o.mapCodes)!=null&&m.length)){let r=await this.fetchMapDetails(o.mapCodes[0]);r&&(c.mapDetails=r);}return c}};async function _(l,e,t,n=.8,i=e,a=t){let s=document.createElement("canvas");s.width=e,s.height=t;let p=s.getContext("2d");if(!p)return new Blob;p.putImageData(new ImageData(new Uint8ClampedArray(l),e,t),0,0);let o=document.createElement("canvas");o.width=i,o.height=a;let c=o.getContext("2d");return c?(c.drawImage(s,0,0,i,a),new Promise(d=>{o.toBlob(u=>d(u!=null?u:new Blob),"image/jpeg",n);})):new Blob}async function X(l,e,t,n){let i=l.createFramebuffer();if(!i)return null;let a;try{l.bindFramebuffer(l.FRAMEBUFFER,i),l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,l.TEXTURE_2D,e,0),a=new Uint8Array(t*n*4),l.readPixels(0,0,t,n,l.RGBA,l.UNSIGNED_BYTE,a);}finally{l.bindFramebuffer(l.FRAMEBUFFER,null),l.deleteFramebuffer(i);}let s=new Uint8ClampedArray(a.length);for(let u=0;u<n;u+=1){let m=u*t*4,r=(n-u-1)*t*4;s.set(a.subarray(m,m+t*4),r);}let p=Math.min(1,1280/Math.max(t,n)),o=Math.round(t*p),c=Math.round(n*p),d=await _(s.buffer,t,n,.7,o,c);return d.size?{blob:d,width:o,height:c}:null}function B(l,e){let t=l,n=(1-t[8])*e.width/2+e.x,i=(1-t[9])*e.height/2+e.y,a=e.width/2*t[0],s=e.height/2*t[5];return {fx:a,fy:s,px:n,py:i,width:e.width,height:e.height}}function G(l){return new Float32Array(l)}var U=.2,N=.8,$=60,O=1e4,W=300,q=10,T=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,n;if(e.preventDefault(),this.session)try{this.session.end();}catch{}(n=(t=this.options).onContextLost)==null||n.call(t);};this.handleContextRestored=()=>{var e,t;(t=(e=this.options).onContextRestored)==null||t.call(e);};let n=e.canvas;n instanceof HTMLCanvasElement&&(n.addEventListener("webglcontextlost",this.handleContextLost),n.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,n;try{if(!navigator.xr)throw new Error("WebXR not supported on this device.");let i=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(i);}catch(i){(n=(t=this.options).onError)==null||n.call(t,i);}}async initSession(e){var s,p,o,c;await this.gl.makeXRCompatible();let t={};this.options.framebufferScaleFactor!==void 0&&(t.framebufferScaleFactor=this.options.framebufferScaleFactor);let n=new XRWebGLLayer(e,this.gl,t);await e.updateRenderState({baseLayer:n});let i=await e.requestReferenceSpace((s=this.options.referenceSpaceType)!=null?s:"local");this.session=e,this.baseLayer=n,this.referenceSpace=i;let a=XRWebGLBinding;this.xrBinding=new a(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")),(p=this.adapterSessionStartHandler)==null||p.call(this),(c=(o=this.options).onSessionStart)==null||c.call(o),this.options.autoLocalize&&e.requestAnimationFrame(()=>{this.localizeFrame();});}handleSessionEnd(){var e,t,n;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),(n=(t=this.options).onSessionEnd)==null||n.call(t);}xrLoop(e,t){var p;this.session.requestAnimationFrame((o,c)=>this.xrLoop(o,c));let n=this.lastFrameTime===0?0:(e-this.lastFrameTime)/1e3;this.lastFrameTime=e;let i=t.getViewerPose(this.referenceSpace);if(!i){this.options.relocalization&&(this.trackingLossFrames+=1,this.trackingLossFrames>=$&&(this.hadTrackingLoss=true));return}this.hadTrackingLoss&&!this._isLocalizing&&this.options.relocalization?(this.hadTrackingLoss=false,this.trackingLossFrames=0,this.localizeFrame()):this.trackingLossFrames=0;let a=i.views[0],s=this.baseLayer.getViewport(a);(p=this.xrFrameHandler)==null||p.call(this,{time:e,frame:t,pose:i,view:a,viewport:s,baseLayer:this.baseLayer,referenceSpace:this.referenceSpace,deltaSeconds:n});}async localizeFrame(){var p,o,c,d,u,m,r,f,g,v,C,I,b;if(!this.session)throw new Error("No active XR session. Start AR before calling localizeFrame().");let e=(p=this.options.confidenceCheck)!=null?p:false,t=Math.max(U,Math.min((o=this.options.confidenceThreshold)!=null?o:.5,N));(d=(c=this.options).onLocalizationInit)==null||d.call(c),this._isLocalizing=true;let n=null,i;try{let y=await this.captureFrame();n=y.result,i=y.failureReason;}catch(y){return (m=(u=this.options).onError)==null||m.call(u,y),null}finally{this._isLocalizing=false;}if(n&&(!e||((r=n.localizeData.confidence)!=null?r:0)>=t)&&n)return (g=(f=this.options).onLocalizationSuccess)==null||g.call(f,n),this.trackerSpace&&((v=this.adapterResultHandler)==null||v.call(this,n,this.trackerSpace)),n;let s=i!=null?i:n?e?`Best confidence ${(C=n.localizeData.confidence)!=null?C:0} below threshold ${t}.`:void 0:"All attempts failed to produce a pose.";return (b=(I=this.options).onLocalizationFailure)==null||b.call(I,s),null}async captureFrame(){var i;let e=this.session,t=this.referenceSpace,n=(i=this.options.localizationTrackingTimeoutMs)!=null?i:O;return new Promise((a,s)=>{let p=Date.now(),o=(c,d)=>{e.requestAnimationFrame(async(u,m)=>{var r,f,g,v,C,I,b,y,D;try{let S=Date.now()-p,A=m.getViewerPose(t);if(!A){if(S>=n||c+1>=W){let R=(n/1e3).toFixed(1);a({result:null,failureReason:`Tracking unavailable: no viewer pose within ${R}s. Try moving the device or ensuring good lighting.`});}else o(c+1,d);return}let H=A.views;for(let R of H){let x=R.camera;if(!x)continue;let z=(g=(f=(r=this.xrBinding)==null?void 0:r.getCameraImage)==null?void 0:f.call(r,x))!=null?g:null;if(!z)continue;let{width:k,height:P}=x;if(!k||!P)continue;let L=await X(this.gl,z,k,P);if(!L)continue;let M=B(R.projectionMatrix,{width:L.width,height:L.height,x:0,y:0});if(M){(C=(v=this.options).onFrameCaptured)==null||C.call(v,L),(b=(I=this.options).onCameraIntrinsics)==null||b.call(I,M),this.trackerSpace=G(R.transform.matrix);let h=await this.options.client.localizeWithFrame(L,M);h!=null&&h.localizeData&&((D=(y=this.options).onPoseResult)==null||D.call(y,{poseFound:h.localizeData.poseFound,position:h.localizeData.position,rotation:h.localizeData.rotation,mapIds:h.localizeData.mapIds,confidence:h.localizeData.confidence})),a({result:h});return}}d+1>=q?a({result:null,failureReason:"Camera image not available. The device or browser may not support camera access in AR."}):o(c+1,d+1);}catch(S){s(S);}});};o(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;}};
2
- export{F as DEFAULT_ENDPOINTS,w as MultisetClient,T as XRSessionManager};
1
+ import E from'axios';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 w=class{constructor(e){this.accessToken=null;this.mapDetailsCache={};let{clientId:t,clientSecret:n,...i}=e;this.credentials={clientId:t,clientSecret:n},this.config=i,this.endpoints={...x,...i.endpoints};}get token(){return this.accessToken}async authorize(){var n,i,r;let e=await E.post(this.endpoints.authUrl,{},{auth:{username:this.credentials.clientId,password:this.credentials.clientSecret}}),t=(r=(n=e.data)==null?void 0:n.token)!=null?r:(i=e.data)==null?void 0:i.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 E.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,n){var i;if(!this.accessToken)throw new Error("Access token is missing. Call authorize() first.");return this.queryLocalization(e,t,(i=n==null?void 0:n.fetchMapDetails)!=null?i:false)}async fetchMapDetails(e){if(!this.accessToken)return null;let t=this.mapDetailsCache[e];if(t)return t;try{let n=await E.get(`${this.endpoints.mapDetailsUrl}${e}`,{headers:{Authorization:`Bearer ${this.accessToken}`}});return this.mapDetailsCache[e]=n.data,n.data}catch{return null}}async getGeoPoseComponents(){if(typeof navigator=="undefined"||!("geolocation"in navigator)||!navigator.geolocation)return null;try{let e=await new Promise((a,p)=>{navigator.geolocation.getCurrentPosition(a,p,{enableHighAccuracy:!0,timeout:1e4,maximumAge:0});}),{latitude:t,longitude:n,altitude:i}=e.coords,r=typeof i=="number"&&!Number.isNaN(i)?i:0;return {latitude:t,longitude:n,altitude:r}}catch{return null}}async queryLocalization(e,t,n){var u,d,m;let i=new FormData;this.config.mapType==="map"?i.append("mapCode",this.config.code):i.append("mapSetCode",this.config.code);let r=(u=this.config.isRightHanded)!=null?u:true;i.append("isRightHanded",`${r}`),i.append("fx",`${t.fx}`),i.append("fy",`${t.fy}`),i.append("px",`${t.px}`),i.append("py",`${t.py}`),i.append("width",`${e.width}`),i.append("height",`${e.height}`),i.append("queryImage",e.blob),this.config.convertToGeoCoordinates!==void 0&&i.append("convertToGeoCoordinates",`${this.config.convertToGeoCoordinates}`),"hintMapCodes"in this.config&&((d=this.config.hintMapCodes)!=null&&d.length)&&this.config.hintMapCodes.forEach(l=>{i.append("hintMapCodes",l);}),this.config.hintPosition&&i.append("hintPosition",this.config.hintPosition);let a;if(this.config.passGeoPose){let l=await this.getGeoPoseComponents();if(l){let{latitude:h,longitude:g,altitude:v}=l;a=`${h},${g},${v}`;}}if(a&&i.append("geoHint",a),this.config.hintRadius!==void 0){let l=Number(this.config.hintRadius);if(Number.isNaN(l)||l<1||l>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.");i.append("hintRadius",`${l}`);}"use2DFiltering"in this.config&&this.config.use2DFiltering!==void 0&&i.append("use2DFiltering",`${this.config.use2DFiltering}`);let s=(await E.post(this.endpoints.queryUrl,i,{headers:{Authorization:`Bearer ${this.accessToken}`}})).data;if(!s.poseFound)return null;let c={localizeData:s};if(n&&((m=s.mapCodes)!=null&&m.length)){let l=await this.fetchMapDetails(s.mapCodes[0]);l&&(c.mapDetails=l);}return c}};async function _(o,e,t,n=.8,i=e,r=t){let a=document.createElement("canvas");a.width=e,a.height=t;let p=a.getContext("2d");if(!p)return new Blob;p.putImageData(new ImageData(new Uint8ClampedArray(o),e,t),0,0);let s=document.createElement("canvas");s.width=i,s.height=r;let c=s.getContext("2d");return c?(c.drawImage(a,0,0,i,r),new Promise(u=>{s.toBlob(d=>u(d!=null?d:new Blob),"image/jpeg",n);})):new Blob}async function B(o,e,t,n){let i=o.createFramebuffer();if(!i)return null;let r=o.getParameter(o.FRAMEBUFFER_BINDING),a;try{o.bindFramebuffer(o.FRAMEBUFFER,i),o.framebufferTexture2D(o.FRAMEBUFFER,o.COLOR_ATTACHMENT0,o.TEXTURE_2D,e,0),a=new Uint8Array(t*n*4),o.readPixels(0,0,t,n,o.RGBA,o.UNSIGNED_BYTE,a);}finally{o.bindFramebuffer(o.FRAMEBUFFER,r),o.deleteFramebuffer(i);}let p=new Uint8ClampedArray(a.length);for(let m=0;m<n;m+=1){let l=m*t*4,h=(n-m-1)*t*4;p.set(a.subarray(l,l+t*4),h);}let s=Math.min(1,1280/Math.max(t,n)),c=Math.round(t*s),u=Math.round(n*s),d=await _(p.buffer,t,n,.7,c,u);return d.size?{blob:d,width:c,height:u}:null}function X(o,e){let t=o,n=(1-t[8])*e.width/2+e.x,i=(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:n,py:i,width:e.width,height:e.height}}function G(o){return new Float32Array(o)}var N=.2,U=.8,$=60,O=1e4,W=300,q=10,T=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,n;if(e.preventDefault(),this.session)try{this.session.end();}catch{}(n=(t=this.options).onContextLost)==null||n.call(t);};this.handleContextRestored=()=>{var e,t;(t=(e=this.options).onContextRestored)==null||t.call(e);};let n=e.canvas;n instanceof HTMLCanvasElement&&(n.addEventListener("webglcontextlost",this.handleContextLost),n.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,n;try{if(!navigator.xr)throw new Error("WebXR not supported on this device.");let i=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(i);}catch(i){(n=(t=this.options).onError)==null||n.call(t,i);}}async initSession(e){var a,p,s,c;await this.gl.makeXRCompatible();let t={};this.options.framebufferScaleFactor!==void 0&&(t.framebufferScaleFactor=this.options.framebufferScaleFactor);let n=new XRWebGLLayer(e,this.gl,t);await e.updateRenderState({baseLayer:n});let i=await e.requestReferenceSpace((a=this.options.referenceSpaceType)!=null?a:"local");this.session=e,this.baseLayer=n,this.referenceSpace=i;let r=XRWebGLBinding;this.xrBinding=new r(e,this.gl),e.addEventListener("end",()=>this.handleSessionEnd()),e.requestAnimationFrame((u,d)=>this.xrLoop(u,d)),this.arButton&&(this.arButton.textContent="STOP AR",this.arButton.classList.replace("multiset-ar-inactive","multiset-ar-active")),(p=this.adapterSessionStartHandler)==null||p.call(this),(c=(s=this.options).onSessionStart)==null||c.call(s),this.options.autoLocalize&&e.requestAnimationFrame(()=>{this.localizeFrame();});}handleSessionEnd(){var e,t,n;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),(n=(t=this.options).onSessionEnd)==null||n.call(t);}xrLoop(e,t){var p;this.session.requestAnimationFrame((s,c)=>this.xrLoop(s,c));let n=this.lastFrameTime===0?0:(e-this.lastFrameTime)/1e3;this.lastFrameTime=e;let i=t.getViewerPose(this.referenceSpace);if(!i){this.options.relocalization&&(this.trackingLossFrames+=1,this.trackingLossFrames>=$&&(this.hadTrackingLoss=true));return}this.hadTrackingLoss&&!this._isLocalizing&&this.options.relocalization?(this.hadTrackingLoss=false,this.trackingLossFrames=0,this.localizeFrame()):this.trackingLossFrames=0;let r=i.views[0],a=this.baseLayer.getViewport(r);(p=this.xrFrameHandler)==null||p.call(this,{time:e,frame:t,pose:i,view:r,viewport:a,baseLayer:this.baseLayer,referenceSpace:this.referenceSpace,deltaSeconds:n});}async localizeFrame(){var p,s,c,u,d,m,l,h,g,v,I,C,b;if(!this.session)throw new Error("No active XR session. Start AR before calling localizeFrame().");let e=(p=this.options.confidenceCheck)!=null?p:false,t=Math.max(N,Math.min((s=this.options.confidenceThreshold)!=null?s:.5,U));(u=(c=this.options).onLocalizationInit)==null||u.call(c),this._isLocalizing=true;let n=null,i;try{let y=await this.captureFrame();n=y.result,i=y.failureReason;}catch(y){return (m=(d=this.options).onError)==null||m.call(d,y),null}finally{this._isLocalizing=false;}if(n&&(!e||((l=n.localizeData.confidence)!=null?l:0)>=t)&&n)return (g=(h=this.options).onLocalizationSuccess)==null||g.call(h,n),this.trackerSpace&&((v=this.adapterResultHandler)==null||v.call(this,n,this.trackerSpace)),n;let a=i!=null?i:n?e?`Best confidence ${(I=n.localizeData.confidence)!=null?I:0} below threshold ${t}.`:void 0:"All attempts failed to produce a pose.";return (b=(C=this.options).onLocalizationFailure)==null||b.call(C,a),null}async captureFrame(){var i;let e=this.session,t=this.referenceSpace,n=(i=this.options.localizationTrackingTimeoutMs)!=null?i:O;return new Promise((r,a)=>{let p=Date.now(),s=(c,u)=>{e.requestAnimationFrame(async(d,m)=>{var l,h,g,v,I,C,b,y,D;try{let S=Date.now()-p,A=m.getViewerPose(t);if(!A){if(S>=n||c+1>=W){let R=(n/1e3).toFixed(1);r({result:null,failureReason:`Tracking unavailable: no viewer pose within ${R}s. Try moving the device or ensuring good lighting.`});}else s(c+1,u);return}let H=A.views;for(let R of H){let F=R.camera;if(!F)continue;let z=(g=(h=(l=this.xrBinding)==null?void 0:l.getCameraImage)==null?void 0:h.call(l,F))!=null?g:null;if(!z)continue;let{width:k,height:P}=F;if(!k||!P)continue;let L=await B(this.gl,z,k,P);if(!L)continue;let M=X(R.projectionMatrix,{width:L.width,height:L.height,x:0,y:0});if(M){(I=(v=this.options).onFrameCaptured)==null||I.call(v,L),(b=(C=this.options).onCameraIntrinsics)==null||b.call(C,M),this.trackerSpace=G(R.transform.matrix);let f=await this.options.client.localizeWithFrame(L,M);f!=null&&f.localizeData&&((D=(y=this.options).onPoseResult)==null||D.call(y,{poseFound:f.localizeData.poseFound,position:f.localizeData.position,rotation:f.localizeData.rotation,mapIds:f.localizeData.mapIds,confidence:f.localizeData.confidence})),r({result:f});return}}u+1>=q?r({result:null,failureReason:"Camera image not available. The device or browser may not support camera access in AR."}):s(c+1,u+1);}catch(S){a(S);}});};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;}};
2
+ export{x as DEFAULT_ENDPOINTS,w as MultisetClient,T as XRSessionManager};
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
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=`
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 k={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={...k,...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(c=>{o.append("hintMapCodes",c);}),this.config.hintPosition&&o.append("hintPosition",this.config.hintPosition);let n;if(this.config.passGeoPose){let c=await this.getGeoPoseComponents();if(c){let{latitude:h,longitude:f,altitude:w}=c;n=`${h},${f},${w}`;}}if(n&&o.append("geoHint",n),this.config.hintRadius!==void 0){let c=Number(this.config.hintRadius);if(Number.isNaN(c)||c<1||c>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",`${c}`);}"use2DFiltering"in this.config&&this.config.use2DFiltering!==void 0&&o.append("use2DFiltering",`${this.config.use2DFiltering}`);let s=(await D.post(this.endpoints.queryUrl,o,{headers:{Authorization:`Bearer ${this.accessToken}`}})).data;if(!s.poseFound)return null;let d={localizeData:s};if(i&&((m=s.mapCodes)!=null&&m.length)){let c=await this.fetchMapDetails(s.mapCodes[0]);c&&(d.mapDetails=c);}return d}};async function q(a,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(a),e,t),0,0);let s=document.createElement("canvas");s.width=o,s.height=r;let d=s.getContext("2d");return d?(d.drawImage(n,0,0,o,r),new Promise(u=>{s.toBlob(p=>u(p!=null?p:new Blob),"image/jpeg",i);})):new Blob}async function _(a,e,t,i){let o=a.createFramebuffer();if(!o)return null;let r=a.getParameter(a.FRAMEBUFFER_BINDING),n;try{a.bindFramebuffer(a.FRAMEBUFFER,o),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,e,0),n=new Uint8Array(t*i*4),a.readPixels(0,0,t,i,a.RGBA,a.UNSIGNED_BYTE,n);}finally{a.bindFramebuffer(a.FRAMEBUFFER,r),a.deleteFramebuffer(o);}let l=new Uint8ClampedArray(n.length);for(let m=0;m<i;m+=1){let c=m*t*4,h=(i-m-1)*t*4;l.set(n.subarray(c,c+t*4),h);}let s=Math.min(1,1280/Math.max(t,i)),d=Math.round(t*s),u=Math.round(i*s),p=await q(l.buffer,t,i,.7,d,u);return p.size?{blob:p,width:d,height:u}:null}function V(a,e){let t=a,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(a){return new Float32Array(a)}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,s,d;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),(d=(s=this.options).onSessionStart)==null||d.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,d)=>this.xrLoop(s,d));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,s,d,u,p,m,c,h,f,w,C,b,M;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((s=this.options.confidenceThreshold)!=null?s:.5,K));(u=(d=this.options).onLocalizationInit)==null||u.call(d),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||((c=i.localizeData.confidence)!=null?c: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 (M=(b=this.options).onLocalizationFailure)==null||M.call(b,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(),s=(d,u)=>{e.requestAnimationFrame(async(p,m)=>{var c,h,f,w,C,b,M,R,I;try{let T=Date.now()-l,z=m.getViewerPose(t);if(!z){if(T>=i||d+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 s(d+1,u);return}let A=z.views;for(let L of A){let x=L.camera;if(!x)continue;let F=(f=(h=(c=this.xrBinding)==null?void 0:c.getCameraImage)==null?void 0:h.call(c,x))!=null?f:null;if(!F)continue;let{width:S,height:U}=x;if(!S||!U)continue;let H=await _(this.gl,F,S,U);if(!H)continue;let B=V(L.projectionMatrix,{width:H.width,height:H.height,x:0,y:0});if(B){(C=(w=this.options).onFrameCaptured)==null||C.call(w,H),(M=(b=this.options).onCameraIntrinsics)==null||M.call(b,B),this.trackerSpace=O(L.transform.matrix);let y=await this.options.client.localizeWithFrame(H,B);y!=null&&y.localizeData&&((I=(R=this.options).onPoseResult)==null||I.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."}):s(d+1,u+1);}catch(T){n(T);}});};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 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 $(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};
93
+ `;function $(a={}){var f,w,C,b,M,R,I,T,z,A,L,x,F,S;let e=(f=a.color)!=null?f:"#7B2CBF",t=(w=a.opacity)!=null?w:150/255,i=(C=a.gridColor)!=null?C:"#ffeb3b",o=(b=a.gridScale)!=null?b:2,r=(M=a.gridLineWidth)!=null?M:.02,n=(R=a.showGrid)!=null?R:1,l=(I=a.center)!=null?I:new g.Vector3(0,0,0),s=(T=a.radius)!=null?T:1,d=(z=a.progress)!=null?z:1,u=(A=a.glowColor)!=null?A:"#FF3A00",p=(L=a.glowWidth)!=null?L:.05,m=(x=a.glowIntensity)!=null?x:2,c=(F=a.lightColor)!=null?F:"#ffffff",h=(S=a.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:s},uProgress:{value:d},uGlowColor:{value:typeof u=="string"?new g.Color(u):u},uGlowWidth:{value:p},uGlowIntensity:{value:m},uLightColor:{value:typeof c=="string"?new g.Color(c):c},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,s=>{let d=new g.Box3().setFromObject(s.scene),u=d.getSize(new g.Vector3),p=d.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,s.scene.traverse(c=>{let h=c;h.isMesh&&(h.material=m,h.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 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,s;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:(l=i.getOverlayRoot())!=null?l:document.body;d.contains(o)||d.appendChild(o),(s=t.onButtonCreated)==null||s.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,c,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((c=(m=this.options).onLocalizationSuccess)==null||c.call(m,e,n),!this.world)return;let{showMesh:l,showGizmo:s,session:d}=this.options,u=s!==false;if(l&&((h=e.localizeData.mapCodes)!=null&&h[0]))try{let f=await d.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),!d.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{k as DEFAULT_ENDPOINTS,X as MultisetClient,N as ThreeAdapter,G as XRSessionManager};
@@ -1,4 +1,4 @@
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=`
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(o,e,t,i=.8,r=e,a=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(o),e,t),0,0);let s=document.createElement("canvas");s.width=r,s.height=a;let c=s.getContext("2d");return c?(c.drawImage(n,0,0,r,a),new Promise(d=>{s.toBlob(u=>d(u!=null?u:new Blob),"image/jpeg",i);})):new Blob}async function N(o,e,t,i){let r=o.createFramebuffer();if(!r)return null;let a=o.getParameter(o.FRAMEBUFFER_BINDING),n;try{o.bindFramebuffer(o.FRAMEBUFFER,r),o.framebufferTexture2D(o.FRAMEBUFFER,o.COLOR_ATTACHMENT0,o.TEXTURE_2D,e,0),n=new Uint8Array(t*i*4),o.readPixels(0,0,t,i,o.RGBA,o.UNSIGNED_BYTE,n);}finally{o.bindFramebuffer(o.FRAMEBUFFER,a),o.deleteFramebuffer(r);}let l=new Uint8ClampedArray(n.length);for(let h=0;h<i;h+=1){let m=h*t*4,p=(i-h-1)*t*4;l.set(n.subarray(m,m+t*4),p);}let s=Math.min(1,1280/Math.max(t,i)),c=Math.round(t*s),d=Math.round(i*s),u=await O(l.buffer,t,i,.7,c,d);return u.size?{blob:u,width:c,height:d}:null}function V(o,e){let t=o,i=(1-t[8])*e.width/2+e.x,r=(1-t[9])*e.height/2+e.y,a=e.width/2*t[0],n=e.height/2*t[5];return {fx:a,fy:n,px:i,py:r,width:e.width,height:e.height}}function k(o){return new Float32Array(o)}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 a=XRWebGLBinding;this.xrBinding=new a(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 a=r.views[0],n=this.baseLayer.getViewport(a);(l=this.xrFrameHandler)==null||l.call(this,{time:e,frame:t,pose:r,view:a,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 R=await this.captureFrame();i=R.result,r=R.failureReason;}catch(R){return (h=(u=this.options).onError)==null||h.call(u,R),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((a,n)=>{let l=Date.now(),s=(c,d)=>{e.requestAnimationFrame(async(u,h)=>{var m,p,E,L,y,T,C,R,z;try{let x=Date.now()-l,F=h.getViewerPose(t);if(!F){if(x>=i||c+1>=$){let b=(i/1e3).toFixed(1);a({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:X}=M;if(!H||!X)continue;let G=await N(this.gl,S,H,X);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 w=await this.options.client.localizeWithFrame(G,P);w!=null&&w.localizeData&&((z=(R=this.options).onPoseResult)==null||z.call(R,{poseFound:w.localizeData.poseFound,position:w.localizeData.position,rotation:w.localizeData.rotation,mapIds:w.localizeData.mapIds,confidence:w.localizeData.confidence})),a({result:w});return}}d+1>=Q?a({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 _(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};
93
+ `;function _(o={}){var E,L,y,T,C,R,z,x,F,A,b,M,S,H;let e=(E=o.color)!=null?E:"#7B2CBF",t=(L=o.opacity)!=null?L:150/255,i=(y=o.gridColor)!=null?y:"#ffeb3b",r=(T=o.gridScale)!=null?T:2,a=(C=o.gridLineWidth)!=null?C:.02,n=(R=o.showGrid)!=null?R:1,l=(z=o.center)!=null?z:new f.Vector3(0,0,0),s=(x=o.radius)!=null?x:1,c=(F=o.progress)!=null?F:1,d=(A=o.glowColor)!=null?A:"#FF3A00",u=(b=o.glowWidth)!=null?b:.05,h=(M=o.glowIntensity)!=null?M:2,m=(S=o.lightColor)!=null?S:"#ffffff",p=(H=o.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:a},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,a;if(this.scene.getObjectByName(e._id))return;let t=(a=(r=e.mapMesh)==null?void 0:r.rawMesh)==null?void 0:a.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 B=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(a=>this.onXRFrame(a)),t.setAdapterResultHandler((a,n)=>{this.handleLocalizationResult(a,n);}),t.setAdapterSessionHandlers(()=>{r.matrixAutoUpdate=false;let a=t.getBaseLayer();a&&(this.xrRenderTarget=new f.WebGLRenderTarget(a.framebufferWidth,a.framebufferHeight)),this.stopPreviewLoop();},()=>{var a,n;i.setRenderTarget(null),this.xrRenderTarget&&(i.setRenderTargetFramebuffer(this.xrRenderTarget,null),this.xrRenderTarget.dispose(),this.xrRenderTarget=null),(a=this.world)==null||a.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:a,camera:n}=t;return this.resizeHandler=()=>{n.aspect=window.innerWidth/window.innerHeight,n.updateProjectionMatrix(),a.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 a,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=(a=this.options).onXRFrame)==null||n.call(a,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,a=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),a.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{B as ThreeAdapter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multisetai/vps",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Multiset VPS WebXR SDK - Core client and WebXR controller.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",