@woosh/meep-engine 3.25.0 → 3.27.0

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 (295) hide show
  1. package/package.json +1 -1
  2. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
  3. package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
  4. package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
  5. package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
  6. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
  7. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
  8. package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
  9. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
  10. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
  11. package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
  12. package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
  13. package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
  14. package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
  15. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +66 -0
  16. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  17. package/src/core/geom/3d/shape/HeightMapShape3D.js +314 -20
  18. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
  20. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  21. package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
  22. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  23. package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
  24. package/src/engine/physics/cloth/MEASUREMENTS.md +582 -0
  25. package/src/engine/physics/cloth/PLAN.md +330 -49
  26. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
  27. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  28. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
  29. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +65 -7
  30. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  31. package/src/engine/physics/cloth/ecs/ClothInstance.js +72 -8
  32. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +25 -4
  33. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  34. package/src/engine/physics/cloth/ecs/ClothSystem.js +75 -8
  35. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +41 -4
  36. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  37. package/src/engine/physics/cloth/ecs/ClothWorld.js +207 -63
  38. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +10 -0
  39. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  40. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +17 -1
  41. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +27 -3
  42. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  43. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +28 -3
  44. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +75 -10
  45. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  46. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +131 -12
  47. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
  48. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  49. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
  50. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
  51. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  52. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
  53. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  54. package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
  55. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  56. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
  57. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  58. package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
  59. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +12 -2
  60. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  61. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +12 -2
  62. package/src/engine/physics/cloth/solver/cloth_step_instance.js +1 -1
  63. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
  64. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
  65. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
  66. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +23 -9
  67. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -1
  68. package/src/engine/physics/cloth/wind/AbstractClothWind.js +23 -9
  69. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +7 -5
  70. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +12 -9
  72. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
  73. package/src/engine/physics/cloth/wind/ClothFluidWind.js +5 -2
  74. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +7 -2
  75. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  76. package/src/engine/physics/cloth/wind/cloth_sample_air.js +12 -5
  77. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  78. package/src/shade/playground/vgeo_runtime/README.md +167 -22
  79. package/src/shade/playground/vgeo_runtime/index.html +112 -62
  80. package/src/shade/playground/vgeo_runtime/main.js +660 -83
  81. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
  82. package/src/shade/playground/vgeo_viewer/sample_asset.js +19 -2
  83. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
  84. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  85. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
  86. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
  88. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +73 -5
  89. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +26 -15
  90. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +5 -3
  91. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +18 -0
  92. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  93. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +20 -0
  94. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +56 -9
  96. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  97. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -0
  98. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
  99. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  100. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
  101. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
  102. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  103. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
  104. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
  105. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  106. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
  107. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
  108. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  109. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
  110. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
  111. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
  112. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
  113. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
  114. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
  115. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
  116. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
  117. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
  118. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
  119. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
  120. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
  121. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
  122. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
  123. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
  124. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
  125. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
  127. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
  128. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  129. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
  130. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
  131. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  132. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
  133. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
  134. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  135. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
  136. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
  137. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
  138. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
  139. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
  140. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  141. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
  142. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
  143. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
  144. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
  145. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
  146. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  147. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
  148. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
  149. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
  150. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
  151. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
  152. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
  153. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
  154. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +55 -0
  156. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  157. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +202 -13
  158. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  159. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +147 -10
  160. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +637 -0
  161. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
  162. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
  163. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
  164. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +58 -28
  165. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  166. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +77 -105
  167. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +105 -22
  169. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
  171. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  172. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +47 -489
  173. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1363 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
  183. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  184. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
  185. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +15 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +186 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +20 -8
  210. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  211. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +580 -188
  212. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
  213. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
  214. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
  250. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
  251. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
  252. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
  253. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  254. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
  255. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  256. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
  257. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  258. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  259. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
  260. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  261. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
  262. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  263. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  264. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
  265. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
  266. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  267. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  268. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  269. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
  270. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  271. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
  272. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  273. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
  274. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  275. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
  276. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  277. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
  278. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  279. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +7 -1
  280. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  281. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +7 -1
  282. package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
  283. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  284. package/src/shade/renderer/scene/GPUSceneContext.js +59 -4
  285. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  286. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
  287. package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
  288. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  289. package/src/shade/renderer/view/GPUViewContext.js +21 -0
  290. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  291. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
  292. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
  293. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
  294. package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
  295. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @typedef {import("./GPUVirtualGeometryRuntime.js").GPUVirtualGeometryRuntime} GPUVirtualGeometryRuntime
3
+ */
4
+ /**
5
+ * What cutting is per **view** rather than per frame.
6
+ *
7
+ * A view owns this the way it owns its HZB and its previous camera, and for the same reason: these
8
+ * are the things two views must not share. The runtime above it owns what a *scene* has — the page
9
+ * tables, the arena, the pool — and a frame owns the feedback buffer every view writes into.
10
+ *
11
+ * ## Why the params are here and not on the runtime
12
+ *
13
+ * `projection_k` is `screen_height / (2·tan(fov_y/2))`: a property of a render target and a camera,
14
+ * which is to say of a view. One buffer on the runtime meant one value for the frame, written from
15
+ * whichever view opened it — so a shadow cascade cut against the main view's projection and
16
+ * selected a level for a screen it is not drawn to. That is a live defect independent of anything
17
+ * a kept cut needs, and the fix is that each view writes its own.
18
+ *
19
+ * **One buffer per view, not one buffer with an offset per view.** Views are few — a main view and
20
+ * a handful of cascades — and a uniform is tens of bytes, so the saving from packing them would be
21
+ * nothing against giving every per-view value a second index to be wrong in.
22
+ *
23
+ * @author Alex Goldring
24
+ * @copyright Company Named Limited (c) 2026
25
+ */
26
+ export class VGeoViewCut {
27
+ /**
28
+ * @param {Object} options
29
+ * @param {GPUDevice} options.device
30
+ * @param {string} [options.label] names the buffer in a capture
31
+ */
32
+ constructor({ device, label }: {
33
+ device: GPUDevice;
34
+ label?: string;
35
+ });
36
+ /**
37
+ * The uniform every pass of this view's cut reads.
38
+ *
39
+ * @returns {GPUBuffer}
40
+ */
41
+ get params_buffer(): GPUBuffer;
42
+ /**
43
+ * @returns {number}
44
+ */
45
+ get projection_k(): number;
46
+ /**
47
+ * Where this view's last cut stood, as one bit per page row.
48
+ *
49
+ * @returns {GPUBuffer|undefined}
50
+ */
51
+ get frontier_buffer(): any;
52
+ /**
53
+ * @returns {number}
54
+ */
55
+ get frontier_word_count(): number;
56
+ /**
57
+ * Size the frontier to the tier it will name rows of.
58
+ *
59
+ * Lazily, and re-made rather than grown when the tier's capacity changes: what it holds
60
+ * is row indices of that tier, so a bigger tier does not extend the old answer, it
61
+ * invalidates it. Dropping it costs one frame of root descent, which is the fallback
62
+ * every other invalidation takes too.
63
+ *
64
+ * @param {number} page_row_capacity
65
+ * @returns {void}
66
+ */
67
+ resize_frontier(page_row_capacity: number): void;
68
+ /**
69
+ * Take this view's projection from the target it draws to and the camera it draws with.
70
+ *
71
+ * @param {Object} options
72
+ * @param {number} options.screen_height pixels of the render target
73
+ * @param {number} options.fov_y radians
74
+ * @returns {void}
75
+ */
76
+ set_projection({ screen_height, fov_y }: {
77
+ screen_height: number;
78
+ fov_y: number;
79
+ }): void;
80
+ /**
81
+ * Publish the frame's shared settings and this view's own, as one uniform.
82
+ *
83
+ * Everything but `projection_k` and `flags` is a property of the runtime or the frame, so it is
84
+ * read from the runtime at write time rather than mirrored here — a second copy of `tau` is a
85
+ * second thing to forget to update.
86
+ *
87
+ * @param {Object} options
88
+ * @param {GPUVirtualGeometryRuntime} options.runtime inside an open frame
89
+ * @param {boolean} [options.coarsen] whether this view's cut may walk up
90
+ * @returns {void}
91
+ */
92
+ write_params({ runtime, coarsen }: {
93
+ runtime: GPUVirtualGeometryRuntime;
94
+ coarsen?: boolean;
95
+ }): void;
96
+ destroy(): void;
97
+ #private;
98
+ }
99
+ export type GPUVirtualGeometryRuntime = import("./GPUVirtualGeometryRuntime.js").GPUVirtualGeometryRuntime;
100
+ //# sourceMappingURL=VGeoViewCut.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VGeoViewCut.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js"],"names":[],"mappings":"AAOA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAwCI;;;;OAIG;IACH;QAH8B,MAAM;QACR,KAAK,GAAtB,MAAM;OAehB;IAED;;;;OAIG;IACH,+BAEC;IAED;;OAEG;IACH,2BAEC;IAED;;;;OAIG;IACH,2BAEC;IAED;;OAEG;IACH,kCAEC;IAED;;;;;;;;;;OAUG;IACH,mCAHW,MAAM,GACJ,IAAI,CAkBhB;IAED;;;;;;;OAOG;IACH;QAJ2B,aAAa,EAA7B,MAAM;QACU,KAAK,EAArB,MAAM;QACJ,IAAI,CAShB;IAED;;;;;;;;;;;OAWG;IACH;QAJ8C,OAAO,EAA1C,yBAAyB;QACP,OAAO,GAAzB,OAAO;QACL,IAAI,CA8BhB;IAED,gBAIC;;CACJ;wCAlNY,OAAO,gCAAgC,EAAE,yBAAyB"}
@@ -0,0 +1,219 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+ import { VGEO_CUT_FLAG_COARSEN } from "./cut/VGEO_CUT_FLAG_COARSEN.js";
3
+ import { VGEO_CUT_FLAG_CULL } from "./cut/VGEO_CUT_FLAG_CULL.js";
4
+ import { VGEO_CUT_PARAMS_STRUCT } from "./cut/VGEO_CUT_PARAMS_STRUCT.js";
5
+ import { vgeo_frontier_words } from "./vgeo_frontier_words.js";
6
+ import { write_gpu_typed_buffer } from "../../../shader/type/serde/write_gpu_typed_buffer.js";
7
+
8
+ /**
9
+ * @typedef {import("./GPUVirtualGeometryRuntime.js").GPUVirtualGeometryRuntime} GPUVirtualGeometryRuntime
10
+ */
11
+
12
+ /**
13
+ * What cutting is per **view** rather than per frame.
14
+ *
15
+ * A view owns this the way it owns its HZB and its previous camera, and for the same reason: these
16
+ * are the things two views must not share. The runtime above it owns what a *scene* has — the page
17
+ * tables, the arena, the pool — and a frame owns the feedback buffer every view writes into.
18
+ *
19
+ * ## Why the params are here and not on the runtime
20
+ *
21
+ * `projection_k` is `screen_height / (2·tan(fov_y/2))`: a property of a render target and a camera,
22
+ * which is to say of a view. One buffer on the runtime meant one value for the frame, written from
23
+ * whichever view opened it — so a shadow cascade cut against the main view's projection and
24
+ * selected a level for a screen it is not drawn to. That is a live defect independent of anything
25
+ * a kept cut needs, and the fix is that each view writes its own.
26
+ *
27
+ * **One buffer per view, not one buffer with an offset per view.** Views are few — a main view and
28
+ * a handful of cascades — and a uniform is tens of bytes, so the saving from packing them would be
29
+ * nothing against giving every per-view value a second index to be wrong in.
30
+ *
31
+ * @author Alex Goldring
32
+ * @copyright Company Named Limited (c) 2026
33
+ */
34
+ export class VGeoViewCut {
35
+ /**
36
+ * @type {GPUDevice}
37
+ */
38
+ #device;
39
+
40
+ /**
41
+ * @type {string}
42
+ */
43
+ #label;
44
+
45
+ /**
46
+ * @type {GPUBuffer}
47
+ */
48
+ #params;
49
+
50
+ /**
51
+ * Scratch for one params write, so a per-frame write allocates nothing.
52
+ * @type {ArrayBuffer}
53
+ */
54
+ #scratch;
55
+
56
+ /**
57
+ * `screen_height / (2 · tan(fov_y / 2))`, this view's.
58
+ * @type {number}
59
+ */
60
+ #projection_k = 1;
61
+
62
+ /**
63
+ * One bit per page row: the pages this view's cut drew from, kept between frames.
64
+ * Undefined until the first frame that knows how big the tier is.
65
+ * @type {GPUBuffer|undefined}
66
+ */
67
+ #frontier;
68
+
69
+ /**
70
+ * @type {number}
71
+ */
72
+ #frontier_word_count = 0;
73
+
74
+ /**
75
+ * @param {Object} options
76
+ * @param {GPUDevice} options.device
77
+ * @param {string} [options.label] names the buffer in a capture
78
+ */
79
+ constructor({ device, label = 'a view' }) {
80
+ assert.defined(device, 'device');
81
+
82
+ this.#device = device;
83
+ this.#label = label;
84
+
85
+ this.#params = device.createBuffer({
86
+ label: `VGeoViewCut/params (${label})`,
87
+ size: VGEO_CUT_PARAMS_STRUCT.aligned_size,
88
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
89
+ });
90
+
91
+ this.#scratch = new ArrayBuffer(VGEO_CUT_PARAMS_STRUCT.aligned_size);
92
+ }
93
+
94
+ /**
95
+ * The uniform every pass of this view's cut reads.
96
+ *
97
+ * @returns {GPUBuffer}
98
+ */
99
+ get params_buffer() {
100
+ return this.#params;
101
+ }
102
+
103
+ /**
104
+ * @returns {number}
105
+ */
106
+ get projection_k() {
107
+ return this.#projection_k;
108
+ }
109
+
110
+ /**
111
+ * Where this view's last cut stood, as one bit per page row.
112
+ *
113
+ * @returns {GPUBuffer|undefined}
114
+ */
115
+ get frontier_buffer() {
116
+ return this.#frontier;
117
+ }
118
+
119
+ /**
120
+ * @returns {number}
121
+ */
122
+ get frontier_word_count() {
123
+ return this.#frontier_word_count;
124
+ }
125
+
126
+ /**
127
+ * Size the frontier to the tier it will name rows of.
128
+ *
129
+ * Lazily, and re-made rather than grown when the tier's capacity changes: what it holds
130
+ * is row indices of that tier, so a bigger tier does not extend the old answer, it
131
+ * invalidates it. Dropping it costs one frame of root descent, which is the fallback
132
+ * every other invalidation takes too.
133
+ *
134
+ * @param {number} page_row_capacity
135
+ * @returns {void}
136
+ */
137
+ resize_frontier(page_row_capacity) {
138
+ const words = vgeo_frontier_words(page_row_capacity);
139
+
140
+ if (this.#frontier !== undefined && words === this.#frontier_word_count) {
141
+ return;
142
+ }
143
+
144
+ this.#frontier?.destroy();
145
+
146
+ this.#frontier_word_count = words;
147
+
148
+ this.#frontier = this.#device.createBuffer({
149
+ label: `VGeoViewCut/frontier (${this.#label})`,
150
+ size: Math.max(4, words * 4),
151
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Take this view's projection from the target it draws to and the camera it draws with.
157
+ *
158
+ * @param {Object} options
159
+ * @param {number} options.screen_height pixels of the render target
160
+ * @param {number} options.fov_y radians
161
+ * @returns {void}
162
+ */
163
+ set_projection({ screen_height, fov_y }) {
164
+ assert.isNumber(screen_height, 'screen_height');
165
+ assert.greaterThan(screen_height, 0, 'screen_height');
166
+ assert.isNumber(fov_y, 'fov_y');
167
+ assert.greaterThan(fov_y, 0, 'fov_y');
168
+
169
+ this.#projection_k = screen_height / (2 * Math.tan(fov_y * 0.5));
170
+ }
171
+
172
+ /**
173
+ * Publish the frame's shared settings and this view's own, as one uniform.
174
+ *
175
+ * Everything but `projection_k` and `flags` is a property of the runtime or the frame, so it is
176
+ * read from the runtime at write time rather than mirrored here — a second copy of `tau` is a
177
+ * second thing to forget to update.
178
+ *
179
+ * @param {Object} options
180
+ * @param {GPUVirtualGeometryRuntime} options.runtime inside an open frame
181
+ * @param {boolean} [options.coarsen] whether this view's cut may walk up
182
+ * @returns {void}
183
+ */
184
+ write_params({ runtime, coarsen = false }) {
185
+ assert.defined(runtime, 'runtime');
186
+
187
+ const layout = runtime.feedback_layout;
188
+
189
+ assert.defined(layout, 'runtime.feedback_layout — begin_frame must have run');
190
+
191
+ write_gpu_typed_buffer({
192
+ tau: runtime.tau,
193
+ projection_k: this.#projection_k,
194
+ queue_capacity: runtime.queue_capacity,
195
+ claim_word_count: runtime.claim_word_capacity,
196
+ descent_steps: runtime.descent_steps,
197
+ page_slot_words: runtime.pool.page_slot_words,
198
+ touch_bits_base: layout.touch_bits_base,
199
+ want_base: layout.want_base,
200
+ want_capacity: runtime.want_capacity,
201
+ frontier_word_count: this.#frontier_word_count,
202
+ frame_tag: runtime.pool.frame,
203
+ instance_capacity: runtime.instance_capacity,
204
+ meshlet_capacity: runtime.meshlet_capacity,
205
+ flags: (runtime.cull_enabled ? VGEO_CUT_FLAG_CULL : 0)
206
+ | (coarsen ? VGEO_CUT_FLAG_COARSEN : 0),
207
+ }, VGEO_CUT_PARAMS_STRUCT, this.#scratch, 0);
208
+
209
+ this.#device.queue.writeBuffer(
210
+ this.#params, 0, this.#scratch, 0, VGEO_CUT_PARAMS_STRUCT.aligned_size
211
+ );
212
+ }
213
+
214
+ destroy() {
215
+ this.#params.destroy();
216
+
217
+ this.#frontier?.destroy();
218
+ }
219
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * What an executed cut item expands into — the three shapes a child can have.
3
+ *
4
+ * The traversal states its production as a *kind*, a count and a base rather than as children
5
+ * written anywhere, because any lane of the subgroup has to be able to build child `k` of any other
6
+ * lane's item out of a handful of shuffled words. A kind is what makes those words mean something
7
+ * without a second read of the row that produced them.
8
+ */
9
+ export type VGEO_CUT_EXPAND = number;
10
+ export namespace VGEO_CUT_EXPAND {
11
+ let NONE: number;
12
+ let NODES: number;
13
+ let CLUSTERS: number;
14
+ let PAGE: number;
15
+ let PARENTS: number;
16
+ }
17
+ //# sourceMappingURL=VGEO_CUT_EXPAND.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VGEO_CUT_EXPAND.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js"],"names":[],"mappings":";;;;;;;;8BAYU,MAAM"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * What an executed cut item expands into — the three shapes a child can have.
3
+ *
4
+ * The traversal states its production as a *kind*, a count and a base rather than as children
5
+ * written anywhere, because any lane of the subgroup has to be able to build child `k` of any other
6
+ * lane's item out of a handful of shuffled words. A kind is what makes those words mean something
7
+ * without a second read of the row that produced them.
8
+ *
9
+ * @see shader_vgeo_cut_traverse
10
+ *
11
+ * @author Alex Goldring
12
+ * @copyright Company Named Limited (c) 2026
13
+ * @enum {number}
14
+ */
15
+ export const VGEO_CUT_EXPAND = {
16
+ /**
17
+ * Nothing. Culled, below the cut, drawn, or clamped — every terminal case of the rule.
18
+ */
19
+ NONE: 0,
20
+ /**
21
+ * `count` child nodes of the same page, starting at node index `first`.
22
+ */
23
+ NODES: 1,
24
+ /**
25
+ * `count` clusters, spread over the `span` groups starting at group index `first`.
26
+ *
27
+ * The count is every cluster the leaf covers rather than a number of chunks: a lane no longer
28
+ * walks a run of them, so there is nothing to chunk. `span` is carried instead of assumed
29
+ * because the walk that maps child `k` back to a group has to terminate on a row the builder
30
+ * wrote, not on a bound this file believes about the format.
31
+ */
32
+ CLUSTERS: 2,
33
+ /**
34
+ * One node 0, in the page at `page_row` — a descent crossing a page boundary, already claimed
35
+ * by the lane that produced it.
36
+ */
37
+ PAGE: 3,
38
+ /**
39
+ * `count` entries of the parent rows of the page at `page_row`, starting at entry `first` —
40
+ * a group's whole parent list, which is one step of a walk up.
41
+ *
42
+ * Unlike {@link PAGE} these are **not** claimed by the producer; each child claims the page
43
+ * it resolves to when it is executed. See `VGEO_QUEUE_TARGET_PARENT_BIT` for why the claim
44
+ * cannot be hoisted into the producer the way the descent's can.
45
+ */
46
+ PARENTS: 4,
47
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `VGEO_CUT_PARAMS_STRUCT.flags`: a cluster below the cut walks **up** instead of stopping.
3
+ *
4
+ * Every edge the descent follows points down, so a traversal that finds itself below the cut — its
5
+ * consuming step already projecting to no more than tau — can only stop, and a runtime that wanted
6
+ * to keep a cut between frames would have to answer every coarsening camera by re-descending from
7
+ * the root. With this set, such a cluster expands into the pages holding its group\x27s parents
8
+ * instead (format §6.3), and the walk continues until it reaches clusters the rule draws.
9
+ *
10
+ * Off by default, and the descent with it off is byte for byte the descent that shipped: the root
11
+ * seed reaches every group through a parent that projected above tau, so the branch this opens is
12
+ * one the descent does not take. It is a flag rather than a behaviour because the cut it belongs to
13
+ * is a *kept* one, which is per view, and CUT_PLAN_2026_09_14 §7.6 is where a view gets to say so.
14
+ *
15
+ * @author Alex Goldring
16
+ * @copyright Company Named Limited (c) 2026
17
+ * @type {number}
18
+ */
19
+ export const VGEO_CUT_FLAG_COARSEN: number;
20
+ //# sourceMappingURL=VGEO_CUT_FLAG_COARSEN.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VGEO_CUT_FLAG_COARSEN.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,oCAFU,MAAM,CAEuB"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `VGEO_CUT_PARAMS_STRUCT.flags`: a cluster below the cut walks **up** instead of stopping.
3
+ *
4
+ * Every edge the descent follows points down, so a traversal that finds itself below the cut — its
5
+ * consuming step already projecting to no more than tau — can only stop, and a runtime that wanted
6
+ * to keep a cut between frames would have to answer every coarsening camera by re-descending from
7
+ * the root. With this set, such a cluster expands into the pages holding its group\x27s parents
8
+ * instead (format §6.3), and the walk continues until it reaches clusters the rule draws.
9
+ *
10
+ * Off by default, and the descent with it off is byte for byte the descent that shipped: the root
11
+ * seed reaches every group through a parent that projected above tau, so the branch this opens is
12
+ * one the descent does not take. It is a flag rather than a behaviour because the cut it belongs to
13
+ * is a *kept* one, which is per view, and CUT_PLAN_2026_09_14 §7.6 is where a view gets to say so.
14
+ *
15
+ * @author Alex Goldring
16
+ * @copyright Company Named Limited (c) 2026
17
+ * @type {number}
18
+ */
19
+ export const VGEO_CUT_FLAG_COARSEN = 2;
@@ -1 +1 @@
1
- {"version":3,"file":"VGEO_CUT_PARAMS_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,kDA+D2B;6BAjFE,yCAAyC"}
1
+ {"version":3,"file":"VGEO_CUT_PARAMS_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,kDAiF2B;6BAnGE,yCAAyC"}
@@ -41,9 +41,25 @@ export const VGEO_CUT_PARAMS_STRUCT = WebGPUStruct.from({
41
41
  */
42
42
  claim_word_count: u32,
43
43
  /**
44
- * How many clusters one group-chunk item covers.
44
+ * Words of this view's frontier bitmask — one bit per page row, and the bound a write
45
+ * into it is clamped against.
46
+ *
47
+ * Zero says this view keeps no frontier, which is what every cut did before one existed
48
+ * and what a cut still does when the flag is off: the bound rejects every write rather
49
+ * than a branch having to ask.
50
+ */
51
+ frontier_word_count: u32,
52
+ /**
53
+ * Steps of the descent one dispatch of the traversal runs before handing what it still holds
54
+ * back to the queue.
55
+ *
56
+ * WGSL will not let a loop around a subgroup operation have a non-uniform trip count, and
57
+ * nothing launders one — so the descent cannot stop when the wave runs dry. It runs this many
58
+ * times and masks, at about ten instructions a step for a wave with nothing left. That makes
59
+ * this a tuning knob between idle steps and dispatches, and not a safety bound:
60
+ * `VGEO_CUT_STAT.QUEUE_REMAINING` is what says it was set too low.
45
61
  */
46
- cluster_chunk: u32,
62
+ descent_steps: u32,
47
63
  /**
48
64
  * Arena words one page slot holds — the stride a page row is multiplied by.
49
65
  *
@@ -53,19 +69,21 @@ export const VGEO_CUT_PARAMS_STRUCT = WebGPUStruct.from({
53
69
  */
54
70
  page_slot_words: u32,
55
71
  /**
56
- * Word offset in the feedback buffer of the per-page-row touch stamps.
72
+ * Word offset in the feedback buffer of the touch bits — one per page row, set with an
73
+ * `atomicOr` when a page's claim is won. The bit is the dedup and the record at once, so there
74
+ * is no list to overflow and nothing per row to clear beyond the transient itself.
57
75
  */
58
- touch_stamp_base: u32,
59
- /**
60
- * Word offset in the feedback buffer of the per-lookup-word want stamps. A want's stamp index
61
- * is this plus the geometry's lookup offset plus the child page index, which is why the page
62
- * lookup has its own buffer and its own allocator: it makes that a compact, dense index.
63
- */
64
- want_stamp_base: u32,
76
+ touch_bits_base: u32,
65
77
  want_base: u32,
66
78
  want_capacity: u32,
67
- touch_base: u32,
68
- touch_capacity: u32,
79
+ /**
80
+ * What this frame writes into the want-stamp buffer to claim a want, and what it compares
81
+ * against to dedup one. The stamps are persistent and one per lookup word — one per page of
82
+ * every registered geometry — so they are not cleared per frame; a stamp holding this frame's
83
+ * tag was written this frame, and any other value was not. Never zero, which is what a fresh
84
+ * buffer holds.
85
+ */
86
+ frame_tag: u32,
69
87
  /**
70
88
  * Records the VG instance buffer holds, for the one append in the cut that had no bound.
71
89
  */
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_vgeo_cut_access.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;GAeG;AACH,oCAFU,SAAS,CAqIZ;0BA/JmB,0CAA0C"}
1
+ {"version":3,"file":"chunk_vgeo_cut_access.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;GAeG;AACH,oCAFU,SAAS,CAmJZ;0BA9KmB,0CAA0C"}
@@ -9,6 +9,7 @@ import { VGEO_NODE_ROW_OFFSET } from "../layout/VGEO_NODE_ROW_OFFSET.js";
9
9
  import { VGEO_NODE_ROW_WORDS } from "../layout/VGEO_NODE_ROW_WORDS.js";
10
10
  import { VGEO_PAGE_ROW_OFFSET } from "../layout/VGEO_PAGE_ROW_OFFSET.js";
11
11
  import { VGEO_PAGE_ROW_WORDS } from "../layout/VGEO_PAGE_ROW_WORDS.js";
12
+ import { VGEO_PARENT_ROW_WORDS } from "../layout/VGEO_PARENT_ROW_WORDS.js";
12
13
 
13
14
  /**
14
15
  * Addressing and arithmetic shared by every pass of the cut — how to find a row, and how to project
@@ -33,6 +34,7 @@ const VG_PAGE_ROW_WORDS = ${VGEO_PAGE_ROW_WORDS}u;
33
34
  const VG_NODE_ROW_WORDS = ${VGEO_NODE_ROW_WORDS}u;
34
35
  const VG_GROUP_ROW_WORDS = ${VGEO_GROUP_ROW_WORDS}u;
35
36
  const VG_CLUSTER_ROW_WORDS = ${VGEO_CLUSTER_ROW_WORDS}u;
37
+ const VG_PARENT_ROW_WORDS = ${VGEO_PARENT_ROW_WORDS}u;
36
38
  const VG_INSTANCE_WORDS = ${VGEO_INSTANCE_WORDS}u;
37
39
  const VG_GEOMETRY_ROW_WORDS = ${VGEO_GEOMETRY_ROW_WORDS}u;
38
40
 
@@ -80,6 +82,19 @@ fn vg_cluster_base(page_row: u32) -> u32 {
80
82
  + vg_page_field(page_row, ${VGEO_PAGE_ROW_OFFSET.GROUP_COUNT}u) * VG_GROUP_ROW_WORDS;
81
83
  }
82
84
 
85
+ /**
86
+ * The fourth section: this page's parent rows, which is where a walk *up* reads.
87
+ *
88
+ * It may be empty, and a reader has to check rather than assume: the page row's parent
89
+ * entry count is zero for
90
+ * every page of a container written before format 4, which has no upward edge at all. Zero is not a
91
+ * malformed page; it is an asset that can only be re-descended.
92
+ */
93
+ fn vg_parent_base(page_row: u32) -> u32 {
94
+ return vg_cluster_base(page_row)
95
+ + vg_page_field(page_row, ${VGEO_PAGE_ROW_OFFSET.CLUSTER_COUNT}u) * VG_CLUSTER_ROW_WORDS;
96
+ }
97
+
83
98
  fn vg_arena_f32(word: u32) -> f32 {
84
99
  return bitcast<f32>(vg_arena[word]);
85
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shader_vgeo_cut_collect.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js"],"names":[],"mappings":"AA0PA,oDAIG;8BAxP2B,qCAAqC"}
1
+ {"version":3,"file":"shader_vgeo_cut_collect.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js"],"names":[],"mappings":"AA2QA,oDAIG;8BAzQ2B,qCAAqC"}
@@ -102,7 +102,24 @@ fn vg_store_plane(base: u32, plane: u32, row_w: vec4<f32>, row: vec4<f32>, sign:
102
102
  fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
103
103
  let input_index = global_id.x;
104
104
 
105
- if (input_index >= input_meshes.count) {
105
+ /*
106
+ The count, against what the collection can actually hold, the way every sibling filter over
107
+ this shape reads it. The producer feeding this seam — \`shader_hzb_mesh_filter_2way\` — reserves
108
+ a slot with an unconditional \`atomicAdd\` and bounds-checks only the element *write*, so a
109
+ bucket whose positive set overflows hands over a count past the end of its own elements. The
110
+ indirect dispatch is built from that same count, so the overshoot arrives here as extra lanes
111
+ rather than as a loop bound this pass could have ignored.
112
+
113
+ Reading past the end is not the failure — robustness bounds that. The failure is what the
114
+ bounded read comes back with: a mesh row this bucket never selected, which the lines below
115
+ treat as a real instance, and if that row's geometry happens to be virtual it is collected and
116
+ cut. Every other bound in this pass degrades toward *fewer* instances; this one degraded into a
117
+ cut of geometry nobody asked for, which is the one direction a silently-wrong picture comes
118
+ from.
119
+ */
120
+ let input_size = min(input_meshes.count, arrayLength(&input_meshes.elements));
121
+
122
+ if (input_index >= input_size) {
106
123
  return;
107
124
  }
108
125
 
@@ -1 +1 @@
1
- {"version":3,"file":"shader_vgeo_cut_queue_prepare.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js"],"names":[],"mappings":"AA2EA,0DAIG;8BA3E2B,qCAAqC"}
1
+ {"version":3,"file":"shader_vgeo_cut_queue_prepare.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js"],"names":[],"mappings":"AAiEA,0DAIG;8BAnE2B,qCAAqC"}
@@ -1,5 +1,3 @@
1
- import { atomic_u32 } from "../../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
2
- import { WebGPUArray } from "../../../../shader/type/WebGPUArray.js";
3
1
  import { CodeChunk } from "../../../../shader/compiler/CodeChunk.js";
4
2
  import { COLLECTION_U32_STRUCT_WRITE } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_WRITE.js";
5
3
  import { ComputeShader } from "../../../../shader/ComputeShader.js";
@@ -8,8 +6,6 @@ import {
8
6
  } from "../../../../gpu_primitive/indirect/STRUCT_DISPATCH_COMPUTE_COMMAND.js";
9
7
  import { ShaderResourceSetDescriptor } from "../../../../shader/resource/ShaderResourceSetDescriptor.js";
10
8
  import { chunk_divide_round_up_u32 } from "../../../../shader/chunk/math/chunk_divide_round_up_u32.js";
11
- import { VGEO_CUT_STAT } from "../layout/VGEO_CUT_STAT.js";
12
- import { VGEO_FEEDBACK_OFFSET } from "../layout/VGEO_FEEDBACK_OFFSET.js";
13
9
  import { VGEO_CUT_PARAMS_STRUCT } from "./VGEO_CUT_PARAMS_STRUCT.js";
14
10
  import { VGEO_CUT_WORKGROUP_SIZE } from "./VGEO_CUT_WORKGROUP_SIZE.js";
15
11
 
@@ -27,6 +23,11 @@ import { VGEO_CUT_WORKGROUP_SIZE } from "./VGEO_CUT_WORKGROUP_SIZE.js";
27
23
  * the buffer this iteration reads is the one the next iteration writes, and there is exactly one
28
24
  * moment when neither pass is touching it.
29
25
  *
26
+ * **It records no statistic.** There is another wavefront after it, so the count it sees is a
27
+ * frontier rather than a remainder, and it runs once per iteration per expansion site, so anything
28
+ * it stored would be overwritten by the next iteration and then by the next site. What the descent
29
+ * was left holding is {@link shader_vgeo_cut_queue_remainder}, recorded once, after the loop.
30
+ *
30
31
  * @author Alex Goldring
31
32
  * @copyright Company Named Limited (c) 2026
32
33
  */
@@ -40,8 +41,6 @@ resources.createGroup()
40
41
  // what the next wavefront will produce into
41
42
  .addStorageBuffer("queue_spare", COLLECTION_U32_STRUCT_WRITE, true)
42
43
  .addStorageBuffer("command", STRUCT_DISPATCH_COMPUTE_COMMAND, true)
43
- // the frame's counters: this is the only pass that can see how deep the descent went
44
- .addStorageBuffer("feedback", WebGPUArray.from(atomic_u32), true)
45
44
  ;
46
45
 
47
46
  const body = CodeChunk.from(
@@ -56,15 +55,6 @@ fn main() {
56
55
  atomicStore(&queue_ready.count, count);
57
56
  atomicStore(&queue_spare.count, 0u);
58
57
 
59
- /*
60
- What was outstanding when this pass ran. A plain store rather than an add, so the last prepare
61
- of the frame is the one that is read — and the seam records one extra prepare after the
62
- wavefront loop, whose whole purpose is to leave this number behind. A descent that stops with
63
- work still queued is the one degradation that costs a hole rather than coarseness, and until
64
- now nothing anywhere counted it (REVIEW_LEDGER M8).
65
- */
66
- atomicStore(&feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + ${VGEO_CUT_STAT.QUEUE_REMAINING}u], count);
67
-
68
58
  command.workgroupCountX = divide_round_up_u32(count, ${VGEO_CUT_WORKGROUP_SIZE}u);
69
59
  command.workgroupCountY = 1u;
70
60
  command.workgroupCountZ = 1u;
@@ -0,0 +1,3 @@
1
+ export const shader_vgeo_cut_queue_remainder: ComputeShader;
2
+ import { ComputeShader } from "../../../../shader/ComputeShader.js";
3
+ //# sourceMappingURL=shader_vgeo_cut_queue_remainder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_vgeo_cut_queue_remainder.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js"],"names":[],"mappings":"AAwEA,4DAIG;8BAxE2B,qCAAqC"}