@woosh/meep-engine 3.2.0 → 3.4.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 (893) hide show
  1. package/editor/process/SymbolicDisplayProcess.js +106 -106
  2. package/editor/process/symbolic/{SoundEmitterSymbolicDisplay.js → AudioEmitterSymbolicDisplay.js} +67 -57
  3. package/package.json +94 -94
  4. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +110 -102
  5. package/src/avif/encoder_worker.js +5 -18
  6. package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.d.ts +54 -0
  7. package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.d.ts.map +1 -1
  8. package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.js +10 -3
  9. package/src/core/color/PQ/PQ_constants.d.ts +43 -0
  10. package/src/core/color/PQ/PQ_constants.d.ts.map +1 -0
  11. package/src/core/color/PQ/PQ_constants.js +50 -0
  12. package/src/core/color/PQ/PQ_to_linear.d.ts +24 -0
  13. package/src/core/color/PQ/PQ_to_linear.d.ts.map +1 -0
  14. package/src/core/color/PQ/PQ_to_linear.js +35 -0
  15. package/src/core/color/PQ/linear_to_PQ.d.ts +27 -0
  16. package/src/core/color/PQ/linear_to_PQ.d.ts.map +1 -0
  17. package/src/core/color/PQ/linear_to_PQ.js +32 -0
  18. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_other_face.d.ts +32 -0
  19. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_other_face.d.ts.map +1 -0
  20. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_other_face.js +59 -0
  21. package/src/core/geom/3d/topology/struct/binary/query/bt_face_third_vertex.d.ts +26 -0
  22. package/src/core/geom/3d/topology/struct/binary/query/bt_face_third_vertex.d.ts.map +1 -0
  23. package/src/core/geom/3d/topology/struct/binary/query/bt_face_third_vertex.js +55 -0
  24. package/src/engine/EntityCreator.d.ts +19 -11
  25. package/src/engine/EntityCreator.d.ts.map +1 -1
  26. package/src/engine/EntityCreator.js +116 -94
  27. package/src/engine/achievements/AchievementManager.d.ts.map +1 -1
  28. package/src/engine/achievements/AchievementManager.js +437 -433
  29. package/src/engine/animation/AnimatedActions.d.ts +6 -1
  30. package/src/engine/animation/AnimatedActions.d.ts.map +1 -1
  31. package/src/engine/animation/AnimatedActions.js +111 -81
  32. package/src/engine/animation/AnimationUtils.d.ts.map +1 -1
  33. package/src/engine/animation/AnimationUtils.js +234 -252
  34. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +275 -269
  35. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  36. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +290 -265
  37. package/src/engine/ecs/util/hideEntityGracefully.d.ts.map +1 -1
  38. package/src/engine/ecs/util/hideEntityGracefully.js +196 -208
  39. package/src/engine/graphics3/VolumetricLightMap.d.ts +90 -0
  40. package/src/engine/graphics3/VolumetricLightMap.d.ts.map +1 -0
  41. package/src/engine/graphics3/VolumetricLightMap.js +160 -0
  42. package/src/engine/graphics3/VolumetricLightMapSerializationAdapter.d.ts +32 -0
  43. package/src/engine/graphics3/VolumetricLightMapSerializationAdapter.d.ts.map +1 -0
  44. package/src/engine/graphics3/VolumetricLightMapSerializationAdapter.js +67 -0
  45. package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts +98 -0
  46. package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts.map +1 -0
  47. package/src/engine/graphics3/VolumetricLightMapSystem3.js +261 -0
  48. package/src/engine/intelligence/behavior/primitive/ActionBehavior.d.ts +3 -1
  49. package/src/engine/intelligence/behavior/primitive/ActionBehavior.d.ts.map +1 -1
  50. package/src/engine/intelligence/behavior/primitive/ActionBehavior.js +4 -2
  51. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  52. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +536 -0
  53. package/src/engine/sound/SoundEngine.d.ts +2 -2
  54. package/src/engine/sound/SoundEngine.js +124 -124
  55. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts +20 -0
  56. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
  57. package/src/engine/sound/ecs/audio/AudioEmitter.js +25 -2
  58. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +6 -6
  59. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -1
  60. package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +338 -314
  61. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts +143 -0
  62. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -0
  63. package/src/engine/sound/ecs/trigger/AudioEventTrigger.js +191 -0
  64. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.d.ts +33 -0
  65. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.d.ts.map +1 -0
  66. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.js +81 -0
  67. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts +65 -0
  68. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts.map +1 -0
  69. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.js +184 -0
  70. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +999 -993
  71. package/src/engine/sound/sopra/README.md +644 -643
  72. package/src/engine/sound/sopra/SopraEngine.d.ts +2 -2
  73. package/src/engine/sound/sopra/SopraEngine.js +432 -432
  74. package/src/engine/sound/sopra/legacy/SoundAttenuationFunction.d.ts.map +1 -0
  75. package/src/engine/sound/{ecs → sopra/legacy}/SoundController.d.ts +3 -3
  76. package/src/engine/sound/sopra/legacy/SoundController.d.ts.map +1 -0
  77. package/src/engine/sound/{ecs → sopra/legacy}/SoundController.js +176 -176
  78. package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitter.d.ts +11 -27
  79. package/src/engine/sound/sopra/legacy/SoundEmitter.d.ts.map +1 -0
  80. package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitter.js +352 -382
  81. package/src/engine/sound/sopra/legacy/SoundEmitterFlags.d.ts.map +1 -0
  82. package/src/engine/sound/sopra/legacy/SoundEmitterSerializationAdapter.d.ts.map +1 -0
  83. package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationUpgrader_0_1.d.ts.map +1 -1
  84. package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationUpgrader_1_2.d.ts.map +1 -1
  85. package/src/engine/sound/sopra/legacy/SoundPanningModelType.d.ts.map +1 -0
  86. package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundTrack.d.ts +11 -55
  87. package/src/engine/sound/sopra/legacy/SoundTrack.d.ts.map +1 -0
  88. package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundTrack.js +278 -357
  89. package/src/engine/sound/sopra/legacy/SoundTrackFlags.d.ts.map +1 -0
  90. package/src/engine/sound/sopra/legacy/convertLegacySoundComponents.d.ts +34 -0
  91. package/src/engine/sound/sopra/legacy/convertLegacySoundComponents.d.ts.map +1 -0
  92. package/src/engine/sound/sopra/legacy/convertLegacySoundComponents.js +279 -0
  93. package/src/engine/sound/sopra/legacy/soundEmitterToEventDescription.d.ts +3 -3
  94. package/src/engine/sound/sopra/legacy/soundEmitterToEventDescription.d.ts.map +1 -1
  95. package/src/engine/sound/sopra/legacy/soundEmitterToEventDescription.js +122 -122
  96. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  97. package/src/shade/device/mock/SoftwareGPUDevice.js +7 -1
  98. package/src/shade/device/timing/GPUTimerArray.d.ts.map +1 -1
  99. package/src/shade/device/timing/GPUTimerArray.js +10 -0
  100. package/src/shade/playground/add_random_meshes.d.ts +19 -3
  101. package/src/shade/playground/add_random_meshes.d.ts.map +1 -1
  102. package/src/shade/playground/add_random_meshes.js +132 -84
  103. package/src/shade/playground/bvh_repro/README.md +57 -0
  104. package/src/shade/playground/bvh_repro/bvh_repro_device.d.ts +33 -0
  105. package/src/shade/playground/bvh_repro/bvh_repro_device.d.ts.map +1 -0
  106. package/src/shade/playground/bvh_repro/bvh_repro_device.js +90 -0
  107. package/src/shade/playground/bvh_repro/index.html +124 -0
  108. package/src/shade/playground/bvh_repro/main.d.ts.map +1 -0
  109. package/src/shade/playground/bvh_repro/main.js +254 -0
  110. package/src/shade/playground/load_default_environment.d.ts +10 -1
  111. package/src/shade/playground/load_default_environment.d.ts.map +1 -1
  112. package/src/shade/playground/load_default_environment.js +44 -20
  113. package/src/shade/playground/make_playground_asset_manager.d.ts +16 -0
  114. package/src/shade/playground/make_playground_asset_manager.d.ts.map +1 -0
  115. package/src/shade/playground/make_playground_asset_manager.js +33 -0
  116. package/src/shade/playground/skinned_blas_refit/README.md +103 -0
  117. package/src/shade/playground/skinned_blas_refit/add_floor.d.ts +47 -0
  118. package/src/shade/playground/skinned_blas_refit/add_floor.d.ts.map +1 -0
  119. package/src/shade/playground/skinned_blas_refit/add_floor.js +71 -0
  120. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.d.ts +28 -0
  121. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.d.ts.map +1 -0
  122. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.js +745 -0
  123. package/src/shade/playground/skinned_blas_refit/flat_environment.d.ts +30 -0
  124. package/src/shade/playground/skinned_blas_refit/flat_environment.d.ts.map +1 -0
  125. package/src/shade/playground/skinned_blas_refit/flat_environment.js +67 -0
  126. package/src/shade/playground/skinned_blas_refit/index.html +168 -0
  127. package/src/shade/playground/skinned_blas_refit/main.d.ts +8 -0
  128. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -0
  129. package/src/shade/playground/skinned_blas_refit/main.js +502 -0
  130. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +81 -0
  131. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -0
  132. package/src/shade/playground/skinned_blas_refit/place_character.js +116 -0
  133. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.d.ts +21 -0
  134. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.d.ts.map +1 -0
  135. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.js +104 -0
  136. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.d.ts +23 -0
  137. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.d.ts.map +1 -0
  138. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.js +94 -0
  139. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.d.ts +26 -0
  140. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.d.ts.map +1 -0
  141. package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.js +134 -0
  142. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts +40 -0
  143. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts.map +1 -0
  144. package/src/shade/playground/skinned_blas_refit/sweep_views.js +135 -0
  145. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.d.ts +31 -0
  146. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.d.ts.map +1 -0
  147. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.js +240 -0
  148. package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.d.ts +20 -0
  149. package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.d.ts.map +1 -0
  150. package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.js +202 -0
  151. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts +50 -0
  152. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts.map +1 -0
  153. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.js +366 -0
  154. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts +17 -0
  155. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts.map +1 -0
  156. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.js +249 -0
  157. package/src/shade/playground/sponza_path_trace/README.md +57 -0
  158. package/src/shade/playground/sponza_path_trace/index.html +164 -0
  159. package/src/shade/playground/sponza_path_trace/main.d.ts +8 -0
  160. package/src/shade/playground/sponza_path_trace/main.d.ts.map +1 -0
  161. package/src/shade/playground/sponza_path_trace/main.js +363 -0
  162. package/src/shade/renderer/Renderer.d.ts +16 -0
  163. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  164. package/src/shade/renderer/Renderer.js +23 -4
  165. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +5 -1
  166. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  167. package/src/shade/renderer/animation/GPUAnimationManager.js +28 -3
  168. package/src/shade/renderer/animation/Skin.d.ts +9 -7
  169. package/src/shade/renderer/animation/Skin.d.ts.map +1 -1
  170. package/src/shade/renderer/animation/Skin.js +9 -7
  171. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts +35 -0
  172. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts.map +1 -0
  173. package/src/shade/renderer/animation/compute_skin_world_bounds.js +146 -0
  174. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  175. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +41 -0
  176. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/GPUGeometryManager.js +65 -15
  178. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +78 -7
  179. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +302 -77
  181. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +18 -6
  182. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
  183. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +19 -6
  184. package/src/shade/renderer/geometry/bvh/bvh2_check_bounds.d.ts +51 -0
  185. package/src/shade/renderer/geometry/bvh/bvh2_check_bounds.d.ts.map +1 -0
  186. package/src/shade/renderer/geometry/bvh/bvh2_check_bounds.js +260 -0
  187. package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.d.ts +23 -0
  188. package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.d.ts.map +1 -0
  189. package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.js +82 -0
  190. package/src/shade/renderer/geometry/bvh/record_blas_refit.d.ts +25 -0
  191. package/src/shade/renderer/geometry/bvh/record_blas_refit.d.ts.map +1 -0
  192. package/src/shade/renderer/geometry/bvh/record_blas_refit.js +102 -0
  193. package/src/shade/renderer/geometry/bvh/shader_blas_refit_leaf_bounds.d.ts +30 -0
  194. package/src/shade/renderer/geometry/bvh/shader_blas_refit_leaf_bounds.d.ts.map +1 -0
  195. package/src/shade/renderer/geometry/bvh/shader_blas_refit_leaf_bounds.js +122 -0
  196. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_empty_gpu_structure.d.ts +23 -0
  197. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_empty_gpu_structure.d.ts.map +1 -0
  198. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_empty_gpu_structure.js +34 -0
  199. package/src/shade/renderer/gpu_primitive/bvh/BVH_BUFFER_LAYOUT.d.ts +55 -0
  200. package/src/shade/renderer/gpu_primitive/bvh/BVH_BUFFER_LAYOUT.d.ts.map +1 -0
  201. package/src/shade/renderer/gpu_primitive/bvh/BVH_BUFFER_LAYOUT.js +70 -0
  202. package/src/shade/renderer/gpu_primitive/bvh/BVH_BUILD_SETTINGS_STRUCT.d.ts +37 -0
  203. package/src/shade/renderer/gpu_primitive/bvh/BVH_BUILD_SETTINGS_STRUCT.d.ts.map +1 -0
  204. package/src/shade/renderer/gpu_primitive/bvh/BVH_BUILD_SETTINGS_STRUCT.js +45 -0
  205. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +1115 -0
  206. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +201 -0
  207. package/src/shade/renderer/gpu_primitive/bvh/check_bvh_structure.d.ts +88 -0
  208. package/src/shade/renderer/gpu_primitive/bvh/check_bvh_structure.d.ts.map +1 -0
  209. package/src/shade/renderer/gpu_primitive/bvh/check_bvh_structure.js +233 -0
  210. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.d.ts +18 -0
  211. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.d.ts.map +1 -0
  212. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.js +38 -0
  213. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.d.ts +16 -0
  214. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.d.ts.map +1 -0
  215. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.js +79 -0
  216. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.d.ts +16 -0
  217. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.d.ts.map +1 -0
  218. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.js +49 -0
  219. package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.d.ts +43 -0
  220. package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.d.ts.map +1 -0
  221. package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.js +217 -0
  222. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts +24 -0
  223. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts.map +1 -0
  224. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.js +143 -0
  225. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts +17 -0
  226. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts.map +1 -0
  227. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.js +83 -0
  228. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_refit.d.ts +24 -0
  229. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_refit.d.ts.map +1 -0
  230. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_refit.js +141 -0
  231. package/src/shade/renderer/gpu_primitive/bvh/verify_gpu_bvh_build.d.ts +31 -0
  232. package/src/shade/renderer/gpu_primitive/bvh/verify_gpu_bvh_build.d.ts.map +1 -0
  233. package/src/shade/renderer/gpu_primitive/bvh/verify_gpu_bvh_build.js +422 -0
  234. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  235. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +1 -2
  236. package/src/shade/renderer/gpu_primitive/sort/SORT_PASS_SETTINGS_STRUCT.d.ts +9 -0
  237. package/src/shade/renderer/gpu_primitive/sort/SORT_PASS_SETTINGS_STRUCT.d.ts.map +1 -0
  238. package/src/shade/renderer/gpu_primitive/sort/SORT_PASS_SETTINGS_STRUCT.js +23 -0
  239. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_digit.d.ts +18 -0
  240. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_digit.d.ts.map +1 -0
  241. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_digit.js +32 -0
  242. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_rank.d.ts +27 -0
  243. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_rank.d.ts.map +1 -0
  244. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_rank.js +41 -0
  245. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_workgroup_scan.d.ts +25 -0
  246. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_workgroup_scan.d.ts.map +1 -0
  247. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_workgroup_scan.js +74 -0
  248. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +71 -0
  249. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts.map +1 -0
  250. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -0
  251. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +37 -0
  252. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -0
  253. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +197 -0
  254. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.d.ts +16 -0
  255. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.d.ts.map +1 -0
  256. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.js +85 -0
  257. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.d.ts +15 -0
  258. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.d.ts.map +1 -0
  259. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.js +192 -0
  260. package/src/shade/renderer/gpu_primitive/sort/verify_radix_sort.d.ts +12 -0
  261. package/src/shade/renderer/gpu_primitive/sort/verify_radix_sort.d.ts.map +1 -0
  262. package/src/shade/renderer/gpu_primitive/sort/verify_radix_sort.js +188 -0
  263. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts +16 -4
  264. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
  265. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +235 -24
  266. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  267. package/src/shade/renderer/scene/GPUSceneContext.js +15 -3
  268. package/src/shade/renderer/scene/SkinnedMesh.d.ts +57 -11
  269. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +1 -1
  270. package/src/shade/renderer/scene/SkinnedMesh.js +111 -11
  271. package/src/shade/renderer/scene/optimization/geometry/internal/anchor_grow_topological.d.ts.map +1 -1
  272. package/src/shade/renderer/scene/optimization/geometry/internal/anchor_grow_topological.js +12 -3
  273. package/src/shade/renderer/scene/optimization/geometry/internal/match_validate_topology.js +3 -3
  274. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_window.js +3 -3
  275. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts.map +1 -1
  276. package/src/shade/renderer/scene/serialization/deserialize_scene.js +0 -2
  277. package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts +22 -0
  278. package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts.map +1 -0
  279. package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.js +145 -0
  280. package/src/shade/renderer/scene/verify_gpu_tlas_build.d.ts +18 -0
  281. package/src/shade/renderer/scene/verify_gpu_tlas_build.d.ts.map +1 -0
  282. package/src/shade/renderer/scene/verify_gpu_tlas_build.js +364 -0
  283. package/src/shade/renderer/shader/chunk/binary/chunk_split_by_3.d.ts +9 -1
  284. package/src/shade/renderer/shader/chunk/binary/chunk_split_by_3.d.ts.map +1 -1
  285. package/src/shade/renderer/shader/chunk/binary/chunk_split_by_3.js +29 -21
  286. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_v3_morton_encode.d.ts +22 -0
  287. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_v3_morton_encode.d.ts.map +1 -0
  288. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_v3_morton_encode.js +31 -0
  289. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.d.ts.map +1 -1
  290. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.js +87 -39
  291. package/src/shade/renderer/shader/chunk/geometry/format/chunk_geometry_read_triangle_bounds.d.ts +17 -0
  292. package/src/shade/renderer/shader/chunk/geometry/format/chunk_geometry_read_triangle_bounds.d.ts.map +1 -0
  293. package/src/shade/renderer/shader/chunk/geometry/format/chunk_geometry_read_triangle_bounds.js +40 -0
  294. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.d.ts +15 -0
  295. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.d.ts.map +1 -0
  296. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.js +52 -0
  297. package/src/shade/renderer/shader/chunk/geometry/ray/RAY_STRUCT.d.ts +9 -0
  298. package/src/shade/renderer/shader/chunk/geometry/ray/RAY_STRUCT.d.ts.map +1 -1
  299. package/src/shade/renderer/shader/chunk/geometry/ray/RAY_STRUCT.js +9 -0
  300. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_transform_m4.d.ts +20 -0
  301. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_transform_m4.d.ts.map +1 -1
  302. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_transform_m4.js +52 -34
  303. package/src/shade/renderer/texture/virtual/README.md +255 -276
  304. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  305. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +66 -2
  306. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  307. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +83 -0
  308. package/src/view/interaction/InterfaceCommand.d.ts +8 -8
  309. package/src/view/interaction/InterfaceCommand.d.ts.map +1 -1
  310. package/src/view/interaction/InterfaceCommand.js +146 -146
  311. package/src/view/interaction/createInterfaceCommandButton.d.ts.map +1 -1
  312. package/src/view/interaction/createInterfaceCommandButton.js +115 -124
  313. package/src/engine/ecs/components/Timer.d.ts +0 -50
  314. package/src/engine/ecs/components/Timer.d.ts.map +0 -1
  315. package/src/engine/ecs/components/Timer.js +0 -80
  316. package/src/engine/ecs/evaluation/PointFitnessBinary.d.ts +0 -22
  317. package/src/engine/ecs/evaluation/PointFitnessBinary.d.ts.map +0 -1
  318. package/src/engine/ecs/evaluation/PointFitnessBinary.js +0 -33
  319. package/src/engine/ecs/evaluation/PointFitnessConstant.d.ts +0 -12
  320. package/src/engine/ecs/evaluation/PointFitnessConstant.d.ts.map +0 -1
  321. package/src/engine/ecs/evaluation/PointFitnessConstant.js +0 -27
  322. package/src/engine/ecs/evaluation/PointFitnessFunction.d.ts +0 -17
  323. package/src/engine/ecs/evaluation/PointFitnessFunction.d.ts.map +0 -1
  324. package/src/engine/ecs/evaluation/PointFitnessFunction.js +0 -20
  325. package/src/engine/ecs/evaluation/arithmetic/PointFitnessAdd.d.ts +0 -12
  326. package/src/engine/ecs/evaluation/arithmetic/PointFitnessAdd.d.ts.map +0 -1
  327. package/src/engine/ecs/evaluation/arithmetic/PointFitnessAdd.js +0 -27
  328. package/src/engine/ecs/evaluation/arithmetic/PointFitnessMultiply.d.ts +0 -12
  329. package/src/engine/ecs/evaluation/arithmetic/PointFitnessMultiply.d.ts.map +0 -1
  330. package/src/engine/ecs/evaluation/arithmetic/PointFitnessMultiply.js +0 -28
  331. package/src/engine/ecs/evaluation/complex/PointFitnessGaussianBlur.d.ts +0 -50
  332. package/src/engine/ecs/evaluation/complex/PointFitnessGaussianBlur.d.ts.map +0 -1
  333. package/src/engine/ecs/evaluation/complex/PointFitnessGaussianBlur.js +0 -176
  334. package/src/engine/ecs/evaluation/json/deserializeFromJSON_PointFitnessFunction.d.ts +0 -7
  335. package/src/engine/ecs/evaluation/json/deserializeFromJSON_PointFitnessFunction.d.ts.map +0 -1
  336. package/src/engine/ecs/evaluation/json/deserializeFromJSON_PointFitnessFunction.js +0 -68
  337. package/src/engine/ecs/evaluation/json/serializeToJSON_PointFitnessFunction.d.ts +0 -7
  338. package/src/engine/ecs/evaluation/json/serializeToJSON_PointFitnessFunction.d.ts.map +0 -1
  339. package/src/engine/ecs/evaluation/json/serializeToJSON_PointFitnessFunction.js +0 -89
  340. package/src/engine/ecs/evaluation/world/ReadTerrainLayerWeightPointFitness.d.ts +0 -17
  341. package/src/engine/ecs/evaluation/world/ReadTerrainLayerWeightPointFitness.d.ts.map +0 -1
  342. package/src/engine/ecs/evaluation/world/ReadTerrainLayerWeightPointFitness.js +0 -60
  343. package/src/engine/ecs/systems/TimerSystem.d.ts +0 -10
  344. package/src/engine/ecs/systems/TimerSystem.d.ts.map +0 -1
  345. package/src/engine/ecs/systems/TimerSystem.js +0 -86
  346. package/src/engine/graphics/FULL_SCREEN_QUAD_VERTEX_SHADER.d.ts +0 -13
  347. package/src/engine/graphics/FULL_SCREEN_QUAD_VERTEX_SHADER.d.ts.map +0 -1
  348. package/src/engine/graphics/FULL_SCREEN_QUAD_VERTEX_SHADER.js +0 -14
  349. package/src/engine/graphics/StandardFrameBuffers.d.ts +0 -7
  350. package/src/engine/graphics/StandardFrameBuffers.d.ts.map +0 -1
  351. package/src/engine/graphics/StandardFrameBuffers.js +0 -9
  352. package/src/engine/graphics/copy_transform_to_threejs_object.d.ts +0 -7
  353. package/src/engine/graphics/copy_transform_to_threejs_object.d.ts.map +0 -1
  354. package/src/engine/graphics/copy_transform_to_threejs_object.js +0 -12
  355. package/src/engine/graphics/ecs/light/binding/LightBinding.d.ts +0 -42
  356. package/src/engine/graphics/ecs/light/binding/LightBinding.d.ts.map +0 -1
  357. package/src/engine/graphics/ecs/light/binding/LightBinding.js +0 -133
  358. package/src/engine/graphics/ecs/light/binding/fp/FPLightBinding.d.ts +0 -25
  359. package/src/engine/graphics/ecs/light/binding/fp/FPLightBinding.d.ts.map +0 -1
  360. package/src/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +0 -90
  361. package/src/engine/graphics/ecs/light/binding/three/applyRotation.d.ts +0 -7
  362. package/src/engine/graphics/ecs/light/binding/three/applyRotation.d.ts.map +0 -1
  363. package/src/engine/graphics/ecs/light/binding/three/applyRotation.js +0 -24
  364. package/src/engine/graphics/ecs/light/binding/three/threeEnsureLightObject.d.ts +0 -7
  365. package/src/engine/graphics/ecs/light/binding/three/threeEnsureLightObject.d.ts.map +0 -1
  366. package/src/engine/graphics/ecs/light/binding/three/threeEnsureLightObject.js +0 -12
  367. package/src/engine/graphics/ecs/light/binding/three/threeMakeLight.d.ts +0 -8
  368. package/src/engine/graphics/ecs/light/binding/three/threeMakeLight.d.ts.map +0 -1
  369. package/src/engine/graphics/ecs/light/binding/three/threeMakeLight.js +0 -41
  370. package/src/engine/graphics/ecs/light/shadow/LightShadow.d.ts +0 -4
  371. package/src/engine/graphics/ecs/light/shadow/LightShadow.d.ts.map +0 -1
  372. package/src/engine/graphics/ecs/light/shadow/LightShadow.js +0 -4
  373. package/src/engine/graphics/ecs/light/shadow/ShadowManager.d.ts +0 -27
  374. package/src/engine/graphics/ecs/light/shadow/ShadowManager.d.ts.map +0 -1
  375. package/src/engine/graphics/ecs/light/shadow/ShadowManager.js +0 -53
  376. package/src/engine/graphics/ecs/light/shadow/ShadowMap.d.ts +0 -8
  377. package/src/engine/graphics/ecs/light/shadow/ShadowMap.d.ts.map +0 -1
  378. package/src/engine/graphics/ecs/light/shadow/ShadowMap.js +0 -7
  379. package/src/engine/graphics/ecs/light/shadow/compute_view_frustum_aabb_in_space.d.ts +0 -14
  380. package/src/engine/graphics/ecs/light/shadow/compute_view_frustum_aabb_in_space.d.ts.map +0 -1
  381. package/src/engine/graphics/ecs/light/shadow/compute_view_frustum_aabb_in_space.js +0 -62
  382. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.d.ts +0 -30
  383. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.d.ts.map +0 -1
  384. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.js +0 -77
  385. package/src/engine/graphics/ecs/light/shadow/setShadowCameraDimensionsDiscrete.d.ts +0 -13
  386. package/src/engine/graphics/ecs/light/shadow/setShadowCameraDimensionsDiscrete.d.ts.map +0 -1
  387. package/src/engine/graphics/ecs/light/shadow/setShadowCameraDimensionsDiscrete.js +0 -43
  388. package/src/engine/graphics/ecs/light/three/light2type.d.ts +0 -8
  389. package/src/engine/graphics/ecs/light/three/light2type.d.ts.map +0 -1
  390. package/src/engine/graphics/ecs/light/three/light2type.js +0 -20
  391. package/src/engine/graphics/ecs/mesh/applyTransformToThreeObject.d.ts +0 -7
  392. package/src/engine/graphics/ecs/mesh/applyTransformToThreeObject.d.ts.map +0 -1
  393. package/src/engine/graphics/ecs/mesh/applyTransformToThreeObject.js +0 -13
  394. package/src/engine/graphics/particles/node-based/codegen/CodeContext.d.ts +0 -20
  395. package/src/engine/graphics/particles/node-based/codegen/CodeContext.d.ts.map +0 -1
  396. package/src/engine/graphics/particles/node-based/codegen/CodeContext.js +0 -47
  397. package/src/engine/graphics/particles/node-based/codegen/CodeGenerator.d.ts +0 -12
  398. package/src/engine/graphics/particles/node-based/codegen/CodeGenerator.d.ts.map +0 -1
  399. package/src/engine/graphics/particles/node-based/codegen/CodeGenerator.js +0 -19
  400. package/src/engine/graphics/particles/node-based/codegen/glsl/GLSLCodeGenerator.d.ts +0 -18
  401. package/src/engine/graphics/particles/node-based/codegen/glsl/GLSLCodeGenerator.d.ts.map +0 -1
  402. package/src/engine/graphics/particles/node-based/codegen/glsl/GLSLCodeGenerator.js +0 -249
  403. package/src/engine/graphics/particles/node-based/codegen/glsl/genAttributeInputName.d.ts +0 -7
  404. package/src/engine/graphics/particles/node-based/codegen/glsl/genAttributeInputName.d.ts.map +0 -1
  405. package/src/engine/graphics/particles/node-based/codegen/glsl/genAttributeInputName.js +0 -8
  406. package/src/engine/graphics/particles/node-based/codegen/glsl/genAttributeOutputName.d.ts +0 -7
  407. package/src/engine/graphics/particles/node-based/codegen/glsl/genAttributeOutputName.d.ts.map +0 -1
  408. package/src/engine/graphics/particles/node-based/codegen/glsl/genAttributeOutputName.js +0 -8
  409. package/src/engine/graphics/particles/node-based/codegen/glsl/getTypeByteSize.d.ts +0 -14
  410. package/src/engine/graphics/particles/node-based/codegen/glsl/getTypeByteSize.d.ts.map +0 -1
  411. package/src/engine/graphics/particles/node-based/codegen/glsl/getTypeByteSize.js +0 -20
  412. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/curl/glslm_curlNoise.d.ts +0 -3
  413. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/curl/glslm_curlNoise.d.ts.map +0 -1
  414. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/curl/glslm_curlNoise.js +0 -58
  415. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/curl/glslm_snoiseVector3.d.ts +0 -3
  416. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/curl/glslm_snoiseVector3.d.ts.map +0 -1
  417. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/curl/glslm_snoiseVector3.js +0 -44
  418. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_mod289_v3.d.ts +0 -3
  419. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_mod289_v3.d.ts.map +0 -1
  420. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_mod289_v3.js +0 -28
  421. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_mod289_v4.d.ts +0 -3
  422. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_mod289_v4.d.ts.map +0 -1
  423. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_mod289_v4.js +0 -28
  424. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_permute.d.ts +0 -3
  425. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_permute.d.ts.map +0 -1
  426. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_permute.js +0 -39
  427. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_snoise.d.ts +0 -3
  428. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_snoise.d.ts.map +0 -1
  429. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_snoise.js +0 -124
  430. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_tylorInvSqrt.d.ts +0 -3
  431. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_tylorInvSqrt.d.ts.map +0 -1
  432. package/src/engine/graphics/particles/node-based/codegen/glsl/modules/noise/simplex/3d/glslm_tylorInvSqrt.js +0 -30
  433. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModule.d.ts +0 -64
  434. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModule.d.ts.map +0 -1
  435. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModule.js +0 -131
  436. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleReference.d.ts +0 -32
  437. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleReference.d.ts.map +0 -1
  438. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleReference.js +0 -62
  439. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleRegistry.d.ts +0 -46
  440. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleRegistry.d.ts.map +0 -1
  441. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleRegistry.js +0 -272
  442. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionParameterSpecification.d.ts +0 -28
  443. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionParameterSpecification.d.ts.map +0 -1
  444. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionParameterSpecification.js +0 -57
  445. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionSignature.d.ts +0 -32
  446. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionSignature.d.ts.map +0 -1
  447. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionSignature.js +0 -55
  448. package/src/engine/graphics/particles/node-based/editor/ParticleSpecificationEditorView.d.ts +0 -34
  449. package/src/engine/graphics/particles/node-based/editor/ParticleSpecificationEditorView.d.ts.map +0 -1
  450. package/src/engine/graphics/particles/node-based/editor/ParticleSpecificationEditorView.js +0 -178
  451. package/src/engine/graphics/particles/node-based/nodes/FloatConstant.d.ts +0 -7
  452. package/src/engine/graphics/particles/node-based/nodes/FloatConstant.d.ts.map +0 -1
  453. package/src/engine/graphics/particles/node-based/nodes/FloatConstant.js +0 -31
  454. package/src/engine/graphics/particles/node-based/nodes/ParticleDataTypes.d.ts +0 -13
  455. package/src/engine/graphics/particles/node-based/nodes/ParticleDataTypes.d.ts.map +0 -1
  456. package/src/engine/graphics/particles/node-based/nodes/ParticleDataTypes.js +0 -13
  457. package/src/engine/graphics/particles/node-based/nodes/ReadFloatUniform.d.ts +0 -7
  458. package/src/engine/graphics/particles/node-based/nodes/ReadFloatUniform.d.ts.map +0 -1
  459. package/src/engine/graphics/particles/node-based/nodes/ReadFloatUniform.js +0 -26
  460. package/src/engine/graphics/particles/node-based/nodes/ReadPosition.d.ts +0 -4
  461. package/src/engine/graphics/particles/node-based/nodes/ReadPosition.d.ts.map +0 -1
  462. package/src/engine/graphics/particles/node-based/nodes/ReadPosition.js +0 -5
  463. package/src/engine/graphics/particles/node-based/nodes/ReadVelocity.d.ts +0 -6
  464. package/src/engine/graphics/particles/node-based/nodes/ReadVelocity.d.ts.map +0 -1
  465. package/src/engine/graphics/particles/node-based/nodes/ReadVelocity.js +0 -14
  466. package/src/engine/graphics/particles/node-based/nodes/ShaderNode.d.ts +0 -37
  467. package/src/engine/graphics/particles/node-based/nodes/ShaderNode.d.ts.map +0 -1
  468. package/src/engine/graphics/particles/node-based/nodes/ShaderNode.js +0 -73
  469. package/src/engine/graphics/particles/node-based/nodes/Vector3Constant.d.ts +0 -7
  470. package/src/engine/graphics/particles/node-based/nodes/Vector3Constant.d.ts.map +0 -1
  471. package/src/engine/graphics/particles/node-based/nodes/Vector3Constant.js +0 -30
  472. package/src/engine/graphics/particles/node-based/nodes/Vector3Merge.d.ts +0 -7
  473. package/src/engine/graphics/particles/node-based/nodes/Vector3Merge.d.ts.map +0 -1
  474. package/src/engine/graphics/particles/node-based/nodes/Vector3Merge.js +0 -30
  475. package/src/engine/graphics/particles/node-based/nodes/Vector3Split.d.ts +0 -7
  476. package/src/engine/graphics/particles/node-based/nodes/Vector3Split.d.ts.map +0 -1
  477. package/src/engine/graphics/particles/node-based/nodes/Vector3Split.js +0 -32
  478. package/src/engine/graphics/particles/node-based/nodes/WriteVelocity.d.ts +0 -6
  479. package/src/engine/graphics/particles/node-based/nodes/WriteVelocity.d.ts.map +0 -1
  480. package/src/engine/graphics/particles/node-based/nodes/WriteVelocity.js +0 -15
  481. package/src/engine/graphics/particles/node-based/nodes/attribute/ReadVector3Attribute.d.ts +0 -7
  482. package/src/engine/graphics/particles/node-based/nodes/attribute/ReadVector3Attribute.d.ts.map +0 -1
  483. package/src/engine/graphics/particles/node-based/nodes/attribute/ReadVector3Attribute.js +0 -27
  484. package/src/engine/graphics/particles/node-based/nodes/attribute/WriteVector3Attribute.d.ts +0 -7
  485. package/src/engine/graphics/particles/node-based/nodes/attribute/WriteVector3Attribute.d.ts.map +0 -1
  486. package/src/engine/graphics/particles/node-based/nodes/attribute/WriteVector3Attribute.js +0 -25
  487. package/src/engine/graphics/particles/node-based/nodes/math/AddFloatNode.d.ts +0 -7
  488. package/src/engine/graphics/particles/node-based/nodes/math/AddFloatNode.d.ts.map +0 -1
  489. package/src/engine/graphics/particles/node-based/nodes/math/AddFloatNode.js +0 -26
  490. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Add.d.ts +0 -7
  491. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Add.d.ts.map +0 -1
  492. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Add.js +0 -25
  493. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Divide.d.ts +0 -7
  494. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Divide.d.ts.map +0 -1
  495. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Divide.js +0 -25
  496. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Multiply.d.ts +0 -7
  497. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Multiply.d.ts.map +0 -1
  498. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Multiply.js +0 -25
  499. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Subtract.d.ts +0 -7
  500. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Subtract.d.ts.map +0 -1
  501. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Subtract.js +0 -25
  502. package/src/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.d.ts +0 -7
  503. package/src/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.d.ts.map +0 -1
  504. package/src/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.js +0 -39
  505. package/src/engine/graphics/particles/node-based/nodes/particle_data_type_component_count.d.ts +0 -39
  506. package/src/engine/graphics/particles/node-based/nodes/particle_data_type_component_count.d.ts.map +0 -1
  507. package/src/engine/graphics/particles/node-based/nodes/particle_data_type_component_count.js +0 -45
  508. package/src/engine/graphics/particles/node-based/particle/GeometryAttributes.d.ts +0 -9
  509. package/src/engine/graphics/particles/node-based/particle/GeometryAttributes.d.ts.map +0 -1
  510. package/src/engine/graphics/particles/node-based/particle/GeometryAttributes.js +0 -10
  511. package/src/engine/graphics/particles/node-based/particle/ParticleAttributeBinding.d.ts +0 -13
  512. package/src/engine/graphics/particles/node-based/particle/ParticleAttributeBinding.d.ts.map +0 -1
  513. package/src/engine/graphics/particles/node-based/particle/ParticleAttributeBinding.js +0 -14
  514. package/src/engine/graphics/particles/node-based/particle/ParticleAttributeSpecification.d.ts +0 -50
  515. package/src/engine/graphics/particles/node-based/particle/ParticleAttributeSpecification.d.ts.map +0 -1
  516. package/src/engine/graphics/particles/node-based/particle/ParticleAttributeSpecification.js +0 -47
  517. package/src/engine/graphics/particles/node-based/particle/ParticleSpecification.d.ts +0 -51
  518. package/src/engine/graphics/particles/node-based/particle/ParticleSpecification.d.ts.map +0 -1
  519. package/src/engine/graphics/particles/node-based/particle/ParticleSpecification.js +0 -93
  520. package/src/engine/graphics/particles/node-based/populateFunctionModuleRegistry.d.ts +0 -6
  521. package/src/engine/graphics/particles/node-based/populateFunctionModuleRegistry.d.ts.map +0 -1
  522. package/src/engine/graphics/particles/node-based/populateFunctionModuleRegistry.js +0 -23
  523. package/src/engine/graphics/particles/node-based/populateNodeRegistry.d.ts +0 -7
  524. package/src/engine/graphics/particles/node-based/populateNodeRegistry.d.ts.map +0 -1
  525. package/src/engine/graphics/particles/node-based/populateNodeRegistry.js +0 -48
  526. package/src/engine/graphics/particles/node-based/rendering/AbstractParticleRenderer.d.ts +0 -21
  527. package/src/engine/graphics/particles/node-based/rendering/AbstractParticleRenderer.d.ts.map +0 -1
  528. package/src/engine/graphics/particles/node-based/rendering/AbstractParticleRenderer.js +0 -35
  529. package/src/engine/graphics/particles/node-based/rendering/ParticleRenderCommand.d.ts +0 -20
  530. package/src/engine/graphics/particles/node-based/rendering/ParticleRenderCommand.d.ts.map +0 -1
  531. package/src/engine/graphics/particles/node-based/rendering/ParticleRenderCommand.js +0 -35
  532. package/src/engine/graphics/particles/node-based/rendering/ParticleRenderSpecification.d.ts +0 -14
  533. package/src/engine/graphics/particles/node-based/rendering/ParticleRenderSpecification.d.ts.map +0 -1
  534. package/src/engine/graphics/particles/node-based/rendering/ParticleRenderSpecification.js +0 -17
  535. package/src/engine/graphics/particles/node-based/rendering/billboard/ParticleBillboardShader.d.ts +0 -5
  536. package/src/engine/graphics/particles/node-based/rendering/billboard/ParticleBillboardShader.d.ts.map +0 -1
  537. package/src/engine/graphics/particles/node-based/rendering/billboard/ParticleBillboardShader.js +0 -150
  538. package/src/engine/graphics/particles/node-based/simulation/EmitterAttributeData.d.ts +0 -55
  539. package/src/engine/graphics/particles/node-based/simulation/EmitterAttributeData.d.ts.map +0 -1
  540. package/src/engine/graphics/particles/node-based/simulation/EmitterAttributeData.js +0 -105
  541. package/src/engine/graphics/particles/node-based/simulation/GLDataBuffer.d.ts +0 -49
  542. package/src/engine/graphics/particles/node-based/simulation/GLDataBuffer.d.ts.map +0 -1
  543. package/src/engine/graphics/particles/node-based/simulation/GLDataBuffer.js +0 -103
  544. package/src/engine/graphics/particles/node-based/simulation/GLSLParticleSimulator.d.ts +0 -4
  545. package/src/engine/graphics/particles/node-based/simulation/GLSLParticleSimulator.d.ts.map +0 -1
  546. package/src/engine/graphics/particles/node-based/simulation/GLSLParticleSimulator.js +0 -6
  547. package/src/engine/graphics/particles/node-based/simulation/GLSLSimulationShader.d.ts +0 -83
  548. package/src/engine/graphics/particles/node-based/simulation/GLSLSimulationShader.d.ts.map +0 -1
  549. package/src/engine/graphics/particles/node-based/simulation/GLSLSimulationShader.js +0 -188
  550. package/src/engine/graphics/particles/node-based/simulation/TransformFeedback.d.ts +0 -123
  551. package/src/engine/graphics/particles/node-based/simulation/TransformFeedback.d.ts.map +0 -1
  552. package/src/engine/graphics/particles/node-based/simulation/TransformFeedback.js +0 -415
  553. package/src/engine/graphics/render/buffer/FrameBufferManager.d.ts +0 -71
  554. package/src/engine/graphics/render/buffer/FrameBufferManager.d.ts.map +0 -1
  555. package/src/engine/graphics/render/buffer/FrameBufferManager.js +0 -229
  556. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.d.ts +0 -22
  557. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.d.ts.map +0 -1
  558. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +0 -84
  559. package/src/engine/graphics/render/forward_plus/LightRenderMetadata.d.ts +0 -33
  560. package/src/engine/graphics/render/forward_plus/LightRenderMetadata.d.ts.map +0 -1
  561. package/src/engine/graphics/render/forward_plus/LightRenderMetadata.js +0 -61
  562. package/src/engine/graphics/render/forward_plus/SPECIFICATION.md +0 -155
  563. package/src/engine/graphics/render/forward_plus/assign_cluster.d.ts +0 -29
  564. package/src/engine/graphics/render/forward_plus/assign_cluster.d.ts.map +0 -1
  565. package/src/engine/graphics/render/forward_plus/assign_cluster.js +0 -124
  566. package/src/engine/graphics/render/forward_plus/cluster/compute_light_data_hash.d.ts +0 -7
  567. package/src/engine/graphics/render/forward_plus/cluster/compute_light_data_hash.d.ts.map +0 -1
  568. package/src/engine/graphics/render/forward_plus/cluster/compute_light_data_hash.js +0 -17
  569. package/src/engine/graphics/render/forward_plus/cluster/compute_light_data_hash_0.d.ts +0 -7
  570. package/src/engine/graphics/render/forward_plus/cluster/compute_light_data_hash_0.d.ts.map +0 -1
  571. package/src/engine/graphics/render/forward_plus/cluster/compute_light_data_hash_0.js +0 -17
  572. package/src/engine/graphics/render/forward_plus/cluster/read_plane_pair.d.ts +0 -9
  573. package/src/engine/graphics/render/forward_plus/cluster/read_plane_pair.d.ts.map +0 -1
  574. package/src/engine/graphics/render/forward_plus/cluster/read_plane_pair.js +0 -29
  575. package/src/engine/graphics/render/forward_plus/cluster/write_cluster_planes.d.ts +0 -12
  576. package/src/engine/graphics/render/forward_plus/cluster/write_cluster_planes.d.ts.map +0 -1
  577. package/src/engine/graphics/render/forward_plus/cluster/write_cluster_planes.js +0 -43
  578. package/src/engine/graphics/render/forward_plus/computeFrustumCorners.d.ts +0 -8
  579. package/src/engine/graphics/render/forward_plus/computeFrustumCorners.d.ts.map +0 -1
  580. package/src/engine/graphics/render/forward_plus/computeFrustumCorners.js +0 -68
  581. package/src/engine/graphics/render/forward_plus/debug/createLayerSwitcher.d.ts +0 -4
  582. package/src/engine/graphics/render/forward_plus/debug/createLayerSwitcher.d.ts.map +0 -1
  583. package/src/engine/graphics/render/forward_plus/debug/createLayerSwitcher.js +0 -46
  584. package/src/engine/graphics/render/forward_plus/debug/createScreenGrid.d.ts +0 -14
  585. package/src/engine/graphics/render/forward_plus/debug/createScreenGrid.d.ts.map +0 -1
  586. package/src/engine/graphics/render/forward_plus/debug/createScreenGrid.js +0 -327
  587. package/src/engine/graphics/render/forward_plus/materials/FP_INJECTION_POINT_ACCUMULATION.d.ts +0 -2
  588. package/src/engine/graphics/render/forward_plus/materials/FP_INJECTION_POINT_ACCUMULATION.d.ts.map +0 -1
  589. package/src/engine/graphics/render/forward_plus/materials/FP_INJECTION_POINT_ACCUMULATION.js +0 -1
  590. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.d.ts +0 -2
  591. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.d.ts.map +0 -1
  592. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +0 -40
  593. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_APPLY_DECALS.d.ts +0 -2
  594. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_APPLY_DECALS.d.ts.map +0 -1
  595. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_APPLY_DECALS.js +0 -74
  596. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_DECODE_PARS.d.ts +0 -2
  597. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_DECODE_PARS.d.ts.map +0 -1
  598. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_DECODE_PARS.js +0 -55
  599. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_LOAD_METADATA.d.ts +0 -2
  600. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_LOAD_METADATA.d.ts.map +0 -1
  601. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_LOAD_METADATA.js +0 -11
  602. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.d.ts +0 -2
  603. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.d.ts.map +0 -1
  604. package/src/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +0 -34
  605. package/src/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.d.ts +0 -7
  606. package/src/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.d.ts.map +0 -1
  607. package/src/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +0 -60
  608. package/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.d.ts +0 -7
  609. package/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.d.ts.map +0 -1
  610. package/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.js +0 -38
  611. package/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_shader.d.ts +0 -7
  612. package/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_shader.d.ts.map +0 -1
  613. package/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_shader.js +0 -30
  614. package/src/engine/graphics/render/forward_plus/model/Decal.d.ts +0 -51
  615. package/src/engine/graphics/render/forward_plus/model/Decal.d.ts.map +0 -1
  616. package/src/engine/graphics/render/forward_plus/model/Decal.js +0 -133
  617. package/src/engine/graphics/render/forward_plus/plugin/forwardPlusMaterialMarker.d.ts +0 -16
  618. package/src/engine/graphics/render/forward_plus/plugin/forwardPlusMaterialMarker.d.ts.map +0 -1
  619. package/src/engine/graphics/render/forward_plus/plugin/forwardPlusMaterialMarker.js +0 -18
  620. package/src/engine/graphics/render/forward_plus/plugin/isLitMaterial.d.ts +0 -7
  621. package/src/engine/graphics/render/forward_plus/plugin/isLitMaterial.d.ts.map +0 -1
  622. package/src/engine/graphics/render/forward_plus/plugin/isLitMaterial.js +0 -8
  623. package/src/engine/graphics/render/forward_plus/query/analytical_biplanar_corner_mapping.d.ts +0 -10
  624. package/src/engine/graphics/render/forward_plus/query/analytical_biplanar_corner_mapping.d.ts.map +0 -1
  625. package/src/engine/graphics/render/forward_plus/query/analytical_biplanar_corner_mapping.js +0 -65
  626. package/src/engine/graphics/render/forward_plus/query/analytical_triplanar_corner_mapping.d.ts +0 -7
  627. package/src/engine/graphics/render/forward_plus/query/analytical_triplanar_corner_mapping.d.ts.map +0 -1
  628. package/src/engine/graphics/render/forward_plus/query/analytical_triplanar_corner_mapping.js +0 -8
  629. package/src/engine/graphics/render/forward_plus/query/cube_mapping.d.ts +0 -11
  630. package/src/engine/graphics/render/forward_plus/query/cube_mapping.d.ts.map +0 -1
  631. package/src/engine/graphics/render/forward_plus/query/cube_mapping.js +0 -38
  632. package/src/engine/graphics/render/forward_plus/query/detailed_sphere_frustum_intersection_test.d.ts +0 -21
  633. package/src/engine/graphics/render/forward_plus/query/detailed_sphere_frustum_intersection_test.d.ts.map +0 -1
  634. package/src/engine/graphics/render/forward_plus/query/detailed_sphere_frustum_intersection_test.js +0 -96
  635. package/src/engine/graphics/render/forward_plus/query/point_light_inside_volume.d.ts +0 -22
  636. package/src/engine/graphics/render/forward_plus/query/point_light_inside_volume.d.ts.map +0 -1
  637. package/src/engine/graphics/render/forward_plus/query/point_light_inside_volume.js +0 -44
  638. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.d.ts +0 -11
  639. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.d.ts.map +0 -1
  640. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +0 -169
  641. package/src/engine/graphics/render/forward_plus/query/spot_light_inside_volume.d.ts +0 -9
  642. package/src/engine/graphics/render/forward_plus/query/spot_light_inside_volume.d.ts.map +0 -1
  643. package/src/engine/graphics/render/forward_plus/query/spot_light_inside_volume.js +0 -33
  644. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts +0 -2
  645. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts.map +0 -1
  646. package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +0 -2
  647. package/src/engine/graphics/render/forward_plus/sort_decal_data.d.ts +0 -9
  648. package/src/engine/graphics/render/forward_plus/sort_decal_data.d.ts.map +0 -1
  649. package/src/engine/graphics/render/forward_plus/sort_decal_data.js +0 -102
  650. package/src/engine/graphics/render/forward_plus/testClusterEquality.d.ts +0 -10
  651. package/src/engine/graphics/render/forward_plus/testClusterEquality.d.ts.map +0 -1
  652. package/src/engine/graphics/render/forward_plus/testClusterEquality.js +0 -22
  653. package/src/engine/graphics/render/frame_graph/webgl/WebGLRenderContext.d.ts +0 -19
  654. package/src/engine/graphics/render/frame_graph/webgl/WebGLRenderContext.d.ts.map +0 -1
  655. package/src/engine/graphics/render/frame_graph/webgl/WebGLRenderContext.js +0 -62
  656. package/src/engine/graphics/shaders/AlphaBlendShader.d.ts +0 -18
  657. package/src/engine/graphics/shaders/AlphaBlendShader.d.ts.map +0 -1
  658. package/src/engine/graphics/shaders/AlphaBlendShader.js +0 -42
  659. package/src/engine/graphics/shaders/ClearShader.d.ts +0 -8
  660. package/src/engine/graphics/shaders/ClearShader.d.ts.map +0 -1
  661. package/src/engine/graphics/shaders/ClearShader.js +0 -28
  662. package/src/engine/graphics/shaders/ScreenSpaceQuadShader.d.ts +0 -13
  663. package/src/engine/graphics/shaders/ScreenSpaceQuadShader.d.ts.map +0 -1
  664. package/src/engine/graphics/shaders/ScreenSpaceQuadShader.js +0 -38
  665. package/src/engine/graphics/shaders/ScreenSpaceShader.d.ts +0 -7
  666. package/src/engine/graphics/shaders/ScreenSpaceShader.d.ts.map +0 -1
  667. package/src/engine/graphics/shaders/ScreenSpaceShader.js +0 -102
  668. package/src/engine/graphics/shaders/chunks/glsl_octahedral_impostor.d.ts +0 -102
  669. package/src/engine/graphics/shaders/chunks/glsl_octahedral_impostor.d.ts.map +0 -1
  670. package/src/engine/graphics/shaders/chunks/glsl_octahedral_impostor.js +0 -277
  671. package/src/engine/graphics/shaders/chunks/glsl_voxel_impostor_splat.d.ts +0 -40
  672. package/src/engine/graphics/shaders/chunks/glsl_voxel_impostor_splat.d.ts.map +0 -1
  673. package/src/engine/graphics/shaders/chunks/glsl_voxel_impostor_splat.js +0 -57
  674. package/src/engine/graphics/shaders/glsl_gen_swizzled_read.d.ts +0 -8
  675. package/src/engine/graphics/shaders/glsl_gen_swizzled_read.d.ts.map +0 -1
  676. package/src/engine/graphics/shaders/glsl_gen_swizzled_read.js +0 -39
  677. package/src/engine/graphics/shadows/README.md +0 -6
  678. package/src/engine/graphics/shadows/vsm.glsl.d.ts +0 -3
  679. package/src/engine/graphics/shadows/vsm.glsl.d.ts.map +0 -1
  680. package/src/engine/graphics/shadows/vsm.glsl.js +0 -43
  681. package/src/engine/graphics/util/composeMatrix4.d.ts +0 -9
  682. package/src/engine/graphics/util/composeMatrix4.d.ts.map +0 -1
  683. package/src/engine/graphics/util/composeMatrix4.js +0 -13
  684. package/src/engine/graphics/util/threeUpdateMatrix.d.ts +0 -6
  685. package/src/engine/graphics/util/threeUpdateMatrix.d.ts.map +0 -1
  686. package/src/engine/graphics/util/threeUpdateMatrix.js +0 -14
  687. package/src/engine/graphics/util/threeUpdateTransform.d.ts +0 -6
  688. package/src/engine/graphics/util/threeUpdateTransform.d.ts.map +0 -1
  689. package/src/engine/graphics/util/threeUpdateTransform.js +0 -16
  690. package/src/engine/sound/ecs/SoundController.d.ts.map +0 -1
  691. package/src/engine/sound/ecs/SoundControllerSystem.d.ts +0 -23
  692. package/src/engine/sound/ecs/SoundControllerSystem.d.ts.map +0 -1
  693. package/src/engine/sound/ecs/SoundControllerSystem.js +0 -103
  694. package/src/engine/sound/ecs/emitter/SoundAttenuationFunction.d.ts.map +0 -1
  695. package/src/engine/sound/ecs/emitter/SoundEmitter.d.ts.map +0 -1
  696. package/src/engine/sound/ecs/emitter/SoundEmitterComponentContext.d.ts +0 -55
  697. package/src/engine/sound/ecs/emitter/SoundEmitterComponentContext.d.ts.map +0 -1
  698. package/src/engine/sound/ecs/emitter/SoundEmitterComponentContext.js +0 -265
  699. package/src/engine/sound/ecs/emitter/SoundEmitterFlags.d.ts.map +0 -1
  700. package/src/engine/sound/ecs/emitter/SoundEmitterSerializationAdapter.d.ts.map +0 -1
  701. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.d.ts +0 -88
  702. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.d.ts.map +0 -1
  703. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.js +0 -159
  704. package/src/engine/sound/ecs/emitter/SoundPanningModelType.d.ts.map +0 -1
  705. package/src/engine/sound/ecs/emitter/SoundTrack.d.ts.map +0 -1
  706. package/src/engine/sound/ecs/emitter/SoundTrackFlags.d.ts.map +0 -1
  707. package/src/engine/sound/ecs/emitter/loadSoundTrackAsset.d.ts +0 -8
  708. package/src/engine/sound/ecs/emitter/loadSoundTrackAsset.d.ts.map +0 -1
  709. package/src/engine/sound/ecs/emitter/loadSoundTrackAsset.js +0 -41
  710. package/src/shade/playground/FramePerformanceMonitor.d.ts +0 -114
  711. package/src/shade/playground/FramePerformanceMonitor.d.ts.map +0 -1
  712. package/src/shade/playground/FramePerformanceMonitor.js +0 -468
  713. package/src/shade/playground/add_random_lights.d.ts +0 -8
  714. package/src/shade/playground/add_random_lights.d.ts.map +0 -1
  715. package/src/shade/playground/add_random_lights.js +0 -50
  716. package/src/shade/playground/animation_prototype.d.ts +0 -24
  717. package/src/shade/playground/animation_prototype.d.ts.map +0 -1
  718. package/src/shade/playground/animation_prototype.js +0 -508
  719. package/src/shade/playground/animation_prototype_skinning.d.ts +0 -31
  720. package/src/shade/playground/animation_prototype_skinning.d.ts.map +0 -1
  721. package/src/shade/playground/animation_prototype_skinning.js +0 -647
  722. package/src/shade/playground/animation_prototype_stress.d.ts +0 -35
  723. package/src/shade/playground/animation_prototype_stress.d.ts.map +0 -1
  724. package/src/shade/playground/animation_prototype_stress.js +0 -765
  725. package/src/shade/playground/enable_picker.d.ts +0 -8
  726. package/src/shade/playground/enable_picker.d.ts.map +0 -1
  727. package/src/shade/playground/enable_picker.js +0 -60
  728. package/src/shade/playground/gltf_skinned_prototype.d.ts +0 -27
  729. package/src/shade/playground/gltf_skinned_prototype.d.ts.map +0 -1
  730. package/src/shade/playground/gltf_skinned_prototype.js +0 -560
  731. package/src/shade/playground/gltf_skinned_stress_prototype.d.ts +0 -24
  732. package/src/shade/playground/gltf_skinned_stress_prototype.d.ts.map +0 -1
  733. package/src/shade/playground/gltf_skinned_stress_prototype.js +0 -387
  734. package/src/shade/playground/gltf_viewer.d.ts +0 -2
  735. package/src/shade/playground/gltf_viewer.d.ts.map +0 -1
  736. package/src/shade/playground/gltf_viewer.js +0 -283
  737. package/src/shade/playground/main.d.ts.map +0 -1
  738. package/src/shade/playground/main.js +0 -2727
  739. package/src/shade/playground/make_animated_instances.d.ts +0 -9
  740. package/src/shade/playground/make_animated_instances.d.ts.map +0 -1
  741. package/src/shade/playground/make_animated_instances.js +0 -118
  742. package/src/shade/playground/prototype_virtual_texture.d.ts +0 -2
  743. package/src/shade/playground/prototype_virtual_texture.d.ts.map +0 -1
  744. package/src/shade/playground/prototype_virtual_texture.js +0 -274
  745. package/src/shade/playground/prototype_volumetrics_01.d.ts +0 -2
  746. package/src/shade/playground/prototype_volumetrics_01.d.ts.map +0 -1
  747. package/src/shade/playground/prototype_volumetrics_01.js +0 -206
  748. package/src/shade/playground/sample.d.ts +0 -2
  749. package/src/shade/playground/sample.d.ts.map +0 -1
  750. package/src/shade/playground/sample.js +0 -234
  751. package/src/shade/playground/sample_load_gltf.d.ts +0 -9
  752. package/src/shade/playground/sample_load_gltf.d.ts.map +0 -1
  753. package/src/shade/playground/sample_load_gltf.js +0 -103
  754. package/src/shade/playground/spread_node3d_grid.d.ts +0 -7
  755. package/src/shade/playground/spread_node3d_grid.d.ts.map +0 -1
  756. package/src/shade/playground/spread_node3d_grid.js +0 -20
  757. package/src/shade/renderer/geometry/bvh/GPUGeometryBVH.d.ts +0 -24
  758. package/src/shade/renderer/geometry/bvh/GPUGeometryBVH.d.ts.map +0 -1
  759. package/src/shade/renderer/geometry/bvh/GPUGeometryBVH.js +0 -88
  760. package/src/shade/renderer/gpu_primitive/prefix_sum/v0/shader_exclusive_prefix_scan_add.d.ts +0 -3
  761. package/src/shade/renderer/gpu_primitive/prefix_sum/v0/shader_exclusive_prefix_scan_add.d.ts.map +0 -1
  762. package/src/shade/renderer/gpu_primitive/prefix_sum/v0/shader_exclusive_prefix_scan_add.js +0 -49
  763. package/src/shade/renderer/gpu_primitive/prefix_sum/v0/shader_exclusive_prefix_sum_scan.d.ts +0 -3
  764. package/src/shade/renderer/gpu_primitive/prefix_sum/v0/shader_exclusive_prefix_sum_scan.d.ts.map +0 -1
  765. package/src/shade/renderer/gpu_primitive/prefix_sum/v0/shader_exclusive_prefix_sum_scan.js +0 -93
  766. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdl.d.ts +0 -24
  767. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdl.d.ts.map +0 -1
  768. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdl.js +0 -119
  769. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_one_sweep_prefix_scan.d.ts +0 -7
  770. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_one_sweep_prefix_scan.d.ts.map +0 -1
  771. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_one_sweep_prefix_scan.js +0 -235
  772. package/src/shade/renderer/gpu_primitive/sort/NOTES.md +0 -5
  773. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_common.d.ts +0 -7
  774. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_common.d.ts.map +0 -1
  775. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_common.js +0 -136
  776. package/src/shade/renderer/gpu_primitive/sort/ffx/chunk_safe_load_uint4_umax.d.ts +0 -18
  777. package/src/shade/renderer/gpu_primitive/sort/ffx/chunk_safe_load_uint4_umax.d.ts.map +0 -1
  778. package/src/shade/renderer/gpu_primitive/sort/ffx/chunk_safe_load_uint4_umax.js +0 -108
  779. package/src/shade/renderer/gpu_primitive/sort/ffx/defs.d.ts +0 -35
  780. package/src/shade/renderer/gpu_primitive/sort/ffx/defs.d.ts.map +0 -1
  781. package/src/shade/renderer/gpu_primitive/sort/ffx/defs.js +0 -42
  782. package/src/shade/renderer/gpu_primitive/sort/ffx/graph_radix_sort.d.ts +0 -13
  783. package/src/shade/renderer/gpu_primitive/sort/ffx/graph_radix_sort.d.ts.map +0 -1
  784. package/src/shade/renderer/gpu_primitive/sort/ffx/graph_radix_sort.js +0 -116
  785. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_bit_histogram.d.ts +0 -3
  786. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_bit_histogram.d.ts.map +0 -1
  787. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_bit_histogram.js +0 -120
  788. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_distribute_part_sum_int4.d.ts +0 -3
  789. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_distribute_part_sum_int4.d.ts.map +0 -1
  790. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_distribute_part_sum_int4.js +0 -76
  791. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scan_exclusive_partial.d.ts +0 -3
  792. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scan_exclusive_partial.d.ts.map +0 -1
  793. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scan_exclusive_partial.js +0 -125
  794. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scan_exclusive_uint4.d.ts +0 -3
  795. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scan_exclusive_uint4.d.ts.map +0 -1
  796. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scan_exclusive_uint4.js +0 -140
  797. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scatter_keys_and_values.d.ts +0 -3
  798. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scatter_keys_and_values.d.ts.map +0 -1
  799. package/src/shade/renderer/gpu_primitive/sort/ffx/shader_scatter_keys_and_values.js +0 -338
  800. package/src/shade/renderer/gpu_primitive/sort/gaussian_splatting/x.d.ts +0 -7
  801. package/src/shade/renderer/gpu_primitive/sort/gaussian_splatting/x.d.ts.map +0 -1
  802. package/src/shade/renderer/gpu_primitive/sort/gaussian_splatting/x.js +0 -261
  803. package/src/shade/renderer/gpu_primitive/sort/one_sweep/chunk_extract_digit.d.ts +0 -3
  804. package/src/shade/renderer/gpu_primitive/sort/one_sweep/chunk_extract_digit.d.ts.map +0 -1
  805. package/src/shade/renderer/gpu_primitive/sort/one_sweep/chunk_extract_digit.js +0 -14
  806. package/src/shade/renderer/gpu_primitive/sort/one_sweep/defs.d.ts +0 -25
  807. package/src/shade/renderer/gpu_primitive/sort/one_sweep/defs.d.ts.map +0 -1
  808. package/src/shade/renderer/gpu_primitive/sort/one_sweep/defs.js +0 -25
  809. package/src/shade/renderer/gpu_primitive/sort/one_sweep/graph_radix_sort.d.ts +0 -15
  810. package/src/shade/renderer/gpu_primitive/sort/one_sweep/graph_radix_sort.d.ts.map +0 -1
  811. package/src/shade/renderer/gpu_primitive/sort/one_sweep/graph_radix_sort.js +0 -192
  812. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_digit_binning_pass_pairs.d.ts +0 -5
  813. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_digit_binning_pass_pairs.d.ts.map +0 -1
  814. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_digit_binning_pass_pairs.js +0 -990
  815. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_global_histogram.d.ts +0 -5
  816. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_global_histogram.d.ts.map +0 -1
  817. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_global_histogram.js +0 -82
  818. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_init_sweep.d.ts +0 -3
  819. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_init_sweep.d.ts.map +0 -1
  820. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_init_sweep.js +0 -44
  821. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_scan.d.ts +0 -5
  822. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_scan.d.ts.map +0 -1
  823. package/src/shade/renderer/gpu_primitive/sort/one_sweep/shader_scan.js +0 -156
  824. package/src/shade/renderer/gpu_primitive/sort/one_sweep/test_radix_sort.d.ts +0 -6
  825. package/src/shade/renderer/gpu_primitive/sort/one_sweep/test_radix_sort.d.ts.map +0 -1
  826. package/src/shade/renderer/gpu_primitive/sort/one_sweep/test_radix_sort.js +0 -55
  827. package/src/shade/renderer/gpu_primitive/sort/one_sweep/verify_radix_sort_one_sweep.d.ts +0 -14
  828. package/src/shade/renderer/gpu_primitive/sort/one_sweep/verify_radix_sort_one_sweep.d.ts.map +0 -1
  829. package/src/shade/renderer/gpu_primitive/sort/one_sweep/verify_radix_sort_one_sweep.js +0 -110
  830. package/src/shade/renderer/gpu_primitive/sort/v4/graph_radix_sort.d.ts +0 -12
  831. package/src/shade/renderer/gpu_primitive/sort/v4/graph_radix_sort.d.ts.map +0 -1
  832. package/src/shade/renderer/gpu_primitive/sort/v4/graph_radix_sort.js +0 -74
  833. package/src/shade/renderer/gpu_primitive/sort/v4/shader_radix_sort.d.ts +0 -3
  834. package/src/shade/renderer/gpu_primitive/sort/v4/shader_radix_sort.d.ts.map +0 -1
  835. package/src/shade/renderer/gpu_primitive/sort/v4/shader_radix_sort.js +0 -125
  836. package/src/shade/renderer/scene/optimization/geometry/internal/bt_face_loop_helpers.d.ts +0 -32
  837. package/src/shade/renderer/scene/optimization/geometry/internal/bt_face_loop_helpers.d.ts.map +0 -1
  838. package/src/shade/renderer/scene/optimization/geometry/internal/bt_face_loop_helpers.js +0 -77
  839. package/src/shade/renderer/scene/optimization/geometry/internal/bt_find_edge_between.d.ts +0 -12
  840. package/src/shade/renderer/scene/optimization/geometry/internal/bt_find_edge_between.d.ts.map +0 -1
  841. package/src/shade/renderer/scene/optimization/geometry/internal/bt_find_edge_between.js +0 -35
  842. package/src/shade/renderer/scene/serialization/linear_to_pq.d.ts +0 -2
  843. package/src/shade/renderer/scene/serialization/linear_to_pq.d.ts.map +0 -1
  844. package/src/shade/renderer/scene/serialization/linear_to_pq.js +0 -14
  845. package/src/shade/renderer/scene/serialization/pq_to_linear.d.ts +0 -9
  846. package/src/shade/renderer/scene/serialization/pq_to_linear.d.ts.map +0 -1
  847. package/src/shade/renderer/scene/serialization/pq_to_linear.js +0 -30
  848. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_calculate_morton_code.d.ts +0 -7
  849. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_calculate_morton_code.d.ts.map +0 -1
  850. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_calculate_morton_code.js +0 -36
  851. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_get_morton_codes_from_unit_coord.d.ts +0 -7
  852. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_get_morton_codes_from_unit_coord.d.ts.map +0 -1
  853. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_get_morton_codes_from_unit_coord.js +0 -54
  854. package/src/shade/renderer/shader/chunk/bvh/packed/NOTES.md +0 -19
  855. package/src/shade/renderer/shader/chunk/bvh/packed/PACKED_BVH_NODE_STRUCT.d.ts +0 -3
  856. package/src/shade/renderer/shader/chunk/bvh/packed/PACKED_BVH_NODE_STRUCT.d.ts.map +0 -1
  857. package/src/shade/renderer/shader/chunk/bvh/packed/PACKED_BVH_NODE_STRUCT.js +0 -9
  858. package/src/shade/renderer/shader/chunk/bvh/packed/PACKED_BVH_NODE_WORD_COUNT.d.ts +0 -6
  859. package/src/shade/renderer/shader/chunk/bvh/packed/PACKED_BVH_NODE_WORD_COUNT.d.ts.map +0 -1
  860. package/src/shade/renderer/shader/chunk/bvh/packed/PACKED_BVH_NODE_WORD_COUNT.js +0 -5
  861. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_make_f32_interval_f16_safe.d.ts +0 -8
  862. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_make_f32_interval_f16_safe.d.ts.map +0 -1
  863. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_make_f32_interval_f16_safe.js +0 -17
  864. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_pack_f32_interval_to_u32.d.ts +0 -3
  865. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_pack_f32_interval_to_u32.d.ts.map +0 -1
  866. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_pack_f32_interval_to_u32.js +0 -14
  867. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_from_unpacked_node.d.ts +0 -3
  868. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_from_unpacked_node.d.ts.map +0 -1
  869. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_from_unpacked_node.js +0 -27
  870. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_read_node.d.ts +0 -3
  871. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_read_node.d.ts.map +0 -1
  872. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_read_node.js +0 -31
  873. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_write_node.d.ts +0 -3
  874. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_write_node.d.ts.map +0 -1
  875. package/src/shade/renderer/shader/chunk/bvh/packed/chunk_packed_bvh_write_node.js +0 -25
  876. package/src/shade/renderer/shader/chunk/bvh/packed/shader_pack_blas.d.ts +0 -3
  877. package/src/shade/renderer/shader/chunk/bvh/packed/shader_pack_blas.d.ts.map +0 -1
  878. package/src/shade/renderer/shader/chunk/bvh/packed/shader_pack_blas.js +0 -42
  879. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundAttenuationFunction.d.ts +0 -0
  880. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundAttenuationFunction.js +0 -0
  881. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterFlags.d.ts +0 -0
  882. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterFlags.js +0 -0
  883. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationAdapter.d.ts +0 -0
  884. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationAdapter.js +0 -0
  885. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationUpgrader_0_1.d.ts +0 -0
  886. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationUpgrader_0_1.js +0 -0
  887. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationUpgrader_1_2.d.ts +0 -0
  888. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundEmitterSerializationUpgrader_1_2.js +0 -0
  889. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundPanningModelType.d.ts +0 -0
  890. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundPanningModelType.js +0 -0
  891. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundTrackFlags.d.ts +0 -0
  892. /package/src/engine/sound/{ecs/emitter → sopra/legacy}/SoundTrackFlags.js +0 -0
  893. /package/src/shade/playground/{main.d.ts → bvh_repro/main.d.ts} +0 -0
@@ -1,643 +1,644 @@
1
- # Sopra
2
-
3
- An object-oriented, data-driven sound engine for the meep ECS, loosely modelled on FMOD / Wwise
4
- concepts (events, a mixer bus tree, RTPC parameters, voice stealing, snapshots, ducking) but built
5
- around meep's own data model instead of an opaque middleware bank.
6
-
7
- Sopra is **ECS-agnostic at its core**. The engine (`SopraEngine` + its services) knows nothing about
8
- entities; it is a self-contained audio renderer driven by a single clock. A thin ECS layer
9
- (`AudioEmitter` + `AudioEmitterSystem`, outside this folder under `sound/ecs/audio/`) binds it to the
10
- game. You can use the core standalone (tools, previews, tests) with nothing but a `BaseAudioContext`
11
- and a `BufferProvider`.
12
-
13
- > The name "sopra" is internal. The player-facing / integration layer uses familiar terms
14
- > (`AudioEmitter`, `AudioEventTrigger`); "sopra" never appears in user-facing API.
15
-
16
- ---
17
-
18
- ## The one idea you must understand: definition vs. runtime
19
-
20
- Everything in Sopra is split into two halves. Get this and the rest follows.
21
-
22
- | | **Definition** (authored data) | **Runtime** (transient playback) |
23
- |---|---|---|
24
- | What | `EventDescription`, the `*AudioClip` graph, `BusDefinition`, `*AudioEffect`, `ParameterDefinition`, `MixerSnapshot`, `DuckingRule` | `EventInstance`, `Voice`, the live WebAudio node graph |
25
- | Lifetime | Immutable, shared, **serializable** (save/load, network) | Created on trigger, pooled, **never serialized** |
26
- | Holds | Spec only — urls, gains in dB, curves, child clips, routing | WebAudio nodes, the resolved timeline, the playhead, RNG state |
27
- | Lives in | `definition/` | `runtime/` |
28
-
29
- A definition is a recipe. Playing it spawns a transient `EventInstance` that reads the recipe once,
30
- resolves a concrete timeline of leaf plays, and drives WebAudio nodes. The same definition can back
31
- many simultaneous instances. **Definitions never hold playback state** — that is the rule the whole
32
- architecture defends.
33
-
34
- ```
35
- EventDescription (definition)
36
- │ engine.playEvent(...)
37
-
38
- EventInstance (runtime) ──spawns──► Voice ──► bus chain ──► destination
39
- ```
40
-
41
- ---
42
-
43
- ## Directory map
44
-
45
- ```
46
- sopra/
47
- SopraEngine.js the facade: owns the bus graph, parameters, active instances, the clock
48
- definition/ immutable, serializable authored data (+ co-located *SerializationAdapter.js)
49
- EventDescription.js the triggerable unit (root clip + routing + 3D + voice config)
50
- BusDefinition.js one node in the mixer tree (gain, effect chain, aux sends)
51
- ParameterDefinition.js a declared RTPC parameter
52
- MixerSnapshot.js a named set of per-bus target gains
53
- DuckingRule.js an emulated sidechain duck (trigger bus → target bus)
54
- SopraPanningModel.js HRTF | EqualPower
55
- VoiceStealMode.js None | Oldest | Quietest
56
- clip/ the clip graph — what actually makes sound
57
- AbstractAudioClip.js base; planTimeline() + loops() + collectSampleClips()
58
- SampleAudioClip.js a single audio asset (the only buffer-referencing leaf)
59
- SilenceAudioClip.js dead air (a gap in a sequence)
60
- SequenceContainerAudioClip.js plays children in order
61
- RandomContainerAudioClip.js plays one child at weighted random (avoid-repeat)
62
- SwitchContainerAudioClip.js plays one child chosen by a parameter (discrete)
63
- BlendContainerAudioClip.js plays several children, gains driven by a parameter (continuous)
64
- effect/ bus insert effects
65
- AbstractAudioEffect.js base; build(ctx) → { input, output }
66
- EqEffect.js BiquadFilter
67
- CompressorEffect.js DynamicsCompressor
68
- ReverbEffect.js Convolver (procedural impulse response)
69
- runtime/ transient playback state
70
- EventInstance.js one triggered playing of an event (cursor-based scheduler)
71
- Voice.js / VoicePool.js one pooled AudioBufferSourceNode + its gain/detune
72
- BusGraph.js instantiates BusDefinitions into chained WebAudio nodes
73
- VoiceManager.js per-event instance limits + voice stealing
74
- ParameterStore.js live RTPC values + change bindings
75
- SopraPlaybackContext.js per-source seeded RNG + random-container history (determinism)
76
- asset/ how the engine gets decoded buffers
77
- BufferProvider.js the interface (tryGet sync / get async)
78
- AssetManagerBufferProvider.js production: pulls from the meep AssetManager
79
- StubBufferProvider.js in-memory, for tests / offline
80
- serialization/ sopraJSON (type-tag JSON dispatch) + the binary registry + test harness
81
- util/ buildAttenuationCurve, fadeOutAndStop, MockAudioContext
82
- legacy/ SoundEmitter sopra translator (strangler migration only)
83
- ```
84
-
85
- The ECS binding lives **outside** this folder, under `sound/ecs/audio/`: `AudioEmitter.js` (component),
86
- `AudioEmitterSystem.js` (system), and the spatial-scaling layer `SpatialAudioIndex.js` (BVH cull) +
87
- `LiveEmitterSet.js` (live/dormant budget) that lets it carry ~100k 3D emitters (see ECS integration).
88
-
89
- ---
90
-
91
- ## Quick start (standalone)
92
-
93
- The core needs three things: an audio context, a destination node, and a `BufferProvider`.
94
-
95
- ```js
96
- import { SopraEngine } from "./SopraEngine.js";
97
- import { BufferProvider } from "./asset/BufferProvider.js";
98
- import { EventDescription } from "./definition/EventDescription.js";
99
- import { SampleAudioClip } from "./definition/clip/SampleAudioClip.js";
100
-
101
- // 1. Tell Sopra how to obtain decoded AudioBuffers. Here, a trivial in-memory provider.
102
- class MapBufferProvider extends BufferProvider {
103
- constructor(map) { super(); this.map = map; } // Map<url, AudioBuffer>
104
- tryGet(url, usingAlias) { return this.map.get(url) ?? null; } // sync fast path (already decoded)
105
- get(url, usingAlias) { // async path (rejects if unavailable)
106
- const b = this.map.get(url);
107
- return b ? Promise.resolve(b) : Promise.reject(new Error(`missing ${url}`));
108
- }
109
- }
110
-
111
- const ctx = new AudioContext();
112
- const buffers = new Map([["click.ogg", await ctx.decodeAudioData(bytes)]]);
113
- const engine = new SopraEngine(ctx, ctx.destination, new MapBufferProvider(buffers));
114
-
115
- // 2. Describe an event (a definition). Reuse it as many times as you like.
116
- const click = EventDescription.from("ui.click", SampleAudioClip.from("click.ogg"), { busId: "effects" });
117
-
118
- // 3. Play it. playOneShot auto-releases when the sound finishes.
119
- engine.playOneShot(click);
120
-
121
- // 4. Drive the engine once per frame — this is mandatory (see "The update loop").
122
- function frame() { engine.update(); requestAnimationFrame(frame); }
123
- frame();
124
- ```
125
-
126
- `SopraEngine` ships with a default bus tree — `master` → (`effects`, `music`, `ambient`) — at the
127
- legacy mix, so `busId: "effects"` works out of the box.
128
-
129
- ---
130
-
131
- ## The clip graph
132
-
133
- `EventDescription.rootClip` is a tree of `AbstractAudioClip` nodes. Each node implements
134
- `planTimeline()`, which the instance calls **once** at trigger time to flatten the tree into a list of
135
- timed leaf plays. Gain (dB) and pitch (cents) accumulate additively down the tree and are resolved
136
- there the runtime never sees an "inherit" sentinel.
137
-
138
- Only `SampleAudioClip` references a buffer; everything else arranges, selects, or layers.
139
-
140
- ### SampleAudioClip — a single asset (leaf)
141
-
142
- ```js
143
- SampleAudioClip.from("explosion.ogg", {
144
- gain: -3, // dB, added to the event/parent gain
145
- pitch: 0, // cents
146
- loop: false,
147
- loopStart: 0, loopEnd: 0,
148
- pitchRandom: 50, // ± cents, randomised per trigger (deterministic, see below)
149
- gainRandom: 2, // ± dB, randomised per trigger
150
- usingAlias: false // if true, `url` is an AssetManager alias, not a path
151
- });
152
- ```
153
-
154
- A `loop: true` sample plays forever — it makes its event a **persistent source** (see one-shot
155
- vs. persistent below).
156
-
157
- ### SilenceAudioClip — a gap
158
-
159
- ```js
160
- SilenceAudioClip.from(0.5); // 0.5s of dead air, e.g. between sequence steps
161
- ```
162
-
163
- ### SequenceContainerAudioClip — children in order
164
-
165
- ```js
166
- SequenceContainerAudioClip.from([
167
- SampleAudioClip.from("intro.ogg"),
168
- SilenceAudioClip.from(0.25),
169
- SampleAudioClip.from("loop.ogg", { loop: true }) // a looping child is terminal: the sequence
170
- ]); // cannot advance past it
171
- ```
172
-
173
- ### RandomContainerAudioClip — one child at weighted random
174
-
175
- Picks one child per trigger, avoiding the last N picks. Weights are **per-child, one entry per child**
176
- (default `1` = uniform); a weight of `0` means "never picked".
177
-
178
- ```js
179
- RandomContainerAudioClip.from(
180
- [SampleAudioClip.from("step1.ogg"), SampleAudioClip.from("step2.ogg"), SampleAudioClip.from("step3.ogg")],
181
- { avoidRepeatingLast: 1, weights: [3, 1, 1] } // step1 ~3× as likely; never the same twice in a row
182
- );
183
- ```
184
-
185
- Selection is **deterministic** given a seed (see Determinism) — critical for networked play.
186
-
187
- ### SwitchContainerAudioClip — one child by a parameter (discrete)
188
-
189
- Reads a parameter once at trigger, rounds + clamps it to a child index. Classic surface-switch:
190
-
191
- ```js
192
- SwitchContainerAudioClip.from(
193
- [grassClip, stoneClip, woodClip],
194
- { parameter: "surface", defaultValue: 0 } // surface 0→grass, 1→stone, 2→wood
195
- );
196
- ```
197
-
198
- ### BlendContainerAudioClip — several children, gains by a parameter (continuous)
199
-
200
- Reads a parameter once at trigger and plays every child whose blend gain is > 0, each scaled by its
201
- per-child `AnimationCurve` (parameter value linear gain). A child with no curve is always full.
202
-
203
- ```js
204
- import { AnimationCurve } from "../../animation/curve/AnimationCurve.js";
205
-
206
- BlendContainerAudioClip.from(
207
- [calmLayer, stormLayer],
208
- {
209
- parameter: "weather",
210
- blends: [
211
- AnimationCurve.linear(0, 1, 1, 0), // calm: full at 0, silent at 1
212
- AnimationCurve.linear(0, 0, 1, 1) // storm: silent at 0, full at 1
213
- ]
214
- }
215
- );
216
- ```
217
-
218
- > v1 Blend is a **trigger-time snapshot**: the mix is fixed when the event starts; it does not
219
- > re-blend live as the parameter sweeps afterwards. Live per-voice re-blend is a planned follow-up.
220
-
221
- ---
222
-
223
- ## Events
224
-
225
- `EventDescription` is the triggerable unit. It wraps a root clip with routing, 3D, and voice config.
226
-
227
- ```js
228
- import { SopraPanningModel } from "./definition/SopraPanningModel.js";
229
- import { VoiceStealMode } from "./definition/VoiceStealMode.js";
230
-
231
- EventDescription.from("monster.roar", rootClip, {
232
- busId: "effects", // which mixer bus this routes to
233
- gainDb: 0, // event master gain
234
- is3D: true, // enable spatialization
235
- panningModel: SopraPanningModel.HRTF,
236
- distanceMin: 2, // panner reference distance
237
- distanceMax: 60, // beyond this the source is culled (virtualized)
238
- attenuation: AnimationCurve.linear(0, 1, 60, 0), // distance linear gain multiplier
239
- maxInstances: 8, // concurrency cap for this event
240
- priority: 0,
241
- stealMode: VoiceStealMode.Oldest,
242
- virtualThresholdDb: -60 // below this post-attenuation gain a voice goes virtual
243
- });
244
- ```
245
-
246
- Non-3D events ignore the 3D fields; `attenuation` defaults to a flat-1 curve (no attenuation).
247
-
248
- An `EventDescription` is a plain object — hold it wherever you like (a module constant, a component
249
- field, a map of your own) and pass it straight to the playback methods:
250
-
251
- ```js
252
- engine.playOneShot(roar, { position: monsterPos });
253
- ```
254
-
255
- ---
256
-
257
- ## Playback and instance control
258
-
259
- `playEvent` / `playOneShot` / `createInstance` / `crossfade` all take an `EventDescription` directly —
260
- there is no id registry. Keep a reference to the description and pass it in.
261
-
262
- ```js
263
- // fire-and-forget; auto-releases when the content finishes
264
- engine.playOneShot(click);
265
-
266
- // keep the handle to control it; persistent until you stop it
267
- const inst = engine.playEvent(music, { busId: "music" });
268
-
269
- // build without starting (e.g. to configure first), then start manually
270
- const i = engine.createInstance(music);
271
- i.start(engine.currentTime);
272
- ```
273
-
274
- `playEvent` returns the `EventInstance`, or **`null`** if the play was denied by the voice limit
275
- (steal mode `None`). Always handle the null.
276
-
277
- ### One-shot vs. persistent
278
-
279
- - `oneShot: true` (what `playOneShot` sets) — the instance **self-releases** when its timeline
280
- finishes, and is killed by a `maxLifetime` backstop (default 60s) as a safety net.
281
- - `oneShot: false` (default for `playEvent`) the instance **persists** until you stop it. Use this
282
- for looping music/ambience (whose root clip loops). A *non-looping*, non-one-shot instance plays
283
- once then sits idle (silent) until stopped usually not what you want, so loop the clip or use
284
- `playOneShot`.
285
-
286
- The ECS `AudioEmitterSystem` derives `oneShot` automatically from `event.rootClip.loops()`.
287
-
288
- ### EventInstance API
289
-
290
- ```js
291
- inst.setGainDb(-6); // immediate volume (dB), composes with 3D attenuation
292
- inst.fadeToGainDb(0, 2); // click-safe ramp to 0 dB over 2s (does not stop)
293
- inst.fadeOutAndStop(1.5); // fade to silence over 1.5s, then stop (audio-clock deadline)
294
- inst.seek(10); // jump the playhead to 10s (keeps the resolved timeline + RNG)
295
- inst.restart(); // seek(0)
296
- inst.stop(); // stop now, tear down nodes, fire onEnded
297
-
298
- inst.playhead; // current position in seconds
299
- inst.gainDb; // current instance gain (dB)
300
- inst.state; // EventInstanceState: Initial | Playing | Stopped
301
- inst.currentGain; // current post-attenuation linear gain
302
- inst.onEnded.add(i => { ... }); // fires once when the instance fully stops
303
- ```
304
-
305
- ### Crossfade
306
-
307
- ```js
308
- // fade `current` out and a fresh play of `calmTrack` in, over 3s
309
- const next = engine.crossfade(current, calmTrack, { busId: "music", duration: 3 });
310
- ```
311
-
312
- ---
313
-
314
- ## Buses, effects, and sends
315
-
316
- The mixer is a tree of `BusDefinition`s. Each bus is `input → effect[0] → … → effect[n] → gain`, and
317
- its output routes into its parent's input (or the engine destination for a root bus, `parentId: ""`).
318
-
319
- `setBuses` **replaces** the whole tree (and rebuilds the WebAudio graph). Effects and sends are wired
320
- at build time; there is no live effect insertion.
321
-
322
- ```js
323
- import { BusDefinition } from "./definition/BusDefinition.js";
324
- import { EqEffect, EqFilterType } from "./definition/effect/EqEffect.js";
325
- import { CompressorEffect } from "./definition/effect/CompressorEffect.js";
326
- import { ReverbEffect } from "./definition/effect/ReverbEffect.js";
327
-
328
- engine.setBuses([
329
- BusDefinition.from("master", { gainDb: 0 }), // root (parentId "")
330
- BusDefinition.from("music", { parentId: "master", gainDb: -6,
331
- effects: [CompressorEffect.from({ threshold: -18, ratio: 4 })] }),
332
- BusDefinition.from("sfx", { parentId: "master",
333
- effects: [EqEffect.from({ filterType: EqFilterType.Highshelf, frequency: 6000, gainDb: -3 })],
334
- sends: [{ targetBusId: "reverb", levelDb: -9 }] }), // post-fader aux send
335
- BusDefinition.from("reverb", { parentId: "master", // a "reverb bus": others send to it
336
- effects: [ReverbEffect.from({ decaySeconds: 2.0, decayPower: 2 })] })
337
- ]);
338
- ```
339
-
340
- A **send** routes a post-fader copy of a bus into another bus at a given level — the standard way to
341
- share one reverb across many sources. `ReverbEffect` generates its impulse response procedurally
342
- (decaying noise), so there is no IR asset to load and `build` stays synchronous.
343
-
344
- Live bus volume (linear gain):
345
-
346
- ```js
347
- engine.getBusVolume("music"); // → linear gain
348
- engine.setBusVolume("music", 0.5);
349
- ```
350
-
351
- ---
352
-
353
- ## Parameters (RTPC)
354
-
355
- Named float values that drive selection (`Switch`/`Blend`) and automation. They live in the
356
- `ParameterStore`; `Switch`/`Blend` read them **once at trigger time**.
357
-
358
- ```js
359
- engine.defineParameter("surface", 0); // declare with a default (no-op if already defined)
360
- engine.setParameter("surface", 1); // 1 the next footstep Switch picks child 1 (stone)
361
- engine.getParameter("surface"); // → 1
362
-
363
- // Drive a bus volume from a parameter through a curve — updates live as the parameter changes.
364
- engine.bindParameterToBusVolume("tension", "music", AnimationCurve.linear(0, 0.2, 1, 1));
365
- engine.setParameter("tension", 0.8); // music bus volume follows the curve immediately
366
-
367
- // Or bind an arbitrary callback (runs on change, and once now if already set).
368
- engine.bindParameter("tension", value => console.log("tension is", value));
369
- ```
370
-
371
- Note the timing difference: bus-volume bindings update **live**; clip selection (`Switch`/`Blend`) is
372
- sampled **when the event is triggered**, so changing a parameter affects the *next* play, not voices
373
- already sounding.
374
-
375
- ---
376
-
377
- ## 3D / spatialization
378
-
379
- Set the listener position, give 3D events a position, and call `update()` each frame to re-attenuate.
380
-
381
- ```js
382
- engine.setListener(camera.position); // a shared Vector3
383
-
384
- const inst = engine.playOneShot(roar, { position: monster.position });
385
- // `position` is held by reference moving the Vector3 moves the source; update() re-evaluates.
386
- ```
387
-
388
- Per instance, distance attenuation is a custom gain node driven by `attenuation.evaluate(distance)`;
389
- the `PannerNode` does direction only (rolloff disabled). Beyond `distanceMax`, or below
390
- `virtualThresholdDb`, the instance goes **virtual**: its voices stop while the playhead keeps
391
- advancing, and revive at the correct child + buffer offset when it becomes audible again.
392
-
393
- Virtualization bounds the *voice* (source-node) count among the **live** instances. The bigger lever
394
- for huge worlds is one tier up, in the ECS layer: the `LiveEmitterSet` keeps all-but-a-budget of the
395
- registered 3D emitters **dormant** (not even an `EventInstance`), so a scene can register ~100k
396
- emitters and still tick only ~budget of them. See **ECS integration**.
397
-
398
- ---
399
-
400
- ## Voice limits and stealing
401
-
402
- `VoiceManager` caps concurrent instances **per event** at `EventDescription.maxInstances` and steals
403
- when full, per the event's `stealMode`:
404
-
405
- - `None` — over the limit, the new play is dropped (`playEvent` returns `null`).
406
- - `Oldest` — stop the earliest-started instance.
407
- - `Quietest` — stop the instance with the lowest post-attenuation gain.
408
-
409
- Defaults (`maxInstances: 32`, `stealMode: Oldest`) effectively never engage until content opts into a
410
- low limit e.g. a machine-gun: `maxInstances: 6`.
411
-
412
- ---
413
-
414
- ## Mixer snapshots and ducking
415
-
416
- ### Snapshots — shift the whole mix between game states
417
-
418
- A `MixerSnapshot` is a named set of per-bus target gains (dB). Apply it instantly or as a click-safe
419
- ramp.
420
-
421
- ```js
422
- import { MixerSnapshot } from "./definition/MixerSnapshot.js";
423
-
424
- const combat = MixerSnapshot.from("combat", [
425
- { busId: "music", gainDb: 0 },
426
- { busId: "ambient", gainDb: -12 }
427
- ]);
428
-
429
- engine.applySnapshot(combat, { duration: 1.5 }); // ramp into the combat mix over 1.5s
430
- const saved = engine.captureSnapshot("pre-combat", ["music", "ambient"]); // grab the current mix to restore later
431
- ```
432
-
433
- ### Ducking — emulated sidechain
434
-
435
- WebAudio has no native sidechain, so this is **play-state** ducking: while any instance is live on the
436
- trigger bus, the target bus is attenuated by `duckDb` (smooth `setTargetAtTime` attack/release),
437
- restored to its captured nominal when the trigger goes quiet.
438
-
439
- ```js
440
- import { DuckingRule } from "./definition/DuckingRule.js";
441
-
442
- // duck music by 8 dB whenever anything plays on the effects bus
443
- engine.addDucker(DuckingRule.from({
444
- triggerBusId: "effects", targetBusId: "music",
445
- duckDb: -8, attack: 0.1, release: 0.4
446
- }));
447
-
448
- engine.clearDuckers(); // remove all rules (restoring any currently-ducked target)
449
- ```
450
-
451
- The trigger matches by `instance.busId`. Duckers are evaluated every `update()`.
452
-
453
- ---
454
-
455
- ## Determinism
456
-
457
- Random selection (`RandomContainer`, per-trigger pitch/gain randomisation) runs on a **seeded** RNG
458
- held in a `SopraPlaybackContext`. Same seed identical pick stream networked clients stay in sync.
459
-
460
- ```js
461
- // seed from a replicated source, e.g. entity id + fixed-step tick
462
- engine.playEvent(footsteps, { seed: entityId * 31 + tick });
463
-
464
- // or supply your own context (its history persists across re-triggers — reuse one per emitter)
465
- import { SopraPlaybackContext } from "./runtime/SopraPlaybackContext.js";
466
- const ctx = new SopraPlaybackContext(seed);
467
- engine.playEvent(footsteps, { playbackContext: ctx });
468
- ```
469
-
470
- If you supply neither, the engine's shared `defaultPlaybackContext` is used.
471
-
472
- ---
473
-
474
- ## The update loop
475
-
476
- `SopraEngine` is driven by a single clock — the injected `AudioContext.currentTime`. **You must call
477
- `engine.update()` once per frame.** It advances every instance (scheduling/virtualization, 3D
478
- attenuation, fade-out deadlines, one-shot release) and evaluates ducking rules.
479
-
480
- ```js
481
- engine.update(); // uses the live clock
482
- engine.update(someTime); // or pass an explicit context time (tests do this)
483
- ```
484
-
485
- Nothing self-schedules with `setTimeout`; fades and stops are resolved against the audio clock inside
486
- `update`, so a late frame never desynchronises audio.
487
-
488
- ---
489
-
490
- ## Serialization
491
-
492
- Definitions are fully serializable, two ways:
493
-
494
- **JSON** — every definition has `toJSON()` / `fromJSON()`. Polymorphic clip/effect trees go through
495
- type-tagged dispatch in `serialization/sopraJSON.js`:
496
-
497
- ```js
498
- const json = description.toJSON();
499
- const restored = new EventDescription();
500
- restored.fromJSON(json);
501
- ```
502
-
503
- **Binary** — each class has a co-located `<Class>SerializationAdapter.js`. Register them all on a
504
- `BinarySerializationRegistry` with `populateSopraSerializationRegistry`:
505
-
506
- ```js
507
- import { BinarySerializationRegistry } from "../../ecs/storage/binary/BinarySerializationRegistry.js";
508
- import { populateSopraSerializationRegistry } from "./serialization/populateSopraSerializationRegistry.js";
509
-
510
- const registry = new BinarySerializationRegistry();
511
- populateSopraSerializationRegistry(registry);
512
- ```
513
-
514
- Numeric fields are stored as float32. `serialization/sopraSerializationHarness.js` provides
515
- `makeSopraObjectAdapter()` + `binaryRoundTrip()` for round-trip tests.
516
-
517
- ---
518
-
519
- ## ECS integration
520
-
521
- In-game you almost never touch `SopraEngine` directly — you add an `AudioEmitter` component.
522
-
523
- ```js
524
- import { AudioEmitter } from "../ecs/audio/AudioEmitter.js";
525
-
526
- const emitter = new AudioEmitter();
527
- emitter.event = EventDescription.from(
528
- "torch.loop", SampleAudioClip.from("torch.ogg", { loop: true }),
529
- { busId: "ambient", is3D: true, distanceMax: 20 }
530
- );
531
- emitter.autoplay = true; // this is a looping 3D event -> spatially managed (sounds when the
532
- // listener is in range + within budget); see the two play paths below
533
- emitter.volume.set(0.8); // live multiplier on top of the event gain (Vector1)
534
-
535
- entity.add(emitter).add(new Transform(...));
536
- ```
537
-
538
- `AudioEmitter` **owns a full `EventDescription`** — the whole clip graph, routing, 3D, voice config —
539
- as first-class ECS data. There is no global "bank"; the `EntityComponentDataset` *is* the data store.
540
-
541
- `AudioEmitterSystem(assetManager, soundEngine, liveEmitterSetOptions?)` drives all emitters. It shares
542
- the one `SopraEngine` (via `SoundEngine.createSopra(bufferProvider)`, idempotent), feeds the
543
- `SoundListener` pose, and ticks the engine each frame. *How* an emitter plays is decided **once at
544
- link**, from `autoplay` + the event:
545
-
546
- - **Spatially managed** — `autoplay && is3D && looping`. Registered with a `LiveEmitterSet` (a BVH
547
- broadphase, `SpatialAudioIndex`, + a live/dormant lifecycle) and left **dormant**: no instance, no
548
- nodes, no per-frame work just one BVH leaf. Each frame the system culls by the listener position and
549
- promotes the nearest in-range emitters up to a global voice **budget** (default 64), demoting the rest
550
- (a hard cut when culled out of range, a click-safe fade on contention). This is what lets the engine
551
- carry **~100,000 registered emitters** while only the audible ~budget ever hold WebAudio nodes the
552
- per-frame cost tracks the budget, not the registered count.
553
- - **Direct** any other `autoplay` event (2D sounds like music / ambience beds, or finite 3D
554
- one-shots): played immediately on link, stopped on unlink. Nothing to cull by distance, and these are
555
- few.
556
- - **Inert** — `autoplay === false`: neither played nor registered.
557
-
558
- The entity `Transform.position` is held by the instance (a 3D source tracks the moving entity);
559
- `AudioEmitter.volume` is a live multiplier carried **through** promote/demote, so a managed emitter
560
- keeps its volume across a cull. `system.instanceFor(entity)` returns the active instance (or `null`
561
- while dormant).
562
-
563
- > **Content rule for managed crowds:** the live `budget` and an event's `maxInstances` are independent
564
- > caps. If many emitters share one *content-equal* `EventDescription` (e.g. 100k identical birds), give
565
- > that event `maxInstances budget` content-equal events share one polyphony bucket, so a lower cap
566
- > would gate the budget and fewer than `budget` would actually sound.
567
-
568
- In production the provider is an `AssetManagerBufferProvider` over the meep `AssetManager` (shared
569
- decode cache + the alias system).
570
-
571
- ---
572
-
573
- ## Testing
574
-
575
- The entire core is unit-testable without real audio: a `MockAudioContext` records the constructed
576
- graph and scheduled events, and a `StubBufferProvider` hands over fake buffers. Tests assert the graph
577
- shape, timeline math, voice lifecycle, deterministic selection, and serialization never sound.
578
-
579
- ```js
580
- import { SopraEngine } from "./SopraEngine.js";
581
- import { MockAudioContext } from "./util/MockAudioContext.js";
582
- import { StubBufferProvider } from "./asset/StubBufferProvider.js";
583
-
584
- const ctx = new MockAudioContext();
585
- const provider = new StubBufferProvider();
586
- provider.set("x.ogg", { duration: 2 }); // a fake buffer is anything with a `duration`
587
- // provider.failOn("y.ogg"); // simulate a failed/missing asset
588
-
589
- const engine = new SopraEngine(ctx, ctx.destination, provider);
590
- const inst = engine.playOneShot(EventDescription.from("e", SampleAudioClip.from("x.ogg")));
591
-
592
- ctx.currentTime = 2;
593
- engine.update(2);
594
- // inst.state === EventInstanceState.Stopped (the one-shot self-released at the end)
595
- ```
596
-
597
- Run the suite from the repo root:
598
-
599
- ```
600
- npx jest --config jest.conf.json engine/sound
601
- ```
602
-
603
- ---
604
-
605
- ## Design rules (don't break these)
606
-
607
- - **Definitions are immutable, shared, and serializable.** No WebAudio nodes, no playback state, no
608
- per-instance mutation on a definition. Runtime state lives on `EventInstance` / the
609
- `SopraPlaybackContext`.
610
- - **Gain is composed exactly once.** Authored gains are dB and accumulate down the clip tree at plan
611
- time; bus/instance gains are linear on their own nodes. Don't double-apply.
612
- - **One clock.** Everything reads `AudioContext.currentTime`; no `setTimeout`-driven audio.
613
- - **The core never creates an `AudioContext`** and never imports ECS. It takes a context, a
614
- destination, and a `BufferProvider`.
615
- - **Errors surface.** Expected failures (missing asset, unresolved alias, limit reached) return a
616
- sentinel (`null`) or reject; unexpected errors throw. Nothing is silently swallowed.
617
- - **Determinism is sacred.** Random selection is seeded from a replicated source; never reach for
618
- `Math.random()` in the playback path.
619
-
620
- ---
621
-
622
- ## Glossary
623
-
624
- Acronyms and shorthand used in this document (and the code).
625
-
626
- | Term | Expansion | Meaning in Sopra |
627
- |---|---|---|
628
- | **2D / 3D** | two- / three-dimensional | A 2D event is non-positional (plays straight into its bus); a 3D event (`is3D: true`) is spatialised — panned and distance-attenuated relative to the listener. |
629
- | **API** | Application Programming Interface | The public methods/classes you call. |
630
- | **aux send** | auxiliary send | A post-fader copy of a bus routed into another bus at a level (`BusDefinition.sends`), e.g. feeding a shared reverb bus. |
631
- | **cents** | | Pitch unit; 100 cents = 1 semitone, 1200 = 1 octave. All pitch offsets/randomisation are in cents. |
632
- | **dB** | decibel | Logarithmic gain unit; 0 dB = unity, −6 dB half power. **All authored gains are in dB**; node gains on the WebAudio graph are linear (the two are converted by `dB2Volume` / `volume2dB`). |
633
- | **ECS** | Entity Component System | meep's architecture: entities are ids, data lives in components, behaviour in systems. Sopra's *core* is ECS-agnostic; the ECS binding is `AudioEmitter` + `AudioEmitterSystem`. |
634
- | **EQ** | equaliser | A filter insert (`EqEffect`), backed by a WebAudio `BiquadFilterNode`. |
635
- | **FMOD / Wwise** | (product names) | Industry audio middleware. Sopra borrows their concepts — events, a bus tree, RTPC, voice stealing, snapshots, ducking — but is built on meep's data model, not a bank file. |
636
- | **HRTF** | Head-Related Transfer Function | The high-quality (per-source convolution) 3D panning model; one of the `SopraPanningModel` options (the other, `EqualPower`, is cheaper). |
637
- | **Hz** | hertz | Frequency unit (cycles/second), e.g. an EQ cutoff/centre frequency. |
638
- | **IR** | Impulse Response | The convolution kernel that defines a reverb's space. `ReverbEffect` **generates one procedurally** (decaying noise), so there is no IR asset to load. |
639
- | **JSON** | JavaScript Object Notation | One of the two serialization formats (human-readable; via `toJSON`/`fromJSON` + the type-tag dispatch in `sopraJSON.js`). The other is binary. |
640
- | **Q** | quality factor | A filter's bandwidth/resonance control (`EqEffect.Q`). |
641
- | **RNG** | Random Number Generator | Sopra's RNG is **seeded** (per `SopraPlaybackContext`) so random selection is reproducible across networked clients. |
642
- | **RTPC** | Real-Time Parameter Control | A named float "parameter" (FMOD's term). Drives `Switch`/`Blend` selection and bus-volume automation. Stored in the `ParameterStore`; see `defineParameter` / `setParameter`. |
643
- | **WebAudio** | Web Audio API | The browser audio API Sopra renders through (`AudioContext`, `GainNode`, `PannerNode`, `BiquadFilterNode`, `ConvolverNode`, …). Sopra never creates the `AudioContext` meep's `SoundEngine` does. |
1
+ # Sopra
2
+
3
+ An object-oriented, data-driven sound engine for the meep ECS, loosely modelled on FMOD / Wwise
4
+ concepts (events, a mixer bus tree, RTPC parameters, voice stealing, snapshots, ducking) but built
5
+ around meep's own data model instead of an opaque middleware bank.
6
+
7
+ Sopra is **ECS-agnostic at its core**. The engine (`SopraEngine` + its services) knows nothing about
8
+ entities; it is a self-contained audio renderer driven by a single clock. A thin ECS layer
9
+ (`AudioEmitter` + `AudioEmitterSystem`, outside this folder under `sound/ecs/audio/`) binds it to the
10
+ game. You can use the core standalone (tools, previews, tests) with nothing but a `BaseAudioContext`
11
+ and a `BufferProvider`.
12
+
13
+ > The name "sopra" is internal. The player-facing / integration layer uses familiar terms
14
+ > (`AudioEmitter`, `AudioEventTrigger`); "sopra" never appears in user-facing API.
15
+
16
+ ---
17
+
18
+ ## The one idea you must understand: definition vs. runtime
19
+
20
+ Everything in Sopra is split into two halves. Get this and the rest follows.
21
+
22
+ | | **Definition** (authored data) | **Runtime** (transient playback) |
23
+ |---|---|---|
24
+ | What | `EventDescription`, the `*AudioClip` graph, `BusDefinition`, `*AudioEffect`, `ParameterDefinition`, `MixerSnapshot`, `DuckingRule` | `EventInstance`, `Voice`, the live WebAudio node graph |
25
+ | Lifetime | Immutable, shared, **serializable** (save/load, network) | Created on trigger, pooled, **never serialized** |
26
+ | Holds | Spec only — urls, gains in dB, curves, child clips, routing | WebAudio nodes, the resolved timeline, the playhead, RNG state |
27
+ | Lives in | `definition/` | `runtime/` |
28
+
29
+ A definition is a recipe. Playing it spawns a transient `EventInstance` that reads the recipe once,
30
+ resolves a concrete timeline of leaf plays, and drives WebAudio nodes. The same definition can back
31
+ many simultaneous instances. **Definitions never hold playback state** — that is the rule the whole
32
+ architecture defends.
33
+
34
+ ```
35
+ EventDescription (definition)
36
+ │ engine.playEvent(...)
37
+
38
+ EventInstance (runtime) ──spawns──► Voice ──► bus chain ──► destination
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Directory map
44
+
45
+ ```
46
+ sopra/
47
+ SopraEngine.js the facade: owns the bus graph, parameters, active instances, the clock
48
+ definition/ immutable, serializable authored data (+ co-located *SerializationAdapter.js)
49
+ EventDescription.js the triggerable unit (root clip + routing + 3D + voice config)
50
+ BusDefinition.js one node in the mixer tree (gain, effect chain, aux sends)
51
+ ParameterDefinition.js a declared RTPC parameter
52
+ MixerSnapshot.js a named set of per-bus target gains
53
+ DuckingRule.js an emulated sidechain duck (trigger bus → target bus)
54
+ SopraPanningModel.js HRTF | EqualPower
55
+ VoiceStealMode.js None | Oldest | Quietest
56
+ clip/ the clip graph — what actually makes sound
57
+ AbstractAudioClip.js base; planTimeline() + loops() + collectSampleClips()
58
+ SampleAudioClip.js a single audio asset (the only buffer-referencing leaf)
59
+ SilenceAudioClip.js dead air (a gap in a sequence)
60
+ SequenceContainerAudioClip.js plays children in order
61
+ RandomContainerAudioClip.js plays one child at weighted random (avoid-repeat)
62
+ SwitchContainerAudioClip.js plays one child chosen by a parameter (discrete)
63
+ BlendContainerAudioClip.js plays several children, gains driven by a parameter (continuous)
64
+ effect/ bus insert effects
65
+ AbstractAudioEffect.js base; build(ctx) → { input, output }
66
+ EqEffect.js BiquadFilter
67
+ CompressorEffect.js DynamicsCompressor
68
+ ReverbEffect.js Convolver (procedural impulse response)
69
+ runtime/ transient playback state
70
+ EventInstance.js one triggered playing of an event (cursor-based scheduler)
71
+ Voice.js / VoicePool.js one pooled AudioBufferSourceNode + its gain/detune
72
+ BusGraph.js instantiates BusDefinitions into chained WebAudio nodes
73
+ VoiceManager.js per-event instance limits + voice stealing
74
+ ParameterStore.js live RTPC values + change bindings
75
+ SopraPlaybackContext.js per-source seeded RNG + random-container history (determinism)
76
+ asset/ how the engine gets decoded buffers
77
+ BufferProvider.js the interface (tryGet sync / get async)
78
+ AssetManagerBufferProvider.js production: pulls from the meep AssetManager
79
+ StubBufferProvider.js in-memory, for tests / offline
80
+ serialization/ sopraJSON (type-tag JSON dispatch) + the binary registry + test harness
81
+ util/ buildAttenuationCurve, fadeOutAndStop, MockAudioContext
82
+ legacy/ frozen SoundEmitter/SoundController readers + the converter that
83
+ turns saved ones into AudioEmitter / AudioEventTrigger
84
+ ```
85
+
86
+ The ECS binding lives **outside** this folder, under `sound/ecs/audio/`: `AudioEmitter.js` (component),
87
+ `AudioEmitterSystem.js` (system), and the spatial-scaling layer `SpatialAudioIndex.js` (BVH cull) +
88
+ `LiveEmitterSet.js` (live/dormant budget) that lets it carry ~100k 3D emitters (see ECS integration).
89
+
90
+ ---
91
+
92
+ ## Quick start (standalone)
93
+
94
+ The core needs three things: an audio context, a destination node, and a `BufferProvider`.
95
+
96
+ ```js
97
+ import { SopraEngine } from "./SopraEngine.js";
98
+ import { BufferProvider } from "./asset/BufferProvider.js";
99
+ import { EventDescription } from "./definition/EventDescription.js";
100
+ import { SampleAudioClip } from "./definition/clip/SampleAudioClip.js";
101
+
102
+ // 1. Tell Sopra how to obtain decoded AudioBuffers. Here, a trivial in-memory provider.
103
+ class MapBufferProvider extends BufferProvider {
104
+ constructor(map) { super(); this.map = map; } // Map<url, AudioBuffer>
105
+ tryGet(url, usingAlias) { return this.map.get(url) ?? null; } // sync fast path (already decoded)
106
+ get(url, usingAlias) { // async path (rejects if unavailable)
107
+ const b = this.map.get(url);
108
+ return b ? Promise.resolve(b) : Promise.reject(new Error(`missing ${url}`));
109
+ }
110
+ }
111
+
112
+ const ctx = new AudioContext();
113
+ const buffers = new Map([["click.ogg", await ctx.decodeAudioData(bytes)]]);
114
+ const engine = new SopraEngine(ctx, ctx.destination, new MapBufferProvider(buffers));
115
+
116
+ // 2. Describe an event (a definition). Reuse it as many times as you like.
117
+ const click = EventDescription.from("ui.click", SampleAudioClip.from("click.ogg"), { busId: "effects" });
118
+
119
+ // 3. Play it. playOneShot auto-releases when the sound finishes.
120
+ engine.playOneShot(click);
121
+
122
+ // 4. Drive the engine once per frame — this is mandatory (see "The update loop").
123
+ function frame() { engine.update(); requestAnimationFrame(frame); }
124
+ frame();
125
+ ```
126
+
127
+ `SopraEngine` ships with a default bus tree — `master` → (`effects`, `music`, `ambient`) at the
128
+ legacy mix, so `busId: "effects"` works out of the box.
129
+
130
+ ---
131
+
132
+ ## The clip graph
133
+
134
+ `EventDescription.rootClip` is a tree of `AbstractAudioClip` nodes. Each node implements
135
+ `planTimeline()`, which the instance calls **once** at trigger time to flatten the tree into a list of
136
+ timed leaf plays. Gain (dB) and pitch (cents) accumulate additively down the tree and are resolved
137
+ there — the runtime never sees an "inherit" sentinel.
138
+
139
+ Only `SampleAudioClip` references a buffer; everything else arranges, selects, or layers.
140
+
141
+ ### SampleAudioClip — a single asset (leaf)
142
+
143
+ ```js
144
+ SampleAudioClip.from("explosion.ogg", {
145
+ gain: -3, // dB, added to the event/parent gain
146
+ pitch: 0, // cents
147
+ loop: false,
148
+ loopStart: 0, loopEnd: 0,
149
+ pitchRandom: 50, // ± cents, randomised per trigger (deterministic, see below)
150
+ gainRandom: 2, // ± dB, randomised per trigger
151
+ usingAlias: false // if true, `url` is an AssetManager alias, not a path
152
+ });
153
+ ```
154
+
155
+ A `loop: true` sample plays forever — it makes its event a **persistent source** (see one-shot
156
+ vs. persistent below).
157
+
158
+ ### SilenceAudioClip — a gap
159
+
160
+ ```js
161
+ SilenceAudioClip.from(0.5); // 0.5s of dead air, e.g. between sequence steps
162
+ ```
163
+
164
+ ### SequenceContainerAudioClip — children in order
165
+
166
+ ```js
167
+ SequenceContainerAudioClip.from([
168
+ SampleAudioClip.from("intro.ogg"),
169
+ SilenceAudioClip.from(0.25),
170
+ SampleAudioClip.from("loop.ogg", { loop: true }) // a looping child is terminal: the sequence
171
+ ]); // cannot advance past it
172
+ ```
173
+
174
+ ### RandomContainerAudioClip — one child at weighted random
175
+
176
+ Picks one child per trigger, avoiding the last N picks. Weights are **per-child, one entry per child**
177
+ (default `1` = uniform); a weight of `0` means "never picked".
178
+
179
+ ```js
180
+ RandomContainerAudioClip.from(
181
+ [SampleAudioClip.from("step1.ogg"), SampleAudioClip.from("step2.ogg"), SampleAudioClip.from("step3.ogg")],
182
+ { avoidRepeatingLast: 1, weights: [3, 1, 1] } // step1 ~3× as likely; never the same twice in a row
183
+ );
184
+ ```
185
+
186
+ Selection is **deterministic** given a seed (see Determinism) — critical for networked play.
187
+
188
+ ### SwitchContainerAudioClip — one child by a parameter (discrete)
189
+
190
+ Reads a parameter once at trigger, rounds + clamps it to a child index. Classic surface-switch:
191
+
192
+ ```js
193
+ SwitchContainerAudioClip.from(
194
+ [grassClip, stoneClip, woodClip],
195
+ { parameter: "surface", defaultValue: 0 } // surface 0→grass, 1→stone, 2→wood
196
+ );
197
+ ```
198
+
199
+ ### BlendContainerAudioClip — several children, gains by a parameter (continuous)
200
+
201
+ Reads a parameter once at trigger and plays every child whose blend gain is > 0, each scaled by its
202
+ per-child `AnimationCurve` (parameter value → linear gain). A child with no curve is always full.
203
+
204
+ ```js
205
+ import { AnimationCurve } from "../../animation/curve/AnimationCurve.js";
206
+
207
+ BlendContainerAudioClip.from(
208
+ [calmLayer, stormLayer],
209
+ {
210
+ parameter: "weather",
211
+ blends: [
212
+ AnimationCurve.linear(0, 1, 1, 0), // calm: full at 0, silent at 1
213
+ AnimationCurve.linear(0, 0, 1, 1) // storm: silent at 0, full at 1
214
+ ]
215
+ }
216
+ );
217
+ ```
218
+
219
+ > v1 Blend is a **trigger-time snapshot**: the mix is fixed when the event starts; it does not
220
+ > re-blend live as the parameter sweeps afterwards. Live per-voice re-blend is a planned follow-up.
221
+
222
+ ---
223
+
224
+ ## Events
225
+
226
+ `EventDescription` is the triggerable unit. It wraps a root clip with routing, 3D, and voice config.
227
+
228
+ ```js
229
+ import { SopraPanningModel } from "./definition/SopraPanningModel.js";
230
+ import { VoiceStealMode } from "./definition/VoiceStealMode.js";
231
+
232
+ EventDescription.from("monster.roar", rootClip, {
233
+ busId: "effects", // which mixer bus this routes to
234
+ gainDb: 0, // event master gain
235
+ is3D: true, // enable spatialization
236
+ panningModel: SopraPanningModel.HRTF,
237
+ distanceMin: 2, // panner reference distance
238
+ distanceMax: 60, // beyond this the source is culled (virtualized)
239
+ attenuation: AnimationCurve.linear(0, 1, 60, 0), // distance linear gain multiplier
240
+ maxInstances: 8, // concurrency cap for this event
241
+ priority: 0,
242
+ stealMode: VoiceStealMode.Oldest,
243
+ virtualThresholdDb: -60 // below this post-attenuation gain a voice goes virtual
244
+ });
245
+ ```
246
+
247
+ Non-3D events ignore the 3D fields; `attenuation` defaults to a flat-1 curve (no attenuation).
248
+
249
+ An `EventDescription` is a plain object hold it wherever you like (a module constant, a component
250
+ field, a map of your own) and pass it straight to the playback methods:
251
+
252
+ ```js
253
+ engine.playOneShot(roar, { position: monsterPos });
254
+ ```
255
+
256
+ ---
257
+
258
+ ## Playback and instance control
259
+
260
+ `playEvent` / `playOneShot` / `createInstance` / `crossfade` all take an `EventDescription` directly
261
+ there is no id registry. Keep a reference to the description and pass it in.
262
+
263
+ ```js
264
+ // fire-and-forget; auto-releases when the content finishes
265
+ engine.playOneShot(click);
266
+
267
+ // keep the handle to control it; persistent until you stop it
268
+ const inst = engine.playEvent(music, { busId: "music" });
269
+
270
+ // build without starting (e.g. to configure first), then start manually
271
+ const i = engine.createInstance(music);
272
+ i.start(engine.currentTime);
273
+ ```
274
+
275
+ `playEvent` returns the `EventInstance`, or **`null`** if the play was denied by the voice limit
276
+ (steal mode `None`). Always handle the null.
277
+
278
+ ### One-shot vs. persistent
279
+
280
+ - `oneShot: true` (what `playOneShot` sets) the instance **self-releases** when its timeline
281
+ finishes, and is killed by a `maxLifetime` backstop (default 60s) as a safety net.
282
+ - `oneShot: false` (default for `playEvent`) the instance **persists** until you stop it. Use this
283
+ for looping music/ambience (whose root clip loops). A *non-looping*, non-one-shot instance plays
284
+ once then sits idle (silent) until stopped — usually not what you want, so loop the clip or use
285
+ `playOneShot`.
286
+
287
+ The ECS `AudioEmitterSystem` derives `oneShot` automatically from `event.rootClip.loops()`.
288
+
289
+ ### EventInstance API
290
+
291
+ ```js
292
+ inst.setGainDb(-6); // immediate volume (dB), composes with 3D attenuation
293
+ inst.fadeToGainDb(0, 2); // click-safe ramp to 0 dB over 2s (does not stop)
294
+ inst.fadeOutAndStop(1.5); // fade to silence over 1.5s, then stop (audio-clock deadline)
295
+ inst.seek(10); // jump the playhead to 10s (keeps the resolved timeline + RNG)
296
+ inst.restart(); // seek(0)
297
+ inst.stop(); // stop now, tear down nodes, fire onEnded
298
+
299
+ inst.playhead; // current position in seconds
300
+ inst.gainDb; // current instance gain (dB)
301
+ inst.state; // EventInstanceState: Initial | Playing | Stopped
302
+ inst.currentGain; // current post-attenuation linear gain
303
+ inst.onEnded.add(i => { ... }); // fires once when the instance fully stops
304
+ ```
305
+
306
+ ### Crossfade
307
+
308
+ ```js
309
+ // fade `current` out and a fresh play of `calmTrack` in, over 3s
310
+ const next = engine.crossfade(current, calmTrack, { busId: "music", duration: 3 });
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Buses, effects, and sends
316
+
317
+ The mixer is a tree of `BusDefinition`s. Each bus is `input effect[0] effect[n] gain`, and
318
+ its output routes into its parent's input (or the engine destination for a root bus, `parentId: ""`).
319
+
320
+ `setBuses` **replaces** the whole tree (and rebuilds the WebAudio graph). Effects and sends are wired
321
+ at build time; there is no live effect insertion.
322
+
323
+ ```js
324
+ import { BusDefinition } from "./definition/BusDefinition.js";
325
+ import { EqEffect, EqFilterType } from "./definition/effect/EqEffect.js";
326
+ import { CompressorEffect } from "./definition/effect/CompressorEffect.js";
327
+ import { ReverbEffect } from "./definition/effect/ReverbEffect.js";
328
+
329
+ engine.setBuses([
330
+ BusDefinition.from("master", { gainDb: 0 }), // root (parentId "")
331
+ BusDefinition.from("music", { parentId: "master", gainDb: -6,
332
+ effects: [CompressorEffect.from({ threshold: -18, ratio: 4 })] }),
333
+ BusDefinition.from("sfx", { parentId: "master",
334
+ effects: [EqEffect.from({ filterType: EqFilterType.Highshelf, frequency: 6000, gainDb: -3 })],
335
+ sends: [{ targetBusId: "reverb", levelDb: -9 }] }), // post-fader aux send
336
+ BusDefinition.from("reverb", { parentId: "master", // a "reverb bus": others send to it
337
+ effects: [ReverbEffect.from({ decaySeconds: 2.0, decayPower: 2 })] })
338
+ ]);
339
+ ```
340
+
341
+ A **send** routes a post-fader copy of a bus into another bus at a given level — the standard way to
342
+ share one reverb across many sources. `ReverbEffect` generates its impulse response procedurally
343
+ (decaying noise), so there is no IR asset to load and `build` stays synchronous.
344
+
345
+ Live bus volume (linear gain):
346
+
347
+ ```js
348
+ engine.getBusVolume("music"); // → linear gain
349
+ engine.setBusVolume("music", 0.5);
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Parameters (RTPC)
355
+
356
+ Named float values that drive selection (`Switch`/`Blend`) and automation. They live in the
357
+ `ParameterStore`; `Switch`/`Blend` read them **once at trigger time**.
358
+
359
+ ```js
360
+ engine.defineParameter("surface", 0); // declare with a default (no-op if already defined)
361
+ engine.setParameter("surface", 1); // 1 the next footstep Switch picks child 1 (stone)
362
+ engine.getParameter("surface"); // → 1
363
+
364
+ // Drive a bus volume from a parameter through a curve — updates live as the parameter changes.
365
+ engine.bindParameterToBusVolume("tension", "music", AnimationCurve.linear(0, 0.2, 1, 1));
366
+ engine.setParameter("tension", 0.8); // music bus volume follows the curve immediately
367
+
368
+ // Or bind an arbitrary callback (runs on change, and once now if already set).
369
+ engine.bindParameter("tension", value => console.log("tension is", value));
370
+ ```
371
+
372
+ Note the timing difference: bus-volume bindings update **live**; clip selection (`Switch`/`Blend`) is
373
+ sampled **when the event is triggered**, so changing a parameter affects the *next* play, not voices
374
+ already sounding.
375
+
376
+ ---
377
+
378
+ ## 3D / spatialization
379
+
380
+ Set the listener position, give 3D events a position, and call `update()` each frame to re-attenuate.
381
+
382
+ ```js
383
+ engine.setListener(camera.position); // a shared Vector3
384
+
385
+ const inst = engine.playOneShot(roar, { position: monster.position });
386
+ // `position` is held by reference — moving the Vector3 moves the source; update() re-evaluates.
387
+ ```
388
+
389
+ Per instance, distance attenuation is a custom gain node driven by `attenuation.evaluate(distance)`;
390
+ the `PannerNode` does direction only (rolloff disabled). Beyond `distanceMax`, or below
391
+ `virtualThresholdDb`, the instance goes **virtual**: its voices stop while the playhead keeps
392
+ advancing, and revive at the correct child + buffer offset when it becomes audible again.
393
+
394
+ Virtualization bounds the *voice* (source-node) count among the **live** instances. The bigger lever
395
+ for huge worlds is one tier up, in the ECS layer: the `LiveEmitterSet` keeps all-but-a-budget of the
396
+ registered 3D emitters **dormant** (not even an `EventInstance`), so a scene can register ~100k
397
+ emitters and still tick only ~budget of them. See **ECS integration**.
398
+
399
+ ---
400
+
401
+ ## Voice limits and stealing
402
+
403
+ `VoiceManager` caps concurrent instances **per event** at `EventDescription.maxInstances` and steals
404
+ when full, per the event's `stealMode`:
405
+
406
+ - `None` — over the limit, the new play is dropped (`playEvent` returns `null`).
407
+ - `Oldest` — stop the earliest-started instance.
408
+ - `Quietest` — stop the instance with the lowest post-attenuation gain.
409
+
410
+ Defaults (`maxInstances: 32`, `stealMode: Oldest`) effectively never engage until content opts into a
411
+ low limit — e.g. a machine-gun: `maxInstances: 6`.
412
+
413
+ ---
414
+
415
+ ## Mixer snapshots and ducking
416
+
417
+ ### Snapshots — shift the whole mix between game states
418
+
419
+ A `MixerSnapshot` is a named set of per-bus target gains (dB). Apply it instantly or as a click-safe
420
+ ramp.
421
+
422
+ ```js
423
+ import { MixerSnapshot } from "./definition/MixerSnapshot.js";
424
+
425
+ const combat = MixerSnapshot.from("combat", [
426
+ { busId: "music", gainDb: 0 },
427
+ { busId: "ambient", gainDb: -12 }
428
+ ]);
429
+
430
+ engine.applySnapshot(combat, { duration: 1.5 }); // ramp into the combat mix over 1.5s
431
+ const saved = engine.captureSnapshot("pre-combat", ["music", "ambient"]); // grab the current mix to restore later
432
+ ```
433
+
434
+ ### Ducking — emulated sidechain
435
+
436
+ WebAudio has no native sidechain, so this is **play-state** ducking: while any instance is live on the
437
+ trigger bus, the target bus is attenuated by `duckDb` (smooth `setTargetAtTime` attack/release),
438
+ restored to its captured nominal when the trigger goes quiet.
439
+
440
+ ```js
441
+ import { DuckingRule } from "./definition/DuckingRule.js";
442
+
443
+ // duck music by 8 dB whenever anything plays on the effects bus
444
+ engine.addDucker(DuckingRule.from({
445
+ triggerBusId: "effects", targetBusId: "music",
446
+ duckDb: -8, attack: 0.1, release: 0.4
447
+ }));
448
+
449
+ engine.clearDuckers(); // remove all rules (restoring any currently-ducked target)
450
+ ```
451
+
452
+ The trigger matches by `instance.busId`. Duckers are evaluated every `update()`.
453
+
454
+ ---
455
+
456
+ ## Determinism
457
+
458
+ Random selection (`RandomContainer`, per-trigger pitch/gain randomisation) runs on a **seeded** RNG
459
+ held in a `SopraPlaybackContext`. Same seed → identical pick stream → networked clients stay in sync.
460
+
461
+ ```js
462
+ // seed from a replicated source, e.g. entity id + fixed-step tick
463
+ engine.playEvent(footsteps, { seed: entityId * 31 + tick });
464
+
465
+ // or supply your own context (its history persists across re-triggers — reuse one per emitter)
466
+ import { SopraPlaybackContext } from "./runtime/SopraPlaybackContext.js";
467
+ const ctx = new SopraPlaybackContext(seed);
468
+ engine.playEvent(footsteps, { playbackContext: ctx });
469
+ ```
470
+
471
+ If you supply neither, the engine's shared `defaultPlaybackContext` is used.
472
+
473
+ ---
474
+
475
+ ## The update loop
476
+
477
+ `SopraEngine` is driven by a single clock the injected `AudioContext.currentTime`. **You must call
478
+ `engine.update()` once per frame.** It advances every instance (scheduling/virtualization, 3D
479
+ attenuation, fade-out deadlines, one-shot release) and evaluates ducking rules.
480
+
481
+ ```js
482
+ engine.update(); // uses the live clock
483
+ engine.update(someTime); // or pass an explicit context time (tests do this)
484
+ ```
485
+
486
+ Nothing self-schedules with `setTimeout`; fades and stops are resolved against the audio clock inside
487
+ `update`, so a late frame never desynchronises audio.
488
+
489
+ ---
490
+
491
+ ## Serialization
492
+
493
+ Definitions are fully serializable, two ways:
494
+
495
+ **JSON** every definition has `toJSON()` / `fromJSON()`. Polymorphic clip/effect trees go through
496
+ type-tagged dispatch in `serialization/sopraJSON.js`:
497
+
498
+ ```js
499
+ const json = description.toJSON();
500
+ const restored = new EventDescription();
501
+ restored.fromJSON(json);
502
+ ```
503
+
504
+ **Binary** each class has a co-located `<Class>SerializationAdapter.js`. Register them all on a
505
+ `BinarySerializationRegistry` with `populateSopraSerializationRegistry`:
506
+
507
+ ```js
508
+ import { BinarySerializationRegistry } from "../../ecs/storage/binary/BinarySerializationRegistry.js";
509
+ import { populateSopraSerializationRegistry } from "./serialization/populateSopraSerializationRegistry.js";
510
+
511
+ const registry = new BinarySerializationRegistry();
512
+ populateSopraSerializationRegistry(registry);
513
+ ```
514
+
515
+ Numeric fields are stored as float32. `serialization/sopraSerializationHarness.js` provides
516
+ `makeSopraObjectAdapter()` + `binaryRoundTrip()` for round-trip tests.
517
+
518
+ ---
519
+
520
+ ## ECS integration
521
+
522
+ In-game you almost never touch `SopraEngine` directly — you add an `AudioEmitter` component.
523
+
524
+ ```js
525
+ import { AudioEmitter } from "../ecs/audio/AudioEmitter.js";
526
+
527
+ const emitter = new AudioEmitter();
528
+ emitter.event = EventDescription.from(
529
+ "torch.loop", SampleAudioClip.from("torch.ogg", { loop: true }),
530
+ { busId: "ambient", is3D: true, distanceMax: 20 }
531
+ );
532
+ emitter.autoplay = true; // this is a looping 3D event -> spatially managed (sounds when the
533
+ // listener is in range + within budget); see the two play paths below
534
+ emitter.volume.set(0.8); // live multiplier on top of the event gain (Vector1)
535
+
536
+ entity.add(emitter).add(new Transform(...));
537
+ ```
538
+
539
+ `AudioEmitter` **owns a full `EventDescription`** the whole clip graph, routing, 3D, voice config
540
+ as first-class ECS data. There is no global "bank"; the `EntityComponentDataset` *is* the data store.
541
+
542
+ `AudioEmitterSystem(assetManager, soundEngine, liveEmitterSetOptions?)` drives all emitters. It shares
543
+ the one `SopraEngine` (via `SoundEngine.createSopra(bufferProvider)`, idempotent), feeds the
544
+ `SoundListener` pose, and ticks the engine each frame. *How* an emitter plays is decided **once at
545
+ link**, from `autoplay` + the event:
546
+
547
+ - **Spatially managed** — `autoplay && is3D && looping`. Registered with a `LiveEmitterSet` (a BVH
548
+ broadphase, `SpatialAudioIndex`, + a live/dormant lifecycle) and left **dormant**: no instance, no
549
+ nodes, no per-frame work just one BVH leaf. Each frame the system culls by the listener position and
550
+ promotes the nearest in-range emitters up to a global voice **budget** (default 64), demoting the rest
551
+ (a hard cut when culled out of range, a click-safe fade on contention). This is what lets the engine
552
+ carry **~100,000 registered emitters** while only the audible ~budget ever hold WebAudio nodes — the
553
+ per-frame cost tracks the budget, not the registered count.
554
+ - **Direct** any other `autoplay` event (2D sounds like music / ambience beds, or finite 3D
555
+ one-shots): played immediately on link, stopped on unlink. Nothing to cull by distance, and these are
556
+ few.
557
+ - **Inert** — `autoplay === false`: neither played nor registered.
558
+
559
+ The entity `Transform.position` is held by the instance (a 3D source tracks the moving entity);
560
+ `AudioEmitter.volume` is a live multiplier carried **through** promote/demote, so a managed emitter
561
+ keeps its volume across a cull. `system.instanceFor(entity)` returns the active instance (or `null`
562
+ while dormant).
563
+
564
+ > **Content rule for managed crowds:** the live `budget` and an event's `maxInstances` are independent
565
+ > caps. If many emitters share one *content-equal* `EventDescription` (e.g. 100k identical birds), give
566
+ > that event `maxInstances budget` content-equal events share one polyphony bucket, so a lower cap
567
+ > would gate the budget and fewer than `budget` would actually sound.
568
+
569
+ In production the provider is an `AssetManagerBufferProvider` over the meep `AssetManager` (shared
570
+ decode cache + the alias system).
571
+
572
+ ---
573
+
574
+ ## Testing
575
+
576
+ The entire core is unit-testable without real audio: a `MockAudioContext` records the constructed
577
+ graph and scheduled events, and a `StubBufferProvider` hands over fake buffers. Tests assert the graph
578
+ shape, timeline math, voice lifecycle, deterministic selection, and serialization — never sound.
579
+
580
+ ```js
581
+ import { SopraEngine } from "./SopraEngine.js";
582
+ import { MockAudioContext } from "./util/MockAudioContext.js";
583
+ import { StubBufferProvider } from "./asset/StubBufferProvider.js";
584
+
585
+ const ctx = new MockAudioContext();
586
+ const provider = new StubBufferProvider();
587
+ provider.set("x.ogg", { duration: 2 }); // a fake buffer is anything with a `duration`
588
+ // provider.failOn("y.ogg"); // simulate a failed/missing asset
589
+
590
+ const engine = new SopraEngine(ctx, ctx.destination, provider);
591
+ const inst = engine.playOneShot(EventDescription.from("e", SampleAudioClip.from("x.ogg")));
592
+
593
+ ctx.currentTime = 2;
594
+ engine.update(2);
595
+ // inst.state === EventInstanceState.Stopped (the one-shot self-released at the end)
596
+ ```
597
+
598
+ Run the suite from the repo root:
599
+
600
+ ```
601
+ npx jest --config jest.conf.json engine/sound
602
+ ```
603
+
604
+ ---
605
+
606
+ ## Design rules (don't break these)
607
+
608
+ - **Definitions are immutable, shared, and serializable.** No WebAudio nodes, no playback state, no
609
+ per-instance mutation on a definition. Runtime state lives on `EventInstance` / the
610
+ `SopraPlaybackContext`.
611
+ - **Gain is composed exactly once.** Authored gains are dB and accumulate down the clip tree at plan
612
+ time; bus/instance gains are linear on their own nodes. Don't double-apply.
613
+ - **One clock.** Everything reads `AudioContext.currentTime`; no `setTimeout`-driven audio.
614
+ - **The core never creates an `AudioContext`** and never imports ECS. It takes a context, a
615
+ destination, and a `BufferProvider`.
616
+ - **Errors surface.** Expected failures (missing asset, unresolved alias, limit reached) return a
617
+ sentinel (`null`) or reject; unexpected errors throw. Nothing is silently swallowed.
618
+ - **Determinism is sacred.** Random selection is seeded from a replicated source; never reach for
619
+ `Math.random()` in the playback path.
620
+
621
+ ---
622
+
623
+ ## Glossary
624
+
625
+ Acronyms and shorthand used in this document (and the code).
626
+
627
+ | Term | Expansion | Meaning in Sopra |
628
+ |---|---|---|
629
+ | **2D / 3D** | two- / three-dimensional | A 2D event is non-positional (plays straight into its bus); a 3D event (`is3D: true`) is spatialised — panned and distance-attenuated relative to the listener. |
630
+ | **API** | Application Programming Interface | The public methods/classes you call. |
631
+ | **aux send** | auxiliary send | A post-fader copy of a bus routed into another bus at a level (`BusDefinition.sends`), e.g. feeding a shared reverb bus. |
632
+ | **cents** | | Pitch unit; 100 cents = 1 semitone, 1200 = 1 octave. All pitch offsets/randomisation are in cents. |
633
+ | **dB** | decibel | Logarithmic gain unit; 0 dB = unity, −6 dB half power. **All authored gains are in dB**; node gains on the WebAudio graph are linear (the two are converted by `dB2Volume` / `volume2dB`). |
634
+ | **ECS** | Entity Component System | meep's architecture: entities are ids, data lives in components, behaviour in systems. Sopra's *core* is ECS-agnostic; the ECS binding is `AudioEmitter` + `AudioEmitterSystem`. |
635
+ | **EQ** | equaliser | A filter insert (`EqEffect`), backed by a WebAudio `BiquadFilterNode`. |
636
+ | **FMOD / Wwise** | (product names) | Industry audio middleware. Sopra borrows their concepts events, a bus tree, RTPC, voice stealing, snapshots, ducking — but is built on meep's data model, not a bank file. |
637
+ | **HRTF** | Head-Related Transfer Function | The high-quality (per-source convolution) 3D panning model; one of the `SopraPanningModel` options (the other, `EqualPower`, is cheaper). |
638
+ | **Hz** | hertz | Frequency unit (cycles/second), e.g. an EQ cutoff/centre frequency. |
639
+ | **IR** | Impulse Response | The convolution kernel that defines a reverb's space. `ReverbEffect` **generates one procedurally** (decaying noise), so there is no IR asset to load. |
640
+ | **JSON** | JavaScript Object Notation | One of the two serialization formats (human-readable; via `toJSON`/`fromJSON` + the type-tag dispatch in `sopraJSON.js`). The other is binary. |
641
+ | **Q** | quality factor | A filter's bandwidth/resonance control (`EqEffect.Q`). |
642
+ | **RNG** | Random Number Generator | Sopra's RNG is **seeded** (per `SopraPlaybackContext`) so random selection is reproducible across networked clients. |
643
+ | **RTPC** | Real-Time Parameter Control | A named float "parameter" (FMOD's term). Drives `Switch`/`Blend` selection and bus-volume automation. Stored in the `ParameterStore`; see `defineParameter` / `setParameter`. |
644
+ | **WebAudio** | Web Audio API | The browser audio API Sopra renders through (`AudioContext`, `GainNode`, `PannerNode`, `BiquadFilterNode`, `ConvolverNode`, …). Sopra never creates the `AudioContext` — meep's `SoundEngine` does. |