@woosh/meep-engine 3.15.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 (1118) hide show
  1. package/editor/Editor.js +7 -7
  2. package/editor/actions/concrete/TransformModifyAction.d.ts +4 -4
  3. package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
  4. package/editor/actions/concrete/TransformModifyAction.js +4 -4
  5. package/editor/camera/camera_framing.js +7 -7
  6. package/editor/ecs/component/editors/ecs/Transform64Editor.d.ts +20 -0
  7. package/editor/ecs/component/editors/ecs/Transform64Editor.d.ts.map +1 -0
  8. package/editor/ecs/component/editors/ecs/Transform64Editor.js +70 -0
  9. package/editor/ecs/component/prototypeObjectEditor.js +2 -2
  10. package/editor/ecs/component/registerEngineComponentEditors.js +3 -3
  11. package/editor/particles/effect/ParticleEffectDocument.d.ts +411 -0
  12. package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -0
  13. package/editor/particles/effect/ParticleEffectDocument.js +1010 -0
  14. package/editor/particles/effect/ParticleReferenceSimulation.d.ts +113 -0
  15. package/editor/particles/effect/ParticleReferenceSimulation.d.ts.map +1 -0
  16. package/editor/particles/effect/ParticleReferenceSimulation.js +377 -0
  17. package/editor/particles/effect/actions/ParticleGroupDefineAction.d.ts +35 -0
  18. package/editor/particles/effect/actions/ParticleGroupDefineAction.d.ts.map +1 -0
  19. package/editor/particles/effect/actions/ParticleGroupDefineAction.js +45 -0
  20. package/editor/particles/effect/make_starter_particle_effect.d.ts +23 -0
  21. package/editor/particles/effect/make_starter_particle_effect.d.ts.map +1 -0
  22. package/editor/particles/effect/make_starter_particle_effect.js +177 -0
  23. package/editor/persistence/buildNewSceneDataset.d.ts.map +1 -1
  24. package/editor/persistence/buildNewSceneDataset.js +10 -8
  25. package/editor/process/symbolic/AudioEmitterSymbolicDisplay.js +67 -67
  26. package/editor/process/symbolic/CameraSymbolicDisplay.js +146 -146
  27. package/editor/process/symbolic/GridPositionSymbolicDisplay.js +6 -6
  28. package/editor/process/symbolic/LightSymbolicDisplay.js +172 -172
  29. package/editor/process/symbolic/ParticleEmitterSymbolicDisplay.d.ts.map +1 -1
  30. package/editor/process/symbolic/ParticleEmitterSymbolicDisplay.js +6 -3
  31. package/editor/process/symbolic/PositionedMarkerSymbolicDisplay.js +6 -6
  32. package/editor/selection/editor_pick.js +130 -130
  33. package/editor/templates/entity_templates.js +7 -7
  34. package/editor/tools/TransformToolV2.d.ts +3 -3
  35. package/editor/tools/TransformToolV2.d.ts.map +1 -1
  36. package/editor/tools/TransformToolV2.js +58 -25
  37. package/editor/tools/paint/TerrainHeightPaintTool.d.ts.map +1 -1
  38. package/editor/tools/paint/TerrainHeightPaintTool.js +11 -9
  39. package/editor/tools/v2/GizmoNode.js +2 -2
  40. package/editor/tools/v2/TransformControls.d.ts +3 -3
  41. package/editor/tools/v2/TransformControls.d.ts.map +1 -1
  42. package/editor/tools/v2/TransformControls.js +1003 -971
  43. package/editor/tools/v2/handle/gizmo_drag_plane.d.ts.map +1 -1
  44. package/editor/tools/v2/handle/gizmo_drag_plane.js +6 -1
  45. package/editor/view/ecs/components/common/AutoCanvasView.js +17 -0
  46. package/editor/view/node-graph/NodeGraphClipboard.d.ts +186 -0
  47. package/editor/view/node-graph/NodeGraphClipboard.d.ts.map +1 -0
  48. package/editor/view/node-graph/NodeGraphClipboard.js +231 -0
  49. package/editor/view/node-graph/NodeGraphEditorView.d.ts +201 -2
  50. package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
  51. package/editor/view/node-graph/NodeGraphEditorView.js +602 -7
  52. package/editor/view/node-graph/NodeGraphMinimapView.d.ts +120 -0
  53. package/editor/view/node-graph/NodeGraphMinimapView.d.ts.map +1 -0
  54. package/editor/view/node-graph/NodeGraphMinimapView.js +859 -0
  55. package/editor/view/node-graph/NodeGraphPaletteView.d.ts +112 -0
  56. package/editor/view/node-graph/NodeGraphPaletteView.d.ts.map +1 -0
  57. package/editor/view/node-graph/NodeGraphPaletteView.js +352 -0
  58. package/editor/view/node-graph/NodeGraphSearchMenuView.d.ts +76 -0
  59. package/editor/view/node-graph/NodeGraphSearchMenuView.d.ts.map +1 -0
  60. package/editor/view/node-graph/NodeGraphSearchMenuView.js +247 -0
  61. package/editor/view/node-graph/NodeGraphView.d.ts +147 -5
  62. package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
  63. package/editor/view/node-graph/NodeGraphView.js +891 -82
  64. package/editor/view/node-graph/NodeIconView.d.ts +33 -0
  65. package/editor/view/node-graph/NodeIconView.d.ts.map +1 -0
  66. package/editor/view/node-graph/NodeIconView.js +54 -0
  67. package/editor/view/node-graph/NodeView.d.ts +71 -1
  68. package/editor/view/node-graph/NodeView.d.ts.map +1 -1
  69. package/editor/view/node-graph/NodeView.js +318 -17
  70. package/editor/view/node-graph/PortView.d.ts +41 -1
  71. package/editor/view/node-graph/PortView.d.ts.map +1 -1
  72. package/editor/view/node-graph/PortView.js +121 -69
  73. package/editor/view/node-graph/actions/ConnectionDeleteAction.d.ts +16 -3
  74. package/editor/view/node-graph/actions/ConnectionDeleteAction.d.ts.map +1 -1
  75. package/editor/view/node-graph/actions/ConnectionDeleteAction.js +29 -3
  76. package/editor/view/node-graph/actions/NodeCreateAction.d.ts +65 -0
  77. package/editor/view/node-graph/actions/NodeCreateAction.d.ts.map +1 -0
  78. package/editor/view/node-graph/actions/NodeCreateAction.js +108 -0
  79. package/editor/view/node-graph/actions/NodeDeleteAction.d.ts +6 -0
  80. package/editor/view/node-graph/actions/NodeDeleteAction.d.ts.map +1 -1
  81. package/editor/view/node-graph/actions/NodeDeleteAction.js +24 -2
  82. package/editor/view/node-graph/actions/connection_bind_actions.d.ts +23 -0
  83. package/editor/view/node-graph/actions/connection_bind_actions.d.ts.map +1 -0
  84. package/editor/view/node-graph/actions/connection_bind_actions.js +39 -0
  85. package/editor/view/node-graph/connection_wire_geometry.d.ts +34 -0
  86. package/editor/view/node-graph/connection_wire_geometry.d.ts.map +1 -1
  87. package/editor/view/node-graph/connection_wire_geometry.js +79 -3
  88. package/editor/view/node-graph/node-graph.css +678 -0
  89. package/editor/view/particles/effect/ParticleCodeEditorView.d.ts +37 -0
  90. package/editor/view/particles/effect/ParticleCodeEditorView.d.ts.map +1 -0
  91. package/editor/view/particles/effect/ParticleCodeEditorView.js +480 -0
  92. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts +20 -0
  93. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -0
  94. package/editor/view/particles/effect/ParticleCurveEditorView.js +574 -0
  95. package/editor/view/particles/effect/ParticleEffectEditorView.d.ts +61 -0
  96. package/editor/view/particles/effect/ParticleEffectEditorView.d.ts.map +1 -0
  97. package/editor/view/particles/effect/ParticleEffectEditorView.js +223 -0
  98. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts +25 -0
  99. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -0
  100. package/editor/view/particles/effect/ParticleEmitterInspectorView.js +632 -0
  101. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts +24 -0
  102. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -0
  103. package/editor/view/particles/effect/ParticleGradientEditorView.js +472 -0
  104. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts +161 -0
  105. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -0
  106. package/editor/view/particles/effect/ParticleGraphEditorView.js +1666 -0
  107. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts +22 -0
  108. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -0
  109. package/editor/view/particles/effect/ParticleNodeParametersView.js +553 -0
  110. package/editor/view/particles/effect/ParticlePreviewView.d.ts +52 -0
  111. package/editor/view/particles/effect/ParticlePreviewView.d.ts.map +1 -0
  112. package/editor/view/particles/effect/ParticlePreviewView.js +533 -0
  113. package/editor/view/particles/effect/particle-editor.css +644 -0
  114. package/editor/view/prepareMeshLibrary.d.ts.map +1 -1
  115. package/editor/view/prepareMeshLibrary.js +8 -4
  116. package/package.json +1 -1
  117. package/samples/engine/first-scene/main.js +152 -152
  118. package/samples/generation/generators/mir_generator_place_bases.js +3 -3
  119. package/src/core/assert.d.ts +28 -24
  120. package/src/core/assert.d.ts.map +1 -1
  121. package/src/core/assert.js +34 -26
  122. package/src/core/binary/allocator/OffsetAllocator.d.ts +25 -16
  123. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  124. package/src/core/binary/allocator/OffsetAllocator.js +10 -1
  125. package/src/core/collection/array/typed/float32_array_hash.d.ts +21 -0
  126. package/src/core/collection/array/typed/float32_array_hash.d.ts.map +1 -0
  127. package/src/core/collection/array/typed/float32_array_hash.js +38 -0
  128. package/src/core/geom/3d/shape/PosedShape3D.d.ts +17 -0
  129. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  130. package/src/core/geom/3d/shape/PosedShape3D.js +34 -2
  131. package/src/core/graph/csr/CSRGraph.d.ts +8 -1
  132. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -1
  133. package/src/core/graph/csr/CSRGraph.js +14 -6
  134. package/src/core/graph/format/graphviz/graphviz_escape_html_label.d.ts +17 -0
  135. package/src/core/graph/format/graphviz/graphviz_escape_html_label.d.ts.map +1 -0
  136. package/src/core/graph/format/graphviz/graphviz_escape_html_label.js +25 -0
  137. package/src/core/graph/format/graphviz/graphviz_escape_quoted.d.ts +16 -0
  138. package/src/core/graph/format/graphviz/graphviz_escape_quoted.d.ts.map +1 -0
  139. package/src/core/graph/format/graphviz/graphviz_escape_quoted.js +24 -0
  140. package/src/core/model/node-graph/NodeGraph.d.ts +12 -0
  141. package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
  142. package/src/core/model/node-graph/NodeGraph.js +21 -6
  143. package/src/core/model/node-graph/node/NodeDescription.d.ts +36 -0
  144. package/src/core/model/node-graph/node/NodeDescription.d.ts.map +1 -1
  145. package/src/core/model/node-graph/node/NodeDescription.js +41 -0
  146. package/src/core/model/node-graph/visual/ConnectionVisualData.d.ts +119 -0
  147. package/src/core/model/node-graph/visual/ConnectionVisualData.d.ts.map +1 -0
  148. package/src/core/model/node-graph/visual/ConnectionVisualData.js +317 -0
  149. package/src/core/model/node-graph/visual/NodeDescriptionVisualRegistry.d.ts +4 -0
  150. package/src/core/model/node-graph/visual/NodeDescriptionVisualRegistry.d.ts.map +1 -1
  151. package/src/core/model/node-graph/visual/NodeDescriptionVisualRegistry.js +125 -22
  152. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts +91 -2
  153. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
  154. package/src/core/model/node-graph/visual/NodeGraphVisualData.js +164 -113
  155. package/src/core/model/node-graph/visual/layout/LayoutBoxGraph.d.ts +162 -0
  156. package/src/core/model/node-graph/visual/layout/LayoutBoxGraph.d.ts.map +1 -0
  157. package/src/core/model/node-graph/visual/layout/LayoutBoxGraph.js +288 -0
  158. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts +133 -0
  159. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts.map +1 -0
  160. package/src/core/model/node-graph/visual/layout/LayoutProblem.js +168 -0
  161. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +175 -0
  162. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -0
  163. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +203 -0
  164. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts +226 -0
  165. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts.map +1 -0
  166. package/src/core/model/node-graph/visual/layout/RouteGrid.js +405 -0
  167. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts +159 -0
  168. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts.map +1 -0
  169. package/src/core/model/node-graph/visual/layout/RouteSearch.js +436 -0
  170. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts +93 -0
  171. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts.map +1 -0
  172. package/src/core/model/node-graph/visual/layout/RouteSet.js +176 -0
  173. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.d.ts +48 -0
  174. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.d.ts.map +1 -0
  175. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +561 -0
  176. package/src/core/model/node-graph/visual/layout/layout_assign_layers.d.ts +34 -0
  177. package/src/core/model/node-graph/visual/layout/layout_assign_layers.d.ts.map +1 -0
  178. package/src/core/model/node-graph/visual/layout/layout_assign_layers.js +202 -0
  179. package/src/core/model/node-graph/visual/layout/layout_break_cycles.d.ts +34 -0
  180. package/src/core/model/node-graph/visual/layout/layout_break_cycles.d.ts.map +1 -0
  181. package/src/core/model/node-graph/visual/layout/layout_break_cycles.js +254 -0
  182. package/src/core/model/node-graph/visual/layout/layout_build_problem.d.ts +29 -0
  183. package/src/core/model/node-graph/visual/layout/layout_build_problem.d.ts.map +1 -0
  184. package/src/core/model/node-graph/visual/layout/layout_build_problem.js +191 -0
  185. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts +35 -0
  186. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +1 -0
  187. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.js +109 -0
  188. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts +59 -0
  189. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts.map +1 -0
  190. package/src/core/model/node-graph/visual/layout/layout_node_graph.js +173 -0
  191. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts +46 -0
  192. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +1 -0
  193. package/src/core/model/node-graph/visual/layout/layout_order_layers.js +534 -0
  194. package/src/core/model/node-graph/visual/layout/layout_orient_links.d.ts +21 -0
  195. package/src/core/model/node-graph/visual/layout/layout_orient_links.d.ts.map +1 -0
  196. package/src/core/model/node-graph/visual/layout/layout_orient_links.js +49 -0
  197. package/src/core/model/node-graph/visual/layout/route_connections.d.ts +70 -0
  198. package/src/core/model/node-graph/visual/layout/route_connections.d.ts.map +1 -0
  199. package/src/core/model/node-graph/visual/layout/route_connections.js +716 -0
  200. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts +34 -0
  201. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts.map +1 -0
  202. package/src/core/model/node-graph/visual/layout/route_grid_build.js +229 -0
  203. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts +31 -0
  204. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts.map +1 -0
  205. package/src/core/model/node-graph/visual/layout/route_nudge.js +249 -0
  206. package/src/core/model/node-graph/visual/layout/route_to_spline.d.ts +29 -0
  207. package/src/core/model/node-graph/visual/layout/route_to_spline.d.ts.map +1 -0
  208. package/src/core/model/node-graph/visual/layout/route_to_spline.js +120 -0
  209. package/src/engine/EngineHarness.d.ts.map +1 -1
  210. package/src/engine/EngineHarness.js +593 -586
  211. package/src/engine/EntityCreator.js +116 -116
  212. package/src/engine/achievements/AchievementManager.js +437 -437
  213. package/src/engine/animation/AnimatedActions.js +111 -111
  214. package/src/engine/animation/AnimationUtils.d.ts.map +1 -1
  215. package/src/engine/animation/AnimationUtils.js +20 -8
  216. package/src/engine/animation/Animations.d.ts +1 -0
  217. package/src/engine/animation/Animations.d.ts.map +1 -1
  218. package/src/engine/animation/Animations.js +74 -66
  219. package/src/engine/animation/clip/bind_property_writer.d.ts.map +1 -1
  220. package/src/engine/animation/clip/bind_property_writer.js +12 -5
  221. package/src/engine/animation/curve/binding/BoundTransform64Writer.d.ts +29 -0
  222. package/src/engine/animation/curve/binding/BoundTransform64Writer.d.ts.map +1 -0
  223. package/src/engine/animation/curve/binding/BoundTransform64Writer.js +80 -0
  224. package/src/engine/animation/removeEntityWithMeshParticlesEffect.js +4 -4
  225. package/src/engine/asset/loaders/gltf_test_fixtures.d.ts.map +1 -1
  226. package/src/engine/asset/loaders/gltf_test_fixtures.js +5 -4
  227. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +12 -12
  228. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  229. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2078 -2045
  230. package/src/engine/control/first-person/abilities/LedgeGrab.js +1 -1
  231. package/src/engine/control/first-person/abilities/Mantle.js +1 -1
  232. package/src/engine/control/first-person/abilities/Slide.js +1 -1
  233. package/src/engine/control/first-person/collision/KinematicMover.d.ts +5 -9
  234. package/src/engine/control/first-person/collision/KinematicMover.d.ts.map +1 -1
  235. package/src/engine/control/first-person/collision/KinematicMover.js +59 -29
  236. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +2 -2
  237. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -1
  238. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +7 -7
  239. package/src/engine/ecs/EventType.js +10 -10
  240. package/src/engine/ecs/dynamic_actions/actions/definition/SendRequestActionDescription.d.ts.map +1 -1
  241. package/src/engine/ecs/dynamic_actions/actions/definition/SendRequestActionDescription.js +12 -4
  242. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +4 -4
  243. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
  244. package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +10 -11
  245. package/src/engine/ecs/grid/pick.js +1 -1
  246. package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.d.ts +1 -1
  247. package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +13 -13
  248. package/src/engine/ecs/gui/hud/testHudEdgeStick.js +3 -3
  249. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts +10 -10
  250. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts.map +1 -1
  251. package/src/engine/ecs/ik/InverseKinematicsSystem.js +8 -8
  252. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.d.ts.map +1 -1
  253. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +120 -97
  254. package/src/engine/ecs/ik/ik_bone_chain.d.ts +16 -5
  255. package/src/engine/ecs/ik/ik_bone_chain.d.ts.map +1 -1
  256. package/src/engine/ecs/ik/ik_bone_chain.js +16 -4
  257. package/src/engine/ecs/ik/ik_probe_terrain_contact.d.ts +7 -3
  258. package/src/engine/ecs/ik/ik_probe_terrain_contact.d.ts.map +1 -1
  259. package/src/engine/ecs/ik/ik_probe_terrain_contact.js +20 -16
  260. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +18 -0
  261. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -0
  262. package/src/engine/ecs/ik/ik_write_local_rotation.js +26 -0
  263. package/src/engine/ecs/parent/EntityNode.d.ts +24 -6
  264. package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
  265. package/src/engine/ecs/parent/EntityNode.js +49 -42
  266. package/src/engine/ecs/parent/EntityNodeFlags.d.ts +0 -1
  267. package/src/engine/ecs/parent/EntityNodeFlags.js +7 -8
  268. package/src/engine/ecs/speaker/VoiceSystem.d.ts +2 -2
  269. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  270. package/src/engine/ecs/speaker/VoiceSystem.js +4 -4
  271. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  272. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +2 -0
  273. package/src/engine/ecs/terrain/ecs/Terrain.d.ts +5 -2
  274. package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
  275. package/src/engine/ecs/terrain/ecs/Terrain.js +7 -4
  276. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +3 -3
  277. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts +7 -7
  278. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  279. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +360 -316
  280. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts +41 -0
  281. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts.map +1 -0
  282. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.js +40 -0
  283. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +521 -0
  284. package/src/engine/ecs/transform/Transform64.d.ts +48 -11
  285. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
  286. package/src/engine/ecs/transform/Transform64.js +54 -15
  287. package/src/engine/ecs/transform/Transform64SerializationAdapter.d.ts +37 -0
  288. package/src/engine/ecs/transform/Transform64SerializationAdapter.d.ts.map +1 -0
  289. package/src/engine/ecs/transform/Transform64SerializationAdapter.js +75 -0
  290. package/src/engine/ecs/transform/t64_allocation_probe.d.ts +31 -0
  291. package/src/engine/ecs/transform/t64_allocation_probe.d.ts.map +1 -0
  292. package/src/engine/ecs/transform/t64_allocation_probe.js +78 -0
  293. package/src/engine/ecs/transform/t64_announce_change.d.ts +36 -0
  294. package/src/engine/ecs/transform/t64_announce_change.d.ts.map +1 -0
  295. package/src/engine/ecs/transform/t64_announce_change.js +39 -0
  296. package/src/engine/ecs/transform/t64_equals_components.d.ts +30 -0
  297. package/src/engine/ecs/transform/t64_equals_components.d.ts.map +1 -0
  298. package/src/engine/ecs/transform/t64_equals_components.js +59 -0
  299. package/src/engine/ecs/transform/t64_read_rotation.d.ts +13 -0
  300. package/src/engine/ecs/transform/t64_read_rotation.d.ts.map +1 -0
  301. package/src/engine/ecs/transform/t64_read_rotation.js +16 -0
  302. package/src/engine/ecs/transform/t64_read_translation.d.ts +14 -0
  303. package/src/engine/ecs/transform/t64_read_translation.d.ts.map +1 -0
  304. package/src/engine/ecs/transform/t64_read_translation.js +17 -0
  305. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts +30 -0
  306. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts.map +1 -0
  307. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.js +29 -0
  308. package/src/engine/ecs/transform-attachment/TransformAttachment.d.ts +5 -5
  309. package/src/engine/ecs/transform-attachment/TransformAttachment.d.ts.map +1 -1
  310. package/src/engine/ecs/transform-attachment/TransformAttachment.js +4 -4
  311. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts +10 -10
  312. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  313. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +63 -20
  314. package/src/engine/graphics/debug/createDebugLabel.js +3 -3
  315. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.d.ts.map +1 -1
  316. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +5 -4
  317. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  318. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +8 -3
  319. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +6 -6
  320. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  321. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +25 -13
  322. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraLanderSystem.js +1 -1
  323. package/src/engine/graphics/ecs/mesh/setMesh.js +2 -2
  324. package/src/engine/graphics/ecs/path/entity/EntityPath.d.ts.map +1 -1
  325. package/src/engine/graphics/ecs/path/entity/EntityPath.js +21 -7
  326. package/src/engine/graphics/ecs/path/entity/EntityPathMarkerDefinition.d.ts +4 -4
  327. package/src/engine/graphics/ecs/path/entity/EntityPathMarkerDefinition.d.ts.map +1 -1
  328. package/src/engine/graphics/ecs/path/entity/EntityPathMarkerDefinition.js +4 -4
  329. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts +2 -2
  330. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  331. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +141 -135
  332. package/src/engine/graphics/geometry/MikkT/Build4RuleGroups.js +2 -2
  333. package/src/engine/graphics/geometry/MikkT/DegenEpilogue.js +1 -1
  334. package/src/engine/graphics/geometry/MikkT/DegenPrologue.js +1 -1
  335. package/src/engine/graphics/geometry/MikkT/EvalTspace.js +1 -1
  336. package/src/engine/graphics/geometry/MikkT/GenerateTSpaces.js +3 -3
  337. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +659 -0
  338. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +21 -5
  339. package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts +45 -0
  340. package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts.map +1 -1
  341. package/src/engine/graphics/render/frame_graph/FrameGraph.js +282 -60
  342. package/src/engine/graphics/render/frame_graph/FramePassBuilder.d.ts.map +1 -1
  343. package/src/engine/graphics/render/frame_graph/FramePassBuilder.js +20 -9
  344. package/src/engine/graphics/render/frame_graph/FramePassNode.d.ts +12 -0
  345. package/src/engine/graphics/render/frame_graph/FramePassNode.d.ts.map +1 -1
  346. package/src/engine/graphics/render/frame_graph/FramePassNode.js +13 -0
  347. package/src/engine/graphics/render/frame_graph/FramePassResources.d.ts.map +1 -1
  348. package/src/engine/graphics/render/frame_graph/FramePassResources.js +5 -0
  349. package/src/engine/graphics/render/frame_graph/ResourceEntry.d.ts +19 -1
  350. package/src/engine/graphics/render/frame_graph/ResourceEntry.d.ts.map +1 -1
  351. package/src/engine/graphics/render/frame_graph/ResourceEntry.js +23 -1
  352. package/src/engine/graphics/render/frame_graph/backend/void/VoidRenderContext.d.ts +15 -1
  353. package/src/engine/graphics/render/frame_graph/backend/void/VoidRenderContext.d.ts.map +1 -1
  354. package/src/engine/graphics/render/frame_graph/backend/void/VoidRenderContext.js +33 -16
  355. package/src/engine/graphics/render/frame_graph/resource/RenderResourceManager.d.ts.map +1 -1
  356. package/src/engine/graphics/render/frame_graph/resource/RenderResourceManager.js +19 -1
  357. package/src/engine/graphics/sh3/path_tracer/populate_path_traced_scene_from_ecd.js +6 -6
  358. package/src/engine/graphics3/CameraSystem.d.ts +6 -6
  359. package/src/engine/graphics3/CameraSystem.d.ts.map +1 -1
  360. package/src/engine/graphics3/CameraSystem.js +170 -170
  361. package/src/engine/graphics3/DecalSystem.d.ts +6 -6
  362. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  363. package/src/engine/graphics3/DecalSystem.js +449 -449
  364. package/src/engine/graphics3/LightSystem.d.ts +6 -6
  365. package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
  366. package/src/engine/graphics3/LightSystem.js +230 -221
  367. package/src/engine/graphics3/MeshSystem.d.ts +6 -6
  368. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  369. package/src/engine/graphics3/MeshSystem.js +43 -22
  370. package/src/engine/graphics3/ParticipatingMediaSystem.d.ts +20 -15
  371. package/src/engine/graphics3/ParticipatingMediaSystem.d.ts.map +1 -1
  372. package/src/engine/graphics3/ParticipatingMediaSystem.js +198 -184
  373. package/src/engine/graphics3/ParticleEmitterSystem.d.ts +6 -6
  374. package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
  375. package/src/engine/graphics3/ParticleEmitterSystem.js +306 -289
  376. package/src/engine/graphics3/PickingSystem.d.ts +6 -6
  377. package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
  378. package/src/engine/graphics3/PickingSystem.js +273 -273
  379. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -6
  380. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  381. package/src/engine/graphics3/ShadedGeometrySystem.js +174 -169
  382. package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -1
  383. package/src/engine/graphics3/TerrainSystem.js +565 -566
  384. package/src/engine/graphics3/Trail3DSystem.d.ts +6 -6
  385. package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -1
  386. package/src/engine/graphics3/Trail3DSystem.js +221 -221
  387. package/src/engine/graphics3/camera_sync_from_transform.d.ts +2 -2
  388. package/src/engine/graphics3/camera_sync_from_transform.d.ts.map +1 -1
  389. package/src/engine/graphics3/camera_sync_from_transform.js +2 -1
  390. package/src/engine/graphics3/debug/gizmo_view_from_camera.js +4 -4
  391. package/src/engine/graphics3/particles/GPUParticularRenderer.d.ts +6 -0
  392. package/src/engine/graphics3/particles/GPUParticularRenderer.d.ts.map +1 -1
  393. package/src/engine/graphics3/particles/GPUParticularRenderer.js +82 -53
  394. package/src/engine/graphics3/particles/particle_gpu_records.d.ts +12 -8
  395. package/src/engine/graphics3/particles/particle_gpu_records.d.ts.map +1 -1
  396. package/src/engine/graphics3/particles/particle_gpu_records.js +53 -45
  397. package/src/engine/graphics3/preview/make_model_preview_scene.js +1 -1
  398. package/src/engine/graphics3/shade_camera_projection_ray.js +4 -4
  399. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts.map +1 -1
  400. package/src/engine/graphics3/shade_node_to_entity_composition.js +88 -84
  401. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +7 -7
  402. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  403. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +8 -8
  404. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts +9 -8
  405. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
  406. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +25 -8
  407. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +2 -2
  408. package/src/engine/intelligence/behavior/ecs/OrbitingBehavior.d.ts.map +1 -1
  409. package/src/engine/intelligence/behavior/ecs/OrbitingBehavior.js +218 -204
  410. package/src/engine/intelligence/behavior/util/RotationBehavior.js +5 -5
  411. package/src/engine/intelligence/mcts/StateNode.js +1 -1
  412. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +7 -7
  413. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
  414. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -15
  415. package/src/engine/interpolation/pose_interpoland.d.ts +2 -2
  416. package/src/engine/interpolation/pose_interpoland.js +4 -4
  417. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts +4 -4
  418. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  419. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +39 -14
  420. package/src/engine/network/adapters/TransformReplicationAdapter.d.ts +7 -7
  421. package/src/engine/network/adapters/TransformReplicationAdapter.d.ts.map +1 -1
  422. package/src/engine/network/adapters/TransformReplicationAdapter.js +19 -20
  423. package/src/engine/network/replication/Replicator.d.ts +5 -3
  424. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  425. package/src/engine/network/replication/Replicator.js +65 -16
  426. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +3 -3
  427. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  428. package/src/engine/physics/ccd/linear_sweep.js +9 -3
  429. package/src/engine/physics/constraint/solve_constraints.js +10 -10
  430. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +8 -8
  431. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -1
  432. package/src/engine/physics/ecs/ColliderObserverSystem.js +6 -6
  433. package/src/engine/physics/ecs/PhysicsSystem.d.ts +22 -32
  434. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  435. package/src/engine/physics/ecs/PhysicsSystem.js +2334 -2310
  436. package/src/engine/physics/ecs/find_non_finite_physics_state.js +6 -6
  437. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +7 -7
  438. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts.map +1 -1
  439. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.js +16 -8
  440. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +4 -4
  441. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts.map +1 -1
  442. package/src/engine/physics/fluid/ecs/FluidSystem.js +6 -6
  443. package/src/engine/physics/fluid/ecs/WorkerFluidSystem.d.ts +2 -2
  444. package/src/engine/physics/fluid/ecs/WorkerFluidSystem.d.ts.map +1 -1
  445. package/src/engine/physics/fluid/ecs/WorkerFluidSystem.js +4 -4
  446. package/src/engine/physics/fluid/ecs/fluid_reanchor_field.js +7 -7
  447. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +4 -4
  448. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +7 -7
  449. package/src/engine/physics/inertia/world_inverse_inertia.js +1 -1
  450. package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
  451. package/src/engine/physics/integration/integrate_position.js +13 -12
  452. package/src/engine/physics/inverse_kinematics/fabrik/fabrik_solve.d.ts.map +1 -1
  453. package/src/engine/physics/inverse_kinematics/fabrik/fabrik_solve.js +23 -5
  454. package/src/engine/physics/narrowphase/compute_penetration.js +18 -14
  455. package/src/engine/physics/narrowphase/convex_convex_manifold.js +2 -2
  456. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +9 -9
  457. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  458. package/src/engine/physics/narrowphase/narrowphase_step.js +95 -68
  459. package/src/engine/physics/narrowphase/refine_ray_concave.js +1 -1
  460. package/src/engine/physics/narrowphase/refine_ray_hit.js +3 -3
  461. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  462. package/src/engine/physics/queries/overlap_shape.js +19 -7
  463. package/src/engine/physics/queries/raycast.js +3 -3
  464. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  465. package/src/engine/physics/queries/shape_cast.js +628 -620
  466. package/src/engine/physics/solver/solve_contacts.js +10 -10
  467. package/src/engine/physics/vehicle/RaycastVehicle.d.ts +6 -5
  468. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  469. package/src/engine/physics/vehicle/RaycastVehicle.js +10 -5
  470. package/src/engine/sound/ecs/SoundListenerSystem.d.ts +16 -4
  471. package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
  472. package/src/engine/sound/ecs/SoundListenerSystem.js +68 -11
  473. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +7 -7
  474. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -1
  475. package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +343 -338
  476. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts +2 -2
  477. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
  478. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +356 -345
  479. package/src/engine/sound/ecs/audio/SpatialAudioIndex.d.ts +23 -2
  480. package/src/engine/sound/ecs/audio/SpatialAudioIndex.d.ts.map +1 -1
  481. package/src/engine/sound/ecs/audio/SpatialAudioIndex.js +174 -140
  482. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts +6 -6
  483. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts.map +1 -1
  484. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.js +185 -184
  485. package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.js +1 -1
  486. package/src/engine/sound/simulation/core/AcousticRegionIndex.d.ts +2 -1
  487. package/src/engine/sound/simulation/core/AcousticRegionIndex.d.ts.map +1 -1
  488. package/src/engine/sound/simulation/core/AcousticRegionIndex.js +4 -3
  489. package/src/engine/sound/simulation/core/AcousticVolumeRegion.d.ts +3 -2
  490. package/src/engine/sound/simulation/core/AcousticVolumeRegion.d.ts.map +1 -1
  491. package/src/engine/sound/simulation/core/AcousticVolumeRegion.js +6 -4
  492. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts +6 -6
  493. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts.map +1 -1
  494. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +25 -6
  495. package/src/engine/sound/simulation/ecs/AcousticVolumeSystem.d.ts +7 -7
  496. package/src/engine/sound/simulation/ecs/AcousticVolumeSystem.d.ts.map +1 -1
  497. package/src/engine/sound/simulation/ecs/AcousticVolumeSystem.js +6 -6
  498. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  499. package/src/engine/sound/sopra/runtime/EventInstance.js +8 -2
  500. package/src/format/scene/gltf/gltf_component_type.d.ts.map +1 -1
  501. package/src/format/scene/gltf/gltf_component_type.js +3 -1
  502. package/src/format/texture/ktx2/ktx2_read.d.ts.map +1 -1
  503. package/src/format/texture/ktx2/ktx2_read.js +2 -1
  504. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
  505. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +8 -1
  506. package/src/generation/markers/GridCellActionPlaceMarker.d.ts +4 -4
  507. package/src/generation/markers/GridCellActionPlaceMarker.d.ts.map +1 -1
  508. package/src/generation/markers/GridCellActionPlaceMarker.js +16 -6
  509. package/src/generation/markers/MarkerNode.d.ts +3 -3
  510. package/src/generation/markers/MarkerNode.d.ts.map +1 -1
  511. package/src/generation/markers/MarkerNode.js +3 -3
  512. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.d.ts +4 -4
  513. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.d.ts.map +1 -1
  514. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +7 -7
  515. package/src/generation/markers/actions/MarkerNodeActionImaginary.d.ts.map +1 -1
  516. package/src/generation/markers/actions/MarkerNodeActionImaginary.js +20 -2
  517. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.js +1 -1
  518. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts.map +1 -1
  519. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.js +13 -3
  520. package/src/generation/markers/transform/MarkerNodeTransformRotateRandom.d.ts.map +1 -1
  521. package/src/generation/markers/transform/MarkerNodeTransformRotateRandom.js +11 -1
  522. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.d.ts.map +1 -1
  523. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.js +8 -4
  524. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts.map +1 -1
  525. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +13 -5
  526. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.d.ts.map +1 -1
  527. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.js +8 -2
  528. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.d.ts.map +1 -1
  529. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.js +16 -2
  530. package/src/shade/device/graph/BufferResourceDescriptor.d.ts.map +1 -1
  531. package/src/shade/device/graph/BufferResourceDescriptor.js +193 -184
  532. package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
  533. package/src/shade/device/graph/TextureResourceDescriptor.js +12 -0
  534. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  535. package/src/shade/device/mock/SoftwareGPUDevice.js +8 -0
  536. package/src/shade/playground/avboit/main.js +3 -3
  537. package/src/shade/playground/basis_textures/main.js +1 -1
  538. package/src/shade/playground/ground_seam/main.js +1 -1
  539. package/src/shade/playground/particle_editor/README.md +216 -0
  540. package/src/shade/playground/particle_editor/index.html +76 -0
  541. package/src/shade/playground/particle_editor/main.d.ts +2 -0
  542. package/src/shade/playground/particle_editor/main.d.ts.map +1 -0
  543. package/src/shade/playground/particle_editor/main.js +139 -0
  544. package/src/shade/playground/particle_system/README.md +92 -62
  545. package/src/shade/playground/particle_system/index.html +67 -21
  546. package/src/shade/playground/particle_system/main.js +247 -102
  547. package/src/shade/{renderer/particles → playground/particle_system}/particle_prototype.d.ts +21 -18
  548. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -0
  549. package/src/shade/{renderer/particles → playground/particle_system}/particle_prototype.js +196 -181
  550. package/src/shade/playground/particle_system/particle_scene.d.ts +136 -20
  551. package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -1
  552. package/src/shade/playground/particle_system/particle_scene.js +487 -670
  553. package/src/shade/playground/skinned_blas_refit/sweep_views.js +2 -2
  554. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.d.ts.map +1 -1
  555. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.js +2 -1
  556. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts.map +1 -1
  557. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.js +2 -1
  558. package/src/shade/playground/sponza_path_trace/main.js +1 -1
  559. package/src/shade/playground/volumetrics_froxel/main.js +917 -917
  560. package/src/shade/playground/volumetrics_froxel/measure.js +559 -559
  561. package/src/shade/renderer/Renderer.d.ts +28 -0
  562. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  563. package/src/shade/renderer/Renderer.js +152 -8
  564. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  565. package/src/shade/renderer/atmosphere/GPUSky.js +4 -2
  566. package/src/shade/renderer/buffer/graph_read_buffer.d.ts.map +1 -1
  567. package/src/shade/renderer/buffer/graph_read_buffer.js +8 -1
  568. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  569. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts +30 -0
  570. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts.map +1 -1
  571. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.js +84 -0
  572. package/src/shade/renderer/buffer/table/gpu_database_words.d.ts +24 -0
  573. package/src/shade/renderer/buffer/table/gpu_database_words.d.ts.map +1 -0
  574. package/src/shade/renderer/buffer/table/gpu_database_words.js +92 -0
  575. package/src/shade/renderer/camera/Camera.d.ts +2 -2
  576. package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
  577. package/src/shade/renderer/camera/Camera.js +11 -5
  578. package/src/shade/renderer/camera/GPUCameraContext.d.ts.map +1 -1
  579. package/src/shade/renderer/camera/GPUCameraContext.js +2 -1
  580. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +3 -3
  581. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
  582. package/src/shade/renderer/camera/OrbitalCameraController.js +31 -16
  583. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +2 -2
  584. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  585. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +4 -3
  586. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +10 -5
  587. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +1 -1
  588. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +8 -4
  589. package/src/shade/renderer/extension/FrameContext.d.ts.map +1 -1
  590. package/src/shade/renderer/extension/FrameContext.js +5 -0
  591. package/src/shade/renderer/extension/FrameRecord.d.ts +16 -0
  592. package/src/shade/renderer/extension/FrameRecord.d.ts.map +1 -1
  593. package/src/shade/renderer/extension/FrameRecord.js +31 -0
  594. package/src/shade/renderer/extension/GBufferTextures.d.ts +11 -0
  595. package/src/shade/renderer/extension/GBufferTextures.d.ts.map +1 -1
  596. package/src/shade/renderer/extension/GBufferTextures.js +14 -0
  597. package/src/shade/renderer/geometry/attribute/gpu_vertex_buffer_layout_from_spec.js +1 -1
  598. package/src/shade/renderer/geometry/util/geometry_stripify.js +6 -6
  599. package/src/shade/renderer/geometry/virtual/format/prototypeVGEOFormatViewer.js +8 -8
  600. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts.map +1 -1
  601. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.js +14 -5
  602. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
  603. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +17 -9
  604. package/src/shade/renderer/global_illumination/probe/octahedral/border/graph_lpv_paint_border_depth.d.ts +2 -1
  605. package/src/shade/renderer/global_illumination/probe/octahedral/border/graph_lpv_paint_border_depth.d.ts.map +1 -1
  606. package/src/shade/renderer/global_illumination/probe/octahedral/border/graph_lpv_paint_border_depth.js +4 -1
  607. package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.d.ts +2 -1
  608. package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.d.ts.map +1 -1
  609. package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.js +11 -1
  610. package/src/shade/renderer/global_illumination/probe/octahedral/graph_lpv_shade.d.ts +1 -1
  611. package/src/shade/renderer/global_illumination/probe/octahedral/graph_lpv_shade.d.ts.map +1 -1
  612. package/src/shade/renderer/global_illumination/probe/octahedral/graph_lpv_shade.js +4 -2
  613. package/src/shade/renderer/global_illumination/sharc/SpatialHashRadianceCache.d.ts.map +1 -1
  614. package/src/shade/renderer/global_illumination/sharc/SpatialHashRadianceCache.js +5 -1
  615. package/src/shade/renderer/light/cluster/cull/graph_cull_lights.d.ts.map +1 -1
  616. package/src/shade/renderer/light/cluster/cull/graph_cull_lights.js +35 -11
  617. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  618. package/src/shade/renderer/particles/DESIGN.md +361 -117
  619. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +266 -87
  620. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  621. package/src/shade/renderer/particles/GPUParticleSystem.js +919 -145
  622. package/src/shade/renderer/particles/ParticleConstants.d.ts +134 -5
  623. package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
  624. package/src/shade/renderer/particles/ParticleConstants.js +148 -6
  625. package/src/shade/renderer/particles/ParticleRenderMode.d.ts +19 -0
  626. package/src/shade/renderer/particles/ParticleRenderMode.d.ts.map +1 -0
  627. package/src/shade/renderer/particles/ParticleRenderMode.js +33 -0
  628. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +5 -4
  629. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  630. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +11 -15
  631. package/src/shade/renderer/particles/coherence/shader_particle_bucket.d.ts +2 -2
  632. package/src/shade/renderer/particles/coherence/shader_particle_bucket.d.ts.map +1 -1
  633. package/src/shade/renderer/particles/coherence/shader_particle_bucket.js +20 -15
  634. package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts +7 -8
  635. package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts.map +1 -1
  636. package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.js +7 -17
  637. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts +56 -0
  638. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts.map +1 -0
  639. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.js +68 -0
  640. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.d.ts +39 -0
  641. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.d.ts.map +1 -0
  642. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.js +52 -0
  643. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts +83 -0
  644. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -0
  645. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +167 -0
  646. package/src/shade/renderer/particles/data/chunk_particle_emitter.d.ts +21 -5
  647. package/src/shade/renderer/particles/data/chunk_particle_emitter.d.ts.map +1 -1
  648. package/src/shade/renderer/particles/data/chunk_particle_emitter.js +44 -85
  649. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts +37 -0
  650. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -0
  651. package/src/shade/renderer/particles/data/particle_emitter_record.js +109 -0
  652. package/src/shade/renderer/particles/data/particle_header.d.ts +62 -0
  653. package/src/shade/renderer/particles/data/particle_header.d.ts.map +1 -0
  654. package/src/shade/renderer/particles/data/particle_header.js +103 -0
  655. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +179 -0
  656. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts.map +1 -0
  657. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +303 -0
  658. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +138 -1
  659. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
  660. package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +152 -44
  661. package/src/shade/renderer/particles/graph/ParticleNodeGroup.d.ts +283 -0
  662. package/src/shade/renderer/particles/graph/ParticleNodeGroup.d.ts.map +1 -0
  663. package/src/shade/renderer/particles/graph/ParticleNodeGroup.js +419 -0
  664. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +33 -2
  665. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
  666. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +720 -185
  667. package/src/shade/renderer/particles/graph/ParticleValueType.d.ts +188 -0
  668. package/src/shade/renderer/particles/graph/ParticleValueType.d.ts.map +1 -0
  669. package/src/shade/renderer/particles/graph/ParticleValueType.js +287 -0
  670. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts +16 -9
  671. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
  672. package/src/shade/renderer/particles/graph/compile_particle_graph.js +469 -205
  673. package/src/shade/renderer/particles/graph/flatten_particle_graph.d.ts +11 -0
  674. package/src/shade/renderer/particles/graph/flatten_particle_graph.d.ts.map +1 -0
  675. package/src/shade/renderer/particles/graph/flatten_particle_graph.js +244 -0
  676. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts +27 -0
  677. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -0
  678. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +81 -0
  679. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts +83 -0
  680. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -0
  681. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +294 -0
  682. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.d.ts +22 -0
  683. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.d.ts.map +1 -0
  684. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.js +524 -0
  685. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts +22 -0
  686. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts.map +1 -0
  687. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.js +517 -0
  688. package/src/shade/renderer/particles/graph/groups/particle_groups_utility.d.ts +70 -0
  689. package/src/shade/renderer/particles/graph/groups/particle_groups_utility.d.ts.map +1 -0
  690. package/src/shade/renderer/particles/graph/groups/particle_groups_utility.js +161 -0
  691. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts +8 -0
  692. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -0
  693. package/src/shade/renderer/particles/graph/groups/simplex_reference.js +185 -0
  694. package/src/shade/renderer/particles/graph/infer_particle_graph_types.d.ts +88 -0
  695. package/src/shade/renderer/particles/graph/infer_particle_graph_types.d.ts.map +1 -0
  696. package/src/shade/renderer/particles/graph/infer_particle_graph_types.js +234 -0
  697. package/src/shade/renderer/particles/graph/make_particle_group.d.ts +98 -0
  698. package/src/shade/renderer/particles/graph/make_particle_group.d.ts.map +1 -0
  699. package/src/shade/renderer/particles/graph/make_particle_group.js +409 -0
  700. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts +17 -0
  701. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts.map +1 -0
  702. package/src/shade/renderer/particles/graph/particle_compare_ops.js +22 -0
  703. package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts +11 -4
  704. package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts.map +1 -1
  705. package/src/shade/renderer/particles/graph/particle_graph_authoring.js +121 -108
  706. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts +58 -0
  707. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts.map +1 -0
  708. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.js +49 -0
  709. package/src/shade/renderer/particles/graph/particle_graph_distributions.d.ts +29 -0
  710. package/src/shade/renderer/particles/graph/particle_graph_distributions.d.ts.map +1 -0
  711. package/src/shade/renderer/particles/graph/particle_graph_distributions.js +170 -0
  712. package/src/shade/renderer/particles/graph/particle_graph_json.d.ts +87 -0
  713. package/src/shade/renderer/particles/graph/particle_graph_json.d.ts.map +1 -0
  714. package/src/shade/renderer/particles/graph/particle_graph_json.js +196 -0
  715. package/src/shade/renderer/particles/graph/particle_group_json.d.ts +86 -0
  716. package/src/shade/renderer/particles/graph/particle_group_json.d.ts.map +1 -0
  717. package/src/shade/renderer/particles/graph/particle_group_json.js +182 -0
  718. package/src/shade/renderer/particles/graph/particle_group_library.d.ts +33 -0
  719. package/src/shade/renderer/particles/graph/particle_group_library.d.ts.map +1 -0
  720. package/src/shade/renderer/particles/graph/particle_group_library.js +75 -0
  721. package/src/shade/renderer/particles/graph/particle_node_library.d.ts +37 -0
  722. package/src/shade/renderer/particles/graph/particle_node_library.d.ts.map +1 -0
  723. package/src/shade/renderer/particles/graph/particle_node_library.js +64 -0
  724. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +186 -0
  725. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -0
  726. package/src/shade/renderer/particles/graph/particle_node_parameters.js +312 -0
  727. package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts +30 -0
  728. package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -0
  729. package/src/shade/renderer/particles/graph/particle_node_presentation.js +342 -0
  730. package/src/shade/renderer/particles/graph/particle_ramp.d.ts +230 -0
  731. package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -0
  732. package/src/shade/renderer/particles/graph/particle_ramp.js +403 -0
  733. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +72 -0
  734. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -0
  735. package/src/shade/renderer/particles/graph/validate_particle_graph.js +495 -0
  736. package/src/shade/renderer/particles/graph_particles.d.ts +98 -69
  737. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  738. package/src/shade/renderer/particles/graph_particles.js +277 -81
  739. package/src/shade/renderer/particles/graph_particles_avboit.d.ts +107 -0
  740. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -0
  741. package/src/shade/renderer/particles/graph_particles_avboit.js +313 -0
  742. package/src/shade/renderer/particles/graph_particles_billboard.d.ts +37 -0
  743. package/src/shade/renderer/particles/graph_particles_billboard.d.ts.map +1 -0
  744. package/src/shade/renderer/particles/graph_particles_billboard.js +93 -0
  745. package/src/shade/renderer/particles/isa/InstructionStream.d.ts +83 -21
  746. package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
  747. package/src/shade/renderer/particles/isa/InstructionStream.js +186 -48
  748. package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts +13 -10
  749. package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts.map +1 -1
  750. package/src/shade/renderer/particles/isa/ParticleAssembler.js +30 -26
  751. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +74 -21
  752. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
  753. package/src/shade/renderer/particles/isa/ParticleProgram.js +131 -81
  754. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +372 -22
  755. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  756. package/src/shade/renderer/particles/isa/ParticleVMISA.js +694 -66
  757. package/src/shade/renderer/particles/isa/particle_assembly.d.ts +173 -0
  758. package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -0
  759. package/src/shade/renderer/particles/isa/particle_assembly.js +1214 -0
  760. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts +9 -0
  761. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts.map +1 -0
  762. package/src/shade/renderer/particles/isa/validate_particle_program.js +128 -0
  763. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +48 -3
  764. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
  765. package/src/shade/renderer/particles/layout/ParticleLayout.js +101 -5
  766. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts +77 -0
  767. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -0
  768. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +219 -0
  769. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts +83 -0
  770. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -0
  771. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +283 -0
  772. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +133 -0
  773. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts.map +1 -0
  774. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +334 -0
  775. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts +117 -0
  776. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts.map +1 -0
  777. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +70 -0
  778. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts +97 -0
  779. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts.map +1 -0
  780. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +462 -0
  781. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts +116 -0
  782. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts.map +1 -0
  783. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +687 -0
  784. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +57 -0
  785. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts.map +1 -0
  786. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +860 -0
  787. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts +115 -0
  788. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts.map +1 -0
  789. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.js +264 -0
  790. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +199 -0
  791. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -0
  792. package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +477 -0
  793. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +100 -0
  794. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts.map +1 -0
  795. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +236 -0
  796. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +371 -0
  797. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -0
  798. package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +764 -0
  799. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +128 -0
  800. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -0
  801. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +376 -0
  802. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts +43 -0
  803. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -0
  804. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +337 -0
  805. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +107 -0
  806. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -0
  807. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +166 -0
  808. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts +99 -0
  809. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -0
  810. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +313 -0
  811. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts +12 -0
  812. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -0
  813. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.js +198 -0
  814. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts +4 -0
  815. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -0
  816. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.js +51 -0
  817. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts +23 -0
  818. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -0
  819. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +678 -0
  820. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts +22 -0
  821. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -0
  822. package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +221 -0
  823. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts +4 -0
  824. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -0
  825. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +63 -0
  826. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts +4 -0
  827. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -0
  828. package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +87 -0
  829. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts +4 -0
  830. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -0
  831. package/src/shade/renderer/particles/optimizer/pass_peephole.js +392 -0
  832. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts +4 -0
  833. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -0
  834. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +361 -0
  835. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts +4 -0
  836. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -0
  837. package/src/shade/renderer/particles/optimizer/pass_schedule.js +244 -0
  838. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts +4 -0
  839. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -0
  840. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +154 -0
  841. package/src/shade/renderer/particles/particle_test_fixtures.d.ts +151 -0
  842. package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +1 -0
  843. package/src/shade/renderer/particles/particle_test_fixtures.js +229 -0
  844. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +206 -64
  845. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  846. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +404 -83
  847. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +109 -0
  848. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -0
  849. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +127 -0
  850. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +249 -0
  851. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -0
  852. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +425 -0
  853. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts +77 -18
  854. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts.map +1 -1
  855. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +130 -0
  856. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -0
  857. package/src/shade/renderer/particles/runtime/ProgramHeap.js +595 -0
  858. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts +91 -0
  859. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts.map +1 -0
  860. package/src/shade/renderer/particles/runtime/ProgramPlacement.js +106 -0
  861. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +9 -6
  862. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
  863. package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -19
  864. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts +17 -0
  865. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts.map +1 -0
  866. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js +75 -0
  867. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.d.ts +20 -0
  868. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.d.ts.map +1 -0
  869. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.js +94 -0
  870. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts +1 -2
  871. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts.map +1 -1
  872. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js +1 -2
  873. package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.d.ts +11 -0
  874. package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.d.ts.map +1 -0
  875. package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.js +13 -0
  876. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts +28 -0
  877. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts.map +1 -0
  878. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.js +136 -0
  879. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_age.d.ts +17 -0
  880. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_age.d.ts.map +1 -0
  881. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_age.js +22 -0
  882. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.d.ts +14 -0
  883. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.d.ts.map +1 -0
  884. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.js +23 -0
  885. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +1 -1
  886. package/src/shade/renderer/particles/shaders/chunk_particle_scene_view_depth.d.ts +18 -0
  887. package/src/shade/renderer/particles/shaders/chunk_particle_scene_view_depth.d.ts.map +1 -0
  888. package/src/shade/renderer/particles/shaders/chunk_particle_scene_view_depth.js +24 -0
  889. package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.d.ts +26 -0
  890. package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.d.ts.map +1 -0
  891. package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.js +59 -0
  892. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts +35 -0
  893. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts.map +1 -0
  894. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.js +133 -0
  895. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts +14 -0
  896. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -0
  897. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +153 -0
  898. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.d.ts +3 -0
  899. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.d.ts.map +1 -0
  900. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.js +124 -0
  901. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts +19 -0
  902. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -0
  903. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +147 -0
  904. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts +27 -8
  905. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  906. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +43 -68
  907. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts +33 -0
  908. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -0
  909. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +114 -0
  910. package/src/shade/renderer/particles/shaders/shader_particle_emitter_tick.d.ts +5 -0
  911. package/src/shade/renderer/particles/shaders/shader_particle_emitter_tick.d.ts.map +1 -0
  912. package/src/shade/renderer/particles/shaders/shader_particle_emitter_tick.js +216 -0
  913. package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
  914. package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +7 -3
  915. package/src/shade/renderer/particles/shaders/shader_particle_render.d.ts.map +1 -1
  916. package/src/shade/renderer/particles/shaders/shader_particle_render.js +132 -197
  917. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts +8 -0
  918. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  919. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +42 -56
  920. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts +45 -0
  921. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -0
  922. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +123 -0
  923. package/src/shade/renderer/particles/shaders/shader_particle_spawn_commands.d.ts +26 -0
  924. package/src/shade/renderer/particles/shaders/shader_particle_spawn_commands.d.ts.map +1 -0
  925. package/src/shade/renderer/particles/shaders/shader_particle_spawn_commands.js +66 -0
  926. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts +51 -0
  927. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts.map +1 -0
  928. package/src/shade/renderer/particles/sort/graph_particle_sort.js +120 -0
  929. package/src/shade/renderer/particles/sort/shader_particle_sort.d.ts +1 -1
  930. package/src/shade/renderer/particles/sort/shader_particle_sort.d.ts.map +1 -1
  931. package/src/shade/renderer/particles/sort/shader_particle_sort.js +21 -36
  932. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts +6 -0
  933. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -0
  934. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +16 -0
  935. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +6 -3
  936. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  937. package/src/shade/renderer/particles/vm/ParticleVMReference.js +285 -154
  938. package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
  939. package/src/shade/renderer/particles/vm/chunk_particle_vm.js +264 -170
  940. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts +43 -0
  941. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts.map +1 -0
  942. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.js +55 -0
  943. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts +62 -0
  944. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts.map +1 -0
  945. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.js +86 -0
  946. package/src/shade/renderer/postprocess/denoise/debug/graph_pass_debug_reprojection.d.ts +1 -2
  947. package/src/shade/renderer/postprocess/denoise/debug/graph_pass_debug_reprojection.d.ts.map +1 -1
  948. package/src/shade/renderer/postprocess/denoise/debug/graph_pass_debug_reprojection.js +0 -3
  949. package/src/shade/renderer/postprocess/dof/gather/DepthOfFieldU.js +1 -1
  950. package/src/shade/renderer/postprocess/dof/raymarch/DepthOfField.js +1 -1
  951. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  952. package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
  953. package/src/shade/renderer/postprocess/nss/NSS.js +3 -2
  954. package/src/shade/renderer/postprocess/nss/generate_NSS_WEIGHTS_ACTUAL.js +3 -2
  955. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +87 -0
  956. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -0
  957. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +61 -0
  958. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +179 -0
  959. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +27 -2
  960. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.d.ts +9 -2
  961. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.d.ts.map +1 -1
  962. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +12 -3
  963. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.d.ts +18 -0
  964. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.d.ts.map +1 -0
  965. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +58 -0
  966. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +25 -1
  967. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  968. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +69 -10
  969. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.d.ts.map +1 -1
  970. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js +10 -4
  971. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts.map +1 -1
  972. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +4 -39
  973. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts +7 -2
  974. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  975. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +16 -2
  976. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.d.ts +3 -3
  977. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.d.ts.map +1 -1
  978. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.js +29 -23
  979. package/src/shade/renderer/scene/optimization/geometry/internal/anchor_grow_topological.d.ts +2 -2
  980. package/src/shade/renderer/scene/optimization/geometry/internal/anchor_grow_topological.d.ts.map +1 -1
  981. package/src/shade/renderer/scene/optimization/geometry/internal/anchor_grow_topological.js +3 -3
  982. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.d.ts +4 -4
  983. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.d.ts.map +1 -1
  984. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.js +2 -2
  985. package/src/shade/renderer/scene/optimization/geometry/internal/match_refit_validate.d.ts +2 -2
  986. package/src/shade/renderer/scene/optimization/geometry/internal/match_refit_validate.d.ts.map +1 -1
  987. package/src/shade/renderer/scene/optimization/geometry/internal/match_refit_validate.js +2 -2
  988. package/src/shade/renderer/scene/optimization/geometry/internal/match_solve_transform.d.ts +7 -7
  989. package/src/shade/renderer/scene/optimization/geometry/internal/match_solve_transform.d.ts.map +1 -1
  990. package/src/shade/renderer/scene/optimization/geometry/internal/match_solve_transform.js +79 -71
  991. package/src/shade/renderer/shader/chunk/math/chunk_lower_bound_branchless.d.ts.map +1 -1
  992. package/src/shade/renderer/shader/chunk/math/chunk_lower_bound_branchless.js +3 -1
  993. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts +22 -0
  994. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts.map +1 -0
  995. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.js +32 -0
  996. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts +9 -0
  997. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts.map +1 -0
  998. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.js +19 -0
  999. package/src/shade/renderer/shader/chunk/noise/psrdnoise/README.md +65 -0
  1000. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts +24 -0
  1001. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts.map +1 -0
  1002. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.js +83 -0
  1003. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts +25 -0
  1004. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts.map +1 -0
  1005. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.js +42 -0
  1006. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts +31 -0
  1007. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts.map +1 -0
  1008. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.js +80 -0
  1009. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts +26 -0
  1010. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts.map +1 -0
  1011. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.js +109 -0
  1012. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts +38 -0
  1013. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts.map +1 -0
  1014. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.js +129 -0
  1015. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts +21 -0
  1016. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts.map +1 -0
  1017. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.js +35 -0
  1018. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts +19 -0
  1019. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts.map +1 -0
  1020. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.js +28 -0
  1021. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts +13 -0
  1022. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts.map +1 -0
  1023. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.js +22 -0
  1024. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts +22 -0
  1025. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts.map +1 -0
  1026. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.js +59 -0
  1027. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts +23 -0
  1028. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts.map +1 -0
  1029. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.js +74 -0
  1030. package/src/shade/renderer/shader/chunk/random/chunk_hash_to_float01.d.ts +13 -3
  1031. package/src/shade/renderer/shader/chunk/random/chunk_hash_to_float01.d.ts.map +1 -1
  1032. package/src/shade/renderer/shader/chunk/random/chunk_hash_to_float01.js +15 -5
  1033. package/src/shade/renderer/shader/chunk/random/chunk_random_uint.d.ts +8 -0
  1034. package/src/shade/renderer/shader/chunk/random/chunk_random_uint.d.ts.map +1 -1
  1035. package/src/shade/renderer/shader/chunk/random/chunk_random_uint.js +15 -5
  1036. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg.d.ts +7 -0
  1037. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg.d.ts.map +1 -1
  1038. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg.js +17 -7
  1039. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg_advance.d.ts +17 -0
  1040. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg_advance.d.ts.map +1 -0
  1041. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg_advance.js +26 -0
  1042. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg_output.d.ts +15 -0
  1043. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg_output.d.ts.map +1 -0
  1044. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg_output.js +26 -0
  1045. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
  1046. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +8 -2
  1047. package/src/shade/renderer/shadow/map/PointLightShadowmap.d.ts.map +1 -1
  1048. package/src/shade/renderer/shadow/map/PointLightShadowmap.js +7 -2
  1049. package/src/shade/renderer/shadow/map/SpotLightShadowmap.d.ts.map +1 -1
  1050. package/src/shade/renderer/shadow/map/SpotLightShadowmap.js +3 -15
  1051. package/src/shade/renderer/shadow/map/TetrahedronPointLightShadowmap.d.ts.map +1 -1
  1052. package/src/shade/renderer/shadow/map/TetrahedronPointLightShadowmap.js +10 -4
  1053. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts.map +1 -1
  1054. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.js +7 -2
  1055. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +2 -2
  1056. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts +3 -3
  1057. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts.map +1 -1
  1058. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.js +3 -3
  1059. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts +34 -1
  1060. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts.map +1 -1
  1061. package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +41 -1
  1062. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -2
  1063. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  1064. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +115 -15
  1065. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  1066. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +35 -4
  1067. package/src/view/minimap/Minimap.d.ts.map +1 -1
  1068. package/src/view/minimap/Minimap.js +227 -225
  1069. package/src/view/minimap/MinimapCanvasView.js +3 -3
  1070. package/src/view/minimap/MinimapMarker.d.ts +45 -0
  1071. package/src/view/minimap/MinimapMarker.d.ts.map +1 -0
  1072. package/src/view/minimap/MinimapMarker.js +80 -0
  1073. package/src/view/minimap/MinimapMarkerCollection.d.ts +6 -5
  1074. package/src/view/minimap/MinimapMarkerCollection.d.ts.map +1 -1
  1075. package/src/view/minimap/MinimapMarkerCollection.js +6 -6
  1076. package/src/view/minimap/MinimapMarkerSerializationAdapter.d.ts +19 -0
  1077. package/src/view/minimap/MinimapMarkerSerializationAdapter.d.ts.map +1 -0
  1078. package/src/view/minimap/MinimapMarkerSerializationAdapter.js +42 -0
  1079. package/src/view/minimap/dom/MinimapCameraView.d.ts +1 -1
  1080. package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
  1081. package/src/view/minimap/dom/MinimapCameraView.js +18 -4
  1082. package/src/view/minimap/dom/MinimapMarkerView.js +3 -3
  1083. package/src/view/minimap/gl/MarkerGL.js +3 -3
  1084. package/src/view/util/DomLayoutFrame.d.ts +53 -0
  1085. package/src/view/util/DomLayoutFrame.d.ts.map +1 -0
  1086. package/src/view/util/DomLayoutFrame.js +122 -0
  1087. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts +0 -15
  1088. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts.map +0 -1
  1089. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.js +0 -19
  1090. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts +0 -45
  1091. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts.map +0 -1
  1092. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.js +0 -241
  1093. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts +0 -24
  1094. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts.map +0 -1
  1095. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.js +0 -40
  1096. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts +0 -19
  1097. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts.map +0 -1
  1098. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.js +0 -28
  1099. package/src/engine/ecs/util/hideEntityGracefully.d.ts +0 -9
  1100. package/src/engine/ecs/util/hideEntityGracefully.d.ts.map +0 -1
  1101. package/src/engine/ecs/util/hideEntityGracefully.js +0 -196
  1102. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts +0 -14
  1103. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +0 -1
  1104. package/src/shade/renderer/particles/cull/chunk_particle_cull.js +0 -38
  1105. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts +0 -156
  1106. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts.map +0 -1
  1107. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.js +0 -214
  1108. package/src/shade/renderer/particles/particle_prototype.d.ts.map +0 -1
  1109. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts +0 -43
  1110. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts.map +0 -1
  1111. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.js +0 -86
  1112. package/src/shade/renderer/particles/runtime/ProgramArena.js +0 -115
  1113. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts +0 -34
  1114. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts.map +0 -1
  1115. package/src/shade/renderer/particles/runtime/spawn_request_encoding.js +0 -52
  1116. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts +0 -22
  1117. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts.map +0 -1
  1118. package/src/shade/renderer/particles/shaders/chunk_particle_context.js +0 -58
@@ -0,0 +1,1666 @@
1
+ import { Color } from "../../../../src/core/color/Color.js";
2
+ import { PortDirection } from "../../../../src/core/model/node-graph/node/PortDirection.js";
3
+ import { ActionProcessor } from "../../../../src/core/process/undo/ActionProcessor.js";
4
+ import { infer_particle_graph_types } from "../../../../src/shade/renderer/particles/graph/infer_particle_graph_types.js";
5
+ import { particle_group_from_nodes } from "../../../../src/shade/renderer/particles/graph/make_particle_group.js";
6
+ import {
7
+ PARTICLE_GRAPH_ERROR,
8
+ PARTICLE_GRAPH_INFO,
9
+ PARTICLE_GRAPH_SEVERITY_RANK,
10
+ PARTICLE_GRAPH_WARNING,
11
+ } from "../../../../src/shade/renderer/particles/graph/particle_graph_diagnostic.js";
12
+ import {
13
+ particle_group_descriptions,
14
+ } from "../../../../src/shade/renderer/particles/graph/particle_group_json.js";
15
+ import {
16
+ is_particle_group_boundary,
17
+ is_particle_group_description,
18
+ } from "../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js";
19
+ import {
20
+ clone_particle_parameters,
21
+ particle_node_default_parameters,
22
+ particle_node_parameters,
23
+ } from "../../../../src/shade/renderer/particles/graph/particle_node_parameters.js";
24
+ import {
25
+ PARTICLE_NODE_REGISTRY,
26
+ PARTICLE_VALUE_TYPE,
27
+ } from "../../../../src/shade/renderer/particles/graph/ParticleNodeRegistry.js";
28
+ import {
29
+ particle_library_descriptions,
30
+ } from "../../../../src/shade/renderer/particles/graph/particle_node_library.js";
31
+ import {
32
+ PARTICLE_TYPE_COLOR,
33
+ PARTICLE_TYPE_F32,
34
+ PARTICLE_TYPE_VEC2,
35
+ PARTICLE_TYPE_VEC3,
36
+ PARTICLE_TYPE_VEC4,
37
+ } from "../../../../src/shade/renderer/particles/graph/ParticleValueType.js";
38
+ import KeyboardDevice from "../../../../src/engine/input/devices/KeyboardDevice.js";
39
+ import { KeyCodes } from "../../../../src/engine/input/devices/KeyCodes.js";
40
+ import LabelView from "../../../../src/view/common/LabelView.js";
41
+ import EmptyView from "../../../../src/view/elements/EmptyView.js";
42
+ import View from "../../../../src/view/View.js";
43
+ import { NodeGraphCamera } from "../../node-graph/NodeGraphCamera.js";
44
+ import { NodeGraphClipboard } from "../../node-graph/NodeGraphClipboard.js";
45
+ import { NodeGraphEditorView } from "../../node-graph/NodeGraphEditorView.js";
46
+ import { NodeCreateAction } from "../../node-graph/actions/NodeCreateAction.js";
47
+ import { NodeDeleteAction } from "../../node-graph/actions/NodeDeleteAction.js";
48
+ import { ConnectionCreateAction } from "../../node-graph/actions/ConnectionCreateAction.js";
49
+ import { NodesMoveAction } from "../../node-graph/actions/NodesMoveAction.js";
50
+ import { SelectionSetAction } from "../../node-graph/actions/SelectionSetAction.js";
51
+ import { ParticleGroupDefineAction } from "../../../particles/effect/actions/ParticleGroupDefineAction.js";
52
+ import { ParticleNodeParametersView } from "./ParticleNodeParametersView.js";
53
+
54
+ /**
55
+ * The graph layer of the particle editor: the two phases of an effect's simulation, authored as
56
+ * node graphs.
57
+ *
58
+ * Built *with* the node-graph editor rather than in it. Everything particle-specific arrives
59
+ * through the seams the base offers — the node library the canvas's add-node menu offers, a
60
+ * parameter-view factory that draws vector, enum, attribute and swizzle controls, the one rule the
61
+ * clipboard needs (a group's boundary blocks are not something there can be a second of), and a
62
+ * problems list fed by the document's own compile. The base is left knowing nothing about particles.
63
+ *
64
+ * ## Adding a node
65
+ *
66
+ * On the canvas, where the node is going. Right-click and the library opens under the cursor with
67
+ * the caret in a search field; type a few letters and press Enter and the node lands at the point
68
+ * that was clicked. Drop a wire on open canvas and the same menu opens, narrowed to the types that
69
+ * have a port to take it, and picking one wires it up as it arrives.
70
+ *
71
+ * There is no palette down the side any more. It was a fine list and a bad way to add a node: every
72
+ * node cost a trip to the edge of the window and back, and the node arrived in the middle of the
73
+ * view rather than where it was wanted.
74
+ *
75
+ * ## Groups
76
+ *
77
+ * A {@link ../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js group} is a node made
78
+ * of nodes, and double-clicking one opens it: the canvas shows the group's own graph and the toolbar
79
+ * grows a breadcrumb back out. Groups nest, so the breadcrumb does. The groups shipped with the
80
+ * editor are locked — one body shared by every instance in every effect — and open read-only.
81
+ *
82
+ * ## Two phases, two graphs
83
+ *
84
+ * INIT runs once when a particle is spawned, UPDATE once per frame per live particle. They are
85
+ * separate graphs with separate cameras and separate selections, and switching between them is a
86
+ * matter of which one is visible — both stay built, so a phase comes back exactly where it was
87
+ * rather than reset to the origin.
88
+ *
89
+ * ## What is undoable
90
+ *
91
+ * Everything that touches a graph, through the {@link ActionProcessor} the host supplies. Adding a
92
+ * node from the menu, wiring, moving, deleting, pasting, and every parameter edit inside a node all
93
+ * land on one timeline, so a host editor's global undo covers particle authoring without knowing it
94
+ * exists.
95
+ */
96
+
97
+ /** Height of the phase / action toolbar, px. @type {number} */
98
+ const TOOLBAR_HEIGHT = 32;
99
+
100
+ /** Height of the problems strip along the bottom, px. @type {number} */
101
+ const PROBLEMS_HEIGHT = 96;
102
+
103
+ /**
104
+ * One colour per type a value can have, and one for a port whose value is not known — nothing
105
+ * wired into it yet, or a parameter that does not describe a width.
106
+ *
107
+ * Every port in the library is declared with the one value type; which value it carries is
108
+ * resolved per node by `infer_particle_graph_types`, and that is what a port is coloured by and a
109
+ * wire drawn in. A wire meeting a port of another colour is a conversion, which is the point: a
110
+ * `vec4` literal feeding a `vec3` add shows as a pink wire into an amber port.
111
+ *
112
+ * Unresolved is registered rather than left to the default because the default exists for a type
113
+ * nobody has thought about, and this one has been.
114
+ *
115
+ * A colour is a `vec4` and gets a colour of its own anyway. Nothing is converted where the two
116
+ * meet — they are the same four lanes — so the change of hue along a wire is not a warning about
117
+ * anything; it is where a raw vector starts being used as a colour, or a colour stops being one,
118
+ * which is the thing a semantic type exists to make visible.
119
+ *
120
+ * @type {Map<number, Color>} data type id -> colour
121
+ */
122
+ const PARTICLE_TYPE_COLORS = new Map([
123
+ [PARTICLE_VALUE_TYPE.id, new Color(0.58, 0.62, 0.68)],
124
+ [PARTICLE_TYPE_F32.id, new Color(0.55, 0.80, 1.0)],
125
+ [PARTICLE_TYPE_VEC2.id, new Color(0.55, 0.88, 0.50)],
126
+ [PARTICLE_TYPE_VEC3.id, new Color(1.0, 0.78, 0.35)],
127
+ [PARTICLE_TYPE_VEC4.id, new Color(0.95, 0.55, 0.80)],
128
+ [PARTICLE_TYPE_COLOR.id, new Color(0.72, 0.60, 0.98)],
129
+ ]);
130
+
131
+ /**
132
+ * The categories the add-node menu groups the library into, in the order they are offered. A node
133
+ * type not named here falls into "other", so the library gaining a type never hides it.
134
+ *
135
+ * @type {Array<{name: string, types: string[]}>}
136
+ */
137
+ const PALETTE_CATEGORIES = [
138
+ { name: "sources", types: ["const", "color", "builtin", "attribute", "random", "curve"] },
139
+ { name: "output", types: ["setAttribute", "kill"] },
140
+ // The three that are authored data rather than wiring, and are edited as a picture: a gradient
141
+ // strip and a curve in the unit square. Their own heading, because "a colour ramp" is a thing an
142
+ // author goes looking for by name and would not think to look for under `sources`.
143
+ { name: "ramps", types: ["gradientRGBA", "gradientRGB", "curveLiteral"] },
144
+ { name: "arithmetic", types: ["add", "sub", "mul", "div", "mad", "scale", "min", "max", "pow", "step", "mix", "clamp", "saturate", "smoothstep", "remap", "oneMinus"] },
145
+ { name: "math", types: ["neg", "abs", "floor", "fract", "round", "ceil", "sqrt", "rsqrt", "sin", "cos", "tan", "asin", "acos", "atan2", "exp", "log"] },
146
+ { name: "vector", types: ["vec2", "vec3", "vec4", "decompose2", "decompose3", "decompose4", "swizzle", "dot", "cross", "length", "normalize", "distance", "angleBetween2", "angleBetween3"] },
147
+ { name: "logic", types: ["compare", "select"] },
148
+ { name: "rotation", types: ["quatFromAxisAngle", "quatLookRotation", "quatRotate"] },
149
+ { name: "sampling", types: ["sampleSphereSurface", "sampleSphereVolume"] },
150
+ { name: "noise", types: ["simplex3", "simplex4", "curl3", "curl4", "srdnoise3", "psrdnoise3"] },
151
+ ];
152
+
153
+ /**
154
+ * Whether a port could take a value of a given type, for the menu that finishes a dropped wire.
155
+ *
156
+ * Every port in the library declares the one {@link PARTICLE_VALUE_TYPE} — including a group's, so
157
+ * that a wire may be dragged between any two ports and the graph model never refuses one on a type
158
+ * it does not decide. What a particle node reads is decided by what is wired into it, so for a stock
159
+ * type the answer is always yes, and what the menu is really filtering by is which side the wire came
160
+ * out of. That is the useful filter anyway: a wire out of an output cannot be finished by a `const`.
161
+ *
162
+ * A group *declares* what each of its ports is, separately from the port, and there the answer means
163
+ * something. A value goes in if the shapes match, if it is a scalar (which broadcasts), or if the
164
+ * port is wider (the missing lanes read zero). A port narrower than the value is left out: offering
165
+ * `cross` for a `vec4` would be offering to drop a lane. A group port declared with no type at all
166
+ * takes the shape of what arrives, and so takes anything.
167
+ *
168
+ * @param {Port} port
169
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleValueType.js").ParticleValueType|null} dataType
170
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleNodeDescription.js").ParticleNodeDescription} description
171
+ * @returns {boolean}
172
+ */
173
+ function particle_port_accepts(port, dataType, description) {
174
+ if (dataType === null || dataType.isParticleValueType !== true) {
175
+ return true;
176
+ }
177
+
178
+ const declared = description.group?.portType(port.name, port.direction) ?? null;
179
+
180
+ if (declared === null) {
181
+ return true;
182
+ }
183
+
184
+ return dataType.is_scalar || declared.components >= dataType.components;
185
+ }
186
+
187
+ export class ParticleGraphEditorView extends View {
188
+ /**
189
+ * @type {Array<{id: string, label: string, editor: NodeGraphEditorView, toggle: View}>}
190
+ */
191
+ #phases = [];
192
+
193
+ /**
194
+ * @type {string}
195
+ */
196
+ #active = "init";
197
+
198
+ /**
199
+ * @type {EmptyView}
200
+ */
201
+ #problems;
202
+
203
+ /**
204
+ * @type {EmptyView}
205
+ */
206
+ #body;
207
+
208
+ /**
209
+ * @type {EmptyView}
210
+ */
211
+ #toolbar;
212
+
213
+ /**
214
+ * The breadcrumb back out of whatever groups are open, and empty while none is.
215
+ * @type {EmptyView}
216
+ */
217
+ #trail;
218
+
219
+ /**
220
+ * The two commands whose availability depends on what is selected. See {@link #refreshCommands}.
221
+ * @type {View}
222
+ */
223
+ #group_button;
224
+
225
+ /**
226
+ * @type {View}
227
+ */
228
+ #ungroup_button;
229
+
230
+ /**
231
+ * The groups currently open, outermost first, each with the canvas showing it. Empty means the
232
+ * phase graphs are what is on screen.
233
+ *
234
+ * @type {Array<{group: import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup, editor: NodeGraphEditorView}>}
235
+ */
236
+ #open_groups = [];
237
+
238
+ /**
239
+ * One clipboard for every canvas this view builds — both phases, and the body of every group
240
+ * opened inside them.
241
+ *
242
+ * `Ctrl+C` in INIT and `Ctrl+V` in UPDATE is the same gesture an author expects it to be, and a
243
+ * clipboard per canvas would make it two. It belongs to this view rather than to the module,
244
+ * because what it holds is node types this document knows — a group an author made here has no
245
+ * meaning in another document's graph.
246
+ *
247
+ * @type {NodeGraphClipboard}
248
+ */
249
+ #clipboard = new NodeGraphClipboard();
250
+
251
+ /**
252
+ * Phases whose camera has not yet been pointed at their contents. A graph that has just been
253
+ * arranged for the first time is somewhere in particular, and it is not the origin.
254
+ * Discharged by {@link #frameIfNeeded}.
255
+ * @type {Set<string>}
256
+ */
257
+ #needs_framing = new Set();
258
+
259
+ /**
260
+ * The last compile's diagnostics, kept so a node view that appears after them can still be
261
+ * marked. Nodes arrive from an undo as readily as from the menu.
262
+ * @type {Array<{scope: string, node: number, severity: string}>}
263
+ */
264
+ #diagnostics = [];
265
+
266
+ /**
267
+ * The resolved types of each phase's graph, by phase id, as of the last change to the effect.
268
+ * Filled on demand — see {@link #typesOf} — and emptied whenever the effect changes, since any
269
+ * edit may retype ports far from itself.
270
+ * @type {Map<string, import("../../../../src/shade/renderer/particles/graph/infer_particle_graph_types.js").ParticleGraphTypes>}
271
+ */
272
+ #types = new Map();
273
+
274
+ /**
275
+ * The resolved types of each open group's body, by group. See {@link #groupTypes}.
276
+ * @type {Map<import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup, import("../../../../src/shade/renderer/particles/graph/infer_particle_graph_types.js").ParticleGraphTypes>}
277
+ */
278
+ #group_types = new Map();
279
+
280
+ /**
281
+ * @param {object} options
282
+ * @param {import("../../../particles/effect/ParticleEffectDocument.js").ParticleEffectDocument} options.effect
283
+ * @param {ActionProcessor} [options.actionProcessor] shared with a host editor for a single undo
284
+ * timeline across the whole application
285
+ */
286
+ constructor({ effect, actionProcessor = new ActionProcessor({}) }) {
287
+ super();
288
+
289
+ this.el = document.createElement('div');
290
+
291
+ this.addClass('ui-particle-graph-editor');
292
+
293
+ /**
294
+ * @type {import("../../../particles/effect/ParticleEffectDocument.js").ParticleEffectDocument}
295
+ */
296
+ this.effect = effect;
297
+
298
+ /**
299
+ * @type {ActionProcessor}
300
+ */
301
+ this.actionProcessor = actionProcessor;
302
+
303
+ this.#toolbar = new EmptyView({ classList: ['toolbar'] });
304
+ this.#body = new EmptyView({ classList: ['body'] });
305
+ this.#problems = new EmptyView({ classList: ['problems'] });
306
+
307
+ for (const phase of [{ id: "init", label: "INIT" }, { id: "update", label: "UPDATE" }]) {
308
+ this.#phases.push(this.#buildPhase(phase.id, phase.label));
309
+ }
310
+
311
+ this.addChild(this.#toolbar);
312
+ this.addChild(this.#body);
313
+ this.addChild(this.#problems);
314
+
315
+ this.#buildToolbar();
316
+
317
+ this.setPhase(this.#active);
318
+
319
+ this.#refreshCommands();
320
+
321
+ // Before anything else downstream of a change: a node cannot be drawn until every canvas
322
+ // knows how big its type is, and a group the author just made is a type nothing has seen.
323
+ this.bindSignal(effect.on.changed, this.#ensureGroupPrototypes, this);
324
+
325
+ this.#ensureGroupPrototypes();
326
+
327
+ this.bindSignal(effect.on.changed, this.refreshProblems, this);
328
+ this.on.linked.add(this.refreshProblems, this);
329
+
330
+ // a port's type follows the graph, so every change is a chance for every port to differ
331
+ this.bindSignal(effect.on.changed, this.#refreshTypes, this);
332
+
333
+ this.bindSignal(this.size.onChanged, this.layout, this);
334
+ this.on.linked.add(this.layout, this);
335
+
336
+ this.#bindShortcuts();
337
+ }
338
+
339
+ /**
340
+ * `Ctrl+G` groups the selection and `Ctrl+Shift+G` opens one back up.
341
+ *
342
+ * On this view rather than on a canvas, because it is this view that owns both commands and
343
+ * because a keystroke has to reach them whichever canvas happens to be on screen. The canvases
344
+ * do not stop key events, so one typed over a graph arrives here.
345
+ */
346
+ #bindShortcuts() {
347
+ this.el.setAttribute('tabindex', '-1');
348
+
349
+ const keyboard = new KeyboardDevice(this.el);
350
+
351
+ keyboard.on.down.add(event => {
352
+ if (!event.ctrlKey || event.keyCode !== KeyCodes.g) {
353
+ return;
354
+ }
355
+
356
+ const target = event.target;
357
+
358
+ if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
359
+ // typing into a field — a node's parameter, the search box, a group's name
360
+ return;
361
+ }
362
+
363
+ event.preventDefault();
364
+ event.stopPropagation();
365
+
366
+ const done = event.shiftKey ? this.ungroupSelection() : this.groupSelection();
367
+
368
+ done.catch(e => console.error(event.shiftKey ? "could not ungroup" : "could not group", e));
369
+ });
370
+
371
+ this.on.linked.add(keyboard.start, keyboard);
372
+ this.on.unlinked.add(keyboard.stop, keyboard);
373
+ }
374
+
375
+ /**
376
+ * @param {string} id
377
+ * @param {string} label
378
+ * @returns {{id: string, label: string, editor: NodeGraphEditorView, toggle: View}}
379
+ */
380
+ #buildPhase(id, label) {
381
+ const effect = this.effect;
382
+
383
+ const visual = effect[`${id}_visual`];
384
+
385
+ for (const [type_id, color] of PARTICLE_TYPE_COLORS) {
386
+ visual.addDataColor(type_id, color);
387
+ }
388
+
389
+ // A graph nobody has placed yet — a new effect, or one loaded from a file with no positions
390
+ // — would otherwise open as a stack of nodes on top of each other at the origin. Checked
391
+ // before the editor is built, because building it gives every node visual data at 0,0 and
392
+ // there is then no way to tell "not placed" from "placed at the origin".
393
+ const unplaced = visual.nodes.size === 0 && effect[id].getNodes().length > 0;
394
+
395
+ const editor = this.#buildCanvas({
396
+ graph: effect[id],
397
+ visual,
398
+ types: () => this.#typesOf(id),
399
+ });
400
+
401
+ editor.addClass(`phase-${id}`);
402
+
403
+ if (unplaced) {
404
+ editor.layout();
405
+
406
+ // the camera cannot be pointed at the result yet, see #frameIfNeeded
407
+ this.#needs_framing.add(id);
408
+ }
409
+
410
+ this.bindSignal(editor.on.arranged, () => this.#frameIfNeeded());
411
+
412
+ this.#body.addChild(editor);
413
+
414
+ // A node's marker cannot be applied off the document's change signal: that fires before the
415
+ // graph view has built the node's view, because this view's bindings are linked before its
416
+ // children's. The graph view says when the view exists, which is the only moment that works
417
+ // — for a node the canvas menu just added and for one an undo brings back alike.
418
+ this.bindSignal(editor.graphView.on.nodeViewAdded, node => this.#markNode(id, node.id));
419
+
420
+ // Two phases, two maps, one opinion about whether a map is wanted. Folding one away and
421
+ // finding the other still open on the next phase switch would read as the fold not having
422
+ // worked. Setting a value it already holds announces nothing, so this settles rather than
423
+ // loops.
424
+ this.bindSignal(editor.minimap.collapsed.onChanged, collapsed => {
425
+ for (const phase of this.#phases) {
426
+ phase.editor.minimap.collapsed.set(collapsed);
427
+ }
428
+ });
429
+
430
+ const toggle = new EmptyView({ classList: ['phase-toggle'] });
431
+
432
+ toggle.addChild(new LabelView(label, { classList: ['label'] }));
433
+ toggle.el.addEventListener('click', () => this.setPhase(id));
434
+
435
+ this.#toolbar.addChild(toggle);
436
+
437
+ return { id, label, editor, toggle };
438
+ }
439
+
440
+ /**
441
+ * One canvas over one graph, with everything particle-specific wired into the base's seams.
442
+ *
443
+ * Shared between the two phase graphs and the body of every group that gets opened, because they
444
+ * differ in exactly two things — which graph, and whether it can be edited — and everything else
445
+ * about how a particle graph is drawn and added to should not be written twice.
446
+ *
447
+ * @param {object} options
448
+ * @param {NodeGraph} options.graph
449
+ * @param {NodeGraphVisualData} options.visual
450
+ * @param {function():import("../../../../src/shade/renderer/particles/graph/infer_particle_graph_types.js").ParticleGraphTypes} options.types
451
+ * @param {boolean} [options.readOnly]
452
+ * @returns {NodeGraphEditorView}
453
+ */
454
+ #buildCanvas({ graph, visual, types, readOnly = false }) {
455
+ const effect = this.effect;
456
+
457
+ for (const [type_id, color] of PARTICLE_TYPE_COLORS) {
458
+ visual.addDataColor(type_id, color);
459
+ }
460
+
461
+ const editor = new NodeGraphEditorView({
462
+ graph,
463
+ nodeRegistry: PARTICLE_NODE_REGISTRY,
464
+ visual,
465
+ camera: new NodeGraphCamera(),
466
+ actionProcessor: this.actionProcessor,
467
+ readOnly,
468
+ clipboard: this.#clipboard,
469
+ // A group body's input and output blocks are its edge, not its contents: there is one of
470
+ // each, the group holds them by reference, and a second would survive flattening and
471
+ // reach the compiler. So they are left out of a copy rather than the copy being refused
472
+ // — an author who dragged a box around a whole group body wants what is inside it.
473
+ copyable: node => !is_particle_group_boundary(node),
474
+ library: {
475
+ // The menu heads each *run* of one category, so the order it is handed decides the
476
+ // order it shows; sorting here keeps that decision on the particle side of the seam.
477
+ descriptions: () => [...particle_library_descriptions(), ...effect.groups.map(g => g.description)]
478
+ .sort((a, b) => category_rank(a.name) - category_rank(b.name)),
479
+ categoryOf: description => category_of(description.name),
480
+ describe: description => description.help,
481
+ accepts: particle_port_accepts,
482
+ parametersOf: description => this.#defaultParameters(description),
483
+ },
484
+ parameterViewFactory: ({ node, commit }) => {
485
+ // A group's configuration is its wiring, and its boundary blocks are its edge:
486
+ // neither declares a parameter, and neither is in the schema to be asked about. A
487
+ // node with no parameters gets no container at all, rather than an empty one.
488
+ if (is_particle_group_description(node.description)) {
489
+ return null;
490
+ }
491
+
492
+ if (particle_node_parameters(node.description.name).length === 0) {
493
+ return null;
494
+ }
495
+
496
+ return new ParticleNodeParametersView({ effect, node, commit });
497
+ },
498
+ // What a port carries on this node: its output's type, or for an input the type the
499
+ // node reads it as — which is what an empty port is waiting for. Unknown falls back to
500
+ // the declared type, and its colour.
501
+ portDataType: endpoint => {
502
+ const resolved = types();
503
+
504
+ const type = endpoint.port.direction === PortDirection.Out
505
+ ? resolved.output(endpoint.instance.id, endpoint.port.name)
506
+ : resolved.input(endpoint.instance.id, endpoint.port.name);
507
+
508
+ return type ?? endpoint.port.dataType;
509
+ },
510
+ });
511
+
512
+ // Before anything is drawn on it: a canvas cannot build a node until its registry knows how
513
+ // big the type is, and the types this document made are in no shared registry.
514
+ this.#generateGroupPrototypes(editor);
515
+
516
+ // what the commands apply to is what is selected, and that is per canvas
517
+ for (const signal of [editor.selection.nodes.on.added, editor.selection.nodes.on.removed]) {
518
+ editor.bindSignal(signal, () => this.#refreshCommands());
519
+ }
520
+
521
+ // Double-click a group to open it. Bound on the canvas rather than on this view, so that
522
+ // closing a group takes its bindings with it — and bindings are linked before children, so
523
+ // this is in place before the graph view builds the first node.
524
+ editor.bindSignal(editor.graphView.on.nodeViewAdded, (node, nodeView) => {
525
+ if (node.description.isParticleGroupBoundaryDescription === true) {
526
+ nodeView.addClass('is-group-boundary');
527
+
528
+ return;
529
+ }
530
+
531
+ if (node.description.isParticleGroupNodeDescription !== true) {
532
+ return;
533
+ }
534
+
535
+ nodeView.addClass('is-group');
536
+
537
+ nodeView.el.addEventListener('dblclick', event => {
538
+ event.preventDefault();
539
+ event.stopPropagation();
540
+
541
+ this.openGroup(node.description.group);
542
+ });
543
+ });
544
+
545
+ return editor;
546
+ }
547
+
548
+ /**
549
+ * The parameters a node of this type should arrive with.
550
+ *
551
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleNodeDescription.js").ParticleNodeDescription} description
552
+ * @returns {object}
553
+ */
554
+ #defaultParameters(description) {
555
+ if (is_particle_group_description(description)) {
556
+ return {};
557
+ }
558
+
559
+ return particle_node_default_parameters(description.name, { layout: this.#layoutOrNothing() });
560
+ }
561
+
562
+ /**
563
+ * Give every canvas a box for every node type this document carries of its own.
564
+ *
565
+ * A canvas generates the box it draws a node in from the registry it was built with, and throws
566
+ * when it cannot find one — which is the right behaviour, since the alternative is a node drawn
567
+ * at nothing by nothing. A group an author has just made is a type that registry has never seen,
568
+ * so it is told here, on every change, for every canvas.
569
+ *
570
+ * Cheap and idempotent: a registry generates a box from port and parameter counts and keys it by
571
+ * the description's id, so telling it twice about the same type costs an arithmetic pass.
572
+ */
573
+ #ensureGroupPrototypes() {
574
+ for (const canvas of [...this.#phases.map(phase => phase.editor), ...this.#open_groups.map(open => open.editor)]) {
575
+ this.#generateGroupPrototypes(canvas);
576
+ }
577
+ }
578
+
579
+ /**
580
+ * The same, for one canvas — which is what a canvas built after the fact needs, and there is no
581
+ * change to hang it off: a group's body is opened, not announced.
582
+ *
583
+ * @param {NodeGraphEditorView} canvas
584
+ */
585
+ #generateGroupPrototypes(canvas) {
586
+ for (const group of this.effect.groups) {
587
+ for (const description of particle_group_descriptions(group)) {
588
+ canvas.visualRegistry.generate(description);
589
+ }
590
+ }
591
+ }
592
+
593
+ #buildToolbar() {
594
+ this.#trail = new EmptyView({ classList: ['group-trail'] });
595
+
596
+ this.#toolbar.addChild(this.#trail);
597
+
598
+ this.#toolbar.addChild(new EmptyView({ classList: ['spacer'] }));
599
+
600
+ this.#group_button = this.#buildButton("Group", () => {
601
+ this.groupSelection().catch(e => console.error("could not group the selection", e));
602
+ });
603
+
604
+ this.#ungroup_button = this.#buildButton("Ungroup", () => {
605
+ this.ungroupSelection().catch(e => console.error("could not ungroup", e));
606
+ });
607
+
608
+ this.#toolbar.addChild(this.#group_button);
609
+ this.#toolbar.addChild(this.#ungroup_button);
610
+
611
+ // The auto-layouter moves every node, which is a big enough change to an author's
612
+ // arrangement that it belongs behind a button rather than happening on its own — and behind
613
+ // an undo, which is what {@link arrange} adds over calling the layouter directly.
614
+ this.#toolbar.addChild(this.#buildButton("Arrange", () => this.arrange()));
615
+ }
616
+
617
+ /**
618
+ * Say whether each command applies to what is selected right now, and why not when it does not.
619
+ *
620
+ * Grouping can be refused for a reason that is not obvious from looking at the canvas — a
621
+ * selection something outside it runs in the middle of cannot become one node — and a button that
622
+ * looked available and then did nothing would be the worst of both. So the reason is worked out
623
+ * up front and shown on the button, which is where an author will look for it.
624
+ *
625
+ * Cheap: the check is a walk downstream from the selection, over a graph with tens of nodes in
626
+ * it, run when the selection changes.
627
+ */
628
+ #refreshCommands() {
629
+ const editor = this.activeEditor();
630
+
631
+ const selected = editor.selection.nodes.asArray();
632
+
633
+ const grouping = this.#whyNotGroup(editor, selected);
634
+
635
+ this.#group_button.setClass('disabled', grouping !== null);
636
+ this.#group_button.el.setAttribute('title', grouping ?? "make one node out of the selection (Ctrl+G)");
637
+
638
+ const groups = selected
639
+ .map(id => editor.graph.getNode(id))
640
+ .filter(node => node?.description.isParticleGroupNodeDescription === true);
641
+
642
+ const ungrouping = editor.readOnly
643
+ ? "this group is locked"
644
+ : (groups.length === 0 ? "select a group node" : null);
645
+
646
+ this.#ungroup_button.setClass('disabled', ungrouping !== null);
647
+ this.#ungroup_button.el.setAttribute('title', ungrouping ?? "put back what the group is made of (Ctrl+Shift+G)");
648
+ }
649
+
650
+ /**
651
+ * Why the selection cannot be grouped, or `null` when it can.
652
+ *
653
+ * @param {NodeGraphEditorView} editor
654
+ * @param {number[]} selected
655
+ * @returns {string|null}
656
+ */
657
+ #whyNotGroup(editor, selected) {
658
+ if (editor.readOnly) {
659
+ return "this group is locked";
660
+ }
661
+
662
+ if (selected.length === 0) {
663
+ return "select something to group";
664
+ }
665
+
666
+ try {
667
+ // built and thrown away: the question "could this be grouped" and the answer "here is the
668
+ // group" are the same work, and doing it twice is cheaper than two ways of being wrong
669
+ particle_group_from_nodes({
670
+ graph: editor.graph,
671
+ nodes: selected,
672
+ name: "__probe",
673
+ });
674
+ } catch (e) {
675
+ return e.message;
676
+ }
677
+
678
+ return null;
679
+ }
680
+
681
+ /**
682
+ * Turn what is selected into a group, and put the group where the selection was.
683
+ *
684
+ * The one gesture that makes a graph smaller. Which wires become ports, what they are called and
685
+ * what type they are is worked out from the selection — see
686
+ * {@link ../../../../src/shade/renderer/particles/graph/make_particle_group.js} — so a group
687
+ * arrives finished rather than as a form to fill in, and its face is the author's to change
688
+ * afterwards.
689
+ *
690
+ * Everything it does is one step on the timeline: the nodes leaving, the group type appearing,
691
+ * the node that replaces them, and every wire re-made around it. An undo that left a type behind
692
+ * in the add-node menu would be an undo that did not undo.
693
+ *
694
+ * @returns {Promise<NodeInstance|null>} the node that replaced the selection, or null when there
695
+ * was nothing selected to group
696
+ */
697
+ async groupSelection() {
698
+ const editor = this.activeEditor();
699
+
700
+ if (editor.readOnly) {
701
+ throw new Error("This group is locked, so what is inside it cannot be re-grouped.");
702
+ }
703
+
704
+ const selected = editor.selection.nodes.asArray().slice();
705
+
706
+ if (selected.length === 0) {
707
+ return null;
708
+ }
709
+
710
+ const graph = editor.graph;
711
+ const visual = editor.visual;
712
+
713
+ const { group, inputs, outputs } = particle_group_from_nodes({
714
+ graph,
715
+ visual,
716
+ visualRegistry: editor.visualRegistry,
717
+ layout: this.#layoutOrNothing(),
718
+ nodes: selected,
719
+ name: this.effect.unusedGroupName(),
720
+ label: `Group ${this.effect.groups.length + 1}`,
721
+ help: "a group made from a selection",
722
+ icon: PARTICLE_GROUP_ICON,
723
+ });
724
+
725
+ const centre = centroid(visual, selected);
726
+
727
+ const create = new NodeCreateAction(
728
+ graph, visual, editor.visualRegistry, group.description, centre.x, centre.y
729
+ );
730
+
731
+ this.actionProcessor.mark('group');
732
+
733
+ // The group is defined before the node that uses it is created: creating one needs a box to
734
+ // draw it in, and that is generated when the document announces the type.
735
+ await this.actionProcessor.doMany([
736
+ new SelectionSetAction(editor.selection, [], []),
737
+ ...selected.map(id => new NodeDeleteAction(graph, visual, id)),
738
+ new ParticleGroupDefineAction(this.effect, group),
739
+ create,
740
+ ]);
741
+
742
+ const node = create.node;
743
+
744
+ const wires = [];
745
+
746
+ for (const entry of inputs) {
747
+ const port = group.description.findPortByNameAndDirection(entry.port, PortDirection.In);
748
+
749
+ wires.push(new ConnectionCreateAction(graph, entry.from.node, entry.from.port, node.id, port.id));
750
+ }
751
+
752
+ for (const entry of outputs) {
753
+ const port = group.description.findPortByNameAndDirection(entry.port, PortDirection.Out);
754
+
755
+ for (const target of entry.to) {
756
+ wires.push(new ConnectionCreateAction(graph, node.id, port.id, target.node, target.port));
757
+ }
758
+ }
759
+
760
+ // and what is selected afterwards is the thing the author just made
761
+ wires.push(new SelectionSetAction(editor.selection, [node.id], []));
762
+
763
+ await this.actionProcessor.doMany(wires);
764
+
765
+ return node;
766
+ }
767
+
768
+ /**
769
+ * Replace every selected group node with the nodes it is made of.
770
+ *
771
+ * The way out of a grouping made by mistake, and the way in to a library group an author wants to
772
+ * change one use of: the definition is not touched, only this instance. What lands in the graph
773
+ * is what compilation would have inlined anyway.
774
+ *
775
+ * @returns {Promise<NodeInstance[]>} the nodes that replaced them; empty when nothing applied
776
+ */
777
+ async ungroupSelection() {
778
+ const editor = this.activeEditor();
779
+
780
+ if (editor.readOnly) {
781
+ throw new Error("This group is locked, so what is inside it cannot be changed.");
782
+ }
783
+
784
+ const selected = editor.selection.nodes.asArray()
785
+ .map(id => editor.graph.getNode(id))
786
+ .filter(node => node !== undefined && node.description.isParticleGroupNodeDescription === true);
787
+
788
+ if (selected.length === 0) {
789
+ return [];
790
+ }
791
+
792
+ this.actionProcessor.mark('ungroup');
793
+
794
+ const opened = [];
795
+
796
+ for (const node of selected) {
797
+ opened.push(...await this.#ungroup(editor, node));
798
+ }
799
+
800
+ await this.actionProcessor.do(new SelectionSetAction(
801
+ editor.selection,
802
+ opened.map(node => node.id),
803
+ []
804
+ ));
805
+
806
+ return opened;
807
+ }
808
+
809
+ /**
810
+ * One group node, replaced by a copy of its body.
811
+ *
812
+ * Built out of the same actions every other edit is, rather than as a bespoke reversible splice:
813
+ * the nodes arrive through {@link NodeCreateAction}, the wires through
814
+ * {@link ConnectionCreateAction}, and the group node leaves through {@link NodeDeleteAction}, so
815
+ * undo already knows what to do with all of it.
816
+ *
817
+ * @param {NodeGraphEditorView} editor
818
+ * @param {NodeInstance} node the group instance
819
+ * @returns {Promise<NodeInstance[]>}
820
+ */
821
+ async #ungroup(editor, node) {
822
+ const graph = editor.graph;
823
+ const visual = editor.visual;
824
+
825
+ const group = node.description.group;
826
+ const body = group.graph;
827
+
828
+ const placed = visual.getNode(node.id)?.dimensions.position;
829
+
830
+ // Where the body sits inside the group, so what comes out of it lands around where the node
831
+ // was rather than at the origin.
832
+ const origin = body_origin(group);
833
+
834
+ /** @type {Map<number, NodeCreateAction>} body node id -> the action that recreates it */
835
+ const created = new Map();
836
+
837
+ for (const inner of body.getNodes()) {
838
+ if (inner === group.inputNode || inner === group.outputNode) {
839
+ continue;
840
+ }
841
+
842
+ const at = group.visual.getNode(inner.id)?.dimensions.position;
843
+
844
+ created.set(inner.id, new NodeCreateAction(
845
+ graph,
846
+ visual,
847
+ editor.visualRegistry,
848
+ inner.description,
849
+ (placed?.x ?? 0) + (at === undefined ? 0 : at.x - origin.x),
850
+ (placed?.y ?? 0) + (at === undefined ? 0 : at.y - origin.y),
851
+ // deeply: an ungrouped node must not share so much as a gradient stop with the group
852
+ // definition it came out of
853
+ clone_particle_parameters(inner.parameters)
854
+ ));
855
+ }
856
+
857
+ await this.actionProcessor.doMany(Array.from(created.values()));
858
+
859
+ // What the group node was wired to, read before it goes.
860
+ const sources = new Map();
861
+ const targets = new Map();
862
+
863
+ for (const connection of node.inConnections) {
864
+ sources.set(connection.target.port.name, {
865
+ node: connection.source.instance.id,
866
+ port: connection.source.port.id,
867
+ });
868
+ }
869
+
870
+ for (const connection of node.outConnections) {
871
+ const listed = targets.get(connection.source.port.name) ?? [];
872
+
873
+ listed.push({ node: connection.target.instance.id, port: connection.target.port.id });
874
+
875
+ targets.set(connection.source.port.name, listed);
876
+ }
877
+
878
+ const wires = [];
879
+
880
+ for (const connection of body.getConnections()) {
881
+ const from = connection.source;
882
+ const to = connection.target;
883
+
884
+ const from_boundary = from.instance === group.inputNode;
885
+ const to_boundary = to.instance === group.outputNode;
886
+
887
+ if (from_boundary && to_boundary) {
888
+ const source = sources.get(from.port.name);
889
+
890
+ if (source !== undefined) {
891
+ for (const target of targets.get(to.port.name) ?? []) {
892
+ wires.push(new ConnectionCreateAction(
893
+ graph, source.node, source.port, target.node, target.port
894
+ ));
895
+ }
896
+ }
897
+
898
+ continue;
899
+ }
900
+
901
+ if (from_boundary) {
902
+ const source = sources.get(from.port.name);
903
+
904
+ if (source !== undefined) {
905
+ wires.push(new ConnectionCreateAction(
906
+ graph, source.node, source.port, created.get(to.instance.id).node.id, to.port.id
907
+ ));
908
+ }
909
+
910
+ continue;
911
+ }
912
+
913
+ if (to_boundary) {
914
+ for (const target of targets.get(to.port.name) ?? []) {
915
+ wires.push(new ConnectionCreateAction(
916
+ graph, created.get(from.instance.id).node.id, from.port.id, target.node, target.port
917
+ ));
918
+ }
919
+
920
+ continue;
921
+ }
922
+
923
+ wires.push(new ConnectionCreateAction(
924
+ graph,
925
+ created.get(from.instance.id).node.id, from.port.id,
926
+ created.get(to.instance.id).node.id, to.port.id
927
+ ));
928
+ }
929
+
930
+ // last: deleting the group node takes its own wires with it, and the ones above replace them
931
+ await this.actionProcessor.doMany([...wires, new NodeDeleteAction(graph, visual, node.id)]);
932
+
933
+ return Array.from(created.values()).map(action => action.node);
934
+ }
935
+
936
+ /**
937
+ * The effect's attribute schema, or nothing when the declarations do not make one.
938
+ *
939
+ * @returns {import("../../../../src/shade/renderer/particles/layout/ParticleLayout.js").ParticleLayout|undefined}
940
+ */
941
+ #layoutOrNothing() {
942
+ try {
943
+ return this.effect.buildLayout();
944
+ } catch (e) {
945
+ // a broken attribute schema types the attribute reads as unknown, and nothing else
946
+ return undefined;
947
+ }
948
+ }
949
+
950
+ /**
951
+ * Show the body of a group instead of the graph that holds it.
952
+ *
953
+ * Every instance of a group shares one body, so this is the group's own graph and not a copy of
954
+ * it — which is the point, and is why the ones shipped with the editor are locked: an edit inside
955
+ * an unlocked group is an edit to every instance of it in every effect. A locked one opens
956
+ * read-only, and is worth opening anyway to read.
957
+ *
958
+ * Groups nest, so this stacks: opening one from inside another pushes onto the trail rather than
959
+ * replacing it.
960
+ *
961
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup} group
962
+ * @returns {void}
963
+ */
964
+ openGroup(group) {
965
+ const unplaced = group.visual.nodes.size === 0;
966
+
967
+ const editor = this.#buildCanvas({
968
+ graph: group.graph,
969
+ visual: group.visual,
970
+ types: () => this.#groupTypes(group),
971
+ readOnly: group.locked,
972
+ });
973
+
974
+ editor.addClass('group-body');
975
+
976
+ this.#open_groups.push({ group, editor });
977
+
978
+ // An editable group's body is not part of the document, so nothing in the effect's change
979
+ // signal says when its types have moved. Its own graph does.
980
+ for (const signal of [
981
+ group.graph.on.nodeAdded,
982
+ group.graph.on.nodeRemoved,
983
+ group.graph.on.connectionAdded,
984
+ group.graph.on.connectionRemoved,
985
+ ]) {
986
+ editor.bindSignal(signal, () => {
987
+ this.#group_types.delete(group);
988
+
989
+ editor.graphView.refreshPortTypes();
990
+ });
991
+ }
992
+
993
+ this.#body.addChild(editor);
994
+
995
+ if (unplaced) {
996
+ // A group's body is built in code and has never been arranged, so the first time anybody
997
+ // looks at one is the moment to do it. The result is kept on the definition, so the
998
+ // second look is where the first one left it.
999
+ editor.layout();
1000
+
1001
+ // bound on the canvas rather than on this view, so closing the group takes the binding
1002
+ // with it rather than leaving one pointed at a canvas nobody will draw again
1003
+ editor.bindSignal(editor.on.arranged, final => {
1004
+ if (final) {
1005
+ editor.cameraContainAll();
1006
+ }
1007
+ });
1008
+ }
1009
+
1010
+ this.#showActive();
1011
+ this.layout();
1012
+
1013
+ if (!editor.isArrangementProvisional()) {
1014
+ editor.cameraContainAll();
1015
+ }
1016
+ }
1017
+
1018
+ /**
1019
+ * Leave the innermost open group. Harmless when none is open.
1020
+ * @returns {void}
1021
+ */
1022
+ closeGroup() {
1023
+ this.openGroupDepth(this.#open_groups.length - 1);
1024
+ }
1025
+
1026
+ /**
1027
+ * Go back to a particular depth in the trail: 0 is the phase graph, 1 the outermost group.
1028
+ *
1029
+ * @param {number} depth
1030
+ * @returns {void}
1031
+ */
1032
+ openGroupDepth(depth) {
1033
+ const target = Math.max(0, Math.min(depth, this.#open_groups.length));
1034
+
1035
+ for (const closing of this.#open_groups.splice(target)) {
1036
+ this.#body.removeChild(closing.editor);
1037
+ }
1038
+
1039
+ this.#showActive();
1040
+ this.layout();
1041
+ }
1042
+
1043
+ /**
1044
+ * The groups currently open, outermost first.
1045
+ *
1046
+ * @returns {import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup[]}
1047
+ */
1048
+ openGroups() {
1049
+ return this.#open_groups.map(entry => entry.group);
1050
+ }
1051
+
1052
+ /**
1053
+ * Re-run the automatic layout over the graph on screen, as one undoable step.
1054
+ *
1055
+ * It moves every node in the graph, which makes it the most destructive thing on the toolbar:
1056
+ * an author who does not like the result has lost an arrangement they may have spent a while on.
1057
+ * So the positions before and after are recorded and pushed as a {@link NodesMoveAction}, the
1058
+ * same action a drag lands on the timeline.
1059
+ *
1060
+ * Inside a locked group it does nothing: an arrangement is a change to the group's definition
1061
+ * like any other, and a locked group's definition is not the author's to change.
1062
+ */
1063
+ arrange() {
1064
+ const editor = this.activeEditor();
1065
+
1066
+ if (editor.readOnly) {
1067
+ return;
1068
+ }
1069
+
1070
+ const open = this.#open_groups[this.#open_groups.length - 1];
1071
+
1072
+ const graph = open === undefined ? this.effect[this.#active] : open.group.graph;
1073
+ const visual = open === undefined ? this.effect[`${this.#active}_visual`] : open.group.visual;
1074
+
1075
+ /** @type {{visual: NodeVisualData, from: Vector2}[]} */
1076
+ const before = [];
1077
+
1078
+ for (const node of graph.getNodes()) {
1079
+ const node_visual = visual.getNode(node.id);
1080
+
1081
+ if (node_visual !== undefined) {
1082
+ before.push({ visual: node_visual, from: node_visual.dimensions.position.clone() });
1083
+ }
1084
+ }
1085
+
1086
+ editor.layout();
1087
+
1088
+ const moved = before.filter(entry => !entry.visual.dimensions.position.equals(entry.from));
1089
+
1090
+ if (moved.length === 0) {
1091
+ return;
1092
+ }
1093
+
1094
+ // the nodes are already where the layouter put them; the action records the net change so
1095
+ // the whole arrange lands on the timeline as one entry
1096
+ this.actionProcessor.mark('arrange');
1097
+ this.actionProcessor.do(new NodesMoveAction(moved.map(entry => ({
1098
+ visual: entry.visual,
1099
+ from: entry.from,
1100
+ to: entry.visual.dimensions.position.clone()
1101
+ }))));
1102
+ }
1103
+
1104
+ /**
1105
+ * @param {string} label
1106
+ * @param {function()} action
1107
+ * @returns {View}
1108
+ */
1109
+ #buildButton(label, action) {
1110
+ const button = new EmptyView({ classList: ['toolbar-button'] });
1111
+
1112
+ button.addChild(new LabelView(label));
1113
+
1114
+ button.el.addEventListener('click', () => {
1115
+ if (button.el.classList.contains('disabled')) {
1116
+ // the title says why, and doing nothing is what "disabled" means
1117
+ return;
1118
+ }
1119
+
1120
+ action();
1121
+ });
1122
+
1123
+ return button;
1124
+ }
1125
+
1126
+ /**
1127
+ * Add a node of the given type to the phase being edited, seeded with the defaults its type
1128
+ * declares — so what lands in the graph is a node that compiles rather than one to repair.
1129
+ *
1130
+ * @param {ParticleNodeDescription} description
1131
+ * @param {object} [options] position, see {@link NodeGraphEditorView#addNode}
1132
+ * @returns {Promise<NodeInstance>} the new node, once the action timeline has applied the add
1133
+ */
1134
+ async addNode(description, options = {}) {
1135
+ const editor = this.activeEditor();
1136
+
1137
+ if (editor.readOnly) {
1138
+ // the canvas on screen is a locked group's body, which is not the author's to add to
1139
+ throw new Error(
1140
+ `Cannot add a '${description.name}': `
1141
+ + `the group '${this.#open_groups[this.#open_groups.length - 1].group.name}' is locked.`
1142
+ );
1143
+ }
1144
+
1145
+ return editor.addNode(description, {
1146
+ ...options,
1147
+ parameters: this.#defaultParameters(description),
1148
+ });
1149
+ }
1150
+
1151
+ /**
1152
+ * The resolved types of one group's body, computed on first use and kept.
1153
+ *
1154
+ * A group's body does not change while an effect is being edited — the shipped ones are locked,
1155
+ * and an unlocked one changing is a change to the group rather than to the effect — so unlike a
1156
+ * phase's types these are not thrown away when the document changes. They are keyed on the group
1157
+ * itself, so two effects open on the same group share one answer.
1158
+ *
1159
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup} group
1160
+ * @returns {import("../../../../src/shade/renderer/particles/graph/infer_particle_graph_types.js").ParticleGraphTypes}
1161
+ */
1162
+ #groupTypes(group) {
1163
+ let types = this.#group_types.get(group);
1164
+
1165
+ if (types === undefined) {
1166
+ // No layout: a group has no effect and so no attribute schema of its own. A group that
1167
+ // reads an attribute types that read as unknown, which is honest — what it reads depends
1168
+ // on the effect it is placed in.
1169
+ types = infer_particle_graph_types(group.graph);
1170
+
1171
+ this.#group_types.set(group, types);
1172
+ }
1173
+
1174
+ return types;
1175
+ }
1176
+
1177
+ /**
1178
+ * The resolved types of one phase's graph, computed on first use since the effect last changed.
1179
+ *
1180
+ * @param {string} id `"init"` or `"update"`
1181
+ * @returns {import("../../../../src/shade/renderer/particles/graph/infer_particle_graph_types.js").ParticleGraphTypes}
1182
+ */
1183
+ #typesOf(id) {
1184
+ let types = this.#types.get(id);
1185
+
1186
+ if (types === undefined) {
1187
+ types = infer_particle_graph_types(this.effect[id], { layout: this.#layoutOrNothing() });
1188
+
1189
+ this.#types.set(id, types);
1190
+ }
1191
+
1192
+ return types;
1193
+ }
1194
+
1195
+ /**
1196
+ * Forget the resolved types and have every port in both phases ask again.
1197
+ *
1198
+ * The open groups are asked too. Their own types have not changed — a group's body is not part
1199
+ * of the document — but a group editor's ports are drawn by the same path, and one left showing
1200
+ * the colours it had before a rebuild would be the only stale thing on screen.
1201
+ */
1202
+ #refreshTypes() {
1203
+ this.#types.clear();
1204
+
1205
+ for (const phase of this.#phases) {
1206
+ phase.editor.graphView.refreshPortTypes();
1207
+ }
1208
+
1209
+ for (const open of this.#open_groups) {
1210
+ open.editor.graphView.refreshPortTypes();
1211
+ }
1212
+ }
1213
+
1214
+ /**
1215
+ * The canvas an edit would land on: the innermost open group, or the phase being edited.
1216
+ *
1217
+ * @returns {NodeGraphEditorView}
1218
+ */
1219
+ activeEditor() {
1220
+ const open = this.#open_groups[this.#open_groups.length - 1];
1221
+
1222
+ return open === undefined
1223
+ ? this.#phases.find(phase => phase.id === this.#active).editor
1224
+ : open.editor;
1225
+ }
1226
+
1227
+ /**
1228
+ * @returns {string} `"init"` or `"update"`
1229
+ */
1230
+ activePhase() {
1231
+ return this.#active;
1232
+ }
1233
+
1234
+ /**
1235
+ * Show one phase. Both stay built, so the one being left keeps its camera and its selection.
1236
+ * @param {string} id `"init"` or `"update"`
1237
+ */
1238
+ setPhase(id) {
1239
+ this.#active = id;
1240
+
1241
+ // A group is opened from a graph, so leaving that graph leaves the group. Coming back to
1242
+ // find somebody else's group still open would be the phase switch not having happened.
1243
+ for (const closing of this.#open_groups.splice(0)) {
1244
+ this.#body.removeChild(closing.editor);
1245
+ }
1246
+
1247
+ for (const phase of this.#phases) {
1248
+ phase.toggle.setClass('active', phase.id === id);
1249
+ }
1250
+
1251
+ this.#showActive();
1252
+
1253
+ this.layout();
1254
+ this.refreshProblems();
1255
+ }
1256
+
1257
+ /**
1258
+ * Show exactly one canvas — the innermost open group, or the active phase — and redraw the trail
1259
+ * back out to it.
1260
+ */
1261
+ #showActive() {
1262
+ const active = this.activeEditor();
1263
+
1264
+ for (const phase of this.#phases) {
1265
+ phase.editor.visible = phase.editor === active;
1266
+ }
1267
+
1268
+ for (const open of this.#open_groups) {
1269
+ open.editor.visible = open.editor === active;
1270
+ }
1271
+
1272
+ this.#refreshCommands();
1273
+
1274
+ this.#trail.removeAllChildren();
1275
+
1276
+ if (this.#open_groups.length === 0) {
1277
+ // nothing to find the way back from
1278
+ return;
1279
+ }
1280
+
1281
+ const crumb = (label, depth, group) => {
1282
+ const view = new EmptyView({ classList: ['crumb'] });
1283
+
1284
+ const current = depth === this.#open_groups.length;
1285
+
1286
+ if (current && group !== undefined && !group.locked) {
1287
+ // The group an author is inside, and made: its name is the one thing about it that
1288
+ // wants changing the moment it exists, so it is a field rather than a word.
1289
+ view.addChild(this.#buildGroupNameField(group));
1290
+ } else {
1291
+ // `name` rather than `label`: LabelView puts `label` on every one of its elements,
1292
+ // so the crumb's name and its "locked" tag would be indistinguishable by class
1293
+ view.addChild(new LabelView(label, { classList: ['name'] }));
1294
+ }
1295
+
1296
+ if (group?.locked === true) {
1297
+ view.addChild(new LabelView("locked", { classList: ['locked'] }));
1298
+ }
1299
+
1300
+ view.setClass('current', current);
1301
+
1302
+ view.el.addEventListener('click', event => {
1303
+ if (event.target instanceof HTMLInputElement) {
1304
+ // renaming the group is not asking to leave it
1305
+ return;
1306
+ }
1307
+
1308
+ this.openGroupDepth(depth);
1309
+ });
1310
+
1311
+ this.#trail.addChild(view);
1312
+ };
1313
+
1314
+ crumb(this.#active.toUpperCase(), 0, undefined);
1315
+
1316
+ this.#open_groups.forEach((open, index) => crumb(open.group.label, index + 1, open.group));
1317
+ }
1318
+
1319
+ /**
1320
+ * The field that renames the group being edited.
1321
+ *
1322
+ * What it changes is the *label* — what a person reads. The group's name is an address: it is
1323
+ * what a saved graph holds and what a node is resolved by, and renaming that would mean
1324
+ * rewriting every node that used it. Groups an author makes are numbered rather than named, and
1325
+ * this is what makes that all right.
1326
+ *
1327
+ * Committed when the field is left or Enter is pressed, not per keystroke: a rename that fires
1328
+ * on every letter would put a dozen entries on the undo timeline for one edit.
1329
+ *
1330
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup} group
1331
+ * @returns {View}
1332
+ */
1333
+ #buildGroupNameField(group) {
1334
+ const field = document.createElement('input');
1335
+
1336
+ field.setAttribute('type', 'text');
1337
+ field.setAttribute('spellcheck', 'false');
1338
+ field.classList.add('name', 'rename');
1339
+ field.value = group.label;
1340
+
1341
+ field.addEventListener('change', () => this.renameGroup(group, field.value));
1342
+
1343
+ field.addEventListener('keydown', event => {
1344
+ if (event.key === "Enter") {
1345
+ field.blur();
1346
+ }
1347
+ });
1348
+
1349
+ // typing a name is not a graph shortcut, and Delete in here must not delete the selection
1350
+ field.addEventListener('keydown', event => event.stopPropagation());
1351
+
1352
+ return new EmptyView({ el: field });
1353
+ }
1354
+
1355
+ /**
1356
+ * Call a group something else.
1357
+ *
1358
+ * Reaches every node already on screen that is an instance of it: a canvas is not rebuilt for a
1359
+ * word, and one left showing the old name would be the only stale thing in the window.
1360
+ *
1361
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup} group
1362
+ * @param {string} label
1363
+ * @returns {void}
1364
+ */
1365
+ renameGroup(group, label) {
1366
+ const wanted = label.trim();
1367
+
1368
+ if (wanted === "" || wanted === group.label) {
1369
+ return;
1370
+ }
1371
+
1372
+ group.label = wanted;
1373
+ group.description.display_label = wanted;
1374
+
1375
+ for (const canvas of [...this.#phases.map(phase => phase.editor), ...this.#open_groups.map(open => open.editor)]) {
1376
+ for (const nodeView of canvas.graphView.nodeViews.values()) {
1377
+ if (nodeView.node.description === group.description) {
1378
+ nodeView.refreshLabel();
1379
+ }
1380
+ }
1381
+ }
1382
+
1383
+ this.effect.touch();
1384
+ }
1385
+
1386
+ /**
1387
+ * Rebuild the problems strip from a fresh compile of the effect.
1388
+ *
1389
+ * Everything is listed, whichever phase it belongs to, because a problem in the phase an author
1390
+ * is not looking at is exactly the one they would otherwise hunt for. Nodes carrying a problem
1391
+ * are marked in the graph as well.
1392
+ *
1393
+ * Loudest first, so a strip too short to show everything shows what matters. What is left over
1394
+ * at the bottom is the notes — a node nothing reads, most of all — and a graph with nothing but
1395
+ * those still says it has no problems, because it has none: they are things worth knowing about
1396
+ * an effect that compiles.
1397
+ */
1398
+ refreshProblems() {
1399
+ // The graph's own problems, not the running program's: with the code layer authoritative the
1400
+ // graphs are not compiled at all, and a panel that then said "no problems" about a graph
1401
+ // with a dangling input in plain sight would be lying about the thing it is showing.
1402
+ const diagnostics = this.effect.graphDiagnostics();
1403
+
1404
+ this.#diagnostics = diagnostics;
1405
+
1406
+ // stable within a level, so the order the checks found them in survives
1407
+ diagnostics.sort((a, b) =>
1408
+ PARTICLE_GRAPH_SEVERITY_RANK[b.severity] - PARTICLE_GRAPH_SEVERITY_RANK[a.severity]);
1409
+
1410
+ this.#problems.removeAllChildren();
1411
+
1412
+ if (!diagnostics.some(diagnostic => diagnostic.severity !== PARTICLE_GRAPH_INFO)) {
1413
+ this.#problems.addChild(new LabelView("No problems.", { classList: ['none'] }));
1414
+ }
1415
+
1416
+ for (const diagnostic of diagnostics) {
1417
+ const entry = new EmptyView({ classList: ['problem', diagnostic.severity] });
1418
+
1419
+ const where = diagnostic.node >= 0
1420
+ ? `${diagnostic.scope}: node ${diagnostic.node}`
1421
+ : diagnostic.scope;
1422
+
1423
+ entry.addChild(new LabelView(where, { classList: ['where'] }));
1424
+ entry.addChild(new LabelView(diagnostic.message, { classList: ['message'] }));
1425
+
1426
+ if (diagnostic.node >= 0) {
1427
+ entry.el.addEventListener('click', () => this.revealNode(diagnostic.scope, diagnostic.node));
1428
+ }
1429
+
1430
+ this.#problems.addChild(entry);
1431
+ }
1432
+
1433
+ this.#markProblemNodes(diagnostics);
1434
+ }
1435
+
1436
+ /**
1437
+ * Put a class on the view of every node a diagnostic names, so the graph shows where the
1438
+ * problems are and not only the list below it.
1439
+ *
1440
+ * @param {Array<{scope: string, node: number, severity: string}>} diagnostics
1441
+ */
1442
+ #markProblemNodes(diagnostics) {
1443
+ for (const phase of this.#phases) {
1444
+ for (const node_id of phase.editor.graphView.nodeViews.keys()) {
1445
+ this.#markNode(phase.id, node_id, diagnostics);
1446
+ }
1447
+ }
1448
+ }
1449
+
1450
+ /**
1451
+ * Mark one node from the diagnostics in hand.
1452
+ *
1453
+ * @param {string} phase_id
1454
+ * @param {number} node_id
1455
+ * @param {Array<{scope: string, node: number, severity: string}>} [diagnostics]
1456
+ */
1457
+ #markNode(phase_id, node_id, diagnostics = this.#diagnostics) {
1458
+ const phase = this.#phases.find(candidate => candidate.id === phase_id);
1459
+ const nodeView = phase?.editor.graphView.nodeViews.get(node_id);
1460
+
1461
+ if (nodeView === undefined) {
1462
+ return;
1463
+ }
1464
+
1465
+ let severity;
1466
+
1467
+ for (const diagnostic of diagnostics) {
1468
+ if (diagnostic.scope !== phase_id || diagnostic.node !== node_id) {
1469
+ continue;
1470
+ }
1471
+
1472
+ // a node wears the loudest thing said about it: an error over a warning, either over a note
1473
+ if (
1474
+ severity === undefined
1475
+ || PARTICLE_GRAPH_SEVERITY_RANK[diagnostic.severity] > PARTICLE_GRAPH_SEVERITY_RANK[severity]
1476
+ ) {
1477
+ severity = diagnostic.severity;
1478
+ }
1479
+ }
1480
+
1481
+ nodeView.setClass('has-error', severity === PARTICLE_GRAPH_ERROR);
1482
+ nodeView.setClass('has-warning', severity === PARTICLE_GRAPH_WARNING);
1483
+ nodeView.setClass('has-info', severity === PARTICLE_GRAPH_INFO);
1484
+ }
1485
+
1486
+ /**
1487
+ * Switch to the phase a node is in and centre the view on it.
1488
+ *
1489
+ * @param {string} phase_id `"init"` or `"update"`
1490
+ * @param {number} node_id
1491
+ */
1492
+ revealNode(phase_id, node_id) {
1493
+ const phase = this.#phases.find(candidate => candidate.id === phase_id);
1494
+
1495
+ if (phase === undefined) {
1496
+ return;
1497
+ }
1498
+
1499
+ this.setPhase(phase_id);
1500
+
1501
+ const visual = this.effect[`${phase_id}_visual`].getNode(node_id);
1502
+
1503
+ if (visual === undefined) {
1504
+ return;
1505
+ }
1506
+
1507
+ const camera = phase.editor.camera;
1508
+ const scale = camera.scale.getValue();
1509
+
1510
+ camera.position.set(
1511
+ visual.dimensions.position.x + visual.dimensions.size.x / 2 - (phase.editor.size.x / 2) / scale,
1512
+ visual.dimensions.position.y + visual.dimensions.size.y / 2 - (phase.editor.size.y / 2) / scale
1513
+ );
1514
+
1515
+ phase.editor.selection.nodes.reset();
1516
+ phase.editor.selection.nodes.add(node_id);
1517
+ }
1518
+
1519
+ /**
1520
+ * The add-node menu of the canvas currently on screen — a test's way in, and a host's way to
1521
+ * open it from a menu of its own.
1522
+ *
1523
+ * @returns {import("../../node-graph/NodeGraphSearchMenuView.js").NodeGraphSearchMenuView|null}
1524
+ */
1525
+ searchMenu() {
1526
+ return this.activeEditor().searchMenu;
1527
+ }
1528
+
1529
+ layout() {
1530
+ const width = this.size.x;
1531
+ const height = this.size.y;
1532
+
1533
+ const body_height = Math.max(0, height - TOOLBAR_HEIGHT - PROBLEMS_HEIGHT);
1534
+
1535
+ this.#toolbar.position.set(0, 0);
1536
+ this.#toolbar.size.set(width, TOOLBAR_HEIGHT);
1537
+
1538
+ this.#body.position.set(0, TOOLBAR_HEIGHT);
1539
+ this.#body.size.set(width, body_height);
1540
+
1541
+ // Every canvas takes the whole body — the phases, and any group opened over them — because
1542
+ // exactly one of them is visible at a time.
1543
+ for (const canvas of [...this.#phases.map(phase => phase.editor), ...this.#open_groups.map(open => open.editor)]) {
1544
+ canvas.position.set(0, 0);
1545
+ canvas.size.set(width, body_height);
1546
+ }
1547
+
1548
+ this.#problems.position.set(0, TOOLBAR_HEIGHT + body_height);
1549
+ this.#problems.size.set(width, PROBLEMS_HEIGHT);
1550
+
1551
+ this.#frameIfNeeded();
1552
+ }
1553
+
1554
+ /**
1555
+ * Point the camera of any phase arranged for the first time at what the arranging produced.
1556
+ *
1557
+ * Two things have to have happened, and they arrive in either order — hence trying from both
1558
+ * ends. The editor needs a size, or there is no viewport to fit a graph into. And its
1559
+ * arrangement has to be the final one: a graph arranged before its nodes were drawn is arranged
1560
+ * again from their real sizes, and a camera aimed at the first attempt is aimed at where the
1561
+ * nodes were about to stop being.
1562
+ */
1563
+ #frameIfNeeded() {
1564
+ for (const phase of this.#phases) {
1565
+ if (!this.#needs_framing.has(phase.id)) {
1566
+ continue;
1567
+ }
1568
+
1569
+ const editor = phase.editor;
1570
+
1571
+ if (editor.size.x <= 0 || editor.size.y <= 0) {
1572
+ continue;
1573
+ }
1574
+
1575
+ if (editor.isArrangementProvisional()) {
1576
+ continue;
1577
+ }
1578
+
1579
+ this.#needs_framing.delete(phase.id);
1580
+
1581
+ editor.cameraContainAll();
1582
+ }
1583
+ }
1584
+ }
1585
+
1586
+ /**
1587
+ * The glyph a group made out of a selection carries: a box with a smaller box inside it, which is
1588
+ * what one is.
1589
+ *
1590
+ * @type {string}
1591
+ */
1592
+ const PARTICLE_GROUP_ICON = "M4 5h16v14H4z M9 10h6v4H9z";
1593
+
1594
+ /**
1595
+ * The middle of a set of nodes, in graph space, so a group lands where the thing it replaced was.
1596
+ *
1597
+ * @param {NodeGraphVisualData} visual
1598
+ * @param {number[]} nodes
1599
+ * @returns {{x: number, y: number}}
1600
+ */
1601
+ function centroid(visual, nodes) {
1602
+ let x = 0;
1603
+ let y = 0;
1604
+ let counted = 0;
1605
+
1606
+ for (const id of nodes) {
1607
+ const placed = visual.getNode(id);
1608
+
1609
+ if (placed === undefined) {
1610
+ continue;
1611
+ }
1612
+
1613
+ x += placed.dimensions.position.x;
1614
+ y += placed.dimensions.position.y;
1615
+
1616
+ counted++;
1617
+ }
1618
+
1619
+ return counted === 0 ? { x: 0, y: 0 } : { x: x / counted, y: y / counted };
1620
+ }
1621
+
1622
+ /**
1623
+ * The top-left corner of a group's body, so what comes out of an ungrouping keeps its arrangement
1624
+ * relative to where the group node was rather than jumping to wherever the body happens to sit.
1625
+ *
1626
+ * @param {import("../../../../src/shade/renderer/particles/graph/ParticleNodeGroup.js").ParticleNodeGroup} group
1627
+ * @returns {{x: number, y: number}}
1628
+ */
1629
+ function body_origin(group) {
1630
+ let x = Infinity;
1631
+ let y = Infinity;
1632
+
1633
+ for (const node of group.graph.getNodes()) {
1634
+ const placed = group.visual.getNode(node.id);
1635
+
1636
+ if (placed === undefined) {
1637
+ continue;
1638
+ }
1639
+
1640
+ x = Math.min(x, placed.dimensions.position.x);
1641
+ y = Math.min(y, placed.dimensions.position.y);
1642
+ }
1643
+
1644
+ return Number.isFinite(x) ? { x, y } : { x: 0, y: 0 };
1645
+ }
1646
+
1647
+
1648
+ /**
1649
+ * @param {string} type node type name
1650
+ * @returns {string}
1651
+ */
1652
+ function category_of(type) {
1653
+ const index = category_rank(type);
1654
+
1655
+ return index === PALETTE_CATEGORIES.length ? "other" : PALETTE_CATEGORIES[index].name;
1656
+ }
1657
+
1658
+ /**
1659
+ * @param {string} type node type name
1660
+ * @returns {number} index into {@link PALETTE_CATEGORIES}, or its length for an uncategorised type
1661
+ */
1662
+ function category_rank(type) {
1663
+ const index = PALETTE_CATEGORIES.findIndex(candidate => candidate.types.includes(type));
1664
+
1665
+ return index === -1 ? PALETTE_CATEGORIES.length : index;
1666
+ }