@woosh/meep-engine 2.155.0 → 2.157.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 (1098) hide show
  1. package/README.md +2 -4
  2. package/build/bundle-worker-image-decoder.js +1 -1
  3. package/build/bundle-worker-terrain.js +1 -1
  4. package/editor/view/ecs/ComponentControlView.d.ts +0 -9
  5. package/editor/view/ecs/ComponentControlView.js +2 -98
  6. package/editor/view/ecs/components/common/AutoCanvasView.js +100 -53
  7. package/editor/view/ecs/components/common/TextController.js +59 -0
  8. package/editor/view/node-graph/NodeGraphCamera.js +90 -0
  9. package/editor/view/node-graph/NodeGraphEditorView.js +121 -22
  10. package/editor/view/node-graph/NodeGraphSelection.js +89 -0
  11. package/editor/view/node-graph/NodeGraphView.js +669 -453
  12. package/editor/view/node-graph/NodeView.js +211 -135
  13. package/editor/view/node-graph/actions/ConnectionCreateAction.js +53 -0
  14. package/editor/view/node-graph/actions/ConnectionDeleteAction.js +36 -0
  15. package/editor/view/node-graph/actions/NodeDeleteAction.js +88 -0
  16. package/editor/view/node-graph/actions/NodeParameterSetAction.js +52 -0
  17. package/editor/view/node-graph/actions/NodesMoveAction.js +41 -0
  18. package/editor/view/node-graph/actions/SelectionSetAction.js +60 -0
  19. package/editor/view/node-graph/connection_wire_geometry.js +107 -0
  20. package/package.json +1 -1
  21. package/samples/generation/SampleGenerator0.js +8 -1
  22. package/src/core/binary/32BitEncoder.js +1 -1
  23. package/src/core/binary/reinterpret_float32_as_uint32.d.ts +7 -0
  24. package/src/core/binary/reinterpret_float32_as_uint32.d.ts.map +1 -0
  25. package/src/core/binary/reinterpret_float32_as_uint32.js +13 -0
  26. package/src/core/binary/reinterpret_uint32_as_float32.d.ts +7 -0
  27. package/src/core/binary/reinterpret_uint32_as_float32.d.ts.map +1 -0
  28. package/src/core/binary/reinterpret_uint32_as_float32.js +14 -0
  29. package/src/core/binary/to_half_float_uint16.js +3 -3
  30. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.d.ts.map +1 -1
  31. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.js +1 -3
  32. package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.d.ts.map +1 -1
  33. package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.js +275 -253
  34. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts +12 -0
  35. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts.map +1 -0
  36. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.js +92 -0
  37. package/src/core/bvh8/BVH8.d.ts +127 -0
  38. package/src/core/bvh8/BVH8.d.ts.map +1 -0
  39. package/src/core/bvh8/BVH8.js +436 -0
  40. package/src/core/bvh8/NOTES.md +63 -0
  41. package/src/core/bvh8/build/BVH8Converter.d.ts +59 -0
  42. package/src/core/bvh8/build/BVH8Converter.d.ts.map +1 -0
  43. package/src/core/bvh8/build/BVH8Converter.js +588 -0
  44. package/src/core/bvh8/build/NodeProxy.d.ts +66 -0
  45. package/src/core/bvh8/build/NodeProxy.d.ts.map +1 -0
  46. package/src/core/bvh8/build/NodeProxy.js +308 -0
  47. package/src/core/bvh8/build/TriangleCluster.d.ts +29 -0
  48. package/src/core/bvh8/build/TriangleCluster.d.ts.map +1 -0
  49. package/src/core/bvh8/build/TriangleCluster.js +123 -0
  50. package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts +8 -0
  51. package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts.map +1 -0
  52. package/src/core/bvh8/build/aabb3_compute_merge_cost.js +29 -0
  53. package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts +10 -0
  54. package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts.map +1 -0
  55. package/src/core/bvh8/build/aabb3_from_triangle_by_index.js +18 -0
  56. package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts +10 -0
  57. package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts.map +1 -0
  58. package/src/core/bvh8/build/bvh8_build_for_geometry.js +303 -0
  59. package/src/core/bvh8/build/bvh8_from_proxy.d.ts +9 -0
  60. package/src/core/bvh8/build/bvh8_from_proxy.d.ts.map +1 -0
  61. package/src/core/bvh8/build/bvh8_from_proxy.js +256 -0
  62. package/src/core/bvh8/build/byte.d.ts +7 -0
  63. package/src/core/bvh8/build/byte.d.ts.map +1 -0
  64. package/src/core/bvh8/build/byte.js +10 -0
  65. package/src/core/bvh8/build/encode_bounds_e.d.ts +9 -0
  66. package/src/core/bvh8/build/encode_bounds_e.d.ts.map +1 -0
  67. package/src/core/bvh8/build/encode_bounds_e.js +12 -0
  68. package/src/core/bvh8/bvh8_convert_to_dot.d.ts +11 -0
  69. package/src/core/bvh8/bvh8_convert_to_dot.d.ts.map +1 -0
  70. package/src/core/bvh8/bvh8_convert_to_dot.js +133 -0
  71. package/src/core/bvh8/bvh8_count_primitives.d.ts +22 -0
  72. package/src/core/bvh8/bvh8_count_primitives.d.ts.map +1 -0
  73. package/src/core/bvh8/bvh8_count_primitives.js +98 -0
  74. package/src/core/bvh8/bvh8_geometry_validate.d.ts +16 -0
  75. package/src/core/bvh8/bvh8_geometry_validate.d.ts.map +1 -0
  76. package/src/core/bvh8/bvh8_geometry_validate.js +149 -0
  77. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts +16 -0
  78. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts.map +1 -0
  79. package/src/core/bvh8/bvh8_geometry_validate_indirect.js +177 -0
  80. package/src/core/bvh8/bvh8_get_node_bounds.d.ts +9 -0
  81. package/src/core/bvh8/bvh8_get_node_bounds.d.ts.map +1 -0
  82. package/src/core/bvh8/bvh8_get_node_bounds.js +35 -0
  83. package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts +10 -0
  84. package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts.map +1 -0
  85. package/src/core/bvh8/bvh8_get_node_child_bounds.js +53 -0
  86. package/src/core/bvh8/bvh8_node_child_surface_area.d.ts +9 -0
  87. package/src/core/bvh8/bvh8_node_child_surface_area.d.ts.map +1 -0
  88. package/src/core/bvh8/bvh8_node_child_surface_area.js +18 -0
  89. package/src/core/bvh8/bvh8_node_count_triangles.d.ts +8 -0
  90. package/src/core/bvh8/bvh8_node_count_triangles.d.ts.map +1 -0
  91. package/src/core/bvh8/bvh8_node_count_triangles.js +28 -0
  92. package/src/core/bvh8/bvh8_quality.d.ts +8 -0
  93. package/src/core/bvh8/bvh8_quality.d.ts.map +1 -0
  94. package/src/core/bvh8/bvh8_quality.js +73 -0
  95. package/src/core/bvh8/bvh8_validate_structure.d.ts +15 -0
  96. package/src/core/bvh8/bvh8_validate_structure.d.ts.map +1 -0
  97. package/src/core/bvh8/bvh8_validate_structure.js +87 -0
  98. package/src/core/cache/Cache.d.ts.map +1 -1
  99. package/src/core/cache/Cache.js +7 -0
  100. package/src/core/cache/FrequencySketch.d.ts.map +1 -1
  101. package/src/core/cache/FrequencySketch.js +8 -4
  102. package/src/core/clipboard/obtainClipBoard.d.ts +6 -0
  103. package/src/core/clipboard/obtainClipBoard.d.ts.map +1 -0
  104. package/src/core/clipboard/obtainClipBoard.js +29 -0
  105. package/src/core/clipboard/safeClipboardReadText.d.ts +6 -0
  106. package/src/core/clipboard/safeClipboardReadText.d.ts.map +1 -0
  107. package/src/core/clipboard/safeClipboardReadText.js +55 -0
  108. package/src/core/clipboard/safeClipboardWriteText.d.ts +8 -0
  109. package/src/core/clipboard/safeClipboardWriteText.d.ts.map +1 -0
  110. package/src/core/clipboard/safeClipboardWriteText.js +23 -0
  111. package/src/core/collection/Uint32MinHeap.d.ts +56 -0
  112. package/src/core/collection/Uint32MinHeap.d.ts.map +1 -0
  113. package/src/core/collection/Uint32MinHeap.js +109 -0
  114. package/src/core/collection/array/array_quick_sort_by_lookup_map.js +1 -1
  115. package/src/core/collection/array/array_set_diff_sorting.d.ts.map +1 -1
  116. package/src/core/collection/array/array_set_diff_sorting.js +4 -1
  117. package/src/core/collection/array/array_shuffle.d.ts.map +1 -1
  118. package/src/core/collection/array/array_shuffle.js +30 -27
  119. package/src/core/collection/array/binarySearchLowIndex.d.ts.map +1 -1
  120. package/src/core/collection/array/binarySearchLowIndex.js +4 -3
  121. package/src/core/collection/array/typed/array_buffer_hash.js +1 -1
  122. package/src/core/collection/array/typed/is_typed_array_equals.d.ts.map +1 -1
  123. package/src/core/collection/array/typed/is_typed_array_equals.js +12 -2
  124. package/src/core/collection/heap/BinaryHeap.d.ts.map +1 -1
  125. package/src/core/collection/heap/BinaryHeap.js +12 -2
  126. package/src/core/collection/list/FilteredListProjection.js +1 -1
  127. package/src/core/collection/queue/Deque.d.ts.map +1 -1
  128. package/src/core/collection/queue/Deque.js +10 -8
  129. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  130. package/src/core/collection/table/RowFirstTable.js +4 -2
  131. package/src/core/collection/table/RowFirstTableSpec.js +2 -2
  132. package/src/{engine/physics/island → core/collection/union-find}/union_find.d.ts +8 -5
  133. package/src/core/collection/union-find/union_find.d.ts.map +1 -0
  134. package/src/{engine/physics/island → core/collection/union-find}/union_find.js +8 -5
  135. package/src/core/color/operations/color_lerp.d.ts.map +1 -1
  136. package/src/core/color/operations/color_lerp.js +10 -3
  137. package/src/core/color/rgb2uint32.js +1 -1
  138. package/src/core/color/rgbe9995_to_rgb.js +1 -1
  139. package/src/core/dom/isImageBitmap.d.ts +7 -0
  140. package/src/core/dom/isImageBitmap.d.ts.map +1 -0
  141. package/src/core/dom/isImageBitmap.js +12 -0
  142. package/src/core/function/frameThrottle.d.ts +8 -0
  143. package/src/core/function/frameThrottle.d.ts.map +1 -0
  144. package/src/core/function/frameThrottle.js +23 -0
  145. package/src/core/function/objectsEqual.d.ts.map +1 -1
  146. package/src/core/function/objectsEqual.js +2 -1
  147. package/src/core/geom/2d/aabb/AABB2.d.ts.map +1 -1
  148. package/src/core/geom/2d/aabb/AABB2.js +12 -11
  149. package/src/core/geom/2d/convex-hull/convex_hull_jarvis_2d.d.ts.map +1 -1
  150. package/src/core/geom/2d/convex-hull/convex_hull_jarvis_2d.js +30 -4
  151. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.d.ts.map +1 -1
  152. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +6 -2
  153. package/src/core/geom/2d/hash-grid/SpatialHashGrid.d.ts.map +1 -1
  154. package/src/core/geom/2d/hash-grid/SpatialHashGrid.js +388 -386
  155. package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
  156. package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -3
  157. package/src/{engine/physics/narrowphase/clip_against_axis_uv.d.ts → core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts} +3 -3
  158. package/src/core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts.map +1 -0
  159. package/src/{engine/physics/narrowphase/clip_against_axis_uv.js → core/geom/2d/polygon/polygon2_clip_axis_halfplane.js} +51 -51
  160. package/src/core/geom/2d/quad-tree/QuadTreeDatum.d.ts.map +1 -1
  161. package/src/core/geom/2d/quad-tree/QuadTreeDatum.js +9 -1
  162. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.d.ts +3 -1
  163. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.d.ts.map +1 -1
  164. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.js +3 -1
  165. package/src/core/geom/2d/quad-tree-binary/QuadTree.js +714 -714
  166. package/src/core/geom/2d/r-tree/StaticR2Tree.d.ts.map +1 -1
  167. package/src/core/geom/2d/r-tree/StaticR2Tree.js +5 -4
  168. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.d.ts.map +1 -1
  169. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.js +33 -29
  170. package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.d.ts.map +1 -1
  171. package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.js +3 -1
  172. package/src/core/geom/3d/aabb/aabb3_signed_distance_to_aabb3.d.ts.map +1 -1
  173. package/src/core/geom/3d/aabb/aabb3_signed_distance_to_aabb3.js +10 -7
  174. package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts → core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts} +9 -7
  175. package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts.map +1 -0
  176. package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.js → core/geom/3d/aabb/aabb3_transform_oriented_inverse.js} +9 -7
  177. package/src/core/geom/3d/aabb/aabb3_transformed_compute_plane_side.d.ts.map +1 -1
  178. package/src/core/geom/3d/aabb/aabb3_transformed_compute_plane_side.js +30 -9
  179. package/src/core/geom/3d/aabb/compute_aabb_from_points.js +3 -3
  180. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts +12 -0
  181. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts.map +1 -0
  182. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.js +46 -0
  183. package/src/core/geom/3d/box/box3_projected_half_extent.d.ts +28 -0
  184. package/src/core/geom/3d/box/box3_projected_half_extent.d.ts.map +1 -0
  185. package/src/core/geom/3d/box/box3_projected_half_extent.js +35 -0
  186. package/src/core/geom/3d/box/box3_raycast.d.ts +37 -0
  187. package/src/core/geom/3d/box/box3_raycast.d.ts.map +1 -0
  188. package/src/core/geom/3d/box/box3_raycast.js +81 -0
  189. package/src/core/geom/3d/capsule/capsule_raycast.d.ts +35 -0
  190. package/src/core/geom/3d/capsule/capsule_raycast.d.ts.map +1 -0
  191. package/src/core/geom/3d/capsule/capsule_raycast.js +93 -0
  192. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.d.ts.map +1 -1
  193. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.js +4 -0
  194. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +1 -1
  195. package/src/core/geom/3d/frustum/read_cluster_frustum_corners.js +1 -1
  196. package/src/core/geom/3d/frustum/read_frustum_corner.d.ts +9 -0
  197. package/src/core/geom/3d/frustum/read_frustum_corner.d.ts.map +1 -0
  198. package/src/core/geom/3d/frustum/read_frustum_corner.js +14 -0
  199. package/src/core/geom/3d/gjk/gjk.d.ts.map +1 -0
  200. package/src/{engine/physics → core/geom/3d}/gjk/gjk.js +430 -372
  201. package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.d.ts +8 -5
  202. package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -0
  203. package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.js +520 -548
  204. package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.d.ts +5 -4
  205. package/src/core/geom/3d/gjk/minkowski_support.d.ts.map +1 -0
  206. package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.js +71 -70
  207. package/src/{engine/physics → core/geom/3d}/gjk/mpr.d.ts +3 -3
  208. package/src/core/geom/3d/gjk/mpr.d.ts.map +1 -0
  209. package/src/{engine/physics → core/geom/3d}/gjk/mpr.js +368 -362
  210. package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.d.ts.map +1 -1
  211. package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.js +3 -2
  212. package/src/core/geom/3d/mat4/decompose_matrix_4_array.d.ts.map +1 -1
  213. package/src/core/geom/3d/mat4/decompose_matrix_4_array.js +12 -2
  214. package/src/core/geom/3d/mat4/eulerAnglesFromMatrix.js +2 -2
  215. package/src/core/geom/3d/mat4/m4_multiply_alphatensor.d.ts +1 -1
  216. package/src/core/geom/3d/mat4/m4_multiply_alphatensor.d.ts.map +1 -1
  217. package/src/core/geom/3d/mat4/m4_multiply_alphatensor.js +19 -13
  218. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.d.ts.map +1 -1
  219. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.js +3 -2
  220. package/src/core/geom/3d/plane/plane3_compute_plane_intersection.js +3 -2
  221. package/src/{engine/physics/integration/quat_integrate.d.ts → core/geom/3d/quaternion/quat3_integrate.d.ts} +2 -2
  222. package/src/core/geom/3d/quaternion/quat3_integrate.d.ts.map +1 -0
  223. package/src/{engine/physics/integration/quat_integrate.js → core/geom/3d/quaternion/quat3_integrate.js} +1 -1
  224. package/src/core/geom/3d/shape/MeshShape3D.d.ts.map +1 -1
  225. package/src/core/geom/3d/shape/MeshShape3D.js +7 -0
  226. package/src/{engine/physics/narrowphase/PosedShape.d.ts → core/geom/3d/shape/PosedShape3D.d.ts} +9 -8
  227. package/src/{engine/physics/narrowphase/PosedShape.d.ts.map → core/geom/3d/shape/PosedShape3D.d.ts.map} +1 -1
  228. package/src/{engine/physics/narrowphase/PosedShape.js → core/geom/3d/shape/PosedShape3D.js} +10 -9
  229. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  230. package/src/core/geom/3d/shape/TransformedShape3D.js +15 -11
  231. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  232. package/src/core/geom/3d/shape/UnionShape3D.js +3 -2
  233. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts.map +1 -1
  234. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +153 -148
  235. package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.d.ts.map +1 -1
  236. package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +7 -0
  237. package/src/core/geom/3d/sphere/harmonics/sh3_sample_by_direction.d.ts.map +1 -1
  238. package/src/core/geom/3d/sphere/harmonics/sh3_sample_by_direction.js +13 -10
  239. package/src/core/geom/3d/sphere/sphere_projected_sphere_radius_sqr.d.ts +1 -1
  240. package/src/core/geom/3d/sphere/sphere_projected_sphere_radius_sqr.js +2 -2
  241. package/src/core/geom/3d/sphere/sphere_raycast.d.ts +33 -0
  242. package/src/core/geom/3d/sphere/sphere_raycast.d.ts.map +1 -0
  243. package/src/core/geom/3d/sphere/sphere_raycast.js +47 -0
  244. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.d.ts +24 -0
  245. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.d.ts.map +1 -0
  246. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.js +39 -0
  247. package/src/core/geom/3d/tetrahedra/triangle/trace_triangular_depth_map.d.ts.map +1 -1
  248. package/src/core/geom/3d/tetrahedra/triangle/trace_triangular_depth_map.js +4 -2
  249. package/src/core/geom/3d/topology/bounds/computeTriangleClusterNormalBoundingCone.js +3 -3
  250. package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +1 -1
  251. package/src/core/geom/3d/topology/tm_vertex_compute_normal.d.ts.map +1 -1
  252. package/src/core/geom/3d/topology/tm_vertex_compute_normal.js +4 -2
  253. package/src/core/geom/3d/util/make_justified_point_grid.d.ts.map +1 -1
  254. package/src/core/geom/3d/util/make_justified_point_grid.js +18 -10
  255. package/src/core/geom/ConicRay.d.ts.map +1 -1
  256. package/src/core/geom/ConicRay.js +11 -13
  257. package/src/core/geom/packing/max-rect/removeRedundantBoxes.d.ts.map +1 -1
  258. package/src/core/geom/packing/max-rect/removeRedundantBoxes.js +19 -4
  259. package/src/core/geom/vec3/v3_orthonormal_matrix_from_normal.d.ts.map +1 -0
  260. package/src/{engine/graphics/sh3/path_tracer/sampling → core/geom/vec3}/v3_orthonormal_matrix_from_normal.js +1 -1
  261. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +1 -1
  262. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +1 -1
  263. package/src/core/graph/coloring/colorizeGraph.js +2 -2
  264. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -1
  265. package/src/core/graph/csr/CSRGraph.js +325 -319
  266. package/src/core/graph/layout/CircleLayout.d.ts.map +1 -1
  267. package/src/core/graph/layout/CircleLayout.js +8 -6
  268. package/src/core/graph/metis/native/refine/compute_kway_params.d.ts.map +1 -1
  269. package/src/core/graph/metis/native/refine/compute_kway_params.js +139 -138
  270. package/src/core/graph/mn_graph_coarsen.d.ts.map +1 -1
  271. package/src/core/graph/mn_graph_coarsen.js +4 -2
  272. package/src/core/graph/v2/NodeContainer.js +7 -7
  273. package/src/core/localization/LocalizationEngine.js +1 -1
  274. package/src/core/math/bell_membership_function.d.ts.map +1 -1
  275. package/src/core/math/bell_membership_function.js +3 -1
  276. package/src/core/math/complex/complex_add.d.ts +4 -4
  277. package/src/core/math/complex/complex_add.d.ts.map +1 -1
  278. package/src/core/math/complex/complex_add.js +14 -5
  279. package/src/core/math/complex/complex_div.d.ts +4 -4
  280. package/src/core/math/complex/complex_div.d.ts.map +1 -1
  281. package/src/core/math/complex/complex_div.js +13 -6
  282. package/src/core/math/complex/complex_mul.d.ts +4 -4
  283. package/src/core/math/complex/complex_mul.d.ts.map +1 -1
  284. package/src/core/math/complex/complex_mul.js +12 -5
  285. package/src/core/math/complex/complex_sub.d.ts +4 -4
  286. package/src/core/math/complex/complex_sub.d.ts.map +1 -1
  287. package/src/core/math/complex/complex_sub.js +14 -5
  288. package/src/core/math/idct_1d.d.ts +4 -4
  289. package/src/core/math/idct_1d.d.ts.map +1 -1
  290. package/src/core/math/idct_1d.js +3 -3
  291. package/src/{engine/physics/fluid/solver/optimal_sor_omega.d.ts → core/math/linalg/sor_optimal_omega.d.ts} +4 -3
  292. package/src/core/math/linalg/sor_optimal_omega.d.ts.map +1 -0
  293. package/src/{engine/physics/fluid/solver/optimal_sor_omega.js → core/math/linalg/sor_optimal_omega.js} +4 -3
  294. package/src/core/math/lookup/ParameterLookupTable.d.ts +123 -0
  295. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -0
  296. package/src/core/math/lookup/ParameterLookupTable.js +495 -0
  297. package/src/core/math/lookup/ParameterLookupTableFlags.d.ts +5 -0
  298. package/src/core/math/lookup/ParameterLookupTableFlags.d.ts.map +1 -0
  299. package/src/core/math/lookup/ParameterLookupTableFlags.js +6 -0
  300. package/src/core/math/noise/create_simplex_noise_2d.d.ts.map +1 -1
  301. package/src/core/math/noise/create_simplex_noise_2d.js +4 -2
  302. package/src/core/math/noise/sdnoise.d.ts.map +1 -1
  303. package/src/core/math/noise/sdnoise.js +12 -9
  304. package/src/core/math/physics/kinematics/computeInterceptPoint.d.ts.map +1 -0
  305. package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.js +79 -79
  306. package/src/core/math/physics/mie/compute_bhmie_optical_properties.d.ts.map +1 -1
  307. package/src/core/math/physics/mie/compute_bhmie_optical_properties.js +94 -50
  308. package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts +3 -6
  309. package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts.map +1 -1
  310. package/src/core/math/physics/mie/lorenz_mie_coefs.js +180 -157
  311. package/src/core/math/physics/mie/mie_ab_to_optical_properties.d.ts +3 -4
  312. package/src/core/math/physics/mie/mie_ab_to_optical_properties.d.ts.map +1 -1
  313. package/src/core/math/physics/mie/mie_ab_to_optical_properties.js +47 -21
  314. package/src/core/math/physics/mie/ri_air.d.ts.map +1 -1
  315. package/src/core/math/physics/mie/ri_air.js +1 -3
  316. package/src/core/math/physics/mie/ri_ammonium_sulfate.d.ts.map +1 -1
  317. package/src/core/math/physics/mie/ri_ammonium_sulfate.js +1 -3
  318. package/src/core/math/physics/mie/ri_brine.d.ts.map +1 -1
  319. package/src/core/math/physics/mie/ri_brine.js +1 -3
  320. package/src/core/math/physics/mie/ri_dust.d.ts.map +1 -1
  321. package/src/core/math/physics/mie/ri_dust.js +1 -3
  322. package/src/core/math/physics/mie/ri_pollen.d.ts.map +1 -1
  323. package/src/core/math/physics/mie/ri_pollen.js +1 -3
  324. package/src/core/math/physics/mie/ri_smoke.d.ts.map +1 -1
  325. package/src/core/math/physics/mie/ri_smoke.js +1 -3
  326. package/src/core/math/physics/mie/ri_soot.d.ts.map +1 -1
  327. package/src/core/math/physics/mie/ri_soot.js +1 -3
  328. package/src/core/math/physics/mie/ri_water.d.ts.map +1 -1
  329. package/src/core/math/physics/mie/ri_water.js +1 -3
  330. package/src/core/math/random/randomIntegerBetween.d.ts.map +1 -1
  331. package/src/core/math/random/randomIntegerBetween.js +4 -1
  332. package/src/core/math/random/random_pick_weighted_index.d.ts +10 -0
  333. package/src/core/math/random/random_pick_weighted_index.d.ts.map +1 -0
  334. package/src/core/math/random/random_pick_weighted_index.js +26 -0
  335. package/src/core/math/solveCubic.d.ts.map +1 -1
  336. package/src/core/math/solveCubic.js +95 -82
  337. package/src/core/math/spline/computeCatmullRomSplineUniformDistance.d.ts.map +1 -1
  338. package/src/core/math/spline/computeCatmullRomSplineUniformDistance.js +13 -0
  339. package/src/core/math/statistics/softmax.js +1 -1
  340. package/src/core/model/node-graph/NodeGraph.d.ts +9 -0
  341. package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
  342. package/src/core/model/node-graph/NodeGraph.js +38 -0
  343. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts +24 -0
  344. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
  345. package/src/core/model/node-graph/visual/NodeGraphVisualData.js +56 -1
  346. package/src/core/model/node-graph/visual/NodeVisualData.js +1 -1
  347. package/src/core/model/object/ImmutableObjectPool.d.ts +7 -0
  348. package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
  349. package/src/core/model/object/ImmutableObjectPool.js +20 -10
  350. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.d.ts.map +1 -1
  351. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +39 -2
  352. package/src/core/model/reactive/model/terminal/ReactiveReference.d.ts.map +1 -1
  353. package/src/core/model/reactive/model/terminal/ReactiveReference.js +2 -0
  354. package/src/core/parser/simple/readHexToken.d.ts.map +1 -1
  355. package/src/core/parser/simple/readHexToken.js +6 -0
  356. package/src/core/path/convertPathToURL.d.ts +9 -0
  357. package/src/core/path/convertPathToURL.d.ts.map +1 -0
  358. package/src/core/path/convertPathToURL.js +107 -0
  359. package/src/core/primitives/numbers/number_pretty_print.d.ts.map +1 -1
  360. package/src/core/primitives/numbers/number_pretty_print.js +4 -1
  361. package/src/core/primitives/strings/string_jaro_winkler.js +1 -1
  362. package/src/core/process/CompositeProcess.js +1 -1
  363. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  364. package/src/core/process/executor/ConcurrentExecutor.js +3 -2
  365. package/src/core/process/task/util/randomCountTask.d.ts.map +1 -1
  366. package/src/core/process/task/util/randomCountTask.js +3 -1
  367. package/src/core/process/undo/ActionProcessor.d.ts.map +1 -1
  368. package/src/core/process/undo/ActionProcessor.js +5 -3
  369. package/src/core/process/worker/WorkerBuilder.js +4 -4
  370. package/src/core/process/worker/extractTransferables.js +1 -1
  371. package/src/engine/animation/curve/AnimationCurve.d.ts.map +1 -1
  372. package/src/engine/animation/curve/AnimationCurve.js +4 -2
  373. package/src/engine/animation/curve/draw/build_tangent_editor.d.ts.map +1 -1
  374. package/src/engine/animation/curve/draw/build_tangent_editor.js +8 -1
  375. package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.d.ts.map +1 -1
  376. package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.js +11 -5
  377. package/src/engine/asset/Asset.d.ts.map +1 -1
  378. package/src/engine/asset/Asset.js +16 -6
  379. package/src/engine/asset/AssetManager.d.ts +61 -52
  380. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  381. package/src/engine/asset/AssetManager.js +1411 -1045
  382. package/src/engine/asset/AssetRequest.d.ts +1 -1
  383. package/src/engine/asset/AssetRequest.d.ts.map +1 -1
  384. package/src/engine/asset/AssetRequest.js +1 -1
  385. package/src/engine/asset/AssetRequestScope.d.ts.map +1 -1
  386. package/src/engine/asset/AssetRequestScope.js +7 -0
  387. package/src/engine/asset/PendingAsset.d.ts +32 -1
  388. package/src/engine/asset/PendingAsset.d.ts.map +1 -1
  389. package/src/engine/asset/PendingAsset.js +108 -61
  390. package/src/engine/asset/loaders/ArrayBufferLoader.js +2 -2
  391. package/src/engine/asset/loaders/AssetLoader.d.ts.map +1 -1
  392. package/src/engine/asset/loaders/AssetLoader.js +19 -2
  393. package/src/engine/asset/loaders/GLTFAssetLoader.d.ts.map +1 -1
  394. package/src/engine/asset/loaders/GLTFAssetLoader.js +123 -114
  395. package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts +1 -1
  396. package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts.map +1 -1
  397. package/src/engine/asset/loaders/JavascriptAssetLoader.js +31 -47
  398. package/src/engine/asset/loaders/JsonAssetLoader.js +1 -1
  399. package/src/engine/asset/loaders/SVGAssetLoader.js +2 -2
  400. package/src/engine/asset/loaders/SoundAssetLoader.js +1 -1
  401. package/src/engine/asset/loaders/TextAssetLoader.js +2 -2
  402. package/src/{core → engine/asset/loaders}/font/FontAsset.d.ts +1 -1
  403. package/src/engine/asset/loaders/font/FontAsset.d.ts.map +1 -0
  404. package/src/{core → engine/asset/loaders}/font/FontAsset.js +21 -21
  405. package/src/{core → engine/asset/loaders}/font/FontAssetLoader.d.ts +1 -1
  406. package/src/engine/asset/loaders/font/FontAssetLoader.d.ts.map +1 -0
  407. package/src/{core → engine/asset/loaders}/font/FontAssetLoader.js +20 -20
  408. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
  409. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
  410. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +11 -20
  411. package/src/engine/asset/loaders/texture/TextureAssetLoader.d.ts.map +1 -1
  412. package/src/engine/asset/loaders/texture/TextureAssetLoader.js +8 -2
  413. package/src/engine/asset/preloader/AssetPreloader.js +1 -1
  414. package/src/engine/control/first-person/DESIGN.md +1 -1
  415. package/src/engine/control/first-person/FirstPersonMotionPhase.d.ts +55 -0
  416. package/src/engine/control/first-person/FirstPersonMotionPhase.d.ts.map +1 -0
  417. package/src/engine/control/first-person/FirstPersonMotionPhase.js +134 -0
  418. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +23 -2
  419. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  420. package/src/engine/control/first-person/FirstPersonPlayerController.js +1 -1
  421. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +168 -0
  422. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  423. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +115 -0
  424. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +71 -0
  425. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  426. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +255 -55
  427. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts +82 -43
  428. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -1
  429. package/src/engine/control/first-person/abilities/LedgeGrab.js +405 -213
  430. package/src/engine/control/first-person/abilities/Mantle.d.ts +6 -0
  431. package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -1
  432. package/src/engine/control/first-person/abilities/Mantle.js +104 -45
  433. package/src/engine/control/first-person/abilities/ScrambleUp.d.ts +61 -0
  434. package/src/engine/control/first-person/abilities/ScrambleUp.d.ts.map +1 -0
  435. package/src/engine/control/first-person/abilities/ScrambleUp.js +182 -0
  436. package/src/engine/control/first-person/math/jumpDynamics.d.ts +84 -0
  437. package/src/engine/control/first-person/math/jumpDynamics.d.ts.map +1 -0
  438. package/src/engine/control/first-person/math/jumpDynamics.js +108 -0
  439. package/src/engine/control/first-person/prototype_first_person_controller.js +45 -1
  440. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts +1 -1
  441. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts.map +1 -1
  442. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +19 -22
  443. package/src/engine/graphics/FrameThrottle.d.ts +1 -7
  444. package/src/engine/graphics/FrameThrottle.d.ts.map +1 -1
  445. package/src/engine/graphics/FrameThrottle.js +2 -24
  446. package/src/engine/graphics/camera/testClippingPlaneComputation.js +1 -1
  447. package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.d.ts +1 -1
  448. package/src/engine/graphics/debug/shape_to_visual_entity.d.ts.map +1 -0
  449. package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.js +159 -159
  450. package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.d.ts +1 -1
  451. package/src/engine/graphics/debug/visualize_tetrahedral_mesh.d.ts.map +1 -0
  452. package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.js +46 -46
  453. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts +1 -1
  454. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts.map +1 -1
  455. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +22 -32
  456. package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +1 -1
  457. package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.d.ts.map +1 -1
  458. package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.js +2 -76
  459. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.d.ts.map +1 -1
  460. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -427
  461. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts +1 -4
  462. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts.map +1 -1
  463. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.js +2 -6
  464. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -2
  465. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +1 -1
  466. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +1 -1
  467. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts +1 -8
  468. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts.map +1 -1
  469. package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +2 -14
  470. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +1 -1
  471. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts +1 -11
  472. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts.map +1 -1
  473. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +2 -46
  474. package/src/engine/graphics/sh3/path_tracer/texture/sample_material.js +1 -1
  475. package/src/engine/graphics/sh3/prototypeSH3Probe.js +1 -1
  476. package/src/engine/graphics/shadows/testShadowMapRendering.js +1 -1
  477. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +27 -0
  478. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -0
  479. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +81 -0
  480. package/src/engine/graphics/texture/isImageBitmap.d.ts +1 -6
  481. package/src/engine/graphics/texture/isImageBitmap.d.ts.map +1 -1
  482. package/src/engine/graphics/texture/isImageBitmap.js +2 -12
  483. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.d.ts +2 -2
  484. package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.d.ts.map +1 -0
  485. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.js +55 -52
  486. package/src/engine/network/NetworkSession.d.ts +12 -1
  487. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  488. package/src/engine/network/NetworkSession.js +52 -1
  489. package/src/engine/network/README.md +45 -0
  490. package/src/engine/network/convertPathToURL.d.ts +1 -8
  491. package/src/engine/network/convertPathToURL.d.ts.map +1 -1
  492. package/src/engine/network/convertPathToURL.js +2 -107
  493. package/src/engine/network/core/quantize/quantize_float.d.ts.map +1 -1
  494. package/src/engine/network/core/quantize/quantize_float.js +7 -0
  495. package/src/engine/network/core/quantize/quantize_position.d.ts.map +1 -1
  496. package/src/engine/network/core/quantize/quantize_position.js +12 -1
  497. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  498. package/src/engine/network/orchestrator/NetworkPeer.js +15 -1
  499. package/src/engine/network/replication/Replicator.d.ts +8 -0
  500. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  501. package/src/engine/network/replication/Replicator.js +48 -0
  502. package/src/engine/network/transport/Channel.d.ts.map +1 -1
  503. package/src/engine/network/transport/Channel.js +46 -12
  504. package/src/engine/network/transport/ReliableCommandPipeline.d.ts +16 -0
  505. package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
  506. package/src/engine/network/transport/ReliableCommandPipeline.js +29 -0
  507. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  508. package/src/engine/network/transport/adapters/NodeUDPTransport.js +7 -1
  509. package/src/engine/network/transport/fragments/packet_size.d.ts +5 -5
  510. package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
  511. package/src/engine/network/transport/fragments/packet_size.js +5 -5
  512. package/src/engine/physics/BULLET_REVIEW.md +1 -1
  513. package/src/engine/physics/CONSTRAINT_SOLVER_BENCH_LOG.md +208 -0
  514. package/src/engine/physics/CONSTRAINT_SOLVER_IMPROVEMENTS_PLAN.md +364 -0
  515. package/src/engine/physics/JOLT_REVIEW.md +2 -2
  516. package/src/engine/physics/PLAN.md +1094 -944
  517. package/src/engine/physics/RAPIER_REVIEW.md +2 -2
  518. package/src/engine/physics/body/BodyStorage.d.ts +2 -12
  519. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -1
  520. package/src/engine/physics/body/BodyStorage.js +406 -452
  521. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  522. package/src/engine/physics/body/SolverBodyState.js +12 -3
  523. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +28 -3
  524. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
  525. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +60 -24
  526. package/src/engine/physics/broadphase/generate_pairs.d.ts +9 -5
  527. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  528. package/src/engine/physics/broadphase/generate_pairs.js +52 -37
  529. package/src/engine/physics/ccd/linear_sweep.d.ts +15 -5
  530. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  531. package/src/engine/physics/ccd/linear_sweep.js +122 -40
  532. package/src/engine/physics/constraint/solve_constraints.d.ts +4 -1
  533. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  534. package/src/engine/physics/constraint/solve_constraints.js +830 -691
  535. package/src/engine/physics/contact/ManifoldStore.d.ts +91 -16
  536. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  537. package/src/engine/physics/contact/ManifoldStore.js +204 -60
  538. package/src/engine/physics/ecs/BodyKind.d.ts +7 -3
  539. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -1
  540. package/src/engine/physics/ecs/BodyKind.js +29 -25
  541. package/src/engine/physics/ecs/Collider.d.ts +7 -0
  542. package/src/engine/physics/ecs/Collider.d.ts.map +1 -1
  543. package/src/engine/physics/ecs/Collider.js +7 -0
  544. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +1 -1
  545. package/src/engine/physics/ecs/PhysicsSystem.d.ts +110 -6
  546. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  547. package/src/engine/physics/ecs/PhysicsSystem.js +2172 -1747
  548. package/src/engine/physics/ecs/RigidBody.d.ts +20 -5
  549. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -1
  550. package/src/engine/physics/ecs/RigidBody.js +307 -286
  551. package/src/engine/physics/ecs/RigidBodyFlags.d.ts +6 -3
  552. package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -1
  553. package/src/engine/physics/ecs/RigidBodyFlags.js +31 -28
  554. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +12 -4
  555. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -1
  556. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +19 -5
  557. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts +10 -0
  558. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts.map +1 -0
  559. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -0
  560. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts +28 -0
  561. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts.map +1 -0
  562. package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -0
  563. package/src/engine/physics/events/ContactEventBuffer.d.ts +11 -0
  564. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -1
  565. package/src/engine/physics/events/ContactEventBuffer.js +40 -0
  566. package/src/engine/physics/events/diff_manifolds.d.ts +30 -13
  567. package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -1
  568. package/src/engine/physics/events/diff_manifolds.js +87 -50
  569. package/src/engine/physics/fluid/FluidField.d.ts +45 -17
  570. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  571. package/src/engine/physics/fluid/FluidField.js +53 -23
  572. package/src/engine/physics/fluid/FluidSimulator.d.ts +141 -5
  573. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  574. package/src/engine/physics/fluid/FluidSimulator.js +336 -43
  575. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +114 -0
  576. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +4 -3
  577. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  578. package/src/engine/physics/fluid/ecs/FluidComponent.js +4 -3
  579. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
  580. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts +41 -0
  581. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts.map +1 -0
  582. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.js +124 -0
  583. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +27 -8
  584. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  585. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +67 -18
  586. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts +42 -0
  587. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts.map +1 -0
  588. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +136 -0
  589. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts +37 -0
  590. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -0
  591. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +169 -0
  592. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts +36 -0
  593. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -0
  594. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +100 -0
  595. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +6 -0
  596. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
  597. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +6 -0
  598. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +7 -2
  599. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
  600. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +17 -12
  601. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts +42 -0
  602. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -0
  603. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -0
  604. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +32 -22
  605. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
  606. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +43 -26
  607. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts +31 -0
  608. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts.map +1 -0
  609. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -0
  610. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +26 -19
  611. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
  612. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +46 -42
  613. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +38 -10
  614. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
  615. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +158 -75
  616. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +22 -17
  617. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  618. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -96
  619. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +30 -1
  620. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  621. package/src/engine/physics/inertia/world_inverse_inertia.js +160 -116
  622. package/src/engine/physics/integration/integrate_position.js +97 -97
  623. package/src/engine/physics/island/IslandBuilder.d.ts +49 -8
  624. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  625. package/src/engine/physics/island/IslandBuilder.js +93 -14
  626. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  627. package/src/engine/physics/narrowphase/box_box_manifold.js +683 -673
  628. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
  629. package/src/engine/physics/narrowphase/box_triangle_contact.js +899 -749
  630. package/src/engine/physics/narrowphase/capsule_contacts.d.ts +27 -0
  631. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  632. package/src/engine/physics/narrowphase/capsule_contacts.js +624 -459
  633. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -1
  634. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +58 -38
  635. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
  636. package/src/engine/physics/narrowphase/compute_penetration.js +369 -325
  637. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +3 -1
  638. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
  639. package/src/engine/physics/narrowphase/convex_convex_manifold.js +568 -425
  640. package/src/engine/physics/narrowphase/convex_decomposition.d.ts +32 -13
  641. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  642. package/src/engine/physics/narrowphase/convex_decomposition.js +61 -65
  643. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +6 -3
  644. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -1
  645. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +66 -10
  646. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +4 -1
  647. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
  648. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +97 -94
  649. package/src/engine/physics/narrowphase/mesh_convex_hull.d.ts.map +1 -1
  650. package/src/engine/physics/narrowphase/mesh_convex_hull.js +13 -8
  651. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
  652. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  653. package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1739
  654. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts +14 -7
  655. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts.map +1 -1
  656. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -69
  657. package/src/engine/physics/narrowphase/refine_ray_concave.d.ts.map +1 -1
  658. package/src/engine/physics/narrowphase/refine_ray_concave.js +5 -3
  659. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -1
  660. package/src/engine/physics/narrowphase/refine_ray_hit.js +81 -78
  661. package/src/engine/physics/persistence/solver_caches.d.ts +20 -0
  662. package/src/engine/physics/persistence/solver_caches.d.ts.map +1 -0
  663. package/src/engine/physics/persistence/solver_caches.js +309 -0
  664. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  665. package/src/engine/physics/queries/overlap_shape.js +187 -184
  666. package/src/engine/physics/queries/raycast.d.ts +3 -2
  667. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  668. package/src/engine/physics/queries/raycast.js +37 -11
  669. package/src/engine/physics/queries/shape_cast.d.ts +18 -5
  670. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  671. package/src/engine/physics/queries/shape_cast.js +417 -393
  672. package/src/engine/physics/solver/solve_contacts.d.ts +22 -6
  673. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  674. package/src/engine/physics/solver/solve_contacts.js +1482 -1338
  675. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  676. package/src/engine/physics/vehicle/RaycastVehicle.js +344 -339
  677. package/src/engine/sound/SoundEngine.d.ts.map +1 -1
  678. package/src/engine/sound/SoundEngine.js +28 -0
  679. package/src/engine/sound/dB2Volume.d.ts +1 -1
  680. package/src/engine/sound/dB2Volume.d.ts.map +1 -1
  681. package/src/engine/sound/dB2Volume.js +1 -1
  682. package/src/engine/sound/ecs/SoundController.d.ts +4 -0
  683. package/src/engine/sound/ecs/SoundController.d.ts.map +1 -1
  684. package/src/engine/sound/ecs/SoundController.js +4 -0
  685. package/src/engine/sound/ecs/SoundControllerSystem.d.ts +5 -0
  686. package/src/engine/sound/ecs/SoundControllerSystem.d.ts.map +1 -1
  687. package/src/engine/sound/ecs/SoundControllerSystem.js +5 -0
  688. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts +69 -0
  689. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -0
  690. package/src/engine/sound/ecs/audio/AudioEmitter.js +83 -0
  691. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +97 -0
  692. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -0
  693. package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +238 -0
  694. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts +90 -0
  695. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -0
  696. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +324 -0
  697. package/src/engine/sound/ecs/audio/SpatialAudioIndex.d.ts +59 -0
  698. package/src/engine/sound/ecs/audio/SpatialAudioIndex.d.ts.map +1 -0
  699. package/src/engine/sound/ecs/audio/SpatialAudioIndex.js +140 -0
  700. package/src/engine/sound/ecs/emitter/SoundEmitter.d.ts +16 -65
  701. package/src/engine/sound/ecs/emitter/SoundEmitter.d.ts.map +1 -1
  702. package/src/engine/sound/ecs/emitter/SoundEmitter.js +19 -224
  703. package/src/engine/sound/ecs/emitter/SoundEmitterComponentContext.d.ts +26 -29
  704. package/src/engine/sound/ecs/emitter/SoundEmitterComponentContext.d.ts.map +1 -1
  705. package/src/engine/sound/ecs/emitter/SoundEmitterComponentContext.js +168 -135
  706. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.d.ts +36 -59
  707. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.d.ts.map +1 -1
  708. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.js +154 -390
  709. package/src/engine/sound/ecs/emitter/SoundTrack.d.ts +20 -23
  710. package/src/engine/sound/ecs/emitter/SoundTrack.d.ts.map +1 -1
  711. package/src/engine/sound/ecs/emitter/SoundTrack.js +34 -152
  712. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +993 -0
  713. package/src/engine/sound/sopra/README.md +643 -7
  714. package/src/engine/sound/sopra/SopraEngine.d.ts +229 -0
  715. package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -0
  716. package/src/engine/sound/sopra/SopraEngine.js +423 -0
  717. package/src/engine/sound/sopra/asset/AssetManagerBufferProvider.d.ts +26 -0
  718. package/src/engine/sound/sopra/asset/AssetManagerBufferProvider.d.ts.map +1 -0
  719. package/src/engine/sound/sopra/asset/AssetManagerBufferProvider.js +71 -0
  720. package/src/engine/sound/sopra/asset/BufferProvider.d.ts +24 -0
  721. package/src/engine/sound/sopra/asset/BufferProvider.d.ts.map +1 -0
  722. package/src/engine/sound/sopra/asset/BufferProvider.js +29 -0
  723. package/src/engine/sound/sopra/asset/StubBufferProvider.d.ts +31 -0
  724. package/src/engine/sound/sopra/asset/StubBufferProvider.d.ts.map +1 -0
  725. package/src/engine/sound/sopra/asset/StubBufferProvider.js +58 -0
  726. package/src/engine/sound/sopra/definition/BusDefinition.d.ts +83 -0
  727. package/src/engine/sound/sopra/definition/BusDefinition.d.ts.map +1 -0
  728. package/src/engine/sound/sopra/definition/BusDefinition.js +142 -0
  729. package/src/engine/sound/sopra/definition/BusDefinitionSerializationAdapter.d.ts +17 -0
  730. package/src/engine/sound/sopra/definition/BusDefinitionSerializationAdapter.d.ts.map +1 -0
  731. package/src/engine/sound/sopra/definition/BusDefinitionSerializationAdapter.js +54 -0
  732. package/src/engine/sound/sopra/definition/DuckingRule.d.ts +71 -0
  733. package/src/engine/sound/sopra/definition/DuckingRule.d.ts.map +1 -0
  734. package/src/engine/sound/sopra/definition/DuckingRule.js +106 -0
  735. package/src/engine/sound/sopra/definition/DuckingRuleSerializationAdapter.d.ts +18 -0
  736. package/src/engine/sound/sopra/definition/DuckingRuleSerializationAdapter.d.ts.map +1 -0
  737. package/src/engine/sound/sopra/definition/DuckingRuleSerializationAdapter.js +31 -0
  738. package/src/engine/sound/sopra/definition/EventDescription.d.ts +132 -0
  739. package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -0
  740. package/src/engine/sound/sopra/definition/EventDescription.js +259 -0
  741. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts +17 -0
  742. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts.map +1 -0
  743. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +71 -0
  744. package/src/engine/sound/sopra/definition/MixerSnapshot.d.ts +51 -0
  745. package/src/engine/sound/sopra/definition/MixerSnapshot.d.ts.map +1 -0
  746. package/src/engine/sound/sopra/definition/MixerSnapshot.js +83 -0
  747. package/src/engine/sound/sopra/definition/MixerSnapshotSerializationAdapter.d.ts +18 -0
  748. package/src/engine/sound/sopra/definition/MixerSnapshotSerializationAdapter.d.ts.map +1 -0
  749. package/src/engine/sound/sopra/definition/MixerSnapshotSerializationAdapter.js +39 -0
  750. package/src/engine/sound/sopra/definition/ParameterDefinition.d.ts +72 -0
  751. package/src/engine/sound/sopra/definition/ParameterDefinition.d.ts.map +1 -0
  752. package/src/engine/sound/sopra/definition/ParameterDefinition.js +117 -0
  753. package/src/engine/sound/sopra/definition/ParameterDefinitionSerializationAdapter.d.ts +18 -0
  754. package/src/engine/sound/sopra/definition/ParameterDefinitionSerializationAdapter.d.ts.map +1 -0
  755. package/src/engine/sound/sopra/definition/ParameterDefinitionSerializationAdapter.js +31 -0
  756. package/src/engine/sound/sopra/definition/SopraPanningModel.d.ts +14 -0
  757. package/src/engine/sound/sopra/definition/SopraPanningModel.d.ts.map +1 -0
  758. package/src/engine/sound/sopra/definition/SopraPanningModel.js +20 -0
  759. package/src/engine/sound/sopra/definition/VoiceStealMode.d.ts +10 -0
  760. package/src/engine/sound/sopra/definition/VoiceStealMode.d.ts.map +1 -0
  761. package/src/engine/sound/sopra/definition/VoiceStealMode.js +18 -0
  762. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +93 -0
  763. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -0
  764. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +109 -0
  765. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +80 -0
  766. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -0
  767. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +181 -0
  768. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClipSerializationAdapter.d.ts +17 -0
  769. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClipSerializationAdapter.d.ts.map +1 -0
  770. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClipSerializationAdapter.js +74 -0
  771. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.d.ts +34 -0
  772. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.d.ts.map +1 -0
  773. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +100 -0
  774. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +101 -0
  775. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -0
  776. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +230 -0
  777. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClipSerializationAdapter.d.ts +17 -0
  778. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClipSerializationAdapter.d.ts.map +1 -0
  779. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClipSerializationAdapter.js +54 -0
  780. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +103 -0
  781. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -0
  782. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +191 -0
  783. package/src/engine/sound/sopra/definition/clip/SampleAudioClipSerializationAdapter.d.ts +18 -0
  784. package/src/engine/sound/sopra/definition/clip/SampleAudioClipSerializationAdapter.d.ts.map +1 -0
  785. package/src/engine/sound/sopra/definition/clip/SampleAudioClipSerializationAdapter.js +39 -0
  786. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +40 -0
  787. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -0
  788. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.js +91 -0
  789. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClipSerializationAdapter.d.ts +17 -0
  790. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClipSerializationAdapter.d.ts.map +1 -0
  791. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClipSerializationAdapter.js +42 -0
  792. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.d.ts +44 -0
  793. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.d.ts.map +1 -0
  794. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +77 -0
  795. package/src/engine/sound/sopra/definition/clip/SilenceAudioClipSerializationAdapter.d.ts +18 -0
  796. package/src/engine/sound/sopra/definition/clip/SilenceAudioClipSerializationAdapter.d.ts.map +1 -0
  797. package/src/engine/sound/sopra/definition/clip/SilenceAudioClipSerializationAdapter.js +27 -0
  798. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +65 -0
  799. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -0
  800. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +131 -0
  801. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClipSerializationAdapter.d.ts +17 -0
  802. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClipSerializationAdapter.d.ts.map +1 -0
  803. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClipSerializationAdapter.js +41 -0
  804. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts +24 -0
  805. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts.map +1 -0
  806. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +24 -0
  807. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts +70 -0
  808. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -0
  809. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +120 -0
  810. package/src/engine/sound/sopra/definition/effect/CompressorEffectSerializationAdapter.d.ts +18 -0
  811. package/src/engine/sound/sopra/definition/effect/CompressorEffectSerializationAdapter.d.ts.map +1 -0
  812. package/src/engine/sound/sopra/definition/effect/CompressorEffectSerializationAdapter.js +31 -0
  813. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts +74 -0
  814. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -0
  815. package/src/engine/sound/sopra/definition/effect/EqEffect.js +128 -0
  816. package/src/engine/sound/sopra/definition/effect/EqEffectSerializationAdapter.d.ts +18 -0
  817. package/src/engine/sound/sopra/definition/effect/EqEffectSerializationAdapter.d.ts.map +1 -0
  818. package/src/engine/sound/sopra/definition/effect/EqEffectSerializationAdapter.js +29 -0
  819. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts +49 -0
  820. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts.map +1 -0
  821. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +101 -0
  822. package/src/engine/sound/sopra/definition/effect/ReverbEffectSerializationAdapter.d.ts +18 -0
  823. package/src/engine/sound/sopra/definition/effect/ReverbEffectSerializationAdapter.d.ts.map +1 -0
  824. package/src/engine/sound/sopra/definition/effect/ReverbEffectSerializationAdapter.js +25 -0
  825. package/src/engine/sound/sopra/legacy/soundEmitterToEventDescription.d.ts +31 -0
  826. package/src/engine/sound/sopra/legacy/soundEmitterToEventDescription.d.ts.map +1 -0
  827. package/src/engine/sound/sopra/legacy/soundEmitterToEventDescription.js +106 -0
  828. package/src/engine/sound/sopra/runtime/BusGraph.d.ts +79 -0
  829. package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -0
  830. package/src/engine/sound/sopra/runtime/BusGraph.js +227 -0
  831. package/src/engine/sound/sopra/runtime/EventInstance.d.ts +144 -0
  832. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -0
  833. package/src/engine/sound/sopra/runtime/EventInstance.js +579 -0
  834. package/src/engine/sound/sopra/runtime/ParameterStore.d.ts +42 -0
  835. package/src/engine/sound/sopra/runtime/ParameterStore.d.ts.map +1 -0
  836. package/src/engine/sound/sopra/runtime/ParameterStore.js +98 -0
  837. package/src/engine/sound/sopra/runtime/SopraPlaybackContext.d.ts +42 -0
  838. package/src/engine/sound/sopra/runtime/SopraPlaybackContext.d.ts.map +1 -0
  839. package/src/engine/sound/sopra/runtime/SopraPlaybackContext.js +68 -0
  840. package/src/engine/sound/sopra/runtime/Voice.d.ts +67 -0
  841. package/src/engine/sound/sopra/runtime/Voice.d.ts.map +1 -0
  842. package/src/engine/sound/sopra/runtime/Voice.js +145 -0
  843. package/src/engine/sound/sopra/runtime/VoiceManager.d.ts +38 -0
  844. package/src/engine/sound/sopra/runtime/VoiceManager.d.ts.map +1 -0
  845. package/src/engine/sound/sopra/runtime/VoiceManager.js +136 -0
  846. package/src/engine/sound/sopra/runtime/VoicePool.d.ts +12 -0
  847. package/src/engine/sound/sopra/runtime/VoicePool.d.ts.map +1 -0
  848. package/src/engine/sound/sopra/runtime/VoicePool.js +17 -0
  849. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts +11 -0
  850. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts.map +1 -0
  851. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +42 -0
  852. package/src/engine/sound/sopra/serialization/sopraJSON.d.ts +33 -0
  853. package/src/engine/sound/sopra/serialization/sopraJSON.d.ts.map +1 -0
  854. package/src/engine/sound/sopra/serialization/sopraJSON.js +99 -0
  855. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts +27 -0
  856. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts.map +1 -0
  857. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +49 -0
  858. package/src/engine/sound/sopra/util/MockAudioContext.d.ts +74 -0
  859. package/src/engine/sound/sopra/util/MockAudioContext.d.ts.map +1 -0
  860. package/src/engine/sound/sopra/util/MockAudioContext.js +215 -0
  861. package/src/engine/sound/sopra/util/buildAttenuationCurve.d.ts +15 -0
  862. package/src/engine/sound/sopra/util/buildAttenuationCurve.d.ts.map +1 -0
  863. package/src/engine/sound/sopra/util/buildAttenuationCurve.js +40 -0
  864. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts +34 -0
  865. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts.map +1 -0
  866. package/src/engine/sound/sopra/util/fadeOutAndStop.js +60 -0
  867. package/src/engine/sound/volume2dB.d.ts +1 -1
  868. package/src/engine/sound/volume2dB.d.ts.map +1 -1
  869. package/src/engine/sound/volume2dB.js +1 -1
  870. package/src/engine/ui/DraggableAspect.d.ts +12 -3
  871. package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
  872. package/src/engine/ui/DraggableAspect.js +115 -83
  873. package/src/generation/COORDINATES.md +54 -0
  874. package/src/generation/GridTaskGroup.js +2 -2
  875. package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -0
  876. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts +9 -1
  877. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts.map +1 -1
  878. package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -59
  879. package/src/generation/automata/CellularAutomata.d.ts +6 -3
  880. package/src/generation/automata/CellularAutomata.d.ts.map +1 -1
  881. package/src/generation/automata/CellularAutomata.js +22 -19
  882. package/src/generation/filtering/CellFilter.d.ts +17 -0
  883. package/src/generation/filtering/CellFilter.d.ts.map +1 -1
  884. package/src/generation/filtering/CellFilter.js +117 -77
  885. package/src/generation/filtering/CellFilterCellMatcher.d.ts.map +1 -1
  886. package/src/generation/filtering/CellFilterCellMatcher.js +2 -0
  887. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts +5 -0
  888. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts.map +1 -1
  889. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.js +15 -0
  890. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts +0 -1
  891. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts.map +1 -1
  892. package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -50
  893. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts +0 -1
  894. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts.map +1 -1
  895. package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -59
  896. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts +0 -1
  897. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts.map +1 -1
  898. package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -33
  899. package/src/generation/filtering/numeric/CellFilterCache.d.ts +1 -0
  900. package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
  901. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts +3 -2
  902. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts.map +1 -1
  903. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +9 -35
  904. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts +0 -1
  905. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts.map +1 -1
  906. package/src/generation/filtering/numeric/complex/CellFilterCurvature.js +19 -43
  907. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts +0 -1
  908. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts.map +1 -1
  909. package/src/generation/filtering/numeric/complex/CellFilterFXAA.js +2 -6
  910. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.d.ts.map +1 -1
  911. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +9 -12
  912. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.d.ts.map +1 -1
  913. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -1
  914. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts +0 -1
  915. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts.map +1 -1
  916. package/src/generation/filtering/numeric/complex/CellFilterSobel.js +2 -6
  917. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts +5 -4
  918. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts.map +1 -1
  919. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.js +5 -4
  920. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts +17 -0
  921. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts.map +1 -0
  922. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -0
  923. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.d.ts.map +1 -1
  924. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.js +7 -1
  925. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.d.ts.map +1 -1
  926. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +7 -10
  927. package/src/generation/filtering/numeric/util/sampler_from_filter.d.ts.map +1 -1
  928. package/src/generation/filtering/numeric/util/sampler_from_filter.js +2 -1
  929. package/src/generation/grid/GridData.d.ts.map +1 -1
  930. package/src/generation/grid/GridData.js +14 -1
  931. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts +10 -3
  932. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts.map +1 -1
  933. package/src/generation/grid/actions/ContinuousGridCellAction.js +18 -3
  934. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts +11 -1
  935. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts.map +1 -1
  936. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.js +13 -3
  937. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +1 -1
  938. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +2 -2
  939. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts +1 -1
  940. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
  941. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +4 -6
  942. package/src/generation/grid/coords/grid_to_texel.d.ts +9 -0
  943. package/src/generation/grid/coords/grid_to_texel.d.ts.map +1 -0
  944. package/src/generation/grid/coords/grid_to_texel.js +10 -0
  945. package/src/generation/grid/coords/texel_to_grid.d.ts +9 -0
  946. package/src/generation/grid/coords/texel_to_grid.d.ts.map +1 -0
  947. package/src/generation/grid/coords/texel_to_grid.js +10 -0
  948. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts +2 -2
  949. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts.map +1 -1
  950. package/src/generation/grid/generation/GridTaskApplyActionToCells.js +10 -6
  951. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
  952. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +20 -21
  953. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts +7 -0
  954. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts.map +1 -1
  955. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +18 -10
  956. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.d.ts.map +1 -1
  957. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +16 -7
  958. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts +5 -3
  959. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts.map +1 -1
  960. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +26 -23
  961. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.d.ts.map +1 -1
  962. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +10 -1
  963. package/src/generation/grid/generation/grid/select/CellSupplierBestN.d.ts.map +1 -1
  964. package/src/generation/grid/generation/grid/select/CellSupplierBestN.js +4 -0
  965. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts +15 -8
  966. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  967. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +89 -92
  968. package/src/generation/markers/GridActionRuleSet.d.ts.map +1 -1
  969. package/src/generation/markers/GridActionRuleSet.js +10 -2
  970. package/src/generation/markers/GridCellActionPlaceMarker.d.ts +11 -0
  971. package/src/generation/markers/GridCellActionPlaceMarker.d.ts.map +1 -1
  972. package/src/generation/markers/GridCellActionPlaceMarker.js +20 -3
  973. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +3 -1
  974. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  975. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +9 -2
  976. package/src/generation/markers/MarkerNode.d.ts +8 -3
  977. package/src/generation/markers/MarkerNode.d.ts.map +1 -1
  978. package/src/generation/markers/MarkerNode.js +12 -5
  979. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +1 -1
  980. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts +1 -1
  981. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts.map +1 -1
  982. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.js +1 -1
  983. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts +1 -1
  984. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts.map +1 -1
  985. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.js +1 -1
  986. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts +1 -1
  987. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts.map +1 -1
  988. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.js +2 -2
  989. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts +1 -1
  990. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts.map +1 -1
  991. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.js +2 -2
  992. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.d.ts.map +1 -1
  993. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.js +6 -4
  994. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.d.ts.map +1 -1
  995. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.js +1 -3
  996. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.d.ts.map +1 -1
  997. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +12 -11
  998. package/src/generation/markers/matcher/MarkerNodeMatcherAnd.js +2 -2
  999. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts +4 -1
  1000. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts.map +1 -1
  1001. package/src/generation/markers/transform/MarkerNodeTransformer.js +4 -1
  1002. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.d.ts.map +1 -1
  1003. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.js +1 -3
  1004. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts +5 -0
  1005. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts.map +1 -1
  1006. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +15 -0
  1007. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.d.ts.map +1 -1
  1008. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.js +1 -3
  1009. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.d.ts.map +1 -1
  1010. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.js +2 -4
  1011. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.d.ts.map +1 -1
  1012. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.js +1 -3
  1013. package/src/generation/placement/GridCellPlacementRule.d.ts.map +1 -1
  1014. package/src/generation/placement/GridCellPlacementRule.js +1 -3
  1015. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
  1016. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -10
  1017. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.d.ts.map +1 -1
  1018. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +6 -4
  1019. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.d.ts.map +1 -1
  1020. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.js +1 -3
  1021. package/src/generation/rules/CellMatcher.d.ts +3 -1
  1022. package/src/generation/rules/CellMatcher.d.ts.map +1 -1
  1023. package/src/generation/rules/CellMatcher.js +3 -1
  1024. package/src/generation/rules/CellMatcherFromFilter.d.ts.map +1 -1
  1025. package/src/generation/rules/CellMatcherFromFilter.js +1 -3
  1026. package/src/generation/rules/CellMatcherLayerBitMaskTest.d.ts.map +1 -1
  1027. package/src/generation/rules/CellMatcherLayerBitMaskTest.js +6 -20
  1028. package/src/generation/test_support/executeTaskTreeSync.d.ts +9 -0
  1029. package/src/generation/test_support/executeTaskTreeSync.d.ts.map +1 -0
  1030. package/src/generation/test_support/executeTaskTreeSync.js +78 -0
  1031. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts +2 -1
  1032. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts.map +1 -1
  1033. package/src/generation/theme/TerrainLayerRuleAggregator.js +9 -6
  1034. package/src/generation/theme/Theme.d.ts +1 -1
  1035. package/src/generation/theme/Theme.d.ts.map +1 -1
  1036. package/src/generation/theme/Theme.js +2 -2
  1037. package/src/generation/theme/ThemeEngine.d.ts +3 -3
  1038. package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
  1039. package/src/generation/theme/ThemeEngine.js +26 -16
  1040. package/src/generation/theme/cell/CellProcessingRule.d.ts +3 -3
  1041. package/src/generation/theme/cell/CellProcessingRule.d.ts.map +1 -1
  1042. package/src/generation/theme/cell/CellProcessingRule.js +6 -10
  1043. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts +1 -1
  1044. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts.map +1 -1
  1045. package/src/generation/theme/cell/CellProcessingRuleSet.js +2 -2
  1046. package/src/view/common/ListView.js +1 -1
  1047. package/src/view/elements/BottomLeftResizeHandleView.d.ts.map +1 -1
  1048. package/src/view/elements/BottomLeftResizeHandleView.js +13 -5
  1049. package/src/core/font/FontAsset.d.ts.map +0 -1
  1050. package/src/core/font/FontAssetLoader.d.ts.map +0 -1
  1051. package/src/core/geom/3d/shape/util/shape_to_visual_entity.d.ts.map +0 -1
  1052. package/src/core/geom/3d/tetrahedra/visualize_tetrahedral_mesh.d.ts.map +0 -1
  1053. package/src/core/process/action/AsynchronousDelayAction.d.ts.map +0 -1
  1054. package/src/engine/graphics/sh3/path_tracer/sampling/v3_orthonormal_matrix_from_normal.d.ts.map +0 -1
  1055. package/src/engine/physics/computeInterceptPoint.d.ts.map +0 -1
  1056. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +0 -1
  1057. package/src/engine/physics/gjk/gjk.d.ts.map +0 -1
  1058. package/src/engine/physics/gjk/gjk_epa_penetration.d.ts.map +0 -1
  1059. package/src/engine/physics/gjk/minkowski_support.d.ts.map +0 -1
  1060. package/src/engine/physics/gjk/mpr.d.ts.map +0 -1
  1061. package/src/engine/physics/integration/quat_integrate.d.ts.map +0 -1
  1062. package/src/engine/physics/island/union_find.d.ts.map +0 -1
  1063. package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +0 -1
  1064. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +0 -1
  1065. package/src/engine/physics/narrowphase/ray_shapes.d.ts +0 -66
  1066. package/src/engine/physics/narrowphase/ray_shapes.d.ts.map +0 -1
  1067. package/src/engine/physics/narrowphase/ray_shapes.js +0 -187
  1068. package/src/engine/sound/ecs/emitter/SoundEmitterChannel.d.ts +0 -23
  1069. package/src/engine/sound/ecs/emitter/SoundEmitterChannel.d.ts.map +0 -1
  1070. package/src/engine/sound/ecs/emitter/SoundEmitterChannel.js +0 -32
  1071. package/src/engine/sound/ecs/emitter/SoundTrackNodes.d.ts +0 -18
  1072. package/src/engine/sound/ecs/emitter/SoundTrackNodes.d.ts.map +0 -1
  1073. package/src/engine/sound/ecs/emitter/SoundTrackNodes.js +0 -18
  1074. package/src/engine/sound/sopra/AbstractAudioClip.d.ts +0 -26
  1075. package/src/engine/sound/sopra/AbstractAudioClip.d.ts.map +0 -1
  1076. package/src/engine/sound/sopra/AbstractAudioClip.js +0 -29
  1077. package/src/engine/sound/sopra/ContainerAudioClip.d.ts +0 -12
  1078. package/src/engine/sound/sopra/ContainerAudioClip.d.ts.map +0 -1
  1079. package/src/engine/sound/sopra/ContainerAudioClip.js +0 -13
  1080. package/src/engine/sound/sopra/RandomContainerAudioClip.d.ts +0 -12
  1081. package/src/engine/sound/sopra/RandomContainerAudioClip.d.ts.map +0 -1
  1082. package/src/engine/sound/sopra/RandomContainerAudioClip.js +0 -15
  1083. package/src/engine/sound/sopra/SequenceContainerAudioClip.d.ts +0 -7
  1084. package/src/engine/sound/sopra/SequenceContainerAudioClip.d.ts.map +0 -1
  1085. package/src/engine/sound/sopra/SequenceContainerAudioClip.js +0 -8
  1086. package/src/engine/sound/sopra/SilenceAudioClip.d.ts +0 -13
  1087. package/src/engine/sound/sopra/SilenceAudioClip.d.ts.map +0 -1
  1088. package/src/engine/sound/sopra/SilenceAudioClip.js +0 -15
  1089. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts +0 -21
  1090. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts.map +0 -1
  1091. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +0 -68
  1092. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts +0 -10
  1093. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts.map +0 -1
  1094. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.js +0 -17
  1095. /package/src/{engine/physics → core/geom/3d}/gjk/NOTES.md +0 -0
  1096. /package/src/{engine/physics → core/geom/3d}/gjk/gjk.d.ts +0 -0
  1097. /package/src/{engine/graphics/sh3/path_tracer/sampling → core/geom/vec3}/v3_orthonormal_matrix_from_normal.d.ts +0 -0
  1098. /package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.d.ts +0 -0
@@ -0,0 +1,993 @@
1
+ # Sopra — Implementation Plan
2
+
3
+ > Object-oriented, FMOD/Wwise-style sound engine for **meep**, built on the WebAudio API.
4
+ > Status: implemented through **P5** (P0–P4 build-out + P5 spatial scaling to 100k emitters). Not yet
5
+ > wired into the production engine config — the legacy `SoundEmitter` path still ships; the native
6
+ > `AudioEmitter`/`AudioEmitterSystem` is fully built and tested but registered only in tests, awaiting
7
+ > the cut-over (register in `makeMirEngineConfig` + `AudioEventTrigger` + serialization wiring; see §9).
8
+
9
+ This plan was produced from a full read of the current sound engine + a deep survey of the
10
+ surrounding meep architecture (ECS core, asset system, serialization, precedents, game-side
11
+ coupling) and an FMOD/Wwise ⇄ WebAudio feasibility study. Every "verified" claim below was
12
+ checked against source.
13
+
14
+ **Source layout** (`engine/sound/sopra/`): `SopraEngine.js` (orchestrator) at the root;
15
+ `definition/` = authored, immutable data (`EventDescription`, `BusDefinition`, `ParameterDefinition`,
16
+ `SopraPanningModel`, `VoiceStealMode`, plus `clip/` and `effect/` families); `runtime/` = transient
17
+ runtime + services (`EventInstance`, `Voice`, `VoicePool`, `BusGraph`, `VoiceManager`,
18
+ `ParameterStore`, `SopraPlaybackContext`); `asset/` = buffer providers; `serialization/` = `sopraJSON`
19
+ + registry (binary adapters stay co-located with their classes); `util/` = `buildAttenuationCurve`,
20
+ `fadeOutAndStop`, `MockAudioContext`; `legacy/` = the SoundEmitter→sopra translator. Specs sit next to
21
+ the code they cover.
22
+
23
+ ---
24
+
25
+ ## 0. Status
26
+
27
+ - **P0 — Core skeleton + ser/de + bus inserts (no ECS): ✅ DONE** (26 tests green via
28
+ `npx jest --config jest.conf.json engine/sound/sopra`).
29
+ Delivered under `sopra/`: the finished clip hierarchy (`AbstractAudioClip`, `ContainerAudioClip`,
30
+ `SampleAudioClip`, `SilenceAudioClip`, `SequenceContainerAudioClip`, `RandomContainerAudioClip`),
31
+ `EventDescription`, `BusDefinition`, `ParameterDefinition` (3D attenuation reuses the existing
32
+ `AnimationCurve`), the effect hierarchy
33
+ (`AbstractAudioEffect`, `EqEffect`, `CompressorEffect`), runtime (`SopraEngine`, `BusGraph`,
34
+ `Voice`, `VoicePool`, `EventInstance`, `ParameterStore`), `BufferProvider` +
35
+ `AssetManagerBufferProvider`/`StubBufferProvider`, the click-safe `fadeOutAndStop` (with the
36
+ Firefox fallback, D1), polymorphic binary adapters (co-located) + JSON dispatchers (`sopraJSON`) +
37
+ `populateSopraSerializationRegistry`, and a `MockAudioContext` test double. `volume2dB`/`dB2Volume`
38
+ are now exported. Specs: `sopraSerialization.spec.js`, `SopraEngine.spec.js`,
39
+ `fadeOutAndStop.spec.js`.
40
+ Deferred to **P3** (integration, not P0): registering the adapters in
41
+ `GameBinarySerializationRegistry` and constructing `SopraEngine` in `makeMirEngineConfig`. P0 keeps
42
+ the legacy engine fully untouched.
43
+ - **P1 — Timeline playback + containers + parameters: ✅ DONE** (sopra suite now 35 tests green).
44
+ Delivered: a polymorphic `AbstractAudioClip.planTimeline(env, gainDb, pitchCents, offset)` on each
45
+ clip (deterministic flatten of the clip graph to timed leaf plays, gain/pitch inheritance resolved
46
+ once; no `instanceof` switching) + `collectSampleClips`, `SopraPlaybackContext` (seeded RNG + random-container
47
+ avoid-repeat history — network-deterministic per D5), Sequence/Random/Silence playback through
48
+ `EventInstance`, per-trigger pitch/gain randomization on `SampleAudioClip`, and parameter→bus-volume
49
+ automation via the reused `AnimationCurve`.
50
+ NOTE: the pumping **lookahead Scheduler** moved to **P2**, where virtualization actually needs it
51
+ (re-spawning virtual voices in-phase). P1 schedules a *finite* timeline eagerly with WebAudio's own
52
+ sample-accurate future `start(when)` — correct and simpler for bounded events.
53
+ - **P2 — Voice management + spatialization + cursor scheduling: ✅ DONE** (sopra suite now 43 tests
54
+ green). Cursor-based playback (each frame `EventInstance.update(now, listener)` evaluates the
55
+ timeline against the playhead, spawning leaves within a lookahead window only while audible);
56
+ **virtualization** — out-of-range instances stop their voices, keep the cursor, and revive at the
57
+ correct child + buffer-offset (D3); **3D spatialization** — per-instance `attenuationGain → panner →
58
+ bus` chain (D4), attenuation = `curve.evaluate(distance)`, with `buildAttenuationCurve` reproducing
59
+ the legacy falloff from `interpolate_irradiance_*`; HRTF/EqualPower panner choice; and a
60
+ **VoiceManager** (per-event `maxInstances` + steal oldest/quietest/none; defaults a no-op).
61
+ NOTES: the lookahead scheduler is realised as the per-instance cursor evaluation (a global priority
62
+ queue is a P4 optimization if profiling warrants); StereoPanner / "no-panner" modes deferred to P4.
63
+ - **P3 — ECS binding / strangler cut-over: P3.1–P3.6 DONE (P3.7 cleanup remains).** `SoundEngine` owns
64
+ the sopra engine via `createSopra(bufferProvider)`; `SoundEmitterSystem(assetManager, soundEngine)`
65
+ (required 2-arg ctor — no switch, no `sopra === null` branch) creates it through an
66
+ `AssetManagerBufferProvider`, reuses the single `SoundAssetLoader` (D7), and drives `sopra.setListener`
67
+ + `sopra.update` from its tick. **sopra is now the single renderer:** every `SoundEmitter` routes
68
+ through a per-entity `SoundEmitterComponentContext` translation record (legacy tracks → sopra
69
+ `EventInstance`s; live `emitter.volume × track.volume` → instance gain; shared `transform.position`
70
+ Vector3; live `track.volume` sets also plumb to the instance gain via `__soundRuntime`). The locked
71
+ public API (`SoundEmitter`: tracks/channel/volume/flags/distanceMin/Max; `SoundTrack`:
72
+ on.ended/flags/volume/time/url — `duration` was dropped, never written) is preserved as
73
+ deprecate-and-plumb; the `nodes` getters + `setVolumeOverTime` throw, while
74
+ `distanceRolloff`/`buildNodes`/`endTrack` and the rest of the non-contract surface were removed
75
+ outright. Channel volume = sopra bus volume (`get/setChannelVolume` proxy; legacy mix intact).
76
+ `CombatEndMusicProcess.switchMusic` now crossfades via `fadeOutAllTracks(1)` + `tracks.add`. All 10
77
+ `new SoundEmitterSystem(...)` call sites updated; the dead `SoundEmitterChannel` (singular) +
78
+ `SoundTrackNodes` classes are deleted; full `engine/sound` suite green (62 tests).
79
+ STILL PENDING (P3.7): single listener-feeder convergence and the remaining `@deprecated` JSDoc sweep.
80
+ - **P4 — build-out: STARTED.** Switch + Blend parameter-driven containers DONE
81
+ (`SwitchContainerAudioClip` = discrete RTPC-keyed single-child pick; `BlendContainerAudioClip` =
82
+ per-child parameter→gain curves, all audible layers play simultaneously). Parameter access threaded
83
+ into the planTimeline `env` (`getParameter`, read once at trigger). Both fully serialized (JSON +
84
+ binary + registry) and folded the dormant `material/` concepts (surface-switch / composition) into
85
+ general primitives. v1 Blend is a **trigger-time snapshot**, not live re-blend as the parameter
86
+ sweeps (follow-up below). **Reverb sends DONE:** `BusDefinition.sends` is now wired at build time
87
+ (post-fader copy → send gain → target bus input), and `ReverbEffect` (`ConvolverNode` + a
88
+ procedurally-generated decaying-noise IR — no IR asset, synchronous build) is a new bus insert.
89
+ **Mixer snapshots DONE:** `MixerSnapshot` (named per-bus target gains) + `SopraEngine.applySnapshot`
90
+ (instant or click-safe ramped blend, via `BusGraph.rampVolume`) + `captureSnapshot`. **Emulated
91
+ ducking DONE:** `DuckingRule` + `SopraEngine.addDucker`/`clearDuckers` — play-state sidechain (duck a
92
+ target bus while any instance plays on a trigger bus; `setTargetAtTime` attack/release via
93
+ `BusGraph.approachVolume`). **Native migration STARTED (additive-first):** native `AudioEmitter`
94
+ component (holds a full `EventDescription` directly) + `AudioEmitterSystem` done at the engine level —
95
+ shares the one sopra (idempotent `createSopra`), autoplay/stop/volume/position/listener, fully tested;
96
+ coexists with the untouched legacy `SoundEmitter`. (The autoplay-every-emitter behavior here is
97
+ **superseded by P5** spatial management — see below.) Remaining: `AudioEventTrigger` + game wiring
98
+ (config/editor/serialization registries) + the `SoundEmitter`→`LegacySoundEmitter` rename & call-site
99
+ flip (see §9). Sound banks were evaluated and DROPPED — the ECS data model (components + dataset +
100
+ AssetManager) already covers every bank role.
101
+ Full `engine/sound` suite green.
102
+ - **P5 — spatial scaling to 100k emitters: ✅ DONE (P5.1–P5.6; see §15 for the full record).** A BVH
103
+ broadphase + live/dormant split so the engine carries far more 3D emitters than can sound at once. A
104
+ registered-but-dormant emitter costs only a BVH leaf (no instance, no nodes, no per-frame work); each
105
+ tick the nearest in-range emitters — up to a global voice **budget** (default 64) — are promoted to
106
+ live instances and the rest demoted. **P5.1** `SpatialAudioIndex` (BVH cull, reactive leaf refit via
107
+ `position.onChanged`, allocation-free `queryAudible`). **P5.2** `LiveEmitterSet` (promote/budget/
108
+ distance-priority stealing/rank-hysteresis). **P5.3** demotion policy (hard cut when culled out of
109
+ range, click-safe fade on contention). **P5.4** continuous-clock phase reconstruction (`EventInstance.startTime`
110
+ + looping-voice buffer-offset wrap). **P5.5** a cull throttle was added then **reverted** — the cull
111
+ runs every tick (BVH is microseconds). **P5.6** `AudioEmitterSystem` wired to `LiveEmitterSet`:
112
+ looping-3D autoplay → spatially managed; 2D + finite-3D-one-shot → direct; non-autoplay → inert;
113
+ per-emitter `AudioEmitter.volume` carried through promote/demote. Two `.skip`-ped 100k stress tests
114
+ prove only `budget` instances exist regardless of N and the BVH prunes the far field (per-frame
115
+ `refresh + tick` ≈ 5 ms at 100k). Full `engine/sound` suite green (298, 2 skipped).
116
+
117
+ ## 1. Recommendation in one paragraph
118
+
119
+ Build sopra as an **ECS-agnostic runtime audio engine** (`SopraEngine` + its services) that is
120
+ fully unit-testable with a mock `AudioContext`, then bind it to meep with a **thin ECS layer**, and
121
+ keep the legacy `SoundEmitter` / `createSound` / channel surface alive as a **translating facade**
122
+ during migration (the *strangler* pattern). There is always **exactly one renderer** (sopra);
123
+ legacy classes become translators, never a second engine. The architecture grafts the best of three
124
+ evaluated stances: the *ECS-agnostic, clock-injected core* (testability), the *clean component/system
125
+ topology* (meep-idiomatic), and the *zero-churn facade* (ships v1 with no call-site / save / settings
126
+ / editor edits).
127
+
128
+ The **spine** is the thing meep lacks and FMOD/Wwise are built on: a **definition / instance split**.
129
+ Today `SoundTrack` conflates the spec (`url`/`time`/`volume`/flags) with the live, single-use
130
+ `AudioBufferSourceNode`. Sopra splits this into immutable **definitions** (the `*AudioClip` tree),
131
+ transient pooled **instances/voices**, and engine-owned **services** (mixer bus tree, scheduler,
132
+ parameter store, voice manager).
133
+
134
+ ---
135
+
136
+ ## 2. Engine philosophy this plan must respect (verified)
137
+
138
+ **meep ECS** (`engine/ecs/`)
139
+ - `System` subclasses declare `dependencies = [ClassA, ClassB]`; the engine auto-delivers
140
+ `link(...componentsInDependencyOrder, entity)` / `unlink(...)` (arity is validated as
141
+ `deps.length + 1`). `components_used = [ResourceAccessSpecification.from(Klass, access)]` is a
142
+ scheduling hint that also auto-registers component columns.
143
+ - `simulate(dt)` runs a **fixed-step lock-step pass** (`fixedUpdate(fixedStep)`) then **one
144
+ variable pass** (`update(dt)`); `getFixedStepAlpha()` gives the sub-step remainder for
145
+ interpolation. `fixedStepTick` only advances in the fixed pass.
146
+ - Components are **plain serializable object instances** stored column-wise
147
+ (`components[componentIndex][entityId]`). Runtime/WebAudio objects must NOT live on the
148
+ component — they live in a system-owned `this.data[entity]` context (the established
149
+ `SoundEmitterComponentContext` discipline).
150
+ - Singletons (the listener) are fetched via `ecd.getAnyComponent(Klass)`. Gameplay→sound uses the
151
+ per-entity event bus (`addEntityEventListener` / `sendEvent`), as `SoundControllerSystem` does.
152
+
153
+ **Conventions**: every persisted type has `toJSON`/`fromJSON` **and** a versioned
154
+ `BinaryClassSerializationAdapter` registered by `typeName`; polymorphic trees recurse through
155
+ `ObjectBasedClassSerializationAdapter` + the shared `objectAdapter` (the behavior-tree precedent);
156
+ `Signal` for events, `List` for observable collections, `Vector1` for change-notifying scalars,
157
+ flags as bitmask enums, `assert.*` (free in prod).
158
+
159
+ **User memories (hard constraints)**
160
+ - **Uniform control flow** — no `null = auto / value = override` sentinels.
161
+ ⚠️ `AbstractAudioClip.parent` / `.channel` are exactly this antipattern; resolve inheritance
162
+ **once** at voice instantiation (flatten), so the runtime tick never sees a sentinel.
163
+ - **Reuse over micro-opt** — prefer tested primitives; lead with end-to-end measurement.
164
+ - **Correctness first, no bandaids**; **black-box tests only** (assert observable outcomes — which
165
+ buffer, which bus, what gain, what `when`, how many real voices — never call counts);
166
+ **no silent catch** (expected failure → sentinel/defer; unexpected → throw); asserts are free.
167
+
168
+ ---
169
+
170
+ ## 3. The current engine and its gaps
171
+
172
+ | Layer | Current | FMOD/Wwise gap |
173
+ |---|---|---|
174
+ | Definition | `SoundEmitter` (List<SoundTrack>, channel, distance, attenuation enum, flags) | no event/instance split |
175
+ | Playback | `SoundTrack` **conflates** spec + live single-use source + state | — |
176
+ | Mixer | **flat** 3 channel `GainNode`s (effects 1.2 / music 0.1 / ambient) → master `Gain → DynamicsCompressor → destination` | no nestable buses, no inserts, no sends |
177
+ | Spatial | per-emitter `PannerNode` (rolloff=0) + custom attenuation `GainNode` via `interpolate_irradiance_*`; BVH hearing-range cull | attenuation is a fixed 3-value enum, not a curve |
178
+ | Voices | **plays every track of every in-range emitter**; only cull is BVH | no limits / priority / stealing / virtualization |
179
+ | Params | none | no RTPC / automation |
180
+ | Timing | `track.time += timeDelta` each frame; `Suspended` flag works around Chrome disconnected-source time-freeze | no lookahead scheduler; sequence/loop precision at mercy of frame rate |
181
+ | Containers | `sopra/` stubs exist with **no** selection logic, scheduler, instance, or serialization | random / sequence / blend / switch are empty classes |
182
+
183
+ Latent bug to *not* faithfully reproduce: `SoundEmitterSystem.update` line ~370 is
184
+ `if (soundTrack.setFlag(...) && ...)` — `setFlag` returns `undefined`, so the suspended-track-end
185
+ branch is dead code and it sets `Suspended|Playing` on every track every frame. Port the **intent**
186
+ (logical time advances while virtual; revive in phase), not the mechanism.
187
+
188
+ ---
189
+
190
+ ## 4. The sopra model — three layers
191
+
192
+ ### 4.1 Definition layer (immutable, serialized, `typeName` + adapter + `toJSON`/`fromJSON`)
193
+
194
+ ```
195
+ AbstractAudioClip (finish the stub: typeName, isAudioClip tag, .from(), compare/equals/hash/clone)
196
+ ├── SampleAudioClip NEW leaf — the only buffer-referencing clip: assetRef(path|alias),
197
+ │ gainDb, pitch(cents), loop + loopStart/loopEnd, pitchRandom, gainRandom
198
+ ├── SilenceAudioClip (stub) duration → pure schedule-cursor offset, emits no source
199
+ ├── ContainerAudioClip (stub) children[]
200
+ │ ├── SequenceContainerAudioClip plays children in order (scheduled, not onended-chained)
201
+ │ ├── RandomContainerAudioClip (stub) avoid_repeating_last via recent-history ring + seededRandom
202
+ │ ├── BlendContainerAudioClip [deferred] parameter-driven crossfade
203
+ │ └── SwitchContainerAudioClip [deferred] discrete parameter selects child (subsumes material/)
204
+ ```
205
+
206
+ Plus three non-clip definition types:
207
+ - **`EventDescription`** — the triggerable unit: `label, rootClip, busId, maxInstances, priority,
208
+ stealMode, virtualThresholdDb, is3D, attenuation: AnimationCurve, distanceMin/Max`.
209
+ (FMOD `EventDescription` / Wwise Actor-Mixer object.)
210
+ - **`BusDefinition`** — `{ id, parentId, gainDb, effects[], sends[] }`. In v1, `effects[]` is **live**
211
+ (an ordered chain of `AbstractAudioEffect` — `EqEffect`/`CompressorEffect`, see D10); `sends[]` ships
212
+ as a **data shape only** (reverb sends are P4) so adding them later is non-breaking.
213
+ - **`AbstractAudioEffect`** (+ `EqEffect`, `CompressorEffect`) — serialized bus-insert effects with a
214
+ `build(ctx) → { input, output }` contract (see D10).
215
+ - **`AnimationCurve`** (reused from `engine/animation/curve/`, a cubic-Hermite keyframe curve) —
216
+ used for **both** parameter automation (RTPC) and 3D distance attenuation. `EventDescription.attenuation`
217
+ is an `AnimationCurve`; since it has no `typeName`/binary adapter of its own, the event adapter
218
+ serializes its keyframes inline. (Supersedes the originally-planned bespoke `AutomationCurve`.)
219
+ - **`ParameterDefinition`** — `{ name, range, default, scope }`.
220
+
221
+ > **Uniform-flow fix:** `parent`/`channel`/`gain`/`pitch` inheritance is resolved **once** when an
222
+ > `EventInstance` is created (top-down flatten). The runtime never branches on a `null`-means-inherit
223
+ > sentinel.
224
+
225
+ ### 4.2 Runtime layer (transient, pooled, **never serialized**)
226
+
227
+ - **`EventInstance`** — one trigger: resolved position, parameter overrides, **schedule cursor**,
228
+ active `Voice`s, one-shot|persistent lifetime. Owns **its** `PannerNode` + attenuation `GainNode`
229
+ (see decision D4). Modeled on `ParticleEmitter.build()`, *not* the behavior-tree re-armed node
230
+ (which cannot produce concurrent voices).
231
+ - **`Voice`** — one throwaway `AudioBufferSourceNode` + a **pooled** trim `GainNode`. The source is
232
+ the only unavoidable per-play allocation (it is single-use).
233
+
234
+ ### 4.3 Services (single instances hung off `SoundEngine`, no ECS imports)
235
+
236
+ - **`SopraEngine`** — ECS-agnostic public API: `playEvent / playOneShot / createInstance / stop`,
237
+ `bus(id)`, `setParameter / getParameter`, `setListener(pose)`, `update(now)`. Constructed with
238
+ `(audioContext, destinationNode, bufferProvider)`; **reuses the existing `AudioContext` + master
239
+ chain verbatim — never a second context.**
240
+ - **`BusGraph`** — instantiates the `BusDefinition` tree into chained `GainNode`s; root →
241
+ `SoundEngine.destination`; **seeds the default `effects`/`music`/`ambient` buses with the exact
242
+ legacy mix (Effects 1.2, Music 0.1)**; exposes `get/setChannelVolume` (linear, see D6).
243
+ - **`Scheduler`** — lookahead queue over `AudioContext.currentTime`; each `update(now)` drains events
244
+ due before `now + lookahead` and calls `start(when, offset, duration)`. Replaces `time += timeDelta`
245
+ and obsoletes the `Suspended` hack. (Reuse `BinaryHeap`.)
246
+ - **`ParameterStore`** — `Map<name, number>` + per-instance overrides + `onChanged` `Signal`s; samples
247
+ bound `AnimationCurve`s → `setTargetAtTime`.
248
+ - **`VoiceManager`** — active-voice registries keyed by `eventId` and `busId`; per-event
249
+ `maxInstances` + per-bus limits + priority + steal-oldest/quietest (by post-attenuation gain);
250
+ **virtualization** (stop+disconnect source, keep advancing the instance cursor, revive in phase).
251
+ - **`VoicePool`** — `ObjectPoolFactory` of pre-wired trim-gain chains.
252
+ - **`BufferProvider`** (interface) + **`AssetManagerBufferProvider`** — `get(ref) → Promise<AudioBuffer>`.
253
+ Prod wraps `AssetManager.promise(resolveAlias(ref) || ref, 'audio')` (shared immutable buffer);
254
+ a stub impl in tests is what makes the core ECS-free unit-testable.
255
+ - **`fadeOutAndStop`** — the ONE click-safe fade primitive (see D1). No call site hand-rolls fades.
256
+
257
+ ### 4.4 ECS binding (thin)
258
+
259
+ - **`SopraEmitter`** (component) `+ Transform` — plain serializable
260
+ `{ eventId, paramOverrides, busOverride, volume: Vector1, flags }`. Runtime `EventInstance` lives
261
+ in `system.data[entity]`.
262
+ - **`SopraEmitterSystem`** `dependencies = [SopraEmitter, Transform]` — `link` → `createInstance`
263
+ + `BVH.link`; `update(dt)` → BVH cull around the listener (reuse `BVHQueryIntersectsSphere` +
264
+ `bvh_query_user_data_generic` + `IncrementalDeltaSet`), push position/params, `engine.update(now)`;
265
+ `unlink` → stop + release. Hosts `playOneShot(eventId, position, overrides)`.
266
+ - **`SoundListener` / `SoundListenerSystem`** — **reused verbatim**; read via `getAnyComponent`,
267
+ forwarded through `SopraEngine.setListener`.
268
+ - BVH out-of-range = **virtual** (not disconnect); the `VoiceManager` decides actual realness under
269
+ budget. This turns the Chrome `Suspended` hack into standard virtual-voice behavior.
270
+
271
+ ---
272
+
273
+ ## 5. Key design decisions (incl. the 5 critique revisions)
274
+
275
+ - **D1 — `fadeOutAndStop` must NOT hard-depend on `cancelAndHoldAtTime`.** It is unimplemented in
276
+ Firefox (and used nowhere in meep today). Feature-detect it; otherwise use the portable idiom:
277
+ read `param.value`, `cancelScheduledValues(now)`, `setValueAtTime(currentValue, now)`, then ramp.
278
+ Always ramp to an **epsilon, never 0** (exponential-ramp-to-0 throws / clicks), and schedule
279
+ `stop()` just after the gain reaches ~epsilon. Test the no-`cancelAndHoldAtTime` path with a mock.
280
+ - **D2 — `playOneShot` owns a max-lifetime timeout (default 60s) AND releases on asset-load
281
+ failure.** `createSound` today is belt-and-suspenders (`on.ended` **and** `Sequence[Delay(60),Die]`).
282
+ A one-shot whose asset 404s must still release — the no-silent-catch sentinel path, not a hang.
283
+ - **D3 — Virtualization revive uses the instance logical cursor, not `t % dur`.** `t % dur` is only
284
+ correct for a single looping leaf. For a `Sequence`/`Random`/one-shot, re-derive the active leaf(s)
285
+ and their offsets from the cursor at `currentTime`, then `start(when, leafOffset)` each.
286
+ - **D4 — `PannerNode` + attenuation `GainNode` are per-`EventInstance` (shared by its leaf voices),
287
+ not per-`Voice`.** This matches today's per-emitter sharing (`buildNodes` builds one chain; all
288
+ tracks feed the single emitter volume node). Per-voice panners would multiply HRTF cost (the
289
+ dominant spatialization cost) on multi-track emitters — a regression for the dense scenes we care
290
+ about. Only the source node + trim gain are per-voice. Panner-type choice (HRTF / equalpower /
291
+ `StereoPanner` for 2D-UI / none) + distance/budget downgrade lives at the instance level.
292
+ - **D5 — Random/Switch selection is network-deterministic (decided).** Seed `seededRandom` from a
293
+ replicated source (`entity id + fixedStepTick`), not `Math.random`. Because the seed depends on
294
+ `fixedStepTick` (which only advances in the fixed pass), a selection decision must be made in
295
+ `fixedUpdate(fixedStep)` **or** stamped with the `fixedStepTick` read once per frame — the
296
+ selection must never depend on the variable `update(dt)` cadence. Keep `setRandomSeed` on the
297
+ container voice (the `WeightedRandomBehavior` precedent) so tests are reproducible.
298
+ - **D6 — Channel-volume facade stays linear end-to-end.** The settings sliders are `{min:0,max:1}`
299
+ linear and `Effects` defaults to **1.2** (above max). Store/return the raw linear gain the slider
300
+ expects; convert to dB only internally if a bus needs it. Preserve 1.2 / 0.1 exactly.
301
+ - **D7 — Single owner of the `SoundAssetLoader` registration.** `AssetManager.registerLoader` throws
302
+ on duplicate type. The rewired `SoundEmitterSystem` already registers it; `SopraEngine` reuses it,
303
+ does not re-register. Make construction order in `makeMirEngineConfig` explicit.
304
+ - **D8 — Clip-tree adapters model the behavior-tree spine, NOT the legacy `SoundEmitter` adapter.**
305
+ The legacy adapter hand-rolls track ser/de inline and is **not** polymorphic. New container
306
+ adapters extend `ObjectBasedClassSerializationAdapter` so children recurse by `typeName`.
307
+ - **D9 — Resolve the dormant overlaps.** `material/` (weighted `SoundMaterialComposition` + terrain
308
+ splat detector) and `asset/SoundAssetPlaybackSpec` are dormant (zero usages/tests). Fold them into
309
+ `Switch`/weighted containers in P4; do not maintain three parallel spec hierarchies.
310
+ - **D10 — Bus insert effects are live in v1 (per the scope decision).** Add an `AbstractAudioEffect`
311
+ base mirroring `AbstractAudioClip` style (`typeName`, `toJSON`/`fromJSON`, adapter, `compare`/
312
+ `equals`/`hash`/`clone`) with a `build(ctx) → { input, output }` contract, plus two concrete
313
+ effects for v1: `EqEffect` (`BiquadFilterNode`, automatable `frequency`/`Q`/`gain`) and
314
+ `CompressorEffect` (`DynamicsCompressorNode`). `BusGraph` wires each bus as
315
+ `input → effect[0] → … → effect[n] → output`; an empty `effects[]` is a direct `input === output`.
316
+ The existing **master** `DynamicsCompressor` (in `SoundEngine`) stays master-glue only — buses must
317
+ not double-compress by default. `WaveShaper`/occlusion-lowpass remain nice-to-have (P4+).
318
+
319
+ ---
320
+
321
+ ## 6. Reuse map (reuse-over-micro-opt)
322
+
323
+ | Existing meep code | Used for |
324
+ |---|---|
325
+ | `sound/SoundEngine.js` (AudioContext, master `Gain→Compressor→destination`, suspend/resume) | injected into `SopraEngine`; never a 2nd context |
326
+ | `sound/ecs/SoundListener*.js` | listener pose, reused **verbatim** |
327
+ | `core/bvh2/bvh3/*` + `BVHQueryIntersectsSphere` + `IncrementalDeltaSet` | hearing-range cull = virtualization trigger |
328
+ | `core/model/object/ObjectPoolFactory.js` | voice trim-gain pool; `ParticlePool`/`BitSet` if fixed-capacity budget wanted |
329
+ | `core/math/random/seededRandom.js` (Mulberry32) + `weightedRandomFromArray.js` | deterministic random/weighted selection; avoid-repeat ring |
330
+ | `Signal`, `Vector1` (onChanged), `List`, `combine_hash`/`computeHashFloat`/`computeStringHash` | params, gains, child collections, voice `onended`, clip hashing |
331
+ | `engine/asset/*` (`AssetManager`, `SoundAssetLoader`, `loadSoundTrackAsset` alias path, `AssetPreloader`) | `AssetManagerBufferProvider`; preload via existing asset manifests (no bank concept) |
332
+ | `engine/animation/curve/AnimationCurve.js` + `Keyframe.js` | the curve type for RTPC automation **and** 3D distance attenuation (`EventDescription.attenuation`) — reused instead of a bespoke curve |
333
+ | `core/math/physics/irradiance/interpolate_irradiance_*` | reference falloff shapes when authoring `AnimationCurve` attenuation presets (P2) |
334
+ | `sound/volume2dB.js` + `dB2Volume.js` (**export them**) | dB↔linear at facade edges, gain randomization, ducking math |
335
+ | `ecs/storage/binary/object/*` + `SequenceBehaviorSerializationAdapter` shape | polymorphic recursive clip-tree ser/de by `typeName` |
336
+ | `intelligence/behavior/*` (`Behavior`, `CompositeBehavior`, `BehaviorSystem`) | definition node contract + system lifecycle shape (but split def/instance) |
337
+ | `SoundEmitterComponentContext` discipline | runtime objects in `data[entity]`; `Suspended` plumbing → `VoiceManager` virtualization |
338
+
339
+ ---
340
+
341
+ ## 7. Serialization plan
342
+
343
+ - Each definition type gets a `typeName`, a `BinaryClassSerializationAdapter` at **version 0**, and a
344
+ parallel `toJSON`/`fromJSON`. Container adapters extend `ObjectBasedClassSerializationAdapter`.
345
+ - Register all in `GameBinarySerializationRegistry.initializeGameBinarySerializationRegistry`
346
+ (`registerAdapters([...])`) **and** in `GameClassRegistry` — the single registration sites, called
347
+ before `config.apply` in `GameBootstrap`.
348
+ - Design byte layouts to be **upgrade-friendly from day one** (varint-counted, append-only fields),
349
+ per the `SoundEmitterSerializationUpgrader_1_2` lesson (which just appends a default `volume`).
350
+ - **The legacy `SoundEmitterSerializationAdapter` (v2) + upgraders `_0_1`/`_1_2` stay registered
351
+ verbatim** — old saves deserialize into a `SoundEmitter` exactly as today; the facade translates at
352
+ link time. No save-format migration in v1.
353
+
354
+ ---
355
+
356
+ ## 8. Migration / back-compat (the four surfaces)
357
+
358
+ Invariant: always exactly one renderer (sopra); legacy classes are translators.
359
+
360
+ 1. **`createSound`** (#1 fire-and-forget, ~7 high-traffic sites). Keep the signature
361
+ `{position, url|track, positioned, channel, volume, timeout}` and self-destruct contract
362
+ byte-for-byte. Reimplement the body to build an ad-hoc `EventDescription` (root =
363
+ `SampleAudioClip`, `busId = channel`, `is3D = positioned`, `gainDb = volume2dB(volume)`) and call
364
+ `playOneShot(desc, {position})`. **Preserve the full safety net** (D2). `GameSounds.js` named
365
+ tracks become named `EventDescription`s keeping their export names.
366
+ 2. **`SoundEmitter` + `fromJSON` + manual entity builds** (footsteps/voice/impacts, boss ambience,
367
+ music stems, title music, achievements, dialogue). v1: keep the exact component shape & `fromJSON`;
368
+ the rewired `SoundEmitterSystem.link` translates each `SoundTrack` → `SampleAudioClip` + a
369
+ persistent `EventInstance` on the channel-bus (attenuation enum → 3-point `AutomationCurve`).
370
+ `tracks.on.added/removed` spawn/stop instances so `emitter.tracks.add/addAll` keep working.
371
+ Direct AudioParam reaches get equivalents: `setVolumeOverTime`/`emitter.volume.onChanged` →
372
+ live voice gain; `resetSoundEmitterTracks` (`t.time=0`) → `instance.seek(0)` **and** write
373
+ `track.time` back from the live cursor so readers stay consistent; `hideEntityGracefully` 2.7s
374
+ fade / `SoundEmitterVolumeBehavior` → `instance.fadeOutAndStop`. `CombatEndMusicProcess` reads
375
+ `track.nodes.volume.gain` directly → expose a **temporary bridge GainNode** at
376
+ `SoundTrack.nodes.volume` during cut-over, then migrate it to a `bus.fadeTo`/voice-crossfade
377
+ primitive and drop the bridge in P4 (do not keep the bridge as steady state).
378
+ 3. **`SoundController`** (UnitMaker only). Keep its v0 adapter frozen in v1. P4: provide
379
+ `SopraEventTrigger` preserving the `{tracks, startEvent, stopEvent, loop, volume, channel}` rule
380
+ shape; migrate UnitMaker last.
381
+ 4. **Channels + settings UI** (must preserve). Seed default buses with the exact legacy mix; keep
382
+ `get/setChannelVolume` on the (rewired) `SoundEmitterSystem` proxying to bus gain **in the linear
383
+ domain** (D6). Sliders bind unchanged. **Editor** (`SoundEmitterController`, symbolic display,
384
+ reset-tracks) keeps working because the component shape is preserved.
385
+
386
+ ---
387
+
388
+ ## 9. Phased plan
389
+
390
+ > Each phase ships behind black-box `*.spec.js` run from `H:/git/moh` root. P0–P2 need **no ECS**.
391
+
392
+ **P0 — Core skeleton + ser/de + bus inserts (no ECS).**
393
+ Finish clip classes; add `SampleAudioClip`, `EventDescription`, `BusDefinition`,
394
+ `ParameterDefinition` (3D attenuation reuses the existing `AnimationCurve`), and the effect hierarchy
395
+ `AbstractAudioEffect`/`EqEffect`/`CompressorEffect`
396
+ (D10); `BusGraph` (default buses at legacy mix, wiring each bus's `input→effects→output` insert
397
+ chain); `EventInstance` + `Voice` (pooled gain); `SopraEngine.playEvent/playOneShot/createInstance/
398
+ stop/bus`; `BufferProvider` + stub; **export `volume2dB`/`dB2Volume`**; `fadeOutAndStop` **with the
399
+ Firefox fallback (D1)**; one adapter per definition + effect type registered.
400
+ *Exit:* a `SampleAudioClip` event plays to the right bus at the right gain, **through a bus insert
401
+ chain (EQ→Compressor) wired in the correct order**, **and** every definition + effect round-trips
402
+ equal (binary + JSON) — in Jest with a mock `AudioContext`, no ECS. Firefox fade path tested. Legacy
403
+ engine untouched and still active. **✅ DONE — 26 tests green (see §0).**
404
+
405
+ **P1 — Timeline playback + containers + parameters. ✅ DONE — sopra suite 35 tests green.**
406
+ A polymorphic `AbstractAudioClip.planTimeline()` (overridden per clip) deterministically flattens the clip graph to timed leaf plays (gain/pitch
407
+ inheritance resolved once); `Random` (seeded + avoid-repeat ring via `SopraPlaybackContext`) and
408
+ `Sequence` (cumulative offsets; `Silence` = offset arithmetic); `ParameterStore` + `AnimationCurve`
409
+ bound to bus volume (same curve type used for 3D attenuation); per-trigger pitch/gain randomization.
410
+ D5 resolved (deterministic). The pumping lookahead `Scheduler` was MOVED TO P2 (it's only needed for
411
+ virtualization / indefinite content); P1 schedules finite timelines eagerly via WebAudio future
412
+ `start(when)`.
413
+ *Exit (met):* sequence schedules children back-to-back with no gap; random avoids last N for a fixed
414
+ seed; `setParameter` observably moves a live gain — black-box, no ECS.
415
+
416
+ **P2 — VoiceManager + spatialization + cursor scheduling. ✅ DONE — sopra suite 43 tests green.**
417
+ Cursor-based per-instance scheduling realises the lookahead model (each frame
418
+ `EventInstance.update(now, listener)` spawns leaves within a lookahead window) — a global priority
419
+ queue is deferred to P4 as an optimization. `VoiceManager` with per-event `maxInstances` + priority +
420
+ steal (oldest/quietest/none). **Cursor-based virtualization** (D3): out-of-range instances stop their
421
+ voices, advance the cursor, and revive at the correct child + buffer-offset. Per-`EventInstance`
422
+ `PannerNode` (rolloff=0) + attenuation `GainNode` driven by `attenuation.evaluate(distance)` (D4);
423
+ `buildAttenuationCurve` authors legacy-equivalent curves from `interpolate_irradiance_*`;
424
+ HRTF/EqualPower panner choice (StereoPanner / no-panner deferred to P4). Per-bus limits also deferred
425
+ to P4 (per-event covers the exit criteria).
426
+ *Exit (met):* over-limit steals the correct victim; a virtualized sequence revives at the correct
427
+ child+offset; attenuation matches the legacy curve at sample distances. Default limits are a no-op /
428
+ stealing is opt-in.
429
+ *Exit:* over-limit steals the correct victim; a virtualized **sequence** (not just a loop) revives at
430
+ the correct child+offset; attenuation matches the legacy curve at sample distances. **Default limits
431
+ are a no-op / stealing is opt-in** (so dense scenes can't regress before measurement).
432
+
433
+ **P3 — ECS binding + facade cut-over (zero call-site / save / settings / editor change).**
434
+ `SopraEmitterSystem` (+ `playOneShot`); reuse `SoundListener*`; construct `SopraEngine` in
435
+ `makeMirEngineConfig` from `sound.context/.destination`; **single loader owner (D7)**. Rewire
436
+ `SoundEmitterSystem` to translate tracks→clips→persistent instances (same constructor); `createSound`
437
+ → `playOneShot` (D2); `GameSounds` as named events; `get/setChannelVolume` proxy (linear, D6);
438
+ temporary `track.nodes.volume` bridge + `track.time` write-back. Legacy v2 adapter/upgraders +
439
+ `SoundController`/`SoundListener` + editor untouched; remove old `SoundTrack` node-rendering once the
440
+ regression suite is green.
441
+ *Exit:* all ~25 call sites, saves, sliders, and the editor behave identically; sopra is the only
442
+ renderer.
443
+
444
+ **P4 — Native migration + FMOD/Wwise build-out (post-strangler).**
445
+
446
+ > **DONE — Switch/Blend containers.** `SwitchContainerAudioClip` (discrete RTPC-keyed: rounds+clamps a
447
+ > parameter to a child index) and `BlendContainerAudioClip` (per-child parameter→linear-gain curves;
448
+ > every child with gain > 0 plays simultaneously, scaled). Parameter access added to the planTimeline
449
+ > `env.getParameter` (read once at trigger). Full JSON+binary serialization + registry; supersedes the
450
+ > dormant `material/` subsystem's surface-switch / composition concepts. **Limitation:** Blend is a
451
+ > trigger-time snapshot — it does NOT re-blend live as the parameter later sweeps. **Live re-blend
452
+ > follow-up:** have plays carry an optional `{gainParam, gainCurve}`, bind the spawned voice's trim
453
+ > gain to the `ParameterStore` (needs an *unbind* on voice retire — ParameterStore.bind currently has
454
+ > no removal). Also still dormant: delete the `material/` files + `asset/SoundAssetPlaybackSpec` once
455
+ > confirmed unreferenced.
456
+
457
+ > **DONE — Reverb / aux sends.** `BusGraph.build` now wires `BusDefinition.sends` (previously a
458
+ > data-only shape): for each send it taps the source bus's output → a send-level `GainNode` →
459
+ > `targetBus.input` (post-fader copy; the dry path to the parent is unchanged). Throws on an unknown
460
+ > send target. `ReverbEffect` is a new `ConvolverNode` insert whose impulse response is generated
461
+ > procedurally at build (decaying noise; params `decaySeconds`/`decayPower`) — so build stays
462
+ > synchronous with no IR-asset dependency. A "reverb bus" = a bus with a `ReverbEffect` insert that
463
+ > other buses send to. **Follow-ups:** live send-level control (sends are static at build); authored-IR
464
+ > source from the BufferProvider (would make build async); pre-fader sends.
465
+
466
+ **Native migration** (user naming: `AudioEmitter` [rename `SoundEmitter`→`LegacySoundEmitter`],
467
+ `AudioEventTrigger` — keep "sopra" internal-only). Decided **additive-first**: `AudioEmitter` holds a
468
+ full `EventDescription`.
469
+
470
+ > **DONE — additive foundation (engine-level, not yet wired into the game).** `AudioEmitter`
471
+ > (`engine/sound/ecs/audio/`) holds a full `EventDescription` + a live `volume` (Vector1) + `autoplay`;
472
+ > serializable (JSON). `AudioEmitterSystem` shares the single sopra (`SoundEngine.createSopra` made
473
+ > idempotent) + self-registers the `SoundAssetLoader` if absent (standalone-capable, guarded), autoplays
474
+ > on link with `oneShot` derived from `event.rootClip.loops()` (finite events self-release at end,
475
+ > looping events persist), plumbs `volume`→instance gain + `transform.position`→instance, and ticks
476
+ > sopra + listener. Coexists with the untouched legacy `SoundEmitter`. Black-box tested.
477
+ > **RENAME DROPPED (owner change of plans):** no `SoundEmitter`→`LegacySoundEmitter` rename. Instead
478
+ > the legacy stack — `SoundEmitter`, `SoundEmitterSystem`, `SoundController`, `SoundControllerSystem` —
479
+ > is annotated `@deprecated` (pointing at `AudioEmitter`/`AudioEmitterSystem`/the forthcoming
480
+ > `AudioEventTrigger`). The classes keep their names; callers migrate organically.
481
+ > **NOT yet done (own pass):** `AudioEventTrigger` (replaces `SoundController`); wiring `AudioEmitter`
482
+ > into `GameClassRegistry` / `GameBinarySerializationRegistry` / the editor (`AudioEmitterController`,
483
+ > symbolic display) / `makeMirEngineConfig`; consolidating the sopra tick to one owner once both systems
484
+ > run together; migrating call sites to `AudioEmitter`.
485
+ >
486
+ > **Post-review fixes landed (P4 review):** D1 — `oneShot` now derived from `event.rootClip.loops()`
487
+ > (looping AudioEmitter events no longer die at the 60s lifetime backstop; added `loops()` to the clip
488
+ > hierarchy). D2 (keystone) — `BusGraph` now keeps an authoritative per-bus `nominal` gain; `getVolume`/
489
+ > `getVolumeDb` read it, `setVolume`/`rampVolume` write it, and `approachVolume` (ducking) deliberately
490
+ > does NOT — so snapshot `captureSnapshot`, duck nominal-capture/restore, and settings read-back are
491
+ > correct under automation (was: stale `gain.value`, which WebAudio never updates under ramps). IR2 —
492
+ > `AudioEmitterSystem` self-registers the `SoundAssetLoader` (guarded). **Deferred (do at wiring time,
493
+ > not band-aided):** IR1 single-owner sopra tick (the double-tick is idempotent-within-frame today and
494
+ > only matters once both systems are in one config); D3 multi-ducker aggregation; IR4 production
495
+ > serialization wiring; the remaining quick-fixes (D4–D9, C3).
496
+
497
+ Flip call sites to `AudioEmitter`; `AudioEventTrigger` replaces `SoundController`; migrate
498
+ `CombatEndMusicProcess` to bus/voice crossfade and drop the bridge; `AudioEmitterController` editor
499
+ panel; `AudioEmitter` v0 adapter + save-translation path. Then the deferred features behind their own
500
+ tests: **~~Snapshots/mixer-states~~ (DONE); ~~Blend/Switch containers~~ (DONE); additional bus insert
501
+ effects (occlusion lowpass / `WaveShaper`) beyond the v1 EQ/Compressor; ~~reverb sends~~ (DONE);
502
+ ~~emulated ducking~~ (DONE); scatterer; adaptive-music timeline.**
503
+
504
+ > **DONE — Emulated ducking.** `DuckingRule` definition (trigger/target bus, `duckDb`, `attack`,
505
+ > `release`) + ser/de + registry. `SopraEngine.addDucker`/`clearDuckers`; evaluated each `update()`:
506
+ > edge-triggered — when the trigger bus has ≥1 live instance the target ducks (`setTargetAtTime` toward
507
+ > nominal+duckDb over attack; nominal captured at engage), restoring over release when the trigger goes
508
+ > quiet. **Play-state** sidechain (active-instance count, NOT signal level — WebAudio has no native
509
+ > sidechain) via the new `BusGraph.approachVolume`. Trigger match is by direct `instance.busId` (child
510
+ > buses not counted in v1). Follow-up: true signal-following duck via `AudioWorklet`.
511
+
512
+ > **DONE — Mixer snapshots.** `MixerSnapshot` definition (id + per-bus target `gainDb`) with full
513
+ > ser/de + registry. `SopraEngine.applySnapshot(snapshot, {duration})` snaps (duration 0 →
514
+ > `setVolume`) or click-safely ramps (`BusGraph.rampVolume` → shared `rampGain`) each listed bus to its
515
+ > target — the FMOD mix-state blend. `captureSnapshot(id, busIds)` reads the current mix (for
516
+ > save/restore). Throws on an unknown bus.
517
+
518
+ > **Sound banks — DROPPED (not a feature).** A "bank" is FMOD/Wwise's catch-all for serialization +
519
+ > load-unit + media package + by-id namespace, needed only because that middleware has no host data
520
+ > model. meep already has every piece: `EventDescription`s are serializable definitions that live as
521
+ > component / `EntityComponentDataset` data; load/unload is the scene/dataset boundary; media is the
522
+ > `AssetManager`'s concern (cache + preload manifests). The only residual — shared "play by id" events
523
+ > — is at most a small `AudioEventLibrary` *component* (id→`EventDescription` map), and even that is
524
+ > optional since `playEvent` already accepts a description object directly.
525
+
526
+ ---
527
+
528
+ ## 10. Testing strategy (black-box only)
529
+
530
+ - **Layer 1 — ECS-free core** (the payoff of the agnostic design): inject a mock `AudioContext`
531
+ (records `createGain`/`createBufferSource`/`connect`/`start(when,offset,duration)`/gain
532
+ automation as an observable graph + schedule), a stub `BufferProvider` (fixed-duration buffers),
533
+ a deterministic clock, and a seeded RNG. Cover: definition round-trip; routing to the right bus at
534
+ the right dB; sequence gapless scheduling (`when` = prev `when` + prev `duration`); random
535
+ avoid-last-N **for a fixed seed (deterministic, D5)**; parameter moves gain; over-limit steals
536
+ correct victim; **virtualized sequence revives at correct child+offset**; attenuation matches
537
+ `interpolate_irradiance_*`; **a bus insert chain wires EQ→Compressor in order (empty `effects[]` is
538
+ pass-through; the master compressor is not double-applied)**; `fadeOutAndStop` never ramps to 0,
539
+ stops after ~epsilon, **and the no-`cancelAndHoldAtTime` fallback path**.
540
+ - **Layer 2 — ECS binding**: an entity with `SopraEmitter+Transform` plays a 3D event, attenuates
541
+ with distance, goes virtual outside BVH range and revives on re-entry; sliders move bus gains.
542
+ - **Layer 3 — back-compat regression** (the strangler safety net): `createSound` self-destructs on
543
+ end **and** on the timeout/asset-failure path; `SoundEmitter.fromJSON` is audibly equivalent;
544
+ `emitter.tracks.add` spawns a voice; `resetSoundEmitterTracks` restarts audibly; channel volume
545
+ round-trips at **1.2 / 0.1** through the linear proxy; an old save deserializes via the frozen v2
546
+ adapter and plays; single `SoundAssetLoader` registration when both engines are constructed.
547
+
548
+ Determinism: seed `seededRandom` from the test (and, per D5, from a replicated source if
549
+ network-deterministic audio is chosen).
550
+
551
+ ---
552
+
553
+ ## 11. Risks
554
+
555
+ | Risk | Sev | Mitigation |
556
+ |---|---|---|
557
+ | Game code pokes `track.nodes.volume.gain` directly (CombatEndMusicProcess) | high | temporary bridge GainNode in P3; migrate to bus/voice crossfade in P4; regression test |
558
+ | `cancelAndHoldAtTime` absent in Firefox | high | D1 feature-detect + portable fallback + test the fallback |
559
+ | One-shot leak on asset 404 | high | D2 max-lifetime timeout + release-on-failure sentinel |
560
+ | Per-voice HRTF cost regression on multi-track emitters | high | D4 panner per-instance, shared across leaf voices |
561
+ | Voice stealing silences sounds the old "play everything" engine played | med | default limits a no-op; stealing opt-in; measure densest scene first |
562
+ | Scheduler/virtualization regresses loop sync or clicks | med | one fade primitive; absolute `when` off `currentTime`; revive-phase tests |
563
+ | New ser/de drifts from conventions | med | D8 model on object adapter; version 0 + day-1 upgrader plan; P0 round-trip specs |
564
+ | Uniform-flow flatten changes resolved gain/bus vs legacy | med | resolve once at instance creation; assert resolved bus/gain/pitch in tests |
565
+ | Duplicate `audio` loader registration crash | low | D7 single owner |
566
+ | `track.time` becomes dead state, breaks readers | med | write `track.time` back from the live cursor each frame |
567
+ | Scope creep (reverb/ducking/snapshots in v1) | med | hard v1 line = spine + facades; ship effects[]/sends[] data shape only |
568
+
569
+ ---
570
+
571
+ ## 12. Decisions
572
+
573
+ **Locked by the owner:**
574
+ 1. **Migration aggressiveness — Facade-first strangler.** One renderer always; `SoundEmitter`/
575
+ `createSound`/channels become translators; sites migrate post-cut-over.
576
+ 2. **v1 scope — Spine + bus inserts.** Spine (split + buses + scheduler + voice manager + params +
577
+ random/sequence + spatialization + facades) **plus live EQ/Compressor insert effects on buses**
578
+ (`BiquadFilterNode` / `DynamicsCompressorNode`). Reverb sends / ducking / snapshots remain
579
+ P4 (banks dropped — see §9). (See D10 for the effect hierarchy and where it lands.)
580
+ 3. **Random/Switch selection — Network-deterministic.** Seed `seededRandom` from a replicated source
581
+ (entity id + `fixedStepTick`); selection is sampled where the fixed tick is stable (see D5).
582
+
583
+ **Still the owner's call (defaults assumed; revisit any time):**
584
+ 4. **`SoundEmitter` endgame** — assume **keep as a frozen compat reader** through P3/P4; delete only
585
+ after full migration + a tested save-translation path. Removing a frozen ~80-line adapter is low value.
586
+ 5. **Voice budget defaults** — assume **high/no-op defaults + opt-in stealing**, measured in the
587
+ densest scene before enabling.
588
+ 6. **Bus tree source of truth** — assume **both**: code-seeded legacy default (1.2/0.1) overridable by
589
+ serialized scene data.
590
+
591
+ ---
592
+
593
+ ## 13. FMOD/Wwise concept → sopra coverage
594
+
595
+ **v1 (core):** definition/instance split · nestable bus tree · **bus insert effects (EQ/Compressor)** ·
596
+ lookahead scheduler · parameters/RTPC + automation curves · voice manager
597
+ (limits/priority/stealing/virtualization) · random + sequence containers · custom 3D attenuation
598
+ curves · one-shot vs persistent · pitch/gain randomization · gapless loop regions
599
+ (`loopStart/loopEnd`).
600
+
601
+ **P4 / deferred (important):** ~~banks~~ (DROPPED — ECS data model covers it) ·
602
+ ~~snapshots/mixer-states~~ **DONE** · ~~blend + switch containers (fold in `material/`)~~ **DONE** ·
603
+ ~~reverb sends (`ConvolverNode`)~~ **DONE** · ~~emulated ducking~~ **DONE** · additional insert effects
604
+ (occlusion lowpass / `WaveShaper`).
605
+
606
+ **Nice-to-have:** scatterer/multi-spawn ambience · `AudioWorklet` (true sidechain + accurate meters)
607
+ · `AnalyserNode` dev meters · `OfflineAudioContext` baking · adaptive-music timeline
608
+ (transitions/stingers/sustain points).
609
+
610
+ ---
611
+
612
+ ## 14. P3 detailed integration sub-plan — route `SoundEmitter` through sopra (real, not a veneer)
613
+
614
+ Goal: the legacy `SoundEmitter` path genuinely renders through sopra. We do **not** keep 100%
615
+ back-compat; instead we **deprecate-and-plumb** — the old public API stays as `@deprecated` members
616
+ that translate into sopra (so call sites are unchanged), and is removed later. Where plumbing reaches
617
+ private state, we rewrite the call site.
618
+
619
+ ### 14.1 Architecture — strangler at the existing spine
620
+ `SoundEmitterSystem` is already the seam: it owns `this.sopra` and ticks `sopra.setListener` +
621
+ `sopra.update` each frame (currently inert). Translation happens **there, at link time** — no new
622
+ system. Per-entity runtime state lives in the (gutted) `SoundEmitterComponentContext`, repurposed from
623
+ a WebAudio renderer into a **translation record**.
624
+
625
+ - **link(emitter,transform,entity)** (sopra branch): translate the emitter to sopra
626
+ `EventDescription`s and `playEvent` a persistent `EventInstance` per persistent/looping track; store
627
+ them in a per-entity `Map<SoundTrack, EventInstance>`.
628
+ - **tracks.on.added / on.removed** stay the hook: added → `playEvent` a new instance; removed →
629
+ `instance.stop()`. Preserves the live-mutation idiom (`SoundController`, `CombatEndMusicProcess`,
630
+ `injectMusic`, `StoryManager`).
631
+ - **emitter.volume.onChanged** → `instance.setGainDb(volume2dB(v))`; **setVolumeOverTime /
632
+ fadeOutAllTracks** → `instance.fadeToGainDb` / `instance.fadeOutAndStop`.
633
+ - **update()**: push `transform.position` into each owned instance (sopra already does distance
634
+ attenuation + panner + virtualization). The BVH stays as a cheap **far-cull pre-gate**.
635
+ - **unlink** → stop all the entity's instances.
636
+ - **createSound** (+ ~9 one-shot sites) → `sopra.playOneShot`, via a kept `@deprecated` facade that
637
+ still returns a destroyable `Entity` (so handle-dependent callers are unchanged) and wires
638
+ `instance.onEnded → builder.destroy`.
639
+
640
+ **Component model:** `SoundEmitter`/`SoundTrack` are **kept as `@deprecated` data components**,
641
+ translated at link time — lowest churn (editor, serialization adapters, `GameClassRegistry`, the 8
642
+ `fromJSON` sites all keep working). No `SopraEmitter` component in v1. **One persistent `SoundTrack` →
643
+ one `EventInstance`** (both already own an independent playhead/gain/loop/ended-signal); the emitter
644
+ maps to a *set* of instances reconciled via the existing `on.added/on.removed` signals.
645
+
646
+ ### 14.2 Sopra gaps to fill first (engine-only, ECS-untouched)
647
+ The engine is fire-and-forget today (content frozen at `#resolve`, no live gain/fade/seek; 2D voices
648
+ route straight to the bus). Add the **live-control surface** without making content mutable:
649
+ 1. **`EventInstance` `#instanceGain`** — one always-on trim gain that *all* voices route through
650
+ (uniform 2D/3D chain head: `instanceGain → [panner if 3D] → bus`). Parity with the legacy
651
+ `nodes.volume`, not new cost. *(do first)*
652
+ 2. **`EventInstance.setGainDb(db)` / `get gainDb`** — composes with `#attenuationGain` (separate node)
653
+ so user volume × attenuation multiply.
654
+ 3. **`EventInstance.fadeToGainDb(target,dur,startAfter)` + public `fadeOutAndStop(dur,startAfter)`** —
655
+ refactor `fadeOutAndStop.js` into a shared `rampGain` helper; stop scheduled via an audio-clock
656
+ deadline checked in `update()` (not `setTimeout`).
657
+ 4. **`EventInstance.seek(seconds)` / `restart()`** — re-base `startedAt`, retire live voices so
658
+ `#evaluate` respawns at the new offset; **must not** reseed `playbackContext` (preserve avoid-repeat
659
+ determinism).
660
+ 5. **`SopraEngine.crossfade(oldInstance, idOrDesc, opts)`** — start new at epsilon, ramp up while
661
+ `old.fadeOutAndStop`.
662
+ 6. **Pure translators** in `sopra/legacy/`: `soundEmitterToEventDescriptions(emitter)` +
663
+ `attenuationFunctionToCurve(fn,min,max)` (dispatch `SoundAttenuationFunction` →
664
+ `interpolate_irradiance_*` → `buildAttenuationCurve`; `Attenuation` flag clear → flat-1 curve;
665
+ `is3D ← Spatialization`; `SoundPanningModelType → SopraPanningModel`).
666
+
667
+ **Gain composition rule (as built):** the translator bakes **NO** gain (`description.gainDb = 0`); the
668
+ per-instance `#instanceGain` carries the full live product `volume2dB(emitter.volume × track.volume)`,
669
+ re-applied on `emitter.volume.onChanged` and on a live `track.volume` set (via the track's
670
+ `__soundRuntime` back-ref); the **bus** carries the channel mix (the legacy 1.2/0.1 already lives on
671
+ sopra buses). Baking the product into the description *and* the instance gain would double-count — so
672
+ the description carries none.
673
+
674
+ ### 14.3 Phased sequence (bottom-up; the 47 sopra tests + 2 legacy specs stay green throughout)
675
+ - **P3.2 — live-control primitives** *(risk: med)*: `#instanceGain`, `setGainDb`, `fadeToGainDb` +
676
+ public `fadeOutAndStop`, `seek`/`restart`, `SopraEngine.crossfade` + unit tests.
677
+ - **P3.3 — pure translators** *(low)*: `soundEmitterToEventDescriptions` + `attenuationFunctionToCurve`
678
+ + unit tests (curves match `interpolate_irradiance_*` at sampled distances); not yet wired.
679
+ - **P3.4 — one-shots** *(med)*: `GameSounds` → registered `EventDescription`s; `createSound` facade →
680
+ `playOneShot` returning a destroyable Entity; legacy path kept when sopra unreachable.
681
+ - **P3.5 — persistent-emitter spine** *(high)*: rewire `SoundEmitterSystem.link` + gut
682
+ `SoundEmitterComponentContext` to a translation record; plumb volume/fade/stop; BVH far-cull kept;
683
+ `get/setChannelVolume` → bus proxies.
684
+ - **P3.6 — hard live-mutation sites** *(med)*: `CombatEndMusicProcess.switchMusic` → `sopra.crossfade`;
685
+ `resetSoundEmitterTracks` → `restart()`; verify `SoundController`/`injectMusic`/`StoryManager` via the
686
+ add/remove plumb.
687
+ - **P3.7 — listener convergence + cleanup** *(med)*: single sopra listener feeder; `@deprecated` JSDoc;
688
+ delete dead WebAudio in the sopra branch.
689
+
690
+ ### 14.4 Deletions vs retained-`@deprecated`
691
+ - **Delete now (sopra branch):** `SoundEmitter.buildNodes`/`nodes`/`getTargetNode`/
692
+ `writeAttenuationVolume`/panner-half of `updatePosition`; `SoundEmitterComponentContext` WebAudio
693
+ body (connect/disconnect/suspend/resume); `SoundTrack.start`/`suspend`/`nodes`/`SoundTrackNodes`;
694
+ the per-track time-advance + `endTrack` loop; `CombatEndMusicProcess` hand-rolled crossfade;
695
+ `resetSoundEmitterTracks` `time=0` body.
696
+ - **Retain `@deprecated`:** `SoundEmitter` + serializable fields, `SoundTrack`, `GameSounds` constants,
697
+ `SoundEmitterChannel`/`channels` (editor dropdown), `get/setChannelVolume`, `fadeOutAllTracks`/
698
+ `stopAllTracks`, `createSound`, `SoundController`/`System`, **both serialization adapters**
699
+ (save-compat — never delete at cutover).
700
+ - **Later (dedicated change):** remove the `sopra === null` legacy WebAudio fallback once prototypes
701
+ are sound-free or sopra-capable; then retire `SoundEmitter` for a native sopra component.
702
+
703
+ ### 14.5 Testing & risks
704
+ Black-box only; existing 47 sopra tests + `SoundEmitterSystem.spec` + `SoundEmitterSerializationAdapter.spec`
705
+ (both exercise the `sopra === null` path) stay green every phase. New coverage per phase via
706
+ `MockAudioContext` + `StubBufferProvider`. **Not unit-testable** (verify in-browser): AudioContext
707
+ bootstrap, autoplay-resume, audible result, dat.gui editor.
708
+
709
+ Top risks: **save-compat** (keep both adapters round-tripping — high); **gain composition** double-fold
710
+ (one rule, dB↔linear round-trip test — med); **createSound handle** (return a real Entity that stops
711
+ its instance on destroy — med); **`#instanceGain` topology change** perturbing the 47 tests (unity gain,
712
+ re-run suite immediately — med); **`seek` reseeding RNG** (must not — med).
713
+
714
+ ### 14.6 Open decisions (recommendations in **bold**)
715
+ 1. Music crossfade ownership → **keep `CombatEndMusicProcess` locating the music emitter + calling
716
+ `sopra.crossfade`** (a `MusicDirector` is later scope).
717
+ 2. Prototypes → **keep the `sopra === null` branch** through P3 (strangler safety net); delete later.
718
+ 3. `createSound` return → **real `Entity`** (callers unchanged); revisit only if the UI-click path shows cost.
719
+ 4. Per-track volume fold → **`description.gainDb` per instance + `#instanceGain` for live volume**.
720
+ 5. `resetSoundEmitterTracks` → **`restart()`** (not stop+replay — preserves RNG/loading).
721
+ 6. `SoundController` → **keep the add/remove plumb** in v1 (single consumer: `UnitMaker`).
722
+
723
+ ### 14.7 LOCKED API contract + no-switch refinement (owner-directed; supersedes the above where they differ)
724
+
725
+ **No switch.** There is no `sopra === null` fallback. `SoundEmitterSystem` ALWAYS routes through sopra.
726
+ Constructor becomes `SoundEmitterSystem(assetManager, soundEngine)` (context/destination derived from
727
+ it; it always `createSopra`s). All 11 construction sites pass the `SoundEngine` (the 10 prototypes/
728
+ `testEffect` pass `sound`/`engine.sound`; the unit spec passes a `MockAudioContext`-backed stub whose
729
+ `createSopra` builds a real `SopraEngine` on the mock + a `StubBufferProvider`). The legacy WebAudio
730
+ renderer is **deleted outright**, not guarded: per-track time-advance loop, `SoundTrackNodes`,
731
+ connect/disconnect virtualization, the channel `GainNode`s, `buildNodes`. (The two background-added
732
+ `SoundEmitterSystem.spec` tests cover that deleted loop and are replaced by sopra-routing tests.)
733
+
734
+ **Preserved public API — the whole contract. Everything else is removed or throws.**
735
+
736
+ `SoundEmitter`:
737
+
738
+ | member | plumbing into sopra |
739
+ |---|---|
740
+ | `tracks` (List) | add → `playEvent` + map; remove → `instance.stop()`; reconciled via `tracks.on.added/removed` |
741
+ | `channel` (string) | `EventDescription.busId` (read at translation; `""` → `effects`) |
742
+ | `volume` (Vector1) | `onChanged` → each owned `instance.setGainDb(volume2dB(emitter.volume × track.volume))` |
743
+ | `flags` | `Spatialization` → `is3D`; `Attenuation` → attenuation curve (read at translation) |
744
+ | `distanceMin` / `distanceMax` | `EventDescription.distanceMin/Max` |
745
+
746
+ `SoundTrack`:
747
+
748
+ | member | plumbing into sopra |
749
+ |---|---|
750
+ | `on.ended` (`{ended:Signal}`) | the track's `EventInstance.onEnded` → `on.ended.send1(track)` |
751
+ | `flags` | `Loop` → `clip.loop`; `UsingAliasURL` → `clip.usingAlias`; `StartWhenReady` → autoplay |
752
+ | `volume` (number) | NOT baked at translation; carried live in the owning instance gain (`emitter.volume × track.volume`), re-applied on a live set via `__soundRuntime` |
753
+ | `time` (number) | written back from the instance playhead each frame; rewind via `restart()` (used by `resetSoundEmitterTracks`) |
754
+ | `url` (string) | `SampleAudioClip.url` |
755
+
756
+ **Node access → fail loud, explicitly NOT public API** (as built). The property getters
757
+ `SoundEmitter.nodes` and `SoundTrack.nodes`, plus `SoundTrack.setVolumeOverTime`, are throwing stubs
758
+ (`get nodes() { throw new Error("... sopra owns the audio graph"); }`) — these are the members external
759
+ code could read. The internal builders that had **no external caller** (`buildNodes` / `getTargetNode` /
760
+ `writeAttenuationVolume` / `start` / `suspend` / `initializeNodes`) and the `SoundTrackNodes` class were
761
+ removed outright. Any straggler (e.g. `CombatEndMusicProcess` reaching `track.nodes.volume.gain`) breaks
762
+ loudly → rewritten (it now uses `fadeOutAllTracks(1)` + `tracks.add`).
763
+
764
+ **Kept as trivial `@deprecated` plumbing** (not in the contract, but behavioral with real callers, 1:1
765
+ to instance ops): `SoundEmitter.fadeOutAllTracks` → `instance.fadeOutAndStop` per owned instance;
766
+ `stopAllTracks` → owner `stopAll`. (Backs `hideEntityGracefully` / `AnimatedActions` unchanged.)
767
+
768
+ **Kept for save-compat (data only, unchanged):** both serialization adapters + the component's
769
+ serializable fields, including `isPositioned` (a thin `flags` wrapper retained for the editor +
770
+ serialization). **Removed entirely** (callers migrated): the `SoundEmitterComponentContext` WebAudio
771
+ body (gutted to a translation record), `endTrack`, `distanceRolloff`, the dead-but-unwritten
772
+ `SoundTrack.duration` (dropped from the locked surface), and the rest of the non-contract surface.
773
+
774
+ This also resolves §14.6 #2 (no `sopra === null` branch) and revises §14.4 (the node members move from
775
+ "retained @deprecated" to "throwing stubs"; there is no legacy fallback to retain).
776
+
777
+ ## 15. P5 — spatial scaling to 100k emitters (BVH broadphase + live/dormant split)
778
+
779
+ **Goal.** Support ~100,000 registered 3D `AudioEmitter`s with per-frame work and WebAudio node count
780
+ bounded by a small audible budget `K`, **not** by the registered count. The fix is to decouple a
781
+ *registered emitter* (cheap data + one BVH leaf) from a *live `EventInstance`* (WebAudio nodes): only
782
+ emitters whose own audible sphere reaches the listener — capped to `K` — are ever live.
783
+
784
+ ### 15.1 Principle — broadphase / narrowphase (mirrors `PhysicsSystem`)
785
+ - **Broadphase (new, cheap, ALL emitters):** a dynamic BVH of emitter audible-spheres; one point query
786
+ at the listener returns the emitters that *can possibly* be heard.
787
+ - **Narrowphase (existing, ≤K live):** the current `EventInstance` per-frame exact
788
+ distance/attenuation + virtualization (`virtualThresholdDb`) decides which live instances actually
789
+ hold a source `Voice`. Unchanged.
790
+
791
+ ### 15.2 Three tiers
792
+
793
+ | Tier | Count (island) | Cost each | Where |
794
+ |---|---|---|---|
795
+ | **Registered / dormant** | ~100k | 1 record + 1 BVH leaf — **no `EventInstance`, no nodes, no per-frame update** | `SpatialAudioIndex` |
796
+ | **Live** | ≤ `K` (default **64**) | an `EventInstance` (panner chain), ticked each frame | sopra + the live set |
797
+ | **Audible voice** | ≤ K, usually fewer | a `Voice` (source node) | existing virtualization |
798
+
799
+ ### 15.3 Reuse (this layer is thin — the BVH does the heavy lifting)
800
+ - `core/bvh2/bvh3/BVH.js` + **`BvhClient`** (`link(tree,data)`/`unlink()`/`resize(x0..z1)`/`write_bounds`)
801
+ — one leaf per emitter; the same per-entity handle `RenderSystem`/`PhysicsSystem` already use.
802
+ - `bvh_query_user_data_generic(out, 0, bvh, bvh.root, BVHQueryIntersectsSphere.from([lx,ly,lz, 0]))` —
803
+ the per-frame cull (point-in-leaf collect). `bvh_query_user_data_nearest_to_point` available if a
804
+ nearest-N selector is preferred over collect-then-select.
805
+ - Existing `EventInstance` virtualization / `seek` / `fadeOutAndStop`, the `VOICE_POOL`, and
806
+ `SoundListener`+`Transform` — all unchanged.
807
+
808
+ ### 15.4 Key trick — leaf AABB = the emitter's OWN audible region (no global radius — owner-locked)
809
+ Each emitter's leaf is sized to its audible sphere: `AABB = position ± event.distanceMax`. The cull is
810
+ then a **point query at the listener**, returning exactly the emitters whose `distanceMax` reaches the
811
+ listener — honoring each emitter's own range, with no hardcoded global radius.
812
+
813
+ ### 15.5 Reactive leaf maintenance (NO per-tick iteration — owner-locked)
814
+ Everything in meep is dynamic; there is **no static/dynamic flag and no per-tick refit loop**. On
815
+ `add`, the leaf subscribes to the emitter's `transform.position.onChanged` (the position channel of
816
+ `Transform.subscribe`); the handler does `bvhClient.resize(position ± distanceMax)`. Unsubscribe on
817
+ `remove`. Cost is proportional to *actual movement*, not emitter count: a forest of still trees refits
818
+ zero leaves/frame; 100k handlers that never fire are just memory. (Live instances separately read the
819
+ shared `position` Vector3 each frame for their panner — but only ≤K of those exist.)
820
+
821
+ ### 15.6 `SpatialAudioIndex` + `LiveEmitterSet` (two thin pieces) [as-built — the sketch's single class split in two]
822
+ - **`SpatialAudioIndex`** (cull-only): owns the emitter `BVH` + records `{ entity, event, position,
823
+ bvhClient, onMove }`.
824
+ - `add(entity, event, position)` → record + `bvhClient.link(bvh, entity)` (leaf user_data = the entity
825
+ id, so queries return entity ids) + `resize(pos ± distanceMax)` + subscribe `position.onChanged`.
826
+ - `remove(entity)` → unsubscribe + `bvhClient.unlink()` + drop the record.
827
+ - `queryAudible(out, out_offset, listenerPosition)` → writes candidate entity ids into the caller's
828
+ reused buffer from `out_offset`, returns the match count (allocation-free; meep out-buffer convention).
829
+ - **`LiveEmitterSet`** (the live/dormant lifecycle): wraps the index; owns the live map
830
+ `{ entity → EventInstance }` + per-emitter records `{ event, position, gainDb, playingSince }`; config
831
+ `{ budget = 64, liveStickiness = 0.8, fadeOutSeconds = 0.15 }`.
832
+ - `add(entity, event, position, gainDb)` → register with the index + record (dormant).
833
+ - `remove(entity)` → demote (hard cut) if live, then `index.remove`.
834
+ - `setGainDb(entity, gainDb)` → update the record + the live instance if any (survives re-promotion).
835
+ - `refresh(listenerPosition)` → cull + budget + diff, **every tick** (§15.7).
836
+
837
+ Non-3D emitters (and finite-3D one-shots) skip the index entirely — the ECS layer plays them directly
838
+ (§15.13 P5.6); only persistent looping 3D emitters are spatially managed.
839
+
840
+ ### 15.7 `LiveEmitterSet.refresh` — every tick [as-built]
841
+ 1. **Cull:** `queryAudible` point query → candidate entity ids (reused buffer); an exact spherical
842
+ refine then drops the conservative-cube corners (`distance > distanceMax`).
843
+ 2. **Budget select:** rank in-range candidates by **effective distance** — a live emitter competes as
844
+ `distance × liveStickiness` so it does not flicker promote/demote at the cutoff (rank hysteresis) —
845
+ and take the nearest `budget`. (The sketch's extra `event.priority` / attenuation-gain tie-breakers
846
+ were not needed; pure distance + stickiness.)
847
+ 3. **Diff** vs the current live set (`#live`) → **demote** leavers, **promote** entrants; at budget a
848
+ closer entrant steals the farthest live slot. The diff is re-derived from `#live` each call (so a
849
+ denied or self-ended promotion is retried automatically), with demote-before-promote ordering.
850
+ 4. `sopra.update(now)` — the caller's, right after `refresh` — ticks only the ≤budget live instances.
851
+
852
+ **No throttle (§15.10):** this runs on every tick. The BVH query is microseconds and the diff is
853
+ re-derived from `#live`, so there is nothing to gate; the scratch containers are reused so the per-tick
854
+ diff is allocation-light apart from the rank entries.
855
+
856
+ ### 15.8 Promotion / demotion + voice slots (allocated at go-live — owner-confirmed)
857
+ `K` is the voice-slot pool, allocated at promotion (the only moment WebAudio cost is incurred).
858
+ - **promote:** `sopra.playEvent(event, { position, oneShot, startTime })` where `startTime = playingSince`
859
+ reconstructs the phase (§15.9 — via the `EventInstance.startTime` option, not a post-hoc `seek`), then
860
+ apply the emitter's `gainDb`, then store the instance.
861
+ - **demote — two cases (owner-locked):**
862
+ - **culled out of range** (the emitter left its own audible sphere → already ~0 gain / virtual):
863
+ **hard cut** (`instance.stop()`). A fade is pointless/wrong — it is already inaudible.
864
+ - **contention / stolen** (a closer emitter evicts a still-in-range, audible live one): **fade**
865
+ (`fadeOutAndStop`) to avoid a click.
866
+ - **stealing = distance priority:** at budget, a closer entrant demotes (steals the slot of) the
867
+ farthest live record.
868
+
869
+ This sits *on top of*, not replacing, sopra's per-event `maxInstances` (polyphony among the live) and
870
+ per-instance virtualization (source-voice gating). **Constraint (P5.2):** `budget` and `maxInstances`
871
+ are independent composed caps. For content-equal ambience you want up to N copies of audible at once,
872
+ that event's `maxInstances` must be ≥ N, else sopra gates the budget — `stealMode None` denies the
873
+ promote (emitter stays dormant, retried next refresh) and `stealMode Oldest` makes the two layers fight
874
+ (churn). Set managed ambience `maxInstances` high (P5.6 wiring).
875
+
876
+ ### 15.9 Phase reconstruction (continuous world clock — owner-decided; supersedes the entity-id phaseOffset idea)
877
+ Dormant emitters don't simulate playback, but the loop conceptually keeps running on the world clock.
878
+ Record `playingSince` (audio clock) **once at registration**; on promotion the instance starts with
879
+ logical `startTime = playingSince`, so its playhead is `now − playingSince` and the looping voice's
880
+ buffer offset wraps into the loop region. A bird you approach is mid-song (continuity); a re-promotion
881
+ after a cull resumes at **total elapsed since link** (the loop kept running while you were away).
882
+ Deterministic from real time — **no engine-invented random phase**. Decorrelation/variety is the content
883
+ author's job (existing per-trigger pitch/gain randomization, RandomContainer), not an engine concern.
884
+ (Rejected the earlier auto entity-id phaseOffset: opinionated/magic, and for sparse chirps the artifact
885
+ is imperceptible; phase-lock matters mainly for tonal loops, which the author can vary.)
886
+
887
+ ### 15.10 Churn control (promotion has real cost)
888
+ - **Hysteresis (as-built):** rank hysteresis via `liveStickiness` — a live emitter competes at
889
+ `distance × liveStickiness` (default 0.8), so a newcomer must be clearly closer to steal its slot; this
890
+ kills promote/demote flicker at the budget cutoff. (The sketch's leaf-AABB / `distanceMax + margin`
891
+ approach was not needed — range-edge churn is inaudible, gain ≈ 0 there; the audible flicker is at the
892
+ *budget* cutoff, which the rank discount handles.) Demote-by-cull is at exactly `distanceMax` (the
893
+ spherical refine).
894
+ - **Cull every tick — NO throttling (owner-decided, P5.5 reverted).** `refresh()` runs the full cull
895
+ on every `update` tick. The BVH point-query is O(log n + candidates) (microseconds; the 100k stress
896
+ shows the whole per-frame `refresh + tick` is ~5 ms), and the promote/demote diff is re-derived from
897
+ `#live` each call, so there is no reason to throttle. A throttle was briefly added and removed — it was
898
+ unnecessary complexity (and introduced a contention-fade gap edge). The diff is allocation-light: the
899
+ scratch containers (`#ranked`, `#inRange`, `#target`, `#demoteScratch`, `#candidates`) are reused
900
+ across calls. (`IncrementalDeltaSet` was considered for the diff but does not fit: `#live` changes
901
+ out-of-band — instances self-end on asset failure, and promotions can be denied by polyphony caps — so
902
+ the diff must be re-derived from `#live` each frame, which a maintained delta set would fight.)
903
+ - **Pool the per-instance output chain** (instanceGain → attenuationGain → panner) — **DEFERRED
904
+ (measure-first).** Original rationale was the "1000 live panners / panner not torn down on virtualize"
905
+ cost; the P5.1–P5.2 live/dormant model already bounds live panner chains to `budget` (≤64), and
906
+ hysteresis minimises promote/demote frequency, so this is now a constant-factor micro-opt on ≤64
907
+ chains churned only on genuine live-set changes. Per project guidance (reuse-over-micro-opt, measure
908
+ first, treat constant-factor diffs as noise) this is held until profiling shows promote/demote
909
+ node-churn is actually hot. AudioBufferSourceNodes are single-use and stay pooled via `VOICE_POOL`;
910
+ only Gain/Panner nodes would be poolable.
911
+
912
+ ### 15.11 What changes where
913
+ - `SopraEngine` core: **unchanged**; its `update` is now O(K) (only live instances are active). No new
914
+ public surface (`playEvent`/`stop`/`seek` exist).
915
+ - **New `SpatialAudioIndex`** (BVH cull + records, thin over the BVH + queries) and **`LiveEmitterSet`**
916
+ (the live/dormant lifecycle: budget + promote/demote/steal + per-emitter gain) layered on it.
917
+ - `LiveEmitterSet.refresh` culls every tick (no throttling — §15.10), with reused scratch so the diff is
918
+ allocation-light. The per-instance output-chain pool is **deferred** (measure-first — §15.10): not
919
+ needed for the 100k target since live chains are already bounded to `budget`.
920
+ - `AudioEmitterSystem` (DONE, P5.6): `link/unlink` → `liveSet.add/remove` for managed (looping 3D
921
+ autoplay) emitters; `update` → `liveSet.refresh(listener)` + `sopra.update`. 2D + finite-3D-one-shot
922
+ autoplay take the direct play path; non-autoplay is inert. No more unconditional autoplay-per-emitter.
923
+ - `AudioEmitter`: **no** `dynamic` flag. `VoiceManager`: unchanged.
924
+
925
+ ### 15.12 Scorecard (target, 100k emitters)
926
+ - Per frame: 1 BVH point query (O(log n + candidates)) + top-K select + O(K) live ticks. **Independent
927
+ of 100k.**
928
+ - WebAudio: ≤K panner chains + ≤K voices.
929
+ - Memory: 100k records + 100k BVH leaves (~a few MB, typed-array backed) + shared events/buffers. Leaf
930
+ refits ∝ movement, not count.
931
+
932
+ ### 15.13 Rollout (incremental, test-first; MockAudioContext + synthetic emitter field + movable mock listener)
933
+ - **P5.1 — DONE** (meep `73f9becc1`). `SpatialAudioIndex` (`engine/sound/ecs/audio/SpatialAudioIndex.js`)
934
+ cull only: BVH add/remove + reactive `position.onChanged` refit + point query (`BVHQueryIntersectsSphere`
935
+ radius 0) → candidate entity ids; leaf user_data = entity id; leaf AABB = `position ± distanceMax`;
936
+ reused query object + result buffer. 12 black-box tests (in/out per-emitter range, reactive refit both
937
+ ways, removal+detach, boundary-inclusive on-axis, repeated-query buffer reuse, 1000-emitter cull). No
938
+ promotion yet.
939
+ - **P5.2 — DONE** (meep `a39ecbbe6`). `LiveEmitterSet` (`engine/sound/ecs/audio/LiveEmitterSet.js`)
940
+ composes the index: `refresh(listener)` promotes nearest-in-range up to `budget` (64), demotes the
941
+ rest; distance-priority stealing; rank hysteresis via live-stickiness; exact spherical refine over the
942
+ conservative cube; demote-frees-before-promote-fills; zombie-safe demote (delete-before-stop) + self-
943
+ end cleanup. Hard cut on demote (fade-on-contention = P5.3). Documented budget↔maxInstances
944
+ dependency + pinned by a test. 12 black-box tests.
945
+ - **P5.3 — DONE** (meep `1e0a0deee`). Demotion policy in `LiveEmitterSet`: refresh builds an `inRange`
946
+ set (exact distanceMax); a demoted live emitter still in range is faded (`fadeOutAndStop`,
947
+ `fadeOutSeconds` default 0.15) — audible, would click — while one that left range is hard-stopped
948
+ (already inaudible). `remove()` (unlink) hard-cuts. Slot frees immediately (delete-before-fade); the
949
+ onEnded `=== instance` guard makes re-promote-during-fade safe. Tests: cut-on-cull, fade-on-contention,
950
+ re-promote-during-fade no-clobber. Adversarial review → CLEAN.
951
+ - **P5.4 — DONE** (meep `ad96e3a00`). Continuous-clock phase reconstruction (see §15.9, owner-decided —
952
+ no random phaseOffset). `EventInstance` gained a logical `startTime` option (playhead = now − startTime)
953
+ + a looping-voice buffer-offset wrap (also fixes long-dormant virtualization revival).
954
+ `LiveEmitterSet` records `playingSince` once at add and promotes with it, so a re-promotion after a
955
+ cull resumes at total elapsed since link. Zombie guard for a finite event whose play time already
956
+ elapsed (self-stops synchronously during start). Tests: resume-at-elapsed + offset-wrap,
957
+ continuity-across-cull, seek-wrap, finite-elapsed guard. Adversarial review → CLEAN.
958
+ - **P5.5 — cull throttling ADDED then REVERTED** (added meep `8264bc328`, reverted later). A throttle
959
+ (`cullIntervalSeconds`/`cullMoveThreshold`) was briefly added, then removed at the owner's direction:
960
+ the BVH point-query is microseconds and the diff is re-derived from `#live` each call, so there is no
961
+ reason not to cull on every `update` tick (100k stress: ~5 ms per `refresh + tick`). What remains from
962
+ P5.5: `refresh()` culls every tick with an **allocation-light diff** — the scratch containers
963
+ (`#ranked`, `#inRange`, `#target`, `#demoteScratch`, `#candidates`) are reused across calls; the
964
+ comparator is module-static. `IncrementalDeltaSet` was considered for the diff but does not fit (`#live`
965
+ changes out-of-band: self-end on asset failure, denial by polyphony caps — the diff must re-derive from
966
+ `#live`). The +9 throttle tests were removed. **Output-chain pool still DEFERRED (measure-first)** —
967
+ see §15.10 (live/dormant already bounds panners to budget; held until profiling shows churn is hot).
968
+ - **P5.6 — DONE** (meep `d4ba84cd4`). Wired `AudioEmitterSystem` to `LiveEmitterSet`. Routing fixed at
969
+ link: **managed** = `autoplay && is3D && rootClip.loops()` → `liveSet.add(entity, event, position,
970
+ volume2dB(volume))`, dormant until refresh; **direct** = any other autoplay (2D, or finite 3D one-shot)
971
+ → immediate `#play`; **inert** = non-autoplay. (Finite 3D one-shots are deliberately direct, not
972
+ managed — a dead one-shot would otherwise re-promote+self-stop every cull and occupy a budget slot:
973
+ the P5.6 review's main RISK.) `update` resolves the `SoundListener`, then refreshes the live set BEFORE
974
+ `sopra.update` (fresh promote spatializes same frame); a listener entity missing its `Transform` is
975
+ tolerated as "no listener" (guard) rather than throwing every frame. Per-emitter gain: `AudioEmitter.volume`
976
+ carried by `LiveEmitterSet` (`add` 4th arg + `setGainDb`), replayed on every promotion (survives
977
+ demote→re-promote). `instanceFor(entity)` exposes the active instance for either path; ctor takes
978
+ `liveEmitterSetOptions`. **100k stress (both `.skip`):** `AudioEmitterSystem.spec` proves only `budget`
979
+ hold a live instance (node count O(budget), not O(N)) + listener-walks-away frees all; `SpatialAudioIndex.spec`
980
+ proves the cull returns only the in-range candidates (~200), not N → per-frame work O(log N + k). 298
981
+ engine/sound green (34 suites), 2 skipped. Adversarial workflow review (6 dims / 21 agents): no
982
+ BUG-level defects; acted on the confirmed RISKs + doc fixes.
983
+ - **Remaining (post-P5):** register `AudioEmitterSystem` in `makeMirEngineConfig` (production wiring; it
984
+ is currently constructed only in tests) and the standing background follow-ups (P5.5 output-chain pool
985
+ if profiling demands it; IR1/IR4; dormant-material cleanup).
986
+
987
+ ### 15.14 Locked decisions (owner)
988
+ - Budget **K = 64** (live instances; virtualization trims actual voices further).
989
+ - **No global radius** — cull by per-emitter `event.distanceMax` (leaf = `pos ± distanceMax`).
990
+ - **No static/dynamic distinction** — everything is dynamic; leaves refit reactively via
991
+ `transform.position.onChanged`, never per-tick iteration.
992
+ - **Demotion:** hard **cut** when culled out of range (already inaudible); **fade** only on contention
993
+ (stealing a still-audible live instance).