nova64 0.2.5 → 0.2.6

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 (140) hide show
  1. package/README.md +25 -8
  2. package/bin/nova64.js +165 -0
  3. package/dist/assets/console-CY_kygm3.js +14 -0
  4. package/dist/assets/console-CY_kygm3.js.map +1 -0
  5. package/dist/assets/main-l0sNRNKZ.js.map +1 -0
  6. package/dist/assets/sky/studio/nx.png +0 -0
  7. package/dist/assets/sky/studio/ny.png +0 -0
  8. package/dist/assets/sky/studio/nz.png +0 -0
  9. package/dist/assets/sky/studio/px.png +0 -0
  10. package/dist/assets/sky/studio/py.png +0 -0
  11. package/dist/assets/sky/studio/pz.png +0 -0
  12. package/dist/assets/vanilla-Dcuy32gi.js +2 -0
  13. package/dist/assets/vanilla-Dcuy32gi.js.map +1 -0
  14. package/dist/console.html +899 -0
  15. package/dist/docs/BENCHMARK.md +77 -0
  16. package/dist/docs/CHEATSHEET.md +255 -0
  17. package/dist/docs/EFFECTS_API_GUIDE.md +577 -0
  18. package/dist/docs/EFFECTS_QUICK_REFERENCE.md +331 -0
  19. package/dist/docs/FONT_CHARACTER_REFERENCE.md +219 -0
  20. package/dist/docs/FREE_GLB_ASSETS.md +330 -0
  21. package/dist/docs/FULLSCREEN_BUTTON_FEATURE.md +296 -0
  22. package/dist/docs/GAMEPAD_SUPPORT.md +348 -0
  23. package/dist/docs/GAME_IMPROVEMENTS.md +278 -0
  24. package/dist/docs/GAME_QUALITY_STATUS.md +300 -0
  25. package/dist/docs/MIGRATION_GUIDE.md +553 -0
  26. package/dist/docs/NOVA64_3D_API.md +356 -0
  27. package/dist/docs/NOVA64_API_REFERENCE.md +1406 -0
  28. package/dist/docs/NOVA64_UI_API.md +503 -0
  29. package/dist/docs/UI_SYSTEM_SUMMARY.md +445 -0
  30. package/dist/docs/VOXEL_ENGINE_GUIDE.md +662 -0
  31. package/dist/docs/VOXEL_QUICK_REFERENCE.md +386 -0
  32. package/dist/docs/api-3d.html +750 -0
  33. package/dist/docs/api-effects.html +385 -0
  34. package/dist/docs/api-improvements.md +121 -0
  35. package/dist/docs/api-skybox.html +407 -0
  36. package/dist/docs/api-sprites.html +321 -0
  37. package/dist/docs/api-voxel.html +337 -0
  38. package/dist/docs/api.html +543 -0
  39. package/dist/docs/assets.html +306 -0
  40. package/dist/docs/audio.html +340 -0
  41. package/dist/docs/blogs.html +286 -0
  42. package/dist/docs/collision.html +316 -0
  43. package/dist/docs/console.html +247 -0
  44. package/dist/docs/editor.html +297 -0
  45. package/dist/docs/font.html +247 -0
  46. package/dist/docs/framebuffer.html +247 -0
  47. package/dist/docs/fullscreen-button.html +297 -0
  48. package/dist/docs/gpu-systems.html +247 -0
  49. package/dist/docs/index.html +580 -0
  50. package/dist/docs/input.html +491 -0
  51. package/dist/docs/physics.html +311 -0
  52. package/dist/docs/screens.html +311 -0
  53. package/dist/docs/storage.html +311 -0
  54. package/dist/docs/textinput.html +332 -0
  55. package/dist/docs/ui.html +488 -0
  56. package/dist/examples/3d-advanced/code.js +695 -0
  57. package/dist/examples/adventure-comic-3d/code.js +342 -0
  58. package/dist/examples/audio-lab/code.js +150 -0
  59. package/dist/examples/boids-flocking/code.js +270 -0
  60. package/dist/examples/crystal-cathedral-3d/code.js +706 -0
  61. package/dist/examples/cyberpunk-city-3d/code.js +1383 -0
  62. package/dist/examples/demoscene/README.md +192 -0
  63. package/dist/examples/demoscene/code.js +1081 -0
  64. package/dist/examples/demoscene/meta.json +21 -0
  65. package/dist/examples/dungeon-crawler-3d/code.js +1117 -0
  66. package/dist/examples/f-zero-nova-3d/code.js +865 -0
  67. package/dist/examples/f-zero-nova-3d/code_old.js +1555 -0
  68. package/dist/examples/fps-demo-3d/code.js +744 -0
  69. package/dist/examples/game-of-life-3d/code.js +338 -0
  70. package/dist/examples/generative-art/code.js +632 -0
  71. package/dist/examples/hello-3d/code.js +325 -0
  72. package/dist/examples/hello-skybox/code.js +183 -0
  73. package/dist/examples/hello-world/code.js +19 -0
  74. package/dist/examples/input-showcase/code.js +109 -0
  75. package/dist/examples/instancing-demo/code.js +315 -0
  76. package/dist/examples/minecraft-demo/code.js +387 -0
  77. package/dist/examples/model-viewer-3d/code.js +114 -0
  78. package/dist/examples/mystical-realm-3d/code.js +1203 -0
  79. package/dist/examples/nature-explorer-3d/code.js +1318 -0
  80. package/dist/examples/particles-demo/code.js +522 -0
  81. package/dist/examples/pbr-showcase/code.js +140 -0
  82. package/dist/examples/physics-demo-3d/code.js +948 -0
  83. package/dist/examples/screen-demo/code.js +267 -0
  84. package/dist/examples/shooter-demo-3d/code.js +1286 -0
  85. package/dist/examples/space-combat-3d/IMPLEMENTATION_SUMMARY.md +109 -0
  86. package/dist/examples/space-combat-3d/README.md +135 -0
  87. package/dist/examples/space-combat-3d/code.js +1332 -0
  88. package/dist/examples/space-harrier-3d/code.js +923 -0
  89. package/dist/examples/star-fox-nova-3d/code.js +1116 -0
  90. package/dist/examples/star-fox-nova-3d/code_backup.js +410 -0
  91. package/dist/examples/star-fox-nova-3d/code_broken.js +1821 -0
  92. package/dist/examples/storage-quest/code.js +209 -0
  93. package/dist/examples/strider-demo-3d/IMPROVEMENT_OPTIONS.md +285 -0
  94. package/dist/examples/strider-demo-3d/cache-test.html +132 -0
  95. package/dist/examples/strider-demo-3d/code-fixed.js +582 -0
  96. package/dist/examples/strider-demo-3d/code-old.js +1537 -0
  97. package/dist/examples/strider-demo-3d/code.js +1462 -0
  98. package/dist/examples/strider-demo-3d/code.js.bak2 +1169 -0
  99. package/dist/examples/strider-demo-3d/fix-game.sh +53 -0
  100. package/dist/examples/super-plumber-64/README.md +128 -0
  101. package/dist/examples/super-plumber-64/code.js +1185 -0
  102. package/dist/examples/super-plumber-64/index.html +88 -0
  103. package/dist/examples/test-2d-overlay/code.js +32 -0
  104. package/dist/examples/test-font/code.js +51 -0
  105. package/dist/examples/test-minimal/code.js +21 -0
  106. package/dist/examples/ui-demo/code.js +306 -0
  107. package/dist/examples/wing-commander-space/README.md +180 -0
  108. package/dist/examples/wing-commander-space/code.js +1285 -0
  109. package/dist/examples/wizardry-3d/CHANGELOG.md +366 -0
  110. package/dist/examples/wizardry-3d/code.js +3928 -0
  111. package/dist/index.html +666 -0
  112. package/dist/os9-shell/assets/index-DIHfrTaW.css +1 -0
  113. package/dist/os9-shell/assets/index-KchE_ngx.js +483 -0
  114. package/dist/os9-shell/assets/index-KchE_ngx.js.map +1 -0
  115. package/dist/os9-shell/index.html +23 -0
  116. package/dist/os9-shell/nova-icon.svg +12 -0
  117. package/index.html +6 -1
  118. package/package.json +37 -32
  119. package/public/assets/sky/studio/nx.png +0 -0
  120. package/public/assets/sky/studio/ny.png +0 -0
  121. package/public/assets/sky/studio/nz.png +0 -0
  122. package/public/assets/sky/studio/px.png +0 -0
  123. package/public/assets/sky/studio/py.png +0 -0
  124. package/public/assets/sky/studio/pz.png +0 -0
  125. package/public/os9-shell/assets/index-KchE_ngx.js +483 -0
  126. package/public/os9-shell/assets/index-KchE_ngx.js.map +1 -0
  127. package/public/os9-shell/index.html +10 -1
  128. package/runtime/api-2d.js +301 -21
  129. package/runtime/api-3d/pbr.js +45 -1
  130. package/runtime/api-3d.js +1 -0
  131. package/runtime/api-effects.js +90 -3
  132. package/runtime/api-gameutils.js +476 -0
  133. package/runtime/api-generative.js +610 -0
  134. package/runtime/api-skybox.js +54 -0
  135. package/runtime/api-voxel.js +139 -28
  136. package/runtime/gpu-threejs.js +13 -9
  137. package/runtime/ui.js +2 -2
  138. package/src/main.js +20 -0
  139. package/public/os9-shell/assets/index-B1Uvacma.js +0 -32825
  140. package/public/os9-shell/assets/index-B1Uvacma.js.map +0 -1
@@ -0,0 +1,662 @@
1
+ # Nova64 Voxel Engine API Guide
2
+
3
+ ## Overview
4
+
5
+ The Nova64 Voxel Engine enables Minecraft-style block-based games with infinite procedurally generated worlds. It features:
6
+
7
+ - **Chunk-based world management** - Efficient memory usage with 16x64x16 chunks
8
+ - **Greedy meshing** - Optimized rendering with minimal draw calls
9
+ - **Procedural terrain generation** - Perlin noise with biomes, caves, and height variation
10
+ - **Multiple block types** - 15 different block materials
11
+ - **Real-time editing** - Place and break blocks instantly
12
+ - **Collision detection** - Full physics support for player and entities
13
+ - **Infinite worlds** - Chunks load/unload dynamically
14
+
15
+ ## Quick Start
16
+
17
+ ```javascript
18
+ export function init() {
19
+ // Setup lighting
20
+ setAmbientLight(0x666666);
21
+ setDirectionalLight([1, 2, 1], 0xffffff, 0.6);
22
+
23
+ // Generate world around player
24
+ updateVoxelWorld(playerX, playerZ);
25
+
26
+ // Add some trees
27
+ placeVoxelTree(10, 35, 10);
28
+ }
29
+
30
+ export function update(dt) {
31
+ // Update chunks as player moves
32
+ updateVoxelWorld(playerX, playerZ);
33
+
34
+ // Get block at position
35
+ const block = getVoxelBlock(x, y, z);
36
+
37
+ // Place or remove blocks
38
+ if (isKeyPressed('Space')) {
39
+ setVoxelBlock(x, y, z, BLOCK_TYPES.STONE);
40
+ }
41
+ }
42
+ ```
43
+
44
+ ## Block Types
45
+
46
+ ### Available Blocks
47
+
48
+ ```javascript
49
+ BLOCK_TYPES.AIR; // 0 - Empty space
50
+ BLOCK_TYPES.GRASS; // 1 - Green grass block
51
+ BLOCK_TYPES.DIRT; // 2 - Brown dirt
52
+ BLOCK_TYPES.STONE; // 3 - Gray stone
53
+ BLOCK_TYPES.SAND; // 4 - Yellow sand
54
+ BLOCK_TYPES.WATER; // 5 - Blue water (transparent)
55
+ BLOCK_TYPES.WOOD; // 6 - Dark brown wood log
56
+ BLOCK_TYPES.LEAVES; // 7 - Green tree leaves
57
+ BLOCK_TYPES.COBBLESTONE; // 8 - Gray cobblestone
58
+ BLOCK_TYPES.PLANKS; // 9 - Wooden planks
59
+ BLOCK_TYPES.GLASS; // 10 - Light blue glass (transparent)
60
+ BLOCK_TYPES.BRICK; // 11 - Red brick
61
+ BLOCK_TYPES.SNOW; // 12 - White snow
62
+ BLOCK_TYPES.ICE; // 13 - Light blue ice
63
+ BLOCK_TYPES.BEDROCK; // 14 - Dark gray bedrock (bottom layer)
64
+ ```
65
+
66
+ ## World Management
67
+
68
+ ### updateVoxelWorld(playerX, playerZ)
69
+
70
+ Updates visible chunks around the player position. Call this in your `update()` function when the player moves significantly.
71
+
72
+ **Parameters:**
73
+
74
+ - `playerX` - Player's X world coordinate
75
+ - `playerZ` - Player's Z world coordinate
76
+
77
+ **Example:**
78
+
79
+ ```javascript
80
+ export function update(dt) {
81
+ // Update every few frames to reduce overhead
82
+ if (Math.random() < 0.1) {
83
+ updateVoxelWorld(player.pos[0], player.pos[2]);
84
+ }
85
+ }
86
+ ```
87
+
88
+ **Performance:** Automatically loads chunks within render distance (4 chunks = 64 blocks) and unloads distant chunks to manage memory.
89
+
90
+ ## Block Manipulation
91
+
92
+ ### getVoxelBlock(x, y, z)
93
+
94
+ Returns the block type at the specified world coordinates.
95
+
96
+ **Parameters:**
97
+
98
+ - `x` - World X coordinate
99
+ - `y` - World Y coordinate (0-63)
100
+ - `z` - World Z coordinate
101
+
102
+ **Returns:** Block type constant (0-14) or `BLOCK_TYPES.AIR` if out of bounds
103
+
104
+ **Example:**
105
+
106
+ ```javascript
107
+ const blockUnderPlayer = getVoxelBlock(
108
+ Math.floor(playerX),
109
+ Math.floor(playerY) - 1,
110
+ Math.floor(playerZ)
111
+ );
112
+
113
+ if (blockUnderPlayer === BLOCK_TYPES.WATER) {
114
+ console.log('Player is standing on water!');
115
+ }
116
+ ```
117
+
118
+ ### setVoxelBlock(x, y, z, blockType)
119
+
120
+ Places or removes a block at the specified world coordinates. Automatically updates chunk meshes.
121
+
122
+ **Parameters:**
123
+
124
+ - `x` - World X coordinate
125
+ - `y` - World Y coordinate (0-63)
126
+ - `z` - World Z coordinate
127
+ - `blockType` - Block type constant (use `BLOCK_TYPES.AIR` to remove)
128
+
129
+ **Example:**
130
+
131
+ ```javascript
132
+ // Break block (set to air)
133
+ setVoxelBlock(10, 35, 10, BLOCK_TYPES.AIR);
134
+
135
+ // Place stone block
136
+ setVoxelBlock(10, 35, 10, BLOCK_TYPES.STONE);
137
+
138
+ // Build a wall
139
+ for (let y = 0; y < 5; y++) {
140
+ setVoxelBlock(20, 30 + y, 20, BLOCK_TYPES.BRICK);
141
+ }
142
+ ```
143
+
144
+ **Performance:** Efficiently updates only affected chunks. Adjacent chunks are automatically marked dirty if the block is on a boundary.
145
+
146
+ ## Raycasting
147
+
148
+ ### raycastVoxelBlock(origin, direction, maxDistance)
149
+
150
+ Casts a ray from a point in a direction to find the first solid block hit. Perfect for mining/building mechanics.
151
+
152
+ **Parameters:**
153
+
154
+ - `origin` - Starting point `[x, y, z]`
155
+ - `direction` - Ray direction `[dx, dy, dz]` (should be normalized)
156
+ - `maxDistance` - Maximum ray distance (default: 10)
157
+
158
+ **Returns:** Object with:
159
+
160
+ ```javascript
161
+ {
162
+ hit: true, // Whether a block was hit
163
+ position: [x, y, z], // Block coordinates
164
+ blockType: 3, // Type of block hit
165
+ distance: 5.2 // Distance to block
166
+ }
167
+ ```
168
+
169
+ **Example:**
170
+
171
+ ```javascript
172
+ // Camera/player looking direction
173
+ const lookDir = [
174
+ -Math.sin(yaw) * Math.cos(pitch),
175
+ Math.sin(pitch),
176
+ -Math.cos(yaw) * Math.cos(pitch),
177
+ ];
178
+
179
+ const result = raycastVoxelBlock(
180
+ [playerX, playerY + eyeHeight, playerZ],
181
+ lookDir,
182
+ 10 // 10 block reach
183
+ );
184
+
185
+ if (result.hit) {
186
+ // Left click to break
187
+ if (isMousePressed(0)) {
188
+ const [x, y, z] = result.position;
189
+ setVoxelBlock(x, y, z, BLOCK_TYPES.AIR);
190
+ }
191
+
192
+ // Right click to place
193
+ if (isMousePressed(2)) {
194
+ // Calculate adjacent block position
195
+ const placeX = Math.floor(result.position[0] - Math.sign(lookDir[0]) * 0.5);
196
+ const placeY = Math.floor(result.position[1] - Math.sign(lookDir[1]) * 0.5);
197
+ const placeZ = Math.floor(result.position[2] - Math.sign(lookDir[2]) * 0.5);
198
+
199
+ setVoxelBlock(placeX, placeY, placeZ, BLOCK_TYPES.COBBLESTONE);
200
+ }
201
+ }
202
+ ```
203
+
204
+ ## Collision Detection
205
+
206
+ ### checkVoxelCollision(position, size)
207
+
208
+ Checks if an axis-aligned bounding box collides with any solid blocks.
209
+
210
+ **Parameters:**
211
+
212
+ - `position` - Center position `[x, y, z]`
213
+ - `size` - Half-size of bounding box (radius)
214
+
215
+ **Returns:** `true` if colliding with solid block, `false` otherwise
216
+
217
+ **Example:**
218
+
219
+ ```javascript
220
+ const playerSize = 0.3; // 0.6 block width
221
+ const playerHeight = 1.8; // 1.8 blocks tall
222
+
223
+ // Check if player's feet are on solid ground
224
+ const onGround = checkVoxelCollision([player.pos[0], player.pos[1], player.pos[2]], playerSize);
225
+
226
+ // Check head collision
227
+ const hitCeiling = checkVoxelCollision(
228
+ [player.pos[0], player.pos[1] + playerHeight, player.pos[2]],
229
+ playerSize
230
+ );
231
+
232
+ // Simple physics
233
+ if (onGround && player.vel[1] <= 0) {
234
+ player.vel[1] = 0;
235
+ player.canJump = true;
236
+ }
237
+
238
+ if (hitCeiling && player.vel[1] > 0) {
239
+ player.vel[1] = 0;
240
+ }
241
+ ```
242
+
243
+ ## Structure Generation
244
+
245
+ ### placeVoxelTree(x, y, z)
246
+
247
+ Generates a tree structure at the specified coordinates. Trees consist of wood trunk with leaf canopy.
248
+
249
+ **Parameters:**
250
+
251
+ - `x` - World X coordinate for tree base
252
+ - `y` - World Y coordinate for ground level
253
+ - `z` - World Z coordinate for tree base
254
+
255
+ **Example:**
256
+
257
+ ```javascript
258
+ export function init() {
259
+ // Generate initial world
260
+ updateVoxelWorld(0, 0);
261
+
262
+ // Add trees to landscape
263
+ placeVoxelTree(10, 35, 10);
264
+ placeVoxelTree(20, 33, 15);
265
+ placeVoxelTree(-5, 36, 8);
266
+
267
+ // Cluster of trees
268
+ for (let i = 0; i < 10; i++) {
269
+ const x = Math.random() * 100 - 50;
270
+ const z = Math.random() * 100 - 50;
271
+ const y = getGroundHeight(x, z);
272
+ placeVoxelTree(x, y, z);
273
+ }
274
+ }
275
+ ```
276
+
277
+ **Tree Structure:**
278
+
279
+ - Trunk: 4-6 blocks tall of `BLOCK_TYPES.WOOD`
280
+ - Leaves: Spherical canopy of `BLOCK_TYPES.LEAVES`
281
+ - Automatic variation in size
282
+
283
+ ## Complete Minecraft-Style Game Example
284
+
285
+ ```javascript
286
+ const player = {
287
+ pos: [8, 40, 8],
288
+ vel: [0, 0, 0],
289
+ rot: [0, 0], // yaw, pitch
290
+ onGround: false,
291
+ selectedBlock: BLOCK_TYPES.GRASS,
292
+ };
293
+
294
+ let mouseLocked = false;
295
+
296
+ export function init() {
297
+ // Setup world
298
+ setAmbientLight(0x666666);
299
+ setDirectionalLight([1, 2, 1], 0xffffff, 0.6);
300
+ setFog(0x87ceeb, 80, 200);
301
+
302
+ // Generate terrain
303
+ updateVoxelWorld(player.pos[0], player.pos[2]);
304
+
305
+ // Add trees
306
+ for (let i = 0; i < 20; i++) {
307
+ const x = Math.random() * 200 - 100;
308
+ const z = Math.random() * 200 - 100;
309
+ placeVoxelTree(x, 35, z);
310
+ }
311
+
312
+ // Pointer lock for mouse control
313
+ const canvas = document.getElementById('screen');
314
+ canvas.addEventListener('click', () => {
315
+ if (!mouseLocked) {
316
+ canvas.requestPointerLock();
317
+ }
318
+ });
319
+
320
+ document.addEventListener('pointerlockchange', () => {
321
+ mouseLocked = document.pointerLockElement === canvas;
322
+ });
323
+
324
+ canvas.addEventListener('mousemove', e => {
325
+ if (mouseLocked) {
326
+ player.rot[0] -= e.movementX * 0.002;
327
+ player.rot[1] -= e.movementY * 0.002;
328
+ player.rot[1] = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, player.rot[1]));
329
+ }
330
+ });
331
+ }
332
+
333
+ export function update(dt) {
334
+ if (!mouseLocked) return;
335
+
336
+ // Movement
337
+ const forward = [-Math.sin(player.rot[0]), 0, -Math.cos(player.rot[0])];
338
+ const right = [-Math.sin(player.rot[0] + Math.PI / 2), 0, -Math.cos(player.rot[0] + Math.PI / 2)];
339
+
340
+ const speed = 4.0;
341
+ if (isKeyDown('KeyW')) {
342
+ player.vel[0] += forward[0] * speed * dt;
343
+ player.vel[2] += forward[2] * speed * dt;
344
+ }
345
+ if (isKeyDown('KeyS')) {
346
+ player.vel[0] -= forward[0] * speed * dt;
347
+ player.vel[2] -= forward[2] * speed * dt;
348
+ }
349
+ if (isKeyDown('KeyA')) {
350
+ player.vel[0] += right[0] * speed * dt;
351
+ player.vel[2] += right[2] * speed * dt;
352
+ }
353
+ if (isKeyDown('KeyD')) {
354
+ player.vel[0] -= right[0] * speed * dt;
355
+ player.vel[2] -= right[2] * speed * dt;
356
+ }
357
+
358
+ // Jump
359
+ if (isKeyPressed('Space') && player.onGround) {
360
+ player.vel[1] = 8.0;
361
+ }
362
+
363
+ // Gravity
364
+ player.vel[1] -= 20.0 * dt;
365
+
366
+ // Apply velocity
367
+ player.pos[0] += player.vel[0] * dt;
368
+ player.pos[1] += player.vel[1] * dt;
369
+ player.pos[2] += player.vel[2] * dt;
370
+
371
+ // Collision
372
+ const collision = checkVoxelCollision(player.pos, 0.3);
373
+ if (collision && player.vel[1] <= 0) {
374
+ player.pos[1] = Math.floor(player.pos[1]) + 1;
375
+ player.vel[1] = 0;
376
+ player.onGround = true;
377
+ } else {
378
+ player.onGround = false;
379
+ }
380
+
381
+ // Damping
382
+ player.vel[0] *= 0.8;
383
+ player.vel[2] *= 0.8;
384
+
385
+ // Camera
386
+ setCameraPosition(player.pos[0], player.pos[1] + 1.6, player.pos[2]);
387
+ const lookDir = [
388
+ -Math.sin(player.rot[0]) * Math.cos(player.rot[1]),
389
+ Math.sin(player.rot[1]),
390
+ -Math.cos(player.rot[0]) * Math.cos(player.rot[1]),
391
+ ];
392
+ setCameraLookAt(lookDir);
393
+
394
+ // Block interaction
395
+ const rayOrigin = [player.pos[0], player.pos[1] + 1.6, player.pos[2]];
396
+ const result = raycastVoxelBlock(rayOrigin, lookDir, 10);
397
+
398
+ if (result.hit) {
399
+ const [x, y, z] = result.position;
400
+
401
+ // Break block
402
+ if (isMousePressed(0)) {
403
+ setVoxelBlock(x, y, z, BLOCK_TYPES.AIR);
404
+ }
405
+
406
+ // Place block
407
+ if (isMousePressed(2)) {
408
+ const placeX = x - Math.sign(lookDir[0]);
409
+ const placeY = y - Math.sign(lookDir[1]);
410
+ const placeZ = z - Math.sign(lookDir[2]);
411
+ setVoxelBlock(placeX, placeY, placeZ, player.selectedBlock);
412
+ }
413
+ }
414
+
415
+ // Update world chunks
416
+ if (Math.random() < 0.1) {
417
+ updateVoxelWorld(player.pos[0], player.pos[2]);
418
+ }
419
+
420
+ // Block selection
421
+ for (let i = 1; i <= 9; i++) {
422
+ if (isKeyPressed(i.toString())) {
423
+ player.selectedBlock = i;
424
+ }
425
+ }
426
+ }
427
+
428
+ export function draw() {
429
+ cls();
430
+
431
+ // Draw crosshair
432
+ if (mouseLocked) {
433
+ const cx = 320,
434
+ cy = 180,
435
+ size = 8;
436
+ rectfill(cx - size, cy - 1, cx + size, cy + 1, rgba8(1, 1, 1, 1));
437
+ rectfill(cx - 1, cy - size, cx + 1, cy + size, rgba8(1, 1, 1, 1));
438
+ }
439
+
440
+ // HUD
441
+ print(`FPS: ${Math.round(1 / getDeltaTime())}`, 4, 4, rgba8(1, 1, 1, 1));
442
+ print(
443
+ `Pos: ${Math.floor(player.pos[0])}, ${Math.floor(player.pos[1])}, ${Math.floor(player.pos[2])}`,
444
+ 4,
445
+ 12,
446
+ rgba8(1, 1, 1, 1)
447
+ );
448
+ }
449
+ ```
450
+
451
+ ## Terrain Generation
452
+
453
+ The voxel engine uses **Perlin noise** for realistic terrain with:
454
+
455
+ ### Features:
456
+
457
+ - **Height variation** - Hills and valleys (20-52 blocks high)
458
+ - **Biomes** - Grass, sand, snow based on temperature/moisture
459
+ - **Cave systems** - Underground tunnels and caverns
460
+ - **Water level** - Ocean at Y=30
461
+ - **Bedrock layer** - Indestructible bottom (Y=0)
462
+
463
+ ### Biome Selection:
464
+
465
+ ```javascript
466
+ Temperature > 0.7 → Snow biome
467
+ Moisture < 0.3 → Desert (sand)
468
+ Default → Grass/dirt
469
+ ```
470
+
471
+ ### Layer Structure:
472
+
473
+ ```
474
+ Y=0 → Bedrock (indestructible)
475
+ Y=1-30 → Stone
476
+ Y=31-33 → Dirt
477
+ Y=34 → Surface (grass/sand/snow)
478
+ Y=35-64 → Air (or water below Y=30)
479
+ ```
480
+
481
+ ## Performance Tips
482
+
483
+ ### Chunk Management
484
+
485
+ - **Render distance**: 4 chunks (64 blocks) - adjustable in code
486
+ - **Chunk size**: 16x64x16 blocks per chunk
487
+ - **Auto-unloading**: Distant chunks automatically removed from memory
488
+
489
+ ### Optimization Techniques Used:
490
+
491
+ 1. **Greedy meshing** - Combines adjacent faces to reduce vertices
492
+ 2. **Face culling** - Hidden faces not rendered
493
+ 3. **Chunk dirty flags** - Only rebuild when blocks change
494
+ 4. **BufferGeometry** - GPU-optimized mesh storage
495
+ 5. **Flat shading** - Fast lighting calculation
496
+ 6. **Ambient occlusion** - Per-face brightness variation
497
+
498
+ ### Best Practices:
499
+
500
+ ```javascript
501
+ // ✅ Good - Update chunks occasionally
502
+ if (frameCount % 10 === 0) {
503
+ updateVoxelWorld(playerX, playerZ);
504
+ }
505
+
506
+ // ❌ Bad - Don't update every frame
507
+ export function update(dt) {
508
+ updateVoxelWorld(playerX, playerZ); // Too expensive!
509
+ }
510
+
511
+ // ✅ Good - Batch block changes
512
+ for (let i = 0; i < 100; i++) {
513
+ setVoxelBlock(x + i, y, z, BLOCK_TYPES.STONE);
514
+ }
515
+ // Chunks updated once after loop
516
+
517
+ // ✅ Good - Check collision efficiently
518
+ const onGround = checkVoxelCollision(playerFeetPos, 0.3);
519
+
520
+ // ❌ Bad - Don't check every nearby block manually
521
+ for (let x = -5; x < 5; x++) {
522
+ for (let z = -5; z < 5; z++) {
523
+ if (getVoxelBlock(px + x, py, pz + z) !== BLOCK_TYPES.AIR) {
524
+ // This is way too slow!
525
+ }
526
+ }
527
+ }
528
+ ```
529
+
530
+ ## Common Patterns
531
+
532
+ ### Finding Ground Height
533
+
534
+ ```javascript
535
+ function getGroundHeight(x, z) {
536
+ for (let y = 63; y >= 0; y--) {
537
+ const block = getVoxelBlock(x, y, z);
538
+ if (block !== BLOCK_TYPES.AIR && block !== BLOCK_TYPES.WATER) {
539
+ return y + 1;
540
+ }
541
+ }
542
+ return 0;
543
+ }
544
+ ```
545
+
546
+ ### Building Structures
547
+
548
+ ```javascript
549
+ // House
550
+ function buildHouse(x, y, z) {
551
+ // Floor
552
+ for (let dx = 0; dx < 8; dx++) {
553
+ for (let dz = 0; dz < 8; dz++) {
554
+ setVoxelBlock(x + dx, y, z + dz, BLOCK_TYPES.PLANKS);
555
+ }
556
+ }
557
+
558
+ // Walls
559
+ for (let dy = 1; dy < 5; dy++) {
560
+ for (let dx = 0; dx < 8; dx++) {
561
+ setVoxelBlock(x + dx, y + dy, z, BLOCK_TYPES.WOOD);
562
+ setVoxelBlock(x + dx, y + dy, z + 7, BLOCK_TYPES.WOOD);
563
+ }
564
+ for (let dz = 0; dz < 8; dz++) {
565
+ setVoxelBlock(x, y + dy, z + dz, BLOCK_TYPES.WOOD);
566
+ setVoxelBlock(x + 7, y + dy, z + dz, BLOCK_TYPES.WOOD);
567
+ }
568
+ }
569
+
570
+ // Roof
571
+ for (let dx = 0; dx < 8; dx++) {
572
+ for (let dz = 0; dz < 8; dz++) {
573
+ setVoxelBlock(x + dx, y + 5, z + dz, BLOCK_TYPES.BRICK);
574
+ }
575
+ }
576
+
577
+ // Door
578
+ setVoxelBlock(x + 3, y + 1, z, BLOCK_TYPES.AIR);
579
+ setVoxelBlock(x + 3, y + 2, z, BLOCK_TYPES.AIR);
580
+ }
581
+ ```
582
+
583
+ ### Mining System
584
+
585
+ ```javascript
586
+ let mining = false;
587
+ let miningProgress = 0;
588
+ let miningBlock = null;
589
+
590
+ function updateMining(dt) {
591
+ const result = raycastVoxelBlock(eyePos, lookDir, 10);
592
+
593
+ if (result.hit && isMouseDown(0)) {
594
+ // Same block
595
+ if (
596
+ miningBlock &&
597
+ miningBlock[0] === result.position[0] &&
598
+ miningBlock[1] === result.position[1] &&
599
+ miningBlock[2] === result.position[2]
600
+ ) {
601
+ miningProgress += dt;
602
+
603
+ // Break after 1 second
604
+ if (miningProgress >= 1.0) {
605
+ const [x, y, z] = miningBlock;
606
+ setVoxelBlock(x, y, z, BLOCK_TYPES.AIR);
607
+ miningProgress = 0;
608
+ miningBlock = null;
609
+ }
610
+ } else {
611
+ // New block
612
+ miningBlock = result.position;
613
+ miningProgress = 0;
614
+ }
615
+ } else {
616
+ miningProgress = 0;
617
+ miningBlock = null;
618
+ }
619
+ }
620
+ ```
621
+
622
+ ## Troubleshooting
623
+
624
+ ### Blocks Not Appearing
625
+
626
+ - Call `updateVoxelWorld()` after placing blocks
627
+ - Check if coordinates are within valid range (Y: 0-63)
628
+ - Verify chunks are loading (check console logs)
629
+
630
+ ### Performance Issues
631
+
632
+ - Reduce render distance in code (change `RENDER_DISTANCE`)
633
+ - Update chunks less frequently
634
+ - Limit block placement/breaking rate
635
+
636
+ ### Collision Not Working
637
+
638
+ - Ensure player size matches collision box
639
+ - Check Y coordinate (height above ground)
640
+ - Verify blocks are solid (not AIR or WATER)
641
+
642
+ ### Raycasting Missing Blocks
643
+
644
+ - Increase ray step precision (reduce step size)
645
+ - Check max distance parameter
646
+ - Ensure camera position is correct
647
+
648
+ ## API Reference Summary
649
+
650
+ | Function | Description | Parameters |
651
+ | -------------------------------------- | ---------------------------------- | --------------------------- |
652
+ | `updateVoxelWorld(x, z)` | Load/update chunks around position | x, z: world coords |
653
+ | `getVoxelBlock(x, y, z)` | Get block type at position | x, y, z: world coords |
654
+ | `setVoxelBlock(x, y, z, type)` | Place/remove block | coords + block type |
655
+ | `raycastVoxelBlock(origin, dir, dist)` | Find block along ray | origin, direction, distance |
656
+ | `checkVoxelCollision(pos, size)` | Check AABB collision | position, half-size |
657
+ | `placeVoxelTree(x, y, z)` | Generate tree structure | x, y, z: base position |
658
+ | `BLOCK_TYPES.*` | Block type constants | 15 types (AIR to BEDROCK) |
659
+
660
+ ---
661
+
662
+ **Ready to build your Minecraft clone!** Check out the complete example in `examples/minecraft-demo/` for a fully playable game with all features implemented.