@woosh/meep-engine 3.26.0 → 3.28.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 (449) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
  4. package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
  5. package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
  6. package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
  7. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
  8. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
  9. package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
  10. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
  11. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
  12. package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
  13. package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
  14. package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
  15. package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
  16. package/src/core/geom/3d/mat4/m4_linear_determinant.d.ts +15 -0
  17. package/src/core/geom/3d/mat4/m4_linear_determinant.d.ts.map +1 -0
  18. package/src/core/geom/3d/mat4/m4_linear_determinant.js +24 -0
  19. package/src/core/geom/3d/mat4/m4_normal_matrix3.d.ts +4 -2
  20. package/src/core/geom/3d/mat4/m4_normal_matrix3.d.ts.map +1 -1
  21. package/src/core/geom/3d/mat4/m4_normal_matrix3.js +21 -11
  22. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +14 -7
  23. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  24. package/src/core/geom/3d/shape/HeightMapShape3D.js +87 -78
  25. package/src/engine/Engine.d.ts.map +1 -1
  26. package/src/engine/Engine.js +38 -1
  27. package/src/engine/graphics3/GraphicsEngine.d.ts +5 -1
  28. package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
  29. package/src/engine/graphics3/GraphicsEngine.js +834 -830
  30. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  31. package/src/shade/RENDERER_CONTRACT.md +19 -10
  32. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +1 -1
  33. package/src/shade/playground/vgeo_runtime/README.md +186 -27
  34. package/src/shade/playground/vgeo_runtime/index.html +112 -62
  35. package/src/shade/playground/vgeo_runtime/main.js +678 -88
  36. package/src/shade/playground/vgeo_runtime/sample_asset.d.ts +18 -0
  37. package/src/shade/playground/vgeo_runtime/sample_asset.d.ts.map +1 -0
  38. package/src/shade/playground/{vgeo_viewer → vgeo_runtime}/sample_asset.js +23 -5
  39. package/src/shade/playground/vgeo_scene/README.md +408 -0
  40. package/src/shade/playground/vgeo_scene/index.html +144 -0
  41. package/src/shade/playground/vgeo_scene/main.d.ts +2 -0
  42. package/src/shade/playground/vgeo_scene/main.d.ts.map +1 -0
  43. package/src/shade/playground/vgeo_scene/main.js +1716 -0
  44. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
  45. package/src/shade/renderer/Renderer.d.ts +4 -1
  46. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  47. package/src/shade/renderer/Renderer.js +5 -2
  48. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +1 -2
  49. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
  50. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  51. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
  52. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  53. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
  54. package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts.map +1 -1
  55. package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +3 -29
  56. package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts +22 -0
  57. package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts.map +1 -0
  58. package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.js +49 -0
  59. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +77 -7
  60. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +36 -23
  61. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +17 -14
  62. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +19 -1
  63. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  64. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +21 -1
  65. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.d.ts.map +1 -1
  66. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.js +5 -9
  67. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevel.d.ts +32 -0
  68. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevel.d.ts.map +1 -0
  69. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts +59 -0
  70. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts.map +1 -0
  71. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelSummary.d.ts +44 -0
  72. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelSummary.d.ts.map +1 -0
  73. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts +36 -0
  74. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -0
  75. package/src/shade/renderer/geometry/virtual/build/{vgeo_build_levels.js → level/vgeo_build_levels.js} +61 -95
  76. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_root_group.d.ts +19 -0
  77. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_root_group.d.ts.map +1 -0
  78. package/src/shade/renderer/geometry/virtual/build/{vgeo_build_root_group.js → level/vgeo_build_root_group.js} +1 -1
  79. package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts +73 -0
  80. package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/build/{VirtualGeometryMesh.js → mesh/VirtualGeometryMesh.js} +7 -7
  82. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +29 -0
  83. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/build/{vgeo_compute_vertex_normals.js → mesh/vgeo_compute_vertex_normals.js} +3 -3
  85. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts +31 -0
  86. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts.map +1 -0
  87. package/src/shade/renderer/geometry/virtual/build/{vgeo_compute_vertex_tangents.js → mesh/vgeo_compute_vertex_tangents.js} +5 -5
  88. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +46 -0
  89. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/build/{vgeo_normalize_source.js → mesh/vgeo_normalize_source.js} +9 -9
  91. package/src/shade/renderer/geometry/virtual/build/page/vgeo_assemble_pages.d.ts +13 -0
  92. package/src/shade/renderer/geometry/virtual/build/page/vgeo_assemble_pages.d.ts.map +1 -0
  93. package/src/shade/renderer/geometry/virtual/build/{vgeo_assemble_pages.js → page/vgeo_assemble_pages.js} +63 -16
  94. package/src/shade/renderer/geometry/virtual/build/page/vgeo_build_page_nodes.d.ts +13 -0
  95. package/src/shade/renderer/geometry/virtual/build/page/vgeo_build_page_nodes.d.ts.map +1 -0
  96. package/src/shade/renderer/geometry/virtual/build/{vgeo_build_page_nodes.js → page/vgeo_build_page_nodes.js} +4 -4
  97. package/src/shade/renderer/geometry/virtual/build/page/vgeo_page_node_count.d.ts +22 -0
  98. package/src/shade/renderer/geometry/virtual/build/page/vgeo_page_node_count.d.ts.map +1 -0
  99. package/src/shade/renderer/geometry/virtual/build/{vgeo_page_node_count.js → page/vgeo_page_node_count.js} +2 -2
  100. package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts +52 -0
  101. package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts.map +1 -0
  102. package/src/shade/renderer/geometry/virtual/build/{VGeoFaceGraph.js → partition/VGeoFaceGraph.js} +1 -1
  103. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts +14 -0
  104. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts.map +1 -0
  105. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_graph.d.ts +29 -0
  106. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_graph.d.ts.map +1 -0
  107. package/src/shade/renderer/geometry/virtual/build/{vgeo_partition_graph.js → partition/vgeo_partition_graph.js} +2 -2
  108. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.d.ts +41 -0
  109. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.d.ts.map +1 -0
  110. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.js +92 -0
  111. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set.d.ts +10 -0
  112. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set.d.ts.map +1 -0
  113. package/src/shade/renderer/geometry/virtual/build/{vgeo_split_face_set.js → partition/vgeo_split_face_set.js} +12 -55
  114. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts +15 -0
  115. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -0
  116. package/src/shade/renderer/geometry/virtual/build/{vgeo_split_face_set_packed.js → partition/vgeo_split_face_set_packed.js} +3 -3
  117. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_bounding_sphere.d.ts +12 -0
  118. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_bounding_sphere.d.ts.map +1 -0
  119. package/src/shade/renderer/geometry/virtual/build/{vgeo_bounding_sphere.js → sphere/vgeo_bounding_sphere.js} +3 -3
  120. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_containing_sphere.d.ts +18 -0
  121. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_containing_sphere.d.ts.map +1 -0
  122. package/src/shade/renderer/geometry/virtual/build/{vgeo_containing_sphere.js → sphere/vgeo_containing_sphere.js} +3 -3
  123. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_sphere_inflate_to_contain.d.ts +9 -0
  124. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_sphere_inflate_to_contain.d.ts.map +1 -0
  125. package/src/shade/renderer/geometry/virtual/build/{vgeo_sphere_inflate_to_contain.js → sphere/vgeo_sphere_inflate_to_contain.js} +1 -1
  126. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts +24 -0
  127. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts.map +1 -0
  128. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts +20 -0
  129. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts.map +1 -0
  130. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts +14 -0
  131. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts.map +1 -0
  132. package/src/shade/renderer/geometry/virtual/build/{vgeo_extract_submesh.js → submesh/vgeo_extract_submesh.js} +5 -5
  133. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts +12 -0
  134. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts.map +1 -0
  135. package/src/shade/renderer/geometry/virtual/build/{vgeo_gather_faces.js → submesh/vgeo_gather_faces.js} +2 -2
  136. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_narrow_indices.d.ts +11 -0
  137. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_narrow_indices.d.ts.map +1 -0
  138. package/src/shade/renderer/geometry/virtual/build/{vgeo_narrow_indices.js → submesh/vgeo_narrow_indices.js} +3 -3
  139. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  140. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  141. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +10 -11
  142. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
  143. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  144. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
  145. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.d.ts +8 -2
  146. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.d.ts.map +1 -1
  147. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.js +8 -2
  148. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
  149. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  150. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
  151. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
  152. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  153. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
  154. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
  155. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  156. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
  157. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.d.ts +15 -0
  158. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.d.ts.map +1 -0
  159. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.js +15 -0
  160. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
  161. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
  162. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
  163. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
  164. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
  165. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
  166. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
  167. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
  168. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
  169. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
  170. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
  171. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
  172. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
  173. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
  174. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts +28 -0
  175. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts.map +1 -1
  176. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +7 -3
  177. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
  178. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  179. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
  180. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
  181. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  182. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
  183. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
  184. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  185. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
  186. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
  187. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  188. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
  189. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
  190. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
  191. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
  192. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
  193. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  194. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
  195. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
  196. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
  197. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
  198. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
  199. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  200. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
  201. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
  202. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
  203. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
  204. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
  205. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
  206. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
  207. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  208. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +63 -3
  209. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  210. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +219 -17
  211. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  212. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +156 -11
  213. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +656 -0
  214. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
  215. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
  217. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +109 -29
  218. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  219. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +173 -105
  220. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +109 -26
  222. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
  224. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  225. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +55 -487
  226. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
  227. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
  230. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
  231. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1388 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
  236. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  237. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
  238. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
  248. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
  249. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +8 -8
  250. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  251. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +11 -73
  252. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts +19 -0
  253. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts.map +1 -0
  254. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.js +98 -0
  255. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts +31 -0
  256. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts.map +1 -0
  257. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.js +99 -0
  258. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.d.ts +17 -0
  259. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.d.ts.map +1 -0
  260. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.js +39 -0
  261. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
  262. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
  263. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
  264. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
  265. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
  266. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
  267. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
  268. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
  269. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
  270. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +130 -0
  271. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
  272. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +32 -37
  273. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  274. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +576 -230
  275. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
  276. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
  277. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
  278. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  279. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
  280. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  281. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
  282. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  283. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
  284. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
  285. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
  286. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
  287. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
  288. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
  289. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
  290. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
  291. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
  292. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
  293. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
  294. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
  295. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
  296. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
  297. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
  298. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
  299. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
  300. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
  301. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
  302. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
  303. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
  304. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
  305. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
  306. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
  307. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
  308. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
  309. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
  310. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
  311. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
  312. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
  313. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
  314. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
  315. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
  316. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  317. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
  318. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  319. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
  320. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  321. package/src/shade/renderer/loader/gltf/load_gltf.js +0 -19
  322. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  323. package/src/shade/renderer/material/chunk_material_draw_side.d.ts +14 -0
  324. package/src/shade/renderer/material/chunk_material_draw_side.d.ts.map +1 -0
  325. package/src/shade/renderer/material/chunk_material_draw_side.js +34 -0
  326. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
  327. package/src/shade/renderer/material/standard/fragment_gbuffer.js +8 -1
  328. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  329. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
  330. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  331. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
  332. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  333. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +13 -1
  334. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  335. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts +19 -5
  336. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
  337. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +23 -5
  338. package/src/shade/renderer/rasterize/bucket/filter_materials_by_bucket.d.ts.map +1 -1
  339. package/src/shade/renderer/rasterize/bucket/filter_materials_by_bucket.js +12 -5
  340. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  341. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
  342. package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.d.ts +22 -0
  343. package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.d.ts.map +1 -0
  344. package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.js +36 -0
  345. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
  346. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  347. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  348. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts +15 -0
  349. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts.map +1 -0
  350. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js +35 -0
  351. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  352. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
  353. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  354. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
  355. package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.d.ts +10 -1
  356. package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.d.ts.map +1 -1
  357. package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.js +38 -29
  358. package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.d.ts +5 -0
  359. package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.d.ts.map +1 -1
  360. package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.js +63 -55
  361. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  362. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
  363. package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.d.ts.map +1 -1
  364. package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.js +1 -0
  365. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  366. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
  367. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  368. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
  369. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  370. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +44 -53
  371. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  372. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +6 -2
  373. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  374. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +6 -2
  375. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts.map +1 -1
  376. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.js +19 -2
  377. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +7 -4
  378. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  379. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +3 -2
  380. package/src/shade/renderer/rasterize/native/chunk_rasterize_triangle.d.ts.map +1 -1
  381. package/src/shade/renderer/rasterize/native/chunk_rasterize_triangle.js +15 -4
  382. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  383. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +16 -5
  384. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.d.ts.map +1 -1
  385. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.js +16 -5
  386. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
  387. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +2 -1
  388. package/src/shade/renderer/rasterize/native/rasterization_shader_resources.d.ts.map +1 -1
  389. package/src/shade/renderer/rasterize/native/rasterization_shader_resources.js +4 -0
  390. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  391. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +16 -7
  392. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  393. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +85 -89
  394. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  395. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +28 -32
  396. package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
  397. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  398. package/src/shade/renderer/scene/GPUSceneContext.js +61 -4
  399. package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts +19 -0
  400. package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts.map +1 -1
  401. package/src/shade/renderer/scene/NODE3D_STRUCT.js +34 -0
  402. package/src/shade/renderer/scene/chunk_node3d_flags.d.ts +9 -0
  403. package/src/shade/renderer/scene/chunk_node3d_flags.d.ts.map +1 -0
  404. package/src/shade/renderer/scene/chunk_node3d_flags.js +23 -0
  405. package/src/shade/renderer/scene/chunk_scene_database_access.d.ts.map +1 -1
  406. package/src/shade/renderer/scene/chunk_scene_database_access.js +15 -1
  407. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  408. package/src/shade/renderer/scene/rows/GPUSceneRows.js +9 -1
  409. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.d.ts +7 -0
  410. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.d.ts.map +1 -1
  411. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.js +16 -4
  412. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.d.ts +12 -0
  413. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.d.ts.map +1 -0
  414. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.js +18 -0
  415. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.d.ts +24 -0
  416. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.d.ts.map +1 -0
  417. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.js +33 -0
  418. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  419. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
  420. package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
  421. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  422. package/src/shade/renderer/view/GPUViewContext.js +21 -0
  423. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  424. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
  425. package/src/shade/playground/vgeo_viewer/README.md +0 -150
  426. package/src/shade/playground/vgeo_viewer/cut_geometry.js +0 -460
  427. package/src/shade/playground/vgeo_viewer/index.html +0 -77
  428. package/src/shade/playground/vgeo_viewer/main.js +0 -1343
  429. package/src/shade/playground/vgeo_viewer/select_cut.js +0 -481
  430. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +0 -258
  431. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +0 -1
  432. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
  433. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +0 -49
  434. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +0 -1
  435. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
  436. package/src/shade/renderer/loader/gltf/fix_up_material_sides.js +0 -109
  437. package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.js +0 -78
  438. package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.js +0 -100
  439. package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.js +0 -26
  440. package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
  441. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.d.ts +0 -3
  442. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.d.ts.map +0 -1
  443. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
  444. /package/src/shade/renderer/geometry/virtual/build/{VGeoLevel.js → level/VGeoLevel.js} +0 -0
  445. /package/src/shade/renderer/geometry/virtual/build/{VGeoLevelOptions.js → level/VGeoLevelOptions.js} +0 -0
  446. /package/src/shade/renderer/geometry/virtual/build/{VGeoLevelSummary.js → level/VGeoLevelSummary.js} +0 -0
  447. /package/src/shade/renderer/geometry/virtual/build/{vgeo_graph_components.js → partition/vgeo_graph_components.js} +0 -0
  448. /package/src/shade/renderer/geometry/virtual/build/{VGeoGatheredFaces.js → submesh/VGeoGatheredFaces.js} +0 -0
  449. /package/src/shade/renderer/geometry/virtual/build/{VGeoSubmesh.js → submesh/VGeoSubmesh.js} +0 -0
@@ -17,6 +17,10 @@ import { vgeo_runtime_page_block_words } from "./vgeo_runtime_page_block_words.j
17
17
  import { vgeo_runtime_page_slot_words } from "./vgeo_runtime_page_slot_words.js";
18
18
  import { vgeo_runtime_write_page_block } from "./vgeo_runtime_write_page_block.js";
19
19
 
20
+ /**
21
+ * @typedef {import("../format/read/VGeoPage.js").VGeoPage} VGeoPage
22
+ */
23
+
20
24
  /**
21
25
  * What a VRAM-resident page **is**, with no device anywhere near it.
22
26
  *
@@ -44,10 +48,10 @@ import { vgeo_runtime_write_page_block } from "./vgeo_runtime_write_page_block.j
44
48
  * row of a second table, which saves the traversal a storage binding it does not have to spare
45
49
  * (RUNTIME_PLAN §4.9) and makes an install one contiguous range.
46
50
  *
47
- * ## This tier answers its own activation question
51
+ * ## This tier answers its own activation question, and keeps the answer
48
52
  *
49
- * {@link refresh_selectable} computes selectability from the arena and the lookup — this tier's
50
- * residency — and consults no reader. It used to publish `VGeoContainerReader.is_selectable`, which
53
+ * Selectability is computed from the arena and the lookup — this tier's residency — and consults
54
+ * no reader. It used to publish `VGeoContainerReader.is_selectable`, which
51
55
  * is a fact about the **RAM** tier, into the flag the kernel reads while the descent was gated on
52
56
  * the **VRAM** lookup. VRAM is a strict subset, so a group could be flagged selectable while a page
53
57
  * holding one of its parents had no row here, and the parent's own ancestor then drew a coarse
@@ -55,6 +59,22 @@ import { vgeo_runtime_write_page_block } from "./vgeo_runtime_write_page_block.j
55
59
  * the group row carrying its parent count (VGEO_GROUP_ROW_OFFSET.PARENT_COUNT) so that the rule
56
60
  * can be evaluated where the residency it is about lives.
57
61
  *
62
+ * And it is **kept, not recomputed**. The rule is design §6's: a group is selectable iff every one
63
+ * of its parent-cluster references is live — the referencing cluster's page resident here and
64
+ * that cluster's own group selectable here. `refresh_selectable` used to evaluate that as a
65
+ * closure over every resident group of the geometry after every install and every evict: 4.2 ms
66
+ * a call at 4,096 resident pages of a real asset, twice per promotion at a full tier, which is
67
+ * where a 637 ms frame came from (RUNTIME_PLAN_2026_09_14 §0). §6 also says how it is meant to
68
+ * be kept — "carried by a counter instead of dependency lists … activation cascades" — and
69
+ * `VGeoContainerReader` already does that for the RAM tier. This tier does it over the arena:
70
+ * the live-reference count lives in the group row's FLAGS word above the flag bit, a page's
71
+ * groups are seeded from the resident parents that reference them when it arrives, and the
72
+ * groups that reach their count cascade into the resident children that were waiting on them
73
+ * (§3 of that plan). An install costs the clusters of the page's resident parents plus the
74
+ * cascade; an eviction under the child rule cascades nothing, because nothing resident depends
75
+ * on a page with no resident children. The rule itself survives as the fixpoint oracle
76
+ * `VGeoRuntimeTables.spec.js` holds the counter to after every step of random tours.
77
+ *
58
78
  * **Nothing here decides anything.** What to install, what to evict — all of that is the pool's.
59
79
  * What this refuses is only what it cannot represent.
60
80
  *
@@ -120,12 +140,39 @@ export class VGeoRuntimeTables {
120
140
  #resident_rows = new Set();
121
141
 
122
142
  /**
123
- * Resident page rows per geometry row — what {@link refresh_selectable} runs over, and what an
124
- * eviction has to look at to find a page's VRAM children.
143
+ * Resident page rows per geometry row.
125
144
  * @type {Map<number, Set<number>>}
126
145
  */
127
146
  #geometry_rows = new Map();
128
147
 
148
+ /**
149
+ * Per geometry row, the reverse index of the DAG over this tier's residency: container page
150
+ * index to the resident page rows whose clusters refer into that page. Written from a page's
151
+ * own child table when it installs and removed when it evicts, so an entry is O(parents) and
152
+ * a lookup is O(1) — design §6's "reverse-reference index", kept for resident pages too. It is
153
+ * what seeds an arriving page's live counts from the parents already here, and what keeps
154
+ * {@link resident_children} without a cluster walk per candidate.
155
+ * @type {Map<number, Map<number, number[]>>}
156
+ */
157
+ #referrers = new Map();
158
+
159
+ /**
160
+ * Per page row, how many distinct child pages of it are resident in this tier — design §6's
161
+ * eviction rule, "no child page resident in this tier", as a number kept at install and evict
162
+ * rather than a walk of the page's clusters per candidate (REVIEW_LEDGER M9 for why it is this
163
+ * tier's own answer and not the reader's).
164
+ * @type {Uint32Array}
165
+ */
166
+ #resident_children;
167
+
168
+ /**
169
+ * Page rows whose group flags flipped since {@link take_activated_rows} last emptied it — what
170
+ * the owner has to upload. Counts move without appearing here: the kernels mask the flag bit
171
+ * and never read the count, so a count alone is not worth a dirty range.
172
+ * @type {number[]}
173
+ */
174
+ #activated = [];
175
+
129
176
  /**
130
177
  * Lookup allocation per geometry row, so an unregistered geometry gives its lookup back.
131
178
  * @type {Map<number, Allocation>}
@@ -196,13 +243,6 @@ export class VGeoRuntimeTables {
196
243
  */
197
244
  #broken_child_refs = 0;
198
245
 
199
- /**
200
- * Scratch for {@link refresh_selectable}: live parent references per resident group, indexed by
201
- * the group's word offset in the arena. One map reused across calls rather than one allocated
202
- * per call, because activation runs on every install and every eviction.
203
- * @type {Map<number, number>}
204
- */
205
- #live_refs = new Map();
206
246
 
207
247
  /**
208
248
  * @param {Object} [options]
@@ -232,6 +272,7 @@ export class VGeoRuntimeTables {
232
272
  this.#lookup = new Uint32Array(lookup_words);
233
273
  this.#geometries = new Uint32Array(geometry_capacity * VGEO_GEOMETRY_ROW_WORDS);
234
274
  this.#generations = new Uint32Array(page_capacity);
275
+ this.#resident_children = new Uint32Array(page_capacity);
235
276
 
236
277
  const words = new Uint32Array(page_capacity * slot_words);
237
278
 
@@ -372,6 +413,7 @@ export class VGeoRuntimeTables {
372
413
 
373
414
  this.#ordinals.set(row, { free: [], high_water: ordinal_capacity });
374
415
  this.#geometry_rows.set(row, new Set());
416
+ this.#referrers.set(row, new Map());
375
417
 
376
418
  return row;
377
419
  }
@@ -399,8 +441,9 @@ export class VGeoRuntimeTables {
399
441
  const allocation = this.#geometry_allocations.get(geometry_row);
400
442
 
401
443
  if (allocation !== undefined) {
444
+ // absent, not row 0: a freed block is still a block some late reader can name
402
445
  this.#lookup.fill(
403
- 0,
446
+ VGEO_PAGE_ROW_NONE,
404
447
  allocation.offset,
405
448
  allocation.offset + this.geometry_field(
406
449
  geometry_row, VGEO_GEOMETRY_ROW_OFFSET.PAGE_COUNT
@@ -422,6 +465,7 @@ export class VGeoRuntimeTables {
422
465
  ] = VGEO_PAGE_ROW_NONE;
423
466
 
424
467
  this.#geometry_rows.delete(geometry_row);
468
+ this.#referrers.delete(geometry_row);
425
469
  this.#ordinals.delete(geometry_row);
426
470
  this.#free_geometry_rows.push(geometry_row);
427
471
 
@@ -487,12 +531,29 @@ export class VGeoRuntimeTables {
487
531
  + this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT) * VGEO_GROUP_ROW_WORDS;
488
532
  }
489
533
 
534
+ /**
535
+ * Word offset of a page's parent rows, which is the end of its cluster rows.
536
+ *
537
+ * Equal to the end of the block when the page has none, which is every page of a container
538
+ * written before `format_version` 4: `PARENT_ENTRY_COUNT` is zero and nothing reads past it.
539
+ *
540
+ * @param {number} page_row
541
+ * @returns {number}
542
+ */
543
+ parent_base(page_row) {
544
+ return this.cluster_base(page_row)
545
+ + this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.CLUSTER_COUNT) * VGEO_CLUSTER_ROW_WORDS;
546
+ }
547
+
490
548
  /**
491
549
  * Make a decoded page resident: one slot, one lookup word.
492
550
  *
493
- * The page installs **not selectable** — every group's flag is clear — because a page that
494
- * arrives drawing is a page that draws before the ancestors it hangs off have. Activation is
495
- * {@link refresh_selectable}.
551
+ * The page's rows are written with every group's flag clear, and then activated in place: its
552
+ * groups are seeded with the live references the resident parents make into them, the ones
553
+ * that reach their parent count flip on, and the flip cascades into whatever resident children
554
+ * were waiting on this page. A page that arrives drawing would draw before the ancestors it
555
+ * hangs off have; a page whose arrival completes a group several pages down turns that group
556
+ * on. Both are this method's, and the rows that flipped are on {@link take_activated_rows}.
496
557
  *
497
558
  * @param {number} geometry_row
498
559
  * @param {VGeoPage} page as `vgeo_read_page` decoded it
@@ -510,8 +571,11 @@ export class VGeoRuntimeTables {
510
571
  const group_count = page.group_cluster_first.length;
511
572
  const cluster_count = page.cluster_count;
512
573
 
513
- const words = VGEO_PAGE_ROW_WORDS
514
- + vgeo_runtime_page_block_words(node_count, group_count, cluster_count);
574
+ const parent_entry_count = page.parent_ref.length;
575
+
576
+ const words = VGEO_PAGE_ROW_WORDS + vgeo_runtime_page_block_words(
577
+ node_count, group_count, cluster_count, parent_entry_count
578
+ );
515
579
 
516
580
  if (words > this.#slot_words) {
517
581
  throw new Error(
@@ -546,6 +610,16 @@ export class VGeoRuntimeTables {
546
610
  this.#arena[base + VGEO_PAGE_ROW_OFFSET.ORDINAL] = ordinal;
547
611
  this.#arena[base + VGEO_PAGE_ROW_OFFSET.GEOMETRY_ROW] = geometry_row;
548
612
  this.#arena[base + VGEO_PAGE_ROW_OFFSET.DECODED_SIZE] = page.decoded_size;
613
+ this.#arena[base + VGEO_PAGE_ROW_OFFSET.PARENT_ENTRY_COUNT] = parent_entry_count;
614
+
615
+ /*
616
+ The generation this row is at as it takes this occupant. An eviction bumps it, so anything
617
+ that stores a page row and outlives the frame can tell "still the page I meant" from "that
618
+ slot was refilled" with one equality against the value it saw. It is mirrored here rather
619
+ than read from #generations because the kernel cannot reach a private field, and it is a
620
+ counter rather than a frame number because a row can be refilled twice inside one frame.
621
+ */
622
+ this.#arena[base + VGEO_PAGE_ROW_OFFSET.GENERATION] = this.#generations[page_row];
549
623
 
550
624
  this.#resident_rows.add(page_row);
551
625
  this.#geometry_rows.get(geometry_row).add(page_row);
@@ -562,6 +636,9 @@ export class VGeoRuntimeTables {
562
636
  ] = page_row;
563
637
  }
564
638
 
639
+ this.#link(page_row, geometry_row, page, lookup_base);
640
+ this.#activate(page_row, geometry_row, page, lookup_base);
641
+
565
642
  return page_row;
566
643
  }
567
644
 
@@ -573,7 +650,8 @@ export class VGeoRuntimeTables {
573
650
  */
574
651
  slot_words_for(page) {
575
652
  return VGEO_PAGE_ROW_WORDS + vgeo_runtime_page_block_words(
576
- page.node_count, page.group_cluster_first.length, page.cluster_count
653
+ page.node_count, page.group_cluster_first.length, page.cluster_count,
654
+ page.parent_ref.length
577
655
  );
578
656
  }
579
657
 
@@ -614,6 +692,10 @@ export class VGeoRuntimeTables {
614
692
 
615
693
  this.#give_ordinal(geometry_row, this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.ORDINAL));
616
694
 
695
+ // before the header is zeroed: both read this page's rows
696
+ this.#deactivate_page(page_row, lookup_base);
697
+ this.#unlink(page_row, geometry_row, page_index, lookup_base);
698
+
617
699
  const base = page_row * this.#slot_words;
618
700
 
619
701
  this.#arena.fill(0, base, base + VGEO_PAGE_ROW_WORDS);
@@ -639,80 +721,177 @@ export class VGeoRuntimeTables {
639
721
  }
640
722
 
641
723
  /**
642
- * Whether any page resident **in this tier** refines out of this one.
724
+ * How many distinct child pages of this one are resident in this tier.
643
725
  *
644
- * Design §6's eviction rule reads "no child page resident in this tier", and this answers it out
645
- * of the arena rather than out of the RAM reader's child table — which returned "no children"
646
- * the moment the RAM tier dropped the page, orphaning every VRAM-resident child under it
647
- * (REVIEW_LEDGER M9).
726
+ * Design §6's eviction rule reads "no child page resident in this tier", and this answers it
727
+ * out of a count kept at install and evict rather than a walk of the page's cluster rows per
728
+ * candidate — and out of this tier's own residency rather than the RAM reader's child table,
729
+ * which returned "no children" the moment the RAM tier dropped the page (REVIEW_LEDGER M9).
648
730
  *
649
731
  * @param {number} page_row
650
- * @returns {boolean}
732
+ * @returns {number}
651
733
  */
652
- has_resident_child(page_row) {
653
- const geometry_row = this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.GEOMETRY_ROW);
734
+ resident_children(page_row) {
735
+ return this.#resident_children[page_row];
736
+ }
654
737
 
655
- const lookup_base = this.geometry_field(
656
- geometry_row, VGEO_GEOMETRY_ROW_OFFSET.LOOKUP_WORD_OFFSET
657
- );
738
+ /**
739
+ * Page rows whose group flags flipped since this was last called, and empties the list.
740
+ *
741
+ * @returns {number[]}
742
+ */
743
+ take_activated_rows() {
744
+ const rows = this.#activated;
745
+
746
+ this.#activated = [];
747
+
748
+ return rows;
749
+ }
750
+
751
+ /**
752
+ * Put an arriving page into the reverse index and the child counts.
753
+ *
754
+ * Both directions, because a page arrives in either order relative to its parents: a child
755
+ * fetched through one parent while another parent page is absent, and that parent arriving
756
+ * later, are both the ordinary streaming path. So the page counts the children of its own that
757
+ * are already here, and every resident parent that refers into it counts one more.
758
+ *
759
+ * @param {number} page_row
760
+ * @param {number} geometry_row
761
+ * @param {VGeoPage} page
762
+ * @param {number} lookup_base
763
+ */
764
+ #link(page_row, geometry_row, page, lookup_base) {
765
+ const referrers = this.#referrers.get(geometry_row);
766
+
767
+ // the child table is the distinct list; the cluster rows repeat it once per cluster
768
+ for (const child of page.child_page_index) {
769
+ let rows = referrers.get(child);
770
+
771
+ if (rows === undefined) {
772
+ rows = [];
773
+
774
+ referrers.set(child, rows);
775
+ }
776
+
777
+ rows.push(page_row);
778
+
779
+ if (this.#lookup[lookup_base + child] !== VGEO_PAGE_ROW_NONE) {
780
+ this.#resident_children[page_row]++;
781
+ }
782
+ }
783
+
784
+ const parents = referrers.get(page.index);
658
785
 
786
+ if (parents !== undefined) {
787
+ for (const parent_row of parents) {
788
+ this.#resident_children[parent_row]++;
789
+ }
790
+ }
791
+ }
792
+
793
+ /**
794
+ * Take a leaving page out of the reverse index and the child counts.
795
+ *
796
+ * @param {number} page_row
797
+ * @param {number} geometry_row
798
+ * @param {number} page_index
799
+ * @param {number} lookup_base
800
+ */
801
+ #unlink(page_row, geometry_row, page_index, lookup_base) {
802
+ const referrers = this.#referrers.get(geometry_row);
803
+
804
+ // out of every child's list of parents; the rows repeat a child once per cluster, and the
805
+ // list holds this row once, so only the first cluster naming a child finds anything
659
806
  const cluster_count = this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.CLUSTER_COUNT);
660
807
  const cluster_base = this.cluster_base(page_row);
661
808
 
662
809
  for (let cluster = 0; cluster < cluster_count; cluster++) {
663
- const child_page_index = this.#arena[
810
+ const child = this.#arena[
664
811
  cluster_base + cluster * VGEO_CLUSTER_ROW_WORDS
665
812
  + VGEO_CLUSTER_ROW_OFFSET.CHILD_PAGE_INDEX
666
813
  ];
667
814
 
668
- if (child_page_index === VGEO_NO_CHILD_PAGE) {
815
+ if (child === VGEO_NO_CHILD_PAGE || child === page_index) {
669
816
  continue;
670
817
  }
671
818
 
672
- const child_row = this.#lookup[lookup_base + child_page_index];
819
+ const rows = referrers.get(child);
673
820
 
674
- if (child_row !== VGEO_PAGE_ROW_NONE && child_row !== page_row) {
675
- return true;
821
+ if (rows === undefined) {
822
+ continue;
823
+ }
824
+
825
+ const at = rows.indexOf(page_row);
826
+
827
+ if (at !== -1) {
828
+ rows.splice(at, 1);
829
+
830
+ if (rows.length === 0) {
831
+ referrers.delete(child);
832
+ }
833
+ }
834
+ }
835
+
836
+ const parents = referrers.get(page_index);
837
+
838
+ if (parents !== undefined) {
839
+ for (const parent_row of parents) {
840
+ this.#resident_children[parent_row]--;
676
841
  }
677
842
  }
678
843
 
679
- return false;
844
+ this.#resident_children[page_row] = 0;
845
+ }
846
+
847
+ /**
848
+ * @param {number} group_row word offset of a group row
849
+ * @returns {number} live parent references counted so far
850
+ */
851
+ #live_count(group_row) {
852
+ return this.#arena[group_row + VGEO_GROUP_ROW_OFFSET.FLAGS] >>> 16;
680
853
  }
681
854
 
682
855
  /**
683
- * Recompute one geometry's group selectability over **this tier's** residency.
856
+ * One more live reference into a group. Above the flag bit, which the kernels mask; a count
857
+ * alone marks nothing dirty.
684
858
  *
685
- * `VIRTUAL_GEOMETRY_DESIGN.md` §6: a group is selectable iff every one of its parent-cluster
686
- * references is live — the referencing cluster's page resident here, and that cluster's own
687
- * group selectable here. Groups with no parents at all are the top of the DAG and are selectable
688
- * the moment their page is. That is a closure over the resident set, so it is computed as one:
689
- * seed the parentless groups and cascade down, counting a reference only when the group making
690
- * it is already selectable.
859
+ * @param {number} group_row
860
+ * @returns {boolean} whether the count now equals the group's parent count
861
+ */
862
+ #count_reference(group_row) {
863
+ const word = group_row + VGEO_GROUP_ROW_OFFSET.FLAGS;
864
+
865
+ this.#arena[word] += 1 << 16;
866
+
867
+ return (this.#arena[word] >>> 16) === this.#arena[group_row + VGEO_GROUP_ROW_OFFSET.PARENT_COUNT];
868
+ }
869
+
870
+ /**
871
+ * Activate an arriving page: seed its groups from the resident parents that refer into them,
872
+ * then cascade from every group that has all of its parents.
691
873
  *
692
- * Recomputed whole rather than propagated incrementally, because an install can turn groups on
693
- * several pages away and an eviction can turn them off again, and because the cost is the same
694
- * order as the install that provoked it — one pass over the geometry's resident clusters. The
695
- * incremental form is a later optimization with a counter to keep correct; the one thing it
696
- * must not be is a *second* implementation of the rule.
874
+ * Same-page parents are not seeded; the cascade reaches them, because the page's own lookup
875
+ * word is already set and a same-page child reference resolves to this row.
697
876
  *
877
+ * @param {number} page_row
698
878
  * @param {number} geometry_row
699
- * @returns {number[]} page rows whose group flags changed, for the caller to upload
879
+ * @param {VGeoPage} page
880
+ * @param {number} lookup_base
700
881
  */
701
- refresh_selectable(geometry_row) {
702
- const rows = this.#geometry_rows.get(geometry_row);
703
-
704
- if (rows === undefined || rows.size === 0) {
705
- return [];
706
- }
707
-
882
+ #activate(page_row, geometry_row, page, lookup_base) {
708
883
  const arena = this.#arena;
709
- const live = this.#live_refs;
710
884
 
711
- live.clear();
885
+ const group_count = page.group_cluster_first.length;
886
+ const group_base = this.group_base(page_row);
712
887
 
713
- const lookup_base = this.geometry_field(
714
- geometry_row, VGEO_GEOMETRY_ROW_OFFSET.LOOKUP_WORD_OFFSET
715
- );
888
+ const parents = this.#referrers.get(geometry_row).get(page.index);
889
+
890
+ if (parents !== undefined) {
891
+ for (const parent_row of parents) {
892
+ this.#seed_from(parent_row, page.index, group_base, group_count);
893
+ }
894
+ }
716
895
 
717
896
  /**
718
897
  * Word offsets of group rows to turn on, as a stack.
@@ -720,37 +899,87 @@ export class VGeoRuntimeTables {
720
899
  */
721
900
  const queue = [];
722
901
 
723
- for (const page_row of rows) {
724
- const group_count = this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT);
725
- const group_base = this.group_base(page_row);
902
+ for (let group = 0; group < group_count; group++) {
903
+ const row = group_base + group * VGEO_GROUP_ROW_WORDS;
726
904
 
727
- for (let group = 0; group < group_count; group++) {
728
- const row = group_base + group * VGEO_GROUP_ROW_WORDS;
905
+ if (this.#live_count(row) === arena[row + VGEO_GROUP_ROW_OFFSET.PARENT_COUNT]) {
906
+ queue.push(row);
907
+ }
908
+ }
729
909
 
730
- live.set(row, 0);
910
+ this.#cascade(queue, lookup_base);
911
+ }
731
912
 
732
- if (arena[row + VGEO_GROUP_ROW_OFFSET.PARENT_COUNT] === 0) {
733
- queue.push(row);
913
+ /**
914
+ * Count the references one resident parent page's **selectable** groups make into an arriving
915
+ * page's groups.
916
+ *
917
+ * @param {number} parent_row
918
+ * @param {number} child_page_index
919
+ * @param {number} child_group_base
920
+ * @param {number} child_group_count
921
+ */
922
+ #seed_from(parent_row, child_page_index, child_group_base, child_group_count) {
923
+ const arena = this.#arena;
924
+
925
+ const group_count = this.page_field(parent_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT);
926
+ const group_base = this.group_base(parent_row);
927
+ const cluster_base = this.cluster_base(parent_row);
928
+
929
+ for (let group = 0; group < group_count; group++) {
930
+ const group_row = group_base + group * VGEO_GROUP_ROW_WORDS;
931
+
932
+ if ((arena[group_row + VGEO_GROUP_ROW_OFFSET.FLAGS] & VGEO_GROUP_FLAG_SELECTABLE) === 0) {
933
+ continue;
934
+ }
935
+
936
+ const first = arena[group_row + VGEO_GROUP_ROW_OFFSET.CLUSTER_FIRST];
937
+ const count = arena[group_row + VGEO_GROUP_ROW_OFFSET.CLUSTER_COUNT];
938
+
939
+ for (let i = 0; i < count; i++) {
940
+ const cluster = cluster_base + (first + i) * VGEO_CLUSTER_ROW_WORDS;
941
+
942
+ if (arena[cluster + VGEO_CLUSTER_ROW_OFFSET.CHILD_PAGE_INDEX] !== child_page_index) {
943
+ continue;
944
+ }
945
+
946
+ const child_group = arena[cluster + VGEO_CLUSTER_ROW_OFFSET.CHILD_GROUP];
947
+
948
+ if (child_group >= child_group_count) {
949
+ // outside the child page's table; counting it would land in a cluster row
950
+ continue;
734
951
  }
952
+
953
+ this.#count_reference(child_group_base + child_group * VGEO_GROUP_ROW_WORDS);
735
954
  }
736
955
  }
956
+ }
737
957
 
738
- /**
739
- * @type {Set<number>}
740
- */
741
- const selectable = new Set();
958
+ /**
959
+ * Turn groups on and let each one count itself into its resident children, turning on the
960
+ * children that reach their parent count — design §6's cascade, over this tier's residency.
961
+ *
962
+ * @param {number[]} queue word offsets of group rows whose count has reached their parent count
963
+ * @param {number} lookup_base
964
+ */
965
+ #cascade(queue, lookup_base) {
966
+ const arena = this.#arena;
742
967
 
743
968
  while (queue.length > 0) {
744
969
  const group_row = queue.pop();
745
970
 
746
- if (selectable.has(group_row)) {
971
+ const flags_word = group_row + VGEO_GROUP_ROW_OFFSET.FLAGS;
972
+
973
+ if ((arena[flags_word] & VGEO_GROUP_FLAG_SELECTABLE) !== 0) {
747
974
  continue;
748
975
  }
749
976
 
750
- selectable.add(group_row);
977
+ arena[flags_word] |= VGEO_GROUP_FLAG_SELECTABLE;
751
978
 
752
979
  const page_row = Math.floor(group_row / this.#slot_words);
753
980
 
981
+ this.#activated.push(page_row);
982
+
754
983
  const cluster_base = this.cluster_base(page_row);
755
984
 
756
985
  const first = arena[group_row + VGEO_GROUP_ROW_OFFSET.CLUSTER_FIRST];
@@ -759,80 +988,131 @@ export class VGeoRuntimeTables {
759
988
  for (let i = 0; i < count; i++) {
760
989
  const cluster = cluster_base + (first + i) * VGEO_CLUSTER_ROW_WORDS;
761
990
 
762
- const child_page_index = arena[
763
- cluster + VGEO_CLUSTER_ROW_OFFSET.CHILD_PAGE_INDEX
764
- ];
991
+ const child = this.#child_group_row(cluster, lookup_base);
765
992
 
766
- if (child_page_index === VGEO_NO_CHILD_PAGE) {
993
+ if (child === -1) {
767
994
  continue;
768
995
  }
769
996
 
770
- const child_row = this.#lookup[lookup_base + child_page_index];
771
-
772
- if (child_row === VGEO_PAGE_ROW_NONE) {
773
- // the child page is not in this tier; its groups stay blocked, which is exactly
774
- // what makes the cluster above clamp and draw
775
- continue;
997
+ if (this.#count_reference(child)) {
998
+ queue.push(child);
776
999
  }
1000
+ }
1001
+ }
1002
+ }
777
1003
 
778
- const child_group = arena[cluster + VGEO_CLUSTER_ROW_OFFSET.CHILD_GROUP];
1004
+ /**
1005
+ * The group row a cluster refines into, if that group's page is resident and the reference is
1006
+ * inside its table.
1007
+ *
1008
+ * @param {number} cluster word offset of the cluster row
1009
+ * @param {number} lookup_base
1010
+ * @returns {number} word offset of the child group row, or -1
1011
+ */
1012
+ #child_group_row(cluster, lookup_base) {
1013
+ const arena = this.#arena;
779
1014
 
780
- if (child_group >= this.page_field(child_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT)) {
781
- // a child_group outside the child page's table; counting it would corrupt a
782
- // neighbour's counter, and the traversal draws the referring cluster instead
783
- continue;
784
- }
1015
+ const child_page_index = arena[cluster + VGEO_CLUSTER_ROW_OFFSET.CHILD_PAGE_INDEX];
785
1016
 
786
- const child = this.group_base(child_row) + child_group * VGEO_GROUP_ROW_WORDS;
1017
+ if (child_page_index === VGEO_NO_CHILD_PAGE) {
1018
+ return -1;
1019
+ }
787
1020
 
788
- const counted = live.get(child) + 1;
1021
+ const child_row = this.#lookup[lookup_base + child_page_index];
789
1022
 
790
- live.set(child, counted);
1023
+ if (child_row === VGEO_PAGE_ROW_NONE) {
1024
+ // the child page is not in this tier; its groups stay blocked, which is exactly what
1025
+ // makes the cluster above clamp and draw
1026
+ return -1;
1027
+ }
791
1028
 
792
- if (counted === arena[child + VGEO_GROUP_ROW_OFFSET.PARENT_COUNT]) {
793
- queue.push(child);
794
- }
795
- }
1029
+ const child_group = arena[cluster + VGEO_CLUSTER_ROW_OFFSET.CHILD_GROUP];
1030
+
1031
+ if (child_group >= this.page_field(child_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT)) {
1032
+ // a child_group outside the child page's table; counting it would corrupt a
1033
+ // neighbour's row, and the traversal draws the referring cluster instead
1034
+ return -1;
796
1035
  }
797
1036
 
798
- /**
799
- * @type {number[]}
800
- */
801
- const changed = [];
1037
+ return this.group_base(child_row) + child_group * VGEO_GROUP_ROW_WORDS;
1038
+ }
1039
+
1040
+ /**
1041
+ * Retract a leaving page's references and turn off whatever they were holding up.
1042
+ *
1043
+ * Under the child rule this finds nothing to retract: a page with no resident child has no
1044
+ * resident group depending on it. It is here for the callers that evict against the rule —
1045
+ * `unregister_geometry`, a tool, a spec — so that a child group is never left selectable
1046
+ * with a parent's page gone, which is the double-draw the whole rule exists to prevent
1047
+ * (REVIEW_LEDGER C1).
1048
+ *
1049
+ * @param {number} page_row
1050
+ * @param {number} lookup_base
1051
+ */
1052
+ #deactivate_page(page_row, lookup_base) {
1053
+ if (this.#resident_children[page_row] === 0) {
1054
+ return;
1055
+ }
802
1056
 
803
- for (const page_row of rows) {
804
- const group_count = this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT);
805
- const group_base = this.group_base(page_row);
1057
+ const arena = this.#arena;
806
1058
 
807
- let dirty = false;
1059
+ const group_count = this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT);
1060
+ const group_base = this.group_base(page_row);
808
1061
 
809
- for (let group = 0; group < group_count; group++) {
810
- const row = group_base + group * VGEO_GROUP_ROW_WORDS;
1062
+ for (let group = 0; group < group_count; group++) {
1063
+ const group_row = group_base + group * VGEO_GROUP_ROW_WORDS;
811
1064
 
812
- const flags = selectable.has(row) ? VGEO_GROUP_FLAG_SELECTABLE : 0;
1065
+ if ((arena[group_row + VGEO_GROUP_ROW_OFFSET.FLAGS] & VGEO_GROUP_FLAG_SELECTABLE) !== 0) {
1066
+ this.#retract(group_row, lookup_base);
1067
+ }
1068
+ }
1069
+ }
813
1070
 
814
- if (arena[row + VGEO_GROUP_ROW_OFFSET.FLAGS] !== flags) {
815
- arena[row + VGEO_GROUP_ROW_OFFSET.FLAGS] = flags;
1071
+ /**
1072
+ * Take one selectable group's references back out of its resident children, and turn off —
1073
+ * recursively — every child group that loses one.
1074
+ *
1075
+ * @param {number} group_row
1076
+ * @param {number} lookup_base
1077
+ */
1078
+ #retract(group_row, lookup_base) {
1079
+ const arena = this.#arena;
816
1080
 
817
- dirty = true;
818
- }
1081
+ const page_row = Math.floor(group_row / this.#slot_words);
1082
+ const cluster_base = this.cluster_base(page_row);
1083
+
1084
+ const first = arena[group_row + VGEO_GROUP_ROW_OFFSET.CLUSTER_FIRST];
1085
+ const count = arena[group_row + VGEO_GROUP_ROW_OFFSET.CLUSTER_COUNT];
1086
+
1087
+ for (let i = 0; i < count; i++) {
1088
+ const cluster = cluster_base + (first + i) * VGEO_CLUSTER_ROW_WORDS;
1089
+
1090
+ const child = this.#child_group_row(cluster, lookup_base);
1091
+
1092
+ if (child === -1) {
1093
+ continue;
819
1094
  }
820
1095
 
821
- if (dirty) {
822
- changed.push(page_row);
1096
+ const flags_word = child + VGEO_GROUP_ROW_OFFSET.FLAGS;
1097
+
1098
+ arena[flags_word] -= 1 << 16;
1099
+
1100
+ if ((arena[flags_word] & VGEO_GROUP_FLAG_SELECTABLE) !== 0) {
1101
+ arena[flags_word] &= ~VGEO_GROUP_FLAG_SELECTABLE;
1102
+
1103
+ this.#activated.push(Math.floor(child / this.#slot_words));
1104
+
1105
+ this.#retract(child, lookup_base);
823
1106
  }
824
1107
  }
825
-
826
- return changed;
827
1108
  }
828
-
829
1109
  /**
830
1110
  * Publish one group's selectability directly.
831
1111
  *
832
- * {@link refresh_selectable} is what a runtime calls; this is for a spec that needs a state the
833
- * rule happens not to produce on the assets measured so far — the cut's own-group term is
834
- * correctness for exactly such a state, and a guard nothing can construct is a guard nothing can
835
- * test. The next {@link refresh_selectable} overwrites it.
1112
+ * Activation is the tables' own; this is for a spec that needs a state the rule happens not to
1113
+ * produce on the assets measured so far — the cut's own-group term is correctness for exactly
1114
+ * such a state, and a guard nothing can construct is a guard nothing can test. It writes the
1115
+ * flag bit and leaves the count, so the next cascade through the group may overwrite it.
836
1116
  *
837
1117
  * @param {number} page_row
838
1118
  * @param {number} group
@@ -844,7 +1124,9 @@ export class VGeoRuntimeTables {
844
1124
  + group * VGEO_GROUP_ROW_WORDS
845
1125
  + VGEO_GROUP_ROW_OFFSET.FLAGS;
846
1126
 
847
- this.#arena[word] = selectable ? VGEO_GROUP_FLAG_SELECTABLE : 0;
1127
+ this.#arena[word] = selectable
1128
+ ? this.#arena[word] | VGEO_GROUP_FLAG_SELECTABLE
1129
+ : this.#arena[word] & ~VGEO_GROUP_FLAG_SELECTABLE;
848
1130
  }
849
1131
 
850
1132
  /**
@@ -872,7 +1154,8 @@ export class VGeoRuntimeTables {
872
1154
  const words = VGEO_PAGE_ROW_WORDS + vgeo_runtime_page_block_words(
873
1155
  this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.NODE_COUNT),
874
1156
  this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.GROUP_COUNT),
875
- this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.CLUSTER_COUNT)
1157
+ this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.CLUSTER_COUNT),
1158
+ this.page_field(page_row, VGEO_PAGE_ROW_OFFSET.PARENT_ENTRY_COUNT)
876
1159
  );
877
1160
 
878
1161
  return [base, words];