minecraft-renderer 0.1.78 → 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 +32 -32
  6. package/dist/minecraft-renderer.js.meta.json +1 -1
  7. package/dist/threeWorker.js +415 -415
  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 +329 -301
  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 +174 -99
  126. package/src/three/globalLegacyBuffer.ts +465 -136
  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 +93 -0
  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 +133 -25
  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 +460 -58
  170. package/src/three/tests/legacyMultiDraw.test.ts +88 -0
  171. package/src/three/tests/pr3PerFrameCpuCuts.test.ts +370 -0
  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 +131 -133
  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
@@ -13,7 +13,7 @@ import {
13
13
  packWord2Empty,
14
14
  packWord3,
15
15
  SHADER_CUBES_FORMAT_VERSION,
16
- SHADER_CUBES_WORDS_PER_FACE,
16
+ SHADER_CUBES_WORDS_PER_FACE
17
17
  } from '../bridge/shaderCubeBridge'
18
18
  import { GlobalBlockBuffer } from '../../three/globalBlockBuffer'
19
19
  import { buildVisibleCubeSpans } from '../../three/cubeDrawSpans'
@@ -54,20 +54,22 @@ test('packWord2: AO diagonal flip sets bit 12', () => {
54
54
  visible_faces: 1 << 0, // up only
55
55
  ao_data: [[0, 1, 2, 3]], // 0+3 >= 1+2 → flip
56
56
  light_data: [[1, 1, 1, 1]],
57
- light_combined: [[255, 255, 255, 255]],
57
+ light_combined: [[255, 255, 255, 255]]
58
58
  }
59
59
  const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
60
60
  const model = {
61
- elements: [{
62
- faces: {
63
- up: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
64
- down: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
65
- east: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
66
- west: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
67
- south: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
68
- north: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
69
- },
70
- }],
61
+ elements: [
62
+ {
63
+ faces: {
64
+ up: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
65
+ down: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
66
+ east: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
67
+ west: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
68
+ south: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
69
+ north: { texture: { u: 0, v: 0, su: 16, sv: 16 } }
70
+ }
71
+ }
72
+ ]
71
73
  }
72
74
  const ok = tryBuildShaderCubeInstances(
73
75
  block,
@@ -77,9 +79,9 @@ test('packWord2: AO diagonal flip sets bit 12', () => {
77
79
  sectionOrigin: { x: 0, y: 0, z: 0 },
78
80
  sectionHeight: 16,
79
81
  tintPalette,
80
- textureIndexMapping,
82
+ textureIndexMapping
81
83
  },
82
- words,
84
+ words
83
85
  )
84
86
  expect(ok).toBe(true)
85
87
  expect(words.length).toBe(SHADER_CUBES_WORDS_PER_FACE)
@@ -93,20 +95,22 @@ test('packWord0: section-local lx/ly/lz and face id', () => {
93
95
  visible_faces: 1 << 2, // east
94
96
  ao_data: [[3, 3, 3, 3]],
95
97
  light_data: [[0.5, 0.5, 0.5, 0.5]],
96
- light_combined: [[128, 128, 128, 128]],
98
+ light_combined: [[128, 128, 128, 128]]
97
99
  }
98
100
  const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
99
101
  const model = {
100
- elements: [{
101
- faces: {
102
- up: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
103
- down: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
104
- east: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
105
- west: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
106
- south: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
107
- north: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
108
- },
109
- }],
102
+ elements: [
103
+ {
104
+ faces: {
105
+ up: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
106
+ down: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
107
+ east: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
108
+ west: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
109
+ south: { texture: { u: 16, v: 0, su: 16, sv: 16 } },
110
+ north: { texture: { u: 16, v: 0, su: 16, sv: 16 } }
111
+ }
112
+ }
113
+ ]
110
114
  }
111
115
  tryBuildShaderCubeInstances(
112
116
  block,
@@ -116,9 +120,9 @@ test('packWord0: section-local lx/ly/lz and face id', () => {
116
120
  sectionOrigin: { x: 0, y: 16, z: 0 },
117
121
  sectionHeight: 16,
118
122
  tintPalette,
119
- textureIndexMapping,
123
+ textureIndexMapping
120
124
  },
121
- words,
125
+ words
122
126
  )
123
127
  const w0 = words[0]!
124
128
  expect(w0 & 0xf).toBe(10) // lx
@@ -130,35 +134,24 @@ test('packWord0: section-local lx/ly/lz and face id', () => {
130
134
  test('isShaderCubeBlock: rejects model rotation and sectionHeight !== 16', () => {
131
135
  const { textureIndexMapping } = requireShaderCubeResources()
132
136
  const baseModel = {
133
- elements: [{
134
- faces: {
135
- up: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
136
- down: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
137
- east: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
138
- west: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
139
- south: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
140
- north: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
141
- },
142
- }],
137
+ elements: [
138
+ {
139
+ faces: {
140
+ up: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
141
+ down: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
142
+ east: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
143
+ west: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
144
+ south: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
145
+ north: { texture: { u: 0, v: 0, su: 16, sv: 16 } }
146
+ }
147
+ }
148
+ ]
143
149
  }
144
- expect(isShaderCubeBlock(
145
- { blockName: 'stone', blockProps: {}, isCube: true, model: baseModel },
146
- baseModel,
147
- 16,
148
- textureIndexMapping,
149
- )).toBe(true)
150
- expect(isShaderCubeBlock(
151
- { blockName: 'stone', blockProps: {}, isCube: true, model: baseModel },
152
- baseModel,
153
- 24,
154
- textureIndexMapping,
155
- )).toBe(false)
156
- expect(isShaderCubeBlock(
157
- { blockName: 'stone', blockProps: {}, isCube: true, model: { ...baseModel, y: 90 } },
158
- { ...baseModel, y: 90 },
159
- 16,
160
- textureIndexMapping,
161
- )).toBe(false)
150
+ expect(isShaderCubeBlock({ blockName: 'stone', blockProps: {}, isCube: true, model: baseModel }, baseModel, 16, textureIndexMapping)).toBe(true)
151
+ expect(isShaderCubeBlock({ blockName: 'stone', blockProps: {}, isCube: true, model: baseModel }, baseModel, 24, textureIndexMapping)).toBe(false)
152
+ expect(
153
+ isShaderCubeBlock({ blockName: 'stone', blockProps: {}, isCube: true, model: { ...baseModel, y: 90 } }, { ...baseModel, y: 90 }, 16, textureIndexMapping)
154
+ ).toBe(false)
162
155
  })
163
156
 
164
157
  test('renderWasmOutputToGeometry: stone emits shaderCubes and skips legacy vertices when enabled', () => {
@@ -168,16 +161,11 @@ test('renderWasmOutputToGeometry: stone emits shaderCubes and skips legacy verti
168
161
  visible_faces: (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5),
169
162
  ao_data: Array.from({ length: 6 }, () => [3, 3, 3, 3]),
170
163
  light_data: Array.from({ length: 6 }, () => [1, 1, 1, 1]),
171
- light_combined: Array.from({ length: 6 }, () => [255, 255, 255, 255]),
164
+ light_combined: Array.from({ length: 6 }, () => [255, 255, 255, 255])
172
165
  }
173
- const out = renderWasmOutputToGeometry(
174
- { blocks: [block], block_count: 1, block_iterations: 0 },
175
- VERSION,
176
- '0,0,0',
177
- { x: 8, y: 8, z: 8 },
178
- undefined,
179
- { shaderCubes: true },
180
- )
166
+ const out = renderWasmOutputToGeometry({ blocks: [block], block_count: 1, block_iterations: 0 }, VERSION, '0,0,0', { x: 8, y: 8, z: 8 }, undefined, {
167
+ shaderCubes: true
168
+ })
181
169
  expect(out.shaderCubes?.count).toBe(6)
182
170
  expect(out.shaderCubes?.formatVersion).toBe(SHADER_CUBES_FORMAT_VERSION)
183
171
  expect(out.shaderCubes?.words.length).toBe(6 * SHADER_CUBES_WORDS_PER_FACE)
@@ -195,16 +183,11 @@ test('renderWasmOutputToGeometry: shaderCubes false keeps legacy path for stone'
195
183
  block_state_id: STONE,
196
184
  visible_faces: 1 << 0,
197
185
  ao_data: [[3, 3, 3, 3]],
198
- light_data: [[1, 1, 1, 1]],
186
+ light_data: [[1, 1, 1, 1]]
199
187
  }
200
- const out = renderWasmOutputToGeometry(
201
- { blocks: [block], block_count: 1, block_iterations: 0 },
202
- VERSION,
203
- '0,0,0',
204
- { x: 8, y: 8, z: 8 },
205
- undefined,
206
- { shaderCubes: false },
207
- )
188
+ const out = renderWasmOutputToGeometry({ blocks: [block], block_count: 1, block_iterations: 0 }, VERSION, '0,0,0', { x: 8, y: 8, z: 8 }, undefined, {
189
+ shaderCubes: false
190
+ })
208
191
  expect(out.shaderCubes).toBeUndefined()
209
192
  expect(out.geometry.positions.length).toBeGreaterThan(0)
210
193
  })
@@ -223,7 +206,7 @@ const SIX_FACE_TEXTURES = {
223
206
  east: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
224
207
  west: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
225
208
  south: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
226
- north: { texture: { u: 0, v: 0, su: 16, sv: 16 } },
209
+ north: { texture: { u: 0, v: 0, su: 16, sv: 16 } }
227
210
  }
228
211
 
229
212
  function aoCorner0FromWord0(w0: number): number {
@@ -237,7 +220,7 @@ test('south face: AO corners remapped to shader order (elemFaces [0,3,1,2] → s
237
220
  visible_faces: 1 << 4, // south
238
221
  ao_data: [[0, 3, 1, 2]],
239
222
  light_data: [[1, 1, 1, 1]],
240
- light_combined: [[10, 20, 30, 40]],
223
+ light_combined: [[10, 20, 30, 40]]
241
224
  }
242
225
  const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
243
226
  const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
@@ -246,7 +229,7 @@ test('south face: AO corners remapped to shader order (elemFaces [0,3,1,2] → s
246
229
  { blockName: 'stone', blockProps: {}, isCube: true, model },
247
230
  model,
248
231
  { sectionOrigin: { x: 0, y: 0, z: 0 }, sectionHeight: 16, tintPalette, textureIndexMapping },
249
- words,
232
+ words
250
233
  )
251
234
  // Shader vi=0 must get elemFaces ao[2]=1, not ao[0]=0
252
235
  expect(aoCorner0FromWord0(words[0]!)).toBe(1)
@@ -263,7 +246,7 @@ test('south face: diagonal flip uses remapped AO (differs from raw elemFaces for
263
246
  visible_faces: 1 << 4,
264
247
  ao_data: [ao],
265
248
  light_data: [[1, 1, 1, 1]],
266
- light_combined: [[255, 255, 255, 255]],
249
+ light_combined: [[255, 255, 255, 255]]
267
250
  }
268
251
  const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
269
252
  const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
@@ -271,25 +254,13 @@ test('south face: diagonal flip uses remapped AO (differs from raw elemFaces for
271
254
  sectionOrigin: { x: 0, y: 0, z: 0 },
272
255
  sectionHeight: 16,
273
256
  tintPalette,
274
- textureIndexMapping,
257
+ textureIndexMapping
275
258
  }
276
- tryBuildShaderCubeInstances(
277
- block,
278
- { blockName: 'stone', blockProps: {}, isCube: true, model },
279
- model,
280
- opts,
281
- wordsFlip,
282
- )
259
+ tryBuildShaderCubeInstances(block, { blockName: 'stone', blockProps: {}, isCube: true, model }, model, opts, wordsFlip)
283
260
  expect(wordsFlip[2]! & (1 << WORD2.DIAGONAL_FLAG_SHIFT)).not.toBe(0)
284
261
 
285
262
  // elemFaces [3,0,0,3] → remapped [0,3,3,0]: 0+0 < 3+3 → no diagonal flip
286
- tryBuildShaderCubeInstances(
287
- { ...block, ao_data: [[3, 0, 0, 3]] },
288
- { blockName: 'stone', blockProps: {}, isCube: true, model },
289
- model,
290
- opts,
291
- wordsNoFlip,
292
- )
263
+ tryBuildShaderCubeInstances({ ...block, ao_data: [[3, 0, 0, 3]] }, { blockName: 'stone', blockProps: {}, isCube: true, model }, model, opts, wordsNoFlip)
293
264
  expect(wordsNoFlip[2]! & (1 << WORD2.DIAGONAL_FLAG_SHIFT)).toBe(0)
294
265
  })
295
266
 
@@ -300,7 +271,7 @@ test('doAO false: full bright AO/light and no diagonal flip', () => {
300
271
  visible_faces: 1 << 0,
301
272
  ao_data: [[0, 0, 0, 0]],
302
273
  light_data: [[0, 0, 0, 0]],
303
- light_combined: [[0, 0, 0, 0]],
274
+ light_combined: [[0, 0, 0, 0]]
304
275
  }
305
276
  const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
306
277
  const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
@@ -313,9 +284,9 @@ test('doAO false: full bright AO/light and no diagonal flip', () => {
313
284
  sectionHeight: 16,
314
285
  tintPalette,
315
286
  textureIndexMapping,
316
- doAO: false,
287
+ doAO: false
317
288
  },
318
- words,
289
+ words
319
290
  )
320
291
  expect(aoCorner0FromWord0(words[0]!)).toBe(3)
321
292
  for (let i = 0; i < 4; i++) {
@@ -324,7 +295,7 @@ test('doAO false: full bright AO/light and no diagonal flip', () => {
324
295
  expect(words[2]! & (1 << WORD2.DIAGONAL_FLAG_SHIFT)).toBe(0)
325
296
  })
326
297
 
327
- const SECTION_ORIGIN_ROUND_TRIP_CASES: Array<{ x: number, y: number, z: number }> = [
298
+ const SECTION_ORIGIN_ROUND_TRIP_CASES: Array<{ x: number; y: number; z: number }> = [
328
299
  { x: 0, y: 16, z: 32 },
329
300
  { x: 0, y: 0, z: 0 },
330
301
  { x: 524288, y: 0, z: 524288 },
@@ -332,33 +303,30 @@ const SECTION_ORIGIN_ROUND_TRIP_CASES: Array<{ x: number, y: number, z: number }
332
303
  { x: 33000000, y: 0, z: 33000000 },
333
304
  { x: -524288, y: 0, z: -524288 },
334
305
  { x: -1000000, y: 0, z: -1000000 },
335
- { x: 1000000, y: 0, z: -1000000 },
306
+ { x: 1000000, y: 0, z: -1000000 }
336
307
  ]
337
308
 
338
- test.each(SECTION_ORIGIN_ROUND_TRIP_CASES)(
339
- 'section base coords round-trip in word2/word3 at origin (%#)',
340
- (sectionOrigin) => {
341
- const words: number[] = []
342
- const block = {
343
- position: [10, 17, 4] as [number, number, number],
344
- visible_faces: 1 << 2,
345
- ao_data: [[3, 3, 3, 3]],
346
- light_data: [[1, 1, 1, 1]],
347
- light_combined: [[255, 255, 255, 255]],
348
- }
349
- const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
350
- const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
351
- tryBuildShaderCubeInstances(
352
- block,
353
- { blockName: 'stone', blockProps: {}, isCube: true, model },
354
- model,
355
- { sectionOrigin, sectionHeight: 16, tintPalette, textureIndexMapping },
356
- words,
357
- )
358
- const base = decodeSectionBaseFromWords(words[2]!, words[3]!)
359
- expect(base).toEqual(sectionOrigin)
360
- },
361
- )
309
+ test.each(SECTION_ORIGIN_ROUND_TRIP_CASES)('section base coords round-trip in word2/word3 at origin (%#)', sectionOrigin => {
310
+ const words: number[] = []
311
+ const block = {
312
+ position: [10, 17, 4] as [number, number, number],
313
+ visible_faces: 1 << 2,
314
+ ao_data: [[3, 3, 3, 3]],
315
+ light_data: [[1, 1, 1, 1]],
316
+ light_combined: [[255, 255, 255, 255]]
317
+ }
318
+ const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
319
+ const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
320
+ tryBuildShaderCubeInstances(
321
+ block,
322
+ { blockName: 'stone', blockProps: {}, isCube: true, model },
323
+ model,
324
+ { sectionOrigin, sectionHeight: 16, tintPalette, textureIndexMapping },
325
+ words
326
+ )
327
+ const base = decodeSectionBaseFromWords(words[2]!, words[3]!)
328
+ expect(base).toEqual(sectionOrigin)
329
+ })
362
330
 
363
331
  test('packWord2Empty: bit 18 set regardless of high X/Z bits in word2', () => {
364
332
  const empty = packWord2Empty()
@@ -376,7 +344,7 @@ test('section index relative decode past 2^20: exact integer subtract', () => {
376
344
  visible_faces: 1 << 2,
377
345
  ao_data: [[3, 3, 3, 3]],
378
346
  light_data: [[1, 1, 1, 1]],
379
- light_combined: [[255, 255, 255, 255]],
347
+ light_combined: [[255, 255, 255, 255]]
380
348
  }
381
349
  const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
382
350
  const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
@@ -388,9 +356,9 @@ test('section index relative decode past 2^20: exact integer subtract', () => {
388
356
  sectionOrigin: { x: sectionBlockX, y: 0, z: 0 },
389
357
  sectionHeight: 16,
390
358
  tintPalette,
391
- textureIndexMapping,
359
+ textureIndexMapping
392
360
  },
393
- words,
361
+ words
394
362
  )
395
363
  const base = decodeSectionBaseFromWords(words[2]!, words[3]!)
396
364
  const sX = base.x / 16
@@ -404,10 +372,7 @@ test('GlobalBlockBuffer: free-list reuses slot with EMPTY sentinel', () => {
404
372
  const mat = createCubeBlockMaterial()
405
373
  const buffer = new GlobalBlockBuffer(mat, scene)
406
374
 
407
- const words = new Uint32Array([
408
- 1, 2, 0, packWord3(0, 0),
409
- 3, 4, 0, packWord3(0, 0),
410
- ])
375
+ const words = new Uint32Array([1, 2, 0, packWord3(0, 0), 3, 4, 0, packWord3(0, 0)])
411
376
  buffer.addSection('a', words, 2)
412
377
  expect(buffer.mesh.geometry.instanceCount).toBe(2)
413
378
 
@@ -425,24 +390,24 @@ test('GlobalBlockBuffer: free-list reuses slot with EMPTY sentinel', () => {
425
390
  })
426
391
 
427
392
  type BufferInternals = {
428
- pendingRanges: Array<{ start: number, end: number }>
429
- pendingMove: { key: string, oldStart: number, newStart: number, count: number } | null
393
+ pendingRanges: Array<{ start: number; end: number }>
394
+ pendingMove: { key: string; oldStart: number; newStart: number; count: number } | null
430
395
  }
431
396
 
432
397
  /** True if some queued (not-yet-uploaded) dirty range covers [start, end] — i.e. it WILL hit the GPU. */
433
- function rangeQueuedForUpload (buffer: GlobalBlockBuffer, start: number, end: number): boolean {
398
+ function rangeQueuedForUpload(buffer: GlobalBlockBuffer, start: number, end: number): boolean {
434
399
  return getBufferInternals(buffer).pendingRanges.some(r => r.start <= end && r.end >= start)
435
400
  }
436
401
 
437
- function getBufferInternals (buffer: GlobalBlockBuffer): BufferInternals {
402
+ function getBufferInternals(buffer: GlobalBlockBuffer): BufferInternals {
438
403
  return buffer as unknown as BufferInternals
439
404
  }
440
405
 
441
- function drainAllUploads (buffer: GlobalBlockBuffer): void {
406
+ function drainAllUploads(buffer: GlobalBlockBuffer): void {
442
407
  while (getBufferInternals(buffer).pendingRanges.length) buffer.uploadDirtyRange()
443
408
  }
444
409
 
445
- function makeSectionWords (faceW0: number[]): Uint32Array {
410
+ function makeSectionWords(faceW0: number[]): Uint32Array {
446
411
  const words = new Uint32Array(faceW0.length * 4)
447
412
  for (let i = 0; i < faceW0.length; i++) {
448
413
  words[i * 4] = faceW0[i]!
@@ -453,7 +418,7 @@ function makeSectionWords (faceW0: number[]): Uint32Array {
453
418
  return words
454
419
  }
455
420
 
456
- function readSectionFaceWords (buffer: GlobalBlockBuffer, key: string): number[] {
421
+ function readSectionFaceWords(buffer: GlobalBlockBuffer, key: string): number[] {
457
422
  const slot = buffer.getSectionSlot(key)
458
423
  if (!slot) throw new Error(`missing section ${key}`)
459
424
  const geo = buffer.mesh.geometry
@@ -469,12 +434,12 @@ function readSectionFaceWords (buffer: GlobalBlockBuffer, key: string): number[]
469
434
  return out
470
435
  }
471
436
 
472
- function finishCurrentMove (buffer: GlobalBlockBuffer): void {
437
+ function finishCurrentMove(buffer: GlobalBlockBuffer): void {
473
438
  drainAllUploads(buffer)
474
439
  buffer.compactStep()
475
440
  }
476
441
 
477
- function isEmptyFace (buffer: GlobalBlockBuffer, index: number): boolean {
442
+ function isEmptyFace(buffer: GlobalBlockBuffer, index: number): boolean {
478
443
  const w2 = (buffer.mesh.geometry.getAttribute('a_w2') as THREE.InstancedBufferAttribute).array as Uint32Array
479
444
  return (w2[index]! & (1 << WORD2.EMPTY_SHIFT)) !== 0
480
445
  }
@@ -730,10 +695,7 @@ test('GlobalBlockBuffer: pendingMove draw start uses oldStart for visible spans'
730
695
  expect(buffer.getSectionDrawStart('c')).toBe(move!.oldStart)
731
696
  expect(buffer.getSectionDrawStart('c')).not.toBe(slotStart)
732
697
 
733
- const spans = buildVisibleCubeSpans(
734
- [{ start: buffer.getSectionDrawStart('c')!, count: 1 }],
735
- buffer.getHighWatermark(),
736
- )
698
+ const spans = buildVisibleCubeSpans([{ start: buffer.getSectionDrawStart('c')!, count: 1 }], buffer.getHighWatermark())
737
699
  expect(spans[0]?.start).toBe(move!.oldStart)
738
700
 
739
701
  buffer.dispose()
@@ -1,10 +1,6 @@
1
1
  //@ts-nocheck
2
2
  import { test, expect } from 'vitest'
3
- import {
4
- splitColumnWasmOutputToSections,
5
- renderWasmOutputToGeometry,
6
- WasmGeometryOutput,
7
- } from '../bridge/render-from-wasm'
3
+ import { splitColumnWasmOutputToSections, renderWasmOutputToGeometry, WasmGeometryOutput } from '../bridge/render-from-wasm'
8
4
 
9
5
  const VERSION = '1.16.5'
10
6
  const STONE = 1 // 1.16.5 stone state id
@@ -38,7 +34,7 @@ function makeSeamFixture(): WasmGeometryOutput {
38
34
  // info is baked in here at the per-block level.
39
35
  visible_faces: FACE_DOWN | SIDE_FACES,
40
36
  ao_data: [],
41
- light_data: [],
37
+ light_data: []
42
38
  })
43
39
  blocks.push({
44
40
  position: [x, 16, z],
@@ -47,7 +43,7 @@ function makeSeamFixture(): WasmGeometryOutput {
47
43
  // other side).
48
44
  visible_faces: FACE_UP | SIDE_FACES,
49
45
  ao_data: [],
50
- light_data: [],
46
+ light_data: []
51
47
  })
52
48
  }
53
49
  }
@@ -58,12 +54,12 @@ function makeSeamFixture(): WasmGeometryOutput {
58
54
  block_state_id: STONE,
59
55
  visible_faces: FACE_UP | FACE_DOWN | SIDE_FACES,
60
56
  ao_data: [],
61
- light_data: [],
57
+ light_data: []
62
58
  })
63
59
  return {
64
60
  blocks,
65
61
  block_count: blocks.length,
66
- block_iterations: 0,
62
+ block_iterations: 0
67
63
  }
68
64
  }
69
65
 
@@ -71,15 +67,15 @@ test('splitColumnWasmOutputToSections: per-section split is equivalent to manual
71
67
  const fullColumn = makeSeamFixture()
72
68
 
73
69
  const requested = [
74
- { x: 0, y: 0, z: 0 }, // contains Y=15 row only
75
- { x: 0, y: 16, z: 0 }, // contains Y=16 row only
76
- { x: 0, y: 32, z: 0 }, // empty section
77
- { x: 0, y: 64, z: 0 }, // contains the isolated block at Y=64
70
+ { x: 0, y: 0, z: 0 }, // contains Y=15 row only
71
+ { x: 0, y: 16, z: 0 }, // contains Y=16 row only
72
+ { x: 0, y: 32, z: 0 }, // empty section
73
+ { x: 0, y: 64, z: 0 } // contains the isolated block at Y=64
78
74
  ]
79
75
 
80
76
  const split = splitColumnWasmOutputToSections(fullColumn, requested, {
81
77
  version: VERSION,
82
- shaderCubes: false,
78
+ shaderCubes: false
83
79
  })
84
80
 
85
81
  expect(split.size).toBe(4)
@@ -98,13 +94,13 @@ test('splitColumnWasmOutputToSections: per-section split is equivalent to manual
98
94
  {
99
95
  blocks: sectionBlocks,
100
96
  block_count: sectionBlocks.length,
101
- block_iterations: fullColumn.block_iterations,
97
+ block_iterations: fullColumn.block_iterations
102
98
  },
103
99
  VERSION,
104
100
  `${r.x},${r.y},${r.z}`,
105
101
  { x: r.x + 8, y: r.y + 8, z: r.z + 8 },
106
102
  undefined,
107
- { shaderCubes: false },
103
+ { shaderCubes: false }
108
104
  )
109
105
  const got = split.get(`${r.x},${r.y},${r.z}`)!.exported
110
106
  expect(got.key).toBe(reference.key)
@@ -149,7 +145,7 @@ test('splitColumnWasmOutputToSections: empty requested-keys list returns empty m
149
145
  const fullColumn = makeSeamFixture()
150
146
  const out = splitColumnWasmOutputToSections(fullColumn, [], {
151
147
  version: VERSION,
152
- shaderCubes: false,
148
+ shaderCubes: false
153
149
  })
154
150
  expect(out.size).toBe(0)
155
151
  })
@@ -158,11 +154,7 @@ test('splitColumnWasmOutputToSections: blocks outside requested sections are dro
158
154
  const fullColumn = makeSeamFixture()
159
155
  // Only request the empty Y=32 section. Y=15/16/64 blocks must NOT
160
156
  // leak into it.
161
- const out = splitColumnWasmOutputToSections(
162
- fullColumn,
163
- [{ x: 0, y: 32, z: 0 }],
164
- { version: VERSION, shaderCubes: false },
165
- )
157
+ const out = splitColumnWasmOutputToSections(fullColumn, [{ x: 0, y: 32, z: 0 }], { version: VERSION, shaderCubes: false })
166
158
  const empty = out.get('0,32,0')!
167
159
  expect(empty.exported.geometry.positions).toEqual([])
168
160
  expect(empty.exported.geometry.indices).toEqual([])