spoint 0.1.61 → 0.1.63

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,6 +1,6 @@
1
1
  import * as THREE from 'three'
2
2
 
3
- export class ARControls {
3
+ export class XRControls {
4
4
  constructor(options = {}) {
5
5
  this.enabled = false
6
6
  this.options = {
@@ -57,13 +57,13 @@ export class ARControls {
57
57
 
58
58
  async init(renderer) {
59
59
  if (!navigator.xr) {
60
- console.warn('[AR] WebXR not supported')
60
+ console.warn('[XR] WebXR not supported')
61
61
  return false
62
62
  }
63
63
 
64
64
  const isSupported = await navigator.xr.isSessionSupported('immersive-ar')
65
65
  if (!isSupported) {
66
- console.warn('[AR] immersive-ar not supported')
66
+ console.warn('[XR] immersive-ar not supported')
67
67
  return false
68
68
  }
69
69
 
@@ -96,10 +96,10 @@ export class ARControls {
96
96
  this.session.addEventListener('planesdetected', (e) => this.onPlanesDetected(e))
97
97
 
98
98
  this.enabled = true
99
- console.log('[AR] Session started')
99
+ console.log('[XR] Session started')
100
100
  return true
101
101
  } catch (err) {
102
- console.error('[AR] Failed to start session:', err)
102
+ console.error('[XR] Failed to start session:', err)
103
103
  return false
104
104
  }
105
105
  }
@@ -116,7 +116,7 @@ export class ARControls {
116
116
  this.hitTestSource = null
117
117
  this.planeDetected = false
118
118
  this.anchorPlaced = false
119
- console.log('[AR] Session ended')
119
+ console.log('[XR] Session ended')
120
120
  }
121
121
 
122
122
  onPlanesDetected(event) {
@@ -180,7 +180,7 @@ export class ARControls {
180
180
  this.anchorRotation.copy(this.reticle.quaternion)
181
181
  this.anchorPlaced = true
182
182
  this.hideReticle()
183
- console.log('[AR] Anchor placed at:', this.anchorPosition)
183
+ console.log('[XR] Anchor placed at:', this.anchorPosition)
184
184
  return true
185
185
  }
186
186
 
@@ -200,7 +200,7 @@ export class ARControls {
200
200
  this.anchorRotation.copy(this.cameraQuaternion)
201
201
  this.anchorPlaced = true
202
202
  this.hideReticle()
203
- console.log('[AR] Anchor placed at camera:', this.anchorPosition)
203
+ console.log('[XR] Anchor placed at camera:', this.anchorPosition)
204
204
  return true
205
205
  }
206
206
 
@@ -233,7 +233,7 @@ export class ARControls {
233
233
  this.anchorRotation.copy(yawQuat)
234
234
  this.anchorPlaced = true
235
235
  this.hideReticle()
236
- console.log('[AR] Set initial FPS position:', this.anchorPosition)
236
+ console.log('[XR] Set initial FPS position:', this.anchorPosition)
237
237
  return true
238
238
  }
239
239
 
@@ -258,7 +258,7 @@ export class ARControls {
258
258
  }
259
259
  }
260
260
 
261
- export async function createARButton(renderer, onStart, onEnd) {
261
+ export async function createXRButton(renderer, onStart, onEnd) {
262
262
  if (!navigator.xr) return null
263
263
 
264
264
  const isSupported = await navigator.xr.isSessionSupported('immersive-ar')
@@ -288,7 +288,7 @@ export async function createARButton(renderer, onStart, onEnd) {
288
288
  if (onStart) {
289
289
  const started = await onStart()
290
290
  if (started) {
291
- button.textContent = 'Exit AR'
291
+ button.textContent = 'Exit XR'
292
292
  button.style.background = 'rgba(150, 0, 0, 0.8)'
293
293
  if (onEnd) {
294
294
  button.onclick = onEnd
package/client/app.js CHANGED
@@ -18,7 +18,7 @@ import { LoadingManager } from './LoadingManager.js'
18
18
  import { fetchCached } from './ModelCache.js'
19
19
  import { createLoadingScreen } from './createLoadingScreen.js'
20
20
  import { MobileControls, detectDevice } from './MobileControls.js'
21
- import { ARControls, createARButton } from './ARControls.js'
21
+ import { XRControls, createXRButton } from './XRControls.js'
22
22
 
23
23
  const loadingMgr = new LoadingManager()
24
24
  const loadingScreen = createLoadingScreen(loadingMgr)
@@ -89,7 +89,7 @@ let vignetteOpacity = 0
89
89
  let vignetteTargetOpacity = 0
90
90
 
91
91
  let mobileControls = null
92
- let arControls = null
92
+ let xrControls = null
93
93
  let arButton = null
94
94
  let arEnabled = false
95
95
  const deviceInfo = detectDevice()
@@ -104,8 +104,8 @@ if (deviceInfo.isMobile) {
104
104
  console.log('[Mobile] Touch controls initialized:', deviceInfo)
105
105
  }
106
106
 
107
- arControls = new ARControls({ placementMode: true, planeDetection: true })
108
- const arReticle = arControls.createReticle()
107
+ xrControls = new XRControls({ placementMode: true, planeDetection: true })
108
+ const arReticle = xrControls.createReticle()
109
109
  scene.add(arReticle)
110
110
 
111
111
  function createLaserPointer() {
@@ -1199,10 +1199,10 @@ function initInputHandler() {
1199
1199
  }
1200
1200
 
1201
1201
  async function initAR() {
1202
- const supported = await arControls.init(renderer)
1202
+ const supported = await xrControls.init(renderer)
1203
1203
  if (supported) {
1204
- arButton = await createARButton(renderer, async () => {
1205
- const started = await arControls.start()
1204
+ arButton = await createXRButton(renderer, async () => {
1205
+ const started = await xrControls.start()
1206
1206
  if (started) {
1207
1207
  arEnabled = true
1208
1208
  scene.background = null
@@ -1213,7 +1213,7 @@ async function initAR() {
1213
1213
  }
1214
1214
  return false
1215
1215
  }, async () => {
1216
- await arControls.end()
1216
+ await xrControls.end()
1217
1217
  arEnabled = false
1218
1218
  scene.background = new THREE.Color(0x87ceeb)
1219
1219
  ground.visible = true
@@ -1566,10 +1566,10 @@ function animate(timestamp) {
1566
1566
  if (arEnabled) {
1567
1567
  const xrFrame = renderer.xr.getFrame()
1568
1568
  if (xrFrame) {
1569
- arControls.update(xrFrame, camera, scene)
1569
+ xrControls.update(xrFrame, camera, scene)
1570
1570
  const arLocal = playerStates.get(client.playerId)
1571
- if (arLocal?.position && !arControls.anchorPlaced) {
1572
- arControls.setInitialFPSPosition(arLocal.position, cam.yaw)
1571
+ if (arLocal?.position && !xrControls.anchorPlaced) {
1572
+ xrControls.setInitialFPSPosition(arLocal.position, cam.yaw)
1573
1573
  }
1574
1574
  }
1575
1575
  }
@@ -1583,11 +1583,11 @@ setupControllers()
1583
1583
  setupHands()
1584
1584
  window.__VR_DEBUG__ = false
1585
1585
  window.debug = {
1586
- scene, camera, renderer, client, playerMeshes, entityMeshes, appModules, inputHandler, playerVrms, playerAnimators, loadingMgr, loadingScreen, controllerModels, controllerGrips, handModels, mobileControls, arControls,
1586
+ scene, camera, renderer, client, playerMeshes, entityMeshes, appModules, inputHandler, playerVrms, playerAnimators, loadingMgr, loadingScreen, controllerModels, controllerGrips, handModels, mobileControls, xrControls,
1587
1587
  enableVRDebug: () => { window.__VR_DEBUG__ = true; console.log('[VR] Debug enabled - button/axis logging active') },
1588
1588
  disableVRDebug: () => { window.__VR_DEBUG__ = false; console.log('[VR] Debug disabled') },
1589
1589
  vrInput: () => inputHandler?.getInput() || null,
1590
1590
  vrSettings: () => vrSettings,
1591
1591
  deviceInfo: () => deviceInfo,
1592
- placeARAnchor: () => arControls?.placeAnchor() || arControls?.placeAtCamera()
1592
+ placeARAnchor: () => xrControls?.placeAnchor() || xrControls?.placeAtCamera()
1593
1593
  }
package/client/camera.js CHANGED
@@ -37,6 +37,7 @@ export function createCameraController(camera, scene) {
37
37
  let editCamSpeed = 8
38
38
  const envMeshes = []
39
39
  let fpsRayTimer = 0, tpsRayTimer = 0, cachedClipDist = 10, cachedAimPoint = null
40
+ let fpsPushX = 0, fpsPushY = 0, fpsPushZ = 0
40
41
  let cameraBone = null
41
42
  let headBone = null
42
43
  let headBoneHidden = false
@@ -150,12 +151,16 @@ export function createCameraController(camera, scene) {
150
151
  } else {
151
152
  camera.position.copy(camTarget)
152
153
  }
154
+ camera.position.x += fpsPushX
155
+ camera.position.y += fpsPushY
156
+ camera.position.z += fpsPushZ
153
157
  if (headBone && !headBoneHidden) { headBone.scale.set(0, 0, 0); headBoneHidden = true }
154
158
  const wallDist = 0.35
155
159
  const fwdWallDist = 0.25
156
160
  fpsRayTimer += frameDt
157
161
  if (fpsRayTimer >= 0.05 && envMeshes.length) {
158
162
  fpsRayTimer = 0
163
+ fpsPushX = 0; fpsPushY = 0; fpsPushZ = 0
159
164
  _fpsRayOrigin.copy(camera.position)
160
165
  _fpsRayDir.set(-fwdX, -fwdY, -fwdZ)
161
166
  camRaycaster.set(_fpsRayOrigin, _fpsRayDir)
@@ -166,6 +171,9 @@ export function createCameraController(camera, scene) {
166
171
  if (localMesh && isDescendant(hit.object, localMesh)) continue
167
172
  const push = wallDist - hit.distance
168
173
  if (push > 0) {
174
+ fpsPushX += fwdX * push
175
+ fpsPushY += fwdY * push
176
+ fpsPushZ += fwdZ * push
169
177
  camera.position.x += fwdX * push
170
178
  camera.position.y += fwdY * push
171
179
  camera.position.z += fwdZ * push
@@ -181,6 +189,9 @@ export function createCameraController(camera, scene) {
181
189
  if (localMesh && isDescendant(hit.object, localMesh)) continue
182
190
  const push = fwdWallDist - hit.distance
183
191
  if (push > 0) {
192
+ fpsPushX -= fwdX * push
193
+ fpsPushY -= fwdY * push
194
+ fpsPushZ -= fwdZ * push
184
195
  camera.position.x -= fwdX * push
185
196
  camera.position.y -= fwdY * push
186
197
  camera.position.z -= fwdZ * push
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spoint",
3
- "version": "0.1.61",
3
+ "version": "0.1.63",
4
4
  "description": "Physics and netcode SDK for multiplayer game servers",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -248,17 +248,19 @@ export class InputHandler {
248
248
  const primaryY = axes[1] ?? 0
249
249
  const secondaryX = axes.length > 2 ? (axes[2] ?? 0) : 0
250
250
  const secondaryY = axes.length > 3 ? (axes[3] ?? 0) : 0
251
+ const moveX = axes.length > 2 ? secondaryX : primaryX
252
+ const moveY = axes.length > 3 ? secondaryY : primaryY
251
253
 
252
254
  if (source.handedness === 'left') {
253
- if (Math.abs(primaryX) > DEAD) {
254
- analogRight = primaryX
255
- if (primaryX > THRESH) right = true
256
- if (primaryX < -THRESH) left = true
255
+ if (Math.abs(moveX) > DEAD) {
256
+ analogRight = moveX
257
+ if (moveX > THRESH) right = true
258
+ if (moveX < -THRESH) left = true
257
259
  }
258
- if (Math.abs(primaryY) > DEAD) {
259
- analogForward = -primaryY
260
- if (primaryY < -THRESH) forward = true
261
- if (primaryY > THRESH) backward = true
260
+ if (Math.abs(moveY) > DEAD) {
261
+ analogForward = -moveY
262
+ if (moveY < -THRESH) forward = true
263
+ if (moveY > THRESH) backward = true
262
264
  }
263
265
 
264
266
  if (btns[0]?.pressed) jump = true
@@ -56,15 +56,14 @@ export class MessageHandler {
56
56
  const oldPlayerId = this._playerId
57
57
  this._playerId = payload.playerId
58
58
  this._currentTick = payload.tick
59
- if (oldPlayerId && oldPlayerId !== this._playerId) {
60
- snapProc?.removePlayer(oldPlayerId)
61
- if (this._smoothInterp) this._smoothInterp.removePlayer(oldPlayerId)
62
- this._callbacks.onPlayerLeft?.(oldPlayerId)
63
- }
64
- if (!this._predEngine) {
65
- this._predEngine = new PredictionEngine(this._config.tickRate || 128)
66
- this._predEngine.init(this._playerId)
59
+ snapProc?.clear()
60
+ if (this._smoothInterp) {
61
+ this._smoothInterp.reset()
62
+ this._smoothInterp.setLocalPlayer(this._playerId)
67
63
  }
64
+ if (oldPlayerId) this._callbacks.onPlayerLeft?.(oldPlayerId)
65
+ this._predEngine = new PredictionEngine(this._config.tickRate || 128)
66
+ this._predEngine.init(this._playerId)
68
67
  if (this._config.smoothInterpolation !== false && !this._smoothInterp) {
69
68
  this._smoothInterp = new SmoothInterpolation({ predictionEnabled: this._config.predictionEnabled !== false })
70
69
  this._smoothInterp.setLocalPlayer(this._playerId)