@woosh/meep-engine 3.60.4 → 3.60.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 (419) hide show
  1. package/CHANGELOG.md +2621 -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 +11 -0
  63. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  64. package/src/shade/renderer/Renderer.js +50 -6
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  67. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  68. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  69. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  70. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  71. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  72. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
  74. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  75. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
  77. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
  80. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
  82. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  83. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  85. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
  86. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
  88. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  89. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  91. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  92. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  93. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
  94. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
  96. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  98. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
  99. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
  101. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
  102. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  111. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  112. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  113. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  114. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  115. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  116. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  117. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  118. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  119. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  120. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  121. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  122. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  123. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  124. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  125. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  126. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  127. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  128. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  129. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  130. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  131. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  132. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  133. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  134. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  135. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  136. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  137. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  138. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  139. package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
  140. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  141. package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
  142. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  143. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  144. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  145. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
  146. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  147. package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
  148. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
  149. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  150. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
  151. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  152. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
  153. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  154. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
  155. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
  156. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
  157. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
  158. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
  159. package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
  160. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  161. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  162. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  163. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  164. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  165. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  166. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  167. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  168. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  169. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  170. package/src/shade/renderer/water/shader_water.js +22 -13
  171. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  172. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  173. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  174. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  175. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  176. package/editor/REWORK_PLAN_2026_08.md +0 -692
  177. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  178. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  179. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  180. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  181. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  182. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  183. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  184. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  185. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  186. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  187. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  188. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  189. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  190. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  191. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  192. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  193. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  194. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  195. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  196. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  197. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  198. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  199. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  200. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  201. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  202. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  203. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  204. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  205. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  206. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  207. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  208. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  209. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  210. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  211. package/src/REVIEW_2026_08_06/generation.md +0 -176
  212. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  213. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  214. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  215. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  216. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  217. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  218. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  219. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  220. package/src/REVIEW_2026_08_06/view.md +0 -667
  221. package/src/REVIEW_2026_08_06.md +0 -610
  222. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  223. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  224. package/src/core/bvh8/NOTES.md +0 -63
  225. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  226. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  227. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  228. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  229. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  230. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  231. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  232. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  233. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  234. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  235. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  236. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  237. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  238. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  239. package/src/engine/REVIEW_2026_07_03.md +0 -211
  240. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  241. package/src/engine/control/first-person/DESIGN.md +0 -658
  242. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  244. package/src/engine/control/first-person/TODO.md +0 -160
  245. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  246. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  247. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  248. package/src/engine/ecs/ik/PLAN.md +0 -179
  249. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  250. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  251. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  252. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  253. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  254. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  255. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  256. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  257. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  258. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  259. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  260. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  261. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  262. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  263. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  264. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  265. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  266. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  267. package/src/engine/physics/cloth/PLAN.md +0 -3056
  268. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  269. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  270. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  271. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  272. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  273. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  274. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  275. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  276. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  277. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  278. package/src/format/image/avif/DECISIONS.md +0 -545
  279. package/src/format/image/jpeg/NOTES.md +0 -3
  280. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  281. package/src/generation/COORDINATES.md +0 -54
  282. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  283. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  284. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  285. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  286. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  287. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  288. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  289. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  290. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  291. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  292. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  293. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  294. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  295. package/src/shade/RENDERER_CONTRACT.md +0 -697
  296. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  297. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  298. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  299. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  300. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  301. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  302. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  303. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  304. package/src/shade/renderer/NOTES.md +0 -78
  305. package/src/shade/renderer/PLAN.md +0 -8
  306. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  307. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  308. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  309. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  310. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  311. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  312. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  313. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  314. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  315. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  316. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  317. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  318. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  319. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  320. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  321. package/src/shade/renderer/camera/orbital/README.md +0 -81
  322. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  323. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  324. package/src/shade/renderer/camera/orbital/index.js +0 -9
  325. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  326. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  327. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  328. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  329. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  330. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  331. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  332. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  333. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  334. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  335. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  336. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  337. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  338. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  339. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  340. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  341. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  342. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  343. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
  344. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
  346. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
  347. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
  349. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
  350. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
  352. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
  353. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
  355. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  356. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  357. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  358. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  359. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  360. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  361. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  362. package/src/shade/renderer/hiz/NOTES.md +0 -3
  363. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  364. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  365. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  366. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  367. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  368. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  369. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  370. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  371. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  372. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  373. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  374. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  375. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  376. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  377. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  378. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  379. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  380. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  381. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  382. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  383. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  384. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  385. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  386. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  387. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  388. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  389. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  390. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  391. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  392. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  393. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  394. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  395. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  396. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  397. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  398. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  399. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  400. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  401. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  402. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  403. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  404. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  405. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  406. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  407. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  408. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  409. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  410. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  411. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  412. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  413. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  414. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  415. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  416. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  417. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  418. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  419. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,261 +0,0 @@
1
- # Plan — Ray-traced reflection IR (probe-baked geometry reverb)
2
-
3
- > The keystone upgrade: replace `bakeReverb`'s single-hit mean-free-path heuristic with a true
4
- > ray-traced, time-binned, **per-band** reflection IR, reusing the engine's Monte-Carlo path tracer.
5
- > Closes the Steam-Audio *reflections* gap (early reflections + room timbre), replaces the hand-tuned
6
- > `DECAY_PER_METRE` constant with measured per-band RT60, and makes `scattering` / `absorption[3]` live
7
- > data.
8
- >
9
- > **Status (2026-06-20): COMPLETE — the keystone is LANDED + committed + green.** The foundation
10
- > (**P1a/P1b** shape-raycast index, the **§0.5** `RowFirstTable`/`CSRGraph`/BVH data structures, the **P4
11
- > TLAS**) and now the reflection-IR bake itself — **P1c → P2 → P3** — are all in. `bakeReverb`'s single-hit
12
- > heuristic + `DECAY_PER_METRE` are gone; reverb RT60 is now *measured* per band from multi-bounce ray
13
- > tracing, validated against an analytic Sabine box, and rendered as a per-band decaying-noise IR.
14
- >
15
- > **One deviation from this plan, for correctness:** the trace terminates by ENERGY THRESHOLD, **not**
16
- > Russian roulette (§1 step 5 / §4 said RR). Fixed-probability RR is the wrong estimator for acoustic
17
- > reflectance — a survivor at bounce *n* carries energy `(1−α)^n` but is scaled by `2^n`, so for a live
18
- > room (`1−α > ½`) the survivor weight grows as `(2(1−α))^n` and rare deep survivors swamp exactly the
19
- > late bins the RT60 slope is fitted to. Deterministic decay-to-floor is unbiased for the fit window and
20
- > far lower variance.
21
-
22
- The structural blueprint is **`engine/graphics/sh3/lpv/LightProbeVolumeBaker.js`** + its
23
- `PathTracerProbeRenderer` — a near-1:1 analogue (probe-volume baking against scene geometry via the path
24
- tracer). We mirror its baker ↔ probe-renderer split and `TaskGroup` orchestration; we swap the
25
- accumulator from SH-of-radiance to **energy-over-time per band**.
26
-
27
- ---
28
-
29
- ## 0. What is baked vs. runtime — the source-agnostic guarantee (answers the dynamic-sources question)
30
-
31
- **The bake NEVER encodes sound sources. It encodes SPACE: (a) per-region reverberation profile and
32
- (b) region connectivity.** Sources are 100% runtime. There is no restriction to static/fixed sources.
33
-
34
- | Concern | Baked? | What's baked | Source / geometry dynamics |
35
- |---|---|---|---|
36
- | Direct path: occlusion, transmission, air, distance | **never** — real-time ray-trace every frame against the live `AcousticOccluderIndex` | nothing | **sources AND moving occluders fully dynamic** |
37
- | Reverb (reflection IR / per-band RT60) | yes, per **probe** | the SPACE's reverberation response at that point (room geometry + materials), source-agnostic | **sources fully dynamic** — any source routes into the reverb selected by the **listener's** position; geometry assumed mostly-static |
38
- | Pathing (corner-leakage) | yes | inter-probe **visibility graph** (the space's connectivity), source-agnostic | **sources fully dynamic** — the path source↔listener is solved at runtime from live positions; geometry static-assumed (+ live recheck below) |
39
-
40
- **Why reverb is source-agnostic** — "reverb = reflections with the source at the listener." The
41
- late/diffuse reverberant field of a room is approximately uniform and a property of the room (volume +
42
- surface absorption), not of where the source is. So one **listener-centric** reverb per probe serves
43
- every source in that room: `ProbeReverbRenderer` already selects by the *listener's* nearest probe, and
44
- all sources send into that one shared reverb bus. A source can move anywhere — it never indexes the bake.
45
-
46
- **Early reflections are the one source-position-dependent part.** The per-probe envelope bakes them
47
- listener-centric (correct when source ≈ listener; and when the source is far, the position-independent
48
- late tail dominates anyway). True per-source early reflections would be a separate real-time pass —
49
- deferred; the direct-path occlusion machinery already does per-source real-time work, and the late tail
50
- is the dominant reverb cue.
51
-
52
- **Moving objects (dynamic geometry):**
53
- - **Occlusion / transmission — fully live.** The occluder index is dynamic (O(1) `setTransform`), so a
54
- closing door / moving platform correctly blocks the *direct* path in real-time. No bake involved.
55
- - **Baked reverb + baked visibility — encode bake-time geometry.** A mover that changes acoustic
56
- *topology* (a door sealing a room) is not in the bake. Policy, in order of cost:
57
- 1. Most reverb-affecting geometry is static (walls/floors); small movers barely shift RT60 → accept.
58
- 2. **Pathing live recheck** (cheap, from the review): re-verify the chosen exit edge with a single
59
- `anyHit` ray each frame against live geometry — a closed door re-blocks the leak instantly even
60
- though the baked graph still has the edge. One ray per pathed source.
61
- 3. **Opt-in door variants** for big dynamic dividers (vault door, portcullis gating a whole area's
62
- reverb): bake open/closed variants for the affected probes and blend on door state (Steam Audio's
63
- "dynamic geometry" approach) — per set-piece, not the default.
64
- 4. **Re-bake affected probes** on major static-set changes (level streaming) — offline, rare.
65
-
66
- This is the standard **real-time-direct / baked-indirect** split (Steam Audio's exact model): live where
67
- source + geometry move, baked where it is expensive and mostly-static, with targeted live rechecks for
68
- the dynamic cases that matter.
69
-
70
- ---
71
-
72
- ## 0.5 Foundation data structures (owner-directed, resolved)
73
-
74
- These replace the v1 POJO/array structures across the existing + new probe code with the engine's
75
- binary-backed primitives.
76
-
77
- 1. **ProbeField store → `RowFirstTable`** (`core/collection/table/`), **not** `BinaryElementPool`. Probes
78
- are baked **write-once** and read by integer row index, so a fixed-schema columnar binary table fits
79
- exactly: one allocation, cache-friendly, no per-probe JS object. (`BinaryElementPool`'s alloc/free
80
- pool semantics are for churny dynamic elements — unneeded here.) Schema via `RowFirstTableSpec`:
81
- `x, y, z` (f32) · `reverbDecayLow/Mid/High` (f32, widened from the v1 scalar) · `bvhLeaf` (u32). The
82
- `AcousticProbe` class becomes a thin row cursor/accessor (or is dropped for row-index access).
83
-
84
- 2. **Pathing connectivity → `CSRGraph`** (`core/graph/csr/`), replacing `AcousticPathGraph.#adjacency`
85
- (array-of-arrays). Baked once ⇒ CSR is the ideal static-graph form — `edge_addresses` (row pointers) +
86
- `adjacency` + `edge_weights` in one buffer, with the cache-friendly `for (k=xadj[v]; k<xadj[v+1]; k++)`
87
- walk that `computeExitField`/Dijkstra want. `edge_weights` is **`Float32Array`** (owner-updated — its
88
- doc now cites "acoustic coupling"), so path distances go in **directly**, no quantization.
89
- `bakeVisibility` builds it two-pass (count degrees → prefix-sum `edge_addresses` → fill) or via
90
- `CSRGraph.fromArrays`.
91
-
92
- 3. **Probe nearest → BVH + `bvh_query_user_data_nearest_to_point`** (`core/bvh2/bvh3/query/`), replacing
93
- `ProbeField.nearest`'s linear scan. `ProbeField` builds a `BVH` of probe point-AABBs (leaf `user_data`
94
- = row index) once after baking (the `SpatialAudioIndex` precedent); `nearest(x,y,z)` = one query →
95
- row index, O(log n). This matters under the bake (`bakeVisibility` is O(probes²) nearest-style work)
96
- and per-frame (`computeExitField` snaps listener + every pathed source to a probe).
97
-
98
- 4. **`AcousticOccluderIndex` body → class** (replacing the `#bodies` POJO): a real `OccluderBody` holding
99
- `shape, material, matrix, inverse, localAABB, worldAABB` (the triangle `blas/indices/positions` of this
100
- v1 sketch are gone — §0.6 below raycasts the `shape` directly, so only meshes carry an internal BLAS).
101
- `matrix` (the **forward** world transform) maps the local hit position + normal back to world space.
102
-
103
- 5. **`body.inverse` mandatory — no `null` polymorphism.** `addBody`'s matrix defaults to `M4_IDENTITY`
104
- and the inverse is **always** computed; `#localizeRay` always transforms (drop the `inverse === null`
105
- fast-path). Uniform flow per [[feedback_uniform_flow]]. Production cost is nil — real occluder bodies
106
- always carry a `Transform` matrix anyway; the identity fast-path was a test-only convenience.
107
-
108
- **Landing:** (4)+(5)+the stored forward matrix = the foundation of **P1a/P1b**. (1)+(3) = part of the
109
- **P2** probe refactor (the probe schema widens for per-band decay there regardless). (2) = a pathing
110
- refactor that can ride with P2 or land standalone first.
111
-
112
- ---
113
-
114
- ## 0.6 Raycast shapes directly — drop the triangulation (owner-directed)
115
-
116
- The v1 `acoustic_geometry_from_shape` triangulates collider shapes (box → 12 tris, …) into mesh soup —
117
- counter-productive: lossy for primitives, more triangles, a per-body BLAS for a 2-tri wall. **Replace it
118
- with a first-class `AbstractShape3D.raycast`**, so the occluder index stores **shapes** and raycasts them
119
- exactly (closed-form for primitives, an internal BLAS only for meshes).
120
-
121
- **Contract:** `AbstractShape3D.raycast(hit: Float32Array, ray: Ray3) → boolean`, shape at its LOCAL
122
- origin (the caller localises the ray), `hit = [px, py, pz, nx, ny, nz]` (local surface point + unit
123
- normal). The hit distance `t` is recovered by the caller as `(hitPoint − origin)·dir` (unit dir).
124
-
125
- **It is mostly glue** — the narrowphase already factored the local math into core functions that
126
- `refine_ray_hit` dispatches to:
127
- - `SphereShape3D` → `core/geom/3d/sphere/sphere_raycast.js`
128
- - `BoxShape3D` → `core/geom/3d/box/box3_raycast.js`
129
- - `CapsuleShape3D` → `core/geom/3d/capsule/capsule_raycast.js`
130
- - `MeshShape3D` → an **internal lazy ebvh BLAS** (`ebvh_build_for_geometry_morton` +
131
- `ebvh_geometry_query_nearest_triangle_ray` + `construct_ray_hit_from_geometry`); the normal is
132
- normalised and flipped to face the incoming ray. (Owner-approved: MeshShape3D gains an internal BLAS.)
133
-
134
- `AcousticOccluderIndex` then holds `shape + material + matrix + inverse` per body; `closestHit`/`anyHit`
135
- localise the world ray into body space and call `shape.raycast`, transforming the hit point (by the
136
- forward matrix) and normal (by the rotation) back to world. **`acoustic_geometry_from_shape` is deleted**;
137
- `AcousticBody`/`AcousticSimulationSystem` pass the `Collider.shape` straight through. (Could later let
138
- the physics `refine_ray_concave` share `MeshShape3D.raycast` — out of scope.)
139
-
140
- ---
141
-
142
- ## 1. Model — acoustic ray-tracing energy histogram
143
-
144
- From a probe (source = listener), shoot N rays over the sphere. Each ray carries a **per-band energy
145
- throughput** `[low, mid, high]`, init `1`. Bounce loop (modeled on `PathTracer.path_trace`):
146
-
147
- 1. `index.closestHit` → `t`, world hit position + **normal** (P1a).
148
- 2. `pathLength += t`; deposit current energy into `histogram[band][bin]`, `bin = floor(pathLength / c / binSeconds)` (`c` = speed of sound).
149
- 3. fold absorption: `energy[band] *= (1 − material.absorption[band])`.
150
- 4. scatter: with prob `material.scattering` → diffuse (`getBiasedNormalSample`, cosine lobe about the normal); else specular (reflect direction about the normal).
151
- 5. `shiftForward(SELF_OCCLUSION_OFFSET · max(1,|origin|))`; Russian-roulette terminate (unbiased survivor scaling) after `min_bounce`.
152
- 6. miss (escaped to open sky) → stop.
153
-
154
- Per probe: the per-band histogram (the **reflectogram**) → **per-band RT60** (decay slope, via Schroeder
155
- integration) + the early bins (room signature). This is the classic CATT/ODEON statistical method, and
156
- the same energy model Steam Audio's baked reflections use.
157
-
158
- ---
159
-
160
- ## 2. Phases
161
-
162
- **P1 — Foundation (geometry-only tests).**
163
- - **✓ LANDED — P1a — `AbstractShape3D.raycast(hit, ray)`** (§0.6) on Sphere / Box / Capsule / Mesh — glue over the
164
- narrowphase `*_raycast` core functions + an internal mesh BLAS. Engine-wide, generally useful, purely
165
- additive to the shape classes. Test: known ray-vs-sphere/box/capsule/mesh hits (position + normal) and
166
- misses, in the shape's local frame.
167
- - **✓ LANDED — P1b — `OccluderBody` class + occluder-index refactor to shapes** (§0.5 (4)(5), §0.6). Bodies hold
168
- `shape + material + matrix + inverse` (inverse mandatory, identity default); `closestHit`/`anyHit`
169
- localise the ray + `shape.raycast`, transform hit point (forward matrix) + normal (rotation) to world,
170
- recover `t` for cross-body ordering; world-AABB broadphase from `shape.compute_bounding_box`. **Delete
171
- `acoustic_geometry_from_shape`**; `AcousticBody`/`AcousticSimulationSystem` pass `Collider.shape`
172
- through; `RayHit` gains world position + normal. Update the dependent specs (they currently feed
173
- triangle soup). Test: occlusion/ray behaviour unchanged on shape colliders; hit normal correct.
174
- - **✓ LANDED — P1c — scatter + offset primitives**: `v3_reflect` (core, new) for the specular bounce;
175
- the cosine-diffuse scatter reuses `getBiasedNormalSample` and the magnitude-scaled self-occlusion offset
176
- reuses `Ray3.shiftForward` directly (both already existed — no wrappers needed). Tested: reflection law
177
- (angle in = angle out, parallel-to-surface unchanged, unit-length preserved).
178
-
179
- **✓ LANDED — P2 — Bake core (no WebAudio).** `acoustic_trace_energy` (one ray's multi-bounce per-band
180
- deposit into a time-binned echogram — energy-threshold termination, not RR; see the deviation note up
181
- top) + `echogram_band_rt60` (Schroeder + ISO 3382 T30 slope) + `bakeReverbBands` (N rays → per-band
182
- RT60); `AcousticProbe` widened to `reverbDecay[3]` (scalar kept as the derived mean) + `ProbeField`
183
- table widened. **Sabine box gate passes** (baked cube RT60 ≈ 0.161·V/(S·α)). `bakeReverb` deleted.
184
- - `acoustic_trace_energy(index, origin, dir, …, histogram)` — one ray's multi-bounce energy deposit
185
- (allocation-free, seeded).
186
- - `ReflectionProbeRenderer.bake(pos, probe)` — N rays → per-band histogram → per-band RT60 + early
187
- envelope (mirrors `PathTracerProbeRenderer.bake`).
188
- - `AcousticReverbBaker.bake(probeField, ecd)` → `TaskGroup` (chunked over probes via `countTask`, like the
189
- LPV baker; logs ms/probe).
190
- - **Widen `AcousticProbe`**: `reverbDecaySeconds` scalar → `reverbDecay[3]` (per-band) + optionally a short
191
- early-reflection envelope; **keep the scalar derived from the bands** so the existing
192
- `reverbImpulseResponse` / `ProbeReverbRenderer` path stays valid as a regression gate until the new path
193
- is proven. Update `toJSON`/`fromJSON` + `bakeProbeField`.
194
- - **Validation gate — analytic Sabine box:** a closed box with known absorption has a known
195
- RT60 (`0.161·V/(S·α)`); assert the baked late-slope matches within tolerance. Plus: per-band absorption
196
- → per-band RT60 differs; open scene → ~no tail.
197
-
198
- **✓ LANDED — P3 — Render upgrade.**
199
- - `reverbImpulseResponse` shapes **per-band** decaying noise from `reverbDecay[3]` (each band's tail =
200
- its RT60), summed → a geometry-derived IR with room *timbre*. `ProbeReverbRenderer` consumes the
201
- widened probe. Test (`MockAudioContext`): IR band content reflects the per-band decays; crossfade still
202
- click-safe.
203
-
204
- **P4 — Optional, measure-first (not the keystone).**
205
- - NEE-to-source (deposit `source→wall→listener` paths for a cleaner early-reflection IR at lower ray
206
- count) — only if random-bounce variance is shown to be a problem.
207
- - **✓ LANDED — Body-level TLAS** over `AcousticOccluderIndex` — a dynamic BVH over the bodies' world AABBs,
208
- gather via `bvh_query_user_data_ray_segment` (leaf user-data = handle, `BvhClient` refit on
209
- `setTransform`). Landed early on owner request rather than waiting on the bake bench; `closestHit` /
210
- `anyHit` are now O(log n + hits).
211
-
212
- ---
213
-
214
- ## 3. Reuse map
215
-
216
- | Lifted **verbatim** (engine primitives) | Adapted / new (acoustic) |
217
- |---|---|
218
- | `getBiasedNormalSample` (cosine scatter), `construct_ray_hit_from_geometry` (hit normal), `random_point_on_sphere`, `Ray3.shiftForward` + scale-aware offset, the RR survivor-scaling pattern, `TaskGroup`/`countTask`, the baker ↔ probe-renderer split | the bounce loop (energy-time histogram vs radiance/SH), absorption-throughput fold, specular/diffuse split by `scattering`, Schroeder → RT60 reduction, per-band IR shaping |
219
-
220
- Keep the binary **`ebvh`** as the BLAS leaf (do not fork `BufferedGeometryBVH`'s inlined raycast). **Skip
221
- BVH8** (no CPU traversal kernel; lost to `ebvh` for 2-tri walls).
222
-
223
- ---
224
-
225
- ## 4. Key decisions
226
-
227
- - **Dx — source-agnostic space bake (see §0).** The bake = per-region reverb profile + connectivity;
228
- sources are fully runtime; reverb is selected by the *listener*; pathing is solved at runtime. Moving
229
- geometry is live for occlusion, static-assumed for baked indirect, with a live path-edge `anyHit`
230
- recheck + opt-in door variants. **No restriction to static sources, ever.**
231
- - **Statistical (energy-histogram) reverb**, one shared listener-centric IR per probe — affordable for
232
- WebAudio; not per-source convolution.
233
- - **Per-band throughout** (collapsing to a scalar is the regression we are fixing).
234
- - **Unbiased & leak-free**: RR survivor scaling is mandatory; the scale-aware self-occlusion offset is
235
- mandatory (a fixed epsilon silently leaks energy through walls at large world coords).
236
- - **Back-compat scalar path kept as the regression gate** until the per-band path validates against
237
- Sabine — *correctness-first, no bandaid*.
238
- - **Skip wetness/humidity** (owner-agreed) and the wet-JCA physics.
239
-
240
- ---
241
-
242
- ## 5. Testing
243
-
244
- Core (`core/` + `probe/`) is WebAudio-free → geometry-only tests, no audio mock. The Sabine box is the
245
- correctness gate for P2. The render (P3) uses `MockAudioContext`. Bench the bake ray cost before any
246
- TLAS. Run from the repo root: `npx jest --config jest.conf.json engine/sound/simulation`.
247
-
248
- ## 6. Risks
249
-
250
- - **Probe-contract widening** (scalar → per-band) ripples through `AcousticProbe` serialization,
251
- `bakeProbeField`, `reverbImpulseResponse`, `ProbeReverbRenderer` — hence P2 is the L item. Land P1
252
- first (both S, self-contained), keep the scalar path behind the new curve.
253
- - **Bake cost** (rays × bounces × probes) is real but offline; `TaskGroup` chunking keeps it
254
- non-blocking. Don't reach for the TLAS until the bench says so.
255
- - **Validation honesty**: trust the bake to replace `DECAY_PER_METRE` only after the Sabine-box RT60
256
- matches analytics.
257
-
258
- ## 7. Sequence
259
-
260
- P1a + P1b (S each, zero behavior change) → P2 (bake + Sabine gate) → P3 (render). P4 stays
261
- measured/optional.
@@ -1,121 +0,0 @@
1
- # Topologically-aware probe-visibility graph
2
-
3
- ## The cliff
4
-
5
- `bakeVisibility` connects every mutually-visible probe pair via an all-pairs `for i, for j<i` loop.
6
- With no occluders that is the **complete graph** — `n(n-1)/2` edges, O(n²) time *and* memory. A 128³ probe
7
- field (2,097,152 probes) would try to materialise **2.199e12 edges** → OOM. (Bench:
8
- `probe/bakeVisibility.bench.spec.js`.)
9
-
10
- Pruning a distance cutoff into that loop does **not** fix it — it still *enumerates* all pairs (O(n²) time),
11
- and the scheme is topologically blind. The fix is to never enumerate the complete graph: generate candidate
12
- edges from the **spatial topology** of the probe cloud, so we only ever touch O(n) of them.
13
-
14
- This is, in the literature, a **sparse geometric spanner** built like a **sparse roadmap spanner (SPARS2)**:
15
- a base graph + connectivity bridges + path-quality shortcuts. References that map 1:1 onto the three stages:
16
- SPARS/SPARS2 (Dobson & Bekris 2014 — names stage B a *"bridge"*, stage C a *"shortcut"*); the greedy
17
- geometric spanner (Bose et al. — stage C's length test `dist_G(u,v) > t·‖uv‖`); PRM* component-connection
18
- (stage B). Steam Audio, by contrast, keeps the all-pairs loop and just places **few** probes (5 m floor grid)
19
- — a placement lever we deliberately treat separately.
20
-
21
- ## Decisions (locked)
22
-
23
- - **Base = Delaunay, no jitter.** `compute_delaunay_tetrahedral_mesh` on the probe positions. (Grid fields
24
- have a clean dedicated tessellator, `tetrahedral_mesh_build_from_grid`, but wiring it by grid-structure is
25
- part of the *placement* workstream — not conflated here.)
26
- - **Full A + B + C** in this change.
27
- - **Dense probe fields stay.** This is purely a graph-construction fix; placement is a separate workstream.
28
- - Caveat we are buying with B+C: **3D Delaunay is not a proven constant-stretch spanner** (2D is, ≤1.998;
29
- 3D has no such bound — Erickson, Xia). So the base graph *can* detour badly and *can* be fragmented by
30
- walls; B repairs connectivity and C repairs path quality. They are mandatory, not optional.
31
-
32
- ## Stage A — Delaunay base graph (`probe_delaunay_edges.js`)
33
-
34
- 1. Copy probe positions into a packed `[x,y,z]*n`; `compute_delaunay_tetrahedral_mesh(mesh, points, n)`.
35
- 2. Extract the **unique undirected edges** of the live tets — 6 per tet (`getVertexIndex` pairs), deduped
36
- (materialise the freed-tet skip set once; do **not** call `exists()` per tet — it is O(free)). The tet
37
- mesh triangulates the convex hull, so this is a single connected graph of **≈6–7·n** edges.
38
- 3. Drop edges that fail `probe_edge_visible(field, index, a, b)`; keep survivors weighted by distance.
39
-
40
- Result: a sparse, occlusion-respecting base graph. **O(n)** edges, **O(n)** shadow rays. (2.1M probes →
41
- ~13M edges / rays vs 2.2e12 — ~150,000× fewer.) Dropping occluded edges is what fragments the graph into
42
- **islands** (rooms), which stage B repairs.
43
-
44
- ## Stage B — bridge the islands (`probe_visibility_bridge_components.js`)
45
-
46
- A door the Delaunay edge happened to miss leaves two acoustically-connected rooms as separate components.
47
-
48
- 1. `uf_init` + `uf_union` over the surviving base edges → connected components (canonical root = min member).
49
- 2. For each probe, **radius-query the probe BVH** (`bvh_query_user_data_intersects_sphere`, radius = k× the
50
- median base-edge length) for nearby probes in a **different** component; among the **visible** ones keep
51
- the **shortest** edge per unordered component-pair (the PRM/SPARS bridge heuristic).
52
- 3. Add those bridges, re-`uf_union`, repeat until the component count stops dropping. Genuinely sealed
53
- regions stay separate (correct — a closed vault should not leak).
54
-
55
- **O(n · |radius neighbours|)**, no all-pairs. Bridges are the only edges that can exceed the local Delaunay
56
- length, so they are also the place corner-leak pathing will most want.
57
-
58
- ## Stage C — augment for path quality (`probe_visibility_augment.js`)
59
-
60
- The Delaunay base routes only through local hops, so a graph path can detour or kink where a clear straight
61
- line exists. Add a **budgeted fraction** of extra edges (cap ≤ ~30% of base) on two criteria:
62
-
63
- - **C1 length (greedy spanner).** Candidate chords `(u,v)` from the 2-ring (a shared base neighbour `w`) and
64
- short BVH-radius pairs. Add iff `(u,v)` is visible **and** `dist_G(u,v) > t·‖uv‖` — the current graph route
65
- is ≥ t× the straight line. `dist_G` is evaluated with a **distance-bounded Dijkstra capped at `t·‖uv‖`**
66
- (reuse the heap Dijkstra; stop early once the cap is exceeded), so it is cheap, not a full SSSP per pair.
67
- - **C2 directionality (diffraction-angle gate).** For a 2-ring kink `u–w–v`, with `d0 = ̂(u−w)`, `d1 = ̂(v−w)`,
68
- add the chord iff visible **and** `dot(d0, −d1) < X` — the angle at `w` is acute, a sharp corner the sound
69
- must wrap around. Acoustically a bend is a diffraction point whose HF loss grows with angle (UTD/Maekawa),
70
- so straightening it is worth an edge even when it barely shortens the route. This is an acoustic heuristic,
71
- **not** a spanner property — hence the budget cap, so it composes with C1 rather than overrunning it.
72
-
73
- **O(n · degree²)** candidates from the 2-ring; each gated test is local/bounded. Process shortest-first,
74
- stop at the budget.
75
-
76
- ## Assembly — `bakeVisibility` rewrite
77
-
78
- `A (delaunay edges → visible) → B (bridge) → C (augment) → CSRGraph (both half-edges) → field.setVisibilityGraph`.
79
- The CSR build, the `EDGE_WEIGHT_BLOCKED` runtime recheck, and `findAcousticPath` are unchanged downstream —
80
- this only changes which edges exist, not their representation. Weights remain inter-probe distance so the
81
- recheck restores them identically.
82
-
83
- ## New primitives that may be needed
84
-
85
- - Tet → unique-edge extraction with an O(tets) freed-skip (helper in `probe_delaunay_edges.js`).
86
- - A median base-edge-length helper to set the stage-B radius and the stage-C candidate radius.
87
- - (If 2-ring proves insufficient at scale) WSPD candidate pairs — deferred unless measured to be needed.
88
-
89
- ## Test plan
90
-
91
- - `probe_delaunay_edges.spec.js`: a small grid tetrahedralises to the expected adjacency; coincident/degenerate
92
- inputs; edge uniqueness.
93
- - `bakeVisibility.spec.js` (extend): empty scene is now **sparse** (≈O(n), assert ≪ n²) yet still **connected**
94
- (one component) and every kept edge is visible; a wall fragments then B re-bridges through a gap; the
95
- existing two-rooms-corridor integration test still passes (reachability + direction + per-band).
96
- - Re-point `bakeVisibility.bench.spec.js`: the complete-graph assertion becomes a **sparsity + connectivity**
97
- assertion; the 128³ case should now *complete* (sweep added to confirm ~linear edges/time).
98
- - Stage C: a deliberate kink (L-shaped corridor with a clear diagonal) gains the shortcut; budget cap honoured.
99
-
100
- ## Open knobs (defaults to pick during implementation, document in code)
101
-
102
- - stage-B radius multiplier `k` (× median edge length); stage-C stretch `t`; stage-C angle `X`; stage-C budget
103
- fraction. All bake-time constants with JSDoc rationale (per the project's no-magic / uniform-flow style).
104
-
105
- ## As-built notes (landed)
106
-
107
- - **Defaults chosen:** stage-B radius `2.5×` median edge length; stage-C stretch `1.3`, kink `dot < −0.5`
108
- (~corners <60°), budget `0.2×` base edges.
109
- - **Coplanar degeneracy is handled, not avoided:** a valid 3D Delaunay 1-skeleton is connected, so
110
- `probe_delaunay_edges` checks connectivity and falls back to the complete graph when the extraction is
111
- disconnected (a near-coplanar/degenerate field — e.g. the y=0 test scenes). Dense 3D fields never hit it.
112
- - **Stage B is boundary-driven:** it searches only from the endpoints of dropped (occluded) edges (`sources`),
113
- not all `n` probes — an interior probe with all-visible neighbours can't be a missed-door near side. An
114
- empty scene drops nothing, so stage B is a no-op (measured: 10 s → 20 ms at 13.8k probes).
115
- - **Spatial sort:** `probe_delaunay_edges` Morton-sorts the points before the incremental tetrahedralisation
116
- (the core's own TODO) and maps tet vertices back through the permutation. ~25% off the build.
117
- - **Result:** edges are O(n) (measured 6.7–8.0 per probe across 8³–32³, always 1 component); the old all-pairs
118
- O(n²)/OOM is gone. The 128³ case no longer OOMs and completes.
119
- - **Remaining bottleneck = the core incremental Delaunay BUILD** (~98% of bake time, super-linear). Follow-ups
120
- (out of scope here): wire `tetrahedral_mesh_build_from_grid` for grid fields (O(n) — the placement
121
- workstream), and/or speed up core's Delaunay (BRIO/spatial-sort insertion is its standing TODO).