@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
@@ -1 +1 @@
1
- {"version":3,"file":"sample_asset.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/vgeo_viewer/sample_asset.js"],"names":[],"mappings":"AAyFA;;;;;;;;;;;GAWG;AACH,2CALW,MAAM,UACN,MAAM,cACN,MAAM,GACJ;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAiBtD;+BAzGM,+DAA+D"}
1
+ {"version":3,"file":"sample_asset.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/vgeo_viewer/sample_asset.js"],"names":[],"mappings":"AA0GA;;;;;;;;;;;GAWG;AACH,2CALW,MAAM,UACN,MAAM,cACN,MAAM,GACJ;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAiBtD;+BA1HM,+DAA+D"}
@@ -389,7 +389,10 @@ export class Renderer {
389
389
  *
390
390
  * @param {PerspectiveCamera} camera
391
391
  * @param {Scene} scene
392
- * @param {number} [time_delta_seconds]
392
+ * @param {number} [time_delta_seconds] simulation seconds this frame advances by — the particle
393
+ * simulation, the animation tick and exposure adaptation all step by it. Zero by default, which
394
+ * draws the current state and moves nothing; a fixed fraction of a second here instead would run
395
+ * the simulation at that rate no matter what the caller's clock was doing.
393
396
  * @returns {boolean} whether frame was rendered, will return false if previous frame hasn't finished yet
394
397
  */
395
398
  render(camera: PerspectiveCamera, scene: Scene, time_delta_seconds?: number): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"Renderer.d.ts","sourceRoot":"","sources":["../../../../src/shade/renderer/Renderer.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Renderer.d.ts","sourceRoot":"","sources":["../../../../src/shade/renderer/Renderer.js"],"names":[],"mappings":"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"}
@@ -1720,13 +1720,16 @@ export class Renderer {
1720
1720
  *
1721
1721
  * @param {PerspectiveCamera} camera
1722
1722
  * @param {Scene} scene
1723
- * @param {number} [time_delta_seconds]
1723
+ * @param {number} [time_delta_seconds] simulation seconds this frame advances by — the particle
1724
+ * simulation, the animation tick and exposure adaptation all step by it. Zero by default, which
1725
+ * draws the current state and moves nothing; a fixed fraction of a second here instead would run
1726
+ * the simulation at that rate no matter what the caller's clock was doing.
1724
1727
  * @returns {boolean} whether frame was rendered, will return false if previous frame hasn't finished yet
1725
1728
  */
1726
1729
  render(
1727
1730
  camera,
1728
1731
  scene,
1729
- time_delta_seconds = 0.01666
1732
+ time_delta_seconds = 0
1730
1733
  ) {
1731
1734
  if (this.#device_lost) {
1732
1735
  // device is lost, can't render — and asking the context for a texture would throw
@@ -677,7 +677,7 @@ add_extension(e); remove_extension(e); extension_count(phase);
677
677
 
678
678
  ## 8. Migration
679
679
 
680
- Nine live systems, one probe, one prototype viewer. Every one of them is the same mechanical change:
680
+ Nine live systems and one probe. Every one of them is the same mechanical change:
681
681
  a closure becomes a class, `context.color` becomes `frame.get(SceneColor).color`, and the return
682
682
  value becomes a publication.
683
683
 
@@ -693,7 +693,6 @@ value becomes a publication.
693
693
  | `DebugDrawSystem` | `AfterTransparency` | `after: [FogOfWarExtension]` |
694
694
  | `Trail3DSystem` | `AfterTransparency` | — |
695
695
  | `probeShadePassInjection` | all | the gate is rewritten and gains the two checks it is currently blind to: a G-buffer replacement, and an order flip |
696
- | `vgeo_viewer` playground | `AfterTransparency` | prototype; mechanical |
697
696
 
698
697
  **The `AfterTransparency` chain is settled, not open.** Fog of war is last among the content
699
698
  extensions, because it conceals and therefore belongs over everything it is meant to conceal —
@@ -72,6 +72,17 @@ export class GPUGeometryBVHManager {
72
72
  */
73
73
  get empty_tree_address(): number;
74
74
  get gpu_memory_usage(): number;
75
+ /**
76
+ * Bytes of the node arena that trees actually occupy: its capacity, less every region
77
+ * {@link #allocator} still holds free.
78
+ *
79
+ * Beside {@link gpu_memory_usage}, which is what the arenas cost whether or not anything is
80
+ * in them. The gap between the two is what a released tree gives back and what the next tree
81
+ * of that size takes, so it is the one worth watching.
82
+ *
83
+ * @returns {number} in bytes
84
+ */
85
+ get gpu_memory_usage_occupied(): number;
75
86
  /**
76
87
  * The tree belonging to `owner`, registered against `source`'s shape if it does not exist yet.
77
88
  *
@@ -1 +1 @@
1
- {"version":3,"file":"GPUGeometryBVHManager.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js"],"names":[],"mappings":"AAmBA;;;GAGG;AAEH;;;;;GAKG;AACH,gDAGG;AAEH;;;;;;;;;;;GAWG;AACH,sCAFU,MAAM,CAEyB;AAoBzC;;;;;;;;;;;;;;GAcG;AACH;IA0II;;;OAGG;IACH,+BAoDC;IA1LD;;;OAGG;IACH,iCAEC;IAOD;;;OAGG;IACH,6BAEC;IAuCD;;OAEG;IACH,gCAEC;IAOD;;OAEG;IACH,mCAEC;IA+BD;;OAEG;IACH,gCAEC;IA6ED;;;;OAIG;IACH,iCAEC;IAED,+BAoBC;IAED;;;;;;;;;;;;;;OAcG;IACH,cALW,MAAM,UACN,eAAe,GAEb,sBAAsB,CAalC;IA8DD;;;;;;;;;;;;OAYG;IACH,wBAHW,MAAM,GACJ;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAC,GAAC,SAAS,CAqB3I;IAED;;;;;;OAMG;IACH,mBAHW,MAAM,GACJ,MAAM,GAAC,SAAS,CAU5B;IAED;;;;;;;;;OASG;IACH,0BAFW,WAAW,QAQrB;IAED;;;;;;;;;;;OAWG;IACH,cAHW,MAAM,GACJ,OAAO,CA8BnB;IA4LD;;;;;;;OAOG;IACH,eAOC;;CAuIJ;8BAxzBY,OAAO,uBAAuB,EAAE,eAAe;yBAC/C,OAAO,sDAAsD,EAAE,UAAU;6BAbzD,mCAAmC;uCASzB,6BAA6B"}
1
+ {"version":3,"file":"GPUGeometryBVHManager.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js"],"names":[],"mappings":"AAkBA;;;GAGG;AAEH;;;;;GAKG;AACH,gDAGG;AAEH;;;;;;;;;;;GAWG;AACH,sCAFU,MAAM,CAEyB;AAoBzC;;;;;;;;;;;;;;GAcG;AACH;IA0II;;;OAGG;IACH,+BAoDC;IA1LD;;;OAGG;IACH,iCAEC;IAOD;;;OAGG;IACH,6BAEC;IAuCD;;OAEG;IACH,gCAEC;IAOD;;OAEG;IACH,mCAEC;IA+BD;;OAEG;IACH,gCAEC;IA6ED;;;;OAIG;IACH,iCAEC;IAED,+BAoBC;IAED;;;;;;;;;OASG;IACH,wCAIC;IAED;;;;;;;;;;;;;;OAcG;IACH,cALW,MAAM,UACN,eAAe,GAEb,sBAAsB,CAalC;IA8DD;;;;;;;;;;;;OAYG;IACH,wBAHW,MAAM,GACJ;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAC,GAAC,SAAS,CAqB3I;IAED;;;;;;OAMG;IACH,mBAHW,MAAM,GACJ,MAAM,GAAC,SAAS,CAU5B;IAED;;;;;;;;;OASG;IACH,0BAFW,WAAW,QAQrB;IAED;;;;;;;;;;;OAWG;IACH,cAHW,MAAM,GACJ,OAAO,CA8BnB;IA4LD;;;;;;;OAOG;IACH,eAOC;;CAgIJ;8BAj0BY,OAAO,uBAAuB,EAAE,eAAe;yBAC/C,OAAO,sDAAsD,EAAE,UAAU;6BAbzD,mCAAmC;uCASzB,6BAA6B"}
@@ -4,7 +4,6 @@ import { platform_compute_endianness } from "../../../../core/binary/platform_co
4
4
  import { array_buffer_copy } from "../../../../core/collection/array/typed/array_buffer_copy.js";
5
5
  import { Deque } from "../../../../core/collection/queue/Deque.js";
6
6
  import { round_up } from "../../../../core/math/round_up.js";
7
- import { number_format_by_thousands } from "../../../../core/primitives/numbers/number_format_by_thousands.js";
8
7
  import { u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
9
8
  import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
10
9
  import { BVH2_NODE_STRUCT } from "../../shader/chunk/bvh/BVH2_NODE_STRUCT.js";
@@ -307,6 +306,22 @@ export class GPUGeometryBVHManager {
307
306
  return r;
308
307
  }
309
308
 
309
+ /**
310
+ * Bytes of the node arena that trees actually occupy: its capacity, less every region
311
+ * {@link #allocator} still holds free.
312
+ *
313
+ * Beside {@link gpu_memory_usage}, which is what the arenas cost whether or not anything is
314
+ * in them. The gap between the two is what a released tree gives back and what the next tree
315
+ * of that size takes, so it is the one worth watching.
316
+ *
317
+ * @returns {number} in bytes
318
+ */
319
+ get gpu_memory_usage_occupied() {
320
+ const free_nodes = this.#allocator.storageReport().totalFreeSpace;
321
+
322
+ return (this.#node_capacity - free_nodes) * BVH2_NODE_STRUCT.size;
323
+ }
324
+
310
325
  /**
311
326
  * The tree belonging to `owner`, registered against `source`'s shape if it does not exist yet.
312
327
  *
@@ -828,13 +843,6 @@ export class GPUGeometryBVHManager {
828
843
  );
829
844
  }
830
845
 
831
- const free_nodes = this.#allocator.storageReport().freeStorage;
832
-
833
- console.warn(
834
- `BLAS size: ${number_format_by_thousands((this.#node_capacity - free_nodes) * BVH2_NODE_STRUCT.size)} bytes` +
835
- ` of ${number_format_by_thousands(this.#node_capacity * BVH2_NODE_STRUCT.size)}`
836
- );
837
-
838
846
  device.queue.submit([encoder.finish()])
839
847
 
840
848
  // free up the temp buffer
@@ -1 +1 @@
1
- {"version":3,"file":"GPUMeshletManager.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/meshlet/GPUMeshletManager.js"],"names":[],"mappings":"AAuFA;IAqEI;;;;;;OAMG;IACH;QAJ8B,MAAM;QACR,qBAAqB,GAAtC,MAAM;QACW,yBAAyB,GAA1C,MAAM;OAkChB;IAzFD,6BAEC;IAOD,iCAEC;IAgFD,gBAKC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,sBAHW,MAAM,uBACN,MAAM,QAuHhB;IAqRD;;;;;;;;;;;OAWG;IACH,qBAJW,4BAA4B,GAE1B,OAAO,CAmBnB;IAgCD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,+BAHW,4BAA4B,GAC1B,4BAA4B,CA8BxC;IAED;;;;;;;;;;;;OAYG;IACH,gBAFW,sBAAsB,QA8GhC;IAED,gBAGC;IAED;;;;OAIG;IACH,iBAHW,YAAY,GACV,4BAA4B,CA6BxC;IAED,mCASC;IAED,wCAQC;IAED,+BAYC;;CACJ;yBA/4BY,OAAO,sDAAsD,EAAE,UAAU;qCACzE,OAAO,2CAA2C,EAAE,sBAAsB;2BAC1E,OAAO,mBAAmB,EAAE,YAAY;AA6BrD;IACI;;OAEG;IACH,UAFU,UAAU,CAEZ;IACR;;OAEG;IACH,MAFU,UAAU,CAEhB;IAEJ;;;OAGG;IACH,WAFU,MAAM,CAEF;IAEd;;;OAGG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,0BAFU,WAAW,CAEI;IAEzB;;;OAGG;IACH,aAAsB;CACzB"}
1
+ {"version":3,"file":"GPUMeshletManager.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/meshlet/GPUMeshletManager.js"],"names":[],"mappings":"AAuFA;IA4EI;;;;;;OAMG;IACH;QAJ8B,MAAM;QACR,qBAAqB,GAAtC,MAAM;QACW,yBAAyB,GAA1C,MAAM;OAkChB;IAhGD,6BAEC;IAOD,iCAEC;IAuFD,gBAKC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,sBAHW,MAAM,uBACN,MAAM,QAuHhB;IAoRD;;;;;;;;;;;OAWG;IACH,qBAJW,4BAA4B,GAE1B,OAAO,CAkBnB;IAgCD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,+BAHW,4BAA4B,GAC1B,4BAA4B,CA8BxC;IAED;;;;;;;;;;;;OAYG;IACH,gBAFW,sBAAsB,QA8GhC;IAED,gBAGC;IAED;;;;OAIG;IACH,iBAHW,YAAY,GACV,4BAA4B,CA6BxC;IAED,mCASC;IAED,wCAQC;IAED,+BAYC;;CACJ;yBAp5BY,OAAO,sDAAsD,EAAE,UAAU;qCACzE,OAAO,2CAA2C,EAAE,sBAAsB;2BAC1E,OAAO,mBAAmB,EAAE,YAAY;AA6BrD;IACI;;OAEG;IACH,UAFU,UAAU,CAEZ;IACR;;OAEG;IACH,MAFU,UAAU,CAEhB;IAEJ;;;OAGG;IACH,WAFU,MAAM,CAEF;IAEd;;;OAGG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,0BAFU,WAAW,CAEI;IAEzB;;;OAGG;IACH,aAAsB;CACzB"}
@@ -129,10 +129,17 @@ export class GPUMeshletManager {
129
129
  #deallocations_since_last_rebuild = 0;
130
130
 
131
131
  /**
132
+ * Every live allocation, in the order it was made — which is the order a rebuild packs them in.
132
133
  *
133
- * @type {MeshletBatchAllocationRecord[]}
134
+ * A `Set` and not an array: {@link remove_batch} used to find its record with `indexOf` and take
135
+ * it out with `splice`, a walk of every record the manager held per removal. A static scene
136
+ * never noticed. A virtual-geometry tier evicts pages every frame, and each eviction paid a
137
+ * scan of every resident page and every static batch — 15 µs at 64,000 records, and an asset's
138
+ * unregister paid it once per page (RUNTIME_PLAN_2026_09_14 §0, step 0).
139
+ *
140
+ * @type {Set<MeshletBatchAllocationRecord>}
134
141
  */
135
- #records = [];
142
+ #records = new Set();
136
143
 
137
144
  /**
138
145
  * Queue of GPU-side clones that have been allocated but not yet
@@ -407,7 +414,7 @@ export class GPUMeshletManager {
407
414
  const device = this.#device;
408
415
 
409
416
  const records = this.#records;
410
- const record_count = records.length;
417
+ const record_count = records.size;
411
418
  const new_allocator_data = new OffsetAllocator(
412
419
  new_data_size,
413
420
  Math.max(record_count * 2, ALLOCATION_LIMIT)
@@ -438,9 +445,8 @@ export class GPUMeshletManager {
438
445
 
439
446
  const moved_records = [];
440
447
 
441
- // move data
442
- for (let i = 0; i < record_count; i++) {
443
- const record = records[i];
448
+ // move data, in allocation order, which is the order the set keeps
449
+ for (const record of records) {
444
450
 
445
451
  const new_allocation_data = new_allocator_data.allocate(record.data_size);
446
452
  const new_allocation_metadata = new_allocator_metadata.allocate(record.meshlet_count);
@@ -613,7 +619,7 @@ export class GPUMeshletManager {
613
619
 
614
620
  record.metadata_buffer_original = batch.metadata_buffer;
615
621
 
616
- this.#records.push(record);
622
+ this.#records.add(record);
617
623
 
618
624
  return record;
619
625
  }
@@ -633,8 +639,7 @@ export class GPUMeshletManager {
633
639
  remove_batch(record) {
634
640
  assert.defined(record, 'record');
635
641
 
636
- const index = this.#records.indexOf(record);
637
- if (index === -1) {
642
+ if (!this.#records.has(record)) {
638
643
  return false;
639
644
  }
640
645
 
@@ -643,7 +648,7 @@ export class GPUMeshletManager {
643
648
  this.#allocator_data.free(record.data);
644
649
  this.#allocator_metadata.free(record.metadata);
645
650
 
646
- this.#records.splice(index, 1);
651
+ this.#records.delete(record);
647
652
  this.#deallocations_since_last_rebuild++;
648
653
 
649
654
  return true;
@@ -722,7 +727,7 @@ export class GPUMeshletManager {
722
727
  // the clone's metadata correctly under its new data offset.
723
728
  record.metadata_buffer_original = source.metadata_buffer_original;
724
729
 
725
- this.#records.push(record);
730
+ this.#records.add(record);
726
731
 
727
732
  // The queue names the two records rather than the addresses they
728
733
  // hold right now. Both are in `#records`, so a rebuild between
@@ -1 +1 @@
1
- {"version":3,"file":"MeshletBatch.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/meshlet/MeshletBatch.js"],"names":[],"mappings":"AAkEA;;GAEG;AACH;IAiBI;;;OAGG;IACH,oCAGC;IAXD,+BAEC;IA6BD;;;OAGG;IACH,wCAGC;IAfD;;;OAGG;IACH,mCAEC;IAqBD;;;OAGG;IACH,yBAEC;IAdD;;;OAGG;IACH,oBAEC;IAUD;;;OAGG;IACH,QAFa,MAAM,CASlB;IAED;;;OAGG;IACH,cAFW,YAAY,WAQtB;IAED;;;;OAIG;IACH,YAFa,MAAM,CAoFlB;IAED;;;OAGG;IACH,iBAEC;IAED;;;;OAIG;IACH,wBAHW,MAAM,GACL,EAAE,CAeb;IAED;;;OAGG;IACH,yBAFW,MAAM;;;;MAgChB;IA4LD,qBA+BC;IAED;;;OAGG;IACH,gBAFW,QAAQ,QASlB;IAIL;;;;OAIG;IACH,yBAFU,OAAO,CAEoB;;CAPpC;uBA1gBY,OAAO,gBAAgB,EAAE,QAAQ"}
1
+ {"version":3,"file":"MeshletBatch.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/meshlet/MeshletBatch.js"],"names":[],"mappings":"AAwCA;;GAEG;AACH;IAiBI;;;OAGG;IACH,oCAGC;IAXD,+BAEC;IA6BD;;;OAGG;IACH,wCAGC;IAfD;;;OAGG;IACH,mCAEC;IAqBD;;;OAGG;IACH,yBAEC;IAdD;;;OAGG;IACH,oBAEC;IAUD;;;OAGG;IACH,QAFa,MAAM,CASlB;IAED;;;OAGG;IACH,cAFW,YAAY,WAQtB;IAED;;;;OAIG;IACH,YAFa,MAAM,CAoFlB;IAED;;;OAGG;IACH,iBAEC;IAED;;;;OAIG;IACH,wBAHW,MAAM,GACL,EAAE,CAeb;IAED;;;OAGG;IACH,yBAFW,MAAM;;;;MAgChB;IA4LD,qBA+BC;IAED;;;OAGG;IACH,gBAFW,QAAQ,QASlB;IAIL;;;;OAIG;IACH,yBAFU,OAAO,CAEoB;;CAPpC;uBA/eY,OAAO,gBAAgB,EAAE,QAAQ"}
@@ -11,10 +11,11 @@ import { aabb3_from_v3_array } from "../../../../core/geom/3d/aabb/aabb3_from_v3
11
11
  import { round_up } from "../../../../core/math/round_up.js";
12
12
  import { read_wgsl_type_value } from "../../shader/type/serde/read_gpu_typed_buffer.js";
13
13
  import { write_wgsl_type_value } from "../../shader/type/serde/write_gpu_typed_buffer.js";
14
- import { encode_normals_to_octahedral_u32 } from "../normals/encode_normals_to_octahedral_u32.js";
15
- import { encode_tangents_to_u32 } from "../normals/encode_tangents_to_u32.js";
16
14
  import { StandardAttributes } from "../StandardAttributes.js";
17
15
  import { geometry_to_meshlets_meshoptimizer } from "./build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js";
16
+ import {
17
+ ENCODED_ATTRIBUTE_DEFAULT_VALUES
18
+ } from "./encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.js";
18
19
  import { ENCODED_ATTRIBUTE_SIZES } from "./encoding/ENCODED_ATTRIBUTE_SIZES.js";
19
20
  import { ENCODED_ORDERED_ATTRIBUTES } from "./encoding/ENCODED_ORDERED_ATTRIBUTES.js";
20
21
  import { MESHLET_ATTRIBUTE_COMPRESSION_FLAGS } from "./encoding/MESHLET_ATTRIBUTE_COMPRESSION_FLAGS.js";
@@ -30,33 +31,6 @@ import { meshlet_get_attribute_offset } from "./meshlet_get_attribute_offset.js"
30
31
  */
31
32
 
32
33
 
33
- const ENCODED_ATTRIBUTE_DEFAULT_VALUES = {
34
- [StandardAttributes.Color]: 0xFFFFFFFF,
35
- [StandardAttributes.TextureCoordinates0]: [0, 0],
36
- [StandardAttributes.TextureCoordinates1]: 0,
37
- [StandardAttributes.Normal]: 0,
38
- [StandardAttributes.Tangent]: 0,
39
- [StandardAttributes.SkinningJoints]: [0,0],
40
- // Single u32 with all four packed unorm8 weights at zero —
41
- // matches the new 1-u32-per-vertex layout (was [0,0] for the
42
- // old f16×4 / 2-u32 layout).
43
- [StandardAttributes.SkinningWeights]: 0,
44
- }
45
-
46
- {
47
- const default_normal = new Uint32Array(1);
48
- encode_normals_to_octahedral_u32(default_normal, 0, 1, [0, 0, 1]);
49
-
50
- ENCODED_ATTRIBUTE_DEFAULT_VALUES[StandardAttributes.Normal] = default_normal[0];
51
- }
52
-
53
- {
54
- const default_tangent = new Uint32Array(1);
55
- encode_tangents_to_u32(default_tangent, 0, 1, [0, 0, 1, 1]);
56
-
57
- ENCODED_ATTRIBUTE_DEFAULT_VALUES[StandardAttributes.Tangent] = default_tangent[0];
58
- }
59
-
60
34
  const DEBUG_ATTRIBUTE_SIZE_TOTALS = {};
61
35
 
62
36
  globalThis.meshlet_debug = DEBUG_ATTRIBUTE_SIZE_TOTALS;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * What an attribute section holds, already encoded, when the geometry does not carry the attribute
3
+ * at all. The section is written once and flagged compressed, so this is the value every vertex of
4
+ * that meshlet reads.
5
+ *
6
+ * It lives in its own module because it is not private to the encoder that writes it: the virtual
7
+ * geometry builder produces payloads that must be **byte-identical** to these, and the only way to
8
+ * hold it to that is for its spec to compare against this object rather than against a copy of it.
9
+ * Every other table the two share — order, word sizes, compression flags — is already shared that
10
+ * way; this was the one that was not, and so the one whose drift nothing would have caught.
11
+ *
12
+ * Note what is deliberately asymmetric: colour's default is opaque white with its alpha byte set,
13
+ * while `encode_colors_to_u32` writes three channels and leaves alpha zero. A geometry with no
14
+ * colour channel therefore reads a different word than one whose every vertex is white. That is
15
+ * long-standing behaviour and changing it would change what every existing asset decodes to.
16
+ *
17
+ * Position has no entry: it is never absent.
18
+ *
19
+ * @type {Object<StandardAttributes, number|number[]>}
20
+ */
21
+ export const ENCODED_ATTRIBUTE_DEFAULT_VALUES: any;
22
+ //# sourceMappingURL=ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,mDAUE"}
@@ -0,0 +1,49 @@
1
+ import { encode_normals_to_octahedral_u32 } from "../../normals/encode_normals_to_octahedral_u32.js";
2
+ import { encode_tangents_to_u32 } from "../../normals/encode_tangents_to_u32.js";
3
+ import { StandardAttributes } from "../../StandardAttributes.js";
4
+
5
+ /**
6
+ * What an attribute section holds, already encoded, when the geometry does not carry the attribute
7
+ * at all. The section is written once and flagged compressed, so this is the value every vertex of
8
+ * that meshlet reads.
9
+ *
10
+ * It lives in its own module because it is not private to the encoder that writes it: the virtual
11
+ * geometry builder produces payloads that must be **byte-identical** to these, and the only way to
12
+ * hold it to that is for its spec to compare against this object rather than against a copy of it.
13
+ * Every other table the two share — order, word sizes, compression flags — is already shared that
14
+ * way; this was the one that was not, and so the one whose drift nothing would have caught.
15
+ *
16
+ * Note what is deliberately asymmetric: colour's default is opaque white with its alpha byte set,
17
+ * while `encode_colors_to_u32` writes three channels and leaves alpha zero. A geometry with no
18
+ * colour channel therefore reads a different word than one whose every vertex is white. That is
19
+ * long-standing behaviour and changing it would change what every existing asset decodes to.
20
+ *
21
+ * Position has no entry: it is never absent.
22
+ *
23
+ * @type {Object<StandardAttributes, number|number[]>}
24
+ */
25
+ export const ENCODED_ATTRIBUTE_DEFAULT_VALUES = {
26
+ [StandardAttributes.Color]: 0xFFFFFFFF,
27
+ [StandardAttributes.TextureCoordinates0]: [0, 0],
28
+ [StandardAttributes.TextureCoordinates1]: 0,
29
+ [StandardAttributes.Normal]: 0,
30
+ [StandardAttributes.Tangent]: 0,
31
+ [StandardAttributes.SkinningJoints]: [0, 0],
32
+ // Single u32 with all four packed unorm8 weights at zero — matches the 1-u32-per-vertex
33
+ // layout (was [0,0] for the old f16×4 / 2-u32 layout).
34
+ [StandardAttributes.SkinningWeights]: 0,
35
+ };
36
+
37
+ {
38
+ const default_normal = new Uint32Array(1);
39
+ encode_normals_to_octahedral_u32(default_normal, 0, 1, [0, 0, 1]);
40
+
41
+ ENCODED_ATTRIBUTE_DEFAULT_VALUES[StandardAttributes.Normal] = default_normal[0];
42
+ }
43
+
44
+ {
45
+ const default_tangent = new Uint32Array(1);
46
+ encode_tangents_to_u32(default_tangent, 0, 1, [0, 0, 1, 1]);
47
+
48
+ ENCODED_ATTRIBUTE_DEFAULT_VALUES[StandardAttributes.Tangent] = default_tangent[0];
49
+ }
@@ -28,8 +28,10 @@ consumer reads it, and `runtime/RUNTIME_PLAN.md` §4.8 says why: at the moment a
28
28
  per-cluster test the cut has already passed is strictly tighter than any page-level test, so the
29
29
  page-level one can never reject anything. Its consumer is prefetch, which is a later campaign.
30
30
 
31
- `shade/playground/vgeo_viewer/` drives the reader end to end, and its `select_cut.js` is a CPU
32
- reference traversal of the cut rule this format was shaped around.
31
+ `shade/playground/vgeo_runtime/` and `shade/playground/vgeo_scene/` drive the reader end to end
32
+ against a device, and `runtime/cut/__fixtures__/vgeo_select_cut.js` is a CPU reference traversal of the
33
+ cut rule this format was shaped around — the oracle the GPU cut is held to, and the only traversal
34
+ of it that is not a kernel.
33
35
 
34
36
  ## 1. Design constraints (inherited, binding)
35
37
 
@@ -116,7 +118,7 @@ All u64/u128 fields are naturally 8-byte aligned.
116
118
  | offset | type | field | notes |
117
119
  |-------:|-----------|--------------------------|-------|
118
120
  | 0 | u32 | magic | `'VGEO'` = 0x4F454756 |
119
- | 4 | u16 | format_version | 3 today; breaking layout changes only |
121
+ | 4 | u16 | format_version | 4 today; breaking layout changes only |
120
122
  | 6 | u16 | min_reader_version | 3 today; reader MUST reject if its version is lower |
121
123
  | 8 | u16 | header_size | = 256 |
122
124
  | 10 | u8 | hash_algo | 0 = xxHash3; readers MUST reject unknown values |
@@ -145,6 +147,15 @@ All u64/u128 fields are naturally 8-byte aligned.
145
147
  | 160 | [u8; 88] | reserved | |
146
148
  | 248 | u64 | header_checksum | xxh3-64 of bytes 0–255 with this field zeroed (`asset_id` already final) |
147
149
 
150
+ **`format_version` 4 moved and `min_reader_version` did not**, which is the pair working as
151
+ intended rather than an oversight. 4 added the parent tables (§6.3, §6.4): they occupy bytes that
152
+ were reserved and written as zero, and they sit between the cluster records and the payload, so
153
+ every offset a version-3 reader computes lands exactly where it did and such a reader reads a
154
+ version-4 file correctly by ignoring them. In the other direction a version-4 reader meets
155
+ `parent_table_offset = 0` on an older file and takes it as "this container has no upward edge",
156
+ which is true — so neither direction needs a version test, and nothing has to be rebuilt to stay
157
+ readable.
158
+
148
159
  ### 4.1 Level table (`level_count` × 32 B, immediately after the header)
149
160
 
150
161
  Statistics per level, at `256 + 32·i`, ending where the root page frame begins. Small —
@@ -293,9 +304,15 @@ about 0.6 ms for a 256 KB page.
293
304
  ## 6. Decoded page
294
305
 
295
306
  ```
296
- [ PageHeader (56 B) ] [ Group table ] [ Node table ] [ Cluster records ] [ Payload ]
307
+ [ PageHeader (56 B) ] [ Group table ] [ Node table ] [ Cluster records ]
308
+ [ Parent-page table ] [ Group-parent table ] [ Payload ]
297
309
  ```
298
310
 
311
+ The two parent tables sit between the cluster records and the payload, and that placement is the
312
+ reason `min_reader_version` did not move (§4): `node_table_offset`'s `= 56 + 8·group_count` stays
313
+ true, every earlier offset is where it was, and both tables hold 4-byte entries over sections that
314
+ are already multiples of four, so §11.8's word-aligned payload survives.
315
+
299
316
  PageHeader:
300
317
 
301
318
  | offset | type | field | notes |
@@ -309,7 +326,9 @@ PageHeader:
309
326
  | 12 | u32 | payload_offset | |
310
327
  | 16 | u32 | payload_size | |
311
328
  | 20 | u32 | node_table_offset | = `56 + 8·group_count`; the node table follows the group table |
312
- | 24 | [u8; 8] | reserved | |
329
+ | 24 | u32 | parent_table_offset | start of the parent section — the parent-page table, then the group-parent table. **0 means the page carries neither**, which is what every container written before `format_version` 4 says about itself |
330
+ | 28 | u16 | parent_entry_count | entries in the group-parent table (§6.3) = Σ `parent_cluster_count` over this page's groups |
331
+ | 30 | u16 | parent_page_count | entries in the parent-page table (§6.4) |
313
332
  | 32 | metric | metric | this page's own traversal metric (§6.2) — the root node's, repeated here so an installed page can be tested from itself |
314
333
 
315
334
  Group table — `group_count` × 8 B. Groups are the atomic LOD/residency unit; because a
@@ -320,8 +339,44 @@ construction — no global group index exists or is needed:
320
339
  |-------:|------|----------------------|-------|
321
340
  | 0 | u16 | cluster_first | index into this page's cluster records |
322
341
  | 2 | u16 | cluster_count | ≥ 1; ≤ 4096 (format cap, §11.5) |
323
- | 4 | u16 | parent_cluster_count | number of parent clusters referencing this group, `SAME_PAGE` references included; 0 exactly for the root page's topmost-level groups — drives activation (§10) |
324
- | 6 | u16 | reserved | |
342
+ | 4 | u16 | parent_cluster_count | number of parent clusters referencing this group, `SAME_PAGE` references included; 0 exactly for the root page's topmost-level groups — drives activation (§10). Also the length of this group's run in the group-parent table |
343
+ | 6 | u16 | parent_first | index of that run's first entry (§6.3). Groups tile the table in order, exactly as `cluster_first` tiles the cluster records |
344
+
345
+ ### 6.3 Group-parent table (`parent_entry_count` × 4 B)
346
+
347
+ The format's **only upward edge**, and the mirror of the child table with everything a parent does
348
+ not need taken out. Every entry here is the reverse of exactly one cluster's
349
+ `child_ref`/`child_group` pair, and §11.16 holds the two to each other.
350
+
351
+ | offset | type | field | notes |
352
+ |-------:|------|----------------|-------|
353
+ | 0 | u16 | parent_ref | index into the parent-page table (§6.4), or `SAME_PAGE` |
354
+ | 2 | u16 | parent_cluster | cluster index within that page |
355
+
356
+ **Four bytes an entry, against the child table's 48**, because the two directions are not
357
+ symmetric. A child reference carries a fetch range and a metric copy because the child may be
358
+ absent and the decision to fetch it is taken before it arrives. A parent of a group in the cut is
359
+ resident already — `VGEO_GROUP_FLAG_SELECTABLE` is exactly "every parent reference is live" — so a
360
+ parent reference has nothing to decide and only has to say where.
361
+
362
+ Measured across 8,899 pages of 30 converted containers: 17.4 entries a page on average and 26 at
363
+ the worst, so the table runs to about 70 bytes against pages of 56–256 KB, and compresses with the
364
+ rest of them (§5: tables are 7% of page bytes at 1.6×).
365
+
366
+ What it is *for* is a cut that is kept between frames. A cut that has descended to a group and then
367
+ sees the camera pull back has to draw the clusters that consumed that group instead, and without
368
+ this it could only find them by descending from the root again — which is the cost keeping a cut is
369
+ meant to remove, paid on the common case.
370
+
371
+ ### 6.4 Parent-page table (`parent_page_count` × 4 B)
372
+
373
+ One `page_index u32` per **distinct other** page holding a parent of one of this page's groups,
374
+ deduplicated and ascending. A parent inside this page spends `SAME_PAGE` in §6.3 instead and has no
375
+ entry here, so a page never appears in its own table.
376
+
377
+ It lives in the decoded page rather than beside the plaintext child table because nothing needs it
378
+ before decode: no fetch range is computed from it, and in the blob it compresses with the other
379
+ tables. Measured: 4.9 entries a page on average, 18 at the worst.
325
380
 
326
381
  ### 6.1 Node table (`node_count` × 32 B)
327
382
 
@@ -734,6 +789,21 @@ clustering and simplification dominate regardless.
734
789
  into more bytes than a page holds has no layout, and the builder refuses it naming the page size
735
790
  that would work, rather than writing a page over the size the header states.
736
791
 
792
+ 15. **Parent-table bounds.** `parent_entry_count ≤ 65,535`, so that a group record's u16
793
+ `parent_first` can index the whole table, and `parent_page_count ≤ parent_entry_count`, since
794
+ no entry can name more than one page. The first is a cap rather than a wider field because the
795
+ distance is not close: the worst page of 8,899 measured carries 26 entries, which leaves the
796
+ bound standing 2,521× above it, and widening `parent_first` would cost the group record its
797
+ 8-byte size. A builder that ever approached the cap would split the page.
798
+
799
+ 16. **The two edges agree.** Every entry of a page's group-parent table (§6.3) resolves to a
800
+ cluster whose `child_group` is the group whose run the entry is in; each group's run holds
801
+ exactly the clusters that name it, with no repeats; and the run is sorted by
802
+ (page index, cluster index). The first is what makes a coarsen legal at all. The third is what
803
+ lets a runtime elect one appender out of a group's several parents by taking the first entry of
804
+ the run, rather than carrying a dedup bitmask sized by instances × groups — so the order is
805
+ load-bearing and not presentation.
806
+
737
807
  ## 12. Open
738
808
 
739
809
  - Page codec ids beyond raw and LZ4 (§5). LZ4 is the default and is where the cheap
@@ -15,12 +15,14 @@ RAM tier's budget, and `runtime/` is everything §7 describes — the selection
15
15
  pass, the VRAM page pool, the feedback loop, and the seam through which VG instances enter the
16
16
  meshlet pipeline ([runtime/RUNTIME_PLAN.md](./runtime/RUNTIME_PLAN.md)).
17
17
 
18
- Two playgrounds prove two different things and it is worth not confusing them.
19
- `shade/playground/vgeo_viewer/` puts a clamped **CPU** cut of a streaming container on screen
20
- through Shade's direct geometry path — it proves the DAG, the format and the clamp, and by
21
- construction it proves nothing about the engine. `shade/playground/vgeo_runtime/` puts an ordinary
22
- `Mesh` in an ordinary `Scene` and draws it entirely from a **GPU** cut through the meshlet
23
- pipeline — it proves the seam and nothing about the DAG. §10 says which milestone that leaves us
18
+ `shade/playground/vgeo_runtime/` puts an ordinary `Mesh` in an ordinary `Scene` and draws it
19
+ entirely from a **GPU** cut through the meshlet pipeline — it proves the engine seam, and
20
+ `shade/playground/vgeo_scene/` opens a whole converted set at once, where the claim about a *scene*
21
+ is measured. What proves the DAG, the format and the clamp is not a page at all: it is
22
+ `runtime/cut/__fixtures__/vgeo_select_cut.js`, a CPU traversal of the same rule that every cut
23
+ spec is held to. A third playground once drew that traversal on screen through Shade's direct
24
+ geometry path, with its own renderer and its own streaming loop; once the GPU page could show
25
+ everything it showed, it was a second runtime for no gain, and it was retired. §10 says which milestone that leaves us
24
26
  in, and the order the work actually arrived in.
25
27
 
26
28
  ## 1. What and why
@@ -245,8 +247,12 @@ Pinned:
245
247
  same answer as by stopping its descent rather than by evaluating it everywhere: draw a
246
248
  cluster iff
247
249
 
248
- `project(parent) > τ AND (project(self) ≤ τ OR child group non-selectable)`
250
+ `own group selectable AND project(parent) > τ AND (project(self) ≤ τ OR child group
251
+ non-selectable)`
249
252
 
253
+ The first term is not decoration: a group that is resident but not yet selectable satisfies
254
+ the rest of the rule while the coarser stand-in still covers the same surface, and both are
255
+ drawn a few microns apart — which reads as corrupt geometry rather than as a missing page.
250
256
  The clamp is what makes "no holes, ever" (§6) true: without it, when the τ-selected
251
257
  level lies below the streaming frontier, *no* resident cluster on that path satisfies
252
258
  the pure rule and the guaranteed stand-in is never selected. The child-group
@@ -265,16 +271,18 @@ Pinned:
265
271
  scale this design targets is millions of clusters every frame, most of them off-screen. A
266
272
  traversal costs the cut. It also gets two things for free that the flat rule pays for
267
273
  separately — a missing page simply stops the descent, which *is* the residency clamp, and
268
- culling at an interior node discards a whole region rather than one cluster. The parallelism
269
- objection is answered by nvpro's persistent-thread and subgroup-ballot scheme (see the
270
- vk_lod_clusters comparison, §2.4); and the hierarchy it descends exists at two granularities. Pages
271
- form a rooted, acyclic, fully-reachable DAG (§11.3–11.4 of the format), measurably
274
+ culling at an interior node discards a whole region rather than one cluster. WebGPU guarantees no
275
+ forward progress across workgroups, so the persistent-thread answer (nvpro, vk_lod_clusters
276
+ comparison §2.4) is unbounded waiting and is not available; a wave redistributes its own
277
+ production among its lanes instead, and the descent's depth runs inside one dispatch. The
278
+ hierarchy it descends exists at two granularities. Pages form a rooted, acyclic,
279
+ fully-reachable DAG (§11.3–11.4 of the format), measurably
272
280
  many-parented on any asset large enough to have more than one page per band, and every
273
281
  child-table entry and page header now carries a **traversal metric** so a page can be tested
274
282
  *before* it is fetched. Below page granularity, each page carries a tree over its own groups
275
283
  (format §6.1–6.2). Cost, measured: 0.3%–1.6% of asset size.
276
284
 
277
- *What exists.* `playground/vgeo_viewer/select_cut.js` is this rule on the CPU, against a
285
+ *What exists.* `runtime/cut/__fixtures__/vgeo_select_cut.js` is this rule on the CPU, against a
278
286
  partially resident container: descend from the root's parentless groups, refine where
279
287
  `project(parent) > τ`, take the cluster where it does not, and stop where the child group is
280
288
  not selectable — recording the want that would unblock it. It is the reference the GPU pass
@@ -493,12 +501,11 @@ because activation is safe at every arrival order). RAM eviction is no longer op
493
501
  material upstream of the builder), so the mesh-keyed material buckets downstream stay
494
502
  unchanged.
495
503
 
496
- What it reads is the **VG selection buffer** — a VG-owned, densely maintained table of
497
- resident clusters (two (sphere, error) pairs, geometry id, own-page and child-page/group
498
- indices, child-group selectable bit — the page indices are what touch and want emission
499
- stamp), plus per-geometry resident-cluster index tables. The existing metadata buffer is
500
- *not* usable for this (freed slices hold garbage, and it carries no error pairs), which is
501
- why the selection buffer exists.
504
+ What it reads is the **page arena** — one fixed-stride slot per resident page, holding that
505
+ page's header, node rows, group rows and cluster rows — and the per-geometry lookup that
506
+ resolves a child page index to a slot (RUNTIME_PLAN §3.1). There is no selection buffer and
507
+ no page table: a page's header is the first words of its own slot, and the two (sphere,
508
+ error) pairs are in its cluster rows.
502
509
 
503
510
  Superseded: this step previously specified a **flat** evaluation of the rule over every
504
511
  row of that buffer, at a cost of `O(Σ over visible instances of resident(geometry))`. §4
@@ -513,10 +520,16 @@ because activation is safe at every arrival order). RAM eviction is no longer op
513
520
  instances enter through their own expansion step. M0 was where that seam was to be fixed
514
521
  and it was not (§10); it is the first thing M1 has to do.
515
522
 
516
- Open: shadow views (v1 takes the one cut per view of §4, sharing setup rather than results,
517
- and a proxy where a view does not justify a cut); DRS τ semantics; the traversal's GPU shape —
518
- persistent threads over a queue, per nvpro, against what WebGPU without 64-bit atomics actually
519
- makes affordable.
523
+ The traversal's GPU shape is settled and built: one indirect dispatch per spill generation, the
524
+ descent's depth inside the kernel, work redistributed across a subgroup's lanes by prefix sum. A
525
+ step costs about 0.5 µs whatever the wave holds, so a light asset pays for the shape of its descent
526
+ rather than for its geometry, while a container with real work in the frontier pays mostly for the
527
+ work. How many dispatches a cut needs is a queue-drain quantity rather than depth divided by the
528
+ step count: a wave keeps `subgroup_size` children and spills the rest to the next dispatch.
529
+ CUT_PLAN_2026_09_14 proposes to stop re-walking from the root by keeping the cut between frames.
530
+
531
+ Open: shadow views (v1 takes the one cut per view of §4, sharing setup rather than results, and a
532
+ proxy where a view does not justify a cut); DRS τ semantics.
520
533
 
521
534
  Settled since: **flat evaluation versus a hierarchy is no longer a measurement to take.** §4
522
535
  pins the traversal, and the hierarchy it descends is already written into every built asset
@@ -618,7 +631,7 @@ is the piece still missing, and M1 is where the work now starts.
618
631
  Acceptance: crack-free under τ sweep and flythrough (incl. group-boundary polyline and
619
632
  flip validation); drawn-triangle count tracks resolution, not source size; §3 build
620
633
  validations green.
621
- **Done**: the builder; a CPU cut (`playground/vgeo_viewer/select_cut.js`) that is a traversal
634
+ **Done**: the builder; a CPU cut (`runtime/cut/__fixtures__/vgeo_select_cut.js`) that is a traversal
622
635
  rather than the flat pass planned here, and that runs against a partially resident container,
623
636
  which was M2's job; τ-sweep watertightness as a spec (`build/vgeo_cut.spec.js` counts edges
624
637
  used by one triangle instead of two, at a spread of thresholds, and wants zero); the