minecraft-renderer 0.1.79 → 0.1.81

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 (205) hide show
  1. package/README.md +66 -26
  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 +66 -66
  6. package/dist/minecraft-renderer.js.meta.json +1 -1
  7. package/dist/threeWorker.js +450 -450
  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 +349 -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/cameraCollisionBlockCache.ts +156 -0
  113. package/src/three/cameraCollisionSolidity.ts +50 -0
  114. package/src/three/cameraShake.ts +15 -6
  115. package/src/three/chunkMeshManager.ts +223 -390
  116. package/src/three/cinimaticScript.ts +26 -15
  117. package/src/three/cubeDrawSpans.ts +27 -37
  118. package/src/three/cubeMultiDraw.ts +9 -22
  119. package/src/three/documentRenderer.ts +15 -18
  120. package/src/three/entities.ts +175 -150
  121. package/src/three/entity/EntityMesh.ts +114 -108
  122. package/src/three/entity/animations.js +3 -3
  123. package/src/three/entity/armorModels.ts +15 -15
  124. package/src/three/entity/gltfAnimationUtils.ts +2 -5
  125. package/src/three/fireworks.ts +34 -32
  126. package/src/three/fireworksRenderer.ts +32 -29
  127. package/src/three/globalBlockBuffer.ts +167 -100
  128. package/src/three/globalLegacyBuffer.ts +248 -264
  129. package/src/three/graphicsBackendBase.ts +19 -25
  130. package/src/three/graphicsBackendOffThread.ts +12 -15
  131. package/src/three/hand.ts +21 -21
  132. package/src/three/handLegacy.ts +3 -13
  133. package/src/three/holdingBlock.ts +116 -79
  134. package/src/three/holdingBlockFactory.ts +1 -4
  135. package/src/three/holdingBlockItemIdentity.test.ts +25 -17
  136. package/src/three/holdingBlockItemIdentity.ts +9 -6
  137. package/src/three/holdingBlockLegacy.ts +113 -132
  138. package/src/three/itemMesh.ts +20 -29
  139. package/src/three/legacyMultiDraw.ts +10 -16
  140. package/src/three/legacySectionCull.ts +8 -14
  141. package/src/three/menuBackground/activeView.ts +1 -4
  142. package/src/three/menuBackground/assetUrl.ts +1 -1
  143. package/src/three/menuBackground/classic.ts +4 -12
  144. package/src/three/menuBackground/gpuPreference.ts +1 -3
  145. package/src/three/menuBackground/index.ts +2 -11
  146. package/src/three/menuBackground/renderer.ts +1 -5
  147. package/src/three/menuBackground/types.ts +1 -4
  148. package/src/three/menuBackground/v2.ts +196 -96
  149. package/src/three/menuBackground/v2Meta.ts +3 -3
  150. package/src/three/menuBackground/worldBlocks.ts +37 -35
  151. package/src/three/modules/blockBreakParticles.ts +59 -28
  152. package/src/three/modules/cameraBobbing.ts +3 -6
  153. package/src/three/modules/index.ts +1 -1
  154. package/src/three/modules/rain.ts +10 -23
  155. package/src/three/modules/sciFiWorldReveal.ts +11 -25
  156. package/src/three/modules/starfield.ts +7 -13
  157. package/src/three/renderSlot.ts +28 -16
  158. package/src/three/rendererModuleSystem.ts +1 -3
  159. package/src/three/sceneOrigin.ts +96 -33
  160. package/src/three/sectionRaycastAabb.ts +24 -110
  161. package/src/three/shaderCubeMesh.ts +6 -17
  162. package/src/three/shaders/cubeBlockShader.ts +85 -96
  163. package/src/three/shaders/legacyBlockShader.ts +21 -43
  164. package/src/three/shaders/textureIndexMapping.ts +89 -95
  165. package/src/three/shaders/tintPalette.ts +156 -170
  166. package/src/three/signTextureCache.ts +9 -12
  167. package/src/three/skyboxRenderer.ts +62 -70
  168. package/src/three/tests/chunkMeshManagerLegacy.test.ts +34 -64
  169. package/src/three/tests/cubeDrawSpans.test.ts +55 -25
  170. package/src/three/tests/globalBlockBuffer.test.ts +217 -0
  171. package/src/three/tests/globalLegacyBuffer.test.ts +300 -41
  172. package/src/three/tests/legacyMultiDraw.test.ts +8 -29
  173. package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
  174. package/src/three/tests/signTextureCache.test.ts +4 -4
  175. package/src/three/thirdPersonVoxelRaycast.ts +120 -0
  176. package/src/three/threeJsMedia.ts +55 -72
  177. package/src/three/threeJsParticles.ts +32 -41
  178. package/src/three/threeJsSound.ts +3 -3
  179. package/src/three/threeJsUtils.ts +3 -3
  180. package/src/three/threeWorker.ts +2 -2
  181. package/src/three/waypointSprite.ts +55 -82
  182. package/src/three/waypoints.ts +20 -23
  183. package/src/three/world/cursorBlock.ts +25 -12
  184. package/src/three/world/vr.ts +11 -17
  185. package/src/three/worldGeometryExport.ts +15 -34
  186. package/src/three/worldRendererThree.ts +144 -166
  187. package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
  188. package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
  189. package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
  190. package/src/wasm-mesher/tests/cameraCollisionBlockCache.test.ts +82 -0
  191. package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
  192. package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
  193. package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
  194. package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +1 -93
  195. package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
  196. package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
  197. package/src/wasm-mesher/tests/thirdPersonVoxelRaycast.test.ts +63 -0
  198. package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
  199. package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
  200. package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
  201. package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
  202. package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
  203. package/src/worldView/worldView.spiral.test.ts +1 -1
  204. package/src/worldView/worldView.ts +34 -39
  205. package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
@@ -3,57 +3,62 @@ import { proxy } from 'valtio'
3
3
  import type { GameMode, HandItemBlock, BlocksShapes, BlockShape, MovementState, CameraPerspective, Team, ItemSpecificContextProperties } from './types'
4
4
 
5
5
  // edit src/mineflayer/playerState.ts for implementation of player state from mineflayer
6
- export const getInitialPlayerState = () => proxy({
7
- playerSkin: undefined as string | undefined,
8
- inWater: false,
9
- waterBreathing: false,
10
- backgroundColor: [0, 0, 0] as [number, number, number],
11
- ambientLight: 0,
12
- directionalLight: 0,
13
- eyeHeight: 0,
14
- gameMode: undefined as GameMode | undefined,
15
- lookingAtBlock: undefined as {
16
- x: number
17
- y: number
18
- z: number
19
- face?: number
20
- shapes: BlocksShapes
21
- } | undefined,
22
- diggingBlock: undefined as {
23
- x: number
24
- y: number
25
- z: number
26
- stage: number
27
- face?: number
28
- mergedShape: BlockShape | undefined
29
- } | undefined,
30
- movementState: 'NOT_MOVING' as MovementState,
31
- onGround: true,
32
- sneaking: false,
33
- flying: false,
34
- sprinting: false,
35
- walkDist: 0,
36
- prevWalkDist: 0,
37
- bob: 0,
38
- prevBob: 0,
39
- itemUsageTicks: 0,
40
- username: '',
41
- onlineMode: false,
42
- /** Dimension ambient lighting preset (e.g. nether) — from login/respawn dimension data when available */
43
- cardinalLight: 'default' as string,
44
- lightingDisabled: false,
45
- shouldHideHand: false,
46
- heldItemMain: undefined as HandItemBlock | undefined,
47
- heldItemOff: undefined as HandItemBlock | undefined,
48
- perspective: 'first_person' as CameraPerspective,
49
- onFire: false,
50
- /** Gameplay FOV scale (sprint, bow, zoom, etc.); base FOV comes from renderer options. */
51
- fovMultiplier: 1,
6
+ export const getInitialPlayerState = () =>
7
+ proxy({
8
+ playerSkin: undefined as string | undefined,
9
+ inWater: false,
10
+ waterBreathing: false,
11
+ backgroundColor: [0, 0, 0] as [number, number, number],
12
+ ambientLight: 0,
13
+ directionalLight: 0,
14
+ eyeHeight: 0,
15
+ gameMode: undefined as GameMode | undefined,
16
+ lookingAtBlock: undefined as
17
+ | {
18
+ x: number
19
+ y: number
20
+ z: number
21
+ face?: number
22
+ shapes: BlocksShapes
23
+ }
24
+ | undefined,
25
+ diggingBlock: undefined as
26
+ | {
27
+ x: number
28
+ y: number
29
+ z: number
30
+ stage: number
31
+ face?: number
32
+ mergedShape: BlockShape | undefined
33
+ }
34
+ | undefined,
35
+ movementState: 'NOT_MOVING' as MovementState,
36
+ onGround: true,
37
+ sneaking: false,
38
+ flying: false,
39
+ sprinting: false,
40
+ walkDist: 0,
41
+ prevWalkDist: 0,
42
+ bob: 0,
43
+ prevBob: 0,
44
+ itemUsageTicks: 0,
45
+ username: '',
46
+ onlineMode: false,
47
+ /** Dimension ambient lighting preset (e.g. nether) — from login/respawn dimension data when available */
48
+ cardinalLight: 'default' as string,
49
+ lightingDisabled: false,
50
+ shouldHideHand: false,
51
+ heldItemMain: undefined as HandItemBlock | undefined,
52
+ heldItemOff: undefined as HandItemBlock | undefined,
53
+ perspective: 'first_person' as CameraPerspective,
54
+ onFire: false,
55
+ /** Gameplay FOV scale (sprint, bow, zoom, etc.); base FOV comes from renderer options. */
56
+ fovMultiplier: 1,
52
57
 
53
- cameraSpectatingEntity: undefined as number | undefined,
58
+ cameraSpectatingEntity: undefined as number | undefined,
54
59
 
55
- team: undefined as Team | undefined,
56
- })
60
+ team: undefined as Team | undefined
61
+ })
57
62
 
58
63
  export const getPlayerStateUtils = (reactive: PlayerStateReactive) => ({
59
64
  isSpectator() {
@@ -80,7 +85,7 @@ export type PlayerStateRenderer = PlayerStateReactive
80
85
  export const getItemSelector = (playerState: PlayerStateRenderer, specificProperties: ItemSpecificContextProperties, item?: import('prismarine-item').Item) => {
81
86
  return {
82
87
  ...specificProperties,
83
- 'minecraft:date': new Date(),
88
+ 'minecraft:date': new Date()
84
89
  // "minecraft:context_dimension": bot.entityp,
85
90
  // 'minecraft:time': bot.time.timeOfDay / 24_000,
86
91
  }
@@ -23,15 +23,9 @@ export interface HandItemBlock {
23
23
 
24
24
  export type MovementState = 'NOT_MOVING' | 'WALKING' | 'SPRINTING' | 'SNEAKING'
25
25
  export type ItemSpecificContextProperties = Partial<
26
- Pick<
27
- ItemSelector['properties'],
28
- | 'minecraft:using_item'
29
- | 'minecraft:use_duration'
30
- | 'minecraft:use_cycle'
31
- | 'minecraft:display_context'
32
- >
26
+ Pick<ItemSelector['properties'], 'minecraft:using_item' | 'minecraft:use_duration' | 'minecraft:use_cycle' | 'minecraft:display_context'>
33
27
  >
34
28
  export type CameraPerspective = 'first_person' | 'third_person_back' | 'third_person_front'
35
29
 
36
- export type BlockShape = { position: { x: number, y: number, z: number }; width: number; height: number; depth: number; }
30
+ export type BlockShape = { position: { x: number; y: number; z: number }; width: number; height: number; depth: number }
37
31
  export type BlocksShapes = BlockShape[]
@@ -32,17 +32,19 @@ export const displayEntitiesDebugList = (mcData: IndexedData) => {
32
32
 
33
33
  // Test entities
34
34
  const results: Array<{
35
- entity: string;
36
- supported: boolean;
37
- type?: 'obj' | 'bedrock' | 'gltf' | 'special';
38
- mappedFrom?: string;
39
- textureMap?: boolean;
40
- errors?: string[];
35
+ entity: string
36
+ supported: boolean
37
+ type?: 'obj' | 'bedrock' | 'gltf' | 'special'
38
+ mappedFrom?: string
39
+ textureMap?: boolean
40
+ errors?: string[]
41
41
  }> = []
42
- const entityNames = Object.keys(mcData.entitiesArray.reduce((acc, entity) => {
43
- acc[entity.name] = true
44
- return acc
45
- }, {}))
42
+ const entityNames = Object.keys(
43
+ mcData.entitiesArray.reduce((acc, entity) => {
44
+ acc[entity.name] = true
45
+ return acc
46
+ }, {})
47
+ )
46
48
 
47
49
  // Add loading indicator
48
50
  const loading = document.createElement('div')
@@ -57,13 +59,12 @@ export const displayEntitiesDebugList = (mcData: IndexedData) => {
57
59
  results.push({
58
60
  entity,
59
61
  supported: true,
60
- type: 'special',
62
+ type: 'special'
61
63
  })
62
64
  continue
63
65
  }
64
66
 
65
67
  try {
66
-
67
68
  const { mesh: entityMesh } = new EntityMesh(version, entity, undefined, {}, debugFlags)
68
69
  // find the most distant pos child
69
70
  globalThis.objects ??= {}
@@ -165,9 +166,11 @@ export const displayEntitiesDebugList = (mcData: IndexedData) => {
165
166
  }
166
167
 
167
168
  // log object with errors per entity
168
- const errors = results.filter(r => r.errors).map(r => ({
169
- entity: r.entity,
170
- errors: r.errors
171
- }))
169
+ const errors = results
170
+ .filter(r => r.errors)
171
+ .map(r => ({
172
+ entity: r.entity,
173
+ errors: r.errors
174
+ }))
172
175
  console.log(errors)
173
176
  }
@@ -35,7 +35,7 @@ export interface PlaygroundSceneConfig {
35
35
  }
36
36
 
37
37
  const appGraphicBackends = [
38
- createGraphicsBackendSingleThread,
38
+ createGraphicsBackendSingleThread
39
39
  // createGraphicsBackendOffThread
40
40
  ]
41
41
 
@@ -44,7 +44,7 @@ const includedVersions = globalThis.includedVersions
44
44
  export class BasePlaygroundScene {
45
45
  appViewer = new AppViewer({
46
46
  config: {
47
- statsVisible: 2,
47
+ statsVisible: 2
48
48
  }
49
49
  })
50
50
 
@@ -68,13 +68,18 @@ export class BasePlaygroundScene {
68
68
  // GUI
69
69
  gui = new GUI()
70
70
  params = {} as Record<string, any>
71
- paramOptions = {} as Partial<Record<keyof typeof this.params, {
72
- hide?: boolean
73
- options?: string[]
74
- min?: number
75
- max?: number
76
- reloadOnChange?: boolean
77
- }>>
71
+ paramOptions = {} as Partial<
72
+ Record<
73
+ keyof typeof this.params,
74
+ {
75
+ hide?: boolean
76
+ options?: string[]
77
+ min?: number
78
+ max?: number
79
+ reloadOnChange?: boolean
80
+ }
81
+ >
82
+ >
78
83
  onParamUpdate = {} as Record<string, () => void>
79
84
  alwaysIgnoreQs = [] as string[]
80
85
  skipUpdateQs = false
@@ -141,7 +146,7 @@ export class BasePlaygroundScene {
141
146
  })
142
147
  }
143
148
 
144
- onParamsUpdate(paramName: string, object: any) { }
149
+ onParamsUpdate(paramName: string, object: any) {}
145
150
 
146
151
  updateQs(paramName: string, valueSet: any) {
147
152
  if (this.skipUpdateQs) return
@@ -201,16 +206,15 @@ export class BasePlaygroundScene {
201
206
  }
202
207
 
203
208
  // Overridable methods
204
- setupWorld() { }
205
- sceneReset() { }
209
+ setupWorld() {}
210
+ sceneReset() {}
206
211
 
207
212
  // eslint-disable-next-line max-params
208
213
  addWorldBlock(xOffset: number, yOffset: number, zOffset: number, blockName: BlockNames, properties?: Record<string, any>) {
209
214
  if (xOffset > 16 || yOffset > 16 || zOffset > 16) throw new Error('Offset too big')
210
- const block =
211
- properties ?
212
- this.Block.fromProperties(this.mcData.blocksByName[blockName].id, properties ?? {}, 0) :
213
- this.Block.fromStateId(this.mcData.blocksByName[blockName].defaultState, 0)
215
+ const block = properties
216
+ ? this.Block.fromProperties(this.mcData.blocksByName[blockName].id, properties ?? {}, 0)
217
+ : this.Block.fromStateId(this.mcData.blocksByName[blockName].defaultState, 0)
214
218
  this.world.setBlock(this.targetPos.offset(xOffset, yOffset, zOffset), block)
215
219
  }
216
220
 
@@ -291,12 +295,7 @@ export class BasePlaygroundScene {
291
295
 
292
296
  // Create our own camera for OrbitControls - this is separate from the internal worldRenderer camera
293
297
  // We sync our camera state to the backend via updateCamera()
294
- this.camera = new THREE.PerspectiveCamera(
295
- this.appViewer.inWorldRenderingConfig.fov || 75,
296
- window.innerWidth / window.innerHeight,
297
- 0.1,
298
- 1000
299
- )
298
+ this.camera = new THREE.PerspectiveCamera(this.appViewer.inWorldRenderingConfig.fov || 75, window.innerWidth / window.innerHeight, 0.1, 1000)
300
299
 
301
300
  // Setup world (adds blocks, etc.)
302
301
  this.setupWorld()
@@ -311,9 +310,7 @@ export class BasePlaygroundScene {
311
310
  if (this.enableCameraControls) {
312
311
  const canvas = document.querySelector('#viewer-canvas')
313
312
  if (canvas) {
314
- const controls = this.enableCameraOrbitControl
315
- ? new OrbitControls(this.camera, canvas as HTMLElement)
316
- : undefined
313
+ const controls = this.enableCameraOrbitControl ? new OrbitControls(this.camera, canvas as HTMLElement) : undefined
317
314
  this.controls = controls
318
315
 
319
316
  this.resetCamera()
@@ -335,7 +332,7 @@ export class BasePlaygroundScene {
335
332
  this.camera.position.y.toFixed(2),
336
333
  this.camera.position.z.toFixed(2),
337
334
  this.camera.rotation.x.toFixed(2),
338
- this.camera.rotation.y.toFixed(2),
335
+ this.camera.rotation.y.toFixed(2)
339
336
  ].join(',')
340
337
  }, 200)
341
338
 
@@ -483,9 +480,7 @@ export class BasePlaygroundScene {
483
480
  this.currentFps = fps
484
481
 
485
482
  const isSeriousDelay = this.maxFrameDelay > 150
486
- const delayText = isSeriousDelay
487
- ? `<span style="color: #ff4444;">${this.maxFrameDelay.toFixed(0)}ms</span>`
488
- : `${this.maxFrameDelay.toFixed(0)}ms`
483
+ const delayText = isSeriousDelay ? `<span style="color: #ff4444;">${this.maxFrameDelay.toFixed(0)}ms</span>` : `${this.maxFrameDelay.toFixed(0)}ms`
489
484
 
490
485
  // Update the DOM element directly - single line format
491
486
  this.debugFpsElement.innerHTML = `FPS: ${fps} | Max Delay: ${delayText}`
@@ -502,16 +497,18 @@ export class BasePlaygroundScene {
502
497
  }
503
498
 
504
499
  addKeyboardShortcuts() {
505
- document.addEventListener('keydown', (e) => {
500
+ document.addEventListener('keydown', e => {
506
501
  if (!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
507
502
  if (e.code === 'KeyR') {
508
503
  this.controls?.reset()
509
504
  this.resetCamera()
510
505
  }
511
- if (e.code === 'KeyE') { // refresh block (main)
506
+ if (e.code === 'KeyE') {
507
+ // refresh block (main)
512
508
  this.worldView!.setBlockStateId(this.targetPos, this.world.getBlockStateId(this.targetPos))
513
509
  }
514
- if (e.code === 'KeyF') { // reload all chunks
510
+ if (e.code === 'KeyF') {
511
+ // reload all chunks
515
512
  this.sceneReset()
516
513
  this.worldView!.unloadAllChunks()
517
514
  void this.worldView!.init(this.targetPos)
@@ -4,15 +4,15 @@ import { proxy, ref, useSnapshot } from 'valtio'
4
4
  export type ButtonName = 'jump' | 'sneak'
5
5
 
6
6
  export const joystickPointer = proxy({
7
- pointer: null as { x: number, y: number, pointerId: number } | null,
8
- joystickInner: null as HTMLDivElement | null,
7
+ pointer: null as { x: number; y: number; pointerId: number } | null,
8
+ joystickInner: null as HTMLDivElement | null
9
9
  })
10
10
 
11
11
  export const cameraPointer = proxy({
12
- pointer: null as { x: number, y: number, pointerId: number } | null,
12
+ pointer: null as { x: number; y: number; pointerId: number } | null
13
13
  })
14
14
 
15
- export const handleMovementStickDelta = (e?: { clientX: number, clientY: number }) => {
15
+ export const handleMovementStickDelta = (e?: { clientX: number; clientY: number }) => {
16
16
  const max = 32
17
17
  let x = 0
18
18
  let y = 0
@@ -31,7 +31,7 @@ export const handleMovementStickDelta = (e?: { clientX: number, clientY: number
31
31
  const vector = {
32
32
  x: x / max,
33
33
  y: 0,
34
- z: y / max,
34
+ z: y / max
35
35
  }
36
36
 
37
37
  console.log('Movement vector:', vector)
@@ -81,12 +81,12 @@ export const MobileControls = () => {
81
81
 
82
82
  const buttonPositions = {
83
83
  jump: [85, 60],
84
- sneak: [85, 75],
84
+ sneak: [85, 75]
85
85
  }
86
86
 
87
87
  const buttonIcons = {
88
88
  jump: '↑',
89
- sneak: '↓',
89
+ sneak: '↓'
90
90
  }
91
91
 
92
92
  return {
@@ -107,7 +107,7 @@ export const MobileControls = () => {
107
107
  fontSize: '16px',
108
108
  userSelect: 'none',
109
109
  transform: 'translate(-50%, -50%)',
110
- border: '2px solid rgba(255, 255, 255, 0.3)',
110
+ border: '2px solid rgba(255, 255, 255, 0.3)'
111
111
  } satisfies CSSProperties,
112
112
  onPointerDown(e: PType) {
113
113
  const elem = e.currentTarget as HTMLElement
@@ -117,7 +117,7 @@ export const MobileControls = () => {
117
117
  },
118
118
  onPointerUp: pointerup,
119
119
  onLostPointerCapture: pointerup,
120
- children: buttonIcons[name],
120
+ children: buttonIcons[name]
121
121
  }
122
122
  }
123
123
 
@@ -129,140 +129,144 @@ export const MobileControls = () => {
129
129
 
130
130
  if (!usingTouch) return null
131
131
 
132
- return <div>
133
- {/* Movement Joystick */}
134
- <div
135
- className='movement_joystick_outer'
136
- ref={joystickOuter}
137
- style={{
138
- display: movementPointer ? 'flex' : 'none',
139
- borderRadius: '50%',
140
- width: joystickSize,
141
- height: joystickSize,
142
- border: '2px solid rgba(0, 0, 0, 0.5)',
143
- backgroundColor: 'rgba(255, 255, 255, 0.3)',
144
- position: 'fixed',
145
- justifyContent: 'center',
146
- alignItems: 'center',
147
- transform: 'translate(-50%, -50%)',
148
- zIndex: Z_INDEX_INTERACTIBLE,
149
- ...(movementPointer ? {
150
- left: `${movementPointer.x / window.innerWidth * 100}%`,
151
- top: `${movementPointer.y / window.innerHeight * 100}%`
152
- } : {}),
153
- }}
154
- >
132
+ return (
133
+ <div>
134
+ {/* Movement Joystick */}
155
135
  <div
156
- className='movement_joystick_inner'
136
+ className="movement_joystick_outer"
137
+ ref={joystickOuter}
157
138
  style={{
139
+ display: movementPointer ? 'flex' : 'none',
158
140
  borderRadius: '50%',
159
- width: joystickSize * 0.35,
160
- height: joystickSize * 0.35,
161
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
162
- position: 'absolute',
141
+ width: joystickSize,
142
+ height: joystickSize,
143
+ border: '2px solid rgba(0, 0, 0, 0.5)',
144
+ backgroundColor: 'rgba(255, 255, 255, 0.3)',
145
+ position: 'fixed',
146
+ justifyContent: 'center',
147
+ alignItems: 'center',
148
+ transform: 'translate(-50%, -50%)',
149
+ zIndex: Z_INDEX_INTERACTIBLE,
150
+ ...(movementPointer
151
+ ? {
152
+ left: `${(movementPointer.x / window.innerWidth) * 100}%`,
153
+ top: `${(movementPointer.y / window.innerHeight) * 100}%`
154
+ }
155
+ : {})
163
156
  }}
164
- ref={joystickInner}
165
- />
166
- </div>
157
+ >
158
+ <div
159
+ className="movement_joystick_inner"
160
+ style={{
161
+ borderRadius: '50%',
162
+ width: joystickSize * 0.35,
163
+ height: joystickSize * 0.35,
164
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
165
+ position: 'absolute'
166
+ }}
167
+ ref={joystickInner}
168
+ />
169
+ </div>
170
+
171
+ {/* Up/Down Action Buttons */}
172
+ <div {...buttonProps('jump')} />
173
+ <div {...buttonProps('sneak')} />
174
+
175
+ {/* Movement touch area (left half of screen) */}
176
+ <div
177
+ style={{
178
+ position: 'fixed',
179
+ left: '0',
180
+ top: '0',
181
+ width: '50%',
182
+ height: '100%',
183
+ zIndex: Z_INDEX_INTERACTIBLE - 1
184
+ }}
185
+ onPointerDown={e => {
186
+ if (joystickPointer.pointer) return
167
187
 
168
- {/* Up/Down Action Buttons */}
169
- <div {...buttonProps('jump')} />
170
- <div {...buttonProps('sneak')} />
188
+ joystickPointer.pointer = {
189
+ x: e.clientX,
190
+ y: e.clientY,
191
+ pointerId: e.pointerId
192
+ }
171
193
 
172
- {/* Movement touch area (left half of screen) */}
173
- <div
174
- style={{
175
- position: 'fixed',
176
- left: '0',
177
- top: '0',
178
- width: '50%',
179
- height: '100%',
180
- zIndex: Z_INDEX_INTERACTIBLE - 1,
181
- }}
182
- onPointerDown={(e) => {
183
- if (joystickPointer.pointer) return
184
-
185
- joystickPointer.pointer = {
186
- x: e.clientX,
187
- y: e.clientY,
188
- pointerId: e.pointerId,
189
- }
194
+ const elem = e.currentTarget as HTMLElement
195
+ elem.setPointerCapture(e.pointerId)
196
+ }}
197
+ onPointerMove={e => {
198
+ if (!joystickPointer.pointer || e.pointerId !== joystickPointer.pointer.pointerId) return
190
199
 
191
- const elem = e.currentTarget as HTMLElement
192
- elem.setPointerCapture(e.pointerId)
193
- }}
194
- onPointerMove={(e) => {
195
- if (!joystickPointer.pointer || e.pointerId !== joystickPointer.pointer.pointerId) return
200
+ handleMovementStickDelta({
201
+ clientX: e.clientX,
202
+ clientY: e.clientY
203
+ })
204
+ }}
205
+ onPointerUp={e => {
206
+ if (!joystickPointer.pointer || e.pointerId !== joystickPointer.pointer.pointerId) return
196
207
 
197
- handleMovementStickDelta({
198
- clientX: e.clientX,
199
- clientY: e.clientY,
200
- })
201
- }}
202
- onPointerUp={(e) => {
203
- if (!joystickPointer.pointer || e.pointerId !== joystickPointer.pointer.pointerId) return
208
+ joystickPointer.pointer = null
209
+ handleMovementStickDelta() // Reset position
204
210
 
205
- joystickPointer.pointer = null
206
- handleMovementStickDelta() // Reset position
211
+ const elem = e.currentTarget as HTMLElement
212
+ elem.releasePointerCapture(e.pointerId)
213
+ }}
214
+ onLostPointerCapture={e => {
215
+ if (!joystickPointer.pointer || e.pointerId !== joystickPointer.pointer.pointerId) return
207
216
 
208
- const elem = e.currentTarget as HTMLElement
209
- elem.releasePointerCapture(e.pointerId)
210
- }}
211
- onLostPointerCapture={(e) => {
212
- if (!joystickPointer.pointer || e.pointerId !== joystickPointer.pointer.pointerId) return
213
-
214
- joystickPointer.pointer = null
215
- handleMovementStickDelta() // Reset position
216
- }}
217
- />
218
-
219
- {/* Camera rotation touch area (right half of screen, excluding buttons) */}
220
- <div
221
- style={{
222
- position: 'fixed',
223
- right: '0',
224
- top: '0',
225
- width: '50%',
226
- height: '100%',
227
- zIndex: Z_INDEX_INTERACTIBLE - 2,
228
- }}
229
- onPointerDown={(e) => {
230
- if (cameraPointer.pointer) return
231
-
232
- cameraPointer.pointer = {
233
- x: e.clientX,
234
- y: e.clientY,
235
- pointerId: e.pointerId,
236
- }
217
+ joystickPointer.pointer = null
218
+ handleMovementStickDelta() // Reset position
219
+ }}
220
+ />
237
221
 
238
- const elem = e.currentTarget as HTMLElement
239
- elem.setPointerCapture(e.pointerId)
240
- }}
241
- onPointerMove={(e) => {
242
- if (!cameraPointer.pointer || e.pointerId !== cameraPointer.pointer.pointerId) return
222
+ {/* Camera rotation touch area (right half of screen, excluding buttons) */}
223
+ <div
224
+ style={{
225
+ position: 'fixed',
226
+ right: '0',
227
+ top: '0',
228
+ width: '50%',
229
+ height: '100%',
230
+ zIndex: Z_INDEX_INTERACTIBLE - 2
231
+ }}
232
+ onPointerDown={e => {
233
+ if (cameraPointer.pointer) return
234
+
235
+ cameraPointer.pointer = {
236
+ x: e.clientX,
237
+ y: e.clientY,
238
+ pointerId: e.pointerId
239
+ }
243
240
 
244
- const deltaX = e.clientX - cameraPointer.pointer.x
245
- const deltaY = e.clientY - cameraPointer.pointer.y
241
+ const elem = e.currentTarget as HTMLElement
242
+ elem.setPointerCapture(e.pointerId)
243
+ }}
244
+ onPointerMove={e => {
245
+ if (!cameraPointer.pointer || e.pointerId !== cameraPointer.pointer.pointerId) return
246
246
 
247
- handleCameraRotation(deltaX, deltaY)
247
+ const deltaX = e.clientX - cameraPointer.pointer.x
248
+ const deltaY = e.clientY - cameraPointer.pointer.y
248
249
 
249
- // Update pointer position for continuous rotation
250
- cameraPointer.pointer.x = e.clientX
251
- cameraPointer.pointer.y = e.clientY
252
- }}
253
- onPointerUp={(e) => {
254
- if (!cameraPointer.pointer || e.pointerId !== cameraPointer.pointer.pointerId) return
250
+ handleCameraRotation(deltaX, deltaY)
255
251
 
256
- cameraPointer.pointer = null
252
+ // Update pointer position for continuous rotation
253
+ cameraPointer.pointer.x = e.clientX
254
+ cameraPointer.pointer.y = e.clientY
255
+ }}
256
+ onPointerUp={e => {
257
+ if (!cameraPointer.pointer || e.pointerId !== cameraPointer.pointer.pointerId) return
257
258
 
258
- const elem = e.currentTarget as HTMLElement
259
- elem.releasePointerCapture(e.pointerId)
260
- }}
261
- onLostPointerCapture={(e) => {
262
- if (!cameraPointer.pointer || e.pointerId !== cameraPointer.pointer.pointerId) return
263
-
264
- cameraPointer.pointer = null
265
- }}
266
- />
267
- </div>
259
+ cameraPointer.pointer = null
260
+
261
+ const elem = e.currentTarget as HTMLElement
262
+ elem.releasePointerCapture(e.pointerId)
263
+ }}
264
+ onLostPointerCapture={e => {
265
+ if (!cameraPointer.pointer || e.pointerId !== cameraPointer.pointer.pointerId) return
266
+
267
+ cameraPointer.pointer = null
268
+ }}
269
+ />
270
+ </div>
271
+ )
268
272
  }