@splnlss/3d-story-viewer 0.8.3 → 0.8.5

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,7 +1,14 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __typeError = (msg) => {
3
+ throw TypeError(msg);
4
+ };
2
5
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
6
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- var _a2;
7
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
8
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
11
+ var _a2, _destinationTileTimeout;
5
12
  import { S as ShaderChunk, M as Matrix4, V as Vector3, O as Object3D, a as Vector2, b as Mesh, P as PlaneGeometry, c as ShaderMaterial, R as Ray, E as EventDispatcher$1, d as Plane, e as Raycaster, C as Clock, Q as Quaternion, f as MathUtils, T as TrianglesDrawMode, g as TriangleFanDrawMode, h as TriangleStripDrawMode, L as Loader, i as LoaderUtils, F as FileLoader, j as MeshPhysicalMaterial, k as Color, l as LinearSRGBColorSpace, m as SRGBColorSpace, n as SpotLight, o as PointLight, D as DirectionalLight, I as InstancedMesh, p as InstancedBufferAttribute, B as BufferGeometry, q as TextureLoader, r as ImageBitmapLoader, s as BufferAttribute, t as InterleavedBuffer, u as LinearMipmapLinearFilter, N as NearestMipmapLinearFilter, v as LinearMipmapNearestFilter, w as NearestMipmapNearestFilter, x as LinearFilter, y as NearestFilter, z as RepeatWrapping, A as MirroredRepeatWrapping, G as ClampToEdgeWrapping, H as PointsMaterial, J as Material, K as LineBasicMaterial, U as MeshStandardMaterial, W as DoubleSide, X as MeshBasicMaterial, Y as PropertyBinding, Z as SkinnedMesh, _ as LineSegments, $ as Line, a0 as LineLoop, a1 as Points, a2 as Group$1, a3 as PerspectiveCamera, a4 as OrthographicCamera, a5 as Skeleton, a6 as AnimationClip, a7 as Bone, a8 as InterpolateDiscrete, a9 as InterpolateLinear, aa as InterleavedBufferAttribute, ab as Texture, ac as VectorKeyframeTrack, ad as NumberKeyframeTrack, ae as QuaternionKeyframeTrack, af as ColorManagement, ag as FrontSide, ah as Interpolant, ai as Box3, aj as Sphere, ak as Euler, al as Spherical, am as LoadingManager, an as Frustum, ao as DefaultLoadingManager, ap as Matrix3, aq as TextureUtils, ar as CompressedCubeTexture, as as CompressedArrayTexture, at as CompressedTexture, au as NoColorSpace, av as RGBA_PVRTC_2BPPV1_Format, aw as RGBA_PVRTC_4BPPV1_Format, ax as RGBA_BPTC_Format, ay as RED_GREEN_RGTC2_Format, az as SIGNED_RED_GREEN_RGTC2_Format, aA as RED_RGTC1_Format, aB as SIGNED_RED_RGTC1_Format, aC as RGBA_S3TC_DXT5_Format, aD as RGB_S3TC_DXT1_Format, aE as RGBA_S3TC_DXT1_Format, aF as RGBA_ASTC_6x6_Format, aG as RGBA_ASTC_4x4_Format, aH as SIGNED_RG11_EAC_Format, aI as RG11_EAC_Format, aJ as SIGNED_R11_EAC_Format, aK as R11_EAC_Format, aL as RGB_ETC2_Format, aM as RGBA_ETC2_EAC_Format, aN as RGBFormat, aO as RedFormat, aP as RGFormat, aQ as RGBAFormat, aR as UnsignedByteType, aS as HalfFloatType, aT as UnsignedInt101111Type, aU as UnsignedInt5999Type, aV as UnsignedShortType, aW as FloatType, aX as DataTexture, aY as Data3DTexture, aZ as RGB_PVRTC_4BPPV1_Format, a_ as RGB_ETC1_Format, a$ as RGB_BPTC_UNSIGNED_Format, b0 as REVISION, b1 as TextureSource, b2 as ImageUtils, b3 as Scene, b4 as ecefToGeodeticPosition, b5 as getEnuBasis, b6 as Float32BufferAttribute, b7 as LinearMipMapLinearFilter, b8 as Triangle, b9 as CanvasTexture, ba as WebGLRenderer, bb as WebGLRenderTarget, bc as OneFactor, bd as ZeroFactor, be as CustomBlending, bf as Box2, bg as Matrix2, bh as Vector4, bi as validateGeodeticPosition, bj as validateRotation, bk as geodeticToEcefPosition, bl as DataTextureLoader, bm as DataUtils, bn as BackSide, bo as BoxGeometry, bp as normalizeLayerOffset, bq as geodeticOffsetToEcefDelta, br as validateTuple, bs as validateScale, bt as enuToEcefDelta, bu as RingGeometry, bv as AgXToneMapping, bw as EquirectangularReflectionMapping, bx as requireFiniteNumber } from "./index-a8PLKOvo.js";
6
13
  var bayer_dither_hash_pars_default$1 = "#ifdef USE_HASH\nuniform float hashOpacity;varying float vCameraDistance;float bayerDitherPattern(vec2 p){float bayerMatrix[16];bayerMatrix[0]=0.0;bayerMatrix[1]=8.0;bayerMatrix[2]=2.0;bayerMatrix[3]=10.0;bayerMatrix[4]=12.0;bayerMatrix[5]=4.0;bayerMatrix[6]=14.0;bayerMatrix[7]=6.0;bayerMatrix[8]=3.0;bayerMatrix[9]=11.0;bayerMatrix[10]=1.0;bayerMatrix[11]=9.0;bayerMatrix[12]=15.0;bayerMatrix[13]=7.0;bayerMatrix[14]=13.0;bayerMatrix[15]=5.0;int x=int(mod(p.x,4.0));int y=int(mod(p.y,4.0));int index=x+y*4;return bayerMatrix[index]/16.0;}\n#endif\n";
7
14
  var bayer_dither_hash_default$1 = "#ifdef USE_HASH\nfloat hashAmount=smoothstep(5e4,1e2,vCameraDistance)*0.75+0.1;float ditherValue=bayerDitherPattern(gl_FragCoord.xy);if(hashAmount<ditherValue){discard;}\n#endif\n";
@@ -156,7 +163,7 @@ class CSS2DRenderer {
156
163
  }
157
164
  let sparkPromise = null;
158
165
  function loadSpark() {
159
- sparkPromise ?? (sparkPromise = import("./spark.module-CHPihKhu.js").catch((error) => {
166
+ sparkPromise ?? (sparkPromise = import("./spark.module-SbwV3up9.js").catch((error) => {
160
167
  sparkPromise = null;
161
168
  throw error;
162
169
  }));
@@ -6177,7 +6184,7 @@ class GlobeControls extends EnvironmentControls {
6177
6184
  }
6178
6185
  }
6179
6186
  _updateRotation(...args) {
6180
- if (this._rotationMode === 1 || this._isNearControls()) {
6187
+ if (this._rotationMode === 1 || this._isNearControls() || this.rotationSpeed !== 0 && this.pointerTracker.getPointerType() === "mouse" && this.pointerTracker.isRightClicked()) {
6181
6188
  this._rotationMode = 1;
6182
6189
  super._updateRotation(...args);
6183
6190
  } else {
@@ -7711,11 +7718,10 @@ class TileDecoders {
7711
7718
  this.disposed = false;
7712
7719
  }
7713
7720
  getDraco() {
7714
- var _a3, _b2;
7715
7721
  if (this.disposed) throw new Error("Tile decoders disposed");
7716
7722
  if (!this.draco) {
7717
7723
  const loader = new DRACOLoader();
7718
- if ((_b2 = (_a3 = globalThis.navigator) == null ? void 0 : _a3.userAgent) == null ? void 0 : _b2.includes("OculusBrowser/")) loader.decoderConfig.type = "js";
7724
+ loader.decoderConfig.type = "js";
7719
7725
  this.draco = managedLoader(loader, "_initDecoder", "decodeGeometry", "decoderPending");
7720
7726
  }
7721
7727
  return this.draco;
@@ -13195,14 +13201,15 @@ function applyGrayscale(material) {
13195
13201
  class GlobeManager extends EventDispatcher {
13196
13202
  constructor(scene, camera, renderer, options = {}) {
13197
13203
  super();
13204
+ __privateAdd(this, _destinationTileTimeout, null);
13198
13205
  this.scene = scene;
13199
13206
  this.camera = camera;
13200
13207
  this.renderer = renderer;
13201
13208
  this.tiles = null;
13202
13209
  this.destinationTileCamera = null;
13203
13210
  this.destinationTileResolution = 0;
13204
- this.destinationTileTimeout = null;
13205
13211
  this.previousAutoDisableRendererCulling = null;
13212
+ this.parseQueueTimer = null;
13206
13213
  this.dracoLoader = null;
13207
13214
  this.ownsDecoders = !options.decoders;
13208
13215
  this.decoders = options.decoders ?? new TileDecoders(renderer);
@@ -13213,6 +13220,7 @@ class GlobeManager extends EventDispatcher {
13213
13220
  }
13214
13221
  }
13215
13222
  initTiles() {
13223
+ this.stopParseQueuePump();
13216
13224
  if (this.tiles) {
13217
13225
  this.setDestinationTilePrefetch(null);
13218
13226
  this.scene.remove(this.tiles.group);
@@ -13236,6 +13244,19 @@ class GlobeManager extends EventDispatcher {
13236
13244
  this.scene.add(this.tiles.group);
13237
13245
  updateTilesCamera(this.tiles, this.camera, this.renderer);
13238
13246
  this.attachTileLoadListener();
13247
+ this.startParseQueuePump();
13248
+ }
13249
+ startParseQueuePump() {
13250
+ this.stopParseQueuePump();
13251
+ this.parseQueueTimer = setInterval(() => {
13252
+ var _a3;
13253
+ const queue = (_a3 = this.tiles) == null ? void 0 : _a3.parseQueue;
13254
+ if ((queue == null ? void 0 : queue.items.length) > 0 && queue.currJobs < queue.maxJobs) queue.tryRunJobs();
13255
+ }, 100);
13256
+ }
13257
+ stopParseQueuePump() {
13258
+ if (this.parseQueueTimer !== null) clearInterval(this.parseQueueTimer);
13259
+ this.parseQueueTimer = null;
13239
13260
  }
13240
13261
  attachTileLoadListener() {
13241
13262
  this.tiles.addEventListener("load-model", ({ scene }) => {
@@ -13252,6 +13273,8 @@ class GlobeManager extends EventDispatcher {
13252
13273
  }
13253
13274
  /** The renderer shares one cache and request scheduler between both registered cameras. */
13254
13275
  setDestinationTilePrefetch(target) {
13276
+ const timeoutMs = (target == null ? void 0 : target.timeoutMs) ?? 12e3;
13277
+ if (target && (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 3e4)) return;
13255
13278
  this.clearDestinationTilePrefetch();
13256
13279
  if (!target || !this.tiles) return;
13257
13280
  let position;
@@ -13275,7 +13298,7 @@ class GlobeManager extends EventDispatcher {
13275
13298
  this.destinationTileResolution = target.resolutionPixels;
13276
13299
  this.tiles.setCamera(camera);
13277
13300
  this.updateDestinationTileResolution();
13278
- this.destinationTileTimeout = setTimeout(() => this.clearDestinationTilePrefetch(), 12e3);
13301
+ __privateSet(this, _destinationTileTimeout, setTimeout(() => this.clearDestinationTilePrefetch(), timeoutMs));
13279
13302
  }
13280
13303
  updateDestinationTileResolution() {
13281
13304
  var _a3, _b2;
@@ -13287,8 +13310,8 @@ class GlobeManager extends EventDispatcher {
13287
13310
  this.tiles.setResolution(this.destinationTileCamera, pixels, pixels);
13288
13311
  }
13289
13312
  clearDestinationTilePrefetch() {
13290
- if (this.destinationTileTimeout !== null) clearTimeout(this.destinationTileTimeout);
13291
- this.destinationTileTimeout = null;
13313
+ if (__privateGet(this, _destinationTileTimeout) !== null) clearTimeout(__privateGet(this, _destinationTileTimeout));
13314
+ __privateSet(this, _destinationTileTimeout, null);
13292
13315
  if (this.destinationTileCamera && this.tiles) {
13293
13316
  this.tiles.deleteCamera(this.destinationTileCamera);
13294
13317
  this.tiles.autoDisableRendererCulling = this.previousAutoDisableRendererCulling;
@@ -13299,12 +13322,15 @@ class GlobeManager extends EventDispatcher {
13299
13322
  }
13300
13323
  update() {
13301
13324
  if (!this.tiles) return;
13325
+ const parseQueue = this.tiles.parseQueue;
13326
+ if ((parseQueue == null ? void 0 : parseQueue.items.length) > 0 && parseQueue.currJobs < parseQueue.maxJobs) parseQueue.tryRunJobs();
13302
13327
  updateTilesCamera(this.tiles, this.camera, this.renderer);
13303
13328
  this.updateDestinationTileResolution();
13304
13329
  this.tiles.errorTarget = 20;
13305
13330
  this.tiles.update();
13306
13331
  }
13307
13332
  dispose() {
13333
+ this.stopParseQueuePump();
13308
13334
  this.clearDestinationTilePrefetch();
13309
13335
  if (this.tiles) {
13310
13336
  this.scene.remove(this.tiles.group);
@@ -13315,6 +13341,7 @@ class GlobeManager extends EventDispatcher {
13315
13341
  this.listeners = {};
13316
13342
  }
13317
13343
  }
13344
+ _destinationTileTimeout = new WeakMap();
13318
13345
  var Easing = Object.freeze({
13319
13346
  Linear: Object.freeze({
13320
13347
  None: function(amount) {
@@ -14367,86 +14394,32 @@ function RGBEPromise(url, options = {}) {
14367
14394
  );
14368
14395
  });
14369
14396
  }
14370
- var stats_min$1 = { exports: {} };
14371
- var stats_min = stats_min$1.exports;
14372
- var hasRequiredStats_min;
14373
- function requireStats_min() {
14374
- if (hasRequiredStats_min) return stats_min$1.exports;
14375
- hasRequiredStats_min = 1;
14376
- (function(module, exports2) {
14377
- (function(f2, e) {
14378
- module.exports = e();
14379
- })(stats_min, function() {
14380
- var f2 = function() {
14381
- function e(a3) {
14382
- c3.appendChild(a3.dom);
14383
- return a3;
14384
- }
14385
- function u2(a3) {
14386
- for (var d2 = 0; d2 < c3.children.length; d2++) c3.children[d2].style.display = d2 === a3 ? "block" : "none";
14387
- l3 = a3;
14388
- }
14389
- var l3 = 0, c3 = document.createElement("div");
14390
- c3.style.cssText = "position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";
14391
- c3.addEventListener("click", function(a3) {
14392
- a3.preventDefault();
14393
- u2(++l3 % c3.children.length);
14394
- }, false);
14395
- var k2 = (performance || Date).now(), g2 = k2, a2 = 0, r2 = e(new f2.Panel("FPS", "#0ff", "#002")), h2 = e(new f2.Panel("MS", "#0f0", "#020"));
14396
- if (self.performance && self.performance.memory) var t2 = e(new f2.Panel("MB", "#f08", "#201"));
14397
- u2(0);
14398
- return { REVISION: 16, dom: c3, addPanel: e, showPanel: u2, begin: function() {
14399
- k2 = (performance || Date).now();
14400
- }, end: function() {
14401
- a2++;
14402
- var c4 = (performance || Date).now();
14403
- h2.update(c4 - k2, 200);
14404
- if (c4 > g2 + 1e3 && (r2.update(1e3 * a2 / (c4 - g2), 100), g2 = c4, a2 = 0, t2)) {
14405
- var d2 = performance.memory;
14406
- t2.update(d2.usedJSHeapSize / 1048576, d2.jsHeapSizeLimit / 1048576);
14407
- }
14408
- return c4;
14409
- }, update: function() {
14410
- k2 = this.end();
14411
- }, domElement: c3, setMode: u2 };
14412
- };
14413
- f2.Panel = function(e, f3, l3) {
14414
- var c3 = Infinity, k2 = 0, g2 = Math.round, a2 = g2(window.devicePixelRatio || 1), r2 = 80 * a2, h2 = 48 * a2, t2 = 3 * a2, v2 = 2 * a2, d2 = 3 * a2, m2 = 15 * a2, n2 = 74 * a2, p2 = 30 * a2, q2 = document.createElement("canvas");
14415
- q2.width = r2;
14416
- q2.height = h2;
14417
- q2.style.cssText = "width:80px;height:48px";
14418
- var b2 = q2.getContext("2d");
14419
- b2.font = "bold " + 9 * a2 + "px Helvetica,Arial,sans-serif";
14420
- b2.textBaseline = "top";
14421
- b2.fillStyle = l3;
14422
- b2.fillRect(0, 0, r2, h2);
14423
- b2.fillStyle = f3;
14424
- b2.fillText(e, t2, v2);
14425
- b2.fillRect(d2, m2, n2, p2);
14426
- b2.fillStyle = l3;
14427
- b2.globalAlpha = 0.9;
14428
- b2.fillRect(d2, m2, n2, p2);
14429
- return { dom: q2, update: function(h3, w2) {
14430
- c3 = Math.min(c3, h3);
14431
- k2 = Math.max(k2, h3);
14432
- b2.fillStyle = l3;
14433
- b2.globalAlpha = 1;
14434
- b2.fillRect(0, 0, r2, m2);
14435
- b2.fillStyle = f3;
14436
- b2.fillText(g2(h3) + " " + e + " (" + g2(c3) + "-" + g2(k2) + ")", t2, v2);
14437
- b2.drawImage(q2, d2 + a2, m2, n2 - a2, p2, d2, m2, n2 - a2, p2);
14438
- b2.fillRect(d2 + n2 - a2, m2, a2, p2);
14439
- b2.fillStyle = l3;
14440
- b2.globalAlpha = 0.9;
14441
- b2.fillRect(d2 + n2 - a2, m2, a2, g2((1 - h3 / w2) * p2));
14442
- } };
14443
- };
14444
- return f2;
14445
- });
14446
- })(stats_min$1);
14447
- return stats_min$1.exports;
14397
+ const finite = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
14398
+ function readLoadingDiagnostics(viewer) {
14399
+ var _a3, _b2, _c, _d, _e, _f, _g, _h;
14400
+ const tiles = (_b2 = (_a3 = viewer.globeManager) == null ? void 0 : _a3.tiles) == null ? void 0 : _b2.stats;
14401
+ const pager = (_c = viewer.sparkRenderer) == null ? void 0 : _c.pager;
14402
+ const pendingTiles = tiles && [tiles.queued, tiles.downloading, tiles.parsing].map(finite);
14403
+ let pendingRad = null;
14404
+ if (pager && [pager.fetchPriority, pager.fetchers, pager.fetched].every(Array.isArray)) {
14405
+ const pending = /* @__PURE__ */ new Map();
14406
+ for (const { splats, chunk } of [...pager.fetchPriority, ...pager.fetchers, ...pager.fetched]) {
14407
+ if (!splats || !Number.isInteger(chunk) || ((_d = pager.getSplatsChunk) == null ? void 0 : _d.call(pager, splats, chunk))) continue;
14408
+ if (!pending.has(splats)) pending.set(splats, /* @__PURE__ */ new Set());
14409
+ pending.get(splats).add(chunk);
14410
+ }
14411
+ pendingRad = [...pending.values()].reduce((sum, chunks) => sum + chunks.size, 0);
14412
+ }
14413
+ return {
14414
+ fps: finite(viewer.diagnosticFps),
14415
+ tilesVisible: finite(tiles == null ? void 0 : tiles.visible),
14416
+ tilesPending: (pendingTiles == null ? void 0 : pendingTiles.every((value) => value !== null)) ? pendingTiles.reduce((sum, value) => sum + value, 0) : null,
14417
+ tilesFailed: finite(tiles == null ? void 0 : tiles.failed),
14418
+ radPages: finite((_e = pager == null ? void 0 : pager.pageLru) == null ? void 0 : _e.size),
14419
+ radPending: pendingRad,
14420
+ gpuTextures: finite((_h = (_g = (_f = viewer.renderer) == null ? void 0 : _f.info) == null ? void 0 : _g.memory) == null ? void 0 : _h.textures)
14421
+ };
14448
14422
  }
14449
- requireStats_min();
14450
14423
  function computeUpVector(position, target) {
14451
14424
  const forward = new Vector3().subVectors(target, position).normalize();
14452
14425
  const referenceUp = position.clone().normalize();
@@ -14615,6 +14588,7 @@ class TilesLayer extends ContentLayer {
14615
14588
  super();
14616
14589
  this.type = "TilesLayer";
14617
14590
  this.isTilesLayer = true;
14591
+ this.disposed = false;
14618
14592
  const renderOrder = (options == null ? void 0 : options.renderOrder) ?? 0;
14619
14593
  const implicit = (options == null ? void 0 : options.implicit) ?? false;
14620
14594
  const overlayMode = (options == null ? void 0 : options.blendeMode) == "overlay" ? true : false;
@@ -14654,6 +14628,7 @@ class TilesLayer extends ContentLayer {
14654
14628
  updateTilesCamera(tiles, this.camera, this.renderer);
14655
14629
  tiles.addEventListener("load-model", (event) => {
14656
14630
  var _a3;
14631
+ if (this.disposed) return;
14657
14632
  if (hasOffset && !offsetApplied) {
14658
14633
  try {
14659
14634
  const bounds = new Sphere();
@@ -14707,6 +14682,8 @@ class TilesLayer extends ContentLayer {
14707
14682
  }
14708
14683
  }
14709
14684
  dispose() {
14685
+ if (this.disposed) return;
14686
+ this.disposed = true;
14710
14687
  super.dispose();
14711
14688
  if (this.tiles) {
14712
14689
  this.tiles.dispose();
@@ -14716,23 +14693,392 @@ class TilesLayer extends ContentLayer {
14716
14693
  if (this.ownsDecoders) this.decoders.dispose();
14717
14694
  }
14718
14695
  }
14696
+ var MeshoptDecoder = function() {
14697
+ var wasm_base = "b9H79Tebbbe8Fv9Gbb9Gvuuuuueu9Giuuub9Geueu9Giuuueuixkbeeeddddillviebeoweuecj:Gdkr;Neqo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbeY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVbdE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbiL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtblK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949WboY9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVJ9V29VVbrl79IV9Rbwq:VZkdbk:XYi5ud9:du8Jjjjjbcj;kb9Rgv8Kjjjjbc9:hodnalTmbcuhoaiRbbgrc;WeGc:Ge9hmbarcsGgwce0mbc9:hoalcufadcd4cbawEgDadfgrcKcaawEgqaraq0Egk6mbaicefhxcj;abad9Uc;WFbGcjdadca0EhmaialfgPar9Rgoadfhsavaoadz:jjjjbgzceVhHcbhOdndninaeaO9nmeaPax9RaD6mdamaeaO9RaOamfgoae6EgAcsfglc9WGhCabaOad2fhXaAcethQaxaDfhiaOaeaoaeao6E9RhLalcl4cifcd4hKazcj;cbfaAfhYcbh8AazcjdfhEaHh3incbh5dnawTmbaxa8Acd4fRbbh5kcbh8Eazcj;cbfhqinaih8Fdndndndna5a8Ecet4ciGgoc9:fPdebdkaPa8F9RaA6mrazcj;cbfa8EaA2fa8FaAz:jjjjb8Aa8FaAfhixdkazcj;cbfa8EaA2fcbaAz:kjjjb8Aa8FhixekaPa8F9RaK6mva8FaKfhidnaCTmbaPai9RcK6mbaocdtc:q:G:cjbfcj:G:cjbawEhaczhrcbhlinargoc9Wfghaqfhrdndndndndndnaaa8Fahco4fRbbalcoG4ciGcdtfydbPDbedvivvvlvkar9cb83bwar9cb83bbxlkarcbaiRbdai8Xbb9c:c:qj:bw9:9c:q;c1:I1e:d9c:b:c:e1z9:gg9cjjjjjz:dg8J9qE86bbaqaofgrcGfcbaicdfa8J9c8N1:NfghRbbag9cjjjjjw:dg8J9qE86bbarcVfcbaha8J9c8M1:NfghRbbag9cjjjjjl:dg8J9qE86bbarc7fcbaha8J9c8L1:NfghRbbag9cjjjjjd:dg8J9qE86bbarctfcbaha8J9c8K1:NfghRbbag9cjjjjje:dg8J9qE86bbarc91fcbaha8J9c8J1:NfghRbbag9cjjjj;ab:dg8J9qE86bbarc4fcbaha8J9cg1:NfghRbbag9cjjjja:dg8J9qE86bbarc93fcbaha8J9ch1:NfghRbbag9cjjjjz:dgg9qE86bbarc94fcbahag9ca1:NfghRbbai8Xbe9c:c:qj:bw9:9c:q;c1:I1e:d9c:b:c:e1z9:gg9cjjjjjz:dg8J9qE86bbarc95fcbaha8J9c8N1:NfgiRbbag9cjjjjjw:dg8J9qE86bbarc96fcbaia8J9c8M1:NfgiRbbag9cjjjjjl:dg8J9qE86bbarc97fcbaia8J9c8L1:NfgiRbbag9cjjjjjd:dg8J9qE86bbarc98fcbaia8J9c8K1:NfgiRbbag9cjjjjje:dg8J9qE86bbarc99fcbaia8J9c8J1:NfgiRbbag9cjjjj;ab:dg8J9qE86bbarc9:fcbaia8J9cg1:NfgiRbbag9cjjjja:dg8J9qE86bbarcufcbaia8J9ch1:NfgiRbbag9cjjjjz:dgg9qE86bbaiag9ca1:NfhixikaraiRblaiRbbghco4g8Ka8KciSg8KE86bbaqaofgrcGfaiclfa8Kfg8KRbbahcl4ciGg8La8LciSg8LE86bbarcVfa8Ka8Lfg8KRbbahcd4ciGg8La8LciSg8LE86bbarc7fa8Ka8Lfg8KRbbahciGghahciSghE86bbarctfa8Kahfg8KRbbaiRbeghco4g8La8LciSg8LE86bbarc91fa8Ka8Lfg8KRbbahcl4ciGg8La8LciSg8LE86bbarc4fa8Ka8Lfg8KRbbahcd4ciGg8La8LciSg8LE86bbarc93fa8Ka8Lfg8KRbbahciGghahciSghE86bbarc94fa8Kahfg8KRbbaiRbdghco4g8La8LciSg8LE86bbarc95fa8Ka8Lfg8KRbbahcl4ciGg8La8LciSg8LE86bbarc96fa8Ka8Lfg8KRbbahcd4ciGg8La8LciSg8LE86bbarc97fa8Ka8Lfg8KRbbahciGghahciSghE86bbarc98fa8KahfghRbbaiRbigico4g8Ka8KciSg8KE86bbarc99faha8KfghRbbaicl4ciGg8Ka8KciSg8KE86bbarc9:faha8KfghRbbaicd4ciGg8Ka8KciSg8KE86bbarcufaha8KfgrRbbaiciGgiaiciSgiE86bbaraifhixdkaraiRbwaiRbbghcl4g8Ka8KcsSg8KE86bbaqaofgrcGfaicwfa8Kfg8KRbbahcsGghahcsSghE86bbarcVfa8KahfghRbbaiRbeg8Kcl4g8La8LcsSg8LE86bbarc7faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarctfaha8KfghRbbaiRbdg8Kcl4g8La8LcsSg8LE86bbarc91faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc4faha8KfghRbbaiRbig8Kcl4g8La8LcsSg8LE86bbarc93faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc94faha8KfghRbbaiRblg8Kcl4g8La8LcsSg8LE86bbarc95faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc96faha8KfghRbbaiRbvg8Kcl4g8La8LcsSg8LE86bbarc97faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc98faha8KfghRbbaiRbog8Kcl4g8La8LcsSg8LE86bbarc99faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc9:faha8KfghRbbaiRbrgicl4g8Ka8KcsSg8KE86bbarcufaha8KfgrRbbaicsGgiaicsSgiE86bbaraifhixekarai8Pbw83bwarai8Pbb83bbaiczfhikdnaoaC9pmbalcdfhlaoczfhraPai9RcL0mekkaoaC6moaimexokaCmva8FTmvkaqaAfhqa8Ecefg8Ecl9hmbkdndndndnawTmbasa8Acd4fRbbgociGPlbedrbkaATmdaza8Afh8Fazcj;cbfhhcbh8EaEhaina8FRbbhraahocbhlinaoahalfRbbgqce4cbaqceG9R7arfgr86bbaoadfhoaAalcefgl9hmbkaacefhaa8Fcefh8FahaAfhha8Ecefg8Ecl9hmbxikkaATmeaza8Afhaazcj;cbfhhcbhoceh8EaYh8FinaEaofhlaa8Vbbhrcbhoinala8FaofRbbcwtahaofRbbgqVc;:FiGce4cbaqceG9R7arfgr87bbaladfhlaLaocefgofmbka8FaQfh8FcdhoaacdfhaahaQfhha8EceGhlcbh8EalmbxdkkaATmbaocl4h8Eaza8AfRbbhqcwhoa3hlinalRbbaotaqVhqalcefhlaocwfgoca9hmbkcbhhaEh8FaYhainazcj;cbfahfRbbhrcwhoaahlinalRbbaotarVhralaAfhlaocwfgoca9hmbkara8E94aq7hqcbhoa8Fhlinalaqao486bbalcefhlaocwfgoca9hmbka8Fadfh8FaacefhaahcefghaA9hmbkkaEclfhEa3clfh3a8Aclfg8Aad6mbkaXazcjdfaAad2z:jjjjb8AazazcjdfaAcufad2fadz:jjjjb8AaAaOfhOaihxaimbkc9:hoxdkcbc99aPax9RakSEhoxekc9:hokavcj;kbf8Kjjjjbaok:ysezu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnalaeci9UgrcHf6mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgDce0mbavc;abfcFecjez:kjjjb8Aav9cu83iUav9cu83i8Wav9cu83iyav9cu83iaav9cu83iKav9cu83izav9cu83iwav9cu83ibaialfc9WfhqaicefgwarfhldnaeTmbcmcsaDceSEhkcbhxcbhmcbhrcbhicbhoindnalaq9nmbc9:hoxikdndnawRbbgDc;Ve0mbavc;abfaoaDcu7gPcl4fcsGcitfgsydlhzasydbhHdndnaDcsGgsak9pmbavaiaPfcsGcdtfydbaxasEhDaxasTgOfhxxekdndnascsSmbcehOasc987asamffcefhDxekalcefhDal8SbbgscFeGhPdndnascu9mmbaDhlxekalcvfhlaPcFbGhPcrhsdninaD8SbbgOcFbGastaPVhPaOcu9kmeaDcefhDascrfgsc8J9hmbxdkkaDcefhlkcehOaPce4cbaPceG9R7amfhDkaDhmkavc;abfaocitfgsaDBdbasazBdlavaicdtfaDBdbavc;abfaocefcsGcitfgsaHBdbasaDBdlaocdfhoaOaifhidnadcd9hmbabarcetfgsaH87ebasclfaD87ebascdfaz87ebxdkabarcdtfgsaHBdbascwfaDBdbasclfazBdbxekdnaDcpe0mbavaiaqaDcsGfRbbgscl4gP9RcsGcdtfydbaxcefgOaPEhDavaias9RcsGcdtfydbaOaPTgzfgOascsGgPEhsaPThPdndnadcd9hmbabarcetfgHax87ebaHclfas87ebaHcdfaD87ebxekabarcdtfgHaxBdbaHcwfasBdbaHclfaDBdbkavaicdtfaxBdbavc;abfaocitfgHaDBdbaHaxBdlavaicefgicsGcdtfaDBdbavc;abfaocefcsGcitfgHasBdbaHaDBdlavaiazfgicsGcdtfasBdbavc;abfaocdfcsGcitfgDaxBdbaDasBdlaocifhoaiaPfhiaOaPfhxxekaxcbalRbbgsEgHaDc;:eSgDfhOascsGhAdndnascl4gCmbaOcefhzxekaOhzavaiaC9RcsGcdtfydbhOkdndnaAmbazcefhxxekazhxavaias9RcsGcdtfydbhzkdndnaDTmbalcefhDxekalcdfhDal8SbegPcFeGhsdnaPcu9kmbalcofhHascFbGhscrhldninaD8SbbgPcFbGaltasVhsaPcu9kmeaDcefhDalcrfglc8J9hmbkaHhDxekaDcefhDkasce4cbasceG9R7amfgmhHkdndnaCcsSmbaDhsxekaDcefhsaD8SbbglcFeGhPdnalcu9kmbaDcvfhOaPcFbGhPcrhldninas8SbbgDcFbGaltaPVhPaDcu9kmeascefhsalcrfglc8J9hmbkaOhsxekascefhskaPce4cbaPceG9R7amfgmhOkdndnaAcsSmbashlxekascefhlas8SbbgDcFeGhPdnaDcu9kmbascvfhzaPcFbGhPcrhDdninal8SbbgscFbGaDtaPVhPascu9kmealcefhlaDcrfgDc8J9hmbkazhlxekalcefhlkaPce4cbaPceG9R7amfgmhzkdndnadcd9hmbabarcetfgDaH87ebaDclfaz87ebaDcdfaO87ebxekabarcdtfgDaHBdbaDcwfazBdbaDclfaOBdbkavc;abfaocitfgDaOBdbaDaHBdlavaicdtfaHBdbavc;abfaocefcsGcitfgDazBdbaDaOBdlavaicefgicsGcdtfaOBdbavc;abfaocdfcsGcitfgDaHBdbaDazBdlavaiaCTaCcsSVfgicsGcdtfazBdbaiaATaAcsSVfhiaocifhokawcefhwaocsGhoaicsGhiarcifgrae6mbkkcbc99alaqSEhokavc;aef8Kjjjjbaok:clevu8Jjjjjbcz9Rhvdnalaecvf9pmbc9:skdnaiRbbc;:eGc;qeSmbcuskav9cb83iwaicefhoaialfc98fhrdnaeTmbdnadcdSmbcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcdtfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgiBdbalaiBdbawcefgwae9hmbxdkkcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcetfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgi87ebalaiBdbawcefgwae9hmbkkcbc99aoarSEk:Lvoeue99dud99eud99dndnadcl9hmbaeTmeindndnabcdfgd8Sbb:Yab8Sbbgi:Ygl:l:tabcefgv8Sbbgo:Ygr:l:tgwJbb;:9cawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai86bbdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad86bbdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad86bbabclfhbaecufgembxdkkaeTmbindndnabclfgd8Ueb:Yab8Uebgi:Ygl:l:tabcdfgv8Uebgo:Ygr:l:tgwJb;:FSawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai87ebdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad87ebdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad87ebabcwfhbaecufgembkkk:4ioiue99dud99dud99dnaeTmbcbhiabhlindndnal8Uebgv:YgoJ:ji:1Salcof8UebgrciVgw:Y:vgDNJbbbZJbbb:;avcu9kEMgq:lJbbb9p9DTmbaq:Ohkxekcjjjj94hkkalclf8Uebhvalcdf8UebhxalarcefciGcetfak87ebdndnax:YgqaDNJbbbZJbbb:;axcu9kEMgm:lJbbb9p9DTmbam:Ohxxekcjjjj94hxkabaiarciGgkfcd7cetfax87ebdndnav:YgmaDNJbbbZJbbb:;avcu9kEMgP:lJbbb9p9DTmbaP:Ohvxekcjjjj94hvkalarcufciGcetfav87ebdndnawaw2:ZgPaPMaoaoN:taqaqN:tamamN:tgoJbbbbaoJbbbb9GE:raDNJbbbZMgD:lJbbb9p9DTmbaD:Ohrxekcjjjj94hrkalakcetfar87ebalcwfhlaiclfhiaecufgembkkk9mbdnadcd4ae2gdTmbinababydbgecwtcw91:Yaece91cjjj98Gcjjj;8if::NUdbabclfhbadcufgdmbkkk:Tvirud99eudndnadcl9hmbaeTmeindndnabRbbgiabcefgl8Sbbgvabcdfgo8Sbbgrf9R:YJbbuJabcifgwRbbgdce4adVgDcd4aDVgDcl4aDVgD:Z:vgqNJbbbZMgk:lJbbb9p9DTmbak:Ohxxekcjjjj94hxkaoax86bbdndnaraif:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohoxekcjjjj94hokalao86bbdndnavaifar9R:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohixekcjjjj94hikabai86bbdndnaDadcetGadceGV:ZaqNJbbbZMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkawad86bbabclfhbaecufgembxdkkaeTmbindndnab8Vebgiabcdfgl8Uebgvabclfgo8Uebgrf9R:YJbFu9habcofgw8Vebgdce4adVgDcd4aDVgDcl4aDVgDcw4aDVgD:Z:vgqNJbbbZMgk:lJbbb9p9DTmbak:Ohxxekcjjjj94hxkaoax87ebdndnaraif:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohoxekcjjjj94hokalao87ebdndnavaifar9R:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohixekcjjjj94hikabai87ebdndnaDadcetGadceGV:ZaqNJbbbZMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkawad87ebabcwfhbaecufgembkkk9teiucbcbyd:K:G:cjbgeabcifc98GfgbBd:K:G:cjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaik;LeeeudndnaeabVciGTmbabhixekdndnadcz9pmbabhixekabhiinaiaeydbBdbaiclfaeclfydbBdbaicwfaecwfydbBdbaicxfaecxfydbBdbaeczfheaiczfhiadc9Wfgdcs0mbkkadcl6mbinaiaeydbBdbaeclfheaiclfhiadc98fgdci0mbkkdnadTmbinaiaeRbb86bbaicefhiaecefheadcufgdmbkkabk;aeedudndnabciGTmbabhixekaecFeGc:b:c:ew2hldndnadcz9pmbabhixekabhiinaialBdbaicxfalBdbaicwfalBdbaiclfalBdbaiczfhiadc9Wfgdcs0mbkkadcl6mbinaialBdbaiclfhiadc98fgdci0mbkkdnadTmbinaiae86bbaicefhiadcufgdmbkkabkk83dbcj:Gdk8Kbbbbdbbblbbbwbbbbbbbebbbdbbblbbbwbbbbc:K:Gdkl8W:qbb";
14698
+ var wasm_simd = "b9H79TebbbeKl9Gbb9Gvuuuuueu9Giuuub9Geueuixkbbebeeddddilve9Weeeviebeoweuecj:Gdkr;Neqo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbdY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVblE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtboK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbrL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949WbwY9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVJ9V29VVbDl79IV9Rbqq:W9Dklbzik94evu8Jjjjjbcz9Rhbcbheincbhdcbhiinabcwfadfaicjuaead4ceGglE86bbaialfhiadcefgdcw9hmbkaeai86b:q:W:cjbaecitab8Piw83i:q:G:cjbaecefgecjd9hmbkk:JBl8Aud97dur978Jjjjjbcj;kb9Rgv8Kjjjjbc9:hodnalTmbcuhoaiRbbgrc;WeGc:Ge9hmbarcsGgwce0mbc9:hoalcufadcd4cbawEgDadfgrcKcaawEgqaraq0Egk6mbaialfgxar9RhodnadTgmmbavaoad;8qbbkaicefhPcj;abad9Uc;WFbGcjdadca0EhsdndndnadTmbaoadfhzcbhHinaeaH9nmdaxaP9RaD6miabaHad2fhOaPaDfhAasaeaH9RaHasfae6EgCcsfgocl4cifcd4hXavcj;cbfaoc9WGgQcetfhLavcj;cbfaQci2fhKavcj;cbfaQfhYcbh8Aaoc;ab6hEincbh3dnawTmbaPa8Acd4fRbbh3kcbh5avcj;cbfh8Eindndndndna3a5cet4ciGgoc9:fPdebdkaxaA9RaQ6mwdnaQTmbavcj;cbfa5aQ2faAaQ;8qbbkaAaCfhAxdkaQTmeavcj;cbfa5aQ2fcbaQ;8kbxekaxaA9RaX6moaoclVcbawEhraAaXfhocbhidnaEmbaxao9Rc;Gb6mbcbhlina8EalfhidndndndndndnaAalco4fRbbgqciGarfPDbedibledibkaipxbbbbbbbbbbbbbbbbpklbxlkaiaopbblaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLg8Fcdp:mea8FpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogapxiiiiiiiiiiiiiiiip8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbahaoclffagRb:q:W:cjbfhoxikaiaopbbwaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogapxssssssssssssssssp8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbahaocwffagRb:q:W:cjbfhoxdkaiaopbbbpklbaoczfhoxekaiaopbbdaoRbbghcitpbi:q:G:cjbahRb:q:W:cjbghpsaoRbeggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbahaocdffagRb:q:W:cjbfhokdndndndndndnaqcd4ciGarfPDbedibledibkaiczfpxbbbbbbbbbbbbbbbbpklbxlkaiczfaopbblaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLg8Fcdp:mea8FpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogapxiiiiiiiiiiiiiiiip8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbahaoclffagRb:q:W:cjbfhoxikaiczfaopbbwaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogapxssssssssssssssssp8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbahaocwffagRb:q:W:cjbfhoxdkaiczfaopbbbpklbaoczfhoxekaiczfaopbbdaoRbbghcitpbi:q:G:cjbahRb:q:W:cjbghpsaoRbeggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbahaocdffagRb:q:W:cjbfhokdndndndndndnaqcl4ciGarfPDbedibledibkaicafpxbbbbbbbbbbbbbbbbpklbxlkaicafaopbblaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLg8Fcdp:mea8FpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogapxiiiiiiiiiiiiiiiip8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbahaoclffagRb:q:W:cjbfhoxikaicafaopbbwaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogapxssssssssssssssssp8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbahaocwffagRb:q:W:cjbfhoxdkaicafaopbbbpklbaoczfhoxekaicafaopbbdaoRbbghcitpbi:q:G:cjbahRb:q:W:cjbghpsaoRbeggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbahaocdffagRb:q:W:cjbfhokdndndndndndnaqco4arfPDbedibledibkaic8Wfpxbbbbbbbbbbbbbbbbpklbxlkaic8Wfaopbblaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLg8Fcdp:mea8FpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogapxiiiiiiiiiiiiiiiip8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Ngicitpbi:q:G:cjbaiRb:q:W:cjbgipsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Ngqcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbaiaoclffaqRb:q:W:cjbfhoxikaic8Wfaopbbwaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogapxssssssssssssssssp8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Ngicitpbi:q:G:cjbaiRb:q:W:cjbgipsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Ngqcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spklbaiaocwffaqRb:q:W:cjbfhoxdkaic8Wfaopbbbpklbaoczfhoxekaic8WfaopbbdaoRbbgicitpbi:q:G:cjbaiRb:q:W:cjbgipsaoRbegqcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbaiaocdffaqRb:q:W:cjbfhokalc;abfhialcjefaQ0meaihlaxao9Rc;Fb0mbkkdnaiaQ9pmbaici4hlinaxao9RcK6mwa8EaifhqdndndndndndnaAaico4fRbbalcoG4ciGarfPDbedibledibkaqpxbbbbbbbbbbbbbbbbpkbbxlkaqaopbblaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLg8Fcdp:mea8FpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogapxiiiiiiiiiiiiiiiip8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spkbbahaoclffagRb:q:W:cjbfhoxikaqaopbbwaopbbbg8Fclp:mea8FpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogapxssssssssssssssssp8Jg8Fp5b9cjF;8;4;W;G;ab9:9cU1:Nghcitpbi:q:G:cjbahRb:q:W:cjbghpsa8Fp5e9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPaaa8Fp9spkbbahaocwffagRb:q:W:cjbfhoxdkaqaopbbbpkbbaoczfhoxekaqaopbbdaoRbbghcitpbi:q:G:cjbahRb:q:W:cjbghpsaoRbeggcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpkbbahaocdffagRb:q:W:cjbfhokalcdfhlaiczfgiaQ6mbkkaohAaoTmoka8EaQfh8Ea5cefg5cl9hmbkdndndndnawTmbaza8Acd4fRbbglciGPlbedwbkaQTmdavcjdfa8Afhlava8Afpbdbh8Jcbhoinalavcj;cbfaofpblbg8KaYaofpblbg8LpmbzeHdOiAlCvXoQrLg8MaLaofpblbg8NaKaofpblbgypmbzeHdOiAlCvXoQrLg8PpmbezHdiOAlvCXorQLg8Fcep9Ta8Fpxeeeeeeeeeeeeeeeegap9op9Hp9rg8Fa8Jp9Ug8Jp9Abbbaladfgla8Ja8Fa8Fpmlvorlvorlvorlvorp9Ug8Jp9Abbbaladfgla8Ja8Fa8FpmwDqkwDqkwDqkwDqkp9Ug8Jp9Abbbaladfgla8Ja8Fa8FpmxmPsxmPsxmPsxmPsp9Ug8Jp9Abbbaladfgla8Ja8Ma8PpmwDKYqk8AExm35Ps8E8Fg8Fcep9Ta8Faap9op9Hp9rg8Fp9Ug8Jp9Abbbaladfgla8Ja8Fa8Fpmlvorlvorlvorlvorp9Ug8Jp9Abbbaladfgla8Ja8Fa8FpmwDqkwDqkwDqkwDqkp9Ug8Jp9Abbbaladfgla8Ja8Fa8FpmxmPsxmPsxmPsxmPsp9Ug8Jp9Abbbaladfgla8Ja8Ka8LpmwKDYq8AkEx3m5P8Es8Fg8Ka8NaypmwKDYq8AkEx3m5P8Es8Fg8LpmbezHdiOAlvCXorQLg8Fcep9Ta8Faap9op9Hp9rg8Fp9Ug8Jp9Abbbaladfgla8Ja8Fa8Fpmlvorlvorlvorlvorp9Ug8Jp9Abbbaladfgla8Ja8Fa8FpmwDqkwDqkwDqkwDqkp9Ug8Jp9Abbbaladfgla8Ja8Fa8FpmxmPsxmPsxmPsxmPsp9Ug8Jp9Abbbaladfgla8Ja8Ka8LpmwDKYqk8AExm35Ps8E8Fg8Fcep9Ta8Faap9op9Hp9rg8Fp9Ugap9Abbbaladfglaaa8Fa8Fpmlvorlvorlvorlvorp9Ugap9Abbbaladfglaaa8Fa8FpmwDqkwDqkwDqkwDqkp9Ugap9Abbbaladfglaaa8Fa8FpmxmPsxmPsxmPsxmPsp9Ug8Jp9AbbbaladfhlaoczfgoaQ6mbxikkaQTmeavcjdfa8Afhlava8Afpbdbh8Jcbhoinalavcj;cbfaofpblbg8KaYaofpblbg8LpmbzeHdOiAlCvXoQrLg8MaLaofpblbg8NaKaofpblbgypmbzeHdOiAlCvXoQrLg8PpmbezHdiOAlvCXorQLg8Fcep:nea8Fpxebebebebebebebebgap9op:bep9rg8Fa8Jp:oeg8Jp9Abbbaladfgla8Ja8Fa8Fpmlvorlvorlvorlvorp:oeg8Jp9Abbbaladfgla8Ja8Fa8FpmwDqkwDqkwDqkwDqkp:oeg8Jp9Abbbaladfgla8Ja8Fa8FpmxmPsxmPsxmPsxmPsp:oeg8Jp9Abbbaladfgla8Ja8Ma8PpmwDKYqk8AExm35Ps8E8Fg8Fcep:nea8Faap9op:bep9rg8Fp:oeg8Jp9Abbbaladfgla8Ja8Fa8Fpmlvorlvorlvorlvorp:oeg8Jp9Abbbaladfgla8Ja8Fa8FpmwDqkwDqkwDqkwDqkp:oeg8Jp9Abbbaladfgla8Ja8Fa8FpmxmPsxmPsxmPsxmPsp:oeg8Jp9Abbbaladfgla8Ja8Ka8LpmwKDYq8AkEx3m5P8Es8Fg8Ka8NaypmwKDYq8AkEx3m5P8Es8Fg8LpmbezHdiOAlvCXorQLg8Fcep:nea8Faap9op:bep9rg8Fp:oeg8Jp9Abbbaladfgla8Ja8Fa8Fpmlvorlvorlvorlvorp:oeg8Jp9Abbbaladfgla8Ja8Fa8FpmwDqkwDqkwDqkwDqkp:oeg8Jp9Abbbaladfgla8Ja8Fa8FpmxmPsxmPsxmPsxmPsp:oeg8Jp9Abbbaladfgla8Ja8Ka8LpmwDKYqk8AExm35Ps8E8Fg8Fcep:nea8Faap9op:bep9rg8Fp:oegap9Abbbaladfglaaa8Fa8Fpmlvorlvorlvorlvorp:oegap9Abbbaladfglaaa8Fa8FpmwDqkwDqkwDqkwDqkp:oegap9Abbbaladfglaaa8Fa8FpmxmPsxmPsxmPsxmPsp:oeg8Jp9AbbbaladfhlaoczfgoaQ6mbxdkkaQTmbcbhocbalcl4gl9Rc8FGhiavcjdfa8Afhrava8Afpbdbhainaravcj;cbfaofpblbg8JaYaofpblbg8KpmbzeHdOiAlCvXoQrLg8LaLaofpblbg8MaKaofpblbg8NpmbzeHdOiAlCvXoQrLgypmbezHdiOAlvCXorQLg8Faip:Rea8Falp:Tep9qg8Faap9rgap9Abbbaradfgraaa8Fa8Fpmlvorlvorlvorlvorp9rgap9Abbbaradfgraaa8Fa8FpmwDqkwDqkwDqkwDqkp9rgap9Abbbaradfgraaa8Fa8FpmxmPsxmPsxmPsxmPsp9rgap9Abbbaradfgraaa8LaypmwDKYqk8AExm35Ps8E8Fg8Faip:Rea8Falp:Tep9qg8Fp9rgap9Abbbaradfgraaa8Fa8Fpmlvorlvorlvorlvorp9rgap9Abbbaradfgraaa8Fa8FpmwDqkwDqkwDqkwDqkp9rgap9Abbbaradfgraaa8Fa8FpmxmPsxmPsxmPsxmPsp9rgap9Abbbaradfgraaa8Ja8KpmwKDYq8AkEx3m5P8Es8Fg8Ja8Ma8NpmwKDYq8AkEx3m5P8Es8Fg8KpmbezHdiOAlvCXorQLg8Faip:Rea8Falp:Tep9qg8Fp9rgap9Abbbaradfgraaa8Fa8Fpmlvorlvorlvorlvorp9rgap9Abbbaradfgraaa8Fa8FpmwDqkwDqkwDqkwDqkp9rgap9Abbbaradfgraaa8Fa8FpmxmPsxmPsxmPsxmPsp9rgap9Abbbaradfgraaa8Ja8KpmwDKYqk8AExm35Ps8E8Fg8Faip:Rea8Falp:Tep9qg8Fp9rgap9Abbbaradfgraaa8Fa8Fpmlvorlvorlvorlvorp9rgap9Abbbaradfgraaa8Fa8FpmwDqkwDqkwDqkwDqkp9rgap9Abbbaradfgraaa8Fa8FpmxmPsxmPsxmPsxmPsp9rgap9AbbbaradfhraoczfgoaQ6mbkka8Aclfg8Aad6mbkdnaCad2goTmbaOavcjdfao;8qbbkdnammbavavcjdfaCcufad2fad;8qbbkaCaHfhHc9:hoaAhPaAmbxlkkaeTmbaDalfhrcbhocuhlinaralaD9RglfaD6mdasaeao9Raoasfae6Eaofgoae6mbkaial9RhPkcbc99axaP9RakSEhoxekc9:hokavcj;kbf8Kjjjjbaokwbz:bjjjbkNsezu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnalaeci9UgrcHf6mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgDce0mbavc;abfcFecje;8kbav9cu83iUav9cu83i8Wav9cu83iyav9cu83iaav9cu83iKav9cu83izav9cu83iwav9cu83ibaialfc9WfhqaicefgwarfhldnaeTmbcmcsaDceSEhkcbhxcbhmcbhrcbhicbhoindnalaq9nmbc9:hoxikdndnawRbbgDc;Ve0mbavc;abfaoaDcu7gPcl4fcsGcitfgsydlhzasydbhHdndnaDcsGgsak9pmbavaiaPfcsGcdtfydbaxasEhDaxasTgOfhxxekdndnascsSmbcehOasc987asamffcefhDxekalcefhDal8SbbgscFeGhPdndnascu9mmbaDhlxekalcvfhlaPcFbGhPcrhsdninaD8SbbgOcFbGastaPVhPaOcu9kmeaDcefhDascrfgsc8J9hmbxdkkaDcefhlkcehOaPce4cbaPceG9R7amfhDkaDhmkavc;abfaocitfgsaDBdbasazBdlavaicdtfaDBdbavc;abfaocefcsGcitfgsaHBdbasaDBdlaocdfhoaOaifhidnadcd9hmbabarcetfgsaH87ebasclfaD87ebascdfaz87ebxdkabarcdtfgsaHBdbascwfaDBdbasclfazBdbxekdnaDcpe0mbavaiaqaDcsGfRbbgscl4gP9RcsGcdtfydbaxcefgOaPEhDavaias9RcsGcdtfydbaOaPTgzfgOascsGgPEhsaPThPdndnadcd9hmbabarcetfgHax87ebaHclfas87ebaHcdfaD87ebxekabarcdtfgHaxBdbaHcwfasBdbaHclfaDBdbkavaicdtfaxBdbavc;abfaocitfgHaDBdbaHaxBdlavaicefgicsGcdtfaDBdbavc;abfaocefcsGcitfgHasBdbaHaDBdlavaiazfgicsGcdtfasBdbavc;abfaocdfcsGcitfgDaxBdbaDasBdlaocifhoaiaPfhiaOaPfhxxekaxcbalRbbgsEgHaDc;:eSgDfhOascsGhAdndnascl4gCmbaOcefhzxekaOhzavaiaC9RcsGcdtfydbhOkdndnaAmbazcefhxxekazhxavaias9RcsGcdtfydbhzkdndnaDTmbalcefhDxekalcdfhDal8SbegPcFeGhsdnaPcu9kmbalcofhHascFbGhscrhldninaD8SbbgPcFbGaltasVhsaPcu9kmeaDcefhDalcrfglc8J9hmbkaHhDxekaDcefhDkasce4cbasceG9R7amfgmhHkdndnaCcsSmbaDhsxekaDcefhsaD8SbbglcFeGhPdnalcu9kmbaDcvfhOaPcFbGhPcrhldninas8SbbgDcFbGaltaPVhPaDcu9kmeascefhsalcrfglc8J9hmbkaOhsxekascefhskaPce4cbaPceG9R7amfgmhOkdndnaAcsSmbashlxekascefhlas8SbbgDcFeGhPdnaDcu9kmbascvfhzaPcFbGhPcrhDdninal8SbbgscFbGaDtaPVhPascu9kmealcefhlaDcrfgDc8J9hmbkazhlxekalcefhlkaPce4cbaPceG9R7amfgmhzkdndnadcd9hmbabarcetfgDaH87ebaDclfaz87ebaDcdfaO87ebxekabarcdtfgDaHBdbaDcwfazBdbaDclfaOBdbkavc;abfaocitfgDaOBdbaDaHBdlavaicdtfaHBdbavc;abfaocefcsGcitfgDazBdbaDaOBdlavaicefgicsGcdtfaOBdbavc;abfaocdfcsGcitfgDaHBdbaDazBdlavaiaCTaCcsSVfgicsGcdtfazBdbaiaATaAcsSVfhiaocifhokawcefhwaocsGhoaicsGhiarcifgrae6mbkkcbc99alaqSEhokavc;aef8Kjjjjbaok:clevu8Jjjjjbcz9Rhvdnalaecvf9pmbc9:skdnaiRbbc;:eGc;qeSmbcuskav9cb83iwaicefhoaialfc98fhrdnaeTmbdnadcdSmbcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcdtfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgiBdbalaiBdbawcefgwae9hmbxdkkcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcetfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgi87ebalaiBdbawcefgwae9hmbkkcbc99aoarSEk;Toio97eue97aec98Ghedndnadcl9hmbaeTmecbhdinababpbbbgicKp:RecKp:Sep;6eglaicwp:RecKp:Sep;6ealp;Geaiczp:RecKp:Sep;6egvp;Gep;Kep;Legopxbbbbbbbbbbbbbbbbp:2egralpxbbbjbbbjbbbjbbbjgwp9op9rp;Keglpxbb;:9cbb;:9cbb;:9cbb;:9calalp;Meaoaop;Meavaravawp9op9rp;Keglalp;Mep;Kep;Kep;Jep;Negvp;Mepxbbn0bbn0bbn0bbn0grp;KepxFbbbFbbbFbbbFbbbp9oaipxbbbFbbbFbbbFbbbFp9op9qalavp;Mearp;Kecwp:RepxbFbbbFbbbFbbbFbbp9op9qaoavp;Mearp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qpkbbabczfhbadclfgdae6mbxdkkaeTmbcbhdinabczfgDaDpbbbgipxbbbbbbFFbbbbbbFFgwp9oabpbbbgoaipmbediwDqkzHOAKY8AEgvczp:Reczp:Sep;6eglaoaipmlvorxmPsCXQL358E8FpxFubbFubbFubbFubbp9op;6eavczp:Sep;6egvp;Gealp;Gep;Kep;Legipxbbbbbbbbbbbbbbbbp:2egralpxbbbjbbbjbbbjbbbjgqp9op9rp;Keglpxb;:FSb;:FSb;:FSb;:FSalalp;Meaiaip;Meavaravaqp9op9rp;Keglalp;Mep;Kep;Kep;Jep;Negvp;Mepxbbn0bbn0bbn0bbn0grp;KepxFFbbFFbbFFbbFFbbp9oaiavp;Mearp;Keczp:Rep9qgialavp;Mearp;KepxFFbbFFbbFFbbFFbbp9oglpmwDKYqk8AExm35Ps8E8Fp9qpkbbabaoawp9oaialpmbezHdiOAlvCXorQLp9qpkbbabcafhbadclfgdae6mbkkk;2ileue97euo97dnaec98GgiTmbcbheinabcKfpx:ji:1S:ji:1S:ji:1S:ji:1SabpbbbglabczfgvpbbbgopmlvorxmPsCXQL358E8Fgrczp:Segwpxibbbibbbibbbibbbp9qp;6egDp;NegqaDaDp;MegDaDp;KealaopmbediwDqkzHOAKY8AEgDczp:Reczp:Sep;6eglalp;MeaDczp:Sep;6egoaop;Mearczp:Reczp:Sep;6egrarp;Mep;Kep;Kep;Lepxbbbbbbbbbbbbbbbbp:4ep;Jep;Mepxbbn0bbn0bbn0bbn0gDp;KepxFFbbFFbbFFbbFFbbgkp9oaqaop;MeaDp;Keczp:Rep9qgoaqalp;MeaDp;Keakp9oaqarp;MeaDp;Keczp:Rep9qgDpmwDKYqk8AExm35Ps8E8Fglp5eawclp:RegqpEi:T:j83ibavalp5baqpEd:T:j83ibabcwfaoaDpmbezHdiOAlvCXorQLgDp5eaqpEe:T:j83ibabaDp5baqpEb:T:j83ibabcafhbaeclfgeai6mbkkkuee97dnadcd4ae2c98GgeTmbcbhdinababpbbbgicwp:Recwp:Sep;6eaicep:SepxbbjFbbjFbbjFbbjFp9opxbbjZbbjZbbjZbbjZp:Uep;Mepkbbabczfhbadclfgdae6mbkkk:Sodw97euaec98Ghedndnadcl9hmbaeTmecbhdinabpxbbuJbbuJbbuJbbuJabpbbbgicKp:TeglaicYp:Tep9qgvcdp:Teavp9qgvclp:Teavp9qgop;6ep;Negvaicwp:RecKp:SegraipxFbbbFbbbFbbbFbbbgwp9ogDp:Uep;6ep;Mepxbbn0bbn0bbn0bbn0gqp;Kecwp:RepxbFbbbFbbbFbbbFbbp9oavaDarp:Xeaiczp:RecKp:Segip:Uep;6ep;Meaqp;Keawp9op9qavaDaraip:Uep:Xep;6ep;Meaqp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qavaoalcep:Rep9oalpxebbbebbbebbbebbbp9op9qp;6ep;Meaqp;KecKp:Rep9qpkbbabczfhbadclfgdae6mbxdkkaeTmbcbhdinabczfgkpxbFu9hbFu9hbFu9hbFu9habpbbbglakpbbbgrpmlvorxmPsCXQL358E8Fgvczp:TegqavcHp:Tep9qgicdp:Teaip9qgiclp:Teaip9qgicwp:Teaip9qgop;6ep;NegialarpmbediwDqkzHOAKY8AEgDpxFFbbFFbbFFbbFFbbglp9ograDczp:Segwp:Ueavczp:Reczp:SegDp:Xep;6ep;Mepxbbn0bbn0bbn0bbn0gvp;Kealp9oaiarawaDp:Uep:Xep;6ep;Meavp;Keczp:Rep9qgwaiaoaqcep:Rep9oaqpxebbbebbbebbbebbbp9op9qp;6ep;Meavp;Keczp:ReaiaDarp:Uep;6ep;Meavp;Kealp9op9qgipmwDKYqk8AExm35Ps8E8FpkbbabawaipmbezHdiOAlvCXorQLpkbbabcafhbadclfgdae6mbkkk9teiucbcbydj:G:cjbgeabcifc98GfgbBdj:G:cjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaikkxebcj:Gdklz:zbb";
14699
+ var detector = new Uint8Array([
14700
+ 0,
14701
+ 97,
14702
+ 115,
14703
+ 109,
14704
+ 1,
14705
+ 0,
14706
+ 0,
14707
+ 0,
14708
+ 1,
14709
+ 4,
14710
+ 1,
14711
+ 96,
14712
+ 0,
14713
+ 0,
14714
+ 3,
14715
+ 3,
14716
+ 2,
14717
+ 0,
14718
+ 0,
14719
+ 5,
14720
+ 3,
14721
+ 1,
14722
+ 0,
14723
+ 1,
14724
+ 12,
14725
+ 1,
14726
+ 0,
14727
+ 10,
14728
+ 22,
14729
+ 2,
14730
+ 12,
14731
+ 0,
14732
+ 65,
14733
+ 0,
14734
+ 65,
14735
+ 0,
14736
+ 65,
14737
+ 0,
14738
+ 252,
14739
+ 10,
14740
+ 0,
14741
+ 0,
14742
+ 11,
14743
+ 7,
14744
+ 0,
14745
+ 65,
14746
+ 0,
14747
+ 253,
14748
+ 15,
14749
+ 26,
14750
+ 11
14751
+ ]);
14752
+ var wasmpack = new Uint8Array([
14753
+ 32,
14754
+ 0,
14755
+ 65,
14756
+ 2,
14757
+ 1,
14758
+ 106,
14759
+ 34,
14760
+ 33,
14761
+ 3,
14762
+ 128,
14763
+ 11,
14764
+ 4,
14765
+ 13,
14766
+ 64,
14767
+ 6,
14768
+ 253,
14769
+ 10,
14770
+ 7,
14771
+ 15,
14772
+ 116,
14773
+ 127,
14774
+ 5,
14775
+ 8,
14776
+ 12,
14777
+ 40,
14778
+ 16,
14779
+ 19,
14780
+ 54,
14781
+ 20,
14782
+ 9,
14783
+ 27,
14784
+ 255,
14785
+ 113,
14786
+ 17,
14787
+ 42,
14788
+ 67,
14789
+ 24,
14790
+ 23,
14791
+ 146,
14792
+ 148,
14793
+ 18,
14794
+ 14,
14795
+ 22,
14796
+ 45,
14797
+ 70,
14798
+ 69,
14799
+ 56,
14800
+ 114,
14801
+ 101,
14802
+ 21,
14803
+ 25,
14804
+ 63,
14805
+ 75,
14806
+ 136,
14807
+ 108,
14808
+ 28,
14809
+ 118,
14810
+ 29,
14811
+ 73,
14812
+ 115
14813
+ ]);
14814
+ if (typeof WebAssembly !== "object") {
14815
+ return {
14816
+ supported: false
14817
+ };
14818
+ }
14819
+ var wasm = WebAssembly.validate(detector) ? unpack(wasm_simd) : unpack(wasm_base);
14820
+ var instance;
14821
+ var ready = WebAssembly.instantiate(wasm, {}).then(function(result) {
14822
+ instance = result.instance;
14823
+ instance.exports.__wasm_call_ctors();
14824
+ });
14825
+ function unpack(data) {
14826
+ var result = new Uint8Array(data.length);
14827
+ for (var i2 = 0; i2 < data.length; ++i2) {
14828
+ var ch = data.charCodeAt(i2);
14829
+ result[i2] = ch > 96 ? ch - 97 : ch > 64 ? ch - 39 : ch + 4;
14830
+ }
14831
+ var write = 0;
14832
+ for (var i2 = 0; i2 < data.length; ++i2) {
14833
+ result[write++] = result[i2] < 60 ? wasmpack[result[i2]] : (result[i2] - 60) * 64 + result[++i2];
14834
+ }
14835
+ return result.buffer.slice(0, write);
14836
+ }
14837
+ function decode(instance2, fun, target, count, size, source, filter) {
14838
+ var sbrk = instance2.exports.sbrk;
14839
+ var count4 = count + 3 & -4;
14840
+ var tp = sbrk(count4 * size);
14841
+ var sp = sbrk(source.length);
14842
+ var heap = new Uint8Array(instance2.exports.memory.buffer);
14843
+ heap.set(source, sp);
14844
+ var res = fun(tp, count, size, sp, source.length);
14845
+ if (res == 0 && filter) {
14846
+ filter(tp, count4, size);
14847
+ }
14848
+ target.set(heap.subarray(tp, tp + count * size));
14849
+ sbrk(tp - sbrk(0));
14850
+ if (res != 0) {
14851
+ throw new Error("Malformed buffer data: " + res);
14852
+ }
14853
+ }
14854
+ var filters = {
14855
+ NONE: "",
14856
+ OCTAHEDRAL: "meshopt_decodeFilterOct",
14857
+ QUATERNION: "meshopt_decodeFilterQuat",
14858
+ EXPONENTIAL: "meshopt_decodeFilterExp",
14859
+ COLOR: "meshopt_decodeFilterColor"
14860
+ };
14861
+ var decoders = {
14862
+ ATTRIBUTES: "meshopt_decodeVertexBuffer",
14863
+ TRIANGLES: "meshopt_decodeIndexBuffer",
14864
+ INDICES: "meshopt_decodeIndexSequence"
14865
+ };
14866
+ var workers = [];
14867
+ var requestId = 0;
14868
+ function createWorker(url) {
14869
+ var worker = {
14870
+ object: new Worker(url),
14871
+ pending: 0,
14872
+ requests: {}
14873
+ };
14874
+ worker.object.onmessage = function(event) {
14875
+ var data = event.data;
14876
+ worker.pending -= data.count;
14877
+ worker.requests[data.id][data.action](data.value);
14878
+ delete worker.requests[data.id];
14879
+ };
14880
+ return worker;
14881
+ }
14882
+ function initWorkers(count) {
14883
+ var source = "self.ready = WebAssembly.instantiate(new Uint8Array([" + new Uint8Array(wasm) + "]), {}).then(function(result) { result.instance.exports.__wasm_call_ctors(); return result.instance; });self.onmessage = " + workerProcess.name + ";" + decode.toString() + workerProcess.toString();
14884
+ var blob = new Blob([source], { type: "text/javascript" });
14885
+ var url = URL.createObjectURL(blob);
14886
+ for (var i2 = workers.length; i2 < count; ++i2) {
14887
+ workers[i2] = createWorker(url);
14888
+ }
14889
+ for (var i2 = count; i2 < workers.length; ++i2) {
14890
+ workers[i2].object.postMessage({});
14891
+ }
14892
+ workers.length = count;
14893
+ URL.revokeObjectURL(url);
14894
+ }
14895
+ function decodeWorker(count, size, source, mode, filter) {
14896
+ var worker = workers[0];
14897
+ for (var i2 = 1; i2 < workers.length; ++i2) {
14898
+ if (workers[i2].pending < worker.pending) {
14899
+ worker = workers[i2];
14900
+ }
14901
+ }
14902
+ return new Promise(function(resolve, reject) {
14903
+ var data = new Uint8Array(source);
14904
+ var id = ++requestId;
14905
+ worker.pending += count;
14906
+ worker.requests[id] = { resolve, reject };
14907
+ worker.object.postMessage({ id, count, size, source: data, mode, filter }, [data.buffer]);
14908
+ });
14909
+ }
14910
+ function workerProcess(event) {
14911
+ var data = event.data;
14912
+ self.ready.then(function(instance2) {
14913
+ if (!data.id) {
14914
+ return self.close();
14915
+ }
14916
+ try {
14917
+ var target = new Uint8Array(data.count * data.size);
14918
+ decode(instance2, instance2.exports[data.mode], target, data.count, data.size, data.source, instance2.exports[data.filter]);
14919
+ self.postMessage({ id: data.id, count: data.count, action: "resolve", value: target }, [target.buffer]);
14920
+ } catch (error) {
14921
+ self.postMessage({ id: data.id, count: data.count, action: "reject", value: error });
14922
+ }
14923
+ });
14924
+ }
14925
+ return {
14926
+ ready,
14927
+ supported: true,
14928
+ useWorkers: function(count) {
14929
+ initWorkers(count);
14930
+ },
14931
+ decodeVertexBuffer: function(target, count, size, source, filter) {
14932
+ decode(instance, instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]);
14933
+ },
14934
+ decodeIndexBuffer: function(target, count, size, source) {
14935
+ decode(instance, instance.exports.meshopt_decodeIndexBuffer, target, count, size, source);
14936
+ },
14937
+ decodeIndexSequence: function(target, count, size, source) {
14938
+ decode(instance, instance.exports.meshopt_decodeIndexSequence, target, count, size, source);
14939
+ },
14940
+ decodeGltfBuffer: function(target, count, size, source, mode, filter) {
14941
+ decode(instance, instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]);
14942
+ },
14943
+ decodeGltfBufferAsync: function(count, size, source, mode, filter) {
14944
+ if (workers.length > 0) {
14945
+ return decodeWorker(count, size, source, decoders[mode], filters[filter]);
14946
+ }
14947
+ return ready.then(function() {
14948
+ var target = new Uint8Array(count * size);
14949
+ decode(instance, instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]);
14950
+ return target;
14951
+ });
14952
+ }
14953
+ };
14954
+ }();
14719
14955
  var patch_default = "uniform vec3 diffuse;uniform float opacity;\n#ifndef FLAT_SHADED\nvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main(){vec4 diffuseColor=vec4(diffuse,opacity);\n#include <clipping_planes_fragment>\n#include <logdepthbuf_fragment>\n#include <map_fragment>\n#include <alphamap_fragment>\n#include <alphatest_fragment>\n#include <alphahash_fragment>\n#include <specularmap_fragment>\nReflectedLight reflectedLight=ReflectedLight(vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));\n#ifdef USE_LIGHTMAP\nvec4 lightMapTexel=texture2D(lightMap,vLightMapUv);reflectedLight.indirectDiffuse+=lightMapTexel.rgb*lightMapIntensity*RECIPROCAL_PI;\n#else\nreflectedLight.indirectDiffuse+=vec3(1.0);\n#endif\n#include <aomap_fragment>\nreflectedLight.indirectDiffuse*=diffuseColor.rgb;vec3 outgoingLight=reflectedLight.indirectDiffuse;\n#include <envmap_fragment>\n#include <opaque_fragment>\n#include <tonemapping_fragment>\n#include <colorspace_fragment>\n#include <fog_fragment>\n#include <premultiplied_alpha_fragment>\n#include <dithering_fragment>\n#ifdef USE_COLOR\ngl_FragColor.a=vColor.r;\n#endif\n}";
14956
+ const GAUSSIAN_FORMATS = /* @__PURE__ */ new Set(["ply", "sog", "spz", "rad"]);
14957
+ function requireNonEmptyString(value, field) {
14958
+ if (typeof value !== "string" || value.trim().length === 0) {
14959
+ throw new Error(`${field} must be a non-empty string.`);
14960
+ }
14961
+ }
14962
+ function validateGaussianSplatLayerDefinition(definition) {
14963
+ var _a3, _b2, _c, _d;
14964
+ if (!definition || typeof definition !== "object") {
14965
+ throw new Error("Gaussian splat layer definition must be an object.");
14966
+ }
14967
+ requireNonEmptyString(definition.id, "id");
14968
+ requireNonEmptyString(definition.name, "name");
14969
+ if (definition.type !== "gaussian-splat") {
14970
+ throw new Error('type must be "gaussian-splat".');
14971
+ }
14972
+ if (!Array.isArray(definition.labels) || !definition.labels.every((label) => typeof label === "string")) {
14973
+ throw new Error("labels must be an array of strings.");
14974
+ }
14975
+ requireNonEmptyString((_a3 = definition.data) == null ? void 0 : _a3.url, "data.url");
14976
+ if (!GAUSSIAN_FORMATS.has((_b2 = definition.data) == null ? void 0 : _b2.format)) {
14977
+ throw new Error('data.format must be "ply", "sog", "spz", or "rad".');
14978
+ }
14979
+ const renderOrder = ((_c = definition.options) == null ? void 0 : _c.renderOrder) ?? 0;
14980
+ if (renderOrder !== 0) {
14981
+ throw new Error("Gaussian splat layers only support renderOrder 0.");
14982
+ }
14983
+ const transform = (_d = definition.options) == null ? void 0 : _d.transform;
14984
+ const anchor = transform == null ? void 0 : transform.anchor;
14985
+ if (!anchor) {
14986
+ throw new Error("options.transform.anchor must contain finite longitude, latitude, and altitude values.");
14987
+ }
14988
+ validateGeodeticPosition(anchor.longitude, anchor.latitude, anchor.altitude, "Gaussian anchor");
14989
+ const translationENU = transform.translationENU ?? [0, 0, 0];
14990
+ const rotationDegrees = transform.rotationDegrees ?? [0, 0, 0];
14991
+ const scale = transform.scale ?? 1;
14992
+ validateTuple(translationENU, "translationENU");
14993
+ validateTuple(rotationDegrees, "rotationDegrees");
14994
+ validateScale(scale, "scale");
14995
+ return {
14996
+ ...definition,
14997
+ labels: [...definition.labels],
14998
+ data: { ...definition.data },
14999
+ options: {
15000
+ ...definition.options,
15001
+ renderOrder: 0,
15002
+ transform: {
15003
+ anchor: { ...anchor },
15004
+ translationENU: [...translationENU],
15005
+ rotationDegrees: [...rotationDegrees],
15006
+ scale
15007
+ }
15008
+ }
15009
+ };
15010
+ }
15011
+ function makeGaussianSplatTransform(transform) {
15012
+ const { anchor, translationENU, rotationDegrees, scale } = transform;
15013
+ const basis = getEnuBasis(anchor.longitude, anchor.latitude);
15014
+ const east = new Vector3().fromArray(basis.east);
15015
+ const north = new Vector3().fromArray(basis.north);
15016
+ const up = new Vector3().fromArray(basis.up);
15017
+ const enuFrame = new Matrix4().makeBasis(east, north, up);
15018
+ enuFrame.setPosition(new Vector3().fromArray(geodeticToEcefPosition(anchor.longitude, anchor.latitude, anchor.altitude)));
15019
+ const rotation = new Quaternion().setFromEuler(new Euler(rotationDegrees[0] * Math.PI / 180, rotationDegrees[1] * Math.PI / 180, rotationDegrees[2] * Math.PI / 180, "XYZ"));
15020
+ const localTransform = new Matrix4().compose(new Vector3().fromArray(translationENU), rotation, new Vector3(scale, scale, scale));
15021
+ return enuFrame.multiply(localTransform);
15022
+ }
15023
+ function normalizeLocalMeshTransform(transform) {
15024
+ if (!transform || typeof transform !== "object") {
15025
+ throw new Error("Mesh transform must be an object.");
15026
+ }
15027
+ const anchor = transform.anchor;
15028
+ if (!anchor) {
15029
+ throw new Error("Mesh transform anchor is required.");
15030
+ }
15031
+ validateGeodeticPosition(anchor.longitude, anchor.latitude, anchor.altitude, "Mesh transform anchor");
15032
+ const translationENU = transform.translationENU ?? [0, 0, 0];
15033
+ const rotationDegrees = transform.rotationDegrees ?? [90, 0, 0];
15034
+ const scale = transform.scale ?? 1;
15035
+ validateTuple(translationENU, "Mesh translationENU");
15036
+ validateTuple(rotationDegrees, "Mesh rotationDegrees");
15037
+ validateScale(scale, "Mesh scale");
15038
+ return { anchor: { ...anchor }, translationENU: [...translationENU], rotationDegrees: [...rotationDegrees], scale };
15039
+ }
14720
15040
  class MeshLayer extends ContentLayer {
14721
15041
  constructor(url, options = {}, callbacks = {}) {
14722
15042
  super();
14723
15043
  this.type = "MeshLayer";
14724
15044
  this.isMeshLayer = true;
14725
15045
  const renderOrder = (options == null ? void 0 : options.renderOrder) ?? 0;
14726
- const offset = normalizeLayerOffset(options.offset, "Mesh offset");
15046
+ if (options.transform !== void 0 && (options.offset !== void 0 || options.offsetOrigin !== void 0)) {
15047
+ throw new Error("Mesh transform and legacy offset/offsetOrigin are mutually exclusive.");
15048
+ }
15049
+ const transform = options.transform === void 0 ? null : normalizeLocalMeshTransform(options.transform);
15050
+ const renderLayer = transform ? 0 : 6;
15051
+ this.xrRenderLayer = renderLayer;
15052
+ const offset = transform ? { lon: 0, lat: 0, alt: 0 } : normalizeLayerOffset(options.offset, "Mesh offset");
14727
15053
  const hasOffset = offset.lon !== 0 || offset.lat !== 0 || offset.alt !== 0;
15054
+ if (transform) {
15055
+ this.matrix.copy(makeGaussianSplatTransform(transform));
15056
+ this.matrix.decompose(this.position, this.quaternion, this.scale);
15057
+ }
15058
+ this.abortController = new AbortController();
15059
+ this.disposed = false;
14728
15060
  const loader = new GLTFLoader();
14729
- loader.load(
14730
- url,
14731
- (gltf) => {
14732
- var _a3;
14733
- const root = gltf.scene;
14734
- root.traverse((child) => {
14735
- child.layers.set(6);
15061
+ loader.setMeshoptDecoder(MeshoptDecoder);
15062
+ if (options.decoders) {
15063
+ loader.setDRACOLoader(options.decoders.getDraco());
15064
+ loader.setKTX2Loader(options.decoders.getKTX2());
15065
+ }
15066
+ const reportError = (error) => {
15067
+ var _a3;
15068
+ if (!this.disposed && (error == null ? void 0 : error.name) !== "AbortError") {
15069
+ (_a3 = callbacks.onError) == null ? void 0 : _a3.call(callbacks, error instanceof Error ? error : new Error(String(error)));
15070
+ }
15071
+ };
15072
+ const onLoad = (gltf) => {
15073
+ var _a3;
15074
+ const root = gltf.scene;
15075
+ if (this.disposed) {
15076
+ this.disposeObjectResources(root);
15077
+ return;
15078
+ }
15079
+ root.traverse((child) => {
15080
+ child.layers.set(renderLayer);
15081
+ if (!transform) {
14736
15082
  const materials = Array.isArray(child.material) ? child.material : child.material ? [child.material] : [];
14737
15083
  for (const material of materials) {
14738
15084
  material.transparent = true;
@@ -14740,28 +15086,32 @@ class MeshLayer extends ContentLayer {
14740
15086
  program.fragmentShader = patch_default;
14741
15087
  };
14742
15088
  }
14743
- });
14744
- this.mesh = root;
14745
- this.add(root);
14746
- if (hasOffset) {
14747
- try {
14748
- const origin = options.offsetOrigin;
14749
- const position = validateGeodeticPosition(origin == null ? void 0 : origin.longitude, origin == null ? void 0 : origin.latitude, origin == null ? void 0 : origin.altitude, "Mesh offset origin");
14750
- this.position.fromArray(geodeticOffsetToEcefDelta({ lon: position.longitude, lat: position.latitude, alt: position.altitude }, offset));
14751
- } catch (error) {
14752
- (_a3 = callbacks.onError) == null ? void 0 : _a3.call(callbacks, error instanceof Error ? error : new Error(String(error)));
14753
- }
14754
15089
  }
14755
- },
14756
- void 0,
14757
- (error) => {
14758
- var _a3;
14759
- return (_a3 = callbacks.onError) == null ? void 0 : _a3.call(callbacks, error instanceof Error ? error : new Error(String(error)));
15090
+ });
15091
+ this.mesh = root;
15092
+ this.add(root);
15093
+ if (hasOffset) {
15094
+ try {
15095
+ const origin = options.offsetOrigin;
15096
+ const position = validateGeodeticPosition(origin == null ? void 0 : origin.longitude, origin == null ? void 0 : origin.latitude, origin == null ? void 0 : origin.altitude, "Mesh offset origin");
15097
+ this.position.fromArray(geodeticOffsetToEcefDelta({ lon: position.longitude, lat: position.latitude, alt: position.altitude }, offset));
15098
+ } catch (error) {
15099
+ (_a3 = callbacks.onError) == null ? void 0 : _a3.call(callbacks, error instanceof Error ? error : new Error(String(error)));
15100
+ }
14760
15101
  }
14761
- );
14762
- this.layers.set(renderOrder);
15102
+ };
15103
+ void fetch(url, { signal: this.abortController.signal }).then(async (response) => {
15104
+ if (!response.ok) throw new Error(`Failed to load mesh: ${response.status} ${response.statusText}`);
15105
+ const bytes = await response.arrayBuffer();
15106
+ if (this.disposed) return;
15107
+ loader.parse(bytes, url.slice(0, url.lastIndexOf("/") + 1), onLoad, reportError);
15108
+ }).catch(reportError);
15109
+ this.layers.set(transform ? 0 : renderOrder);
14763
15110
  }
14764
15111
  dispose() {
15112
+ if (this.disposed) return;
15113
+ this.disposed = true;
15114
+ this.abortController.abort();
14765
15115
  super.dispose();
14766
15116
  if (this.mesh) {
14767
15117
  this.disposeObjectResources(this.mesh);
@@ -14770,19 +15120,24 @@ class MeshLayer extends ContentLayer {
14770
15120
  }
14771
15121
  }
14772
15122
  }
15123
+ function abortError() {
15124
+ return new DOMException("Worker job canceled", "AbortError");
15125
+ }
14773
15126
  class WorkerPool2 {
14774
15127
  constructor(limit = 4) {
14775
15128
  this.limit = limit;
14776
15129
  this.queue = [];
14777
15130
  this.workers = [];
14778
- this.workersResolve = [];
15131
+ this.active = [];
14779
15132
  this.workerStatus = 0;
14780
15133
  this.workerCreator = null;
15134
+ this.disposed = false;
14781
15135
  }
14782
15136
  initWorker(workerId) {
14783
15137
  if (!this.workers[workerId]) {
14784
15138
  const worker = this.workerCreator();
14785
- worker.addEventListener("message", this.onMessage.bind(this, workerId));
15139
+ worker.addEventListener("message", (event) => this.onMessage(workerId, worker, event));
15140
+ worker.addEventListener("error", (event) => this.onError(workerId, worker, event));
14786
15141
  this.workers[workerId] = worker;
14787
15142
  }
14788
15143
  }
@@ -14790,15 +15145,63 @@ class WorkerPool2 {
14790
15145
  for (let i2 = 0; i2 < this.limit; i2++) if (!(this.workerStatus & 1 << i2)) return i2;
14791
15146
  return -1;
14792
15147
  }
14793
- onMessage(workerId, msg) {
14794
- const resolve = this.workersResolve[workerId];
14795
- resolve && resolve(msg);
14796
- if (this.queue.length) {
14797
- const { resolve: resolve2, msg: msg2, transfer } = this.queue.shift();
14798
- this.workersResolve[workerId] = resolve2;
14799
- this.workers[workerId].postMessage(msg2, transfer);
14800
- } else {
14801
- this.workerStatus ^= 1 << workerId;
15148
+ finishJob(workerId, job) {
15149
+ var _a3;
15150
+ if (this.active[workerId] !== job) return false;
15151
+ (_a3 = job.signal) == null ? void 0 : _a3.removeEventListener("abort", job.onAbort);
15152
+ this.active[workerId] = null;
15153
+ this.workerStatus &= ~(1 << workerId);
15154
+ return true;
15155
+ }
15156
+ onMessage(workerId, worker, event) {
15157
+ if (this.workers[workerId] !== worker) return;
15158
+ const job = this.active[workerId];
15159
+ if (!job || !this.finishJob(workerId, job)) return;
15160
+ job.resolve(event);
15161
+ this.drain();
15162
+ }
15163
+ onError(workerId, worker, event) {
15164
+ if (this.workers[workerId] !== worker) return;
15165
+ const job = this.active[workerId];
15166
+ if (!job || !this.finishJob(workerId, job)) return;
15167
+ worker.terminate();
15168
+ this.workers[workerId] = null;
15169
+ job.reject((event == null ? void 0 : event.error) ?? new Error("Worker job failed"));
15170
+ this.drain();
15171
+ }
15172
+ cancelJob(job) {
15173
+ var _a3, _b2;
15174
+ if (job.workerId === null) {
15175
+ const index = this.queue.indexOf(job);
15176
+ if (index < 0) return;
15177
+ this.queue.splice(index, 1);
15178
+ (_a3 = job.signal) == null ? void 0 : _a3.removeEventListener("abort", job.onAbort);
15179
+ job.reject(abortError());
15180
+ return;
15181
+ }
15182
+ const workerId = job.workerId;
15183
+ if (!this.finishJob(workerId, job)) return;
15184
+ (_b2 = this.workers[workerId]) == null ? void 0 : _b2.terminate();
15185
+ this.workers[workerId] = null;
15186
+ job.reject(abortError());
15187
+ this.drain();
15188
+ }
15189
+ startJob(workerId, job) {
15190
+ this.initWorker(workerId);
15191
+ job.workerId = workerId;
15192
+ this.active[workerId] = job;
15193
+ this.workerStatus |= 1 << workerId;
15194
+ try {
15195
+ this.workers[workerId].postMessage(job.msg, job.transfer);
15196
+ } catch (error) {
15197
+ this.onError(workerId, this.workers[workerId], { error });
15198
+ }
15199
+ }
15200
+ drain() {
15201
+ while (this.queue.length) {
15202
+ const workerId = this.getIdleWorker();
15203
+ if (workerId < 0) return;
15204
+ this.startJob(workerId, this.queue.shift());
14802
15205
  }
14803
15206
  }
14804
15207
  setWorkerCreator(workerCreator) {
@@ -14806,25 +15209,35 @@ class WorkerPool2 {
14806
15209
  }
14807
15210
  setWorkerLimit(limit) {
14808
15211
  this.limit = limit;
15212
+ this.drain();
14809
15213
  }
14810
- postMessage(msg, transfer) {
14811
- return new Promise((resolve) => {
14812
- const workerId = this.getIdleWorker();
14813
- if (workerId !== -1) {
14814
- this.initWorker(workerId);
14815
- this.workerStatus |= 1 << workerId;
14816
- this.workersResolve[workerId] = resolve;
14817
- this.workers[workerId].postMessage(msg, transfer);
14818
- } else {
14819
- this.queue.push({ resolve, msg, transfer });
14820
- }
15214
+ postMessage(msg, transfer, { signal } = {}) {
15215
+ if (this.disposed || (signal == null ? void 0 : signal.aborted)) return Promise.reject(abortError());
15216
+ return new Promise((resolve, reject) => {
15217
+ const job = { msg, transfer, signal, resolve, reject, workerId: null, onAbort: null };
15218
+ job.onAbort = () => this.cancelJob(job);
15219
+ signal == null ? void 0 : signal.addEventListener("abort", job.onAbort, { once: true });
15220
+ this.queue.push(job);
15221
+ this.drain();
14821
15222
  });
14822
15223
  }
14823
15224
  dispose() {
14824
- this.workers.forEach((worker) => worker.terminate());
14825
- this.workersResolve.length = 0;
15225
+ var _a3;
15226
+ if (this.disposed) return;
15227
+ this.disposed = true;
15228
+ for (const job of this.queue.splice(0)) {
15229
+ (_a3 = job.signal) == null ? void 0 : _a3.removeEventListener("abort", job.onAbort);
15230
+ job.reject(abortError());
15231
+ }
15232
+ for (let i2 = 0; i2 < this.active.length; i2++) {
15233
+ const job = this.active[i2];
15234
+ if (job) {
15235
+ this.finishJob(i2, job);
15236
+ job.reject(abortError());
15237
+ }
15238
+ }
15239
+ this.workers.forEach((worker) => worker == null ? void 0 : worker.terminate());
14826
15240
  this.workers.length = 0;
14827
- this.queue.length = 0;
14828
15241
  this.workerStatus = 0;
14829
15242
  }
14830
15243
  }
@@ -14850,7 +15263,33 @@ function intersectsTimeFrame(timeFrameStart = /* @__PURE__ */ new Date(-864e13),
14850
15263
  }
14851
15264
  return true;
14852
15265
  }
14853
- class ArrowFeature extends Object3D {
15266
+ class WorkerFeature extends Object3D {
15267
+ constructor() {
15268
+ super();
15269
+ this.workerAbortController = new AbortController();
15270
+ this.disposed = false;
15271
+ }
15272
+ runWorker(message, callbacks, onSuccess) {
15273
+ geoWorkerPool.postMessage(message, void 0, { signal: this.workerAbortController.signal }).then((response) => {
15274
+ var _a3;
15275
+ if (this.disposed) return;
15276
+ const { success, error } = response.data;
15277
+ if (success) onSuccess(response.data);
15278
+ else (_a3 = callbacks.onError) == null ? void 0 : _a3.call(callbacks, new Error((error == null ? void 0 : error.message) ?? String(error)));
15279
+ }).catch((error) => {
15280
+ var _a3;
15281
+ if (!this.disposed && (error == null ? void 0 : error.name) !== "AbortError") {
15282
+ (_a3 = callbacks.onError) == null ? void 0 : _a3.call(callbacks, error instanceof Error ? error : new Error(String(error)));
15283
+ }
15284
+ });
15285
+ }
15286
+ dispose() {
15287
+ if (this.disposed) return;
15288
+ this.disposed = true;
15289
+ this.workerAbortController.abort();
15290
+ }
15291
+ }
15292
+ class ArrowFeature extends WorkerFeature {
14854
15293
  constructor(data, options = {}, callbacks = {}) {
14855
15294
  var _a3, _b2, _c;
14856
15295
  super();
@@ -14861,28 +15300,22 @@ class ArrowFeature extends Object3D {
14861
15300
  const type = "arrow";
14862
15301
  const renderOrder = (options == null ? void 0 : options.renderOrder) ?? 0;
14863
15302
  const color = ((_c = data == null ? void 0 : data.properties) == null ? void 0 : _c.color) ?? 15955057;
14864
- geoWorkerPool.postMessage({ type, data, color }).then((response) => {
14865
- var _a4;
14866
- const { success, error, origin, meshVertexBuffer } = response.data;
14867
- if (success) {
14868
- this.position.fromArray(origin);
14869
- const meshGeometry = new BufferGeometry();
14870
- meshGeometry.setAttribute("position", new BufferAttribute(meshVertexBuffer, 3));
14871
- const meshMaterial = new MeshBasicMaterial({ color, side: DoubleSide, depthTest: false, opacity: 0.75, transparent: true, toneMapped: false });
14872
- meshMaterial.onBeforeCompile = (program) => {
14873
- program.vertexShader = annotation_default$1;
14874
- program.fragmentShader = annotation_default;
14875
- };
14876
- const mesh = new Mesh(meshGeometry, meshMaterial);
14877
- mesh.layers.set(renderOrder);
14878
- this.add(mesh);
14879
- } else {
14880
- (_a4 = callbacks.onError) == null ? void 0 : _a4.call(callbacks, new Error((error == null ? void 0 : error.message) ?? String(error)));
14881
- }
15303
+ this.runWorker({ type, data, color }, callbacks, ({ origin, meshVertexBuffer }) => {
15304
+ this.position.fromArray(origin);
15305
+ const meshGeometry = new BufferGeometry();
15306
+ meshGeometry.setAttribute("position", new BufferAttribute(meshVertexBuffer, 3));
15307
+ const meshMaterial = new MeshBasicMaterial({ color, side: DoubleSide, depthTest: false, opacity: 0.75, transparent: true, toneMapped: false });
15308
+ meshMaterial.onBeforeCompile = (program) => {
15309
+ program.vertexShader = annotation_default$1;
15310
+ program.fragmentShader = annotation_default;
15311
+ };
15312
+ const mesh = new Mesh(meshGeometry, meshMaterial);
15313
+ mesh.layers.set(renderOrder);
15314
+ this.add(mesh);
14882
15315
  });
14883
15316
  }
14884
15317
  }
14885
- class PerimeterFeature extends Object3D {
15318
+ class PerimeterFeature extends WorkerFeature {
14886
15319
  constructor(data, options = {}, callbacks = {}) {
14887
15320
  var _a3, _b2, _c;
14888
15321
  super();
@@ -14893,32 +15326,26 @@ class PerimeterFeature extends Object3D {
14893
15326
  const type = "perimeter";
14894
15327
  const renderOrder = (options == null ? void 0 : options.renderOrder) ?? 0;
14895
15328
  const color = ((_c = data == null ? void 0 : data.properties) == null ? void 0 : _c.color) ?? 15955057;
14896
- geoWorkerPool.postMessage({ type, data, color }).then((response) => {
14897
- var _a4;
14898
- const { success, error, origin, lineVertexBuffer, lineVertexRGBBuffer, meshVertexBuffer, meshVertexRGBBuffer, meshIndexBuffer } = response.data;
14899
- if (success) {
14900
- this.position.fromArray(origin);
14901
- const meshGeometry = new BufferGeometry();
14902
- meshGeometry.setAttribute("position", new BufferAttribute(meshVertexBuffer, 3));
14903
- meshGeometry.setAttribute("color", new BufferAttribute(meshVertexRGBBuffer, 3, true));
14904
- meshGeometry.setIndex(new BufferAttribute(meshIndexBuffer, 1));
14905
- const meshMaterial = new MeshBasicMaterial({ opacity: 0.2, transparent: true, side: DoubleSide, depthTest: false, vertexColors: true, toneMapped: false });
14906
- meshMaterial.onBeforeCompile = (program) => {
14907
- program.vertexShader = annotation_default$1;
14908
- program.fragmentShader = annotation_default;
14909
- };
14910
- const mesh = new Mesh(meshGeometry, meshMaterial);
14911
- mesh.layers.set(renderOrder);
14912
- const lineGeometry = new BufferGeometry();
14913
- lineGeometry.setAttribute("position", new BufferAttribute(lineVertexBuffer, 3));
14914
- lineGeometry.setAttribute("color", new BufferAttribute(lineVertexRGBBuffer, 3, true));
14915
- const line = new LineSegments(lineGeometry, new LineBasicMaterial({ vertexColors: true, toneMapped: false }));
14916
- line.layers.set(renderOrder);
14917
- line.add(mesh);
14918
- this.add(line);
14919
- } else {
14920
- (_a4 = callbacks.onError) == null ? void 0 : _a4.call(callbacks, new Error((error == null ? void 0 : error.message) ?? String(error)));
14921
- }
15329
+ this.runWorker({ type, data, color }, callbacks, ({ origin, lineVertexBuffer, lineVertexRGBBuffer, meshVertexBuffer, meshVertexRGBBuffer, meshIndexBuffer }) => {
15330
+ this.position.fromArray(origin);
15331
+ const meshGeometry = new BufferGeometry();
15332
+ meshGeometry.setAttribute("position", new BufferAttribute(meshVertexBuffer, 3));
15333
+ meshGeometry.setAttribute("color", new BufferAttribute(meshVertexRGBBuffer, 3, true));
15334
+ meshGeometry.setIndex(new BufferAttribute(meshIndexBuffer, 1));
15335
+ const meshMaterial = new MeshBasicMaterial({ opacity: 0.2, transparent: true, side: DoubleSide, depthTest: false, vertexColors: true, toneMapped: false });
15336
+ meshMaterial.onBeforeCompile = (program) => {
15337
+ program.vertexShader = annotation_default$1;
15338
+ program.fragmentShader = annotation_default;
15339
+ };
15340
+ const mesh = new Mesh(meshGeometry, meshMaterial);
15341
+ mesh.layers.set(renderOrder);
15342
+ const lineGeometry = new BufferGeometry();
15343
+ lineGeometry.setAttribute("position", new BufferAttribute(lineVertexBuffer, 3));
15344
+ lineGeometry.setAttribute("color", new BufferAttribute(lineVertexRGBBuffer, 3, true));
15345
+ const line = new LineSegments(lineGeometry, new LineBasicMaterial({ vertexColors: true, toneMapped: false }));
15346
+ line.layers.set(renderOrder);
15347
+ line.add(mesh);
15348
+ this.add(line);
14922
15349
  });
14923
15350
  }
14924
15351
  }
@@ -14928,6 +15355,7 @@ class GeojsonLayer extends ContentLayer {
14928
15355
  super();
14929
15356
  this.type = "GeojsonLayer";
14930
15357
  this.isGeojsonLayer = true;
15358
+ this.disposed = false;
14931
15359
  for (let i2 = 0; i2 < ((_a3 = data.features) == null ? void 0 : _a3.length); i2++) {
14932
15360
  const feature = data.features[i2];
14933
15361
  switch (feature.properties.type) {
@@ -14957,78 +15385,13 @@ class GeojsonLayer extends ContentLayer {
14957
15385
  }
14958
15386
  }
14959
15387
  dispose() {
15388
+ if (this.disposed) return;
15389
+ this.disposed = true;
14960
15390
  super.dispose();
14961
15391
  this.disposeObjectResources();
14962
15392
  this.clear();
14963
15393
  }
14964
15394
  }
14965
- const GAUSSIAN_FORMATS = /* @__PURE__ */ new Set(["ply", "sog", "spz", "rad"]);
14966
- function requireNonEmptyString(value, field) {
14967
- if (typeof value !== "string" || value.trim().length === 0) {
14968
- throw new Error(`${field} must be a non-empty string.`);
14969
- }
14970
- }
14971
- function validateGaussianSplatLayerDefinition(definition) {
14972
- var _a3, _b2, _c, _d;
14973
- if (!definition || typeof definition !== "object") {
14974
- throw new Error("Gaussian splat layer definition must be an object.");
14975
- }
14976
- requireNonEmptyString(definition.id, "id");
14977
- requireNonEmptyString(definition.name, "name");
14978
- if (definition.type !== "gaussian-splat") {
14979
- throw new Error('type must be "gaussian-splat".');
14980
- }
14981
- if (!Array.isArray(definition.labels) || !definition.labels.every((label) => typeof label === "string")) {
14982
- throw new Error("labels must be an array of strings.");
14983
- }
14984
- requireNonEmptyString((_a3 = definition.data) == null ? void 0 : _a3.url, "data.url");
14985
- if (!GAUSSIAN_FORMATS.has((_b2 = definition.data) == null ? void 0 : _b2.format)) {
14986
- throw new Error('data.format must be "ply", "sog", "spz", or "rad".');
14987
- }
14988
- const renderOrder = ((_c = definition.options) == null ? void 0 : _c.renderOrder) ?? 0;
14989
- if (renderOrder !== 0) {
14990
- throw new Error("Gaussian splat layers only support renderOrder 0.");
14991
- }
14992
- const transform = (_d = definition.options) == null ? void 0 : _d.transform;
14993
- const anchor = transform == null ? void 0 : transform.anchor;
14994
- if (!anchor) {
14995
- throw new Error("options.transform.anchor must contain finite longitude, latitude, and altitude values.");
14996
- }
14997
- validateGeodeticPosition(anchor.longitude, anchor.latitude, anchor.altitude, "Gaussian anchor");
14998
- const translationENU = transform.translationENU ?? [0, 0, 0];
14999
- const rotationDegrees = transform.rotationDegrees ?? [0, 0, 0];
15000
- const scale = transform.scale ?? 1;
15001
- validateTuple(translationENU, "translationENU");
15002
- validateTuple(rotationDegrees, "rotationDegrees");
15003
- validateScale(scale, "scale");
15004
- return {
15005
- ...definition,
15006
- labels: [...definition.labels],
15007
- data: { ...definition.data },
15008
- options: {
15009
- ...definition.options,
15010
- renderOrder: 0,
15011
- transform: {
15012
- anchor: { ...anchor },
15013
- translationENU: [...translationENU],
15014
- rotationDegrees: [...rotationDegrees],
15015
- scale
15016
- }
15017
- }
15018
- };
15019
- }
15020
- function makeGaussianSplatTransform(transform) {
15021
- const { anchor, translationENU, rotationDegrees, scale } = transform;
15022
- const basis = getEnuBasis(anchor.longitude, anchor.latitude);
15023
- const east = new Vector3().fromArray(basis.east);
15024
- const north = new Vector3().fromArray(basis.north);
15025
- const up = new Vector3().fromArray(basis.up);
15026
- const enuFrame = new Matrix4().makeBasis(east, north, up);
15027
- enuFrame.setPosition(new Vector3().fromArray(geodeticToEcefPosition(anchor.longitude, anchor.latitude, anchor.altitude)));
15028
- const rotation = new Quaternion().setFromEuler(new Euler(rotationDegrees[0] * Math.PI / 180, rotationDegrees[1] * Math.PI / 180, rotationDegrees[2] * Math.PI / 180, "XYZ"));
15029
- const localTransform = new Matrix4().compose(new Vector3().fromArray(translationENU), rotation, new Vector3(scale, scale, scale));
15030
- return enuFrame.multiply(localTransform);
15031
- }
15032
15395
  function formatType(spark, format) {
15033
15396
  return { ply: spark.SplatFileType.PLY, sog: spark.SplatFileType.PCSOGSZIP, spz: spark.SplatFileType.SPZ, rad: spark.SplatFileType.RAD }[format];
15034
15397
  }
@@ -15054,6 +15417,10 @@ class GaussianSplatLayer extends ContentLayer {
15054
15417
  }
15055
15418
  setEnabled(enabled) {
15056
15419
  if (this.loadState === "disposed") return;
15420
+ if (!enabled) {
15421
+ this.dispose();
15422
+ return;
15423
+ }
15057
15424
  const wasEnabled = this.visible;
15058
15425
  this.visible = enabled;
15059
15426
  if (enabled && !wasEnabled && (this.loadState === "idle" || this.loadState === "error")) {
@@ -15141,9 +15508,11 @@ class GaussianSplatLayer extends ContentLayer {
15141
15508
  });
15142
15509
  }
15143
15510
  disposeMesh(mesh) {
15511
+ var _a3, _b2;
15144
15512
  if (!mesh || mesh.userData.gaussianSplatDisposed) return;
15145
15513
  mesh.userData.gaussianSplatDisposed = true;
15146
15514
  mesh.removeFromParent();
15515
+ if (mesh.paged) (_b2 = (_a3 = this.callbacks).releasePagedSplats) == null ? void 0 : _b2.call(_a3, mesh.paged);
15147
15516
  mesh.dispose();
15148
15517
  if (this.splatMesh === mesh) this.splatMesh = null;
15149
15518
  }
@@ -15159,6 +15528,197 @@ class GaussianSplatLayer extends ContentLayer {
15159
15528
  super.dispose();
15160
15529
  }
15161
15530
  }
15531
+ class ContentLayerRegistry {
15532
+ /** @param {{ group?: import('three').Group, createLayer?: (definition: any) => any, onError?: (definition: any, error: Error) => void, onAllSplatsDisabled?: () => void }} [options] */
15533
+ constructor({ group, createLayer, onError, onAllSplatsDisabled } = {}) {
15534
+ this.group = group;
15535
+ this.createLayer = createLayer;
15536
+ this.onError = onError;
15537
+ this.onAllSplatsDisabled = onAllSplatsDisabled;
15538
+ this.definitions = [];
15539
+ this.enabledLabels = /* @__PURE__ */ new Set();
15540
+ this.active = /* @__PURE__ */ new Map();
15541
+ this.timeFrameStart = null;
15542
+ this.timeFrameEnd = null;
15543
+ this.disposed = false;
15544
+ }
15545
+ setDefinitions(definitions = []) {
15546
+ if (this.disposed) return;
15547
+ this.clear();
15548
+ this.definitions = [...definitions];
15549
+ this.reconcile();
15550
+ }
15551
+ setEnabledLabels(labels = []) {
15552
+ if (this.disposed) return;
15553
+ this.enabledLabels = new Set(labels);
15554
+ this.reconcile();
15555
+ }
15556
+ setTimeFrame(start, end) {
15557
+ var _a3;
15558
+ if (this.disposed) return;
15559
+ this.timeFrameStart = start;
15560
+ this.timeFrameEnd = end;
15561
+ for (const layer of this.active.values()) (_a3 = layer.setTimeFrame) == null ? void 0 : _a3.call(layer, start, end);
15562
+ }
15563
+ getActiveLayer(id) {
15564
+ return this.active.get(id) ?? null;
15565
+ }
15566
+ createActiveLayer(definition) {
15567
+ var _a3, _b2, _c, _d, _e;
15568
+ const layer = this.createLayer(definition);
15569
+ try {
15570
+ layer.contentLayerId = definition.id;
15571
+ layer.setLabels(definition.labels);
15572
+ layer.contentRenderOrder = definition.type === "mesh" && ((_a3 = definition.options) == null ? void 0 : _a3.transform) ? 0 : ((_b2 = definition.options) == null ? void 0 : _b2.renderOrder) ?? 0;
15573
+ layer.xrRenderLayer = layer.xrRenderLayer ?? (definition.type === "mesh" && ((_c = definition.options) == null ? void 0 : _c.transform) ? 0 : definition.type === "mesh" ? 6 : layer.contentRenderOrder);
15574
+ (_d = layer.setTimeFrame) == null ? void 0 : _d.call(layer, this.timeFrameStart, this.timeFrameEnd);
15575
+ layer.setEnabled(true);
15576
+ return layer;
15577
+ } catch (error) {
15578
+ (_e = layer.dispose) == null ? void 0 : _e.call(layer);
15579
+ throw error;
15580
+ }
15581
+ }
15582
+ orderActiveLayers() {
15583
+ const order = new Map(this.definitions.map((definition, index) => [definition.id, index]));
15584
+ this.group.children.sort((a2, b2) => (order.get(a2.contentLayerId) ?? 0) - (order.get(b2.contentLayerId) ?? 0));
15585
+ }
15586
+ /** Replace one definition while preserving unrelated live layers. */
15587
+ replaceDefinition(id, definition) {
15588
+ var _a3, _b2, _c, _d;
15589
+ if (this.disposed) return false;
15590
+ const index = this.definitions.findIndex((item) => item.id === id);
15591
+ const wanted = ((_a3 = definition == null ? void 0 : definition.labels) == null ? void 0 : _a3.some((label) => this.enabledLabels.has(label))) ?? false;
15592
+ let incoming = null;
15593
+ if (wanted) {
15594
+ try {
15595
+ incoming = this.createActiveLayer(definition);
15596
+ } catch (error) {
15597
+ (_b2 = this.onError) == null ? void 0 : _b2.call(this, definition, error);
15598
+ return false;
15599
+ }
15600
+ }
15601
+ const outgoing = this.active.get(id);
15602
+ const hadSplats = [...this.active.values()].some((layer) => layer.isGaussianSplatLayer);
15603
+ if (outgoing) {
15604
+ (_c = outgoing.dispose) == null ? void 0 : _c.call(outgoing);
15605
+ this.group.remove(outgoing);
15606
+ this.active.delete(id);
15607
+ }
15608
+ if (definition) {
15609
+ if (index < 0) this.definitions.push(definition);
15610
+ else this.definitions[index] = definition;
15611
+ } else if (index >= 0) this.definitions.splice(index, 1);
15612
+ if (incoming) {
15613
+ this.group.add(incoming);
15614
+ this.active.set(id, incoming);
15615
+ }
15616
+ this.orderActiveLayers();
15617
+ if (hadSplats && ![...this.active.values()].some((layer) => layer.isGaussianSplatLayer)) (_d = this.onAllSplatsDisabled) == null ? void 0 : _d.call(this);
15618
+ return true;
15619
+ }
15620
+ reconcile() {
15621
+ var _a3, _b2, _c;
15622
+ const wanted = new Set(this.definitions.filter((definition) => {
15623
+ var _a4;
15624
+ return (_a4 = definition.labels) == null ? void 0 : _a4.some((label) => this.enabledLabels.has(label));
15625
+ }).map((definition) => definition.id));
15626
+ const hadSplats = [...this.active.values()].some((layer) => layer.isGaussianSplatLayer);
15627
+ for (const [id, layer] of this.active) {
15628
+ if (!wanted.has(id)) {
15629
+ (_a3 = layer.dispose) == null ? void 0 : _a3.call(layer);
15630
+ this.group.remove(layer);
15631
+ this.active.delete(id);
15632
+ }
15633
+ }
15634
+ for (const definition of this.definitions) {
15635
+ if (!wanted.has(definition.id) || this.active.has(definition.id)) continue;
15636
+ try {
15637
+ const layer = this.createActiveLayer(definition);
15638
+ this.group.add(layer);
15639
+ this.active.set(definition.id, layer);
15640
+ } catch (error) {
15641
+ (_b2 = this.onError) == null ? void 0 : _b2.call(this, definition, error);
15642
+ }
15643
+ }
15644
+ this.orderActiveLayers();
15645
+ if (hadSplats && ![...this.active.values()].some((layer) => layer.isGaussianSplatLayer)) (_c = this.onAllSplatsDisabled) == null ? void 0 : _c.call(this);
15646
+ }
15647
+ clear() {
15648
+ var _a3, _b2;
15649
+ for (const layer of this.active.values()) {
15650
+ (_a3 = layer.dispose) == null ? void 0 : _a3.call(layer);
15651
+ this.group.remove(layer);
15652
+ }
15653
+ const hadSplats = [...this.active.values()].some((layer) => layer.isGaussianSplatLayer);
15654
+ this.active.clear();
15655
+ this.definitions = [];
15656
+ if (hadSplats) (_b2 = this.onAllSplatsDisabled) == null ? void 0 : _b2.call(this);
15657
+ }
15658
+ dispose() {
15659
+ if (this.disposed) return;
15660
+ this.clear();
15661
+ this.disposed = true;
15662
+ }
15663
+ }
15664
+ class SplatDestinationPrefetch {
15665
+ constructor({ getRenderer, getLayer }) {
15666
+ this.getRenderer = getRenderer;
15667
+ this.getLayer = getLayer;
15668
+ this.target = null;
15669
+ this.boundRenderer = null;
15670
+ this.boundMeshes = [];
15671
+ this.timeoutId = null;
15672
+ this.disposed = false;
15673
+ }
15674
+ set(target) {
15675
+ if (this.disposed || !target || !Number.isFinite(target.timeoutMs) || target.timeoutMs <= 0 || target.timeoutMs > 3e4) return;
15676
+ this.clear("cancel");
15677
+ this.target = target;
15678
+ this.timeoutId = setTimeout(() => this.clear("timeout"), target.timeoutMs);
15679
+ this.sync();
15680
+ }
15681
+ sync() {
15682
+ var _a3;
15683
+ if (this.disposed || !this.target) return;
15684
+ const renderer = this.getRenderer();
15685
+ const meshes = [...new Set(this.target.layerIds)].map((id) => this.getLayer(id)).filter(
15686
+ (layer) => {
15687
+ var _a4, _b2, _c;
15688
+ return (layer == null ? void 0 : layer.isGaussianSplatLayer) && layer.visible && ((_b2 = (_a4 = layer.definition) == null ? void 0 : _a4.data) == null ? void 0 : _b2.format) === "rad" && ((_c = layer.splatMesh) == null ? void 0 : _c.paged) && layer.loadState !== "disposed";
15689
+ }
15690
+ ).map((layer) => layer.splatMesh);
15691
+ if (renderer === this.boundRenderer && meshes.length === this.boundMeshes.length && meshes.every((mesh, i2) => mesh === this.boundMeshes[i2])) return;
15692
+ (_a3 = this.boundRenderer) == null ? void 0 : _a3.clearDestinationHint(false);
15693
+ this.boundRenderer = null;
15694
+ this.boundMeshes = [];
15695
+ if (!renderer || meshes.length === 0) return;
15696
+ const target = this.target;
15697
+ renderer.setDestinationHint({
15698
+ position: new Vector3().fromArray(geodeticToEcefPosition(target.longitude, target.latitude, target.altitude)),
15699
+ quaternion: geodeticToEcefRotation(target.longitude, target.latitude, target.pitch, target.yaw, target.roll),
15700
+ meshes,
15701
+ maxChunks: target.mode === "xr" ? 1 : 4,
15702
+ maxSplats: 3e4
15703
+ });
15704
+ this.boundRenderer = renderer;
15705
+ this.boundMeshes = meshes;
15706
+ }
15707
+ clear(reason = "cancel") {
15708
+ var _a3;
15709
+ if (this.timeoutId !== null) clearTimeout(this.timeoutId);
15710
+ this.timeoutId = null;
15711
+ this.target = null;
15712
+ (_a3 = this.boundRenderer) == null ? void 0 : _a3.clearDestinationHint(reason === "arrival");
15713
+ this.boundRenderer = null;
15714
+ this.boundMeshes = [];
15715
+ }
15716
+ dispose() {
15717
+ if (this.disposed) return;
15718
+ this.clear("cancel");
15719
+ this.disposed = true;
15720
+ }
15721
+ }
15162
15722
  function applyKeyboardMovement(position, forward, right, up, state, deltaTime, movementSpeed, boostMultiplier) {
15163
15723
  const boost = state.BOOST ? boostMultiplier : 1;
15164
15724
  const distance = movementSpeed * deltaTime * boost;
@@ -15533,127 +16093,47 @@ class XRNavigationCue {
15533
16093
  this.scene.remove(this.group);
15534
16094
  }
15535
16095
  }
15536
- const cesiumLogoUrl = "data:image/png;base64,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";
15537
- const googleLogoUrl = "data:image/png;base64,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";
15538
- const HEAD_PANEL_OFFSET = new Matrix4().makeTranslation(-0.35, -0.55, -1.2);
15539
- function attributionText(tileAttributions = [], terrainCredits = []) {
15540
- const values = [
15541
- ...tileAttributions.filter(({ type, value }) => type === "string" && typeof value === "string").map(({ value }) => value),
15542
- ...terrainCredits.filter((value) => typeof value === "string")
15543
- ];
15544
- return [...new Set(values.map((value) => value.replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&nbsp;/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").trim()).filter(Boolean))];
15545
- }
15546
- function wrap(ctx, value, maxWidth) {
15547
- const lines = [];
15548
- let line = "";
15549
- const words = value.split(/\s+/).flatMap((word) => {
15550
- if (ctx.measureText(word).width <= maxWidth) return [word];
15551
- const pieces = [];
15552
- let piece = "";
15553
- for (const character of word) {
15554
- if (piece && ctx.measureText(piece + character).width > maxWidth) {
15555
- pieces.push(piece);
15556
- piece = "";
15557
- }
15558
- piece += character;
15559
- }
15560
- if (piece) pieces.push(piece);
15561
- return pieces;
15562
- });
15563
- for (const word of words) {
15564
- const candidate = line ? `${line} ${word}` : word;
15565
- if (line && ctx.measureText(candidate).width > maxWidth) {
15566
- lines.push(line);
15567
- line = word;
15568
- } else line = candidate;
15569
- }
15570
- if (line) lines.push(line);
15571
- return lines;
15572
- }
15573
- function layoutAttributionLines(ctx, values) {
15574
- const lines = values.flatMap((value) => wrap(ctx, value, 540));
15575
- const rows = Math.max(1, Math.ceil(lines.length / 2));
15576
- const lineHeight = Math.min(38, 230 / rows);
15577
- const fontSize = Math.min(32, lineHeight - 4);
15578
- return lines.map((text, index) => ({
15579
- text,
15580
- x: index < rows ? 30 : 630,
15581
- y: 120 + index % rows * lineHeight,
15582
- fontSize
15583
- }));
15584
- }
15585
- class XRAttributionPanel {
16096
+ const HEAD_OFFSET = new Matrix4().makeTranslation(0.35, -0.32, -0.9);
16097
+ class XRDiagnosticsPanel {
15586
16098
  constructor() {
15587
16099
  const canvas = document.createElement("canvas");
15588
- canvas.width = 1200;
15589
- canvas.height = 360;
15590
- this.canvas = canvas;
16100
+ canvas.width = 480;
16101
+ canvas.height = 220;
15591
16102
  this.context = canvas.getContext("2d");
15592
16103
  this.texture = new CanvasTexture(canvas);
15593
16104
  this.texture.colorSpace = SRGBColorSpace;
15594
- this.mesh = new Mesh(new PlaneGeometry(1.1, 0.33), new MeshBasicMaterial({ map: this.texture, transparent: true, depthTest: false, depthWrite: false, side: DoubleSide, toneMapped: false }));
15595
- this.mesh.name = "XRAttributionPanel";
16105
+ this.mesh = new Mesh(new PlaneGeometry(0.42, 0.1925), new MeshBasicMaterial({ map: this.texture, transparent: true, depthTest: false, depthWrite: false, side: DoubleSide, toneMapped: false }));
16106
+ this.mesh.name = "XRDiagnosticsPanel";
15596
16107
  this.mesh.matrixAutoUpdate = false;
15597
16108
  this.mesh.layers.set(31);
15598
- this.mesh.renderOrder = 10002;
15599
- this.terrainCredits = [];
15600
- this.lastText = "";
15601
- this.lastTileCheckMs = -Infinity;
15602
- this.tileCredits = [];
15603
- this.logos = [];
15604
- for (const url of [cesiumLogoUrl, googleLogoUrl]) {
15605
- const image = new Image();
15606
- image.onload = () => this.draw();
15607
- image.src = url;
15608
- this.logos.push(image);
15609
- }
15610
- this.draw();
15611
- }
15612
- setTerrainCredits(credits) {
15613
- this.terrainCredits = Array.isArray(credits) ? credits : [];
15614
- this.draw();
15615
- }
15616
- update(headMatrix, tiles, timeMs) {
15617
- var _a3;
15618
- this.mesh.matrix.copy(headMatrix).multiply(HEAD_PANEL_OFFSET);
15619
- this.mesh.matrixWorldNeedsUpdate = true;
15620
- if (timeMs - this.lastTileCheckMs >= 1e3) {
15621
- this.lastTileCheckMs = timeMs;
15622
- this.tileCredits = ((_a3 = tiles == null ? void 0 : tiles.getAttributions) == null ? void 0 : _a3.call(tiles)) ?? [];
15623
- this.draw();
15624
- }
16109
+ this.mesh.renderOrder = 10003;
16110
+ this.rows = [];
15625
16111
  }
15626
- draw() {
15627
- var _a3, _b2;
16112
+ setRows(rows) {
16113
+ this.rows = rows.slice(0, 5).map(String);
15628
16114
  const ctx = this.context;
15629
16115
  if (!ctx) return;
15630
- const lines = attributionText(this.tileCredits, this.terrainCredits);
15631
- const signature = lines.join("\n") + ":" + this.logos.map((logo) => logo.complete && logo.naturalWidth > 0).join(",");
15632
- if (signature === this.lastText) return;
15633
- this.lastText = signature;
15634
- ctx.clearRect(0, 0, 1200, 360);
15635
- ctx.fillStyle = "rgba(255,255,255,0.82)";
15636
- ctx.fillRect(0, 0, 1200, 360);
15637
- ctx.fillStyle = "#1b2430";
15638
- ctx.font = "bold 28px Arial, sans-serif";
15639
- if (((_a3 = this.logos[0]) == null ? void 0 : _a3.complete) && this.logos[0].naturalWidth > 0) ctx.drawImage(this.logos[0], 30, 22, 294, 50);
15640
- else ctx.fillText("Cesium ion", 30, 61);
15641
- if (((_b2 = this.logos[1]) == null ? void 0 : _b2.complete) && this.logos[1].naturalWidth > 0) ctx.drawImage(this.logos[1], 390, 28, 272, 50);
15642
- else ctx.fillText("Google Maps", 390, 61);
16116
+ ctx.clearRect(0, 0, 480, 220);
16117
+ ctx.fillStyle = "rgba(17,24,39,0.9)";
16118
+ ctx.beginPath();
16119
+ ctx.roundRect(0, 0, 480, 220, 24);
16120
+ ctx.fill();
16121
+ ctx.fillStyle = "#e5e7eb";
15643
16122
  ctx.font = "32px Arial, sans-serif";
15644
- for (const line of layoutAttributionLines(ctx, lines.length ? lines : ["Google Maps 3D Tiles"])) {
15645
- ctx.font = `${line.fontSize}px Arial, sans-serif`;
15646
- ctx.fillText(line.text, line.x, line.y);
15647
- }
16123
+ this.rows.forEach((row, index) => ctx.fillText(row, 24, 45 + index * 39, 432));
15648
16124
  this.texture.needsUpdate = true;
15649
16125
  }
16126
+ update(headMatrix) {
16127
+ this.mesh.matrix.copy(headMatrix).multiply(HEAD_OFFSET);
16128
+ this.mesh.matrixWorldNeedsUpdate = true;
16129
+ }
15650
16130
  dispose() {
15651
16131
  this.mesh.geometry.dispose();
15652
16132
  this.mesh.material.dispose();
15653
16133
  this.texture.dispose();
15654
16134
  }
15655
16135
  }
15656
- function createXRRenderBridge(viewer, initialHeadPose, { showAttribution = true } = {}) {
16136
+ function createXRRenderBridge(viewer, initialHeadPose, _options = {}) {
15657
16137
  const { camera, renderer } = viewer;
15658
16138
  if (camera.parent !== null) throw new Error("WebXR camera bridge requires an unparented viewer camera");
15659
16139
  camera.updateMatrixWorld(true);
@@ -15668,24 +16148,22 @@ function createXRRenderBridge(viewer, initialHeadPose, { showAttribution = true
15668
16148
  let currentHead = camera.matrix.clone().fromArray(initialHeadPose.matrix);
15669
16149
  let disposed = false;
15670
16150
  const comfort = new XRComfortOverlay();
15671
- const attribution = !showAttribution || typeof document === "undefined" || typeof Image === "undefined" ? null : new XRAttributionPanel();
16151
+ let diagnostics = null;
15672
16152
  const navigationCue = new XRNavigationCue(viewer.scene);
15673
16153
  anchor.add(comfort.mesh);
15674
- if (attribution) anchor.add(attribution.mesh);
15675
16154
  const restoreWorldPose = (world) => {
15676
16155
  if (camera.parent === anchor) anchor.remove(camera);
15677
16156
  world.decompose(camera.position, camera.quaternion, camera.scale);
15678
16157
  camera.updateMatrixWorld(true);
15679
16158
  };
15680
16159
  const renderBridge = (scene, renderCamera) => {
15681
- var _a3;
15682
16160
  if (disposed || renderCamera !== camera) return originalRender.call(renderer, scene, renderCamera);
15683
16161
  camera.updateMatrixWorld(true);
15684
16162
  const worldBeforeRender = camera.matrixWorld.clone();
15685
16163
  anchor.matrix.copy(rig.getVisualWorldFromLocalMatrix());
15686
16164
  anchor.updateMatrixWorld(true);
15687
16165
  comfort.update(currentHead);
15688
- attribution == null ? void 0 : attribution.update(currentHead, (_a3 = viewer.globeManager) == null ? void 0 : _a3.tiles, performance.now());
16166
+ diagnostics == null ? void 0 : diagnostics.update(currentHead);
15689
16167
  anchor.add(camera);
15690
16168
  currentHead.decompose(camera.position, camera.quaternion, camera.scale);
15691
16169
  camera.updateMatrixWorld(true);
@@ -15708,7 +16186,26 @@ function createXRRenderBridge(viewer, initialHeadPose, { showAttribution = true
15708
16186
  getHeadForward: () => rig.getVisualHeadForward(),
15709
16187
  getControllerWorldRay: (controller) => rig.getControllerWorldRay(controller),
15710
16188
  setNavigationCue: (cue) => navigationCue.set(cue),
15711
- setTerrainCredits: (credits) => attribution == null ? void 0 : attribution.setTerrainCredits(credits),
16189
+ setTerrainCredits: () => {
16190
+ },
16191
+ setDiagnosticsRows(rows) {
16192
+ if (disposed) return;
16193
+ if (!Array.isArray(rows) || rows.length === 0) {
16194
+ if (diagnostics) {
16195
+ anchor.remove(diagnostics.mesh);
16196
+ diagnostics.dispose();
16197
+ diagnostics = null;
16198
+ }
16199
+ return;
16200
+ }
16201
+ if (!diagnostics) {
16202
+ if (typeof document === "undefined") return;
16203
+ diagnostics = new XRDiagnosticsPanel();
16204
+ anchor.add(diagnostics.mesh);
16205
+ }
16206
+ diagnostics.setRows(rows);
16207
+ diagnostics.update(currentHead);
16208
+ },
15712
16209
  setPlayerPose(pose) {
15713
16210
  if (disposed) return;
15714
16211
  rig.setPose(pose);
@@ -15720,7 +16217,7 @@ function createXRRenderBridge(viewer, initialHeadPose, { showAttribution = true
15720
16217
  restoreWorldPose(rig.getVisualWorldHeadMatrix());
15721
16218
  },
15722
16219
  hasUi() {
15723
- return Boolean(attribution) || comfort.moving || comfort.navigationLimit !== null || comfort.fade > 0;
16220
+ return Boolean(diagnostics) || comfort.moving || comfort.navigationLimit !== null || comfort.fade > 0;
15724
16221
  },
15725
16222
  setNavigationLimit(reason) {
15726
16223
  if (comfort.setNavigationLimit(reason)) comfort.update(currentHead);
@@ -15748,9 +16245,10 @@ function createXRRenderBridge(viewer, initialHeadPose, { showAttribution = true
15748
16245
  if (camera.parent === anchor) restoreWorldPose(rig.getVisualWorldHeadMatrix());
15749
16246
  anchor.remove(comfort.mesh);
15750
16247
  comfort.dispose();
15751
- if (attribution) {
15752
- anchor.remove(attribution.mesh);
15753
- attribution.dispose();
16248
+ if (diagnostics) {
16249
+ anchor.remove(diagnostics.mesh);
16250
+ diagnostics.dispose();
16251
+ diagnostics = null;
15754
16252
  }
15755
16253
  navigationCue.dispose();
15756
16254
  viewer.scene.remove(anchor);
@@ -15763,7 +16261,6 @@ class WebXRSession {
15763
16261
  this.viewer = viewer;
15764
16262
  this.onFrame = options.onFrame;
15765
16263
  this.onStateChange = options.onStateChange;
15766
- this.showAttribution = options.showAttribution !== false;
15767
16264
  this.session = null;
15768
16265
  this.starting = null;
15769
16266
  this.bridge = null;
@@ -15873,8 +16370,10 @@ class WebXRSession {
15873
16370
  if (!referenceSpace) return;
15874
16371
  const pose = frame.getViewerPose(referenceSpace);
15875
16372
  if (!pose) return;
15876
- if (!this.bridge) this.bridge = createXRRenderBridge(this.viewer, pose.transform, { showAttribution: this.showAttribution });
15877
- else this.bridge.updateHeadPose(pose.transform);
16373
+ if (!this.bridge) {
16374
+ this.bridge = createXRRenderBridge(this.viewer, pose.transform, { showAttribution: false });
16375
+ this.bridge.setDiagnosticsRows(this.viewer.xrDiagnosticsRows);
16376
+ } else this.bridge.updateHeadPose(pose.transform);
15878
16377
  (_a3 = this.onFrame) == null ? void 0 : _a3.call(this, { time, frame, pose });
15879
16378
  this.applySparkProfile(this.viewer.sparkRenderer);
15880
16379
  this.viewer.animate(time);
@@ -15980,6 +16479,85 @@ function readXRFrameInput(frame, referenceSpace) {
15980
16479
  });
15981
16480
  return { head, controllers };
15982
16481
  }
16482
+ class DesktopLookControls {
16483
+ constructor(canvas, onLook) {
16484
+ var _a3;
16485
+ this.canvas = canvas;
16486
+ this.onLook = onLook;
16487
+ this.root = canvas.ownerDocument ?? canvas.getRootNode();
16488
+ this.window = this.root.defaultView ?? (typeof window === "undefined" ? null : window);
16489
+ this.pointer = null;
16490
+ this.down = (event) => {
16491
+ if (event.pointerType !== "mouse" || event.buttons !== 1 && event.buttons !== 2 || this.pointer) return;
16492
+ this.pointer = { id: event.pointerId, startX: event.clientX, startY: event.clientY, x: event.clientX, y: event.clientY, dragging: false };
16493
+ };
16494
+ this.move = (event) => {
16495
+ var _a4, _b2;
16496
+ const pointer = this.pointer;
16497
+ if (!pointer || event.pointerId !== pointer.id) return;
16498
+ if (!pointer.dragging) {
16499
+ if (Math.hypot(event.clientX - pointer.startX, event.clientY - pointer.startY) < 4) return;
16500
+ pointer.dragging = true;
16501
+ (_b2 = (_a4 = this.canvas).setPointerCapture) == null ? void 0 : _b2.call(_a4, pointer.id);
16502
+ }
16503
+ const dx = event.clientX - pointer.x;
16504
+ const dy = event.clientY - pointer.y;
16505
+ pointer.x = event.clientX;
16506
+ pointer.y = event.clientY;
16507
+ if (dx || dy) this.onLook(dx, dy);
16508
+ event.preventDefault();
16509
+ };
16510
+ this.end = (event) => {
16511
+ var _a4, _b2;
16512
+ if (!this.pointer || event.pointerId !== void 0 && event.pointerId !== this.pointer.id) return;
16513
+ if (this.pointer.dragging) {
16514
+ try {
16515
+ (_b2 = (_a4 = this.canvas).releasePointerCapture) == null ? void 0 : _b2.call(_a4, this.pointer.id);
16516
+ } catch {
16517
+ }
16518
+ }
16519
+ this.pointer = null;
16520
+ };
16521
+ this.wheel = (event) => event.preventDefault();
16522
+ this.contextMenu = (event) => event.preventDefault();
16523
+ canvas.addEventListener("pointerdown", this.down);
16524
+ canvas.addEventListener("wheel", this.wheel, { passive: false });
16525
+ canvas.addEventListener("contextmenu", this.contextMenu);
16526
+ this.root.addEventListener("pointermove", this.move);
16527
+ this.root.addEventListener("pointerup", this.end);
16528
+ this.root.addEventListener("pointercancel", this.end);
16529
+ this.root.addEventListener("lostpointercapture", this.end);
16530
+ (_a3 = this.window) == null ? void 0 : _a3.addEventListener("blur", this.end);
16531
+ }
16532
+ handleKeyDown(event) {
16533
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return false;
16534
+ const target = event.target;
16535
+ if ((target == null ? void 0 : target.isContentEditable) || ["INPUT", "TEXTAREA", "SELECT"].includes(target == null ? void 0 : target.tagName)) return false;
16536
+ if (target !== this.canvas && target !== this.root.body && target !== this.root.documentElement) return false;
16537
+ const delta = {
16538
+ ArrowLeft: [-16, 0],
16539
+ ArrowRight: [16, 0],
16540
+ ArrowUp: [0, -16],
16541
+ ArrowDown: [0, 16]
16542
+ }[event.key];
16543
+ if (!delta) return false;
16544
+ event.preventDefault();
16545
+ this.onLook(delta[0], delta[1]);
16546
+ return true;
16547
+ }
16548
+ dispose() {
16549
+ var _a3;
16550
+ this.end({});
16551
+ this.canvas.removeEventListener("pointerdown", this.down);
16552
+ this.canvas.removeEventListener("wheel", this.wheel);
16553
+ this.canvas.removeEventListener("contextmenu", this.contextMenu);
16554
+ this.root.removeEventListener("pointermove", this.move);
16555
+ this.root.removeEventListener("pointerup", this.end);
16556
+ this.root.removeEventListener("pointercancel", this.end);
16557
+ this.root.removeEventListener("lostpointercapture", this.end);
16558
+ (_a3 = this.window) == null ? void 0 : _a3.removeEventListener("blur", this.end);
16559
+ }
16560
+ }
15983
16561
  const shadowCanvas = document.createElement("canvas");
15984
16562
  shadowCanvas.width = 128;
15985
16563
  shadowCanvas.height = 128;
@@ -16020,6 +16598,11 @@ class Viewer extends EventDispatcher {
16020
16598
  this.type = "viewer";
16021
16599
  this.disposed = false;
16022
16600
  this.xrSession = null;
16601
+ this.xrDiagnosticsRows = null;
16602
+ this.loadingDiagnosticsEnabled = false;
16603
+ this.diagnosticFps = null;
16604
+ this.diagnosticWindowStart = null;
16605
+ this.diagnosticFrameCount = 0;
16023
16606
  this.sparkRenderer = null;
16024
16607
  this.transparentBackground = options.transparentBackground ?? true;
16025
16608
  Tokens.CESIUM = options.cesiumToken || void 0;
@@ -16058,14 +16641,33 @@ class Viewer extends EventDispatcher {
16058
16641
  this.scene = new Scene();
16059
16642
  this.content = new Group$1();
16060
16643
  this.scene.add(this.content);
16644
+ this.contentLayerRegistry = new ContentLayerRegistry({
16645
+ group: this.content,
16646
+ createLayer: (definition) => this.createContentLayer(definition),
16647
+ onError: (definition, error) => this.dispatchEvent({
16648
+ type: ViewerEvents.CONTENT_LAYER_ERROR,
16649
+ layerId: typeof (definition == null ? void 0 : definition.id) === "string" && definition.id.length > 0 ? definition.id : null,
16650
+ error: error instanceof Error ? error : new Error(String(error))
16651
+ }),
16652
+ onAllSplatsDisabled: () => this.disposeSparkRenderer()
16653
+ });
16654
+ this.splatDestinationPrefetch = new SplatDestinationPrefetch({
16655
+ getRenderer: () => this.sparkRenderer,
16656
+ getLayer: (id) => this.contentLayerRegistry.getActiveLayer(id)
16657
+ });
16061
16658
  this.topLayerIndex = 0;
16062
16659
  this.enabledLayers = [];
16063
16660
  this.labels = /* @__PURE__ */ new Map();
16064
16661
  this.features = /* @__PURE__ */ new Map();
16065
16662
  this.globeControls = new GlobeControls(this.scene, this.camera, this.renderer.domElement);
16066
16663
  this.globeControls.enableDamping = true;
16664
+ this._viewModeState = { version: 0, confirmedRotationSpeed: this.globeControls.rotationSpeed };
16665
+ this.desktopNavigationController = null;
16666
+ this._desktopControlsBefore = null;
16667
+ this.desktopLookControls = null;
16067
16668
  this._onGlobeControlsStart = () => {
16068
16669
  this.transitionControls.cancel();
16670
+ this.globeControls.adjustHeight = true;
16069
16671
  };
16070
16672
  this.globeControls.addEventListener("start", this._onGlobeControlsStart);
16071
16673
  this.transitionControls = new TransitionControls(this.camera);
@@ -16104,6 +16706,8 @@ class Viewer extends EventDispatcher {
16104
16706
  DOWN: false
16105
16707
  };
16106
16708
  this._onKeyDown = (event) => {
16709
+ var _a3;
16710
+ if (this.desktopNavigationController && this.keysEnabled && ((_a3 = this.desktopLookControls) == null ? void 0 : _a3.handleKeyDown(event))) return;
16107
16711
  if (event.repeat && !this.keysDown[event.code]) return;
16108
16712
  this.keysDown[event.code] = true;
16109
16713
  this.updateMovementState();
@@ -16115,9 +16719,15 @@ class Viewer extends EventDispatcher {
16115
16719
  this._onResize = (event) => {
16116
16720
  this.resizeView(event);
16117
16721
  };
16722
+ this._onWindowBlur = () => this._clearHeldKeys();
16723
+ this._onVisibilityChange = () => {
16724
+ if (document.hidden) this._clearHeldKeys();
16725
+ };
16118
16726
  window.addEventListener("keydown", this._onKeyDown);
16119
16727
  window.addEventListener("keyup", this._onKeyUp);
16120
16728
  window.addEventListener("resize", this._onResize);
16729
+ window.addEventListener("blur", this._onWindowBlur);
16730
+ document.addEventListener("visibilitychange", this._onVisibilityChange);
16121
16731
  if (container) this.appendTo(container);
16122
16732
  this.sky = new Sky();
16123
16733
  this.sky.scale.setScalar(2e7);
@@ -16159,12 +16769,13 @@ class Viewer extends EventDispatcher {
16159
16769
  }
16160
16770
  /** @param {{ onFrame?: (input: { time: number, frame: XRFrame, pose: XRViewerPose }) => void, onStateChange?: (active: boolean) => void, showAttribution?: boolean }} [options] */
16161
16771
  startXRSession(options = {}) {
16772
+ var _a3, _b2;
16162
16773
  if (this.disposed) return Promise.reject(new Error("Viewer has been disposed"));
16774
+ (_b2 = (_a3 = this.desktopNavigationController) == null ? void 0 : _a3.interrupt) == null ? void 0 : _b2.call(_a3, "XR session started");
16163
16775
  if (!this.xrSession) this.xrSession = new WebXRSession(this, options);
16164
16776
  else {
16165
16777
  this.xrSession.onFrame = options.onFrame;
16166
16778
  this.xrSession.onStateChange = options.onStateChange;
16167
- this.xrSession.showAttribution = options.showAttribution !== false;
16168
16779
  }
16169
16780
  return this.xrSession.start();
16170
16781
  }
@@ -16234,6 +16845,9 @@ class Viewer extends EventDispatcher {
16234
16845
  set keysEnabled(enabled) {
16235
16846
  if (enabled === this._keysEnabled) return;
16236
16847
  this._keysEnabled = enabled;
16848
+ this._clearHeldKeys();
16849
+ }
16850
+ _clearHeldKeys() {
16237
16851
  this.keysDown = {};
16238
16852
  for (const key in this.movementState) this.movementState[key] = false;
16239
16853
  }
@@ -16249,6 +16863,82 @@ class Viewer extends EventDispatcher {
16249
16863
  }
16250
16864
  }
16251
16865
  }
16866
+ if (this.movementState.FRONT || this.movementState.BACK || this.movementState.LEFT || this.movementState.RIGHT || this.movementState.UP || this.movementState.DOWN) {
16867
+ if (this.globeControls) this.globeControls.adjustHeight = true;
16868
+ }
16869
+ }
16870
+ /** Install one desktop camera owner. A null controller restores the prior globe controls. @param {DesktopNavigationController | null} controller */
16871
+ setDesktopNavigationController(controller) {
16872
+ var _a3, _b2, _c, _d;
16873
+ if (this.desktopNavigationController === controller) return;
16874
+ if (controller && this.xrActive) return;
16875
+ this._clearHeldKeys();
16876
+ if (controller) {
16877
+ this.transitionControls.cancel();
16878
+ if (this.desktopNavigationController) (_b2 = (_a3 = this.desktopNavigationController).interrupt) == null ? void 0 : _b2.call(_a3, "replaced");
16879
+ if (!this._desktopControlsBefore) {
16880
+ this._desktopControlsBefore = { enabled: this.globeControls.enabled, rotationSpeed: this.globeControls.rotationSpeed };
16881
+ }
16882
+ this.globeControls.enabled = false;
16883
+ this.globeControls.adjustHeight = false;
16884
+ this.globeControls.globeInertiaFactor = 0;
16885
+ this.globeControls.globeInertia.identity();
16886
+ this.desktopNavigationController = controller;
16887
+ const canvas = (_c = this.renderer) == null ? void 0 : _c.domElement;
16888
+ if ((canvas == null ? void 0 : canvas.getRootNode) && !this.desktopLookControls) this.desktopLookControls = new DesktopLookControls(canvas, (dx, dy) => this._applyDesktopLook(dx, dy));
16889
+ if (canvas == null ? void 0 : canvas.focus) {
16890
+ if (canvas.tabIndex < 0) canvas.tabIndex = 0;
16891
+ canvas.focus({ preventScroll: true });
16892
+ }
16893
+ } else {
16894
+ this.desktopNavigationController = null;
16895
+ (_d = this.desktopLookControls) == null ? void 0 : _d.dispose();
16896
+ this.desktopLookControls = null;
16897
+ if (this._desktopControlsBefore) {
16898
+ this.globeControls.adjustHeight = true;
16899
+ this.globeControls.rotationSpeed = this._desktopControlsBefore.rotationSpeed;
16900
+ this.globeControls.enabled = this._desktopControlsBefore.enabled;
16901
+ this._desktopControlsBefore = null;
16902
+ }
16903
+ }
16904
+ }
16905
+ /** Rotate Walk view around its eye; pointer delta is CSS pixels. */
16906
+ _applyDesktopLook(dx, dy) {
16907
+ var _a3, _b2;
16908
+ if (!this.desktopNavigationController || ((_b2 = (_a3 = this.desktopNavigationController).canLook) == null ? void 0 : _b2.call(_a3)) === false || this.xrActive) return;
16909
+ const { lon, lat, pitch, yaw, roll } = this.cameraCoords;
16910
+ if (![lon, lat, pitch, yaw, roll, dx, dy].every(Number.isFinite)) return;
16911
+ const nextPitch = MathUtils.clamp(pitch - dy * 0.15, -80, 80);
16912
+ const nextYaw = yaw - dx * 0.15;
16913
+ this.camera.quaternion.copy(geodeticToEcefRotation(lon, lat, nextPitch, nextYaw, roll));
16914
+ this.camera.updateMatrixWorld(true);
16915
+ this.cameraCoords = ecefToGeodeticRotation(this.camera.position.x, this.camera.position.y, this.camera.position.z, this.camera.quaternion);
16916
+ }
16917
+ /** Turn Walk toward north without moving its eye or leaving Walk. */
16918
+ turnDesktopNorth() {
16919
+ if (!this.desktopNavigationController || this.xrActive) return false;
16920
+ const { lon, lat, pitch, roll } = this.cameraCoords;
16921
+ if (![lon, lat, pitch, roll].every(Number.isFinite)) return false;
16922
+ this.camera.quaternion.copy(geodeticToEcefRotation(lon, lat, pitch, 0, roll));
16923
+ this.camera.updateMatrixWorld(true);
16924
+ this.cameraCoords = ecefToGeodeticRotation(this.camera.position.x, this.camera.position.y, this.camera.position.z, this.camera.quaternion);
16925
+ return true;
16926
+ }
16927
+ /** Invoke the desktop controller after globe input and before tiles/content/render. Invalid results leave the previous eye intact. */
16928
+ _applyDesktopNavigationFrame(timeMs, deltaSeconds) {
16929
+ const controller = this.desktopNavigationController;
16930
+ if (!controller || this.xrActive) return;
16931
+ const pose = this.cameraCoords;
16932
+ const result = controller.update({ timeMs, deltaSeconds, pose: { lon: pose.lon, lat: pose.lat, alt: pose.alt, pitch: pose.pitch, yaw: pose.yaw, roll: pose.roll }, movement: { ...this.movementState } });
16933
+ const { longitude, latitude, altitude } = (result == null ? void 0 : result.position) ?? {};
16934
+ if (![longitude, latitude, altitude].every(Number.isFinite) || longitude < -180 || longitude > 180 || latitude < -90 || latitude > 90 || result.pitch !== void 0 && !Number.isFinite(result.pitch)) {
16935
+ console.error("Desktop navigation returned an invalid camera pose");
16936
+ return;
16937
+ }
16938
+ this.camera.position.fromArray(geodeticToEcefPosition(longitude, latitude, altitude));
16939
+ if (result.pitch !== void 0) this.camera.quaternion.copy(geodeticToEcefRotation(longitude, latitude, result.pitch, pose.yaw, pose.roll));
16940
+ this.camera.updateMatrixWorld(true);
16941
+ this.cameraCoords = ecefToGeodeticRotation(this.camera.position.x, this.camera.position.y, this.camera.position.z, this.camera.quaternion);
16252
16942
  }
16253
16943
  /**
16254
16944
  * @param {number} lon
@@ -16327,11 +17017,8 @@ class Viewer extends EventDispatcher {
16327
17017
  }
16328
17018
  clearContentLayers() {
16329
17019
  var _a3;
16330
- while (this.content.children.length > 0) {
16331
- const layer = this.content.children[0];
16332
- (_a3 = layer.dispose) == null ? void 0 : _a3.call(layer);
16333
- this.content.remove(layer);
16334
- }
17020
+ (_a3 = this.splatDestinationPrefetch) == null ? void 0 : _a3.clear("cancel");
17021
+ this.contentLayerRegistry.clear();
16335
17022
  this.disposeSparkRenderer();
16336
17023
  }
16337
17024
  async ensureSparkRenderer() {
@@ -16347,110 +17034,111 @@ class Viewer extends EventDispatcher {
16347
17034
  return this.sparkRenderer;
16348
17035
  }
16349
17036
  disposeSparkRenderer() {
16350
- var _a3, _b2;
17037
+ var _a3, _b2, _c;
16351
17038
  this.sparkRendererGeneration = (this.sparkRendererGeneration ?? 0) + 1;
16352
17039
  if (!this.sparkRenderer) return;
17040
+ (_a3 = this.splatDestinationPrefetch) == null ? void 0 : _a3.sync();
16353
17041
  this.sparkRenderer.removeFromParent();
16354
- (_b2 = (_a3 = this.sparkRenderer).clearSplats) == null ? void 0 : _b2.call(_a3);
17042
+ (_c = (_b2 = this.sparkRenderer).clearSplats) == null ? void 0 : _c.call(_b2);
16355
17043
  this.sparkRenderer.dispose();
16356
17044
  this.sparkRenderer = null;
16357
17045
  }
17046
+ /** @private @param {import('../main.js').ContentLayerDefinition} sourceLayerData */
17047
+ prepareContentLayerDefinition(sourceLayerData) {
17048
+ const layerData = (sourceLayerData == null ? void 0 : sourceLayerData.type) === "gaussian-splat" ? validateGaussianSplatLayerDefinition(sourceLayerData) : sourceLayerData;
17049
+ if (typeof (layerData == null ? void 0 : layerData.id) !== "string" || !layerData.id || !Array.isArray(layerData.labels)) {
17050
+ throw new Error("Content layer requires a non-empty id and labels array.");
17051
+ }
17052
+ if (!["3d-tiles", "mesh", "geojson", "gaussian-splat"].includes(layerData.type)) {
17053
+ throw new Error(`Unsupported content layer type: ${String(layerData.type)}`);
17054
+ }
17055
+ return layerData;
17056
+ }
17057
+ /** @private @param {import('../main.js').ContentLayerDefinition} layerData */
17058
+ createContentLayer(layerData) {
17059
+ const onError = (error) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_ERROR, layerId: layerData.id, error });
17060
+ switch (layerData.type) {
17061
+ case "3d-tiles":
17062
+ return new TilesLayer(layerData.data.url, { camera: this.camera, renderer: this.renderer, ...layerData.options, decoders: this.tileDecoders }, { onError });
17063
+ case "mesh":
17064
+ return new MeshLayer(layerData.data.url, { ...layerData.options, decoders: this.tileDecoders }, { onError });
17065
+ case "geojson":
17066
+ return new GeojsonLayer(layerData.data, layerData.options, { onError });
17067
+ case "gaussian-splat":
17068
+ return new GaussianSplatLayer(layerData, {
17069
+ ensureRenderer: () => this.ensureSparkRenderer(),
17070
+ releasePagedSplats: (paged) => {
17071
+ var _a3, _b2;
17072
+ return (_b2 = (_a3 = this.sparkRenderer) == null ? void 0 : _a3.releasePagedSplats) == null ? void 0 : _b2.call(_a3, paged);
17073
+ },
17074
+ onStart: (layer) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_LOAD_START, layerId: layer.contentLayerId }),
17075
+ onProgress: (layer, progress) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_LOAD_PROGRESS, layerId: layer.contentLayerId, progress }),
17076
+ onReady: (layer) => {
17077
+ this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_READY, layerId: layer.contentLayerId });
17078
+ this.splatDestinationPrefetch.sync();
17079
+ },
17080
+ onError: (layer, error) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_ERROR, layerId: layer.contentLayerId, error })
17081
+ });
17082
+ default:
17083
+ throw new Error(`Unsupported content layer type: ${String(layerData.type)}`);
17084
+ }
17085
+ }
17086
+ /** @private */
17087
+ reportContentLayerError(sourceLayerData, error) {
17088
+ this.dispatchEvent({
17089
+ type: ViewerEvents.CONTENT_LAYER_ERROR,
17090
+ layerId: typeof (sourceLayerData == null ? void 0 : sourceLayerData.id) === "string" && sourceLayerData.id.length > 0 ? sourceLayerData.id : null,
17091
+ error: error instanceof Error ? error : new Error(String(error))
17092
+ });
17093
+ }
17094
+ /** @private */
17095
+ refreshContentLayerDepth() {
17096
+ this.topLayerIndex = Math.max(0, ...this.content.children.map((layer) => Math.max(layer.contentRenderOrder ?? 0, layer.xrRenderLayer ?? 0)));
17097
+ this.globeControls.pivotMesh.layers.set(this.topLayerIndex);
17098
+ }
16358
17099
  /** @param {import('../main.js').ContentLayerDefinition[]} content */
16359
17100
  defineContentLayers(content = []) {
16360
- var _a3, _b2, _c, _d;
16361
- this.topLayerIndex = 0;
16362
- this.clearContentLayers();
16363
- for (let i2 = 0; i2 < content.length; i2++) {
16364
- const sourceLayerData = content[i2];
17101
+ const definitions = [];
17102
+ for (const sourceLayerData of content) {
16365
17103
  try {
16366
- const layerData = (sourceLayerData == null ? void 0 : sourceLayerData.type) === "gaussian-splat" ? validateGaussianSplatLayerDefinition(sourceLayerData) : sourceLayerData;
16367
- this.topLayerIndex = Math.max(this.topLayerIndex, ((_a3 = layerData == null ? void 0 : layerData.options) == null ? void 0 : _a3.renderOrder) ?? 0);
16368
- switch (layerData == null ? void 0 : layerData.type) {
16369
- case "3d-tiles": {
16370
- const tilesLayer = new TilesLayer(
16371
- layerData.data.url,
16372
- { camera: this.camera, renderer: this.renderer, ...layerData.options, decoders: this.tileDecoders },
16373
- { onError: (error) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_ERROR, layerId: layerData.id, error }) }
16374
- );
16375
- tilesLayer.contentLayerId = layerData.id;
16376
- tilesLayer.setLabels(layerData.labels);
16377
- (_b2 = tilesLayer.setTimeFrame) == null ? void 0 : _b2.call(tilesLayer, this.timeFrameStart, this.timeFrameEnd);
16378
- tilesLayer.setEnabled(false);
16379
- this.content.add(tilesLayer);
16380
- break;
16381
- }
16382
- case "mesh": {
16383
- const meshLayer = new MeshLayer(
16384
- layerData.data.url,
16385
- { ...layerData.options },
16386
- { onError: (error) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_ERROR, layerId: layerData.id, error }) }
16387
- );
16388
- meshLayer.contentLayerId = layerData.id;
16389
- meshLayer.setLabels(layerData.labels);
16390
- meshLayer.setEnabled(false);
16391
- this.content.add(meshLayer);
16392
- break;
16393
- }
16394
- case "geojson": {
16395
- const geojsonLayer = new GeojsonLayer(layerData.data, layerData.options, {
16396
- onError: (error) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_ERROR, layerId: layerData.id, error })
16397
- });
16398
- geojsonLayer.contentLayerId = layerData.id;
16399
- geojsonLayer.setLabels(layerData.labels);
16400
- (_c = geojsonLayer.setTimeFrame) == null ? void 0 : _c.call(geojsonLayer, this.timeFrameStart, this.timeFrameEnd);
16401
- geojsonLayer.setEnabled(false);
16402
- this.content.add(geojsonLayer);
16403
- break;
16404
- }
16405
- case "gaussian-splat": {
16406
- const gaussianLayer = new GaussianSplatLayer(layerData, {
16407
- ensureRenderer: () => this.ensureSparkRenderer(),
16408
- onStart: (layer) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_LOAD_START, layerId: layer.contentLayerId }),
16409
- onProgress: (layer, progress) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_LOAD_PROGRESS, layerId: layer.contentLayerId, progress }),
16410
- onReady: (layer) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_READY, layerId: layer.contentLayerId }),
16411
- onError: (layer, error) => this.dispatchEvent({ type: ViewerEvents.CONTENT_LAYER_ERROR, layerId: layer.contentLayerId, error })
16412
- });
16413
- this.content.add(gaussianLayer);
16414
- break;
16415
- }
16416
- default:
16417
- throw new Error(`Unsupported content layer type: ${String(layerData == null ? void 0 : layerData.type)}`);
16418
- }
16419
- this.content.children.at(-1).xrRenderLayer = layerData.type === "mesh" ? 6 : ((_d = layerData.options) == null ? void 0 : _d.renderOrder) ?? 0;
17104
+ definitions.push(this.prepareContentLayerDefinition(sourceLayerData));
16420
17105
  } catch (error) {
16421
- this.dispatchEvent({
16422
- type: ViewerEvents.CONTENT_LAYER_ERROR,
16423
- layerId: typeof (sourceLayerData == null ? void 0 : sourceLayerData.id) === "string" && sourceLayerData.id.length > 0 ? sourceLayerData.id : null,
16424
- error: error instanceof Error ? error : new Error(String(error))
16425
- });
17106
+ this.reportContentLayerError(sourceLayerData, error);
16426
17107
  }
16427
17108
  }
16428
- this.globeControls.pivotMesh.layers.set(this.topLayerIndex);
16429
- this.enableContentLayers(this.enabledLayers);
17109
+ this.contentLayerRegistry.setDefinitions(definitions);
17110
+ this.splatDestinationPrefetch.sync();
17111
+ this.refreshContentLayerDepth();
16430
17112
  }
16431
- enableContentLayers(labels = []) {
16432
- this.enabledLayers = labels;
16433
- for (let i2 = 0; i2 < this.content.children.length; i2++) {
16434
- const contentLayer = this.content.children[i2];
16435
- let enabled = false;
16436
- for (let j2 = 0; j2 < labels.length; j2++) {
16437
- const label = labels[j2];
16438
- if (contentLayer.labels.has(label)) {
16439
- enabled = true;
16440
- break;
16441
- }
17113
+ /** Replace, add, or remove one content layer without rebuilding its siblings. */
17114
+ /** @param {string} id @param {import('../main.js').ContentLayerDefinition | null} definition */
17115
+ replaceContentLayer(id, definition) {
17116
+ if (this.disposed) return;
17117
+ if (typeof id !== "string" || id.length === 0) throw new Error("Content layer id must be a non-empty string.");
17118
+ if (definition && definition.id !== id) throw new Error("Replacement layer id must match the requested id.");
17119
+ let prepared = null;
17120
+ if (definition) {
17121
+ try {
17122
+ prepared = this.prepareContentLayerDefinition(definition);
17123
+ } catch (error) {
17124
+ this.reportContentLayerError(definition, error);
17125
+ return;
16442
17126
  }
16443
- contentLayer.setEnabled(enabled);
16444
17127
  }
17128
+ if (!this.contentLayerRegistry.replaceDefinition(id, prepared)) return;
17129
+ this.splatDestinationPrefetch.sync();
17130
+ this.refreshContentLayerDepth();
17131
+ }
17132
+ enableContentLayers(labels = []) {
17133
+ this.enabledLayers = labels;
17134
+ this.contentLayerRegistry.setEnabledLabels(labels);
17135
+ this.splatDestinationPrefetch.sync();
17136
+ this.refreshContentLayerDepth();
16445
17137
  }
16446
17138
  setTimeFrame(start, end) {
16447
- var _a3;
16448
17139
  this.timeFrameStart = start ? new Date(start) : null;
16449
17140
  this.timeFrameEnd = end ? new Date(end) : null;
16450
- for (let i2 = 0; i2 < this.content.children.length; i2++) {
16451
- const contentLayer = this.content.children[i2];
16452
- (_a3 = contentLayer.setTimeFrame) == null ? void 0 : _a3.call(contentLayer, this.timeFrameStart, this.timeFrameEnd);
16453
- }
17141
+ this.contentLayerRegistry.setTimeFrame(this.timeFrameStart, this.timeFrameEnd);
16454
17142
  }
16455
17143
  /**
16456
17144
  * @param {string} id
@@ -16510,7 +17198,16 @@ class Viewer extends EventDispatcher {
16510
17198
  }
16511
17199
  animate(time) {
16512
17200
  var _a3, _b2, _c;
16513
- if (this.stats) this.stats.begin();
17201
+ if (this.loadingDiagnosticsEnabled) {
17202
+ if (this.diagnosticWindowStart === null) this.diagnosticWindowStart = time;
17203
+ this.diagnosticFrameCount++;
17204
+ const elapsed = time - this.diagnosticWindowStart;
17205
+ if (elapsed >= 1e3) {
17206
+ this.diagnosticFps = Math.round(this.diagnosticFrameCount * 1e3 / elapsed);
17207
+ this.diagnosticWindowStart = time;
17208
+ this.diagnosticFrameCount = 0;
17209
+ }
17210
+ }
16514
17211
  this.transitionControls.update(time);
16515
17212
  this.state.get("time").value = time;
16516
17213
  const deltaTime = this.clock.getDelta();
@@ -16519,7 +17216,10 @@ class Viewer extends EventDispatcher {
16519
17216
  this.updateCameraDirections();
16520
17217
  this.cameraCoords = ecefToGeodeticRotation(this.camera.position.x, this.camera.position.y, this.camera.position.z, this.camera.quaternion);
16521
17218
  this.sky.setSurfaceUp(geodeticToEcefUpVector(this.cameraCoords.lon, this.cameraCoords.lat));
16522
- if (this.keysEnabled) {
17219
+ if (this.desktopNavigationController) {
17220
+ this._applyDesktopNavigationFrame(time, deltaTime);
17221
+ this.updateCameraDirections();
17222
+ } else if (this.keysEnabled) {
16523
17223
  applyKeyboardMovement(this.camera.position, this.cameraForward, this.cameraRight, this.cameraUp, this.movementState, deltaTime, this.movementSpeed, this.boostMultiplier);
16524
17224
  }
16525
17225
  this.globeManager.update();
@@ -16566,9 +17266,9 @@ class Viewer extends EventDispatcher {
16566
17266
  }
16567
17267
  this.cameraCoords = ecefToGeodeticRotation(this.camera.position.x, this.camera.position.y, this.camera.position.z, this.camera.quaternion);
16568
17268
  this.dispatchEvent({ type: ViewerEvents.ANIMATED, time, deltaTime });
16569
- if (this.stats) this.stats.end();
16570
17269
  }
16571
17270
  render() {
17271
+ this.splatDestinationPrefetch.sync();
16572
17272
  this.renderer.render(this.scene, this.camera);
16573
17273
  this.css2DRenderer.render(this.scene, this.camera);
16574
17274
  if (this.state.get("added") === true && this.state.get("ready") === false) {
@@ -16632,15 +17332,20 @@ class Viewer extends EventDispatcher {
16632
17332
  * @param {number} [yaw]
16633
17333
  * @param {number} [roll]
16634
17334
  * @param {number} [duration]
17335
+ * @returns {Promise<boolean>} Whether the requested transition completed.
16635
17336
  */
16636
17337
  async alignCamera(lon, lat, alt, pitch, yaw, roll, duration) {
17338
+ var _a3, _b2;
17339
+ (_b2 = (_a3 = this.desktopNavigationController) == null ? void 0 : _a3.interrupt) == null ? void 0 : _b2.call(_a3, "alignCamera");
16637
17340
  const position = validateGeodeticPosition(lon, lat, alt, "Camera position");
16638
17341
  const rotation = validateRotation(pitch ?? this.cameraCoords.pitch, yaw ?? this.cameraCoords.yaw, roll ?? this.cameraCoords.roll, "Camera rotation");
16639
17342
  const resolvedDuration = requireFiniteNumber(duration ?? TweenSettings.DURATION, "Camera transition duration");
16640
17343
  const targetPosition = new Vector3().fromArray(geodeticToEcefPosition(position.longitude, position.latitude, position.altitude));
16641
17344
  const targetQuaternion = geodeticToEcefRotation(position.longitude, position.latitude, rotation.pitch, rotation.yaw, rotation.roll);
17345
+ if (this.globeControls) this.globeControls.adjustHeight = false;
16642
17346
  return this.transitionControls.animateTo(targetPosition, targetQuaternion, resolvedDuration).then((completed) => {
16643
17347
  if (completed) this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt, ...rotation });
17348
+ return completed;
16644
17349
  });
16645
17350
  }
16646
17351
  /**
@@ -16650,8 +17355,11 @@ class Viewer extends EventDispatcher {
16650
17355
  * @param {number} [distance]
16651
17356
  * @param {number} [pitch]
16652
17357
  * @param {number} [duration]
17358
+ * @returns {Promise<boolean>} Whether the requested transition completed.
16653
17359
  */
16654
17360
  async focusCamera(lon, lat, alt, distance, pitch, duration) {
17361
+ var _a3, _b2;
17362
+ (_b2 = (_a3 = this.desktopNavigationController) == null ? void 0 : _a3.interrupt) == null ? void 0 : _b2.call(_a3, "focusCamera");
16655
17363
  const position = validateGeodeticPosition(lon, lat, alt, "Camera focus");
16656
17364
  const resolvedDistance = requireFiniteNumber(distance ?? 2e3, "Camera focus distance");
16657
17365
  const rotation = validateRotation(pitch ?? this.cameraCoords.pitch, 0, 0, "Camera rotation");
@@ -16660,25 +17368,72 @@ class Viewer extends EventDispatcher {
16660
17368
  const targetQuaternion = geodeticToEcefRotation(position.longitude, position.latitude, rotation.pitch, rotation.yaw, rotation.roll);
16661
17369
  const direction = new Vector3(0, 0, 1).applyQuaternion(targetQuaternion);
16662
17370
  targetPosition.addScaledVector(direction, resolvedDistance);
17371
+ if (this.globeControls) this.globeControls.adjustHeight = true;
16663
17372
  return this.transitionControls.animateTo(targetPosition, targetQuaternion, resolvedDuration).then((completed) => {
16664
17373
  if (completed) this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt });
17374
+ return completed;
16665
17375
  });
16666
17376
  }
16667
17377
  /**
16668
17378
  * Temporarily load Google 3D tiles around a WGS84 destination without changing the live view.
16669
17379
  * Position and altitude use degrees and WGS84 ellipsoidal metres; rotation uses degrees.
16670
- * @param {{longitude:number, latitude:number, altitude:number, pitch:number, yaw:number, roll:number, resolutionPixels:128|256} | null} target
17380
+ * @param {{longitude:number, latitude:number, altitude:number, pitch:number, yaw:number, roll:number, resolutionPixels:128|256, timeoutMs?:number} | null} target
16671
17381
  */
16672
17382
  setDestinationTilePrefetch(target) {
16673
17383
  if (this.disposed) return;
16674
17384
  this.globeManager.setDestinationTilePrefetch(target);
16675
17385
  }
17386
+ /**
17387
+ * Warm only active RAD layers at a WGS84 destination. This never changes the live camera.
17388
+ * @param {{longitude:number, latitude:number, altitude:number, pitch:number, yaw:number, roll:number, layerIds:string[], mode:'desktop'|'xr', timeoutMs:number} | null} target
17389
+ * @param {'cancel'|'arrival'} [clearReason]
17390
+ */
17391
+ setDestinationSplatPrefetch(target, clearReason = "cancel") {
17392
+ if (this.disposed) return;
17393
+ if (!target) {
17394
+ this.splatDestinationPrefetch.clear(clearReason);
17395
+ return;
17396
+ }
17397
+ try {
17398
+ validateGeodeticPosition(target.longitude, target.latitude, target.altitude, "Destination splat prefetch");
17399
+ validateRotation(target.pitch, target.yaw, target.roll, "Destination splat prefetch rotation");
17400
+ } catch {
17401
+ return;
17402
+ }
17403
+ if (!Array.isArray(target.layerIds) || !target.layerIds.every((id) => typeof id === "string") || !["desktop", "xr"].includes(target.mode)) return;
17404
+ this.splatDestinationPrefetch.set(target);
17405
+ }
17406
+ /** Optional viewer-owned counters, sampled by the app only while its stats setting is on.
17407
+ * @param {boolean} enabled
17408
+ */
17409
+ setLoadingDiagnosticsEnabled(enabled) {
17410
+ this.loadingDiagnosticsEnabled = Boolean(enabled);
17411
+ if (!enabled) {
17412
+ this.diagnosticFps = null;
17413
+ this.diagnosticWindowStart = null;
17414
+ this.diagnosticFrameCount = 0;
17415
+ }
17416
+ }
17417
+ getLoadingDiagnostics() {
17418
+ return readLoadingDiagnostics(this);
17419
+ }
17420
+ /** Short numeric rows in a small lower-right panel for both XR eyes.
17421
+ * @param {string[] | null} rows
17422
+ */
17423
+ setXRDiagnosticsPanel(rows) {
17424
+ var _a3, _b2;
17425
+ this.xrDiagnosticsRows = Array.isArray(rows) && rows.length > 0 ? rows.slice(0, 5).map(String) : null;
17426
+ (_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.setDiagnosticsRows(this.xrDiagnosticsRows);
17427
+ }
16676
17428
  /**
16677
17429
  * @param {number} [pitch]
16678
17430
  * @param {number} [yaw]
16679
17431
  * @param {number} [duration]
17432
+ * @returns {Promise<boolean>} Whether the requested transition completed.
16680
17433
  */
16681
17434
  async angleCamera(pitch, yaw, duration) {
17435
+ var _a3, _b2;
17436
+ (_b2 = (_a3 = this.desktopNavigationController) == null ? void 0 : _a3.interrupt) == null ? void 0 : _b2.call(_a3, "angleCamera");
16682
17437
  const rotation = validateRotation(pitch ?? this.cameraCoords.pitch, yaw ?? this.cameraCoords.yaw, 0, "Camera rotation");
16683
17438
  const resolvedDuration = requireFiniteNumber(duration ?? TweenSettings.DURATION, "Camera transition duration");
16684
17439
  const pivot = this.getCameraPivot();
@@ -16690,15 +17445,27 @@ class Viewer extends EventDispatcher {
16690
17445
  targetPosition.addScaledVector(direction, distance);
16691
17446
  return this.transitionControls.animateTo(targetPosition, targetQuaternion, resolvedDuration).then((completed) => {
16692
17447
  if (completed) this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt });
17448
+ return completed;
16693
17449
  });
16694
17450
  }
16695
- setViewMode(mode = "3d") {
16696
- if (mode == "3d") {
16697
- this.globeControls.rotationSpeed = 1;
16698
- return this.angleCamera(-60, void 0, 500);
16699
- } else {
16700
- this.globeControls.rotationSpeed = 0;
16701
- return this.angleCamera(-90, 0, 500);
17451
+ /** @param {'2d' | '3d'} [mode] @returns {Promise<boolean>} Whether the camera orientation transition completed. */
17452
+ async setViewMode(mode = "3d") {
17453
+ var _a3, _b2;
17454
+ (_b2 = (_a3 = this.desktopNavigationController) == null ? void 0 : _a3.interrupt) == null ? void 0 : _b2.call(_a3, "setViewMode");
17455
+ const request = this._viewModeState ?? (this._viewModeState = { version: 0, confirmedRotationSpeed: this.globeControls.rotationSpeed });
17456
+ const version = ++request.version;
17457
+ const targetRotationSpeed = mode === "3d" ? 1 : 0;
17458
+ this.globeControls.rotationSpeed = targetRotationSpeed;
17459
+ try {
17460
+ const completed = mode === "3d" ? await this.angleCamera(-60, void 0, 500) : await this.angleCamera(-90, 0, 500);
17461
+ if (request.version === version && !this.disposed) {
17462
+ if (completed) request.confirmedRotationSpeed = targetRotationSpeed;
17463
+ else this.globeControls.rotationSpeed = request.confirmedRotationSpeed;
17464
+ }
17465
+ return completed;
17466
+ } catch (error) {
17467
+ if (request.version === version && !this.disposed) this.globeControls.rotationSpeed = request.confirmedRotationSpeed;
17468
+ throw error;
16702
17469
  }
16703
17470
  }
16704
17471
  exportScene() {
@@ -16723,9 +17490,12 @@ class Viewer extends EventDispatcher {
16723
17490
  link.click();
16724
17491
  }
16725
17492
  dispose() {
16726
- var _a3, _b2, _c, _d, _e, _f, _g, _h, _i2, _j, _k, _l, _m, _n2, _o;
17493
+ var _a3, _b2, _c, _d, _e, _f, _g, _h, _i2, _j, _k, _l, _m, _n2, _o, _p;
16727
17494
  if (this.disposed) return;
16728
17495
  this.disposed = true;
17496
+ (_a3 = this.splatDestinationPrefetch) == null ? void 0 : _a3.dispose();
17497
+ (_c = (_b2 = this.desktopNavigationController) == null ? void 0 : _b2.interrupt) == null ? void 0 : _c.call(_b2, "viewer disposed");
17498
+ if (this.desktopNavigationController || this.desktopLookControls) this.setDesktopNavigationController(null);
16729
17499
  if (this.xrSession) {
16730
17500
  void this.xrSession.dispose().catch((error) => console.error("WebXR session end failed during viewer disposal", error));
16731
17501
  this.xrSession = null;
@@ -16736,6 +17506,8 @@ class Viewer extends EventDispatcher {
16736
17506
  window.removeEventListener("keydown", this._onKeyDown);
16737
17507
  window.removeEventListener("keyup", this._onKeyUp);
16738
17508
  window.removeEventListener("resize", this._onResize);
17509
+ window.removeEventListener("blur", this._onWindowBlur);
17510
+ document.removeEventListener("visibilitychange", this._onVisibilityChange);
16739
17511
  window.removeEventListener("pointermove", this._onPointerMove);
16740
17512
  this.globeControls.removeEventListener("start", this._onGlobeControlsStart);
16741
17513
  this.globeControls.dispose();
@@ -16758,17 +17530,16 @@ class Viewer extends EventDispatcher {
16758
17530
  }
16759
17531
  this.labels.clear();
16760
17532
  this.features.clear();
16761
- (_b2 = (_a3 = this.scene.environment) == null ? void 0 : _a3.dispose) == null ? void 0 : _b2.call(_a3);
17533
+ (_e = (_d = this.scene.environment) == null ? void 0 : _d.dispose) == null ? void 0 : _e.call(_d);
16762
17534
  this.scene.environment = null;
16763
- (_e = (_d = (_c = this.sky) == null ? void 0 : _c.geometry) == null ? void 0 : _d.dispose) == null ? void 0 : _e.call(_d);
16764
- (_h = (_g = (_f = this.sky) == null ? void 0 : _f.material) == null ? void 0 : _g.dispose) == null ? void 0 : _h.call(_g);
16765
- (_i2 = this.sky) == null ? void 0 : _i2.removeFromParent();
16766
- (_k = (_j = this.stats) == null ? void 0 : _j.dom) == null ? void 0 : _k.remove();
17535
+ (_h = (_g = (_f = this.sky) == null ? void 0 : _f.geometry) == null ? void 0 : _g.dispose) == null ? void 0 : _h.call(_g);
17536
+ (_k = (_j = (_i2 = this.sky) == null ? void 0 : _i2.material) == null ? void 0 : _j.dispose) == null ? void 0 : _k.call(_j);
17537
+ (_l = this.sky) == null ? void 0 : _l.removeFromParent();
16767
17538
  this.css2DRenderer.domElement.remove();
16768
17539
  this.renderer.domElement.remove();
16769
- (_m = (_l = this.renderer.renderLists) == null ? void 0 : _l.dispose) == null ? void 0 : _m.call(_l);
17540
+ (_n2 = (_m = this.renderer.renderLists) == null ? void 0 : _m.dispose) == null ? void 0 : _n2.call(_m);
16770
17541
  this.renderer.dispose();
16771
- (_o = (_n2 = this.renderer).forceContextLoss) == null ? void 0 : _o.call(_n2);
17542
+ (_p = (_o = this.renderer).forceContextLoss) == null ? void 0 : _p.call(_o);
16772
17543
  this.container = null;
16773
17544
  this.listeners = {};
16774
17545
  }