@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 class NodeGraphEditorView extends View {
28
28
  * type the menu places, so a node arrives ready to compile rather than to repair
29
29
  * @param {boolean} [readOnly] show the graph without offering to change it; see
30
30
  * {@link NodeGraphView}. Turns off the add-node menu and the editing shortcuts too.
31
+ * @param {NodeGraphClipboard} [clipboard] what `Ctrl+C` writes and `Ctrl+V` reads. A host with
32
+ * several canvases over one document passes one to all of them, so a copy taken in one
33
+ * pastes in the next; on its own, a canvas gets one of its own and copies to itself.
34
+ * @param {function(NodeInstance):boolean} [copyable] whether a node may be had a second of, for
35
+ * a host with types that exist once per graph. See
36
+ * {@link node_graph_fragment_from_nodes}.
31
37
  */
32
- constructor({ graph, nodeRegistry, visual, camera, actions, actionProcessor, parameterViewFactory, portDataType, minimap, library, readOnly }: NodeGraph);
38
+ constructor({ graph, nodeRegistry, visual, camera, actions, actionProcessor, parameterViewFactory, portDataType, minimap, library, readOnly, clipboard, copyable }: NodeGraph);
33
39
  /**
34
40
  * @readonly
35
41
  */
@@ -43,6 +49,17 @@ export class NodeGraphEditorView extends View {
43
49
  * @type {ActionProcessor}
44
50
  */
45
51
  actionProcessor: ActionProcessor<any, any>;
52
+ /**
53
+ * What a copy is written to and a paste read from. Shared with the host's other canvases
54
+ * when it supplied one.
55
+ *
56
+ * @type {NodeGraphClipboard}
57
+ */
58
+ clipboard: NodeGraphClipboard;
59
+ /**
60
+ * @type {function(NodeInstance):boolean}
61
+ */
62
+ copyable: (arg0: NodeInstance) => boolean;
46
63
  /**
47
64
  *
48
65
  * @type {NodeGraphSelection}
@@ -181,11 +198,52 @@ export class NodeGraphEditorView extends View {
181
198
  * queues, so nothing has been removed on return
182
199
  */
183
200
  deleteSelection(): Promise<any>;
201
+ /**
202
+ * Take a copy of the selected nodes, and of every wire they hold whole.
203
+ *
204
+ * Reading, not editing, so a read-only canvas offers it: opening one of a library's own groups
205
+ * to take a copy of what is inside it is the point of being able to open them.
206
+ *
207
+ * @returns {boolean} whether anything was copied. A selection with nothing copyable in it leaves
208
+ * the clipboard alone rather than emptying it, which is the one outcome an author
209
+ * asking for a copy certainly did not want.
210
+ */
211
+ copySelection(): boolean;
212
+ /**
213
+ * Put what was copied into this graph, in the middle of what the author is looking at.
214
+ *
215
+ * Where a paste lands is the one decision here. It goes to the middle of the view rather than
216
+ * back where it was copied from, for the same reason a node added from the menu with no position
217
+ * does: what arrives has to be somewhere the author can see it, and the place it was copied from
218
+ * may be a long way off screen — a copy taken in one phase and pasted in the other has no
219
+ * meaningful "back where it was" at all. The arrangement inside the fragment is kept exactly; it
220
+ * is the whole of it that moves. A repeat paste of the same content steps aside by
221
+ * {@link NODE_GRAPH_PASTE_STEP} so that copies do not hide each other.
222
+ *
223
+ * @returns {Promise<NodeInstance[]>} the nodes that landed, once the timeline has applied them;
224
+ * empty when there was nothing on the clipboard
225
+ * @throws if this canvas is read-only
226
+ */
227
+ paste(): Promise<NodeInstance[]>;
228
+ /**
229
+ * A second of everything selected, beside the originals.
230
+ *
231
+ * Beside rather than in the middle of the view, which is where {@link #paste} puts things: a
232
+ * duplicate is a second of something the author is already looking at, and centring it would
233
+ * take it away from the thing it is a second of. The clipboard is not touched — `Ctrl+D` is not
234
+ * a copy, and it must not cost the author whatever they had copied earlier.
235
+ *
236
+ * @returns {Promise<NodeInstance[]>} the new nodes; empty when nothing selected could be had a
237
+ * second of
238
+ * @throws if this canvas is read-only
239
+ */
240
+ duplicateSelection(): Promise<NodeInstance[]>;
184
241
  cameraContainAll(): void;
185
242
  #private;
186
243
  }
187
244
  import View from "../../../src/view/View.js";
188
245
  import { ActionProcessor } from "../../../src/core/process/undo/ActionProcessor.js";
246
+ import { NodeGraphClipboard } from "./NodeGraphClipboard.js";
189
247
  import { NodeGraphSelection } from "./NodeGraphSelection.js";
190
248
  import { NodeGraphCamera } from "./NodeGraphView.js";
191
249
  import { NodeDescriptionVisualRegistry } from "../../../src/core/model/node-graph/visual/NodeDescriptionVisualRegistry.js";
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphEditorView.d.ts","sourceRoot":"","sources":["../../../../editor/view/node-graph/NodeGraphEditorView.js"],"names":[],"mappings":"AA4CA;IAyBI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,0JAiOC;IAvRD;;OAEG;IACH,iBAWE;IAuDE;;OAEG;IACH,UAFU,OAAO,CAEO;IAExB;;;OAGG;IACH,2CAAsC;IAEtC;;;OAGG;IACH,WAFU,kBAAkB,CAEa;IAEzC;;;OAGG;IACH,QAFU,eAAe,CAEL;IACpB;;;OAGG;IACH,4BAAoB;IAEpB;;;OAGG;IACH,iBAAkB;IAElB,mBAAuC;IAYvC;;;OAGG;IACH,gBAFU,6BAA6B,CAEH;IAepC;;OAEG;IACH,WAFU,aAAa,CAEG;IA2E1B;;;;;;;;OAQG;IACH,SAFU,oBAAoB,GAAC,IAAI,CAEhB;IA4BnB;;;;;OAKG;IACH,YAFU,uBAAuB,GAAC,IAAI,CAEhB;IAEtB;;;;;;;;;;OAUG;IACH,aAFU,qBAAqB,GAAC,IAAI,CAEb;IAgF3B;;;;;;;;;;;;;;;OAeG;IACH;QAP4B,CAAC,GAAlB,MAAM;QACW,CAAC,GAAlB,MAAM;QACW,UAAU,GAA3B,MAAM;QAC6B,QAAQ;QAC7B,IAAI;QAChB,qBAAqB,CAuBjC;IAED;;;;;;;;;;;;OAYG;IACH,eAWC;IAED;;;;;;;;;OASG;IACH,4BAFa,OAAO,CAInB;IAED;;;;;;;;;;;;;OAaG;IACH;QAN4B,CAAC,GAAlB,MAAM;QACW,CAAC,GAAlB,MAAM;QACW,UAAU,GAA3B,MAAM;QACJ,qBAAqB,CA6BjC;IAED;;;OAGG;IACH,0BAFa,OAAO,CAQnB;IAED;;;;;OAKG;IACH,gCA8BC;IAED,yBAuDC;;CACJ;iBAtmBgB,2BAA2B;gCAHZ,mDAAmD;mCAOhD,yBAAyB;gCAFb,oBAAoB;8CAS5D,4EAA4E;8BATpC,oBAAoB;qCAC9B,2BAA2B;wCAexB,8BAA8B;oBALlD,mCAAmC"}
1
+ {"version":3,"file":"NodeGraphEditorView.d.ts","sourceRoot":"","sources":["../../../../editor/view/node-graph/NodeGraphEditorView.js"],"names":[],"mappings":"AAmDA;IAyBI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACH,+KAiSC;IA7VD;;OAEG;IACH,iBAWE;IA+DE;;OAEG;IACH,UAFU,OAAO,CAEO;IAExB;;;OAGG;IACH,2CAAsC;IAEtC;;;;;OAKG;IACH,WAFU,kBAAkB,CAEF;IAE1B;;OAEG;IACH,kCAFiC,OAAO,CAEA;IAExC;;;OAGG;IACH,WAFU,kBAAkB,CAEa;IAEzC;;;OAGG;IACH,QAFU,eAAe,CAEL;IACpB;;;OAGG;IACH,4BAAoB;IAEpB;;;OAGG;IACH,iBAAkB;IAElB,mBAAuC;IAYvC;;;OAGG;IACH,gBAFU,6BAA6B,CAEH;IAepC;;OAEG;IACH,WAFU,aAAa,CAEG;IA4H1B;;;;;;;;OAQG;IACH,SAFU,oBAAoB,GAAC,IAAI,CAEhB;IA4BnB;;;;;OAKG;IACH,YAFU,uBAAuB,GAAC,IAAI,CAEhB;IAEtB;;;;;;;;;;OAUG;IACH,aAFU,qBAAqB,GAAC,IAAI,CAEb;IAgF3B;;;;;;;;;;;;;;;OAeG;IACH;QAP4B,CAAC,GAAlB,MAAM;QACW,CAAC,GAAlB,MAAM;QACW,UAAU,GAA3B,MAAM;QAC6B,QAAQ;QAC7B,IAAI;QAChB,qBAAqB,CAwBjC;IAED;;;;;;;;;;;;OAYG;IACH,eAWC;IAED;;;;;;;;;OASG;IACH,4BAFa,OAAO,CAInB;IAED;;;;;;;;;;;;;OAaG;IACH;QAN4B,CAAC,GAAlB,MAAM;QACW,CAAC,GAAlB,MAAM;QACW,UAAU,GAA3B,MAAM;QACJ,qBAAqB,CA6BjC;IAED;;;OAGG;IACH,0BAFa,OAAO,CAQnB;IAED;;;;;OAKG;IACH,gCA8BC;IAED;;;;;;;;;OASG;IACH,iBAJa,OAAO,CAmBnB;IAED;;;;;;;;;;;;;;OAcG;IACH,SAJa,QAAQ,cAAc,CAAC,CAiCnC;IAED;;;;;;;;;;;OAWG;IACH,sBAJa,QAAQ,cAAc,CAAC,CAqBnC;IA+DD,yBAuDC;;CACJ;iBAz1BgB,2BAA2B;gCAHZ,mDAAmD;mCA4B5E,yBAAyB;mCArBG,yBAAyB;gCAFb,oBAAoB;8CAS5D,4EAA4E;8BATpC,oBAAoB;qCAC9B,2BAA2B;wCAexB,8BAA8B;oBALlD,mCAAmC"}
@@ -21,8 +21,15 @@ import Vector2 from "../../../src/core/geom/Vector2.js";
21
21
  import ButtonView from "../../../src/view/elements/button/ButtonView.js";
22
22
  import EmptyView from "../../../src/view/elements/EmptyView.js";
23
23
  import { PortDirection } from "../../../src/core/model/node-graph/node/PortDirection.js";
24
- import { ConnectionCreateAction } from "./actions/ConnectionCreateAction.js";
24
+ import { connection_bind_actions } from "./actions/connection_bind_actions.js";
25
25
  import { NodeGraphSearchMenuView } from "./NodeGraphSearchMenuView.js";
26
+ import { ConnectionCreateAction } from "./actions/ConnectionCreateAction.js";
27
+ import {
28
+ NODE_GRAPH_PASTE_STEP,
29
+ NodeGraphClipboard,
30
+ node_graph_fragment_centre,
31
+ node_graph_fragment_from_nodes,
32
+ } from "./NodeGraphClipboard.js";
26
33
 
27
34
  /**
28
35
  * Whether a port could take a value of this type, knowing nothing about the graph's domain: the same
@@ -96,6 +103,12 @@ export class NodeGraphEditorView extends View {
96
103
  * type the menu places, so a node arrives ready to compile rather than to repair
97
104
  * @param {boolean} [readOnly] show the graph without offering to change it; see
98
105
  * {@link NodeGraphView}. Turns off the add-node menu and the editing shortcuts too.
106
+ * @param {NodeGraphClipboard} [clipboard] what `Ctrl+C` writes and `Ctrl+V` reads. A host with
107
+ * several canvases over one document passes one to all of them, so a copy taken in one
108
+ * pastes in the next; on its own, a canvas gets one of its own and copies to itself.
109
+ * @param {function(NodeInstance):boolean} [copyable] whether a node may be had a second of, for
110
+ * a host with types that exist once per graph. See
111
+ * {@link node_graph_fragment_from_nodes}.
99
112
  */
100
113
  constructor({
101
114
  graph,
@@ -108,7 +121,9 @@ export class NodeGraphEditorView extends View {
108
121
  portDataType = undefined,
109
122
  minimap = true,
110
123
  library = undefined,
111
- readOnly = false
124
+ readOnly = false,
125
+ clipboard = new NodeGraphClipboard(),
126
+ copyable = undefined
112
127
  }) {
113
128
  super();
114
129
 
@@ -123,6 +138,19 @@ export class NodeGraphEditorView extends View {
123
138
  */
124
139
  this.actionProcessor = actionProcessor;
125
140
 
141
+ /**
142
+ * What a copy is written to and a paste read from. Shared with the host's other canvases
143
+ * when it supplied one.
144
+ *
145
+ * @type {NodeGraphClipboard}
146
+ */
147
+ this.clipboard = clipboard;
148
+
149
+ /**
150
+ * @type {function(NodeInstance):boolean}
151
+ */
152
+ this.copyable = copyable ?? (() => true);
153
+
126
154
  /**
127
155
  *
128
156
  * @type {NodeGraphSelection}
@@ -230,11 +258,60 @@ export class NodeGraphEditorView extends View {
230
258
  event.stopPropagation();
231
259
 
232
260
  actionProcessor.undo();
233
- } else if (event.keyCode === KeyCodes.y) {
261
+
262
+ return;
263
+ }
264
+
265
+ if (event.keyCode === KeyCodes.y) {
234
266
  event.preventDefault();
235
267
  event.stopPropagation();
236
268
 
237
269
  actionProcessor.redo();
270
+
271
+ return;
272
+ }
273
+
274
+ // The clipboard's three want Ctrl and nothing else. `AltGr` is `Ctrl+Alt` on a European
275
+ // keyboard, so a canvas that answered that combination would copy every time an author
276
+ // typed one of the characters behind it; and `Ctrl+Shift+C` belongs to the browser.
277
+ if (event.shiftKey || event.altKey) {
278
+ return;
279
+ }
280
+
281
+ // Copying reads the graph, so a locked group body offers it: taking a copy of something
282
+ // out of one of the library's own groups and putting it in a graph of your own is the
283
+ // point of being able to open them. Putting something *into* one is not.
284
+ if (event.keyCode === KeyCodes.c) {
285
+ event.preventDefault();
286
+ event.stopPropagation();
287
+
288
+ this.copySelection();
289
+
290
+ return;
291
+ }
292
+
293
+ if (readOnly) {
294
+ return;
295
+ }
296
+
297
+ // `Ctrl+D` is the browser's bookmark shortcut, so it is swallowed whether or not there
298
+ // is anything selected to duplicate — leaving it through on an empty selection would
299
+ // mean the canvas sometimes bookmarked the page instead.
300
+ if (event.keyCode === KeyCodes.d) {
301
+ event.preventDefault();
302
+ event.stopPropagation();
303
+
304
+ this.duplicateSelection()
305
+ .catch(e => console.error("could not duplicate the selection", e));
306
+
307
+ return;
308
+ }
309
+
310
+ if (event.keyCode === KeyCodes.v) {
311
+ event.preventDefault();
312
+ event.stopPropagation();
313
+
314
+ this.paste().catch(e => console.error("could not paste", e));
238
315
  }
239
316
  });
240
317
 
@@ -419,12 +496,13 @@ export class NodeGraphEditorView extends View {
419
496
  const outgoing = endpoint.port.direction === PortDirection.Out;
420
497
 
421
498
  // `addNode` marked the timeline and has not marked it again, so this joins the same step
422
- await this.actionProcessor.do(new ConnectionCreateAction(
499
+ await this.actionProcessor.doMany(connection_bind_actions(
423
500
  this.graph,
424
501
  outgoing ? endpoint.instance.id : node.id,
425
502
  outgoing ? endpoint.port.id : port.id,
426
503
  outgoing ? node.id : endpoint.instance.id,
427
- outgoing ? port.id : endpoint.port.id
504
+ outgoing ? port.id : endpoint.port.id,
505
+ this.visual
428
506
  ));
429
507
 
430
508
  return node;
@@ -562,6 +640,171 @@ export class NodeGraphEditorView extends View {
562
640
  await this.actionProcessor.doMany(actions);
563
641
  }
564
642
 
643
+ /**
644
+ * Take a copy of the selected nodes, and of every wire they hold whole.
645
+ *
646
+ * Reading, not editing, so a read-only canvas offers it: opening one of a library's own groups
647
+ * to take a copy of what is inside it is the point of being able to open them.
648
+ *
649
+ * @returns {boolean} whether anything was copied. A selection with nothing copyable in it leaves
650
+ * the clipboard alone rather than emptying it, which is the one outcome an author
651
+ * asking for a copy certainly did not want.
652
+ */
653
+ copySelection() {
654
+ const fragment = node_graph_fragment_from_nodes({
655
+ graph: this.graph,
656
+ visual: this.visual,
657
+ nodes: this.selection.nodes.asArray(),
658
+ copyable: this.copyable,
659
+ });
660
+
661
+ if (fragment === null) {
662
+ return false;
663
+ }
664
+
665
+ this.clipboard.write(fragment);
666
+
667
+ return true;
668
+ }
669
+
670
+ /**
671
+ * Put what was copied into this graph, in the middle of what the author is looking at.
672
+ *
673
+ * Where a paste lands is the one decision here. It goes to the middle of the view rather than
674
+ * back where it was copied from, for the same reason a node added from the menu with no position
675
+ * does: what arrives has to be somewhere the author can see it, and the place it was copied from
676
+ * may be a long way off screen — a copy taken in one phase and pasted in the other has no
677
+ * meaningful "back where it was" at all. The arrangement inside the fragment is kept exactly; it
678
+ * is the whole of it that moves. A repeat paste of the same content steps aside by
679
+ * {@link NODE_GRAPH_PASTE_STEP} so that copies do not hide each other.
680
+ *
681
+ * @returns {Promise<NodeInstance[]>} the nodes that landed, once the timeline has applied them;
682
+ * empty when there was nothing on the clipboard
683
+ * @throws if this canvas is read-only
684
+ */
685
+ async paste() {
686
+ if (this.readOnly) {
687
+ throw new Error("This graph is read-only, so nothing can be pasted into it.");
688
+ }
689
+
690
+ const clipboard = this.clipboard;
691
+
692
+ const fragment = clipboard.read();
693
+
694
+ if (fragment === null) {
695
+ return [];
696
+ }
697
+
698
+ const centre = node_graph_fragment_centre(fragment);
699
+ const target = this.viewCentreInGraphSpace();
700
+
701
+ const step = clipboard.pastes * NODE_GRAPH_PASTE_STEP;
702
+
703
+ // before the placing rather than after it: the timeline queues, so two pastes issued in one
704
+ // tick — which is what holding Ctrl+V down is — would otherwise both read the same count and
705
+ // land on top of each other
706
+ clipboard.notePaste();
707
+
708
+ return this.#placeFragment(
709
+ fragment,
710
+ target.x - centre.x + step,
711
+ target.y - centre.y + step,
712
+ 'paste'
713
+ );
714
+ }
715
+
716
+ /**
717
+ * A second of everything selected, beside the originals.
718
+ *
719
+ * Beside rather than in the middle of the view, which is where {@link #paste} puts things: a
720
+ * duplicate is a second of something the author is already looking at, and centring it would
721
+ * take it away from the thing it is a second of. The clipboard is not touched — `Ctrl+D` is not
722
+ * a copy, and it must not cost the author whatever they had copied earlier.
723
+ *
724
+ * @returns {Promise<NodeInstance[]>} the new nodes; empty when nothing selected could be had a
725
+ * second of
726
+ * @throws if this canvas is read-only
727
+ */
728
+ async duplicateSelection() {
729
+ if (this.readOnly) {
730
+ throw new Error("This graph is read-only, so nothing in it can be duplicated.");
731
+ }
732
+
733
+ const fragment = node_graph_fragment_from_nodes({
734
+ graph: this.graph,
735
+ visual: this.visual,
736
+ nodes: this.selection.nodes.asArray(),
737
+ copyable: this.copyable,
738
+ });
739
+
740
+ if (fragment === null) {
741
+ return [];
742
+ }
743
+
744
+ return this.#placeFragment(fragment, NODE_GRAPH_PASTE_STEP, NODE_GRAPH_PASTE_STEP, 'duplicate');
745
+ }
746
+
747
+ /**
748
+ * Build a fragment into this graph, offset, as one undoable step, and leave it selected.
749
+ *
750
+ * Two batches under one mark, because the wires need ids the creates have not handed out yet —
751
+ * the same shape an ungrouping has, and for the same reason. What is selected afterwards is what
752
+ * just arrived, so it can be dragged into place without being hunted for first.
753
+ *
754
+ * @param {import("./NodeGraphClipboard.js").NodeGraphFragment} fragment
755
+ * @param {number} offset_x graph-space
756
+ * @param {number} offset_y graph-space
757
+ * @param {string} label what the step is called on the timeline
758
+ * @returns {Promise<NodeInstance[]>}
759
+ */
760
+ async #placeFragment(fragment, offset_x, offset_y, label) {
761
+ const graph = this.graph;
762
+ const visual = this.visual;
763
+
764
+ // A canvas draws a node in a box generated from its type, and throws when it has none — so a
765
+ // fragment carrying a type this canvas has never drawn would fail from inside the timeline,
766
+ // half-way through a step. Which is reachable: the clipboard is shared between canvases, and
767
+ // a host's canvases need not have been built from the same set of types. Generating a box is
768
+ // arithmetic over port and parameter counts, keyed by the description, so telling a registry
769
+ // about a type it already knows costs nothing.
770
+ for (const record of fragment.nodes) {
771
+ this.visualRegistry.generate(record.description);
772
+ }
773
+
774
+ const creates = fragment.nodes.map(record => new NodeCreateAction(
775
+ graph,
776
+ visual,
777
+ this.visualRegistry,
778
+ record.description,
779
+ record.x + offset_x,
780
+ record.y + offset_y,
781
+ // cloned again on the way out: one fragment pasted twice must not hand both copies the
782
+ // same parameter objects, nor either of them the clipboard's
783
+ structuredClone(record.parameters)
784
+ ));
785
+
786
+ this.actionProcessor.mark(label);
787
+
788
+ await this.actionProcessor.doMany(creates);
789
+
790
+ const nodes = creates.map(create => create.node);
791
+
792
+ const wires = fragment.connections.map(wire => new ConnectionCreateAction(
793
+ graph,
794
+ nodes[wire.from].id,
795
+ wire.fromPort,
796
+ nodes[wire.to].id,
797
+ wire.toPort
798
+ ));
799
+
800
+ // `mark` has not been called again, so this joins the same step
801
+ wires.push(new SelectionSetAction(this.selection, nodes.map(node => node.id), []));
802
+
803
+ await this.actionProcessor.doMany(wires);
804
+
805
+ return nodes;
806
+ }
807
+
565
808
  cameraContainAll() {
566
809
  /**
567
810
  *
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphView.d.ts","sourceRoot":"","sources":["../../../../editor/view/node-graph/NodeGraphView.js"],"names":[],"mappings":";AAyGA;IA4GI;;;;;;;;;;;;;;;;;;;OAmBG;IACH,gJA8cC;IA7kBD,mBAAmC;IAEnC;;;;;;;;;OASG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAQ,CAAC,CAET;IAmBtB;;;OAGG;IACH,qBAFmB,yBAAyB,cAE/B;IAEb;;OAEG;IACH,iBA0DE;IAEF;;;;OAIG;IACH,mBAFU,OAAO,CAEA;IAmCb;;;OAGG;IACH,2CAAsC;IAMtC;;;OAGG;IACH,QAFU,eAAe,CAEL;IAEpB;;;OAGG;IACH,iBAAkB;IAElB;;;OAGG;IACH,4BAAoB;IAEpB;;;OAGG;IACH,WAFU,kBAAkB,CAEF;IAma9B;;;;;;;;;OASG;IACH,oBAFa,IAAI,CAgBhB;IAED;;;;;;;;OAQG;IACH,gBAFa,IAAI,CAMhB;IAED;;;;;;;;OAQG;IACH,cAFa,OAAO,CAInB;IAgBD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,gCAFa,IAAI,CA+NhB;IAED;;;;;;;;OAQG;IACH,0BAHW,KAAK,GACH,MAAM,EAAE,CAwBpB;IAED;;;;;;;;;;;OAWG;IACH,gCAHW,KAAK,GACH,MAAM,EAAE,CAsBpB;IAED;;;;;;;;;;OAUG;IACH,6BAJW,KAAK,SACL,UAAU,GAAC,YAAY,GACrB,IAAI,CAgDhB;IAED;;;;OAIG;IACH,wBAHW,OAAO,GACL,aAAW,IAAI,CAiC3B;IAED;;;;;;;OAOG;IACH,4BAJW,MAAM,GAAC,IAAI,gBACX,MAAM,GAAC,IAAI,SACX,UAAU,GAAC,YAAY,QA8CjC;IAGD;;;;;;;OAOG;IACH,wDAFa,OAAO,CAcnB;IAED;;;;;;;;;OASG;IACH,+CAFa,oBAAoB,CAYhC;IAED;;;;;;OAMG;IACH,oBALW,wBAAwB,QACxB,oBAAoB,iCAEpB,OAAO,QA+DjB;IAED;;;;OAIG;IACH,mCAHW,yBAAyB,UACzB,OAAO,QAiBjB;IAeD;;;;OAIG;IACH,kCAHW,OAAO,UACP,OAAO,QAIjB;IAED;;;;OAIG;IACH,kCAHW,OAAO,UACP,OAAO,QAIjB;;CACJ;iBAn3CgB,2BAA2B;yBAInB,eAAe;0CAIE,sEAAsE;gCAChF,mDAAmD;gCACnD,sBAAsB;mCACnB,yBAAyB;kBAQ1C,yCAAyC;oBAjBvC,mCAAmC;qCAgBlB,mEAAmE"}
1
+ {"version":3,"file":"NodeGraphView.d.ts","sourceRoot":"","sources":["../../../../editor/view/node-graph/NodeGraphView.js"],"names":[],"mappings":";AA0GA;IA4GI;;;;;;;;;;;;;;;;;;;OAmBG;IACH,gJAyhBC;IAxpBD,mBAAmC;IAEnC;;;;;;;;;OASG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAQ,CAAC,CAET;IAmBtB;;;OAGG;IACH,qBAFmB,yBAAyB,cAE/B;IAEb;;OAEG;IACH,iBA0DE;IAEF;;;;OAIG;IACH,mBAFU,OAAO,CAEA;IAmCb;;;OAGG;IACH,2CAAsC;IAMtC;;;OAGG;IACH,QAFU,eAAe,CAEL;IAEpB;;;OAGG;IACH,iBAAkB;IAElB;;;OAGG;IACH,4BAAoB;IAEpB;;;OAGG;IACH,WAFU,kBAAkB,CAEF;IA8e9B;;;;;;;;;OASG;IACH,oBAFa,IAAI,CAgBhB;IAED;;;;;;;;OAQG;IACH,gBAFa,IAAI,CAMhB;IAED;;;;;;;;OAQG;IACH,cAFa,OAAO,CAInB;IAgBD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,gCAFa,IAAI,CA+NhB;IAED;;;;;;;;OAQG;IACH,0BAHW,KAAK,GACH,MAAM,EAAE,CAwBpB;IAED;;;;;;;;;;;OAWG;IACH,gCAHW,KAAK,GACH,MAAM,EAAE,CAsBpB;IAED;;;;;;;;;;OAUG;IACH,6BAJW,KAAK,SACL,UAAU,GAAC,YAAY,GACrB,IAAI,CAgDhB;IAED;;;;OAIG;IACH,wBAHW,OAAO,GACL,aAAW,IAAI,CAiC3B;IAED;;;;;;;OAOG;IACH,4BAJW,MAAM,GAAC,IAAI,gBACX,MAAM,GAAC,IAAI,SACX,UAAU,GAAC,YAAY,QA8CjC;IAGD;;;;;;;OAOG;IACH,wDAFa,OAAO,CAcnB;IAED;;;;;;;;;OASG;IACH,+CAFa,oBAAoB,CAYhC;IAED;;;;;;OAMG;IACH,oBALW,wBAAwB,QACxB,oBAAoB,iCAEpB,OAAO,QA+DjB;IAED;;;;OAIG;IACH,mCAHW,yBAAyB,UACzB,OAAO,QAiBjB;IAeD;;;;OAIG;IACH,kCAHW,OAAO,UACP,OAAO,QAIjB;IAED;;;;OAIG;IACH,kCAHW,OAAO,UACP,OAAO,QAIjB;;CACJ;iBA/7CgB,2BAA2B;yBAInB,eAAe;0CAIE,sEAAsE;gCAChF,mDAAmD;gCACnD,sBAAsB;mCACnB,yBAAyB;kBAS1C,yCAAyC;oBAlBvC,mCAAmC;qCAiBlB,mEAAmE"}
@@ -13,7 +13,8 @@ import { NodeInstancePortReference } from "../../../src/core/model/node-graph/no
13
13
  import { ActionProcessor } from "../../../src/core/process/undo/ActionProcessor.js";
14
14
  import { NodeGraphCamera } from "./NodeGraphCamera.js";
15
15
  import { NodeGraphSelection } from "./NodeGraphSelection.js";
16
- import { ConnectionCreateAction } from "./actions/ConnectionCreateAction.js";
16
+ import { connection_bind_actions } from "./actions/connection_bind_actions.js";
17
+ import { ConnectionDeleteAction } from "./actions/ConnectionDeleteAction.js";
17
18
  import { NodeParameterSetAction } from "./actions/NodeParameterSetAction.js";
18
19
  import { NodesMoveAction } from "./actions/NodesMoveAction.js";
19
20
  import { SelectionSetAction } from "./actions/SelectionSetAction.js";
@@ -299,7 +300,20 @@ export class NodeGraphView extends View {
299
300
  *
300
301
  * @type {boolean}
301
302
  */
302
- consumed: false
303
+ consumed: false,
304
+
305
+ /**
306
+ * The wire this gesture picked up, when it began on an input that already had one.
307
+ *
308
+ * Dragging out of a bound input is that wire being moved rather than a second one being
309
+ * made, so the gesture continues from the source it came from and this is what is on
310
+ * the end of it. It is not taken off the graph until the drop says where it is going —
311
+ * a gesture that ends on a port that refuses it, or on the port it started from, has to
312
+ * leave the graph as it found it — so while the drag runs it is only hidden.
313
+ *
314
+ * @type {Connection|null}
315
+ */
316
+ detached: null
303
317
  };
304
318
 
305
319
  const vBlockCanvas = new ListView(graph.nodes, {
@@ -340,12 +354,25 @@ export class NodeGraphView extends View {
340
354
  return;
341
355
  }
342
356
 
357
+ // An input holds one wire, so a drag out of a bound one is that
358
+ // wire being taken hold of: what is on the end of the gesture is
359
+ // its source, and where it is let go decides what it feeds — or
360
+ // whether it feeds anything, which is how one is pulled off.
361
+ const held = port.direction === PortDirection.In
362
+ ? node.getEndpoint(port.id).inConnections[0] ?? null
363
+ : null;
364
+
343
365
  const endpoint = new NodeInstancePortReference();
344
366
 
345
- endpoint.set(node, port);
367
+ if (held === null) {
368
+ endpoint.set(node, port);
369
+ } else {
370
+ endpoint.set(held.source.instance, held.source.port);
371
+ }
346
372
 
347
373
  tempConnection.enabled = true;
348
374
  tempConnection.consumed = false;
375
+ tempConnection.detached = held;
349
376
  tempConnection.endpoint = endpoint;
350
377
 
351
378
  // The wire is drawn from here to the anchor, and a gesture that ends
@@ -362,8 +389,10 @@ export class NodeGraphView extends View {
362
389
 
363
390
  const endpoint = tempConnection.endpoint;
364
391
  const consumed = tempConnection.consumed;
392
+ const detached = tempConnection.detached;
365
393
 
366
394
  tempConnection.enabled = false;
395
+ tempConnection.detached = null;
367
396
 
368
397
  requestRedraw();
369
398
 
@@ -373,6 +402,15 @@ export class NodeGraphView extends View {
373
402
  return;
374
403
  }
375
404
 
405
+ if (detached !== null) {
406
+ // A wire taken off an input and let go over nothing is a wire
407
+ // removed. Its own step: what the host makes of the drop below
408
+ // — a menu that may be dismissed — is a separate decision, and
409
+ // the removal stands whichever way that goes.
410
+ actionProcessor.mark('disconnect');
411
+ actionProcessor.do(new ConnectionDeleteAction(graph, detached, visual));
412
+ }
413
+
376
414
  const anchor = tempConnection.anchor;
377
415
 
378
416
  self.transformPointGraph2Canvas(anchor, v2_pointer);
@@ -443,19 +481,46 @@ export class NodeGraphView extends View {
443
481
  const source_ref = graph.getConnectionEndpoint(source_node, source_port);
444
482
  const target_ref = graph.getConnectionEndpoint(target_node, target_port);
445
483
 
484
+ const detached = tempConnection.detached;
485
+
486
+ if (
487
+ detached !== null
488
+ && detached.source === source_ref
489
+ && detached.target === target_ref
490
+ ) {
491
+ // a wire picked up and put back where it came from: the
492
+ // gesture did nothing, and leaving it alone is what makes
493
+ // that true — nothing reaches the timeline
494
+ return;
495
+ }
496
+
446
497
  const duplicate = source_ref.connections.some(
447
498
  c => c.source === source_ref && c.target === target_ref
448
499
  );
449
500
 
450
- if (!duplicate) {
451
- actionProcessor.mark('create connection');
452
- actionProcessor.do(new ConnectionCreateAction(
501
+ const actions = duplicate
502
+ ? []
503
+ : connection_bind_actions(
453
504
  graph,
454
505
  source_node, source_port,
455
- target_node, target_port
456
- ));
506
+ target_node, target_port,
507
+ visual
508
+ );
509
+
510
+ if (detached !== null) {
511
+ // the wire this gesture is holding now feeds somewhere
512
+ // else, so it comes off where it was — one step, because
513
+ // it was one gesture
514
+ actions.unshift(new ConnectionDeleteAction(graph, detached, visual));
457
515
  }
458
516
 
517
+ if (actions.length > 0) {
518
+ actionProcessor.mark(detached === null
519
+ ? 'create connection'
520
+ : 'move connection');
521
+
522
+ actionProcessor.doMany(actions);
523
+ }
459
524
  }
460
525
  }
461
526
  });
@@ -598,6 +663,13 @@ export class NodeGraphView extends View {
598
663
  //draw connections: a wire carries what comes out of its source
599
664
  graph.connections.forEach(connection => {
600
665
 
666
+ if (connection === tempConnection.detached) {
667
+ // in hand rather than on the graph: it is drawn below, running to the cursor.
668
+ // Still on the graph because where it ends up is the drop's to decide, and one
669
+ // that lands back where it started has to leave no trace.
670
+ return;
671
+ }
672
+
601
673
  this.drawConnection(
602
674
  ctx,
603
675
  this.resolveConnectionPath(connection),
@@ -690,6 +762,10 @@ export class NodeGraphView extends View {
690
762
  this.bindSignal(graph.on.connectionAdded, requestRedraw);
691
763
  this.bindSignal(graph.on.connectionRemoved, requestRedraw);
692
764
 
765
+ // connection ids are pooled the way node ids are, so a wire that is gone must not leave its
766
+ // selection behind for an unrelated future one to be handed
767
+ this.bindSignal(graph.on.connectionRemoved, connection => selection.connections.removeOneOf(connection.id));
768
+
693
769
  // selected wires are drawn highlighted
694
770
  this.bindSignal(selection.connections.on.added, requestRedraw);
695
771
  this.bindSignal(selection.connections.on.removed, requestRedraw);
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Bind an input to a source, taking off whatever that input was already holding.
3
+ *
4
+ * An input takes one wire. A second one dropped on it is an author saying what should feed it,
5
+ * not asking for a merge the graph has no rule for — so the wire that was there comes off in the
6
+ * same gesture, and on the same step of the timeline. That an editor can never leave an input with
7
+ * two sources is the point: a graph loaded from a file may be in that state and is reported for it,
8
+ * but no gesture on the canvas can put one there.
9
+ *
10
+ * Returned rather than performed, so a caller in the middle of a larger step — a node and its first
11
+ * wire, say — can fold them into it. {@link ActionProcessor#doMany} applies them in order.
12
+ *
13
+ * @param {NodeGraph} graph
14
+ * @param {number} sourceNode
15
+ * @param {number} sourcePort
16
+ * @param {number} targetNode
17
+ * @param {number} targetPort input port; what is already bound to it is unbound first
18
+ * @param {NodeGraphVisualData} [visual] source of the removed wires' paths; without it the paths are
19
+ * left alone, which is what a caller with no visual data wants
20
+ * @returns {Action[]}
21
+ */
22
+ export function connection_bind_actions(graph: NodeGraph, sourceNode: number, sourcePort: number, targetNode: number, targetPort: number, visual?: NodeGraphVisualData): Action[];
23
+ //# sourceMappingURL=connection_bind_actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection_bind_actions.d.ts","sourceRoot":"","sources":["../../../../../editor/view/node-graph/actions/connection_bind_actions.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,sEARW,MAAM,cACN,MAAM,cACN,MAAM,cACN,MAAM,iCAGJ,QAAQ,CAgBpB"}
@@ -0,0 +1,39 @@
1
+ import { ConnectionCreateAction } from "./ConnectionCreateAction.js";
2
+ import { ConnectionDeleteAction } from "./ConnectionDeleteAction.js";
3
+
4
+ /**
5
+ * Bind an input to a source, taking off whatever that input was already holding.
6
+ *
7
+ * An input takes one wire. A second one dropped on it is an author saying what should feed it,
8
+ * not asking for a merge the graph has no rule for — so the wire that was there comes off in the
9
+ * same gesture, and on the same step of the timeline. That an editor can never leave an input with
10
+ * two sources is the point: a graph loaded from a file may be in that state and is reported for it,
11
+ * but no gesture on the canvas can put one there.
12
+ *
13
+ * Returned rather than performed, so a caller in the middle of a larger step — a node and its first
14
+ * wire, say — can fold them into it. {@link ActionProcessor#doMany} applies them in order.
15
+ *
16
+ * @param {NodeGraph} graph
17
+ * @param {number} sourceNode
18
+ * @param {number} sourcePort
19
+ * @param {number} targetNode
20
+ * @param {number} targetPort input port; what is already bound to it is unbound first
21
+ * @param {NodeGraphVisualData} [visual] source of the removed wires' paths; without it the paths are
22
+ * left alone, which is what a caller with no visual data wants
23
+ * @returns {Action[]}
24
+ */
25
+ export function connection_bind_actions(graph, sourceNode, sourcePort, targetNode, targetPort, visual = undefined) {
26
+ const target = graph.getConnectionEndpoint(targetNode, targetPort);
27
+
28
+ const actions = [];
29
+
30
+ // off before on, so the graph is never holding an input with two sources — not even between two
31
+ // actions of one step, where anything watching it would see one
32
+ for (const connection of target === undefined ? [] : target.inConnections) {
33
+ actions.push(new ConnectionDeleteAction(graph, connection, visual));
34
+ }
35
+
36
+ actions.push(new ConnectionCreateAction(graph, sourceNode, sourcePort, targetNode, targetPort));
37
+
38
+ return actions;
39
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ParticleCodeEditorView.d.ts","sourceRoot":"","sources":["../../../../../editor/view/particles/effect/ParticleCodeEditorView.js"],"names":[],"mappings":"AAgDA;IA2DI;;;OAGG;IACH;QAFyG,MAAM,EAApG,OAAO,qDAAqD,EAAE,sBAAsB;OA6G9F;IAxGG,mBAAuC;IAIvC;;OAEG;IACH,QAFU,OAAO,qDAAqD,EAAE,sBAAsB,CAE1E;IAmGxB;;OAEG;IACH,wBAYC;IAED;;;;OAIG;IACH,gBAsCC;IAwGD;;;OAGG;IACH,iBAFW,MAAM,QAahB;IAsBD;;OAEG;IACH,eAyBC;IAcD,eAcC;;CACJ;iBA5dgB,8BAA8B"}
1
+ {"version":3,"file":"ParticleCodeEditorView.d.ts","sourceRoot":"","sources":["../../../../../editor/view/particles/effect/ParticleCodeEditorView.js"],"names":[],"mappings":"AAgDA;IA2DI;;;OAGG;IACH;QAFyG,MAAM,EAApG,OAAO,qDAAqD,EAAE,sBAAsB;OA6G9F;IAxGG,mBAAuC;IAIvC;;OAEG;IACH,QAFU,OAAO,qDAAqD,EAAE,sBAAsB,CAE1E;IAmGxB;;OAEG;IACH,wBAYC;IAED;;;;OAIG;IACH,gBAsCC;IAyGD;;;OAGG;IACH,iBAFW,MAAM,QAahB;IAsBD;;OAEG;IACH,eAyBC;IAcD,eAcC;;CACJ;iBA7dgB,8BAA8B"}
@@ -283,9 +283,10 @@ export class ParticleCodeEditorView extends View {
283
283
  /**
284
284
  * What the optimizer did, in the two numbers that decide whether it was worth it.
285
285
  *
286
- * Instructions are what the VM steps through and registers are what limits how much of an effect
287
- * fits at all (see `PARTICLE_VM_REGISTER_SLOTS`), so those are the pair. Blank when the box is
288
- * not ticked: there is nothing to compare a program against itself with.
286
+ * Instructions are what the VM steps through and registers are what decides which interpreter
287
+ * runs it: past `PARTICLE_VM_FAST_REGISTER_SLOTS` the whole system falls back to the wide VM,
288
+ * which works and is far slower. So those are the pair. Blank when the box is not ticked: there
289
+ * is nothing to compare a program against itself with.
289
290
  *
290
291
  * @param {import("../../../particles/effect/ParticleEffectDocument.js").ParticleEffectCompilation} compilation
291
292
  */