@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
@@ -28,8 +28,14 @@ export type PARTICLE_EFFECT_SOURCE = string;
28
28
  * ## Optimizing
29
29
  *
30
30
  * {@link optimize} runs the compiled program through
31
- * {@link ../../../src/shade/renderer/particles/optimizer/optimize_particle_program.js the optimizer}
32
- * before anybody gets it. It is a property of the effect rather than of a view because it changes
31
+ * {@link ../../../src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js the graph optimizer}
32
+ * before anybody gets it.
33
+ *
34
+ * There are two optimizers and they take the same arguments, so which one an editor runs is a choice
35
+ * rather than a rewrite. It is this one because it is both better and very much faster: on `curl4`
36
+ * the pass pipeline needs 3,690 ms against this one's 276, and comes out with 2,828 instructions
37
+ * against 2,826. A second-and-a-half of that difference is the pipeline running itself twice to
38
+ * decide about lane peeling. At 3.7 seconds an edit the setting could not be on at all. It is a property of the effect rather than of a view because it changes
33
39
  * what runs — the preview, the reference simulation and anything else downstream of {@link compile}
34
40
  * all get the optimized program — and a switch that changed what runs while living in one panel
35
41
  * would be invisible from the other three.
@@ -130,8 +136,17 @@ export class ParticleEffectDocument {
130
136
  /**
131
137
  * Whether {@link compile} hands back the optimized program.
132
138
  *
133
- * Off by default, and off for every effect saved before it existed, because it is a thing an
134
- * author turns on to see what it does rather than something done to their effect behind them.
139
+ * ON by default. It was off while it was new — a thing an author turned on to see what it did —
140
+ * and what changes that is not confidence but the promise being checkable: a program's meaning
141
+ * is its final record, its kill flag and its RNG state, and the optimizer is held to leaving all
142
+ * three identical to the bit over every environment the differential harness runs. An author who
143
+ * cannot observe the difference should not have to ask for it.
144
+ *
145
+ * The one rewrite that is not bit-exact — folding `x * 0`, which gives up the sign of that zero
146
+ * — is argued where it lives and is on there, not here. A tick-box in the editor is not the
147
+ * place to quietly widen what the optimizer may do; see {@link #optimized}.
148
+ *
149
+ * Turning it OFF still works and is what an author debugging a lowering wants, so the box stays.
135
150
  *
136
151
  * @type {boolean}
137
152
  */
@@ -331,11 +346,11 @@ export class ParticleEffectDocument {
331
346
  * on, because `bind_render` throws on one — and an effect that fails to build over a stale
332
347
  * binding is a worse thing to hand an author than one that draws without a colour.
333
348
  *
334
- * @param {{layout: ParticleLayout, program: object}} effect what {@link compile} produced,
349
+ * @param {{layout: ParticleLayout, program: object}} compiled what {@link compile} produced,
335
350
  * packaged the way `create_particle_effect` does
336
351
  * @returns {object}
337
352
  */
338
- emitterConfig(effect: {
353
+ emitterConfig({ layout, program }: {
339
354
  layout: ParticleLayout;
340
355
  program: object;
341
356
  }): object;
@@ -1 +1 @@
1
- {"version":3,"file":"ParticleEffectDocument.d.ts","sourceRoot":"","sources":["../../../../editor/particles/effect/ParticleEffectDocument.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ParticleEffectDocument.d.ts","sourceRoot":"","sources":["../../../../editor/particles/effect/ParticleEffectDocument.js"],"names":[],"mappings":"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"}
@@ -29,7 +29,7 @@ import {
29
29
  } from "../../../src/shade/renderer/particles/isa/particle_assembly.js";
30
30
  import { PARTICLE_TYPE_COLOR } from "../../../src/shade/renderer/particles/graph/ParticleValueType.js";
31
31
  import { ParticleLayout } from "../../../src/shade/renderer/particles/layout/ParticleLayout.js";
32
- import { optimize_compiled_particle_program } from "../../../src/shade/renderer/particles/optimizer/optimize_particle_program.js";
32
+ import { optimize_particle_program_vector } from "../../../src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js";
33
33
  import { EMITTER_RENDER_CHANNELS } from "../../../src/shade/renderer/particles/runtime/ParticleEmitter.js";
34
34
 
35
35
  /**
@@ -58,8 +58,14 @@ import { EMITTER_RENDER_CHANNELS } from "../../../src/shade/renderer/particles/r
58
58
  * ## Optimizing
59
59
  *
60
60
  * {@link optimize} runs the compiled program through
61
- * {@link ../../../src/shade/renderer/particles/optimizer/optimize_particle_program.js the optimizer}
62
- * before anybody gets it. It is a property of the effect rather than of a view because it changes
61
+ * {@link ../../../src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js the graph optimizer}
62
+ * before anybody gets it.
63
+ *
64
+ * There are two optimizers and they take the same arguments, so which one an editor runs is a choice
65
+ * rather than a rewrite. It is this one because it is both better and very much faster: on `curl4`
66
+ * the pass pipeline needs 3,690 ms against this one's 276, and comes out with 2,828 instructions
67
+ * against 2,826. A second-and-a-half of that difference is the pipeline running itself twice to
68
+ * decide about lane peeling. At 3.7 seconds an edit the setting could not be on at all. It is a property of the effect rather than of a view because it changes
63
69
  * what runs — the preview, the reference simulation and anything else downstream of {@link compile}
64
70
  * all get the optimized program — and a switch that changed what runs while living in one panel
65
71
  * would be invisible from the other three.
@@ -169,7 +175,8 @@ export class ParticleEffectDocument {
169
175
  cull: false,
170
176
  bounds_center: [0, 1, 0],
171
177
  bounds_radius: 3,
172
- atlas_region: [0, 0, 1, 1],
178
+ /** image to draw with, by URL; null draws against the default atlas, a white texel */
179
+ texture: null,
173
180
  flipbook: [1, 1],
174
181
  /** render channel -> attribute name; a channel absent here is not bound */
175
182
  render: {
@@ -195,12 +202,21 @@ export class ParticleEffectDocument {
195
202
  /**
196
203
  * Whether {@link compile} hands back the optimized program.
197
204
  *
198
- * Off by default, and off for every effect saved before it existed, because it is a thing an
199
- * author turns on to see what it does rather than something done to their effect behind them.
205
+ * ON by default. It was off while it was new — a thing an author turned on to see what it did —
206
+ * and what changes that is not confidence but the promise being checkable: a program's meaning
207
+ * is its final record, its kill flag and its RNG state, and the optimizer is held to leaving all
208
+ * three identical to the bit over every environment the differential harness runs. An author who
209
+ * cannot observe the difference should not have to ask for it.
210
+ *
211
+ * The one rewrite that is not bit-exact — folding `x * 0`, which gives up the sign of that zero
212
+ * — is argued where it lives and is on there, not here. A tick-box in the editor is not the
213
+ * place to quietly widen what the optimizer may do; see {@link #optimized}.
214
+ *
215
+ * Turning it OFF still works and is what an author debugging a lowering wants, so the box stays.
200
216
  *
201
217
  * @type {boolean}
202
218
  */
203
- optimize = false;
219
+ optimize = true;
204
220
 
205
221
  /**
206
222
  * Bumped on every {@link touch}. A view that caches something derived from the document can
@@ -250,7 +266,7 @@ export class ParticleEffectDocument {
250
266
  * A change to a document is seen by three panels and each of them asks what it compiles to, so
251
267
  * without this one edit is three compiles. That was affordable when an effect was forty
252
268
  * instructions; a graph with a `curl3` group in it lowers to about four thousand, which is 78ms
253
- * to compile and another 570ms to optimize on this machine — three times over, on every
269
+ * to compile and another 214ms to optimize on this machine — three times over, on every
254
270
  * keystroke.
255
271
  *
256
272
  * The key is the {@link version} and the two settings that decide what a compile does, rather
@@ -554,7 +570,7 @@ export class ParticleEffectDocument {
554
570
  }
555
571
 
556
572
  try {
557
- return { program: optimize_compiled_particle_program(program), unoptimized: program };
573
+ return { program: optimize_particle_program_vector(program), unoptimized: program };
558
574
  } catch (e) {
559
575
  diagnostics.push({
560
576
  scope: "effect",
@@ -849,23 +865,24 @@ export class ParticleEffectDocument {
849
865
  * on, because `bind_render` throws on one — and an effect that fails to build over a stale
850
866
  * binding is a worse thing to hand an author than one that draws without a colour.
851
867
  *
852
- * @param {{layout: ParticleLayout, program: object}} effect what {@link compile} produced,
868
+ * @param {{layout: ParticleLayout, program: object}} compiled what {@link compile} produced,
853
869
  * packaged the way `create_particle_effect` does
854
870
  * @returns {object}
855
871
  */
856
- emitterConfig(effect) {
872
+ emitterConfig({ layout, program }) {
857
873
  const render = {};
858
874
 
859
875
  for (const channel of EMITTER_RENDER_CHANNELS) {
860
876
  const attribute = this.emitter.render[channel];
861
877
 
862
- if (attribute !== undefined && effect.layout.has(attribute)) {
878
+ if (attribute !== undefined && layout.has(attribute)) {
863
879
  render[channel] = attribute;
864
880
  }
865
881
  }
866
882
 
867
883
  return {
868
- effect,
884
+ layout,
885
+ program,
869
886
  name: this.name,
870
887
  spawn_rate: this.emitter.spawn_rate,
871
888
  flags: {
@@ -880,7 +897,7 @@ export class ParticleEffectDocument {
880
897
  center: this.emitter.bounds_center,
881
898
  radius: this.emitter.bounds_radius,
882
899
  },
883
- atlas_region: this.emitter.atlas_region,
900
+ texture: this.emitter.texture,
884
901
  flipbook: this.emitter.flipbook,
885
902
  render,
886
903
  };
@@ -978,9 +995,13 @@ export class ParticleEffectDocument {
978
995
  : PARTICLE_EFFECT_SOURCE.GRAPH;
979
996
  this.assembly = json.assembly ?? "";
980
997
 
981
- // absent reads as off, so an effect saved before the optimizer existed opens as the program
982
- // its author last saw
983
- this.optimize = json.optimize === true;
998
+ // Absent reads as ON, which is the default this document is constructed with. An effect
999
+ // saved before the setting existed therefore opens optimized — which is a change to what
1000
+ // runs for that author, and the reason it is safe is the reason the default moved: the
1001
+ // optimizer leaves the record, the kill flag and the RNG state identical to the bit. What is
1002
+ // stored is a departure from the default in either direction, so an author who turned it off
1003
+ // still gets it off.
1004
+ this.optimize = json.optimize !== false;
984
1005
 
985
1006
  this.touch();
986
1007
 
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Take a copy of some of a graph.
3
+ *
4
+ * The wires that come along are the ones the fragment holds whole — both ends among the copied
5
+ * nodes. A wire with one end outside cannot be brought back: the node it reached is not part of
6
+ * what was copied, and a paste elsewhere in the graph, or in another graph entirely, has nothing to
7
+ * attach it to.
8
+ *
9
+ * @param {object} params
10
+ * @param {NodeGraph} params.graph
11
+ * @param {NodeGraphVisualData} [params.visual] where the nodes are; without it, everything is at the
12
+ * origin and a paste arranges nothing
13
+ * @param {Iterable<number>} params.nodes ids to copy; ones that are not in the graph are skipped
14
+ * @param {function(NodeInstance):boolean} [params.copyable] whether a node may be had a second of.
15
+ * Everything, by default. A host with node types that exist once per graph — a group body's
16
+ * two boundary blocks — says so here, and they are left out rather than the whole copy being
17
+ * refused.
18
+ * @returns {NodeGraphFragment|null} `null` when nothing was copied, so that a copy of nothing can be
19
+ * told from a copy of something and left to leave the clipboard alone
20
+ */
21
+ export function node_graph_fragment_from_nodes({ graph, visual, nodes, copyable }: {
22
+ graph: NodeGraph;
23
+ visual?: NodeGraphVisualData;
24
+ nodes: Iterable<number>;
25
+ copyable?: (arg0: NodeInstance) => boolean;
26
+ }): NodeGraphFragment | null;
27
+ /**
28
+ * The middle of a fragment, in the graph space it was copied from.
29
+ *
30
+ * What a paste puts where the author is looking, so that what lands is centred on the view rather
31
+ * than hanging off one corner of it.
32
+ *
33
+ * @param {NodeGraphFragment} fragment
34
+ * @returns {{x: number, y: number}}
35
+ */
36
+ export function node_graph_fragment_centre(fragment: NodeGraphFragment): {
37
+ x: number;
38
+ y: number;
39
+ };
40
+ /**
41
+ * Nodes lifted out of a graph, waiting to be put back into one.
42
+ *
43
+ * ## Why a fragment rather than a graph
44
+ *
45
+ * What is copied cannot be node ids: ids are pooled, so the ones a fragment was cut from are handed
46
+ * to unrelated nodes the moment the originals are deleted, and a paste that named them would wire
47
+ * itself to whatever happened to be holding them. A fragment therefore refers to its own nodes by
48
+ * **index**, and is a thing in its own right rather than a view onto the graph it came from.
49
+ *
50
+ * Nor can it be a live {@link NodeInstance}: the instance would keep pointing at the graph it is in,
51
+ * and its parameters would be shared with it — an author editing the original after copying it would
52
+ * be editing what they had copied. Parameters are cloned on the way in for the same reason a group
53
+ * clones its body on the way out.
54
+ *
55
+ * A {@link NodeDescription}, on the other hand, *is* carried by reference. A description is a type,
56
+ * shared by every instance of it, and there is nothing to copy; it is also the one part of a node
57
+ * that cannot be written down — a particle node's description carries the closure that is the whole
58
+ * of what the node does. Which is why this clipboard is an object in the page rather than text on
59
+ * the system one: what it holds is only meaningful to a canvas that shares its node library.
60
+ *
61
+ * ## Who holds one
62
+ *
63
+ * A host with several canvases over one document — the particle editor's two phases, and the body of
64
+ * every group opened inside them — builds one of these and gives it to all of them, so a copy in one
65
+ * pastes in the next. A canvas built without one gets its own, and copies to itself.
66
+ */
67
+ /**
68
+ * One node in a fragment.
69
+ *
70
+ * @typedef {object} NodeGraphFragmentNode
71
+ * @property {NodeDescription} description the type, by reference
72
+ * @property {object} parameters a deep copy, shared with nothing
73
+ * @property {number} x graph-space position it was copied from
74
+ * @property {number} y graph-space position it was copied from
75
+ */
76
+ /**
77
+ * One wire in a fragment, between two of its own nodes.
78
+ *
79
+ * @typedef {object} NodeGraphFragmentConnection
80
+ * @property {number} from index into the fragment's nodes
81
+ * @property {number} fromPort port id on that node's description
82
+ * @property {number} to index into the fragment's nodes
83
+ * @property {number} toPort port id on that node's description
84
+ */
85
+ /**
86
+ * @typedef {object} NodeGraphFragment
87
+ * @property {NodeGraphFragmentNode[]} nodes never empty — a fragment with no nodes is `null`
88
+ * @property {NodeGraphFragmentConnection[]} connections
89
+ */
90
+ /**
91
+ * How far each repeat paste of the same content steps, in graph-space units.
92
+ *
93
+ * Enough to see the copy is a second thing rather than a redraw of the first, and small enough that
94
+ * it lands next to what it came from rather than somewhere else entirely.
95
+ *
96
+ * @type {number}
97
+ */
98
+ export const NODE_GRAPH_PASTE_STEP: number;
99
+ /**
100
+ * What was copied, and how many times it has been put down since.
101
+ */
102
+ export class NodeGraphClipboard {
103
+ /**
104
+ * How many times what is held has been pasted already.
105
+ *
106
+ * A paste lands in the middle of what the author is looking at, so a second one would land
107
+ * exactly on top of the first and read as nothing having happened. The count is what steps it
108
+ * aside; see {@link NODE_GRAPH_PASTE_STEP}.
109
+ *
110
+ * @returns {number}
111
+ */
112
+ get pastes(): number;
113
+ /**
114
+ * @returns {boolean}
115
+ */
116
+ isEmpty(): boolean;
117
+ /**
118
+ * @returns {NodeGraphFragment|null}
119
+ */
120
+ read(): NodeGraphFragment | null;
121
+ /**
122
+ * Replace what is held. New content starts its paste count over, because the first paste of
123
+ * something new belongs where the author is looking rather than however far the last thing had
124
+ * walked.
125
+ *
126
+ * @param {NodeGraphFragment} fragment
127
+ */
128
+ write(fragment: NodeGraphFragment): void;
129
+ /**
130
+ * Record that what is held has been put down. Called by whoever is pasting it, once the paste is
131
+ * going ahead — a paste a canvas refused must not move the next one aside.
132
+ */
133
+ notePaste(): void;
134
+ clear(): void;
135
+ #private;
136
+ }
137
+ /**
138
+ * One node in a fragment.
139
+ */
140
+ export type NodeGraphFragmentNode = {
141
+ /**
142
+ * the type, by reference
143
+ */
144
+ description: NodeDescription;
145
+ /**
146
+ * a deep copy, shared with nothing
147
+ */
148
+ parameters: object;
149
+ /**
150
+ * graph-space position it was copied from
151
+ */
152
+ x: number;
153
+ /**
154
+ * graph-space position it was copied from
155
+ */
156
+ y: number;
157
+ };
158
+ /**
159
+ * One wire in a fragment, between two of its own nodes.
160
+ */
161
+ export type NodeGraphFragmentConnection = {
162
+ /**
163
+ * index into the fragment's nodes
164
+ */
165
+ from: number;
166
+ /**
167
+ * port id on that node's description
168
+ */
169
+ fromPort: number;
170
+ /**
171
+ * index into the fragment's nodes
172
+ */
173
+ to: number;
174
+ /**
175
+ * port id on that node's description
176
+ */
177
+ toPort: number;
178
+ };
179
+ export type NodeGraphFragment = {
180
+ /**
181
+ * never empty — a fragment with no nodes is `null`
182
+ */
183
+ nodes: NodeGraphFragmentNode[];
184
+ connections: NodeGraphFragmentConnection[];
185
+ };
186
+ //# sourceMappingURL=NodeGraphClipboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeGraphClipboard.d.ts","sourceRoot":"","sources":["../../../../editor/view/node-graph/NodeGraphClipboard.js"],"names":[],"mappings":"AAmIA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAX6B,KAAK;IACM,MAAM;IAEV,KAAK,EAA9B,SAAS,MAAM,CAAC;IACwB,QAAQ,2BAAzB,OAAO;IAI5B,iBAAiB,GAAC,IAAI,CA2DlC;AAED;;;;;;;;GAQG;AACH,qDAHW,iBAAiB;OACX,MAAM;OAAK,MAAM;EAcjC;AAtOD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;;;;GAQG;AAEH;;;;;;;;GAQG;AAEH;;;;GAIG;AAEH;;;;;;;GAOG;AACH,oCAFU,MAAM,CAEwB;AAExC;;GAEG;AACH;IAWI;;;;;;;;OAQG;IACH,qBAEC;IAED;;OAEG;IACH,WAFa,OAAO,CAInB;IAED;;OAEG;IACH,QAFa,iBAAiB,GAAC,IAAI,CAIlC;IAED;;;;;;OAMG;IACH,gBAFW,iBAAiB,QAK3B;IAED;;;OAGG;IACH,kBAEC;IAED,cAGC;;CACJ;;;;;;;;;;;;gBAhGa,MAAM;;;;OACN,MAAM;;;;OACN,MAAM;;;;;;;;;UAON,MAAM;;;;cACN,MAAM;;;;QACN,MAAM;;;;YACN,MAAM;;;;;;WAKN,qBAAqB,EAAE;iBACvB,2BAA2B,EAAE"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Nodes lifted out of a graph, waiting to be put back into one.
3
+ *
4
+ * ## Why a fragment rather than a graph
5
+ *
6
+ * What is copied cannot be node ids: ids are pooled, so the ones a fragment was cut from are handed
7
+ * to unrelated nodes the moment the originals are deleted, and a paste that named them would wire
8
+ * itself to whatever happened to be holding them. A fragment therefore refers to its own nodes by
9
+ * **index**, and is a thing in its own right rather than a view onto the graph it came from.
10
+ *
11
+ * Nor can it be a live {@link NodeInstance}: the instance would keep pointing at the graph it is in,
12
+ * and its parameters would be shared with it — an author editing the original after copying it would
13
+ * be editing what they had copied. Parameters are cloned on the way in for the same reason a group
14
+ * clones its body on the way out.
15
+ *
16
+ * A {@link NodeDescription}, on the other hand, *is* carried by reference. A description is a type,
17
+ * shared by every instance of it, and there is nothing to copy; it is also the one part of a node
18
+ * that cannot be written down — a particle node's description carries the closure that is the whole
19
+ * of what the node does. Which is why this clipboard is an object in the page rather than text on
20
+ * the system one: what it holds is only meaningful to a canvas that shares its node library.
21
+ *
22
+ * ## Who holds one
23
+ *
24
+ * A host with several canvases over one document — the particle editor's two phases, and the body of
25
+ * every group opened inside them — builds one of these and gives it to all of them, so a copy in one
26
+ * pastes in the next. A canvas built without one gets its own, and copies to itself.
27
+ */
28
+
29
+ /**
30
+ * One node in a fragment.
31
+ *
32
+ * @typedef {object} NodeGraphFragmentNode
33
+ * @property {NodeDescription} description the type, by reference
34
+ * @property {object} parameters a deep copy, shared with nothing
35
+ * @property {number} x graph-space position it was copied from
36
+ * @property {number} y graph-space position it was copied from
37
+ */
38
+
39
+ /**
40
+ * One wire in a fragment, between two of its own nodes.
41
+ *
42
+ * @typedef {object} NodeGraphFragmentConnection
43
+ * @property {number} from index into the fragment's nodes
44
+ * @property {number} fromPort port id on that node's description
45
+ * @property {number} to index into the fragment's nodes
46
+ * @property {number} toPort port id on that node's description
47
+ */
48
+
49
+ /**
50
+ * @typedef {object} NodeGraphFragment
51
+ * @property {NodeGraphFragmentNode[]} nodes never empty — a fragment with no nodes is `null`
52
+ * @property {NodeGraphFragmentConnection[]} connections
53
+ */
54
+
55
+ /**
56
+ * How far each repeat paste of the same content steps, in graph-space units.
57
+ *
58
+ * Enough to see the copy is a second thing rather than a redraw of the first, and small enough that
59
+ * it lands next to what it came from rather than somewhere else entirely.
60
+ *
61
+ * @type {number}
62
+ */
63
+ export const NODE_GRAPH_PASTE_STEP = 32;
64
+
65
+ /**
66
+ * What was copied, and how many times it has been put down since.
67
+ */
68
+ export class NodeGraphClipboard {
69
+ /**
70
+ * @type {NodeGraphFragment|null}
71
+ */
72
+ #fragment = null;
73
+
74
+ /**
75
+ * @type {number}
76
+ */
77
+ #pastes = 0;
78
+
79
+ /**
80
+ * How many times what is held has been pasted already.
81
+ *
82
+ * A paste lands in the middle of what the author is looking at, so a second one would land
83
+ * exactly on top of the first and read as nothing having happened. The count is what steps it
84
+ * aside; see {@link NODE_GRAPH_PASTE_STEP}.
85
+ *
86
+ * @returns {number}
87
+ */
88
+ get pastes() {
89
+ return this.#pastes;
90
+ }
91
+
92
+ /**
93
+ * @returns {boolean}
94
+ */
95
+ isEmpty() {
96
+ return this.#fragment === null;
97
+ }
98
+
99
+ /**
100
+ * @returns {NodeGraphFragment|null}
101
+ */
102
+ read() {
103
+ return this.#fragment;
104
+ }
105
+
106
+ /**
107
+ * Replace what is held. New content starts its paste count over, because the first paste of
108
+ * something new belongs where the author is looking rather than however far the last thing had
109
+ * walked.
110
+ *
111
+ * @param {NodeGraphFragment} fragment
112
+ */
113
+ write(fragment) {
114
+ this.#fragment = fragment;
115
+ this.#pastes = 0;
116
+ }
117
+
118
+ /**
119
+ * Record that what is held has been put down. Called by whoever is pasting it, once the paste is
120
+ * going ahead — a paste a canvas refused must not move the next one aside.
121
+ */
122
+ notePaste() {
123
+ this.#pastes++;
124
+ }
125
+
126
+ clear() {
127
+ this.#fragment = null;
128
+ this.#pastes = 0;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Take a copy of some of a graph.
134
+ *
135
+ * The wires that come along are the ones the fragment holds whole — both ends among the copied
136
+ * nodes. A wire with one end outside cannot be brought back: the node it reached is not part of
137
+ * what was copied, and a paste elsewhere in the graph, or in another graph entirely, has nothing to
138
+ * attach it to.
139
+ *
140
+ * @param {object} params
141
+ * @param {NodeGraph} params.graph
142
+ * @param {NodeGraphVisualData} [params.visual] where the nodes are; without it, everything is at the
143
+ * origin and a paste arranges nothing
144
+ * @param {Iterable<number>} params.nodes ids to copy; ones that are not in the graph are skipped
145
+ * @param {function(NodeInstance):boolean} [params.copyable] whether a node may be had a second of.
146
+ * Everything, by default. A host with node types that exist once per graph — a group body's
147
+ * two boundary blocks — says so here, and they are left out rather than the whole copy being
148
+ * refused.
149
+ * @returns {NodeGraphFragment|null} `null` when nothing was copied, so that a copy of nothing can be
150
+ * told from a copy of something and left to leave the clipboard alone
151
+ */
152
+ export function node_graph_fragment_from_nodes({ graph, visual, nodes, copyable = () => true }) {
153
+ /** @type {Map<number, number>} node id -> its index in the fragment */
154
+ const index = new Map();
155
+
156
+ /** @type {NodeGraphFragmentNode[]} */
157
+ const records = [];
158
+
159
+ for (const id of nodes) {
160
+ if (index.has(id)) {
161
+ // a selection should not hold one node twice, and a fragment must not whatever it does
162
+ continue;
163
+ }
164
+
165
+ const node = graph.getNode(id);
166
+
167
+ if (node === undefined || !copyable(node)) {
168
+ continue;
169
+ }
170
+
171
+ const placed = visual === undefined ? undefined : visual.getNode(id);
172
+
173
+ index.set(id, records.length);
174
+
175
+ records.push({
176
+ description: node.description,
177
+ // deeply: a copy must not share so much as a gradient stop with what it was copied from
178
+ parameters: structuredClone(node.parameters),
179
+ x: placed?.dimensions.position.x ?? 0,
180
+ y: placed?.dimensions.position.y ?? 0,
181
+ });
182
+ }
183
+
184
+ if (records.length === 0) {
185
+ return null;
186
+ }
187
+
188
+ /** @type {NodeGraphFragmentConnection[]} */
189
+ const connections = [];
190
+
191
+ graph.traverseConnections(connection => {
192
+ const from = index.get(connection.source.instance.id);
193
+ const to = index.get(connection.target.instance.id);
194
+
195
+ if (from === undefined || to === undefined) {
196
+ return;
197
+ }
198
+
199
+ connections.push({
200
+ from,
201
+ fromPort: connection.source.port.id,
202
+ to,
203
+ toPort: connection.target.port.id,
204
+ });
205
+ });
206
+
207
+ return { nodes: records, connections };
208
+ }
209
+
210
+ /**
211
+ * The middle of a fragment, in the graph space it was copied from.
212
+ *
213
+ * What a paste puts where the author is looking, so that what lands is centred on the view rather
214
+ * than hanging off one corner of it.
215
+ *
216
+ * @param {NodeGraphFragment} fragment
217
+ * @returns {{x: number, y: number}}
218
+ */
219
+ export function node_graph_fragment_centre(fragment) {
220
+ let x = 0;
221
+ let y = 0;
222
+
223
+ for (const node of fragment.nodes) {
224
+ x += node.x;
225
+ y += node.y;
226
+ }
227
+
228
+ const count = fragment.nodes.length;
229
+
230
+ return count === 0 ? { x: 0, y: 0 } : { x: x / count, y: y / count };
231
+ }