@woosh/meep-engine 3.60.4 → 3.60.5

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 (379) hide show
  1. package/CHANGELOG.md +2602 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/MIGRATION_2_TO_3.md +136 -0
  4. package/SECURITY.md +4 -0
  5. package/editor/EditorCameraNavigation.d.ts +2 -1
  6. package/editor/EditorCameraNavigation.d.ts.map +1 -1
  7. package/editor/EditorCameraNavigation.js +51 -57
  8. package/package.json +6 -2
  9. package/src/engine/EngineHarness.d.ts +3 -9
  10. package/src/engine/EngineHarness.d.ts.map +1 -1
  11. package/src/engine/EngineHarness.js +6 -8
  12. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  13. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  14. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  15. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  16. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  17. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  18. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  19. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  21. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  22. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  27. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  28. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/water/Water.js +8 -0
  30. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  31. package/src/engine/graphics3/WaterSystem.js +731 -734
  32. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  33. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  34. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  35. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  36. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  37. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  38. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  39. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  40. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  41. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  42. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  43. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  44. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  45. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  46. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  47. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  48. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  49. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  50. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  51. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  52. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  53. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  54. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  55. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  56. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  57. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  58. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/shade/playground/water_refraction/README.md +5 -6
  61. package/src/shade/playground/water_refraction/index.html +1 -1
  62. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  63. package/src/shade/renderer/Renderer.js +7 -5
  64. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  67. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  68. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  69. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  70. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  71. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  72. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +2 -2
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +2 -2
  74. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +2 -1
  75. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +18 -1
  77. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  78. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  80. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  81. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  82. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  83. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  84. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  85. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  86. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  87. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +5 -5
  88. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  89. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +10 -10
  90. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  91. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  92. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  93. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  94. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  95. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  96. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  98. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  99. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  100. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  101. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  102. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  103. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  104. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  105. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  106. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  107. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  108. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  109. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  110. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  111. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  112. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  113. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  114. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  115. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  116. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  117. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  118. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  119. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  120. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  121. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  122. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  123. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  124. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  125. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  126. package/src/shade/renderer/material/GPUMaterialManager.d.ts +7 -0
  127. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  128. package/src/shade/renderer/material/GPUMaterialManager.js +11 -0
  129. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  130. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  131. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  132. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  133. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  134. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  135. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  136. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  137. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  138. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  139. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  140. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  141. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  142. package/src/shade/renderer/water/shader_water.js +22 -13
  143. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  144. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  145. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  146. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  147. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  148. package/editor/REWORK_PLAN_2026_08.md +0 -692
  149. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  150. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  151. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  152. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  153. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  154. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  155. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  156. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  157. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  158. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  159. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  160. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  161. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  162. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  163. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  164. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  165. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  166. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  167. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  168. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  169. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  170. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  171. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  172. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  173. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  174. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  175. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  176. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  177. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  178. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  179. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  180. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  181. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  182. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  183. package/src/REVIEW_2026_08_06/generation.md +0 -176
  184. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  185. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  186. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  187. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  188. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  189. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  190. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  191. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  192. package/src/REVIEW_2026_08_06/view.md +0 -667
  193. package/src/REVIEW_2026_08_06.md +0 -610
  194. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  195. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  196. package/src/core/bvh8/NOTES.md +0 -63
  197. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  198. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  199. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  200. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  201. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  202. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  203. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  204. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  205. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  206. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  207. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  208. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  209. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  210. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  211. package/src/engine/REVIEW_2026_07_03.md +0 -211
  212. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  213. package/src/engine/control/first-person/DESIGN.md +0 -658
  214. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  215. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  216. package/src/engine/control/first-person/TODO.md +0 -160
  217. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  218. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  219. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  220. package/src/engine/ecs/ik/PLAN.md +0 -179
  221. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  222. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  223. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  224. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  225. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  226. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  227. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  228. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  229. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  230. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  231. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  232. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  233. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  234. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  235. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  236. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  237. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  238. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  239. package/src/engine/physics/cloth/PLAN.md +0 -3056
  240. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  241. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  242. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  243. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  244. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  245. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  246. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  247. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  248. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  249. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  250. package/src/format/image/avif/DECISIONS.md +0 -545
  251. package/src/format/image/jpeg/NOTES.md +0 -3
  252. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  253. package/src/generation/COORDINATES.md +0 -54
  254. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  255. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  256. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  257. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  258. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  259. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  260. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  261. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  262. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  263. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  264. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  265. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  266. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  267. package/src/shade/RENDERER_CONTRACT.md +0 -697
  268. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  269. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  270. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  271. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  272. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  273. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  274. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  275. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  276. package/src/shade/renderer/NOTES.md +0 -78
  277. package/src/shade/renderer/PLAN.md +0 -8
  278. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  279. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  280. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  281. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  282. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  283. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  284. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  285. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  286. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  287. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  288. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  289. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  290. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  291. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  292. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  293. package/src/shade/renderer/camera/orbital/README.md +0 -81
  294. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  295. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  296. package/src/shade/renderer/camera/orbital/index.js +0 -9
  297. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  298. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  299. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  300. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  301. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  302. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  303. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  304. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  305. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  306. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  307. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  308. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  309. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  310. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  311. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  312. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  313. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  314. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  315. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  316. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  317. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  318. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  319. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  320. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  321. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  322. package/src/shade/renderer/hiz/NOTES.md +0 -3
  323. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  324. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  325. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  326. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  327. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  328. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  329. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  330. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  331. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  332. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  333. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  334. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  335. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  336. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  337. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  338. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  339. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  340. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  341. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  342. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  343. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  344. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  345. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  346. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  347. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  348. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  349. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  350. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  351. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  352. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  353. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  354. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  355. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  356. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  357. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  358. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  359. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  360. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  361. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  362. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  363. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  364. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  365. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  366. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  367. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  368. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  369. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  370. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  371. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  372. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  373. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  374. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  375. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  376. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  377. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  378. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  379. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,364 +0,0 @@
1
- # Message transport
2
-
3
- Status: LANDED, design record. Planned 2026-10-15, revised after two adversarial reviews of the plan (§9),
4
- implemented, then reviewed adversarially again (§10). Replaced `transport/Channel.js`, `transport/fragments/*`
5
- and `transport/ReliableCommandPipeline.js` with one connection layer that carries messages of any size, for
6
- every message type the engine sends and for user messages.
7
-
8
- ## 1. Why
9
-
10
- All engine traffic leaves `NetworkPeer` through one function, `#send_to_peer`. A message was one datagram, or
11
- it was cut into fragments by `fragment_send.js`. That path had five independent ceilings, all measured
12
- (2026-10-14, probes `zz_probe_join` / `zz_probe_wire`):
13
-
14
- | Ceiling | Effect |
15
- |---|---|
16
- | `FragmentAssembler.max_message_size` 65,536 B | larger messages dropped silently: a world of 2,990 one-component entities could never be joined |
17
- | uint8 chunk count, 255 × 1,186 B ≈ 302 KB | send throws; for INITIAL_SYNC on every tick forever, for a 20k-entity spawn frame every tick in `closeFixedStep` |
18
- | `Channel` acks: latest + 32-bit bitfield, only on packets the receiver sends anyway | a message of 34+ fragments sent in one tick is never fully acked; its fragments age out as lost though they arrived (one spawn frame re-sent 32×) |
19
- | NACK / retention timers on `performance.now()` | repair ignores the simulation clock; a spec ticking faster than wall time gets no repair |
20
- | no pacing | a 447 KB snapshot leaves in one tick |
21
-
22
- Steady-state wire cost was also poor: host → client sent `2 + owned entities` datagrams per tick (each
23
- AUTH_STATE, TIME_DILATION and FRAME_MARKER its own datagram with a 9 B channel header). 16 owned entities: 17
24
- datagrams, 346 B payload, 822 B on the wire with UDP/IPv4 headers.
25
-
26
- **Measured after** (same probe, 16 owned entities): host → client 1 datagram, 237 B payload, 265 B on the wire
27
- per tick (3.1× less); client → host 2 datagrams → 1. A 5,000-entity world joins over Loopback; 20,000 joins
28
- paced, including while it grows by 1,000 entities a tick (`initial_sync_large_world.spec.js`).
29
-
30
- ## 2. Requirements
31
-
32
- 1. Any message type, engine or user, up to a configured size, survives loss and arrives intact.
33
- 2. Receiver memory per connection is bounded by configuration, never by what a peer claims; so is the
34
- sender's (queues are capped; a join's pages are built only as the window frees). So is receiver time (§3.9).
35
- 3. What a peer can make the sender do is bounded by what the sender chose to send (README, "Connecting").
36
- 4. One datagram per peer per tick in steady state; per-message overhead of a few bytes.
37
- 5. No per-packet or per-message allocation in steady state (buffers grow to a high-watermark and stay; §4).
38
- 6. Every timer runs on a clock the caller supplies; the network stack never reads wall time itself.
39
- 7. Large transfers never delay latency-critical traffic.
40
- 8. The action stream keeps its contract: confirm a slice only when every packet carrying it is acked, abandon
41
- it when any is lost (never credit what was not delivered).
42
-
43
- ## 3. Design
44
-
45
- One class per peer, `Connection` (`transport/connection/`), used by `NetworkPeer` in place of `Channel` +
46
- fragments + `ReliableCommandPipeline`. A message is still `[NetworkPacketType byte][payload]`; `NetworkPeer`'s
47
- dispatch is unchanged except that FRAGMENT and NACK_FRAGMENT are gone, RELIABLE_COMMAND lost its logical seq,
48
- INITIAL_SYNC is a page, and TIME_DILATION carries the host's frame.
49
-
50
- ### 3.1 Packet layer (after QUIC, RFC 9000 §12–13, §17.1, §19.3; RFC 9002)
51
-
52
- ```
53
- u8 flags bit0 ACK present, bit1 4-byte packet number, bits 4–7 protocol version (1)
54
- u16|u32 packet number truncated; the full number increases monotonically and is never reused
55
- [ACK] varint largest acknowledged (full number)
56
- varint ack delay (8 µs units)
57
- varint additional range count (≤ 63)
58
- varint first range
59
- count × (varint gap, varint range length)
60
- frames to the end of the datagram
61
- ```
62
-
63
- - **Packet numbers are never reused**; a retransmission is new frames in a new packet. Encoded in 2 bytes while
64
- `number − largest acknowledged < 16,384`, else 4 (RFC 9000 §17.1), expanded by Appendix A.3.
65
- - **Acks are ranges**: one ACK covers any burst. The receiver tracks at most `max_ack_ranges` (32, at most 64);
66
- everything below its floor is dropped as a duplicate or too old. The floor rises when an ACK frame of its own
67
- is acknowledged (§13.2.4) or when the oldest range is pushed out by the cap. A side that sends only ACKs adds
68
- a PING once per RTT so that it ever hears which ACKs arrived. The ACK takes at most half a datagram; ranges
69
- that do not fit wait for a later ACK.
70
- - **Loss** (RFC 9002 §6.1): packet threshold 3, time threshold `9/8 × max(srtt, latest_rtt)`, floored at the
71
- timer granularity. **Lost means not confirmed**, as in QUIC: a packet that arrived but whose acknowledgement
72
- never got through — every ACK carrying it lost, or crowded out by newer ranges past `max_ack_ranges` holes —
73
- is reported lost. The action stream's contract (requirement 8) is exactly this: never credit the unconfirmed.
74
- - **Probe timeout** (§6.2) doubles per expiry. On expiry the oldest outstanding packet whose reliable bytes are
75
- still unacknowledged has them queued again (never declared lost); a packet whose bytes were all acknowledged
76
- by another — the one it re-sent, an earlier probe — is passed over; with none, a PING. A probe may pass an
77
- empty token bucket once.
78
- - **Notices are deferred.** `onMessageAcked` / `onMessageLost` are told after the walk that settled them —
79
- the end of a flush, or of an ACK's processing — never in the middle of one. A handler may send, flush
80
- (which tells the rest, in order) or dispose (after which nothing more is told).
81
- - **RTT** from ack delay, clamped to `max_ack_delay`; Karn-free since numbers are never reused.
82
- - **Timer granularity and `max_ack_delay` are one tick.** All sends and receives happen at fixed-step
83
- boundaries, so nothing finer is real.
84
- - **Validation before action.** A datagram is parsed whole before any of it is acted on; a malformed one is
85
- dropped unacknowledged (`onMalformedDatagram`). An ACK naming a packet never sent is a protocol error (§3.9).
86
- - **Transports that are already reliable** (`transport.reliable`: WebSocket) never declare loss and never
87
- probe: on TCP a re-send queues behind the original and makes a stall worse. Loopback is *not* reliable: its
88
- `drop_next` loses packets, and the specs need the loss path.
89
- - **Datagram size per transport**: `Transport.max_datagram_bytes`, in [64, 16,383]. 1,200 by default; WebRTC
90
- 1,150 so a full datagram fits one SCTP packet (§8); WebTransport reads `datagrams.maxDatagramSize` once.
91
-
92
- ### 3.2 Messages
93
-
94
- ```
95
- 0x01 MESSAGE varint length, bytes unreliable, at most one datagram
96
- 0x02 PING asks for an ACK
97
- 0x10|lane varint offset, varint length, bytes STREAM, reliable lane 0..3
98
- ```
99
-
100
- **Unreliable messages fit one datagram** (1,192 B at the default size). There is no segmented unreliable tier:
101
- a segmented message evicted from reassembly after its packets were acked would be credited by the action
102
- stream without being applied — exactly the old fragment-eviction defect. Larger is refused (throws); a caller
103
- with more goes reliable. Each carries an optional token, and the connection reports `acked(token)` or
104
- `lost(token)` with its packet, exactly once. When the ACK opening a flush leaves too little room for the
105
- largest message, the ACK goes alone.
106
-
107
- **Reliable lanes**, after QUIC streams: each lane is an ordered byte stream of `[varint length][bytes]`.
108
- - Sender: the message is copied once into the lane's buffer; segments are ranges of it; each packet records the
109
- ranges it carried; a lost range is queued again minus anything acknowledged since. Bytes are released when
110
- room is needed, not per ack (a large message's tail is not slid down once per packet).
111
- - **Flow control without frames**: a sender never sends a byte at or past `acked_prefix + receive_window`. The
112
- receiver delivers each message the moment its bytes are contiguous, so its contiguous point is never behind
113
- the sender's acked prefix, and what it holds is at most `max_message_bytes + receive_window`. This holds only
114
- if both ends use the same `max_message_bytes` and `receive_window_bytes`; a segment past the receiver's bound,
115
- a message declaring more than its maximum, or more holes than an honest sender makes (§3.9) is a **protocol
116
- error that ends the connection** (QUIC's FLOW_CONTROL_ERROR), never a silent drop of acknowledged data.
117
- - **Queue cap**: `max_queued_bytes` per lane; `send_reliable` throws past it.
118
- - **Delivery mark**: `send_reliable` returns the offset past the message; `is_delivered(lane, mark)` asks
119
- whether the acked prefix has reached it.
120
-
121
- Lanes, in scheduling order:
122
-
123
- | Lane | Carries | Paced |
124
- |---|---|---|
125
- | CONTROL | RESUME_HELLO/ACCEPT/REJECT, DISCONNECT, RECOVERY_REQUEST — engine-only, one datagram each | no |
126
- | (unreliable) | ACTION_STREAM slices, AUTH_STATE, TIME_DILATION, FRAME_MARKER | no |
127
- | FRAMES | action-stream frames larger than a datagram | no — the stream waits on them |
128
- | USER | `send_reliable_command`, up to `max_message_bytes` | yes |
129
- | BULK | INITIAL_SYNC pages, STATE_BURST | yes |
130
-
131
- ### 3.3 Scheduler
132
-
133
- Every message for a peer is queued; `flush` sends them packed into as few datagrams as fit, in the order above,
134
- the ACK in the first datagram. A token bucket per connection at `send_rate_bytes_per_second` (default 256 KiB/s)
135
- paces USER and BULK; unpaced traffic is counted against it and may take it at most one burst below zero. The
136
- burst is two ticks of rate (at least two datagrams). Paced lanes always get at least one datagram a flush, so a
137
- peer that owns many entities cannot starve a join. Congestion control, when built (`CONGESTION_CONTROL.md`),
138
- sets the rate; transport backpressure (`bufferedAmount`) is a follow-up.
139
-
140
- **When things go out.** `NetworkPeer.send_*` only queue. `NetworkPeer.send_queued()` flushes every connection.
141
- `NetworkPeer.end_tick`, `ServerAuthoritativeServer.end_tick` (after `onTickComplete`) and
142
- `ServerAuthoritativeClient.end_tick` call it last, so one tick's traffic — the action stream, AUTH_STATE,
143
- TIME_DILATION, join pages; the client's FRAME_MARKER, queued before `end_tick` — leaves in one flush. A send
144
- outside a tick is flushed where it is made: RESUME_HELLO by `connect()`, a kick's last word by the kick.
145
- `flush_outbound` only queues.
146
-
147
- **Closing.** `disconnect_peer` never sends. An explicit close (`drop_peer`, `disconnect`, a kick) calls
148
- `NetworkPeer.flush_peer(id)` after queueing DISCONNECT and tears down in `finally`: one best-effort datagram.
149
- A transport that has already died is never flushed. Teardown from inside a connection's own dispatch is safe:
150
- the receive loop stops at the first message after disposal.
151
-
152
- ### 3.4 Clock
153
-
154
- `NetworkPeer` takes a required `clock: () => number` (ms) and `tick_period_ms`. `NetworkSession` passes its own
155
- `#clock_ms`, the render-paced clock that already drives timeouts, grace and reconnects: one clock, and the fixed
156
- steps of one update all see the same time, so a burst of catch-up steps cannot age packets whose acks could not
157
- have arrived.
158
-
159
- ### 3.5 What moved where
160
-
161
- | Message | Before | After |
162
- |---|---|---|
163
- | ACTION_STREAM slice ≤ datagram | own datagram + notice | unreliable message + notice, coalesced |
164
- | ACTION_STREAM frame > datagram | fragments, ≤ 64 KiB, 33-window | FRAMES, reliable, once (§3.6) |
165
- | AUTH_STATE, TIME_DILATION, FRAME_MARKER | own datagram each | unreliable, coalesced; AUTH_STATE > datagram throws |
166
- | RECOVERY_REQUEST, RESUME_*, DISCONNECT | unreliable datagram | CONTROL |
167
- | STATE_BURST | fragments | BULK |
168
- | INITIAL_SYNC | one message ≤ 64 KiB, sent twice | lazily built pages on BULK, catch-up rounds, then FINAL (§3.7) |
169
- | RELIABLE_COMMAND | `ReliableCommandPipeline`, ≤ 1,178 B | USER, ≤ `max_message_bytes` |
170
-
171
- ### 3.6 Oversized action-stream frames
172
-
173
- A frame whose group does not fit one datagram goes on FRAMES, unpaced, once, keeping the head flag it was
174
- packed with. While it is in flight the pack skips it and sends what follows as further slices, which the
175
- receiver holds until it lands; it does not stall the stream. It is credited when delivered, like any slice,
176
- through `#credit_confirmed`. Unpaced because the action stream cannot outlast the 32-frame ring: a frame that
177
- takes longer to deliver than the ring holds loses the frames after it.
178
-
179
- A frame larger than `max_message_bytes` can never be delivered. Once it is the pack start it is given up and
180
- said so (`NetworkPeer.onFrameTooLarge(peer_id, frame_start, frame_end, bytes)`), credited, and the stream goes
181
- on behind it — never a throw, which would stop the tick for every peer.
182
-
183
- ### 3.7 Joining a world of any size
184
-
185
- Host, per joining peer (`orchestrator/HostJoin.js`):
186
- 1. **Hold** the peer's action stream (`hold_outbound`); skip its AUTH_STATE.
187
- 2. **First round.** At the first tick, collect the networked entities. If the whole world fits
188
- `JOIN_FINAL_ROUND_BYTES` (256 KiB) and the lane's room, it goes in that tick and the round is the last:
189
- every entity is at the same frame. Otherwise pages of whole entities (`JOIN_PAGE_BYTES`, 16 KiB; a bigger
190
- entity is a page by itself) are built only as BULK's window (128 KiB for a join) frees, each at the current
191
- frame, noting each entity's frame sent. Host memory per joiner: the window plus 12 bytes per entity (its
192
- frame sent, and its place in the list).
193
- 3. **Catch-up rounds.** When every page is delivered, compare each networked entity's last-changed frame
194
- (`NetworkPeer.last_changed_frame`, stamped for everything its executor executes or records — a
195
- direct write reported with `net_mutate_component` included; a write nobody reports is not a
196
- change the join can know of) with the frame its state
197
- was sent; entities changed since, or created since, go out as a round at the current frame. A catch-up
198
- round always tries to finish in its tick, with what BULK may still hold (`max_queued_bytes − unacked −
199
- max_message_bytes`) as its budget: what changed while a world went out is a fraction of it, and a round
200
- that may only page would never shrink for a world that changes faster than a tick's budget.
201
- 4. **Release.** A round that finishes in its tick leaves the client with the whole world at that frame D: every
202
- entity it carries is at D, every entity it leaves out unchanged since its state went out. The FINAL page
203
- (frame D) goes after it, and the peer's stream is released from D + 1 (still in the ring — the next frame).
204
- The join is over once FINAL is *delivered*: until then a peer that drops holds part of a world and is synced
205
- afresh rather than resumed.
206
- 5. **Bounded.** At most `JOIN_MAX_ROUNDS` (8) rounds; a join that has not converged is dropped
207
- (`join_did_not_converge`). Pages are only built as the window frees, so a peer that never acknowledges costs
208
- the window and nothing else.
209
-
210
- Client:
211
- - From `connect()` until its binding's answer is whole, the client **holds inbound** action stream and
212
- AUTH_STATE (`hold_inbound`): a stream that overtakes the pages is about a world the client does not hold yet.
213
- Bounded by `max_queued_bytes`; past it the connection is broken (§3.9) and the client joins again.
214
- - The FIRST page issues the token, seeks the frame counter, clears prediction state and forgets the timeline,
215
- and puts the binding in **Syncing**, which counts as the binding's answer: a later RESUME_ACCEPT/REJECT is
216
- stale, the reconnect ladder stops.
217
- - Each page is applied as it lands (creating entities as INITIAL_SYNC did).
218
- - FINAL seeks again, repeats the clears and `forget_timeline` (prediction ran on a partial world meanwhile),
219
- sets the world start frame, releases outbound, and makes the binding **Synced**. The held inbound is applied
220
- once the step's inbound is done (not inside the page's dispatch, which shares the receive buffer), then
221
- `NetworkSession.onSynced` fires. RESUME_ACCEPT releases the hold the same way.
222
- - **Seeking.** A page's frame can be old when it lands — a late FINAL — so the client seeks to
223
- `max(page frame, host frame seen) + 1 + depth`, where the host's frame comes with every TIME_DILATION.
224
-
225
- ### 3.8 Deleted
226
-
227
- `Channel.js`, `ReliableCommandPipeline.js`, `fragments/*`, FRAGMENT / NACK_FRAGMENT, `NetworkPeer.channel_for`
228
- (now `connection_for`), `#pending_initial_sync`'s resend count. Hard break, no shims.
229
-
230
- ### 3.9 Trust, and a connection that breaks
231
-
232
- The connection does not authenticate datagrams; its transport delivers only the peer's. WebRTC (DTLS) and
233
- WebTransport / WebSocket (TLS) do; `NodeUDPTransport` drops datagrams from any source but its remote (by port
234
- alone when the remote is a host name); Loopback and Simulated are in-process. Before this was stated, one stray
235
- datagram numbered ahead of the peer's wedged a connection for good: the receiver acknowledged it, and the
236
- sender dropped every datagram carrying that ACK, silently (measured: 0 of 300 messages through, for a stray
237
- 1,000 ahead or 2^30 ahead).
238
-
239
- `Connection.onProtocolError` says the connection is no longer whole:
240
- - a reliable lane broke its limits (past the window, a message over `max_message_bytes`, a bad length);
241
- - more than `max(1,024, window / 256)` holes held out of order on a lane: an honest sender's holes are packets
242
- it lost and has not re-sent, a few hundred at most in a 256 KiB window, while a peer sending one-byte
243
- segments two bytes apart had the receiver spend 46 ms a datagram at 512k ranges (measured; now refused after
244
- 6 datagrams, the worst taking 1.5 ms; ranges are added by binary search);
245
- - the peer acknowledged a packet this side never sent: it took in a datagram that was not ours.
246
-
247
- `NetworkPeer.onProtocolError` adds the client's inbound hold overflowing (§3.7). `NetworkSession` handles
248
- every one as a dropped transport and closes the transport so the other end hears of it at once: on the host
249
- the peer goes into the grace window; on the client the reconnect ladder resumes on a new connection. A stray
250
- datagram on either side now costs a resume (the specs allow 30 ticks), where it cost the connection.
251
-
252
- ## 4. Allocation and copies
253
-
254
- - Outbound: unreliable bytes are copied once into a staging buffer, reliable bytes once into the lane buffer, and
255
- from either straight into the datagram. The transport's own copy is the last.
256
- - Inbound: a datagram is parsed in place; an unreliable message is dispatched as a view into it; stream bytes are
257
- copied once into the lane's receive buffer and dispatched as a view.
258
- - Per-packet state is struct-of-arrays (packet table, record ring, notice queue) grown to a high-watermark.
259
- - `NetworkPeer`'s per-slice `PendingAck` objects are a typed-array pool keyed by token (`PendingSlices`).
260
- - Copies go through `bytes_copy`: a loop up to 64 bytes, `set` over a `subarray` view past that. Measured (Node
261
- 22): the loop costs ~1.2 ns a byte, the view 50–70 ns flat, so a loop for all sizes made 1 KB copies 20×
262
- slower. Two connections exchanging ten tokened messages a tick plus ACKs, 200k ticks: with `subarray` on every
263
- copy, 236 scavenges at 100 B messages; now 13 at 20 B, 212 at 100 B and 226 at 1,000 B, where each copy is one
264
- short-lived view.
265
-
266
- ## 5. Phases
267
-
268
- All landed: **P1** Connection; **P2** NetworkPeer on Connection, old layers deleted; **P3** oversized frames,
269
- the join, resume/disconnect paths, forest specs; **P4** README "Connecting", the packet table, this record.
270
-
271
- ## 6. Defaults
272
-
273
- | Option | Default | Why |
274
- |---|---|---|
275
- | `send_rate_bytes_per_second` | 262,144 | GNS's default clamp; a 447 KB join in ~1.8 s |
276
- | `max_message_bytes` | 1 MiB | largest USER/BULK/FRAMES message; pages are far smaller |
277
- | `receive_window_bytes` | 256 KiB | ≥ rate × 1 s RTT, so the window never limits the paced rate |
278
- | `max_queued_bytes` | 4 MiB per lane | a lane this far behind is a peer that is gone |
279
- | `max_ack_ranges` | 32 (≤ 64) | QUIC implementations keep a few dozen |
280
- | `JOIN_PAGE_BYTES` | 16 KiB | small enough that a page is one tick of rate |
281
- | `JOIN_FINAL_ROUND_BYTES` | 256 KiB | a first round this size finishes in one tick |
282
- | `JOIN_MAX_ROUNDS` | 8 | a join that needs more is a world changing faster than a peer can be sent it |
283
-
284
- ## 7. Not in scope
285
-
286
- Congestion control and transport backpressure; encryption, handshakes and anti-spoofing tokens (§3.9 states
287
- what is assumed of transports); level-baseline identity; the open action-stream issues in
288
- `netcode-open-defects` (silent watermark skip at `max_packets_per_tick = 1`, silent loss past the ring floor).
289
-
290
- ## 8. Open
291
-
292
- Stated, not measured:
293
- - A client that spawns networked entities locally *during* a join can take a network id a later page carries.
294
- Clients pre-build pools before connecting (GAP-038); spawning mid-join is not guarded.
295
- - The WebRTC datagram size (1,150) is from Chrome's source as remembered, not a device measurement.
296
- - A stray from the remote's own address and port — a previous connection's packet on a reused socket pair — is
297
- not filtered by `NodeUDPTransport`; it costs a resume (§3.9), and a lower-numbered one can mark a lost packet
298
- acknowledged. A connection id would close it.
299
-
300
- From the implementation review, kept open (§10):
301
- - **I5** An oversized non-head frame behind a frame lost past the ring floor is never applied while the stream
302
- stays quiet. The same class as the ring-floor loss in §7.
303
- - **I7** A tokenless reconnect after an incomplete join is refused (NoSessionToken). Tokenless claims are
304
- refused on purpose: they are what an id-squatter looks like.
305
-
306
- Measured in passing: 1,500 entities created a tick outrun the action stream itself (the forest spec runs 1,000);
307
- not a join defect.
308
-
309
- ## 9. Plan review dispositions
310
-
311
- Protocol review (R1) and integration review (R2) of the plan, 2026-10-15.
312
-
313
- | # | Finding | Disposition |
314
- |---|---|---|
315
- | R1.1, R2.8 | segmented unreliable message evicted after its packets were acked is credited | **removed the tier**: unreliable ≤ one datagram |
316
- | R1.2 | 16-bit packet numbers wrap under a silent peer; ring overwrites live entries | 2/4-byte encoding by distance; packet table grows, never wraps; ACK of an unsent number refused (now a protocol error, §3.9) |
317
- | R1.3, R2.13 | steps × period clock: catch-up steps fake losses; RTT quantised | session `#clock_ms`; granularity and `max_ack_delay` one tick |
318
- | R1.4 | probe timeout without backoff, behind the bucket | doubles per expiry; one probe passes an empty bucket; never declares loss |
319
- | R1.5 | frameless flow control assumes matching config | violation is a connection-ending protocol error, documented; no silent drop |
320
- | R1.6, R2.10 | unbounded queues; unpaced traffic starves BULK; user messages unpaced | per-lane queue cap; bucket floor; paced lanes get ≥ 1 datagram a flush; USER lane paced |
321
- | R1.7, R2.3 | frozen snapshot = world-sized memory per joiner; ledger missing, retention-bound, empty-burst deadlock | **lazy pages + per-entity change stamps**; no ledger; catch-up as pages; FINAL page even when nothing changed |
322
- | R1.8 | one code path misbehaves on TCP | reliable transports never declare loss or probe |
323
- | R1.9 | 1,200 B datagram = two SCTP packets on WebRTC | WebRTC declares 1,150 (§8) |
324
- | R1.10, R2.2 | oversized frame behind BULK; stall past ring; re-pack re-sends it | FRAMES lane ahead of paced lanes, unpaced; skipped while in flight |
325
- | R1.11 | ack-only side can never prune ranges | PING once per RTT in ack-only packets; floor rule stated |
326
- | R1.12 | ACK frames unvalidated | range count ≤ 63, numbers < next sent, delay clamped |
327
- | R1.13 | no version | 4-bit version in every datagram; anti-spoofing out of scope (§7) |
328
- | R1.14 | burst of 22 datagrams | burst = two ticks of rate |
329
- | R1.15 | exactly one outcome per packet | first wins; a late ACK of a lost packet is ignored |
330
- | R2.1 | paged join is not the binding's answer; ladder restarts it; stale reject acted on | **Syncing** binding state on page 0 |
331
- | R2.4 | page-by-page apply breaks clear-on-sync | clears and `forget_timeline` repeated at FINAL; host holds AUTH_STATE until release |
332
- | R2.5 | id collision from client spawns mid-join | stated (§8) |
333
- | R2.6 | flush placement; spec breaks | single flush at the end of each `end_tick`; FRAME_MARKER queued before it |
334
- | R2.7 | flushing in `disconnect_peer` sends on dead transports | `disconnect_peer` never sends; explicit `flush_peer` on explicit close only |
335
- | R2.9 | peer withholds BULK acks to make the host re-serialize forever | at most 8 rounds; pages only as the window frees |
336
- | R2.11 | resume accepted over a half-applied world | incomplete join → StaleFrame, fresh sync |
337
- | R2.12 | release checked outside the flush that applies it | release from D + 1, the next frame, by construction |
338
- | R2.14 | forest spec budget too small for the default rate | spec budget states the rate |
339
- | R2.15 | README contradictions | P4 |
340
-
341
- ## 10. Implementation review dispositions
342
-
343
- Connection review (C) and peer/session integration review (I) of the implementation, 2026-10-15. Each fix was
344
- pinned by a spec that failed first.
345
-
346
- | # | Finding | Disposition |
347
- |---|---|---|
348
- | C1 | one stray datagram wedges the connection for good | ACK of an unsent packet is a protocol error; session resumes on a new connection; NodeUDP filters by source (§3.9) |
349
- | C2 | `flush` throws `RangeError` for a full-size unreliable message when an ACK is owed | the ACK goes alone |
350
- | C3 | a handler flushing from an ACK notice made acked messages report lost (23 of 200) | notices deferred to the end of the walk |
351
- | C4 | `dispose()` in `onMessageLost` did not stop the walk; later notices still told | deferred notices stop at dispose |
352
- | C5 | a probe whose bytes were acked elsewhere sent nothing; a tail loss then never recovered (> 1 h) | probes pass over such packets; PING when none has bytes |
353
- | C6 | one-byte segments two bytes apart: 46 ms a datagram at 512k ranges | hole cap, protocol error; binary-search insert |
354
- | C7 | delivered messages reported lost past `max_ack_ranges` holes | lost = not confirmed, documented (§3.1); the action stream's contract |
355
- | C8 | `max_ack_ranges` above 64 made the peer reject every ACK | asserted ≤ 64 |
356
- | I1 | actions arriving before the FIRST page applied to the old world | inbound held from `connect()` |
357
- | I2 | a frame over `max_message_bytes` threw every tick, for every peer | given up, `onFrameTooLarge` |
358
- | I3 | join counted complete when FINAL was queued, not delivered | FINAL_SENT until delivered |
359
- | I4 | a world changing more than 256 KiB a round could never be joined | catch-up budget is the lane's room |
360
- | I5 | non-head oversized frame behind a frame lost past the ring floor | open (§8) |
361
- | I6 | inbound-hold overflow dropped acknowledged frames silently | protocol error; session wiring (§3.9) |
362
- | I7 | tokenless reconnect after an incomplete join refused | open, by design (§8) |
363
- | I8 | `release_inbound` ran inside the INITIAL_SYNC dispatch | released after the step's inbound (with I1) |
364
- | — | `subarray` views were 2.3 of 2.5 KB a tick of the layer's allocation | `bytes_copy` (§4) |