@woosh/meep-engine 3.56.0 → 3.57.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 (625) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/DUPLICATION_REVIEW_2026_10_24.md +1072 -0
  4. package/src/core/binary/BitSet.js +1 -1
  5. package/src/core/binary/FLOAT16_MAX.d.ts +2 -0
  6. package/src/core/binary/FLOAT16_MAX.d.ts.map +1 -0
  7. package/src/core/binary/FLOAT16_MAX.js +1 -0
  8. package/src/core/binary/base58/base58_encode.js +2 -2
  9. package/src/core/binary/type/TypeBuilder.js +1 -1
  10. package/src/core/bvh2/bvh3/BVH.js +1 -1
  11. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
  12. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +7 -3
  13. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.d.ts.map +1 -1
  14. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.js +5 -1
  15. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.d.ts.map +1 -1
  16. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +195 -246
  17. package/src/core/collection/CuckooFilter.js +1 -1
  18. package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
  19. package/src/core/collection/array/isArrayEqual.js +33 -58
  20. package/src/core/collection/array/typed/array_buffer_hash.d.ts.map +1 -1
  21. package/src/core/collection/array/typed/array_buffer_hash.js +41 -39
  22. package/src/core/collection/array/typed/float32_array_hash.js +38 -38
  23. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -1
  24. package/src/core/collection/array/typed/uint16_array_hash.d.ts.map +1 -1
  25. package/src/core/collection/array/typed/uint16_array_hash.js +30 -29
  26. package/src/core/collection/array/typed/uint32_array_hash.d.ts +2 -1
  27. package/src/core/collection/array/typed/uint32_array_hash.d.ts.map +1 -1
  28. package/src/core/collection/array/typed/uint32_array_hash.js +21 -20
  29. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -1
  30. package/src/core/collection/array/typed/uint8_array_hash.d.ts.map +1 -1
  31. package/src/core/collection/array/typed/uint8_array_hash.js +37 -36
  32. package/src/core/collection/array/typed/uint_array_for_count.js +2 -2
  33. package/src/core/collection/list/List.d.ts.map +1 -1
  34. package/src/core/collection/list/List.js +3 -19
  35. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  36. package/src/core/collection/table/RowFirstTable.js +4 -28
  37. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  38. package/src/core/debug/matchers/DescribeAs.js +62 -64
  39. package/src/core/function/FunctionCompiler.js +4 -4
  40. package/src/core/function/objectsEqual.d.ts.map +1 -1
  41. package/src/core/function/objectsEqual.js +3 -2
  42. package/src/core/geom/2d/bvh/BVH2D.d.ts.map +1 -1
  43. package/src/core/geom/2d/bvh/BVH2D.js +4 -3
  44. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +5 -2
  45. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  46. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +49 -11
  47. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
  48. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +122 -159
  49. package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
  50. package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -5
  51. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts +18 -0
  52. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts.map +1 -0
  53. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.js +97 -0
  54. package/src/core/geom/2d/r-tree/StaticR2Tree.js +2 -2
  55. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts +21 -0
  56. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts.map +1 -0
  57. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.js +54 -0
  58. package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts.map +1 -1
  59. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +20 -53
  60. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts +1 -1
  61. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts.map +1 -1
  62. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -42
  63. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -1
  64. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +30 -32
  65. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -1
  66. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +1 -5
  67. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -1
  68. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +1 -15
  69. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
  70. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +105 -116
  71. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.d.ts.map +1 -1
  72. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.js +36 -54
  73. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts +5 -10
  74. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts.map +1 -1
  75. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +20 -82
  76. package/src/core/geom/3d/plane/plane3_slerp.d.ts.map +1 -1
  77. package/src/core/geom/3d/plane/plane3_slerp.js +87 -102
  78. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +12 -0
  79. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -1
  80. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +107 -60
  81. package/src/core/geom/3d/ray/ray3_compute_closest_point.d.ts.map +1 -1
  82. package/src/core/geom/3d/ray/ray3_compute_closest_point.js +37 -43
  83. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  84. package/src/core/geom/3d/shape/ConvexHullShape3D.js +5 -16
  85. package/src/core/geom/3d/shape/MeshShape3D.js +2 -56
  86. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  87. package/src/core/geom/3d/shape/TransformedShape3D.js +10 -7
  88. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  89. package/src/core/geom/3d/shape/UnionShape3D.js +9 -3
  90. package/src/core/geom/3d/shape/json/shape_to_type.js +2 -2
  91. package/src/core/geom/3d/sphere/harmonics/SH3_COEFFICIENTS.js +17 -17
  92. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
  93. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +6 -2
  94. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -1
  95. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +3 -2
  96. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts +20 -2
  97. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  98. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +52 -37
  99. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -1
  100. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +40 -56
  101. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  102. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +251 -260
  103. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -1
  104. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +104 -113
  105. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.d.ts.map +1 -1
  106. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.js +227 -238
  107. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  108. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +15 -24
  109. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  110. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +31 -115
  111. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  112. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +142 -150
  113. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  114. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +151 -194
  115. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.d.ts.map +1 -1
  116. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +60 -85
  117. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  118. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +156 -171
  119. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.d.ts.map +1 -1
  120. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +8 -44
  121. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  122. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +2 -7
  123. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -1
  124. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +3 -2
  125. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.d.ts.map +1 -1
  126. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +128 -133
  127. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts +8 -14
  128. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts.map +1 -1
  129. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +36 -82
  130. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  131. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +7 -144
  132. package/src/core/geom/ConicRay.d.ts.map +1 -1
  133. package/src/core/geom/ConicRay.js +230 -237
  134. package/src/core/localization/LocaleDataset.d.ts +6 -0
  135. package/src/core/localization/LocaleDataset.d.ts.map +1 -1
  136. package/src/core/localization/LocaleDataset.js +48 -37
  137. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  138. package/src/core/localization/LocalizationEngine.js +3 -2
  139. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  140. package/src/core/math/lookup/ParameterLookupTable.js +3 -1
  141. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
  142. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +330 -400
  143. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -0
  144. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  145. package/src/core/math/spline/spline3_hermite_nearest_point.js +134 -167
  146. package/src/core/model/DebouncedObservedBoolean.d.ts +1 -2
  147. package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
  148. package/src/core/model/DebouncedObservedBoolean.js +1 -1
  149. package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
  150. package/src/core/model/node-graph/node/NodeInstance.js +2 -7
  151. package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +1 -1
  152. package/src/core/model/object/optional_equality.d.ts +3 -3
  153. package/src/core/model/object/optional_equality.d.ts.map +1 -1
  154. package/src/core/model/object/optional_equality.js +10 -27
  155. package/src/core/model/object/write_property.js +1 -1
  156. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +2 -2
  157. package/src/core/primitives/strings/string_compute_byte_size.d.ts +3 -3
  158. package/src/core/primitives/strings/string_compute_byte_size.d.ts.map +1 -1
  159. package/src/core/primitives/strings/string_compute_byte_size.js +8 -21
  160. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  161. package/src/core/process/executor/ConcurrentExecutor.js +14 -2
  162. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts +6 -3
  163. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts.map +1 -1
  164. package/src/engine/achievements/gateway/StorageAchievementGateway.js +31 -75
  165. package/src/engine/asset/loaders/SVGAssetLoader.d.ts.map +1 -1
  166. package/src/engine/asset/loaders/SVGAssetLoader.js +33 -31
  167. package/src/engine/control/first-person/math/criticallyDampedSpring.d.ts.map +1 -1
  168. package/src/engine/control/first-person/math/criticallyDampedSpring.js +3 -14
  169. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  170. package/src/engine/ecs/EntityComponentDataset.js +4 -1
  171. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts +0 -2
  172. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts.map +1 -1
  173. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +3 -3
  174. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
  175. package/src/engine/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
  176. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
  177. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  178. package/src/engine/graphics3/WaterSystem.js +2 -1
  179. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
  180. package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
  181. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
  182. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  183. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
  184. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  185. package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
  186. package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
  187. package/src/engine/input/ecs/systems/InputSystem.js +2 -1
  188. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
  189. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  190. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
  191. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
  192. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
  193. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  194. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
  195. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
  196. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
  197. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
  198. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
  199. package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
  200. package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
  201. package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
  202. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
  203. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
  204. package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
  205. package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
  206. package/src/engine/intelligence/mcts/StateNode.js +366 -364
  207. package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  208. package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
  209. package/src/engine/navigation/ecs/components/Path.js +2 -1
  210. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  211. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
  212. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  213. package/src/engine/physics/body/SolverBodyState.js +2 -6
  214. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  215. package/src/engine/physics/ccd/linear_sweep.js +3 -16
  216. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  217. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
  218. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
  219. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  220. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
  221. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  222. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  223. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
  224. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
  225. package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
  226. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  227. package/src/engine/physics/integration/integrate_velocity.js +3 -18
  228. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
  229. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  230. package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
  231. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  232. package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
  233. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  234. package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
  235. package/src/engine/save/StorageBackedList.d.ts +5 -0
  236. package/src/engine/save/StorageBackedList.d.ts.map +1 -1
  237. package/src/engine/save/StorageBackedList.js +161 -144
  238. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  239. package/src/engine/simulation/Ticker.js +394 -391
  240. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  241. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
  242. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
  243. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
  244. package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
  245. package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
  246. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
  247. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  248. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
  249. package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
  250. package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
  251. package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
  252. package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
  253. package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
  254. package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
  255. package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
  256. package/src/format/image/avif/av1/encode/quantise.js +1 -55
  257. package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
  258. package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
  259. package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
  260. package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
  261. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
  262. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  263. package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
  264. package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
  265. package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
  266. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
  267. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
  268. package/src/generation/foliage/FOLIAGE_DESIGN.md +165 -15
  269. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
  270. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
  271. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
  272. package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
  273. package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
  274. package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
  275. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
  276. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
  277. package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
  278. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
  279. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
  280. package/src/generation/foliage/analysis/crown_opacity_measure.js +649 -0
  281. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
  282. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
  283. package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +192 -0
  284. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
  285. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
  286. package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
  287. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
  288. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
  289. package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
  290. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
  291. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
  292. package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
  293. package/src/generation/foliage/asset/TreeAsset.d.ts +5 -0
  294. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  295. package/src/generation/foliage/asset/TreeAsset.js +6 -0
  296. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  297. package/src/generation/foliage/asset/generate_tree.js +23 -6
  298. package/src/generation/foliage/config/{BranchLevelConfig.d.ts → BranchGeneratorConfig.d.ts} +61 -75
  299. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
  300. package/src/generation/foliage/config/{BranchLevelConfig.js → BranchGeneratorConfig.js} +83 -126
  301. package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
  302. package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
  303. package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
  304. package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
  305. package/src/generation/foliage/config/FoliageCardType.js +2 -2
  306. package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
  307. package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
  308. package/src/generation/foliage/config/FoliageConfig.js +47 -93
  309. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
  310. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  311. package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
  312. package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
  313. package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
  314. package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
  315. package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
  316. package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
  317. package/src/generation/foliage/config/FoliageTileContent.js +12 -0
  318. package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
  319. package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
  320. package/src/generation/foliage/config/LeafApexShape.js +17 -0
  321. package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
  322. package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
  323. package/src/generation/foliage/config/LeafArchitecture.js +288 -0
  324. package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
  325. package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
  326. package/src/generation/foliage/config/LeafBaseShape.js +21 -0
  327. package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
  328. package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
  329. package/src/generation/foliage/config/LeafLobation.js +14 -0
  330. package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
  331. package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
  332. package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
  333. package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
  334. package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
  335. package/src/generation/foliage/config/ShootBudZone.js +219 -0
  336. package/src/generation/foliage/config/ShootGrowthConfig.d.ts +84 -0
  337. package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
  338. package/src/generation/foliage/config/ShootGrowthConfig.js +146 -0
  339. package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
  340. package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
  341. package/src/generation/foliage/config/ShootSystemRule.js +316 -0
  342. package/src/generation/foliage/config/TreeLODConfig.d.ts +1 -1
  343. package/src/generation/foliage/config/TreeLODConfig.js +1 -1
  344. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +40 -8
  345. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
  346. package/src/generation/foliage/config/TreeSpeciesConfig.js +124 -68
  347. package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
  348. package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
  349. package/src/generation/foliage/config/TreeWindConfig.js +34 -25
  350. package/src/generation/foliage/index.d.ts +19 -2
  351. package/src/generation/foliage/index.js +63 -44
  352. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
  353. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
  354. package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
  355. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
  356. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
  357. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
  358. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +34 -0
  359. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
  360. package/src/generation/foliage/material/foliage_atlas_cutout.js +174 -0
  361. package/src/generation/foliage/material/foliage_tile.d.ts +110 -0
  362. package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
  363. package/src/generation/foliage/material/foliage_tile.js +286 -0
  364. package/src/generation/foliage/material/leaf_geometry.d.ts +103 -0
  365. package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
  366. package/src/generation/foliage/material/leaf_geometry.js +528 -0
  367. package/src/generation/foliage/material/make_foliage_material.d.ts +13 -33
  368. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  369. package/src/generation/foliage/material/make_foliage_material.js +356 -605
  370. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +39 -4
  371. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  372. package/src/generation/foliage/mesh/foliage_collect_attachments.js +637 -569
  373. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
  374. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
  375. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
  376. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  377. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1023 -1049
  378. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +9 -2
  379. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  380. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +467 -454
  381. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  382. package/src/generation/foliage/presets/make_tree_species_preset.js +1648 -870
  383. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +35 -0
  384. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
  385. package/src/generation/foliage/skeleton/ShootFrameworkHash.js +129 -0
  386. package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
  387. package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
  388. package/src/generation/foliage/skeleton/ShootGirth.js +212 -0
  389. package/src/generation/foliage/skeleton/ShootLightField.d.ts +73 -0
  390. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
  391. package/src/generation/foliage/skeleton/ShootLightField.js +197 -0
  392. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +106 -3
  393. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  394. package/src/generation/foliage/skeleton/TreeSkeleton.js +217 -39
  395. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
  396. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
  397. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
  398. package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
  399. package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
  400. package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
  401. package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
  402. package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
  403. package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
  404. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
  405. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
  406. package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
  407. package/src/generation/foliage/skeleton/shoot_demography.d.ts +22 -0
  408. package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
  409. package/src/generation/foliage/skeleton/shoot_demography.js +96 -0
  410. package/src/generation/foliage/skeleton/shoot_geometry.d.ts +66 -0
  411. package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
  412. package/src/generation/foliage/skeleton/shoot_geometry.js +109 -0
  413. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +166 -0
  414. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
  415. package/src/generation/foliage/skeleton/shoot_systems_simulate.js +588 -0
  416. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +28 -12
  417. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
  418. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +137 -102
  419. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
  420. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
  421. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
  422. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  423. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
  424. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
  425. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  426. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2048 -1871
  427. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +17 -0
  428. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
  429. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +231 -0
  430. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
  431. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
  432. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
  433. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
  434. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
  435. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
  436. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  437. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
  438. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
  439. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  440. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
  441. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
  442. package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
  443. package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
  444. package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
  445. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
  446. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
  447. package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
  448. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  449. package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
  450. package/src/shade/playground/foliage_wind/index.html +6 -0
  451. package/src/shade/playground/foliage_wind/main.js +14 -0
  452. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  453. package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
  454. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
  455. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
  456. package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
  457. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
  458. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
  459. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  460. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  461. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
  462. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +1 -62
  463. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
  464. package/src/shade/renderer/camera/OrbitalCameraController.js +1 -374
  465. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
  466. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
  467. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
  468. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
  469. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
  470. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +2 -2
  471. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
  472. package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
  473. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
  474. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
  475. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
  476. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
  477. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
  478. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
  479. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
  480. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
  481. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  482. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
  483. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
  484. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
  485. package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
  486. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
  487. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
  488. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
  489. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
  490. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
  491. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
  492. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  493. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
  494. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
  495. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
  496. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
  497. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
  498. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
  499. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
  500. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
  501. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
  502. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
  503. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
  504. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
  505. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
  506. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +17 -7
  507. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
  508. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
  509. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
  510. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
  511. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
  512. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
  513. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
  514. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
  515. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
  516. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
  517. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
  518. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
  519. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  520. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
  521. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  522. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
  523. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
  524. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
  525. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
  526. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
  527. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
  528. package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
  529. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
  530. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
  531. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  532. package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
  533. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  534. package/src/shade/renderer/loader/usd/load_usd.js +6 -19
  535. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  536. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
  537. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  538. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
  539. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
  540. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
  541. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
  542. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
  543. package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
  544. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  545. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
  546. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
  547. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
  548. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
  549. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  550. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
  551. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  552. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
  553. package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
  554. package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
  555. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  556. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
  557. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  558. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
  559. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  560. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
  561. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  562. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
  563. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
  564. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
  565. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  566. package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
  567. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  568. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
  569. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  570. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
  571. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  572. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
  573. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
  574. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
  575. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  576. package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
  577. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  578. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
  579. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
  580. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
  581. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
  582. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
  583. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
  584. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
  585. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
  586. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  587. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
  588. package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
  589. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  590. package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
  591. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  592. package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
  593. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  594. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
  595. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  596. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
  597. package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
  598. package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
  599. package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
  600. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  601. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
  602. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  603. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
  604. package/src/shade/renderer/water/shader_water_avboit.js +1 -1
  605. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  606. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +260 -23
  607. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
  608. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  609. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +269 -69
  610. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  611. package/src/shade/wgsl/validate_wgsl_source.js +27 -1
  612. package/src/view/controller/controls/ListController.d.ts.map +1 -1
  613. package/src/view/controller/controls/ListController.js +118 -113
  614. package/src/view/controller/controls/Vector1Control.js +97 -97
  615. package/src/view/elements/image/SvgImageView.d.ts +1 -0
  616. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  617. package/src/view/elements/image/SvgImageView.js +92 -90
  618. package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
  619. package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
  620. package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
  621. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  622. package/src/engine/network/PriorityFetch.d.ts +0 -59
  623. package/src/engine/network/PriorityFetch.d.ts.map +0 -1
  624. package/src/engine/network/PriorityFetch.js +0 -193
  625. package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
@@ -1,391 +1,394 @@
1
- import { assert } from "../../core/assert.js";
2
- import Signal from "../../core/events/signal/Signal.js";
3
- import { current_time_in_seconds } from "../../core/time/current_time_in_seconds.js";
4
- import Clock from '../Clock.js';
5
-
6
- /**
7
- * Simulation tick generator
8
- * Dispatches "tick" every animation frame or "maxDelay" time, whichever happens to be soonest
9
- * This is essentially the timing bus that all the simulation systems subscribe to for their step advancement
10
- *
11
- * A tick taken in an animation frame runs inside that frame and is measured to the frame's timestamp,
12
- * and {@link Ticker#onFrame} follows it, so whatever draws from `onFrame` draws the simulation as of
13
- * that frame.
14
- *
15
- *
16
- * @example
17
- * ticker.onTick.add(delta_s => {
18
- * //do something every tick
19
- * });
20
- * ticker.start();
21
- *
22
- * @author Alex Goldring
23
- * @copyright Company Named Limited (c) 2026
24
- */
25
- class Ticker {
26
- /**
27
- * @readonly
28
- * @type {Clock}
29
- */
30
- clock = new Clock();
31
-
32
- /**
33
- * When `true`, ticking is suspended while the host document/tab is in the
34
- * background (hidden, or stored in the back/forward cache) and resumes from
35
- * the current moment once it returns to the foreground.
36
- *
37
- * This avoids dispatching a flood of catch-up ticks (or one huge delta) for
38
- * the time spent suspended, which would otherwise destabilise the simulation.
39
- *
40
- * Has no effect in environments without document/visibility support (e.g.
41
- * Node.js), where the relevant lifecycle events simply never fire.
42
- *
43
- * @type {boolean}
44
- */
45
- suspend_in_background = true;
46
-
47
- /**
48
- * @private
49
- * @type {boolean}
50
- */
51
- #isRunning = false;
52
-
53
- /**
54
- * Whether ticking is currently suspended because the host page is in the background
55
- * @private
56
- * @type {boolean}
57
- */
58
- #isSuspended = false;
59
-
60
- #animationFrameHandle = -1;
61
- #timeoutHandle = -1;
62
-
63
- /**
64
- * Incremented by {@link Ticker#stop}. The loop closures capture the value they were started
65
- * with and refuse to schedule anything once it moves, so a callback already in flight when
66
- * stop() ran cannot re-arm the loop behind it. Deliberately not keyed on #isRunning: pause()
67
- * clears that while the loop is meant to keep cycling.
68
- * @private
69
- * @type {number}
70
- */
71
- #generation = 0;
72
-
73
- /**
74
- * Time delta in seconds dispatched by the last tick
75
- * @type {number}
76
- */
77
- #last_tick_delta_s = 0;
78
-
79
- /**
80
- * Dispatches time delta in seconds since last tick
81
- * @readonly
82
- * @type {Signal<number>}
83
- */
84
- onTick = new Signal();
85
-
86
- /**
87
- * Dispatched once per animation frame, after that frame's tick - or with none, while paused or
88
- * suspended. The place to draw: the simulation is at the frame's timestamp here.
89
- * Not dispatched for the {@link start}'s `maxTimeout` fallback ticks, which are not frames.
90
- * @readonly
91
- * @type {Signal}
92
- */
93
- onFrame = new Signal();
94
-
95
- constructor() {
96
- this.clock.pause();
97
- }
98
-
99
- /**
100
- * Owned by {@link start} and {@link stop}; the two handles stay purely for cancellation.
101
- *
102
- * This used to be `#timeoutHandle !== -1 && #animationFrameHandle !== -1`, but `start()` only
103
- * assigns the animation-frame handle - the timeout handle stays -1 until the first frame
104
- * callback runs - so for the whole first frame the ticker reported itself inactive. `start()`'s
105
- * own "Already running" guard therefore did not fire, and `pause()`/`resume()`, which throw
106
- * when the loop is NOT active, did. A second `start()` inside that window installed a second
107
- * rAF/timeout chain, and a graphics context lost and restored inside it left the simulation
108
- * paused for ever, because Engine's restore path gates `resume()` on this.
109
- *
110
- * Unlike `#isRunning`, which `pause()` clears, this stays true across a pause.
111
- *
112
- * @type {boolean}
113
- */
114
- #loop_started = false;
115
-
116
- #isUpdateLoopActive() {
117
- return this.#loop_started;
118
- }
119
-
120
- /**
121
- * Whether the update loop is cycling. {@link Ticker#pause} and {@link Ticker#resume} require this,
122
- * they throw otherwise.
123
- * @returns {boolean}
124
- */
125
- get is_active() {
126
- return this.#isUpdateLoopActive();
127
- }
128
-
129
- /**
130
- * Whether tick dispatch is currently stopped via {@link Ticker#pause}. Suspension caused by the host
131
- * page going into the background is not reported here, see {@link Ticker#suspend_in_background}.
132
- * @returns {boolean}
133
- */
134
- get is_paused() {
135
- return !this.#isRunning;
136
- }
137
-
138
- /**
139
- * Stop dispatching ticks because the host page moved to the background.
140
- * The clock is paused so no simulation time accrues while suspended. The
141
- * update loop itself keeps cycling so it can pick back up cleanly, but
142
- * {@link Ticker#onTick} stays silent until the page returns to the foreground.
143
- * @private
144
- */
145
- #suspend() {
146
- if (!this.suspend_in_background) {
147
- return;
148
- }
149
-
150
- if (!this.#isRunning) {
151
- // not actively ticking, nothing to suspend
152
- return;
153
- }
154
-
155
- if (this.#isSuspended) {
156
- return;
157
- }
158
-
159
- this.#isSuspended = true;
160
-
161
- this.clock.pause();
162
- }
163
-
164
- /**
165
- * Resume after the host page returned to the foreground.
166
- *
167
- * The clock is always restarted here (it was paused while suspended), with the
168
- * delta accumulated for the suspended period discarded so that time continues
169
- * from the current moment rather than catching up all at once. Whether ticks
170
- * actually flow afterwards is still governed by the running flag, so a manual
171
- * {@link Ticker#pause} taken during suspension is preserved.
172
- * @private
173
- */
174
- #resume() {
175
- if (!this.#isSuspended) {
176
- return;
177
- }
178
-
179
- this.#isSuspended = false;
180
-
181
- this.clock.getDelta(); //discard time spent suspended
182
- this.clock.start();
183
- }
184
-
185
- #handleVisibilityChange = () => {
186
- const doc = globalThis.document;
187
-
188
- if (doc === undefined) {
189
- return;
190
- }
191
-
192
- if (doc.visibilityState === 'hidden') {
193
- this.#suspend();
194
- } else {
195
- this.#resume();
196
- }
197
- };
198
-
199
- #handlePageHide = () => {
200
- this.#suspend();
201
- };
202
-
203
- #handlePageShow = () => {
204
- this.#resume();
205
- };
206
-
207
- /**
208
- * Subscribe to page lifecycle events where the host environment provides them.
209
- * Degrades gracefully where there is no DOM event target (e.g. Node.js).
210
- * @private
211
- */
212
- #addLifecycleListeners() {
213
- const doc = globalThis.document;
214
- if (doc !== undefined && typeof doc.addEventListener === 'function') {
215
- doc.addEventListener('visibilitychange', this.#handleVisibilityChange);
216
- }
217
-
218
- if (typeof globalThis.addEventListener === 'function') {
219
- globalThis.addEventListener('pagehide', this.#handlePageHide);
220
- globalThis.addEventListener('pageshow', this.#handlePageShow);
221
- }
222
- }
223
-
224
- /**
225
- * @private
226
- */
227
- #removeLifecycleListeners() {
228
- const doc = globalThis.document;
229
- if (doc !== undefined && typeof doc.removeEventListener === 'function') {
230
- doc.removeEventListener('visibilitychange', this.#handleVisibilityChange);
231
- }
232
-
233
- if (typeof globalThis.removeEventListener === 'function') {
234
- globalThis.removeEventListener('pagehide', this.#handlePageHide);
235
- globalThis.removeEventListener('pageshow', this.#handlePageShow);
236
- }
237
- }
238
-
239
- /**
240
- *
241
- * @param {Object} [options]
242
- * @param {number} [options.maxTimeout]
243
- */
244
- start({ maxTimeout = 100 } = {}) {
245
- assert.isNumber(maxTimeout, 'maxTimeout');
246
- assert.greaterThan(maxTimeout, 0);
247
-
248
- if (this.#isUpdateLoopActive()) {
249
- throw new Error("Already running");
250
- }
251
-
252
- this.#loop_started = true;
253
- this.#isRunning = true;
254
- this.#isSuspended = false;
255
-
256
- const generation = this.#generation;
257
- const is_current = () => this.#generation === generation;
258
-
259
- /**
260
- * @param {number} time in seconds, on the {@link current_time_in_seconds} timeline
261
- */
262
- const update = (time) => {
263
- if (!this.#isRunning || this.#isSuspended) {
264
- return;
265
- }
266
-
267
- const delta = this.clock.getDeltaAt(time);
268
-
269
- this.#last_tick_delta_s = delta;
270
-
271
- this.onTick.send1(delta);
272
- }
273
-
274
- const timeoutCallback = () => {
275
- cancelAnimationFrame(this.#animationFrameHandle);
276
-
277
- if (!is_current()) {
278
- return;
279
- }
280
-
281
- animate(current_time_in_seconds());
282
- }
283
-
284
- /**
285
- * @param {number} timestamp the frame's, in milliseconds
286
- */
287
- const animationFrameCallback = (timestamp) => {
288
- clearTimeout(this.#timeoutHandle);
289
-
290
- if (!is_current()) {
291
- return;
292
- }
293
-
294
- /*
295
- Ticked here, on the frame's own timestamp, and before the frame is announced. This used to
296
- be pushed to a setTimeout(0) "allowing draw to happen" first, which made every frame draw
297
- the simulation as of the previous frame's timeout - and that fired whenever the previous
298
- draw finished, so a steady motion was drawn at a different speed every frame.
299
- */
300
- animate(timestamp * 1e-3);
301
-
302
- //a tick listener is allowed to stop us
303
- if (!is_current()) {
304
- return;
305
- }
306
-
307
- this.onFrame.send0();
308
- }
309
-
310
- /**
311
- * @param {number} time in seconds, on the {@link current_time_in_seconds} timeline
312
- */
313
- const animate = (time) => {
314
- if (!is_current()) {
315
- return;
316
- }
317
-
318
- this.#animationFrameHandle = requestAnimationFrame(animationFrameCallback);
319
-
320
- update(time);
321
-
322
- //update() dispatches onTick, and a listener is allowed to stop us from inside it
323
- if (!is_current()) {
324
- return;
325
- }
326
-
327
- this.#timeoutHandle = setTimeout(timeoutCallback, maxTimeout);
328
- }
329
-
330
- this.clock.getDelta(); //purge delta
331
- this.clock.start();
332
-
333
- this.#addLifecycleListeners();
334
-
335
- //recorded, so a stop() taken before the first frame lands can cancel it. The generation guard
336
- //already makes the callback a no-op, but an uncancelled frame request keeps the closures (and
337
- //everything the tick listeners hold) alive until it fires
338
- this.#animationFrameHandle = requestAnimationFrame(animationFrameCallback);
339
-
340
- //if we are starting while the page is already in the background, suspend right away
341
- const doc = globalThis.document;
342
- if (doc !== undefined && doc.visibilityState === 'hidden') {
343
- this.#suspend();
344
- }
345
- }
346
-
347
- pause() {
348
-
349
- if (!this.#isUpdateLoopActive()) {
350
- throw new Error("Not currently running");
351
- }
352
-
353
- this.#isRunning = false;
354
-
355
- //freeze the clock so no simulation time accrues while paused; without this
356
- //the first getDelta() after resume() returns the whole paused duration
357
- this.clock.pause();
358
- }
359
-
360
- resume() {
361
-
362
- if (!this.#isUpdateLoopActive()) {
363
- throw new Error("Not currently running");
364
- }
365
-
366
-
367
- this.#isRunning = true;
368
-
369
- //discard the time spent paused and restart from the current moment,
370
- //mirroring #resume() for the background-suspend path
371
- this.clock.getDelta();
372
- this.clock.start();
373
- }
374
-
375
- stop() {
376
- this.#generation++;
377
-
378
- this.#removeLifecycleListeners();
379
-
380
- clearTimeout(this.#timeoutHandle);
381
- cancelAnimationFrame(this.#animationFrameHandle);
382
- this.#loop_started = false;
383
- this.#isRunning = false;
384
- this.#isSuspended = false;
385
-
386
- this.#timeoutHandle = -1;
387
- this.#animationFrameHandle = -1;
388
- }
389
- }
390
-
391
- export default Ticker;
1
+ import { assert } from "../../core/assert.js";
2
+ import Signal from "../../core/events/signal/Signal.js";
3
+ import { current_time_in_seconds } from "../../core/time/current_time_in_seconds.js";
4
+ import Clock from '../Clock.js';
5
+
6
+ /**
7
+ * Simulation tick generator
8
+ * Dispatches "tick" every animation frame or "maxDelay" time, whichever happens to be soonest
9
+ * This is essentially the timing bus that all the simulation systems subscribe to for their step advancement
10
+ *
11
+ * A tick taken in an animation frame runs inside that frame and is measured to the frame's timestamp,
12
+ * and {@link Ticker#onFrame} follows it, so whatever draws from `onFrame` draws the simulation as of
13
+ * that frame.
14
+ *
15
+ *
16
+ * @example
17
+ * ticker.onTick.add(delta_s => {
18
+ * //do something every tick
19
+ * });
20
+ * ticker.start();
21
+ *
22
+ * @author Alex Goldring
23
+ * @copyright Company Named Limited (c) 2026
24
+ */
25
+ class Ticker {
26
+ /**
27
+ * @readonly
28
+ * @type {Clock}
29
+ */
30
+ clock = new Clock();
31
+
32
+ /**
33
+ * When `true`, ticking is suspended while the host document/tab is in the
34
+ * background (hidden, or stored in the back/forward cache) and resumes from
35
+ * the current moment once it returns to the foreground.
36
+ *
37
+ * This avoids dispatching a flood of catch-up ticks (or one huge delta) for
38
+ * the time spent suspended, which would otherwise destabilise the simulation.
39
+ *
40
+ * Has no effect in environments without document/visibility support (e.g.
41
+ * Node.js), where the relevant lifecycle events simply never fire.
42
+ *
43
+ * @type {boolean}
44
+ */
45
+ suspend_in_background = true;
46
+
47
+ /**
48
+ * @private
49
+ * @type {boolean}
50
+ */
51
+ #isRunning = false;
52
+
53
+ /**
54
+ * Whether ticking is currently suspended because the host page is in the background
55
+ * @private
56
+ * @type {boolean}
57
+ */
58
+ #isSuspended = false;
59
+
60
+ #animationFrameHandle = -1;
61
+ #timeoutHandle = -1;
62
+
63
+ /**
64
+ * Incremented by {@link Ticker#stop}. The loop closures capture the value they were started
65
+ * with and refuse to schedule anything once it moves, so a callback already in flight when
66
+ * stop() ran cannot re-arm the loop behind it. Deliberately not keyed on #isRunning: pause()
67
+ * clears that while the loop is meant to keep cycling.
68
+ * @private
69
+ * @type {number}
70
+ */
71
+ #generation = 0;
72
+
73
+ /**
74
+ * Time delta in seconds dispatched by the last tick
75
+ * @type {number}
76
+ */
77
+ #last_tick_delta_s = 0;
78
+
79
+ /**
80
+ * Dispatches time delta in seconds since last tick
81
+ * @readonly
82
+ * @type {Signal<number>}
83
+ */
84
+ onTick = new Signal();
85
+
86
+ /**
87
+ * Dispatched once per animation frame, after that frame's tick - or with none, while paused or
88
+ * suspended. The place to draw: the simulation is at the frame's timestamp here.
89
+ * Not dispatched for the {@link start}'s `maxTimeout` fallback ticks, which are not frames.
90
+ * @readonly
91
+ * @type {Signal}
92
+ */
93
+ onFrame = new Signal();
94
+
95
+ constructor() {
96
+ this.clock.pause();
97
+ }
98
+
99
+ /**
100
+ * Owned by {@link start} and {@link stop}; the two handles stay purely for cancellation.
101
+ *
102
+ * This used to be `#timeoutHandle !== -1 && #animationFrameHandle !== -1`, but `start()` only
103
+ * assigns the animation-frame handle - the timeout handle stays -1 until the first frame
104
+ * callback runs - so for the whole first frame the ticker reported itself inactive. `start()`'s
105
+ * own "Already running" guard therefore did not fire, and `pause()`/`resume()`, which throw
106
+ * when the loop is NOT active, did. A second `start()` inside that window installed a second
107
+ * rAF/timeout chain, and a graphics context lost and restored inside it left the simulation
108
+ * paused for ever, because Engine's restore path gates `resume()` on this.
109
+ *
110
+ * Unlike `#isRunning`, which `pause()` clears, this stays true across a pause.
111
+ *
112
+ * @type {boolean}
113
+ */
114
+ #loop_started = false;
115
+
116
+ #isUpdateLoopActive() {
117
+ return this.#loop_started;
118
+ }
119
+
120
+ /**
121
+ * Whether the update loop is cycling. {@link Ticker#pause} and {@link Ticker#resume} require this,
122
+ * they throw otherwise.
123
+ * @returns {boolean}
124
+ */
125
+ get is_active() {
126
+ return this.#isUpdateLoopActive();
127
+ }
128
+
129
+ /**
130
+ * Whether tick dispatch is currently stopped via {@link Ticker#pause}. Suspension caused by the host
131
+ * page going into the background is not reported here, see {@link Ticker#suspend_in_background}.
132
+ * @returns {boolean}
133
+ */
134
+ get is_paused() {
135
+ return !this.#isRunning;
136
+ }
137
+
138
+ /**
139
+ * Stop dispatching ticks because the host page moved to the background.
140
+ * The clock is paused so no simulation time accrues while suspended. The
141
+ * update loop itself keeps cycling so it can pick back up cleanly, but
142
+ * {@link Ticker#onTick} stays silent until the page returns to the foreground.
143
+ * @private
144
+ */
145
+ #suspend() {
146
+ if (!this.suspend_in_background) {
147
+ return;
148
+ }
149
+
150
+ if (!this.#isRunning) {
151
+ // not actively ticking, nothing to suspend
152
+ return;
153
+ }
154
+
155
+ if (this.#isSuspended) {
156
+ return;
157
+ }
158
+
159
+ this.#isSuspended = true;
160
+
161
+ this.clock.pause();
162
+ }
163
+
164
+ /**
165
+ * Resume after the host page returned to the foreground.
166
+ *
167
+ * The clock is restarted here when not manually paused, with the
168
+ * delta accumulated for the suspended period discarded so that time continues
169
+ * from the current moment rather than catching up all at once. Whether ticks
170
+ * actually flow afterwards is still governed by the running flag, so a manual
171
+ * {@link Ticker#pause} taken during suspension is preserved.
172
+ * @private
173
+ */
174
+ #resume() {
175
+ if (!this.#isSuspended) {
176
+ return;
177
+ }
178
+
179
+ this.#isSuspended = false;
180
+
181
+ this.clock.getDelta(); //discard time spent suspended
182
+
183
+ if (this.#isRunning) {
184
+ this.clock.start();
185
+ }
186
+ }
187
+
188
+ #handleVisibilityChange = () => {
189
+ const doc = globalThis.document;
190
+
191
+ if (doc === undefined) {
192
+ return;
193
+ }
194
+
195
+ if (doc.visibilityState === 'hidden') {
196
+ this.#suspend();
197
+ } else {
198
+ this.#resume();
199
+ }
200
+ };
201
+
202
+ #handlePageHide = () => {
203
+ this.#suspend();
204
+ };
205
+
206
+ #handlePageShow = () => {
207
+ this.#resume();
208
+ };
209
+
210
+ /**
211
+ * Subscribe to page lifecycle events where the host environment provides them.
212
+ * Degrades gracefully where there is no DOM event target (e.g. Node.js).
213
+ * @private
214
+ */
215
+ #addLifecycleListeners() {
216
+ const doc = globalThis.document;
217
+ if (doc !== undefined && typeof doc.addEventListener === 'function') {
218
+ doc.addEventListener('visibilitychange', this.#handleVisibilityChange);
219
+ }
220
+
221
+ if (typeof globalThis.addEventListener === 'function') {
222
+ globalThis.addEventListener('pagehide', this.#handlePageHide);
223
+ globalThis.addEventListener('pageshow', this.#handlePageShow);
224
+ }
225
+ }
226
+
227
+ /**
228
+ * @private
229
+ */
230
+ #removeLifecycleListeners() {
231
+ const doc = globalThis.document;
232
+ if (doc !== undefined && typeof doc.removeEventListener === 'function') {
233
+ doc.removeEventListener('visibilitychange', this.#handleVisibilityChange);
234
+ }
235
+
236
+ if (typeof globalThis.removeEventListener === 'function') {
237
+ globalThis.removeEventListener('pagehide', this.#handlePageHide);
238
+ globalThis.removeEventListener('pageshow', this.#handlePageShow);
239
+ }
240
+ }
241
+
242
+ /**
243
+ *
244
+ * @param {Object} [options]
245
+ * @param {number} [options.maxTimeout]
246
+ */
247
+ start({ maxTimeout = 100 } = {}) {
248
+ assert.isNumber(maxTimeout, 'maxTimeout');
249
+ assert.greaterThan(maxTimeout, 0);
250
+
251
+ if (this.#isUpdateLoopActive()) {
252
+ throw new Error("Already running");
253
+ }
254
+
255
+ this.#loop_started = true;
256
+ this.#isRunning = true;
257
+ this.#isSuspended = false;
258
+
259
+ const generation = this.#generation;
260
+ const is_current = () => this.#generation === generation;
261
+
262
+ /**
263
+ * @param {number} time in seconds, on the {@link current_time_in_seconds} timeline
264
+ */
265
+ const update = (time) => {
266
+ if (!this.#isRunning || this.#isSuspended) {
267
+ return;
268
+ }
269
+
270
+ const delta = this.clock.getDeltaAt(time);
271
+
272
+ this.#last_tick_delta_s = delta;
273
+
274
+ this.onTick.send1(delta);
275
+ }
276
+
277
+ const timeoutCallback = () => {
278
+ cancelAnimationFrame(this.#animationFrameHandle);
279
+
280
+ if (!is_current()) {
281
+ return;
282
+ }
283
+
284
+ animate(current_time_in_seconds());
285
+ }
286
+
287
+ /**
288
+ * @param {number} timestamp the frame's, in milliseconds
289
+ */
290
+ const animationFrameCallback = (timestamp) => {
291
+ clearTimeout(this.#timeoutHandle);
292
+
293
+ if (!is_current()) {
294
+ return;
295
+ }
296
+
297
+ /*
298
+ Ticked here, on the frame's own timestamp, and before the frame is announced. This used to
299
+ be pushed to a setTimeout(0) "allowing draw to happen" first, which made every frame draw
300
+ the simulation as of the previous frame's timeout - and that fired whenever the previous
301
+ draw finished, so a steady motion was drawn at a different speed every frame.
302
+ */
303
+ animate(timestamp * 1e-3);
304
+
305
+ //a tick listener is allowed to stop us
306
+ if (!is_current()) {
307
+ return;
308
+ }
309
+
310
+ this.onFrame.send0();
311
+ }
312
+
313
+ /**
314
+ * @param {number} time in seconds, on the {@link current_time_in_seconds} timeline
315
+ */
316
+ const animate = (time) => {
317
+ if (!is_current()) {
318
+ return;
319
+ }
320
+
321
+ this.#animationFrameHandle = requestAnimationFrame(animationFrameCallback);
322
+
323
+ update(time);
324
+
325
+ //update() dispatches onTick, and a listener is allowed to stop us from inside it
326
+ if (!is_current()) {
327
+ return;
328
+ }
329
+
330
+ this.#timeoutHandle = setTimeout(timeoutCallback, maxTimeout);
331
+ }
332
+
333
+ this.clock.getDelta(); //purge delta
334
+ this.clock.start();
335
+
336
+ this.#addLifecycleListeners();
337
+
338
+ //recorded, so a stop() taken before the first frame lands can cancel it. The generation guard
339
+ //already makes the callback a no-op, but an uncancelled frame request keeps the closures (and
340
+ //everything the tick listeners hold) alive until it fires
341
+ this.#animationFrameHandle = requestAnimationFrame(animationFrameCallback);
342
+
343
+ //if we are starting while the page is already in the background, suspend right away
344
+ const doc = globalThis.document;
345
+ if (doc !== undefined && doc.visibilityState === 'hidden') {
346
+ this.#suspend();
347
+ }
348
+ }
349
+
350
+ pause() {
351
+
352
+ if (!this.#isUpdateLoopActive()) {
353
+ throw new Error("Not currently running");
354
+ }
355
+
356
+ this.#isRunning = false;
357
+
358
+ //freeze the clock so no simulation time accrues while paused; without this
359
+ //the first getDelta() after resume() returns the whole paused duration
360
+ this.clock.pause();
361
+ }
362
+
363
+ resume() {
364
+
365
+ if (!this.#isUpdateLoopActive()) {
366
+ throw new Error("Not currently running");
367
+ }
368
+
369
+
370
+ this.#isRunning = true;
371
+
372
+ //discard the time spent paused and restart from the current moment,
373
+ //mirroring #resume() for the background-suspend path
374
+ this.clock.getDelta();
375
+ this.clock.start();
376
+ }
377
+
378
+ stop() {
379
+ this.#generation++;
380
+
381
+ this.#removeLifecycleListeners();
382
+
383
+ clearTimeout(this.#timeoutHandle);
384
+ cancelAnimationFrame(this.#animationFrameHandle);
385
+ this.#loop_started = false;
386
+ this.#isRunning = false;
387
+ this.#isSuspended = false;
388
+
389
+ this.#timeoutHandle = -1;
390
+ this.#animationFrameHandle = -1;
391
+ }
392
+ }
393
+
394
+ export default Ticker;