@woosh/meep-engine 3.16.0 → 3.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/editor/particles/effect/ParticleEffectDocument.d.ts +21 -6
  2. package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
  3. package/editor/particles/effect/ParticleEffectDocument.js +38 -17
  4. package/editor/view/node-graph/NodeGraphClipboard.d.ts +186 -0
  5. package/editor/view/node-graph/NodeGraphClipboard.d.ts.map +1 -0
  6. package/editor/view/node-graph/NodeGraphClipboard.js +231 -0
  7. package/editor/view/node-graph/NodeGraphEditorView.d.ts +59 -1
  8. package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
  9. package/editor/view/node-graph/NodeGraphEditorView.js +248 -5
  10. package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
  11. package/editor/view/node-graph/NodeGraphView.js +84 -8
  12. package/editor/view/node-graph/actions/connection_bind_actions.d.ts +23 -0
  13. package/editor/view/node-graph/actions/connection_bind_actions.d.ts.map +1 -0
  14. package/editor/view/node-graph/actions/connection_bind_actions.js +39 -0
  15. package/editor/view/particles/effect/ParticleCodeEditorView.d.ts.map +1 -1
  16. package/editor/view/particles/effect/ParticleCodeEditorView.js +4 -3
  17. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts +20 -0
  18. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -0
  19. package/editor/view/particles/effect/ParticleCurveEditorView.js +574 -0
  20. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
  21. package/editor/view/particles/effect/ParticleEmitterInspectorView.js +27 -1
  22. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts +24 -0
  23. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -0
  24. package/editor/view/particles/effect/ParticleGradientEditorView.js +472 -0
  25. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts +5 -0
  26. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -1
  27. package/editor/view/particles/effect/ParticleGraphEditorView.js +61 -31
  28. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
  29. package/editor/view/particles/effect/ParticleNodeParametersView.js +33 -0
  30. package/editor/view/particles/effect/particle-editor.css +123 -35
  31. package/package.json +1 -1
  32. package/src/core/binary/allocator/OffsetAllocator.d.ts +25 -16
  33. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  34. package/src/core/binary/allocator/OffsetAllocator.js +10 -1
  35. package/src/core/collection/array/typed/float32_array_hash.d.ts +21 -0
  36. package/src/core/collection/array/typed/float32_array_hash.d.ts.map +1 -0
  37. package/src/core/collection/array/typed/float32_array_hash.js +38 -0
  38. package/src/core/graph/csr/CSRGraph.d.ts +8 -1
  39. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -1
  40. package/src/core/graph/csr/CSRGraph.js +14 -6
  41. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts +24 -0
  42. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts.map +1 -1
  43. package/src/core/model/node-graph/visual/layout/LayoutProblem.js +27 -0
  44. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +26 -0
  45. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
  46. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +28 -0
  47. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts +92 -3
  48. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts.map +1 -1
  49. package/src/core/model/node-graph/visual/layout/RouteGrid.js +405 -242
  50. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts +50 -5
  51. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts.map +1 -1
  52. package/src/core/model/node-graph/visual/layout/RouteSearch.js +160 -24
  53. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts +7 -0
  54. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts.map +1 -1
  55. package/src/core/model/node-graph/visual/layout/RouteSet.js +8 -0
  56. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +9 -3
  57. package/src/core/model/node-graph/visual/layout/layout_build_problem.d.ts.map +1 -1
  58. package/src/core/model/node-graph/visual/layout/layout_build_problem.js +7 -0
  59. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts +9 -3
  60. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +1 -1
  61. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.js +17 -3
  62. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts +9 -6
  63. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts.map +1 -1
  64. package/src/core/model/node-graph/visual/layout/layout_node_graph.js +49 -7
  65. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts +11 -1
  66. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +1 -1
  67. package/src/core/model/node-graph/visual/layout/layout_order_layers.js +135 -16
  68. package/src/core/model/node-graph/visual/layout/route_connections.d.ts +29 -0
  69. package/src/core/model/node-graph/visual/layout/route_connections.d.ts.map +1 -1
  70. package/src/core/model/node-graph/visual/layout/route_connections.js +716 -309
  71. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts +3 -2
  72. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts.map +1 -1
  73. package/src/core/model/node-graph/visual/layout/route_grid_build.js +7 -15
  74. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts +6 -0
  75. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts.map +1 -1
  76. package/src/core/model/node-graph/visual/layout/route_nudge.js +42 -13
  77. package/src/engine/animation/AnimationUtils.js +246 -246
  78. package/src/engine/animation/Animations.js +74 -74
  79. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2078 -2078
  80. package/src/engine/ecs/EventType.d.ts +0 -1
  81. package/src/engine/ecs/EventType.js +1 -26
  82. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +1 -1
  83. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -1
  84. package/src/engine/ecs/ik/ik_write_local_rotation.js +3 -7
  85. package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
  86. package/src/engine/ecs/parent/EntityNode.js +4 -9
  87. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  88. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +360 -364
  89. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts +41 -0
  90. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts.map +1 -0
  91. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.js +40 -0
  92. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +8 -0
  93. package/src/engine/ecs/transform/t64_announce_change.d.ts +10 -7
  94. package/src/engine/ecs/transform/t64_announce_change.d.ts.map +1 -1
  95. package/src/engine/ecs/transform/t64_announce_change.js +12 -12
  96. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts +30 -0
  97. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts.map +1 -0
  98. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.js +29 -0
  99. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  100. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +13 -21
  101. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  102. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +4 -8
  103. package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
  104. package/src/engine/graphics3/LightSystem.js +4 -8
  105. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  106. package/src/engine/graphics3/MeshSystem.js +9 -19
  107. package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
  108. package/src/engine/graphics3/ParticleEmitterSystem.js +4 -8
  109. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  110. package/src/engine/graphics3/ShadedGeometrySystem.js +4 -10
  111. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts +1 -1
  112. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
  113. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +4 -8
  114. package/src/engine/intelligence/behavior/ecs/OrbitingBehavior.js +218 -218
  115. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  116. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  117. package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
  118. package/src/engine/sound/ecs/SoundListenerSystem.js +6 -8
  119. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts +0 -4
  120. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts.map +1 -1
  121. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +5 -11
  122. package/src/shade/playground/particle_editor/README.md +43 -2
  123. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
  124. package/src/shade/playground/particle_system/particle_prototype.js +4 -5
  125. package/src/shade/playground/particle_system/particle_scene.js +4 -4
  126. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  127. package/src/shade/renderer/Renderer.js +13 -1
  128. package/src/shade/renderer/particles/DESIGN.md +104 -19
  129. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +64 -50
  130. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  131. package/src/shade/renderer/particles/GPUParticleSystem.js +176 -78
  132. package/src/shade/renderer/particles/ParticleConstants.d.ts +59 -23
  133. package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
  134. package/src/shade/renderer/particles/ParticleConstants.js +66 -23
  135. package/src/shade/renderer/particles/ParticleRenderMode.d.ts +19 -0
  136. package/src/shade/renderer/particles/ParticleRenderMode.d.ts.map +1 -0
  137. package/src/shade/renderer/particles/ParticleRenderMode.js +33 -0
  138. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
  139. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +167 -166
  140. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts +37 -0
  141. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -0
  142. package/src/shade/renderer/particles/data/particle_emitter_record.js +109 -0
  143. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +3 -3
  144. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +303 -303
  145. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +18 -0
  146. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
  147. package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +152 -133
  148. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +0 -11
  149. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
  150. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +720 -621
  151. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
  152. package/src/shade/renderer/particles/graph/compile_particle_graph.js +8 -3
  153. package/src/shade/renderer/particles/graph/flatten_particle_graph.d.ts.map +1 -1
  154. package/src/shade/renderer/particles/graph/flatten_particle_graph.js +244 -213
  155. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -1
  156. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +6 -0
  157. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -1
  158. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +294 -319
  159. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.d.ts.map +1 -1
  160. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.js +524 -517
  161. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts +22 -0
  162. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts.map +1 -0
  163. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.js +517 -0
  164. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
  165. package/src/shade/renderer/particles/graph/groups/simplex_reference.js +185 -159
  166. package/src/shade/renderer/particles/graph/make_particle_group.d.ts.map +1 -1
  167. package/src/shade/renderer/particles/graph/make_particle_group.js +2 -20
  168. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts +17 -0
  169. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts.map +1 -0
  170. package/src/shade/renderer/particles/graph/particle_compare_ops.js +22 -0
  171. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts +28 -8
  172. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts.map +1 -1
  173. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.js +49 -25
  174. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +40 -0
  175. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
  176. package/src/shade/renderer/particles/graph/particle_node_parameters.js +312 -234
  177. package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
  178. package/src/shade/renderer/particles/graph/particle_node_presentation.js +59 -3
  179. package/src/shade/renderer/particles/graph/particle_ramp.d.ts +230 -0
  180. package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -0
  181. package/src/shade/renderer/particles/graph/particle_ramp.js +403 -0
  182. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +7 -1
  183. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
  184. package/src/shade/renderer/particles/graph/validate_particle_graph.js +66 -10
  185. package/src/shade/renderer/particles/graph_particles.d.ts +23 -69
  186. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  187. package/src/shade/renderer/particles/graph_particles.js +105 -262
  188. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  189. package/src/shade/renderer/particles/graph_particles_avboit.js +3 -2
  190. package/src/shade/renderer/particles/graph_particles_billboard.d.ts +37 -0
  191. package/src/shade/renderer/particles/graph_particles_billboard.d.ts.map +1 -0
  192. package/src/shade/renderer/particles/graph_particles_billboard.js +93 -0
  193. package/src/shade/renderer/particles/isa/InstructionStream.d.ts +51 -22
  194. package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
  195. package/src/shade/renderer/particles/isa/InstructionStream.js +98 -38
  196. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +49 -8
  197. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
  198. package/src/shade/renderer/particles/isa/ParticleProgram.js +95 -150
  199. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +306 -64
  200. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  201. package/src/shade/renderer/particles/isa/ParticleVMISA.js +505 -136
  202. package/src/shade/renderer/particles/isa/particle_assembly.d.ts +36 -12
  203. package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
  204. package/src/shade/renderer/particles/isa/particle_assembly.js +354 -139
  205. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts +9 -0
  206. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts.map +1 -0
  207. package/src/shade/renderer/particles/isa/validate_particle_program.js +128 -0
  208. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +23 -0
  209. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
  210. package/src/shade/renderer/particles/layout/ParticleLayout.js +68 -0
  211. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts +77 -0
  212. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -0
  213. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +219 -0
  214. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts +83 -0
  215. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -0
  216. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +283 -0
  217. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +133 -0
  218. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts.map +1 -0
  219. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +334 -0
  220. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts +117 -0
  221. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts.map +1 -0
  222. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +70 -0
  223. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts +97 -0
  224. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts.map +1 -0
  225. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +462 -0
  226. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts +116 -0
  227. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts.map +1 -0
  228. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +687 -0
  229. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +57 -0
  230. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts.map +1 -0
  231. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +860 -0
  232. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts +115 -0
  233. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts.map +1 -0
  234. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.js +264 -0
  235. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +81 -42
  236. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -1
  237. package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +477 -478
  238. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +100 -0
  239. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts.map +1 -0
  240. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +236 -0
  241. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +139 -59
  242. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
  243. package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +764 -647
  244. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +40 -7
  245. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
  246. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +376 -213
  247. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts +30 -3
  248. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -1
  249. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +337 -223
  250. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +24 -38
  251. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  252. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +166 -206
  253. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts +99 -0
  254. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -0
  255. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +313 -0
  256. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts +3 -2
  257. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -1
  258. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.js +198 -197
  259. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -1
  260. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts +19 -0
  261. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
  262. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +678 -561
  263. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts +22 -0
  264. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -0
  265. package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +221 -0
  266. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
  267. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +63 -72
  268. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
  269. package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +87 -86
  270. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
  271. package/src/shade/renderer/particles/optimizer/pass_peephole.js +392 -271
  272. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
  273. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +361 -268
  274. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts +4 -0
  275. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -0
  276. package/src/shade/renderer/particles/optimizer/pass_schedule.js +244 -0
  277. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
  278. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +154 -151
  279. package/src/shade/renderer/particles/particle_test_fixtures.d.ts +20 -0
  280. package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +1 -1
  281. package/src/shade/renderer/particles/particle_test_fixtures.js +229 -203
  282. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +99 -25
  283. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  284. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +438 -286
  285. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +109 -0
  286. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -0
  287. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +127 -0
  288. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +87 -102
  289. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  290. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +184 -163
  291. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts +26 -0
  292. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts.map +1 -1
  293. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +130 -0
  294. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -0
  295. package/src/shade/renderer/particles/runtime/ProgramHeap.js +595 -0
  296. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts +91 -0
  297. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts.map +1 -0
  298. package/src/shade/renderer/particles/runtime/ProgramPlacement.js +106 -0
  299. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +5 -2
  300. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
  301. package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -19
  302. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts +28 -0
  303. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts.map +1 -0
  304. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.js +136 -0
  305. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts +35 -0
  306. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts.map +1 -0
  307. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.js +133 -0
  308. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts +18 -9
  309. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  310. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +20 -80
  311. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts +33 -0
  312. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -0
  313. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +114 -0
  314. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts +8 -0
  315. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  316. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +33 -101
  317. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts +45 -0
  318. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -0
  319. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +123 -0
  320. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts +51 -0
  321. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts.map +1 -0
  322. package/src/shade/renderer/particles/sort/graph_particle_sort.js +120 -0
  323. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts +6 -0
  324. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -0
  325. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +16 -0
  326. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +4 -1
  327. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  328. package/src/shade/renderer/particles/vm/ParticleVMReference.js +261 -140
  329. package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
  330. package/src/shade/renderer/particles/vm/chunk_particle_vm.js +217 -255
  331. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts +43 -0
  332. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts.map +1 -0
  333. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.js +55 -0
  334. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts +62 -0
  335. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts.map +1 -0
  336. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.js +86 -0
  337. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts +22 -0
  338. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts.map +1 -0
  339. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.js +32 -0
  340. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts +9 -0
  341. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts.map +1 -0
  342. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.js +19 -0
  343. package/src/shade/renderer/shader/chunk/noise/psrdnoise/README.md +65 -0
  344. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts +24 -0
  345. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts.map +1 -0
  346. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.js +83 -0
  347. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts +25 -0
  348. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts.map +1 -0
  349. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.js +42 -0
  350. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts +31 -0
  351. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts.map +1 -0
  352. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.js +80 -0
  353. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts +26 -0
  354. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts.map +1 -0
  355. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.js +109 -0
  356. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts +38 -0
  357. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts.map +1 -0
  358. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.js +129 -0
  359. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts +21 -0
  360. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts.map +1 -0
  361. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.js +35 -0
  362. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts +19 -0
  363. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts.map +1 -0
  364. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.js +28 -0
  365. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts +13 -0
  366. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts.map +1 -0
  367. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.js +22 -0
  368. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts +22 -0
  369. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts.map +1 -0
  370. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.js +59 -0
  371. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts +23 -0
  372. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts.map +1 -0
  373. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.js +74 -0
  374. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts +34 -1
  375. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts.map +1 -1
  376. package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +41 -1
  377. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -2
  378. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  379. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +49 -10
  380. package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
  381. package/src/view/minimap/dom/MinimapCameraView.js +4 -9
  382. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts +0 -15
  383. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts.map +0 -1
  384. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts +0 -45
  385. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts.map +0 -1
  386. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts +0 -24
  387. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts.map +0 -1
  388. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts +0 -19
  389. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts.map +0 -1
  390. package/src/engine/ecs/transform/__probe.d.ts +0 -4
  391. package/src/engine/ecs/transform/__probe.d.ts.map +0 -1
  392. package/src/engine/ecs/util/hideEntityGracefully.d.ts +0 -9
  393. package/src/engine/ecs/util/hideEntityGracefully.d.ts.map +0 -1
  394. package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts +0 -27
  395. package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts.map +0 -1
  396. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts +0 -14
  397. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +0 -1
  398. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts +0 -156
  399. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts.map +0 -1
  400. package/src/shade/renderer/particles/runtime/Emitter.d.ts +0 -219
  401. package/src/shade/renderer/particles/runtime/Emitter.d.ts.map +0 -1
  402. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts +0 -77
  403. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts.map +0 -1
  404. package/src/shade/renderer/particles/runtime/ProgramArena.js +0 -155
  405. package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts +0 -15
  406. package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts.map +0 -1
  407. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts +0 -34
  408. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts.map +0 -1
  409. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts +0 -32
  410. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts.map +0 -1
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Where one program sits in the {@link ./ProgramHeap.js ProgramHeap}, and what an emitter record
3
+ * carries to find it.
4
+ *
5
+ * A placement is the heap's, not the caller's: {@link ./ProgramHeap.js#acquire} hands one out and
6
+ * {@link ./ProgramHeap.js#release} takes it back, and every field here is written by the heap. It is
7
+ * shared — every emitter running the same bytecode holds the same placement object, which is what
8
+ * puts them in one simulation bucket — and it is MUTATED IN PLACE when the heap repacks. Holders
9
+ * therefore see the new offsets without being handed a new object, and only have to restage the
10
+ * record they wrote the old ones into.
11
+ *
12
+ * The offsets are section-relative, which is what lets the heap move a program without the shader
13
+ * knowing: instruction offsets count instructions from the code section's base, and
14
+ * {@link ProgramPlacement#constant_offset} counts words from the constant section's base. The one
15
+ * absolute address in the whole buffer is the header word saying where the code section starts.
16
+ */
17
+ export class ProgramPlacement {
18
+
19
+ /**
20
+ * Dense-ish id of this program: the value the emitter record carries and the simulation-order
21
+ * pass histograms on. Stable for the life of the placement, repacks included — the offsets move,
22
+ * the id does not.
23
+ *
24
+ * Ids are handed out lowest-free-first and a released one is reused, so they stay inside
25
+ * `[0, ProgramHeap#program_id_capacity)` however many programs come and go.
26
+ *
27
+ * @type {number}
28
+ */
29
+ program_id = -1;
30
+
31
+ /**
32
+ * First instruction of the INIT section, counted in instructions from the code base.
33
+ * @type {number}
34
+ */
35
+ init_offset = 0;
36
+
37
+ /**
38
+ * Instructions in the INIT section.
39
+ * @type {number}
40
+ */
41
+ init_count = 0;
42
+
43
+ /**
44
+ * First instruction of the UPDATE section, counted in instructions from the code base. Directly
45
+ * after INIT — the two sections of a program are allocated as one contiguous range.
46
+ * @type {number}
47
+ */
48
+ update_offset = 0;
49
+
50
+ /**
51
+ * Instructions in the UPDATE section.
52
+ * @type {number}
53
+ */
54
+ update_count = 0;
55
+
56
+ /**
57
+ * First word of this program's constant pool, counted in words from the constant base. The VM
58
+ * adds it to every program-local constant reference.
59
+ * @type {number}
60
+ */
61
+ constant_offset = 0;
62
+
63
+ /**
64
+ * The heap's own copy of the bytecode — the key it is filed under, and what a repack rewrites
65
+ * into the moved range.
66
+ *
67
+ * @type {import("../isa/ParticleProgram.js").ParticleProgram|null}
68
+ */
69
+ program = null;
70
+
71
+ /**
72
+ * How many emitters hold this placement. The heap frees the ranges and releases the id when it
73
+ * reaches zero, so one emitter of a shared effect going away does not take the effect with it.
74
+ *
75
+ * @type {number}
76
+ */
77
+ references = 0;
78
+
79
+ /**
80
+ * The code range, in instructions, as {@link ../../../../core/binary/allocator/OffsetAllocator.js}
81
+ * handed it out. `null` for a program with no instructions at all.
82
+ *
83
+ * @type {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null}
84
+ */
85
+ code_allocation = null;
86
+
87
+ /**
88
+ * The constant-pool range, in words. `null` for a program with an empty pool.
89
+ * @type {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null}
90
+ */
91
+ constant_allocation = null;
92
+
93
+ /**
94
+ * @returns {number} instructions this program occupies in the code section, both sections summed
95
+ */
96
+ get instruction_count() {
97
+ return this.init_count + this.update_count;
98
+ }
99
+
100
+ /**
101
+ * @returns {number} words this program occupies in the constant section
102
+ */
103
+ get constant_word_count() {
104
+ return this.program === null ? 0 : this.program.constant_word_count;
105
+ }
106
+ }
@@ -2,8 +2,11 @@
2
2
  * Compile a particle effect: a per-particle attribute {@link ../layout/ParticleLayout.js} plus INIT
3
3
  * and UPDATE node graphs, lowered to VM bytecode.
4
4
  *
5
- * The returned value bundles the layout with the compiled program so the {@link ./EmitterRegistry.js}
6
- * can resolve render-attribute names to record offsets and pack the program into the arena.
5
+ * The two halves come back together because they are compiled together, and an emitter takes both:
6
+ * the layout is what a render binding resolves a name against, the program is what the heap packs.
7
+ * They are not a value in their own right, so they go into an emitter by being spread —
8
+ * `ParticleEmitter.from({ ...create_particle_effect({ layout, update }), spawn_rate: 100 })` — and
9
+ * the emitter keeps them as two fields rather than as one bag.
7
10
  *
8
11
  * @param {object} params
9
12
  * @param {import("../layout/ParticleLayout.js").ParticleLayout} params.layout
@@ -1 +1 @@
1
- {"version":3,"file":"create_particle_effect.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/create_particle_effect.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH;IALwE,MAAM,EAAnE,OAAO,6BAA6B,EAAE,cAAc;IACjC,IAAI;IACJ,MAAM;;YACb,OAAO,6BAA6B,EAAE,cAAc;aAAW,OAAO,2BAA2B,EAAE,eAAe;EAKxI"}
1
+ {"version":3,"file":"create_particle_effect.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/create_particle_effect.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH;IALwE,MAAM,EAAnE,OAAO,6BAA6B,EAAE,cAAc;IACjC,IAAI;IACJ,MAAM;;YACb,OAAO,6BAA6B,EAAE,cAAc;aAAW,OAAO,2BAA2B,EAAE,eAAe;EAKxI"}
@@ -1,19 +1,22 @@
1
- import { compile_particle_effect } from "../graph/compile_particle_graph.js";
2
-
3
- /**
4
- * Compile a particle effect: a per-particle attribute {@link ../layout/ParticleLayout.js} plus INIT
5
- * and UPDATE node graphs, lowered to VM bytecode.
6
- *
7
- * The returned value bundles the layout with the compiled program so the {@link ./EmitterRegistry.js}
8
- * can resolve render-attribute names to record offsets and pack the program into the arena.
9
- *
10
- * @param {object} params
11
- * @param {import("../layout/ParticleLayout.js").ParticleLayout} params.layout
12
- * @param {NodeGraph} [params.init]
13
- * @param {NodeGraph} [params.update]
14
- * @returns {{ layout: import("../layout/ParticleLayout.js").ParticleLayout, program: import("../isa/ParticleProgram.js").ParticleProgram }}
15
- */
16
- export function create_particle_effect({ layout, init, update }) {
17
- const program = compile_particle_effect({ init, update, layout });
18
- return { layout, program };
19
- }
1
+ import { compile_particle_effect } from "../graph/compile_particle_graph.js";
2
+
3
+ /**
4
+ * Compile a particle effect: a per-particle attribute {@link ../layout/ParticleLayout.js} plus INIT
5
+ * and UPDATE node graphs, lowered to VM bytecode.
6
+ *
7
+ * The two halves come back together because they are compiled together, and an emitter takes both:
8
+ * the layout is what a render binding resolves a name against, the program is what the heap packs.
9
+ * They are not a value in their own right, so they go into an emitter by being spread —
10
+ * `ParticleEmitter.from({ ...create_particle_effect({ layout, update }), spawn_rate: 100 })` — and
11
+ * the emitter keeps them as two fields rather than as one bag.
12
+ *
13
+ * @param {object} params
14
+ * @param {import("../layout/ParticleLayout.js").ParticleLayout} params.layout
15
+ * @param {NodeGraph} [params.init]
16
+ * @param {NodeGraph} [params.update]
17
+ * @returns {{ layout: import("../layout/ParticleLayout.js").ParticleLayout, program: import("../isa/ParticleProgram.js").ParticleProgram }}
18
+ */
19
+ export function create_particle_effect({ layout, init, update }) {
20
+ const program = compile_particle_effect({ init, update, layout });
21
+ return { layout, program };
22
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What the emit pass does for one particle born this frame — which emitter it belongs to, and what
3
+ * its record holds once it exists.
4
+ *
5
+ * Shared by {@link ./shader_particle_emit.js} and {@link ./shader_particle_emit_wide.js} for the
6
+ * same reason {@link ./chunk_particle_simulate_step.js} is shared: two register backings, one
7
+ * meaning, and the difference between the shaders is how they get an index and nothing else.
8
+ *
9
+ * ## What stays in the entry points
10
+ *
11
+ * Both atomic sections: popping a free slot off the dead-list stack, and appending the newborn to
12
+ * the alive list. They bracket `particle_emit_one` rather than living inside it, because the pop
13
+ * has to fail before any record is touched, and because an atomic array behind a pointer parameter
14
+ * is a shape nothing else in the engine uses.
15
+ *
16
+ * The pop is the delicate one, and its guard must catch WRAPPED values rather than just zero. When
17
+ * many threads race an empty stack, the first over-pop wraps the counter to `0xFFFFFFFF` before its
18
+ * undo lands, and a concurrent thread then observes a huge old value. Checking only `== 0` would let
19
+ * it index `dead[old - 1]` with garbage and hand out a bogus slot, corrupting a live record. The
20
+ * dead count can never legitimately exceed the pool capacity, so `> capacity` identifies every
21
+ * wrapped state; each thread that subtracted also adds back exactly once, so the counter converges
22
+ * to 0. Both entry points spell that out; this paragraph is where it is explained.
23
+ *
24
+ * @type {CodeChunk}
25
+ */
26
+ export const chunk_particle_emit_step: CodeChunk;
27
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
28
+ //# sourceMappingURL=chunk_particle_emit_step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_particle_emit_step.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_emit_step.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,uCAFU,SAAS,CAoGhB;0BAvIuB,oCAAoC"}
@@ -0,0 +1,136 @@
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import { chunk_lower_bound_branchless } from "../../shader/chunk/math/chunk_lower_bound_branchless.js";
3
+ import {
4
+ PARTICLE_RECORD_HEADER_EMITTER,
5
+ PARTICLE_RECORD_USER_WORD_START,
6
+ PARTICLE_RECORD_WORD_COUNT,
7
+ PARTICLE_VM_INSTRUCTION_WORDS,
8
+ } from "../ParticleConstants.js";
9
+ import { chunk_particle_header } from "../data/particle_header.js";
10
+ import { chunk_particle_emitter_age } from "./chunk_particle_emitter_age.js";
11
+ import { chunk_particle_setup_context } from "./chunk_particle_setup_context.js";
12
+
13
+ /**
14
+ * What the emit pass does for one particle born this frame — which emitter it belongs to, and what
15
+ * its record holds once it exists.
16
+ *
17
+ * Shared by {@link ./shader_particle_emit.js} and {@link ./shader_particle_emit_wide.js} for the
18
+ * same reason {@link ./chunk_particle_simulate_step.js} is shared: two register backings, one
19
+ * meaning, and the difference between the shaders is how they get an index and nothing else.
20
+ *
21
+ * ## What stays in the entry points
22
+ *
23
+ * Both atomic sections: popping a free slot off the dead-list stack, and appending the newborn to
24
+ * the alive list. They bracket `particle_emit_one` rather than living inside it, because the pop
25
+ * has to fail before any record is touched, and because an atomic array behind a pointer parameter
26
+ * is a shape nothing else in the engine uses.
27
+ *
28
+ * The pop is the delicate one, and its guard must catch WRAPPED values rather than just zero. When
29
+ * many threads race an empty stack, the first over-pop wraps the counter to `0xFFFFFFFF` before its
30
+ * undo lands, and a concurrent thread then observes a huge old value. Checking only `== 0` would let
31
+ * it index `dead[old - 1]` with garbage and hand out a bogus slot, corrupting a live record. The
32
+ * dead count can never legitimately exceed the pool capacity, so `> capacity` identifies every
33
+ * wrapped state; each thread that subtracted also adds back exactly once, so the counter converges
34
+ * to 0. Both entry points spell that out; this paragraph is where it is explained.
35
+ *
36
+ * @type {CodeChunk}
37
+ */
38
+ export const chunk_particle_emit_step = CodeChunk.from(/* language=wgsl */ `
39
+ const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
40
+ const PARTICLE_USER_WORD_START : u32 = ${PARTICLE_RECORD_USER_WORD_START}u;
41
+ const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
42
+ const PARTICLE_INSTRUCTION_WORDS : u32 = ${PARTICLE_VM_INSTRUCTION_WORDS}u;
43
+
44
+ // Which emitter newborn i belongs to, and where in that emitter's batch it sits.
45
+ struct ParticleEmitAssignment {
46
+ valid : bool,
47
+ emitter_row : u32,
48
+ // This particle's place in its emitter's batch this frame, n / count — the SPAWN_FRACTION
49
+ // contract, for spreading a batch along a spawn curve.
50
+ spawn_fraction : f32,
51
+ }
52
+
53
+ // Locate newborn i in the prefix scan of the tick pass's per-row spawn counts.
54
+ //
55
+ // The emitter is the first row whose inclusive sum exceeds i; its batch starts at the sum before,
56
+ // which is the exclusive sum. Rows that spawned nothing this frame have equal sums and the search
57
+ // steps over them. That is the meshes-to-meshlets expansion applied to particles: the per-emitter
58
+ // count is unbounded and no thread loops over it.
59
+ fn particle_emit_assignment(
60
+ prefix : ptr<storage, array<u32>>,
61
+ emitter_count : u32,
62
+ i : u32,
63
+ ) -> ParticleEmitAssignment {
64
+ var r : ParticleEmitAssignment;
65
+ r.valid = false;
66
+ r.emitter_row = 0u;
67
+ r.spawn_fraction = 0.0;
68
+
69
+ // The scan's last inclusive sum is the number of particles born this frame. An empty list has
70
+ // no last element to read; it also has no particles.
71
+ if (emitter_count == 0u) { return r; }
72
+ if (i >= (*prefix)[emitter_count - 1u]) { return r; }
73
+
74
+ let emitter_row = lower_bound_branchless(prefix, i + 1u, emitter_count);
75
+ var batch_start = 0u;
76
+ if (emitter_row > 0u) {
77
+ batch_start = (*prefix)[emitter_row - 1u];
78
+ }
79
+ let batch_size = (*prefix)[emitter_row] - batch_start;
80
+
81
+ r.valid = true;
82
+ r.emitter_row = emitter_row;
83
+ r.spawn_fraction = f32(i - batch_start) / f32(batch_size);
84
+
85
+ return r;
86
+ }
87
+
88
+ // Give a freshly popped slot its particle: clear what the last occupant left, stamp the header with
89
+ // the emitter row and its generation, and run that emitter's INIT program over the record. The
90
+ // emitter's position and axes come from its scene node, so a particle born of an emitter riding a
91
+ // bone starts where the bone is this frame.
92
+ fn particle_emit_one(
93
+ scene_database : ptr<storage, array<u32>>,
94
+ emitter_database : ptr<storage, array<u32>>,
95
+ program : ptr<storage, array<u32>>,
96
+ pool : ptr<storage, array<u32>, read_write>,
97
+ emitter_row : u32,
98
+ slot : u32,
99
+ spawn_fraction : f32,
100
+ dt : f32,
101
+ time : f32,
102
+ frame : u32,
103
+ ) {
104
+ let record_base = slot * PARTICLE_RECORD_WORDS;
105
+
106
+ let em = particle_emitter_read(emitter_database, emitter_row);
107
+ let node = scene_read_node(scene_database, em.node);
108
+
109
+ // Clear stale user state from a recycled slot (each write targets a distinct word).
110
+ for (var w = PARTICLE_USER_WORD_START; w < PARTICLE_RECORD_WORDS; w = w + 1u) {
111
+ (*pool)[record_base + w] = 0u;
112
+ }
113
+ (*pool)[record_base + PARTICLE_HEADER_EMITTER] = particle_header_pack(emitter_row, em.generation);
114
+
115
+ particle_vm_reset();
116
+ particle_setup_context(
117
+ em, node, slot,
118
+ dt, time,
119
+ particle_emitter_age(emitter_database, emitter_row),
120
+ spawn_fraction, frame,
121
+ );
122
+ particle_vm_execute(
123
+ program,
124
+ em.init_offset * PARTICLE_INSTRUCTION_WORDS,
125
+ em.init_count,
126
+ em.constant_offset,
127
+ pool,
128
+ record_base,
129
+ );
130
+ }
131
+ `, [
132
+ chunk_particle_setup_context,
133
+ chunk_particle_emitter_age,
134
+ chunk_particle_header,
135
+ chunk_lower_bound_branchless,
136
+ ]);
@@ -0,0 +1,35 @@
1
+ /**
2
+ * What the simulate pass does to one particle — everything between reading its slot out of the
3
+ * coherence list and deciding whether it lives.
4
+ *
5
+ * It is a chunk rather than the body of a shader because there are two simulate shaders and only one
6
+ * simulation. {@link ./shader_particle_simulate.js} runs one invocation per particle over the fast
7
+ * register file; {@link ./shader_particle_simulate_wide.js} runs a bounded launch with a grid-stride
8
+ * loop over the wide one. They differ in how they get an index and in nothing else, and everything
9
+ * that is not "how do I get an index" lives here so it cannot drift between them.
10
+ *
11
+ * ## What stays in the entry points
12
+ *
13
+ * The compaction atomics. `particle_simulate_one` returns a verdict and the caller acts on it, so
14
+ * the two `atomicAdd`s and the list appends sit in `main` where the dispatch shape can be seen next
15
+ * to them. That is also why this chunk takes no pointer to `counters`: an atomic array behind a
16
+ * pointer parameter is a shape nothing else in the engine uses, and the seam is not worth being the
17
+ * first.
18
+ *
19
+ * ## The padding verdict is a verdict, not an early exit
20
+ *
21
+ * A lane the coherence pass padded a bucket out with returns {@link PARTICLE_SIM_SKIP}, and the
22
+ * caller then does nothing at all with it. Getting this wrong is not subtle in its consequences:
23
+ * appending a padding lane would put {@link PARTICLE_SIM_PAD_SLOT} — `0xffffffff` — on the alive
24
+ * list or the free list, and a later emit would take it off the free list and use it as a record
25
+ * base.
26
+ *
27
+ * Returning early from this function leaves the lane inactive for the rest of it, which is exactly
28
+ * what the wave-uniform read below needs, and is the same active set the old inline early-`return`
29
+ * produced.
30
+ *
31
+ * @type {CodeChunk}
32
+ */
33
+ export const chunk_particle_simulate_step: CodeChunk;
34
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
35
+ //# sourceMappingURL=chunk_particle_simulate_step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_particle_simulate_step.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_simulate_step.js"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,2CAFU,SAAS,CA2FhB;0BApIuB,oCAAoC"}
@@ -0,0 +1,133 @@
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import {
3
+ PARTICLE_RECORD_HEADER_EMITTER,
4
+ PARTICLE_RECORD_WORD_COUNT,
5
+ PARTICLE_SIM_PAD_SLOT,
6
+ PARTICLE_VM_INSTRUCTION_WORDS,
7
+ } from "../ParticleConstants.js";
8
+ import { chunk_particle_header } from "../data/particle_header.js";
9
+ import { chunk_particle_emitter_age } from "./chunk_particle_emitter_age.js";
10
+ import { chunk_particle_setup_context } from "./chunk_particle_setup_context.js";
11
+
12
+ /**
13
+ * What the simulate pass does to one particle — everything between reading its slot out of the
14
+ * coherence list and deciding whether it lives.
15
+ *
16
+ * It is a chunk rather than the body of a shader because there are two simulate shaders and only one
17
+ * simulation. {@link ./shader_particle_simulate.js} runs one invocation per particle over the fast
18
+ * register file; {@link ./shader_particle_simulate_wide.js} runs a bounded launch with a grid-stride
19
+ * loop over the wide one. They differ in how they get an index and in nothing else, and everything
20
+ * that is not "how do I get an index" lives here so it cannot drift between them.
21
+ *
22
+ * ## What stays in the entry points
23
+ *
24
+ * The compaction atomics. `particle_simulate_one` returns a verdict and the caller acts on it, so
25
+ * the two `atomicAdd`s and the list appends sit in `main` where the dispatch shape can be seen next
26
+ * to them. That is also why this chunk takes no pointer to `counters`: an atomic array behind a
27
+ * pointer parameter is a shape nothing else in the engine uses, and the seam is not worth being the
28
+ * first.
29
+ *
30
+ * ## The padding verdict is a verdict, not an early exit
31
+ *
32
+ * A lane the coherence pass padded a bucket out with returns {@link PARTICLE_SIM_SKIP}, and the
33
+ * caller then does nothing at all with it. Getting this wrong is not subtle in its consequences:
34
+ * appending a padding lane would put {@link PARTICLE_SIM_PAD_SLOT} — `0xffffffff` — on the alive
35
+ * list or the free list, and a later emit would take it off the free list and use it as a record
36
+ * base.
37
+ *
38
+ * Returning early from this function leaves the lane inactive for the rest of it, which is exactly
39
+ * what the wave-uniform read below needs, and is the same active set the old inline early-`return`
40
+ * produced.
41
+ *
42
+ * @type {CodeChunk}
43
+ */
44
+ export const chunk_particle_simulate_step = CodeChunk.from(/* language=wgsl */ `
45
+ const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
46
+ const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
47
+ const PARTICLE_INSTRUCTION_WORDS : u32 = ${PARTICLE_VM_INSTRUCTION_WORDS}u;
48
+ const PARTICLE_SIM_PAD_SLOT : u32 = ${PARTICLE_SIM_PAD_SLOT}u;
49
+
50
+ // Verdicts particle_simulate_one returns. SKIP is a lane that never held a particle.
51
+ const PARTICLE_SIM_SKIP : u32 = 0u;
52
+ const PARTICLE_SIM_ALIVE : u32 = 1u;
53
+ const PARTICLE_SIM_KILLED : u32 = 2u;
54
+
55
+ // The value the wave's first live lane holds, in every lane.
56
+ //
57
+ // Everything that reaches the interpreter in one wave belongs to one bucket of sim_list: the
58
+ // coherence pass grouped the list by program and padded each group to a whole workgroup, and the
59
+ // padding and orphan lanes have left by the time a program runs. So the three numbers that pick a
60
+ // section are the same in every lane. The compiler cannot see that — they come out of a table row
61
+ // found through a per-lane header, which is as divergent as a value gets — and reading them from
62
+ // the first lane is what tells it. The rest follows on its own: the instruction words are then
63
+ // fetched through the scalar unit, the opcode switch branches on a scalar, and the fast register
64
+ // file is indexed through M0 directly instead of through a waterfall loop over the lanes' indices.
65
+ // (The wide file is indexed per-lane whatever happens, and keeps the other two.) Emit keeps its
66
+ // per-lane decode, because its waves span emitters.
67
+ //
68
+ // The grid-stride caller preserves this: its stride is a whole number of workgroups, so an
69
+ // iteration covers a workgroup-aligned span of the list and a wave still sees one bucket.
70
+ //
71
+ // The uniformity diagnostic is off because the call sits behind per-lane early returns. That is the
72
+ // situation the builtin is defined for — it reads the first ACTIVE lane — and the one WGSL's
73
+ // analysis over-approximates.
74
+ @diagnostic(off, subgroup_uniformity)
75
+ fn particle_wave_uniform(value : u32) -> u32 {
76
+ return subgroupBroadcastFirst(value);
77
+ }
78
+
79
+ // Run one particle's UPDATE program and say what became of it. Everything the caller then has to do
80
+ // is atomic.
81
+ fn particle_simulate_one(
82
+ scene_database : ptr<storage, array<u32>>,
83
+ emitter_database : ptr<storage, array<u32>>,
84
+ program : ptr<storage, array<u32>>,
85
+ pool : ptr<storage, array<u32>, read_write>,
86
+ slot : u32,
87
+ dt : f32,
88
+ time : f32,
89
+ frame : u32,
90
+ ) -> u32 {
91
+ // A lane the coherence pass padded the bucket out with. It owns no slot, so it has no verdict
92
+ // and the caller must not book one for it. Padding only ever appears in the tail of a bucket, so
93
+ // every real lane in this wave still belongs to the one bucket, and the switch the survivors
94
+ // execute is uniform regardless.
95
+ if (slot == PARTICLE_SIM_PAD_SLOT) { return PARTICLE_SIM_SKIP; }
96
+
97
+ let record_base = slot * PARTICLE_RECORD_WORDS;
98
+ let header = (*pool)[record_base + PARTICLE_HEADER_EMITTER];
99
+ let emitter_index = particle_header_emitter(header);
100
+
101
+ let em = particle_emitter_read(emitter_database, emitter_index);
102
+
103
+ // An orphan: its emitter is gone and the row is free or somebody else's. Freed without running
104
+ // a program — there is no program of its own left to run.
105
+ if (particle_header_generation(header) != em.generation) { return PARTICLE_SIM_KILLED; }
106
+
107
+ let node = scene_read_node(scene_database, em.node);
108
+
109
+ particle_vm_reset();
110
+ particle_setup_context(
111
+ em, node, slot,
112
+ dt, time,
113
+ particle_emitter_age(emitter_database, emitter_index),
114
+ 0.0, frame,
115
+ );
116
+ particle_vm_execute(
117
+ program,
118
+ particle_wave_uniform(em.update_offset) * PARTICLE_INSTRUCTION_WORDS,
119
+ particle_wave_uniform(em.update_count),
120
+ particle_wave_uniform(em.constant_offset),
121
+ pool,
122
+ record_base,
123
+ );
124
+
125
+ if (vm_killed) { return PARTICLE_SIM_KILLED; }
126
+
127
+ return PARTICLE_SIM_ALIVE;
128
+ }
129
+ `, [
130
+ chunk_particle_setup_context,
131
+ chunk_particle_emitter_age,
132
+ chunk_particle_header,
133
+ ]);
@@ -1,16 +1,14 @@
1
1
  /**
2
2
  * The particle emit pass: one thread per particle born this frame.
3
3
  *
4
- * Its input is the prefix scan of the emitter tick pass's per-row spawn counts. Thread `i` finds
5
- * the emitter it belongs to by binary search over the inclusive sums — the first row whose sum
6
- * exceeds `i` — and its place within that emitter's batch from the sum before. That is the
7
- * meshes-to-meshlets expansion applied to particles: the per-emitter count is unbounded, no thread
8
- * loops, and the dispatch is sized on the GPU from the scan's total.
4
+ * Its input is the prefix scan of the emitter tick pass's per-row spawn counts; thread `i` finds the
5
+ * emitter it belongs to by binary search over the inclusive sums, and its place within that
6
+ * emitter's batch from the sum before. Then: pop a free slot from the dead list, clear the record,
7
+ * stamp the header, run the emitter's INIT program, and append the slot to the new alive list.
9
8
  *
10
- * Then, as ever: pop a free slot from the dead list, clear the record, stamp the header with the
11
- * emitter row and its generation, run the emitter's INIT program to give the particle its state,
12
- * and append the slot to the new alive list. The emitter's position and axes come from its scene
13
- * node, so a particle born of an emitter riding a bone starts where the bone is this frame.
9
+ * The per-newborn work is {@link ./chunk_particle_emit_step.js}, shared with
10
+ * {@link ./shader_particle_emit_wide.js}. What this file is, is the *fast* register backing plus the
11
+ * one-lane-per-newborn dispatch that suits it.
14
12
  *
15
13
  * Runs before simulate in the frame so newborns join the same alive list survivors are compacted
16
14
  * into. Shares the VM + context + emitter chunks with simulate.
@@ -22,6 +20,17 @@
22
20
  * size — so the two must agree, and the constant it uses is the one it is.
23
21
  */
24
22
  export const PARTICLE_EMIT_WORKGROUP_SIZE: number;
23
+ /**
24
+ * Per-dispatch, 16 bytes, read-only.
25
+ *
26
+ * These were separate uniforms, which meant a transient buffer, a staging copy and a bind group
27
+ * entry each for a few bytes of frame state. WGSL allows one immediate per entry point, so carrying
28
+ * them as immediate data means carrying them together.
29
+ *
30
+ * @type {WebGPUStruct}
31
+ */
32
+ export const EMIT_SETTINGS: WebGPUStruct;
25
33
  export const shader_particle_emit: ComputeShader;
34
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
26
35
  import { ComputeShader } from "../../shader/ComputeShader.js";
27
36
  //# sourceMappingURL=shader_particle_emit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_emit.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;GAGG;AACH,kDAA8E;AAuH9E,iDAIG;8BAnK2B,+BAA+B"}
1
+ {"version":3,"file":"shader_particle_emit.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACH,kDAA8E;AAE9E;;;;;;;;GAQG;AACH,4BAFU,YAAY,CAOK;AAqD3B,iDAIG;6BA1G0B,mCAAmC;8BAGlC,+BAA+B"}