@woosh/meep-engine 3.22.0 → 3.23.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 (267) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +118 -0
  3. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -0
  4. package/src/core/geom/3d/hash-grid/PointHashGrid3.js +283 -0
  5. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/BoxShape3D.js +6 -17
  7. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/CapsuleShape3D.js +3 -14
  9. package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/CylinderShape3D.js +3 -21
  11. package/src/core/geom/3d/shape/PlaneShape3D.d.ts +105 -0
  12. package/src/core/geom/3d/shape/PlaneShape3D.d.ts.map +1 -0
  13. package/src/core/geom/3d/shape/PlaneShape3D.js +251 -0
  14. package/src/core/geom/3d/shape/SphereShape3D.js +3 -3
  15. package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
  16. package/src/core/geom/3d/shape/json/shape_to_type.js +3 -0
  17. package/src/core/geom/3d/shape/json/type_adapters.d.ts +14 -0
  18. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/json/type_adapters.js +15 -0
  20. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +51 -0
  21. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -0
  22. package/src/core/geom/3d/shape/sdf/sdf3_box.js +113 -0
  23. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +46 -0
  24. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -0
  25. package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +82 -0
  26. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +60 -0
  27. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -0
  28. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +126 -0
  29. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts +50 -0
  30. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts.map +1 -0
  31. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.js +53 -0
  32. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +52 -0
  33. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -0
  34. package/src/core/geom/3d/shape/sdf/sdf3_plane.js +61 -0
  35. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +41 -0
  36. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -0
  37. package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +71 -0
  38. package/src/core/process/ConcurrencyGate.d.ts +103 -0
  39. package/src/core/process/ConcurrencyGate.d.ts.map +1 -0
  40. package/src/core/process/ConcurrencyGate.js +207 -0
  41. package/src/engine/asset/AssetManager.d.ts +10 -0
  42. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  43. package/src/engine/asset/AssetManager.js +10 -0
  44. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +30 -13
  45. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +26 -0
  46. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -0
  47. package/src/engine/graphics3/pose/collect_entity_playbacks.js +40 -0
  48. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  49. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +74 -101
  50. package/src/engine/physics/cloth/MEASUREMENTS.md +1287 -4
  51. package/src/engine/physics/cloth/PLAN.md +1967 -1581
  52. package/src/engine/physics/cloth/build/ClothProxy.d.ts +147 -0
  53. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -0
  54. package/src/engine/physics/cloth/build/ClothProxy.js +207 -0
  55. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +70 -0
  56. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -0
  57. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +256 -0
  58. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +176 -0
  59. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +435 -0
  61. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts +12 -0
  62. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts.map +1 -0
  63. package/src/engine/physics/cloth/collider/ClothColliderKind.js +38 -0
  64. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts +120 -0
  65. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/collider/ClothColliderRecord.js +137 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +25 -0
  68. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -0
  69. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +190 -0
  70. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +44 -0
  71. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -0
  72. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +173 -0
  73. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +94 -0
  74. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +275 -0
  76. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts +126 -0
  77. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -0
  78. package/src/engine/physics/cloth/ecs/ClothCollider.js +199 -0
  79. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +9 -0
  80. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +32 -0
  82. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +114 -0
  83. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +243 -0
  85. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +66 -57
  86. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +109 -1
  87. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/ecs/ClothInstance.js +479 -363
  89. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +95 -0
  90. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -0
  91. package/src/engine/physics/cloth/ecs/ClothRig.js +140 -0
  92. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +30 -1
  93. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  94. package/src/engine/physics/cloth/ecs/ClothSystem.js +1021 -773
  95. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +90 -0
  96. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +374 -0
  98. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts +32 -3
  99. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.js +283 -254
  101. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +59 -0
  102. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +328 -0
  104. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +13 -0
  105. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +288 -0
  107. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +58 -0
  108. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +199 -0
  110. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +8 -63
  111. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  112. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +317 -645
  113. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +61 -0
  114. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  115. package/src/engine/physics/cloth/ecs/cloth_write_back.js +212 -449
  116. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +49 -0
  117. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -0
  118. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +115 -0
  119. package/src/engine/physics/cloth/playground/README.md +155 -1
  120. package/src/engine/physics/cloth/playground/collide.html +178 -0
  121. package/src/engine/physics/cloth/playground/collide_build.d.ts +95 -0
  122. package/src/engine/physics/cloth/playground/collide_build.d.ts.map +1 -0
  123. package/src/engine/physics/cloth/playground/collide_build.js +315 -0
  124. package/src/engine/physics/cloth/playground/collide_main.d.ts +2 -0
  125. package/src/engine/physics/cloth/playground/collide_main.d.ts.map +1 -0
  126. package/src/engine/physics/cloth/playground/collide_main.js +720 -0
  127. package/src/engine/physics/cloth/playground/garment.html +182 -0
  128. package/src/engine/physics/cloth/playground/garment_build.d.ts +78 -0
  129. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -0
  130. package/src/engine/physics/cloth/playground/garment_build.js +359 -0
  131. package/src/engine/physics/cloth/playground/garment_main.d.ts +2 -0
  132. package/src/engine/physics/cloth/playground/garment_main.d.ts.map +1 -0
  133. package/src/engine/physics/cloth/playground/garment_main.js +633 -0
  134. package/src/engine/physics/cloth/solver/ClothState.d.ts +208 -5
  135. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/ClothState.js +302 -8
  137. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +87 -0
  138. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_contact_find.js +343 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +112 -0
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -0
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +448 -0
  143. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts +4 -1
  144. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +16 -1
  146. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +112 -5
  147. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +117 -6
  149. package/src/engine/physics/cloth/solver/cloth_step.d.ts +40 -9
  150. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step.js +122 -10
  152. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +95 -0
  153. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -0
  154. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +285 -0
  155. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +129 -0
  156. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -0
  157. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +501 -0
  158. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +75 -0
  159. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -0
  160. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +202 -0
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/shade/playground/vgeo_viewer/README.md +18 -0
  163. package/src/shade/playground/vgeo_viewer/main.js +87 -50
  164. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  165. package/src/shade/renderer/buffer/table/GPUDatabase.js +191 -62
  166. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +94 -2
  167. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  168. package/src/shade/renderer/buffer/table/GPUTypedTable.js +414 -2
  169. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts +14 -0
  170. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts.map +1 -0
  171. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.js +13 -0
  172. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts +17 -0
  173. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts.map +1 -0
  174. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.js +116 -0
  175. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +9 -4
  176. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +843 -734
  178. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +12 -0
  179. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +13 -0
  181. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +17 -0
  182. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  183. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +185 -30
  184. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +17 -0
  185. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +141 -24
  186. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +204 -64
  187. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +110 -10
  188. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +19 -0
  189. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +19 -6
  190. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  191. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +26 -7
  192. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +173 -14
  193. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  194. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +458 -51
  195. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +49 -13
  196. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +52 -14
  198. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts +20 -0
  199. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts.map +1 -0
  200. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js +19 -0
  201. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts +27 -0
  202. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts.map +1 -0
  203. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js +48 -0
  204. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts +29 -0
  205. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts.map +1 -0
  206. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js +60 -0
  207. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +8 -1
  208. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +32 -2
  210. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +258 -0
  211. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +1 -0
  212. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +723 -0
  213. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +49 -0
  214. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +1 -0
  215. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +50 -0
  216. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  217. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  218. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts +3 -0
  219. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
  220. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +121 -21
  221. package/src/shade/renderer/texture/virtual/README.md +6 -4
  222. package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
  223. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +7 -0
  224. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.d.ts +3 -3
  225. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +3 -3
  226. package/src/engine/ecs/system/SystemExecutionPhase.d.ts +0 -9
  227. package/src/engine/ecs/system/SystemExecutionPhase.d.ts.map +0 -1
  228. package/src/engine/graphics/texture/virtual/NOTES.md +0 -128
  229. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts +0 -6
  230. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts.map +0 -1
  231. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.js +0 -5
  232. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts +0 -49
  233. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts.map +0 -1
  234. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.js +0 -264
  235. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts +0 -44
  236. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts.map +0 -1
  237. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.js +0 -228
  238. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts +0 -3
  239. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts.map +0 -1
  240. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.js +0 -73
  241. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts +0 -14
  242. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts.map +0 -1
  243. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.js +0 -85
  244. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts +0 -12
  245. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts.map +0 -1
  246. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.js +0 -63
  247. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts +0 -12
  248. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts.map +0 -1
  249. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.js +0 -243
  250. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts +0 -30
  251. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts.map +0 -1
  252. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.js +0 -39
  253. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts +0 -9
  254. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts.map +0 -1
  255. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.js +0 -24
  256. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts +0 -9
  257. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts.map +0 -1
  258. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.js +0 -26
  259. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts +0 -11
  260. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts.map +0 -1
  261. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.js +0 -12
  262. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts +0 -7
  263. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts.map +0 -1
  264. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.js +0 -16
  265. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts +0 -7
  266. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts.map +0 -1
  267. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.js +0 -35
@@ -15,9 +15,23 @@ export class VGeoReadOptions {
15
15
  * want anyway, so a prefix that overshoots the root frame has bought the next pages rather than
16
16
  * wasted a fetch.
17
17
  *
18
- * 256 KB is one nominal page plus the head, so it covers the root frame of a default build
19
- * whole. Set it to {@link VGEO_HEADER_SIZE} for the strict two-round-trip start, which is what a
20
- * reader measuring cold-start bytes wants.
18
+ * **How much overshoot is worth paying for is a measured number, and it is small.** The
19
+ * always-resident set of a real build is the header, the level table and a root page holding the
20
+ * complete topmost level — which build invariant §11.7 makes exactly one cluster. Measured on
21
+ * two torus builds (7.7K and 42K source triangles, 8 and 12 levels): the root page decoded to
22
+ * 1,732 B and 1,472 B, and the whole set came to about 2.4 KB. So a prefix is speculation about
23
+ * the *next* band, and at the hundreds-of-KB pages design §5 targets it buys one page. 64 KiB
24
+ * covers the always-resident set of any plausible asset in one request with room for that page;
25
+ * the 256 KiB this used to default to bought the same page and cost four times the transfer,
26
+ * which across a thousand open assets is 256 MB of it.
27
+ *
28
+ * Set it to {@link VGEO_HEADER_SIZE} for the strict two-round-trip start, which is what a reader
29
+ * measuring cold-start bytes wants — and what a runtime holding many assets at once should
30
+ * prefer, because the speculative page it gives up is one it can fetch when a cut asks for it.
31
+ *
32
+ * Whatever the prefix, the reader does not keep it for life: it is released the first time a
33
+ * read falls outside it, and {@link VGeoContainerReader.release_head} drops it on demand. See
34
+ * that method for why.
21
35
  *
22
36
  * @type {number}
23
37
  */
@@ -28,15 +42,13 @@ export class VGeoReadOptions {
28
42
  * **Off, and it is the right default.** {@link vgeo_validate_container} reads every byte of the
29
43
  * file — every frame, every checksum, the directory against a full frame scan — which is the
30
44
  * one thing an incremental reader exists to avoid, and it answers a question about the *writer*
31
- * rather than about the view being put on screen. Turning it on costs the whole file and the
32
- * whole audit, on a file that may be gigabytes.
33
- *
34
- * What is *not* optional, and does not live here: the reject rules of §4 and §10 that
35
- * {@link vgeo_read_header} and {@link vgeo_read_page} apply unconditionally — magic, reader
36
- * version, payload encoding, hash algorithm, unknown required feature bits, unknown codecs, and
37
- * a `decoded_size` outside what the stored bytes could produce. Those are not validation; they
38
- * are the difference between refusing a file and misreading it.
45
+ * rather than about the view being put on screen. Measured on a 514 MiB container: one 514 MiB
46
+ * range and 19.4 seconds, and it is a single `ArrayBuffer`, so a multi-GB asset does not run
47
+ * slowly — it fails.
39
48
  *
49
+ * @deprecated a runtime reader must not carry a switch that reads the whole file. Call
50
+ * {@link vgeo_audit_container} instead, which is a tool talking to a tool and says so, and
51
+ * which refuses a file too large to audit this way rather than trying.
40
52
  * @type {boolean}
41
53
  */
42
54
  validate: boolean;
@@ -50,19 +62,43 @@ export class VGeoReadOptions {
50
62
  * difference between a coarse stand-in and a wrong surface.
51
63
  *
52
64
  * Off by default here for the same reason {@link validate} is: hashing every installed byte is a
53
- * real cost, and a tool looking at a file it just built is not defending against the network.
65
+ * real cost, and a tool looking at a file it just built is not defending against the network. A
66
+ * reader fetching over HTTP should turn it on — it is what makes {@link fetch_retries} and the
67
+ * quarantine that follows them able to see corruption at all.
54
68
  *
55
69
  * @type {boolean}
56
70
  */
57
71
  verify_frames: boolean;
58
72
  /**
59
- * How many page fetches may be in flight at once.
73
+ * How many page fetches may be in flight at once, **per reader**.
60
74
  *
61
75
  * Enough to keep a connection busy, few enough that a traversal's whole want list does not
62
76
  * become one burst — the wants are ranked, and issuing them all at once discards the ranking.
63
77
  *
78
+ * This bounds one reader and nothing more: eight readers installing wants at this default were
79
+ * measured issuing 48 concurrent range requests, because nothing here knows about the other
80
+ * seven. A total across readers is a policy, and it lives in the `ConcurrencyGate` that
81
+ * `VGeoResidencyManager` puts in front of every reader registered with it.
82
+ *
64
83
  * @type {number}
65
84
  */
66
85
  max_concurrent_fetches: number;
86
+ /**
87
+ * How many times a failed page fetch is retried before the page is quarantined.
88
+ *
89
+ * §10: bounded retries with backoff, then quarantine — never a retry loop, because corruption at
90
+ * a content-addressed URL is deterministic. Two is the bound because the failures worth retrying
91
+ * are transient by definition: a dropped connection, a 503 from one edge node. A third attempt
92
+ * is answering the same question again.
93
+ *
94
+ * @type {number}
95
+ */
96
+ fetch_retries: number;
97
+ /**
98
+ * Milliseconds before the first retry; each further attempt doubles it.
99
+ *
100
+ * @type {number}
101
+ */
102
+ fetch_retry_backoff_ms: number;
67
103
  }
68
104
  //# sourceMappingURL=VGeoReadOptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VGeoReadOptions.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH;IACI;;;;;;;;;;;;;;;OAeG;IACH,mBAFU,MAAM,CAEe;IAE/B;;;;;;;;;;;;;;;;OAgBG;IACH,UAFU,OAAO,CAEA;IAEjB;;;;;;;;;;;;;OAaG;IACH,eAFU,OAAO,CAEK;IAEtB;;;;;;;OAOG;IACH,wBAFU,MAAM,CAEW;CAC9B"}
1
+ {"version":3,"file":"VGeoReadOptions.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH;IACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,mBAFU,MAAM,CAEc;IAE9B;;;;;;;;;;;;;;OAcG;IACH,UAFU,OAAO,CAEA;IAEjB;;;;;;;;;;;;;;;OAeG;IACH,eAFU,OAAO,CAEK;IAEtB;;;;;;;;;;;;OAYG;IACH,wBAFU,MAAM,CAEW;IAE3B;;;;;;;;;OASG;IACH,eAFU,MAAM,CAEE;IAElB;;;;OAIG;IACH,wBAFU,MAAM,CAEY;CAC/B"}
@@ -17,13 +17,27 @@ export class VGeoReadOptions {
17
17
  * want anyway, so a prefix that overshoots the root frame has bought the next pages rather than
18
18
  * wasted a fetch.
19
19
  *
20
- * 256 KB is one nominal page plus the head, so it covers the root frame of a default build
21
- * whole. Set it to {@link VGEO_HEADER_SIZE} for the strict two-round-trip start, which is what a
22
- * reader measuring cold-start bytes wants.
20
+ * **How much overshoot is worth paying for is a measured number, and it is small.** The
21
+ * always-resident set of a real build is the header, the level table and a root page holding the
22
+ * complete topmost level — which build invariant §11.7 makes exactly one cluster. Measured on
23
+ * two torus builds (7.7K and 42K source triangles, 8 and 12 levels): the root page decoded to
24
+ * 1,732 B and 1,472 B, and the whole set came to about 2.4 KB. So a prefix is speculation about
25
+ * the *next* band, and at the hundreds-of-KB pages design §5 targets it buys one page. 64 KiB
26
+ * covers the always-resident set of any plausible asset in one request with room for that page;
27
+ * the 256 KiB this used to default to bought the same page and cost four times the transfer,
28
+ * which across a thousand open assets is 256 MB of it.
29
+ *
30
+ * Set it to {@link VGEO_HEADER_SIZE} for the strict two-round-trip start, which is what a reader
31
+ * measuring cold-start bytes wants — and what a runtime holding many assets at once should
32
+ * prefer, because the speculative page it gives up is one it can fetch when a cut asks for it.
33
+ *
34
+ * Whatever the prefix, the reader does not keep it for life: it is released the first time a
35
+ * read falls outside it, and {@link VGeoContainerReader.release_head} drops it on demand. See
36
+ * that method for why.
23
37
  *
24
38
  * @type {number}
25
39
  */
26
- head_prefix_bytes = 256 * 1024;
40
+ head_prefix_bytes = 64 * 1024;
27
41
 
28
42
  /**
29
43
  * Whether to run the whole-file audit when the container is opened.
@@ -31,15 +45,13 @@ export class VGeoReadOptions {
31
45
  * **Off, and it is the right default.** {@link vgeo_validate_container} reads every byte of the
32
46
  * file — every frame, every checksum, the directory against a full frame scan — which is the
33
47
  * one thing an incremental reader exists to avoid, and it answers a question about the *writer*
34
- * rather than about the view being put on screen. Turning it on costs the whole file and the
35
- * whole audit, on a file that may be gigabytes.
36
- *
37
- * What is *not* optional, and does not live here: the reject rules of §4 and §10 that
38
- * {@link vgeo_read_header} and {@link vgeo_read_page} apply unconditionally — magic, reader
39
- * version, payload encoding, hash algorithm, unknown required feature bits, unknown codecs, and
40
- * a `decoded_size` outside what the stored bytes could produce. Those are not validation; they
41
- * are the difference between refusing a file and misreading it.
48
+ * rather than about the view being put on screen. Measured on a 514 MiB container: one 514 MiB
49
+ * range and 19.4 seconds, and it is a single `ArrayBuffer`, so a multi-GB asset does not run
50
+ * slowly — it fails.
42
51
  *
52
+ * @deprecated a runtime reader must not carry a switch that reads the whole file. Call
53
+ * {@link vgeo_audit_container} instead, which is a tool talking to a tool and says so, and
54
+ * which refuses a file too large to audit this way rather than trying.
43
55
  * @type {boolean}
44
56
  */
45
57
  validate = false;
@@ -54,19 +66,45 @@ export class VGeoReadOptions {
54
66
  * difference between a coarse stand-in and a wrong surface.
55
67
  *
56
68
  * Off by default here for the same reason {@link validate} is: hashing every installed byte is a
57
- * real cost, and a tool looking at a file it just built is not defending against the network.
69
+ * real cost, and a tool looking at a file it just built is not defending against the network. A
70
+ * reader fetching over HTTP should turn it on — it is what makes {@link fetch_retries} and the
71
+ * quarantine that follows them able to see corruption at all.
58
72
  *
59
73
  * @type {boolean}
60
74
  */
61
75
  verify_frames = false;
62
76
 
63
77
  /**
64
- * How many page fetches may be in flight at once.
78
+ * How many page fetches may be in flight at once, **per reader**.
65
79
  *
66
80
  * Enough to keep a connection busy, few enough that a traversal's whole want list does not
67
81
  * become one burst — the wants are ranked, and issuing them all at once discards the ranking.
68
82
  *
83
+ * This bounds one reader and nothing more: eight readers installing wants at this default were
84
+ * measured issuing 48 concurrent range requests, because nothing here knows about the other
85
+ * seven. A total across readers is a policy, and it lives in the `ConcurrencyGate` that
86
+ * `VGeoResidencyManager` puts in front of every reader registered with it.
87
+ *
69
88
  * @type {number}
70
89
  */
71
90
  max_concurrent_fetches = 6;
91
+
92
+ /**
93
+ * How many times a failed page fetch is retried before the page is quarantined.
94
+ *
95
+ * §10: bounded retries with backoff, then quarantine — never a retry loop, because corruption at
96
+ * a content-addressed URL is deterministic. Two is the bound because the failures worth retrying
97
+ * are transient by definition: a dropped connection, a 503 from one edge node. A third attempt
98
+ * is answering the same question again.
99
+ *
100
+ * @type {number}
101
+ */
102
+ fetch_retries = 2;
103
+
104
+ /**
105
+ * Milliseconds before the first retry; each further attempt doubles it.
106
+ *
107
+ * @type {number}
108
+ */
109
+ fetch_retry_backoff_ms = 50;
72
110
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The largest file {@link vgeo_audit_container} will read in one piece, in bytes.
3
+ *
4
+ * The audit takes the whole container as a single `ArrayBuffer`, because every invariant of
5
+ * `VGEO_FORMAT.md` §11 is a cross-check between two places in the file and a streaming audit would
6
+ * be a different program. That makes the size a hard question rather than a slow one: measured on a
7
+ * synthetic 514 MiB container the audit read 514 MiB in one range and took 19.4 seconds, and the
8
+ * next power of two up is where a browser tab stops being able to hold it at all.
9
+ *
10
+ * 1 GiB is therefore the line, and it is drawn here rather than left to the allocator so that the
11
+ * failure is a sentence naming the file's size instead of an out-of-memory several frames later. A
12
+ * caller with a reason — a build machine, a file it just wrote — passes its own limit.
13
+ *
14
+ * @type {number}
15
+ *
16
+ * @author Alex Goldring
17
+ * @copyright Company Named Limited (c) 2026
18
+ */
19
+ export const VGEO_MAX_AUDIT_BYTES: number;
20
+ //# sourceMappingURL=VGEO_MAX_AUDIT_BYTES.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VGEO_MAX_AUDIT_BYTES.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,mCALU,MAAM,CAKuC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The largest file {@link vgeo_audit_container} will read in one piece, in bytes.
3
+ *
4
+ * The audit takes the whole container as a single `ArrayBuffer`, because every invariant of
5
+ * `VGEO_FORMAT.md` §11 is a cross-check between two places in the file and a streaming audit would
6
+ * be a different program. That makes the size a hard question rather than a slow one: measured on a
7
+ * synthetic 514 MiB container the audit read 514 MiB in one range and took 19.4 seconds, and the
8
+ * next power of two up is where a browser tab stops being able to hold it at all.
9
+ *
10
+ * 1 GiB is therefore the line, and it is drawn here rather than left to the allocator so that the
11
+ * failure is a sentence naming the file's size instead of an out-of-memory several frames later. A
12
+ * caller with a reason — a build machine, a file it just wrote — passes its own limit.
13
+ *
14
+ * @type {number}
15
+ *
16
+ * @author Alex Goldring
17
+ * @copyright Company Named Limited (c) 2026
18
+ */
19
+ export const VGEO_MAX_AUDIT_BYTES = 1024 * 1024 * 1024;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The whole-file audit: every build invariant of `VGEO_FORMAT.md` §11, every checksum, and the
3
+ * directory against what a frame scan reconstructs.
4
+ *
5
+ * **This reads the entire file**, which is the one thing `VGeoContainerReader` exists to avoid, and
6
+ * that is why it lives here instead of on it. It answers a question about whoever *produced* the
7
+ * file; nothing about reading one depends on it having been asked, and a renderer holding a thousand
8
+ * open containers must not have a method within reach that turns one of them into a multi-gigabyte
9
+ * allocation.
10
+ *
11
+ * The size check is the point of the wrapper as much as the location is. {@link vgeo_validate_container}
12
+ * takes one `ArrayBuffer` because every §11 invariant is a cross-check between two places in the
13
+ * file, so the audit has a ceiling rather than a slope: measured, a 514 MiB container audited in
14
+ * 19.4 seconds, and past {@link VGEO_MAX_AUDIT_BYTES} the allocation is what fails. Refusing with
15
+ * the file's size in the message is better than an out-of-memory in whatever ran next.
16
+ *
17
+ * @param {VGeoContainerReader} reader an open container; only its byte source is used
18
+ * @param {number} [max_bytes] the ceiling to refuse above; a build machine auditing a file it just
19
+ * wrote is the caller that has a reason to raise it
20
+ * @returns {Promise<VGeoDefect[]>} empty is the only good answer
21
+ * @throws {Error} when the file is larger than the audit can hold
22
+ *
23
+ * @author Alex Goldring
24
+ * @copyright Company Named Limited (c) 2026
25
+ */
26
+ export function vgeo_audit_container(reader: VGeoContainerReader, max_bytes?: number): Promise<VGeoDefect[]>;
27
+ //# sourceMappingURL=vgeo_audit_container.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vgeo_audit_container.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,8EARW,MAAM,GAEJ,QAAQ,YAAY,CAAC,CAwBjC"}
@@ -0,0 +1,48 @@
1
+ import { BinaryBuffer } from "../../../../../../../core/binary/BinaryBuffer.js";
2
+ import { vgeo_validate_container } from "../../vgeo_validate_container.js";
3
+ import { VGEO_MAX_AUDIT_BYTES } from "./VGEO_MAX_AUDIT_BYTES.js";
4
+
5
+ /**
6
+ * The whole-file audit: every build invariant of `VGEO_FORMAT.md` §11, every checksum, and the
7
+ * directory against what a frame scan reconstructs.
8
+ *
9
+ * **This reads the entire file**, which is the one thing `VGeoContainerReader` exists to avoid, and
10
+ * that is why it lives here instead of on it. It answers a question about whoever *produced* the
11
+ * file; nothing about reading one depends on it having been asked, and a renderer holding a thousand
12
+ * open containers must not have a method within reach that turns one of them into a multi-gigabyte
13
+ * allocation.
14
+ *
15
+ * The size check is the point of the wrapper as much as the location is. {@link vgeo_validate_container}
16
+ * takes one `ArrayBuffer` because every §11 invariant is a cross-check between two places in the
17
+ * file, so the audit has a ceiling rather than a slope: measured, a 514 MiB container audited in
18
+ * 19.4 seconds, and past {@link VGEO_MAX_AUDIT_BYTES} the allocation is what fails. Refusing with
19
+ * the file's size in the message is better than an out-of-memory in whatever ran next.
20
+ *
21
+ * @param {VGeoContainerReader} reader an open container; only its byte source is used
22
+ * @param {number} [max_bytes] the ceiling to refuse above; a build machine auditing a file it just
23
+ * wrote is the caller that has a reason to raise it
24
+ * @returns {Promise<VGeoDefect[]>} empty is the only good answer
25
+ * @throws {Error} when the file is larger than the audit can hold
26
+ *
27
+ * @author Alex Goldring
28
+ * @copyright Company Named Limited (c) 2026
29
+ */
30
+ export async function vgeo_audit_container(reader, max_bytes = VGEO_MAX_AUDIT_BYTES) {
31
+ const source = reader.source;
32
+
33
+ if (source.byte_length > max_bytes) {
34
+ throw new Error(
35
+ `${source.name} is ${source.byte_length} bytes and the whole-file audit reads a`
36
+ + ` container as one buffer, which is bounded at ${max_bytes};`
37
+ + ` audit it where it was built, or raise the bound deliberately`
38
+ );
39
+ }
40
+
41
+ const bytes = await source.read(0, source.byte_length);
42
+
43
+ const whole = bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength
44
+ ? bytes.buffer
45
+ : bytes.slice().buffer;
46
+
47
+ return vgeo_validate_container(BinaryBuffer.fromArrayBuffer(whole));
48
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Install every page the directory lists.
3
+ *
4
+ * The opposite of what `VGeoContainerReader` is for, and exactly what a tool wants when the question
5
+ * is about the file rather than about a view of it — the pages no cut reaches are the ones a bug
6
+ * hides in.
7
+ *
8
+ * It lives here rather than on the reader because at the scale the format targets this is not a slow
9
+ * operation but an impossible one, and a renderer must not have it within reach of a container it is
10
+ * holding. Measured on a synthetic 2,000-page container of 544 KB pages: 514 MiB resident in 210 ms.
11
+ * The pages of one 100-million-triangle asset are several gigabytes, and there are supposed to be a
12
+ * thousand assets.
13
+ *
14
+ * **It goes on past a page it cannot read, and then fails.** A tool auditing a file wants the count
15
+ * of what could not be installed rather than the first entry on the list, and every reason is on the
16
+ * reader's quarantine afterwards (`VGeoContainerReader.quarantine`) whether this throws or not. The
17
+ * throw is what makes it a tool rather than a runtime path: the runtime's answer to a page that will
18
+ * not arrive is the clamped cut, and a tool's answer is to say so.
19
+ *
20
+ * @param {VGeoContainerReader} reader
21
+ * @param {function(number, number): void} [on_progress] called with pages attempted and total
22
+ * @returns {Promise<number>} how many pages are resident afterwards
23
+ * @throws {Error} when any page could not be installed, naming the count and the first reason
24
+ *
25
+ * @author Alex Goldring
26
+ * @copyright Company Named Limited (c) 2026
27
+ */
28
+ export function vgeo_install_all_pages(reader: VGeoContainerReader, on_progress?: (arg0: number, arg1: number) => void): Promise<number>;
29
+ //# sourceMappingURL=vgeo_install_all_pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vgeo_install_all_pages.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,yFAPoB,MAAM,QAAE,MAAM,KAAG,IAAI,GAC5B,QAAQ,MAAM,CAAC,CAsC3B"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Install every page the directory lists.
3
+ *
4
+ * The opposite of what `VGeoContainerReader` is for, and exactly what a tool wants when the question
5
+ * is about the file rather than about a view of it — the pages no cut reaches are the ones a bug
6
+ * hides in.
7
+ *
8
+ * It lives here rather than on the reader because at the scale the format targets this is not a slow
9
+ * operation but an impossible one, and a renderer must not have it within reach of a container it is
10
+ * holding. Measured on a synthetic 2,000-page container of 544 KB pages: 514 MiB resident in 210 ms.
11
+ * The pages of one 100-million-triangle asset are several gigabytes, and there are supposed to be a
12
+ * thousand assets.
13
+ *
14
+ * **It goes on past a page it cannot read, and then fails.** A tool auditing a file wants the count
15
+ * of what could not be installed rather than the first entry on the list, and every reason is on the
16
+ * reader's quarantine afterwards (`VGeoContainerReader.quarantine`) whether this throws or not. The
17
+ * throw is what makes it a tool rather than a runtime path: the runtime's answer to a page that will
18
+ * not arrive is the clamped cut, and a tool's answer is to say so.
19
+ *
20
+ * @param {VGeoContainerReader} reader
21
+ * @param {function(number, number): void} [on_progress] called with pages attempted and total
22
+ * @returns {Promise<number>} how many pages are resident afterwards
23
+ * @throws {Error} when any page could not be installed, naming the count and the first reason
24
+ *
25
+ * @author Alex Goldring
26
+ * @copyright Company Named Limited (c) 2026
27
+ */
28
+ export async function vgeo_install_all_pages(reader, on_progress = undefined) {
29
+ const directory = await reader.read_directory();
30
+
31
+ const total = directory.page_count;
32
+
33
+ let failed = 0;
34
+ let first = '';
35
+
36
+ for (let index = 0; index < total; index++) {
37
+ try {
38
+ await reader.install(index, directory.frame_offset[index], directory.fetch_size[index]);
39
+ } catch (e) {
40
+ failed++;
41
+
42
+ if (first === '') {
43
+ first = String(e?.message ?? e);
44
+ }
45
+ }
46
+
47
+ if (on_progress !== undefined) {
48
+ on_progress(index + 1, total);
49
+ }
50
+ }
51
+
52
+ if (failed > 0) {
53
+ throw new Error(
54
+ `${failed} of ${total} pages of ${reader.source.name} could not be installed;`
55
+ + ` the first was: ${first}`
56
+ );
57
+ }
58
+
59
+ return reader.resident_page_count;
60
+ }
@@ -11,12 +11,19 @@
11
11
  * numbers. §10 requires the response be `206` with the range that was asked for, so that is checked
12
12
  * on every read.
13
13
  *
14
+ * **Each range gets its own abort signal.** `init` is the whole source's — credentials, headers, and
15
+ * an abort that tears down every request this source will ever make — while the signal
16
+ * {@link VGeoByteSource.read} passes belongs to one page. A camera that moved wants to drop the
17
+ * fetches for the pages it stopped wanting and keep the rest, and that is only possible if the two
18
+ * are separate: the request is issued under both, and either one aborting it is enough.
19
+ *
14
20
  * The length comes from a `HEAD`, falling back to a one-byte ranged `GET` when the server declines
15
21
  * one — `Content-Range` names the total either way, and a CDN that refuses `HEAD` is common enough
16
22
  * to be worth the fallback rather than an error.
17
23
  *
18
24
  * @param {string} url
19
- * @param {RequestInit} [init] passed to every request — credentials, an abort signal, headers
25
+ * @param {RequestInit} [init] passed to every request — credentials, headers, and an abort signal
26
+ * that applies to the whole source
20
27
  * @returns {Promise<VGeoByteSource>}
21
28
  * @throws {Error} when the resource is missing, or does not serve ranges
22
29
  *
@@ -1 +1 @@
1
- {"version":3,"file":"vgeo_fetch_byte_source.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,4CARW,MAAM,SACN,WAAW,GACT,QAAQ,cAAc,CAAC,CA6CnC;+BAlE8B,qBAAqB"}
1
+ {"version":3,"file":"vgeo_fetch_byte_source.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,4CATW,MAAM,SACN,WAAW,GAET,QAAQ,cAAc,CAAC,CA8CnC;+BA1E8B,qBAAqB"}
@@ -13,12 +13,19 @@ import { VGeoByteSource } from "./VGeoByteSource.js";
13
13
  * numbers. §10 requires the response be `206` with the range that was asked for, so that is checked
14
14
  * on every read.
15
15
  *
16
+ * **Each range gets its own abort signal.** `init` is the whole source's — credentials, headers, and
17
+ * an abort that tears down every request this source will ever make — while the signal
18
+ * {@link VGeoByteSource.read} passes belongs to one page. A camera that moved wants to drop the
19
+ * fetches for the pages it stopped wanting and keep the rest, and that is only possible if the two
20
+ * are separate: the request is issued under both, and either one aborting it is enough.
21
+ *
16
22
  * The length comes from a `HEAD`, falling back to a one-byte ranged `GET` when the server declines
17
23
  * one — `Content-Range` names the total either way, and a CDN that refuses `HEAD` is common enough
18
24
  * to be worth the fallback rather than an error.
19
25
  *
20
26
  * @param {string} url
21
- * @param {RequestInit} [init] passed to every request — credentials, an abort signal, headers
27
+ * @param {RequestInit} [init] passed to every request — credentials, headers, and an abort signal
28
+ * that applies to the whole source
22
29
  * @returns {Promise<VGeoByteSource>}
23
30
  * @throws {Error} when the resource is missing, or does not serve ranges
24
31
  *
@@ -30,7 +37,7 @@ export async function vgeo_fetch_byte_source(url, init = {}) {
30
37
 
31
38
  return new VGeoByteSource(
32
39
  byte_length,
33
- async (offset, length) => {
40
+ async (offset, length, signal) => {
34
41
  if (length === 0) {
35
42
  return new Uint8Array(0);
36
43
  }
@@ -40,6 +47,7 @@ export async function vgeo_fetch_byte_source(url, init = {}) {
40
47
  const response = await fetch(url, {
41
48
  ...init,
42
49
  headers: { ...init.headers, Range: `bytes=${offset}-${last}` },
50
+ signal: either(init.signal, signal),
43
51
  });
44
52
 
45
53
  if (response.status !== 206) {
@@ -66,6 +74,28 @@ export async function vgeo_fetch_byte_source(url, init = {}) {
66
74
  );
67
75
  }
68
76
 
77
+ /**
78
+ * One signal that fires when either of two does.
79
+ *
80
+ * `AbortSignal.any` is the standard answer and is what this uses when both are there; the cases
81
+ * where only one is are the common ones and cost nothing.
82
+ *
83
+ * @param {AbortSignal} [a]
84
+ * @param {AbortSignal} [b]
85
+ * @returns {AbortSignal|undefined}
86
+ */
87
+ function either(a, b) {
88
+ if (a === undefined || a === null) {
89
+ return b ?? undefined;
90
+ }
91
+
92
+ if (b === undefined || b === null) {
93
+ return a;
94
+ }
95
+
96
+ return AbortSignal.any([a, b]);
97
+ }
98
+
69
99
  /**
70
100
  * How long the resource is.
71
101
  *