@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
@@ -1,4 +1,10 @@
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 { float32_array_hash } from "../../../../core/collection/array/typed/float32_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";
6
+ import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";
7
+ import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
2
8
  import { Node3D } from "../../scene/Node3D.js";
3
9
  import { EMITTER_ATTRIBUTE_ABSENT, make_emitter_flags } from "../data/PARTICLE_EMITTER_STRUCT.js";
4
10
 
@@ -44,76 +50,63 @@ export const EMITTER_RENDER_CHANNEL_COMPONENTS = Object.freeze({
44
50
  * particles, within a frame, because the emitter's table row is retired with it and its particles
45
51
  * carry that row's generation. There is no transform of its own to keep in step with anything.
46
52
  *
47
- * The rest is the CPU model of one row of the emitter table
48
- * ({@link ../data/PARTICLE_EMITTER_STRUCT.js}): the compiled effect and its placement in the
49
- * program arena, spawn rate, blend / projection / feature flags, bounds sphere, render-attribute
50
- * bindings, atlas region and flipbook grid. {@link write_record} is the whole of the translation
51
- * between the two. Fields are plain data with no setters — after changing any of them, set
52
- * {@link dirty} so {@link ./EmitterRegistry.js} restages the row on its next flush. A flag rather
53
- * than a setter per field because a row is restaged whole either way: one changed field and ten
54
- * cost the same upload.
53
+ * The rest is a description of an effect and nothing else: the attribute {@link layout} and the
54
+ * compiled {@link program}, the {@link texture} to draw with, spawn rate, blend / projection /
55
+ * feature flags, bounds sphere, render-attribute bindings and flipbook grid. Every one of those is
56
+ * the author's, means the same thing with no device present, and is what a saved effect is made of.
55
57
  *
56
- * What is NOT here is anything the GPU integrates per frame — spawn accumulator, age, sleep. That
57
- * is {@link ../data/PARTICLE_EMITTER_STATE.js}, and it stays on the GPU.
58
+ * **Nothing here is the GPU's.** Which table row the emitter was given, which tenancy of it, where
59
+ * its program was placed in the program heap, which `transforms` row its node ended up in, where
60
+ * its texture was packed into the atlas — all of that is
61
+ * {@link ./GPUParticleEmitterContext.js GPUParticleEmitterContext}, held by the
62
+ * {@link ./EmitterRegistry.js} that registered the emitter and reachable through
63
+ * {@link ./EmitterRegistry.js#context}. An emitter no registry holds has none, which is also how
64
+ * "is this emitter live?" is asked. Nor is anything the GPU integrates per frame here — spawn
65
+ * accumulator, age, sleep are {@link ../data/PARTICLE_EMITTER_STATE.js}, and they stay on the GPU.
58
66
  *
59
- * Instances become live through a {@link ./EmitterRegistry.js}, which assigns {@link row} and
60
- * {@link generation} and resolves the program placement. Constructing one directly gives you an
61
- * emitter no table knows about.
67
+ * Fields are plain data with no setters. After changing any of them, set `needsUpdate = true` — the
68
+ * node's own change counter, the same one the renderer reads to decide whether a transform needs
69
+ * re-uploading — and {@link ./EmitterRegistry.js#flush} restages the row on its next flush. One
70
+ * counter rather than a setter per field because a row is restaged whole either way: one changed
71
+ * field and ten cost the same upload.
62
72
  */
63
73
  export class ParticleEmitter extends Node3D {
64
74
 
65
75
  /**
66
- * Row this emitter occupies in the emitter table. Stable for the emitter's whole life — it is
67
- * what every live particle's record header stores, so it cannot be renumbered while particles
68
- * are in flight. `-1` until the registry assigns one.
76
+ * The per-particle attribute schema: which named attributes a particle of this emitter has, how
77
+ * wide each is, and what word of the record it sits at.
69
78
  *
70
- * Not to be confused with {@link Node3D#id}, which is the node's own identity and the key the
71
- * scene context maps to a `transforms` row.
72
- *
73
- * @type {number}
74
- */
75
- row = -1;
76
-
77
- /**
78
- * Which tenancy of {@link row} this emitter is. Assigned by the registry, distinct from every
79
- * other emitter it has ever assigned, never zero. Stamped into every particle the emitter
80
- * spawns, and what lets the simulate pass tell those particles from a later tenant's.
81
- *
82
- * @type {number}
79
+ * @type {import("../layout/ParticleLayout.js").ParticleLayout}
83
80
  */
84
- generation = 0;
81
+ layout;
85
82
 
86
83
  /**
87
- * Row of the scene database's `transforms` table this node occupies, as the scene context
88
- * reported it — what the record's `node` field carries. `0` (the scene root) until bound, so
89
- * an emitter that is registered before its node is placed still reads a valid row.
84
+ * The compiled INIT/UPDATE bytecode run for every particle of this emitter.
90
85
  *
91
- * @type {number}
86
+ * @type {import("../isa/ParticleProgram.js").ParticleProgram}
92
87
  */
93
- transform_row = 0;
88
+ program;
94
89
 
95
90
  /**
96
- * Compiled effect: the per-particle attribute layout plus the INIT/UPDATE bytecode.
91
+ * Image to draw the particles with, by URL, or `null` to draw against the default atlas — a
92
+ * single white texel, so an untextured emitter is a flat quad of its colour.
97
93
  *
98
- * @type {{layout: import("../layout/ParticleLayout.js").ParticleLayout, program: import("../isa/ParticleProgram.js").ParticleProgram}}
99
- */
100
- effect;
101
-
102
- /**
103
- * Where this emitter's program sits in the shared arena, and the dense program id the
104
- * simulation-order bucketing keys on. Assigned by {@link EmitterRegistry#add} from
105
- * {@link ../runtime/ProgramArena.js}; emitters compiled from the same graph share one.
94
+ * A URL rather than a texture, and no uv rect: the particle system packs every emitter's image
95
+ * into one sheet so that a hundred effects sharing a puff of smoke pay for one image, and where
96
+ * a given image lands in that sheet is the system's answer, not the author's — it changes on
97
+ * every repack, without the emitter changing. The resolved patch is
98
+ * {@link ./GPUParticleEmitterContext.js#atlas_region}.
106
99
  *
107
- * @type {{init_offset: number, init_count: number, update_offset: number, update_count: number, constant_offset: number, program_id: number}}
100
+ * @type {string|null}
108
101
  */
109
- placement;
102
+ texture = null;
110
103
 
111
104
  /**
112
105
  * Base RNG seed.
113
106
  *
114
- * Two emitters running one program produce identical particles from identical seeds, so leaving
115
- * this at 0 is almost never what an author wants — {@link EmitterRegistry#add} reads 0 as
116
- * "unset" and derives one from the generation instead.
107
+ * Two emitters running one program produce identical particles from identical seeds. `0` reads
108
+ * as "unset", and the row written for such an emitter takes its registration's generation
109
+ * instead, which no other emitter of that registry shares.
117
110
  *
118
111
  * @type {number}
119
112
  */
@@ -155,13 +148,8 @@ export class ParticleEmitter extends Node3D {
155
148
  bounds_radius = 1;
156
149
 
157
150
  /**
158
- * Atlas sub-rect: uv offset `.xy`, uv scale `.zw`. Mirrors meep's `AtlasPatch`.
159
- * @type {Float32Array}
160
- */
161
- atlas_region = new Float32Array([0, 0, 1, 1]);
162
-
163
- /**
164
- * Flipbook grid: columns, rows. `[1, 1]` is a single frame.
151
+ * Flipbook grid: columns, rows, over whatever region {@link texture} was packed into. `[1, 1]`
152
+ * is a single frame.
165
153
  * @type {Float32Array}
166
154
  */
167
155
  flipbook = new Float32Array([1, 1]);
@@ -179,14 +167,6 @@ export class ParticleEmitter extends Node3D {
179
167
  /** @type {number} record word offset of velocity, read by the STRETCHED projection */
180
168
  render_velocity = EMITTER_ATTRIBUTE_ABSENT;
181
169
 
182
- /**
183
- * Whether the table row is out of step with the fields above. Set it after changing anything;
184
- * {@link EmitterRegistry#flush} clears it once the row has been staged for upload.
185
- *
186
- * @type {boolean}
187
- */
188
- dirty = true;
189
-
190
170
  get type() {
191
171
  return "ParticleEmitter";
192
172
  }
@@ -206,9 +186,9 @@ export class ParticleEmitter extends Node3D {
206
186
  */
207
187
  bind_render(channels) {
208
188
  assert.isObject(channels, 'channels');
209
- assert.defined(this.effect, 'effect');
189
+ assert.defined(this.layout, 'layout');
210
190
 
211
- const layout = this.effect.layout;
191
+ const layout = this.layout;
212
192
 
213
193
  for (const channel of Object.keys(channels)) {
214
194
  const offset = layout.offsetOf(channels[channel]);
@@ -227,100 +207,181 @@ export class ParticleEmitter extends Node3D {
227
207
  }
228
208
  }
229
209
 
230
- this.dirty = true;
210
+ this.needsUpdate = true;
211
+ }
212
+
213
+ /**
214
+ * Structural equality over everything an emitter *is*: where it sits, what it runs, what it
215
+ * draws with, and how it is bound to the renderer. Two emitters that compare equal describe one
216
+ * effect in one place, and one row would serve both.
217
+ *
218
+ * The node's identity is not part of it — `id`, parent and children say where an emitter is in
219
+ * a scene, not what it is — and neither is anything the GPU assigned it, which is not here to
220
+ * be compared. {@link transform_global} is left out too, being derived from
221
+ * {@link transform_local} and the parent chain.
222
+ *
223
+ * @param {ParticleEmitter} other
224
+ * @returns {boolean}
225
+ */
226
+ equals(other) {
227
+ if (this === other) {
228
+ return true;
229
+ }
230
+
231
+ return this.name === other.name
232
+ && this.texture === other.texture
233
+ && this.seed === other.seed
234
+ && this.spawn_rate === other.spawn_rate
235
+ && this.flags === other.flags
236
+ && this.bounds_radius === other.bounds_radius
237
+ && this.render_position === other.render_position
238
+ && this.render_size === other.render_size
239
+ && this.render_color === other.render_color
240
+ && this.render_rotation === other.render_rotation
241
+ && this.render_frame === other.render_frame
242
+ && this.render_velocity === other.render_velocity
243
+ && is_typed_array_equals(this.bounds_center, other.bounds_center)
244
+ && is_typed_array_equals(this.flipbook, other.flipbook)
245
+ && this.transform_local.equals(other.transform_local)
246
+ && this.layout.equals(other.layout)
247
+ && this.program.equals(other.program);
231
248
  }
232
249
 
233
250
  /**
234
- * Fill `record` with this emitter as the value the emitter table stores — every field of
235
- * {@link ../data/PARTICLE_EMITTER_STRUCT.js}, none omitted.
251
+ * Hash over everything {@link equals} compares, in the same terms — the compiled program hashes
252
+ * by its own bytecode rather than by object identity, so two emitters separately compiled from
253
+ * one graph hash equally, as they compare equally.
236
254
  *
237
- * Omitting one would not write zeros: the serializer skips absent fields, and table pages are
238
- * recycled buffers, so a skipped field keeps whatever the previous tenant of the slot left
239
- * there.
255
+ * @returns {number} int32
256
+ */
257
+ hash() {
258
+ const bindings = hash_mix3(
259
+ hash_mix3(this.render_position, this.render_size, this.render_color),
260
+ hash_mix3(this.render_rotation, this.render_frame, this.render_velocity),
261
+ this.flags
262
+ );
263
+
264
+ const geometry = hash_mix3(
265
+ float32_array_hash(this.bounds_center, 0, this.bounds_center.length),
266
+ computeHashFloat(this.bounds_radius),
267
+ float32_array_hash(this.flipbook, 0, this.flipbook.length)
268
+ );
269
+
270
+ const appearance = hash_mix3(
271
+ computeStringHash(this.name),
272
+ computeStringHash(this.texture),
273
+ hash_mix2(this.seed, computeHashFloat(this.spawn_rate))
274
+ );
275
+
276
+ return hash_mix3(
277
+ hash_mix2(bindings, geometry),
278
+ hash_mix2(appearance, this.transform_local.hash()),
279
+ hash_mix2(this.layout.hash(), this.program.hash())
280
+ );
281
+ }
282
+
283
+ /**
284
+ * Make this emitter a copy of `other`: same effect, same settings, same placement.
240
285
  *
241
- * Writes into a caller-supplied object rather than returning a fresh one so the registry can
242
- * stage every row of a frame through one module-static record — the table serializes it
243
- * synchronously, so nothing outlives the call.
286
+ * The layout and the compiled program are shared rather than duplicated — both are immutable
287
+ * once compiled, and sharing them is what puts two emitters of one effect on one program id in
288
+ * the program heap, hence in one simulation bucket.
244
289
  *
245
- * @param {object} record the staging object, see {@link create_emitter_record}
246
- * @returns {object} `record`
290
+ * What is not copied is the node's identity and its place in a scene ({@link Node3D#id},
291
+ * parent, children), and anything a registry gave the original: a copy is a second emitter, not
292
+ * a second reference to the first one's table row.
293
+ *
294
+ * @param {ParticleEmitter} other
247
295
  */
248
- write_record(record) {
249
- assert.defined(this.placement, 'placement');
250
-
251
- const placement = this.placement;
252
-
253
- record.init_offset = placement.init_offset;
254
- record.init_count = placement.init_count;
255
- record.update_offset = placement.update_offset;
256
- record.update_count = placement.update_count;
257
- record.constant_offset = placement.constant_offset;
258
- record.program_id = placement.program_id;
259
-
260
- record.seed = this.seed;
261
- record.flags = this.flags;
262
- record.spawn_rate = this.spawn_rate;
263
- record.node = this.transform_row;
264
- record.generation = this.generation;
265
-
266
- record.bounds_center.set(this.bounds_center);
267
- record.bounds_radius = this.bounds_radius;
268
-
269
- record.render_position = this.render_position;
270
- record.render_size = this.render_size;
271
- record.render_color = this.render_color;
272
- record.render_rotation = this.render_rotation;
273
- record.render_frame = this.render_frame;
274
- record.render_velocity = this.render_velocity;
275
-
276
- record.atlas_region.set(this.atlas_region);
277
- record.flipbook.set(this.flipbook);
278
-
279
- return record;
296
+ copy(other) {
297
+ super.copy(other);
298
+
299
+ this.name = other.name;
300
+
301
+ this.layout = other.layout;
302
+ this.program = other.program;
303
+ this.texture = other.texture;
304
+
305
+ this.seed = other.seed;
306
+ this.spawn_rate = other.spawn_rate;
307
+ this.flags = other.flags;
308
+
309
+ this.bounds_center.set(other.bounds_center);
310
+ this.bounds_radius = other.bounds_radius;
311
+ this.flipbook.set(other.flipbook);
312
+
313
+ this.render_position = other.render_position;
314
+ this.render_size = other.render_size;
315
+ this.render_color = other.render_color;
316
+ this.render_rotation = other.render_rotation;
317
+ this.render_frame = other.render_frame;
318
+ this.render_velocity = other.render_velocity;
280
319
  }
281
320
 
282
321
  /**
283
- * This emitter as a fresh record object. {@link write_record} into a shared one is what the
284
- * per-frame path uses; this is for tests and one-off inspection.
322
+ * A second emitter equal to this one, and registered with nothing. Its subtree is cloned the
323
+ * way {@link Node3D#clone} clones one — overridden only because the base builds a plain
324
+ * `Node3D`, which would keep the transform and drop the effect.
285
325
  *
286
- * @returns {object}
326
+ * @returns {ParticleEmitter}
287
327
  */
288
- to_record() {
289
- return this.write_record(create_emitter_record());
328
+ clone() {
329
+ const r = new ParticleEmitter();
330
+
331
+ r.copy(this);
332
+
333
+ for (const child of this.children) {
334
+ const clone = child.clone();
335
+
336
+ clone.parent = r;
337
+
338
+ r.children.push(clone);
339
+ }
340
+
341
+ return r;
290
342
  }
291
343
 
292
344
  /**
293
- * Build an emitter from a plain description. Every parameter is optional except the effect —
294
- * an emitter with no program has nothing to run.
345
+ * Build an emitter from a plain description. Every parameter is optional except the compiled
346
+ * effect — an emitter with no program has nothing to run.
347
+ *
348
+ * `layout` and `program` are the two halves of what {@link ./create_particle_effect.js} returns,
349
+ * so an effect goes in by spreading it: `ParticleEmitter.from({ ...effect, spawn_rate: 100 })`.
295
350
  *
296
351
  * @param {object} config
297
- * @param {{layout: object, program: object}} config.effect compiled effect, see
298
- * {@link ./create_particle_effect.js}
352
+ * @param {import("../layout/ParticleLayout.js").ParticleLayout} config.layout per-particle
353
+ * attribute schema
354
+ * @param {import("../isa/ParticleProgram.js").ParticleProgram} config.program compiled INIT /
355
+ * UPDATE bytecode
299
356
  * @param {ArrayLike<number>} [config.position] local translation, `[x, y, z]`
357
+ * @param {string|null} [config.texture] image URL to draw with
300
358
  * @param {number} [config.seed]
301
359
  * @param {number} [config.spawn_rate] particles/second
302
360
  * @param {object} [config.flags] passed to {@link make_emitter_flags}
303
361
  * @param {{center?: ArrayLike<number>, radius?: number}} [config.bounds]
304
362
  * @param {Object<string,string>} [config.render] render channel -> attribute name
305
- * @param {ArrayLike<number>} [config.atlas_region] [uvOffsetX, uvOffsetY, uvScaleX, uvScaleY]
306
363
  * @param {ArrayLike<number>} [config.flipbook] [cols, rows]
307
364
  * @param {string} [config.name]
308
365
  * @returns {ParticleEmitter}
309
366
  */
310
367
  static from(config) {
311
368
  assert.isObject(config, 'config');
312
- assert.defined(config.effect, 'config.effect');
313
- assert.defined(config.effect.program, 'config.effect.program');
314
- assert.defined(config.effect.layout, 'config.effect.layout');
369
+ assert.defined(config.layout, 'config.layout');
370
+ assert.defined(config.program, 'config.program');
315
371
 
316
372
  const emitter = new ParticleEmitter();
317
373
 
318
- emitter.effect = config.effect;
374
+ emitter.layout = config.layout;
375
+ emitter.program = config.program;
319
376
 
320
377
  if (config.name !== undefined) {
321
378
  emitter.name = config.name;
322
379
  }
323
380
 
381
+ if (config.texture !== undefined) {
382
+ emitter.texture = config.texture;
383
+ }
384
+
324
385
  if (config.position !== undefined) {
325
386
  emitter.transform_local.setTranslation(config.position[0], config.position[1], config.position[2]);
326
387
  emitter.updateMatrices();
@@ -345,10 +406,6 @@ export class ParticleEmitter extends Node3D {
345
406
  }
346
407
  }
347
408
 
348
- if (config.atlas_region !== undefined) {
349
- emitter.atlas_region.set(config.atlas_region);
350
- }
351
-
352
409
  if (config.flipbook !== undefined) {
353
410
  emitter.flipbook.set(config.flipbook);
354
411
  }
@@ -366,39 +423,3 @@ export class ParticleEmitter extends Node3D {
366
423
  * @type {boolean}
367
424
  */
368
425
  ParticleEmitter.prototype.isParticleEmitter = true;
369
-
370
- /**
371
- * An empty staging record with every field of {@link ../data/PARTICLE_EMITTER_STRUCT.js} present,
372
- * typed arrays for the vector fields so {@link ParticleEmitter#write_record} can copy into them.
373
- *
374
- * @returns {object}
375
- */
376
- export function create_emitter_record() {
377
- return {
378
- init_offset: 0,
379
- init_count: 0,
380
- update_offset: 0,
381
- update_count: 0,
382
- constant_offset: 0,
383
- program_id: 0,
384
-
385
- seed: 0,
386
- flags: 0,
387
- spawn_rate: 0,
388
- node: 0,
389
- generation: 0,
390
-
391
- bounds_center: new Float32Array(3),
392
- bounds_radius: 0,
393
-
394
- render_position: 0,
395
- render_size: 0,
396
- render_color: 0,
397
- render_rotation: 0,
398
- render_frame: 0,
399
- render_velocity: 0,
400
-
401
- atlas_region: new Float32Array(4),
402
- flipbook: new Float32Array(2),
403
- };
404
- }
@@ -34,6 +34,32 @@ export class ProgramArena {
34
34
  * @type {number}
35
35
  */
36
36
  constant_word_count: number;
37
+ /**
38
+ * Slots the hungriest program in the arena needs — the maximum of every added program's
39
+ * `register_count`.
40
+ *
41
+ * This is the number that picks an interpreter. It is a property of the SET, not of a program:
42
+ * one program past {@link ../ParticleConstants.js PARTICLE_VM_FAST_REGISTER_SLOTS} moves every
43
+ * pass in the system onto the wide register file, including the emitters whose programs would
44
+ * have fit. Per-program dispatch would be the other design, and a much larger one — two pipelines
45
+ * live at once, the coherence pass's buckets split along a second axis, and two indirect
46
+ * commands to size. This is a fallback for a case that should not arise, so it is the whole
47
+ * system or none of it.
48
+ *
49
+ * @type {number}
50
+ */
51
+ register_high_water: number;
52
+ /**
53
+ * Whether the arena holds a program the fast interpreter's register file cannot hold, and the
54
+ * system must therefore run on {@link ../vm/chunk_particle_vm_registers_wide.js}.
55
+ *
56
+ * Monotonic in practice: removing an emitter does not remove its program from the arena (ids are
57
+ * dense and buckets are keyed on them), so once the set has seen a wide program it stays wide
58
+ * until the arena itself is rebuilt.
59
+ *
60
+ * @returns {boolean}
61
+ */
62
+ get requires_wide_registers(): boolean;
37
63
  /**
38
64
  * Content key -> the placement the first identical program got.
39
65
  * @type {Map<string, {init_offset: number, init_count: number, update_offset: number, update_count: number, constant_offset: number, program_id: number}>}
@@ -1 +1 @@
1
- {"version":3,"file":"ProgramArena.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/ProgramArena.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;GAaG;AACH;IAEI;;;OAGG;IACH,mBAFU,MAAM,EAAE,CAEK;IAEvB;;;OAGG;IACH,gBAFU,MAAM,EAAE,CAEE;IAEpB;;;OAGG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;;OAIG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,UAFU,IAAI,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAC,CAAC,CAErI;IAErB;;;;OAIG;IACH,4BAEC;IAED;;;;;;;;;;;;;;;OAeG;IACH,aAHW,OAAO,2BAA2B,EAAE,eAAe;qBACnC,MAAM;oBAAc,MAAM;uBAAiB,MAAM;sBAAgB,MAAM;yBAAmB,MAAM;oBAAc,MAAM;MAgC9I;IAUD;;;;;;OAMG;IACH,wBAFa,WAAW,CAcvB;;CACJ"}
1
+ {"version":3,"file":"ProgramArena.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/ProgramArena.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;GAaG;AACH;IAEI;;;OAGG;IACH,mBAFU,MAAM,EAAE,CAEK;IAEvB;;;OAGG;IACH,gBAFU,MAAM,EAAE,CAEE;IAEpB;;;OAGG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;;OAIG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;;;;;;;;;;;OAaG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;;;;;;;OASG;IACH,uCAEC;IAED;;;OAGG;IACH,UAFU,IAAI,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAC,CAAC,CAErI;IAErB;;;;OAIG;IACH,4BAEC;IAED;;;;;;;;;;;;;;;OAeG;IACH,aAHW,OAAO,2BAA2B,EAAE,eAAe;qBACnC,MAAM;oBAAc,MAAM;uBAAiB,MAAM;sBAAgB,MAAM;yBAAmB,MAAM;oBAAc,MAAM;MAkC9I;IAUD;;;;;;OAMG;IACH,wBAFa,WAAW,CAcvB;;CACJ"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Holds every distinct compiled {@link ../isa/ParticleProgram.js ParticleProgram} the emitter set
3
+ * runs, packs them into one buffer — a header, every constant pool, then every instruction stream —
4
+ * and hands back the {@link ./ProgramPlacement.js placement} each emitter records.
5
+ *
6
+ * Data before code, behind a four-word header whose first word says where the code starts: the VM
7
+ * reads both sections through one binding (a storage buffer per stage is not free, and code and
8
+ * constants are read together), and an emitter's constant pool sits next to the pools of the
9
+ * programs it shares a wave with.
10
+ *
11
+ * **Programs are placed, not appended.** Each section is a range allocator
12
+ * ({@link ../../../../core/binary/allocator/OffsetAllocator.js}) over a flat word array, so a
13
+ * program that is no longer wanted gives its space back and the next one takes it. This is what the
14
+ * emitter table has always been able to do, and what the packed buffer could not: an authoring
15
+ * session that adds, edits and drops effects for an hour no longer grows the buffer for an hour.
16
+ *
17
+ * Because VM instructions carry no absolute code addresses (control flow is branchless) and constant
18
+ * references are program-local (the VM adds the emitter's `constant_offset`), a program is
19
+ * relocatable — it can be placed at any offset, and moved to another one by copying its words and
20
+ * rewriting the placement. INIT and UPDATE are one allocation, laid out back-to-back, because they
21
+ * are always wanted together.
22
+ *
23
+ * **Deduplication is by CONTENT, not object identity**, and it is the {@link HashMap} that does it:
24
+ * two emitters that authored the same graph separately compile to distinct `ParticleProgram` objects
25
+ * holding the same bytecode, and `ParticleProgram` already answers `equals`/`hash` over exactly
26
+ * that. They land on one placement, one bucket, and one copy of the code. Keying on the emitter
27
+ * instead would be simpler and strictly worse: N emitters running one shared effect would become N
28
+ * buckets, each padded out to a whole workgroup, which both wastes lanes and splits a run that was
29
+ * already program-coherent.
30
+ *
31
+ * **Sharing is what makes {@link ProgramHeap#release} a reference count** rather than a delete: the
32
+ * last emitter of an effect frees it, and the ones before it do not.
33
+ */
34
+ export class ProgramHeap {
35
+ /**
36
+ * Bumped whenever the packed buffer would come out different from the last one
37
+ * {@link ProgramHeap#build_buffer} produced — a program was placed, or the sections were
38
+ * repacked. A holder that uploads the buffer re-uploads when this moves.
39
+ *
40
+ * Releasing a program does NOT move it. The words it occupied are dead rather than changed, and
41
+ * re-uploading the buffer to remove bytes nothing addresses would be a rebuild for nothing; the
42
+ * next program placed there is what makes the buffer differ, and that bumps this.
43
+ *
44
+ * @type {number}
45
+ */
46
+ version: number;
47
+ /**
48
+ * Bumped when a repack moved programs that were already placed — every existing placement now
49
+ * holds different offsets, so every emitter record built from one is out of date.
50
+ *
51
+ * Separate from {@link ProgramHeap#version} because the two ask for different work: that one
52
+ * says "upload the buffer again", this one says "restage every row". A repack moves both; an
53
+ * ordinary placement moves only the first.
54
+ *
55
+ * @type {number}
56
+ */
57
+ placement_version: number;
58
+ /**
59
+ * Distinct programs currently held — and therefore effects, not emitters.
60
+ * @returns {number}
61
+ */
62
+ get program_count(): number;
63
+ /**
64
+ * How many program ids the heap has had in play at once, which is the number of bins the
65
+ * simulation-order pass has to histogram into: live ids are all below it.
66
+ *
67
+ * It rises to the set's peak and stays there, because released ids are reused rather than
68
+ * renumbered. That costs an empty bin per id the set is currently below its peak by, and an
69
+ * empty bin is free — it rounds up to zero workgroups and shifts nothing after it — whereas
70
+ * renumbering would mean rewriting every emitter record that carries an id, and resizing the
71
+ * coherence buffers every time an effect came or went.
72
+ *
73
+ * @returns {number}
74
+ */
75
+ get program_id_capacity(): number;
76
+ /**
77
+ * Register slots the hungriest program currently held needs — the maximum of every live
78
+ * program's `register_count`, and `0` for an empty heap.
79
+ *
80
+ * The heap has no opinion about what that number means; it is the caller that compares it
81
+ * against {@link ../ParticleConstants.js PARTICLE_VM_FAST_REGISTER_SLOTS} and picks an
82
+ * interpreter, because which register backing a pass is compiled against is the VM's business
83
+ * and not the store's. What matters here is that the number is a property of the SET: there is
84
+ * one pipeline per pass and it is chosen once, so one hungry effect decides for every emitter in
85
+ * the system, including the ones whose programs would have fit.
86
+ *
87
+ * It falls again when that effect is released. The heap knows exactly what it holds, so there is
88
+ * no reason for the answer to be a high-water mark that only a full rebuild could bring down.
89
+ *
90
+ * @returns {number}
91
+ */
92
+ get max_register_count(): number;
93
+ /**
94
+ * Take a reference on `program`, placing it if the heap does not already hold an identical one.
95
+ *
96
+ * The placement it returns is what the emitter record carries and what the coherence pass
97
+ * buckets on. It is SHARED with every other holder of the same bytecode, and the heap mutates it
98
+ * in place when it repacks, so a caller keeps the object rather than copying its fields —
99
+ * copies go stale, the object does not.
100
+ *
101
+ * @param {import("../isa/ParticleProgram.js").ParticleProgram} program
102
+ * @returns {ProgramPlacement}
103
+ */
104
+ acquire(program: import("../isa/ParticleProgram.js").ParticleProgram): ProgramPlacement;
105
+ /**
106
+ * Give back a reference taken by {@link ProgramHeap#acquire}. The program's ranges and its id are
107
+ * released when the last one goes.
108
+ *
109
+ * @param {ProgramPlacement} placement
110
+ * @returns {boolean} whether that was the last reference, and the program is now gone
111
+ */
112
+ release(placement: ProgramPlacement): boolean;
113
+ /**
114
+ * The packed buffer: `[header][constants][code]`. Word
115
+ * {@link ../ParticleConstants.js PARTICLE_PROGRAM_CODE_BASE_WORD} of the header is the word index
116
+ * the code starts at — the only absolute address in the buffer, and the reason a placement can
117
+ * hold section-relative offsets and survive the sections being resized.
118
+ *
119
+ * Both sections come out at their full capacity rather than trimmed to what is live: the offsets
120
+ * a placement holds are offsets into the capacity, and trimming would mean moving programs to
121
+ * close the holes, which is what a repack is for and what a buffer rebuild should not silently
122
+ * become.
123
+ *
124
+ * @returns {Uint32Array}
125
+ */
126
+ build_buffer(): Uint32Array;
127
+ #private;
128
+ }
129
+ import { ProgramPlacement } from "./ProgramPlacement.js";
130
+ //# sourceMappingURL=ProgramHeap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgramHeap.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/ProgramHeap.js"],"names":[],"mappings":"AAmJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;IAEI;;;;;;;;;;OAUG;IACH,SAFU,MAAM,CAEJ;IAEZ;;;;;;;;;OASG;IACH,mBAFU,MAAM,CAEM;IAgDtB;;;OAGG;IACH,4BAEC;IAED;;;;;;;;;;;OAWG;IACH,kCAEC;IAED;;;;;;;;;;;;;;;OAeG;IACH,iCAEC;IAED;;;;;;;;;;OAUG;IACH,iBAHW,OAAO,2BAA2B,EAAE,eAAe,GACjD,gBAAgB,CAuC5B;IAED;;;;;;OAMG;IACH,mBAHW,gBAAgB,GACd,OAAO,CAiCnB;IAED;;;;;;;;;;;;OAYG;IACH,gBAFa,WAAW,CAcvB;;CAwJJ;iCA5iBgC,uBAAuB"}