minecraft-renderer 0.1.79 → 0.1.80

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.
Files changed (200) hide show
  1. package/README.md +29 -25
  2. package/dist/mesher.js +36 -36
  3. package/dist/mesher.js.map +4 -4
  4. package/dist/mesherWasm.js +217 -217
  5. package/dist/minecraft-renderer.js +27 -27
  6. package/dist/minecraft-renderer.js.meta.json +1 -1
  7. package/dist/threeWorker.js +133 -133
  8. package/package.json +5 -2
  9. package/src/bundler/bundlePrepare.ts +3 -8
  10. package/src/graphicsBackend/appViewer.ts +10 -7
  11. package/src/graphicsBackend/config.ts +1 -5
  12. package/src/graphicsBackend/playerState.ts +35 -34
  13. package/src/graphicsBackend/preloadWorkers.ts +43 -41
  14. package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
  15. package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
  16. package/src/graphicsBackend/types.ts +2 -2
  17. package/src/index.ts +6 -27
  18. package/src/lib/DebugGui.ts +34 -31
  19. package/src/lib/animationController.ts +9 -9
  20. package/src/lib/bakeLegacyLight.ts +1 -6
  21. package/src/lib/bindAbortableListener.test.ts +32 -12
  22. package/src/lib/bindAbortableListener.ts +14 -6
  23. package/src/lib/blockEntityLightRegistry.ts +11 -20
  24. package/src/lib/blockEntityLighting.test.ts +1 -6
  25. package/src/lib/blockEntityLighting.ts +5 -5
  26. package/src/lib/buildSharedConfig.mjs +4 -4
  27. package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
  28. package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
  29. package/src/lib/cameraBobbing.ts +1 -1
  30. package/src/lib/canvas2DOverlay.example.ts +13 -33
  31. package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
  32. package/src/lib/canvas2DOverlay.ts +28 -47
  33. package/src/lib/cleanupDecorator.ts +2 -2
  34. package/src/lib/createPlayerObject.test.ts +2 -7
  35. package/src/lib/createPlayerObject.ts +18 -25
  36. package/src/lib/frameTimingCollector.ts +2 -5
  37. package/src/lib/guiRenderer.ts +57 -42
  38. package/src/lib/items.ts +15 -9
  39. package/src/lib/mesherlogReader.ts +5 -6
  40. package/src/lib/simpleUtils.ts +5 -5
  41. package/src/lib/skyLight.ts +3 -3
  42. package/src/lib/smoothSwitcher.ts +11 -18
  43. package/src/lib/ui/newStats.ts +10 -12
  44. package/src/lib/utils/proxy.ts +7 -1
  45. package/src/lib/utils/skins.ts +4 -4
  46. package/src/lib/utils.ts +1 -1
  47. package/src/lib/workerMessageSanitize.ts +5 -12
  48. package/src/lib/workerProxy.ts +52 -42
  49. package/src/lib/workerSyncOps.test.ts +58 -41
  50. package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
  51. package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
  52. package/src/lib/worldrendererCommon.ts +338 -211
  53. package/src/mesher-legacy/mesher.ts +9 -4
  54. package/src/mesher-legacy/test/a.ts +1 -1
  55. package/src/mesher-legacy/test/mesherTester.ts +2 -2
  56. package/src/mesher-legacy/test/playground.ts +1 -1
  57. package/src/mesher-legacy/test/run/test-js.ts +1 -1
  58. package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
  59. package/src/mesher-legacy/test/test-perf.ts +1 -1
  60. package/src/mesher-legacy/test/tests.test.ts +2 -2
  61. package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
  62. package/src/mesher-shared/blockEntityMetadata.ts +28 -19
  63. package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
  64. package/src/mesher-shared/computeHeightmap.ts +2 -4
  65. package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
  66. package/src/mesher-shared/faceOcclusion.ts +324 -0
  67. package/src/mesher-shared/models.ts +80 -131
  68. package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
  69. package/src/mesher-shared/shared.ts +46 -46
  70. package/src/mesher-shared/standaloneRenderer.ts +40 -44
  71. package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
  72. package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
  73. package/src/mesher-shared/vertexShading.ts +2 -11
  74. package/src/mesher-shared/world.ts +19 -19
  75. package/src/mesher-shared/worldLighting.test.ts +2 -2
  76. package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
  77. package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
  78. package/src/performanceMonitor/index.ts +1 -5
  79. package/src/performanceMonitor/types.ts +1 -1
  80. package/src/playerState/playerState.ts +55 -50
  81. package/src/playerState/types.ts +2 -8
  82. package/src/playground/allEntitiesDebug.ts +19 -16
  83. package/src/playground/baseScene.ts +29 -32
  84. package/src/playground/mobileControls.tsx +133 -129
  85. package/src/playground/playground.html +76 -73
  86. package/src/playground/playground.ts +14 -1
  87. package/src/playground/playgroundUi.tsx +100 -74
  88. package/src/playground/reactUtils.ts +3 -7
  89. package/src/playground/scenes/entities.ts +10 -7
  90. package/src/playground/scenes/frequentUpdates.ts +5 -5
  91. package/src/playground/scenes/geometryExport.ts +6 -20
  92. package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
  93. package/src/playground/scenes/index.ts +1 -1
  94. package/src/playground/scenes/lightingStarfield.ts +18 -12
  95. package/src/playground/scenes/main.ts +15 -11
  96. package/src/playground/scenes/partialBlockCulling.ts +31 -0
  97. package/src/playground/scenes/railsCobweb.ts +1 -1
  98. package/src/playground/scenes/rotationIssue.ts +1 -1
  99. package/src/playground/scenes/slabsOptimization.ts +1 -2
  100. package/src/playground/scenes/transparencyIssue.ts +1 -1
  101. package/src/playground/shared.ts +2 -2
  102. package/src/resourcesManager/resourcesManager.ts +29 -54
  103. package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
  104. package/src/shims/minecraftData.ts +70 -24
  105. package/src/sign-renderer/index.html +10 -12
  106. package/src/sign-renderer/index.ts +29 -29
  107. package/src/sign-renderer/playground.ts +22 -15
  108. package/src/sign-renderer/tests.test.ts +16 -13
  109. package/src/sign-renderer/vite.config.ts +2 -2
  110. package/src/three/appShared.ts +46 -25
  111. package/src/three/bannerRenderer.ts +33 -61
  112. package/src/three/cameraShake.ts +15 -6
  113. package/src/three/chunkMeshManager.ts +239 -282
  114. package/src/three/cinimaticScript.ts +26 -15
  115. package/src/three/cubeDrawSpans.ts +27 -37
  116. package/src/three/cubeMultiDraw.ts +9 -22
  117. package/src/three/documentRenderer.ts +15 -18
  118. package/src/three/entities.ts +175 -150
  119. package/src/three/entity/EntityMesh.ts +114 -108
  120. package/src/three/entity/animations.js +3 -3
  121. package/src/three/entity/armorModels.ts +15 -15
  122. package/src/three/entity/gltfAnimationUtils.ts +2 -5
  123. package/src/three/fireworks.ts +34 -32
  124. package/src/three/fireworksRenderer.ts +32 -29
  125. package/src/three/globalBlockBuffer.ts +167 -100
  126. package/src/three/globalLegacyBuffer.ts +257 -166
  127. package/src/three/graphicsBackendBase.ts +19 -25
  128. package/src/three/graphicsBackendOffThread.ts +12 -15
  129. package/src/three/hand.ts +21 -21
  130. package/src/three/handLegacy.ts +3 -13
  131. package/src/three/holdingBlock.ts +116 -79
  132. package/src/three/holdingBlockFactory.ts +1 -4
  133. package/src/three/holdingBlockItemIdentity.test.ts +25 -17
  134. package/src/three/holdingBlockItemIdentity.ts +9 -6
  135. package/src/three/holdingBlockLegacy.ts +113 -132
  136. package/src/three/itemMesh.ts +20 -29
  137. package/src/three/legacyMultiDraw.ts +10 -16
  138. package/src/three/legacySectionCull.ts +8 -14
  139. package/src/three/menuBackground/activeView.ts +1 -4
  140. package/src/three/menuBackground/assetUrl.ts +1 -1
  141. package/src/three/menuBackground/classic.ts +4 -12
  142. package/src/three/menuBackground/gpuPreference.ts +1 -3
  143. package/src/three/menuBackground/index.ts +2 -11
  144. package/src/three/menuBackground/renderer.ts +1 -5
  145. package/src/three/menuBackground/types.ts +1 -4
  146. package/src/three/menuBackground/v2.ts +196 -96
  147. package/src/three/menuBackground/v2Meta.ts +3 -3
  148. package/src/three/menuBackground/worldBlocks.ts +37 -35
  149. package/src/three/modules/blockBreakParticles.ts +59 -28
  150. package/src/three/modules/cameraBobbing.ts +3 -6
  151. package/src/three/modules/index.ts +1 -1
  152. package/src/three/modules/rain.ts +10 -23
  153. package/src/three/modules/sciFiWorldReveal.ts +11 -25
  154. package/src/three/modules/starfield.ts +7 -13
  155. package/src/three/renderSlot.ts +28 -16
  156. package/src/three/rendererModuleSystem.ts +1 -3
  157. package/src/three/sceneOrigin.ts +96 -33
  158. package/src/three/sectionRaycastAabb.ts +30 -18
  159. package/src/three/shaderCubeMesh.ts +6 -17
  160. package/src/three/shaders/cubeBlockShader.ts +85 -96
  161. package/src/three/shaders/legacyBlockShader.ts +21 -43
  162. package/src/three/shaders/textureIndexMapping.ts +89 -95
  163. package/src/three/shaders/tintPalette.ts +156 -170
  164. package/src/three/signTextureCache.ts +9 -12
  165. package/src/three/skyboxRenderer.ts +62 -70
  166. package/src/three/tests/chunkMeshManagerLegacy.test.ts +34 -34
  167. package/src/three/tests/cubeDrawSpans.test.ts +55 -25
  168. package/src/three/tests/globalBlockBuffer.test.ts +217 -0
  169. package/src/three/tests/globalLegacyBuffer.test.ts +300 -41
  170. package/src/three/tests/legacyMultiDraw.test.ts +8 -29
  171. package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
  172. package/src/three/tests/signTextureCache.test.ts +4 -4
  173. package/src/three/threeJsMedia.ts +55 -72
  174. package/src/three/threeJsParticles.ts +32 -41
  175. package/src/three/threeJsSound.ts +3 -3
  176. package/src/three/threeJsUtils.ts +3 -3
  177. package/src/three/threeWorker.ts +2 -2
  178. package/src/three/waypointSprite.ts +55 -82
  179. package/src/three/waypoints.ts +20 -23
  180. package/src/three/world/cursorBlock.ts +25 -12
  181. package/src/three/world/vr.ts +11 -17
  182. package/src/three/worldGeometryExport.ts +15 -34
  183. package/src/three/worldRendererThree.ts +117 -129
  184. package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
  185. package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
  186. package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
  187. package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
  188. package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
  189. package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
  190. package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +17 -4
  191. package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
  192. package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
  193. package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
  194. package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
  195. package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
  196. package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
  197. package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
  198. package/src/worldView/worldView.spiral.test.ts +1 -1
  199. package/src/worldView/worldView.ts +34 -39
  200. package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
@@ -3,23 +3,23 @@ import * as THREE from 'three'
3
3
  import type { SceneOrigin } from './sceneOrigin'
4
4
 
5
5
  interface ParticleMesh extends THREE.Mesh {
6
- velocity: THREE.Vector3;
7
- worldPos: THREE.Vector3;
6
+ velocity: THREE.Vector3
7
+ worldPos: THREE.Vector3
8
8
  }
9
9
 
10
10
  interface ParticleConfig {
11
- fountainHeight: number;
12
- resetHeight: number;
13
- xVelocityRange: number;
14
- zVelocityRange: number;
15
- particleCount: number;
16
- particleRadiusRange: { min: number; max: number };
17
- yVelocityRange: { min: number; max: number };
11
+ fountainHeight: number
12
+ resetHeight: number
13
+ xVelocityRange: number
14
+ zVelocityRange: number
15
+ particleCount: number
16
+ particleRadiusRange: { min: number; max: number }
17
+ yVelocityRange: { min: number; max: number }
18
18
  }
19
19
 
20
20
  export interface FountainOptions {
21
- position?: { x: number, y: number, z: number }
22
- particleConfig?: Partial<ParticleConfig>;
21
+ position?: { x: number; y: number; z: number }
22
+ particleConfig?: Partial<ParticleConfig>
23
23
  }
24
24
 
25
25
  export class Fountain {
@@ -29,15 +29,17 @@ export class Fountain {
29
29
  private readonly sceneOrigin: SceneOrigin | undefined
30
30
  container: THREE.Object3D | undefined
31
31
 
32
- constructor (public sectionId: string, options: FountainOptions = {}, sceneOrigin?: SceneOrigin) {
32
+ constructor(
33
+ public sectionId: string,
34
+ options: FountainOptions = {},
35
+ sceneOrigin?: SceneOrigin
36
+ ) {
33
37
  this.position = options.position ? new THREE.Vector3(options.position.x, options.position.y, options.position.z) : new THREE.Vector3(0, 0, 0)
34
38
  this.config = this.createConfig(options.particleConfig)
35
39
  this.sceneOrigin = sceneOrigin
36
40
  }
37
41
 
38
- private createConfig (
39
- particleConfigOverride?: Partial<ParticleConfig>
40
- ): { particleConfig: ParticleConfig } {
42
+ private createConfig(particleConfigOverride?: Partial<ParticleConfig>): { particleConfig: ParticleConfig } {
41
43
  const particleConfig: ParticleConfig = {
42
44
  fountainHeight: 10,
43
45
  resetHeight: 0,
@@ -52,27 +54,26 @@ export class Fountain {
52
54
  return { particleConfig }
53
55
  }
54
56
 
55
- private toSceneX (worldX: number): number {
57
+ private toSceneX(worldX: number): number {
56
58
  return this.sceneOrigin ? this.sceneOrigin.toSceneX(worldX) : worldX
57
59
  }
58
60
 
59
- private toSceneY (worldY: number): number {
61
+ private toSceneY(worldY: number): number {
60
62
  return this.sceneOrigin ? this.sceneOrigin.toSceneY(worldY) : worldY
61
63
  }
62
64
 
63
- private toSceneZ (worldZ: number): number {
65
+ private toSceneZ(worldZ: number): number {
64
66
  return this.sceneOrigin ? this.sceneOrigin.toSceneZ(worldZ) : worldZ
65
67
  }
66
68
 
67
-
68
- createParticles (container: THREE.Object3D): void {
69
+ createParticles(container: THREE.Object3D): void {
69
70
  this.container = container
70
71
  const colorStart = new THREE.Color(0xff_ff_00)
71
72
  const colorEnd = new THREE.Color(0xff_a5_00)
72
73
 
73
74
  for (let i = 0; i < this.config.particleConfig.particleCount; i++) {
74
- const radius = Math.random() *
75
- (this.config.particleConfig.particleRadiusRange.max - this.config.particleConfig.particleRadiusRange.min) +
75
+ const radius =
76
+ Math.random() * (this.config.particleConfig.particleRadiusRange.max - this.config.particleConfig.particleRadiusRange.min) +
76
77
  this.config.particleConfig.particleRadiusRange.min
77
78
  const geometry = new THREE.SphereGeometry(radius)
78
79
  const material = new THREE.MeshBasicMaterial({
@@ -103,7 +104,7 @@ export class Fountain {
103
104
  }
104
105
  }
105
106
 
106
- render (): void {
107
+ render(): void {
107
108
  for (const particle of this.particles) {
108
109
  particle.velocity.y -= 0.01 + Math.random() * 0.1
109
110
  particle.worldPos.add(particle.velocity)
@@ -121,15 +122,11 @@ export class Fountain {
121
122
  )
122
123
  }
123
124
 
124
- particle.position.set(
125
- this.toSceneX(particle.worldPos.x),
126
- this.toSceneY(particle.worldPos.y),
127
- this.toSceneZ(particle.worldPos.z)
128
- )
125
+ particle.position.set(this.toSceneX(particle.worldPos.x), this.toSceneY(particle.worldPos.y), this.toSceneZ(particle.worldPos.z))
129
126
  }
130
127
  }
131
128
 
132
- private updateParticleCount (newCount: number): void {
129
+ private updateParticleCount(newCount: number): void {
133
130
  if (newCount !== this.config.particleConfig.particleCount) {
134
131
  this.config.particleConfig.particleCount = newCount
135
132
  const currentCount = this.particles.length
@@ -142,7 +139,7 @@ export class Fountain {
142
139
  }
143
140
  }
144
141
 
145
- private addParticles (count: number): void {
142
+ private addParticles(count: number): void {
146
143
  const geometry = new THREE.SphereGeometry(0.1)
147
144
  const material = new THREE.MeshBasicMaterial({ color: 0x00_ff_00 })
148
145
 
@@ -150,24 +147,18 @@ export class Fountain {
150
147
  const mesh = new THREE.Mesh(geometry, material)
151
148
  const particle = mesh as unknown as ParticleMesh
152
149
  particle.worldPos = this.position.clone()
153
- particle.position.set(
154
- this.toSceneX(this.position.x),
155
- this.toSceneY(this.position.y),
156
- this.toSceneZ(this.position.z)
157
- )
150
+ particle.position.set(this.toSceneX(this.position.x), this.toSceneY(this.position.y), this.toSceneZ(this.position.z))
158
151
  particle.velocity = new THREE.Vector3(
159
- Math.random() * this.config.particleConfig.xVelocityRange -
160
- this.config.particleConfig.xVelocityRange / 2,
152
+ Math.random() * this.config.particleConfig.xVelocityRange - this.config.particleConfig.xVelocityRange / 2,
161
153
  Math.random() * 2,
162
- Math.random() * this.config.particleConfig.zVelocityRange -
163
- this.config.particleConfig.zVelocityRange / 2
154
+ Math.random() * this.config.particleConfig.zVelocityRange - this.config.particleConfig.zVelocityRange / 2
164
155
  )
165
156
  this.particles.push(particle)
166
157
  this.container!.add(particle)
167
158
  }
168
159
  }
169
160
 
170
- private removeParticles (count: number): void {
161
+ private removeParticles(count: number): void {
171
162
  for (let i = 0; i < count; i++) {
172
163
  const particle = this.particles.pop()
173
164
  if (particle) {
@@ -176,7 +167,7 @@ export class Fountain {
176
167
  }
177
168
  }
178
169
 
179
- public dispose (): void {
170
+ public dispose(): void {
180
171
  for (const particle of this.particles) {
181
172
  particle.geometry.dispose()
182
173
  if (Array.isArray(particle.material)) {
@@ -15,7 +15,7 @@ export class ThreeJsSound implements SoundSystem {
15
15
  this.stopAll()
16
16
  })
17
17
 
18
- worldRenderer.onReactiveConfigUpdated('volume', (volume) => {
18
+ worldRenderer.onReactiveConfigUpdated('volume', volume => {
19
19
  this.changeVolume(volume)
20
20
  })
21
21
  }
@@ -26,7 +26,7 @@ export class ThreeJsSound implements SoundSystem {
26
26
  this.worldRenderer.camera.add(this.audioListener)
27
27
  }
28
28
 
29
- playSound(position: { x: number, y: number, z: number }, path: string, volume = 1, pitch = 1, timeout = 500) {
29
+ playSound(position: { x: number; y: number; z: number }, path: string, volume = 1, pitch = 1, timeout = 500) {
30
30
  this.initAudioListener()
31
31
 
32
32
  const sound = new THREE.PositionalAudio(this.audioListener!)
@@ -35,7 +35,7 @@ export class ThreeJsSound implements SoundSystem {
35
35
 
36
36
  const audioLoader = new THREE.AudioLoader()
37
37
  const start = Date.now()
38
- void audioLoader.loadAsync(path).then((buffer) => {
38
+ void audioLoader.loadAsync(path).then(buffer => {
39
39
  if (Date.now() - start > timeout) {
40
40
  console.warn('Ignored playing sound', path, 'due to timeout:', timeout, 'ms <', Date.now() - start, 'ms')
41
41
  return
@@ -70,17 +70,17 @@ export const loadThreeJsTextureFromBitmap = (image: ImageBitmap) => {
70
70
  }
71
71
 
72
72
  /** Worker-safe sync handle; image loads via fetch + OffscreenCanvas (not TextureLoader). */
73
- export function loadNearestFilterTexture (imageUrl: string): THREE.Texture {
73
+ export function loadNearestFilterTexture(imageUrl: string): THREE.Texture {
74
74
  const { texture, promise } = loadThreeJsTextureFromUrlSync(imageUrl)
75
75
  texture.magFilter = THREE.NearestFilter
76
76
  texture.minFilter = THREE.NearestFilter
77
- void promise.catch((err) => {
77
+ void promise.catch(err => {
78
78
  console.error('[texture] failed to load', imageUrl, err)
79
79
  })
80
80
  return texture
81
81
  }
82
82
 
83
- export async function loadTexture (texture: string, cb: (texture: THREE.Texture) => void, onLoad?: () => void): Promise<void> {
83
+ export async function loadTexture(texture: string, cb: (texture: THREE.Texture) => void, onLoad?: () => void): Promise<void> {
84
84
  const cached = textureCache[texture]
85
85
  if (!cached) {
86
86
  const { promise, resolve } = Promise.withResolvers<THREE.Texture>()
@@ -1,7 +1,7 @@
1
1
  //@ts-nocheck
2
2
  import { augmentWorkerMcData } from '../lib/buildWorkerMcDataIndexes'
3
3
 
4
- globalThis.structuredClone ??= (value) => JSON.parse(JSON.stringify(value))
4
+ globalThis.structuredClone ??= value => JSON.parse(JSON.stringify(value))
5
5
 
6
6
  const applyWorkerMcData = (raw: Record<string, unknown>) => {
7
7
  augmentWorkerMcData(raw)
@@ -23,7 +23,7 @@ self.addEventListener('message', (event: MessageEvent) => {
23
23
 
24
24
  if (Array.isArray(data)) {
25
25
  // eslint-disable-next-line unicorn/no-array-for-each
26
- data.forEach((msg) => {
26
+ data.forEach(msg => {
27
27
  if (msg.type === 'mcData') {
28
28
  applyWorkerMcData(msg.mcData)
29
29
  }
@@ -21,19 +21,19 @@ export const WAYPOINT_CONFIG = {
21
21
  LAYOUT: {
22
22
  DOT_Y: 0.3,
23
23
  NAME_Y: 0.45,
24
- DISTANCE_Y: 0.55,
24
+ DISTANCE_Y: 0.55
25
25
  },
26
26
  // Multiplier for canvas internal resolution to keep text crisp
27
27
  CANVAS_SCALE: 2,
28
28
  ARROW: {
29
29
  enabledDefault: false,
30
30
  pixelSize: 50,
31
- paddingPx: 50,
31
+ paddingPx: 50
32
32
  },
33
33
  // Default visual scale factor (can be overridden globally or per-waypoint)
34
34
  DEFAULT_VISUAL_SCALE: 1,
35
35
  // Default opacity (can be overridden globally or per-waypoint)
36
- DEFAULT_OPACITY: 1,
36
+ DEFAULT_OPACITY: 1
37
37
  }
38
38
 
39
39
  export type WaypointSprite = {
@@ -43,12 +43,7 @@ export type WaypointSprite = {
43
43
  enableOffscreenArrow: (enabled: boolean) => void
44
44
  setArrowParent: (parent: THREE.Object3D | null) => void
45
45
  // Convenience combined updater
46
- updateForCamera: (
47
- cameraPosition: THREE.Vector3,
48
- camera: THREE.PerspectiveCamera,
49
- viewportWidthPx: number,
50
- viewportHeightPx: number
51
- ) => boolean
46
+ updateForCamera: (cameraPosition: THREE.Vector3, camera: THREE.PerspectiveCamera, viewportWidthPx: number, viewportHeightPx: number) => boolean
52
47
  // Utilities
53
48
  setColor: (color: number) => void
54
49
  setLabel: (label?: string) => void
@@ -58,33 +53,35 @@ export type WaypointSprite = {
58
53
  dispose: () => void
59
54
  }
60
55
 
61
- export function createWaypointSprite (options: {
62
- position: THREE.Vector3 | { x: number, y: number, z: number },
63
- color?: number,
64
- label?: string,
65
- depthTest?: boolean,
56
+ export function createWaypointSprite(options: {
57
+ position: THREE.Vector3 | { x: number; y: number; z: number }
58
+ color?: number
59
+ label?: string
60
+ depthTest?: boolean
66
61
  // Y offset in world units used by updateScaleWorld only (screen-pixel API ignores this)
67
- labelYOffset?: number,
68
- metadata?: any,
69
- visualScale?: number,
70
- opacity?: number,
62
+ labelYOffset?: number
63
+ metadata?: any
64
+ visualScale?: number
65
+ opacity?: number
71
66
  }): WaypointSprite {
72
- let displayColor = options.color ?? 0xFF_00_00
67
+ let displayColor = options.color ?? 0xff_00_00
73
68
  const depthTest = options.depthTest ?? false
74
69
 
75
70
  // Get visual scale from options, metadata, server metadata, or default
76
71
  // Priority: options.visualScale > metadata.visualScale > window.serverMetadata?.waypointVisualScale > DEFAULT
77
- const visualScale = options.visualScale
78
- ?? options.metadata?.visualScale
79
- ?? (typeof window === 'undefined' ? undefined : (window as any).serverMetadata?.waypointVisualScale)
80
- ?? WAYPOINT_CONFIG.DEFAULT_VISUAL_SCALE
72
+ const visualScale =
73
+ options.visualScale ??
74
+ options.metadata?.visualScale ??
75
+ (typeof window === 'undefined' ? undefined : (window as any).serverMetadata?.waypointVisualScale) ??
76
+ WAYPOINT_CONFIG.DEFAULT_VISUAL_SCALE
81
77
 
82
78
  // Get opacity from options, metadata, server metadata, or default
83
79
  // Priority: options.opacity > metadata.opacity > window.serverMetadata?.waypointOpacity > DEFAULT
84
- const opacity = options.opacity
85
- ?? options.metadata?.opacity
86
- ?? (typeof window === 'undefined' ? undefined : (window as any).serverMetadata?.waypointOpacity)
87
- ?? WAYPOINT_CONFIG.DEFAULT_OPACITY
80
+ const opacity =
81
+ options.opacity ??
82
+ options.metadata?.opacity ??
83
+ (typeof window === 'undefined' ? undefined : (window as any).serverMetadata?.waypointOpacity) ??
84
+ WAYPOINT_CONFIG.DEFAULT_OPACITY
88
85
 
89
86
  const labelCanvas = createCanvas(getLabelCanvasSize(), getLabelCanvasSize())
90
87
  drawCombinedOntoCanvas(labelCanvas, displayColor, options.label ?? '', '0m', visualScale)
@@ -98,7 +95,7 @@ export function createWaypointSprite (options: {
98
95
  transparent: true,
99
96
  opacity: 1,
100
97
  depthTest,
101
- depthWrite: false,
98
+ depthWrite: false
102
99
  })
103
100
  const sprite = new THREE.Sprite(material)
104
101
  sprite.position.set(0, 0, 0)
@@ -122,11 +119,11 @@ export function createWaypointSprite (options: {
122
119
  const { x, y, z } = options.position
123
120
  group.position.set(x, y, z)
124
121
 
125
- function refreshLabelTexture () {
122
+ function refreshLabelTexture() {
126
123
  labelTexture.needsUpdate = true
127
124
  }
128
125
 
129
- function paintArrowOnCanvas () {
126
+ function paintArrowOnCanvas() {
130
127
  if (!arrowCanvas || !arrowCtx) return
131
128
  const size = arrowCanvas.width
132
129
  arrowCtx.clearRect(0, 0, size, size)
@@ -144,7 +141,7 @@ export function createWaypointSprite (options: {
144
141
  if (arrowTexture) arrowTexture.needsUpdate = true
145
142
  }
146
143
 
147
- function setColor (newColor: number) {
144
+ function setColor(newColor: number) {
148
145
  displayColor = newColor
149
146
  lastDistanceText = '0m'
150
147
  lastDistanceBucket = 0
@@ -153,13 +150,13 @@ export function createWaypointSprite (options: {
153
150
  if (arrowSprite) paintArrowOnCanvas()
154
151
  }
155
152
 
156
- function setLabel (newLabel?: string) {
153
+ function setLabel(newLabel?: string) {
157
154
  currentLabel = newLabel ?? ''
158
155
  drawCombinedOntoCanvas(labelCanvas, displayColor, currentLabel, lastDistanceText, visualScale)
159
156
  refreshLabelTexture()
160
157
  }
161
158
 
162
- function updateDistanceText (label: string, distanceText: string) {
159
+ function updateDistanceText(label: string, distanceText: string) {
163
160
  if (distanceText === lastDistanceText) {
164
161
  return
165
162
  }
@@ -169,27 +166,22 @@ export function createWaypointSprite (options: {
169
166
  refreshLabelTexture()
170
167
  }
171
168
 
172
- function setVisible (visible: boolean) {
169
+ function setVisible(visible: boolean) {
173
170
  sprite.visible = visible
174
171
  }
175
172
 
176
- function setPosition (nx: number, ny: number, nz: number) {
173
+ function setPosition(nx: number, ny: number, nz: number) {
177
174
  group.position.set(nx, ny, nz)
178
175
  }
179
176
 
180
- function updateScaleScreenPixels (
181
- cameraPosition: THREE.Vector3,
182
- cameraFov: number,
183
- distance: number,
184
- viewportHeightPx: number
185
- ) {
186
- const vFovRad = cameraFov * Math.PI / 180
177
+ function updateScaleScreenPixels(cameraPosition: THREE.Vector3, cameraFov: number, distance: number, viewportHeightPx: number) {
178
+ const vFovRad = (cameraFov * Math.PI) / 180
187
179
  const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * distance
188
- const scale = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.TARGET_SCREEN_PX * visualScale / viewportHeightPx)
180
+ const scale = worldUnitsPerScreenHeightAtDist * ((WAYPOINT_CONFIG.TARGET_SCREEN_PX * visualScale) / viewportHeightPx)
189
181
  sprite.scale.set(scale, scale, 1)
190
182
  }
191
183
 
192
- function ensureArrow () {
184
+ function ensureArrow() {
193
185
  if (arrowSprite) return
194
186
  const size = 128
195
187
  arrowCanvas = createCanvas(size, size)
@@ -206,22 +198,18 @@ export function createWaypointSprite (options: {
206
198
  if (arrowParent) arrowParent.add(arrowSprite)
207
199
  }
208
200
 
209
- function enableOffscreenArrow (enabled: boolean) {
201
+ function enableOffscreenArrow(enabled: boolean) {
210
202
  arrowEnabled = enabled
211
203
  if (!enabled && arrowSprite) arrowSprite.visible = false
212
204
  }
213
205
 
214
- function setArrowParent (parent: THREE.Object3D | null) {
206
+ function setArrowParent(parent: THREE.Object3D | null) {
215
207
  if (arrowSprite?.parent) arrowSprite.parent.remove(arrowSprite)
216
208
  arrowParent = parent
217
209
  if (arrowSprite && parent) parent.add(arrowSprite)
218
210
  }
219
211
 
220
- function updateOffscreenArrow (
221
- camera: THREE.PerspectiveCamera,
222
- viewportWidthPx: number,
223
- viewportHeightPx: number
224
- ): boolean {
212
+ function updateOffscreenArrow(camera: THREE.PerspectiveCamera, viewportWidthPx: number, viewportHeightPx: number): boolean {
225
213
  if (!arrowEnabled) return true
226
214
  ensureArrow()
227
215
  if (!arrowSprite) return true
@@ -246,7 +234,7 @@ export function createWaypointSprite (options: {
246
234
  const y = toWp.dot(upCam)
247
235
 
248
236
  const aspect = viewportWidthPx / viewportHeightPx
249
- const vFovRad = camera.fov * Math.PI / 180
237
+ const vFovRad = (camera.fov * Math.PI) / 180
250
238
  const hFovRad = 2 * Math.atan(Math.tan(vFovRad / 2) * aspect)
251
239
 
252
240
  // Determine if waypoint is inside view frustum using angular checks
@@ -294,8 +282,8 @@ export function createWaypointSprite (options: {
294
282
 
295
283
  // Apply padding in pixel space by clamping
296
284
  const padding = WAYPOINT_CONFIG.ARROW.paddingPx
297
- const pxX = ((ndcX + 1) * 0.5) * viewportWidthPx
298
- const pxY = ((1 - ndcY) * 0.5) * viewportHeightPx
285
+ const pxX = (ndcX + 1) * 0.5 * viewportWidthPx
286
+ const pxY = (1 - ndcY) * 0.5 * viewportHeightPx
299
287
  const clampedPxX = Math.min(Math.max(pxX, padding), viewportWidthPx - padding)
300
288
  const clampedPxY = Math.min(Math.max(pxY, padding), viewportHeightPx - padding)
301
289
  ndcX = (clampedPxX / viewportWidthPx) * 2 - 1
@@ -305,7 +293,8 @@ export function createWaypointSprite (options: {
305
293
  const placeDist = Math.max(2, camera.near * 4)
306
294
  const halfPlaneHeight = Math.tan(vFovRad / 2) * placeDist
307
295
  const halfPlaneWidth = halfPlaneHeight * aspect
308
- const pos = camPos.clone()
296
+ const pos = camPos
297
+ .clone()
309
298
  .add(forward.clone().multiplyScalar(placeDist))
310
299
  .add(right.clone().multiplyScalar(ndcX * halfPlaneWidth))
311
300
  .add(upCam.clone().multiplyScalar(ndcY * halfPlaneHeight))
@@ -320,21 +309,16 @@ export function createWaypointSprite (options: {
320
309
 
321
310
  // Constant pixel size for arrow (use fixed placement distance) with visual scale
322
311
  const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * placeDist
323
- const sPx = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.ARROW.pixelSize * visualScale / viewportHeightPx)
312
+ const sPx = worldUnitsPerScreenHeightAtDist * ((WAYPOINT_CONFIG.ARROW.pixelSize * visualScale) / viewportHeightPx)
324
313
  arrowSprite.scale.set(sPx, sPx, 1)
325
314
  return false
326
315
  }
327
316
 
328
- function computeDistance (cameraPosition: THREE.Vector3): number {
317
+ function computeDistance(cameraPosition: THREE.Vector3): number {
329
318
  return cameraPosition.distanceTo(group.position)
330
319
  }
331
320
 
332
- function updateForCamera (
333
- cameraPosition: THREE.Vector3,
334
- camera: THREE.PerspectiveCamera,
335
- viewportWidthPx: number,
336
- viewportHeightPx: number
337
- ): boolean {
321
+ function updateForCamera(cameraPosition: THREE.Vector3, camera: THREE.PerspectiveCamera, viewportWidthPx: number, viewportHeightPx: number): boolean {
338
322
  const distance = computeDistance(cameraPosition)
339
323
  updateScaleScreenPixels(cameraPosition, camera.fov, distance, viewportHeightPx)
340
324
 
@@ -349,7 +333,7 @@ export function createWaypointSprite (options: {
349
333
  return onScreen
350
334
  }
351
335
 
352
- function dispose () {
336
+ function dispose() {
353
337
  const mat = sprite.material
354
338
  mat.map?.dispose()
355
339
  mat.dispose()
@@ -378,28 +362,22 @@ export function createWaypointSprite (options: {
378
362
  updateDistanceText,
379
363
  setVisible,
380
364
  setPosition,
381
- dispose,
365
+ dispose
382
366
  }
383
367
  }
384
368
 
385
369
  // Internal helpers
386
- function computeLabelCanvasLineScale (): number {
370
+ function computeLabelCanvasLineScale(): number {
387
371
  const dpr = globalThis.devicePixelRatio || 1
388
372
  const effectiveDpr = Math.min(dpr, LABEL_CANVAS_MAX_DEVICE_PIXEL_RATIO)
389
373
  return WAYPOINT_CONFIG.CANVAS_SCALE * effectiveDpr
390
374
  }
391
375
 
392
- function getLabelCanvasSize (): number {
376
+ function getLabelCanvasSize(): number {
393
377
  return Math.round(WAYPOINT_CONFIG.CANVAS_SIZE * computeLabelCanvasLineScale())
394
378
  }
395
379
 
396
- function drawCombinedOntoCanvas (
397
- canvas: OffscreenCanvas,
398
- color: number,
399
- id: string,
400
- distance: string,
401
- visualScale: number
402
- ): void {
380
+ function drawCombinedOntoCanvas(canvas: OffscreenCanvas, color: number, id: string, distance: string, visualScale: number): void {
403
381
  const size = canvas.width
404
382
  const scale = computeLabelCanvasLineScale()
405
383
  const ctx = canvas.getContext('2d')!
@@ -443,17 +421,12 @@ function drawCombinedOntoCanvas (
443
421
 
444
422
  export const WaypointHelpers = {
445
423
  // World-scale constant size helper
446
- computeWorldScale (distance: number, fixedReference = 10) {
424
+ computeWorldScale(distance: number, fixedReference = 10) {
447
425
  return Math.max(0.0001, distance / fixedReference)
448
426
  },
449
427
  // Screen-pixel constant size helper
450
- computeScreenPixelScale (
451
- camera: THREE.PerspectiveCamera,
452
- distance: number,
453
- pixelSize: number,
454
- viewportHeightPx: number
455
- ) {
456
- const vFovRad = camera.fov * Math.PI / 180
428
+ computeScreenPixelScale(camera: THREE.PerspectiveCamera, distance: number, pixelSize: number, viewportHeightPx: number) {
429
+ const vFovRad = (camera.fov * Math.PI) / 180
457
430
  const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * distance
458
431
  return worldUnitsPerScreenHeightAtDist * (pixelSize / viewportHeightPx)
459
432
  }
@@ -32,9 +32,7 @@ export class WaypointsRenderer {
32
32
  private lastUpdateTime = 0
33
33
  private readonly UPDATE_THROTTLE_MS = 16 // ~60fps max update rate
34
34
 
35
- constructor(
36
- private readonly worldRenderer: WorldRendererThree
37
- ) {
35
+ constructor(private readonly worldRenderer: WorldRendererThree) {
38
36
  if (process.env.NODE_ENV !== 'production') {
39
37
  // this.addWaypoint('spawn', 0, 0, 0, { })
40
38
  }
@@ -60,8 +58,7 @@ export class WaypointsRenderer {
60
58
  for (const waypoint of this.waypoints.values()) {
61
59
  const waypointPos = new THREE.Vector3(waypoint.x, waypoint.y, waypoint.z)
62
60
  const distance = playerPos.distanceTo(waypointPos)
63
- const visible = (!waypoint.minDistance || distance >= waypoint.minDistance) &&
64
- (waypoint.maxDistance === Infinity || distance <= waypoint.maxDistance)
61
+ const visible = (!waypoint.minDistance || distance >= waypoint.minDistance) && (waypoint.maxDistance === Infinity || distance <= waypoint.maxDistance)
65
62
 
66
63
  waypoint.sprite.setVisible(visible)
67
64
 
@@ -90,17 +87,11 @@ export class WaypointsRenderer {
90
87
 
91
88
  // Removed sprite/label texture creation. Use utils/waypointSprite.ts
92
89
 
93
- addWaypoint(
94
- id: string,
95
- x: number,
96
- y: number,
97
- z: number,
98
- options: WaypointOptions = {}
99
- ) {
90
+ addWaypoint(id: string, x: number, y: number, z: number, options: WaypointOptions = {}) {
100
91
  // Remove existing waypoint if it exists
101
92
  this.removeWaypoint(id)
102
93
 
103
- const color = options.color ?? 0xFF_00_00
94
+ const color = options.color ?? 0xff_00_00
104
95
  const { label, metadata } = options
105
96
  const minDistance = options.minDistance ?? 0
106
97
  const maxDistance = options.maxDistance ?? Infinity
@@ -108,8 +99,8 @@ export class WaypointsRenderer {
108
99
  const sprite = createWaypointSprite({
109
100
  position: new THREE.Vector3(x, y, z),
110
101
  color,
111
- label: (label || id),
112
- metadata,
102
+ label: label || id,
103
+ metadata
113
104
  })
114
105
  sprite.enableOffscreenArrow(true)
115
106
  sprite.setArrowParent(this.waypointScene)
@@ -117,9 +108,15 @@ export class WaypointsRenderer {
117
108
  this.waypointScene.add(sprite.group)
118
109
 
119
110
  this.waypoints.set(id, {
120
- id, x: x + 0.5, y: y + 0.5, z: z + 0.5, minDistance, maxDistance,
121
- color, label,
122
- sprite,
111
+ id,
112
+ x: x + 0.5,
113
+ y: y + 0.5,
114
+ z: z + 0.5,
115
+ minDistance,
116
+ maxDistance,
117
+ color,
118
+ label,
119
+ sprite
123
120
  })
124
121
  }
125
122
 
@@ -139,11 +136,11 @@ export class WaypointsRenderer {
139
136
  }
140
137
 
141
138
  testWaypoint() {
142
- this.addWaypoint('Test Point', 0, 70, 0, { color: 0x00_FF_00, label: 'Test Point' })
143
- this.addWaypoint('Spawn', 0, 64, 0, { color: 0xFF_FF_00, label: 'Spawn' })
144
- this.addWaypoint('Far Point', 100, 70, 100, { color: 0x00_00_FF, label: 'Far Point' })
145
- this.addWaypoint('Far Point 2', 180, 170, 100, { color: 0x00_00_FF, label: 'Far Point 2' })
146
- this.addWaypoint('Far Point 3', 1000, 100, 1000, { color: 0x00_00_FF, label: 'Far Point 3' })
139
+ this.addWaypoint('Test Point', 0, 70, 0, { color: 0x00_ff_00, label: 'Test Point' })
140
+ this.addWaypoint('Spawn', 0, 64, 0, { color: 0xff_ff_00, label: 'Spawn' })
141
+ this.addWaypoint('Far Point', 100, 70, 100, { color: 0x00_00_ff, label: 'Far Point' })
142
+ this.addWaypoint('Far Point 2', 180, 170, 100, { color: 0x00_00_ff, label: 'Far Point 2' })
143
+ this.addWaypoint('Far Point 3', 1000, 100, 1000, { color: 0x00_00_ff, label: 'Far Point 3' })
147
144
  }
148
145
 
149
146
  getWaypoint(id: string): Waypoint | undefined {