@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
@@ -125,7 +125,8 @@ function grow_typed(array, length) {
125
125
  * - Its record (`MESH_CARD_SET_STRUCT`) is written when a capture starts.
126
126
  *
127
127
  * **Lifetime.** {@link acquire} makes a card set for a pair and {@link release} gives it back; the
128
- * caller keeps one per pair. A card set waits until its geometry's layout is placed
128
+ * caller keeps one per pair. A card set of an aliased geometry ({@link alias}) is its source's: it
129
+ * captures the source's layout through the source's meshlets. A card set waits until its geometry's layout is placed
129
130
  * ({@link set_layout}), is then captured, and turns resident ({@link onResident}) on the frame its
130
131
  * last page is recorded: the capture's writes come before any later pass reads it. A layout that
131
132
  * goes ({@link drop_layout}) withdraws its card sets ({@link onWithdrawn}) back to waiting.
@@ -160,6 +161,12 @@ export class GPUMeshCardSets {
160
161
 
161
162
  #ids = new IdPool();
162
163
 
164
+ /**
165
+ * The source of each aliased geometry id.
166
+ * @type {Map<number, number>}
167
+ */
168
+ #source_of = new Map();
169
+
163
170
  // ---- per card set id ----
164
171
 
165
172
  #state = new Uint8Array(64);
@@ -265,6 +272,14 @@ export class GPUMeshCardSets {
265
272
  */
266
273
  #frame_material_contexts = null;
267
274
 
275
+ /**
276
+ * What a frame's capture traces with: set by {@link graph_capture}. Only what is traced is made
277
+ * resident, each run's material as its run is taken, so a frame that traces nothing leaves the
278
+ * resident materials as they were.
279
+ * @type {GPUResidentMaterialContext|null}
280
+ */
281
+ #frame_materials = null;
282
+
268
283
  // the frame's shelves in the scratch
269
284
  #shelf_x = 0;
270
285
  #shelf_y = 0;
@@ -471,7 +486,8 @@ export class GPUMeshCardSets {
471
486
  /**
472
487
  * A card set for a pair. The caller keeps one per pair.
473
488
  *
474
- * @param {number} geometry the geometry id whose layout it captures: the source's, for a skinned row
489
+ * @param {number} geometry the geometry id the pair draws; an aliased one's card set captures its source's
490
+ * layout ({@link alias})
475
491
  * @param {ShadeMaterial} material
476
492
  * @returns {number} card set id
477
493
  */
@@ -479,6 +495,8 @@ export class GPUMeshCardSets {
479
495
  assert.isNonNegativeInteger(geometry, 'geometry');
480
496
  assert.defined(material, 'material');
481
497
 
498
+ geometry = this.#source_of.get(geometry) ?? geometry;
499
+
482
500
  const id = this.#ids.get();
483
501
 
484
502
  this.#ensure_id(id);
@@ -627,6 +645,60 @@ export class GPUMeshCardSets {
627
645
  }
628
646
  }
629
647
 
648
+ /**
649
+ * The geometry `clone` is drawn as `source` from here on: its card sets, and those acquired for it after, capture
650
+ * `source`'s layout through `source`'s meshlets, the two being in one local space. A card set of `clone` waits
651
+ * for `source`'s layout, as one acquired for `source` does.
652
+ *
653
+ * @param {number} clone
654
+ * @param {number} source
655
+ */
656
+ alias(clone, source) {
657
+ assert.notEqual(clone, source, 'a geometry cannot alias itself');
658
+
659
+ this.#source_of.set(clone, source);
660
+
661
+ // its own layout, if it had one, went with its cache: what it has waits
662
+ this.drop_layout(clone);
663
+
664
+ const sets = this.#sets_of_geometry.get(clone);
665
+
666
+ if (sets === undefined) {
667
+ return;
668
+ }
669
+
670
+ this.#sets_of_geometry.delete(clone);
671
+
672
+ for (let i = 0; i < sets.length; i++) {
673
+ const id = sets[i];
674
+
675
+ this.#geometry[id] = source;
676
+
677
+ let of_source = this.#sets_of_geometry.get(source);
678
+
679
+ if (of_source === undefined) {
680
+ of_source = [];
681
+ this.#sets_of_geometry.set(source, of_source);
682
+ }
683
+
684
+ of_source.push(id);
685
+
686
+ if (this.#layout_pages.has(source)) {
687
+ this.#start(id);
688
+ }
689
+ }
690
+ }
691
+
692
+ /**
693
+ * `clone` is no longer aliased: card sets acquired for it from here on capture its own layout. Those it has keep
694
+ * capturing its source's until they are given back.
695
+ *
696
+ * @param {number} clone
697
+ */
698
+ unalias(clone) {
699
+ this.#source_of.delete(clone);
700
+ }
701
+
630
702
  /**
631
703
  * Pages from the atlas for a card set whose layout is placed, and its first capture queued.
632
704
  *
@@ -787,6 +859,9 @@ export class GPUMeshCardSets {
787
859
  // a template that cannot be drawn this way is traced
788
860
  }
789
861
 
862
+ // its row as the material stands now, repacked if it has moved since
863
+ this.#frame_materials.obtain_material(this.#material[id]);
864
+
790
865
  const first = this.#next_page[id];
791
866
  const count = Math.min(pages - first, this.#frame_left);
792
867
 
@@ -930,7 +1005,8 @@ export class GPUMeshCardSets {
930
1005
  * @param {number} options.budget pages captured at most, `card_capture_budget`
931
1006
  * @param {number} options.arena graph handle of the arena, as the frame's bake left it
932
1007
  * @param {GPUBuffer} options.headers
933
- * @param {GPUResidentMaterialContext} options.materials what the trace shades with
1008
+ * @param {GPUResidentMaterialContext} options.materials what the trace shades with: each traced
1009
+ * material is made resident, and the rows committed, before the trace is recorded
934
1010
  * @param {GPUMaterialManager} options.material_contexts what the raster draws with: each
935
1011
  * material's template and bind group
936
1012
  * @param {Object} options.blas the geometry bindings `ray_query_blas_nearest` reads, whose
@@ -947,10 +1023,12 @@ export class GPUMeshCardSets {
947
1023
  }
948
1024
 
949
1025
  this.#frame_material_contexts = material_contexts;
1026
+ this.#frame_materials = materials;
950
1027
 
951
1028
  this.#take(budget);
952
1029
 
953
1030
  this.#frame_material_contexts = null;
1031
+ this.#frame_materials = null;
954
1032
 
955
1033
  const completed = this.#completed;
956
1034
 
@@ -961,6 +1039,9 @@ export class GPUMeshCardSets {
961
1039
  let emissive = graph_import_texture(graph, this.#atlas.texture_at(1), "mesh_card_emissive");
962
1040
 
963
1041
  if (this.#frame_runs > 0) {
1042
+ // what the runs' materials made resident, written before the trace reads it
1043
+ materials.commit();
1044
+
964
1045
  this.#ensure_runs(this.#frame_runs);
965
1046
 
966
1047
  this.#device.queue.writeBuffer(this.#runs, 0, this.#run_scratch, 0, 4 * this.#frame_runs);
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The triangles a virtual geometry's proxy is cut to by default: {@link VGEO_PROXY_TRIANGLE_SHARE} of the source's,
3
+ * at least one cluster's and at most {@link VGEO_PROXY_TRIANGLE_MAX}.
4
+ *
5
+ * @param {number} source_triangles
6
+ * @returns {number}
7
+ */
8
+ export function vgeo_proxy_triangle_limit(source_triangles: number): number;
9
+ /**
10
+ * The share of the source's triangles a proxy keeps by default.
11
+ * @type {number}
12
+ */
13
+ export const VGEO_PROXY_TRIANGLE_SHARE: number;
14
+ /**
15
+ * Most triangles a proxy has by default, however large the source.
16
+ * @type {number}
17
+ */
18
+ export const VGEO_PROXY_TRIANGLE_MAX: number;
19
+ //# sourceMappingURL=vgeo_proxy_triangle_limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vgeo_proxy_triangle_limit.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js"],"names":[],"mappings":"AAeA;;;;;;GAMG;AACH,4DAHW,MAAM,GACJ,MAAM,CAIlB;AArBD;;;GAGG;AACH,wCAFU,MAAM,CAE8B;AAE9C;;;GAGG;AACH,sCAFU,MAAM,CAE6B"}
@@ -0,0 +1,25 @@
1
+ import { clamp } from "../../../../../core/math/clamp.js";
2
+ import { VGEO_MAX_CLUSTER_TRIANGLE_COUNT } from "../format/cluster/VGEO_MAX_CLUSTER_TRIANGLE_COUNT.js";
3
+
4
+ /**
5
+ * The share of the source's triangles a proxy keeps by default.
6
+ * @type {number}
7
+ */
8
+ export const VGEO_PROXY_TRIANGLE_SHARE = 0.01;
9
+
10
+ /**
11
+ * Most triangles a proxy has by default, however large the source.
12
+ * @type {number}
13
+ */
14
+ export const VGEO_PROXY_TRIANGLE_MAX = 64000;
15
+
16
+ /**
17
+ * The triangles a virtual geometry's proxy is cut to by default: {@link VGEO_PROXY_TRIANGLE_SHARE} of the source's,
18
+ * at least one cluster's and at most {@link VGEO_PROXY_TRIANGLE_MAX}.
19
+ *
20
+ * @param {number} source_triangles
21
+ * @returns {number}
22
+ */
23
+ export function vgeo_proxy_triangle_limit(source_triangles) {
24
+ return Math.floor(clamp(source_triangles * VGEO_PROXY_TRIANGLE_SHARE, VGEO_MAX_CLUSTER_TRIANGLE_COUNT, VGEO_PROXY_TRIANGLE_MAX));
25
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Turn a virtual geometry into an ordinary meshlet geometry of at most `triangle_limit` triangles: a
3
+ * proxy, for whatever wants a plain mesh of an asset that is only clusters.
4
+ *
5
+ * **No simplification happens here.** The DAG already holds the asset at every level of detail; the
6
+ * proxy is a cut through it, and the cut's clusters are meshlets already (`VGEO_FORMAT.md` §8). The
7
+ * cut starts at the roots and refines, one group at a time, the group whose parents carry the largest
8
+ * `self_error`, and stops at the first refinement that would take it over the limit — so the error is
9
+ * as uniform as the DAG allows.
10
+ *
11
+ * A group is refined only once every one of its parents is in the cut (`group_parent_count`, §6), and
12
+ * then all of them are replaced together, so the cut is watertight at every step, as a view's cut is.
13
+ *
14
+ * Pages are installed as the descent reaches them, down to one band below the cut: a small proxy of a
15
+ * large asset reads the coarse prefix of the file and nothing else.
16
+ *
17
+ * The DAG's roots are as coarse as it goes: a limit below the roots' triangle count gets the roots.
18
+ *
19
+ * @param {VGeoContainerReader} reader an open container, which is one material's geometry; the pages the
20
+ * descent reaches are installed into it and left there
21
+ * @param {number} triangle_limit
22
+ * @returns {Promise<MeshletGeometry>}
23
+ *
24
+ * @author Alex Goldring
25
+ * @copyright Company Named Limited (c) 2026
26
+ */
27
+ export function vgeo_to_proxy_mesh(reader: VGeoContainerReader, triangle_limit: number): Promise<MeshletGeometry>;
28
+ export type VGeoContainerReader = import("../format/read/VGeoContainerReader.js").VGeoContainerReader;
29
+ export type VGeoPage = import("../format/read/VGeoPage.js").VGeoPage;
30
+ import { MeshletGeometry } from "../../MeshletGeometry.js";
31
+ //# sourceMappingURL=vgeo_to_proxy_mesh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vgeo_to_proxy_mesh.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,2CARW,mBAAmB,kBAEnB,MAAM,GACJ,QAAQ,eAAe,CAAC,CAcpC;kCA7CY,OAAO,uCAAuC,EAAE,mBAAmB;uBACnE,OAAO,4BAA4B,EAAE,QAAQ;gCAP1B,0BAA0B"}
@@ -0,0 +1,343 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+ import { BinaryBuffer } from "../../../../../core/binary/BinaryBuffer.js";
3
+ import { platform_compute_endianness } from "../../../../../core/binary/platform_compute_endianness.js";
4
+ import { IndexedFloatMaxHeap } from "../../../../../core/collection/heap/IndexedFloatMaxHeap.js";
5
+ import { aabb3_array_combine } from "../../../../../core/geom/3d/aabb/aabb3_array_combine.js";
6
+ import { blas_from_meshlets } from "../../blas_from_meshlets.js";
7
+ import { MESHLET_METADATA_STRUCT } from "../../meshlet/encoding/MESHLET_METADATA_STRUCT.js";
8
+ import { MeshletGeometry } from "../../MeshletGeometry.js";
9
+ import { VGEO_NO_CHILD } from "../format/cluster/VGEO_NO_CHILD.js";
10
+ import { VGEO_SAME_PAGE } from "../format/cluster/VGEO_SAME_PAGE.js";
11
+ import { vgeo_meshlet_metadata_write } from "../runtime/vgeo_meshlet_metadata_write.js";
12
+
13
+ /**
14
+ * @typedef {import("../format/read/VGeoContainerReader.js").VGeoContainerReader} VGeoContainerReader
15
+ * @typedef {import("../format/read/VGeoPage.js").VGeoPage} VGeoPage
16
+ */
17
+
18
+ /**
19
+ * A page not yet given its groups' ids.
20
+ * @type {number}
21
+ */
22
+ const NO_BASE = -1;
23
+
24
+ /**
25
+ * Turn a virtual geometry into an ordinary meshlet geometry of at most `triangle_limit` triangles: a
26
+ * proxy, for whatever wants a plain mesh of an asset that is only clusters.
27
+ *
28
+ * **No simplification happens here.** The DAG already holds the asset at every level of detail; the
29
+ * proxy is a cut through it, and the cut's clusters are meshlets already (`VGEO_FORMAT.md` §8). The
30
+ * cut starts at the roots and refines, one group at a time, the group whose parents carry the largest
31
+ * `self_error`, and stops at the first refinement that would take it over the limit — so the error is
32
+ * as uniform as the DAG allows.
33
+ *
34
+ * A group is refined only once every one of its parents is in the cut (`group_parent_count`, §6), and
35
+ * then all of them are replaced together, so the cut is watertight at every step, as a view's cut is.
36
+ *
37
+ * Pages are installed as the descent reaches them, down to one band below the cut: a small proxy of a
38
+ * large asset reads the coarse prefix of the file and nothing else.
39
+ *
40
+ * The DAG's roots are as coarse as it goes: a limit below the roots' triangle count gets the roots.
41
+ *
42
+ * @param {VGeoContainerReader} reader an open container, which is one material's geometry; the pages the
43
+ * descent reaches are installed into it and left there
44
+ * @param {number} triangle_limit
45
+ * @returns {Promise<MeshletGeometry>}
46
+ *
47
+ * @author Alex Goldring
48
+ * @copyright Company Named Limited (c) 2026
49
+ */
50
+ export async function vgeo_to_proxy_mesh(reader, triangle_limit) {
51
+ assert.defined(reader.root, 'reader.root — the container must be open');
52
+ assert.isNonNegativeInteger(triangle_limit, 'triangle_limit');
53
+
54
+ const cut = new ProxyCut(reader);
55
+
56
+ await cut.descend(triangle_limit);
57
+
58
+ return cut.build();
59
+ }
60
+
61
+ /**
62
+ * The cut, and the bookkeeping of its descent.
63
+ *
64
+ * Groups are given dense ids as their page is installed, so the per-group state is typed arrays sized
65
+ * once from the header's `total_groups`.
66
+ */
67
+ class ProxyCut {
68
+ /**
69
+ * @param {VGeoContainerReader} reader
70
+ */
71
+ constructor(reader) {
72
+ this.reader = reader;
73
+
74
+ const capacity = reader.header.total_groups;
75
+
76
+ /**
77
+ * First group id of each page; {@link NO_BASE} until the page is installed.
78
+ */
79
+ this.page_base = new Int32Array(reader.header.total_pages).fill(NO_BASE);
80
+
81
+ this.next_base = 0;
82
+
83
+ this.group_page = new Uint32Array(capacity);
84
+ this.group_index = new Uint16Array(capacity);
85
+
86
+ /**
87
+ * Parents of the group in the cut so far.
88
+ */
89
+ this.arrived = new Uint16Array(capacity);
90
+
91
+ /**
92
+ * Their triangles: what refining the group takes out of the cut.
93
+ */
94
+ this.parent_triangles = new Uint32Array(capacity);
95
+
96
+ this.refined = new Uint8Array(capacity);
97
+
98
+ /**
99
+ * Groups whose every parent is in the cut, by the error those parents carry.
100
+ */
101
+ this.refinable = new IndexedFloatMaxHeap(capacity);
102
+
103
+ /**
104
+ * Every cluster that entered the cut, as the id of its group, its index in its page and the id
105
+ * of its child group (-1 for a leaf). One leaves the cut when its child group is refined.
106
+ * @type {number[]}
107
+ */
108
+ this.entered_group = [];
109
+ this.entered_cluster = [];
110
+ this.entered_child = [];
111
+
112
+ this.triangle_count = 0;
113
+ }
114
+
115
+ /**
116
+ * @param {number} limit
117
+ * @returns {Promise<void>}
118
+ */
119
+ async descend(limit) {
120
+ const root = this.reader.root;
121
+
122
+ this.#register(root);
123
+
124
+ for (let group = 0; group < root.group_parent_count.length; group++) {
125
+ // no cluster refines into it: the top of the DAG
126
+ if (root.group_parent_count[group] === 0) {
127
+ await this.#enter(this.page_base[root.index] + group);
128
+ }
129
+ }
130
+
131
+ const refinable = this.refinable;
132
+
133
+ while (refinable.size > 0) {
134
+ const id = refinable.pop_max();
135
+
136
+ if (this.triangle_count - this.parent_triangles[id] + this.#group_triangles(id) > limit) {
137
+ // the largest error left does not fit: refining anywhere finer would make it less uniform
138
+ break;
139
+ }
140
+
141
+ this.refined[id] = 1;
142
+ this.triangle_count -= this.parent_triangles[id];
143
+
144
+ await this.#enter(id);
145
+ }
146
+ }
147
+
148
+ /**
149
+ * The cut's clusters as a meshlet geometry: their payloads gathered as they are stored, a metadata
150
+ * row each, and the BVH the mesh path builds.
151
+ *
152
+ * @returns {MeshletGeometry}
153
+ */
154
+ build() {
155
+ /** @type {VGeoPage[]} */
156
+ const pages = [];
157
+ /** @type {number[]} */
158
+ const clusters = [];
159
+
160
+ let data_size = 0;
161
+
162
+ for (let i = 0; i < this.entered_group.length; i++) {
163
+ const child = this.entered_child[i];
164
+
165
+ if (child !== -1 && this.refined[child] === 1) {
166
+ continue;
167
+ }
168
+
169
+ const page = this.reader.page(this.group_page[this.entered_group[i]]);
170
+ const cluster = this.entered_cluster[i];
171
+
172
+ pages.push(page);
173
+ clusters.push(cluster);
174
+
175
+ data_size += page.cluster_payload_size[cluster];
176
+ }
177
+
178
+ const count = clusters.length;
179
+
180
+ const data = new Uint8Array(data_size);
181
+
182
+ const metadata = BinaryBuffer.fromEndianness(platform_compute_endianness());
183
+
184
+ metadata.setCapacity(count * MESHLET_METADATA_STRUCT.size);
185
+
186
+ const result = new MeshletGeometry();
187
+
188
+ const box = result.bounding_box;
189
+
190
+ box.set([Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity]);
191
+
192
+ let address = 0;
193
+
194
+ for (let i = 0; i < count; i++) {
195
+ const page = pages[i];
196
+ const cluster = clusters[i];
197
+
198
+ const start = page.payload_offset + page.cluster_payload_offset[cluster];
199
+ const size = page.cluster_payload_size[cluster];
200
+
201
+ data.set(page.bytes.subarray(start, start + size), address);
202
+
203
+ // §11.8: every payload size is a multiple of four, so each cluster starts on a word
204
+ vgeo_meshlet_metadata_write(metadata, page, cluster, address >>> 2);
205
+
206
+ // `aabb` is the cluster's tight fit, so their union is the proxy's
207
+ aabb3_array_combine(box, 0, box, 0, page.aabb, cluster * 6);
208
+
209
+ address += size;
210
+ }
211
+
212
+ const batch = result.meshlets;
213
+
214
+ batch.count = count;
215
+ batch.data_buffer = data.buffer;
216
+ batch.metadata_buffer = metadata.data.slice(0, count * MESHLET_METADATA_STRUCT.size);
217
+
218
+ // the box-diagonal sphere `meshlet_geometry_build_from_geometry` gives a mesh
219
+ const sphere = result.bounding_sphere;
220
+
221
+ sphere[0] = (box[0] + box[3]) * 0.5;
222
+ sphere[1] = (box[1] + box[4]) * 0.5;
223
+ sphere[2] = (box[2] + box[5]) * 0.5;
224
+ sphere[3] = 0.5 * Math.hypot(box[3] - box[0], box[4] - box[1], box[5] - box[2]);
225
+
226
+ result.name = this.reader.source.name;
227
+ result.primitive_count = this.triangle_count;
228
+ result.bvh = blas_from_meshlets(batch, result.primitive_count, box);
229
+
230
+ return result;
231
+ }
232
+
233
+ /**
234
+ * @param {number} id
235
+ * @returns {number}
236
+ */
237
+ #group_triangles(id) {
238
+ const page = this.reader.page(this.group_page[id]);
239
+ const group = this.group_index[id];
240
+
241
+ const first = page.group_cluster_first[group];
242
+ const end = first + page.group_cluster_count[group];
243
+
244
+ let triangles = 0;
245
+
246
+ for (let cluster = first; cluster < end; cluster++) {
247
+ triangles += page.triangle_count[cluster];
248
+ }
249
+
250
+ return triangles;
251
+ }
252
+
253
+ /**
254
+ * Give an installed page's groups their ids.
255
+ *
256
+ * @param {VGeoPage} page
257
+ */
258
+ #register(page) {
259
+ if (this.page_base[page.index] !== NO_BASE) {
260
+ return;
261
+ }
262
+
263
+ const base = this.next_base;
264
+ const group_count = page.group_cluster_count.length;
265
+
266
+ this.page_base[page.index] = base;
267
+
268
+ for (let group = 0; group < group_count; group++) {
269
+ this.group_page[base + group] = page.index;
270
+ this.group_index[base + group] = group;
271
+ }
272
+
273
+ this.next_base = base + group_count;
274
+ }
275
+
276
+ /**
277
+ * Put a group's clusters in the cut, and count each in at its child group, which becomes
278
+ * refinable once its last parent arrives.
279
+ *
280
+ * @param {number} id
281
+ * @returns {Promise<void>}
282
+ */
283
+ async #enter(id) {
284
+ const reader = this.reader;
285
+ const page = reader.page(this.group_page[id]);
286
+ const group = this.group_index[id];
287
+
288
+ const first = page.group_cluster_first[group];
289
+ const end = first + page.group_cluster_count[group];
290
+
291
+ // the child pages first: a child group's parent count lives in its own page
292
+ const installs = [];
293
+
294
+ for (let cluster = first; cluster < end; cluster++) {
295
+ const child_ref = page.child_ref[cluster];
296
+
297
+ if (child_ref === VGEO_NO_CHILD || child_ref === VGEO_SAME_PAGE) {
298
+ continue;
299
+ }
300
+
301
+ const child_page = page.child_page_index[child_ref];
302
+
303
+ if (!reader.is_resident(child_page)) {
304
+ installs.push(reader.install(
305
+ child_page, page.child_frame_offset[child_ref], page.child_fetch_size[child_ref]
306
+ ));
307
+ }
308
+ }
309
+
310
+ for (const child_page of await Promise.all(installs)) {
311
+ this.#register(child_page);
312
+ }
313
+
314
+ for (let cluster = first; cluster < end; cluster++) {
315
+ const triangles = page.triangle_count[cluster];
316
+
317
+ this.triangle_count += triangles;
318
+
319
+ this.entered_group.push(id);
320
+ this.entered_cluster.push(cluster);
321
+
322
+ const child_ref = page.child_ref[cluster];
323
+
324
+ if (child_ref === VGEO_NO_CHILD) {
325
+ this.entered_child.push(-1);
326
+ continue;
327
+ }
328
+
329
+ const child_page = reader.page(child_ref === VGEO_SAME_PAGE ? page.index : page.child_page_index[child_ref]);
330
+ const child_group = page.child_group[cluster];
331
+ const child = this.page_base[child_page.index] + child_group;
332
+
333
+ this.entered_child.push(child);
334
+
335
+ this.arrived[child]++;
336
+ this.parent_triangles[child] += triangles;
337
+
338
+ if (this.arrived[child] === child_page.group_parent_count[child_group]) {
339
+ this.refinable.insert(child, page.self_error[cluster]);
340
+ }
341
+ }
342
+ }
343
+ }
@@ -36,7 +36,22 @@ export class VirtualGeometry extends MeshletGeometry {
36
36
  * @type {number}
37
37
  */
38
38
  vg_row: number;
39
+ /**
40
+ * An ordinary geometry standing in for this one where a plain mesh is needed: what its geometry cache is baked
41
+ * from and its cards are drawn from. A cut of the container ({@link vgeo_to_proxy_mesh}) at
42
+ * {@link vgeo_proxy_triangle_limit} of the source's triangles, in the geometry's own space, with its attributes;
43
+ * asked for once, and the same proxy every time after.
44
+ *
45
+ * TODO: a container is expected to be delivered with its proxy, baked offline, and the proxy loaded here. Until
46
+ * then it is cut here, through a reader of its own over the container's bytes: the shared {@link reader}'s pages
47
+ * are its residency's, and the cut would install pages behind that residency's budget.
48
+ *
49
+ * @returns {Promise<MeshletGeometry>}
50
+ */
51
+ get_proxy(): Promise<MeshletGeometry>;
39
52
  isVirtualGeometry: boolean;
53
+ #private;
40
54
  }
41
55
  import { MeshletGeometry } from "../../MeshletGeometry.js";
56
+ import { VGeoContainerReader } from "../format/read/VGeoContainerReader.js";
42
57
  //# sourceMappingURL=VirtualGeometry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualGeometry.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAeI;;OAEG;IACH,yCAqBC;IAtCD;;;;OAIG;IACH,4BAAO;IAEP;;;;OAIG;IACH,QAFU,MAAM,CAEgB;IAyDpC,2BAA2C;CAF1C;gCA5F+B,0BAA0B"}
1
+ {"version":3,"file":"VirtualGeometry.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAqBI;;OAEG;IACH,oBAFW,mBAAmB,EAuB7B;IA5CD;;;;OAIG;IACH,QAFU,mBAAmB,CAEtB;IAEP;;;;OAIG;IACH,QAFU,MAAM,CAEgB;IAkChC;;;;;;;;;;;OAWG;IACH,aAFa,QAAQ,eAAe,CAAC,CAQpC;IAwCL,2BAA2C;;CAF1C;gCAlI+B,0BAA0B;oCACtB,uCAAuC"}
@@ -1,5 +1,8 @@
1
1
  import { assert } from "../../../../../core/assert.js";
2
2
  import { MeshletGeometry } from "../../MeshletGeometry.js";
3
+ import { VGeoContainerReader } from "../format/read/VGeoContainerReader.js";
4
+ import { vgeo_proxy_triangle_limit } from "../proxy/vgeo_proxy_triangle_limit.js";
5
+ import { vgeo_to_proxy_mesh } from "../proxy/vgeo_to_proxy_mesh.js";
3
6
  import { VGEO_GEOMETRY_ROW_NONE } from "./layout/VGEO_GEOMETRY_ROW_NONE.js";
4
7
 
5
8
  /**
@@ -38,6 +41,12 @@ export class VirtualGeometry extends MeshletGeometry {
38
41
  */
39
42
  vg_row = VGEO_GEOMETRY_ROW_NONE;
40
43
 
44
+ /**
45
+ * The proxy, once asked for.
46
+ * @type {Promise<MeshletGeometry>|null}
47
+ */
48
+ #proxy = null;
49
+
41
50
  /**
42
51
  * @param {VGeoContainerReader} reader an open container
43
52
  */
@@ -64,6 +73,35 @@ export class VirtualGeometry extends MeshletGeometry {
64
73
  this.primitive_count = Number(header.source_face_count);
65
74
  }
66
75
 
76
+ /**
77
+ * An ordinary geometry standing in for this one where a plain mesh is needed: what its geometry cache is baked
78
+ * from and its cards are drawn from. A cut of the container ({@link vgeo_to_proxy_mesh}) at
79
+ * {@link vgeo_proxy_triangle_limit} of the source's triangles, in the geometry's own space, with its attributes;
80
+ * asked for once, and the same proxy every time after.
81
+ *
82
+ * TODO: a container is expected to be delivered with its proxy, baked offline, and the proxy loaded here. Until
83
+ * then it is cut here, through a reader of its own over the container's bytes: the shared {@link reader}'s pages
84
+ * are its residency's, and the cut would install pages behind that residency's budget.
85
+ *
86
+ * @returns {Promise<MeshletGeometry>}
87
+ */
88
+ get_proxy() {
89
+ if (this.#proxy === null) {
90
+ this.#proxy = this.#cut_proxy();
91
+ }
92
+
93
+ return this.#proxy;
94
+ }
95
+
96
+ /**
97
+ * @returns {Promise<MeshletGeometry>}
98
+ */
99
+ async #cut_proxy() {
100
+ const reader = await VGeoContainerReader.open(this.reader.source);
101
+
102
+ return vgeo_to_proxy_mesh(reader, vgeo_proxy_triangle_limit(this.primitive_count));
103
+ }
104
+
67
105
  /**
68
106
  * A virtual geometry's identity is its **container**, not its meshlets.
69
107
  *