@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,30 +1,19 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
+ import { is_typed_array_equals } from "../../../../core/collection/array/typed/is_typed_array_equals.js";
3
+ import { uint32_array_hash } from "../../../../core/collection/array/typed/uint32_array_hash.js";
4
+ import { hash_mix2 } from "../../../../core/math/hash/hash_mix2.js";
5
+ import { hash_mix3 } from "../../../../core/math/hash/hash_mix3.js";
2
6
  import {
3
- PARTICLE_RECORD_WORD_COUNT,
4
7
  PARTICLE_VM_INSTRUCTION_WORDS,
5
- PARTICLE_VM_MAX_INSTRUCTIONS,
6
8
  PARTICLE_VM_REGISTER_SLOTS,
7
9
  } from "../ParticleConstants.js";
8
- import {
9
- swizzle_span,
10
- VM_DEST,
11
- VM_ISA,
12
- VM_MAX_WIDTH,
13
- VM_OP,
14
- VM_OPERAND,
15
- VM_WIDTH,
16
- vm_decode_op,
17
- vm_decode_width,
18
- vm_dest_width,
19
- vm_operation_width,
20
- } from "./ParticleVMISA.js";
21
10
 
22
11
  /**
23
12
  * A compiled particle program: two instruction streams (INIT and UPDATE) plus a shared constant
24
- * pool. This is the value the node compiler emits and the runtime packs into the program arena.
13
+ * pool. This is the value the node compiler emits and the runtime packs into the program heap.
25
14
  *
26
15
  * Instruction streams are flat `Uint32Array`s, {@link PARTICLE_VM_INSTRUCTION_WORDS} words per
27
- * instruction. The constant pool is a flat `Float32Array`, 4 floats (one `vec4f`) per constant.
16
+ * instruction. The constant pool is a flat `Float32Array`, one float per word.
28
17
  */
29
18
  export class ParticleProgram {
30
19
 
@@ -41,13 +30,13 @@ export class ParticleProgram {
41
30
  update;
42
31
 
43
32
  /**
44
- * Constant pool, 4 floats (one `vec4f`) per entry.
33
+ * Constant pool, one float per word.
45
34
  * @type {Float32Array}
46
35
  */
47
36
  constants;
48
37
 
49
38
  /**
50
- * Number of vec4 registers the program needs.
39
+ * Register slots the program needs.
51
40
  * @type {number}
52
41
  */
53
42
  register_count;
@@ -67,7 +56,11 @@ export class ParticleProgram {
67
56
 
68
57
  assert.equal(init.length % PARTICLE_VM_INSTRUCTION_WORDS, 0, "init length must be a multiple of the instruction width");
69
58
  assert.equal(update.length % PARTICLE_VM_INSTRUCTION_WORDS, 0, "update length must be a multiple of the instruction width");
70
- assert.lessThanOrEqual(register_count, PARTICLE_VM_REGISTER_SLOTS, "register_count exceeds the VM register file size");
59
+ assert.lessThanOrEqual(
60
+ register_count,
61
+ PARTICLE_VM_REGISTER_SLOTS,
62
+ "register_count exceeds the slots a VM instruction can address"
63
+ );
71
64
 
72
65
  this.init = init;
73
66
  this.update = update;
@@ -91,143 +84,95 @@ export class ParticleProgram {
91
84
  }
92
85
 
93
86
  /**
94
- * Validate structural invariants (opcodes known, register indices in range, instruction budget,
95
- * constant references in range). Throws on the first problem. Intended for tests and asset
96
- * ingestion, not the hot path.
87
+ * The constant pool as the raw IEEE-754 words it is made of, without copying — a view of the
88
+ * same bytes, so writing through it writes the pool.
89
+ *
90
+ * This is the form the pool is compared, hashed and packed in, because it holds constants, not
91
+ * measurements. `-0` and `+0` are the same number and different constants — a `DIV` by each
92
+ * disagrees about the sign of the infinity it produces — and the assembler already keeps them
93
+ * apart, interning with `Object.is`; equality that read the pool as floats would put back
94
+ * together what interning took care to separate. Reading bits also keeps
95
+ * {@link ParticleProgram#equals} reflexive over a pool holding a NaN.
96
+ *
97
+ * @returns {Uint32Array}
97
98
  */
98
- validate() {
99
- validate_stream(this.init, "init", this.constant_word_count, this.register_count);
100
- validate_stream(this.update, "update", this.constant_word_count, this.register_count);
101
- assert.lessThanOrEqual(this.init_instruction_count, PARTICLE_VM_MAX_INSTRUCTIONS, "init exceeds instruction budget");
102
- assert.lessThanOrEqual(this.update_instruction_count, PARTICLE_VM_MAX_INSTRUCTIONS, "update exceeds instruction budget");
99
+ get constant_words() {
100
+ // a Float32Array is 4-byte aligned by construction, so this view always exists
101
+ return new Uint32Array(this.constants.buffer, this.constants.byteOffset, this.constants.length);
103
102
  }
104
- }
105
-
106
- /**
107
- * @param {Uint32Array} words
108
- * @param {string} label
109
- * @param {number} constant_word_count
110
- * @param {number} register_count
111
- */
112
- function validate_stream(words, label, constant_word_count, register_count) {
113
- const instruction_count = words.length / PARTICLE_VM_INSTRUCTION_WORDS;
114
-
115
- for (let i = 0; i < instruction_count; i++) {
116
- const base = i * PARTICLE_VM_INSTRUCTION_WORDS;
117
- const word0 = words[base];
118
- const op = vm_decode_op(word0);
119
- const width = vm_decode_width(word0);
120
- const meta = VM_ISA.get(op);
121
-
122
- if (meta === undefined) {
123
- throw new Error(`${label}[${i}]: unknown opcode ${op}`);
124
- }
125
-
126
- const dst = words[base + 1];
127
- const s0 = words[base + 2];
128
-
129
- if (meta.width !== VM_WIDTH.NONE) {
130
- assert.greaterThanOrEqual(
131
- width,
132
- meta.min_width,
133
- `${label}[${i}] (${meta.name}): width must be >= ${meta.min_width}`
134
- );
135
- assert.lessThanOrEqual(width, VM_MAX_WIDTH, `${label}[${i}] (${meta.name}): width must be <= ${VM_MAX_WIDTH}`);
136
- }
137
-
138
- const operation_width = vm_operation_width(op, width);
139
-
140
- // Every register operand names a RUN of slots, and a run that overshoots the file reads
141
- // whatever the next value holds rather than failing — so the bound is on its end.
142
- /** @type {Array<{label: string, base: number, span: number}>} */
143
- const ranges = [];
144
-
145
- if (meta.dst) {
146
- // Destination for value-producing ops; for STORE_ATTR/KILL the dst slot holds a SOURCE,
147
- // and its span is what the instruction reads.
148
- const span = meta.dest === VM_DEST.NONE ? operation_width : vm_dest_width(op, width);
149
- ranges.push({ label: "dst", base: dst, span });
150
- }
151
-
152
- const operands = meta.operands;
153
- for (let s = 0; s < 3; s++) {
154
- if (operands[s] !== VM_OPERAND.REG) {
155
- continue;
156
- }
157
-
158
- // A swizzle reaches into its source by the lanes its pattern names, which bear no
159
- // relation to the destination's width — a four-lane broadcast reads one slot, and a
160
- // three-lane reversal reads four.
161
- const span = op === VM_OP.SWIZZLE
162
- ? swizzle_span(words[base + 3])
163
- : (meta.scalar_operands.includes(s) ? 1 : operation_width);
164
103
 
165
- ranges.push({ label: `s${s}`, base: words[base + 2 + s], span });
104
+ /**
105
+ * Structural equality: the same two instruction streams, the same constant pool bit for bit,
106
+ * and the same register budget. Two programs that compare equal are one program — the VM would
107
+ * execute them identically.
108
+ *
109
+ * @param {ParticleProgram} other
110
+ * @returns {boolean}
111
+ */
112
+ equals(other) {
113
+ if (this === other) {
114
+ return true;
166
115
  }
167
116
 
168
- for (const range of ranges) {
169
- assert.lessThanOrEqual(
170
- range.base + range.span,
171
- register_count,
172
- `${label}[${i}] (${meta.name}): ${range.label} range `
173
- + `[${range.base}, ${range.base + range.span}) exceeds the ${register_count}-slot register file`
174
- );
175
- }
117
+ return this.register_count === other.register_count
118
+ && is_typed_array_equals(this.init, other.init)
119
+ && is_typed_array_equals(this.update, other.update)
120
+ && is_typed_array_equals(this.constant_words, other.constant_words);
121
+ }
176
122
 
177
- // Two operands may name the same slots or none of the same ones, but not overlap partially.
178
- // Every executor reads slot `c` of its sources to write slot `c` of its destination, so an
179
- // exact alias is fine — the allocator relies on it to let a result reuse a consumed input —
180
- // and a shifted one would read slots the same instruction has already overwritten.
181
- for (let a = 0; a < ranges.length; a++) {
182
- for (let b = a + 1; b < ranges.length; b++) {
183
- const x = ranges[a];
184
- const y = ranges[b];
185
- const overlaps = x.base < y.base + y.span && y.base < x.base + x.span;
186
-
187
- if (overlaps && x.base !== y.base) {
188
- throw new Error(
189
- `${label}[${i}] (${meta.name}): ${x.label} range [${x.base}, ${x.base + x.span}) and `
190
- + `${y.label} range [${y.base}, ${y.base + y.span}) overlap partially; operands must name `
191
- + `the same slots or disjoint ones`
192
- );
193
- }
194
- }
195
- }
123
+ /**
124
+ * Hash over everything {@link ParticleProgram#equals} compares, and in the same terms — the pool
125
+ * goes through the same bit view, so equal programs hash equally.
126
+ *
127
+ * @returns {number} int32
128
+ */
129
+ hash() {
130
+ const constant_words = this.constant_words;
131
+
132
+ return hash_mix2(
133
+ hash_mix3(
134
+ uint32_array_hash(this.init, 0, this.init.length),
135
+ uint32_array_hash(this.update, 0, this.update.length),
136
+ uint32_array_hash(constant_words, 0, constant_words.length)
137
+ ),
138
+ this.register_count
139
+ );
140
+ }
196
141
 
197
- if (op === VM_OP.LOAD_CONST) {
198
- // The load reads one word per lane, so the whole run has to be inside the pool.
199
- assert.lessThanOrEqual(
200
- s0 + operation_width,
201
- constant_word_count,
202
- `${label}[${i}] (LOAD_CONST): words [${s0}, ${s0 + operation_width}) exceed the `
203
- + `${constant_word_count}-word constant pool`
204
- );
205
- }
142
+ /**
143
+ * Take on another program's code, becoming equal to it.
144
+ *
145
+ * The streams and the pool are duplicated rather than shared. A compiled program is treated as
146
+ * immutable, but nothing here enforces that — the optimizer's passes read and rewrite these
147
+ * arrays directly — so a copy that aliased the original would let a rewrite of one silently
148
+ * become a rewrite of both.
149
+ *
150
+ * @param {ParticleProgram} other
151
+ */
152
+ copy(other) {
153
+ this.init = other.init.slice();
154
+ this.update = other.update.slice();
155
+ this.constants = other.constants.slice();
156
+ this.register_count = other.register_count;
157
+ }
206
158
 
207
- // Attribute accesses must stay inside one record. An out-of-range offset is NOT caught by
208
- // GPU robustness — record_base + offset lands inside the pool buffer, silently reading or
209
- // corrupting the NEXT PARTICLE'S record.
210
- if (op === VM_OP.LOAD_ATTR || op === VM_OP.STORE_ATTR) {
211
- const offset = words[base + 2];
212
- const components = words[base + 3];
213
- const name = VM_ISA.get(op).name;
214
- assert.greaterThanOrEqual(components, 1, `${label}[${i}] (${name}): component count must be >= 1`);
215
- assert.lessThanOrEqual(components, 4, `${label}[${i}] (${name}): component count must be <= 4`);
216
- assert.lessThanOrEqual(
217
- offset + components,
218
- PARTICLE_RECORD_WORD_COUNT,
219
- `${label}[${i}] (${name}): attribute access [${offset}, ${offset + components}) exceeds the ${PARTICLE_RECORD_WORD_COUNT}-word record`
220
- );
221
-
222
- // A store writes one record word per lane, so it cannot be asked for more words than
223
- // the register holds — the extra ones would come out of the next value.
224
- if (op === VM_OP.STORE_ATTR) {
225
- assert.equal(
226
- width,
227
- components,
228
- `${label}[${i}] (STORE_ATTR): width ${width} must equal the component count ${components}`
229
- );
230
- }
231
- }
159
+ /**
160
+ * A second program equal to this one and sharing none of its storage.
161
+ *
162
+ * @returns {ParticleProgram}
163
+ */
164
+ clone() {
165
+ // the constructor wants a whole program, so it gets an empty one — the copy overwrites
166
+ // every word of it before anything can observe it
167
+ const r = new ParticleProgram({
168
+ init: new Uint32Array(0),
169
+ update: new Uint32Array(0),
170
+ constants: new Float32Array(0),
171
+ register_count: 0,
172
+ });
173
+
174
+ r.copy(this);
175
+
176
+ return r;
232
177
  }
233
178
  }