@heliguy-xyz/splat-viewer 1.0.0-rc.3 → 1.0.0-rc.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.
- package/dist/web-component/FlyCameraScript.d.ts.map +1 -1
- package/dist/web-component/SplatViewerCore.d.ts +5 -0
- package/dist/web-component/SplatViewerCore.d.ts.map +1 -1
- package/dist/web-component/SplatViewerElement.d.ts +1 -0
- package/dist/web-component/SplatViewerElement.d.ts.map +1 -1
- package/dist/web-component/splat-viewer.esm.js +150 -30
- package/dist/web-component/splat-viewer.esm.min.js +1 -1
- package/dist/web-component/splat-viewer.js +150 -30
- package/dist/web-component/splat-viewer.min.js +1 -1
- package/dist/web-component/types/FlyCameraScript.d.ts.map +1 -1
- package/dist/web-component/types/SplatViewerCore.d.ts +5 -0
- package/dist/web-component/types/SplatViewerCore.d.ts.map +1 -1
- package/dist/web-component/types/SplatViewerElement.d.ts +1 -0
- package/dist/web-component/types/SplatViewerElement.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -104580,7 +104580,11 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
104580
104580
|
: { x: 0, y: 0, z: 0 };
|
|
104581
104581
|
this.emitFlyEvent?.('fly-camera-move', {
|
|
104582
104582
|
position: { x: pos.x, y: pos.y, z: pos.z },
|
|
104583
|
-
velocity: {
|
|
104583
|
+
velocity: {
|
|
104584
|
+
x: this._velocity.x,
|
|
104585
|
+
y: this._velocity.y,
|
|
104586
|
+
z: this._velocity.z,
|
|
104587
|
+
},
|
|
104584
104588
|
});
|
|
104585
104589
|
this._lastMoveEmitTime = now;
|
|
104586
104590
|
}
|
|
@@ -104611,7 +104615,8 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
104611
104615
|
document.addEventListener('mousemove', this._onMouseMove);
|
|
104612
104616
|
document.addEventListener('pointerlockchange', this._onPointerLockChange);
|
|
104613
104617
|
const canvas = this.app.graphicsDevice.canvas;
|
|
104614
|
-
this._onClickToLock =
|
|
104618
|
+
this._onClickToLock =
|
|
104619
|
+
this._onClickToLock || (() => this._requestPointerLock());
|
|
104615
104620
|
canvas.addEventListener('mousedown', this._onClickToLock);
|
|
104616
104621
|
};
|
|
104617
104622
|
FlyCamera.prototype.deactivate = function () {
|
|
@@ -104661,7 +104666,11 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
104661
104666
|
return {
|
|
104662
104667
|
position: { x: pos.x, y: pos.y, z: pos.z },
|
|
104663
104668
|
rotation: { pitch: this._pitch, yaw: this._yaw },
|
|
104664
|
-
velocity: {
|
|
104669
|
+
velocity: {
|
|
104670
|
+
x: this._velocity.x,
|
|
104671
|
+
y: this._velocity.y,
|
|
104672
|
+
z: this._velocity.z,
|
|
104673
|
+
},
|
|
104665
104674
|
isMoving: Math.abs(this._velocity.x) +
|
|
104666
104675
|
Math.abs(this._velocity.y) +
|
|
104667
104676
|
Math.abs(this._velocity.z) >
|
|
@@ -104669,17 +104678,47 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
104669
104678
|
};
|
|
104670
104679
|
};
|
|
104671
104680
|
FlyCamera.prototype._handleKeyDown = function (e) {
|
|
104672
|
-
|
|
104681
|
+
const keys = [];
|
|
104682
|
+
if (e.code) {
|
|
104683
|
+
keys.push(e.code);
|
|
104684
|
+
}
|
|
104685
|
+
if (e.key) {
|
|
104686
|
+
keys.push(e.key);
|
|
104687
|
+
if (e.key.length === 1) {
|
|
104688
|
+
// Allow matching against both `KeyW` style codes and plain characters
|
|
104689
|
+
keys.push(`Key${e.key.toUpperCase()}`);
|
|
104690
|
+
keys.push(e.key.toUpperCase());
|
|
104691
|
+
keys.push(e.key.toLowerCase());
|
|
104692
|
+
}
|
|
104693
|
+
}
|
|
104694
|
+
for (const k of keys) {
|
|
104695
|
+
this._pressed.add(k);
|
|
104696
|
+
}
|
|
104673
104697
|
};
|
|
104674
104698
|
FlyCamera.prototype._handleKeyUp = function (e) {
|
|
104675
|
-
|
|
104699
|
+
const keys = [];
|
|
104700
|
+
if (e.code) {
|
|
104701
|
+
keys.push(e.code);
|
|
104702
|
+
}
|
|
104703
|
+
if (e.key) {
|
|
104704
|
+
keys.push(e.key);
|
|
104705
|
+
if (e.key.length === 1) {
|
|
104706
|
+
keys.push(`Key${e.key.toUpperCase()}`);
|
|
104707
|
+
keys.push(e.key.toUpperCase());
|
|
104708
|
+
keys.push(e.key.toLowerCase());
|
|
104709
|
+
}
|
|
104710
|
+
}
|
|
104711
|
+
for (const k of keys) {
|
|
104712
|
+
this._pressed.delete(k);
|
|
104713
|
+
}
|
|
104676
104714
|
};
|
|
104677
104715
|
FlyCamera.prototype._handleMouseMove = function (e) {
|
|
104678
104716
|
if (!this._isPointerLocked || !this._isActive)
|
|
104679
104717
|
return;
|
|
104718
|
+
// Invert horizontal (yaw) rotation: moving mouse right rotates view left, and vice versa
|
|
104680
104719
|
const dx = e.movementX * this.lookSensitivity;
|
|
104681
104720
|
const dy = e.movementY * this.lookSensitivity * (this.invertY ? 1 : -1);
|
|
104682
|
-
this._yaw = (this._yaw
|
|
104721
|
+
this._yaw = (this._yaw - dx) % 360;
|
|
104683
104722
|
this._pitch = Math.max(-89, Math.min(89, this._pitch + dy));
|
|
104684
104723
|
};
|
|
104685
104724
|
FlyCamera.prototype._handlePointerLockChange = function () {
|
|
@@ -104702,15 +104741,19 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
104702
104741
|
}
|
|
104703
104742
|
}
|
|
104704
104743
|
};
|
|
104705
|
-
FlyCamera.prototype._updateVelocity = function (
|
|
104744
|
+
FlyCamera.prototype._updateVelocity = function (_dt) {
|
|
104706
104745
|
// Input direction (local space)
|
|
104707
104746
|
const kb = this.keyBindings;
|
|
104708
|
-
const
|
|
104709
|
-
|
|
104710
|
-
|
|
104711
|
-
|
|
104712
|
-
const
|
|
104713
|
-
const
|
|
104747
|
+
const isPressed = (binding, fallbacks) => {
|
|
104748
|
+
const all = [binding, ...fallbacks].filter(Boolean);
|
|
104749
|
+
return all.some(k => this._pressed.has(k));
|
|
104750
|
+
};
|
|
104751
|
+
const forward = isPressed(kb.forward, ['KeyW', 'w', 'W']) ? 1 : 0;
|
|
104752
|
+
const backward = isPressed(kb.backward, ['KeyS', 's', 'S']) ? 1 : 0;
|
|
104753
|
+
const left = isPressed(kb.left, ['KeyA', 'a', 'A']) ? 1 : 0;
|
|
104754
|
+
const right = isPressed(kb.right, ['KeyD', 'd', 'D']) ? 1 : 0;
|
|
104755
|
+
const up = isPressed(kb.up, ['KeyE', 'e', 'E']) ? 1 : 0;
|
|
104756
|
+
const down = isPressed(kb.down, ['KeyQ', 'q', 'Q']) ? 1 : 0;
|
|
104714
104757
|
const inputZ = forward - backward;
|
|
104715
104758
|
const inputX = right - left;
|
|
104716
104759
|
const inputY = up - down;
|
|
@@ -104718,17 +104761,25 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
104718
104761
|
const planarLen = Math.hypot(inputX, inputZ);
|
|
104719
104762
|
const nx = planarLen > 0 ? inputX / planarLen : 0;
|
|
104720
104763
|
const nz = planarLen > 0 ? inputZ / planarLen : 0;
|
|
104721
|
-
// Effective speed with modifiers
|
|
104722
|
-
const speed = this._getEffectiveSpeed();
|
|
104723
|
-
// Compute direction vectors from
|
|
104724
|
-
const
|
|
104725
|
-
const
|
|
104726
|
-
|
|
104727
|
-
|
|
104728
|
-
|
|
104729
|
-
|
|
104730
|
-
|
|
104731
|
-
|
|
104764
|
+
// Effective speed with modifiers (scaled x2 as requested)
|
|
104765
|
+
const speed = this._getEffectiveSpeed() * 2;
|
|
104766
|
+
// Compute direction vectors from the camera entity so movement matches look direction
|
|
104767
|
+
const entity = this.entity;
|
|
104768
|
+
const fwd = entity?.forward && entity.forward.clone
|
|
104769
|
+
? entity.forward.clone()
|
|
104770
|
+
: entity?.forward
|
|
104771
|
+
? new Vec3(entity.forward.x, entity.forward.y, entity.forward.z)
|
|
104772
|
+
: new Vec3(0, 0, -1);
|
|
104773
|
+
const rightVec = entity?.right && entity.right.clone
|
|
104774
|
+
? entity.right.clone()
|
|
104775
|
+
: entity?.right
|
|
104776
|
+
? new Vec3(entity.right.x, entity.right.y, entity.right.z)
|
|
104777
|
+
: new Vec3(1, 0, 0);
|
|
104778
|
+
const upVec = entity?.up && entity.up.clone
|
|
104779
|
+
? entity.up.clone()
|
|
104780
|
+
: entity?.up
|
|
104781
|
+
? new Vec3(entity.up.x, entity.up.y, entity.up.z)
|
|
104782
|
+
: Vec3.UP.clone();
|
|
104732
104783
|
// Target velocity in world space
|
|
104733
104784
|
const target = new Vec3(0, 0, 0);
|
|
104734
104785
|
target.add(fwd.mulScalar(nz * speed));
|
|
@@ -104763,7 +104814,9 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
104763
104814
|
}
|
|
104764
104815
|
};
|
|
104765
104816
|
FlyCamera.prototype._applyConstraints = function () {
|
|
104766
|
-
if (!this.enableCollision &&
|
|
104817
|
+
if (!this.enableCollision &&
|
|
104818
|
+
this.minHeight == null &&
|
|
104819
|
+
this.maxHeight == null) {
|
|
104767
104820
|
return;
|
|
104768
104821
|
}
|
|
104769
104822
|
const pos = this.entity.getPosition
|
|
@@ -140037,7 +140090,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140037
140090
|
this.focus(result.entity);
|
|
140038
140091
|
setTimeout(() => {
|
|
140039
140092
|
const info = this.debugInfo();
|
|
140040
|
-
|
|
140093
|
+
// no-op
|
|
140041
140094
|
if (!info.boundsRadius) {
|
|
140042
140095
|
this.focus(result.entity);
|
|
140043
140096
|
}
|
|
@@ -140833,6 +140886,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140833
140886
|
if (!this.app)
|
|
140834
140887
|
return;
|
|
140835
140888
|
const canvas = this.app.graphicsDevice.canvas;
|
|
140889
|
+
// debug removed
|
|
140836
140890
|
// Ensure canvas and its parent fill available space by default (non-destructive)
|
|
140837
140891
|
if (!canvas.style.display)
|
|
140838
140892
|
canvas.style.display = 'block';
|
|
@@ -140846,18 +140900,22 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140846
140900
|
ps.width = '100%';
|
|
140847
140901
|
if (!ps.height)
|
|
140848
140902
|
ps.height = '100%';
|
|
140903
|
+
// debug removed
|
|
140849
140904
|
}
|
|
140850
140905
|
// Helper: apply resolution and notify dependents
|
|
140851
140906
|
const applyResolution = (width, height) => {
|
|
140852
140907
|
if (canvas.width === width && canvas.height === height)
|
|
140853
140908
|
return;
|
|
140909
|
+
// track previous size if needed in future
|
|
140854
140910
|
canvas.width = width;
|
|
140855
140911
|
canvas.height = height;
|
|
140856
140912
|
this.app.resizeCanvas(width, height);
|
|
140913
|
+
// debug removed
|
|
140857
140914
|
if (this._orbit &&
|
|
140858
140915
|
this._orbit.navigationCube &&
|
|
140859
140916
|
typeof this._orbit.navigationCube.onCanvasResize === 'function') {
|
|
140860
140917
|
this._orbit.navigationCube.onCanvasResize();
|
|
140918
|
+
// debug removed
|
|
140861
140919
|
}
|
|
140862
140920
|
};
|
|
140863
140921
|
// Fallback: compute from CSS box * devicePixelRatio
|
|
@@ -140866,6 +140924,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140866
140924
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
140867
140925
|
const width = Math.floor(rect.width * pixelRatio);
|
|
140868
140926
|
const height = Math.floor(rect.height * pixelRatio);
|
|
140927
|
+
// debug removed
|
|
140869
140928
|
applyResolution(width, height);
|
|
140870
140929
|
};
|
|
140871
140930
|
// Prefer ResizeObserver entry data (devicePixelContentBoxSize when available)
|
|
@@ -140876,6 +140935,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140876
140935
|
if (dpcb && dpcb.length > 0) {
|
|
140877
140936
|
width = Math.ceil(dpcb[0].inlineSize);
|
|
140878
140937
|
height = Math.ceil(dpcb[0].blockSize);
|
|
140938
|
+
// debug removed
|
|
140879
140939
|
}
|
|
140880
140940
|
else {
|
|
140881
140941
|
const cbs = entry.contentBoxSize;
|
|
@@ -140883,6 +140943,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140883
140943
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
140884
140944
|
width = Math.ceil(cbs[0].inlineSize * pixelRatio);
|
|
140885
140945
|
height = Math.ceil(cbs[0].blockSize * pixelRatio);
|
|
140946
|
+
// debug removed
|
|
140886
140947
|
}
|
|
140887
140948
|
}
|
|
140888
140949
|
if (width !== null && height !== null) {
|
|
@@ -140894,6 +140955,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140894
140955
|
};
|
|
140895
140956
|
// Initial resolution setup
|
|
140896
140957
|
updateResolution();
|
|
140958
|
+
// debug removed
|
|
140897
140959
|
// Set up resize observer for automatic resolution updates
|
|
140898
140960
|
if (window.ResizeObserver) {
|
|
140899
140961
|
this._resizeObserver = new ResizeObserver((entries) => {
|
|
@@ -140922,16 +140984,53 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140922
140984
|
}
|
|
140923
140985
|
});
|
|
140924
140986
|
// Observe both the canvas and its parent container for resize events
|
|
140925
|
-
|
|
140987
|
+
try {
|
|
140988
|
+
// Prefer device-pixel-content-box for pixel-perfect canvas sizing
|
|
140989
|
+
;
|
|
140990
|
+
this._resizeObserver.observe(canvas, {
|
|
140991
|
+
box: 'device-pixel-content-box',
|
|
140992
|
+
});
|
|
140993
|
+
}
|
|
140994
|
+
catch {
|
|
140995
|
+
this._resizeObserver.observe(canvas);
|
|
140996
|
+
}
|
|
140997
|
+
// debug removed
|
|
140926
140998
|
if (canvas.parentElement) {
|
|
140927
140999
|
this._resizeObserver.observe(canvas.parentElement);
|
|
141000
|
+
// debug removed
|
|
140928
141001
|
}
|
|
140929
141002
|
}
|
|
140930
141003
|
// Additionally listen to window resize to handle viewport changes
|
|
140931
141004
|
// (e.g., when resizing dev tools). This mirrors superSplat behavior
|
|
140932
141005
|
// and ensures the canvas always matches the available space.
|
|
140933
|
-
|
|
140934
|
-
|
|
141006
|
+
const onWindowResize = () => {
|
|
141007
|
+
updateResolution();
|
|
141008
|
+
};
|
|
141009
|
+
window.addEventListener('resize', onWindowResize);
|
|
141010
|
+
this._resizeHandler = onWindowResize;
|
|
141011
|
+
}
|
|
141012
|
+
/**
|
|
141013
|
+
* Force recalculation of canvas resolution based on current DOM size.
|
|
141014
|
+
* Useful when container layout changes are not captured by the observer.
|
|
141015
|
+
*/
|
|
141016
|
+
updateCanvasResolution() {
|
|
141017
|
+
if (!this.app)
|
|
141018
|
+
return;
|
|
141019
|
+
const canvas = this.app.graphicsDevice.canvas;
|
|
141020
|
+
const rect = canvas.getBoundingClientRect();
|
|
141021
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
141022
|
+
const width = Math.floor(rect.width * pixelRatio);
|
|
141023
|
+
const height = Math.floor(rect.height * pixelRatio);
|
|
141024
|
+
if (canvas.width !== width || canvas.height !== height) {
|
|
141025
|
+
canvas.width = width;
|
|
141026
|
+
canvas.height = height;
|
|
141027
|
+
this.app.resizeCanvas(width, height);
|
|
141028
|
+
if (this._orbit &&
|
|
141029
|
+
this._orbit.navigationCube &&
|
|
141030
|
+
typeof this._orbit.navigationCube.onCanvasResize === 'function') {
|
|
141031
|
+
this._orbit.navigationCube.onCanvasResize();
|
|
141032
|
+
}
|
|
141033
|
+
}
|
|
140935
141034
|
}
|
|
140936
141035
|
}
|
|
140937
141036
|
|
|
@@ -140962,6 +141061,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140962
141061
|
this._config = { ...DEFAULT_CONFIG };
|
|
140963
141062
|
this._isInitialized = false;
|
|
140964
141063
|
this._isDestroyed = false;
|
|
141064
|
+
this._hostResizeObserver = null;
|
|
140965
141065
|
}
|
|
140966
141066
|
// Observed attributes that trigger attributeChangedCallback
|
|
140967
141067
|
static get observedAttributes() {
|
|
@@ -141309,6 +141409,22 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
141309
141409
|
this._canvas.setAttribute('role', 'img');
|
|
141310
141410
|
this._canvas.setAttribute('aria-label', '3D Splat Viewer');
|
|
141311
141411
|
this.appendChild(this._canvas);
|
|
141412
|
+
// Observe host element for size changes and force canvas resolution update
|
|
141413
|
+
try {
|
|
141414
|
+
if (window.ResizeObserver) {
|
|
141415
|
+
this._hostResizeObserver = new ResizeObserver(() => {
|
|
141416
|
+
// Force resolution update in core to sync canvas with host/container
|
|
141417
|
+
try {
|
|
141418
|
+
this._core?.updateCanvasResolution();
|
|
141419
|
+
}
|
|
141420
|
+
catch { }
|
|
141421
|
+
});
|
|
141422
|
+
this._hostResizeObserver.observe(this);
|
|
141423
|
+
if (this.parentElement)
|
|
141424
|
+
this._hostResizeObserver.observe(this.parentElement);
|
|
141425
|
+
}
|
|
141426
|
+
}
|
|
141427
|
+
catch { }
|
|
141312
141428
|
// Update configuration from attributes
|
|
141313
141429
|
this._updateConfigFromAttributes();
|
|
141314
141430
|
// Initialize the core viewer
|
|
@@ -141365,6 +141481,11 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
141365
141481
|
return;
|
|
141366
141482
|
}
|
|
141367
141483
|
try {
|
|
141484
|
+
// Disconnect host resize observer
|
|
141485
|
+
if (this._hostResizeObserver) {
|
|
141486
|
+
this._hostResizeObserver.disconnect();
|
|
141487
|
+
this._hostResizeObserver = null;
|
|
141488
|
+
}
|
|
141368
141489
|
// Clean up core
|
|
141369
141490
|
if (this._core) {
|
|
141370
141491
|
this._core.destroy();
|
|
@@ -141484,7 +141605,6 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
141484
141605
|
return;
|
|
141485
141606
|
}
|
|
141486
141607
|
// Stats handling will be implemented when we add stats functionality
|
|
141487
|
-
console.log('Stats change requested:', this.enableStats);
|
|
141488
141608
|
}
|
|
141489
141609
|
/**
|
|
141490
141610
|
* Set up event listeners for the core viewer
|