@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,6 +1,5 @@
1
1
  import { Color } from "../../../core/color/Color.js";
2
2
  import Vector3 from "../../../core/geom/Vector3.js";
3
- import { DEG_TO_RAD } from "../../../core/math/DEG_TO_RAD.js";
4
3
  import { EntityComponentDataset } from "../../../engine/ecs/EntityComponentDataset.js";
5
4
  import { Transform64 } from "../../../engine/ecs/transform/Transform64.js";
6
5
  import { OrbitalCameraController } from "../../renderer/camera/OrbitalCameraController.js";
@@ -8,32 +7,36 @@ import { PerspectiveCamera } from "../../renderer/camera/PerspectiveCamera.js";
8
7
  import { FramePhase } from "../../renderer/extension/FramePhase.js";
9
8
  import { RenderExtension } from "../../renderer/extension/RenderExtension.js";
10
9
  import { VGEO_CUT_STAT } from "../../renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js";
11
- import { VGeoFeedbackLoop } from "../../renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js";
12
10
  import { VirtualGeometry } from "../../renderer/geometry/virtual/runtime/VirtualGeometry.js";
11
+ import {
12
+ VGeoByteSource
13
+ } from "../../renderer/geometry/virtual/format/read/VGeoByteSource.js";
13
14
  import {
14
15
  VGeoContainerReader
15
16
  } from "../../renderer/geometry/virtual/format/read/VGeoContainerReader.js";
17
+ import {
18
+ vgeo_fetch_byte_source
19
+ } from "../../renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js";
16
20
  import {
17
21
  VGeoReadOptions
18
22
  } from "../../renderer/geometry/virtual/format/read/VGeoReadOptions.js";
19
- import {
20
- VGeoResidencyManager
21
- } from "../../renderer/geometry/virtual/residency/VGeoResidencyManager.js";
22
23
  import { make_sunlight } from "../../renderer/light/make_sunlight.js";
23
24
  import { place_light } from "../../renderer/light/place_light.js";
24
25
  import { StandardShadeMaterial } from "../../renderer/material/StandardShadeMaterial.js";
25
26
  import { Renderer } from "../../renderer/Renderer.js";
26
27
  import { place_primitive } from "../../renderer/scene/rows/place_primitive.js";
27
28
  import { Scene } from "../../renderer/scene/Scene.js";
28
- import { vgeo_sample_source } from "../vgeo_viewer/sample_asset.js";
29
+ import { load_default_environment } from "../load_default_environment.js";
30
+ import { install_profile_hotkey } from "../profile_hotkey.js";
31
+ import { vgeo_sample_source } from "./sample_asset.js";
29
32
 
30
33
  /**
31
34
  * A `.vgeo` container drawn **through the meshlet pipeline**, by a cut selected on the GPU.
32
35
  *
33
- * This is the other half of what `playground/vgeo_viewer/` proves, and the two are worth keeping
34
- * apart. The viewer draws a CPU cut through Shade's direct geometry path: it proves the DAG, the
35
- * format and the clamp, and by construction it proves nothing about the engine. This page draws
36
- * nothing itself. It puts an ordinary mesh row in an ordinary `Scene` with an ordinary material,
36
+ * What proves the DAG, the format and the clamp is not a page:
37
+ * `renderer/geometry/virtual/runtime/cut/__fixtures__/vgeo_select_cut.js` is a CPU traversal of the
38
+ * same rule, and every cut spec is held to it. This page proves the other half — the engine seam —
39
+ * and it draws nothing itself. It puts an ordinary mesh row in an ordinary `Scene` with an ordinary material,
37
40
  * and every triangle on screen arrives because the compute cut appended `MESHLET_DEFINITION_STRUCT`
38
41
  * records into the same collection a static mesh's meshlets go into — through the HZB meshlet
39
42
  * filter, the material bucket, the indirect draw and the G-buffer, none of which know that virtual
@@ -48,6 +51,12 @@ import { vgeo_sample_source } from "../vgeo_viewer/sample_asset.js";
48
51
  * are what fetch the rest.
49
52
  * - **nothing is drawn twice.** `drawn` against the triangle count the rasterizer reports.
50
53
  *
54
+ * The container is built in the page so there is something to look at on load, but the page is not
55
+ * about that container: **drop a `.vgeo` file on it**, or open it at `?file=`, and the asset is
56
+ * swapped for a real one. That is the reading worth having, because a sample built here is a torus
57
+ * of thirteen pages and an asset off a converter is thousands — and the claim being made is about
58
+ * the second.
59
+ *
51
60
  * `__state()` is what a headless session asserts on; everything the panel shows comes from it.
52
61
  *
53
62
  * @author Alex Goldring
@@ -56,6 +65,39 @@ import { vgeo_sample_source } from "../vgeo_viewer/sample_asset.js";
56
65
 
57
66
  const element = id => document.getElementById(id);
58
67
 
68
+ /**
69
+ * The page size every container shown here is expected to have been built at.
70
+ *
71
+ * One number for the asset and for the tier that holds it, and it is fixed for the life of the
72
+ * page: a page size is a bound the container states (FORMAT §11.14), the pool lays its arena out in
73
+ * slots of exactly that stride, and there is no slot-size class table. So a dropped container built
74
+ * at a different size is refused at `register` — loudly, by an error naming both numbers — rather
75
+ * than reconciled. The sample is built at this size for the same reason.
76
+ *
77
+ * @type {number}
78
+ */
79
+ const PAGE_SIZE = 64 * 1024;
80
+
81
+ /**
82
+ * Page slots the VRAM tier is built with, over the engine's default of 1,024.
83
+ *
84
+ * The default is sized for a scene, and this page is a single-asset viewer for containers off a
85
+ * converter — where a ninth of a measured 2,975-asset set has more than a thousand pages, and the
86
+ * largest has seventeen thousand. At 1,024 slots the tier fills, `install` starts refusing, and the
87
+ * cut clamps against a *budget* rather than against τ: the surface stays watertight and goes coarse,
88
+ * `clamped` stops falling to zero, and the one claim this page exists to show — that the cut is a
89
+ * function of the threshold and the resolution, not of the source — is no longer what you are
90
+ * looking at.
91
+ *
92
+ * It is cheap in the place it sounds expensive. A slot holds a page's *runtime rows* rather than its
93
+ * payload — an eighth of the page size, see `vgeo_runtime_page_slot_words` — so this is a 32 MB
94
+ * arena, and the payload goes where a static mesh's meshlets go. What it does spend is the decoded
95
+ * budget the pool derives from it, which is 256 MB.
96
+ *
97
+ * @type {number}
98
+ */
99
+ const PAGE_CAPACITY = 4096;
100
+
59
101
  /**
60
102
  * Opens the VG frame before anything records a rasterization pass, because the seam inside those
61
103
  * passes writes into the feedback buffer this creates.
@@ -103,10 +145,70 @@ class VGeoFrameEnd extends RenderExtension {
103
145
 
104
146
  class VGeoPlayground {
105
147
  /**
106
- * @type {VGeoContainerReader}
148
+ * @type {Renderer}
149
+ */
150
+ renderer;
151
+
152
+ /**
153
+ * Held for a session driving the page rather than for anything here: `fit` measures the
154
+ * document, and the renderer is what writes this element's two sizes.
155
+ * @type {HTMLCanvasElement}
156
+ */
157
+ canvas;
158
+
159
+ /**
160
+ * @type {Scene}
161
+ */
162
+ scene;
163
+
164
+ /**
165
+ * @type {GPUSceneContext}
166
+ */
167
+ scene_context;
168
+
169
+ /**
170
+ * @type {PerspectiveCamera}
171
+ */
172
+ camera;
173
+
174
+ /**
175
+ * @type {OrbitalCameraController}
176
+ */
177
+ controller;
178
+
179
+ /**
180
+ * The one material every asset is drawn with — a `Front`-sided standard material, which is what
181
+ * makes this page able to report a container whose triangles face the wrong way. The viewer
182
+ * beside it draws with `cullMode: 'none'` and cannot.
183
+ *
184
+ * @type {StandardShadeMaterial}
185
+ */
186
+ material;
187
+
188
+ /**
189
+ * The open container, or `undefined` before the first one arrives.
190
+ * @type {VGeoContainerReader|undefined}
107
191
  */
108
192
  reader;
109
193
 
194
+ /**
195
+ * @type {VGeoByteSource|undefined}
196
+ */
197
+ source;
198
+
199
+ /**
200
+ * What the scene draws the container as, held so that {@link retire} can give its record back
201
+ * to the geometry manager — nothing else names it once `place_primitive` has returned.
202
+ * @type {VirtualGeometry|undefined}
203
+ */
204
+ geometry;
205
+
206
+ /**
207
+ * The entity the container is drawn at, or `-1` when nothing is placed.
208
+ * @type {number}
209
+ */
210
+ entity = -1;
211
+
110
212
  /**
111
213
  * @type {GPUVirtualGeometryRuntime}
112
214
  */
@@ -118,7 +220,7 @@ class VGeoPlayground {
118
220
  feedback;
119
221
 
120
222
  /**
121
- * @type {VGeoResidencyManager}
223
+ * @type {VGeoResidency}
122
224
  */
123
225
  residency;
124
226
 
@@ -127,32 +229,110 @@ class VGeoPlayground {
127
229
  */
128
230
  frames = 0;
129
231
 
232
+ /**
233
+ * Height of the render target in pixels, which is what τ is measured against — so it follows
234
+ * the window, and moving the page to a display of a different density changes it.
235
+ * @type {number}
236
+ */
237
+ screen_height = 1;
238
+
130
239
  /**
131
240
  * @type {number}
132
241
  */
133
- canvas_height = 600;
242
+ screen_width = 1;
134
243
 
135
244
  /**
136
245
  * @type {number}
137
246
  */
138
- fov_y = 50 * DEG_TO_RAD;
247
+ fov_y = 1;
248
+
249
+ /**
250
+ * One open at a time. Opening is asynchronous and the frame loop keeps running underneath it,
251
+ * so two drops in flight would race on the swap below.
252
+ * @type {boolean}
253
+ */
254
+ loading = false;
255
+
256
+ /**
257
+ * @type {string}
258
+ */
259
+ status_text = '';
260
+
261
+ /**
262
+ * @param {string} text
263
+ * @param {boolean} [error]
264
+ */
265
+ status(text, error = false) {
266
+ this.status_text = text;
267
+
268
+ const node = element('status');
269
+
270
+ node.textContent = text;
271
+ node.classList.toggle('error', error);
272
+ }
273
+
274
+ /**
275
+ * Bring the canvas, the renderer, the camera and the cut's own notion of the screen up to the
276
+ * size the window actually is.
277
+ *
278
+ * **Measured from the document, never from the canvas.** `Renderer` takes CSS pixels here and
279
+ * writes back both of the canvas's sizes when it configures the context — the backing store in
280
+ * device pixels, and an *inline* `style.width`/`style.height` in CSS pixels. An inline style
281
+ * wins over a stylesheet, so a canvas laid out at `width: 100%` stops following the window the
282
+ * moment the first frame is drawn, and a `fit` that then read `clientWidth` back would be
283
+ * reading the renderer its own last answer: the canvas would never change size again, which is
284
+ * exactly how this page shipped with a fixed viewport.
285
+ *
286
+ * Three things downstream have to follow, and all three are why a fixed-size canvas was wrong
287
+ * rather than merely small:
288
+ *
289
+ * - the camera's **aspect**, which comes off the renderer rather than the window, because the
290
+ * internal resolution is what the projection has to match;
291
+ * - the cut's **screen height**, because `err_px = r_e * screen_height / (2 tan(fov/2) d)` is a
292
+ * count of *render-target* pixels, and a τ of one pixel against a screen height the window
293
+ * has outgrown selects a cut for a screen nobody is looking at;
294
+ * - the cut's **fov**, for the same reason, so that changing the camera's is enough.
295
+ */
296
+ fit() {
297
+ const renderer = this.renderer;
298
+
299
+ const viewport = document.documentElement;
300
+
301
+ const width = Math.max(1, Math.floor(viewport.clientWidth));
302
+ const height = Math.max(1, Math.floor(viewport.clientHeight));
303
+
304
+ // a window dragged onto a display of another density changes this and nothing else
305
+ renderer.pixel_ratio = globalThis.devicePixelRatio || 1;
306
+
307
+ renderer.resize(width, height);
308
+
309
+ this.camera.aspect = renderer.aspect_ratio;
310
+
311
+ /*
312
+ The internal resolution rather than the output one: the rasterizer draws at
313
+ `output × internal_resolution_scale` and upscales, and the cut is selected for what is
314
+ rasterized. At the scale of 1 this page runs at, the two are the same number.
315
+ */
316
+ const resolution = renderer.output_resolution;
317
+ const scale = renderer.internal_resolution_scale;
318
+
319
+ this.screen_width = Math.max(1, Math.floor(resolution.x * scale));
320
+ this.screen_height = Math.max(1, Math.floor(resolution.y * scale));
321
+
322
+ this.fov_y = this.camera.fov;
323
+ }
139
324
 
140
325
  /**
141
326
  * @param {FrameContext} frame
142
327
  */
143
328
  begin(frame) {
144
- this.runtime.begin_frame(frame.graph, {
145
- screen_height: this.canvas_height,
146
- fov_y: this.fov_y,
147
- });
329
+ this.runtime.begin_frame({ graph: frame.graph });
148
330
  }
149
331
 
150
332
  /**
151
333
  * @param {FrameContext} frame
152
334
  */
153
335
  finish(frame) {
154
- // the RAM tier's clock moves inside this: a host that drives the loop gets a bounded
155
- // second tier without having to know it had one to wind
156
336
  this.feedback.read(frame.graph);
157
337
 
158
338
  this.runtime.end_frame();
@@ -160,6 +340,226 @@ class VGeoPlayground {
160
340
  this.frames++;
161
341
  }
162
342
 
343
+ /**
344
+ * Open a container over a byte source and put it on screen in place of whatever is there.
345
+ *
346
+ * A refusal leaves the page exactly as it was, which is the reason the new container is
347
+ * registered *before* the old one is taken down: the two ways this fails — a container built at
348
+ * another page size, and a tier with no room for another root — both fail inside `register`,
349
+ * and a page that had already dropped its asset to find that out would answer a bad file with
350
+ * an empty screen and an error, rather than with the error alone.
351
+ *
352
+ * @param {VGeoByteSource} source
353
+ * @returns {Promise<boolean>} whether the asset on screen changed
354
+ */
355
+ async load(source) {
356
+ if (this.loading) {
357
+ this.status(`a container is still opening — ${source.name} was ignored`, true);
358
+
359
+ return false;
360
+ }
361
+
362
+ this.loading = true;
363
+
364
+ this.status(`opening ${source.name}…`);
365
+
366
+ try {
367
+ /*
368
+ Frame verification on, because this reader is a runtime's rather than a tool's —
369
+ format §10 leaves it off by default precisely because a tool reading a file it just
370
+ built is not defending against a network, and a runtime is. A dropped file is the case
371
+ that was always meant: bytes this page did not produce.
372
+ */
373
+ const options = new VGeoReadOptions();
374
+
375
+ options.verify_frames = true;
376
+
377
+ // the runtime answers activation in the arena; the reader's own counters would be
378
+ // tens of megabytes at fifty thousand pages, read by nothing
379
+ options.track_selectability = false;
380
+
381
+ source.reset_counters();
382
+
383
+ const started = performance.now();
384
+
385
+ const reader = await VGeoContainerReader.open(source, options);
386
+
387
+ const open_ms = performance.now() - started;
388
+
389
+ this.adopt(reader, source);
390
+
391
+ this.status(
392
+ `${source.name} — ${reader.header.total_pages} pages,`
393
+ + ` opened in ${open_ms.toFixed(0)} ms`
394
+ );
395
+
396
+ return true;
397
+ } catch (error) {
398
+ this.status(error.message ?? String(error), true);
399
+
400
+ console.error(error);
401
+
402
+ return false;
403
+ } finally {
404
+ this.loading = false;
405
+ }
406
+ }
407
+
408
+ /**
409
+ * The same door the drop target opens, for a session that has no pointer to drop with — and for
410
+ * a link to an asset. A `.vgeo` is read by ranges, so this is one `HEAD` and one request per
411
+ * page the cut asks for, against a server that honours `Range`.
412
+ *
413
+ * @param {string} url
414
+ * @returns {Promise<boolean>} whether the asset on screen changed
415
+ */
416
+ async load_url(url) {
417
+ this.status(`probing ${url}…`);
418
+
419
+ let source;
420
+
421
+ try {
422
+ source = await vgeo_fetch_byte_source(url);
423
+ } catch (error) {
424
+ this.status(`${url} — ${error.message ?? error}`, true);
425
+
426
+ return false;
427
+ }
428
+
429
+ return this.load(source);
430
+ }
431
+
432
+ /**
433
+ * Register an open container with both tiers, retire the one it replaces, and place it.
434
+ *
435
+ * @param {VGeoContainerReader} reader
436
+ * @param {VGeoByteSource} source
437
+ */
438
+ adopt(reader, source) {
439
+ /*
440
+ Only the root page is resident. Everything else arrives because the cut asked for it,
441
+ which is the loop this page exists to show — and it means the first frames draw a
442
+ coarse, watertight surface rather than nothing at all. A refusal throws here and
443
+ leaves nothing registered.
444
+ */
445
+ const geometry_row = this.residency.register(reader);
446
+
447
+ this.retire();
448
+
449
+ this.reader = reader;
450
+ this.source = source;
451
+ this.geometry = new VirtualGeometry(reader);
452
+
453
+ this.geometry.vg_row = geometry_row;
454
+
455
+ this.entity = place_primitive(
456
+ this.scene_context, this.geometry, this.material, new Transform64(),
457
+ { name: source.name }
458
+ );
459
+
460
+ this.frame_camera(reader.header.object_sphere);
461
+
462
+ /*
463
+ The scene it is drawing has just been replaced wholesale, which is what this exists to be
464
+ told. TAA reprojects through motion vectors, and the pixels the new container covers have
465
+ no correspondence in a history written from the old one — so without this the first frames
466
+ after a drop blend one asset's colour into the other's silhouette.
467
+ */
468
+ this.renderer.indicate_view_change();
469
+ }
470
+
471
+ /**
472
+ * Give back everything the container on screen holds: its mesh row, its entity, its geometry
473
+ * record, its VRAM pages and the decoded bytes it was holding in RAM.
474
+ *
475
+ * **Detaching the mesh row is only the first of them.** `detach_mesh` gives back the `meshes`
476
+ * row and releases the material, and it does *not* give the geometry back to
477
+ * `GPUGeometryManager` — `#write_mesh` calls `add` and `#free_mesh` has no matching `remove`.
478
+ * So without the line below, every container ever dropped stayed named by the manager, and the
479
+ * record it was named by holds the `VirtualGeometry`, which holds the **reader**, which holds
480
+ * every page that reader had decoded. The RAM tier's bytes were not merely uncollected, they
481
+ * were unreachable. Five drops, measured: with `remove`, the manager names none of the five
482
+ * retired geometries and each retired reader is down to its one pinned root page; without it,
483
+ * all five and everything they had streamed.
484
+ *
485
+ * `evict_all` is then about *when* rather than whether — it releases the decoded pages at the
486
+ * swap instead of at whatever garbage collection comes next, which is worth having when the
487
+ * container leaving held a hundred megabytes and the one arriving is about to ask for its own.
488
+ * `VGeoResidencyManager.unregister` says in as many words that this is the caller's business:
489
+ * it stops counting a reader against the budget and drops nothing.
490
+ *
491
+ * What this does *not* give back is the geometry **id**. `__last_geometry_index` only ever
492
+ * counts up — `remove` frees the record, the BLAS slot and the meshlet batch, but not the
493
+ * index — so the metadata table and the BLAS address lookup are still one row longer per drop.
494
+ * Measured at 64 bytes a drop, which is a residual rather than a leak worth a playground
495
+ * reaching into the geometry manager over.
496
+ *
497
+ * `abort()` first, and that is not tidiness either. The wants in flight name page indices *of
498
+ * the container being retired*, and a fetch that lands after its reader is gone resolves a byte
499
+ * range out of a child table nothing owns any more.
500
+ */
501
+ retire() {
502
+ if (this.entity !== -1) {
503
+ this.scene_context.rows.detach_mesh(this.entity);
504
+ this.scene.dataset.removeEntity(this.entity);
505
+
506
+ this.entity = -1;
507
+ }
508
+
509
+ if (this.geometry !== undefined) {
510
+ this.scene_context.geometries.remove(this.geometry);
511
+
512
+ this.geometry = undefined;
513
+ }
514
+
515
+ const reader = this.reader;
516
+
517
+ if (reader === undefined) {
518
+ return;
519
+ }
520
+
521
+ // gives back its rows, its lookup, its RAM slots, and cancels what it had on the wire
522
+ this.residency.unregister(reader);
523
+
524
+ reader.evict_all();
525
+
526
+ this.reader = undefined;
527
+ this.source = undefined;
528
+ }
529
+
530
+ /**
531
+ * Stand the camera off the container's own bounding sphere.
532
+ *
533
+ * A sample torus is a unit across and sits at the origin; a converted asset can be a centimetre
534
+ * or a hundred metres, and can stand a long way from it. Everything that has a length in it —
535
+ * the near plane, the orbit limits, the speed the controller moves at — is taken from the
536
+ * radius for the same reason: a near plane of 2 cm is right for the torus and puts a whole
537
+ * building inside itself.
538
+ *
539
+ * @param {Float32Array} sphere centre xyz then radius, object space — and object space is world
540
+ * space here, because the primitive is placed at the identity
541
+ */
542
+ frame_camera(sphere) {
543
+ const radius = sphere[3] > 0 ? sphere[3] : 1;
544
+
545
+ const center = new Vector3(sphere[0], sphere[1], sphere[2]);
546
+
547
+ const eye = new Vector3(0.35, 0.45, 1);
548
+
549
+ eye.normalize();
550
+ eye.multiplyScalar(radius * 2.8);
551
+ eye.add(center);
552
+
553
+ this.camera.near = radius * 0.005;
554
+ this.camera.far = radius * 200;
555
+
556
+ this.controller.distanceLimits.min = radius * 0.02;
557
+ this.controller.distanceLimits.max = radius * 200;
558
+ this.controller.movement_speed_scale = radius;
559
+
560
+ this.controller.look(eye, center);
561
+ }
562
+
163
563
  /**
164
564
  * Everything a headless session needs, and everything the panel shows.
165
565
  *
@@ -168,12 +568,25 @@ class VGeoPlayground {
168
568
  state() {
169
569
  const stats = this.feedback.stats;
170
570
  const pool = this.runtime.pool;
571
+ const reader = this.reader;
171
572
 
172
573
  return {
173
574
  frames: this.frames,
174
575
  tau: this.runtime.tau,
576
+ status: this.status_text,
577
+ screen_width: this.screen_width,
578
+ screen_height: this.screen_height,
175
579
  feedback_reads: this.feedback.read_count,
176
580
  feedback_skipped: this.feedback.skipped_frames,
581
+ asset: {
582
+ name: this.source?.name ?? '',
583
+ bytes: this.source?.byte_length ?? 0,
584
+ // this thread's reads and the workers', which the source never sees
585
+ bytes_read: (this.source?.bytes_read ?? 0) + this.residency.fetcher.worker_bytes_read,
586
+ faces: reader === undefined ? 0 : Number(reader.header.source_face_count),
587
+ radius: reader?.header.object_sphere[3] ?? 0,
588
+ page_size: reader?.header.nominal_page_size ?? 0,
589
+ },
177
590
  cut: {
178
591
  drawn: stats[VGEO_CUT_STAT.DRAWN],
179
592
  clamped: stats[VGEO_CUT_STAT.CLAMPED],
@@ -182,6 +595,7 @@ class VGeoPlayground {
182
595
  items: stats[VGEO_CUT_STAT.ITEMS],
183
596
  clusters_tested: stats[VGEO_CUT_STAT.CLUSTERS_TESTED],
184
597
  culled_frustum: stats[VGEO_CUT_STAT.CULLED_FRUSTUM],
598
+ culled_cluster: stats[VGEO_CUT_STAT.CULLED_CLUSTER],
185
599
  culled_lod: stats[VGEO_CUT_STAT.CULLED_LOD],
186
600
  meshlets_dropped: stats[VGEO_CUT_STAT.MESHLETS_DROPPED],
187
601
  wants_dropped: stats[VGEO_CUT_STAT.WANTS_DROPPED],
@@ -195,103 +609,177 @@ class VGeoPlayground {
195
609
  vram: {
196
610
  pages: pool.resident_page_count,
197
611
  bytes: pool.resident_bytes,
198
- evicted: pool.evicted_page_count,
199
- refused: pool.refused_install_count,
612
+ evicted: this.residency.evicted_vram_count,
613
+ refused: this.residency.refused_install_count,
200
614
  },
201
615
  ram: {
202
- pages: this.reader.resident_page_count,
203
- bytes: this.reader.resident_bytes,
204
- total_pages: this.reader.header.total_pages,
616
+ pages: this.residency.ram_page_count,
617
+ bytes: this.residency.ram_resident_bytes,
618
+ evicted: this.residency.evicted_ram_count,
619
+ refused: this.residency.refused_fetch_count,
620
+ quarantined: this.residency.quarantined_page_count,
621
+ total_pages: reader?.header.total_pages ?? 0,
205
622
  },
623
+ fetches_in_flight: this.residency.fetches_in_flight,
624
+ worker_fetches: this.residency.fetcher.worker_fetch_count,
625
+ in_process_fetches: this.residency.fetcher.in_process_fetch_count,
626
+ deferred: this.residency.deferred_want_count,
206
627
  };
207
628
  }
208
629
  }
209
630
 
210
- async function start() {
211
- const canvas = element('view');
631
+ /**
632
+ * @param {number} bytes
633
+ * @returns {string}
634
+ */
635
+ function human_bytes(bytes) {
636
+ if (bytes < 1024) {
637
+ return `${bytes} B`;
638
+ }
639
+
640
+ if (bytes < 1024 * 1024) {
641
+ return `${(bytes / 1024).toFixed(0)} KB`;
642
+ }
643
+
644
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
645
+ }
646
+
647
+ /**
648
+ * Take a file the moment it is dropped anywhere on the page.
649
+ *
650
+ * Counted rather than latched, because `dragleave` fires for every element the pointer crosses on
651
+ * its way in — the overlay's own, the panel's — and a boolean flag put the hint away while the file
652
+ * was still over the window.
653
+ *
654
+ * @param {VGeoPlayground} page
655
+ */
656
+ function wire_drop_target(page) {
657
+ const overlay = element('drop');
212
658
 
213
- const status = text => {
214
- element('status').textContent = text;
659
+ let depth = 0;
660
+
661
+ const hide = () => {
662
+ depth = 0;
663
+
664
+ overlay.classList.remove('active');
215
665
  };
216
666
 
217
- const renderer = new Renderer();
667
+ globalThis.addEventListener('dragenter', event => {
668
+ event.preventDefault();
218
669
 
219
- await renderer.initialize({ context: canvas.getContext('webgpu'), pixelRatio: 1 });
670
+ depth++;
220
671
 
221
- renderer.feature_taa_enabled = false;
222
- renderer.feature_ssao_enabled = false;
223
- renderer.feature_bloom_enabled = false;
672
+ overlay.classList.add('active');
673
+ });
224
674
 
225
- renderer.resize(canvas.width, canvas.height);
675
+ globalThis.addEventListener('dragover', event => event.preventDefault());
226
676
 
227
- status('building a container in the page…');
677
+ globalThis.addEventListener('dragleave', () => {
678
+ depth = Math.max(0, depth - 1);
228
679
 
229
- /*
230
- One number for the asset and for the tier that holds it. A page size is a bound the container
231
- states (FORMAT §11.14) and the pool holds pages at exactly one, so a mismatch here is a refusal
232
- at `register` rather than something that limps.
233
- */
234
- const page_size = 64 * 1024;
680
+ if (depth === 0) {
681
+ overlay.classList.remove('active');
682
+ }
683
+ });
235
684
 
236
- const { source, build_ms } = vgeo_sample_source(128, 48, page_size);
685
+ globalThis.addEventListener('drop', async event => {
686
+ event.preventDefault();
237
687
 
238
- /*
239
- Frame verification on, because this reader is a runtime's rather than a tool's — format §10
240
- leaves it off by default precisely because a tool reading a file it just built is not
241
- defending against a network, and a runtime is.
242
- */
243
- const options = new VGeoReadOptions();
688
+ hide();
689
+
690
+ const file = event.dataTransfer?.files[0];
244
691
 
245
- options.verify_frames = true;
692
+ if (file === undefined) {
693
+ return;
694
+ }
246
695
 
247
- const reader = await VGeoContainerReader.open(source, options);
696
+ await page.load(VGeoByteSource.from_blob(file));
697
+
698
+ // the controller's keyboard device listens on the body, and a drop leaves focus elsewhere
699
+ document.body.focus();
700
+ });
701
+ }
702
+
703
+ async function start() {
704
+ const canvas = element('view');
248
705
 
249
706
  const page = new VGeoPlayground();
250
707
 
251
- page.reader = reader;
252
- page.canvas_height = canvas.height;
708
+ page.canvas = canvas;
709
+
710
+ const renderer = new Renderer();
711
+
712
+ page.renderer = renderer;
713
+
714
+ await renderer.initialize({
715
+ context: canvas.getContext('webgpu'),
716
+ pixelRatio: globalThis.devicePixelRatio || 1,
717
+ });
253
718
 
254
- page.residency = new VGeoResidencyManager();
255
- page.residency.register(reader);
719
+ /*
720
+ TAA on, which for a page about a *cut* is not a cosmetic choice. A cut is selected per frame
721
+ against a threshold in pixels, so the clusters it draws change under the camera and the seams
722
+ between two levels of detail land on different pixels from one frame to the next. Without a
723
+ temporal filter every one of those is an aliased edge that crawls, and the crawl reads as the
724
+ cut being unstable when it is the rasterizer being point-sampled. It also costs the readings
725
+ nothing: TAA is downstream of the G-buffer, and the cut has already been selected and drawn
726
+ by the time it runs.
727
+
728
+ SSAO and bloom stay off. They are off because this page is a measurement harness and they are
729
+ two more passes between a change and its effect, not because they would break anything.
730
+ */
731
+ renderer.feature_taa_enabled = true;
732
+ renderer.feature_ssao_enabled = false;
733
+ renderer.feature_bloom_enabled = false;
256
734
 
257
735
  const scene = new Scene();
258
736
 
259
- // the sun stands at an entity, and so does the torus, so the scene names a dataset
737
+ // the sun stands at an entity, and so does the asset, so the scene names a dataset
260
738
  scene.dataset = new EntityComponentDataset();
261
739
 
740
+ page.scene = scene;
741
+
262
742
  // a light stands at an entity of the dataset now, like everything else the scene holds
263
743
  place_light(scene, make_sunlight());
264
744
 
745
+ /*
746
+ Image-based lighting, and the reason is the geometry rather than the picture. A sun alone puts
747
+ every surface facing away from it at ambient zero, and the whole point of a cut is what happens
748
+ at the silhouette and in the creases — the places a single directional light renders as flat
749
+ black. A converted asset arrives with normals and no material authoring, so the environment is
750
+ most of what there is to shade it with.
751
+
752
+ Not awaited, and the page does not depend on it: `test_assets/` is gitignored, so a fresh
753
+ checkout has no sky and gets the sun alone, which still draws every triangle the cut selected.
754
+ The environment lands a frame or two later when it is there.
755
+ */
756
+ load_default_environment(scene);
757
+
265
758
  const camera = new PerspectiveCamera();
266
759
 
267
- camera.near = 0.02;
268
- camera.far = 200;
269
- camera.fov = page.fov_y;
270
- camera.aspect = canvas.width / canvas.height;
760
+ camera.fov_degrees = 50;
271
761
 
272
- const controller = new OrbitalCameraController(camera, document.body);
762
+ page.camera = camera;
763
+ page.controller = new OrbitalCameraController(camera, document.body);
273
764
 
274
- controller.look(new Vector3(0, 1.6, 3.6), new Vector3(0, 0, 0));
765
+ page.fit();
766
+
767
+ globalThis.addEventListener('resize', () => page.fit());
275
768
 
276
769
  // one frame to let the renderer build its scene context, which is what owns the geometry manager
277
770
  renderer.render(camera, scene, 1 / 60);
278
771
 
279
772
  const scene_context = renderer.scenes.obtain(scene);
280
773
 
281
- const runtime = scene_context.enable_virtual_geometry({ page_size });
282
-
283
- page.runtime = runtime;
284
-
285
- /*
286
- Only the root page is resident. Everything else arrives because the cut asked for it, which is
287
- the loop this page exists to show — and it means the first frames draw a coarse, watertight
288
- surface rather than nothing at all.
289
- */
290
- const geometry_row = runtime.pool.register(reader);
291
-
292
- const geometry = new VirtualGeometry(reader);
774
+ page.scene_context = scene_context;
775
+ page.runtime = scene_context.enable_virtual_geometry({
776
+ page_size: PAGE_SIZE,
777
+ table_options: { page_capacity: PAGE_CAPACITY },
778
+ });
293
779
 
294
- geometry.vg_row = geometry_row;
780
+ // the scene context built both tiers and the loop with the runtime; this page only reads them
781
+ page.residency = scene_context.virtual_geometry_residency;
782
+ page.feedback = scene_context.virtual_geometry_feedback;
295
783
 
296
784
  const material = new StandardShadeMaterial();
297
785
 
@@ -299,11 +787,7 @@ async function start() {
299
787
  material.roughness_factor = 0.55;
300
788
  material.metallic_factor = 0;
301
789
 
302
- place_primitive(
303
- scene_context, geometry, material, new Transform64(), { name: 'virtual torus' }
304
- );
305
-
306
- page.feedback = new VGeoFeedbackLoop({ runtime, residency: page.residency });
790
+ page.material = material;
307
791
 
308
792
  /*
309
793
  The loop's only teardown caller anywhere, and worth having for the same reason M12's clock was:
@@ -318,15 +802,71 @@ async function start() {
318
802
  renderer.add_extension(new VGeoFrameEnd(page));
319
803
 
320
804
  element('tau').addEventListener('input', event => {
321
- runtime.tau = Number(event.target.value);
805
+ page.runtime.tau = Number(event.target.value);
322
806
 
323
- element('tau-value').textContent = runtime.tau.toFixed(2);
807
+ element('tau-value').textContent = page.runtime.tau.toFixed(2);
808
+ });
809
+
810
+ // a drag on the τ slider is a drag on the body, and the camera controller listens there
811
+ element('panel').addEventListener('pointerdown', event => event.stopPropagation());
812
+
813
+ wire_drop_target(page);
814
+
815
+ /*
816
+ T records a GPU capture, T again saves it — the same key the other playgrounds bind, out of the
817
+ same module (`playground/profile_hotkey.js`), so there is one implementation of the drain and
818
+ the `.sgpt` naming rather than one per page.
819
+
820
+ What it is for here is the question this page cannot otherwise answer. Every reading in the
821
+ panel is a *count* — clusters drawn, pages visited, wavefronts run — and none of them is a
822
+ cost. The cut is four compute passes ahead of a G-buffer that does not know virtual geometry
823
+ exists, so what is worth knowing is how the seed, the traverse loop, the collect and the
824
+ expansion compare against the rasterization they feed, and whether the descent's wavefront
825
+ count shows up as time or disappears into occupancy. That is a capture, not a counter.
826
+
827
+ The settings line is what makes one readable. A pass at 0.4 ms says nothing without τ, the
828
+ asset and the cut it selected — the same 0.4 ms is a triumph at 10,000 clusters and a scandal
829
+ at nine — so all three go into the note beside the adapter and the resolution.
830
+ */
831
+ install_profile_hotkey({
832
+ renderer,
833
+ name: "vgeo_runtime",
834
+ status: element('profile-status'),
835
+ settings: () => {
836
+ const state = page.state();
837
+
838
+ return [
839
+ `τ=${state.tau}px`,
840
+ state.asset.name,
841
+ `${state.cut.drawn} clusters`,
842
+ `${state.vram.pages} resident of ${state.ram.total_pages}`,
843
+ `${state.screen_width}×${state.screen_height}`,
844
+ ];
845
+ },
324
846
  });
325
847
 
326
848
  globalThis.__state = () => page.state();
327
849
  globalThis.__page = page;
850
+ globalThis.__load_url = url => page.load_url(url);
851
+
852
+ const requested = new URL(globalThis.location.href).searchParams.get('file');
328
853
 
329
- status(`container built in ${build_ms.toFixed(0)} ms · ${reader.header.total_pages} pages`);
854
+ if (requested !== null) {
855
+ await page.load_url(requested);
856
+ } else {
857
+ page.status('building a container in the page…');
858
+
859
+ // yielded so the status paints before the builder takes the thread for half a second
860
+ await new Promise(resolve => setTimeout(resolve, 0));
861
+
862
+ const { source, build_ms } = vgeo_sample_source(128, 48, PAGE_SIZE);
863
+
864
+ await page.load(source);
865
+
866
+ page.status(
867
+ `${page.reader.header.total_pages} pages, built in the page in ${build_ms.toFixed(0)} ms`
868
+ );
869
+ }
330
870
 
331
871
  let stopped = false;
332
872
  let last_time;
@@ -334,12 +874,24 @@ async function start() {
334
874
  function paint() {
335
875
  const state = page.state();
336
876
 
877
+ const name = escape_html(state.asset.name);
878
+
879
+ element('asset').innerHTML = [
880
+ ['source', `<span title="${name}">${name}</span>`],
881
+ ['triangles', state.asset.faces.toLocaleString()],
882
+ ['file', human_bytes(state.asset.bytes)],
883
+ ['read', human_bytes(state.asset.bytes_read)],
884
+ ['view', `${state.screen_width}×${state.screen_height}`],
885
+ ].map(([name, value]) => `<div class="row"><span>${name}</span><span>${value}</span></div>`)
886
+ .join('');
887
+
337
888
  element('cut').innerHTML = [
338
889
  ['drawn clusters', state.cut.drawn],
339
890
  ['clamped', state.cut.clamped],
340
891
  ['pages visited', state.cut.pages],
341
892
  ['clusters tested', state.cut.clusters_tested],
342
893
  ['subtrees culled', state.cut.culled_frustum + state.cut.culled_lod],
894
+ ['clusters culled', state.cut.culled_cluster],
343
895
  ['wants', state.wants],
344
896
  ].map(([name, value]) => `<div class="row"><span>${name}</span><span>${value}</span></div>`)
345
897
  .join('');
@@ -347,11 +899,37 @@ async function start() {
347
899
  const dropped = state.cut.meshlets_dropped + state.cut.queue_dropped
348
900
  + state.cut.instances_dropped;
349
901
 
902
+ /*
903
+ `refused` is the tier saying it had nowhere to put a page the cut asked for, and it is the
904
+ one reading that explains a picture going coarse for a reason that is not τ. It belongs
905
+ beside `clamped` above: a clamped count that will not fall to zero while this climbs is a
906
+ budget, not a threshold.
907
+ */
350
908
  element('residency').innerHTML = [
351
- ['VRAM pages', `${state.vram.pages}`],
352
- ['VRAM bytes', `${(state.vram.bytes / 1024).toFixed(0)} KB`],
909
+ ['VRAM pages', `${state.vram.pages} / ${PAGE_CAPACITY}`],
910
+ ['VRAM bytes', human_bytes(state.vram.bytes)],
353
911
  ['RAM pages', `${state.ram.pages} / ${state.ram.total_pages}`],
912
+ ['RAM evicted', state.ram.evicted],
913
+ ['fetching', state.fetches_in_flight],
914
+ ['worker fetches', `${state.worker_fetches} / ${state.worker_fetches + state.in_process_fetches}`],
354
915
  ['evicted', state.vram.evicted],
916
+ [
917
+ 'refused',
918
+ `<span class="${state.vram.refused > 0 ? 'bad' : 'good'}">`
919
+ + `${state.vram.refused.toLocaleString()}</span>`,
920
+ ],
921
+ /*
922
+ A page that failed its retries is quarantined with its reason and is never asked for
923
+ again, and the clamped cut keeps its surface correct with a coarser ancestor
924
+ indefinitely. That is the difference between a container that is coarse because the
925
+ camera just moved and one that is coarse because a page will never arrive — which look
926
+ identical on screen, and which `clamped` alone cannot tell apart.
927
+ */
928
+ [
929
+ 'quarantined',
930
+ `<span class="${state.ram.quarantined > 0 ? 'bad' : 'good'}">`
931
+ + `${state.ram.quarantined}</span>`,
932
+ ],
355
933
  ['dropped', `<span class="${dropped > 0 ? 'bad' : 'good'}">${dropped}</span>`],
356
934
  ].map(([name, value]) => `<div class="row"><span>${name}</span><span>${value}</span></div>`)
357
935
  .join('');
@@ -367,14 +945,13 @@ async function start() {
367
945
  last_time = time;
368
946
 
369
947
  try {
370
- controller.update(dt);
948
+ page.controller.update(dt);
371
949
 
372
950
  renderer.render(camera, scene, dt);
373
951
  } catch (error) {
374
952
  stopped = true;
375
953
 
376
- status(error.message ?? String(error));
377
- element('status').classList.add('error');
954
+ page.status(error.message ?? String(error), true);
378
955
 
379
956
  console.error(error);
380
957
 
@@ -389,6 +966,19 @@ async function start() {
389
966
  requestAnimationFrame(tick);
390
967
  }
391
968
 
969
+ /**
970
+ * A file name arrives from a drop and lands in the panel's markup, so it is a string from outside
971
+ * the page in the one place a string from outside the page can do something.
972
+ *
973
+ * @param {string} text
974
+ * @returns {string}
975
+ */
976
+ function escape_html(text) {
977
+ return text.replace(/[&<>"]/g, character => ({
978
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;',
979
+ })[character]);
980
+ }
981
+
392
982
  start().catch(error => {
393
983
  element('status').textContent = error.message ?? String(error);
394
984
  element('status').classList.add('error');