@splnlss/3d-story-viewer 0.5.5 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/viewer.js CHANGED
@@ -6471,7 +6471,7 @@ const QUAD_INDICES$1 = new Uint16Array([0, 1, 2, 0, 2, 3]);
6471
6471
  const workerUrl$1 = new URL("assets/viewer/spark-old-worker-932b4a2c87ca.js", import.meta.url).href;
6472
6472
  const workerWasmUrl$1 = new URL("assets/viewer/spark-worker-015de49d2d00.wasm", import.meta.url).href;
6473
6473
  function WorkerWrapper$1(options) {
6474
- const url = new URL(workerUrl$1);
6474
+ const url = new URL(workerUrl$1, globalThis.location.href);
6475
6475
  url.searchParams.set("wasm", workerWasmUrl$1);
6476
6476
  return new Worker(url, {
6477
6477
  name: options == null ? void 0 : options.name
@@ -8218,7 +8218,7 @@ async function withWorker(callback) {
8218
8218
  const workerUrl = new URL("assets/viewer/spark-worker-5ec8a483b87c.js", import.meta.url).href;
8219
8219
  const workerWasmUrl = new URL("assets/viewer/spark-worker-015de49d2d00.wasm", import.meta.url).href;
8220
8220
  function WorkerWrapper$2(options) {
8221
- const url = new URL(workerUrl);
8221
+ const url = new URL(workerUrl, globalThis.location.href);
8222
8222
  url.searchParams.set("wasm", workerWasmUrl);
8223
8223
  return new Worker(url, {
8224
8224
  name: options == null ? void 0 : options.name
@@ -12111,7 +12111,7 @@ const _SplatAccumulator = class _SplatAccumulator2 {
12111
12111
  this.time = 0;
12112
12112
  this.deltaTime = 0;
12113
12113
  this.viewToWorld = new Matrix4();
12114
- this.viewOrigin = new Vector3();
12114
+ this.renderOrigin = new Vector3();
12115
12115
  this.viewDirection = new Vector3();
12116
12116
  this.maxSplats = 0;
12117
12117
  this.numSplats = 0;
@@ -12394,10 +12394,10 @@ const _SplatAccumulator = class _SplatAccumulator2 {
12394
12394
  lodInstances
12395
12395
  }) {
12396
12396
  var _a22;
12397
- this.viewToWorld.copy(camera.matrixWorld);
12398
- camera.getWorldPosition(this.viewOrigin);
12397
+ camera.getWorldPosition(this.renderOrigin);
12398
+ this.viewToWorld.copy(camera.matrixWorld).setPosition(0, 0, 0);
12399
12399
  camera.getWorldDirection(this.viewDirection);
12400
- _SplatAccumulator2.viewCenterUniform.value.copy(this.viewOrigin);
12400
+ _SplatAccumulator2.viewCenterUniform.value.set(0, 0, 0);
12401
12401
  _SplatAccumulator2.viewDirUniform.value.copy(this.viewDirection);
12402
12402
  _SplatAccumulator2.sortRadialUniform.value = sortRadial;
12403
12403
  this.time = time;
@@ -12431,6 +12431,7 @@ const _SplatAccumulator = class _SplatAccumulator2 {
12431
12431
  time: this.time,
12432
12432
  deltaTime: this.deltaTime,
12433
12433
  viewToWorld: this.viewToWorld,
12434
+ renderOrigin: this.renderOrigin,
12434
12435
  camera,
12435
12436
  renderSize,
12436
12437
  globalEdits,
@@ -12695,6 +12696,14 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
12695
12696
  this.sortTimeoutId = -1;
12696
12697
  this.sortedCenter = new Vector3().setScalar(Number.NEGATIVE_INFINITY);
12697
12698
  this.sortedDir = new Vector3().setScalar(0);
12699
+ this.accumToCamera = new Matrix4();
12700
+ this.accumToCameraScale = new Vector3();
12701
+ this.renderCameraToWorld = new Matrix4();
12702
+ this.renderCameraOrigin = new Vector3();
12703
+ this.lodCameraToWorld = new Matrix4();
12704
+ this.lodCameraScale = new Vector3();
12705
+ this.lodViewToObject = new Matrix4();
12706
+ this.lodMeshOrigin = new Vector3();
12698
12707
  this.readback32 = new Uint32Array(0);
12699
12708
  this.lastLodRaycastTime = 0;
12700
12709
  this.lodWorker = null;
@@ -12936,17 +12945,14 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
12936
12945
  this.uniforms.far.value = typedCamera.far;
12937
12946
  const geometry = this.geometry;
12938
12947
  geometry.instanceCount = spark.activeSplats;
12939
- const accumToWorld = new Matrix4();
12940
- if (!this.display.extSplats) {
12941
- accumToWorld.makeTranslation(spark.display.viewOrigin);
12942
- }
12943
- const cameraToWorld = camera.matrixWorld.clone();
12944
- const worldToCamera = cameraToWorld.invert();
12945
- const accumToCamera = worldToCamera.multiply(accumToWorld);
12948
+ const renderCameraToWorld = this.renderCameraToWorld.copy(camera.matrixWorld).setPosition(
12949
+ this.renderCameraOrigin.setFromMatrixPosition(camera.matrixWorld).sub(spark.display.renderOrigin)
12950
+ );
12951
+ const accumToCamera = this.accumToCamera.copy(renderCameraToWorld).invert();
12946
12952
  accumToCamera.decompose(
12947
12953
  this.uniforms.renderToViewPos.value,
12948
12954
  this.uniforms.renderToViewQuat.value,
12949
- new Vector3()
12955
+ this.accumToCameraScale
12950
12956
  );
12951
12957
  this.uniforms.renderToViewBasis.value.setFromMatrix4(accumToCamera);
12952
12958
  this.uniforms.maxStdDev.value = spark.maxStdDev;
@@ -13123,7 +13129,7 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13123
13129
  await new Promise((resolve) => setTimeout(resolve, this.readPause));
13124
13130
  }
13125
13131
  const current = this.current;
13126
- this.sortedCenter.copy(current.viewOrigin);
13132
+ this.sortedCenter.copy(current.renderOrigin);
13127
13133
  this.sortedDir.copy(current.viewDirection);
13128
13134
  const { numSplats, maxSplats } = current;
13129
13135
  const rows = Math.max(1, Math.ceil(maxSplats / 16384));
@@ -13244,8 +13250,9 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13244
13250
  const viewPos = new Vector3();
13245
13251
  const viewQuat = new Quaternion();
13246
13252
  this.current.viewToWorld.decompose(viewPos, viewQuat, new Vector3());
13253
+ const lodPos = this.lodPosOverride ?? this.current.renderOrigin;
13247
13254
  if (this.lodPosOverride) {
13248
- viewPos.copy(this.lodPosOverride);
13255
+ viewPos.copy(this.lodPosOverride).sub(this.current.renderOrigin);
13249
13256
  }
13250
13257
  if (this.lodQuatOverride) {
13251
13258
  viewQuat.copy(this.lodQuatOverride).normalize();
@@ -13254,7 +13261,7 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13254
13261
  if (this.lastLod.pixelScaleLimit !== pixelScaleLimit || this.lastLod.maxSplats !== maxSplats) {
13255
13262
  this.lodDirty = true;
13256
13263
  }
13257
- const distance2 = viewPos.distanceTo(this.lastLod.pos);
13264
+ const distance2 = lodPos.distanceTo(this.lastLod.pos);
13258
13265
  const distanceRamp = Math.max(0, 1 - distance2 / 1);
13259
13266
  const dot2 = viewQuat.dot(this.lastLod.quat);
13260
13267
  const quatRamp = Math.max(0, 1 - (1 - dot2) / 0.01);
@@ -13354,10 +13361,10 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13354
13361
  const deltaPred = new Vector3();
13355
13362
  if (this.lastLod) {
13356
13363
  const deltaTime = Math.max(1, now22 - this.lastLod.timestamp);
13357
- deltaPred.copy(viewPos).sub(this.lastLod.pos).multiplyScalar(this.lastTraverseTime / deltaTime);
13364
+ deltaPred.copy(lodPos).sub(this.lastLod.pos).multiplyScalar(this.lastTraverseTime / deltaTime);
13358
13365
  }
13359
13366
  this.lastLod = {
13360
- pos: viewPos,
13367
+ pos: lodPos.clone(),
13361
13368
  quat: viewQuat,
13362
13369
  pixelScaleLimit,
13363
13370
  maxSplats,
@@ -13369,8 +13376,10 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13369
13376
  deltaPred,
13370
13377
  lodMeshes,
13371
13378
  maxSplats,
13379
+ this.lastLod.pos,
13372
13380
  viewPos,
13373
13381
  viewQuat,
13382
+ this.current.renderOrigin,
13374
13383
  pixelScaleLimit
13375
13384
  );
13376
13385
  this.currentLod = this.lastLod;
@@ -13395,18 +13404,20 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13395
13404
  this.lodIdToSplats.set(lodId, splats);
13396
13405
  }
13397
13406
  }
13398
- async updateLodInstances(worker, deltaPred, lodMeshes, maxSplats, viewPos, viewQuat, pixelScaleLimit) {
13407
+ async updateLodInstances(worker, deltaPred, lodMeshes, maxSplats, lodPos, viewPos, viewQuat, renderOrigin, pixelScaleLimit) {
13399
13408
  const uuidToMesh = /* @__PURE__ */ new Map();
13400
- const cameraToWorld = new Matrix4().compose(
13409
+ const cameraToWorld = this.lodCameraToWorld.compose(
13401
13410
  viewPos,
13402
13411
  viewQuat,
13403
- new Vector3().setScalar(1)
13412
+ this.lodCameraScale.setScalar(1)
13404
13413
  );
13405
13414
  const instances = lodMeshes.reduce(
13406
13415
  (instances2, mesh) => {
13407
13416
  var _a22, _b2;
13408
13417
  uuidToMesh.set(mesh.uuid, mesh);
13409
- const viewToObject = mesh.matrixWorld.clone().invert().multiply(cameraToWorld);
13418
+ const viewToObject = this.lodViewToObject.copy(mesh.matrixWorld).setPosition(
13419
+ this.lodMeshOrigin.setFromMatrixPosition(mesh.matrixWorld).sub(renderOrigin)
13420
+ ).invert().multiply(cameraToWorld);
13410
13421
  const splats = ((_a22 = mesh.packedSplats) == null ? void 0 : _a22.lodSplats) ?? ((_b2 = mesh.extSplats) == null ? void 0 : _b2.lodSplats) ?? mesh.paged;
13411
13422
  if (!splats) {
13412
13423
  return instances2;
@@ -13422,7 +13433,7 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13422
13433
  instanceId: mesh.uuid,
13423
13434
  lodId: record.lodId,
13424
13435
  rootPage: record.rootPage,
13425
- viewToObjectCols: viewToObject.elements,
13436
+ viewToObjectCols: viewToObject.elements.slice(),
13426
13437
  lodScale: mesh.lodScale,
13427
13438
  behindFoveate: mesh.behindFoveate ?? this.behindFoveate,
13428
13439
  coneFov0: mesh.coneFov0 ?? this.coneFov0,
@@ -13457,7 +13468,7 @@ const _SparkRenderer = class _SparkRenderer2 extends Mesh {
13457
13468
  const meshPosition = mesh.getWorldPosition(new Vector3());
13458
13469
  return {
13459
13470
  splats: mesh.paged,
13460
- distance: meshPosition.distanceTo(viewPos)
13471
+ distance: meshPosition.distanceTo(lodPos)
13461
13472
  };
13462
13473
  }).filter((result2) => result2 !== null);
13463
13474
  if (!this.pageSizeWarning && pagedMeshes.length > this.pager.maxPages) {
@@ -15032,6 +15043,11 @@ const _SplatMesh = class _SplatMesh2 extends SplatGenerator {
15032
15043
  this.splatRgba = null;
15033
15044
  this.maxSh = 3;
15034
15045
  this.showLodPageDyno = new DynoInt({ value: 0 });
15046
+ this.objectToRender = new Matrix4();
15047
+ this.objectToRenderOffset = new Vector3();
15048
+ this.worldToObject = new Matrix4();
15049
+ this.worldToView = new Matrix4();
15050
+ this.viewToObjectMatrix = new Matrix4();
15035
15051
  if (options.splats) {
15036
15052
  this.splats = options.splats;
15037
15053
  this.numSplats = options.splats.getNumSplats();
@@ -15433,6 +15449,7 @@ const _SplatMesh = class _SplatMesh2 extends SplatGenerator {
15433
15449
  time,
15434
15450
  deltaTime,
15435
15451
  viewToWorld,
15452
+ renderOrigin,
15436
15453
  camera,
15437
15454
  renderSize,
15438
15455
  globalEdits,
@@ -15464,40 +15481,44 @@ const _SplatMesh = class _SplatMesh2 extends SplatGenerator {
15464
15481
  this.lastSplats = this.context.splats;
15465
15482
  this.generatorDirty = true;
15466
15483
  }
15484
+ this.updateMatrixWorld();
15485
+ const objectToWorld = this.objectToRender.copy(this.matrixWorld);
15486
+ objectToWorld.setPosition(
15487
+ this.objectToRenderOffset.setFromMatrixPosition(this.matrixWorld).sub(renderOrigin)
15488
+ );
15467
15489
  if (!this.covSplats) {
15468
- if (this.context.transform.update(this)) {
15490
+ if (this.context.transform.updateFromMatrix(objectToWorld)) {
15469
15491
  updated = true;
15470
15492
  }
15471
15493
  if (this.context.viewToWorld.updateFromMatrix(viewToWorld) && this.enableViewToWorld) {
15472
15494
  updated = true;
15473
15495
  }
15474
- const worldToView = viewToWorld.clone().invert();
15496
+ const worldToView = this.worldToView.copy(viewToWorld).invert();
15475
15497
  if (this.context.worldToView.updateFromMatrix(worldToView) && this.enableWorldToView) {
15476
15498
  updated = true;
15477
15499
  }
15478
- const objectToWorld = new Matrix4().compose(
15479
- this.context.transform.translate.value,
15480
- this.context.transform.rotate.value,
15481
- new Vector3().setScalar(this.context.transform.scale.value)
15500
+ const viewToObjectMatrix = this.viewToObjectMatrix.multiplyMatrices(
15501
+ this.worldToObject.copy(objectToWorld).invert(),
15502
+ viewToWorld
15482
15503
  );
15483
- const worldToObject = objectToWorld.invert();
15484
- const viewToObjectMatrix = worldToObject.multiply(viewToWorld);
15485
15504
  if (this.context.viewToObject.updateFromMatrix(viewToObjectMatrix) && (this.enableViewToObject || this.context.splats.hasRgbDir())) {
15486
15505
  updated = true;
15487
15506
  }
15488
15507
  } else {
15489
- if (this.context.covTransform.update(this)) {
15508
+ if (this.context.covTransform.updateFromMatrix(objectToWorld)) {
15490
15509
  updated = true;
15491
15510
  }
15492
15511
  if (this.context.covViewToWorld.updateFromMatrix(viewToWorld) && this.enableViewToWorld) {
15493
15512
  updated = true;
15494
15513
  }
15495
- const worldToView = viewToWorld.clone().invert();
15514
+ const worldToView = this.worldToView.copy(viewToWorld).invert();
15496
15515
  if (this.context.covWorldToView.updateFromMatrix(worldToView) && this.enableWorldToView) {
15497
15516
  updated = true;
15498
15517
  }
15499
- const worldToObject = this.matrixWorld.clone().invert();
15500
- const viewToObjectMatrix = worldToObject.multiply(viewToWorld);
15518
+ const viewToObjectMatrix = this.viewToObjectMatrix.multiplyMatrices(
15519
+ this.worldToObject.copy(objectToWorld).invert(),
15520
+ viewToWorld
15521
+ );
15501
15522
  if (this.context.covViewToObject.updateFromMatrix(viewToObjectMatrix) && (this.enableViewToObject || this.context.splats.hasRgbDir())) {
15502
15523
  updated = true;
15503
15524
  }
@@ -17694,6 +17715,7 @@ const _OldSparkRenderer = class _OldSparkRenderer2 extends Mesh {
17694
17715
  this.lastUpdateTime = null;
17695
17716
  this.defaultCameras = [];
17696
17717
  this.lastStochastic = null;
17718
+ this.renderOrigin = new Vector3();
17697
17719
  this.pendingUpdate = {
17698
17720
  scene: null,
17699
17721
  originToWorld: new Matrix4(),
@@ -18033,6 +18055,7 @@ const _OldSparkRenderer = class _OldSparkRenderer2 extends Mesh {
18033
18055
  originToWorld = this.active.toWorld;
18034
18056
  }
18035
18057
  viewToWorld = viewToWorld ?? originToWorld.clone();
18058
+ this.renderOrigin.setFromMatrixPosition(originToWorld);
18036
18059
  const time = this.time ?? this.clock.getElapsedTime();
18037
18060
  const deltaTime = time - (this.lastUpdateTime ?? time);
18038
18061
  this.lastUpdateTime = time;
@@ -18048,6 +18071,7 @@ const _OldSparkRenderer = class _OldSparkRenderer2 extends Mesh {
18048
18071
  time,
18049
18072
  deltaTime,
18050
18073
  viewToWorld,
18074
+ renderOrigin: this.renderOrigin,
18051
18075
  globalEdits
18052
18076
  });
18053
18077
  }
@@ -26706,20 +26730,28 @@ class TransitionControls extends EventDispatcher {
26706
26730
  this.lookAt = new Vector3();
26707
26731
  this.cameraTween = null;
26708
26732
  this.lookAtTween = null;
26733
+ this.activeTransition = null;
26709
26734
  this.is2D = false;
26710
26735
  }
26711
26736
  animateTo(position, quaternion, duration = TweenSettings.DURATION) {
26712
- return new Promise((resolve, reject) => {
26737
+ this.cancel();
26738
+ return new Promise((resolve) => {
26713
26739
  const fromPosition = this.camera.position.clone();
26714
26740
  const fromQuaternion = this.camera.quaternion.clone();
26715
26741
  const toPosition = position.clone();
26716
26742
  const toQuaternion = quaternion.clone();
26743
+ const transition = { resolve, toPosition, toQuaternion };
26744
+ this.activeTransition = transition;
26717
26745
  const deltaPosition = toPosition.clone().sub(fromPosition);
26718
26746
  const deltaDistance = deltaPosition.length();
26719
26747
  const deltaQuaternion = toQuaternion.clone().multiply(fromQuaternion.clone().invert());
26720
26748
  const deltaAngle = Math.acos(Math.min(1, deltaQuaternion.w));
26721
- if (deltaDistance < 1 && deltaAngle < 1) {
26722
- resolve();
26749
+ if (duration <= 0 || deltaDistance < 1 && deltaAngle < 1) {
26750
+ this.camera.position.copy(toPosition);
26751
+ this.camera.quaternion.copy(toQuaternion);
26752
+ this.camera.updateMatrixWorld(true);
26753
+ this.activeTransition = null;
26754
+ resolve(true);
26723
26755
  } else {
26724
26756
  const fromLookAt = new Vector3(0, 0, -deltaDistance * 0.25).applyQuaternion(fromQuaternion).add(fromPosition);
26725
26757
  const toLookAt = new Vector3(0, 0, -deltaDistance * 0.25).applyQuaternion(toQuaternion).add(toPosition);
@@ -26730,15 +26762,24 @@ class TransitionControls extends EventDispatcher {
26730
26762
  this.lookAtTween = new Tween(this.lookAt).to(toLookAt, duration).easing(Easing.Quartic.InOut).onComplete(() => {
26731
26763
  this.lookAt.copy(toLookAt);
26732
26764
  this.lookAtTween = null;
26765
+ this.complete(transition);
26733
26766
  }).start();
26734
26767
  this.cameraTween = new Tween(this.camera).to({ position: toPosition, up: toUp }, duration).easing(Easing.Quartic.InOut).onComplete(() => {
26735
26768
  this.camera.position.copy(toPosition);
26736
26769
  this.cameraTween = null;
26737
- resolve();
26770
+ this.complete(transition);
26738
26771
  }).start();
26739
26772
  }
26740
26773
  });
26741
26774
  }
26775
+ complete(transition) {
26776
+ if (this.activeTransition !== transition || this.cameraTween || this.lookAtTween) return;
26777
+ this.camera.position.copy(transition.toPosition);
26778
+ this.camera.quaternion.copy(transition.toQuaternion);
26779
+ this.camera.updateMatrixWorld(true);
26780
+ this.activeTransition = null;
26781
+ transition.resolve(true);
26782
+ }
26742
26783
  update(time) {
26743
26784
  if (this.cameraUpTween) this.cameraUpTween.update(time);
26744
26785
  if (this.cameraTween) this.cameraTween.update(time);
@@ -26748,6 +26789,8 @@ class TransitionControls extends EventDispatcher {
26748
26789
  }
26749
26790
  }
26750
26791
  cancel() {
26792
+ const transition = this.activeTransition;
26793
+ this.activeTransition = null;
26751
26794
  if (this.cameraTween) {
26752
26795
  this.cameraTween.stop();
26753
26796
  this.cameraTween = null;
@@ -26760,6 +26803,7 @@ class TransitionControls extends EventDispatcher {
26760
26803
  this.cameraUpTween.stop();
26761
26804
  this.cameraUpTween = null;
26762
26805
  }
26806
+ transition == null ? void 0 : transition.resolve(false);
26763
26807
  }
26764
26808
  }
26765
26809
  var sky_default$1 = "uniform vec3 sunPosition;uniform float rayleigh;uniform float turbidity;uniform float mieCoefficient;uniform vec3 up;varying vec3 vWorldPosition;varying vec3 vSunDirection;varying float vSunfade;varying vec3 vBetaR;varying vec3 vBetaM;varying float vSunE;const float e=2.71828182845904523536028747135266249775724709369995957;const float pi=3.141592653589793238462643383279502884197169;const vec3 lambda=vec3(680E-9,550E-9,450E-9);const vec3 totalRayleigh=vec3(5.804542996261093E-6,1.3562911419845635E-5,3.0265902468824876E-5);const float v=4.0;const vec3 K=vec3(0.686,0.678,0.666);const vec3 MieConst=vec3(1.8399918514433978E14,2.7798023919660528E14,4.0790479543861094E14);const float cutoffAngle=1.6110731556870734;const float steepness=1.5;const float EE=1000.0;float sunIntensity(float zenithAngleCos){zenithAngleCos=clamp(zenithAngleCos,-1.0,1.0);return EE*max(0.0,1.0-pow(e,-((cutoffAngle-acos(zenithAngleCos))/steepness)));}vec3 totalMie(float T){float c=(0.2*T)*10E-18;return 0.434*c*MieConst;}void main(){vec4 worldPosition=modelMatrix*vec4(position,1.0);vWorldPosition=worldPosition.xyz;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);gl_Position.z=gl_Position.w;vSunDirection=normalize(sunPosition);vSunE=sunIntensity(dot(vSunDirection,up));vSunfade=1.0-clamp(1.0-exp((sunPosition.y/450000.0)),0.0,1.0);float rayleighCoefficient=rayleigh-(1.0*(1.0-vSunfade));vBetaR=totalRayleigh*rayleighCoefficient;vBetaM=totalMie(turbidity)*mieCoefficient;}";
@@ -27152,7 +27196,7 @@ class GeojsonLayer extends ContentLayer {
27152
27196
  this.clear();
27153
27197
  }
27154
27198
  }
27155
- const GAUSSIAN_FORMATS = /* @__PURE__ */ new Set(["ply", "sog"]);
27199
+ const GAUSSIAN_FORMATS = /* @__PURE__ */ new Set(["ply", "sog", "spz", "rad"]);
27156
27200
  function geodeticToEcefPosition(longitude, latitude, altitude) {
27157
27201
  const semiMajorAxis = 6378137;
27158
27202
  const eccentricity = 0.081819190842622;
@@ -27189,7 +27233,7 @@ function validateGaussianSplatLayerDefinition(definition) {
27189
27233
  }
27190
27234
  requireNonEmptyString((_a3 = definition.data) == null ? void 0 : _a3.url, "data.url");
27191
27235
  if (!GAUSSIAN_FORMATS.has((_b2 = definition.data) == null ? void 0 : _b2.format)) {
27192
- throw new Error('data.format must be "ply" or "sog".');
27236
+ throw new Error('data.format must be "ply", "sog", "spz", or "rad".');
27193
27237
  }
27194
27238
  const renderOrder = ((_c = definition.options) == null ? void 0 : _c.renderOrder) ?? 0;
27195
27239
  if (renderOrder !== 0) {
@@ -27261,7 +27305,9 @@ function makeGaussianSplatTransform(transform) {
27261
27305
  }
27262
27306
  const FORMAT_TYPES = {
27263
27307
  ply: SplatFileType.PLY,
27264
- sog: SplatFileType.PCSOGSZIP
27308
+ sog: SplatFileType.PCSOGSZIP,
27309
+ spz: SplatFileType.SPZ,
27310
+ rad: SplatFileType.RAD
27265
27311
  };
27266
27312
  function normalizeError(error) {
27267
27313
  return error instanceof Error ? error : new Error(String(error));
@@ -27292,39 +27338,15 @@ class GaussianSplatLayer extends ContentLayer {
27292
27338
  }
27293
27339
  }
27294
27340
  async load() {
27295
- var _a3, _b2, _c, _d, _e2, _f, _g, _h, _i2;
27341
+ var _a3, _b2, _c, _d, _e2, _f, _g, _h, _i2, _j;
27296
27342
  if (this.loadState === "loading" || this.loadState === "ready" || this.loadState === "disposed") return;
27297
27343
  const attempt = ++this.loadAttempt;
27298
27344
  this.loadState = "loading";
27299
- this.abortController = new AbortController();
27300
27345
  let mesh = null;
27301
27346
  try {
27302
27347
  (_b2 = (_a3 = this.callbacks).onStart) == null ? void 0 : _b2.call(_a3, this);
27303
27348
  (_d = (_c = this.callbacks).ensureRenderer) == null ? void 0 : _d.call(_c);
27304
- const response = await fetch(this.definition.data.url, { signal: this.abortController.signal });
27305
- if (!response.ok) {
27306
- throw new Error(`Failed to load Gaussian splat: ${response.status} ${response.statusText}`);
27307
- }
27308
- if (!response.body) {
27309
- throw new Error("Failed to load Gaussian splat: response body is unavailable.");
27310
- }
27311
- const contentLengthHeader = response.headers.get("Content-Length");
27312
- const contentLength = contentLengthHeader === null ? void 0 : Number.parseInt(contentLengthHeader, 10);
27313
- mesh = new SplatMesh({
27314
- stream: response.body,
27315
- streamLength: Number.isFinite(contentLength) && contentLength >= 0 ? contentLength : void 0,
27316
- fileType: FORMAT_TYPES[this.definition.data.format],
27317
- onProgress: (event) => {
27318
- var _a4, _b3;
27319
- if (this.loadState !== "disposed" && attempt === this.loadAttempt) {
27320
- (_b3 = (_a4 = this.callbacks).onProgress) == null ? void 0 : _b3.call(_a4, this, {
27321
- loaded: event.loaded,
27322
- total: event.total,
27323
- lengthComputable: event.lengthComputable
27324
- });
27325
- }
27326
- }
27327
- });
27349
+ mesh = this.definition.data.format === "rad" ? this.createPagedMesh() : await this.createDirectMesh(attempt);
27328
27350
  mesh.layers.set(0);
27329
27351
  mesh.matrix.copy(this.transformMatrix);
27330
27352
  mesh.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale);
@@ -27332,23 +27354,66 @@ class GaussianSplatLayer extends ContentLayer {
27332
27354
  mesh.matrixWorldNeedsUpdate = true;
27333
27355
  this.splatMesh = mesh;
27334
27356
  this.add(mesh);
27335
- await mesh.initialized;
27357
+ if (this.definition.data.format === "rad") {
27358
+ if (!((_e2 = mesh.paged) == null ? void 0 : _e2.getRadMeta)) {
27359
+ throw new Error("Failed to initialize paged RAD streaming.");
27360
+ }
27361
+ await Promise.all([mesh.initialized, mesh.paged.getRadMeta()]);
27362
+ } else {
27363
+ await mesh.initialized;
27364
+ }
27336
27365
  if (this.loadState === "disposed" || attempt !== this.loadAttempt) {
27337
27366
  this.disposeMesh(mesh);
27338
27367
  return;
27339
27368
  }
27340
27369
  this.abortController = null;
27341
27370
  this.loadState = "ready";
27342
- (_f = (_e2 = this.callbacks).onReady) == null ? void 0 : _f.call(_e2, this);
27371
+ (_g = (_f = this.callbacks).onReady) == null ? void 0 : _g.call(_f, this);
27343
27372
  } catch (error) {
27344
27373
  this.disposeMesh(mesh);
27345
- const aborted = (_g = this.abortController) == null ? void 0 : _g.signal.aborted;
27374
+ const aborted = (_h = this.abortController) == null ? void 0 : _h.signal.aborted;
27346
27375
  this.abortController = null;
27347
27376
  if (this.loadState === "disposed" || attempt !== this.loadAttempt || aborted) return;
27348
27377
  this.loadState = "error";
27349
- (_i2 = (_h = this.callbacks).onError) == null ? void 0 : _i2.call(_h, this, normalizeError(error));
27378
+ (_j = (_i2 = this.callbacks).onError) == null ? void 0 : _j.call(_i2, this, normalizeError(error));
27350
27379
  }
27351
27380
  }
27381
+ createPagedMesh() {
27382
+ const paged = new PagedSplats({
27383
+ rootUrl: this.definition.data.url,
27384
+ fileType: FORMAT_TYPES[this.definition.data.format]
27385
+ });
27386
+ return new SplatMesh({
27387
+ paged
27388
+ });
27389
+ }
27390
+ async createDirectMesh(attempt) {
27391
+ this.abortController = new AbortController();
27392
+ const response = await fetch(this.definition.data.url, { signal: this.abortController.signal });
27393
+ if (!response.ok) {
27394
+ throw new Error(`Failed to load Gaussian splat: ${response.status} ${response.statusText}`);
27395
+ }
27396
+ if (!response.body) {
27397
+ throw new Error("Failed to load Gaussian splat: response body is unavailable.");
27398
+ }
27399
+ const contentLengthHeader = response.headers.get("Content-Length");
27400
+ const contentLength = contentLengthHeader === null ? void 0 : Number.parseInt(contentLengthHeader, 10);
27401
+ return new SplatMesh({
27402
+ stream: response.body,
27403
+ streamLength: Number.isFinite(contentLength) && contentLength >= 0 ? contentLength : void 0,
27404
+ fileType: FORMAT_TYPES[this.definition.data.format],
27405
+ onProgress: (event) => {
27406
+ var _a3, _b2;
27407
+ if (this.loadState !== "disposed" && attempt === this.loadAttempt) {
27408
+ (_b2 = (_a3 = this.callbacks).onProgress) == null ? void 0 : _b2.call(_a3, this, {
27409
+ loaded: event.loaded,
27410
+ total: event.total,
27411
+ lengthComputable: event.lengthComputable
27412
+ });
27413
+ }
27414
+ }
27415
+ });
27416
+ }
27352
27417
  disposeMesh(mesh) {
27353
27418
  if (!mesh || mesh.userData.gaussianSplatDisposed) return;
27354
27419
  mesh.userData.gaussianSplatDisposed = true;
@@ -27396,12 +27461,17 @@ const ViewerEvents = (
27396
27461
  }
27397
27462
  );
27398
27463
  class Viewer extends EventDispatcher {
27464
+ /**
27465
+ * @param {HTMLElement | null} container
27466
+ * @param {import('../main.js').ViewerOptions} [options]
27467
+ */
27399
27468
  constructor(container, options = {}) {
27400
27469
  super();
27401
27470
  this.isViewer = true;
27402
27471
  this.type = "viewer";
27403
27472
  this.disposed = false;
27404
27473
  this.sparkRenderer = null;
27474
+ this.transparentBackground = options.transparentBackground ?? true;
27405
27475
  Tokens.CESIUM = options.cesiumToken || void 0;
27406
27476
  Tokens.GOOGLEMAPS = options.googleMapsToken || void 0;
27407
27477
  this.state = new StateDispatcher({
@@ -27412,9 +27482,11 @@ class Viewer extends EventDispatcher {
27412
27482
  });
27413
27483
  this.renderer = new WebGLRenderer({
27414
27484
  antialias: true,
27415
- powerPreference: "high-performance"
27485
+ powerPreference: "high-performance",
27486
+ alpha: this.transparentBackground,
27487
+ premultipliedAlpha: true
27416
27488
  });
27417
- this.renderer.setClearColor(16777215, 1);
27489
+ this.renderer.setClearColor(this.transparentBackground ? 0 : 16777215, this.transparentBackground ? 0 : 1);
27418
27490
  this.renderer.toneMapping = AgXToneMapping;
27419
27491
  this.renderer.outputColorSpace = SRGBColorSpace;
27420
27492
  this.renderer.toneMappingExposure = 1;
@@ -27449,6 +27521,7 @@ class Viewer extends EventDispatcher {
27449
27521
  this.transitionControls = new TransitionControls(this.camera);
27450
27522
  this.globeManager = new GlobeManager(this.scene, this.camera, this.renderer, { apiToken: Tokens.CESIUM, googleMapsToken: Tokens.GOOGLEMAPS });
27451
27523
  if (this.globeManager.tiles) {
27524
+ this.globeManager.tiles.group.visible = !this.transparentBackground;
27452
27525
  this.globeControls.setTilesRenderer(this.globeManager.tiles);
27453
27526
  }
27454
27527
  this.cameraCoords = {};
@@ -27492,6 +27565,7 @@ class Viewer extends EventDispatcher {
27492
27565
  if (container) this.appendTo(container);
27493
27566
  this.sky = new Sky();
27494
27567
  this.sky.scale.setScalar(2e7);
27568
+ this.sky.visible = !this.transparentBackground;
27495
27569
  this.scene.add(this.sky);
27496
27570
  const phi = MathUtils.degToRad(80);
27497
27571
  const theta = MathUtils.degToRad(180);
@@ -27551,7 +27625,7 @@ class Viewer extends EventDispatcher {
27551
27625
  return coords;
27552
27626
  }
27553
27627
  setBackgroundColor(color) {
27554
- this.renderer.setClearColor(color, 0);
27628
+ this.renderer.setClearColor(color, this.transparentBackground ? 0 : 1);
27555
27629
  }
27556
27630
  appendTo(container) {
27557
27631
  this.container = container;
@@ -27847,8 +27921,8 @@ class Viewer extends EventDispatcher {
27847
27921
  async alignCamera(lon, lat, alt, pitch = this.cameraCoords.pitch, yaw = this.cameraCoords.yaw, roll = this.cameraCoords.roll, duration = TweenSettings.DURATION) {
27848
27922
  const targetPosition = new Vector3().fromArray(geodeticToEcefPosition$1(lon, lat, alt));
27849
27923
  const targetQuaternion = geodeticToEcefRotation(lon, lat, pitch, yaw, roll);
27850
- return this.transitionControls.animateTo(targetPosition, targetQuaternion, duration).then(() => {
27851
- this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt, pitch, yaw, roll });
27924
+ return this.transitionControls.animateTo(targetPosition, targetQuaternion, duration).then((completed) => {
27925
+ if (completed) this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt, pitch, yaw, roll });
27852
27926
  });
27853
27927
  }
27854
27928
  async focusCamera(lon, lat, alt, distance = 2e3, pitch = this.cameraCoords.pitch, duration = TweenSettings.DURATION) {
@@ -27856,8 +27930,8 @@ class Viewer extends EventDispatcher {
27856
27930
  const targetQuaternion = geodeticToEcefRotation(lon, lat, pitch, 0, 0);
27857
27931
  const direction = new Vector3(0, 0, 1).applyQuaternion(targetQuaternion);
27858
27932
  targetPosition.addScaledVector(direction, distance);
27859
- return this.transitionControls.animateTo(targetPosition, targetQuaternion, duration).then(() => {
27860
- this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt });
27933
+ return this.transitionControls.animateTo(targetPosition, targetQuaternion, duration).then((completed) => {
27934
+ if (completed) this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt });
27861
27935
  });
27862
27936
  }
27863
27937
  async angleCamera(pitch = this.cameraCoords.pitch, yaw = this.cameraCoords.yaw, duration = TweenSettings.DURATION) {
@@ -27868,17 +27942,17 @@ class Viewer extends EventDispatcher {
27868
27942
  const targetQuaternion = geodeticToEcefRotation(lon, lat, pitch, yaw, 0);
27869
27943
  const direction = new Vector3(0, 0, 1).applyQuaternion(targetQuaternion);
27870
27944
  targetPosition.addScaledVector(direction, distance);
27871
- return this.transitionControls.animateTo(targetPosition, targetQuaternion, duration).then(() => {
27872
- this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt });
27945
+ return this.transitionControls.animateTo(targetPosition, targetQuaternion, duration).then((completed) => {
27946
+ if (completed) this.dispatchEvent({ type: ViewerEvents.TRANSITIONED, lon, lat, alt });
27873
27947
  });
27874
27948
  }
27875
27949
  setViewMode(mode = "3d") {
27876
27950
  if (mode == "3d") {
27877
27951
  this.globeControls.rotationSpeed = 1;
27878
- this.angleCamera(-60, void 0, 500);
27952
+ return this.angleCamera(-60, void 0, 500);
27879
27953
  } else {
27880
27954
  this.globeControls.rotationSpeed = 0;
27881
- this.angleCamera(-90, 0, 500);
27955
+ return this.angleCamera(-90, 0, 500);
27882
27956
  }
27883
27957
  }
27884
27958
  exportScene() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splnlss/3d-story-viewer",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -25,10 +25,15 @@
25
25
  }
26
26
  },
27
27
  "scripts": {
28
+ "patch:spark": "patch-package --error-on-fail && node scripts/check-spark-backport.mjs",
29
+ "predev": "yarn patch:spark",
28
30
  "dev": "vite",
31
+ "prebuild": "yarn patch:spark",
29
32
  "build": "vite build && tsc -p tsconfig.types.json",
30
33
  "preview": "vite preview",
34
+ "pretest": "yarn patch:spark",
31
35
  "test": "vitest run",
36
+ "pretest:browser": "yarn patch:spark",
32
37
  "test:browser": "playwright test",
33
38
  "test:all": "npm run test && npm run test:browser",
34
39
  "pack:check": "node scripts/check-package-assets.mjs",
@@ -40,6 +45,8 @@
40
45
  "@loaders.gl/gltf": "^4.3.4",
41
46
  "@loaders.gl/polyfills": "^4.3.4",
42
47
  "@playwright/test": "1.62.1",
48
+ "patch-package": "8.0.1",
49
+ "pngjs": "7.0.0",
43
50
  "typescript": "5.9.3",
44
51
  "vitest": "3.2.7"
45
52
  },
@@ -49,6 +56,7 @@
49
56
  "@sveltejs/vite-plugin-svelte": "^5.0.3",
50
57
  "@tweenjs/tween.js": "^25.0.0",
51
58
  "@vitejs/plugin-basic-ssl": "^1.2.0",
59
+ "dotenv": "^17.2.2",
52
60
  "earcut": "^3.0.1",
53
61
  "sass": "^1.83.4",
54
62
  "stats.js": "^0.17.0",
@@ -57,7 +65,6 @@
57
65
  "terser": "^5.37.0",
58
66
  "three": "0.185.1",
59
67
  "vite": "^6.0.5",
60
- "vite-plugin-glsl": "^1.3.1",
61
- "dotenv": "^17.2.2"
68
+ "vite-plugin-glsl": "^1.3.1"
62
69
  }
63
70
  }