spoint 0.1.676 → 0.1.678

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.
@@ -85,8 +85,8 @@ export default {
85
85
  fillIntensity: 0.4,
86
86
  fillPosition: [-20, 30, -10],
87
87
  shadowMapSize: 1024,
88
- shadowBias: 0.0038,
89
- shadowNormalBias: 0.6,
88
+ shadowBias: -0.0005,
89
+ shadowNormalBias: 0.05,
90
90
  // shadowRadius/shadowBlurSamples are read only by three.js's VSM blur pass
91
91
  // (WebGLShadowMap.js postProcessShadowMap, gated on shadow.type===VSMShadowMap);
92
92
  // client/core/SceneSetup.js hardcodes renderer.shadowMap.type=PCFShadowMap, so
package/client/app.js CHANGED
@@ -258,7 +258,7 @@ try {
258
258
  _showBootFailureOverlay('WebGL2 is required', 'This 3D world needs a browser with WebGL2 support. Please update your browser, enable hardware acceleration, or try a different device.\n\n' + ((err && (err.stack || err.message)) || String(err)))
259
259
  throw err
260
260
  }
261
- const { ambient, studio, sun } = setupLights(scene), { gltfLoader } = createLoaders(renderer)
261
+ const { ambient, studio, sun } = setupLights(scene), { gltfLoader, ktx2Loader } = createLoaders(renderer)
262
262
  // Kick the anim-lib fetch now (idempotent, cached) so it overlaps the world import + cold worker boot instead of serializing behind them.
263
263
  preloadAnimationLibrary(gltfLoader)
264
264
  if (typeof window !== 'undefined') {
@@ -382,8 +382,7 @@ async function _finishLoading() {
382
382
  const SCENERY_BUILD_TIMEOUT_MS = 30000
383
383
  if (_terrainCfg && !terrainBackdrop) {
384
384
  loadingMgr.setLabel('Building world (first load can take up to 30s)...')
385
- let _sceneryTimedOut = false
386
- try { await Promise.race([_buildWorldScenery(), new Promise(r => setTimeout(() => { _sceneryTimedOut = true; r() }, SCENERY_BUILD_TIMEOUT_MS))]) }
385
+ try { await Promise.race([_buildWorldScenery(), new Promise(r => setTimeout(r, SCENERY_BUILD_TIMEOUT_MS))]) }
387
386
  catch (e) { console.error('[terrain] scenery build failed:', e?.message || e) }
388
387
  // Cold-load retry: a transient GL_INVALID_OPERATION storm (ModelPool cluster draw races the index upload) can poison planet init once; drain errors + rebuild once if __terrain never got set.
389
388
  if (typeof window !== 'undefined' && !window.__terrain && _terrainCfg) {
@@ -393,8 +392,7 @@ async function _finishLoading() {
393
392
  try { terrainBackdrop && terrainBackdrop.dispose && terrainBackdrop.dispose() } catch (_) {}
394
393
  terrainBackdrop = null
395
394
  await new Promise(r => setTimeout(r, 500))
396
- _sceneryTimedOut = false
397
- try { await Promise.race([_buildWorldScenery(), new Promise(r => setTimeout(() => { _sceneryTimedOut = true; r() }, SCENERY_BUILD_TIMEOUT_MS))]) }
395
+ try { await Promise.race([_buildWorldScenery(), new Promise(r => setTimeout(r, SCENERY_BUILD_TIMEOUT_MS))]) }
398
396
  catch (e) { console.error('[terrain] scenery rebuild failed:', e?.message || e) }
399
397
  }
400
398
  // The scenery build did not finish before the timeout raced it (or planet is still absent) --
@@ -402,7 +400,13 @@ async function _finishLoading() {
402
400
  // forever, but silently shipping a bare/incomplete scene with no way to recover is its own bug.
403
401
  // Surface it with a Retry action that re-invokes _buildWorldScenery() in place once the terrain
404
402
  // config + scene are already set up, without reloading the page.
405
- if ((_sceneryTimedOut || (typeof window !== 'undefined' && !window.__terrain)) && _terrainCfg) {
403
+ // Only surface the retry toast when the terrain is GENUINELY still absent after the race settles --
404
+ // _sceneryTimedOut alone means the setTimeout won the race, not that the build actually failed: a
405
+ // cold build that finishes a moment after the clock (real terrain now present, window.__terrain set)
406
+ // is a benign timing win, not a defect, and showing a scary "did not finish loading" toast over a
407
+ // fully-working world trains users to distrust a working load. window.__terrain absence is the real
408
+ // failure signal either way.
409
+ if (typeof window !== 'undefined' && !window.__terrain && _terrainCfg) {
406
410
  console.warn('[terrain] scenery build did not complete before timeout -> showing retry toast')
407
411
  showToast('World scenery did not finish loading', 'warn', 8000, {
408
412
  action: {
@@ -676,7 +680,7 @@ cullingHub.register('occlusionQueryBudget', () => occlusionQueryBudget.getStats(
676
680
  // client/core/WebGPUCullingHubIntegration.js's header for the full scope note); call
677
681
  // window.__runWebgpuComputeCull() from a dev console / future opt-in tier to populate it.
678
682
  window.__runWebgpuComputeCull = () => import('./core/WebGPUCullingHubIntegration.js').then(m => m.runAndRegister(cullingHub, { scene, camera }))
679
- const pm = createPlayerManager(scene, gltfLoader, cam, null, sceneGraph, modelPool)
683
+ const pm = createPlayerManager(scene, gltfLoader, cam, ktx2Loader, sceneGraph, modelPool)
680
684
  // Player LOD: real distance-tier classification (FULL/REDUCED/DOT) for the remote-player crowd -- see
681
685
  // core/PlayerLOD.js. tickPlayerAnimators (below) applies the verdict to gate VRM anim/feature updates;
682
686
  // the crowd-dot InstancedMesh2 renders everyone beyond the REDUCED ring at near-zero cost. Instantiated
@@ -26,7 +26,7 @@ const DEFAULTS = {
26
26
  sfxVolume: 1,
27
27
  musicVolume: 1,
28
28
  qualityPreset: 'Medium',
29
- dprAuto: true,
29
+ dprAuto: false,
30
30
  }
31
31
 
32
32
  function loadSaved() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spoint",
3
- "version": "0.1.676",
3
+ "version": "0.1.678",
4
4
  "description": "Physics and netcode SDK for multiplayer game servers",
5
5
  "type": "module",
6
6
  "workspaces": [