@woosh/meep-engine 3.25.0 → 3.27.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 (295) hide show
  1. package/package.json +1 -1
  2. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
  3. package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
  4. package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
  5. package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
  6. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
  7. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
  8. package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
  9. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
  10. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
  11. package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
  12. package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
  13. package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
  14. package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
  15. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +66 -0
  16. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  17. package/src/core/geom/3d/shape/HeightMapShape3D.js +314 -20
  18. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
  20. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  21. package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
  22. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  23. package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
  24. package/src/engine/physics/cloth/MEASUREMENTS.md +582 -0
  25. package/src/engine/physics/cloth/PLAN.md +330 -49
  26. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
  27. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  28. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
  29. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +65 -7
  30. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  31. package/src/engine/physics/cloth/ecs/ClothInstance.js +72 -8
  32. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +25 -4
  33. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  34. package/src/engine/physics/cloth/ecs/ClothSystem.js +75 -8
  35. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +41 -4
  36. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  37. package/src/engine/physics/cloth/ecs/ClothWorld.js +207 -63
  38. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +10 -0
  39. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  40. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +17 -1
  41. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +27 -3
  42. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  43. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +28 -3
  44. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +75 -10
  45. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  46. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +131 -12
  47. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
  48. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  49. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
  50. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
  51. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  52. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
  53. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  54. package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
  55. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  56. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
  57. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  58. package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
  59. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +12 -2
  60. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  61. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +12 -2
  62. package/src/engine/physics/cloth/solver/cloth_step_instance.js +1 -1
  63. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
  64. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
  65. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
  66. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +23 -9
  67. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -1
  68. package/src/engine/physics/cloth/wind/AbstractClothWind.js +23 -9
  69. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +7 -5
  70. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +12 -9
  72. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
  73. package/src/engine/physics/cloth/wind/ClothFluidWind.js +5 -2
  74. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +7 -2
  75. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  76. package/src/engine/physics/cloth/wind/cloth_sample_air.js +12 -5
  77. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  78. package/src/shade/playground/vgeo_runtime/README.md +167 -22
  79. package/src/shade/playground/vgeo_runtime/index.html +112 -62
  80. package/src/shade/playground/vgeo_runtime/main.js +660 -83
  81. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
  82. package/src/shade/playground/vgeo_viewer/sample_asset.js +19 -2
  83. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
  84. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  85. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
  86. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
  88. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +73 -5
  89. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +26 -15
  90. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +5 -3
  91. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +18 -0
  92. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  93. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +20 -0
  94. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +56 -9
  96. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  97. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -0
  98. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
  99. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  100. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
  101. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
  102. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  103. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
  104. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
  105. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  106. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
  107. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
  108. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  109. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
  110. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
  111. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
  112. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
  113. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
  114. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
  115. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
  116. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
  117. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
  118. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
  119. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
  120. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
  121. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
  122. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
  123. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
  124. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
  125. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
  127. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
  128. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  129. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
  130. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
  131. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  132. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
  133. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
  134. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  135. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
  136. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
  137. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
  138. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
  139. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
  140. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  141. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
  142. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
  143. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
  144. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
  145. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
  146. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  147. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
  148. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
  149. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
  150. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
  151. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
  152. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
  153. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
  154. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +55 -0
  156. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  157. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +202 -13
  158. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  159. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +147 -10
  160. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +637 -0
  161. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
  162. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
  163. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
  164. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +58 -28
  165. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  166. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +77 -105
  167. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +105 -22
  169. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
  171. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  172. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +47 -489
  173. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1363 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
  183. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  184. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
  185. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +15 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +186 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +20 -8
  210. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  211. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +580 -188
  212. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
  213. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
  214. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
  250. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
  251. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
  252. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
  253. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  254. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
  255. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  256. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
  257. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  258. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  259. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
  260. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  261. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
  262. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  263. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  264. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
  265. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
  266. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  267. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  268. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  269. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
  270. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  271. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
  272. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  273. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
  274. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  275. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
  276. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  277. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
  278. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  279. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +7 -1
  280. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  281. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +7 -1
  282. package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
  283. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  284. package/src/shade/renderer/scene/GPUSceneContext.js +59 -4
  285. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  286. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
  287. package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
  288. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  289. package/src/shade/renderer/view/GPUViewContext.js +21 -0
  290. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  291. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
  292. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
  293. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
  294. package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
  295. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
@@ -1,201 +1,249 @@
1
- import { assert } from "../../../../core/assert.js";
2
- import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
3
- import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
4
- import { GPUStateAuthorityFlags } from "../../../ecs/gpu/GPUStateAuthorityFlags.js";
5
- import { gpu_authority_revoke } from "../../../ecs/gpu/gpu_authority_revoke.js";
6
- import { TransformAttachment } from "../../../ecs/transform-attachment/TransformAttachment.js";
7
- import { cloth_build_children, cloth_build_rows } from "./cloth_build_rows.js";
8
-
9
- /**
10
- * # Seeding a cloth from a skinned model's joints — §11.2
11
- *
12
- * One particle per joint the proxy names, with the anchor as the fixed set, and
13
- * everything after that is `cloth_build_rows.js` — the same rows, the same
14
- * geodesics, the same leashes the entity path gets. §11 says "the solver is
15
- * identical either way; only seeding and write-back differ", and this file plus
16
- * `cloth_write_back_rig.js` is the whole of the difference.
17
- *
18
- * ## The joints are entities, and cloth takes them back from the GPU
19
- *
20
- * A skinned model is a prefab spawned as entities, so a joint is an entity with
21
- * a `TransformAttachment` — the offset from its parent joint — and a
22
- * `GPUStateAuthority` saying who writes that offset's row. A joint a clip
23
- * drives is the GPU's: the clip resolves the row on the GPU and the CPU never
24
- * writes it, so the attachment's offset stops describing it. Cloth writing that
25
- * offset on such a joint would be writing to something nothing reads.
26
- *
27
- * So the seed **revokes** the GPU's authority over every joint it drives. The
28
- * consequence is stated rather than hidden: a joint cloth simulates stops being
29
- * animatable by a clip, because two writers of one row is the race the
30
- * authority component exists to prevent. That is the right trade for a cape —
31
- * the whole point of simulating it is that nobody keyframes it — and it is an
32
- * authoring error for a garment whose joints are also keyed, which is why the
33
- * seed says so.
34
- *
35
- * ## The animated pose is constant, exactly as it is for a rope
36
- *
37
- * §11.1 says a subtree's authored pose is rigid relative to its anchor, so in
38
- * the anchor's own frame it does not move, and then says "a subtree whose links
39
- * are themselves animated is not an M1 case — that is the rig path, where the
40
- * animated pose comes from the skeleton and is live".
41
- *
42
- * For a **rigged** garment it is not live either, and the reason is the
43
- * authority claim above: cloth owns those joints, so nothing else poses them,
44
- * so their authored pose is the proxy's baked bind pose — constant in the
45
- * anchor's frame, exactly as a rope's is. What moves is the anchor, and the
46
- * anchor is a joint of the character's own animated skeleton, whose pose the
47
- * system evaluates exactly (`t64_evaluate_world`).
48
- *
49
- * @author Alex Goldring
50
- * @copyright Company Named Limited (c) 2026
51
- */
52
-
53
- /**
54
- * Seed `instance` from a proxy and the joints of a skin.
55
- *
56
- * @param {ClothInstance} instance seeded in place
57
- * @param {ClothProxy} proxy
58
- * @param {number[]} joints the skin's joints as entities, in the order the proxy indexes
59
- * @param {EntityComponentDataset} ecd
60
- * @param {number} dt
61
- */
62
- export function cloth_seed_rig(instance, proxy, joints, ecd, dt) {
63
- assert.ok(proxy.isClothProxy === true, 'proxy must be a ClothProxy');
64
-
65
- const joint_count = proxy.joint_count;
66
-
67
- // Node 0 is the anchor, exactly as it is for the entity path: the fixed
68
- // set, the origin of the local frame, and `d_geo = 0`.
69
- const node_count = joint_count + 1;
70
-
71
- instance.node_count = node_count;
72
-
73
- const node_parent = new Int32Array(node_count);
74
-
75
- node_parent[0] = -1;
76
-
77
- for (let i = 0; i < joint_count; i++) {
78
- node_parent[i + 1] = proxy.joint_parent[i] + 1;
79
- }
80
-
81
- instance.node_parent = node_parent;
82
-
83
- const node_joint = new Int32Array(node_count);
84
-
85
- node_joint[0] = joints[proxy.anchor];
86
-
87
- const node_attachment = new Array(node_count);
88
-
89
- node_attachment[0] = null;
90
-
91
- for (let i = 0; i < joint_count; i++) {
92
- const joint = joints[proxy.joint[i]];
93
-
94
- assert.defined(joint, `joint ${proxy.joint[i]} of the skin`);
95
- assert.ok(ecd.entityExists(joint), `joint ${proxy.joint[i]} of the skin, entity ${joint}, does not exist`);
96
-
97
- node_joint[i + 1] = joint;
98
-
99
- const attachment = ecd.getComponent(joint, TransformAttachment);
100
-
101
- assert.defined(attachment, `joint entity ${joint} carries no TransformAttachment to write`);
102
-
103
- node_attachment[i + 1] = attachment;
104
-
105
- // See the module docblock. A clip-driven joint's offset is the GPU's, and taking it back
106
- // is what makes the write-back reach the row at all. An entity that never declared has
107
- // nothing to take back.
108
- gpu_authority_revoke(ecd, joint, GPUStateAuthorityFlags.TransformAttachment);
109
- }
110
-
111
- instance.node_joint = node_joint;
112
- instance.node_attachment = node_attachment;
113
-
114
- // The entity path's arrays have no meaning here and holding stale ones is
115
- // how a write-back reaches into a previous seeding's entities.
116
- instance.node_entity = null;
117
- instance.node_transform = [];
118
- instance.pruned_count = 0;
119
- instance.pruned_entity = null;
120
- instance.pruned_parent = null;
121
- instance.pruned_transform = [];
122
- instance.pruned_attachment = [];
123
-
124
- cloth_build_children(instance);
125
-
126
- read_bind_pose(instance, proxy);
127
-
128
- instance.dynamics_seen.copy(instance.cloth.dynamics);
129
-
130
- cloth_build_rows(instance, dt);
131
-
132
- instance.seeded = true;
133
- }
134
-
135
- /**
136
- * The proxy's bind pose, composed: local offsets per node and the position and
137
- * rotation of every node in the anchor's frame.
138
- *
139
- * @param {ClothInstance} instance
140
- * @param {ClothProxy} proxy
141
- */
142
- function read_bind_pose(instance, proxy) {
143
- const node_count = instance.node_count;
144
-
145
- const local_position = new Float32Array(node_count * 3);
146
- const local_rotation = new Float32Array(node_count * 4);
147
-
148
- const position = new Float32Array(node_count * 3);
149
- const rotation = new Float32Array(node_count * 4);
150
-
151
- // The anchor is the origin of the frame it anchors.
152
- local_rotation[3] = 1;
153
- rotation[3] = 1;
154
-
155
- const parent = instance.node_parent;
156
-
157
- for (let node = 1; node < node_count; node++) {
158
- const joint = node - 1;
159
-
160
- local_position[node * 3] = proxy.rest_position[joint * 3];
161
- local_position[node * 3 + 1] = proxy.rest_position[joint * 3 + 1];
162
- local_position[node * 3 + 2] = proxy.rest_position[joint * 3 + 2];
163
-
164
- local_rotation[node * 4] = proxy.rest_rotation[joint * 4];
165
- local_rotation[node * 4 + 1] = proxy.rest_rotation[joint * 4 + 1];
166
- local_rotation[node * 4 + 2] = proxy.rest_rotation[joint * 4 + 2];
167
- local_rotation[node * 4 + 3] = proxy.rest_rotation[joint * 4 + 3];
168
-
169
- const p = parent[node];
170
-
171
- const pqx = rotation[p * 4];
172
- const pqy = rotation[p * 4 + 1];
173
- const pqz = rotation[p * 4 + 2];
174
- const pqw = rotation[p * 4 + 3];
175
-
176
- v3_quaternion_apply(
177
- COMPOSE, 0,
178
- local_position[node * 3], local_position[node * 3 + 1], local_position[node * 3 + 2],
179
- pqx, pqy, pqz, pqw
180
- );
181
-
182
- position[node * 3] = position[p * 3] + COMPOSE[0];
183
- position[node * 3 + 1] = position[p * 3 + 1] + COMPOSE[1];
184
- position[node * 3 + 2] = position[p * 3 + 2] + COMPOSE[2];
185
-
186
- quat3_multiply(
187
- rotation, node * 4,
188
- pqx, pqy, pqz, pqw,
189
- local_rotation[node * 4], local_rotation[node * 4 + 1],
190
- local_rotation[node * 4 + 2], local_rotation[node * 4 + 3]
191
- );
192
- }
193
-
194
- instance.rest_local_position = local_position;
195
- instance.rest_local_rotation = local_rotation;
196
-
197
- instance.animated_position = position;
198
- instance.animated_rotation = rotation;
199
- }
200
-
201
- const COMPOSE = new Float64Array(3);
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
3
+ import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
4
+ import { GPUStateAuthorityFlags } from "../../../ecs/gpu/GPUStateAuthorityFlags.js";
5
+ import { gpu_authority_grant } from "../../../ecs/gpu/gpu_authority_grant.js";
6
+ import { gpu_authority_revoke } from "../../../ecs/gpu/gpu_authority_revoke.js";
7
+ import { TransformAttachment } from "../../../ecs/transform-attachment/TransformAttachment.js";
8
+ import { cloth_build_children, cloth_build_rows } from "./cloth_build_rows.js";
9
+
10
+ /**
11
+ * # Seeding a cloth from a skinned model's joints — §11.2
12
+ *
13
+ * One particle per joint the proxy names, with the anchor as the fixed set, and
14
+ * everything after that is `cloth_build_rows.js` — the same rows, the same
15
+ * geodesics, the same leashes the entity path gets. §11 says "the solver is
16
+ * identical either way; only seeding and write-back differ", and this file plus
17
+ * `cloth_write_back_rig.js` is the whole of the difference.
18
+ *
19
+ * ## The joints are entities, and cloth takes them back from the GPU
20
+ *
21
+ * A skinned model is a prefab spawned as entities, so a joint is an entity with
22
+ * a `TransformAttachment` — the offset from its parent joint — and a
23
+ * `GPUStateAuthority` saying who writes that offset's row. A joint a clip
24
+ * drives is the GPU's: the clip resolves the row on the GPU and the CPU never
25
+ * writes it, so the attachment's offset stops describing it. Cloth writing that
26
+ * offset on such a joint would be writing to something nothing reads.
27
+ *
28
+ * So the seed **revokes** the GPU's authority over every joint it drives. The
29
+ * consequence is stated rather than hidden: a joint cloth simulates stops being
30
+ * animatable by a clip, because two writers of one row is the race the
31
+ * authority component exists to prevent. That is the right trade for a cape —
32
+ * the whole point of simulating it is that nobody keyframes it — and it is an
33
+ * authoring error for a garment whose joints are also keyed, which is why the
34
+ * seed says so.
35
+ *
36
+ * ## The animated pose is constant, exactly as it is for a rope
37
+ *
38
+ * §11.1 says a subtree's authored pose is rigid relative to its anchor, so in
39
+ * the anchor's own frame it does not move, and then says "a subtree whose links
40
+ * are themselves animated is not an M1 case — that is the rig path, where the
41
+ * animated pose comes from the skeleton and is live".
42
+ *
43
+ * For a **rigged** garment it is not live either, and the reason is the
44
+ * authority claim above: cloth owns those joints, so nothing else poses them,
45
+ * so their authored pose is the proxy's baked bind pose — constant in the
46
+ * anchor's frame, exactly as a rope's is. What moves is the anchor, and the
47
+ * anchor is a joint of the character's own animated skeleton, whose pose the
48
+ * system evaluates exactly (`t64_evaluate_world`).
49
+ *
50
+ * @author Alex Goldring
51
+ * @copyright Company Named Limited (c) 2026
52
+ */
53
+
54
+ /**
55
+ * Seed `instance` from a proxy and the joints of a skin.
56
+ *
57
+ * @param {ClothInstance} instance seeded in place
58
+ * @param {ClothProxy} proxy
59
+ * @param {number[]} joints the skin's joints as entities, in the order the proxy indexes
60
+ * @param {EntityComponentDataset} ecd
61
+ * @param {number} dt
62
+ */
63
+ export function cloth_seed_rig(instance, proxy, joints, ecd, dt) {
64
+ assert.ok(proxy.isClothProxy === true, 'proxy must be a ClothProxy');
65
+
66
+ const joint_count = proxy.joint_count;
67
+
68
+ // Node 0 is the anchor, exactly as it is for the entity path: the fixed
69
+ // set, the origin of the local frame, and `d_geo = 0`.
70
+ const node_count = joint_count + 1;
71
+
72
+ instance.node_count = node_count;
73
+
74
+ const node_parent = new Int32Array(node_count);
75
+
76
+ node_parent[0] = -1;
77
+
78
+ for (let i = 0; i < joint_count; i++) {
79
+ node_parent[i + 1] = proxy.joint_parent[i] + 1;
80
+ }
81
+
82
+ instance.node_parent = node_parent;
83
+
84
+ const node_joint = new Int32Array(node_count);
85
+
86
+ node_joint[0] = joints[proxy.anchor];
87
+
88
+ const node_attachment = new Array(node_count);
89
+
90
+ node_attachment[0] = null;
91
+
92
+ // What this seeding took, so that giving it back is possible. A revoke that
93
+ // nothing can undo is half a transaction, and the half that is missing is
94
+ // the one that runs when the garment is removed.
95
+ const revoked = [];
96
+
97
+ for (let i = 0; i < joint_count; i++) {
98
+ const joint = joints[proxy.joint[i]];
99
+
100
+ assert.defined(joint, `joint ${proxy.joint[i]} of the skin`);
101
+ assert.ok(ecd.entityExists(joint), `joint ${proxy.joint[i]} of the skin, entity ${joint}, does not exist`);
102
+
103
+ node_joint[i + 1] = joint;
104
+
105
+ const attachment = ecd.getComponent(joint, TransformAttachment);
106
+
107
+ assert.defined(attachment, `joint entity ${joint} carries no TransformAttachment to write`);
108
+
109
+ node_attachment[i + 1] = attachment;
110
+
111
+ // See the module docblock. A clip-driven joint's offset is the GPU's, and taking it back
112
+ // is what makes the write-back reach the row at all. An entity that never declared has
113
+ // nothing to take back.
114
+ if (gpu_authority_revoke(ecd, joint, GPUStateAuthorityFlags.TransformAttachment)) {
115
+ revoked.push(joint);
116
+ }
117
+ }
118
+
119
+ instance.revoked_joints = revoked;
120
+
121
+ instance.node_joint = node_joint;
122
+ instance.node_attachment = node_attachment;
123
+
124
+ // The entity path's arrays have no meaning here and holding stale ones is
125
+ // how a write-back reaches into a previous seeding's entities.
126
+ instance.node_entity = null;
127
+ instance.node_transform = [];
128
+ instance.pruned_count = 0;
129
+ instance.pruned_entity = null;
130
+ instance.pruned_parent = null;
131
+ instance.pruned_transform = [];
132
+ instance.pruned_attachment = [];
133
+
134
+ cloth_build_children(instance);
135
+
136
+ read_bind_pose(instance, proxy);
137
+
138
+ instance.dynamics_seen.copy(instance.cloth.dynamics);
139
+
140
+ cloth_build_rows(instance, dt);
141
+
142
+ instance.seeded = true;
143
+ }
144
+
145
+ /**
146
+ * The proxy's bind pose, composed: local offsets per node and the position and
147
+ * rotation of every node in the anchor's frame.
148
+ *
149
+ * @param {ClothInstance} instance
150
+ * @param {ClothProxy} proxy
151
+ */
152
+ function read_bind_pose(instance, proxy) {
153
+ const node_count = instance.node_count;
154
+
155
+ const local_position = new Float32Array(node_count * 3);
156
+ const local_rotation = new Float32Array(node_count * 4);
157
+
158
+ const position = new Float32Array(node_count * 3);
159
+ const rotation = new Float32Array(node_count * 4);
160
+
161
+ // The anchor is the origin of the frame it anchors.
162
+ local_rotation[3] = 1;
163
+ rotation[3] = 1;
164
+
165
+ const parent = instance.node_parent;
166
+
167
+ for (let node = 1; node < node_count; node++) {
168
+ const joint = node - 1;
169
+
170
+ local_position[node * 3] = proxy.rest_position[joint * 3];
171
+ local_position[node * 3 + 1] = proxy.rest_position[joint * 3 + 1];
172
+ local_position[node * 3 + 2] = proxy.rest_position[joint * 3 + 2];
173
+
174
+ local_rotation[node * 4] = proxy.rest_rotation[joint * 4];
175
+ local_rotation[node * 4 + 1] = proxy.rest_rotation[joint * 4 + 1];
176
+ local_rotation[node * 4 + 2] = proxy.rest_rotation[joint * 4 + 2];
177
+ local_rotation[node * 4 + 3] = proxy.rest_rotation[joint * 4 + 3];
178
+
179
+ const p = parent[node];
180
+
181
+ const pqx = rotation[p * 4];
182
+ const pqy = rotation[p * 4 + 1];
183
+ const pqz = rotation[p * 4 + 2];
184
+ const pqw = rotation[p * 4 + 3];
185
+
186
+ v3_quaternion_apply(
187
+ COMPOSE, 0,
188
+ local_position[node * 3], local_position[node * 3 + 1], local_position[node * 3 + 2],
189
+ pqx, pqy, pqz, pqw
190
+ );
191
+
192
+ position[node * 3] = position[p * 3] + COMPOSE[0];
193
+ position[node * 3 + 1] = position[p * 3 + 1] + COMPOSE[1];
194
+ position[node * 3 + 2] = position[p * 3 + 2] + COMPOSE[2];
195
+
196
+ quat3_multiply(
197
+ rotation, node * 4,
198
+ pqx, pqy, pqz, pqw,
199
+ local_rotation[node * 4], local_rotation[node * 4 + 1],
200
+ local_rotation[node * 4 + 2], local_rotation[node * 4 + 3]
201
+ );
202
+ }
203
+
204
+ instance.rest_local_position = local_position;
205
+ instance.rest_local_rotation = local_rotation;
206
+
207
+ instance.animated_position = position;
208
+ instance.animated_rotation = rotation;
209
+ }
210
+
211
+ /**
212
+ * Give back every joint's `TransformAttachment` authority that this cloth's
213
+ * seeding took from the GPU.
214
+ *
215
+ * The seed revokes so that the write-back reaches the row at all, and the
216
+ * consequence the module docblock states — "a joint cloth simulates stops being
217
+ * animatable by a clip" — is only the right trade while the cloth is *there*.
218
+ * A garment removed and nothing re-granting leaves its joints owned by a CPU
219
+ * that is no longer writing them: neither animated nor simulated, and stuck in
220
+ * the pose the solver stopped in.
221
+ *
222
+ * Only the joints the revoke actually changed are given back, so a joint that
223
+ * was already the CPU's before cloth arrived stays the CPU's.
224
+ *
225
+ * @param {ClothInstance} instance
226
+ * @param {EntityComponentDataset} ecd
227
+ * @returns {void}
228
+ */
229
+ export function cloth_release_rig(instance, ecd) {
230
+ const revoked = instance.revoked_joints;
231
+
232
+ if (revoked === null) {
233
+ return;
234
+ }
235
+
236
+ for (let i = 0; i < revoked.length; i++) {
237
+ const joint = revoked[i];
238
+
239
+ if (!ecd.entityExists(joint)) {
240
+ continue;
241
+ }
242
+
243
+ gpu_authority_grant(ecd, joint, GPUStateAuthorityFlags.TransformAttachment);
244
+ }
245
+
246
+ instance.revoked_joints = null;
247
+ }
248
+
249
+ const COMPOSE = new Float64Array(3);
@@ -55,5 +55,26 @@
55
55
  * @returns {void}
56
56
  */
57
57
  export function cloth_seed_subtree(instance: ClothInstance, ecd: EntityComponentDataset, attachments: TransformAttachmentSystem, dt: number): void;
58
+ /**
59
+ * Put the authored local transforms back on the subtree and announce, so a
60
+ * cloth that is taken away leaves the hierarchy the way it found it.
61
+ *
62
+ * `cloth_write_back` overwrites every simulated node's
63
+ * `TransformAttachment#transform` with the solved local pose, every step. That
64
+ * is what makes a recomposition reproduce the simulation rather than undo it —
65
+ * and it means the authored pose exists nowhere but inside the cloth. Removing
66
+ * the component without this leaves the subtree frozen in whatever shape the
67
+ * solver stopped in, and a `Cloth` added back seeds *that* as the pose it is
68
+ * supposed to return to at `blend = 0`.
69
+ *
70
+ * One announcement, on the anchor, which is the same shape the write-back's own
71
+ * pruned-boundary pass uses: everything below is composed by the attachment
72
+ * cascade rather than by a second walk here.
73
+ *
74
+ * @param {ClothInstance} instance
75
+ * @param {EntityComponentDataset} ecd
76
+ * @returns {void}
77
+ */
78
+ export function cloth_release_subtree(instance: ClothInstance, ecd: EntityComponentDataset): void;
58
79
  import { ClothInstance } from "./ClothInstance.js";
59
80
  //# sourceMappingURL=cloth_seed_subtree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_seed_subtree.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_seed_subtree.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH;;;;;;;;;GASG;AACH,6CAPW,aAAa,2EAGb,MAAM,GAEJ,IAAI,CAwGhB;8BAlK6B,oBAAoB"}
1
+ {"version":3,"file":"cloth_seed_subtree.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_seed_subtree.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH;;;;;;;;;GASG;AACH,6CAPW,aAAa,2EAGb,MAAM,GAEJ,IAAI,CAwGhB;AA6GD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,gDAJW,aAAa,gCAEX,IAAI,CAkChB;8BAnU6B,oBAAoB"}
@@ -4,6 +4,7 @@ import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_ap
4
4
  import { GPUStateAuthorityFlags } from "../../../ecs/gpu/GPUStateAuthorityFlags.js";
5
5
  import { gpu_authority_assert_cpu } from "../../../ecs/gpu/gpu_authority_assert_cpu.js";
6
6
  import { TransformAttachment } from "../../../ecs/transform-attachment/TransformAttachment.js";
7
+ import { t64_announce_change } from "../../../ecs/transform/t64_announce_change.js";
7
8
  import {
8
9
  TRANSFORM64_ROTATION_OFFSET,
9
10
  TRANSFORM64_TRANSLATION_OFFSET,
@@ -282,6 +283,60 @@ function read_rest_pose(instance, remembered) {
282
283
  instance.animated_rotation = rotation;
283
284
  }
284
285
 
286
+ /**
287
+ * Put the authored local transforms back on the subtree and announce, so a
288
+ * cloth that is taken away leaves the hierarchy the way it found it.
289
+ *
290
+ * `cloth_write_back` overwrites every simulated node's
291
+ * `TransformAttachment#transform` with the solved local pose, every step. That
292
+ * is what makes a recomposition reproduce the simulation rather than undo it —
293
+ * and it means the authored pose exists nowhere but inside the cloth. Removing
294
+ * the component without this leaves the subtree frozen in whatever shape the
295
+ * solver stopped in, and a `Cloth` added back seeds *that* as the pose it is
296
+ * supposed to return to at `blend = 0`.
297
+ *
298
+ * One announcement, on the anchor, which is the same shape the write-back's own
299
+ * pruned-boundary pass uses: everything below is composed by the attachment
300
+ * cascade rather than by a second walk here.
301
+ *
302
+ * @param {ClothInstance} instance
303
+ * @param {EntityComponentDataset} ecd
304
+ * @returns {void}
305
+ */
306
+ export function cloth_release_subtree(instance, ecd) {
307
+ const rest_position = instance.rest_local_position;
308
+ const rest_rotation = instance.rest_local_rotation;
309
+
310
+ if (rest_position === null || instance.node_entity === null) {
311
+ return;
312
+ }
313
+
314
+ const node_count = instance.node_count;
315
+
316
+ for (let node = 1; node < node_count; node++) {
317
+ const attachment = instance.node_attachment[node];
318
+
319
+ if (attachment === undefined || attachment === null) {
320
+ continue;
321
+ }
322
+
323
+ const transform = attachment.transform;
324
+
325
+ transform.setTranslation(
326
+ rest_position[node * 3], rest_position[node * 3 + 1], rest_position[node * 3 + 2]
327
+ );
328
+
329
+ transform.setRotation(
330
+ rest_rotation[node * 4], rest_rotation[node * 4 + 1],
331
+ rest_rotation[node * 4 + 2], rest_rotation[node * 4 + 3]
332
+ );
333
+
334
+ transform.updateMatrix();
335
+ }
336
+
337
+ t64_announce_change(ecd, instance.node_entity[0]);
338
+ }
339
+
285
340
  /**
286
341
  * @type {Float64Array}
287
342
  * @private
@@ -300,7 +355,13 @@ const COMPOSE = new Float64Array(3);
300
355
  function remember_rest_pose(instance) {
301
356
  const remembered = new Map();
302
357
 
303
- if (!instance.seeded || instance.rest_local_position === null) {
358
+ // Keyed on there *being* a previous capture rather than on
359
+ // {@link ClothInstance#seeded}, because `ClothWorld#reseed` clears `seeded`
360
+ // before this runs — which made the one path that exists to re-walk a live
361
+ // cloth the one path that could not remember anything. `node_entity` is
362
+ // null for a cloth that was previously seeded as a rig, whose captured pose
363
+ // is a joint's and not this walk's.
364
+ if (instance.rest_local_position === null || instance.node_entity === null) {
304
365
  return remembered;
305
366
  }
306
367
 
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_write_back.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_write_back.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH;;;;;;GAMG;AACH,wFAFa,IAAI,CAmDhB;AAyBD;;;;;;;;;GASG;AACH,0FAJW,MAAM,UACN,MAAM,GACJ,IAAI,CA4BhB"}
1
+ {"version":3,"file":"cloth_write_back.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_write_back.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH;;;;;;GAMG;AACH,wFAFa,IAAI,CA2DhB;AAyBD;;;;;;;;;GASG;AACH,0FAJW,MAAM,UACN,MAAM,GACJ,IAAI,CA4BhB"}
@@ -76,16 +76,24 @@ export function cloth_write_back(instance, ecd) {
76
76
  const blended = instance.blended_position;
77
77
  const reconstructed = instance.blended_rotation;
78
78
 
79
- const anchor = instance.node_transform[0];
80
-
81
- const ax = anchor[TRANSFORM64_TRANSLATION_OFFSET];
82
- const ay = anchor[TRANSFORM64_TRANSLATION_OFFSET + 1];
83
- const az = anchor[TRANSFORM64_TRANSLATION_OFFSET + 2];
84
-
85
- const aqx = anchor[TRANSFORM64_ROTATION_OFFSET];
86
- const aqy = anchor[TRANSFORM64_ROTATION_OFFSET + 1];
87
- const aqz = anchor[TRANSFORM64_ROTATION_OFFSET + 2];
88
- const aqw = anchor[TRANSFORM64_ROTATION_OFFSET + 3];
79
+ // The anchor pose the particles were carried into **this step**, not the
80
+ // live component. For `ClothSystem` those are the same value, because the
81
+ // step happened between them. For `WorkerClothSystem` they are not: it
82
+ // writes step T−1 back at the top of tick T, by which time the anchor has
83
+ // moved on, and composing last step's shape against this tick's anchor
84
+ // produces a world pose that describes neither. Nothing rendered can tell —
85
+ // the attachment cascade re-derives position from the anchor and the local
86
+ // transforms either way (§4.1) — but a **nested** cloth reads this pose as
87
+ // its own anchor, and then the two systems hand it different numbers.
88
+ // `MEASUREMENTS.md` §56.
89
+ const ax = instance.anchor_translation[0];
90
+ const ay = instance.anchor_translation[1];
91
+ const az = instance.anchor_translation[2];
92
+
93
+ const aqx = instance.anchor_rotation[0];
94
+ const aqy = instance.anchor_rotation[1];
95
+ const aqz = instance.anchor_rotation[2];
96
+ const aqw = instance.anchor_rotation[3];
89
97
 
90
98
  const parent = instance.node_parent;
91
99
 
@@ -173,7 +173,7 @@ function step_once() {
173
173
 
174
174
  const started = performance.now();
175
175
 
176
- contact_rows = cloth_contact_find(state, colliders.table, colliders.keys, colliders.count);
176
+ contact_rows = cloth_contact_find(state, colliders.table, colliders.keys, colliders.count, FIXED_STEP);
177
177
 
178
178
  cloth_step(
179
179
  state, FIXED_STEP, 0, -9.81, 0,