@woosh/meep-engine 3.16.0 → 3.17.1

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 (431) hide show
  1. package/README.md +8 -72
  2. package/editor/particles/effect/ParticleEffectDocument.d.ts +21 -6
  3. package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
  4. package/editor/particles/effect/ParticleEffectDocument.js +38 -17
  5. package/editor/view/node-graph/NodeGraphClipboard.d.ts +186 -0
  6. package/editor/view/node-graph/NodeGraphClipboard.d.ts.map +1 -0
  7. package/editor/view/node-graph/NodeGraphClipboard.js +231 -0
  8. package/editor/view/node-graph/NodeGraphEditorView.d.ts +59 -1
  9. package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
  10. package/editor/view/node-graph/NodeGraphEditorView.js +248 -5
  11. package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
  12. package/editor/view/node-graph/NodeGraphView.js +84 -8
  13. package/editor/view/node-graph/actions/connection_bind_actions.d.ts +23 -0
  14. package/editor/view/node-graph/actions/connection_bind_actions.d.ts.map +1 -0
  15. package/editor/view/node-graph/actions/connection_bind_actions.js +39 -0
  16. package/editor/view/particles/effect/ParticleCodeEditorView.d.ts.map +1 -1
  17. package/editor/view/particles/effect/ParticleCodeEditorView.js +4 -3
  18. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts +20 -0
  19. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -0
  20. package/editor/view/particles/effect/ParticleCurveEditorView.js +574 -0
  21. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
  22. package/editor/view/particles/effect/ParticleEmitterInspectorView.js +27 -1
  23. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts +24 -0
  24. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -0
  25. package/editor/view/particles/effect/ParticleGradientEditorView.js +472 -0
  26. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts +5 -0
  27. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -1
  28. package/editor/view/particles/effect/ParticleGraphEditorView.js +61 -31
  29. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
  30. package/editor/view/particles/effect/ParticleNodeParametersView.js +33 -0
  31. package/editor/view/particles/effect/particle-editor.css +123 -35
  32. package/package.json +1 -1
  33. package/src/core/binary/allocator/OffsetAllocator.d.ts +25 -16
  34. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  35. package/src/core/binary/allocator/OffsetAllocator.js +10 -1
  36. package/src/core/collection/array/typed/float32_array_hash.d.ts +21 -0
  37. package/src/core/collection/array/typed/float32_array_hash.d.ts.map +1 -0
  38. package/src/core/collection/array/typed/float32_array_hash.js +38 -0
  39. package/src/core/graph/csr/CSRGraph.d.ts +8 -1
  40. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -1
  41. package/src/core/graph/csr/CSRGraph.js +14 -6
  42. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts +24 -0
  43. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts.map +1 -1
  44. package/src/core/model/node-graph/visual/layout/LayoutProblem.js +27 -0
  45. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +26 -0
  46. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
  47. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +28 -0
  48. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts +92 -3
  49. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts.map +1 -1
  50. package/src/core/model/node-graph/visual/layout/RouteGrid.js +405 -242
  51. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts +50 -5
  52. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts.map +1 -1
  53. package/src/core/model/node-graph/visual/layout/RouteSearch.js +160 -24
  54. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts +7 -0
  55. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts.map +1 -1
  56. package/src/core/model/node-graph/visual/layout/RouteSet.js +8 -0
  57. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +9 -3
  58. package/src/core/model/node-graph/visual/layout/layout_build_problem.d.ts.map +1 -1
  59. package/src/core/model/node-graph/visual/layout/layout_build_problem.js +7 -0
  60. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts +9 -3
  61. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +1 -1
  62. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.js +17 -3
  63. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts +9 -6
  64. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts.map +1 -1
  65. package/src/core/model/node-graph/visual/layout/layout_node_graph.js +49 -7
  66. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts +11 -1
  67. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +1 -1
  68. package/src/core/model/node-graph/visual/layout/layout_order_layers.js +135 -16
  69. package/src/core/model/node-graph/visual/layout/route_connections.d.ts +29 -0
  70. package/src/core/model/node-graph/visual/layout/route_connections.d.ts.map +1 -1
  71. package/src/core/model/node-graph/visual/layout/route_connections.js +716 -309
  72. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts +3 -2
  73. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts.map +1 -1
  74. package/src/core/model/node-graph/visual/layout/route_grid_build.js +7 -15
  75. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts +6 -0
  76. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts.map +1 -1
  77. package/src/core/model/node-graph/visual/layout/route_nudge.js +42 -13
  78. package/src/engine/animation/AnimationUtils.js +246 -246
  79. package/src/engine/animation/Animations.js +74 -74
  80. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2078 -2078
  81. package/src/engine/ecs/EventType.d.ts +0 -1
  82. package/src/engine/ecs/EventType.js +1 -26
  83. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +1 -1
  84. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -1
  85. package/src/engine/ecs/ik/ik_write_local_rotation.js +3 -7
  86. package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
  87. package/src/engine/ecs/parent/EntityNode.js +4 -9
  88. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  89. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +360 -364
  90. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts +41 -0
  91. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts.map +1 -0
  92. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.js +40 -0
  93. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +8 -0
  94. package/src/engine/ecs/transform/t64_announce_change.d.ts +10 -7
  95. package/src/engine/ecs/transform/t64_announce_change.d.ts.map +1 -1
  96. package/src/engine/ecs/transform/t64_announce_change.js +12 -12
  97. package/src/engine/ecs/transform/t64_set_rotation_axis_angle.d.ts +25 -0
  98. package/src/engine/ecs/transform/t64_set_rotation_axis_angle.d.ts.map +1 -0
  99. package/src/engine/ecs/transform/t64_set_rotation_axis_angle.js +45 -0
  100. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts +30 -0
  101. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts.map +1 -0
  102. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.js +29 -0
  103. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  104. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +13 -21
  105. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  106. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +4 -8
  107. package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
  108. package/src/engine/graphics3/LightSystem.js +4 -8
  109. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  110. package/src/engine/graphics3/MeshSystem.js +9 -19
  111. package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
  112. package/src/engine/graphics3/ParticleEmitterSystem.js +4 -8
  113. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  114. package/src/engine/graphics3/ShadedGeometrySystem.js +4 -10
  115. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts +1 -1
  116. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
  117. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +4 -8
  118. package/src/engine/intelligence/behavior/ecs/OrbitingBehavior.js +218 -218
  119. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  120. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  121. package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
  122. package/src/engine/sound/ecs/SoundListenerSystem.js +6 -8
  123. package/src/engine/sound/simulation/AcousticSimulator.d.ts +11 -8
  124. package/src/engine/sound/simulation/AcousticSimulator.d.ts.map +1 -1
  125. package/src/engine/sound/simulation/AcousticSimulator.js +45 -36
  126. package/src/engine/sound/simulation/README.md +2 -2
  127. package/src/engine/sound/simulation/core/OcclusionSolver.d.ts.map +1 -1
  128. package/src/engine/sound/simulation/core/VolumeField.d.ts +9 -9
  129. package/src/engine/sound/simulation/core/VolumeField.d.ts.map +1 -1
  130. package/src/engine/sound/simulation/core/VolumeField.js +29 -13
  131. package/src/engine/sound/simulation/core/acoustic_occlusion_solve.d.ts +31 -0
  132. package/src/engine/sound/simulation/core/acoustic_occlusion_solve.d.ts.map +1 -0
  133. package/src/engine/sound/simulation/core/acoustic_occlusion_solve.js +134 -0
  134. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts +0 -4
  135. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts.map +1 -1
  136. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +5 -11
  137. package/src/shade/playground/particle_editor/README.md +43 -2
  138. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
  139. package/src/shade/playground/particle_system/particle_prototype.js +4 -5
  140. package/src/shade/playground/particle_system/particle_scene.js +4 -4
  141. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  142. package/src/shade/playground/volumetrics_froxel/main.js +6 -1
  143. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  144. package/src/shade/renderer/Renderer.js +13 -1
  145. package/src/shade/renderer/particles/DESIGN.md +104 -19
  146. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +64 -50
  147. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  148. package/src/shade/renderer/particles/GPUParticleSystem.js +176 -78
  149. package/src/shade/renderer/particles/ParticleConstants.d.ts +59 -23
  150. package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
  151. package/src/shade/renderer/particles/ParticleConstants.js +66 -23
  152. package/src/shade/renderer/particles/ParticleRenderMode.d.ts +19 -0
  153. package/src/shade/renderer/particles/ParticleRenderMode.d.ts.map +1 -0
  154. package/src/shade/renderer/particles/ParticleRenderMode.js +33 -0
  155. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
  156. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +167 -166
  157. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts +37 -0
  158. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -0
  159. package/src/shade/renderer/particles/data/particle_emitter_record.js +109 -0
  160. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +3 -3
  161. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +303 -303
  162. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +18 -0
  163. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
  164. package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +152 -133
  165. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +0 -11
  166. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
  167. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +720 -621
  168. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
  169. package/src/shade/renderer/particles/graph/compile_particle_graph.js +8 -3
  170. package/src/shade/renderer/particles/graph/flatten_particle_graph.d.ts.map +1 -1
  171. package/src/shade/renderer/particles/graph/flatten_particle_graph.js +244 -213
  172. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -1
  173. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +6 -0
  174. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -1
  175. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +294 -319
  176. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.d.ts.map +1 -1
  177. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.js +524 -517
  178. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts +22 -0
  179. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts.map +1 -0
  180. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.js +517 -0
  181. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
  182. package/src/shade/renderer/particles/graph/groups/simplex_reference.js +185 -159
  183. package/src/shade/renderer/particles/graph/make_particle_group.d.ts.map +1 -1
  184. package/src/shade/renderer/particles/graph/make_particle_group.js +2 -20
  185. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts +17 -0
  186. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts.map +1 -0
  187. package/src/shade/renderer/particles/graph/particle_compare_ops.js +22 -0
  188. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts +28 -8
  189. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts.map +1 -1
  190. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.js +49 -25
  191. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +40 -0
  192. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
  193. package/src/shade/renderer/particles/graph/particle_node_parameters.js +312 -234
  194. package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
  195. package/src/shade/renderer/particles/graph/particle_node_presentation.js +59 -3
  196. package/src/shade/renderer/particles/graph/particle_ramp.d.ts +230 -0
  197. package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -0
  198. package/src/shade/renderer/particles/graph/particle_ramp.js +403 -0
  199. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +7 -1
  200. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
  201. package/src/shade/renderer/particles/graph/validate_particle_graph.js +66 -10
  202. package/src/shade/renderer/particles/graph_particles.d.ts +23 -69
  203. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  204. package/src/shade/renderer/particles/graph_particles.js +105 -262
  205. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  206. package/src/shade/renderer/particles/graph_particles_avboit.js +3 -2
  207. package/src/shade/renderer/particles/graph_particles_billboard.d.ts +37 -0
  208. package/src/shade/renderer/particles/graph_particles_billboard.d.ts.map +1 -0
  209. package/src/shade/renderer/particles/graph_particles_billboard.js +93 -0
  210. package/src/shade/renderer/particles/isa/InstructionStream.d.ts +51 -22
  211. package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
  212. package/src/shade/renderer/particles/isa/InstructionStream.js +98 -38
  213. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +49 -8
  214. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
  215. package/src/shade/renderer/particles/isa/ParticleProgram.js +95 -150
  216. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +306 -64
  217. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  218. package/src/shade/renderer/particles/isa/ParticleVMISA.js +505 -136
  219. package/src/shade/renderer/particles/isa/particle_assembly.d.ts +36 -12
  220. package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
  221. package/src/shade/renderer/particles/isa/particle_assembly.js +354 -139
  222. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts +9 -0
  223. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts.map +1 -0
  224. package/src/shade/renderer/particles/isa/validate_particle_program.js +128 -0
  225. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +23 -0
  226. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
  227. package/src/shade/renderer/particles/layout/ParticleLayout.js +68 -0
  228. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts +77 -0
  229. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -0
  230. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +219 -0
  231. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts +83 -0
  232. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -0
  233. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +283 -0
  234. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +133 -0
  235. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts.map +1 -0
  236. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +334 -0
  237. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts +117 -0
  238. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts.map +1 -0
  239. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +70 -0
  240. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts +97 -0
  241. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts.map +1 -0
  242. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +462 -0
  243. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts +116 -0
  244. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts.map +1 -0
  245. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +687 -0
  246. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +57 -0
  247. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts.map +1 -0
  248. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +860 -0
  249. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts +115 -0
  250. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts.map +1 -0
  251. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.js +264 -0
  252. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +81 -42
  253. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -1
  254. package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +477 -478
  255. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +100 -0
  256. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts.map +1 -0
  257. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +236 -0
  258. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +139 -59
  259. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
  260. package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +764 -647
  261. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +40 -7
  262. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
  263. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +376 -213
  264. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts +30 -3
  265. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -1
  266. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +337 -223
  267. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +24 -38
  268. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  269. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +166 -206
  270. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts +99 -0
  271. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -0
  272. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +313 -0
  273. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts +3 -2
  274. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -1
  275. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.js +198 -197
  276. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -1
  277. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts +19 -0
  278. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
  279. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +678 -561
  280. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts +22 -0
  281. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -0
  282. package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +221 -0
  283. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
  284. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +63 -72
  285. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
  286. package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +87 -86
  287. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
  288. package/src/shade/renderer/particles/optimizer/pass_peephole.js +392 -271
  289. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
  290. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +361 -268
  291. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts +4 -0
  292. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -0
  293. package/src/shade/renderer/particles/optimizer/pass_schedule.js +244 -0
  294. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
  295. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +154 -151
  296. package/src/shade/renderer/particles/particle_test_fixtures.d.ts +20 -0
  297. package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +1 -1
  298. package/src/shade/renderer/particles/particle_test_fixtures.js +229 -203
  299. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +99 -25
  300. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  301. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +438 -286
  302. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +109 -0
  303. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -0
  304. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +127 -0
  305. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +87 -102
  306. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  307. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +184 -163
  308. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +130 -0
  309. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -0
  310. package/src/shade/renderer/particles/runtime/ProgramHeap.js +595 -0
  311. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts +91 -0
  312. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts.map +1 -0
  313. package/src/shade/renderer/particles/runtime/ProgramPlacement.js +106 -0
  314. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +5 -2
  315. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
  316. package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -19
  317. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts +28 -0
  318. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts.map +1 -0
  319. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.js +136 -0
  320. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts +35 -0
  321. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts.map +1 -0
  322. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.js +133 -0
  323. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts +18 -9
  324. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  325. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +20 -80
  326. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts +33 -0
  327. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -0
  328. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +114 -0
  329. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts +8 -0
  330. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  331. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +33 -101
  332. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts +45 -0
  333. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -0
  334. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +123 -0
  335. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts +51 -0
  336. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts.map +1 -0
  337. package/src/shade/renderer/particles/sort/graph_particle_sort.js +120 -0
  338. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts +6 -0
  339. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -0
  340. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +16 -0
  341. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +4 -1
  342. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  343. package/src/shade/renderer/particles/vm/ParticleVMReference.js +261 -140
  344. package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
  345. package/src/shade/renderer/particles/vm/chunk_particle_vm.js +217 -255
  346. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts +43 -0
  347. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts.map +1 -0
  348. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.js +55 -0
  349. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts +62 -0
  350. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts.map +1 -0
  351. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.js +86 -0
  352. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts +22 -0
  353. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts.map +1 -0
  354. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.js +32 -0
  355. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts +9 -0
  356. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts.map +1 -0
  357. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.js +19 -0
  358. package/src/shade/renderer/shader/chunk/noise/psrdnoise/README.md +65 -0
  359. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts +24 -0
  360. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts.map +1 -0
  361. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.js +83 -0
  362. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts +25 -0
  363. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts.map +1 -0
  364. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.js +42 -0
  365. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts +31 -0
  366. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts.map +1 -0
  367. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.js +80 -0
  368. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts +26 -0
  369. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts.map +1 -0
  370. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.js +109 -0
  371. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts +38 -0
  372. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts.map +1 -0
  373. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.js +129 -0
  374. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts +21 -0
  375. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts.map +1 -0
  376. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.js +35 -0
  377. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts +19 -0
  378. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts.map +1 -0
  379. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.js +28 -0
  380. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts +13 -0
  381. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts.map +1 -0
  382. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.js +22 -0
  383. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts +22 -0
  384. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts.map +1 -0
  385. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.js +59 -0
  386. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts +23 -0
  387. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts.map +1 -0
  388. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.js +74 -0
  389. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts +7 -0
  390. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts.map +1 -1
  391. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.js +7 -0
  392. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts +34 -1
  393. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts.map +1 -1
  394. package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +41 -1
  395. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -2
  396. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  397. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +49 -10
  398. package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
  399. package/src/view/minimap/dom/MinimapCameraView.js +4 -9
  400. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts +0 -15
  401. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts.map +0 -1
  402. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts +0 -45
  403. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts.map +0 -1
  404. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts +0 -24
  405. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts.map +0 -1
  406. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts +0 -19
  407. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts.map +0 -1
  408. package/src/engine/ecs/transform/__probe.d.ts +0 -4
  409. package/src/engine/ecs/transform/__probe.d.ts.map +0 -1
  410. package/src/engine/ecs/util/hideEntityGracefully.d.ts +0 -9
  411. package/src/engine/ecs/util/hideEntityGracefully.d.ts.map +0 -1
  412. package/src/engine/sound/simulation/core/OcclusionSolver.js +0 -112
  413. package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts +0 -27
  414. package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts.map +0 -1
  415. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts +0 -14
  416. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +0 -1
  417. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts +0 -156
  418. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts.map +0 -1
  419. package/src/shade/renderer/particles/runtime/Emitter.d.ts +0 -219
  420. package/src/shade/renderer/particles/runtime/Emitter.d.ts.map +0 -1
  421. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts +0 -77
  422. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts.map +0 -1
  423. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts +0 -89
  424. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts.map +0 -1
  425. package/src/shade/renderer/particles/runtime/ProgramArena.js +0 -155
  426. package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts +0 -15
  427. package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts.map +0 -1
  428. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts +0 -34
  429. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts.map +0 -1
  430. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts +0 -32
  431. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts.map +0 -1
@@ -1,319 +1,294 @@
1
- import { ParticleGroupBuilder } from "../ParticleGroupBuilder.js";
2
- import {
3
- PARTICLE_TYPE_F32,
4
- PARTICLE_TYPE_VEC2,
5
- PARTICLE_TYPE_VEC3,
6
- PARTICLE_TYPE_VEC4,
7
- } from "../ParticleValueType.js";
8
-
9
- /**
10
- * Directions, angles and rotations: the groups an effect needs the moment it stops firing particles
11
- * straight up.
12
- *
13
- * ## What the VM has not got
14
- *
15
- * No inverse trigonometry. `acos` is the one this file needs, and what it uses instead is the
16
- * polynomial everybody uses — see {@link acos_approx}. No division-free reciprocal either, so where
17
- * a divisor could be zero the argument is floored to a tiny positive number rather than left to
18
- * produce an infinity: an `Inf` written into a particle's position takes the particle out of the
19
- * world, and one written into a quaternion takes it out of every frame after that too.
20
- */
21
-
22
- /** Turns, in radians. @type {number} */
23
- const TAU = Math.PI * 2;
24
-
25
- /**
26
- * Smallest value a divisor is allowed to be. Chosen to be far below anything a rotation produces and
27
- * far above the point where its reciprocal stops being finite.
28
- * @type {number}
29
- */
30
- const DIVISOR_FLOOR = 1e-8;
31
-
32
- /**
33
- * `acos`, to about five decimal places, in seven instructions.
34
- *
35
- * The VM has sin, cos and the algebra, and no inverse trigonometry at all — adding an opcode for
36
- * this would cost every effect the instruction-decode switch grows by, for a function two nodes in
37
- * the library want. This is the standard minimax polynomial for `acos` on `[0, 1]`, reflected for
38
- * negative inputs: `sqrt(1 - x)` times a cubic, plus `pi` on the negative half.
39
- *
40
- * Worst-case error is under 7e-5 radians, which is a hundredth of a degree — well inside what a
41
- * particle effect can see, and the reason no exact version is worth the opcode.
42
- *
43
- * @param {ParticleGroupBuilder} g
44
- * @param {{node: NodeInstance, port: Port}} x the cosine, expected in `[-1, 1]`
45
- * @returns {{node: NodeInstance, port: Port}} the angle, in radians
46
- */
47
- function acos_approx(g, x) {
48
- const negative = g.op("compare", [x, 0], { op: "lt" });
49
- const magnitude = g.abs(x);
50
-
51
- let r = g.mad(g.f(-0.0187293), magnitude, 0.0742610);
52
-
53
- r = g.mad(r, magnitude, -0.2121144);
54
- r = g.mad(r, magnitude, 1.5707288);
55
- r = g.mul(r, g.sqrt(g.max(g.sub(1, magnitude), 0)));
56
-
57
- // reflect: acos(-t) = pi - acos(t)
58
- r = g.sub(r, g.mul(g.mul(2, negative), r));
59
-
60
- return g.mad(negative, g.f(Math.PI), r);
61
- }
62
-
63
- /**
64
- * A point on the unit sphere, from two numbers in `[0, 1)`.
65
- *
66
- * Uniform over the surface, which is what the `z` lane being taken straight from `u` buys: the area
67
- * of a band of the sphere between two heights depends only on the heights, so spreading `z` evenly
68
- * spreads the points evenly. Taking a latitude evenly instead — the obvious thing, and the wrong one
69
- * — piles them up at the poles.
70
- *
71
- * Feed it a two-lane `random` and it is an unbiased direction.
72
- *
73
- * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
74
- */
75
- export const PARTICLE_GROUP_SAMPLE_SPHERE_SURFACE = (() => {
76
- const g = new ParticleGroupBuilder({
77
- name: "sampleSphereSurface",
78
- label: "Sample Sphere Surface",
79
- icon: "M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18 M3 12h18 M12 3c4 4 4 14 0 18 M12 3c-4 4-4 14 0 18",
80
- help: "uv in [0,1) to a point on the unit sphere, uniformly",
81
- inputs: [{ name: "uv", type: PARTICLE_TYPE_VEC2 }],
82
- outputs: [{ name: "out", type: PARTICLE_TYPE_VEC3 }],
83
- });
84
-
85
- const z = g.mad(g.x(g.in.uv), 2, -1);
86
-
87
- // the radius of the circle at that height; the max guards the rounding at the poles
88
- const radius = g.sqrt(g.max(g.sub(1, g.mul(z, z)), 0));
89
-
90
- const phi = g.mul(g.y(g.in.uv), g.f(TAU));
91
-
92
- g.out("out", g.vec3(g.mul(radius, g.cos(phi)), g.mul(radius, g.sin(phi)), z));
93
-
94
- return g.build();
95
- })();
96
-
97
- /**
98
- * A point inside the unit ball, from three numbers in `[0, 1)`.
99
- *
100
- * A direction from the first two and a radius from the third — and the radius is the cube root of it,
101
- * because the volume inside a radius grows as its cube. Using the number itself would put half the
102
- * points inside the half-radius sphere, which holds an eighth of the volume, and every effect built
103
- * on it would have a bright core it never asked for.
104
- *
105
- * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
106
- */
107
- export const PARTICLE_GROUP_SAMPLE_SPHERE_VOLUME = (() => {
108
- const g = new ParticleGroupBuilder({
109
- name: "sampleSphereVolume",
110
- label: "Sample Sphere Volume",
111
- icon: "M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18 M12 12l5-3 M8 14l1.5-1",
112
- help: "uvw in [0,1) to a point inside the unit sphere, uniformly",
113
- inputs: [{ name: "uvw", type: PARTICLE_TYPE_VEC3 }],
114
- outputs: [{ name: "out", type: PARTICLE_TYPE_VEC3 }],
115
- });
116
-
117
- const direction = g.call(PARTICLE_GROUP_SAMPLE_SPHERE_SURFACE, { uv: g.swz(g.in.uvw, "xy") });
118
-
119
- const radius = g.pow(g.z(g.in.uvw), g.f(1 / 3));
120
-
121
- g.out("out", g.scale(direction.out, radius));
122
-
123
- return g.build();
124
- })();
125
-
126
- /**
127
- * The angle between two directions, in radians, in `[0, pi]`.
128
- *
129
- * `acos` of the cosine, and the cosine is the dot product of the two normalised. The clamp is not
130
- * decoration: a dot product of two unit vectors is arithmetically in `[-1, 1]` and in floating point
131
- * is occasionally a hair outside it, which is exactly where `acos` stops being defined.
132
- *
133
- * Two of them, one per shape, because there is no honest way to do this at "whatever width arrives"
134
- * — the answer for two lanes and the answer for three are different questions about different
135
- * things, and a node that took either would be a node whose result depended on what was plugged in.
136
- *
137
- * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup[]}
138
- */
139
- export const PARTICLE_GROUP_ANGLE_BETWEEN = [PARTICLE_TYPE_VEC2, PARTICLE_TYPE_VEC3].map(type => {
140
- const g = new ParticleGroupBuilder({
141
- name: `angleBetween${type.components}`,
142
- label: `Angle Between (${type.name})`,
143
- icon: "M5 19h14 M5 19L17 7 M11 19a8 8 0 0 0 2.5-5.6",
144
- help: `the angle in radians between two ${type.name} directions`,
145
- inputs: [{ name: "a", type }, { name: "b", type }],
146
- outputs: [{ name: "radians", type: PARTICLE_TYPE_F32 }],
147
- });
148
-
149
- const cosine = g.clamp(g.dot(g.normalize(g.in.a), g.normalize(g.in.b)), -1, 1);
150
-
151
- g.out("radians", acos_approx(g, cosine));
152
-
153
- return g.build();
154
- });
155
-
156
- /**
157
- * A quaternion for a rotation of `angle` radians about `axis`.
158
- *
159
- * `(axis * sin(angle/2), cos(angle/2))`, with the axis normalised first so the result is a unit
160
- * quaternion whatever length the axis arrived at. A zero axis normalises to zero, which gives the
161
- * quaternion `(0, 0, 0, cos(angle/2))` — not a rotation, and not a crash either.
162
- *
163
- * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
164
- */
165
- export const PARTICLE_GROUP_QUAT_FROM_AXIS_ANGLE = (() => {
166
- const g = new ParticleGroupBuilder({
167
- name: "quatFromAxisAngle",
168
- label: "Quaternion From Axis Angle",
169
- icon: "M12 4v16 M6 14a8 8 0 0 0 12 0 M4 9l2 5 2-5",
170
- help: "a rotation about an axis, as a quaternion",
171
- inputs: [
172
- { name: "axis", type: PARTICLE_TYPE_VEC3 },
173
- { name: "angle", type: PARTICLE_TYPE_F32 },
174
- ],
175
- outputs: [{ name: "quat", type: PARTICLE_TYPE_VEC4 }],
176
- });
177
-
178
- const half = g.mul(g.in.angle, 0.5);
179
-
180
- const vector = g.scale(g.normalize(g.in.axis), g.sin(half));
181
-
182
- g.out("quat", g.vec4(g.x(vector), g.y(vector), g.z(vector), g.cos(half)));
183
-
184
- return g.build();
185
- })();
186
-
187
- /**
188
- * Turn a vector by a quaternion.
189
- *
190
- * `v + 2w(q x v) + 2(q x (q x v))`, written the way it is usually written: one cross product, one
191
- * scale, one more cross product. Two cross products beat building a rotation matrix, and there is
192
- * no matrix type here to build one into anyway.
193
- *
194
- * The quaternion is expected to be a unit one. A longer one scales the result by the square of its
195
- * length, which is the identity behaving as it always has rather than anything this checks.
196
- *
197
- * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
198
- */
199
- export const PARTICLE_GROUP_QUAT_ROTATE = (() => {
200
- const g = new ParticleGroupBuilder({
201
- name: "quatRotate",
202
- label: "Rotate By Quaternion",
203
- icon: "M5 12a7 7 0 1 1 3 5.8 M5 8v4h4 M12 12l5-2",
204
- help: "a vector turned by a quaternion",
205
- inputs: [
206
- { name: "quat", type: PARTICLE_TYPE_VEC4 },
207
- { name: "v", type: PARTICLE_TYPE_VEC3 },
208
- ],
209
- outputs: [{ name: "out", type: PARTICLE_TYPE_VEC3 }],
210
- });
211
-
212
- const axis = g.swz(g.in.quat, "xyz");
213
- const w = g.w(g.in.quat);
214
-
215
- const t = g.scale(g.cross(axis, g.in.v), 2);
216
-
217
- g.out("out", g.add(g.add(g.in.v, g.scale(t, w)), g.cross(axis, t)));
218
-
219
- return g.build();
220
- })();
221
-
222
- /**
223
- * The rotation that points `forward` along +Z with `up` as near to +Y as it can be.
224
- *
225
- * The basis is built first — forward, then a right that is perpendicular to both, then the up that
226
- * completes it — and then read off as a quaternion by Shepperd's method: four expressions, one per
227
- * component of the quaternion being the largest, and the largest is picked because the other three
228
- * divide by something near zero.
229
- *
230
- * There are no branches, so all four are computed and one is chosen. That is what a VM with no
231
- * control flow costs, and the choice is a pair of comparisons rather than a jump. Each divisor is
232
- * floored at {@link DIVISOR_FLOOR} first, so the three expressions that are *not* chosen produce a
233
- * finite number rather than an infinity — the selection reads registers rather than blending them,
234
- * but a program that computes infinities is one bad edit away from writing one out.
235
- *
236
- * Degenerate input — `forward` and `up` parallel, or either of them zero — leaves the basis without a
237
- * right vector, and what comes back is finite and arbitrary. Feeding this an `up` that could line up
238
- * with `forward` is the caller's to avoid, exactly as it is in every engine that offers this.
239
- *
240
- * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
241
- */
242
- export const PARTICLE_GROUP_QUAT_LOOK_ROTATION = (() => {
243
- const g = new ParticleGroupBuilder({
244
- name: "quatLookRotation",
245
- label: "Quaternion Look Rotation",
246
- icon: "M12 12l7-4 M12 12v-8 M12 12L5 9 M12 12l3 8",
247
- help: "the rotation that looks along forward, with up upright",
248
- inputs: [
249
- { name: "forward", type: PARTICLE_TYPE_VEC3 },
250
- { name: "up", type: PARTICLE_TYPE_VEC3 },
251
- ],
252
- outputs: [{ name: "quat", type: PARTICLE_TYPE_VEC4 }],
253
- });
254
-
255
- const f = g.normalize(g.in.forward);
256
- const r = g.normalize(g.cross(g.in.up, f));
257
- const u = g.cross(f, r);
258
-
259
- // The rotation matrix, by column: r, u, f. `m(row, column)`.
260
- const lane = ["x", "y", "z"];
261
- const column = [r, u, f];
262
-
263
- const m = (row, col) => g.swz(column[col], lane[row]);
264
-
265
- const m00 = m(0, 0), m01 = m(0, 1), m02 = m(0, 2);
266
- const m10 = m(1, 0), m11 = m(1, 1), m12 = m(1, 2);
267
- const m20 = m(2, 0), m21 = m(2, 1), m22 = m(2, 2);
268
-
269
- const trace = g.add(g.add(m00, m11), m22);
270
-
271
- /**
272
- * One of the four expressions: `magnitude` is four times the square of the component this case
273
- * is the largest of, and `parts` are the other three numerators in `x, y, z, w` order with that
274
- * component's slot left for `magnitude` itself.
275
- *
276
- * @param {*} magnitude
277
- * @param {function(*): Array} parts
278
- * @returns {*} the quaternion for this case
279
- */
280
- const candidate = (magnitude, parts) => {
281
- const safe = g.max(magnitude, g.f(DIVISOR_FLOOR));
282
-
283
- // s = 2*sqrt(safe) is the classical scale; the component this case is largest of is
284
- // 0.25*s, which is safe/s, so every lane of the vector below is a numerator over s.
285
- const s = g.mul(g.sqrt(safe), 2);
286
-
287
- return g.mul(g.vec4(...parts(safe)), g.div(1, s));
288
- };
289
-
290
- const q_trace = candidate(g.add(trace, 1), safe => [
291
- g.sub(m21, m12), g.sub(m02, m20), g.sub(m10, m01), safe,
292
- ]);
293
-
294
- const q_x = candidate(g.sub(g.sub(g.add(1, m00), m11), m22), safe => [
295
- safe, g.add(m01, m10), g.add(m02, m20), g.sub(m21, m12),
296
- ]);
297
-
298
- const q_y = candidate(g.sub(g.sub(g.add(1, m11), m00), m22), safe => [
299
- g.add(m01, m10), safe, g.add(m12, m21), g.sub(m02, m20),
300
- ]);
301
-
302
- const q_z = candidate(g.sub(g.sub(g.add(1, m22), m00), m11), safe => [
303
- g.add(m02, m20), g.add(m12, m21), safe, g.sub(m10, m01),
304
- ]);
305
-
306
- // Largest wins, checked from the bottom up: y over z, then x over both, then the trace over all.
307
- const yz = g.select(q_z, q_y, g.op("compare", [m11, m22], { op: "ge" }));
308
-
309
- const x_largest = g.mul(
310
- g.op("compare", [m00, m11], { op: "ge" }),
311
- g.op("compare", [m00, m22], { op: "ge" })
312
- );
313
-
314
- const xyz = g.select(yz, q_x, x_largest);
315
-
316
- g.out("quat", g.select(xyz, q_trace, g.op("compare", [trace, 0], { op: "gt" })));
317
-
318
- return g.build();
319
- })();
1
+ import { ParticleGroupBuilder } from "../ParticleGroupBuilder.js";
2
+ import {
3
+ PARTICLE_TYPE_F32,
4
+ PARTICLE_TYPE_VEC2,
5
+ PARTICLE_TYPE_VEC3,
6
+ PARTICLE_TYPE_VEC4,
7
+ } from "../ParticleValueType.js";
8
+
9
+ /**
10
+ * Directions, angles and rotations: the groups an effect needs the moment it stops firing particles
11
+ * straight up.
12
+ *
13
+ * ## Dividing by something that might be zero
14
+ *
15
+ * The VM has no guard for it, so where a divisor could be zero the argument is floored to a tiny
16
+ * positive number rather than left to produce an infinity: an `Inf` written into a particle's
17
+ * position takes the particle out of the world, and one written into a quaternion takes it out of
18
+ * every frame after that too.
19
+ *
20
+ * ## `acos` is an opcode now
21
+ *
22
+ * This file used to carry it as a seven-instruction minimax polynomial, good to 7e-5 radians,
23
+ * because the VM had no inverse trigonometry and the comment here argued that an opcode was not
24
+ * worth what the decode switch would grow by. The ISA has `ACOS`, so the group calls it, and the
25
+ * two `angleBetween` groups cost 10 instructions rather than 31.
26
+ */
27
+
28
+ /** Turns, in radians. @type {number} */
29
+ const TAU = Math.PI * 2;
30
+
31
+ /**
32
+ * Smallest value a divisor is allowed to be. Chosen to be far below anything a rotation produces and
33
+ * far above the point where its reciprocal stops being finite.
34
+ * @type {number}
35
+ */
36
+ const DIVISOR_FLOOR = 1e-8;
37
+
38
+ /**
39
+ * A point on the unit sphere, from two numbers in `[0, 1)`.
40
+ *
41
+ * Uniform over the surface, which is what the `z` lane being taken straight from `u` buys: the area
42
+ * of a band of the sphere between two heights depends only on the heights, so spreading `z` evenly
43
+ * spreads the points evenly. Taking a latitude evenly instead — the obvious thing, and the wrong one
44
+ * — piles them up at the poles.
45
+ *
46
+ * Feed it a two-lane `random` and it is an unbiased direction.
47
+ *
48
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
49
+ */
50
+ export const PARTICLE_GROUP_SAMPLE_SPHERE_SURFACE = (() => {
51
+ const g = new ParticleGroupBuilder({
52
+ name: "sampleSphereSurface",
53
+ label: "Sample Sphere Surface",
54
+ icon: "M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18 M3 12h18 M12 3c4 4 4 14 0 18 M12 3c-4 4-4 14 0 18",
55
+ help: "uv in [0,1) to a point on the unit sphere, uniformly",
56
+ inputs: [{ name: "uv", type: PARTICLE_TYPE_VEC2 }],
57
+ outputs: [{ name: "out", type: PARTICLE_TYPE_VEC3 }],
58
+ });
59
+
60
+ const z = g.mad(g.x(g.in.uv), 2, -1);
61
+
62
+ // the radius of the circle at that height; the max guards the rounding at the poles
63
+ const radius = g.sqrt(g.max(g.sub(1, g.mul(z, z)), 0));
64
+
65
+ const phi = g.mul(g.y(g.in.uv), g.f(TAU));
66
+
67
+ g.out("out", g.vec3(g.mul(radius, g.cos(phi)), g.mul(radius, g.sin(phi)), z));
68
+
69
+ return g.build();
70
+ })();
71
+
72
+ /**
73
+ * A point inside the unit ball, from three numbers in `[0, 1)`.
74
+ *
75
+ * A direction from the first two and a radius from the third — and the radius is the cube root of it,
76
+ * because the volume inside a radius grows as its cube. Using the number itself would put half the
77
+ * points inside the half-radius sphere, which holds an eighth of the volume, and every effect built
78
+ * on it would have a bright core it never asked for.
79
+ *
80
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
81
+ */
82
+ export const PARTICLE_GROUP_SAMPLE_SPHERE_VOLUME = (() => {
83
+ const g = new ParticleGroupBuilder({
84
+ name: "sampleSphereVolume",
85
+ label: "Sample Sphere Volume",
86
+ icon: "M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18 M12 12l5-3 M8 14l1.5-1",
87
+ help: "uvw in [0,1) to a point inside the unit sphere, uniformly",
88
+ inputs: [{ name: "uvw", type: PARTICLE_TYPE_VEC3 }],
89
+ outputs: [{ name: "out", type: PARTICLE_TYPE_VEC3 }],
90
+ });
91
+
92
+ const direction = g.call(PARTICLE_GROUP_SAMPLE_SPHERE_SURFACE, { uv: g.swz(g.in.uvw, "xy") });
93
+
94
+ const radius = g.pow(g.z(g.in.uvw), g.f(1 / 3));
95
+
96
+ g.out("out", g.scale(direction.out, radius));
97
+
98
+ return g.build();
99
+ })();
100
+
101
+ /**
102
+ * The angle between two directions, in radians, in `[0, pi]`.
103
+ *
104
+ * `acos` of the cosine, and the cosine is the dot product of the two normalised. The clamp is not
105
+ * decoration: a dot product of two unit vectors is arithmetically in `[-1, 1]` and in floating point
106
+ * is occasionally a hair outside it, which is exactly where `acos` stops being defined.
107
+ *
108
+ * Two of them, one per shape, because there is no honest way to do this at "whatever width arrives"
109
+ * — the answer for two lanes and the answer for three are different questions about different
110
+ * things, and a node that took either would be a node whose result depended on what was plugged in.
111
+ *
112
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup[]}
113
+ */
114
+ export const PARTICLE_GROUP_ANGLE_BETWEEN = [PARTICLE_TYPE_VEC2, PARTICLE_TYPE_VEC3].map(type => {
115
+ const g = new ParticleGroupBuilder({
116
+ name: `angleBetween${type.components}`,
117
+ label: `Angle Between (${type.name})`,
118
+ icon: "M5 19h14 M5 19L17 7 M11 19a8 8 0 0 0 2.5-5.6",
119
+ help: `the angle in radians between two ${type.name} directions`,
120
+ inputs: [{ name: "a", type }, { name: "b", type }],
121
+ outputs: [{ name: "radians", type: PARTICLE_TYPE_F32 }],
122
+ });
123
+
124
+ const cosine = g.clamp(g.dot(g.normalize(g.in.a), g.normalize(g.in.b)), -1, 1);
125
+
126
+ g.out("radians", g.acos(cosine));
127
+
128
+ return g.build();
129
+ });
130
+
131
+ /**
132
+ * A quaternion for a rotation of `angle` radians about `axis`.
133
+ *
134
+ * `(axis * sin(angle/2), cos(angle/2))`, with the axis normalised first so the result is a unit
135
+ * quaternion whatever length the axis arrived at. A zero axis normalises to zero, which gives the
136
+ * quaternion `(0, 0, 0, cos(angle/2))` — not a rotation, and not a crash either.
137
+ *
138
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
139
+ */
140
+ export const PARTICLE_GROUP_QUAT_FROM_AXIS_ANGLE = (() => {
141
+ const g = new ParticleGroupBuilder({
142
+ name: "quatFromAxisAngle",
143
+ label: "Quaternion From Axis Angle",
144
+ icon: "M12 4v16 M6 14a8 8 0 0 0 12 0 M4 9l2 5 2-5",
145
+ help: "a rotation about an axis, as a quaternion",
146
+ inputs: [
147
+ { name: "axis", type: PARTICLE_TYPE_VEC3 },
148
+ { name: "angle", type: PARTICLE_TYPE_F32 },
149
+ ],
150
+ outputs: [{ name: "quat", type: PARTICLE_TYPE_VEC4 }],
151
+ });
152
+
153
+ const half = g.mul(g.in.angle, 0.5);
154
+
155
+ const vector = g.scale(g.normalize(g.in.axis), g.sin(half));
156
+
157
+ g.out("quat", g.vec4(g.x(vector), g.y(vector), g.z(vector), g.cos(half)));
158
+
159
+ return g.build();
160
+ })();
161
+
162
+ /**
163
+ * Turn a vector by a quaternion.
164
+ *
165
+ * `v + 2w(q x v) + 2(q x (q x v))`, written the way it is usually written: one cross product, one
166
+ * scale, one more cross product. Two cross products beat building a rotation matrix, and there is
167
+ * no matrix type here to build one into anyway.
168
+ *
169
+ * The quaternion is expected to be a unit one. A longer one scales the result by the square of its
170
+ * length, which is the identity behaving as it always has rather than anything this checks.
171
+ *
172
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
173
+ */
174
+ export const PARTICLE_GROUP_QUAT_ROTATE = (() => {
175
+ const g = new ParticleGroupBuilder({
176
+ name: "quatRotate",
177
+ label: "Rotate By Quaternion",
178
+ icon: "M5 12a7 7 0 1 1 3 5.8 M5 8v4h4 M12 12l5-2",
179
+ help: "a vector turned by a quaternion",
180
+ inputs: [
181
+ { name: "quat", type: PARTICLE_TYPE_VEC4 },
182
+ { name: "v", type: PARTICLE_TYPE_VEC3 },
183
+ ],
184
+ outputs: [{ name: "out", type: PARTICLE_TYPE_VEC3 }],
185
+ });
186
+
187
+ const axis = g.swz(g.in.quat, "xyz");
188
+ const w = g.w(g.in.quat);
189
+
190
+ const t = g.scale(g.cross(axis, g.in.v), 2);
191
+
192
+ g.out("out", g.add(g.add(g.in.v, g.scale(t, w)), g.cross(axis, t)));
193
+
194
+ return g.build();
195
+ })();
196
+
197
+ /**
198
+ * The rotation that points `forward` along +Z with `up` as near to +Y as it can be.
199
+ *
200
+ * The basis is built first — forward, then a right that is perpendicular to both, then the up that
201
+ * completes it — and then read off as a quaternion by Shepperd's method: four expressions, one per
202
+ * component of the quaternion being the largest, and the largest is picked because the other three
203
+ * divide by something near zero.
204
+ *
205
+ * There are no branches, so all four are computed and one is chosen. That is what a VM with no
206
+ * control flow costs, and the choice is a pair of comparisons rather than a jump. Each divisor is
207
+ * floored at {@link DIVISOR_FLOOR} first, so the three expressions that are *not* chosen produce a
208
+ * finite number rather than an infinity — the selection reads registers rather than blending them,
209
+ * but a program that computes infinities is one bad edit away from writing one out.
210
+ *
211
+ * Degenerate input — `forward` and `up` parallel, or either of them zero — leaves the basis without a
212
+ * right vector, and what comes back is finite and arbitrary. Feeding this an `up` that could line up
213
+ * with `forward` is the caller's to avoid, exactly as it is in every engine that offers this.
214
+ *
215
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
216
+ */
217
+ export const PARTICLE_GROUP_QUAT_LOOK_ROTATION = (() => {
218
+ const g = new ParticleGroupBuilder({
219
+ name: "quatLookRotation",
220
+ label: "Quaternion Look Rotation",
221
+ icon: "M12 12l7-4 M12 12v-8 M12 12L5 9 M12 12l3 8",
222
+ help: "the rotation that looks along forward, with up upright",
223
+ inputs: [
224
+ { name: "forward", type: PARTICLE_TYPE_VEC3 },
225
+ { name: "up", type: PARTICLE_TYPE_VEC3 },
226
+ ],
227
+ outputs: [{ name: "quat", type: PARTICLE_TYPE_VEC4 }],
228
+ });
229
+
230
+ const f = g.normalize(g.in.forward);
231
+ const r = g.normalize(g.cross(g.in.up, f));
232
+ const u = g.cross(f, r);
233
+
234
+ // The rotation matrix, by column: r, u, f. `m(row, column)`.
235
+ const lane = ["x", "y", "z"];
236
+ const column = [r, u, f];
237
+
238
+ const m = (row, col) => g.swz(column[col], lane[row]);
239
+
240
+ const m00 = m(0, 0), m01 = m(0, 1), m02 = m(0, 2);
241
+ const m10 = m(1, 0), m11 = m(1, 1), m12 = m(1, 2);
242
+ const m20 = m(2, 0), m21 = m(2, 1), m22 = m(2, 2);
243
+
244
+ const trace = g.add(g.add(m00, m11), m22);
245
+
246
+ /**
247
+ * One of the four expressions: `magnitude` is four times the square of the component this case
248
+ * is the largest of, and `parts` are the other three numerators in `x, y, z, w` order with that
249
+ * component's slot left for `magnitude` itself.
250
+ *
251
+ * @param {*} magnitude
252
+ * @param {function(*): Array} parts
253
+ * @returns {*} the quaternion for this case
254
+ */
255
+ const candidate = (magnitude, parts) => {
256
+ const safe = g.max(magnitude, g.f(DIVISOR_FLOOR));
257
+
258
+ // s = 2*sqrt(safe) is the classical scale; the component this case is largest of is
259
+ // 0.25*s, which is safe/s, so every lane of the vector below is a numerator over s.
260
+ const s = g.mul(g.sqrt(safe), 2);
261
+
262
+ return g.mul(g.vec4(...parts(safe)), g.div(1, s));
263
+ };
264
+
265
+ const q_trace = candidate(g.add(trace, 1), safe => [
266
+ g.sub(m21, m12), g.sub(m02, m20), g.sub(m10, m01), safe,
267
+ ]);
268
+
269
+ const q_x = candidate(g.sub(g.sub(g.add(1, m00), m11), m22), safe => [
270
+ safe, g.add(m01, m10), g.add(m02, m20), g.sub(m21, m12),
271
+ ]);
272
+
273
+ const q_y = candidate(g.sub(g.sub(g.add(1, m11), m00), m22), safe => [
274
+ g.add(m01, m10), safe, g.add(m12, m21), g.sub(m02, m20),
275
+ ]);
276
+
277
+ const q_z = candidate(g.sub(g.sub(g.add(1, m22), m00), m11), safe => [
278
+ g.add(m02, m20), g.add(m12, m21), safe, g.sub(m10, m01),
279
+ ]);
280
+
281
+ // Largest wins, checked from the bottom up: y over z, then x over both, then the trace over all.
282
+ const yz = g.select(q_z, q_y, g.op("compare", [m11, m22], { op: "ge" }));
283
+
284
+ const x_largest = g.mul(
285
+ g.op("compare", [m00, m11], { op: "ge" }),
286
+ g.op("compare", [m00, m22], { op: "ge" })
287
+ );
288
+
289
+ const xyz = g.select(yz, q_x, x_largest);
290
+
291
+ g.out("quat", g.select(xyz, q_trace, g.op("compare", [trace, 0], { op: "gt" })));
292
+
293
+ return g.build();
294
+ })();