@woosh/meep-engine 3.27.0 → 3.29.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 (648) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/binary/BitSet.d.ts +16 -0
  4. package/src/core/binary/BitSet.d.ts.map +1 -1
  5. package/src/core/binary/BitSet.js +159 -49
  6. package/src/core/binary/allocator/OffsetAllocator.d.ts +48 -0
  7. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  8. package/src/core/binary/allocator/OffsetAllocator.js +208 -9
  9. package/src/core/binary/compression/compress_bytes.d.ts +20 -0
  10. package/src/core/binary/compression/compress_bytes.d.ts.map +1 -0
  11. package/src/core/binary/compression/compress_bytes.js +35 -0
  12. package/src/core/binary/compression/decompress_bytes_into.d.ts +30 -0
  13. package/src/core/binary/compression/decompress_bytes_into.d.ts.map +1 -0
  14. package/src/core/binary/compression/decompress_bytes_into.js +87 -0
  15. package/src/core/binary/compression/deflate_decompress_bound.d.ts +27 -0
  16. package/src/core/binary/compression/deflate_decompress_bound.d.ts.map +1 -0
  17. package/src/core/binary/compression/deflate_decompress_bound.js +32 -0
  18. package/src/core/geom/3d/mat4/m4_linear_determinant.d.ts +15 -0
  19. package/src/core/geom/3d/mat4/m4_linear_determinant.d.ts.map +1 -0
  20. package/src/core/geom/3d/mat4/m4_linear_determinant.js +24 -0
  21. package/src/core/geom/3d/mat4/m4_normal_matrix3.d.ts +4 -2
  22. package/src/core/geom/3d/mat4/m4_normal_matrix3.d.ts.map +1 -1
  23. package/src/core/geom/3d/mat4/m4_normal_matrix3.js +21 -11
  24. package/src/core/geom/3d/quadric/quadric_attribute_add.d.ts +24 -0
  25. package/src/core/geom/3d/quadric/quadric_attribute_add.d.ts.map +1 -0
  26. package/src/core/geom/3d/quadric/quadric_attribute_add.js +31 -0
  27. package/src/core/geom/3d/quadric/quadric_attribute_reduce.d.ts +46 -0
  28. package/src/core/geom/3d/quadric/quadric_attribute_reduce.d.ts.map +1 -0
  29. package/src/core/geom/3d/quadric/quadric_attribute_reduce.js +104 -0
  30. package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.d.ts +62 -0
  31. package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.d.ts.map +1 -0
  32. package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.js +158 -0
  33. package/src/core/geom/3d/quadric/quadric_attribute_size.d.ts +21 -0
  34. package/src/core/geom/3d/quadric/quadric_attribute_size.d.ts.map +1 -0
  35. package/src/core/geom/3d/quadric/quadric_attribute_size.js +24 -0
  36. package/src/core/geom/3d/quadric/quadric_attribute_solve.d.ts +34 -0
  37. package/src/core/geom/3d/quadric/quadric_attribute_solve.d.ts.map +1 -0
  38. package/src/core/geom/3d/quadric/quadric_attribute_solve.js +55 -0
  39. package/src/core/geom/3d/quadric/quadric_attribute_sub.d.ts +28 -0
  40. package/src/core/geom/3d/quadric/quadric_attribute_sub.d.ts.map +1 -0
  41. package/src/core/geom/3d/quadric/quadric_attribute_sub.js +35 -0
  42. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.d.ts +15 -0
  43. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.d.ts.map +1 -1
  44. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.js +35 -0
  45. package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.d.ts +93 -0
  46. package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.d.ts.map +1 -0
  47. package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.js +128 -0
  48. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts +38 -0
  49. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -0
  50. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +113 -0
  51. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +47 -1
  52. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  53. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +677 -8
  54. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.d.ts +22 -0
  55. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.d.ts.map +1 -0
  56. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.js +46 -0
  57. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.d.ts +19 -0
  58. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.d.ts.map +1 -0
  59. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.js +49 -0
  60. package/src/core/graph/layout/layered/BoxLayoutOptions.d.ts +63 -0
  61. package/src/core/graph/layout/layered/BoxLayoutOptions.d.ts.map +1 -0
  62. package/src/core/graph/layout/layered/BoxLayoutOptions.js +80 -0
  63. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/LayoutBoxGraph.d.ts +35 -0
  64. package/src/core/graph/layout/layered/LayoutBoxGraph.d.ts.map +1 -0
  65. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/LayoutBoxGraph.js +53 -1
  66. package/src/core/graph/layout/layered/layout_assign_coordinates.d.ts.map +1 -0
  67. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_coordinates.js +72 -68
  68. package/src/core/graph/layout/layered/layout_assign_layers.d.ts.map +1 -0
  69. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_layers.js +4 -2
  70. package/src/core/graph/layout/layered/layout_break_cycles.d.ts.map +1 -0
  71. package/src/core/graph/layout/layered/layout_insert_lanes.d.ts.map +1 -0
  72. package/src/core/graph/layout/layered/layout_order_layers.d.ts.map +1 -0
  73. package/src/core/graph/layout/layered/layout_orient_links.d.ts.map +1 -0
  74. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +7 -51
  75. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
  76. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +8 -69
  77. package/src/core/model/node-graph/visual/layout/layout_build_problem.js +1 -1
  78. package/src/core/model/node-graph/visual/layout/layout_node_graph.js +6 -6
  79. package/src/core/model/node-graph/visual/layout/route_grid_build.js +1 -1
  80. package/src/engine/Engine.d.ts.map +1 -1
  81. package/src/engine/Engine.js +38 -1
  82. package/src/engine/graphics3/DebugDrawSystem.d.ts +7 -5
  83. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  84. package/src/engine/graphics3/DebugDrawSystem.js +206 -203
  85. package/src/engine/graphics3/DecalSystem.d.ts +4 -5
  86. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  87. package/src/engine/graphics3/DecalSystem.js +5 -5
  88. package/src/engine/graphics3/FogOfWarSystem.d.ts +7 -12
  89. package/src/engine/graphics3/FogOfWarSystem.d.ts.map +1 -1
  90. package/src/engine/graphics3/FogOfWarSystem.js +8 -12
  91. package/src/engine/graphics3/GraphicsEngine.d.ts +5 -1
  92. package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
  93. package/src/engine/graphics3/GraphicsEngine.js +834 -830
  94. package/src/engine/graphics3/prefab/prefab_instantiate.js +230 -230
  95. package/src/shade/RENDERER_CONTRACT.md +31 -17
  96. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +1 -1
  97. package/src/shade/playground/caldera/README.md +529 -0
  98. package/src/shade/playground/caldera/caldera_format.d.ts +151 -0
  99. package/src/shade/playground/caldera/caldera_format.d.ts.map +1 -0
  100. package/src/shade/playground/caldera/caldera_format.js +241 -0
  101. package/src/shade/playground/caldera/index.html +126 -0
  102. package/src/shade/playground/caldera/main.d.ts.map +1 -0
  103. package/src/shade/playground/caldera/main.js +1565 -0
  104. package/src/shade/playground/mesh_row_ceiling/README.md +85 -0
  105. package/src/shade/playground/mesh_row_ceiling/index.html +31 -0
  106. package/src/shade/playground/mesh_row_ceiling/main.d.ts +2 -0
  107. package/src/shade/playground/mesh_row_ceiling/main.d.ts.map +1 -0
  108. package/src/shade/playground/mesh_row_ceiling/main.js +389 -0
  109. package/src/shade/playground/vgeo_runtime/README.md +32 -16
  110. package/src/shade/playground/vgeo_runtime/main.js +21 -7
  111. package/src/shade/playground/{vgeo_viewer → vgeo_runtime}/sample_asset.d.ts +3 -3
  112. package/src/shade/playground/vgeo_runtime/sample_asset.d.ts.map +1 -0
  113. package/src/shade/playground/{vgeo_viewer → vgeo_runtime}/sample_asset.js +12 -11
  114. package/src/shade/playground/vgeo_scene/README.md +487 -0
  115. package/src/shade/playground/vgeo_scene/index.html +144 -0
  116. package/src/shade/playground/vgeo_scene/main.d.ts +2 -0
  117. package/src/shade/playground/vgeo_scene/main.d.ts.map +1 -0
  118. package/src/shade/playground/vgeo_scene/main.js +2217 -0
  119. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  120. package/src/shade/renderer/GraphicsContext.js +6 -0
  121. package/src/shade/renderer/Renderer.d.ts +6 -1
  122. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  123. package/src/shade/renderer/Renderer.js +28 -2
  124. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  125. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +100 -8
  126. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +70 -35
  127. package/src/shade/renderer/extension/RenderExtension.d.ts +15 -18
  128. package/src/shade/renderer/extension/RenderExtension.d.ts.map +1 -1
  129. package/src/shade/renderer/extension/RenderExtension.js +15 -19
  130. package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts +5 -5
  131. package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts.map +1 -1
  132. package/src/shade/renderer/extension/RenderExtensionRegistry.js +29 -166
  133. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  134. package/src/shade/renderer/geometry/GPUGeometryManager.js +73 -16
  135. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  136. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +18 -3
  137. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +663 -0
  138. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +100 -5
  139. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  140. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +688 -81
  141. package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts.map +1 -1
  142. package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +3 -29
  143. package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts +22 -0
  144. package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts.map +1 -0
  145. package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.js +49 -0
  146. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +540 -0
  147. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +159 -66
  148. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +40 -21
  149. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +15 -14
  150. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +358 -0
  151. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +58 -8
  152. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  153. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +64 -10
  154. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.js +5 -9
  156. package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.d.ts +40 -0
  157. package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.d.ts.map +1 -0
  158. package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.js +24 -0
  159. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts +91 -0
  160. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts.map +1 -0
  161. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.js +91 -0
  162. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.d.ts +24 -0
  163. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.d.ts.map +1 -0
  164. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.js +25 -0
  165. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts +77 -0
  166. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts.map +1 -0
  167. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.js +84 -0
  168. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevel.d.ts.map +1 -0
  169. package/src/shade/renderer/geometry/virtual/build/{VGeoLevelOptions.d.ts → level/VGeoLevelOptions.d.ts} +19 -6
  170. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts.map +1 -0
  171. package/src/shade/renderer/geometry/virtual/build/{VGeoLevelOptions.js → level/VGeoLevelOptions.js} +20 -7
  172. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelSummary.d.ts.map +1 -0
  173. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.d.ts +19 -0
  174. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.d.ts.map +1 -0
  175. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.js +58 -0
  176. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.d.ts +18 -0
  177. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.d.ts.map +1 -0
  178. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.js +116 -0
  179. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts +18 -0
  180. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -0
  181. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +545 -0
  182. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts +16 -0
  183. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -0
  184. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +110 -0
  185. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts +11 -0
  186. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.js +308 -0
  188. package/src/shade/renderer/geometry/virtual/build/{vgeo_build_root_group.d.ts → level/vgeo_build_root_group.d.ts} +1 -1
  189. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_root_group.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/virtual/build/{vgeo_build_root_group.js → level/vgeo_build_root_group.js} +1 -1
  191. package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.d.ts +26 -0
  192. package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.js +123 -0
  194. package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.d.ts +26 -0
  195. package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.js +78 -0
  197. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts +24 -0
  198. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.js +337 -0
  200. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts +29 -0
  201. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts.map +1 -0
  202. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.js +147 -0
  203. package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.d.ts +37 -0
  204. package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.d.ts.map +1 -0
  205. package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.js +243 -0
  206. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts +29 -0
  207. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts.map +1 -0
  208. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.js +117 -0
  209. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts +46 -0
  210. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts.map +1 -0
  211. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +45 -0
  212. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +64 -0
  213. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -0
  214. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +68 -0
  215. package/src/shade/renderer/geometry/virtual/build/{VirtualGeometryMesh.d.ts → mesh/VirtualGeometryMesh.d.ts} +13 -8
  216. package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts.map +1 -0
  217. package/src/shade/renderer/geometry/virtual/build/{VirtualGeometryMesh.js → mesh/VirtualGeometryMesh.js} +40 -18
  218. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.d.ts +58 -0
  219. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.d.ts.map +1 -0
  220. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.js +79 -0
  221. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.d.ts +39 -0
  222. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.d.ts.map +1 -0
  223. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.js +68 -0
  224. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.d.ts +53 -0
  225. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.d.ts.map +1 -0
  226. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.js +243 -0
  227. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +45 -0
  228. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -0
  229. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +300 -0
  230. package/src/shade/renderer/geometry/virtual/build/{vgeo_compute_vertex_tangents.d.ts → mesh/vgeo_compute_vertex_tangents.d.ts} +12 -8
  231. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts.map +1 -0
  232. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.js +151 -0
  233. package/src/shade/renderer/geometry/virtual/build/{vgeo_normalize_source.d.ts → mesh/vgeo_normalize_source.d.ts} +8 -1
  234. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -0
  235. package/src/shade/renderer/geometry/virtual/build/{vgeo_normalize_source.js → mesh/vgeo_normalize_source.js} +27 -12
  236. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.d.ts +38 -0
  237. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.d.ts.map +1 -0
  238. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.js +81 -0
  239. package/src/shade/renderer/geometry/virtual/build/{vgeo_assemble_pages.d.ts → page/vgeo_assemble_pages.d.ts} +1 -1
  240. package/src/shade/renderer/geometry/virtual/build/page/vgeo_assemble_pages.d.ts.map +1 -0
  241. package/src/shade/renderer/geometry/virtual/build/{vgeo_assemble_pages.js → page/vgeo_assemble_pages.js} +9 -9
  242. package/src/shade/renderer/geometry/virtual/build/{vgeo_build_page_nodes.d.ts → page/vgeo_build_page_nodes.d.ts} +1 -1
  243. package/src/shade/renderer/geometry/virtual/build/page/vgeo_build_page_nodes.d.ts.map +1 -0
  244. package/src/shade/renderer/geometry/virtual/build/{vgeo_build_page_nodes.js → page/vgeo_build_page_nodes.js} +4 -4
  245. package/src/shade/renderer/geometry/virtual/build/page/vgeo_page_node_count.d.ts.map +1 -0
  246. package/src/shade/renderer/geometry/virtual/build/{vgeo_page_node_count.js → page/vgeo_page_node_count.js} +2 -2
  247. package/src/shade/renderer/geometry/virtual/build/{VGeoFaceGraph.d.ts → partition/VGeoFaceGraph.d.ts} +23 -5
  248. package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts.map +1 -0
  249. package/src/shade/renderer/geometry/virtual/build/{VGeoFaceGraph.js → partition/VGeoFaceGraph.js} +28 -21
  250. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts.map +1 -0
  251. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_graph.d.ts.map +1 -0
  252. package/src/shade/renderer/geometry/virtual/build/{vgeo_partition_graph.js → partition/vgeo_partition_graph.js} +2 -2
  253. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.d.ts +41 -0
  254. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.d.ts.map +1 -0
  255. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.js +92 -0
  256. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set.d.ts.map +1 -0
  257. package/src/shade/renderer/geometry/virtual/build/{vgeo_split_face_set.js → partition/vgeo_split_face_set.js} +13 -56
  258. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -0
  259. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.js +371 -0
  260. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_bounding_sphere.d.ts.map +1 -0
  261. package/src/shade/renderer/geometry/virtual/build/{vgeo_bounding_sphere.js → sphere/vgeo_bounding_sphere.js} +3 -3
  262. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_containing_sphere.d.ts.map +1 -0
  263. package/src/shade/renderer/geometry/virtual/build/{vgeo_containing_sphere.js → sphere/vgeo_containing_sphere.js} +3 -3
  264. package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_sphere_inflate_to_contain.d.ts.map +1 -0
  265. package/src/shade/renderer/geometry/virtual/build/{vgeo_sphere_inflate_to_contain.js → sphere/vgeo_sphere_inflate_to_contain.js} +1 -1
  266. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts +39 -0
  267. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts.map +1 -0
  268. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.js +42 -0
  269. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts +37 -0
  270. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts.map +1 -0
  271. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.js +39 -0
  272. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts +23 -0
  273. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts.map +1 -0
  274. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.js +135 -0
  275. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts +24 -0
  276. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts.map +1 -0
  277. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.js +95 -0
  278. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_narrow_indices.d.ts.map +1 -0
  279. package/src/shade/renderer/geometry/virtual/build/{vgeo_narrow_indices.js → submesh/vgeo_narrow_indices.js} +3 -3
  280. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts +6 -2
  281. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  282. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +37 -16
  283. package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.d.ts +32 -0
  284. package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.d.ts.map +1 -0
  285. package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.js +93 -0
  286. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +20 -6
  287. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  288. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +22 -8
  289. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.d.ts +8 -2
  290. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.d.ts.map +1 -1
  291. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.js +8 -2
  292. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_corner.d.ts +16 -0
  293. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_corner.d.ts.map +1 -0
  294. package/src/shade/renderer/geometry/virtual/format/attribute/{vgeo_layers_copy_vertex.js → vgeo_layers_copy_corner.js} +8 -8
  295. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.d.ts +18 -7
  296. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.d.ts.map +1 -1
  297. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.js +19 -8
  298. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.d.ts +3 -3
  299. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.js +3 -3
  300. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.d.ts +27 -0
  301. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.d.ts.map +1 -0
  302. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.js +97 -0
  303. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.d.ts +7 -3
  304. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.d.ts.map +1 -1
  305. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.js +21 -11
  306. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.d.ts +21 -0
  307. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.d.ts.map +1 -0
  308. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.js +41 -0
  309. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +19 -1
  310. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  311. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +20 -1
  312. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.d.ts +25 -0
  313. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.d.ts.map +1 -0
  314. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.js +24 -0
  315. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.d.ts +5 -0
  316. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.d.ts.map +1 -1
  317. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.js +5 -0
  318. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.d.ts.map +1 -1
  319. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.js +5 -0
  320. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.d.ts +10 -3
  321. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.d.ts.map +1 -1
  322. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.js +37 -3
  323. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +21 -13
  324. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  325. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +37 -13
  326. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.d.ts +8 -2
  327. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.d.ts.map +1 -1
  328. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.js +14 -2
  329. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +18 -0
  330. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  331. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +19 -1
  332. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_OFFSET.js +6 -0
  333. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.d.ts +21 -0
  334. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.d.ts.map +1 -0
  335. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.js +20 -0
  336. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.d.ts +9 -0
  337. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.d.ts.map +1 -1
  338. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.js +10 -1
  339. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.d.ts +15 -0
  340. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.d.ts.map +1 -0
  341. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.js +15 -0
  342. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +1 -2
  343. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +10 -3
  344. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.d.ts +20 -0
  345. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.d.ts.map +1 -0
  346. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.js +43 -0
  347. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts +32 -2
  348. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts.map +1 -1
  349. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +15 -7
  350. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  351. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +2 -2
  352. package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.d.ts +6 -4
  353. package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.d.ts.map +1 -1
  354. package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.js +6 -4
  355. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +13 -2
  356. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  357. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +13 -2
  358. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +5 -1
  359. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -1
  360. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +14 -1
  361. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -1
  362. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +1 -0
  363. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.d.ts +4 -1
  364. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.d.ts.map +1 -1
  365. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.js +53 -11
  366. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.d.ts.map +1 -1
  367. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.js +7 -3
  368. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts +12 -2
  369. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  370. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +120 -37
  371. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts +6 -2
  372. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  373. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +130 -47
  374. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts +2 -2
  375. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  376. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +60 -22
  377. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +385 -0
  378. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +21 -2
  379. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +52 -2
  380. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  381. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +97 -1
  382. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +4 -4
  383. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  384. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +10 -0
  385. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
  386. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +9 -0
  387. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
  388. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +59 -34
  389. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +8 -8
  390. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  391. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +45 -88
  392. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts +19 -0
  393. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts.map +1 -0
  394. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.js +116 -0
  395. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts +31 -0
  396. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts.map +1 -0
  397. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.js +99 -0
  398. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.d.ts +17 -0
  399. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.d.ts.map +1 -0
  400. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.js +39 -0
  401. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -1
  402. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +7 -63
  403. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
  404. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +13 -30
  405. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  406. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +53 -71
  407. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +1 -0
  408. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +22 -4
  409. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +7 -2
  410. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -1
  411. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +8 -3
  412. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  413. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +10 -0
  414. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  415. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +13 -11
  416. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -1
  417. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +13 -11
  418. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  419. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +4 -0
  420. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  421. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +3 -4
  422. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +6 -2
  423. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
  424. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +90 -12
  425. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts +22 -0
  426. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts.map +1 -0
  427. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.js +21 -0
  428. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  429. package/src/shade/renderer/loader/gltf/load_gltf.js +0 -19
  430. package/src/shade/renderer/material/chunk_material_draw_side.d.ts +14 -0
  431. package/src/shade/renderer/material/chunk_material_draw_side.d.ts.map +1 -0
  432. package/src/shade/renderer/material/chunk_material_draw_side.js +34 -0
  433. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
  434. package/src/shade/renderer/material/standard/fragment_gbuffer.js +8 -1
  435. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  436. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +13 -8
  437. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  438. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +3 -6
  439. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  440. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +13 -1
  441. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts +19 -5
  442. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
  443. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +23 -5
  444. package/src/shade/renderer/rasterize/bucket/filter_materials_by_bucket.d.ts.map +1 -1
  445. package/src/shade/renderer/rasterize/bucket/filter_materials_by_bucket.js +12 -5
  446. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  447. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +4 -12
  448. package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.d.ts +22 -0
  449. package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.d.ts.map +1 -0
  450. package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.js +36 -0
  451. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +0 -2
  452. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  453. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +4 -5
  454. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts +15 -0
  455. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts.map +1 -0
  456. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js +35 -0
  457. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  458. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +5 -3
  459. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.d.ts.map +1 -1
  460. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.js +11 -4
  461. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  462. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +4 -3
  463. package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.d.ts +10 -1
  464. package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.d.ts.map +1 -1
  465. package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.js +38 -29
  466. package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.d.ts +5 -0
  467. package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.d.ts.map +1 -1
  468. package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.js +63 -55
  469. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.d.ts.map +1 -1
  470. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.js +3 -0
  471. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
  472. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +94 -90
  473. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  474. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +13 -5
  475. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
  476. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +96 -89
  477. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.d.ts.map +1 -1
  478. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.js +3 -1
  479. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_two_way.d.ts.map +1 -1
  480. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_two_way.js +4 -1
  481. package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.d.ts.map +1 -1
  482. package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.js +1 -0
  483. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
  484. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +100 -89
  485. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.d.ts.map +1 -1
  486. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.js +31 -7
  487. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  488. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +1 -7
  489. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
  490. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +161 -153
  491. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  492. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +2 -7
  493. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  494. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +44 -53
  495. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  496. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +6 -2
  497. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  498. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +6 -2
  499. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts.map +1 -1
  500. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.js +19 -2
  501. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +7 -4
  502. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  503. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +3 -2
  504. package/src/shade/renderer/rasterize/native/chunk_rasterize_triangle.d.ts.map +1 -1
  505. package/src/shade/renderer/rasterize/native/chunk_rasterize_triangle.js +15 -4
  506. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  507. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +16 -5
  508. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.d.ts.map +1 -1
  509. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.js +16 -5
  510. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
  511. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +2 -1
  512. package/src/shade/renderer/rasterize/native/rasterization_shader_resources.d.ts.map +1 -1
  513. package/src/shade/renderer/rasterize/native/rasterization_shader_resources.js +4 -0
  514. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  515. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +16 -7
  516. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  517. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +81 -95
  518. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  519. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +26 -39
  520. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  521. package/src/shade/renderer/scene/GPUSceneContext.js +2 -0
  522. package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts +19 -0
  523. package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts.map +1 -1
  524. package/src/shade/renderer/scene/NODE3D_STRUCT.js +34 -0
  525. package/src/shade/renderer/scene/chunk_node3d_flags.d.ts +9 -0
  526. package/src/shade/renderer/scene/chunk_node3d_flags.d.ts.map +1 -0
  527. package/src/shade/renderer/scene/chunk_node3d_flags.js +23 -0
  528. package/src/shade/renderer/scene/chunk_scene_database_access.d.ts.map +1 -1
  529. package/src/shade/renderer/scene/chunk_scene_database_access.js +15 -1
  530. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  531. package/src/shade/renderer/scene/rows/GPUSceneRows.js +9 -1
  532. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.d.ts +7 -0
  533. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.d.ts.map +1 -1
  534. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.js +16 -4
  535. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.d.ts +12 -0
  536. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.d.ts.map +1 -0
  537. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.js +18 -0
  538. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.d.ts +24 -0
  539. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.d.ts.map +1 -0
  540. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.js +33 -0
  541. package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.d.ts +25 -0
  542. package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.d.ts.map +1 -0
  543. package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.js +24 -0
  544. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +10 -0
  545. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  546. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +30 -21
  547. package/src/core/model/node-graph/visual/layout/LayoutBoxGraph.d.ts.map +0 -1
  548. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.d.ts.map +0 -1
  549. package/src/core/model/node-graph/visual/layout/layout_assign_layers.d.ts.map +0 -1
  550. package/src/core/model/node-graph/visual/layout/layout_break_cycles.d.ts.map +0 -1
  551. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +0 -1
  552. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +0 -1
  553. package/src/core/model/node-graph/visual/layout/layout_orient_links.d.ts.map +0 -1
  554. package/src/shade/playground/vgeo_viewer/README.md +0 -150
  555. package/src/shade/playground/vgeo_viewer/cut_geometry.d.ts +0 -61
  556. package/src/shade/playground/vgeo_viewer/cut_geometry.d.ts.map +0 -1
  557. package/src/shade/playground/vgeo_viewer/cut_geometry.js +0 -460
  558. package/src/shade/playground/vgeo_viewer/index.html +0 -77
  559. package/src/shade/playground/vgeo_viewer/main.d.ts.map +0 -1
  560. package/src/shade/playground/vgeo_viewer/main.js +0 -1343
  561. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +0 -1
  562. package/src/shade/playground/vgeo_viewer/select_cut.d.ts +0 -173
  563. package/src/shade/playground/vgeo_viewer/select_cut.d.ts.map +0 -1
  564. package/src/shade/playground/vgeo_viewer/select_cut.js +0 -481
  565. package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.d.ts.map +0 -1
  566. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.d.ts +0 -24
  567. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.d.ts.map +0 -1
  568. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.js +0 -25
  569. package/src/shade/renderer/geometry/virtual/build/VGeoLevel.d.ts.map +0 -1
  570. package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.d.ts.map +0 -1
  571. package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.d.ts.map +0 -1
  572. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.d.ts +0 -20
  573. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.d.ts.map +0 -1
  574. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.js +0 -20
  575. package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.d.ts.map +0 -1
  576. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +0 -1
  577. package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.d.ts.map +0 -1
  578. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.d.ts +0 -36
  579. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.d.ts.map +0 -1
  580. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.js +0 -1786
  581. package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.d.ts.map +0 -1
  582. package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.d.ts.map +0 -1
  583. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.d.ts +0 -29
  584. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.d.ts.map +0 -1
  585. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.js +0 -75
  586. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.d.ts.map +0 -1
  587. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.js +0 -143
  588. package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.d.ts.map +0 -1
  589. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.d.ts +0 -14
  590. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.d.ts.map +0 -1
  591. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.js +0 -41
  592. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.d.ts +0 -12
  593. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.d.ts.map +0 -1
  594. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.js +0 -71
  595. package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.d.ts.map +0 -1
  596. package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.d.ts.map +0 -1
  597. package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.d.ts.map +0 -1
  598. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +0 -1
  599. package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.d.ts.map +0 -1
  600. package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.d.ts.map +0 -1
  601. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.d.ts.map +0 -1
  602. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.d.ts.map +0 -1
  603. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.js +0 -207
  604. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.d.ts +0 -16
  605. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.d.ts.map +0 -1
  606. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +0 -258
  607. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +0 -1
  608. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +0 -49
  609. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +0 -1
  610. package/src/shade/renderer/loader/gltf/fix_up_material_sides.d.ts +0 -10
  611. package/src/shade/renderer/loader/gltf/fix_up_material_sides.d.ts.map +0 -1
  612. package/src/shade/renderer/loader/gltf/fix_up_material_sides.js +0 -109
  613. package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.d.ts +0 -17
  614. package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.d.ts.map +0 -1
  615. package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.js +0 -78
  616. package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.d.ts +0 -3
  617. package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.d.ts.map +0 -1
  618. package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.js +0 -100
  619. package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.d.ts +0 -8
  620. package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.d.ts.map +0 -1
  621. package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.js +0 -26
  622. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.d.ts +0 -3
  623. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.d.ts.map +0 -1
  624. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_coordinates.d.ts +0 -0
  625. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_layers.d.ts +0 -0
  626. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_break_cycles.d.ts +0 -0
  627. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_break_cycles.js +0 -0
  628. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_insert_lanes.d.ts +0 -0
  629. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_insert_lanes.js +0 -0
  630. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_order_layers.d.ts +0 -0
  631. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_order_layers.js +0 -0
  632. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_orient_links.d.ts +0 -0
  633. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_orient_links.js +0 -0
  634. /package/src/shade/playground/{vgeo_viewer → caldera}/main.d.ts +0 -0
  635. /package/src/shade/renderer/geometry/virtual/build/{VGeoLevel.d.ts → level/VGeoLevel.d.ts} +0 -0
  636. /package/src/shade/renderer/geometry/virtual/build/{VGeoLevel.js → level/VGeoLevel.js} +0 -0
  637. /package/src/shade/renderer/geometry/virtual/build/{VGeoLevelSummary.d.ts → level/VGeoLevelSummary.d.ts} +0 -0
  638. /package/src/shade/renderer/geometry/virtual/build/{VGeoLevelSummary.js → level/VGeoLevelSummary.js} +0 -0
  639. /package/src/shade/renderer/geometry/virtual/build/{vgeo_page_node_count.d.ts → page/vgeo_page_node_count.d.ts} +0 -0
  640. /package/src/shade/renderer/geometry/virtual/build/{vgeo_graph_components.d.ts → partition/vgeo_graph_components.d.ts} +0 -0
  641. /package/src/shade/renderer/geometry/virtual/build/{vgeo_graph_components.js → partition/vgeo_graph_components.js} +0 -0
  642. /package/src/shade/renderer/geometry/virtual/build/{vgeo_partition_graph.d.ts → partition/vgeo_partition_graph.d.ts} +0 -0
  643. /package/src/shade/renderer/geometry/virtual/build/{vgeo_split_face_set.d.ts → partition/vgeo_split_face_set.d.ts} +0 -0
  644. /package/src/shade/renderer/geometry/virtual/build/{vgeo_split_face_set_packed.d.ts → partition/vgeo_split_face_set_packed.d.ts} +0 -0
  645. /package/src/shade/renderer/geometry/virtual/build/{vgeo_bounding_sphere.d.ts → sphere/vgeo_bounding_sphere.d.ts} +0 -0
  646. /package/src/shade/renderer/geometry/virtual/build/{vgeo_containing_sphere.d.ts → sphere/vgeo_containing_sphere.d.ts} +0 -0
  647. /package/src/shade/renderer/geometry/virtual/build/{vgeo_sphere_inflate_to_contain.d.ts → sphere/vgeo_sphere_inflate_to_contain.d.ts} +0 -0
  648. /package/src/shade/renderer/geometry/virtual/build/{vgeo_narrow_indices.d.ts → submesh/vgeo_narrow_indices.d.ts} +0 -0
@@ -0,0 +1,540 @@
1
+ # Attribute-aware simplification — plan, 2026-09-18
2
+
3
+ `VIRTUAL_GEOMETRY_DESIGN.md` §9 lists "attribute-quadric placement and UV-seam constraint planes"
4
+ as out of scope for v1, on the grounds that v1 targets "position/normal-fidelity content". This plan
5
+ is the measurement showing that the *normal* half of that claim does not hold — the builder's shading
6
+ frame is wrong on a third to a half of every level above the leaves — and the design that fixes it.
7
+
8
+ Nothing here changes the container format, the runtime, or the cut rule. §8 says why, and holds the
9
+ work to it.
10
+
11
+ ## 1. What is wrong, measured
12
+
13
+ Instrumented builds of `zorah_main_public.v2.gltf` `mesh1[0]` — 128,318 triangles, 13 levels.
14
+ Instrumentation was temporary and is not in the tree; the probes that produced these numbers are
15
+ reproduced by `vgeo_attribute_fidelity.bench.spec.js` (§9).
16
+
17
+ ### 1.1 The builder ships two different normal fields in one mesh
18
+
19
+ `vgeo_build_group_step` ends a group step with
20
+
21
+ ```js
22
+ vgeo_compute_vertex_normals(submesh.mesh, locked);
23
+ vgeo_compute_vertex_tangents(submesh.mesh, locked);
24
+ ```
25
+
26
+ and those two calls run **two incompatible rules over one mesh**:
27
+
28
+ - an **interior** vertex is given the area-weighted normal of the mesh as the simplifier just left
29
+ it — a property of the coarse tessellation;
30
+ - a **`locked`** vertex — the group's perimeter, which the step was forbidden to move — keeps what
31
+ it inherited, which tracks the surface the asset was authored from.
32
+
33
+ They meet along every triangle that straddles a group perimeter, and the perimeter is not a rare
34
+ place:
35
+
36
+ | | L1 | L3 | L5 | L7 | L8 |
37
+ |---|---|---|---|---|---|
38
+ | pinned share of live vertices | 31% | 38% | 49% | 50% | 37% |
39
+ | pinned normal vs. **the surface it ships on**, p90 / max | 9.5° / 68° | 11.2° / 52° | 17.2° / 154° | 27.6° / 80° | 21.8° / 88° |
40
+ | pinned normal vs. **the source field**, mean | 0.00° | 0.95° | 4.1° | 8.7° | 8.0° |
41
+ | interior normal vs. **the source field**, mean | 5.7° | 9.8° | 15.5° | 21.9° | 26.7° |
42
+
43
+ Read the last two rows together. The pinned value is the *correct* one; it is the interior recompute
44
+ that has walked away from what was authored. A second primitive reaches 175° at L1 — a normal
45
+ pointing into the surface it shades.
46
+
47
+ The visible result is a dark wedge fanning out from a single vertex, and it needs no LOD transition
48
+ to appear: it is wrong in one level, standing still.
49
+
50
+ ### 1.2 Recomputing from coarse geometry guarantees a pop
51
+
52
+ The same vertex's shipped normal, between the level that holds it and the level that replaces it:
53
+ mean 5.3° at L1 rising to 13–23° at L8–L11, p90 13.6° rising to 40–58°. That is not approximation
54
+ error. The area-weighted normal of the coarse mesh is a *different surface's* normal, and the whole
55
+ reason shading normals exist is that they do not have to follow the tessellation.
56
+
57
+ ### 1.3 The representation cannot hold an attribute discontinuity
58
+
59
+ `BinaryTopology` carries one attribute record per vertex, and `bt_merge_vertices_by_distance` says
60
+ what it does with that: *"Only considers distance, no other attributes are accounted for."*
61
+ `bt_vertex_replace` re-points references and orphans the victim's record.
62
+
63
+ Measured on a hard-edged, UV-charted subdivided box pushed through `vgeo_normalize_source`: 1,734
64
+ source vertices become 1,538, the 196 splits along the twelve cube edges are gone, and **six distinct
65
+ normals survive, every one of them axis-aligned** — the master's record won outright and nothing was
66
+ blended. Every hard edge now carries a normal 90° wrong for half the triangles using it, and each UV
67
+ chart bleeds across its seam. Before a single collapse.
68
+
69
+ Zorah does not hit this only because its source primitives carry `["POSITION"]` and nothing else.
70
+ Every textured asset does.
71
+
72
+ ### 1.4 A source with no normals is smoothed across its creases
73
+
74
+ Because Zorah authors no normals, `vgeo_normalize_source` synthesizes them by area-weighted
75
+ averaging over the welded mesh, with no crease rule anywhere. At **LOD 0**, the angle between a
76
+ vertex's normal and its own face's normal: mean 8.6°, p90 19.5°, p99 37.7°, max 179.9°; 2.5% of
77
+ corners over 30°.
78
+
79
+ This is a consequence of §1.3, not an independent defect: hard normals need more than one value at a
80
+ position, and there is nowhere to put the second one.
81
+
82
+ **Which symptom each stage fixes.** The reported defect is two visually distinct things. The dark
83
+ wedge fanning out of a single vertex is §1.1 and §1.2, and §5/§6 remove it. The broad soft gradient
84
+ smeared across a flat panel is §1.4, and §7 is what removes that — it is deferred, so a close-up of
85
+ Zorah will still look smoother than it should after §5 and §6 land. Saying so here rather than
86
+ discovering it in a screenshot.
87
+
88
+ ## 2. Why the current design is what it is
89
+
90
+ `vgeo_compute_vertex_normals` states the case against the obvious alternative correctly:
91
+
92
+ > carrying a surviving vertex's original normal through a dozen collapses shades a coarse level by
93
+ > whichever vertices happened to win, which is visibly wrong.
94
+
95
+ That is true. Survivor-takes-all *is* wrong. What was not considered is the third option: neither
96
+ inherit the attribute nor re-derive it from the coarse geometry, but **fit** it — choose the value
97
+ that best explains the source attribute field over everything folded into the vertex. That is what
98
+ the geometric quadric already does for position, and it is the same machinery.
99
+
100
+ The pin was then added on top to protect cut seams. The pin is *correct* and must survive this plan
101
+ (§3). It only reads as the defect because the interior rule it sits beside is incompatible with it.
102
+
103
+ ## 3. Invariants any fix must keep
104
+
105
+ 1. **A cut is crack-free in geometry.** A vertex two groups share is never moved. Unchanged: this
106
+ plan does not touch `locked`, `protected_faces`, or the boundary polyline check.
107
+ 2. **A cut is crease-free in shading.** If cluster X at level L and cluster Y at level M sit side by
108
+ side in a cut, every vertex they share must carry **byte-identical** attribute values in both
109
+ payloads. Held by a spec: over a whole DAG, every position that appears in two payloads carries
110
+ the same encoded normal and tangent in both — across levels and within one. It needs *both*
111
+ gates removed to go red (§11), because they are genuinely redundant. The seam vertex is on a group perimeter at every level between L and M, so the rule
112
+ that delivers this is: *a pinned vertex keeps its attribute values exactly*. That rule stays.
113
+ Note what it rules out: deriving the frame once on the stitched frontier fixes §1.1 and breaks
114
+ this, because a pinned vertex's one-ring still changes between L and M even though the vertex
115
+ does not move.
116
+ 3. **`r_e` is an object-space length.** `VIRTUAL_GEOMETRY_DESIGN.md` §3's units guard: solve in the
117
+ higher-dimensional metric, report error by plugging the resulting *position* into the pure 3-D
118
+ geometric quadric. The reported error therefore stays exactly what it is today in kind, and the
119
+ cut rule, the error bands and the page layout keep working with no change.
120
+ 4. **Monotonicity.** `parent.error >= self.error` transitively. Already imposed in
121
+ `vgeo_build_group_step`; unaffected.
122
+ 5. **The position weld stays.** `vgeo_normalize_source`'s weld is load-bearing for *connectivity* —
123
+ without it the clusterer shreds the mesh along every seam. §7 separates "weld for topology" from
124
+ "weld for attributes"; it does not remove the first.
125
+
126
+ ## 4. The design
127
+
128
+ Generalized quadrics — Garland & Heckbert 1998 (*Simplifying Surfaces with Color and Texture using
129
+ Quadric Error Metrics*) for the naive `(3+m)`-dimensional lift, **Hoppe 1999** (*New Quadric Metric
130
+ for Simplifying Meshes with Appearance Attributes*) for the form worth implementing. Unreal's Nanite
131
+ uses the latter (`MeshSimplify.h` / `Quadric.h`: attribute-carrying quadrics, per-attribute weights,
132
+ and a separate edge quadric for boundary and seam penalties); `meshoptimizer`'s
133
+ `meshopt_simplifyWithAttributes` is a far more readable second reference for the same maths and for
134
+ weight calibration.
135
+
136
+ ### 4.1 The maths, in the form this codebase will hold it
137
+
138
+ For one triangle `(p1, p2, p3)` and one scalar attribute channel with corner values `(s1, s2, s3)`,
139
+ the attribute is the linear field `s(p) = g·p + d` that interpolates the corners and has no gradient
140
+ along the face normal:
141
+
142
+ ```
143
+ e1 = p2 - p1, e2 = p3 - p1, n = normalize(e1 x e2), det = |e1 x e2|
144
+ g = ( (s2 - s1) * (e2 x n) + (s3 - s1) * (n x e1) ) / det
145
+ d = s1 - g . p1
146
+ ```
147
+
148
+ The error of a candidate `(v, s)` against that triangle is `(g·v + d - s)²`. Accumulated over every
149
+ triangle folded into a vertex, with per-triangle weight `w`:
150
+
151
+ ```
152
+ P = SUM w * (g g^T) 3x3 symmetric 6
153
+ q = SUM w * (d g) vector 3
154
+ r = SUM w * d^2 scalar 1
155
+ W = SUM w scalar 1
156
+ G_i = SUM w * g_i vector, per channel 3m
157
+ D_i = SUM w * d_i scalar, per channel m
158
+ ```
159
+
160
+ `P`, `q`, `r`, `W` occupy **exactly the `Quadric3` layout** — 11 elements, `A`/`b`/`c`/`w` — so an
161
+ attribute quadric is a `Quadric3`-shaped header followed by `4m` elements, and every `quadric3_*`
162
+ function applies to the header unchanged. Size is `11 + 4m`.
163
+
164
+ Minimising over `s` for a fixed `v` is exact and gives the readout:
165
+
166
+ ```
167
+ s_i = (G_i . v + D_i) / W
168
+ ```
169
+
170
+ Substituting it back leaves a **3-D** quadric in `v` alone — the *reduced* quadric:
171
+
172
+ ```
173
+ A_a = P - SUM_i (G_i G_i^T) / W
174
+ b_a = q - SUM_i (D_i G_i) / W
175
+ c_a = r - SUM_i (D_i^2) / W
176
+ ```
177
+
178
+ which is again `Quadric3`-shaped. So placement is unchanged in kind: solve
179
+ `(A_g + A_a) v = -(b_g + b_a)` with the existing `quadric3_optimize`, on the sum of the geometric
180
+ quadric and the reduced attribute quadric. Attributes fall out afterwards.
181
+
182
+ This is the whole reason to implement Hoppe's form rather than the lift: `11 + 4m` elements instead
183
+ of `(m+4)(m+5)/2`, and a 3x3 solve instead of an `(3+m)x(3+m)` one.
184
+
185
+ ### 4.2 Weights
186
+
187
+ `g` has units of `attribute / length`, so `(g·v + d - s)²` is dimensionless while the geometric
188
+ quadric evaluates to `length²`. Summing them without a weight is meaningless. Each channel therefore
189
+ carries a weight with units of length, applied by scaling the attribute values before the quadric is
190
+ built and dividing it out on readout.
191
+
192
+ The weight is stored as a **ratio of the geometry's own bounding-box diagonal**, for the same reason
193
+ `weld_ratio` is (`VGeoBuildOptions#weld_ratio`): a conversion is many geometries at many sizes and no
194
+ one distance is right for all of them.
195
+
196
+ It is resolved once, off the source's bounds, before any pass has removed anything — the same moment
197
+ `weld_distance` is resolved — and travels as an already-multiplied `Float64Array`, one entry per
198
+ `VGEO_ATTRIBUTES` channel, from `vgeo_build` down to `vgeo_build_leaf_frontier` and every group step.
199
+ `vgeo_normalize_source` returns a distance today and keeps doing so; the resolution is its own
200
+ function so the two are not entangled and the weights can be read without normalising anything.
201
+
202
+ Defaults start **low** — low enough that placement barely moves and the DAG's shape, error numbers
203
+ and page layout stay comparable to today's — because the dominant win in §1.1/§1.2 is the *readout*,
204
+ not the placement. Raising them additionally protects creases from being collapsed across, which is
205
+ a second and smaller win. §6.4 is the sweep that picks the shipped numbers, and the numbers it picks
206
+ are recorded here rather than asserted from taste.
207
+
208
+ ### 4.3 Per-channel handling
209
+
210
+ | channel | carried | note |
211
+ |---|---|---|
212
+ | `NORMAL` (3) | in the quadric | renormalised after readout |
213
+ | `TANGENT` (4) | xyz in the quadric **when the mesh has `UV0`**; otherwise derived from the normal | handedness is a discrete flag, taken from the survivor; re-orthogonalised against the final normal |
214
+ | `COLOR` (3) | in the quadric | clamped to `[0, 1]` |
215
+ | `UV0` (2) | in the quadric | |
216
+ | `UV1` (2) | in the quadric | |
217
+
218
+ The tangent split is not a special case dodged: with no `UV0` there is no parameterisation to be
219
+ tangent to and the tangent is a pure function of the normal (`build_tangent_from_normal`, Frisvad).
220
+ A pure function of a byte-identical input is byte-identical, so deriving it costs nothing against
221
+ invariant 2 — and it is *more* robust than blending, because Frisvad's frame flips discontinuously
222
+ and two nearly-opposite tangents average to nothing.
223
+
224
+ **This table governs §5 as much as §6.** The moment the group step stops calling
225
+ `vgeo_compute_vertex_tangents`, something has to produce a tangent, and blending a four-component
226
+ tangent blends the handedness flag — a discrete `±1` — into a number that means nothing. Zorah is
227
+ exactly the `UV0`-less case, so getting this wrong at Stage 0 would trade a shading defect for a
228
+ worse one.
229
+
230
+ ### 4.4 Numerical guards
231
+
232
+ - `g` divides by `det = 2 * area`, so a sliver produces an enormous gradient. Triangles whose `det`
233
+ is below an epsilon relative to the mesh contribute no attribute quadric. `vgeo_normalize_source`
234
+ has already collapsed and killed the worst of them; this is the backstop.
235
+ - `W <= 0` means nothing has been accumulated — a faceless vertex. The readout is skipped and the
236
+ vertex keeps whatever it had.
237
+ - Per-triangle weight is **1**, matching `quadric3_set_from_vector4`'s convention
238
+ (*"One plane, and callers pass unit normals, so it weighs one"*), not Hoppe's area weighting. The
239
+ two terms have to be commensurate when summed, and `quadric3_distance` already reads the whole
240
+ codebase's quadrics as a mean over unit-weight planes.
241
+ - `vgeo_normalize_source`'s own `bt_mesh_collapse_short_edges` stays survivor-takes-all for
242
+ attributes, and that is left alone deliberately: it acts only on edges shorter than the weld
243
+ tolerance — `1e-5` of the diagonal — where the two records it is choosing between differ by less
244
+ than the octahedral encoding can represent. Recorded so it is a decision rather than an oversight.
245
+
246
+ ## 5. Stage 0 — transport instead of recompute
247
+
248
+ The smallest change that removes the §1.1 artifact, and the plumbing every later stage needs.
249
+
250
+ ### 5.1 What changes
251
+
252
+ - `bt_mesh_simplify_with_quadrics` gains an optional per-vertex attribute vector. At each collapse
253
+ the survivor's vector becomes the combination of the two endpoints' blended by their accumulated
254
+ quadric weights — how much source surface each of them stands for. A **restricted** survivor is
255
+ left exactly as it is, which is invariant 2 and is not negotiable.
256
+ - `vgeo_build_group_step` hands it the mesh's channels flattened into that vector, writes the result
257
+ back into the layers for every non-pinned vertex, and **stops calling**
258
+ `vgeo_compute_vertex_normals` / `vgeo_compute_vertex_tangents`.
259
+ - The normal is renormalised after the blend, and the tangent follows §4.3 — derived from the normal
260
+ where the mesh has no `UV0`, blended xyz with the survivor's handedness where it does, then
261
+ re-orthogonalised.
262
+ - `vgeo_normalize_source` keeps calling both — that is the leaf field, and it is the thing everything
263
+ above now tracks. Neither pass becomes dead code.
264
+
265
+ ### 5.2 Why this is on the way to §6 and not a detour
266
+
267
+ Stage 0 and Stage 1 differ only in *how the value at a collapse is chosen*. The plumbing — where the
268
+ value is set, what the pin means, that nothing is re-derived from coarse geometry afterwards — is
269
+ identical, and so are the specs that assert it. Stage 0 is the degenerate case of Stage 1: diagonal
270
+ weights, no coupling to placement.
271
+
272
+ ### 5.3 Acceptance
273
+
274
+ Measured, prototyped, against the source normal field on the same primitive:
275
+
276
+ | level | recompute mean | transport mean | recompute >30° | transport >30° |
277
+ |---|---|---|---|---|
278
+ | L4 | 12.85° | 9.77° | 9.5% | 4.0% |
279
+ | L5 | 15.49° | 11.50° | 14.0% | 5.7% |
280
+ | L7 | 21.87° | 17.41° | 29.2% | 18.4% |
281
+
282
+ The percentages matter more than the means: the pinned/interior split becomes vacuous, both follow
283
+ one rule, and the wedge has nowhere to come from.
284
+
285
+ - [x] A spec proving a pinned vertex's attribute record is byte-identical before and after a
286
+ simplification that moves everything around it. Over a *curved* fixture — see §11's second
287
+ entry for why a flat one proves nothing.
288
+ - [x] A spec proving nothing re-derives a normal from coarse geometry in a group step. Stated as a
289
+ property rather than as equality, because the blend does change values: hand the builder a mesh
290
+ whose authored normals point somewhere its faces do not, and every level still points that way.
291
+ Equality was the wrong assertion — §6 replaced the blend with a fit and the numbers moved
292
+ again, while the property held through both, which is what it was written for.
293
+ - [x] A spec proving a `UV0`-less mesh ships a unit tangent orthogonal to its normal at every level,
294
+ which is §4.3's rule stated as a test.
295
+ - [x] The whole suite green, and both of Stage 0's own specs run red against the pass they replaced
296
+ first: the authored field arrived 175° out where it now arrives within one, and the root's own
297
+ derived field sat 8.6° from the surface it stands for against 3.2°.
298
+ - [x] Zorah smoke conversion clean, with the refusal count unchanged — see §6.4, which ran it.
299
+
300
+ ## 6. Stage 1 — the attribute quadric
301
+
302
+ ### 6.1 New, in `core/geom/3d/quadric/`
303
+
304
+ One function per file with a spec beside it, matching the `quadric3_*` family. Every function reads
305
+ and writes `11 + 4m` consecutive elements of any array-like at any offset, the same way `quadric3_*`
306
+ does.
307
+
308
+ **And the builder takes that offer.** `Quadric3` is carried as an array of objects with `clone`,
309
+ `add` and `sub`; the attribute quadrics are carried as **one flat `Float64Array` indexed by vertex**
310
+ instead, which is the case `quadric3_*`'s own documentation names — *"how a caller holding a great
311
+ many quadrics keeps them in one flat buffer instead of one object each"*. A round clones the whole
312
+ frontier's set once per round; at `11 + 4m` doubles a million-vertex primitive would otherwise be a
313
+ million short-lived objects per round on top of the million already there.
314
+
315
+ - `quadric_attribute_size(m)` — `11 + 4 * m`.
316
+ - `quadric_attribute_set_from_triangle(...)` — §4.1's construction for all `m` channels at once.
317
+ - `quadric_attribute_add(...)` — elementwise; the reduction is done at solve time, never at
318
+ accumulate time, which is what keeps `add` associative.
319
+ - `quadric_attribute_sub(...)` — the fold-back in `vgeo_build_levels` subtracts *gains*.
320
+ - `quadric_attribute_reduce(...)` — writes the `Quadric3`-shaped `(A_a, b_a, c_a)` of §4.1.
321
+ - `quadric_attribute_solve(...)` — the readout `s_i = (G_i·v + D_i)/W`.
322
+
323
+ `Quadric3` itself is **untouched**, and so are its other callers (`bt_mesh_simplify_by_error`,
324
+ `navmesh_build_topology`, `compute_tetrahedral_mesh_from_surface`). Keeping the geometric quadric
325
+ pure is what makes invariant 3 free rather than something to be careful about.
326
+
327
+ ### 6.2 New, in the topology layer
328
+
329
+ - `bt_mesh_compute_vertex_attribute_quadrics(mesh, values, components, ...)` — builds one per vertex
330
+ from every allocated triangle. It takes a flat `values` array and a component count and knows
331
+ nothing about `VGEO_ATTRIBUTES`, so it is reusable and testable on its own.
332
+
333
+ ### 6.3 Changed
334
+
335
+ - `bt_mesh_simplify_with_quadrics` — Stage 0's blend becomes: reduce the summed attribute quadric,
336
+ add it to the geometric one, solve for position on the sum, read the attributes out at that
337
+ position. The cost that orders the heap becomes geometric + attribute, so a collapse that wrecks
338
+ the normal field is expensive. The **returned deviation is still the pure geometric quadric**
339
+ evaluated at the chosen position (invariant 3).
340
+
341
+ **A restricted survivor is still left exactly as it is** — position *and* attributes. The readout
342
+ would move it: a pinned vertex absorbs its victims' quadrics like any other survivor, so `W`, `G`
343
+ and `D` grow under it and the fit at its unchanged position comes out different. That is invariant
344
+ 2, and it is the one place where "read the attributes out" is wrong.
345
+
346
+ **Attributes are opt-in and nothing else opts in.** `bt_mesh_simplify` passes none.
347
+ `bt_mesh_simplify_by_error` turns out not to be a caller at all — it is a separate implementation
348
+ with its own `choose_collapse` and `quadric_cost_at` — which is a stronger isolation than this
349
+ expected, and worth knowing because it simplifies to a *tolerance* that an attribute term in the
350
+ cost would silently move.
351
+ - `VGeoBuildOptions` — per-channel weight ratios.
352
+ - `vgeo_normalize_source` — resolves them to object-space beside `weld_distance`.
353
+ - `vgeo_build_leaf_frontier` — builds the attribute quadrics once from the source, beside
354
+ `bt_mesh_compute_vertex_quadrics`.
355
+ - `vgeo_build_group_step`, `vgeo_build_levels` — carry, fold back and re-index them exactly as
356
+ `Quadric3` is carried, folded back and re-indexed. The fold-back is gains-not-results for the same
357
+ reason.
358
+
359
+ ### 6.4 Acceptance
360
+
361
+ **Met.** Measured on `mesh1[0]` of `zorah_main_public.v2.gltf` — 128,318 triangles, 64,231 welded
362
+ vertices — Stage 0 against Stage 1, same primitive, same measurement, read out of the encoded
363
+ payloads. How far the shipped normal sits from the source's field, by level:
364
+
365
+ | level | Stage 0 mean | Stage 1 mean | Stage 0 over 30° | Stage 1 over 30° |
366
+ |---|---|---|---|---|
367
+ | 1 | 3.36° | **2.21°** | 0.6% | 0.4% |
368
+ | 2 | 3.09° | **1.96°** | 0.5% | 0.4% |
369
+ | 3 | 5.48° | **2.97°** | 1.5% | 0.8% |
370
+ | 4 | 6.44° | **4.84°** | 2.5% | 1.1% |
371
+ | 5 | 7.47° | **5.98°** | 3.5% | 1.9% |
372
+ | 6 | 9.35° | **7.07°** | 6.6% | 2.5% |
373
+ | 7 | 11.85° | **9.22°** | 10.9% | 5.9% |
374
+ | 8 | 16.13° | **12.61°** | 19.2% | 11.6% |
375
+ | 9 | 21.88° | **18.01°** | 30.1% | 22.6% |
376
+ | 10 | 28.69° | **23.85°** | 39.0% | 29.8% |
377
+ | 11 | 31.63° | **26.70°** | 40.7% | 35.6% |
378
+
379
+ Better at every level, by a third at L1–L3 and by a fifth or more through the middle of the DAG,
380
+ which is the part a camera actually spends its time in. Level 0 reads `0.01°` on both, which is the
381
+ octahedral encoding and nothing else — the leaves are exact, as they must be.
382
+
383
+ - [x] Source-field error at every level at most Stage 0's, and materially below it at L3 and above.
384
+ - [x] A sweep of the weight ratios: `VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS` carries the table and the
385
+ argument. `1/1024`. Above `1/64` it stops being a trade — eighteen times the geometric error
386
+ for a normal field that is *worse* — because this content is smooth and there is no crease for
387
+ the placement term to defend. A subdivided cube, which is all crease, goes from 14.9° of
388
+ worst-case normal error to **1.38°** at `1/4`; that is what raising it is for.
389
+ - [x] `self_error` at the root **fell**, 7.325e-2 to 6.019e-2, which is 0.82x and inside the 20% the
390
+ gate allowed in either direction.
391
+ - [x] Levels 13 to 14, clusters 2,677 to 2,686 — a third of a percent. The DAG is the same shape.
392
+ - [x] Build time 2,373 ms to 2,906 ms, **1.22x**, against the 2x gate. All the scratch in
393
+ `evaluate_edge_collapse` is module-level and grown once per channel count, never allocated per
394
+ candidate.
395
+ - [x] The whole suite green: 19,377 tests.
396
+ - [x] Zorah smoke conversion, run both sides of the change: **203 of 203** geometries under 5,000
397
+ triangles convert on each, and **450 of 450** under 20,000 convert here with the full container
398
+ audit on — every build invariant, checksum and directory record, in every file. 3,095,102
399
+ source triangles, no refusals either side. Bytes 12.0 to 12.1 MiB on the smaller run, which is
400
+ 0.8%, and the conversion is 9.7 s against 10.1 s.
401
+ - [x] Peak builder memory, as process RSS across the level loop, both sides of the change:
402
+
403
+ | primitive | Stage 0 | Stage 1 | |
404
+ |---|---|---|---|
405
+ | 400,008 triangles | 774 MiB, 9.7 s | 874 MiB, 9.7 s | 1.13x, 1.00x |
406
+ | 801,427 triangles | 3,055 MiB, 32.7 s | 3,741 MiB, 37.4 s | 1.22x, 1.14x |
407
+
408
+ The `11 + 4m` doubles a vertex carries against `Quadric3`'s `11` is 23 for a normal-only asset,
409
+ and the frontier's set is one flat buffer rather than an object each; a fifth more is what that
410
+ comes to in practice. Not the *largest* primitive — that one is 1,076,562 triangles and takes
411
+ many minutes.
412
+
413
+ **The reading that twice the triangles cost 3.4x the time is not a superlinearity, and saying
414
+ so here was wrong.** Investigated separately: the builder is linear, in **clusters**, at about
415
+ a millisecond each — and how many clusters a source cuts into is set by its vertex-to-face
416
+ ratio rather than by its triangle count, so two primitives of the same size can be an order of
417
+ magnitude apart in cost. Triangles were the wrong x-axis.
418
+
419
+ ## 7. Stage 2 — wedges. Specified here, planned in full separately
420
+
421
+ §1.3 and §1.4 need a position to carry more than one attribute record. That is a change to what
422
+ `BinaryTopology` means for this builder, and it reaches the clusterer, the payload encoder and the
423
+ gather — a much larger blast radius than §5 and §6, with none of their measurements to lean on until
424
+ the format work is done. Doing it badly is worse than not doing it, so it is specified here and taken
425
+ separately.
426
+
427
+ **Taken up in [WEDGE_PLAN_2026_09_18.md](./WEDGE_PLAN_2026_09_18.md)**, which is this section with
428
+ the representation decided, the collapse rule chosen, and three staged gates. What follows is the
429
+ shape it starts from.
430
+
431
+ - **Weld for connectivity, not for attributes.** `bt_merge_vertices_by_distance` keeps doing exactly
432
+ what it does. What changes is that a topology vertex gains a small set of *wedges* — attribute
433
+ records — and a loop names one of them, so one position can shade two ways.
434
+ - **Seams are pinned by constraint planes, not by luck.** The mechanism already exists:
435
+ `bt_mesh_compute_vertex_quadrics`'s `add_boundary_constraints` adds Garland & Heckbert's
436
+ perpendicular plane at every open edge at `BOUNDARY_WEIGHT = 3`. An attribute seam is the same
437
+ situation — sliding along the surface destroys something the face-plane quadric cannot see — and
438
+ wants the same plane. This is the "boundary-plane-penalty mechanism" `VIRTUAL_GEOMETRY_DESIGN.md`
439
+ §2 already requires, reused rather than invented.
440
+ - **A collapse merges wedges that agree and keeps those that do not**, which is where the vertex-count
441
+ growth is bounded.
442
+ - **Crease-angle synthesis** (§1.4) then becomes available for a source that authors no normals:
443
+ split by angle instead of averaging a 179° corner into one value. It is blocked on wedges and on
444
+ nothing else.
445
+
446
+ ## 8. What this does not change
447
+
448
+ - **The container format.** No new fields, no version move. Attribute values are encoded exactly as
449
+ they are today (`vgeo_encode_cluster_payload`, octahedral normals and tangents).
450
+ - **The runtime.** Nothing on the device reads a quadric.
451
+ - **The cut rule.** `r_e` stays an object-space length by invariant 3.
452
+ - **Existing `.vgeo` files.** They remain readable; they are simply built from a worse metric, and a
453
+ rebuild is what improves them. The Zorah asset needs re-converting to benefit (§9).
454
+
455
+ ## 9. Measurement
456
+
457
+ The three probes that produced §1 become a bench spec, `vgeo_attribute_fidelity.bench.spec.js`,
458
+ beside the builder — so the numbers in this document can be re-taken rather than believed.
459
+
460
+ It follows the house shape for a bench (`atlas_generate.bench.spec.js`): **deterministic synthetic
461
+ fixtures, no asset dependency, behind `.skip`** so it is not a gate on a normal run. No spec in this
462
+ package reads `test_assets/`, and one that did could not run in CI, where the 51 GiB of converted
463
+ Zorah is not present. The Zorah figures in §1 come from a scratch driver over the real container and
464
+ stay there; what the bench gives is the same three measurements on geometry the repository owns, so a
465
+ regression is caught by the suite rather than by a conversion someone remembers to run.
466
+
467
+ The three:
468
+
469
+ - **shipped vs. the surface it ships on**, split by pinned / interior. §1.1's table. This is the one
470
+ that should read zero for both columns after Stage 0.
471
+ - **shipped vs. the source attribute field**, sampled at the nearest source vertex. §1.2 and §5.3.
472
+ - **shipped vs. the level below at the same vertex** — the pop across a LOD transition.
473
+
474
+ Per `test-helpers-live-in-the-specs`, the fixtures and the sampling grid live in the spec file, not
475
+ in a shared helper.
476
+
477
+ The end-to-end check is the Zorah smoke conversion: the 5-second subset run that
478
+ `vgeo-build-refusal-harness` describes, whose refusal list is the regression signal.
479
+
480
+ ## 10. Rejected
481
+
482
+ - **Derive the frame once on the stitched frontier.** Fixes §1.1 and breaks invariant 3: a seam
483
+ vertex's one-ring differs between the level that holds it and the level that replaces it even
484
+ though the vertex never moves, so the two payloads disagree and the cut creases. Trades a wedge for
485
+ a seam.
486
+ - **Bake the source normals into a map.** No UVs on the content that shows the defect, and it
487
+ contradicts the premise that virtual geometry carries its own detail.
488
+ - **Keep the survivor's attribute record.** §2: this is the failure the current design was written
489
+ to avoid, and it is a real one.
490
+ - **The full `(3+m)`-dimensional quadric.** Correct, and strictly more expensive than §4.1 for the
491
+ same answer.
492
+
493
+ ## 11. Review ledger
494
+
495
+ This plan was reviewed against the code before any of it was written. What the review changed:
496
+
497
+ | # | finding | resolution |
498
+ |---|---|---|
499
+ | 1 | §4.1's closed form was asserted, not checked | Verified numerically before the plan was accepted: interpolation residual and `g·n` both at `8e-15`, the reduced form matches the exact minimum over `s` to `2e-14`, and the reduced 3x3 solve reaches the same optimum as gradient descent on the full `(3+m)`-dimensional problem to `1e-15`. The same three properties become specs in §6.1. |
500
+ | 2 | Stage 0 stopped calling `vgeo_compute_vertex_tangents` without saying what produces a tangent instead — and blending a 4-component tangent blends the handedness flag. Zorah is the `UV0`-less case that would have shipped it | §4.3 now says it governs §5 as much as §6; §5.1 states the rule; §5.3 adds the spec |
501
+ | 3 | §6.3 said "read the attributes out at that position" with no exception, which moves a **pinned** vertex's value and breaks invariant 2 | §6.3 states the exception and why the readout is wrong there |
502
+ | 4 | Nothing said what happens to `bt_mesh_simplify_by_error`, which shares `evaluate_edge_collapse` and simplifies to a *tolerance* | §6.3: attributes are opt-in, and neither other caller opts in |
503
+ | 5 | §6.3 said the attribute quadrics are carried "exactly as `Quadric3` is" — an object per vertex, cloned per round, at `11 + 4m` doubles each | §6.1: one flat `Float64Array` indexed by vertex, which is the idiom `quadric3_*` documents for exactly this |
504
+ | 6 | The plan implied it fixed the reported symptom outright; the soft gradient across flat panels is §1.4 and needs §7 | §1.4 now states which stage fixes which half |
505
+ | 7 | "within a stated factor" / "a stated tolerance" are not acceptance criteria | §6.4 names 2x on build time and 20% on `self_error`, and asks for level and cluster counts |
506
+ | 8 | §9 put the Zorah measurement in a spec; no spec in this package reads `test_assets/`, and CI has no Zorah | §9: synthetic fixtures behind `.skip`, house shape; the Zorah driver stays a scratch script |
507
+ | 9 | Weight resolution was hand-waved onto `vgeo_normalize_source`, which returns a distance | §4.2: its own function, resolved at the same moment, travelling as a `Float64Array` per channel |
508
+ | 10 | `bt_mesh_collapse_short_edges` is survivor-takes-all for attributes and the plan was silent | §4.4: named, with the reason it is left alone |
509
+
510
+ ## 12. Implementation review ledger
511
+
512
+ The work was reviewed against itself after it landed. What that found:
513
+
514
+ | # | finding | resolution |
515
+ |---|---|---|
516
+ | 1 | A step handed the level loop one `Float64Array` per surviving vertex, where the geometric side hands over a reference and allocates nothing | The step keeps the buffer the simplifier finished with, whole, and `step.quadrics` — which already had an identical key set — says which entries are live. Same output; 2,906 ms to 2,774. |
517
+ | 2 | "A pinned vertex keeps its record" was asserted over a *flat* fixture with a field affine over the whole mesh — where every triangle projects the same gradient and the fit reproduces the original value at every point, pin or no pin. The spec could not have failed | Bent the grid. Removing the pin now fails it. |
518
+ | 3 | Nothing asserted the invariant §3.2 states, which is the one the DAG rests on | A spec over every position in a whole DAG. It needs **both** pins removed to go red — the write-side gate catches what the collapse-side gate lets through — which is a real property of the design rather than a weakness of the spec, and is recorded rather than deduplicated away. |
519
+ | 4 | The blend fallback — a vertex with no field to fit from — was unreachable from any spec | Handing the simplifier quadrics that are all zero is that case everywhere at once. |
520
+ | 5 | A fitted colour can leave `[0, 1]`, which §4.3 called for and the code did not do. The encoder saturates, so no word was ever wrong — but the out-of-range value stays in the layer, and it is what the *next* level's field is fitted from | Clamped on the way back into the layer. |
521
+ | 6 | `bt_mesh_simplify_by_error` was documented as a caller that passes `null` | It is not a caller at all — its own `choose_collapse` and `quadric_cost_at`. A stronger isolation than claimed, and stated correctly now. |
522
+ | 7 | The bench's pop column keyed by coordinate, so it compared only vertices that never moved — the pinned perimeters, which are byte-identical by construction. It would have reported a pop of zero on a build that had one | Sampled at the nearest place on the coarser surface instead, which is what a pixel sees. |
523
+ | 8 | The default-ratio note quoted one cube as "a subdivided cube" | Sixteen subdivisions per face reads 14.9° of worst-case normal error against 1.38° at a quarter; twenty-four reads a hundredth of a degree at every ratio. Named which. |
524
+
525
+ **`check-types` is at its budget of 19, and none of the nineteen are in a file this touched.**
526
+
527
+ Worth saying how that was arrived at, because the first answer was wrong. `npm run check-types` in a
528
+ `.claude/worktrees/` tree reports *zero*, and zero is not progress — the script spawns
529
+ `<pkg>/../../node_modules/.bin/tsc`, which a bare worktree does not have, `spawnSync` fails silently,
530
+ and the run counts errors in an empty output. The number only means anything from a tree with a
531
+ populated `node_modules`, or by invoking the main checkout's compiler directly:
532
+
533
+ ```
534
+ /h/git/CompanyNamed/meep/node_modules/.bin/tsc --project tsconfig.types.json
535
+ /h/git/CompanyNamed/meep/node_modules/.bin/tsc --project type-check/tsconfig.json
536
+ ```
537
+
538
+ Declarations emit clean; the consumer program reports 19, every one of them in the documented set
539
+ (`Vector3`, `Vector2`, `Quaternion`, `EnginePlugin` and the rest that `scripts/BUDGET.md` lists), and
540
+ none in any file this change wrote or edited.