@woosh/meep-engine 3.24.0 → 3.25.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 (322) hide show
  1. package/package.json +1 -1
  2. package/src/engine/graphics3/PickingSystem.d.ts +3 -3
  3. package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
  4. package/src/engine/graphics3/PickingSystem.js +52 -55
  5. package/src/engine/graphics3/shader_picking_gather.d.ts +40 -0
  6. package/src/engine/graphics3/shader_picking_gather.d.ts.map +1 -0
  7. package/src/engine/graphics3/shader_picking_gather.js +120 -0
  8. package/src/engine/physics/cloth/MEASUREMENTS.md +1050 -0
  9. package/src/engine/physics/cloth/PLAN.md +411 -49
  10. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts +52 -0
  11. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts.map +1 -0
  12. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.js +70 -0
  13. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts +12 -3
  14. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
  15. package/src/engine/physics/cloth/ecs/ClothDynamics.js +340 -331
  16. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +36 -22
  17. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  18. package/src/engine/physics/cloth/ecs/ClothInstance.js +38 -23
  19. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts +84 -0
  20. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts.map +1 -0
  21. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.js +141 -0
  22. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +51 -82
  23. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  24. package/src/engine/physics/cloth/ecs/ClothSystem.js +81 -869
  25. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts +48 -0
  26. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts.map +1 -0
  27. package/src/engine/physics/cloth/ecs/ClothWorkerCore.js +107 -0
  28. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +286 -0
  29. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -0
  30. package/src/engine/physics/cloth/ecs/ClothWorld.js +1104 -0
  31. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +182 -0
  32. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -0
  33. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +562 -0
  34. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts +2 -0
  35. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts.map +1 -0
  36. package/src/engine/physics/cloth/ecs/cloth.worker.js +12 -0
  37. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  38. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +2 -1
  39. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +58 -0
  40. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  41. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +341 -271
  42. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +20 -2
  43. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  44. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +39 -15
  45. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts +29 -0
  46. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts.map +1 -0
  47. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.js +78 -0
  48. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts +17 -0
  49. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts.map +1 -0
  50. package/src/engine/physics/cloth/ecs/makeClothWorker.js +18 -0
  51. package/src/engine/physics/cloth/playground/README.md +73 -2
  52. package/src/engine/physics/cloth/playground/wind.html +166 -0
  53. package/src/engine/physics/cloth/playground/wind_build.d.ts +81 -0
  54. package/src/engine/physics/cloth/playground/wind_build.d.ts.map +1 -0
  55. package/src/engine/physics/cloth/playground/wind_build.js +141 -0
  56. package/src/engine/physics/cloth/playground/wind_main.d.ts +2 -0
  57. package/src/engine/physics/cloth/playground/wind_main.d.ts.map +1 -0
  58. package/src/engine/physics/cloth/playground/wind_main.js +681 -0
  59. package/src/engine/physics/cloth/solver/ClothState.d.ts +134 -79
  60. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  61. package/src/engine/physics/cloth/solver/ClothState.js +273 -12
  62. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +33 -0
  63. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  64. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +34 -0
  65. package/src/engine/physics/cloth/solver/cloth_step.d.ts +21 -2
  66. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  67. package/src/engine/physics/cloth/solver/cloth_step.js +173 -4
  68. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +40 -0
  69. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -0
  70. package/src/engine/physics/cloth/solver/cloth_step_instance.js +284 -0
  71. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts +107 -0
  72. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts.map +1 -0
  73. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.js +263 -0
  74. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +88 -0
  75. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -0
  76. package/src/engine/physics/cloth/wind/AbstractClothWind.js +100 -0
  77. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +85 -0
  78. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -0
  79. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +182 -0
  80. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +79 -0
  81. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -0
  82. package/src/engine/physics/cloth/wind/ClothFluidWind.js +210 -0
  83. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +101 -0
  84. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -0
  85. package/src/engine/physics/cloth/wind/cloth_sample_air.js +290 -0
  86. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  87. package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
  88. package/src/shade/device/mock/texture_copy.js +28 -0
  89. package/src/shade/playground/vgeo_runtime/README.md +94 -0
  90. package/src/shade/playground/vgeo_runtime/index.html +62 -0
  91. package/src/shade/playground/vgeo_runtime/main.d.ts +2 -0
  92. package/src/shade/playground/vgeo_runtime/main.d.ts.map +1 -0
  93. package/src/shade/playground/vgeo_runtime/main.js +399 -0
  94. package/src/shade/playground/vgeo_viewer/sample_asset.js +1 -1
  95. package/src/shade/renderer/camera/Camera.d.ts +14 -0
  96. package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
  97. package/src/shade/renderer/camera/Camera.js +7 -1
  98. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.d.ts.map +1 -1
  99. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.js +16 -1
  100. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  101. package/src/shade/renderer/geometry/GPUGeometryManager.js +29 -9
  102. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts +10 -0
  103. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts.map +1 -1
  104. package/src/shade/renderer/geometry/GPUGeometryMetadata.js +13 -0
  105. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +46 -18
  106. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +70 -22
  107. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +97 -19
  108. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +12 -2
  109. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  110. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +14 -3
  111. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts +2 -2
  112. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  113. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +124 -6
  114. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts +22 -0
  115. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +1 -0
  116. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.js +53 -0
  117. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +8 -1
  118. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  119. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +8 -1
  120. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts +16 -0
  121. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts.map +1 -0
  122. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.js +15 -0
  123. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts +54 -0
  124. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts.map +1 -0
  125. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.js +53 -0
  126. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +13 -2
  127. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  128. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +14 -2
  129. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +100 -0
  130. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  131. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +113 -0
  132. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.d.ts.map +1 -1
  133. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.js +5 -0
  134. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  135. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +108 -0
  136. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  137. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +23 -0
  138. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  139. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +40 -0
  140. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +228 -0
  141. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -0
  142. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +932 -0
  143. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +176 -0
  144. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -0
  145. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +425 -0
  146. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +241 -0
  147. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +574 -0
  148. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +120 -0
  149. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -0
  150. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +674 -0
  151. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +287 -0
  152. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -0
  153. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +976 -0
  154. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +42 -0
  155. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -0
  156. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +96 -0
  157. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts +16 -0
  158. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts.map +1 -0
  159. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.js +15 -0
  160. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts +19 -0
  161. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -0
  162. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +83 -0
  163. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts +9 -0
  164. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts.map +1 -0
  165. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.js +8 -0
  166. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +19 -0
  167. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +160 -0
  169. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts +3 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -0
  171. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +255 -0
  172. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts +3 -0
  173. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +80 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts +3 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +144 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts +3 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +530 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +39 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -0
  183. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +54 -0
  184. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts +41 -0
  185. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts.map +1 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.js +56 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts +49 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +328 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +10 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts.map +1 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +51 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +13 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -0
  195. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +12 -0
  196. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +17 -0
  197. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts.map +1 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +99 -0
  199. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts +9 -0
  200. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts.map +1 -0
  201. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +8 -0
  202. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +7 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +27 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts +14 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.js +13 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts +7 -0
  209. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts.map +1 -0
  210. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.js +35 -0
  211. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts +9 -0
  212. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts.map +1 -0
  213. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.js +8 -0
  214. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts +15 -0
  215. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts.map +1 -0
  216. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.js +14 -0
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +7 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts.map +1 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +36 -0
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +10 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -0
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +9 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts +11 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts.map +1 -0
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.js +54 -0
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts +9 -0
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts.map +1 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.js +8 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts +11 -0
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts.map +1 -0
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.js +10 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts +7 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts.map +1 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.js +30 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts +9 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts.map +1 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.js +8 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts +13 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts.map +1 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.js +12 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts +14 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts.map +1 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.js +13 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +11 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts.map +1 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +61 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts +9 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +8 -0
  250. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts +13 -0
  251. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts.map +1 -0
  252. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.js +12 -0
  253. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts +9 -0
  254. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts.map +1 -0
  255. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.js +8 -0
  256. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts +20 -0
  257. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts.map +1 -0
  258. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.js +19 -0
  259. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts +23 -0
  260. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -0
  261. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +70 -0
  262. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +18 -0
  263. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -0
  264. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +25 -0
  265. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +35 -0
  266. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -0
  267. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +41 -0
  268. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +32 -0
  269. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -0
  270. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +138 -0
  271. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  272. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  273. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  274. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +9 -0
  275. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  276. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +12 -1
  277. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  278. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +12 -1
  279. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  280. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +10 -0
  281. package/src/shade/renderer/scene/GPUSceneContext.d.ts +18 -0
  282. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  283. package/src/shade/renderer/scene/GPUSceneContext.js +647 -594
  284. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  285. package/src/shade/renderer/scene/rows/GPUSceneRows.js +22 -0
  286. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts +35 -0
  287. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts.map +1 -0
  288. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.js +91 -0
  289. package/src/engine/graphics3/instantiate_scene_bundle.d.ts +0 -54
  290. package/src/engine/graphics3/instantiate_scene_bundle.d.ts.map +0 -1
  291. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts +0 -39
  292. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts.map +0 -1
  293. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts +0 -35
  294. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts.map +0 -1
  295. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts +0 -96
  296. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts.map +0 -1
  297. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts +0 -20
  298. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts.map +0 -1
  299. package/src/shade/renderer/animation/skin_bind_transform.d.ts +0 -25
  300. package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +0 -1
  301. package/src/shade/renderer/animation/skin_frame_defect.d.ts +0 -34
  302. package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +0 -1
  303. package/src/shade/renderer/animation/skin_joint_matrix.d.ts +0 -24
  304. package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +0 -1
  305. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +0 -70
  306. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +0 -1
  307. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts +0 -96
  308. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts.map +0 -1
  309. package/src/shade/renderer/scene/InstanceBatch.d.ts +0 -92
  310. package/src/shade/renderer/scene/InstanceBatch.d.ts.map +0 -1
  311. package/src/shade/renderer/scene/Mesh.d.ts +0 -55
  312. package/src/shade/renderer/scene/Mesh.d.ts.map +0 -1
  313. package/src/shade/renderer/scene/Node3D.d.ts +0 -159
  314. package/src/shade/renderer/scene/Node3D.d.ts.map +0 -1
  315. package/src/shade/renderer/scene/Node3DDirtyList.d.ts +0 -59
  316. package/src/shade/renderer/scene/Node3DDirtyList.d.ts.map +0 -1
  317. package/src/shade/renderer/scene/SceneNodeBinding.d.ts +0 -52
  318. package/src/shade/renderer/scene/SceneNodeBinding.d.ts.map +0 -1
  319. package/src/shade/renderer/scene/SkinnedMesh.d.ts +0 -27
  320. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +0 -1
  321. package/src/shade/renderer/scene/TransformAuthority.d.ts +0 -19
  322. package/src/shade/renderer/scene/TransformAuthority.d.ts.map +0 -1
@@ -4,8 +4,8 @@
4
4
  * @param {VirtualGeometryGroup[][]} groups_by_level indexed by level; every group of every level,
5
5
  * including the root level's
6
6
  * @param {Float32Array} object_bounds `[min xyz, max xyz]` of the whole geometry, for the Morton grid
7
- * @param {number} nominal_page_size target decoded bytes per page; a single indivisible group is
8
- * allowed to exceed it
7
+ * @param {number} nominal_page_size decoded bytes per page, as a hard cap: no returned page decodes
8
+ * to more, and a group that cannot fit one on its own throws
9
9
  * @returns {VirtualGeometryPage[]} in file order, root page first
10
10
  */
11
11
  export function vgeo_assemble_pages(groups_by_level: VirtualGeometryGroup[][], object_bounds: Float32Array, nominal_page_size: number): VirtualGeometryPage[];
@@ -1 +1 @@
1
- {"version":3,"file":"vgeo_assemble_pages.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js"],"names":[],"mappings":"AAkEA;;;;;;;;;GASG;AACH,qDAPW,sBAAsB,EAAE,iBAExB,YAAY,qBACZ,MAAM,GAEJ,mBAAmB,EAAE,CAkGjC;oCAvKmC,sCAAsC"}
1
+ {"version":3,"file":"vgeo_assemble_pages.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js"],"names":[],"mappings":"AA2JA;;;;;;;;;GASG;AACH,qDAPW,sBAAsB,EAAE,iBAExB,YAAY,qBACZ,MAAM,GAEJ,mBAAmB,EAAE,CA+HjC;oCA5RmC,sCAAsC"}
@@ -2,9 +2,11 @@ import { assert } from "../../../../../core/assert.js";
2
2
  import { v3_morton_encode_bounded } from "../../../../../core/geom/3d/morton/v3_morton_encode_bounded.js";
3
3
  import { VGEO_CLUSTER_RECORD_SIZE } from "../format/cluster/VGEO_CLUSTER_RECORD_SIZE.js";
4
4
  import { VGEO_GROUP_RECORD_SIZE } from "../format/page/VGEO_GROUP_RECORD_SIZE.js";
5
+ import { VGEO_NODE_RECORD_SIZE } from "../format/page/VGEO_NODE_RECORD_SIZE.js";
5
6
  import { VGEO_PAGE_HEADER_SIZE } from "../format/page/VGEO_PAGE_HEADER_SIZE.js";
6
7
  import { VirtualGeometryPage } from "../format/dag/VirtualGeometryPage.js";
7
8
  import { vgeo_build_page_nodes } from "./vgeo_build_page_nodes.js";
9
+ import { vgeo_page_node_count } from "./vgeo_page_node_count.js";
8
10
 
9
11
  /**
10
12
  * Lay the DAG's groups out into pages, in the coarse-first file order the format requires.
@@ -18,6 +20,13 @@ import { vgeo_build_page_nodes } from "./vgeo_build_page_nodes.js";
18
20
  * adjacent wanted pages into one range, so what the order buys is that pages near each other in the
19
21
  * file are near each other in space.
20
22
  *
23
+ * **`nominal_page_size` is a cap, not a target.** No page this function returns decodes to more than
24
+ * it — that is format invariant §11.14, and it is what lets a VRAM tier address pages as fixed-stride
25
+ * slots with a multiply instead of an allocator. The two rules above leave exactly one way for a page
26
+ * to want more than the cap: a single group too large for a page of its own. Nothing can be done
27
+ * about that here — §11.1 makes a group atomic to its page — so the build refuses, and names the page
28
+ * size that would work.
29
+ *
21
30
  * @author Alex Goldring
22
31
  * @copyright Company Named Limited (c) 2026
23
32
  */
@@ -64,20 +73,102 @@ function group_centroid(group) {
64
73
  return result;
65
74
  }
66
75
 
76
+ /**
77
+ * What a page of `group_count` groups holding `content` bytes of group, cluster and payload records
78
+ * comes to decoded — exactly what {@link vgeo_write_container} will lay out, node table included.
79
+ *
80
+ * The node table is the part that is easy to forget and impossible to leave out: it is written into
81
+ * the page between the group and cluster tables, it is sized from the group count rather than from
82
+ * anything already counted, and a fill loop that ignores it overshoots the cap by 32 bytes a node.
83
+ *
84
+ * @param {number} group_count
85
+ * @param {number} content bytes of group records, cluster records and payloads
86
+ * @returns {number}
87
+ */
88
+ function page_decoded_size(group_count, content) {
89
+ return VGEO_PAGE_HEADER_SIZE
90
+ + vgeo_page_node_count(group_count) * VGEO_NODE_RECORD_SIZE
91
+ + content;
92
+ }
93
+
94
+ /**
95
+ * The smallest `nominal_page_size` a group could ever be laid out under: its own bytes in a page of
96
+ * its own, which is one group and therefore one node.
97
+ *
98
+ * @param {VirtualGeometryGroup} group
99
+ * @returns {number}
100
+ */
101
+ function group_minimum_page_size(group) {
102
+ return page_decoded_size(1, group_size_in_page(group));
103
+ }
104
+
105
+ /**
106
+ * Refuse a page size no layout could satisfy, before laying anything out.
107
+ *
108
+ * Up front, and over every group rather than stopping at the first offender, so that the size the
109
+ * message names is one the whole build would actually succeed at — a caller told about the first
110
+ * group that did not fit would raise the page size, run the build again, and meet the next one.
111
+ *
112
+ * @param {VirtualGeometryGroup[][]} groups_by_level
113
+ * @param {number} nominal_page_size
114
+ */
115
+ function reject_groups_larger_than_a_page(groups_by_level, nominal_page_size) {
116
+ let worst = undefined;
117
+ let worst_level = 0;
118
+ let worst_index = 0;
119
+ let worst_needs = 0;
120
+
121
+ let over_count = 0;
122
+ let total_count = 0;
123
+
124
+ groups_by_level.forEach((groups, level) => {
125
+ groups.forEach((group, index) => {
126
+ total_count++;
127
+
128
+ const needs = group_minimum_page_size(group);
129
+
130
+ if (needs > nominal_page_size) {
131
+ over_count++;
132
+ }
133
+
134
+ if (needs > worst_needs) {
135
+ worst = group;
136
+ worst_level = level;
137
+ worst_index = index;
138
+ worst_needs = needs;
139
+ }
140
+ });
141
+ });
142
+
143
+ if (worst_needs <= nominal_page_size) {
144
+ return;
145
+ }
146
+
147
+ throw new Error(
148
+ `virtual geometry: group ${worst_index} of level ${worst_level} holds ${worst.clusters.length}`
149
+ + ` clusters and needs a page of ${worst_needs} bytes, but nominal_page_size is`
150
+ + ` ${nominal_page_size}. A group never spans pages (VGEO_FORMAT §11.1) and a page never`
151
+ + ` exceeds nominal_page_size (§11.14), so ${over_count} of this build's ${total_count} groups`
152
+ + ` cannot be placed. Build with nominal_page_size of at least ${worst_needs}.`
153
+ );
154
+ }
155
+
67
156
  /**
68
157
  * Assign groups to pages.
69
158
  *
70
159
  * @param {VirtualGeometryGroup[][]} groups_by_level indexed by level; every group of every level,
71
160
  * including the root level's
72
161
  * @param {Float32Array} object_bounds `[min xyz, max xyz]` of the whole geometry, for the Morton grid
73
- * @param {number} nominal_page_size target decoded bytes per page; a single indivisible group is
74
- * allowed to exceed it
162
+ * @param {number} nominal_page_size decoded bytes per page, as a hard cap: no returned page decodes
163
+ * to more, and a group that cannot fit one on its own throws
75
164
  * @returns {VirtualGeometryPage[]} in file order, root page first
76
165
  */
77
166
  export function vgeo_assemble_pages(groups_by_level, object_bounds, nominal_page_size) {
78
167
  assert.isPositiveInteger(nominal_page_size, 'nominal_page_size');
79
168
  assert.greaterThan(groups_by_level.length, 0, 'groups_by_level.length');
80
169
 
170
+ reject_groups_larger_than_a_page(groups_by_level, nominal_page_size);
171
+
81
172
  const pages = [];
82
173
 
83
174
  const top_level = groups_by_level.length - 1;
@@ -118,8 +209,26 @@ export function vgeo_assemble_pages(groups_by_level, object_bounds, nominal_page
118
209
  // header alone.
119
210
  const page = open_page(level);
120
211
 
212
+ let content = 0;
213
+
121
214
  for (const group of groups) {
122
215
  place(page, group);
216
+
217
+ content += group_size_in_page(group);
218
+ }
219
+
220
+ // The cap has no exception, and this is the one page the fill rule below does not get to
221
+ // decide the contents of. A converged build puts a single root group here (§11.7), so
222
+ // reaching this needs a topmost level of several groups that together outgrow a page.
223
+ const size = page_decoded_size(page.groups.length, content);
224
+
225
+ if (size > nominal_page_size) {
226
+ throw new Error(
227
+ `virtual geometry: the topmost level's ${groups.length} groups come to ${size}`
228
+ + ` bytes and the root page must hold all of them (VGEO_FORMAT §11.4), but`
229
+ + ` nominal_page_size is ${nominal_page_size}. Build with nominal_page_size of at`
230
+ + ` least ${size}.`
231
+ );
123
232
  }
124
233
 
125
234
  continue;
@@ -138,24 +247,28 @@ export function vgeo_assemble_pages(groups_by_level, object_bounds, nominal_page
138
247
  keyed.sort((a, b) => (a.code - b.code) || (a.index - b.index));
139
248
 
140
249
  let page = undefined;
141
- let page_size = 0;
250
+ let content = 0;
142
251
 
143
252
  for (const entry of keyed) {
144
253
  const size = group_size_in_page(entry.group);
145
254
 
146
- if (page !== undefined && page_size + size > nominal_page_size) {
255
+ // What the page would come to *with* this group, node table and all — not what it came
256
+ // to without it. The node table grows with the group count, so a page measured before
257
+ // the group lands is measured under a smaller tree than the one it will be written with.
258
+ if (page !== undefined
259
+ && page_decoded_size(page.groups.length + 1, content + size) > nominal_page_size) {
147
260
  page = undefined;
148
261
  }
149
262
 
150
263
  if (page === undefined) {
151
264
  page = open_page(level);
152
265
 
153
- page_size = VGEO_PAGE_HEADER_SIZE;
266
+ content = 0;
154
267
  }
155
268
 
156
269
  place(page, entry.group);
157
270
 
158
- page_size += size;
271
+ content += size;
159
272
  }
160
273
  }
161
274
 
@@ -167,6 +280,11 @@ export function vgeo_assemble_pages(groups_by_level, object_bounds, nominal_page
167
280
  // settled once every group has found its page.
168
281
  for (const page of pages) {
169
282
  page.nodes = vgeo_build_page_nodes(page);
283
+
284
+ assert.equal(
285
+ page.nodes.length, vgeo_page_node_count(page.groups.length),
286
+ `page ${page.index}: the tree came to a different size than the fill loop budgeted for`
287
+ );
170
288
  }
171
289
 
172
290
  return pages;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * How many nodes {@link vgeo_build_page_nodes} will put over a page holding `group_count` groups.
3
+ *
4
+ * The tree's shape is a function of the group *count* alone — every node covers a contiguous run of
5
+ * the page's Morton order and splits it into as-near-equal parts as integers allow — so the node
6
+ * table's size is known before the tree exists. Which is what the page assembler needs: the node
7
+ * table is part of the decoded page, and a page whose size is a hard bound has to be measured with
8
+ * it included, while the tree itself cannot be built until the page's last group has arrived.
9
+ *
10
+ * This duplicates the recurrence in {@link vgeo_build_page_nodes} rather than sharing it, because
11
+ * the two want different things from it — one wants the ranges and one wants only how many there
12
+ * are — and the cost of the duplication is a spec that runs both and compares.
13
+ *
14
+ * @author Alex Goldring
15
+ * @copyright Company Named Limited (c) 2026
16
+ */
17
+ /**
18
+ * @param {number} group_count
19
+ * @returns {number} nodes, at least one
20
+ */
21
+ export function vgeo_page_node_count(group_count: number): number;
22
+ //# sourceMappingURL=vgeo_page_node_count.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vgeo_page_node_count.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AAEH;;;GAGG;AACH,kDAHW,MAAM,GACJ,MAAM,CA8BlB"}
@@ -0,0 +1,53 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+ import { VGEO_NODE_FANOUT } from "../format/page/VGEO_NODE_FANOUT.js";
3
+
4
+ /**
5
+ * How many nodes {@link vgeo_build_page_nodes} will put over a page holding `group_count` groups.
6
+ *
7
+ * The tree's shape is a function of the group *count* alone — every node covers a contiguous run of
8
+ * the page's Morton order and splits it into as-near-equal parts as integers allow — so the node
9
+ * table's size is known before the tree exists. Which is what the page assembler needs: the node
10
+ * table is part of the decoded page, and a page whose size is a hard bound has to be measured with
11
+ * it included, while the tree itself cannot be built until the page's last group has arrived.
12
+ *
13
+ * This duplicates the recurrence in {@link vgeo_build_page_nodes} rather than sharing it, because
14
+ * the two want different things from it — one wants the ranges and one wants only how many there
15
+ * are — and the cost of the duplication is a spec that runs both and compares.
16
+ *
17
+ * @author Alex Goldring
18
+ * @copyright Company Named Limited (c) 2026
19
+ */
20
+
21
+ /**
22
+ * @param {number} group_count
23
+ * @returns {number} nodes, at least one
24
+ */
25
+ export function vgeo_page_node_count(group_count) {
26
+ assert.isPositiveInteger(group_count, 'group_count');
27
+
28
+ /**
29
+ * Node spans in breadth-first order; the walk appends to it as it goes, which is the same order
30
+ * the builder allocates nodes in.
31
+ * @type {number[]}
32
+ */
33
+ const spans = [group_count];
34
+
35
+ for (let index = 0; index < spans.length; index++) {
36
+ const span = spans[index];
37
+
38
+ if (span <= VGEO_NODE_FANOUT) {
39
+ continue;
40
+ }
41
+
42
+ const child_count = Math.min(VGEO_NODE_FANOUT, Math.ceil(span / VGEO_NODE_FANOUT));
43
+
44
+ for (let child = 0; child < child_count; child++) {
45
+ spans.push(
46
+ Math.floor((span * (child + 1)) / child_count)
47
+ - Math.floor((span * child) / child_count)
48
+ );
49
+ }
50
+ }
51
+
52
+ return spans.length;
53
+ }
@@ -48,7 +48,14 @@ export class VGeoWriteOptions {
48
48
  */
49
49
  vertex_attribute_mask: number;
50
50
  /**
51
- * The page size the assembler aimed at. Informational; readers must not assume it.
51
+ * The page size the assembler laid pages out against, and the bound the written file will
52
+ * promise its readers: {@link vgeo_write_container} refuses a page list that exceeds it, and
53
+ * marks the container with the bounded-pages feature bit when it does not (§11.14).
54
+ *
55
+ * Zero states no page size, and then neither happens. That is for a caller that builds a page
56
+ * list by hand and has no such size to state — the reader and residency specs' synthetic
57
+ * containers — and not something a real build does.
58
+ *
52
59
  * @type {number}
53
60
  */
54
61
  nominal_page_size: number;
@@ -1 +1 @@
1
- {"version":3,"file":"VGeoWriteOptions.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH;IACI;;;;;;;;;;OAUG;IACH,OAFU,MAAM,CAEO;IAEvB;;;OAGG;IACH,QAFU,iBAAiB,CAEf;IAEZ;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,uBAFU,MAAM,CAEU;IAE1B;;;OAGG;IACH,mBAFU,MAAM,CAEM;CACzB"}
1
+ {"version":3,"file":"VGeoWriteOptions.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH;IACI;;;;;;;;;;OAUG;IACH,OAFU,MAAM,CAEO;IAEvB;;;OAGG;IACH,QAFU,iBAAiB,CAEf;IAEZ;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,uBAFU,MAAM,CAEU;IAE1B;;;;;;;;;;OAUG;IACH,mBAFU,MAAM,CAEM;CACzB"}
@@ -57,7 +57,14 @@ export class VGeoWriteOptions {
57
57
  vertex_attribute_mask = 1;
58
58
 
59
59
  /**
60
- * The page size the assembler aimed at. Informational; readers must not assume it.
60
+ * The page size the assembler laid pages out against, and the bound the written file will
61
+ * promise its readers: {@link vgeo_write_container} refuses a page list that exceeds it, and
62
+ * marks the container with the bounded-pages feature bit when it does not (§11.14).
63
+ *
64
+ * Zero states no page size, and then neither happens. That is for a caller that builds a page
65
+ * list by hand and has no such size to state — the reader and residency specs' synthetic
66
+ * containers — and not something a real build does.
67
+ *
61
68
  * @type {number}
62
69
  */
63
70
  nominal_page_size = 0;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `feature_flags_ignorable` bit 0: **every page of this container decodes to no more than
3
+ * `nominal_page_size` bytes** (VGEO_FORMAT §11.14).
4
+ *
5
+ * It sits in the *ignorable* word rather than the required one on purpose. The bit adds a promise
6
+ * and takes nothing away, so a reader that has never heard of it reads the file exactly as it read
7
+ * the ones before — which is what §4 means by ignorable, and is why this needs no format version.
8
+ * A reader that *does* care — one allocating fixed-stride page slots, where a single over-size page
9
+ * is a buffer overrun rather than a waste — requires the bit and refuses a container built before
10
+ * it, which is a clean refusal instead of a silent one.
11
+ *
12
+ * @author Alex Goldring
13
+ * @copyright Company Named Limited (c) 2026
14
+ */
15
+ export const VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES: 1;
16
+ //# sourceMappingURL=VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,qDAAsD"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `feature_flags_ignorable` bit 0: **every page of this container decodes to no more than
3
+ * `nominal_page_size` bytes** (VGEO_FORMAT §11.14).
4
+ *
5
+ * It sits in the *ignorable* word rather than the required one on purpose. The bit adds a promise
6
+ * and takes nothing away, so a reader that has never heard of it reads the file exactly as it read
7
+ * the ones before — which is what §4 means by ignorable, and is why this needs no format version.
8
+ * A reader that *does* care — one allocating fixed-stride page slots, where a single over-size page
9
+ * is a buffer overrun rather than a waste — requires the bit and refuses a container built before
10
+ * it, which is a clean refusal instead of a silent one.
11
+ *
12
+ * @author Alex Goldring
13
+ * @copyright Company Named Limited (c) 2026
14
+ */
15
+ export const VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES = 1;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The page size a build targets, and the one a runtime expects, when neither is told otherwise.
3
+ *
4
+ * One constant rather than two defaults because the two ends have to agree exactly: a page size is a
5
+ * hard bound (`VGEO_FORMAT.md` §11.14), and a VRAM tier sizing fixed-stride slots against a
6
+ * different number than the builder laid pages out to refuses every container it is handed. Moving
7
+ * this moves both ends together.
8
+ *
9
+ * **64 KiB, and the reason is that there is only one of it.** Nanite carries two page sizes — 128 KB
10
+ * and 32 KB — for different purposes. We do not want two page types: one size is what makes a slot
11
+ * address a multiply and a residency budget a page count, and every structure downstream of the
12
+ * bound gets simpler for there being a single number. So the question is which single number, and it
13
+ * is pulled three ways:
14
+ *
15
+ * - **Bigger hides network latency.** A page is one HTTP range request, and a round trip costs the
16
+ * same whatever it carries.
17
+ * - **Bigger costs response time.** Nothing in a page is usable until all of it has arrived, so the
18
+ * larger the page the longer the wait between asking for detail and drawing it.
19
+ * - **Bigger exhausts the GPU sooner**, and unevenly: a fixed stride means VRAM per resident page
20
+ * whether the page is full or not, and the device that runs out first is the low-end one this has
21
+ * to keep working on.
22
+ *
23
+ * Against that, 32 KiB is too near the floor — a page has to hold a useful number of clusters in the
24
+ * **worst** case, and the worst case is a payload the encoder could not compress at all. 128 KiB is
25
+ * more than the latency argument buys once the other two are paid. 64 KiB sits between them.
26
+ *
27
+ * Measured fill agrees, which is corroboration rather than the reason. Decoded page sizes read back
28
+ * from two built tori, `waste` being what a fixed stride leaves unused:
29
+ *
30
+ * | page size | 640×320 torus | | | 320×160 torus | | |
31
+ * |---|---:|---:|---:|---:|---:|---:|
32
+ * | | pages | mean fill | waste | pages | mean fill | waste |
33
+ * | 16 KiB | 1,253 | 74% | 5.06 MiB | 317 | 73% | 1.33 MiB |
34
+ * | **64 KiB** | **254** | **91%** | **1.42 MiB** | **69** | **84%** | **0.71 MiB** |
35
+ * | 256 KiB | 69 | 84% | 2.80 MiB | 23 | 63% | 2.15 MiB |
36
+ *
37
+ * Small pages pay the per-page header and node table on more pages and cut bands finer. Large pages
38
+ * are worse than their mean: a band's remainder goes in its last page, so with few pages to a band
39
+ * that remainder dominates — at 256 KiB the tenth-percentile page is 24% and 4% full on these two,
40
+ * against 86% and 32% at 64 KiB.
41
+ *
42
+ * One floor is hard rather than a matter of taste: a group is atomic to its page, so the size has to
43
+ * clear the largest group a build produces or the build is refused outright. The largest here needs
44
+ * about 12 KiB, which is the other reason 32 KiB is uncomfortably close.
45
+ *
46
+ * **Provisional.** Nothing above is a measurement of the thing that will actually decide it — page
47
+ * size against fetch latency and VRAM pressure on a real device under a real camera — and
48
+ * quantization will move what a cluster costs and the fill curve with it.
49
+ *
50
+ * @author Alex Goldring
51
+ * @copyright Company Named Limited (c) 2026
52
+ */
53
+ export const VGEO_DEFAULT_PAGE_SIZE: number;
54
+ //# sourceMappingURL=VGEO_DEFAULT_PAGE_SIZE.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VGEO_DEFAULT_PAGE_SIZE.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,4CAAgD"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The page size a build targets, and the one a runtime expects, when neither is told otherwise.
3
+ *
4
+ * One constant rather than two defaults because the two ends have to agree exactly: a page size is a
5
+ * hard bound (`VGEO_FORMAT.md` §11.14), and a VRAM tier sizing fixed-stride slots against a
6
+ * different number than the builder laid pages out to refuses every container it is handed. Moving
7
+ * this moves both ends together.
8
+ *
9
+ * **64 KiB, and the reason is that there is only one of it.** Nanite carries two page sizes — 128 KB
10
+ * and 32 KB — for different purposes. We do not want two page types: one size is what makes a slot
11
+ * address a multiply and a residency budget a page count, and every structure downstream of the
12
+ * bound gets simpler for there being a single number. So the question is which single number, and it
13
+ * is pulled three ways:
14
+ *
15
+ * - **Bigger hides network latency.** A page is one HTTP range request, and a round trip costs the
16
+ * same whatever it carries.
17
+ * - **Bigger costs response time.** Nothing in a page is usable until all of it has arrived, so the
18
+ * larger the page the longer the wait between asking for detail and drawing it.
19
+ * - **Bigger exhausts the GPU sooner**, and unevenly: a fixed stride means VRAM per resident page
20
+ * whether the page is full or not, and the device that runs out first is the low-end one this has
21
+ * to keep working on.
22
+ *
23
+ * Against that, 32 KiB is too near the floor — a page has to hold a useful number of clusters in the
24
+ * **worst** case, and the worst case is a payload the encoder could not compress at all. 128 KiB is
25
+ * more than the latency argument buys once the other two are paid. 64 KiB sits between them.
26
+ *
27
+ * Measured fill agrees, which is corroboration rather than the reason. Decoded page sizes read back
28
+ * from two built tori, `waste` being what a fixed stride leaves unused:
29
+ *
30
+ * | page size | 640×320 torus | | | 320×160 torus | | |
31
+ * |---|---:|---:|---:|---:|---:|---:|
32
+ * | | pages | mean fill | waste | pages | mean fill | waste |
33
+ * | 16 KiB | 1,253 | 74% | 5.06 MiB | 317 | 73% | 1.33 MiB |
34
+ * | **64 KiB** | **254** | **91%** | **1.42 MiB** | **69** | **84%** | **0.71 MiB** |
35
+ * | 256 KiB | 69 | 84% | 2.80 MiB | 23 | 63% | 2.15 MiB |
36
+ *
37
+ * Small pages pay the per-page header and node table on more pages and cut bands finer. Large pages
38
+ * are worse than their mean: a band's remainder goes in its last page, so with few pages to a band
39
+ * that remainder dominates — at 256 KiB the tenth-percentile page is 24% and 4% full on these two,
40
+ * against 86% and 32% at 64 KiB.
41
+ *
42
+ * One floor is hard rather than a matter of taste: a group is atomic to its page, so the size has to
43
+ * clear the largest group a build produces or the build is refused outright. The largest here needs
44
+ * about 12 KiB, which is the other reason 32 KiB is uncomfortably close.
45
+ *
46
+ * **Provisional.** Nothing above is a measurement of the thing that will actually decide it — page
47
+ * size against fetch latency and VRAM pressure on a real device under a real camera — and
48
+ * quantization will move what a cluster costs and the fill curve with it.
49
+ *
50
+ * @author Alex Goldring
51
+ * @copyright Company Named Limited (c) 2026
52
+ */
53
+ export const VGEO_DEFAULT_PAGE_SIZE = 64 * 1024;
@@ -26,6 +26,14 @@ export class VGeoContainerHeader {
26
26
  * @type {number}
27
27
  */
28
28
  payload_encoding: number;
29
+ /**
30
+ * The header's `feature_flags_ignorable` word, verbatim. Bits a reader does not know are to be
31
+ * ignored rather than refused (§4), which is why the whole word is kept rather than a decoded
32
+ * set of booleans: the only bit defined so far is
33
+ * {@link VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES}, and a reader that needs it tests for it.
34
+ * @type {number}
35
+ */
36
+ feature_flags_ignorable: number;
29
37
  /**
30
38
  * Hex, as the 16 asset-id bytes stand in the file. In a streamed deployment this is also the
31
39
  * file's name, which is what makes same-URL version skew impossible.
@@ -83,8 +91,11 @@ export class VGeoContainerHeader {
83
91
  */
84
92
  dir_block_checksums_offset: number;
85
93
  /**
86
- * The build parameter, informational. A reader must never assume it: per-page sizes come from
87
- * child tables, frames, or the directory.
94
+ * Bytes a decoded page may come to. A **hard bound** when
95
+ * {@link VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES} is set in {@link feature_flags_ignorable}: no
96
+ * page of the container exceeds it, which is what a fixed-stride page slot is sized against.
97
+ * Without that bit it is the advisory build parameter it used to be, and a reader must take
98
+ * per-page sizes from child tables, frames, or the directory as it always has.
88
99
  * @type {number}
89
100
  */
90
101
  nominal_page_size: number;
@@ -1 +1 @@
1
- {"version":3,"file":"VGeoContainerHeader.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH;IACI;;OAEG;IACH,gBAFU,MAAM,CAEG;IAEnB;;;;OAIG;IACH,oBAFU,MAAM,CAEO;IAEvB;;OAEG;IACH,kBAFU,MAAM,CAEK;IAErB;;;;OAIG;IACH,UAFU,MAAM,CAEF;IAEd;;;;;OAKG;IACH,gBAFU,MAAM,CAEI;IAEpB;;;;OAIG;IACH,uBAFU,MAAM,CAEU;IAE1B;;OAEG;IACH,aAFU,MAAM,CAEA;IAEhB;;OAEG;IACH,gBAFU,MAAM,CAEG;IAEnB;;OAEG;IACH,cAFU,MAAM,CAEC;IAEjB;;;OAGG;IACH,kBAFU,MAAM,CAEK;IAErB;;;;OAIG;IACH,sBAFU,MAAM,CAES;IAEzB;;;OAGG;IACH,wBAFU,MAAM,CAEW;IAE3B;;;OAGG;IACH,kBAFU,MAAM,CAEK;IAErB;;OAEG;IACH,4BAFU,MAAM,CAEe;IAE/B;;;;OAIG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;OAEG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,QAFU,iBAAiB,CAEf;IAEZ;;;;OAIG;IACH,wBAEC;CACJ"}
1
+ {"version":3,"file":"VGeoContainerHeader.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH;IACI;;OAEG;IACH,gBAFU,MAAM,CAEG;IAEnB;;;;OAIG;IACH,oBAFU,MAAM,CAEO;IAEvB;;OAEG;IACH,kBAFU,MAAM,CAEK;IAErB;;;;;;OAMG;IACH,yBAFU,MAAM,CAEY;IAE5B;;;;OAIG;IACH,UAFU,MAAM,CAEF;IAEd;;;;;OAKG;IACH,gBAFU,MAAM,CAEI;IAEpB;;;;OAIG;IACH,uBAFU,MAAM,CAEU;IAE1B;;OAEG;IACH,aAFU,MAAM,CAEA;IAEhB;;OAEG;IACH,gBAFU,MAAM,CAEG;IAEnB;;OAEG;IACH,cAFU,MAAM,CAEC;IAEjB;;;OAGG;IACH,kBAFU,MAAM,CAEK;IAErB;;;;OAIG;IACH,sBAFU,MAAM,CAES;IAEzB;;;OAGG;IACH,wBAFU,MAAM,CAEW;IAE3B;;;OAGG;IACH,kBAFU,MAAM,CAEK;IAErB;;OAEG;IACH,4BAFU,MAAM,CAEe;IAE/B;;;;;;;OAOG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;OAEG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,eAFU,YAAY,CAEc;IAEpC;;;OAGG;IACH,QAFU,iBAAiB,CAEf;IAEZ;;;;OAIG;IACH,wBAEC;CACJ"}
@@ -29,6 +29,15 @@ export class VGeoContainerHeader {
29
29
  */
30
30
  payload_encoding = 0;
31
31
 
32
+ /**
33
+ * The header's `feature_flags_ignorable` word, verbatim. Bits a reader does not know are to be
34
+ * ignored rather than refused (§4), which is why the whole word is kept rather than a decoded
35
+ * set of booleans: the only bit defined so far is
36
+ * {@link VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES}, and a reader that needs it tests for it.
37
+ * @type {number}
38
+ */
39
+ feature_flags_ignorable = 0;
40
+
32
41
  /**
33
42
  * Hex, as the 16 asset-id bytes stand in the file. In a streamed deployment this is also the
34
43
  * file's name, which is what makes same-URL version skew impossible.
@@ -97,8 +106,11 @@ export class VGeoContainerHeader {
97
106
  dir_block_checksums_offset = 0;
98
107
 
99
108
  /**
100
- * The build parameter, informational. A reader must never assume it: per-page sizes come from
101
- * child tables, frames, or the directory.
109
+ * Bytes a decoded page may come to. A **hard bound** when
110
+ * {@link VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES} is set in {@link feature_flags_ignorable}: no
111
+ * page of the container exceeds it, which is what a fixed-stride page slot is sized against.
112
+ * Without that bit it is the advisory build parameter it used to be, and a reader must take
113
+ * per-page sizes from child tables, frames, or the directory as it always has.
102
114
  * @type {number}
103
115
  */
104
116
  nominal_page_size = 0;