@woosh/meep-engine 3.40.0 → 3.42.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 (539) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/editor/selection/editor_pick.d.ts.map +1 -1
  4. package/editor/selection/editor_pick.js +2 -1
  5. package/editor/tools/TransformToolV2.d.ts.map +1 -1
  6. package/editor/tools/TransformToolV2.js +7 -1
  7. package/editor/tools/engine/ToolEngine.d.ts.map +1 -1
  8. package/editor/tools/engine/ToolEngine.js +10 -0
  9. package/editor/tools/v2/TransformControls.d.ts.map +1 -1
  10. package/editor/tools/v2/TransformControls.js +7 -20
  11. package/editor/tools/v2/handle/gizmo_drag_plane.d.ts.map +1 -1
  12. package/editor/tools/v2/handle/gizmo_drag_plane.js +4 -0
  13. package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
  14. package/editor/view/ecs/EntityEditor.js +3 -1
  15. package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
  16. package/editor/view/node-graph/NodeGraphView.js +28 -12
  17. package/package.json +1 -1
  18. package/samples/engine/first-scene/index.html +4 -1
  19. package/samples/engine/first-scene/main.js +14 -9
  20. package/src/core/binary/utf8/utf8_decode.js +3 -3
  21. package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.d.ts.map +1 -1
  22. package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.js +112 -113
  23. package/src/core/bvh2/bvh3/ebvh_nodes_sort_sah_local4.js +2 -2
  24. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +14 -14
  25. package/src/core/collection/RingBuffer.d.ts.map +1 -1
  26. package/src/core/collection/RingBuffer.js +4 -0
  27. package/src/core/collection/array/array_contains_duplicates.d.ts.map +1 -1
  28. package/src/core/collection/array/array_contains_duplicates.js +2 -1
  29. package/src/core/collection/array/array_copy.d.ts.map +1 -1
  30. package/src/core/collection/array/array_copy.js +23 -0
  31. package/src/core/collection/array/typed/sparse_typed_array_hash.d.ts +2 -2
  32. package/src/core/collection/array/typed/sparse_typed_array_hash.d.ts.map +1 -1
  33. package/src/core/collection/array/typed/sparse_typed_array_hash.js +9 -8
  34. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -2
  35. package/src/core/collection/array/typed/uint16_array_hash.js +4 -4
  36. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -2
  37. package/src/core/collection/array/typed/uint8_array_hash.js +4 -4
  38. package/src/core/collection/array/weightedRandomFromArray.d.ts +1 -0
  39. package/src/core/collection/array/weightedRandomFromArray.d.ts.map +1 -1
  40. package/src/core/collection/array/weightedRandomFromArray.js +9 -1
  41. package/src/core/collection/heap/BinaryHeap.d.ts.map +1 -1
  42. package/src/core/collection/heap/BinaryHeap.js +4 -0
  43. package/src/core/collection/list/List.d.ts.map +1 -1
  44. package/src/core/collection/list/List.js +4 -2
  45. package/src/core/collection/set/ArraySet.js +1 -1
  46. package/src/core/collection/set/HashSet.d.ts +1 -1
  47. package/src/core/collection/set/HashSet.d.ts.map +1 -1
  48. package/src/core/collection/set/HashSet.js +4 -2
  49. package/src/core/debug/matchers/IsEqual.js +1 -1
  50. package/src/core/debug/matchers/IsIterableContaining.d.ts.map +1 -1
  51. package/src/core/debug/matchers/IsIterableContaining.js +61 -74
  52. package/src/core/events/signal/SignalBinding.js +101 -101
  53. package/src/core/function/extractFunctionBody.js +13 -13
  54. package/src/core/function/objectsEqual.d.ts.map +1 -1
  55. package/src/core/function/objectsEqual.js +15 -14
  56. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.d.ts.map +1 -1
  57. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +207 -172
  58. package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
  59. package/src/core/geom/3d/gjk/gjk_epa_penetration.js +5 -4
  60. package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.d.ts.map +1 -1
  61. package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.js +8 -2
  62. package/src/core/geom/3d/quaternion/swing_twist_clamp.d.ts +24 -0
  63. package/src/core/geom/3d/quaternion/swing_twist_clamp.d.ts.map +1 -0
  64. package/src/core/geom/3d/quaternion/swing_twist_clamp.js +62 -0
  65. package/src/core/geom/3d/quaternion/swing_twist_compose.d.ts +15 -0
  66. package/src/core/geom/3d/quaternion/swing_twist_compose.d.ts.map +1 -0
  67. package/src/core/geom/3d/quaternion/swing_twist_compose.js +36 -0
  68. package/src/core/geom/3d/quaternion/swing_twist_error.d.ts +39 -0
  69. package/src/core/geom/3d/quaternion/swing_twist_error.d.ts.map +1 -0
  70. package/src/core/geom/3d/quaternion/swing_twist_error.js +85 -0
  71. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts +20 -0
  72. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  73. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +182 -0
  74. package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.d.ts +11 -6
  75. package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.d.ts.map +1 -1
  76. package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.js +27 -13
  77. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.d.ts +25 -0
  78. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.d.ts.map +1 -0
  79. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.js +166 -0
  80. package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.d.ts +5 -3
  81. package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.d.ts.map +1 -1
  82. package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.js +5 -3
  83. package/src/core/math/noise/curl_noise_3dt.d.ts.map +1 -1
  84. package/src/core/math/noise/curl_noise_3dt.js +20 -10
  85. package/src/core/math/noise/sdnoise.d.ts +16 -5
  86. package/src/core/math/noise/sdnoise.d.ts.map +1 -1
  87. package/src/core/math/noise/sdnoise.js +43 -9
  88. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -1
  89. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  90. package/src/core/math/spline/spline3_hermite_nearest_point.js +44 -3
  91. package/src/engine/Engine.d.ts.map +1 -1
  92. package/src/engine/Engine.js +6 -2
  93. package/src/engine/animation/curve/AnimationCurve.d.ts +3 -0
  94. package/src/engine/animation/curve/AnimationCurve.d.ts.map +1 -1
  95. package/src/engine/animation/curve/AnimationCurve.js +6 -1
  96. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +9 -0
  97. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  98. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +26 -0
  99. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  100. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +2 -0
  101. package/src/engine/control/first-person/abilities/AbilitySet.d.ts.map +1 -1
  102. package/src/engine/control/first-person/abilities/AbilitySet.js +9 -0
  103. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -1
  104. package/src/engine/control/first-person/abilities/LedgeGrab.js +6 -0
  105. package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -1
  106. package/src/engine/control/first-person/abilities/Slide.js +1 -0
  107. package/src/engine/control/first-person/abilities/WallRun.d.ts +4 -1
  108. package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -1
  109. package/src/engine/control/first-person/abilities/WallRun.js +13 -1
  110. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts +1 -1
  111. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts.map +1 -1
  112. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.js +6 -5
  113. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts +3 -3
  114. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts.map +1 -1
  115. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.js +9 -8
  116. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -1
  117. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +13 -4
  118. package/src/engine/ecs/EntityManager.d.ts +9 -1
  119. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  120. package/src/engine/ecs/EntityManager.js +44 -42
  121. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.d.ts.map +1 -1
  122. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.js +2 -1
  123. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescriptionTable.d.ts.map +1 -1
  124. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescriptionTable.js +1 -0
  125. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
  126. package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +3 -0
  127. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts +20 -0
  128. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts.map +1 -1
  129. package/src/engine/ecs/gpu/GPUStateAuthority.js +21 -0
  130. package/src/engine/ecs/gpu/GPU_AUTHORITY_EVENT_HOLD_CHANGE.d.ts +13 -0
  131. package/src/engine/ecs/gpu/GPU_AUTHORITY_EVENT_HOLD_CHANGE.d.ts.map +1 -0
  132. package/src/engine/ecs/gpu/GPU_AUTHORITY_EVENT_HOLD_CHANGE.js +12 -0
  133. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts +6 -0
  134. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts.map +1 -1
  135. package/src/engine/ecs/gpu/gpu_authority_grant.js +7 -1
  136. package/src/engine/ecs/gpu/gpu_authority_held.d.ts +14 -0
  137. package/src/engine/ecs/gpu/gpu_authority_held.d.ts.map +1 -0
  138. package/src/engine/ecs/gpu/gpu_authority_held.js +23 -0
  139. package/src/engine/ecs/gpu/gpu_authority_hold.d.ts +23 -0
  140. package/src/engine/ecs/gpu/gpu_authority_hold.d.ts.map +1 -0
  141. package/src/engine/ecs/gpu/gpu_authority_hold.js +41 -0
  142. package/src/engine/ecs/gpu/gpu_authority_unhold.d.ts +14 -0
  143. package/src/engine/ecs/gpu/gpu_authority_unhold.d.ts.map +1 -0
  144. package/src/engine/ecs/gpu/gpu_authority_unhold.js +32 -0
  145. package/src/engine/ecs/ik/IKGoal.d.ts +59 -0
  146. package/src/engine/ecs/ik/IKGoal.d.ts.map +1 -0
  147. package/src/engine/ecs/ik/IKGoal.js +83 -0
  148. package/src/engine/ecs/ik/IKGoalSystem.d.ts +75 -0
  149. package/src/engine/ecs/ik/IKGoalSystem.d.ts.map +1 -0
  150. package/src/engine/ecs/ik/IKGoalSystem.js +1456 -0
  151. package/src/engine/ecs/ik/PLAN.md +179 -0
  152. package/src/engine/ecs/parent/EntityNode.js +3 -3
  153. package/src/engine/ecs/speaker/VoiceSystem.d.ts +2 -2
  154. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  155. package/src/engine/ecs/speaker/VoiceSystem.js +4 -0
  156. package/src/engine/ecs/storage/BinaryBufferDeSerializer.js +5 -5
  157. package/src/engine/ecs/storage/BinaryBufferSerializer.d.ts.map +1 -1
  158. package/src/engine/ecs/storage/BinaryBufferSerializer.js +4 -5
  159. package/src/engine/ecs/storage/binary/BinarySerializationRegistry.d.ts.map +1 -1
  160. package/src/engine/ecs/storage/binary/BinarySerializationRegistry.js +3 -2
  161. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +7 -3
  162. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter2.js +1 -1
  163. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.d.ts.map +1 -1
  164. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.js +8 -1
  165. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  166. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +9 -2
  167. package/src/engine/ecs/system/orderSystemsByDeclaredAccess.d.ts +33 -0
  168. package/src/engine/ecs/system/orderSystemsByDeclaredAccess.d.ts.map +1 -0
  169. package/src/engine/ecs/system/orderSystemsByDeclaredAccess.js +282 -0
  170. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  171. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +5 -2
  172. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.d.ts.map +1 -1
  173. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +3 -0
  174. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.d.ts.map +1 -1
  175. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -0
  176. package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +1 -1
  177. package/src/engine/ecs/terrain/tiles/TerrainTile.d.ts.map +1 -1
  178. package/src/engine/ecs/terrain/tiles/TerrainTile.js +13 -1
  179. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
  180. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +1 -0
  181. package/src/engine/ecs/transform/T64WorldCache.js +139 -139
  182. package/src/engine/ecs/transform/t64_evaluate_local.d.ts +25 -0
  183. package/src/engine/ecs/transform/t64_evaluate_local.d.ts.map +1 -0
  184. package/src/engine/ecs/transform/t64_evaluate_local.js +35 -0
  185. package/src/engine/ecs/transform/t64_evaluate_world.d.ts +5 -3
  186. package/src/engine/ecs/transform/t64_evaluate_world.d.ts.map +1 -1
  187. package/src/engine/ecs/transform/t64_evaluate_world.js +128 -126
  188. package/src/engine/graphics/ecs/light/LightSerializationAdapter.d.ts.map +1 -1
  189. package/src/engine/graphics/ecs/light/LightSerializationAdapter.js +13 -1
  190. package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.d.ts +5 -0
  191. package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.d.ts.map +1 -0
  192. package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.js +27 -0
  193. package/src/engine/graphics/ecs/water/Water.d.ts +11 -0
  194. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  195. package/src/engine/graphics/ecs/water/Water.js +17 -0
  196. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
  197. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +3 -1
  198. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.d.ts +9 -0
  199. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.d.ts.map +1 -0
  200. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.js +24 -0
  201. package/src/engine/graphics/ecs/water/WaterWaves.d.ts +30 -9
  202. package/src/engine/graphics/ecs/water/WaterWaves.d.ts.map +1 -1
  203. package/src/engine/graphics/ecs/water/WaterWaves.js +41 -9
  204. package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.d.ts.map +1 -1
  205. package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.js +30 -26
  206. package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.d.ts +6 -0
  207. package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.d.ts.map +1 -0
  208. package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.js +22 -0
  209. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.d.ts.map +1 -1
  210. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.js +3 -5
  211. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +20 -0
  212. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -1
  213. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +36 -0
  214. package/src/engine/graphics3/AnimationGraphSystem.d.ts +2 -0
  215. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  216. package/src/engine/graphics3/AnimationGraphSystem.js +337 -329
  217. package/src/engine/graphics3/AnimationSystem.d.ts +2 -0
  218. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  219. package/src/engine/graphics3/AnimationSystem.js +360 -352
  220. package/src/engine/graphics3/WaterSystem.d.ts +12 -3
  221. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  222. package/src/engine/graphics3/WaterSystem.js +78 -46
  223. package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
  224. package/src/engine/input/devices/PointerDevice.js +29 -4
  225. package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.d.ts +1 -0
  226. package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.d.ts.map +1 -1
  227. package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.js +14 -3
  228. package/src/engine/physics/cloth/MEASUREMENTS.md +130 -0
  229. package/src/engine/physics/cloth/PLAN.md +16 -1
  230. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +5 -6
  231. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
  232. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +5 -6
  233. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +4 -7
  234. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  235. package/src/engine/physics/cloth/ecs/ClothInstance.js +4 -7
  236. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +4 -3
  237. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  238. package/src/engine/physics/cloth/ecs/ClothSystem.js +4 -3
  239. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  240. package/src/engine/physics/cloth/ecs/ClothWorld.js +10 -0
  241. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +24 -24
  242. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  243. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +46 -43
  244. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +1 -1
  245. package/src/engine/physics/cloth/ecs/cloth_write_back.js +1 -1
  246. package/src/engine/physics/constraint/solve_constraints.d.ts +0 -35
  247. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  248. package/src/engine/physics/constraint/solve_constraints.js +1 -83
  249. package/src/engine/physics/ecs/ContactProbe.d.ts +73 -0
  250. package/src/engine/physics/ecs/ContactProbe.d.ts.map +1 -0
  251. package/src/engine/physics/ecs/ContactProbe.js +103 -0
  252. package/src/engine/physics/ecs/ContactProbeSystem.d.ts +44 -0
  253. package/src/engine/physics/ecs/ContactProbeSystem.d.ts.map +1 -0
  254. package/src/engine/physics/ecs/ContactProbeSystem.js +397 -0
  255. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +1 -1
  256. package/src/engine/physics/fluid/ecs/FluidComponent.js +1 -1
  257. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  258. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -1
  259. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +12 -3
  260. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -1
  261. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +8 -2
  262. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts +19 -0
  263. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts.map +1 -1
  264. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.js +41 -2
  265. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts.map +1 -1
  266. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +9 -3
  267. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.d.ts.map +1 -1
  268. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.js +26 -10
  269. package/src/engine/physics/inverse_kinematics/frame_fabrik/FrameFabrikProblem.d.ts +205 -0
  270. package/src/engine/physics/inverse_kinematics/frame_fabrik/FrameFabrikProblem.d.ts.map +1 -0
  271. package/src/engine/physics/inverse_kinematics/frame_fabrik/FrameFabrikProblem.js +245 -0
  272. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_limit_from_joint.d.ts +21 -0
  273. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_limit_from_joint.d.ts.map +1 -0
  274. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_limit_from_joint.js +63 -0
  275. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts +33 -0
  276. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts.map +1 -0
  277. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.js +874 -0
  278. package/src/engine/physics/inverse_kinematics/joint_hinge_mid_axis.d.ts +27 -0
  279. package/src/engine/physics/inverse_kinematics/joint_hinge_mid_axis.d.ts.map +1 -0
  280. package/src/engine/physics/inverse_kinematics/joint_hinge_mid_axis.js +77 -0
  281. package/src/engine/physics/inverse_kinematics/two_bone_path_solve.d.ts +36 -0
  282. package/src/engine/physics/inverse_kinematics/two_bone_path_solve.d.ts.map +1 -0
  283. package/src/engine/physics/inverse_kinematics/two_bone_path_solve.js +97 -0
  284. package/src/engine/physics/inverse_kinematics/two_joint_ik.d.ts +33 -11
  285. package/src/engine/physics/inverse_kinematics/two_joint_ik.d.ts.map +1 -1
  286. package/src/engine/physics/inverse_kinematics/two_joint_ik.js +158 -67
  287. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +3 -6
  288. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
  289. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +22 -9
  290. package/src/engine/ui/DraggableAspect.d.ts +5 -1
  291. package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
  292. package/src/engine/ui/DraggableAspect.js +61 -4
  293. package/src/format/image/avif/heif/ItemProperty.d.ts +1 -1
  294. package/src/format/image/avif/heif/ItemProperty.js +1 -1
  295. package/src/format/image/png/chunk/png_chunk_decode_iTXt.d.ts.map +1 -1
  296. package/src/format/image/png/chunk/png_chunk_decode_iTXt.js +17 -6
  297. package/src/shade/device/mock/SoftwareGPUDevice.d.ts +2 -4
  298. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  299. package/src/shade/device/mock/SoftwareGPUDevice.js +20 -13
  300. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts.map +1 -1
  301. package/src/shade/playground/skinned_blas_refit/sweep_views.js +2 -1
  302. package/src/shade/playground/water_refraction/README.md +10 -11
  303. package/src/shade/playground/water_refraction/main.js +9 -8
  304. package/src/shade/playground/water_refraction/world.js +1 -1
  305. package/src/shade/playground/water_surface/README.md +43 -0
  306. package/src/shade/playground/water_surface/index.html +30 -0
  307. package/src/shade/playground/water_surface/main.d.ts +2 -0
  308. package/src/shade/playground/water_surface/main.d.ts.map +1 -0
  309. package/src/shade/playground/water_surface/main.js +154 -0
  310. package/src/shade/playground/water_surface/world.d.ts +44 -0
  311. package/src/shade/playground/water_surface/world.d.ts.map +1 -0
  312. package/src/shade/playground/water_surface/world.js +160 -0
  313. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts.map +1 -1
  314. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.js +10 -1
  315. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +10 -4
  316. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  317. package/src/shade/renderer/animation/GPUAnimationManager.js +251 -23
  318. package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.d.ts +12 -4
  319. package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.d.ts.map +1 -1
  320. package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.js +12 -4
  321. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
  322. package/src/shade/renderer/animation/chunk_pose_accumulator.js +14 -1
  323. package/src/shade/renderer/animation/pose/PoseChannelIndex.d.ts +78 -0
  324. package/src/shade/renderer/animation/pose/PoseChannelIndex.d.ts.map +1 -0
  325. package/src/shade/renderer/animation/pose/PoseChannelIndex.js +274 -0
  326. package/src/shade/renderer/animation/pose/PosePlayback.d.ts +40 -3
  327. package/src/shade/renderer/animation/pose/PosePlayback.d.ts.map +1 -1
  328. package/src/shade/renderer/animation/pose/PosePlayback.js +77 -3
  329. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts +21 -3
  330. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts.map +1 -1
  331. package/src/shade/renderer/animation/pose/pose_evaluate_local.js +79 -11
  332. package/src/shade/renderer/animation/shader_animation_apply.js +1 -1
  333. package/src/shade/renderer/animation/shader_animation_pose_resolve.d.ts +3 -2
  334. package/src/shade/renderer/animation/shader_animation_pose_resolve.d.ts.map +1 -1
  335. package/src/shade/renderer/animation/shader_animation_pose_resolve.js +187 -176
  336. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  337. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +5 -0
  338. package/src/shade/renderer/binding/BufferBinding.js +2 -2
  339. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  340. package/src/shade/renderer/buffer/table/GPUTypedTable.js +5 -3
  341. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts +10 -3
  342. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts.map +1 -1
  343. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.js +17 -9
  344. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +3 -0
  345. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +1 -1
  346. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +16 -0
  347. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +2 -0
  348. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +1 -1
  349. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +11 -0
  350. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +1 -1
  351. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  352. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +9 -3
  353. package/src/shade/renderer/geometry/util/geometry_simplify_redundant_topology.d.ts.map +1 -1
  354. package/src/shade/renderer/geometry/util/geometry_simplify_redundant_topology.js +2 -2
  355. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  356. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +85 -0
  357. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  358. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +12 -6
  359. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
  360. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +7 -0
  361. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  362. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +3 -1
  363. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  364. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts +3 -1
  365. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts.map +1 -1
  366. package/src/shade/renderer/object_property/chunk_write_object_property.js +5 -2
  367. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts +4 -0
  368. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts.map +1 -1
  369. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.js +6 -1
  370. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  371. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +2 -1
  372. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.d.ts +1 -1
  373. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.d.ts.map +1 -1
  374. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.js +135 -73
  375. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.d.ts +7 -0
  376. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.d.ts.map +1 -1
  377. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.js +29 -1
  378. package/src/shade/renderer/scene/optimization/geometry/internal/face_neighbourhood_hash.d.ts +19 -0
  379. package/src/shade/renderer/scene/optimization/geometry/internal/face_neighbourhood_hash.d.ts.map +1 -0
  380. package/src/shade/renderer/scene/optimization/geometry/internal/face_neighbourhood_hash.js +167 -0
  381. package/src/shade/renderer/scene/optimization/geometry/internal/neighbourhood_anchor_index.d.ts +25 -0
  382. package/src/shade/renderer/scene/optimization/geometry/internal/neighbourhood_anchor_index.d.ts.map +1 -0
  383. package/src/shade/renderer/scene/optimization/geometry/internal/neighbourhood_anchor_index.js +124 -0
  384. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_face_pair.d.ts +19 -0
  385. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_face_pair.d.ts.map +1 -0
  386. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_face_pair.js +48 -0
  387. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +17 -1
  388. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  389. package/src/shade/renderer/scene/rows/GPUSceneRows.js +29 -3
  390. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.d.ts +13 -0
  391. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.d.ts.map +1 -0
  392. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.js +42 -0
  393. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.d.ts +15 -0
  394. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.d.ts.map +1 -0
  395. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.js +39 -0
  396. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  397. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +2 -0
  398. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +15 -0
  399. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  400. package/src/shade/renderer/water/GPUWaterRenderer.js +110 -30
  401. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +16 -8
  402. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  403. package/src/shade/renderer/water/medium/GPUWaterBodies.js +31 -26
  404. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts +0 -1
  405. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts.map +1 -1
  406. package/src/shade/renderer/water/medium/shader_water_meshlets.js +1 -39
  407. package/src/shade/renderer/water/shader_water.d.ts +0 -1
  408. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  409. package/src/shade/renderer/water/shader_water.js +201 -72
  410. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts +70 -0
  411. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -0
  412. package/src/shade/renderer/water/surface/GPUWaterSurface.js +199 -0
  413. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts +5 -2
  414. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts.map +1 -1
  415. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.js +32 -12
  416. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +22 -0
  417. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts.map +1 -0
  418. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +217 -0
  419. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +65 -11
  420. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  421. package/src/shade/renderer/water/surface/graph_water_tessellation.js +163 -28
  422. package/src/shade/renderer/water/surface/lod/WATER_LOD.d.ts +51 -0
  423. package/src/shade/renderer/water/surface/lod/WATER_LOD.d.ts.map +1 -0
  424. package/src/shade/renderer/water/surface/lod/WATER_LOD.js +95 -0
  425. package/src/shade/renderer/water/surface/lod/chunk_water_lod.d.ts +10 -0
  426. package/src/shade/renderer/water/surface/lod/chunk_water_lod.d.ts.map +1 -0
  427. package/src/shade/renderer/water/surface/lod/chunk_water_lod.js +127 -0
  428. package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.d.ts +17 -0
  429. package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.d.ts.map +1 -0
  430. package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.js +246 -0
  431. package/src/shade/renderer/water/surface/lod/shader_water_lod.d.ts +118 -0
  432. package/src/shade/renderer/water/surface/lod/shader_water_lod.d.ts.map +1 -0
  433. package/src/shade/renderer/water/surface/lod/shader_water_lod.js +727 -0
  434. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts +60 -0
  435. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -0
  436. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +228 -0
  437. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +17 -0
  438. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -0
  439. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +49 -0
  440. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +22 -0
  441. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -0
  442. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +143 -0
  443. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +15 -0
  444. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -0
  445. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +121 -0
  446. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +83 -0
  447. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -0
  448. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +502 -0
  449. package/src/shade/renderer/water/surface/shader_water_cull.d.ts +42 -0
  450. package/src/shade/renderer/water/surface/shader_water_cull.d.ts.map +1 -0
  451. package/src/shade/renderer/water/surface/shader_water_cull.js +269 -0
  452. package/src/shade/renderer/water/surface/shader_water_waves_combine.d.ts +15 -0
  453. package/src/shade/renderer/water/surface/shader_water_waves_combine.d.ts.map +1 -0
  454. package/src/shade/renderer/water/surface/shader_water_waves_combine.js +73 -0
  455. package/src/shade/renderer/water/surface/shader_water_waves_derive.d.ts +11 -0
  456. package/src/shade/renderer/water/surface/shader_water_waves_derive.d.ts.map +1 -0
  457. package/src/shade/renderer/water/surface/shader_water_waves_derive.js +78 -0
  458. package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.d.ts +35 -0
  459. package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.d.ts.map +1 -0
  460. package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.js +103 -0
  461. package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.d.ts +22 -0
  462. package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.d.ts.map +1 -0
  463. package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.js +57 -0
  464. package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.d.ts +22 -0
  465. package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.d.ts.map +1 -0
  466. package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.js +25 -0
  467. package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.d.ts +14 -0
  468. package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.d.ts.map +1 -0
  469. package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.js +48 -0
  470. package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.d.ts +23 -0
  471. package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.d.ts.map +1 -0
  472. package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.js +169 -0
  473. package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.d.ts +26 -0
  474. package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.d.ts.map +1 -0
  475. package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.js +161 -0
  476. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  477. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +18 -6
  478. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  479. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +11 -3
  480. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts +0 -28
  481. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts.map +0 -1
  482. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.js +0 -86
  483. package/src/engine/ecs/ik/IKConstraint.d.ts +0 -52
  484. package/src/engine/ecs/ik/IKConstraint.d.ts.map +0 -1
  485. package/src/engine/ecs/ik/IKConstraint.js +0 -95
  486. package/src/engine/ecs/ik/IKProblem.d.ts +0 -45
  487. package/src/engine/ecs/ik/IKProblem.d.ts.map +0 -1
  488. package/src/engine/ecs/ik/IKProblem.js +0 -58
  489. package/src/engine/ecs/ik/IKSolver.d.ts +0 -8
  490. package/src/engine/ecs/ik/IKSolver.d.ts.map +0 -1
  491. package/src/engine/ecs/ik/IKSolver.js +0 -9
  492. package/src/engine/ecs/ik/InverseKinematics.d.ts +0 -48
  493. package/src/engine/ecs/ik/InverseKinematics.d.ts.map +0 -1
  494. package/src/engine/ecs/ik/InverseKinematics.js +0 -119
  495. package/src/engine/ecs/ik/InverseKinematicsSerializationAdapter.d.ts +0 -19
  496. package/src/engine/ecs/ik/InverseKinematicsSerializationAdapter.d.ts.map +0 -1
  497. package/src/engine/ecs/ik/InverseKinematicsSerializationAdapter.js +0 -72
  498. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts +0 -54
  499. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts.map +0 -1
  500. package/src/engine/ecs/ik/InverseKinematicsSystem.js +0 -212
  501. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts +0 -8
  502. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +0 -1
  503. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +0 -153
  504. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.d.ts +0 -5
  505. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.d.ts.map +0 -1
  506. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +0 -120
  507. package/src/engine/ecs/ik/ik_bone_chain.d.ts +0 -64
  508. package/src/engine/ecs/ik/ik_bone_chain.d.ts.map +0 -1
  509. package/src/engine/ecs/ik/ik_bone_chain.js +0 -142
  510. package/src/engine/ecs/ik/ik_probe_terrain_contact.d.ts +0 -42
  511. package/src/engine/ecs/ik/ik_probe_terrain_contact.d.ts.map +0 -1
  512. package/src/engine/ecs/ik/ik_probe_terrain_contact.js +0 -123
  513. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +0 -18
  514. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +0 -1
  515. package/src/engine/ecs/ik/ik_write_local_rotation.js +0 -32
  516. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.d.ts +0 -29
  517. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.d.ts.map +0 -1
  518. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.js +0 -44
  519. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts +0 -4
  520. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts.map +0 -1
  521. package/src/shade/renderer/water/medium/shader_water_bodies_derive.js +0 -32
  522. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts +0 -25
  523. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts.map +0 -1
  524. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.js +0 -128
  525. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts +0 -9
  526. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts.map +0 -1
  527. package/src/shade/renderer/water/surface/chunk_water_tessellation.js +0 -144
  528. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts +0 -13
  529. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts.map +0 -1
  530. package/src/shade/renderer/water/surface/chunk_water_wave.js +0 -40
  531. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts +0 -4
  532. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts.map +0 -1
  533. package/src/shade/renderer/water/surface/shader_water_tiles.js +0 -123
  534. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts +0 -6
  535. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts.map +0 -1
  536. package/src/shade/renderer/water/surface/shader_water_wave_batch.js +0 -85
  537. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts +0 -6
  538. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts.map +0 -1
  539. package/src/shade/renderer/water/surface/shader_water_wave_domain.js +0 -83
@@ -2,6 +2,11 @@
2
2
  * Registers [Water, MeshletGeometry, Transform64] in the scene's existing GPU database. Authored
3
3
  * edits queue writes; idle frames never walk bodies. Transform rows follow the same change events
4
4
  * and GPU hierarchy as shaded geometry. Water does not enter the opaque mesh table or its TLAS.
5
+ *
6
+ * Every body has a surface row (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §6.1): its wind from an
7
+ * optional {@link WaterWaves}, its queued splashes, and what the GPU derives from them each frame. The GPU culls
8
+ * every body against the frame's view before simulating; a hidden body is paused unless
9
+ * {@link Water#simulateWhenHidden} (WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3).
5
10
  */
6
11
  export class WaterSystem extends System<any> {
7
12
  constructor(graphics: any, scene: any);
@@ -19,7 +24,7 @@ export class WaterSystem extends System<any> {
19
24
  inscatter_segments: number;
20
25
  tessellation_pixels: number;
21
26
  };
22
- get waves(): GPUWaterWaveSimulation;
27
+ get waves(): GPUWaterSurface;
23
28
  get transparency_channel(): GPUWaterRenderer;
24
29
  get scene(): any;
25
30
  request_probe(uv: any): Promise<any>;
@@ -30,7 +35,11 @@ export class WaterSystem extends System<any> {
30
35
  link(water: any, geometry: any, transform: any, entity: any): void;
31
36
  unlink(water: any, geometry: any, transform: any, entity: any): void;
32
37
  update(dt: any): void;
33
- /** World-space radius and velocity kick; position is interpreted in the CPU-owned pose. */
38
+ /**
39
+ * A splash at a world position: rings of wave particles of the given world radius (half their wavelength)
40
+ * whose height is the given vertical velocity kick, m/s, over the time a crest takes to cross them. The
41
+ * position is interpreted in the CPU-owned pose; queued on the CPU and spent on the GPU, sixteen a body a frame.
42
+ */
34
43
  splash(entity: any, position: any, radius: any, strength: any): void;
35
44
  record_surface(frame: any): void;
36
45
  record(frame: any): void;
@@ -52,7 +61,7 @@ import { MeshletGeometry } from "../../shade/renderer/geometry/MeshletGeometry.j
52
61
  import Water from "../graphics/ecs/water/Water.js";
53
62
  import WaterWaves from "../graphics/ecs/water/WaterWaves.js";
54
63
  import { ResourceAccessSpecification } from "../../core/model/ResourceAccessSpecification.js";
55
- import { GPUWaterWaveSimulation } from "../../shade/renderer/water/surface/GPUWaterWaveSimulation.js";
64
+ import { GPUWaterSurface } from "../../shade/renderer/water/surface/GPUWaterSurface.js";
56
65
  import { GPUWaterRenderer } from "../../shade/renderer/water/GPUWaterRenderer.js";
57
66
  import { RenderExtension } from "../../shade/renderer/extension/RenderExtension.js";
58
67
  //# sourceMappingURL=WaterSystem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WaterSystem.d.ts","sourceRoot":"","sources":["../../../../src/engine/graphics3/WaterSystem.js"],"names":[],"mappings":"AAyBA;;;;GAIG;AACH;IAyBI,uCAcC;IAtCD,6EAAqD;IACrD,kEAA0F;IAY1F;;;;;;;;;;;MAAkD;IAClD,oCAAmC;IACnC,6CAAqD;IACrD,iBAAmC;IACnC,qCAA8D;IAE9D,0BAGC;IAJD,mBAAiC;IAsBjC,2CAOC;IAED,0BAMC;IAED,mEAoBC;IAUD,qEAkBC;IAED,sBAgBC;IA0CD,2FAA2F;IAC3F,qEASC;IAED,iCAKC;IACD,yBAGC;;CACJ;AAED;IAEI,yBAAsD;IAAvB,YAAoB;IACnD,yBAA4C;CAC/C;AACD;IAEI,yBAAsD;IAAvB,YAAoB;IACnD,yBAAoD;CACvD;uBAlOsB,kBAAkB;4BAEb,iCAAiC;gCAI7B,kDAAkD;kBARhE,gCAAgC;uBAC3B,qCAAqC;4CAShB,iDAAiD;uCAGtD,8DAA8D;iCAFpE,gDAAgD;gCAIjD,mDAAmD"}
1
+ {"version":3,"file":"WaterSystem.d.ts","sourceRoot":"","sources":["../../../../src/engine/graphics3/WaterSystem.js"],"names":[],"mappings":"AA+BA;;;;;;;;;GASG;AACH;IA2BI,uCAaC;IAvCD,6EAAqD;IACrD,kEAA0F;IAc1F;;;;;;;;;;;MAAkD;IAClD,6BAAmC;IACnC,6CAAqD;IACrD,iBAAmC;IACnC,qCAA8D;IAE9D,0BAGC;IAJD,mBAAiC;IAqBjC,2CAOC;IAED,0BAMC;IAED,mEAsBC;IAQD,qEAkBC;IAED,sBAoBC;IAqDD;;;;OAIG;IACH,qEASC;IAED,iCAMC;IACD,yBAGC;;CACJ;AAED;IAEI,yBAAsD;IAAvB,YAAoB;IACnD,yBAA4C;CAC/C;AACD;IAEI,yBAAsD;IAAvB,YAAoB;IACnD,yBAAoD;CACvD;uBAlQsB,kBAAkB;4BAEb,iCAAiC;gCAI7B,kDAAkD;kBARhE,gCAAgC;uBACe,qCAAqC;4CAS1D,iDAAiD;gCAG7D,uDAAuD;iCAFtD,gDAAgD;gCAIjD,mDAAmD"}
@@ -1,6 +1,6 @@
1
1
  import { assert } from "../../core/assert.js";
2
2
  import Water from "../graphics/ecs/water/Water.js";
3
- import WaterWaves from "../graphics/ecs/water/WaterWaves.js";
3
+ import WaterWaves, { WATER_WAVES_SHORE_REFLECTION_DEFAULT } from "../graphics/ecs/water/WaterWaves.js";
4
4
  import { System } from "../ecs/System.js";
5
5
  import { EventType } from "../ecs/EventType.js";
6
6
  import { Transform64 } from "../ecs/transform/Transform64.js";
@@ -12,21 +12,32 @@ import { ResourceAccessKind } from "../../core/model/ResourceAccessKind.js";
12
12
  import { ResourceAccessSpecification } from "../../core/model/ResourceAccessSpecification.js";
13
13
  import { GPUWaterRenderer } from "../../shade/renderer/water/GPUWaterRenderer.js";
14
14
  import { GPUWaterBodies } from "../../shade/renderer/water/medium/GPUWaterBodies.js";
15
- import { GPUWaterWaveSimulation } from "../../shade/renderer/water/surface/GPUWaterWaveSimulation.js";
15
+ import { GPUWaterSurface } from "../../shade/renderer/water/surface/GPUWaterSurface.js";
16
16
  import { FramePhase } from "../../shade/renderer/extension/FramePhase.js";
17
17
  import { RenderExtension } from "../../shade/renderer/extension/RenderExtension.js";
18
18
  import { SceneColor } from "../../shade/renderer/extension/SceneColor.js";
19
19
  import { m4_invert } from "../../core/geom/3d/mat4/m4_invert.js";
20
20
  import { generate_record_writer } from "../../shade/renderer/buffer/table/serde/generate_record_writer.js";
21
21
  import { WATER_WAVE_IMPULSE_LIMIT, WATER_WAVE_RECORD_STRUCT } from "../../shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.js";
22
+ import { WATER_SPECTRUM_BAND_COUNT } from "../../shade/renderer/water/surface/spectrum/WATER_SPECTRUM.js";
22
23
 
23
- const WIND_WRITER = generate_record_writer(WATER_WAVE_RECORD_STRUCT, ['forcing', 'unresolved_variance']);
24
+ // Only the authored fields: a whole-record write would undo what the GPU derives into the row.
25
+ const AUTHORED_WRITER = generate_record_writer(WATER_WAVE_RECORD_STRUCT, ['wind', 'upwind_fetch', 'node', 'geometry', 'simulate_hidden']);
24
26
  const IMPULSE_WRITER = generate_record_writer(WATER_WAVE_RECORD_STRUCT, ['impulses', 'impulse_count']);
27
+ /** The WaterWaves fields a body's row follows. */
28
+ const WAVE_FIELDS = ['windSpeed', 'windDirection', 'upwindFetch', 'shoreReflection'];
29
+ /** A splash's world-to-local matrix: rain can splash hundreds of times a second. */
30
+ const SPLASH_INVERSE = new Float64Array(16);
25
31
 
26
32
  /**
27
33
  * Registers [Water, MeshletGeometry, Transform64] in the scene's existing GPU database. Authored
28
34
  * edits queue writes; idle frames never walk bodies. Transform rows follow the same change events
29
35
  * and GPU hierarchy as shaded geometry. Water does not enter the opaque mesh table or its TLAS.
36
+ *
37
+ * Every body has a surface row (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §6.1): its wind from an
38
+ * optional {@link WaterWaves}, its queued splashes, and what the GPU derives from them each frame. The GPU culls
39
+ * every body against the frame's view before simulating; a hidden body is paused unless
40
+ * {@link Water#simulateWhenHidden} (WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3).
30
41
  */
31
42
  export class WaterSystem extends System {
32
43
  dependencies = [Water, MeshletGeometry, Transform64];
@@ -35,11 +46,13 @@ export class WaterSystem extends System {
35
46
  #scene;
36
47
  #context = null;
37
48
  #renderer = new GPUWaterRenderer();
38
- #waves = new GPUWaterWaveSimulation();
49
+ #waves = new GPUWaterSurface();
39
50
  #bodies = new GPUWaterBodies();
40
51
  #entries = new Map();
41
52
  #dirty = new Set();
42
53
  #impulses = new Set();
54
+ // bodies with wind: while there is none, the shared band tiles are not animated
55
+ #windy = new Set();
43
56
  #extensions = [];
44
57
  #time = 0;
45
58
  get settings() { return this.#renderer.settings; }
@@ -60,9 +73,8 @@ export class WaterSystem extends System {
60
73
  this.#waves.onInputsConsumed.add(context => {
61
74
  if (context !== this.#context) { return; }
62
75
  for (const entry of this.#impulses) {
63
- entry.staged.length = 0;
64
- if (entry.impulses.length !== 0) { this.#dirty.add(entry); }
65
- else { this.#impulses.delete(entry); }
76
+ entry.staged.impulse_count = 0;
77
+ if (entry.queue.length === 0) { this.#impulses.delete(entry); }
66
78
  }
67
79
  });
68
80
  this.#renderer.bodies = this.#bodies;
@@ -87,8 +99,10 @@ export class WaterSystem extends System {
87
99
  }
88
100
 
89
101
  link(water, geometry, transform, entity) {
90
- const entry = { water, geometry, transform, entity, context: null, row: -1, wave: -1, waves: null,
91
- impulses: [], staged: [], wave_record: null };
102
+ // queue: splashes not yet staged, four numbers each (local x, z, radius, kick); staged: the batch on the
103
+ // GPU row until a submitted frame spends it
104
+ const entry = { water, geometry, transform, entity, context: null, row: -1, wave: -1, waves: null, queue: [],
105
+ staged: { impulses: Array.from({ length: WATER_WAVE_IMPULSE_LIMIT }, () => new Float64Array(4)), impulse_count: 0 } };
92
106
  const dataset = this.entityManager.dataset;
93
107
  entry.changed = () => this.#dirty.add(entry);
94
108
  entry.world = () => entry.context?.rows.mark_world(entity);
@@ -109,11 +123,9 @@ export class WaterSystem extends System {
109
123
  }
110
124
 
111
125
  #watch_waves(entry) {
112
- entry.waves?.windSpeed.onChanged.remove(entry.changed);
113
- entry.waves?.windDirection.onChanged.remove(entry.changed);
126
+ if (entry.waves != null) { for (const field of WAVE_FIELDS) { entry.waves[field].onChanged.remove(entry.changed); } }
114
127
  entry.waves = this.entityManager.dataset.getComponent(entry.entity, WaterWaves);
115
- entry.waves?.windSpeed.onChanged.add(entry.changed);
116
- entry.waves?.windDirection.onChanged.add(entry.changed);
128
+ if (entry.waves != null) { for (const field of WAVE_FIELDS) { entry.waves[field].onChanged.add(entry.changed); } }
117
129
  }
118
130
 
119
131
  unlink(water, geometry, transform, entity) {
@@ -121,8 +133,7 @@ export class WaterSystem extends System {
121
133
  if (entry === undefined) { return; }
122
134
  const dataset = this.entityManager.dataset;
123
135
  water.onChanged.remove(entry.changed);
124
- entry.waves?.windSpeed.onChanged.remove(entry.changed);
125
- entry.waves?.windDirection.onChanged.remove(entry.changed);
136
+ if (entry.waves != null) { for (const field of WAVE_FIELDS) { entry.waves[field].onChanged.remove(entry.changed); } }
126
137
  dataset.removeEntityEventListener(entity, TRANSFORM64_EVENT_CHANGE, entry.world);
127
138
  dataset.removeEntityEventListener(entity, TRANSFORM_ATTACHMENT_EVENT_CHANGE, entry.local);
128
139
  dataset.removeEntityEventListener(entity, EventType.ComponentAdded, entry.components);
@@ -132,6 +143,7 @@ export class WaterSystem extends System {
132
143
  entry.context.rows.release(entity);
133
144
  }
134
145
  this.#entries.delete(entity); this.#dirty.delete(entry); this.#impulses.delete(entry);
146
+ this.#windy.delete(entry); this.#waves.windy = this.#windy.size > 0;
135
147
  this.#renderer.body_count--;
136
148
  if (entry.context !== null) { this.#renderer.meshlet_capacity -= entry.geometry.meshlets.count; }
137
149
  }
@@ -144,14 +156,34 @@ export class WaterSystem extends System {
144
156
  this.#context = context;
145
157
  // Device replacement is the only whole-scene rebuild; ordinary frames drain edits.
146
158
  for (const entry of this.#entries.values()) {
147
- entry.context = null; entry.row = -1; entry.wave = -1; entry.wave_record = null;
148
- entry.impulses.unshift(...entry.staged); entry.staged.length = 0;
159
+ entry.context = null; entry.row = -1; entry.wave = -1;
160
+ // a batch the old context never spent goes back to the front of the queue
161
+ const staged = [];
162
+ for (let i = 0; i < entry.staged.impulse_count; i++) { staged.push(...entry.staged.impulses[i]); }
163
+ entry.queue.unshift(...staged); entry.staged.impulse_count = 0;
149
164
  this.#dirty.add(entry);
150
165
  }
151
166
  this.#renderer.meshlet_capacity = 0;
152
167
  }
153
168
  for (const entry of this.#dirty) { this.#write(entry, context); }
154
169
  this.#dirty.clear();
170
+ for (const entry of this.#impulses) { this.#stage(entry, context); }
171
+ }
172
+
173
+ /** Top up a body's batch on its surface row from its queue, up to the row's limit. */
174
+ #stage(entry, context) {
175
+ const staged = entry.staged, queue = entry.queue;
176
+ if (entry.wave === -1 || queue.length === 0 || staged.impulse_count === WATER_WAVE_IMPULSE_LIMIT) { return; }
177
+ const taken = Math.min(queue.length / 4, WATER_WAVE_IMPULSE_LIMIT - staged.impulse_count);
178
+ for (let i = 0; i < taken; i++) {
179
+ const impulse = staged.impulses[staged.impulse_count++];
180
+ for (let c = 0; c < 4; c++) { impulse[c] = queue[4 * i + c]; }
181
+ }
182
+ queue.copyWithin(0, 4 * taken);
183
+ queue.length -= 4 * taken;
184
+ this.#waves.splashed = true;
185
+ for (let i = staged.impulse_count; i < WATER_WAVE_IMPULSE_LIMIT; i++) { staged.impulses[i].fill(0); }
186
+ context.scene_database.get('water_waves').set_fields(entry.wave, staged, IMPULSE_WRITER);
155
187
  }
156
188
 
157
189
  #write(entry, context) {
@@ -163,54 +195,54 @@ export class WaterSystem extends System {
163
195
  entry.context = context;
164
196
  this.#renderer.meshlet_capacity += entry.geometry.meshlets.count;
165
197
  }
166
- if (entry.wave !== -1 || entry.waves != null || entry.impulses.length !== 0) {
167
- const bounds = entry.geometry.bounding_box;
168
- if (entry.wave === -1) {
169
- entry.wave_record = { extent: [bounds[0], bounds[2], bounds[3], bounds[5]],
170
- forcing: [1, 0, 0, 0], impulses: Array.from({ length: WATER_WAVE_IMPULSE_LIMIT }, () => [0, 0, 0, 0]),
171
- node: entry.entity + 1, geometry: context.geometries.getAddress(entry.geometry),
172
- unresolved_variance: 0, impulse_count: 0, first_write: 1, displacement_bounds: [0, 0] };
173
- entry.wave = waves.add(entry.wave_record);
174
- }
175
- const wind = Math.max(0, entry.waves?.windSpeed.getValue() ?? 0);
176
- const direction = entry.waves?.windDirection.getValue() ?? 0;
177
- // Patch only authored fields: a full write would restore GPU-consumed impulses/reset flags.
178
- waves.set_fields(entry.wave, { forcing: [Math.cos(direction), Math.sin(direction), 0.02 * wind * wind, 0.5 * wind],
179
- unresolved_variance: wind > 0 ? 0.003 + 0.00512 * wind : 0 }, WIND_WRITER);
180
- if (entry.impulses.length !== 0) {
181
- entry.staged.push(...entry.impulses.splice(0, WATER_WAVE_IMPULSE_LIMIT - entry.staged.length));
182
- const impulses = entry.staged.slice();
183
- const count = impulses.length;
184
- while (impulses.length < WATER_WAVE_IMPULSE_LIMIT) { impulses.push([0, 0, 0, 0]); }
185
- waves.set_fields(entry.wave, { impulses, impulse_count: count }, IMPULSE_WRITER);
186
- }
198
+ const geometry = context.geometries.getAddress(entry.geometry);
199
+ if (entry.wave === -1) {
200
+ entry.wave = waves.add({ wind: [1, 0, 0, WATER_WAVES_SHORE_REFLECTION_DEFAULT], upwind_fetch: 0,
201
+ impulses: Array.from({ length: WATER_WAVE_IMPULSE_LIMIT }, () => [0, 0, 0, 0]), impulse_count: 0,
202
+ node: entry.entity + 1, geometry, simulate_hidden: 0, derived_for: [-1, -1],
203
+ weights: new Array(WATER_SPECTRUM_BAND_COUNT).fill(0), slope_variance: 0,
204
+ wind_from: [0, 0], wind_to: [0, 0], wind_blend: 1, displacement_bounds: [0, 0, 0, 0], particle_levels: 0 });
187
205
  }
206
+ const waves_component = entry.waves;
207
+ const speed = Math.max(0, waves_component?.windSpeed.getValue() ?? 0);
208
+ const direction = waves_component?.windDirection.getValue() ?? 0;
209
+ const reflection = Math.min(1, Math.max(0, waves_component?.shoreReflection.getValue() ?? WATER_WAVES_SHORE_REFLECTION_DEFAULT));
210
+ waves.set_fields(entry.wave, { wind: [Math.cos(direction), Math.sin(direction), speed, reflection],
211
+ upwind_fetch: Math.max(0, waves_component?.upwindFetch.getValue() ?? 0), node: entry.entity + 1, geometry,
212
+ simulate_hidden: entry.water.simulateWhenHidden.getValue() ? 1 : 0 }, AUTHORED_WRITER);
213
+ if (speed > 0) { this.#windy.add(entry); } else { this.#windy.delete(entry); }
214
+ this.#waves.windy = this.#windy.size > 0;
188
215
  const water = entry.water;
189
- const record = { geometry: context.geometries.getAddress(entry.geometry), node: entry.entity + 1,
216
+ const record = { geometry, node: entry.entity + 1,
190
217
  dirty: 1,
191
- wave: entry.wave === -1 ? 0xffffffff : entry.wave, ior: Math.max(1, water.ior.getValue()),
218
+ wave: entry.wave, ior: Math.max(1, water.ior.getValue()),
192
219
  roughness: Math.min(1, Math.max(0, water.roughness.getValue())), medium: water.medium.to_gpu_record(),
193
220
  backscattering: [0, 0, 0, 0], extinction: [0, 0, 0, 0], diffuse_transmittance: 0 };
194
221
  if (entry.row === -1) { entry.row = bodies.add(record); } else { bodies.set(entry.row, record); }
195
222
  }
196
223
 
197
- /** World-space radius and velocity kick; position is interpreted in the CPU-owned pose. */
224
+ /**
225
+ * A splash at a world position: rings of wave particles of the given world radius (half their wavelength)
226
+ * whose height is the given vertical velocity kick, m/s, over the time a crest takes to cross them. The
227
+ * position is interpreted in the CPU-owned pose; queued on the CPU and spent on the GPU, sixteen a body a frame.
228
+ */
198
229
  splash(entity, position, radius, strength) {
199
230
  const entry = this.#entries.get(entity); assert.defined(entry, 'water entity');
200
231
  assert.greaterThan(radius, 0, 'radius'); assert.isFinite(radius, 'radius'); assert.isFinite(strength, 'strength');
201
232
  for (let i = 0; i < 3; i++) { assert.isFinite(position[i], `position[${i}]`); }
202
- const inverse = new Float64Array(16);
233
+ const inverse = SPLASH_INVERSE;
203
234
  assert.ok(m4_invert(inverse, entry.transform), 'water transform is singular');
204
235
  const x = inverse[0] * position[0] + inverse[4] * position[1] + inverse[8] * position[2] + inverse[12];
205
236
  const z = inverse[2] * position[0] + inverse[6] * position[1] + inverse[10] * position[2] + inverse[14];
206
- entry.impulses.push([x, z, radius, strength]); this.#impulses.add(entry); this.#dirty.add(entry);
237
+ entry.queue.push(x, z, radius, strength); this.#impulses.add(entry);
207
238
  }
208
239
 
209
240
  record_surface(frame) {
210
- const scene = frame.view.scene;
241
+ const view = frame.view, scene = view.scene;
211
242
  if (scene.scene !== this.#scene) { return; }
212
- this.#waves.record({ graph: frame.graph, device: this.#graphics.renderer.graphics.device, scene });
213
- this.#bodies.record({ graph: frame.graph, scene });
243
+ this.#waves.record({ graph: frame.graph, device: this.#graphics.renderer.graphics.device, scene, time: this.#time,
244
+ view: { camera: view.camera.gpu_buffer, projection: view.camera.camera.projection_matrix, height: view.resolution[1] },
245
+ pixels: this.#renderer.settings.tessellation_pixels });
214
246
  }
215
247
  record(frame) {
216
248
  const inspection = this.#renderer.inspect(frame.graph, frame.view, frame.resolution);
@@ -1 +1 @@
1
- {"version":3,"file":"PointerDevice.d.ts","sourceRoot":"","sources":["../../../../../src/engine/input/devices/PointerDevice.js"],"names":[],"mappings":"AA2NA;;;;;GAKG;AACH,mDAJW,OAAO,SACP,UAAU,GAAC,KAAK,WAChB,OAAO,QAejB;AAED;;;;;GAKG;AACH;IAuFI;;;;OAIG;IACH,wBAHW,WAAW,EA+BrB;IAtHD;;;;OAIG;IACH,mBAFU,OAAO,CAEQ;IAEzB;;OAEG;IACH;;;QAGI;;;;;;WAMG;;;QAGH;;WAEG;;;;;;;;;MASL;IAeF;;;OAGG;IACH,kBAAkB;IAElB;;;;OAIG;IACH,kBAFU,iBAAiB,EAAE,CAEL;IAExB;;;OAGG;IACH,yCAEC;IAED;;;OAGG;IACH,0CAEC;IAED;;;OAGG;IACH,2CAEC;IAyID;;;OAGG;IACH,oBAFY,OAAO,CAIlB;IAED;;;OAGG;IACH,4BAsBC;IAED,0BAEC;IAED;;;;OAIG;IACH,qCAHW,OAAO,SACP,UAAU,GAAC,KAAK,QAI1B;IAED,cAiCC;IAED,aA4BC;;CACJ;oBAnkBmB,+BAA+B;mBADhC,uCAAuC;kCAOxB,wBAAwB"}
1
+ {"version":3,"file":"PointerDevice.d.ts","sourceRoot":"","sources":["../../../../../src/engine/input/devices/PointerDevice.js"],"names":[],"mappings":"AAgPA;;;;;GAKG;AACH,mDAJW,OAAO,SACP,UAAU,GAAC,KAAK,WAChB,OAAO,QAejB;AAED;;;;;GAKG;AACH;IAyFI;;;;OAIG;IACH,wBAHW,WAAW,EA+BrB;IAtHD;;;;OAIG;IACH,mBAFU,OAAO,CAEQ;IAEzB;;OAEG;IACH;;;QAGI;;;;;;WAMG;;;QAGH;;WAEG;;;;;;;;;MASL;IAeF;;;OAGG;IACH,kBAAkB;IAElB;;;;OAIG;IACH,kBAFU,iBAAiB,EAAE,CAEL;IAExB;;;OAGG;IACH,yCAEC;IAED;;;OAGG;IACH,0CAEC;IAED;;;OAGG;IACH,2CAEC;IA2ID;;;OAGG;IACH,oBAFY,OAAO,CAIlB;IAED;;;OAGG;IACH,4BAsBC;IAED,0BAEC;IAED;;;;OAIG;IACH,qCAHW,OAAO,SACP,UAAU,GAAC,KAAK,QAI1B;IAED,cAiCC;IAED,aA4BC;;CACJ;oBA5lBmB,+BAA+B;mBADhC,uCAAuC;kCAOxB,wBAAwB"}
@@ -20,6 +20,7 @@ import { suppressContextMenu } from "./mouse/suppressContextMenu.js";
20
20
  * @param {number} [options.maxDistance] in pixels
21
21
  * @param {number} [options.maxDelay] Maximum delay between down and up events in seconds
22
22
  * @param {Signal} options.signal
23
+ * @returns {(id?:number)=>void} clears pending candidates without emitting a tap
23
24
  */
24
25
  function observeTap({
25
26
  up,
@@ -139,6 +140,16 @@ function observeTap({
139
140
  }
140
141
 
141
142
  down.add(handleDown);
143
+
144
+ return id => {
145
+ if (id !== undefined) {
146
+ reset(id);
147
+ return;
148
+ }
149
+ active.clear();
150
+ up.remove(handleUp);
151
+ move.remove(handleMove);
152
+ };
142
153
  }
143
154
 
144
155
  /**
@@ -149,6 +160,7 @@ function observeTap({
149
160
  * @param {Signal} dragStart
150
161
  * @param {Signal} dragEnd
151
162
  * @param {Signal} drag
163
+ * @returns {()=>void} removes pending gesture observations without emitting a drag end
152
164
  */
153
165
  function observeDrag(up, down, move, dragStart, dragEnd, drag) {
154
166
  const origin = new Vector2();
@@ -188,7 +200,8 @@ function observeDrag(up, down, move, dragStart, dragEnd, drag) {
188
200
 
189
201
  lastDragPosition.copy(origin);
190
202
  dragStart.send2(origin, event);
191
- handleDrag(position, event);
203
+ // A start consumer can stop the device and remove this gesture before motion is delivered.
204
+ if (up.contains(handleDragEnd)) handleDrag(position, event);
192
205
  }
193
206
 
194
207
  const lastDragPosition = new Vector2();
@@ -214,6 +227,14 @@ function observeDrag(up, down, move, dragStart, dragEnd, drag) {
214
227
  }
215
228
 
216
229
  down.add(handleDown);
230
+
231
+ return () => {
232
+ // Overlapping presses can register these owned observations more than once.
233
+ while (up.remove(noDrag)) {}
234
+ while (up.remove(handleDragEnd)) {}
235
+ while (move.remove(handleDragStart)) {}
236
+ while (move.remove(handleDrag)) {}
237
+ };
217
238
  }
218
239
 
219
240
 
@@ -245,6 +266,8 @@ export function readPositionFromMouseEvent(result, event, source = event.target)
245
266
  * @copyright Company Named Limited (c) 2026
246
267
  */
247
268
  export class PointerDevice {
269
+ #resetTap;
270
+ #resetDrag;
248
271
 
249
272
  /**
250
273
  * Current live position of the pointer
@@ -355,14 +378,14 @@ export class PointerDevice {
355
378
  // `globalUp`, not `up`, for the same reason observeDrag below uses it: `up` only fires for
356
379
  // a release over the element, so a press that lifted one pixel outside the canvas was
357
380
  // never resolved and never reset - the candidate simply sat in the map.
358
- observeTap({
381
+ this.#resetTap = observeTap({
359
382
  up: this.on.globalUp,
360
383
  down: this.on.down,
361
384
  move: this.on.move,
362
385
  maxDistance: 10,
363
386
  signal: this.on.tap
364
387
  });
365
- observeDrag(this.on.globalUp, this.on.down, this.on.move, this.on.dragStart, this.on.dragEnd, this.on.drag);
388
+ this.#resetDrag = observeDrag(this.on.globalUp, this.on.down, this.on.move, this.on.dragStart, this.on.dragEnd, this.on.drag);
366
389
 
367
390
  }
368
391
 
@@ -424,7 +447,9 @@ export class PointerDevice {
424
447
  * every button for the same reason. The pointer was the one device of the three that did not,
425
448
  * with `PointerEvents.Cancel` sitting unused in the event table as the tell.
426
449
  */
427
- #releaseAllButtons = () => {
450
+ #releaseAllButtons = event => {
451
+ this.#resetTap(event?.type === PointerEvents.Cancel ? event.pointerId : undefined);
452
+ this.#resetDrag();
428
453
  const buttons = this.buttons;
429
454
 
430
455
  for (let i = 0; i < buttons.length; i++) {
@@ -2,6 +2,7 @@
2
2
  * Picks a random behavior to execute.
3
3
  * The selection is done during initialization, and that selected behavior will then run to completion.
4
4
  * NOTE: Weights are relative, so they don't need to add up to any specific value.
5
+ * If every weight is zero, no child runs and the selector fails.
5
6
  *
6
7
  * @example
7
8
  * const behavior = WeightedRandomBehavior.from([
@@ -1 +1 @@
1
- {"version":3,"file":"WeightedRandomBehavior.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/intelligence/behavior/selector/WeightedRandomBehavior.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;GAaG;AACH;IAkEI;;;;OAIG;IACH,sBAHW,8BAAyB,EAAE,GACzB,sBAAsB,CAUlC;;IA7ED;;;;OAIG;IACH,mBAAgB;IAEhB;;;;OAIG;IACH,iBAA+B;IAE/B;;;;OAIG;IACH,mBAAuB;IAEvB;;;OAGG;IACH,iBAFW,MAAM,QAIhB;IAED;;;OAGG;IACH,sBAFW,8BAAyB,EAAE,QAcrC;IAED;;;OAGG;IACH,cAFW,8BAAyB,QAanC;IAiBD,iBAYC;IAkBD,6BAEC;CACJ;yBAnIwB,gBAAgB;gCACT,sBAAsB"}
1
+ {"version":3,"file":"WeightedRandomBehavior.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/intelligence/behavior/selector/WeightedRandomBehavior.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;GAcG;AACH;IAkEI;;;;OAIG;IACH,sBAHW,8BAAyB,EAAE,GACzB,sBAAsB,CAUlC;;IA7ED;;;;OAIG;IACH,mBAAgB;IAEhB;;;;OAIG;IACH,iBAA+B;IAE/B;;;;OAIG;IACH,mBAAuB;IAEvB;;;OAGG;IACH,iBAFW,MAAM,QAIhB;IAED;;;OAGG;IACH,sBAFW,8BAAyB,EAAE,QAcrC;IAED;;;OAGG;IACH,cAFW,8BAAyB,QAanC;IAiBD,iBAiBC;IAsBD,6BAEC;CACJ;yBA9IwB,gBAAgB;gCAET,sBAAsB"}
@@ -2,12 +2,14 @@ import { assert } from "../../../../core/assert.js";
2
2
  import { weightedRandomFromArray } from "../../../../core/collection/array/weightedRandomFromArray.js";
3
3
  import { seededRandom } from "../../../../core/math/random/seededRandom.js";
4
4
  import { Behavior } from "../Behavior.js";
5
+ import { BehaviorStatus } from "../BehaviorStatus.js";
5
6
  import { WeightedElement } from "./WeightedElement.js";
6
7
 
7
8
  /**
8
9
  * Picks a random behavior to execute.
9
10
  * The selection is done during initialization, and that selected behavior will then run to completion.
10
11
  * NOTE: Weights are relative, so they don't need to add up to any specific value.
12
+ * If every weight is zero, no child runs and the selector fails.
11
13
  *
12
14
  * @example
13
15
  * const behavior = WeightedRandomBehavior.from([
@@ -106,6 +108,11 @@ export class WeightedRandomBehavior extends Behavior {
106
108
  */
107
109
  const weightedElement = weightedRandomFromArray(this.__elements, this.__random, WeightedElement.getWeight);
108
110
 
111
+ if (weightedElement === undefined) {
112
+ this.__selected = undefined;
113
+ return;
114
+ }
115
+
109
116
  const selected = weightedElement.data;
110
117
 
111
118
  assert.equal(selected.isBehavior, true, 'selected.isBehavior !== true');
@@ -118,18 +125,22 @@ export class WeightedRandomBehavior extends Behavior {
118
125
 
119
126
  this.__select();
120
127
 
121
- this.__selected.initialize(context);
128
+ if (this.__selected !== undefined) {
129
+ this.__selected.initialize(context);
130
+ }
122
131
  }
123
132
 
124
133
  finalize() {
125
134
  super.finalize();
126
135
 
127
- this.__selected.finalize();
136
+ if (this.__selected !== undefined) {
137
+ this.__selected.finalize();
138
+ }
128
139
 
129
140
  this.__selected = undefined;
130
141
  }
131
142
 
132
143
  tick(timeDelta) {
133
- return this.__selected.tick(timeDelta);
144
+ return this.__selected === undefined ? BehaviorStatus.Failed : this.__selected.tick(timeDelta);
134
145
  }
135
146
  }
@@ -3984,3 +3984,133 @@ colliding readings have a median of 0.90 and the twelve idle ones 0.95.
3984
3984
 
3985
3985
  **No library entry is re-sized.** Its bench cannot see a collider (§58), and a
3986
3986
  garment on a body is the colliding half of the tables above.
3987
+
3988
+ ## 61. A rig's joints were claimed with a bit the GPU never reads, by two parties at once
3989
+
3990
+ Found reading code in the 2026-10-05 IK design review, and measured here before
3991
+ anything changed. Every reading below is a spec that registers a real clip
3992
+ through `GPUAnimationManager` on a `SoftwareGPUDevice` scene over the garment's
3993
+ own dataset (`cloth_rig.spec.js`), or runs the real apply pass under the WGSL
3994
+ emulator (`shader_animation_apply.spec.js`). The specs it replaced granted the
3995
+ bit by hand on joints no clip bound, so none of this was visible to them.
3996
+
3997
+ ```
3998
+ what before after
3999
+ clip unregistered while cloth held it, bit 2 (GPU), and a CPU write of bit 0; the row holds
4000
+ then the garment removed (0.25, -0.5, 0.125) left the row at (0.25, -0.5, 0.125)
4001
+ 0.0020000000949949026, for good
4002
+ rig re-seeded while seeded, then removed bit 0 with the clip still bound bit 2
4003
+ clip binding a joint cloth already holds bit 2; the row stayed 0.0020000000949949026 bit 0; the row is
4004
+ while cloth wrote 0.0011062223929911852 cloth's write
4005
+ last clip leaving a held joint offset (5, -0.10000382363796234, 0): cloth's offset,
4006
+ the clip's pose over cloth's 0.00173… untouched
4007
+ bindings of clips over a held cape rows 3, 4, 5, 6, 7 (shoulder + cape) 3, then NULL ×4
4008
+ apply pass over two held targets 8 accumulator words written none
4009
+ cache / exact walk over a held level cache off by 0.98 in a translation lane; within 1e-12
4010
+ the walk off in lane 12 (world x)
4011
+ ```
4012
+
4013
+ **Why the bit could not have worked.** The apply pass adds every bound clip into
4014
+ its target's accumulator slot whatever the clip's weight, the resolve writes the
4015
+ row, and both run in `tick`, after `build`'s flush. `GPUStateAuthority` gates
4016
+ only that flush. A cape joint whose clip still named its row was the clip's on
4017
+ screen, bit or no bit.
4018
+
4019
+ **What changed.** A CPU writer *holds* a component (`gpu_authority_hold`):
4020
+ `GPUStateAuthority#held` records it, the bit clears, and `gpu_authority_grant`
4021
+ will not set a held bit. The animation manager hears the hold through an entity
4022
+ event on every joint it drives. It points that joint's bindings at
4023
+ `GPU_DATABASE_NULL`, whose type bits `write_object_property` ignores, and it
4024
+ skips the seed when the last clip leaves. When the hold ends it points them back
4025
+ and grants, if a clip is still bound. The exact evaluators read a held level as
4026
+ its offset (`t64_evaluate_local`). Cloth holds every joint it drives and never
4027
+ touches the bit.
4028
+
4029
+ **Not measured:** a device run. The WGSL is unchanged; what changed is what the
4030
+ bindings name, and the emulator runs the real apply pass over it.
4031
+
4032
+ ### Found in review
4033
+
4034
+ An adversarial pass over those six commits. Every candidate was measured before it
4035
+ was believed.
4036
+
4037
+ - **A re-seeded rig leaked its holds** when it was taken away, or refused, before
4038
+ the next seeding. `reseed` cleared `seeded`, the release asks `seeded`, and the
4039
+ joints stayed held: their clips muted and nothing writing them. Before the hold
4040
+ this was a bit that lied while the clip still won on the GPU; muting made it a
4041
+ frozen joint. `reseed` now gives the holds back, and the seed asserts it
4042
+ starts from none. Red first: bits `[0, 0, 0, 0]` against `[2, 2, 2, 2]`, the
4043
+ bindings all NULL, after removing `Cloth`, after removing `ClothRig`, and after
4044
+ a refused proxy.
4045
+ - **One line was pinned by nothing.** Of twelve mutants over the fixes, eleven
4046
+ were killed. The survivor was the row mark a hold makes, which carries an offset
4047
+ the holder wrote before it held. It is pinned now.
4048
+ - Measured and kept: the bind-time bookkeeping costs 129 ns a driven entity
4049
+ (2.5 ms for 19,440, at registration only). The hold check costs the exact
4050
+ evaluation 2.3% a level (64.0 to 65.8 µs over 70 levels, two clips of 210
4051
+ channels, paired median).
4052
+ - Measured and dismissed: a muted rotation binding writes nothing to its slot,
4053
+ rest rotation included (now in the emulator spec). A hold queues one word, the
4054
+ binding's `instance`, and its end queues the row back. A renderer restart
4055
+ reaches `GPUAnimationManager#destroy`, which removes every listener.
4056
+
4057
+ ### What a hold's end hands over
4058
+
4059
+ Found reading code in the 2026-10-06 IK design review: two things the end of a
4060
+ hold did not hand to a clip still bound. Cloth's release is a plain unhold that
4061
+ leaves each joint's offset at cloth's last write-back, so both reached it. Real
4062
+ clips through the manager in `cloth_rig.spec.js`, and the apply and resolve
4063
+ passes under the WGSL emulator in `animation_pose_pipeline.spec.js`.
4064
+
4065
+ The rest rows below read the rest each binding carries, which is what the resolve
4066
+ writes at weight zero (shown under the emulator, not on the cape).
4067
+
4068
+ ```
4069
+ what before after
4070
+ rest a clip keying the cape carries the rest from before the seed, the offset cloth
4071
+ once the garment goes [0, 0, 0, 1] left, z -0.00243
4072
+ the same, the clip bound while cloth held cloth's pose when it bound, the offset cloth
4073
+ z -0.000102 left, z -0.00243
4074
+ row y of a cape joint under a clip keying -0.0999996, cloth's flush before -0.1000130, cloth's
4075
+ x alone, the garment removed between its last five steps last write-back
4076
+ a step and the flush
4077
+ ```
4078
+
4079
+ **What changed.** The end of a hold, with a clip still bound, writes every
4080
+ binding's rest from the offset as the holder left it, with the unmute, and marks
4081
+ the row as a hand-over (`GPUSceneRows#mark_handover`): the flush writes it past
4082
+ the bit, once, and the resolve writes the axes the clip keys after it.
4083
+
4084
+ **Decided, not changed:** a joint whose last clip left while it was held keeps
4085
+ the holder's offset when the hold ends, not the clip's last pose (2d67be636).
4086
+ The clip had been muted since the hold began, or since it bound, so its last pose
4087
+ is one the joint has not shown since; the seed's own rule, carry on from what is
4088
+ on screen, gives the holder's offset.
4089
+
4090
+ **Open, not decided:** cloth's rig path leaves its last pose on the joints when it
4091
+ lets go, where the entity path puts the locals it captured back
4092
+ (`cloth_release_subtree`). The rig path never captured the joints' own offsets,
4093
+ but the instance holds the proxy's bind pose (`rest_local_*`), which it could put
4094
+ back. Measured: after the garment goes, a cape joint's offset rotation has z up
4095
+ to -0.00243 where that bind pose (identity, for the spec's skeleton) has 0, and a
4096
+ clip keying the cape carries it as its rest.
4097
+
4098
+ **Found in review** of these two fixes:
4099
+
4100
+ - **Two lines were pinned by nothing.** Of ten mutants over the fixes, eight were
4101
+ killed. The survivors: the `MARK_LOCAL` inside the hand-over mark, since both
4102
+ gap-2 specs had the holder announce its last write and so mark the row
4103
+ themselves; and the rest read off the wrong component, since the emulator
4104
+ spec's left rotation was `[0.5, 0.5, 0.5, 0.5]` and the cape turns about z
4105
+ alone. Both are pinned now.
4106
+ - **The first bind had the same hole.** A clip that first binds a joint grants
4107
+ the bit at once, so an offset announced earlier in that frame never reached the
4108
+ row: `[0, 0, 0, 1]` against the `[0.1, 0.3, 0.5, 0.806]` announced. Binding
4109
+ marks the hand-over too now. No engine path was found that triggers it today: the
4110
+ drivers re-register a whole clip set in one call, whose outgoing seed is such an
4111
+ announcement, but they set time from the CPU, so that seed equals what the GPU
4112
+ last resolved.
4113
+ - Measured and dismissed: the binding writer over `instance` and `rest_rotation`
4114
+ is two disjoint ranges of one row, which the partial upload shader spec already
4115
+ lands under the emulator; and the worker path writes nothing after a release,
4116
+ because a join for a cloth unlinked or reseeded since its dispatch is dropped.
@@ -368,7 +368,8 @@ said cloth reuses `PhysicsSystem`'s producer/`__interp_restore` contract; M5 mea
368
368
  that contract is entity-keyed and a rigged garment's joints are not entities — and §13.1 and §18 carry
369
369
  what the cloth-shaped version would be and what it would cost. What keeps a cloth-driven bone from
370
370
  fighting an animation-driven one is not interpolation but `TransformAuthority`, which `cloth_seed_rig`
371
- claims (§11.2, `MEASUREMENTS.md` §25).
371
+ claims (§11.2, `MEASUREMENTS.md` §25) — as a hold since §61, because the bit alone never stopped a
372
+ clip on the GPU.
372
373
 
373
374
  ### 4.1 Ordering, and why the answer is not to be ordered
374
375
 
@@ -1430,6 +1431,20 @@ with no component left anywhere naming which joints those were. The seed now rec
1430
1431
  joints its revoke *changed*, and `cloth_release_rig` hands those back when the `Cloth` is removed or
1431
1432
  the `ClothRig` is taken away; a joint that was already the CPU's before cloth arrived stays the CPU's.
1432
1433
 
1434
+ **2026-10-06: the claim never stopped a clip, and the loan was handed back to whoever asked last.**
1435
+ No GPU pass reads `GPUStateAuthority`. A bound clip's bindings write a joint's row through the pose
1436
+ accumulator every frame, after the CPU's flush, whatever the bit says, so clearing the bit only let
1437
+ cloth's flush and the clip race for one row, and the clip won. And cloth and `GPUAnimationManager`
1438
+ each flipped the same bit without the other: a clip that left during the loan was answered by
1439
+ cloth's re-grant with a joint nothing wrote again, and a clip that arrived during it took the bit
1440
+ from under cloth's write-back. The rule now is a **hold**. `GPUStateAuthority#held` records that a CPU
1441
+ writer has the offset, the bit stays clear while it does, and the animation manager — the only
1442
+ writer of the bit — mutes every binding that names a held joint and leaves its offset alone when the
1443
+ last clip goes. Ending the hold grants nothing; a clip still bound takes the joint back. So **"a joint
1444
+ cloth simulates stops being animatable by a clip" is true now, and a garment whose joints are also
1445
+ keyed is not an authoring error**: exporters often bake every bone, and the cape simulates anyway.
1446
+ `MEASUREMENTS.md` §61.
1447
+
1433
1448
  **The anchor's world pose is computed, never read back.** A joint of an animated skeleton has no
1434
1449
  CPU-side `transform_global` — nothing maintains it — so the rig path evaluates the anchor with
1435
1450
  `pose_evaluate_world` over the clips the entity is playing, which is the engine's own sanctioned
@@ -12,12 +12,11 @@
12
12
  * ## It has no `fixedUpdate`, and that is §4.1 applied a second time
13
13
  *
14
14
  * The index has to be refreshed from the world's transforms **before** any
15
- * cloth reads it, and the engine's two ordering mechanisms cannot express that:
16
- * `updateExecutionOrder` scores a system as a sum over the components it
17
- * references and sorts descending, so a system can only be moved *earlier* by
18
- * touching more, and `ClothSystem` — which reads and writes `Transform64` and
19
- * `TransformAttachment` — outscores a system that only reads. Registration
20
- * order does not break a non-tie.
15
+ * cloth reads it, and the derived order says the opposite: `updateExecutionOrder`
16
+ * runs a writer of a component before its readers, `ClothSystem` writes
17
+ * `Transform64`, and the index is not a component, so a system that steps only
18
+ * to read transforms into it would run after cloth. Registration order breaks
19
+ * only the ties that leaves.
21
20
  *
22
21
  * §4.1's conclusion applies unchanged: the answer is not a third mechanism, it
23
22
  * is not needing one. So this system does not step at all. {@link refresh} is