@multisetai/vps 1.0.7-beta.2 → 1.0.7-beta.3

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.
@@ -14,11 +14,7 @@ interface ILocalizeResponse {
14
14
  poseFound: boolean;
15
15
  position: IPosition;
16
16
  rotation: IRotation;
17
- retrieval_scores: number[];
18
- num_matches: number[];
19
17
  confidence: number;
20
- retreived_imgs: string[];
21
- retrieved_imgs?: string[];
22
18
  mapIds: string[];
23
19
  mapCodes: string[];
24
20
  responseTime: number;
@@ -142,6 +138,8 @@ interface IMultisetSdkConfig {
142
138
  endpoints?: Partial<IMultisetSdkEndpoints>;
143
139
  /** If true, show the mesh in the AR session. Default is false. */
144
140
  showMesh?: boolean;
141
+ /** If true, show the coordinate gizmo when a pose is found. Defaults to true. */
142
+ showGizmo?: boolean;
145
143
  /** If true, automatically start a localization run when the AR session starts. */
146
144
  autoLocalize?: boolean;
147
145
  /** If true, automatically re-localize when tracking is lost and then recovered. */
@@ -236,7 +234,6 @@ declare class MultisetClient {
236
234
  private getGeoPoseComponents;
237
235
  private queryLocalization;
238
236
  private fetchMapDetails;
239
- private fetchMapSetDetails;
240
237
  }
241
238
 
242
239
  export { DEFAULT_ENDPOINTS, type ICameraIntrinsicsEvent, type IFrameCaptureEvent, type IGetMapsDetailsResponse, type ILocalizeAndMapDetails, type ILocalizeResponse, type ILocalizeResultEvent, type IMapSetMapsResponse, type IMultisetSdkConfig as IMultisetClientOptions, type IMultisetPublicConfig, type IMultisetSdkConfig, type IMultisetSdkEndpoints, type IPoseResultEvent, type MapType, MultisetClient };
@@ -46,7 +46,6 @@ var MultisetClient = class {
46
46
  }
47
47
  }
48
48
  async authorize() {
49
- var _a, _b, _c, _d, _e;
50
49
  try {
51
50
  const response = await axios.post(
52
51
  this.endpoints.authUrl,
@@ -58,12 +57,12 @@ var MultisetClient = class {
58
57
  }
59
58
  }
60
59
  );
61
- const token = (_c = (_a = response.data) == null ? void 0 : _a.token) != null ? _c : (_b = response.data) == null ? void 0 : _b.access_token;
60
+ const token = response.data?.token ?? response.data?.access_token;
62
61
  if (!token) {
63
62
  throw new Error("Authorization succeeded but no token was returned.");
64
63
  }
65
64
  this.accessToken = token;
66
- (_e = (_d = this.config).onAuthorize) == null ? void 0 : _e.call(_d, token);
65
+ this.config.onAuthorize?.(token);
67
66
  return token;
68
67
  } catch (error) {
69
68
  this.handleError(error);
@@ -71,24 +70,22 @@ var MultisetClient = class {
71
70
  }
72
71
  }
73
72
  handleError(error) {
74
- var _a, _b, _c, _d;
75
73
  if (axios.isAxiosError(error)) {
76
74
  const axiosError = error;
77
- (_b = (_a = this.config).onError) == null ? void 0 : _b.call(_a, axiosError);
75
+ this.config.onError?.(axiosError);
78
76
  } else {
79
- (_d = (_c = this.config).onError) == null ? void 0 : _d.call(_c, error);
77
+ this.config.onError?.(error);
80
78
  }
81
79
  }
82
80
  async localizeWithFrame(frame, intrinsics) {
83
- var _a, _b, _c, _d, _e, _f, _g;
84
81
  if (!this.accessToken) {
85
82
  throw new Error("Access token is missing. Call authorize() first.");
86
83
  }
87
- (_b = (_a = this.config).onFrameCaptured) == null ? void 0 : _b.call(_a, frame);
88
- (_d = (_c = this.config).onCameraIntrinsics) == null ? void 0 : _d.call(_c, intrinsics);
84
+ this.config.onFrameCaptured?.(frame);
85
+ this.config.onCameraIntrinsics?.(intrinsics);
89
86
  const queryResult = await this.queryLocalization(frame, intrinsics);
90
- if ((_e = queryResult == null ? void 0 : queryResult.localizeData) == null ? void 0 : _e.poseFound) {
91
- (_g = (_f = this.config).onPoseResult) == null ? void 0 : _g.call(_f, queryResult.localizeData);
87
+ if (queryResult?.localizeData?.poseFound) {
88
+ this.config.onPoseResult?.(queryResult.localizeData);
92
89
  }
93
90
  return queryResult;
94
91
  }
@@ -112,7 +109,6 @@ var MultisetClient = class {
112
109
  }
113
110
  }
114
111
  async queryLocalization(frame, intrinsics) {
115
- var _a;
116
112
  const formData = new FormData();
117
113
  if (this.config.mapType === "map") {
118
114
  formData.append("mapCode", this.config.code);
@@ -155,7 +151,7 @@ var MultisetClient = class {
155
151
  const result = {
156
152
  localizeData: data
157
153
  };
158
- if (this.config.showMesh && this.config.mapType === "map" && ((_a = data.mapCodes) == null ? void 0 : _a.length)) {
154
+ if (this.config.showMesh && data.mapCodes?.length) {
159
155
  const mapCode = data.mapCodes[0];
160
156
  const cached = this.mapDetailsCache[mapCode];
161
157
  if (cached) {
@@ -190,22 +186,6 @@ var MultisetClient = class {
190
186
  return null;
191
187
  }
192
188
  }
193
- async fetchMapSetDetails(mapSetId) {
194
- try {
195
- const response = await axios.get(
196
- `${this.endpoints.mapSetDetailsUrl}${mapSetId}`,
197
- {
198
- headers: {
199
- Authorization: `Bearer ${this.accessToken}`
200
- }
201
- }
202
- );
203
- return response.data;
204
- } catch (error) {
205
- this.handleError(error);
206
- return null;
207
- }
208
- }
209
189
  };
210
190
 
211
191
  export { DEFAULT_ENDPOINTS, MultisetClient };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/core/config.ts","../../src/lib/core/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ILocalizeAndMapDetails, MapType } from './types';\n\n/** The subset of config that is safe to expose publicly (no credentials). */\nexport type IMultisetPublicConfig = Omit<IMultisetSdkConfig, 'clientId' | 'clientSecret'>;\n\nexport interface IMultisetSdkConfig {\n clientId: string;\n clientSecret: string;\n /** Map or map-set code used for localization. */\n code: string;\n /** Map or map-set type ('map' or 'map-set'). */\n mapType: MapType;\n endpoints?: Partial<IMultisetSdkEndpoints>;\n /** If true, show the mesh in the AR session. Default is false. */\n showMesh?: boolean;\n /** If true, automatically start a localization run when the AR session starts. */\n autoLocalize?: boolean;\n /** If true, automatically re-localize when tracking is lost and then recovered. */\n relocalization?: boolean;\n /** When enabled, only accept a localization result if confidence >= confidenceThreshold. */\n confidenceCheck?: boolean;\n /** Minimum confidence (0.2–0.8) required when confidenceCheck is enabled. */\n confidenceThreshold?: number;\n /** Total single-frame attempts per localization run (1–5). */\n requestAttempts?: number;\n /** Time in seconds between attempts in a localization run (1–5). */\n localizationInterval?: number;\n /** Include device geo pose as a hint in localization requests. */\n passGeoPose?: boolean;\n /** Request geo coordinates in the localization response (if supported by backend). */\n geoCoordinatesInResponse?: boolean;\n /** Max time in ms to wait for a valid viewer pose before failing. Default 10000. */\n localizationTrackingTimeoutMs?: number;\n\n /** Invoked at the start of a localization run. */\n onLocalizationInit?: () => void;\n /** Invoked after a successful localization that meets confidence criteria (if enabled). */\n onLocalizationSuccess?: (result: ILocalizeAndMapDetails) => void;\n /** Invoked when all attempts fail or the best result is below the confidence threshold. */\n onLocalizationFailure?: (reason?: string) => void;\n\n /** Called after a successful authorization with the access token. */\n onAuthorize?: (token: string) => void;\n /** Called whenever a camera frame is captured and sent for localization. */\n onFrameCaptured?: (payload: IFrameCaptureEvent) => void;\n /** Called with the camera intrinsics used for a localization request. */\n onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;\n /** Called with the raw pose/localization result returned by the backend. */\n onPoseResult?: (payload: IPoseResultEvent) => void;\n /** Called when any error occurs during authorization or localization. */\n onError?: (error: unknown) => void;\n}\n\nexport interface IMultisetSdkEndpoints {\n authUrl: string;\n queryUrl: string;\n mapDetailsUrl: string;\n fileDownloadUrl: string;\n mapSetDetailsUrl: string;\n}\n\nexport interface IFrameCaptureEvent {\n blob: Blob;\n width: number;\n height: number;\n}\n\nexport interface ICameraIntrinsicsEvent {\n fx: number;\n fy: number;\n px: number;\n py: number;\n width: number;\n height: number;\n}\n\nexport interface IPoseResultEvent {\n poseFound: boolean;\n position: {\n x: number;\n y: number;\n z: number;\n };\n rotation: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n mapIds: string[];\n confidence?: number;\n}\n\nexport interface ILocalizeResultEvent {\n frame: IFrameCaptureEvent;\n intrinsics: ICameraIntrinsicsEvent;\n response: ILocalizeAndMapDetails | null;\n}\n\nexport const DEFAULT_ENDPOINTS: IMultisetSdkEndpoints = {\n authUrl: 'https://api.multiset.ai/v1/m2m/token',\n queryUrl: 'https://api.multiset.ai/v1/vps/map/query-form',\n mapDetailsUrl: 'https://api.multiset.ai/v1/vps/map/',\n mapSetDetailsUrl: 'https://api.multiset.ai/v1/vps/map-set/',\n fileDownloadUrl: 'https://api.multiset.ai/v1/file',\n};\n","import axios, { AxiosError } from 'axios';\nimport type {\n IMultisetSdkConfig,\n IMultisetPublicConfig,\n IMultisetSdkEndpoints,\n IFrameCaptureEvent,\n ICameraIntrinsicsEvent,\n} from './config';\nimport { DEFAULT_ENDPOINTS } from './config';\nimport type {\n ILocalizeAndMapDetails,\n ILocalizeResponse,\n IGetMapsDetailsResponse,\n IMapSetMapsResponse,\n} from './types';\n\nexport class MultisetClient {\n private readonly credentials: { clientId: string; clientSecret: string };\n private readonly config: IMultisetPublicConfig;\n private readonly endpoints: IMultisetSdkEndpoints;\n private accessToken: string | null = null;\n private mapDetailsCache: Record<string, IGetMapsDetailsResponse> = {};\n\n constructor(input: IMultisetSdkConfig) {\n const { clientId, clientSecret, ...rest } = input;\n this.credentials = { clientId, clientSecret };\n this.config = rest;\n this.endpoints = {\n ...DEFAULT_ENDPOINTS,\n ...rest.endpoints,\n };\n }\n\n get token(): string | null {\n return this.accessToken;\n }\n\n getConfig(): IMultisetPublicConfig {\n return this.config;\n }\n\n async downloadFile(key: string): Promise<string> {\n if (!this.accessToken || !key) {\n return '';\n }\n\n try {\n const response = await axios.get<{ url: string }>(\n `${this.endpoints.fileDownloadUrl}?key=${encodeURIComponent(key)}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n return response.status === 200 ? response.data.url : '';\n } catch (error) {\n this.handleError(error);\n return '';\n }\n }\n\n async authorize(): Promise<string> {\n try {\n const response = await axios.post(\n this.endpoints.authUrl,\n {},\n {\n auth: {\n username: this.credentials.clientId,\n password: this.credentials.clientSecret,\n },\n }\n );\n\n const token: string | undefined =\n response.data?.token ?? response.data?.access_token;\n\n if (!token) {\n throw new Error('Authorization succeeded but no token was returned.');\n }\n\n this.accessToken = token;\n this.config.onAuthorize?.(token);\n return token;\n } catch (error) {\n this.handleError(error);\n throw error;\n }\n }\n\n private handleError(error: unknown): void {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError;\n this.config.onError?.(axiosError);\n } else {\n this.config.onError?.(error);\n }\n }\n\n async localizeWithFrame(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n if (!this.accessToken) {\n throw new Error('Access token is missing. Call authorize() first.');\n }\n\n this.config.onFrameCaptured?.(frame);\n this.config.onCameraIntrinsics?.(intrinsics);\n\n const queryResult = await this.queryLocalization(frame, intrinsics);\n\n if (queryResult?.localizeData?.poseFound) {\n this.config.onPoseResult?.(queryResult.localizeData);\n }\n\n return queryResult;\n }\n\n private async getGeoPoseComponents(): Promise<\n { latitude: number, longitude: number, altitude: number } | null\n > {\n if (\n typeof navigator === 'undefined' ||\n !('geolocation' in navigator) ||\n !navigator.geolocation\n ) {\n return null;\n }\n\n try {\n const position = await new Promise<GeolocationPosition>((resolve, reject) => {\n navigator.geolocation.getCurrentPosition(resolve, reject, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: 0,\n });\n });\n\n const { latitude, longitude, altitude } = position.coords;\n const safeAltitude =\n typeof altitude === 'number' && !Number.isNaN(altitude) ? altitude : 0.0;\n\n return { latitude, longitude, altitude: safeAltitude };\n } catch {\n return null;\n }\n }\n\n private async queryLocalization(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n const formData = new FormData();\n\n if (this.config.mapType === 'map') {\n formData.append('mapCode', this.config.code);\n } else {\n formData.append('mapSetCode', this.config.code);\n }\n formData.append('isRightHanded', 'true');\n formData.append('fx', `${intrinsics.fx}`);\n formData.append('fy', `${intrinsics.fy}`);\n formData.append('px', `${intrinsics.px}`);\n formData.append('py', `${intrinsics.py}`);\n formData.append('width', `${frame.width}`);\n formData.append('height', `${frame.height}`);\n formData.append('queryImage', frame.blob);\n if (this.config.geoCoordinatesInResponse) {\n formData.append('geoCoordinatesInResponse', 'true');\n }\n if (this.config.passGeoPose) {\n const components = await this.getGeoPoseComponents();\n if (components) {\n const { latitude, longitude, altitude } = components;\n const geoHint = `${latitude},${longitude},${altitude}`;\n formData.append('geoHint', geoHint);\n }\n }\n\n try {\n const response = await axios.post<ILocalizeResponse>(\n this.endpoints.queryUrl,\n formData,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n const data = response.data;\n if (!data.poseFound) {\n return null;\n }\n\n const result: ILocalizeAndMapDetails = {\n localizeData: data,\n };\n\n if (\n this.config.showMesh &&\n this.config.mapType === 'map' &&\n data.mapCodes?.length\n ) {\n const mapCode = data.mapCodes[0];\n const cached = this.mapDetailsCache[mapCode];\n if (cached) {\n result.mapDetails = cached;\n } else {\n const mapDetails = await this.fetchMapDetails(mapCode);\n if (mapDetails) {\n this.mapDetailsCache[mapCode] = mapDetails;\n result.mapDetails = mapDetails;\n }\n }\n }\n\n return result;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapDetails(mapCode: string): Promise<IGetMapsDetailsResponse | null> {\n try {\n const response = await axios.get<IGetMapsDetailsResponse>(\n `${this.endpoints.mapDetailsUrl}${mapCode}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapSetDetails(mapSetId: string): Promise<IMapSetMapsResponse | null> {\n try {\n const response = await axios.get<IMapSetMapsResponse>(\n `${this.endpoints.mapSetDetailsUrl}${mapSetId}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/lib/core/config.ts","../../src/lib/core/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ILocalizeAndMapDetails, MapType } from './types';\n\n/** The subset of config that is safe to expose publicly (no credentials). */\nexport type IMultisetPublicConfig = Omit<IMultisetSdkConfig, 'clientId' | 'clientSecret'>;\n\nexport interface IMultisetSdkConfig {\n clientId: string;\n clientSecret: string;\n /** Map or map-set code used for localization. */\n code: string;\n /** Map or map-set type ('map' or 'map-set'). */\n mapType: MapType;\n endpoints?: Partial<IMultisetSdkEndpoints>;\n /** If true, show the mesh in the AR session. Default is false. */\n showMesh?: boolean;\n /** If true, show the coordinate gizmo when a pose is found. Defaults to true. */\n showGizmo?: boolean;\n /** If true, automatically start a localization run when the AR session starts. */\n autoLocalize?: boolean;\n /** If true, automatically re-localize when tracking is lost and then recovered. */\n relocalization?: boolean;\n /** When enabled, only accept a localization result if confidence >= confidenceThreshold. */\n confidenceCheck?: boolean;\n /** Minimum confidence (0.2–0.8) required when confidenceCheck is enabled. */\n confidenceThreshold?: number;\n /** Total single-frame attempts per localization run (1–5). */\n requestAttempts?: number;\n /** Time in seconds between attempts in a localization run (1–5). */\n localizationInterval?: number;\n /** Include device geo pose as a hint in localization requests. */\n passGeoPose?: boolean;\n /** Request geo coordinates in the localization response (if supported by backend). */\n geoCoordinatesInResponse?: boolean;\n /** Max time in ms to wait for a valid viewer pose before failing. Default 10000. */\n localizationTrackingTimeoutMs?: number;\n\n /** Invoked at the start of a localization run. */\n onLocalizationInit?: () => void;\n /** Invoked after a successful localization that meets confidence criteria (if enabled). */\n onLocalizationSuccess?: (result: ILocalizeAndMapDetails) => void;\n /** Invoked when all attempts fail or the best result is below the confidence threshold. */\n onLocalizationFailure?: (reason?: string) => void;\n\n /** Called after a successful authorization with the access token. */\n onAuthorize?: (token: string) => void;\n /** Called whenever a camera frame is captured and sent for localization. */\n onFrameCaptured?: (payload: IFrameCaptureEvent) => void;\n /** Called with the camera intrinsics used for a localization request. */\n onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;\n /** Called with the raw pose/localization result returned by the backend. */\n onPoseResult?: (payload: IPoseResultEvent) => void;\n /** Called when any error occurs during authorization or localization. */\n onError?: (error: unknown) => void;\n}\n\nexport interface IMultisetSdkEndpoints {\n authUrl: string;\n queryUrl: string;\n mapDetailsUrl: string;\n fileDownloadUrl: string;\n mapSetDetailsUrl: string;\n}\n\nexport interface IFrameCaptureEvent {\n blob: Blob;\n width: number;\n height: number;\n}\n\nexport interface ICameraIntrinsicsEvent {\n fx: number;\n fy: number;\n px: number;\n py: number;\n width: number;\n height: number;\n}\n\nexport interface IPoseResultEvent {\n poseFound: boolean;\n position: {\n x: number;\n y: number;\n z: number;\n };\n rotation: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n mapIds: string[];\n confidence?: number;\n}\n\nexport interface ILocalizeResultEvent {\n frame: IFrameCaptureEvent;\n intrinsics: ICameraIntrinsicsEvent;\n response: ILocalizeAndMapDetails | null;\n}\n\nexport const DEFAULT_ENDPOINTS: IMultisetSdkEndpoints = {\n authUrl: 'https://api.multiset.ai/v1/m2m/token',\n queryUrl: 'https://api.multiset.ai/v1/vps/map/query-form',\n mapDetailsUrl: 'https://api.multiset.ai/v1/vps/map/',\n mapSetDetailsUrl: 'https://api.multiset.ai/v1/vps/map-set/',\n fileDownloadUrl: 'https://api.multiset.ai/v1/file',\n};\n","import axios, { AxiosError } from 'axios';\nimport type {\n IMultisetSdkConfig,\n IMultisetPublicConfig,\n IMultisetSdkEndpoints,\n IFrameCaptureEvent,\n ICameraIntrinsicsEvent,\n} from './config';\nimport { DEFAULT_ENDPOINTS } from './config';\nimport type {\n ILocalizeAndMapDetails,\n ILocalizeResponse,\n IGetMapsDetailsResponse,\n} from './types';\n\nexport class MultisetClient {\n private readonly credentials: { clientId: string; clientSecret: string };\n private readonly config: IMultisetPublicConfig;\n private readonly endpoints: IMultisetSdkEndpoints;\n private accessToken: string | null = null;\n private mapDetailsCache: Record<string, IGetMapsDetailsResponse> = {};\n\n constructor(input: IMultisetSdkConfig) {\n const { clientId, clientSecret, ...rest } = input;\n this.credentials = { clientId, clientSecret };\n this.config = rest;\n this.endpoints = {\n ...DEFAULT_ENDPOINTS,\n ...rest.endpoints,\n };\n }\n\n get token(): string | null {\n return this.accessToken;\n }\n\n getConfig(): IMultisetPublicConfig {\n return this.config;\n }\n\n async downloadFile(key: string): Promise<string> {\n if (!this.accessToken || !key) {\n return '';\n }\n\n try {\n const response = await axios.get<{ url: string }>(\n `${this.endpoints.fileDownloadUrl}?key=${encodeURIComponent(key)}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n return response.status === 200 ? response.data.url : '';\n } catch (error) {\n this.handleError(error);\n return '';\n }\n }\n\n async authorize(): Promise<string> {\n try {\n const response = await axios.post(\n this.endpoints.authUrl,\n {},\n {\n auth: {\n username: this.credentials.clientId,\n password: this.credentials.clientSecret,\n },\n }\n );\n\n const token: string | undefined =\n response.data?.token ?? response.data?.access_token;\n\n if (!token) {\n throw new Error('Authorization succeeded but no token was returned.');\n }\n\n this.accessToken = token;\n this.config.onAuthorize?.(token);\n return token;\n } catch (error) {\n this.handleError(error);\n throw error;\n }\n }\n\n private handleError(error: unknown): void {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError;\n this.config.onError?.(axiosError);\n } else {\n this.config.onError?.(error);\n }\n }\n\n async localizeWithFrame(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n if (!this.accessToken) {\n throw new Error('Access token is missing. Call authorize() first.');\n }\n\n this.config.onFrameCaptured?.(frame);\n this.config.onCameraIntrinsics?.(intrinsics);\n\n const queryResult = await this.queryLocalization(frame, intrinsics);\n\n if (queryResult?.localizeData?.poseFound) {\n this.config.onPoseResult?.(queryResult.localizeData);\n }\n\n return queryResult;\n }\n\n private async getGeoPoseComponents(): Promise<\n { latitude: number, longitude: number, altitude: number } | null\n > {\n if (\n typeof navigator === 'undefined' ||\n !('geolocation' in navigator) ||\n !navigator.geolocation\n ) {\n return null;\n }\n\n try {\n const position = await new Promise<GeolocationPosition>((resolve, reject) => {\n navigator.geolocation.getCurrentPosition(resolve, reject, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: 0,\n });\n });\n\n const { latitude, longitude, altitude } = position.coords;\n const safeAltitude =\n typeof altitude === 'number' && !Number.isNaN(altitude) ? altitude : 0.0;\n\n return { latitude, longitude, altitude: safeAltitude };\n } catch {\n return null;\n }\n }\n\n private async queryLocalization(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n const formData = new FormData();\n\n if (this.config.mapType === 'map') {\n formData.append('mapCode', this.config.code);\n } else {\n formData.append('mapSetCode', this.config.code);\n }\n formData.append('isRightHanded', 'true');\n formData.append('fx', `${intrinsics.fx}`);\n formData.append('fy', `${intrinsics.fy}`);\n formData.append('px', `${intrinsics.px}`);\n formData.append('py', `${intrinsics.py}`);\n formData.append('width', `${frame.width}`);\n formData.append('height', `${frame.height}`);\n formData.append('queryImage', frame.blob);\n if (this.config.geoCoordinatesInResponse) {\n formData.append('geoCoordinatesInResponse', 'true');\n }\n if (this.config.passGeoPose) {\n const components = await this.getGeoPoseComponents();\n if (components) {\n const { latitude, longitude, altitude } = components;\n const geoHint = `${latitude},${longitude},${altitude}`;\n formData.append('geoHint', geoHint);\n }\n }\n\n try {\n const response = await axios.post<ILocalizeResponse>(\n this.endpoints.queryUrl,\n formData,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n const data = response.data;\n if (!data.poseFound) {\n return null;\n }\n\n const result: ILocalizeAndMapDetails = {\n localizeData: data,\n };\n\n if (\n this.config.showMesh &&\n data.mapCodes?.length\n ) {\n const mapCode = data.mapCodes[0];\n const cached = this.mapDetailsCache[mapCode];\n if (cached) {\n result.mapDetails = cached;\n } else {\n const mapDetails = await this.fetchMapDetails(mapCode);\n if (mapDetails) {\n this.mapDetailsCache[mapCode] = mapDetails;\n result.mapDetails = mapDetails;\n }\n }\n }\n\n return result;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapDetails(mapCode: string): Promise<IGetMapsDetailsResponse | null> {\n try {\n const response = await axios.get<IGetMapsDetailsResponse>(\n `${this.endpoints.mapDetailsUrl}${mapCode}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import * as THREE3 from 'three';
3
3
  import { ARButton } from 'three/examples/jsm/webxr/ARButton.js';
4
4
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
5
5
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
6
+ import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
6
7
 
7
8
  // src/lib/core/config.ts
8
9
  var DEFAULT_ENDPOINTS = {
@@ -50,7 +51,6 @@ var MultisetClient = class {
50
51
  }
51
52
  }
52
53
  async authorize() {
53
- var _a, _b, _c, _d, _e;
54
54
  try {
55
55
  const response = await axios.post(
56
56
  this.endpoints.authUrl,
@@ -62,12 +62,12 @@ var MultisetClient = class {
62
62
  }
63
63
  }
64
64
  );
65
- const token = (_c = (_a = response.data) == null ? void 0 : _a.token) != null ? _c : (_b = response.data) == null ? void 0 : _b.access_token;
65
+ const token = response.data?.token ?? response.data?.access_token;
66
66
  if (!token) {
67
67
  throw new Error("Authorization succeeded but no token was returned.");
68
68
  }
69
69
  this.accessToken = token;
70
- (_e = (_d = this.config).onAuthorize) == null ? void 0 : _e.call(_d, token);
70
+ this.config.onAuthorize?.(token);
71
71
  return token;
72
72
  } catch (error) {
73
73
  this.handleError(error);
@@ -75,24 +75,22 @@ var MultisetClient = class {
75
75
  }
76
76
  }
77
77
  handleError(error) {
78
- var _a, _b, _c, _d;
79
78
  if (axios.isAxiosError(error)) {
80
79
  const axiosError = error;
81
- (_b = (_a = this.config).onError) == null ? void 0 : _b.call(_a, axiosError);
80
+ this.config.onError?.(axiosError);
82
81
  } else {
83
- (_d = (_c = this.config).onError) == null ? void 0 : _d.call(_c, error);
82
+ this.config.onError?.(error);
84
83
  }
85
84
  }
86
85
  async localizeWithFrame(frame, intrinsics) {
87
- var _a, _b, _c, _d, _e, _f, _g;
88
86
  if (!this.accessToken) {
89
87
  throw new Error("Access token is missing. Call authorize() first.");
90
88
  }
91
- (_b = (_a = this.config).onFrameCaptured) == null ? void 0 : _b.call(_a, frame);
92
- (_d = (_c = this.config).onCameraIntrinsics) == null ? void 0 : _d.call(_c, intrinsics);
89
+ this.config.onFrameCaptured?.(frame);
90
+ this.config.onCameraIntrinsics?.(intrinsics);
93
91
  const queryResult = await this.queryLocalization(frame, intrinsics);
94
- if ((_e = queryResult == null ? void 0 : queryResult.localizeData) == null ? void 0 : _e.poseFound) {
95
- (_g = (_f = this.config).onPoseResult) == null ? void 0 : _g.call(_f, queryResult.localizeData);
92
+ if (queryResult?.localizeData?.poseFound) {
93
+ this.config.onPoseResult?.(queryResult.localizeData);
96
94
  }
97
95
  return queryResult;
98
96
  }
@@ -116,7 +114,6 @@ var MultisetClient = class {
116
114
  }
117
115
  }
118
116
  async queryLocalization(frame, intrinsics) {
119
- var _a;
120
117
  const formData = new FormData();
121
118
  if (this.config.mapType === "map") {
122
119
  formData.append("mapCode", this.config.code);
@@ -159,7 +156,7 @@ var MultisetClient = class {
159
156
  const result = {
160
157
  localizeData: data
161
158
  };
162
- if (this.config.showMesh && this.config.mapType === "map" && ((_a = data.mapCodes) == null ? void 0 : _a.length)) {
159
+ if (this.config.showMesh && data.mapCodes?.length) {
163
160
  const mapCode = data.mapCodes[0];
164
161
  const cached = this.mapDetailsCache[mapCode];
165
162
  if (cached) {
@@ -194,22 +191,6 @@ var MultisetClient = class {
194
191
  return null;
195
192
  }
196
193
  }
197
- async fetchMapSetDetails(mapSetId) {
198
- try {
199
- const response = await axios.get(
200
- `${this.endpoints.mapSetDetailsUrl}${mapSetId}`,
201
- {
202
- headers: {
203
- Authorization: `Bearer ${this.accessToken}`
204
- }
205
- }
206
- );
207
- return response.data;
208
- } catch (error) {
209
- this.handleError(error);
210
- return null;
211
- }
212
- }
213
194
  };
214
195
 
215
196
  // src/lib/webxr/internal/cameraIntrinsics.ts
@@ -239,7 +220,7 @@ async function compressToJpeg(buffer, width, height, quality = 0.8) {
239
220
  const imageData = new ImageData(new Uint8ClampedArray(buffer), width, height);
240
221
  ctx.putImageData(imageData, 0, 0);
241
222
  return new Promise((resolve) => {
242
- canvas.toBlob((blob) => resolve(blob != null ? blob : new Blob()), "image/jpeg", quality);
223
+ canvas.toBlob((blob) => resolve(blob ?? new Blob()), "image/jpeg", quality);
243
224
  });
244
225
  }
245
226
  async function getCameraTextureAsImage(renderer, webGLTexture, width, height) {
@@ -425,21 +406,20 @@ void main() {
425
406
  }
426
407
  `;
427
408
  function createGridMaterial(options = {}) {
428
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
429
- const color = (_a = options.color) != null ? _a : "#7B2CBF";
430
- const opacity = (_b = options.opacity) != null ? _b : 0.6;
431
- const gridColor = (_c = options.gridColor) != null ? _c : "#ffeb3b";
432
- const gridScale = (_d = options.gridScale) != null ? _d : 2;
433
- const gridLineWidth = (_e = options.gridLineWidth) != null ? _e : 0.02;
434
- const showGrid = (_f = options.showGrid) != null ? _f : 1;
435
- const center = (_g = options.center) != null ? _g : new THREE3.Vector3(0, 0, 0);
436
- const radius = (_h = options.radius) != null ? _h : 1;
437
- const progress = (_i = options.progress) != null ? _i : 1;
438
- const glowColor = (_j = options.glowColor) != null ? _j : "#00ffff";
439
- const glowWidth = (_k = options.glowWidth) != null ? _k : 0.05;
440
- const glowIntensity = (_l = options.glowIntensity) != null ? _l : 2;
441
- const lightColor = (_m = options.lightColor) != null ? _m : "#ffffff";
442
- const lightDirection = (_n = options.lightDirection) != null ? _n : new THREE3.Vector3(0.3, 1, 0.3).normalize();
409
+ const color = options.color ?? "#7B2CBF";
410
+ const opacity = options.opacity ?? 0.6;
411
+ const gridColor = options.gridColor ?? "#ffeb3b";
412
+ const gridScale = options.gridScale ?? 2;
413
+ const gridLineWidth = options.gridLineWidth ?? 0.02;
414
+ const showGrid = options.showGrid ?? 1;
415
+ const center = options.center ?? new THREE3.Vector3(0, 0, 0);
416
+ const radius = options.radius ?? 1;
417
+ const progress = options.progress ?? 1;
418
+ const glowColor = options.glowColor ?? "#00ffff";
419
+ const glowWidth = options.glowWidth ?? 0.05;
420
+ const glowIntensity = options.glowIntensity ?? 2;
421
+ const lightColor = options.lightColor ?? "#ffffff";
422
+ const lightDirection = options.lightDirection ?? new THREE3.Vector3(0.3, 1, 0.3).normalize();
443
423
  return new THREE3.ShaderMaterial({
444
424
  vertexShader: VERTEX,
445
425
  fragmentShader: FRAGMENT,
@@ -473,9 +453,13 @@ function createGridMaterial(options = {}) {
473
453
  // src/lib/webxr/mapMeshVisualizer.ts
474
454
  var LARGE_MAP_THRESHOLD = 50;
475
455
  var MapMeshVisualizer = class {
476
- constructor(scene, client) {
456
+ constructor(scene, client, renderer, camera) {
477
457
  this.scene = scene;
478
458
  this.client = client;
459
+ this.renderer = renderer;
460
+ this.camera = camera;
461
+ this.gizmoControl = null;
462
+ this.gizmoHelper = null;
479
463
  this.meshMaterial = null;
480
464
  this.localCenter = new THREE3.Vector3();
481
465
  this.localRadius = 0;
@@ -497,12 +481,29 @@ var MapMeshVisualizer = class {
497
481
  getMeshGroup() {
498
482
  return this.meshGroup;
499
483
  }
484
+ async ensureGizmoLoaded() {
485
+ const cfg = this.client.getConfig();
486
+ if (cfg.showGizmo === false) {
487
+ return;
488
+ }
489
+ if (!this.gizmoControl) {
490
+ const gizmo = new TransformControls(this.camera, this.renderer.domElement);
491
+ gizmo.setMode("translate");
492
+ gizmo.setSpace("local");
493
+ gizmo.enabled = false;
494
+ const helper = gizmo.getHelper();
495
+ this.scene.add(helper);
496
+ gizmo.attach(this.meshGroup);
497
+ this.gizmoControl = gizmo;
498
+ this.gizmoHelper = helper;
499
+ }
500
+ this.gizmoHelper.visible = true;
501
+ }
500
502
  async ensureMeshLoaded(mapDetails) {
501
- var _a, _b;
502
503
  if (this.scene.getObjectByName(mapDetails._id)) {
503
504
  return;
504
505
  }
505
- const meshKey = (_b = (_a = mapDetails.mapMesh) == null ? void 0 : _a.rawMesh) == null ? void 0 : _b.meshLink;
506
+ const meshKey = mapDetails.mapMesh?.rawMesh?.meshLink;
506
507
  if (!meshKey) {
507
508
  return;
508
509
  }
@@ -586,7 +587,6 @@ var MapMeshVisualizer = class {
586
587
  }
587
588
  }
588
589
  update(deltaSeconds, viewerWorldPosition) {
589
- var _a;
590
590
  if (!this.meshMaterial) {
591
591
  return;
592
592
  }
@@ -597,7 +597,7 @@ var MapMeshVisualizer = class {
597
597
  if (!uniforms.uProgress) {
598
598
  return;
599
599
  }
600
- const current = (_a = uniforms.uProgress.value) != null ? _a : 0;
600
+ const current = uniforms.uProgress.value ?? 0;
601
601
  if (current === 0 && uniforms.uCenter && this.lastViewerWorldPosition.lengthSq() > 0) {
602
602
  uniforms.uCenter.value.copy(this.lastViewerWorldPosition);
603
603
  }
@@ -631,13 +631,22 @@ var MapMeshVisualizer = class {
631
631
  });
632
632
  this.scene.remove(this.meshGroup);
633
633
  this.dracoLoader.dispose();
634
+ if (this.gizmoHelper) {
635
+ this.scene.remove(this.gizmoHelper);
636
+ }
637
+ if (this.gizmoControl) {
638
+ this.gizmoControl.dispose();
639
+ }
634
640
  }
635
641
  };
636
642
 
637
643
  // src/lib/webxr/world/World.ts
638
644
  var World = class {
639
- constructor(scene, client) {
640
- this.meshVisualizer = new MapMeshVisualizer(scene, client);
645
+ constructor(scene, client, renderer, camera) {
646
+ this.meshVisualizer = new MapMeshVisualizer(scene, client, renderer, camera);
647
+ }
648
+ async ensureGizmoLoaded() {
649
+ await this.meshVisualizer.ensureGizmoLoaded();
641
650
  }
642
651
  async ensureMeshLoaded(mapDetails) {
643
652
  await this.meshVisualizer.ensureMeshLoaded(mapDetails);
@@ -674,23 +683,21 @@ var WebxrController = class {
674
683
  this.trackerSpace = null;
675
684
  }
676
685
  async initialize(buttonContainer) {
677
- var _a, _b, _c, _d;
678
686
  if (this.experience) {
679
687
  return this.arButton;
680
688
  }
681
689
  if (!window.isSecureContext) {
682
690
  throw new Error("WebXR requires a secure context (HTTPS).");
683
691
  }
684
- const canvas = (_a = this.options.canvas) != null ? _a : document.createElement("canvas");
692
+ const canvas = this.options.canvas ?? document.createElement("canvas");
685
693
  this.experience = new Experience(canvas);
686
- this.world = new World(this.experience.getScene(), this.options.client);
687
694
  const renderer = this.experience.getRenderer();
688
695
  const camera = this.experience.getCamera();
689
696
  const scene = this.experience.getScene();
697
+ this.world = new World(scene, this.options.client, renderer, camera);
690
698
  renderer.xr.addEventListener("sessionstart", () => {
691
- var _a2, _b2;
692
699
  this.isSessionActive = true;
693
- (_b2 = (_a2 = this.options).onSessionStart) == null ? void 0 : _b2.call(_a2);
700
+ this.options.onSessionStart?.();
694
701
  const cfg = this.options.client.getConfig();
695
702
  if (cfg.autoLocalize) {
696
703
  const session = renderer.xr.getSession();
@@ -704,9 +711,8 @@ var WebxrController = class {
704
711
  }
705
712
  });
706
713
  renderer.xr.addEventListener("sessionend", () => {
707
- var _a2, _b2;
708
714
  this.isSessionActive = false;
709
- (_b2 = (_a2 = this.options).onSessionEnd) == null ? void 0 : _b2.call(_a2);
715
+ this.options.onSessionEnd?.();
710
716
  });
711
717
  let lastTime = 0;
712
718
  const animationLoop = (time, frame) => {
@@ -751,11 +757,10 @@ var WebxrController = class {
751
757
  };
752
758
  renderer.setAnimationLoop(animationLoop);
753
759
  const resizeHandler = () => {
754
- var _a2;
755
- (_a2 = this.experience) == null ? void 0 : _a2.resize();
760
+ this.experience?.resize();
756
761
  };
757
762
  window.addEventListener("resize", resizeHandler);
758
- const overlayRoot = (_b = this.options.overlayRoot) != null ? _b : document.body;
763
+ const overlayRoot = this.options.overlayRoot ?? document.body;
759
764
  const arButton = ARButton.createButton(renderer, {
760
765
  requiredFeatures: ["camera-access", "dom-overlay"],
761
766
  domOverlay: { root: overlayRoot }
@@ -766,7 +771,7 @@ var WebxrController = class {
766
771
  }
767
772
  this.arButton = arButton;
768
773
  this.resizeHandler = resizeHandler;
769
- (_d = (_c = this.options).onARButtonCreated) == null ? void 0 : _d.call(_c, arButton);
774
+ this.options.onARButtonCreated?.(arButton);
770
775
  return arButton;
771
776
  }
772
777
  getScene() {
@@ -788,8 +793,7 @@ var WebxrController = class {
788
793
  return this.experience.getRenderer();
789
794
  }
790
795
  hasActiveSession() {
791
- var _a;
792
- return this.isSessionActive && ((_a = this.experience) == null ? void 0 : _a.getRenderer().xr.isPresenting) === true;
796
+ return this.isSessionActive && this.experience?.getRenderer().xr.isPresenting === true;
793
797
  }
794
798
  /**
795
799
  * Runs a single-frame localization: captures one frame, evaluates the result
@@ -798,24 +802,23 @@ var WebxrController = class {
798
802
  * Aligns with Unity SingleFrameLocalizationManager.LocalizeFrame().
799
803
  */
800
804
  async localizeFrame() {
801
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
802
805
  if (!this.experience) {
803
806
  throw new Error("WebXR: WebXR controller has not been initialized.");
804
807
  }
805
808
  const renderer = this.experience.getRenderer();
806
- const session = (_b = (_a = renderer.xr).getSession) == null ? void 0 : _b.call(_a);
809
+ const session = renderer.xr.getSession?.();
807
810
  if (!session) {
808
811
  throw new Error(
809
812
  "WebXR Session: No active WebXR session. Start AR before calling localizeFrame()."
810
813
  );
811
814
  }
812
815
  const cfg = this.options.client.getConfig();
813
- const confidenceCheck = (_c = cfg.confidenceCheck) != null ? _c : false;
816
+ const confidenceCheck = cfg.confidenceCheck ?? false;
814
817
  const confidenceThreshold = Math.max(
815
818
  CONFIDENCE_THRESHOLD_MIN,
816
- Math.min((_d = cfg.confidenceThreshold) != null ? _d : 0.5, CONFIDENCE_THRESHOLD_MAX)
819
+ Math.min(cfg.confidenceThreshold ?? 0.5, CONFIDENCE_THRESHOLD_MAX)
817
820
  );
818
- (_e = cfg.onLocalizationInit) == null ? void 0 : _e.call(cfg);
821
+ cfg.onLocalizationInit?.();
819
822
  this.isLocalizing = true;
820
823
  let best = null;
821
824
  let failureReason;
@@ -826,20 +829,27 @@ var WebxrController = class {
826
829
  } finally {
827
830
  this.isLocalizing = false;
828
831
  }
829
- const accepted = best && (!confidenceCheck || ((_f = best.localizeData.confidence) != null ? _f : 0) >= confidenceThreshold);
832
+ const accepted = best && (!confidenceCheck || (best.localizeData.confidence ?? 0) >= confidenceThreshold);
830
833
  if (accepted && best) {
831
- (_g = cfg.onLocalizationSuccess) == null ? void 0 : _g.call(cfg, best);
832
- if (cfg.showMesh && best.mapDetails && this.world && this.trackerSpace) {
833
- try {
834
- await this.world.ensureMeshLoaded(best.mapDetails);
835
- this.world.applyMeshTransform(best, this.trackerSpace);
836
- } catch {
834
+ cfg.onLocalizationSuccess?.(best);
835
+ if (this.world && this.trackerSpace) {
836
+ const willShowMesh = cfg.showMesh && !!best.mapDetails;
837
+ const willShowGizmo = cfg.showGizmo !== false;
838
+ if (willShowMesh || willShowGizmo) {
839
+ try {
840
+ await this.world.ensureGizmoLoaded();
841
+ if (willShowMesh) {
842
+ await this.world.ensureMeshLoaded(best.mapDetails);
843
+ }
844
+ this.world.applyMeshTransform(best, this.trackerSpace);
845
+ } catch {
846
+ }
837
847
  }
838
848
  }
839
849
  return best;
840
850
  }
841
- const reason = failureReason != null ? failureReason : !best ? "All attempts failed to produce a pose." : confidenceCheck ? `Best confidence ${(_h = best.localizeData.confidence) != null ? _h : 0} below threshold ${confidenceThreshold}.` : void 0;
842
- (_i = cfg.onLocalizationFailure) == null ? void 0 : _i.call(cfg, reason);
851
+ const reason = failureReason ?? (!best ? "All attempts failed to produce a pose." : confidenceCheck ? `Best confidence ${best.localizeData.confidence ?? 0} below threshold ${confidenceThreshold}.` : void 0);
852
+ cfg.onLocalizationFailure?.(reason);
843
853
  return null;
844
854
  }
845
855
  /**
@@ -849,12 +859,11 @@ var WebxrController = class {
849
859
  * result, apiCalled, and an optional failureReason for onLocalizationFailure.
850
860
  */
851
861
  async captureFrame() {
852
- var _a, _b, _c;
853
862
  if (!this.experience) {
854
863
  throw new Error("WebXR: WebXR controller has not been initialized.");
855
864
  }
856
865
  const renderer = this.experience.getRenderer();
857
- const session = (_b = (_a = renderer.xr).getSession) == null ? void 0 : _b.call(_a);
866
+ const session = renderer.xr.getSession?.();
858
867
  if (!session) {
859
868
  throw new Error(
860
869
  "WebXR Session: No active WebXR session. Start AR before capturing."
@@ -868,12 +877,11 @@ var WebxrController = class {
868
877
  }
869
878
  const gl = renderer.getContext();
870
879
  const cfg = this.options.client.getConfig();
871
- const timeoutMs = (_c = cfg.localizationTrackingTimeoutMs) != null ? _c : DEFAULT_TRACKING_TIMEOUT_MS;
880
+ const timeoutMs = cfg.localizationTrackingTimeoutMs ?? DEFAULT_TRACKING_TIMEOUT_MS;
872
881
  return new Promise((resolve, reject) => {
873
882
  const startTime = Date.now();
874
883
  const tryFrame = (attempt, cameraAttemptsWithPose) => {
875
884
  session.requestAnimationFrame(async (_time, xrFrame) => {
876
- var _a2, _b2, _c2, _d;
877
885
  try {
878
886
  const elapsed = Date.now() - startTime;
879
887
  const viewerPose = xrFrame.getViewerPose(referenceSpace);
@@ -898,7 +906,7 @@ var WebxrController = class {
898
906
  const gl2 = gl;
899
907
  const bindingCtor = XRWebGLBinding;
900
908
  const binding = new bindingCtor(session, gl2);
901
- const cameraTexture = (_b2 = (_a2 = binding.getCameraImage) == null ? void 0 : _a2.call(binding, xrCamera)) != null ? _b2 : null;
909
+ const cameraTexture = binding.getCameraImage?.(xrCamera) ?? null;
902
910
  if (!cameraTexture) continue;
903
911
  const width = xrCamera.width;
904
912
  const height = xrCamera.height;
@@ -939,7 +947,7 @@ var WebxrController = class {
939
947
  } finally {
940
948
  gl.bindFramebuffer(
941
949
  gl.FRAMEBUFFER,
942
- (_d = (_c2 = session.renderState.baseLayer) == null ? void 0 : _c2.framebuffer) != null ? _d : null
950
+ session.renderState.baseLayer?.framebuffer ?? null
943
951
  );
944
952
  }
945
953
  });
@@ -948,18 +956,17 @@ var WebxrController = class {
948
956
  });
949
957
  }
950
958
  dispose() {
951
- var _a, _b, _c, _d;
952
959
  if (this.resizeHandler) {
953
960
  window.removeEventListener("resize", this.resizeHandler);
954
961
  }
955
- (_a = this.experience) == null ? void 0 : _a.getRenderer().setAnimationLoop(null);
956
- (_b = this.experience) == null ? void 0 : _b.dispose();
962
+ this.experience?.getRenderer().setAnimationLoop(null);
963
+ this.experience?.dispose();
957
964
  this.experience = null;
958
- (_c = this.world) == null ? void 0 : _c.dispose();
965
+ this.world?.dispose();
959
966
  this.world = null;
960
967
  this.trackingLossFrames = 0;
961
968
  this.hadTrackingLoss = false;
962
- if ((_d = this.arButton) == null ? void 0 : _d.parentElement) {
969
+ if (this.arButton?.parentElement) {
963
970
  this.arButton.parentElement.removeChild(this.arButton);
964
971
  }
965
972
  this.arButton = null;