@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,1343 +0,0 @@
1
- import Vector3 from "../../../core/geom/Vector3.js";
2
- import { DEG_TO_RAD } from "../../../core/math/DEG_TO_RAD.js";
3
- import { OrbitalCameraController } from "../../renderer/camera/orbital/index.js";
4
- import { PerspectiveCamera } from "../../renderer/camera/PerspectiveCamera.js";
5
- import { create_frame_loop } from "../../renderer/create_frame_loop.js";
6
- import { DEFAULT_DEPTH_TEXTURE_VIEW } from "../../renderer/depth/DEFAULT_DEPTH_TEXTURE_VIEW.js";
7
- import { DEPTH_BACKGROUND_VALUE } from "../../renderer/depth/DEPTH_BACKGROUND_VALUE.js";
8
- import { GPUDynamicMeshRenderer } from "../../renderer/dynamic/GPUDynamicMeshRenderer.js";
9
- import { FramePhase } from "../../renderer/extension/FramePhase.js";
10
- import { RenderExtension } from "../../renderer/extension/RenderExtension.js";
11
- import { SceneColor } from "../../renderer/extension/SceneColor.js";
12
- import { ViewTextures } from "../../renderer/extension/ViewTextures.js";
13
- import {
14
- vgeo_codec_name
15
- } from "../../renderer/geometry/virtual/format/frame/vgeo_codec_name.js";
16
- import {
17
- VGeoByteSource
18
- } from "../../renderer/geometry/virtual/format/read/VGeoByteSource.js";
19
- import {
20
- VGeoContainerReader
21
- } from "../../renderer/geometry/virtual/format/read/VGeoContainerReader.js";
22
- import {
23
- vgeo_fetch_byte_source
24
- } from "../../renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js";
25
- import {
26
- VGeoReadOptions
27
- } from "../../renderer/geometry/virtual/format/read/VGeoReadOptions.js";
28
- import {
29
- vgeo_audit_container
30
- } from "../../renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js";
31
- import {
32
- vgeo_install_all_pages
33
- } from "../../renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js";
34
- import { make_sunlight } from "../../renderer/light/make_sunlight.js";
35
- import { place_light } from "../../renderer/light/place_light.js";
36
- import { EntityComponentDataset } from "../../../engine/ecs/EntityComponentDataset.js";
37
- import { Renderer } from "../../renderer/Renderer.js";
38
- import { DynamicMesh } from "../../renderer/scene/DynamicMesh.js";
39
- import { DynamicMeshBatch } from "../../renderer/scene/DynamicMeshBatch.js";
40
- import { Scene } from "../../renderer/scene/Scene.js";
41
- import { VGEO_COLOR_MODE, vgeo_build_cut_geometry } from "./cut_geometry.js";
42
- import { vgeo_sample_source } from "./sample_asset.js";
43
- import { VGeoCut, VGeoCutView, vgeo_select_cut } from "./select_cut.js";
44
-
45
- /**
46
- * An interactive viewer for the `.vgeo` container.
47
- *
48
- * Point it at a file and it is opened *incrementally* — the header, the level table and the root
49
- * page, and after that only the pages a cut actually asks for. What is drawn is not the asset but
50
- * the **cut**: the clusters the container's own metric selects for where the camera is standing,
51
- * coloured so the seams between them are visible.
52
- *
53
- * Two things are therefore on screen at once, and telling them apart is the point of the tool:
54
- *
55
- * - **The cut is frozen until you ask for a new one.** "Adapt to view" re-runs the traversal at
56
- * wherever the camera is now; everything after that is you flying around a decision taken from
57
- * somewhere else, which is the only way to see what a cut actually selected. Turn `follow the
58
- * camera` on to watch it chase instead.
59
- * - **A cut taken from a partly-arrived file is clamped, not wrong.** Where the page holding a
60
- * refinement is missing, the coarser cluster is drawn and a want is recorded — a watertight
61
- * surface either way. `colour by clamp` paints exactly those regions, and `stream wanted pages`
62
- * fetches them and re-adapts until the count reaches zero.
63
- *
64
- * Drawing goes through Shade's **direct geometry path** — a {@link DynamicMesh} drawn straight from
65
- * its attributes, no meshlet encode — because a cut is rebuilt from scratch every time it is
66
- * adapted, and a meshlet build per adapt would price the tool out of being interactive. It is drawn
67
- * *opaque* on that path ({@link GPUDynamicMeshRenderer.opaque}), so the depth buffer orders the
68
- * cut's own triangles: a cut is a solid surface and nothing on the CPU can order one correctly.
69
- *
70
- * The reader under it is not a debug reader. It is `format/read/`, it is what a runtime would use,
71
- * and everything above — the traversal, the clamp, the wants — is the page's own. See README.md.
72
- *
73
- * @author Alex Goldring
74
- * @copyright Company Named Limited (c) 2026
75
- */
76
-
77
- /**
78
- * How many wanted pages one streaming round installs before the cut is retaken and the panel
79
- * redrawn.
80
- *
81
- * Small on purpose. A round that installed every want would arrive as one step from coarse to final
82
- * and show nothing of the process; this is what makes refinement visible while it happens, which is
83
- * the only reason to look at a streaming reader rather than read its numbers.
84
- *
85
- * @type {number}
86
- */
87
- const STREAM_BATCH = 8;
88
-
89
- /**
90
- * The head prefixes the panel offers, in bytes.
91
- *
92
- * §10 gives a reader two cold starts and this is the dial between them: the header alone, and then
93
- * one exact range per page it decides it wants — or one speculative prefix that brings the head and
94
- * whatever else it happens to cover. Both are correct and they cost very differently, and which is
95
- * better depends entirely on how big the asset is against how much of it a view needs. Being able to
96
- * flip between them on one file, and watch `read` and `requests` move, is most of what there is to
97
- * learn about the front of this format.
98
- *
99
- * @type {[string, number][]}
100
- */
101
- const HEAD_PREFIXES = [
102
- ['256 B — header only', 256],
103
- ['16 KB', 16 * 1024],
104
- ['64 KB — the default', 64 * 1024],
105
- ['256 KB', 256 * 1024],
106
- ['1 MB', 1024 * 1024],
107
- ];
108
-
109
- /**
110
- * @param {number} value
111
- * @returns {string}
112
- */
113
- function thousands(value) {
114
- return value.toLocaleString('en-US');
115
- }
116
-
117
- /**
118
- * @param {[string, string][]} entries
119
- * @returns {string} one label/value row apiece
120
- */
121
- function panel_table(entries) {
122
- return entries
123
- .map(([key, value]) => `<div class="row"><span class="muted">${key}</span><span>${value}</span></div>`)
124
- .join('');
125
- }
126
-
127
- /**
128
- * @param {number} bytes
129
- * @returns {string}
130
- */
131
- function human_bytes(bytes) {
132
- if (bytes < 1024) {
133
- return `${bytes} B`;
134
- }
135
-
136
- if (bytes < 1024 * 1024) {
137
- return `${(bytes / 1024).toFixed(1)} KB`;
138
- }
139
-
140
- if (bytes < 1024 * 1024 * 1024) {
141
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
142
- }
143
-
144
- return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
145
- }
146
-
147
- /**
148
- * @param {string} text
149
- * @returns {string}
150
- */
151
- function escape_html(text) {
152
- return String(text).replace(/[&<>]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' })[c]);
153
- }
154
-
155
- /**
156
- * What a reader's quarantine amounts to, for the panel.
157
- *
158
- * A page that has failed its retries is not an error the viewer can act on — the clamped cut keeps
159
- * that surface correct with a coarser ancestor — but it is the difference between an asset that is
160
- * coarse because the camera just moved and one that is coarse because a page will never arrive, and
161
- * those look identical on screen. So the count goes on the panel, with the first reason.
162
- *
163
- * @param {VGeoContainerReader} reader
164
- * @returns {string}
165
- */
166
- function quarantine_summary(reader) {
167
- const count = reader.quarantined_page_count;
168
-
169
- if (count === 0) {
170
- return 'none';
171
- }
172
-
173
- const [page, reason] = reader.quarantine().next().value;
174
-
175
- return `${thousands(count)} page(s) · page ${page}: ${escape_html(reason)}`;
176
- }
177
-
178
- /**
179
- * Everything the panel says about the resident set, in one pass over it.
180
- *
181
- * One pass, and over `resident_pages()` rather than `pages`, because the panel refreshes on every
182
- * streaming round and `VGeoContainerReader.pages` is a snapshot that allocates an array and sorts
183
- * it — 0.29 ms at 20,000 resident pages, and this used to ask for two of them.
184
- *
185
- * Storage: stored is what gets fetched and what sits on disk, decoded is what a resident page costs
186
- * in RAM. The codec is per frame, so a file can genuinely be a mixture — the encoder stores a page
187
- * raw whenever compressing it would not have shrunk it — and naming all of them is more honest than
188
- * naming whichever one came first.
189
- *
190
- * Normals: worth saying outright because the alternative reads as a broken viewer. A source that
191
- * carried no normals encodes the engine default everywhere, every cluster compresses to one constant
192
- * word, and `colour by stored normal` comes out one flat colour across the whole model.
193
- *
194
- * @param {VGeoContainerReader} reader
195
- * @returns {{storage: string, normals: string}}
196
- */
197
- function page_summary(reader) {
198
- let stored = 0;
199
- let decoded = 0;
200
- let per_vertex = 0;
201
- let clusters = 0;
202
- let pages = 0;
203
-
204
- const codecs = new Set();
205
-
206
- for (const page of reader.resident_pages()) {
207
- stored += page.stored_size;
208
- decoded += page.decoded_size;
209
- per_vertex += page.per_vertex_normal_cluster_count;
210
- clusters += page.cluster_count;
211
-
212
- codecs.add(page.codec);
213
-
214
- pages++;
215
- }
216
-
217
- const codec = Array.from(codecs).map(vgeo_codec_name).join(' + ');
218
-
219
- return {
220
- storage: pages === 0
221
- ? '—'
222
- : `${human_bytes(stored)} stored · ${human_bytes(decoded)} decoded`
223
- + ` · ${codec} ${(decoded / Math.max(stored, 1)).toFixed(2)}x`,
224
- normals: `${thousands(per_vertex)} / ${thousands(clusters)} clusters`,
225
- };
226
- }
227
-
228
- /**
229
- * The viewer draws its clusters into the scene, at the phase a full-screen effect that should be
230
- * tonemapped with the rest of the frame belongs at.
231
- */
232
- class VGEOViewerExtension extends RenderExtension {
233
- name = "vgeo viewer";
234
-
235
- phase = FramePhase.AfterTransparency;
236
-
237
- /**
238
- * @type {VGeoViewer}
239
- */
240
- #viewer;
241
-
242
- /**
243
- * @param {VGeoViewer} viewer
244
- */
245
- constructor(viewer) {
246
- super();
247
-
248
- this.#viewer = viewer;
249
- }
250
-
251
- record(frame) {
252
- this.#viewer.record(frame);
253
- }
254
- }
255
-
256
- /**
257
- * Clear the frame's depth, so that the cut is the only thing in it.
258
- *
259
- * **The renderer does not do this when there is nothing to rasterize.** Depth is cleared as a side
260
- * effect of drawing the first opaque bucket, and this viewer's `Scene` holds a light and no meshes,
261
- * so that draw never happens. The renderer also ping-pongs two depth textures frame to frame — so
262
- * left alone, the cut is depth-tested against *its own depth from two frames ago*, and dissolves
263
- * into holes wherever the camera has moved since. It reads as missing geometry and it is not.
264
- *
265
- * A real scene needs none of this and must not have it: the cut has to be occluded by whatever the
266
- * scene put in the depth buffer, which is why the draw itself loads rather than clears.
267
- *
268
- * It runs immediately before the draw rather than at the top of the frame, so everything earlier
269
- * that reads depth still sees the previous frame's. With nothing in the scene there is nothing for
270
- * those passes to occlude, and the alternative is a second registration on another phase to save a
271
- * result that is empty either way.
272
- *
273
- * @param {FrameGraph} graph
274
- * @param {number} depth
275
- * @returns {number} the depth handle to draw against
276
- */
277
- function vgeo_graph_clear_depth(graph, depth) {
278
- const data = {};
279
-
280
- const pass = graph.add('vgeo/clear depth', data, (data, resources, context) => {
281
- const texture = resources.get(data.depth);
282
-
283
- // no draws — the clear is the load op, and ending the pass immediately is what performs it
284
- context.encoder.beginRenderPass({
285
- label: "vgeo/clear depth",
286
- colorAttachments: [],
287
- depthStencilAttachment: {
288
- view: texture.obtainView(DEFAULT_DEPTH_TEXTURE_VIEW),
289
- depthLoadOp: "clear",
290
- depthStoreOp: "store",
291
- depthClearValue: DEPTH_BACKGROUND_VALUE,
292
- },
293
- }).end();
294
- });
295
-
296
- data.depth = pass.write(depth);
297
-
298
- return data.depth;
299
- }
300
-
301
- /**
302
- * The viewer. One container at a time, one cut at a time, and the cut only changes when asked.
303
- */
304
- class VGeoViewer {
305
- /**
306
- * @type {VGeoContainerReader|undefined}
307
- */
308
- #reader = undefined;
309
-
310
- /**
311
- * The source the current container was opened over, kept so that changing a read option can
312
- * re-open it rather than ask for the file again.
313
- * @type {VGeoByteSource|undefined}
314
- */
315
- #source = undefined;
316
-
317
- /**
318
- * @type {VGeoCutGeometry|undefined}
319
- */
320
- #cut_geometry = undefined;
321
-
322
- /**
323
- * @type {VGeoCut}
324
- */
325
- #cut = new VGeoCut();
326
-
327
- /**
328
- * @type {VGeoCutView}
329
- */
330
- #view = new VGeoCutView();
331
-
332
- /**
333
- * @type {VGeoReadOptions}
334
- */
335
- #read_options = new VGeoReadOptions();
336
-
337
- /**
338
- * Whether `?head=` named a prefix, in which case nothing here overrides it.
339
- * @type {boolean}
340
- */
341
- #head_pinned = false;
342
-
343
- /**
344
- * @type {DynamicMeshBatch}
345
- */
346
- #batch = new DynamicMeshBatch();
347
-
348
- /**
349
- * @type {DynamicMesh|undefined}
350
- */
351
- #mesh = undefined;
352
-
353
- /**
354
- * A cut is a solid surface, so it is drawn as one: opaque, writing depth, and ordered by the
355
- * depth buffer rather than by anything this file does.
356
- *
357
- * @type {GPUDynamicMeshRenderer}
358
- */
359
- #dynamic = new GPUDynamicMeshRenderer();
360
-
361
- /**
362
- * Where the camera stood when the current cut was taken, so the panel can say how far you have
363
- * wandered from the decision you are looking at.
364
- * @type {Float32Array}
365
- */
366
- #cut_eye = new Float32Array(3);
367
-
368
- /**
369
- * @type {Float32Array}
370
- */
371
- #eye = new Float32Array(3);
372
-
373
- /**
374
- * @type {boolean}
375
- */
376
- #auto_adapt = false;
377
-
378
- /**
379
- * Whether a clamped cut chases its own wants until there are none left.
380
- * @type {boolean}
381
- */
382
- #auto_stream = true;
383
-
384
- /**
385
- * One streaming loop at a time — the loop retakes the cut between rounds, and two of them would
386
- * be fetching against each other's want lists.
387
- * @type {boolean}
388
- */
389
- #streaming = false;
390
-
391
- /**
392
- * @type {VGEO_COLOR_MODE}
393
- */
394
- #color_mode = VGEO_COLOR_MODE.Cluster;
395
-
396
- /**
397
- * @type {string}
398
- */
399
- #status = 'drop a .vgeo file anywhere on the page';
400
-
401
- /**
402
- * @type {string}
403
- */
404
- #file_label = '';
405
-
406
- /**
407
- * @type {number}
408
- */
409
- #open_ms = 0;
410
-
411
- /**
412
- * Bytes the source had served by the time the container was open — the cold start, measured.
413
- * @type {number}
414
- */
415
- #open_bytes = 0;
416
-
417
- /**
418
- * @type {number}
419
- */
420
- #build_ms = 0;
421
-
422
- /**
423
- * What the last {@link VGeoContainerReader.validate} came to, or `undefined` while it has never
424
- * been asked for — which is the default and the ordinary state.
425
- * @type {VGeoDefect[]|undefined}
426
- */
427
- #defects = undefined;
428
-
429
- /**
430
- * @type {string}
431
- */
432
- #validation_status = 'not run';
433
-
434
- constructor() {
435
- this.canvas = document.createElement('canvas');
436
- this.renderer = new Renderer();
437
- this.camera = new PerspectiveCamera();
438
- this.scene = new Scene();
439
-
440
- // the sun stands at an entity, so the scene names a dataset for it
441
- this.scene.dataset = new EntityComponentDataset();
442
-
443
- this.#dynamic.opaque = true;
444
- }
445
-
446
- /**
447
- * @returns {VGeoContainerReader|undefined}
448
- */
449
- get reader() {
450
- return this.#reader;
451
- }
452
-
453
- /**
454
- * @returns {VGeoCut}
455
- */
456
- get cut() {
457
- return this.#cut;
458
- }
459
-
460
- /**
461
- * Whether a clamped cut chases its own wants until there are none left.
462
- *
463
- * Setting it does not start a run — a caller that wants one calls {@link stream} and holds the
464
- * promise, which is what a scripted session needs in order to wait for the end of it.
465
- *
466
- * @param {boolean} value
467
- */
468
- set_auto_stream(value) {
469
- this.#auto_stream = value;
470
- }
471
-
472
- /**
473
- * @returns {Promise<void>}
474
- */
475
- async start() {
476
- document.body.style.margin = '0';
477
- document.body.style.overflow = 'hidden';
478
- document.body.style.background = '#070b10';
479
-
480
- this.canvas.style.position = 'absolute';
481
- this.canvas.style.inset = '0';
482
- this.canvas.style.outline = 'none';
483
-
484
- // the orbital controller attaches a KeyboardDevice, and a canvas cannot receive key events
485
- // without being focusable
486
- this.canvas.tabIndex = 0;
487
-
488
- document.body.appendChild(this.canvas);
489
-
490
- this.canvas.focus();
491
-
492
- await this.renderer.initialize({ context: this.canvas.getContext('webgpu') });
493
-
494
- /*
495
- Everything that would move the image for reasons unrelated to the cut is off. Automatic
496
- exposure in particular: it adapts to whatever is on screen, so the same cluster would read a
497
- different colour depending on how much of the model is in frame, which is exactly the signal
498
- this tool is trying to show.
499
- */
500
- this.renderer.feature_automatic_exposure_enabled = false;
501
- this.renderer.feature_taa_enabled = true;
502
- this.renderer.feature_bloom_enabled = false;
503
- this.renderer.feature_ssr_enabled = false;
504
- this.renderer.feature_ssao_enabled = true;
505
- this.renderer.feature_shadows_enabled = false;
506
- this.renderer.feature_lpv_enabled = false;
507
- this.renderer.pixel_ratio = 1;
508
-
509
- place_light(this.scene, make_sunlight({ intensity: 3 }));
510
-
511
- this.camera.near = 0.05;
512
- this.camera.far = 500;
513
- this.camera.fov = 55 * DEG_TO_RAD;
514
- this.camera.transform.setTranslation(0, 0.5, 2);
515
- this.camera.transform.lookAt(Vector3.zero);
516
-
517
- this.controller = new OrbitalCameraController(this.camera, this.canvas);
518
- this.controller.distanceLimits.min = 1e-4;
519
- this.controller.distanceLimits.max = 1e5;
520
-
521
- this.#build_interface();
522
- this.#fit_to_window();
523
-
524
- window.addEventListener('resize', () => this.#fit_to_window());
525
-
526
- this.renderer.add_extension(new VGEOViewerExtension(this));
527
-
528
- create_frame_loop((dt) => this.#frame(dt));
529
-
530
- const query = new URL(window.location.href).searchParams;
531
-
532
- const head = query.get('head');
533
-
534
- if (head !== null) {
535
- this.#read_options.head_prefix_bytes = Number(head);
536
- this.#head_pinned = true;
537
- }
538
-
539
- this.#read_options.validate = query.get('validate') !== null;
540
- this.#read_options.verify_frames = query.get('verify') !== null;
541
-
542
- const requested = query.get('file');
543
-
544
- if (requested !== null) {
545
- await this.load_url(requested);
546
- } else if (query.get('sample') !== null) {
547
- await this.open_sample();
548
- }
549
- }
550
-
551
- /**
552
- * @param {FrameContext} frame
553
- */
554
- record(frame) {
555
- const graph = frame.graph;
556
- const scene = frame.get(SceneColor);
557
-
558
- scene.color = this.#dynamic.graph_draw({
559
- graph,
560
- batch: this.#batch,
561
- color: scene.color,
562
- depth: vgeo_graph_clear_depth(graph, frame.get(ViewTextures).depth),
563
- camera: frame.view.camera.buffer,
564
- });
565
- }
566
-
567
- #fit_to_window() {
568
- const width = window.innerWidth;
569
- const height = window.innerHeight;
570
-
571
- this.canvas.width = width;
572
- this.canvas.height = height;
573
-
574
- this.renderer.resize(width, height);
575
-
576
- this.camera.aspect = this.renderer.aspect_ratio;
577
-
578
- this.#view.screen_height = height;
579
- this.#view.fov_y = this.camera.fov;
580
- }
581
-
582
- /**
583
- * @param {number} dt seconds
584
- */
585
- #frame(dt) {
586
- this.controller.update(dt);
587
-
588
- const position = this.camera.transform;
589
-
590
- const moved = position.translation_x !== this.#eye[0]
591
- || position.translation_y !== this.#eye[1]
592
- || position.translation_z !== this.#eye[2];
593
-
594
- this.#eye[0] = position.translation_x;
595
- this.#eye[1] = position.translation_y;
596
- this.#eye[2] = position.translation_z;
597
-
598
- if (moved && this.#auto_adapt) {
599
- this.adapt();
600
- }
601
-
602
- this.renderer.render(this.camera, this.scene, dt);
603
-
604
- if (moved) {
605
- this.#refresh_cut();
606
- }
607
- }
608
-
609
- /**
610
- * Re-render the cut readout alone.
611
- *
612
- * Every number under it moves as the camera does — the drift on every frame, and the whole lot on
613
- * every adapt when `follow the camera` is on. Rebuilding the *whole* panel at that rate would
614
- * also rebuild the controls, which is how a slider stops being draggable mid-drag; this section
615
- * holds no controls, so replacing it is free of that.
616
- */
617
- #refresh_cut() {
618
- const host = this.panel.querySelector('#vgeo-cut');
619
-
620
- if (host === null) {
621
- return;
622
- }
623
-
624
- host.innerHTML = this.#cut_html();
625
- }
626
-
627
- /**
628
- * The cut readout — the cluster count first, because it is the number the tool exists to show,
629
- * and the clamp count second, because it is the one that says the picture is still arriving.
630
- *
631
- * @returns {string}
632
- */
633
- #cut_html() {
634
- const cut = this.#cut;
635
-
636
- const clamped = cut.clamped === 0
637
- ? `<span class="good">0 — this is the cut the file selects</span>`
638
- : `<span class="warn">${thousands(cut.clamped)} waiting on ${cut.wants.length} page(s)</span>`;
639
-
640
- const rows = [
641
- ['triangles', thousands(cut.triangle_count)],
642
- ['clamped', clamped],
643
- ['groups', thousands(cut.groups_visited)],
644
- ['pages read', thousands(cut.pages_touched)],
645
- ['clusters tested', thousands(cut.clusters_tested)],
646
- ['culled subtrees', thousands(cut.culled)],
647
- ['select / build', `${cut.duration_ms.toFixed(1)} / ${this.#build_ms.toFixed(1)} ms`],
648
- ['camera drift', `${this.#drift().toExponential(2)} u`],
649
- ];
650
-
651
- /*
652
- A clamp whose child page is already resident is waiting on a page holding one of that
653
- group's *other* parents (§10, activation) — so it is not counted by any want, and without
654
- this row the panel reads as `20 waiting on 5 page(s)` while five pages would not have
655
- settled all twenty. Only shown when it happens, which on a small asset is never.
656
- */
657
- if (cut.clamped_on_activation > 0) {
658
- rows.push([
659
- 'of those, on a parent',
660
- `<span class="warn">${thousands(cut.clamped_on_activation)}</span>`
661
- ]);
662
- }
663
-
664
- if (cut.broken_child_refs > 0) {
665
- rows.push(['broken child refs', `<span class="bad">${thousands(cut.broken_child_refs)}</span>`]);
666
- }
667
-
668
- return `<div class="count">${thousands(cut.clusters.length)}</div>`
669
- + `<div class="muted" style="margin-bottom:6px">clusters in the current cut</div>`
670
- + panel_table(rows);
671
- }
672
-
673
- /**
674
- * How far the camera has moved since the cut on screen was selected.
675
- * @returns {number}
676
- */
677
- #drift() {
678
- return Math.hypot(
679
- this.#eye[0] - this.#cut_eye[0],
680
- this.#eye[1] - this.#cut_eye[1],
681
- this.#eye[2] - this.#cut_eye[2]
682
- );
683
- }
684
-
685
- /**
686
- * Take a fresh cut at wherever the camera is standing, from whatever the reader currently holds,
687
- * and build the geometry for it.
688
- */
689
- adapt() {
690
- if (this.#reader === undefined) {
691
- return;
692
- }
693
-
694
- // the frustum is derived from matrices the renderer refreshes during its own frame, and an
695
- // adapt can land before one has run — a cut culled against last frame's planes would be a
696
- // silent, hard-to-see wrong answer
697
- this.camera.update();
698
-
699
- this.#view.eye.set(this.#eye);
700
- this.#view.screen_height = this.canvas.height;
701
- this.#view.fov_y = this.camera.fov;
702
- this.#view.frustum.set(this.camera.frustum);
703
-
704
- this.#cut = vgeo_select_cut(this.#reader, this.#view);
705
-
706
- const started = performance.now();
707
-
708
- const previous = this.#cut_geometry;
709
-
710
- this.#cut_geometry = vgeo_build_cut_geometry(this.#cut, this.#color_mode);
711
-
712
- this.#build_ms = performance.now() - started;
713
-
714
- this.#batch.clear();
715
-
716
- // Residency is keyed on the geometry and deliberately survives leaving the batch, so the cut
717
- // that was just replaced would hold its buffers forever otherwise — and this tool replaces
718
- // one on every drag of the tau slider.
719
- if (previous !== undefined) {
720
- this.#dynamic.release(previous.geometry);
721
- }
722
-
723
- this.#mesh = DynamicMesh.from(this.#cut_geometry.geometry);
724
-
725
- this.#batch.add(this.#mesh);
726
-
727
- this.#cut_eye.set(this.#eye);
728
- }
729
-
730
- /**
731
- * Fetch the pages the current cut is clamped against, a batch at a time, retaking the cut after
732
- * each — until nothing is clamped, or the loop is turned off, or a round installs nothing.
733
- *
734
- * Note what is *not* here: any handling for the cut being wrong in the meantime. It is not. Every
735
- * intermediate cut this loop draws is a complete watertight surface at some level of detail, so
736
- * there is nothing to hide while it converges and nothing to reconcile when it does.
737
- *
738
- * @returns {Promise<void>}
739
- */
740
- async stream() {
741
- if (this.#streaming || this.#reader === undefined) {
742
- return;
743
- }
744
-
745
- this.#streaming = true;
746
-
747
- try {
748
- while (this.#cut.wants.length > 0) {
749
- const before = this.#reader.resident_page_count;
750
-
751
- this.#status = `fetching ${Math.min(this.#cut.wants.length, STREAM_BATCH)}`
752
- + ` of ${this.#cut.wants.length} wanted page(s)`;
753
-
754
- this.#refresh_panel();
755
-
756
- await this.#reader.install_wants(this.#cut.wants, STREAM_BATCH);
757
-
758
- // A round that installed nothing means every want is unfetchable, and continuing
759
- // would be a spin against the same list forever.
760
- if (this.#reader.resident_page_count === before) {
761
- this.#status = 'the wanted pages could not be installed';
762
- break;
763
- }
764
-
765
- this.#status = '';
766
-
767
- this.adapt();
768
- this.#refresh_panel();
769
-
770
- if (!this.#auto_stream) {
771
- break;
772
- }
773
- }
774
- } catch (e) {
775
- this.#status = String(e.message ?? e);
776
-
777
- throw e;
778
- } finally {
779
- this.#streaming = false;
780
- this.#refresh_panel();
781
- }
782
- }
783
-
784
- /**
785
- * Open a container over a byte source, and take the first cut.
786
- *
787
- * @param {VGeoByteSource} source
788
- * @returns {Promise<void>}
789
- */
790
- async open(source) {
791
- this.#source = source;
792
- this.#file_label = source.name;
793
- this.#defects = undefined;
794
- this.#validation_status = 'not run';
795
- this.#status = `opening ${source.name}`;
796
-
797
- source.reset_counters();
798
-
799
- this.#refresh_panel();
800
-
801
- const started = performance.now();
802
-
803
- try {
804
- this.#reader = await VGeoContainerReader.open(source, this.#read_options);
805
- } catch (e) {
806
- this.#reader = undefined;
807
- this.#cut = new VGeoCut();
808
- this.#cut_geometry = undefined;
809
- this.#batch.clear();
810
- this.#status = String(e.message ?? e);
811
- this.#refresh_panel();
812
-
813
- throw e;
814
- }
815
-
816
- this.#open_ms = performance.now() - started;
817
- this.#open_bytes = source.bytes_read;
818
- this.#status = '';
819
-
820
- this.#frame_camera();
821
- this.adapt();
822
- this.#refresh_panel();
823
-
824
- if (this.#auto_stream) {
825
- await this.stream();
826
- }
827
- }
828
-
829
- /**
830
- * @param {Blob} blob a dropped `File`
831
- * @returns {Promise<void>}
832
- */
833
- open_blob(blob) {
834
- return this.open(VGeoByteSource.from_blob(blob));
835
- }
836
-
837
- /**
838
- * Build a container in the page and open it, so there is something to look at without a file.
839
- *
840
- * The source is over bytes already in memory, which changes nothing above it: the reader still
841
- * opens on the head and installs a page at a time, and the panel's `read` still says what
842
- * fraction of the container this view actually cost.
843
- *
844
- * @returns {Promise<void>}
845
- */
846
- async open_sample() {
847
- this.#status = 'building a sample asset';
848
- this.#refresh_panel();
849
-
850
- // yielded so the status paints before the builder takes the thread for a second
851
- await new Promise((resolve) => setTimeout(resolve, 0));
852
-
853
- const sample = vgeo_sample_source();
854
-
855
- /*
856
- The default prefix is 64 KB, sized against a *default* build's pages of hundreds of KB. The
857
- sample's are 8 KB, so even that prefix would swallow much of it and there would be little
858
- left to stream — a demonstration of the head prefix rather than of the reader. Sized to the
859
- sample's own pages instead, unless the address bar has already made the choice.
860
- */
861
- if (!this.#head_pinned) {
862
- this.#read_options.head_prefix_bytes = 16 * 1024;
863
- }
864
-
865
- await this.open(sample.source);
866
-
867
- this.#status = `built in ${sample.build_ms.toFixed(0)} ms`;
868
- this.#refresh_panel();
869
- }
870
-
871
- /**
872
- * Open the current source again, from cold, under whatever the read options now say.
873
- *
874
- * Which is the point of it: the head prefix and frame verification are decisions taken at open
875
- * time, and comparing two of them means comparing two opens. Nothing is re-fetched that the
876
- * source would not have re-fetched anyway — a URL source really does go back to the network,
877
- * which is what makes the cold-start number honest.
878
- *
879
- * @returns {Promise<void>}
880
- */
881
- async reopen() {
882
- if (this.#source === undefined) {
883
- return;
884
- }
885
-
886
- await this.open(this.#source);
887
- }
888
-
889
- /**
890
- * @param {string} url
891
- * @returns {Promise<void>}
892
- */
893
- async load_url(url) {
894
- this.#status = `probing ${url}`;
895
- this.#refresh_panel();
896
-
897
- try {
898
- await this.open(await vgeo_fetch_byte_source(url));
899
- } catch (e) {
900
- this.#status = `${url} — ${e.message ?? e}`;
901
- this.#refresh_panel();
902
- }
903
- }
904
-
905
- /**
906
- * Run the whole-file audit, which is the one thing here that reads every byte.
907
- *
908
- * @returns {Promise<VGeoDefect[]>}
909
- */
910
- async validate() {
911
- if (this.#reader === undefined) {
912
- return [];
913
- }
914
-
915
- this.#validation_status = 'reading the whole file…';
916
- this.#refresh_panel();
917
-
918
- const started = performance.now();
919
-
920
- try {
921
- this.#defects = await vgeo_audit_container(this.#reader);
922
- } catch (e) {
923
- this.#defects = undefined;
924
- this.#validation_status = String(e.message ?? e);
925
- this.#refresh_panel();
926
-
927
- throw e;
928
- }
929
-
930
- this.#validation_status = `${(performance.now() - started).toFixed(0)} ms`;
931
- this.#refresh_panel();
932
-
933
- return this.#defects;
934
- }
935
-
936
- /**
937
- * Install every page the directory lists — the opposite of what this reader is for, and what a
938
- * question about the file rather than about a view of it wants.
939
- *
940
- * @returns {Promise<void>}
941
- */
942
- async load_all_pages() {
943
- if (this.#reader === undefined) {
944
- return;
945
- }
946
-
947
- this.#status = 'installing every page';
948
- this.#refresh_panel();
949
-
950
- try {
951
- await vgeo_install_all_pages(this.#reader, (done, total) => {
952
- this.#status = `installing every page — ${done} / ${total}`;
953
- });
954
-
955
- this.#status = '';
956
- } catch (e) {
957
- // A page that could not be read is quarantined rather than fatal now, and the tool
958
- // reports at the end rather than stopping at the first one — so every page that *could*
959
- // be installed is here, and the message says how many could not.
960
- this.#status = String(e.message ?? e);
961
- }
962
-
963
- this.adapt();
964
- this.#refresh_panel();
965
- }
966
-
967
- /**
968
- * Drop everything but the root page, so the file arrives again from cold.
969
- */
970
- reset_residency() {
971
- if (this.#reader === undefined) {
972
- return;
973
- }
974
-
975
- this.#reader.evict_all();
976
-
977
- this.adapt();
978
- this.#refresh_panel();
979
-
980
- if (this.#auto_stream) {
981
- this.stream();
982
- }
983
- }
984
-
985
- /**
986
- * Put the camera where the whole asset is on screen, and scale the clip range to it — vgeo
987
- * assets are authored at whatever scale the source used, and the Stanford models are a tenth of a
988
- * unit across.
989
- */
990
- #frame_camera() {
991
- const sphere = this.#reader.header.object_sphere;
992
-
993
- const radius = Math.max(sphere[3], 1e-6);
994
- const center = new Vector3(sphere[0], sphere[1], sphere[2]);
995
-
996
- const distance = radius / Math.tan(this.camera.fov * 0.5) * 1.15;
997
-
998
- const eye = new Vector3(0.55, 0.42, 0.72);
999
-
1000
- eye.normalize();
1001
- eye.multiplyScalar(distance);
1002
- eye.add(center);
1003
-
1004
- this.camera.near = radius * 0.005;
1005
- this.camera.far = radius * 200;
1006
-
1007
- this.controller.distanceLimits.min = radius * 0.02;
1008
- this.controller.distanceLimits.max = radius * 200;
1009
- this.controller.movement_speed_scale = radius;
1010
-
1011
- this.controller.look(eye, center);
1012
-
1013
- this.#eye[0] = eye.x;
1014
- this.#eye[1] = eye.y;
1015
- this.#eye[2] = eye.z;
1016
- }
1017
-
1018
- #build_interface() {
1019
- const drop = document.getElementById('vgeo-drop');
1020
-
1021
- let drag_depth = 0;
1022
-
1023
- window.addEventListener('dragenter', (event) => {
1024
- event.preventDefault();
1025
- drag_depth++;
1026
- drop.classList.add('active');
1027
- });
1028
-
1029
- window.addEventListener('dragover', (event) => event.preventDefault());
1030
-
1031
- window.addEventListener('dragleave', () => {
1032
- drag_depth = Math.max(0, drag_depth - 1);
1033
-
1034
- if (drag_depth === 0) {
1035
- drop.classList.remove('active');
1036
- }
1037
- });
1038
-
1039
- window.addEventListener('drop', async (event) => {
1040
- event.preventDefault();
1041
-
1042
- drag_depth = 0;
1043
- drop.classList.remove('active');
1044
-
1045
- const file = event.dataTransfer.files[0];
1046
-
1047
- if (file === undefined) {
1048
- return;
1049
- }
1050
-
1051
- await this.open_blob(file);
1052
- });
1053
-
1054
- this.panel = document.getElementById('vgeo-panel');
1055
-
1056
- this.#refresh_panel();
1057
- }
1058
-
1059
- /**
1060
- * @param {string} id
1061
- * @param {function(HTMLElement): void} bind
1062
- */
1063
- #wire(id, bind) {
1064
- const element = this.panel.querySelector(`#${id}`);
1065
-
1066
- if (element !== null) {
1067
- bind(element);
1068
- }
1069
- }
1070
-
1071
- /**
1072
- * The container section: what the header said, and what has actually been read.
1073
- *
1074
- * The second half is the point of the whole exercise. `read` against `file` is the fraction of
1075
- * the asset this view cost, and on anything larger than a toy it is a small one.
1076
- *
1077
- * @returns {string}
1078
- */
1079
- #container_html() {
1080
- const reader = this.#reader;
1081
- const header = reader.header;
1082
- const source = reader.source;
1083
-
1084
- const summary = page_summary(reader);
1085
-
1086
- /*
1087
- Cumulative for the session, and deliberately allowed past the file's own size: evicting and
1088
- re-streaming really does fetch those pages again, and the audit really does read every byte.
1089
- Rendered as a multiple rather than a percentage once it passes one, because "151.8%" reads
1090
- as a broken counter and "1.52× the file" reads as what it is.
1091
- */
1092
- const read_share = source.byte_length === 0
1093
- ? ''
1094
- : source.bytes_read < source.byte_length
1095
- ? ` (${(100 * source.bytes_read / source.byte_length).toFixed(1)}% of the file)`
1096
- : ` (${(source.bytes_read / source.byte_length).toFixed(2)}× the file)`;
1097
-
1098
- return panel_table([
1099
- ['file', `${escape_html(this.#file_label)} · ${human_bytes(source.byte_length)}`],
1100
- ['format', `v${header.format_version} · encoding ${header.payload_encoding}`],
1101
- ['asset id', header.asset_id.slice(0, 16)],
1102
- ['source', `${thousands(header.source_face_count)} tris / ${thousands(header.source_vertex_count)} verts`],
1103
- ['contents', `${thousands(header.total_clusters)} clusters · ${thousands(header.total_pages)} pages · ${header.levels.length} levels`],
1104
- ])
1105
- + `<h2>streaming</h2>`
1106
- + panel_table([
1107
- ['read so far', `${human_bytes(source.bytes_read)}${read_share}`],
1108
- ['requests', thousands(source.request_count)],
1109
- ['cold start', `${human_bytes(this.#open_bytes)} · ${this.#open_ms.toFixed(1)} ms`],
1110
- ['resident', `${thousands(reader.resident_page_count)} / ${thousands(header.total_pages)} pages · ${human_bytes(reader.resident_bytes)}`],
1111
- ['page storage', summary.storage],
1112
- ['per-vertex normals', summary.normals],
1113
- ['head prefix', reader.head_bytes === 0 ? 'released' : human_bytes(reader.head_bytes)],
1114
- ['quarantined', quarantine_summary(reader)],
1115
- ]);
1116
- }
1117
-
1118
-
1119
- /**
1120
- * @returns {string}
1121
- */
1122
- #validation_html() {
1123
- const defects = this.#defects;
1124
-
1125
- const note = `<div class="muted" style="margin-bottom:4px">`
1126
- + `off by default — it reads the whole file</div>`;
1127
-
1128
- if (defects === undefined) {
1129
- return note
1130
- + `<div class="muted">${escape_html(this.#validation_status)}</div>`
1131
- + `<button id="vgeo-validate">validate the whole file</button>`;
1132
- }
1133
-
1134
- const verdict = defects.length === 0
1135
- ? `<div class="good">container valid — every invariant holds</div>`
1136
- : `<div class="bad">${defects.length} defect(s)</div><ol class="bad">${
1137
- defects.slice(0, 12).map((d) => `<li>${escape_html(d.toString())}</li>`).join('')
1138
- }</ol>`;
1139
-
1140
- return note
1141
- + verdict
1142
- + `<div class="row"><span class="muted">took</span><span>${escape_html(this.#validation_status)}</span></div>`
1143
- + `<button id="vgeo-validate">validate again</button>`;
1144
- }
1145
-
1146
- #refresh_panel() {
1147
- const reader = this.#reader;
1148
-
1149
- const header = [`<h1>.vgeo viewer</h1>`];
1150
-
1151
- if (this.#status !== '') {
1152
- header.push(`<div class="muted">${escape_html(this.#status)}</div>`);
1153
- }
1154
-
1155
- if (reader === undefined) {
1156
- this.panel.innerHTML = header.join('')
1157
- + `<div class="muted" style="margin-top:8px">`
1158
- + `or open <code>?file=/some/asset.vgeo</code></div>`
1159
- + `<button id="vgeo-sample">build a sample asset</button>`;
1160
-
1161
- this.#wire('vgeo-sample', (element) => {
1162
- element.onclick = () => this.open_sample();
1163
- });
1164
-
1165
- return;
1166
- }
1167
-
1168
- this.panel.innerHTML = header.join('')
1169
- + `<h2>container</h2>${this.#container_html()}`
1170
- + `<button id="vgeo-stream" ${this.#cut.wants.length === 0 ? 'disabled' : ''}>`
1171
- + `stream ${this.#cut.wants.length} wanted page(s)</button>`
1172
- + `<label><input id="vgeo-auto-stream" type="checkbox" ${this.#auto_stream ? 'checked' : ''}> stream until nothing is clamped</label>`
1173
- + `<label><input id="vgeo-verify" type="checkbox" ${this.#read_options.verify_frames ? 'checked' : ''}> verify each frame's checksum</label>`
1174
- + `<button id="vgeo-load-all">install every page</button>`
1175
- + `<button id="vgeo-evict">evict everything but the root</button>`
1176
- + `<div class="row" style="margin-top:8px"><span class="muted">head prefix</span>`
1177
- + `<span class="muted">re-opens from cold</span></div>`
1178
- + `<select id="vgeo-head">`
1179
- + HEAD_PREFIXES.map(([label, size]) =>
1180
- `<option value="${size}" ${size === this.#read_options.head_prefix_bytes ? 'selected' : ''}>${label}</option>`
1181
- ).join('')
1182
- + `</select>`
1183
- + `<h2>cut</h2>`
1184
- + `<div id="vgeo-cut">${this.#cut_html()}</div>`
1185
- + `<h2>selection</h2>`
1186
- + `<div class="row"><span class="muted">tau</span><span id="vgeo-tau-value">${this.#view.tau.toFixed(2)} px</span></div>`
1187
- + `<input id="vgeo-tau" type="range" min="-1.3" max="1.7" step="0.01" value="${Math.log10(this.#view.tau)}">`
1188
- + `<button id="vgeo-adapt">adapt to view</button>`
1189
- + `<label><input id="vgeo-auto" type="checkbox" ${this.#auto_adapt ? 'checked' : ''}> follow the camera</label>`
1190
- + `<label><input id="vgeo-cull" type="checkbox" ${this.#view.cull_enabled ? 'checked' : ''}> frustum cull while selecting</label>`
1191
- + `<h2>display</h2>`
1192
- + `<select id="vgeo-color">`
1193
- + Object.values(VGEO_COLOR_MODE).map((mode) =>
1194
- `<option value="${mode}" ${mode === this.#color_mode ? 'selected' : ''}>colour by ${mode}</option>`
1195
- ).join('')
1196
- + `</select>`
1197
- + `<h2>validation</h2>${this.#validation_html()}`;
1198
-
1199
- this.#wire('vgeo-adapt', (element) => {
1200
- element.onclick = () => {
1201
- this.adapt();
1202
- this.#refresh_panel();
1203
- };
1204
- });
1205
-
1206
- this.#wire('vgeo-stream', (element) => {
1207
- element.onclick = () => this.stream();
1208
- });
1209
-
1210
- this.#wire('vgeo-auto-stream', (element) => {
1211
- element.onchange = () => {
1212
- this.set_auto_stream(element.checked);
1213
-
1214
- if (element.checked) {
1215
- this.stream();
1216
- }
1217
- };
1218
- });
1219
-
1220
- this.#wire('vgeo-verify', (element) => {
1221
- // read per fetch, so this takes effect on the next page rather than on a reopen
1222
- element.onchange = () => {
1223
- this.#read_options.verify_frames = element.checked;
1224
- };
1225
- });
1226
-
1227
- this.#wire('vgeo-head', (element) => {
1228
- element.onchange = () => {
1229
- this.#read_options.head_prefix_bytes = Number(element.value);
1230
-
1231
- this.reopen();
1232
- };
1233
- });
1234
-
1235
- this.#wire('vgeo-load-all', (element) => {
1236
- element.onclick = () => this.load_all_pages();
1237
- });
1238
-
1239
- this.#wire('vgeo-evict', (element) => {
1240
- element.onclick = () => this.reset_residency();
1241
- });
1242
-
1243
- this.#wire('vgeo-validate', (element) => {
1244
- element.onclick = () => this.validate();
1245
- });
1246
-
1247
- this.#wire('vgeo-tau', (element) => {
1248
- element.oninput = () => {
1249
- this.#view.tau = Math.pow(10, Number(element.value));
1250
-
1251
- this.adapt();
1252
- this.#refresh_panel();
1253
-
1254
- if (this.#auto_stream) {
1255
- this.stream();
1256
- }
1257
- };
1258
- });
1259
-
1260
- this.#wire('vgeo-auto', (element) => {
1261
- element.onchange = () => {
1262
- this.#auto_adapt = element.checked;
1263
- };
1264
- });
1265
-
1266
- this.#wire('vgeo-cull', (element) => {
1267
- element.onchange = () => {
1268
- this.#view.cull_enabled = element.checked;
1269
-
1270
- this.adapt();
1271
- this.#refresh_panel();
1272
- };
1273
- });
1274
-
1275
- this.#wire('vgeo-color', (element) => {
1276
- element.onchange = () => {
1277
- this.#color_mode = element.value;
1278
-
1279
- this.adapt();
1280
- this.#refresh_panel();
1281
- };
1282
- });
1283
- }
1284
- }
1285
-
1286
- const viewer = new VGeoViewer();
1287
-
1288
- /*
1289
- Everything a session might want to reach for, and the handles a scripted one needs. A page that can
1290
- be driven from the console is one that can be driven from a headless browser, which is what makes
1291
- this verifiable without a person watching it.
1292
- */
1293
- Object.assign(globalThis, {
1294
- __vgeo: viewer,
1295
-
1296
- __open_url: (url) => viewer.load_url(url),
1297
- __open_sample: () => viewer.open_sample().then(__state),
1298
- __adapt: () => {
1299
- viewer.adapt();
1300
-
1301
- return __state();
1302
- },
1303
- __stream: () => viewer.stream().then(__state),
1304
- __validate: () => viewer.validate().then((defects) => defects.map(String)),
1305
- __state,
1306
- });
1307
-
1308
- /**
1309
- * Everything a scripted session asks about, in one object.
1310
- *
1311
- * @returns {object}
1312
- */
1313
- function __state() {
1314
- const reader = viewer.reader;
1315
- const cut = viewer.cut;
1316
-
1317
- return {
1318
- open: reader !== undefined,
1319
- asset_id: reader?.header.asset_id,
1320
- total_pages: reader?.header.total_pages,
1321
- total_clusters: reader?.header.total_clusters,
1322
- resident_pages: reader?.resident_page_count ?? 0,
1323
- resident_bytes: reader?.resident_bytes ?? 0,
1324
- head_bytes: reader?.head_bytes ?? 0,
1325
- quarantined_pages: reader?.quarantined_page_count ?? 0,
1326
- file_bytes: reader?.source.byte_length ?? 0,
1327
- bytes_read: reader?.source.bytes_read ?? 0,
1328
- requests: reader?.source.request_count ?? 0,
1329
- clusters: cut.clusters.length,
1330
- triangles: cut.triangle_count,
1331
- clamped: cut.clamped,
1332
- clamped_on_activation: cut.clamped_on_activation,
1333
- wants: cut.wants.length,
1334
- broken_child_refs: cut.broken_child_refs,
1335
- };
1336
- }
1337
-
1338
- viewer.start().catch((e) => {
1339
- console.error(e);
1340
-
1341
- document.getElementById('vgeo-panel').innerHTML =
1342
- `<h1>.vgeo viewer</h1><div class="bad">${e.message ?? e}</div>`;
1343
- });