@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
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Build a sample container and hand back a source over it.
3
+ *
4
+ * The page size is deliberately far below the 256 KB default: a sample that came out as one page
5
+ * would be a container with nothing to stream, and the point of opening this one is to watch it
6
+ * arrive.
7
+ *
8
+ * @param {number} [major]
9
+ * @param {number} [minor]
10
+ * @param {number} [page_size] target decoded bytes per page
11
+ * @returns {{source: VGeoByteSource, build_ms: number}}
12
+ */
13
+ export function vgeo_sample_source(major?: number, minor?: number, page_size?: number): {
14
+ source: VGeoByteSource;
15
+ build_ms: number;
16
+ };
17
+ import { VGeoByteSource } from "../../renderer/geometry/virtual/format/read/VGeoByteSource.js";
18
+ //# sourceMappingURL=sample_asset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample_asset.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/vgeo_runtime/sample_asset.js"],"names":[],"mappings":"AA2GA;;;;;;;;;;;GAWG;AACH,2CALW,MAAM,UACN,MAAM,cACN,MAAM,GACJ;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAiBtD;+BA3HM,+DAA+D"}
@@ -12,7 +12,7 @@ import {
12
12
  } from "../../renderer/geometry/virtual/format/read/VGeoByteSource.js";
13
13
 
14
14
  /**
15
- * A `.vgeo` built in the page, so the viewer has something to open without a file.
15
+ * A `.vgeo` built in the page, so there is something to open without a file.
16
16
  *
17
17
  * The builder is environment-agnostic by design (`VIRTUAL_GEOMETRY_DESIGN.md` §8) — typed arrays and
18
18
  * topology, no file or process API anywhere under it — so the same call the node CLI makes runs here.
@@ -31,8 +31,8 @@ import {
31
31
  *
32
32
  * Curvature is what makes it a useful sample rather than a shape: a flat face simplifies at zero
33
33
  * quadric cost, so a box would produce a DAG whose every step records no error and whose every
34
- * threshold selects the same cut. A torus has an error at every level, which is the thing the viewer
35
- * is drawing.
34
+ * threshold selects the same cut. A torus has an error at every level, which is the thing the cut
35
+ * is selecting against.
36
36
  *
37
37
  * @param {number} major segments the long way round
38
38
  * @param {number} minor segments around the tube
@@ -56,13 +56,31 @@ function torus(major, minor) {
56
56
 
57
57
  const stride = minor + 1;
58
58
 
59
+ /*
60
+ Wound so that a triangle seen from **outside** the tube is counter-clockwise, which is what
61
+ `CullPolicy.Standard` means by a front face and what `vgeo_compute_vertex_normals` takes the
62
+ sign of its normals from.
63
+
64
+ It was the other way round, and the CPU viewer this sample was written for could not see it:
65
+ that page drew its cut with `cullMode: 'none'` and coloured it per cluster, so neither the
66
+ culling nor the shading could report it. The moment the same sample went through the engine's
67
+ material path — this page, where a `Front`-sided material culls back faces — the torus
68
+ rendered as its own far inner wall with the near surface missing, and the normals pointed into
69
+ the tube so what survived was lit from inside. The viewer has since been retired; this is the
70
+ only page that builds it now, and it is the one that could have caught it.
71
+
72
+ The winding of a sample is not a detail of the sample. Everything downstream of the builder
73
+ carries it: the cluster's triangles are stored in this order, the DAG's simplification
74
+ preserves it, and the pool hands it to the rasterizer untouched — so this one line decides
75
+ whether the whole chain has ever been seen drawing a surface the right way out.
76
+ */
59
77
  for (let i = 0; i < major; i++) {
60
78
  for (let j = 0; j < minor; j++) {
61
79
  const a = i * stride + j;
62
80
  const b = a + stride;
63
81
 
64
- indices.push(a, b, a + 1);
65
- indices.push(a + 1, b, b + 1);
82
+ indices.push(a, a + 1, b);
83
+ indices.push(a + 1, b + 1, b);
66
84
  }
67
85
  }
68
86
 
@@ -0,0 +1,408 @@
1
+ # `vgeo_scene` — a whole converted scene, one cut
2
+
3
+ Thousands of `.vgeo` containers, tens of thousands of instances, **one** compute cut, drawn through
4
+ the ordinary meshlet pipeline.
5
+
6
+ [`../vgeo_runtime/`](../vgeo_runtime/README.md) is the page that proves the engine seam, and it does
7
+ it with one container framed on its own bounding sphere. That makes it a *viewer*, and by
8
+ construction it cannot show the other half of what
9
+ [`VIRTUAL_GEOMETRY_DESIGN.md`](../../renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md) §1
10
+ claims — that rendering cost is a function of the threshold and the resolution rather than of the
11
+ source, **across every asset in view at once**, with instances sharing pages and one residency
12
+ budget arbitrating between all of them. With one reader there is nothing to arbitrate.
13
+
14
+ So everything here that the runtime page does not do is about breadth:
15
+
16
+ - **One residency, N containers.** Every asset registers with the same `VGeoResidency`, whose two
17
+ budgets are scene-wide by construction: the RAM tier's bytes and the VRAM tier's slots are counted
18
+ across every reader, and a page evicted from one asset is room for another's.
19
+ - **One cut, N instances.** `shader_vgeo_cut_collect` runs over the visible mesh rows and emits one
20
+ instance record per virtual one; the descent is seeded with one item per instance and every cull
21
+ and error test downstream runs in that instance's own object space. Seventeen thousand instances
22
+ are seventeen thousand seeds of **one** wavefront, not seventeen thousand cuts.
23
+ - **Instances share the asset.** A geometry placed by 381 nodes is one reader, one geometry row, one
24
+ page lookup and one set of resident pages — which is `VirtualGeometry.equals`, and most of why
25
+ this is affordable at all.
26
+
27
+ ## Running it
28
+
29
+ Three things: the dev server in front of the page, an asset server in front of the containers, and
30
+ a scene manifest telling the page which is which.
31
+
32
+ ```
33
+ npm run dev --workspace @woosh/meep-engine
34
+
35
+ node tools/geometry/virtual/vgeo_scene.js <manifest.vgeo.json> --camera "..." --sun "..."
36
+ node tools/geometry/virtual/vgeo_serve.js <container directory>
37
+ ```
38
+
39
+ Then open `/src/shade/playground/vgeo_scene/index.html`. With no parameters it asks the asset server
40
+ what it is holding and opens the one scene that is there; `?scene=<url>` overrides.
41
+
42
+ **The asset server is not optional and vite cannot replace it.** A `.vgeo` is opened out of its head
43
+ and streamed by `Range`, and `vgeo_fetch_byte_source` refuses anything but a `206` naming the range
44
+ it asked for — a `200` is a server ignoring the request and answering the head of the file where the
45
+ reader asked for the middle of a frame, silently and with plausible numbers. Vite also refuses
46
+ `/@fs/` outside the workspace, and a converted scene is tens of gigabytes that has no business
47
+ inside one. `vgeo_serve.js` is ranges, CORS and nothing else; the header that is easy to miss is
48
+ `Access-Control-Expose-Headers`, because a cross-origin response's `Content-Range` is invisible to
49
+ the page without it.
50
+
51
+ ## What a scene manifest is, and what it is not
52
+
53
+ `gltf_to_vgeo.js` already writes everything the page needs — a glTF primitive is one container and
54
+ the nodes that placed it are its instances — but its manifest is a *build report*: every level of
55
+ every DAG, every cluster and group count, the weld distance each geometry settled on. At this scale
56
+ that is twenty-odd megabytes of numbers a renderer has no use for. `vgeo_scene.js` is the projection
57
+ to four fields and a list of matrices: **2.2 MiB for Zorah's 2,966 containers and 17,424 instances**,
58
+ and nothing in it is discovered — it is all in the build manifest or in the containers' own headers.
59
+
60
+ The headers are **read rather than trusted**. A manifest is written by the builder that produced the
61
+ files and a directory is whatever is on disk now, so the probe is what catches a half-finished
62
+ conversion and a container rebuilt at another page size. It costs one head read each and 1.8 s for
63
+ all 2,966.
64
+
65
+ Two fields are neither: `--camera` and `--sun`.
66
+
67
+ - **A bounding box is a bad place to put a camera.** Zorah's instances span 107 km, almost all of it
68
+ terrain, and the town the scene is *about* is forty metres across at the origin — a viewer framed
69
+ on the box opens a hundred kilometres up looking at a speck. The pose belongs to the source, and
70
+ Zorah's own `.cfg` carries one, so it is passed in rather than guessed at either end.
71
+ - **A converted container carries geometry and nothing else.** Design §7: VG is geometry only, so a
72
+ converted set arrives with normals, no material authoring and no lights. The sun is most of what
73
+ there is to shade it with, and the engine's default direction over a scene authored around a
74
+ different one puts every façade a viewer stands in front of into ambient.
75
+
76
+ ## What it measures
77
+
78
+ Zorah, 2,966 containers and 17,424 instances of them, **46.71 GiB** on the server across 947,664
79
+ pages, 1.36 billion source triangles and **10.75 billion instanced** ones. Measured on an
80
+ nvidia/lovelace adapter at a render target of 1578×746, from the scene's authored viewpoint, with a
81
+ **fresh page load per row** — residency is a high-water mark, so a page swept downwards through the
82
+ thresholds reports at every step what the busiest setting it has already been at asked for, and a
83
+ row of this table is only about τ if the page has been at nothing else.
84
+
85
+ | τ (px) | drawn clusters | pages visited | clusters tested | resident pages | bytes read | frame |
86
+ |---:|---:|---:|---:|---:|---:|---:|
87
+ | 0.25 | 387,875 | 79,574 | 1,232,352 | 12,288 *(full)* | 452 MB | 7.3 ms |
88
+ | 0.5 | 182,887 | 51,035 | 617,540 | 9,365 | 242 MB | 5.0 ms |
89
+ | 1 | 84,481 | 31,842 | 279,088 | 6,387 | 128 MB | 4.7 ms |
90
+ | 2 | 45,302 | 22,356 | 139,290 | 4,939 | 76 MB | 4.8 ms |
91
+ | 4 | 28,874 | 17,483 | 79,651 | 4,121 | 52 MB | 5.2 ms |
92
+ | 8 | 21,334 | 15,235 | 56,561 | 3,704 | 40 MB | 4.8 ms |
93
+ | 16 | 18,137 | 14,289 | 45,717 | 3,489 | 35 MB | 6.0 ms |
94
+
95
+ Monotone in τ, and a *fraction* of the asset at every setting: at τ=1 the scene is on screen out of
96
+ **0.67% of its pages** and 128 MB of 46.71 GiB, and at τ=16 out of 0.37% and 35 MB. `clamped` is
97
+ zero at every row but the first, which is the streaming having finished rather than a budget having
98
+ given up — the distinction the `refused` counter beside it exists to make.
99
+
100
+ **τ=0.25 is the budget wall, and it is in the table on purpose.** At the slider's minimum the cut
101
+ wants more than 12,288 page slots, `refused` climbs to 1.1 million, `clamped` stops falling to zero,
102
+ and the cut is then being selected by a **budget** rather than by a threshold — which is the one
103
+ thing this page is not meant to be showing you. It is one slider notch away at all times, and
104
+ `refused` going red is how you know that is what you are looking at. `?pages=` raises the tier.
105
+
106
+ A tour of five viewpoints at τ=1 — a hundred metres up, three hundred out, a nose against one
107
+ façade, the whole 107 km box, and back to the authored pose — held 4.5 to 5.8 ms a frame with
108
+ `clamped`, `refused` and every drop counter at zero throughout, and residency settling at 7,948 of
109
+ 12,288 pages without a single eviction.
110
+
111
+ ## Opening it, and what the first five seconds are
112
+
113
+ Measured cold, three times: **2,966 containers open in about four seconds**, and the whole scene is
114
+ drawing about a second and a half later.
115
+
116
+ The opens are one range request each. §10's always-resident set — header, level table, root frame —
117
+ is 2,560 bytes at the median across this set and 6,528 at the very worst, so the page asks for an
118
+ **8 KB head prefix** rather than the reader's default of 64 KB: every container in the set opens in
119
+ exactly one round trip and the cold read is 7.4 MB of heads instead of 190 MB of over-fetch. The
120
+ byte length comes from the manifest rather than from a `HEAD`, which is 2,966 round trips not spent
121
+ learning something the page was already holding.
122
+
123
+ **About four and a half seconds of that is not this page.** The first frame that draws geometry pays
124
+ the engine's pipeline warm-up, and `vgeo_runtime` — driven the same way, with a thirteen-page torus
125
+ built in-page — sits on exactly the same stall before *its* first frame. It is a fixed cost of a
126
+ cold device under a dev server, it is not a function of the scene, and a bundled build does not pay
127
+ all of it. Containers keep opening underneath it.
128
+
129
+ Containers are **placed as they land** rather than at the end, which costs nothing: a geometry that
130
+ is not registered yet is one the cut does not collect, and both residency tiers recompute their
131
+ budgets per reading rather than at registration, so a scene that grows under the camera is the case
132
+ they were designed for. A container that refuses leaves every other asset exactly as it was and is
133
+ counted — 2,965 of 2,966 is a scene, and the count is what says there is a hole in it.
134
+
135
+ ## The four capacities a scene reaches first
136
+
137
+ These are the page's real finding, because every one of them is an engine default that a
138
+ single-asset page never touches, and two of them degrade *silently*.
139
+
140
+ - **`queue_capacity`, and this is the one that hurt.** At τ=0.5 with 17,424 instances the descent
141
+ pushed past the engine's 65,536 items in flight and `VGEO_CUT_STAT.QUEUE_DROPPED` came back at
142
+ **32,676** — a third of the frontier thrown away. It does not surface as an error or as a visible
143
+ hole; it surfaces as `drawn` wandering over ten thousand clusters between one frame and the next,
144
+ as different subtrees lose the race. At `1 << 18` the same view drops nothing and `drawn` is
145
+ stable, at a cost of 4 MiB a site against 1 MiB.
146
+ - **`lookup_words`** is one word per page of every registered container out of one arena, and the
147
+ default of 65,536 holds a fourteenth of Zorah's 947,664. It is allocated out of an
148
+ `OffsetAllocator` whose bins round *down* — it can refuse an allocation that fits — so this is
149
+ sized to the next power of two above 1.5× the total rather than to the total.
150
+ - **`geometry_capacity`** is one row per container against a default of 256.
151
+ - **`claim_word_capacity`** is one bit per (collected instance, page ordinal of its geometry), and
152
+ the engine derives it from a hint of a thousand instances times the whole tier. At this scale that
153
+ is both too small and too large, and the real bound is knowable exactly: ordinals come out of the
154
+ tier, so `Σ instances × ordinals` is maximised by giving every slot to the most-instanced asset,
155
+ which makes it `max instances of any one geometry × page capacity`. For Zorah that is 381 × the
156
+ tier — a fifth of what the default derivation asks for — doubled here, because an ordinal capacity
157
+ is a high-water mark and a scene that has churned can hold more of them than the tier holds pages.
158
+
159
+ `RasterizationCollectionType.Meshes` is a fifth, and it self-corrects: it grows from what the frame
160
+ reports, so priming it to the instance count only buys the first seconds. But the first seconds are
161
+ when the scene is being placed, and against a default of 1e4 the other 7,424 instances would be
162
+ counted as `instances_dropped` while the collection caught up.
163
+
164
+ ## Two things it approximates, and says so
165
+
166
+ - **Shear.** A transform row carries a TRS and the GPU composes the world from it, so an instance
167
+ whose matrix has shear in it cannot be represented exactly and is placed at the closest
168
+ rigid-plus-scale fit. 391 of Zorah's 17,424 have any and the worst is about eleven degrees off
169
+ orthogonal; the other 17,033 are exact, including the 2,722 reflected ones — `m4_decompose_array`
170
+ folds a negative determinant into a scale axis, so a reflection survives. This is a property of
171
+ the engine's transform model rather than of this page. The reflections surviving is what the next
172
+ section is about.
173
+ - **One material for the whole scene.** Not a simplification being made here: a `.vgeo` carries
174
+ geometry only, so the source's 2,714 materials did not survive a conversion that never asked them
175
+ to. Tinting each container would read better, would be a lie about where the colour came from, and
176
+ would put 2,714 material buckets in front of the draw path to say it with.
177
+
178
+ ## Reflected instances — the bug this page was built to show, and where it went
179
+
180
+ 2,722 of Zorah's 17,424 instances have a negative-determinant transform: the courtyard is
181
+ bilaterally symmetric and the left half is the mirror of the right. Until 2026-09-15 every one of
182
+ them rendered with its near surface culled and its far surface showing through, because:
183
+
184
+ 1. A reflection reverses the orientation of every triangle it transforms, so a reflected instance
185
+ presents the **opposite screen-space winding** from the same geometry under a rotation.
186
+ 2. Front-face determination is fixed-function and reads that winding and nothing else.
187
+ 3. `cullMode` is **pipeline state chosen per material bucket**, and the bucket key was three fields
188
+ of a *material* — transparency, topology and side — with `construct_primitive_state` turning the
189
+ third into a cull mode. Nothing from there down to the rasterizer saw a transform.
190
+
191
+ The sign was never lost — `m4_decompose_array` preserves it and the row the GPU composes reflects
192
+ exactly as the source did — it was simply never consulted.
193
+
194
+ **It is consulted now, and not through the bucket key.** A node's row carries
195
+ `NODE3D_GLOBAL_FLAG_MIRRORED`, derived from its composed world matrix by whoever publishes it, and
196
+ every vertex shader over a meshlet emits that instance's triangle corners in the opposite order —
197
+ `triangle_list_reverse_winding`. The draw is non-indexed and the vertex shader resolves its own
198
+ index, so which corner lands where is already the shader's choice; reversing it costs a `select`,
199
+ no second pipeline, and no fourth field in the bucket key. It is what Nanite does for the same
200
+ reason (`FInstanceSceneData::DeterminantSign`, read in `HWRasterizeVS`), and what the glTF spec
201
+ requires of a conformant renderer. The tangent frame's handedness flips with it.
202
+
203
+ The parameters remain, and now read as diagnostics rather than as fixes:
204
+
205
+ - `?mirrored=tint` colours reflected instances red — in this view the **whole left arcade** comes up
206
+ red while the right stays grey. Nothing about which of them is *drawn* changes.
207
+ - `?mirrored=flip` draws them `Back`-sided. This used to be the page's own fix; `Back` is now drawn
208
+ by reversing winding too, so on a reflected instance the two cancel and it reproduces the old bug
209
+ on demand.
210
+ - `?mirrored=double` draws both sides of them — the fix people reach for first, and still the wrong
211
+ one: it doubles the work and gets the shading wrong.
212
+ - `?side=front|back|double` sets the whole scene's side, for the cruder question of whether a
213
+ surface is missing or merely culled.
214
+
215
+ The bug was hard to recognise because `fragment_gbuffer` flips normal, tangent and face normal when
216
+ `dot(world_face_normal, view_direction) < 0` — a test about the *view*, not about the winding — so
217
+ the far wall you were left looking at was correctly lit, and it read as bad geometry rather than as
218
+ a culling problem. Nothing about any of it was virtual-geometry-specific: it reached every mesh
219
+ placed under a mirroring transform, by any loader or prefab.
220
+
221
+ ## Two different things are called flicker here, and they have different causes
222
+
223
+ **A dropout is not a shimmer and they do not measure alike.** A shimmer moves a tenth of a per cent
224
+ of the pixels and comes from the TAA jitter under sub-pixel geometry; a frame missing a large part
225
+ of what the frames either side of it drew moves tens of per cent and comes from the descent running
226
+ out of wavefronts. One section each, below. Measuring the first when asked about the second cost a
227
+ whole pass of this investigation, and the tell that separates them is the amplified frame
228
+ difference: an **edge map** is the shimmer, **solid blobs** are the dropout.
229
+
230
+ ## The shimmer is the TAA jitter, and the geometry is finer than a pixel
231
+
232
+ There is a visible shimmer over the ornament, and it is **exactly 16 frames long**.
233
+
234
+ Measured over 600 consecutive frame pairs at 780×368 samples (~2×2 screen pixels each), camera
235
+ static, everything settled:
236
+
237
+ | | pixels changing >8/255 per frame | >24/255 | worst single step | period |
238
+ |---|---:|---:|---:|---:|
239
+ | as shipped | 350 (0.12%) | 17 | 57/255 | 16 (r=0.97) |
240
+ | τ=16 | 182 (0.06%) | 13 | 69/255 | 16 (r=0.95) |
241
+ | `?mirrored=flip` | 314 (0.11%) | 21 | 56/255 | 16 (r=0.96) |
242
+ | TAA off | **79,391 (27.66%)** | 33,841 | 161/255 | 16 (r=0.97) |
243
+ | jitter pinned | 89 (0.03%) | 3 | 88/255 | 16 (r=0.96) |
244
+
245
+ Sixteen is `TAA.#jitter_sequence_size`, and the attribution follows from the last two rows. **Pin the
246
+ jitter and fifteen frames out of every sixteen go pixel-static** — 18 to 123 changed samples out of
247
+ 287,040, which is the noise floor — against 240 to 470 *every* frame as shipped. The flicker is the
248
+ Halton jitter cycling the projection under geometry whose detail is finer than a pixel, with TAA
249
+ resolving most but not all of it.
250
+
251
+ An amplified `|frame(t) − frame(t−1)|` over eighteen consecutive pairs says the same thing in one
252
+ picture: it is an **edge map**. Every silhouette and every piece of filigree sparkles; the flat
253
+ courtyard floor is dead black. LOD popping would light up in cluster-shaped patches and does not.
254
+
255
+ Three things fall out of it that are worth writing down:
256
+
257
+ - **`feature_taa_enabled = false` does not turn the jitter off.** `Renderer` writes
258
+ `view_ctx.camera.setViewportOffset` from the jitter sequence unconditionally, and only the
259
+ *resolve* is behind the flag. So TAA off is not "no temporal AA", it is "jitter with nothing to
260
+ resolve it": 27.66% of pixels move every frame, which is forty times worse than shipping it on and
261
+ worse than never jittering at all. Anyone A/B-ing TAA on this content is not measuring what they
262
+ think.
263
+ - **The jitter does move the cut, slightly, and it is not where the flicker comes from.** `drawn`
264
+ and `pages visited` are weakly 16-periodic (r=0.34 and r=0.40) because the cut's frustum planes
265
+ come out of the *jittered* view-projection while `projection_k` — the error metric — does not. So
266
+ what moves is which clusters are inside the frustum, by up to 117 of 84,455 (0.14%), confined to
267
+ the screen border. `vgeo_runtime`'s README says the jitter does not move the cut and its τ table is
268
+ identical either way; at this scale that is very nearly true rather than exactly true, and the
269
+ difference is not visible in the diff image.
270
+ - **`GPUViewContext.setJitter` and `setJitterDelta` write the same two fields.** Only the first is
271
+ called, so nothing is broken today; a caller that used the second would silently overwrite the
272
+ jitter with its delta.
273
+
274
+ None of this is the scene's fault and τ=16 halving the count is the proof: less sub-pixel detail,
275
+ less shimmer, same period. It is what a temporal filter does on content authored at a density no
276
+ rasterizer resolves, which is the content virtual geometry exists to put on screen — so it is worth
277
+ knowing that the page's picture has a floor set by TAA rather than by the cut.
278
+
279
+ ## The dropout: the descent's wavefront bound, and how the engine finds it
280
+
281
+ **`max_iterations` starts at 8, and at a large viewport that is the binding bound rather than the
282
+ safety one.** The descent then stops with items still queued, and a queued item is a **subtree that
283
+ was never expanded** — so what it would have drawn is not on screen that frame. It is the one
284
+ degradation of this cut that costs a *hole* rather than a coarser surface, which is why it reads as
285
+ geometry disappearing rather than as anything softening.
286
+
287
+ Reported from a live session at **3441×1440** with `dropped: queue 82` in the panel and `wavefronts`
288
+ jittering between 8 and 13. Reproduced at that pose and viewport, 900 frames, camera static, with
289
+ the bound pinned:
290
+
291
+ | pinned `max_iterations` | `queue_remaining` non-zero | worst | `drawn` swing |
292
+ |---|---:|---:|---:|
293
+ | **8** | **750 of 900 frames** | 13,467 items | **11,857 clusters** |
294
+ | 16 / 32 / 64 | 0 | 0 | 81 |
295
+
296
+ `drawn` going from a swing of 11,857 clusters to **81** is the flicker, in one number. An amplified
297
+ `|frame(t) − frame(t−1)|` says the same thing in a picture: at 8 it is **solid white blobs** — whole
298
+ pieces of carved ornament blinking on and off — and above it those are gone, leaving only the thin
299
+ edge shimmer of the section above. The two phenomena look nothing alike once they are separated.
300
+
301
+ **It is a resolution story, and that is why it took so long to find.** The cut is a function of the
302
+ render target, so the same viewpoint at 1578×746 — a quarter of the pixels — drains inside 8
303
+ wavefronts and never drops an item. Every negative result in this file's earlier drafts was measured
304
+ at that size. A quarter-sized window is not a smaller version of this test.
305
+
306
+ ### The bound raises itself
307
+
308
+ Nothing here pins it. `GPUVirtualGeometryRuntime.note_incomplete_descent` takes the one reading that
309
+ says the descent was truncated and **doubles the bound, permanently**, which is the same shape the
310
+ rasterizer already uses for meshlet counts: a quantity that cannot be known before the work runs,
311
+ learned from what the work reported, kept as a high-water mark.
312
+
313
+ It has to be learned, because how many wavefronts a cut needs is a function of the frontier's
314
+ *breadth* — the scene, the viewpoint and the render target together — and neither the kernel before
315
+ it runs nor the host at any time can compute it. Doubling rather than solving for it, because
316
+ `QUEUE_REMAINING` is a count of *items* and there is no ratio converting those into wavefronts. It
317
+ is never lowered: a frame that drained is evidence about that frame, not that the scene got smaller,
318
+ and a bound that fell back would re-learn the same lesson at a hole a time every time the camera
319
+ turned away and back. An unused wavefront is an empty indirect dispatch, which is the cheap side of
320
+ that trade.
321
+
322
+ **What it costs when it is wrong is one frame.** Measured cold at 3419×1286 on the reported
323
+ viewpoint: `queue_remaining` non-zero on **1 frame of 600**, and zero for the rest of the session.
324
+ The ceiling is 64, so the worst case is three such frames, once, ever.
325
+
326
+ The panel shows `wavefronts` as *used / bound*, with an arrow and a count when the bound has moved,
327
+ because eight wavefronts is a drained descent under a bound of 32 and a truncated one under a bound
328
+ of 8 — and the reading could not tell them apart while it showed only the count.
329
+
330
+ `?iterations=N` pins both the start and the ceiling, which turns the escalation off and reproduces
331
+ the hole on demand: at 8 the same view gives `queue_remaining` on 395 frames of 500 and a `drawn`
332
+ swing of 15,874.
333
+
334
+ **`descent_steps` is the wrong knob for this.** It sets how many levels one dispatch advances, so it
335
+ answers depth; what runs out here is *breadth* — a wave keeps one child per lane and spills the
336
+ rest, and the spill generations are what consume the bound. Measured at the small viewport, 24
337
+ against 48 left `drawn` bit-identical.
338
+
339
+ ### Catching it where it happens
340
+
341
+ `?catch=0.15` arms {@link FlickerCatcher} — a per-frame detector in the page itself. It judges each
342
+ frame against the pair before it **and** the pair after it, taking the smaller of the two
343
+ departures and only when both point the same way. Judging against the median of all four is the
344
+ obvious thing and is wrong: when the picture takes a persistent *step* — the scene streaming in, a
345
+ coarse level replaced by a fine one — two of the four sit on the far side, the median lands between
346
+ the levels, and the frame *before* the step is convicted for being where it always was. Fourteen
347
+ poses each "caught" one that way. On a step the smaller departure is ~0 by construction, which is
348
+ what makes the corrected test score the reported event at 62% and every one of those artifacts at
349
+ or under 1%.
350
+
351
+ It works on **pixels rather than counters**:
352
+ the cut's statistics come from a readback capped at two in flight and skipped on more than half the
353
+ frames, so `drawn` on any given frame is a reading from one to three frames ago and a one-frame
354
+ disappearance need never appear in it at all. That is why the panel's numbers look calm during one.
355
+
356
+ ```
357
+ ?catch=0.15 count them, panel shows a running tally — fly around looking for one
358
+ ?catch=0.15&freeze=1 stop on the first one and leave that frame on screen
359
+ ```
360
+
361
+ **"copy camera link" is how a viewpoint gets out of the browser.** A viewpoint is the one piece of
362
+ state a person has and a session does not: everything else this page can be told is a URL parameter
363
+ already, and a phenomenon that happens "in many places" is not chaseable without one of them. The
364
+ button writes a link that reopens the page where the camera is standing — `?eye=`/`?at=` from the
365
+ live pose, `?tau=` from the slider as it stands rather than as the page was opened, and every other
366
+ parameter left exactly as it was, so a link captured with `?catch=0.15&mirrored=tint` on comes back
367
+ with both still armed. It goes to the clipboard, and to a selected box under the button when a
368
+ browser declines that. `__camera_url()` is the same string for a session with no pointer.
369
+
370
+ **An event carries its own camera link**, captured at the instant it fires, so `__caught()` is
371
+ self-contained: where it happened is the one thing a report of a one-frame dropout cannot be
372
+ reconstructed without, and by the time anybody reads the report the camera may have moved. The held
373
+ frame goes on *under* the panel, so freezing does not hide the readings that explain it.
374
+
375
+ `__caught()` reports what it has seen and the counters for the five frames around the last one;
376
+ `__catch_rows()` is the per-frame log. Freezing also holds the five frames around it, and
377
+ `__show_frame(n)` pages between them — the frame before and the frame itself, side by side, is what
378
+ says whether the geometry went missing or merely moved.
379
+
380
+ It costs a whole-canvas `drawImage` and a small `getImageData` per frame: 4.2 ms a frame becomes
381
+ 10.3 ms here, which is slack on a 60 Hz display and is why the full-resolution ring is only kept
382
+ when `freeze=1` is asked for.
383
+
384
+ ## Driving it
385
+
386
+ `__state()` is the whole surface a headless session needs and the panel shows nothing it does not:
387
+ the scene's counts, the cut's counters, both residency tiers, the render target's size and the
388
+ camera. `__page.runtime.tau` is the threshold, `__look(eye, target)` stands the camera somewhere,
389
+ and `__page.viewpoints` is what the buttons in the panel are.
390
+
391
+ URL parameters, all of them for a session rather than for a person: `?scene=` the manifest,
392
+ `?tau=` the threshold **before the first container** (see the table above for why a load per row),
393
+ `?pages=` the VRAM tier's slots, `?iterations=` the descent's wavefront ceiling,
394
+ `?eye=x,y,z&at=x,y,z` a viewpoint, `?side=front|back|double` the whole scene's draw side,
395
+ `?mirrored=flip|tint|double` the reflected instances' — and `?catch=<fraction>[&freeze=1]` the
396
+ dropout catcher. `__state().scene.mirrored` is the reflected count the panel shows, and `__caught()`
397
+ the catcher's report.
398
+
399
+ **`T` records a GPU capture and `T` again downloads an `.sgpt`** — the same key and the same module
400
+ (`playground/profile_hotkey.js`) every other playground binds. It answers the question the panel
401
+ cannot: every reading above is a *count* and not one of them is a cost. The capture's note carries
402
+ τ, the container and instance counts, the cut it selected and the resolution, because the same
403
+ 0.4 ms is a triumph at eighty thousand clusters and a scandal at eighteen thousand.
404
+
405
+ The headless recipe is `vgeo_runtime`'s and has not changed — `--enable-unsafe-webgpu` and nothing
406
+ else, pick the CDP target by URL, resize the window rather than the viewport, and poll for `__state`
407
+ rather than trusting `load`. Its README is where those four are written down and why each one costs
408
+ an hour.
@@ -0,0 +1,144 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>meep — a whole virtual-geometry scene</title>
6
+
7
+ <link rel="icon" href="data:,">
8
+
9
+ <style>
10
+ :root { color-scheme: dark; }
11
+
12
+ html, body { height: 100%; margin: 0; overflow: hidden; background: #070b10; }
13
+
14
+ /* Placed, not sized — `Renderer` writes an inline `style.width`/`style.height` every time
15
+ it configures the context, and an inline style beats a rule in here. `main.js` measures
16
+ the document for the same reason. */
17
+ #view { position: absolute; top: 0; left: 0; display: block; }
18
+
19
+ #panel {
20
+ position: absolute; top: 0; right: 0; width: 330px; max-height: 100vh; overflow-y: auto;
21
+ z-index: 10; padding: 12px 14px; box-sizing: border-box;
22
+ font: 12px/1.45 ui-monospace, "Cascadia Mono", Consolas, monospace;
23
+ color: #dfe6ee; background: rgba(12, 16, 22, 0.88);
24
+ border-left: 1px solid #2b3947;
25
+ }
26
+
27
+ #panel h1 { margin: 0 0 8px; font-size: 13px; letter-spacing: 0.06em; color: #7fd2ff; }
28
+
29
+ #panel h2 {
30
+ margin: 14px 0 6px; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
31
+ color: #6b7c8d; border-bottom: 1px solid #24313d; padding-bottom: 3px;
32
+ }
33
+
34
+ #panel .row { display: flex; justify-content: space-between; gap: 8px; }
35
+
36
+ #panel .row span:last-child {
37
+ color: #f2f6fa; text-align: right;
38
+ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
39
+ }
40
+
41
+ #panel .row span:first-child { flex: none; }
42
+ #panel .muted { color: #6b7c8d; }
43
+ #panel .bad { color: #ff8a7a; }
44
+ #panel .good { color: #8fe388; }
45
+ #panel input[type=range] { width: 100%; }
46
+ #panel label { display: block; margin: 6px 0 2px; }
47
+
48
+ #status { white-space: pre-wrap; overflow-wrap: anywhere; }
49
+ #status.error { color: #ff8a7a; }
50
+
51
+ /* The one thing on this page that is not a number: how much of the scene is open. A scene
52
+ arrives container by container and the picture fills in as it does, so a bar is the
53
+ honest shape for it — the page is usable long before it is finished. */
54
+ #progress {
55
+ margin: 8px 0 2px; height: 4px; background: #1b2530; border-radius: 2px;
56
+ overflow: hidden;
57
+ }
58
+
59
+ #progress > div { height: 100%; width: 0; background: #7fd2ff; transition: width 0.2s; }
60
+
61
+ #views { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
62
+
63
+ #views button {
64
+ flex: 1 1 auto; padding: 3px 6px; cursor: pointer;
65
+ font: inherit; font-size: 11px; color: #dfe6ee;
66
+ background: #1b2530; border: 1px solid #2b3947; border-radius: 3px;
67
+ }
68
+
69
+ #views button:hover { background: #24313d; border-color: #3d5164; }
70
+
71
+ #capture { margin-top: 6px; }
72
+
73
+ #capture button {
74
+ width: 100%; padding: 4px 6px; cursor: pointer;
75
+ font: inherit; font-size: 11px; color: #dfe6ee;
76
+ background: #1b2530; border: 1px solid #2b3947; border-radius: 3px;
77
+ }
78
+
79
+ #capture button:hover { background: #24313d; border-color: #3d5164; }
80
+
81
+ /* Selectable and wrapped: the clipboard is the happy path and this is what is left when a
82
+ browser declines it, so it has to be something a person can drag over. */
83
+ #camera-url {
84
+ margin-top: 5px; padding: 4px 6px; user-select: all; word-break: break-all;
85
+ font-size: 11px; color: #9fb4c7; background: #10171f;
86
+ border: 1px solid #24313d; border-radius: 3px;
87
+ }
88
+
89
+ #hint, #profile-note { margin-top: 10px; color: #6b7c8d; }
90
+
91
+ #profile-status { margin-top: 4px; color: #dfe6ee; word-break: break-word; }
92
+ #profile-status.recording { color: #ff8a7a; }
93
+ </style>
94
+ </head>
95
+ <body tabindex="0">
96
+
97
+ <canvas id="view"></canvas>
98
+
99
+ <div id="panel">
100
+ <h1>a whole VG scene</h1>
101
+ <div id="status" class="muted">starting…</div>
102
+ <div id="progress"><div></div></div>
103
+
104
+ <label>threshold τ <span id="tau-value">1.0</span> px</label>
105
+ <input id="tau" type="range" min="0.25" max="16" step="0.25" value="1">
106
+
107
+ <div id="views"></div>
108
+
109
+ <div id="capture">
110
+ <button id="copy-camera" type="button">copy camera link</button>
111
+ <div id="camera-url" hidden></div>
112
+ </div>
113
+
114
+ <h2>scene</h2>
115
+ <div id="scene"></div>
116
+
117
+ <h2>cut</h2>
118
+ <div id="cut"></div>
119
+
120
+ <h2>residency</h2>
121
+ <div id="residency"></div>
122
+
123
+ <div id="catch-section" hidden>
124
+ <h2>dropout catcher</h2>
125
+ <div id="catch"></div>
126
+ <div class="muted" style="margin-top:6px">a frame unlike the two either side of it, by
127
+ luminance. <code>&amp;freeze=1</code> stops on the first one and leaves it on screen.
128
+ <code>__caught()</code> reports, <code>__catch_rows()</code> is the per-frame log.</div>
129
+ </div>
130
+
131
+ <h2>profiling</h2>
132
+ <div id="profile-status">idle · T to record</div>
133
+ <div id="profile-note"><strong>T</strong> starts a GPU capture and <strong>T</strong> again
134
+ stops it and downloads an <code>.sgpt</code>. The note carries τ, the instance count and the
135
+ cut it selected, because a pass timing means nothing without them.</div>
136
+
137
+ <div id="hint">W/A/S/D to move, drag to look, wheel to close in.
138
+ <code>?scene=&lt;url&gt;</code> opens another one.</div>
139
+ </div>
140
+
141
+ <script type="module" src="./main.js"></script>
142
+
143
+ </body>
144
+ </html>
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/vgeo_scene/main.js"],"names":[],"mappings":""}