ue-mcp 1.2.4 → 1.3.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 (243) hide show
  1. package/README.md +4 -3
  2. package/dist/action-class.js +56 -3
  3. package/dist/action-class.js.map +1 -1
  4. package/dist/bridge-timeouts.d.ts +64 -0
  5. package/dist/bridge-timeouts.js +118 -0
  6. package/dist/bridge-timeouts.js.map +1 -0
  7. package/dist/bridge.js +10 -2
  8. package/dist/bridge.js.map +1 -1
  9. package/dist/editor-control.d.ts +72 -5
  10. package/dist/editor-control.js +164 -140
  11. package/dist/editor-control.js.map +1 -1
  12. package/dist/editor-target.d.ts +55 -1
  13. package/dist/editor-target.js +107 -10
  14. package/dist/editor-target.js.map +1 -1
  15. package/dist/engine-observer.d.ts +59 -5
  16. package/dist/engine-observer.js +249 -29
  17. package/dist/engine-observer.js.map +1 -1
  18. package/dist/engine-root.d.ts +91 -0
  19. package/dist/engine-root.js +448 -0
  20. package/dist/engine-root.js.map +1 -0
  21. package/dist/epic-enrich.js +16 -1
  22. package/dist/epic-enrich.js.map +1 -1
  23. package/dist/feedback-cli.js +4 -0
  24. package/dist/feedback-cli.js.map +1 -1
  25. package/dist/feedback-deferred.d.ts +9 -0
  26. package/dist/feedback-deferred.js +2 -0
  27. package/dist/feedback-deferred.js.map +1 -1
  28. package/dist/feedback-fallback.d.ts +99 -0
  29. package/dist/feedback-fallback.js +173 -0
  30. package/dist/feedback-fallback.js.map +1 -0
  31. package/dist/flow/write-methods.js +20 -0
  32. package/dist/flow/write-methods.js.map +1 -1
  33. package/dist/lean-context.js +8 -3
  34. package/dist/lean-context.js.map +1 -1
  35. package/dist/locking.js +11 -2
  36. package/dist/locking.js.map +1 -1
  37. package/dist/project.d.ts +11 -0
  38. package/dist/project.js +23 -2
  39. package/dist/project.js.map +1 -1
  40. package/dist/python-gate.d.ts +95 -0
  41. package/dist/python-gate.js +175 -0
  42. package/dist/python-gate.js.map +1 -0
  43. package/dist/tool-counts.json +16 -16
  44. package/dist/tools/animation.js +288 -24
  45. package/dist/tools/animation.js.map +1 -1
  46. package/dist/tools/asset.js +79 -14
  47. package/dist/tools/asset.js.map +1 -1
  48. package/dist/tools/audio.js +59 -5
  49. package/dist/tools/audio.js.map +1 -1
  50. package/dist/tools/blueprint.js +29 -12
  51. package/dist/tools/blueprint.js.map +1 -1
  52. package/dist/tools/chooser.js +4 -1
  53. package/dist/tools/chooser.js.map +1 -1
  54. package/dist/tools/editor.js +81 -43
  55. package/dist/tools/editor.js.map +1 -1
  56. package/dist/tools/feedback.js +214 -48
  57. package/dist/tools/feedback.js.map +1 -1
  58. package/dist/tools/foliage.js +27 -1
  59. package/dist/tools/foliage.js.map +1 -1
  60. package/dist/tools/gameplay.js +38 -11
  61. package/dist/tools/gameplay.js.map +1 -1
  62. package/dist/tools/gas.js +17 -5
  63. package/dist/tools/gas.js.map +1 -1
  64. package/dist/tools/landscape.js +22 -7
  65. package/dist/tools/landscape.js.map +1 -1
  66. package/dist/tools/level.js +322 -51
  67. package/dist/tools/level.js.map +1 -1
  68. package/dist/tools/material.js +10 -4
  69. package/dist/tools/material.js.map +1 -1
  70. package/dist/tools/niagara.js +3 -2
  71. package/dist/tools/niagara.js.map +1 -1
  72. package/dist/tools/pcg.js +6 -5
  73. package/dist/tools/pcg.js.map +1 -1
  74. package/dist/tools/project.js +47 -20
  75. package/dist/tools/project.js.map +1 -1
  76. package/dist/types.d.ts +21 -0
  77. package/dist/types.js +46 -3
  78. package/dist/types.js.map +1 -1
  79. package/dist/ue-mcp.default.yml +493 -125
  80. package/package.json +2 -2
  81. package/plugin/ue_mcp_bridge/NATIVE_RUNTIME_VISIBILITY.md +53 -0
  82. package/plugin/ue_mcp_bridge/NATIVE_STATIC_MESH_USAGE_PROGRESS.md +115 -0
  83. package/plugin/ue_mcp_bridge/README_MassHandlers.md +97 -0
  84. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +14 -0
  85. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +21 -4
  86. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +9 -0
  87. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +395 -69
  88. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +79 -3
  89. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +25 -0
  90. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +3 -3
  91. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +3061 -0
  92. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +961 -0
  93. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +900 -0
  94. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Pose.cpp +769 -0
  95. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +44 -3
  96. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +217 -11
  97. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +551 -24
  98. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +735 -0
  99. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +352 -73
  100. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +8 -0
  101. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -1
  102. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.cpp +503 -0
  103. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.h +21 -0
  104. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +2 -2
  105. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Enum.cpp +2 -2
  106. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.cpp +902 -0
  107. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.h +33 -0
  108. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +478 -134
  109. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +5 -5
  110. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +933 -0
  111. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.h +35 -0
  112. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +478 -0
  113. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_RenderTarget.cpp +1 -1
  114. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +4 -4
  115. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +2 -2
  116. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +319 -0
  117. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +3 -3
  118. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +482 -35
  119. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +10 -0
  120. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.cpp +502 -0
  121. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.h +43 -0
  122. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +89 -7
  123. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -51
  124. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +107 -0
  125. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +10 -10
  126. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +648 -0
  127. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +5 -1
  128. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.cpp +252 -1
  129. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.h +10 -2
  130. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +252 -41
  131. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +4 -0
  132. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +250 -27
  133. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +303 -125
  134. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +73 -50
  135. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +757 -0
  136. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +11 -2
  137. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +3 -0
  138. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +419 -0
  139. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +39 -161
  140. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +66 -1
  141. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +1323 -0
  142. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BehaviorTree.cpp +1211 -0
  143. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +2 -0
  144. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +60 -0
  145. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +363 -12
  146. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/HandlerEditorState.h +84 -0
  147. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +1288 -36
  148. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +3 -0
  149. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +41 -16
  150. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +959 -213
  151. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +66 -0
  152. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1571 -0
  153. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +316 -0
  154. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Inspection.cpp +280 -0
  155. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +666 -0
  156. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection_Internal.h +63 -0
  157. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +43 -12
  158. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -47
  159. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +527 -0
  160. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1169 -0
  161. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +723 -0
  162. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +325 -0
  163. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Spatial.cpp +360 -0
  164. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Trace.cpp +178 -58
  165. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +337 -0
  166. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +25 -12
  167. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +10 -9
  168. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +686 -0
  169. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.cpp +467 -0
  170. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.h +22 -0
  171. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +452 -175
  172. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +5 -0
  173. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +597 -0
  174. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +17 -15
  175. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +38 -168
  176. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +39 -30
  177. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +392 -78
  178. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +2 -0
  179. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers_Internal.h +83 -0
  180. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +200 -0
  181. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.h +15 -0
  182. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +19 -12
  183. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +31 -1
  184. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +307 -69
  185. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +84 -0
  186. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +8 -41
  187. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +33 -52
  188. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/ActorSelectorTests.cpp +344 -0
  189. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationControlRigTimelineTests.cpp +60 -0
  190. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationPoseTests.cpp +115 -0
  191. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetBulkReadTests.cpp +177 -0
  192. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +276 -0
  193. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPathResolutionTests.cpp +243 -0
  194. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +213 -0
  195. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +235 -0
  196. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AutomationRunnerTests.cpp +72 -0
  197. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp +526 -0
  198. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeNodeTests.cpp +334 -0
  199. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BlueprintHandlerSurfaceTests.cpp +362 -0
  200. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BridgeProtocolTests.cpp +14 -0
  201. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/CollisionQueryTests.cpp +288 -0
  202. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +453 -0
  203. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/EditorFunctionCallTests.cpp +223 -0
  204. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/FoliageBatchTests.cpp +147 -0
  205. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GameThreadGateTests.cpp +82 -0
  206. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GasLiveAttributeTests.cpp +183 -0
  207. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LandscapeSampleTests.cpp +119 -0
  208. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelBatchWriteTests.cpp +176 -0
  209. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelComponentTreeInstanceCountTests.cpp +189 -0
  210. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelConvertBrushesTests.cpp +100 -0
  211. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelInstanceProjectionTests.cpp +265 -0
  212. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelPostProcessOverrideTests.cpp +258 -0
  213. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelQueryComponentsTests.cpp +195 -0
  214. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelRefreshTests.cpp +142 -0
  215. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelSaveReportTests.cpp +125 -0
  216. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelScriptHandlersTests.cpp +42 -0
  217. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelStaticMeshUsageTests.cpp +412 -0
  218. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTraceWorldScopeTests.cpp +133 -0
  219. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTransientActorTests.cpp +205 -0
  220. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelWorldPartitionSettingsTests.cpp +168 -0
  221. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +51 -0
  222. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTests.cpp +379 -0
  223. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MaterialBuildTests.cpp +238 -0
  224. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshBooleanTests.cpp +170 -0
  225. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshGeometryTests.cpp +116 -0
  226. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageSaveExtensionTests.cpp +161 -0
  227. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +253 -0
  228. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/RuntimeVisibilityTests.cpp +143 -0
  229. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerHandlerTests.cpp +660 -0
  230. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerScrubTests.cpp +50 -0
  231. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SkeletonDiffTests.cpp +685 -0
  232. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/WidgetBlueprintResolveTests.cpp +145 -0
  233. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +80 -0
  234. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerFunctionCall.h +509 -0
  235. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerQuery.h +407 -0
  236. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +1008 -77
  237. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
  238. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/MCPEngineStatus.cpp +152 -14
  239. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp +65 -0
  240. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Public/MCPEngineStatus.h +32 -1
  241. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/UE_MCP_BridgeStatus.Build.cs +2 -0
  242. package/skills/ue-mcp-animation/SKILL.md +154 -0
  243. package/skills/ue-mcp-blueprint/SKILL.md +71 -0
@@ -1,6 +1,226 @@
1
1
  import { z } from "zod";
2
2
  import { categoryTool, bp } from "../types.js";
3
3
  import { Vec3, Quat } from "../schemas.js";
4
+ // Keep the Control Rig operation schema self-contained so adding it does not
5
+ // redirect JSON-schema references used by older animation actions.
6
+ const ControlRigVec3 = z.object({
7
+ x: z.number().finite(),
8
+ y: z.number().finite(),
9
+ z: z.number().finite(),
10
+ }).strict();
11
+ const ControlRigRotator = z.object({ pitch: z.number(), yaw: z.number(), roll: z.number() }).strict();
12
+ const ControlRigQuaternion = z.object({
13
+ x: z.number().finite(),
14
+ y: z.number().finite(),
15
+ z: z.number().finite(),
16
+ w: z.number().finite(),
17
+ }).strict().refine((rotation) => Math.abs(Math.hypot(rotation.x, rotation.y, rotation.z, rotation.w) - 1) <= 1e-3, { message: "rotationQuaternion must be normalized" });
18
+ const ControlRigKeyTransform = z.object({
19
+ translation: ControlRigVec3,
20
+ rotationDegrees: ControlRigRotator,
21
+ scale: ControlRigVec3,
22
+ }).strict();
23
+ const ControlRigSetEdit = z.object({
24
+ op: z.literal("set"),
25
+ control: z.string().min(1),
26
+ frame: z.number().int().optional(),
27
+ frames: z.array(z.number().int()).min(1).optional(),
28
+ transform: ControlRigKeyTransform,
29
+ space: z.enum(["local", "global"]).optional(),
30
+ }).strict().refine((edit) => (edit.frame === undefined) !== (edit.frames === undefined), { message: "set operations require exactly one of frame or frames" });
31
+ const ControlRigTransformKey = z.object({
32
+ frame: z.number().int(),
33
+ transform: z.object({
34
+ translation: ControlRigVec3,
35
+ rotationQuaternion: ControlRigQuaternion,
36
+ scale: ControlRigVec3,
37
+ }).strict(),
38
+ }).strict();
39
+ const ControlRigSetKeysEdit = z.object({
40
+ op: z.literal("set_keys"),
41
+ control: z.string().min(1),
42
+ keys: z.array(ControlRigTransformKey).min(1),
43
+ space: z.enum(["local", "global"]).optional(),
44
+ }).strict().refine((edit) => edit.keys.every((key, index) => index === 0 || key.frame > edit.keys[index - 1].frame), { message: "set_keys frames must be strictly increasing" });
45
+ const ControlRigOffsetEdit = z.object({
46
+ op: z.literal("offset"),
47
+ control: z.string().min(1),
48
+ startFrame: z.number().int(),
49
+ endFrame: z.number().int(),
50
+ translationCm: ControlRigVec3.optional(),
51
+ rotationDegrees: ControlRigRotator.optional(),
52
+ scaleMultiplier: ControlRigVec3.optional(),
53
+ space: z.enum(["local", "global"]).optional(),
54
+ blendInFrames: z.number().int().nonnegative().optional(),
55
+ blendOutFrames: z.number().int().nonnegative().optional(),
56
+ }).strict()
57
+ .refine((edit) => edit.endFrame >= edit.startFrame, {
58
+ message: "offset endFrame must be greater than or equal to startFrame",
59
+ })
60
+ .refine((edit) => edit.translationCm !== undefined || edit.rotationDegrees !== undefined || edit.scaleMultiplier !== undefined, { message: "offset operations require translationCm, rotationDegrees, or scaleMultiplier" });
61
+ const ControlRigContactTarget = z.object({
62
+ translation: ControlRigVec3,
63
+ rotationQuaternion: ControlRigQuaternion.optional(),
64
+ }).strict();
65
+ const ControlRigContactLockEdit = z.object({
66
+ op: z.literal("contact_lock"),
67
+ control: z.string().min(1),
68
+ drivenReference: z.string().min(1).optional(),
69
+ startFrame: z.number().int(),
70
+ endFrame: z.number().int(),
71
+ target: ControlRigContactTarget,
72
+ blendInFrames: z.number().int().nonnegative().optional(),
73
+ blendOutFrames: z.number().int().nonnegative().optional(),
74
+ stabilizeControls: z.array(z.string().min(1)).max(8).optional(),
75
+ positionToleranceCm: z.number().finite().positive().max(100).optional(),
76
+ rotationToleranceDegrees: z.number().finite().positive().max(180).optional(),
77
+ }).strict().superRefine((edit, context) => {
78
+ if (edit.endFrame < edit.startFrame) {
79
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["endFrame"], message: "contact_lock endFrame must be at least startFrame" });
80
+ return;
81
+ }
82
+ const intervalCount = edit.endFrame - edit.startFrame;
83
+ const blendIn = edit.blendInFrames ?? 0;
84
+ const blendOut = edit.blendOutFrames ?? 0;
85
+ if (blendIn + blendOut > intervalCount) {
86
+ context.addIssue({
87
+ code: z.ZodIssueCode.custom,
88
+ path: ["blendOutFrames"],
89
+ message: "contact_lock blends must leave at least one fully constrained frame",
90
+ });
91
+ }
92
+ const controlKey = edit.control.toLowerCase();
93
+ const stabilizerKeys = (edit.stabilizeControls ?? []).map((control) => control.toLowerCase());
94
+ if (stabilizerKeys.includes(controlKey)) {
95
+ context.addIssue({
96
+ code: z.ZodIssueCode.custom,
97
+ path: ["stabilizeControls"],
98
+ message: "contact_lock control cannot also be a stabilizer",
99
+ });
100
+ }
101
+ if (new Set(stabilizerKeys).size !== stabilizerKeys.length) {
102
+ context.addIssue({
103
+ code: z.ZodIssueCode.custom,
104
+ path: ["stabilizeControls"],
105
+ message: "contact_lock stabilizers must be unique",
106
+ });
107
+ }
108
+ const frameCount = intervalCount + 1;
109
+ if (frameCount * (stabilizerKeys.length + 1) > 100_000) {
110
+ context.addIssue({
111
+ code: z.ZodIssueCode.custom,
112
+ path: ["endFrame"],
113
+ message: "contact_lock is limited to 100000 control-frame cells",
114
+ });
115
+ }
116
+ });
117
+ const ControlRigSetBoolEdit = z.object({
118
+ op: z.literal("set_bool"),
119
+ control: z.string().min(1),
120
+ frame: z.number().int().optional(),
121
+ frames: z.array(z.number().int()).min(1).optional(),
122
+ value: z.boolean(),
123
+ }).strict().refine((edit) => (edit.frame === undefined) !== (edit.frames === undefined), { message: "set_bool operations require exactly one of frame or frames" });
124
+ const ControlRigSetFloatEdit = z.object({
125
+ op: z.literal("set_float"),
126
+ control: z.string().min(1),
127
+ frame: z.number().int().optional(),
128
+ frames: z.array(z.number().int()).min(1).optional(),
129
+ value: z.number().finite(),
130
+ }).strict().refine((edit) => (edit.frame === undefined) !== (edit.frames === undefined), { message: "set_float operations require exactly one of frame or frames" });
131
+ const ControlRigSetIntEdit = z.object({
132
+ op: z.literal("set_int"),
133
+ control: z.string().min(1),
134
+ frame: z.number().int().optional(),
135
+ frames: z.array(z.number().int()).min(1).optional(),
136
+ value: z.number().int(),
137
+ }).strict().refine((edit) => (edit.frame === undefined) !== (edit.frames === undefined), { message: "set_int operations require exactly one of frame or frames" });
138
+ const ControlRigEditOperation = z.union([
139
+ ControlRigSetEdit,
140
+ ControlRigSetKeysEdit,
141
+ ControlRigOffsetEdit,
142
+ ControlRigContactLockEdit,
143
+ ControlRigSetBoolEdit,
144
+ ControlRigSetFloatEdit,
145
+ ControlRigSetIntEdit,
146
+ ]);
147
+ const IKRigAuthoringChain = z.object({
148
+ name: z.string().min(1),
149
+ startBone: z.string().min(1),
150
+ endBone: z.string().min(1),
151
+ goal: z.string().min(1).optional(),
152
+ }).strict();
153
+ const IKRigFullBodyGoal = z.object({
154
+ name: z.string().min(1),
155
+ bone: z.string().min(1),
156
+ positionAlpha: z.number().finite().min(0).max(1).optional(),
157
+ rotationAlpha: z.number().finite().min(0).max(1).optional(),
158
+ chainDepth: z.number().int().nonnegative().optional(),
159
+ strengthAlpha: z.number().finite().min(0).max(1).optional(),
160
+ pullChainAlpha: z.number().finite().min(0).max(1).optional(),
161
+ pinRotation: z.number().finite().min(0).max(1).optional(),
162
+ }).strict();
163
+ const IKRigFullBodySettings = z.object({
164
+ solverIndex: z.number().int().nonnegative().optional(),
165
+ rootBone: z.string().min(1),
166
+ enabled: z.boolean().optional(),
167
+ goals: z.array(IKRigFullBodyGoal).min(1).max(256),
168
+ }).strict();
169
+ const IKRigExclusion = z.object({
170
+ bone: z.string().min(1),
171
+ excluded: z.boolean(),
172
+ }).strict();
173
+ const IKRetargetChainMapping = z.object({
174
+ targetChain: z.string().min(1),
175
+ sourceChain: z.string().min(1).nullable().optional(),
176
+ }).strict();
177
+ const IKRetargetPose = z.object({
178
+ side: z.enum(["source", "target"]),
179
+ name: z.string().min(1),
180
+ create: z.boolean().optional(),
181
+ reset: z.boolean().optional(),
182
+ autoAlign: z.enum(["chain_to_chain", "mesh_to_mesh", "local_axes", "global_axes"]).optional(),
183
+ bones: z.array(z.string().min(1)).max(10_000).optional(),
184
+ rotationOffsets: z.array(z.object({
185
+ bone: z.string().min(1),
186
+ rotationQuaternion: ControlRigQuaternion,
187
+ }).strict()).max(10_000).optional(),
188
+ rootOffsetZ: z.number().finite().optional(),
189
+ snapBoneToGround: z.string().min(1).optional(),
190
+ }).strict().refine((pose) => pose.rootOffsetZ === undefined || pose.snapBoneToGround === undefined, { message: "retarget pose rootOffsetZ and snapBoneToGround are mutually exclusive" });
191
+ /**
192
+ * Element schemas for the Motion Matching authoring arrays (#936).
193
+ *
194
+ * These were `z.array(z.any())`, which serialises to an array schema with no
195
+ * `items`; VS Code refuses to load a tool that carries one. Each object stays
196
+ * open (`.passthrough()`) so nothing a caller sends today is dropped, and the
197
+ * entries that the handler also accepts as a bare string keep that spelling
198
+ * through a union rather than an untyped element.
199
+ */
200
+ /** set_pose_search_clips: one clip entry. The handler accepts any of the four path spellings. */
201
+ const PoseSearchClipEntry = z.object({
202
+ sequencePath: z.string().optional().describe("Animation asset path (aliases: asset, assetPath, animationPath)"),
203
+ asset: z.string().optional().describe("Alias for sequencePath"),
204
+ assetPath: z.string().optional().describe("Alias for sequencePath"),
205
+ animationPath: z.string().optional().describe("Alias for sequencePath"),
206
+ mirror: z.string().optional().describe("'original' | 'mirrored' | 'both'"),
207
+ disableReselection: z.boolean().optional().describe("Disallow reselecting poses from the same asset"),
208
+ sampleStart: z.number().optional().describe("Sampling range start in seconds"),
209
+ sampleEnd: z.number().optional().describe("Sampling range end in seconds"),
210
+ enabled: z.boolean().optional().describe("Include the clip in the database"),
211
+ }).passthrough();
212
+ /** add_pose_search_schema_pose_channel: one sampled bone. */
213
+ const PoseSearchBoneEntry = z.object({
214
+ bone: z.string().describe("Bone name"),
215
+ flags: z.array(z.string()).optional().describe("Any of: velocity, position, rotation, phase"),
216
+ weight: z.number().optional().describe("Per-bone weight (default 1)"),
217
+ }).passthrough();
218
+ /** create_mirror_data_table: one find/replace bone-name rule. */
219
+ const MirrorFindReplaceExpression = z.object({
220
+ find: z.string().describe("Bone-name fragment to match"),
221
+ replace: z.string().describe("Replacement fragment"),
222
+ method: z.string().optional().describe("suffix (default) | prefix | regex"),
223
+ }).passthrough();
4
224
  export const animationTool = categoryTool("animation", "Animation assets, skeletons, montages, blendspaces, anim blueprints, physics assets.", {
5
225
  read_anim_blueprint: bp("Read AnimBP structure. Params: assetPath", "read_anim_blueprint"),
6
226
  read_montage: bp("Read montage. Params: assetPath", "read_anim_montage", (p) => ({ assetPath: p.assetPath })),
@@ -16,7 +236,7 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
16
236
  create_blendspace: bp("Create blendspace (2D). Params: skeletonPath, name?, packagePath?, axisHorizontal?, axisVertical?", "create_blendspace"),
17
237
  create_blendspace_1d: bp("Create BlendSpace1D. Params: skeletonPath, name?, packagePath?, axisName? (default Speed), axisMin?, axisMax?, gridNum? (#459)", "create_blendspace_1d", (p) => ({ name: p.name, skeletonPath: p.skeletonPath, packagePath: p.packagePath, axisName: p.axisName, axisMin: p.axisMin, axisMax: p.axisMax, gridNum: p.gridNum, onConflict: p.onConflict })),
18
238
  populate_blendspace: bp("One-call axis params + samples authoring for BlendSpace 1D/2D. Params: assetPath, axis? ({name?, min?, max?, gridNum?}) for axis 0, blendspaceAxes? (per-axis array), axisHorizontal?/axisVertical? + horizontalMin/horizontalMax/verticalMin/verticalMax/gridNumHorizontal/gridNumVertical (back-compat), samples ([{animationPath, x, y?}]), clearExisting? (default true) (#459)", "populate_blendspace", (p) => ({ assetPath: p.assetPath, axis: p.axis, axes: p.blendspaceAxes, axisIndex: p.axisIndex, axisHorizontal: p.axisHorizontal, axisVertical: p.axisVertical, horizontalMin: p.horizontalMin, horizontalMax: p.horizontalMax, verticalMin: p.verticalMin, verticalMax: p.verticalMax, gridNumHorizontal: p.gridNumHorizontal, gridNumVertical: p.gridNumVertical, samples: p.samples, clearExisting: p.clearExisting })),
19
- add_notify: bp("Add notify. For PlayMontageNotify the notifyName is also written onto the spawned notify object so OnPlayMontageNotifyBegin broadcasts it (not 'None'), and montage branching-point markers refresh (#528). notifyProperties writes EditAnywhere fields onto the spawned notify object and therefore requires a notifyClass that resolves. Params: assetPath, notifyName, triggerTime, notifyClass?, notifyProperties?", "add_anim_notify"),
239
+ add_notify: bp("Add notify. For PlayMontageNotify the notifyName is also written onto the spawned notify object so OnPlayMontageNotifyBegin broadcasts it (not 'None'), and montage branching-point markers refresh (#528/#880). On a montage the PlayMontageNotify classes are added as BRANCHING POINT notifies, which is the only tick type UAnimNotify_PlayMontageNotify::BranchingPointNotify runs at, so OnPlayMontageNotifyBegin broadcasts without a montage reload; pass branchingPoint to force it either way, and read branchingPointMarkerCount in the response to see what the montage cached. notifyProperties writes EditAnywhere fields onto the spawned notify object and therefore requires a notifyClass that resolves. Params: assetPath, notifyName, triggerTime, notifyClass?, notifyProperties?", "add_anim_notify"),
20
240
  remove_notify: bp("Remove notify(s) by name and/or class. Pass at least one of notifyName/notifyClass; both filters AND. Idempotent: alreadyDeleted=true if no match. Params: assetPath, notifyName?, notifyClass? (#471)", "remove_anim_notify", (p) => ({ assetPath: p.assetPath, notifyName: p.notifyName, notifyClass: p.notifyClass })),
21
241
  get_skeleton_info: bp("Read skeleton. Params: assetPath", "get_skeleton_info"),
22
242
  list_sockets: bp("List sockets. Params: assetPath", "list_animation_sockets"),
@@ -47,22 +267,29 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
47
267
  remove_montage_segment: bp("Remove a segment from a montage slot by index, then relay out the remaining segments and rewrite the montage length. Idempotent: alreadyDeleted=true when the slot already holds no segments. Params: assetPath, segmentIndex, slotName?, slotIndex? (default 0) (#826)", "remove_montage_segment", (p) => ({ assetPath: p.assetPath, segmentIndex: p.segmentIndex, slotName: p.slotName, slotIndex: p.slotIndex })),
48
268
  list_montage_segments: bp("List every slot's segments on a montage so a caller can address them by index: animation path, startPos/endPos trim, playRate, loopCount, track position and length per segment, plus the sections with the slot and segment each one links to. Params: assetPath, slotName? (filter to one slot) (#826)", "list_montage_segments", (p) => ({ assetPath: p.assetPath, slotName: p.slotName })),
49
269
  create_ik_rig: bp("Create IKRigDefinition asset, optionally with retargetRoot + chains[]. Params: name, skeletalMeshPath, packagePath?, retargetRoot?, chains?: [{name, startBone, endBone, goal?}]", "create_ik_rig"),
50
- read_ik_rig: bp("Read IK Rig chains, solvers, skeleton. Params: assetPath", "read_ik_rig"),
270
+ read_ik_rig: bp("Read an IK Rig's preview mesh, skeleton roots/bones, ancestry-validated chains and goal assignments, concrete goals, exclusions, and structured solver/FBIK effector state. Params: assetPath", "read_ik_rig"),
271
+ configure_ik_rig: bp("UE 5.8 only. Author an existing IK Rig through UIKRigController with strict bone, ancestry, goal, and setting validation, native readback, one transaction, and checked save; older engines return unsupported_engine_version. autoSetup='retarget' installs the native retarget definition; 'full_body' installs the retarget definition then Full Body IK before requested desired-state upserts. Params: rigPath, autoSetup? ('retarget'|'full_body'), retargetRoot?, rootMotionBone?, chains?: [{name,startBone,endBone,goal?}], fullBodyIK?: {solverIndex?,rootBone,enabled?,goals:[{name,bone,positionAlpha?,rotationAlpha?,chainDepth?,strengthAlpha?,pullChainAlpha?,pinRotation?}]}, exclusions?: [{bone,excluded}].", "configure_ik_rig", (p) => ({ rigPath: p.rigPath, autoSetup: p.autoSetup, retargetRoot: p.retargetRoot, rootMotionBone: p.rootMotionBone, chains: p.chains, fullBodyIK: p.fullBodyIK, exclusions: p.exclusions })),
51
272
  list_control_rig_variables: bp("List ControlRig variables and hierarchy. Params: assetPath", "list_control_rig_variables"),
52
273
  read_control_rig_graph: bp("Read a Control Rig's RigVM models: every graph with its nodes (name, node path, class), each node's pins (name, pin path, cppType, direction, execute flag, default value, nested sub-pins) and the links between them, plus full member-variable metadata (type, subtype, array-ness, default, public/read-only). list_control_rig_variables only ever reported a node COUNT, which is not enough to verify solver wiring (#774). Params: assetPath, graphName? (substring filter), includePins? (default true), includeDefaults? (default true), includeLinks? (default true), limit? (nodes per graph, default 200)", "read_control_rig_graph", (p) => ({ assetPath: p.assetPath, graphName: p.graphName, includePins: p.includePins, includeDefaults: p.includeDefaults, includeLinks: p.includeLinks, limit: p.limit })),
53
274
  read_control_rig_hierarchy: bp("Read a Control Rig's per-element hierarchy metadata: each element's name, type (Bone|Control|Null|Curve...), index, and parent. Params: assetPath (#619)", "read_control_rig_hierarchy", (p) => ({ assetPath: p.assetPath })),
275
+ begin_control_rig_edit: bp("UE 5.8 only. Create a Sequencer Control Rig editing session over a source AnimSequence; native returns unsupported_engine_version on older engines. Baseline first: before this call, reuse or create a Control Rig for the target character, bind/import the exact target skeleton, add the intended controls, author Forward Solve, add Backward/Inverse Solve, verify it with read_control_rig_hierarchy/read_control_rig_graph, and pass an unchanged source round-trip. For a new baseline, the bundled Epic 5.8 controlrig actions include epic_create, epic_import_bones_from_asset, epic_add_control, and epic_add_backward_solve_graph; epic_create alone is not a usable rig. There is no silent fallback to raw bone-key authoring. rigMode='fk' uses UFKControlRig only when generated FK controls are sufficient; rigMode='asset' requires the verified controlRigPath and rejects rigs without inverse execution. bindingTag is the stable natural key for replay. onConflict is skip|error (default error); existing sessions are never modified. layered defaults false. startFrame is inclusive and endFrame is exclusive. Params: sequencePath, skeletalMeshPath, sourceAnimationPath, rigMode ('fk'|'asset'), controlRigPath?, layered?, startFrame?, endFrame?, displayRate?, bindingTag?, onConflict?. Returns the resolved bindingTag/binding GUID, rig, frame range, controls and created/existed status.", "begin_control_rig_edit", (p) => ({ sequencePath: p.sequencePath, skeletalMeshPath: p.skeletalMeshPath, sourceAnimationPath: p.sourceAnimationPath, rigMode: p.rigMode, controlRigPath: p.controlRigPath, layered: p.layered, startFrame: p.startFrame, endFrame: p.endFrame, displayRate: p.displayRate, bindingTag: p.bindingTag, onConflict: p.onConflict })),
276
+ read_control_rig_edit: bp("UE 5.8 only. Read transform, bool, float/scale-float, and integer/enum controls from a Control Rig editing session without changing editor state; native returns unsupported_engine_version on older engines and has no silent fallback. Params: sequencePath, bindingTag, controlNames?, frames?, space? ('local'|'global'). Scalar samples return value instead of transform. Control metadata includes native controlType, animatable, and enum path/options where applicable. Returns session identity, layered mode, range/rate, filtered control metadata, and requested frame samples.", "read_control_rig_edit", (p) => ({ sequencePath: p.sequencePath, bindingTag: p.bindingTag, controlNames: p.controlNames, frames: p.frames, space: p.space })),
277
+ apply_control_rig_edits: bp("UE 5.8 only. Apply typed Control Rig edits in one transaction; native returns unsupported_engine_version on older engines. There is no silent fallback to raw bone tracks. set_keys writes strictly ordered full per-frame transforms from normalized quaternions and preserves shortest-arc quaternion continuity. A set operation writes one full absolute transform at frame or frames. An offset operation applies translation/rotation/scale deltas across an inclusive frame range with optional edge blends. contact_lock densely constrains a translatable driver control, or an optional driven bone/socket reference, to a fixed component-space target with smooth edge blends and optional pole/control stabilization. Driver and stabilizer keys are read back transactionally. A drivenReference contact returns verification='bake_and_analyze_required'; bake it and analyze every constrained frame before accepting the bone/socket result. set_bool, set_float, and set_int key matching scalar controls; enum controls use set_int with one of the integer values reported in enumOptions. Params: sequencePath, bindingTag, operations[] where set_keys={op:'set_keys',control,keys:[{frame,transform:{translation,rotationQuaternion,scale}}],space?}, set={op:'set',control,frame|frames,transform:{translation,rotationDegrees,scale},space?}, offset={op:'offset',control,startFrame,endFrame,translationCm?,rotationDegrees?,scaleMultiplier?,space?,blendInFrames?,blendOutFrames?}, contact_lock={op:'contact_lock',control,drivenReference?,startFrame,endFrame,target:{translation,rotationQuaternion?},blendInFrames?,blendOutFrames?,stabilizeControls?,positionToleranceCm?,rotationToleranceDegrees?}, set_bool={op:'set_bool',control,frame|frames,value}, set_float={op:'set_float',control,frame|frames,value}, or set_int={op:'set_int',control,frame|frames,value}. Sequencer's current interpolation mode is retained. Returns per-operation counts, affected controls/frames, and contactQa summaries; a failed key/readback batch is undone.", "apply_control_rig_edits", (p) => ({ sequencePath: p.sequencePath, bindingTag: p.bindingTag, operations: p.operations })),
278
+ bake_control_rig_edit: bp("UE 5.8 only. Bake the evaluated Control Rig session to a new AnimSequence asset; native returns unsupported_engine_version on older engines and has no raw-track fallback. The source LevelSequence remains unchanged. outputAssetPath is the output natural key; onConflict is skip|error (default error), never overwrite. Key reduction and Sequencer links are not supported yet, so reduceKeys/createLink must be false or omitted. Params: sequencePath, bindingTag, outputAssetPath, frameRate?, reduceKeys?, tolerance?, createLink?, onConflict?. Returns output asset metadata, frame/rate counts, status, and delete-created-asset rollback.", "bake_control_rig_edit", (p) => ({ sequencePath: p.sequencePath, bindingTag: p.bindingTag, outputAssetPath: p.outputAssetPath, frameRate: p.frameRate, reduceKeys: p.reduceKeys, tolerance: p.tolerance, createLink: p.createLink, onConflict: p.onConflict })),
279
+ analyze_animation: bp("Cross-version, data-driven AnimSequence inspection using the native animation APIs available in the compiled engine. Samples an AnimSequence and reports deterministic numeric motion diagnostics without Python or viewport inference. Params: assetPath (required AnimSequence), skeletalMeshPath?, boneNames?, frames?, sampleRate?, loop?, outputDirectory? (must resolve under Project/Saved/Codex/AnimationQA and must not already contain artifacts). Returns source/rate/range metadata, sampled local/component transforms, root-motion and continuity metrics, and any written analysis artifacts.", "analyze_animation", (p) => ({ assetPath: p.assetPath, skeletalMeshPath: p.skeletalMeshPath, boneNames: p.boneNames, frames: p.frames, sampleRate: p.sampleRate, loop: p.loop, outputDirectory: p.outputDirectory })),
54
280
  set_root_motion: bp("Set root motion settings on AnimSequence. Params: assetPath, enableRootMotion?, forceRootLock?, useNormalizedRootMotionScale?, rootMotionRootLock?", "set_root_motion_settings", (p) => ({ path: p.assetPath, enableRootMotion: p.enableRootMotion, forceRootLock: p.forceRootLock, useNormalizedRootMotionScale: p.useNormalizedRootMotionScale, rootMotionRootLock: p.rootMotionRootLock })),
55
281
  add_virtual_bone: bp("Add virtual bone. Params: skeletonPath, sourceBone, targetBone", "add_virtual_bone"),
56
282
  remove_virtual_bone: bp("Remove virtual bone. Params: skeletonPath, virtualBoneName", "remove_virtual_bone"),
57
283
  create_composite: bp("Create AnimComposite. Params: name, skeletonPath, packagePath?", "create_anim_composite"),
58
284
  list_modifiers: bp("List applied animation modifiers. Params: assetPath", "list_anim_modifiers", (p) => ({ path: p.assetPath })),
59
285
  create_ik_retargeter: bp("Create IKRetargeter asset and (default) initialize the UE 5.7 ops stack: assigns sourceRig+targetRig to all ops, runs AutoMapChains. Returns chainsMapped count. Params: name, packagePath?, sourceRig?, targetRig?, autoMapChains? (default true) (#246)", "create_ik_retargeter", (p) => ({ name: p.name, packagePath: p.packagePath, sourceRig: p.sourceRig, targetRig: p.targetRig, autoMapChains: p.autoMapChains, onConflict: p.onConflict })),
60
- read_ik_retargeter: bp("Read IKRetargeter: source/target rigs and chain mappings. Params: assetPath (#246)", "read_ik_retargeter", (p) => ({ assetPath: p.assetPath })),
286
+ read_ik_retargeter: bp("Read an IK Retargeter's source/target rigs and preview meshes, flattened and per-op chain mappings, typed op stack, and all named/current pose offsets when the compiled engine exposes them. Params: assetPath (#246)", "read_ik_retargeter", (p) => ({ assetPath: p.assetPath })),
287
+ configure_ik_retargeter: bp("UE 5.8 only. Configure an existing IK Retargeter through UIKRetargeterController with the correct default-op and per-op rig assignment order, auto/manual chain mappings, named pose authoring, processor validation, native readback, transaction rollback, and checked save; older engines return unsupported_engine_version. Whole-pose auto-align resets that pose first: create a new pose or pass pose.reset=true to acknowledge replacement, then manual offsets are applied. Params: retargeterPath, sourceRig?, targetRig?, sourcePreviewMesh?, targetPreviewMesh?, ensureDefaultOps? (default true), autoMapMode? ('exact'|'fuzzy'|'clear'), forceRemap? (default false), chainMappings?: [{targetChain,sourceChain?:string|null}], pose?: {side,name,create?,reset?,autoAlign?,bones?,rotationOffsets?:[{bone,rotationQuaternion}],rootOffsetZ?,snapBoneToGround?}.", "configure_ik_retargeter", (p) => ({ retargeterPath: p.retargeterPath, sourceRig: p.sourceRig, targetRig: p.targetRig, sourcePreviewMesh: p.sourcePreviewMesh, targetPreviewMesh: p.targetPreviewMesh, ensureDefaultOps: p.ensureDefaultOps, autoMapMode: p.autoMapMode, forceRemap: p.forceRemap, chainMappings: p.chainMappings, pose: p.pose })),
61
288
  set_ik_rig_mesh: bp("Set the preview/source skeletal mesh on an EXISTING IK Rig. Params: rigPath, meshPath (#701)", "set_ik_rig_mesh", (p) => ({ rigPath: p.rigPath, meshPath: p.meshPath })),
62
289
  set_ik_retargeter_rig: bp("Set the source or target IK Rig on an EXISTING IK Retargeter. Params: retargeterPath, rigPath, side? (source|target, default target) (#703)", "set_ik_retargeter_rig", (p) => ({ retargeterPath: p.retargeterPath, rigPath: p.rigPath, side: p.side })),
63
290
  auto_align_retarget_pose: bp("Auto-align all bones of the source/target retarget pose (chain-to-chain) - fixes a retargeter that outputs a static reference pose. Params: retargeterPath, side? (source|target, default target) (#701)", "auto_align_retarget_pose", (p) => ({ retargeterPath: p.retargeterPath, side: p.side })),
64
291
  reset_retarget_pose: bp("Reset the current retarget pose (all bones) to the reference pose. Params: retargeterPath, side? (source|target, default target) (#701)", "reset_retarget_pose", (p) => ({ retargeterPath: p.retargeterPath, side: p.side })),
65
- batch_retarget_animations: bp("Bake a set of source AnimSequences onto the target skeleton through an IK Retargeter (RunBatchRetarget). Params: retargeterPath, sourceMesh, targetMesh, animPaths[], outputPath? (default: alongside source), prefix?, suffix? (default _Retargeted), overwrite? (#701)", "batch_retarget_animations", (p) => ({ retargeterPath: p.retargeterPath, sourceMesh: p.sourceMesh, targetMesh: p.targetMesh, animPaths: p.animPaths, outputPath: p.outputPath, prefix: p.prefix, suffix: p.suffix, overwrite: p.overwrite })),
292
+ batch_retarget_animations: bp("Bake validated source AnimSequences onto the target skeleton through an IK Retargeter (RunBatchRetarget), save every output, and roll back newly created outputs if the batch is incomplete or unsavable. Overwrite is rejected. Returns mapping completeness and every unmapped target chain so partial retargets are explicit; pass requireCompleteMapping=true only when the target should have no intentional extra chains. Params: retargeterPath, sourceMesh, targetMesh, animPaths[], outputPath? (default: alongside source), prefix?, suffix? (default _Retargeted), overwrite? (must be false), requireCompleteMapping? (default false) (#701)", "batch_retarget_animations", (p) => ({ retargeterPath: p.retargeterPath, sourceMesh: p.sourceMesh, targetMesh: p.targetMesh, animPaths: p.animPaths, outputPath: p.outputPath, prefix: p.prefix, suffix: p.suffix, overwrite: p.overwrite, requireCompleteMapping: p.requireCompleteMapping })),
66
293
  set_anim_blueprint_skeleton: bp("Set target skeleton on AnimBP. Params: assetPath, skeletonPath", "set_anim_blueprint_skeleton"),
67
294
  read_bone_track: bp("Read bone transform samples from AnimSequence. Params: assetPath, boneName, frames?: [int]", "read_bone_track"),
68
295
  create_pose_search_database: bp("Create a PoseSearchDatabase asset (motion matching). Params: name, packagePath?, schemaPath?", "create_pose_search_database"),
@@ -89,10 +316,15 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
89
316
  set_sequence_properties: bp("Batch-set properties on AnimSequence assets. If a path is a Montage and resolveFromMontages is true (default), resolves to its first AnimSequence. Params: assetPaths[], properties{enableRootMotion?, forceRootLock?, useNormalizedRootMotionScale?, rootMotionRootLock?}, resolveFromMontages?", "set_sequence_properties"),
90
317
  bake_root_motion_from_bone: bp("Bake delta translation from a source bone (e.g. pelvis) onto the root bone across the whole sequence; compensates the source bone so world-space position is unchanged. Params: assetPath, sourceBone, rootBone? (default 'root'), axes? (default ['x','y']), interpolation? ('linear'|'per_frame', default 'linear')", "bake_root_motion_from_bone"),
91
318
  // #419/#420 - live-actor skeletal operations (moved from level for proper domain alignment)
92
- get_bone_transform: bp("Read a bone or socket transform on a live actor's SkeletalMeshComponent. Wraps GetBoneTransform / GetSocketTransform. Params: actorLabel, boneName (or socket name), componentName? (default: CharacterMesh0 / Mesh / first SK component), world? (auto|pie|game|editor, default auto), space? (world|component|local, default world). Returns location, rotation, scale (#420)", "get_bone_transform", (p) => ({ actorLabel: p.actorLabel, boneName: p.boneName, componentName: p.componentName, world: p.world, space: p.space })),
93
- list_bones: bp("List bones in a live actor's SkeletalMeshComponent ref skeleton (name, index, parent). Params: actorLabel, componentName?, world? (auto|pie|game|editor, default auto) (#420)", "list_bones", (p) => ({ actorLabel: p.actorLabel, componentName: p.componentName, world: p.world })),
94
- rebind_leader_pose: bp("Re-bind every secondary SkeletalMeshComponent on an actor to a body component (default CharacterMesh0 / Mesh). One-call fix for the 'character explodes after rotating the actor' failure mode. Params: actorLabel, bodyComponent? (#419)", "rebind_leader_pose", (p) => ({ actorLabel: p.actorLabel, bodyComponent: p.bodyComponent })),
95
- preview_animation: bp("Toggle bUpdateAnimationInEditor + VisibilityBasedAnimTickOption=AlwaysTickPoseAndRefreshBones on every SkeletalMeshComponent of an actor. Bypasses the 'cannot be edited on templates' guard for level instances. Params: actorLabel, enabled (#419/#420)", "preview_animation", (p) => ({ actorLabel: p.actorLabel, enabled: p.enabled })),
319
+ get_bone_transform: bp("Read a bone or socket transform on a live actor's SkeletalMeshComponent. Wraps GetBoneTransform / GetSocketTransform. Params: actorLabel OR actorPath, boneName (or socket name), componentName? (default: CharacterMesh0 / Mesh / first SK component), world? (auto|pie|game|editor, default auto), space? (world|component|local, default world). Returns location, rotation, scale (#420)", "get_bone_transform", (p) => ({ actorLabel: p.actorLabel, actorPath: p.actorPath, boneName: p.boneName, componentName: p.componentName, world: p.world, space: p.space })),
320
+ list_bones: bp("List bones in a live actor's SkeletalMeshComponent ref skeleton (name, index, parent). Params: actorLabel OR actorPath, componentName?, world? (auto|pie|game|editor, default auto) (#420)", "list_bones", (p) => ({ actorLabel: p.actorLabel, actorPath: p.actorPath, componentName: p.componentName, world: p.world })),
321
+ rebind_leader_pose: bp("Re-bind every secondary SkeletalMeshComponent on an actor to a body component (default CharacterMesh0 / Mesh). One-call fix for the 'character explodes after rotating the actor' failure mode. Params: actorLabel OR actorPath, bodyComponent? (#419)", "rebind_leader_pose", (p) => ({ actorLabel: p.actorLabel, actorPath: p.actorPath, bodyComponent: p.bodyComponent })),
322
+ // #922/#923/#926 - evaluated pose reads. Everything above this line reads
323
+ // either raw local-space tracks or the reference pose; these evaluate.
324
+ sample_pose: bp("Evaluate an AnimSequence (or a BlendSpace at a blend position) and return COMPOSED bone transforms, which read_bone_track (raw local space) and get_bone_transforms (reference pose only) cannot give. Params: assetPath, boneNames? (omit for every bone), frames? or times? (omit for every sampled key), space? (component default | local | world), skeletalMeshPath? (evaluate with that mesh's proportions), incorporateRootMotion? (default true), blendPosition? {x,y,z} (BlendSpace only). Returns samples:[{frame, time, bones:[{name, location, rotation, scale}]}]. A montage is refused with a pointer to its segments, because a montage has no pose of its own (#923/#926/#922)", "sample_pose", (p) => ({ assetPath: p.assetPath ?? p.path, boneNames: p.boneNames, frames: p.frames, times: p.times, space: p.space, skeletalMeshPath: p.skeletalMeshPath, incorporateRootMotion: p.incorporateRootMotion, blendPosition: p.blendPosition })),
325
+ get_live_bone_transforms: bp("Read the EVALUATED pose off a live SkeletalMeshComponent in the editor world or PIE, for many bones at once. This is the read that tells 'standing' from 'prone' when the reference pose cannot (#922). Also returns componentTransform and an evaluation block (animationMode, animInstanceClass, componentSpaceTransformCount) so a clean component transform sitting on a dead anim instance is visible in one call. Params: actorLabel OR actorPath, componentName? (default CharacterMesh0 / Mesh), boneNames? (omit for every bone, max 1000), space? (world default | component | local), world? (auto|pie|game|editor) (#922/#926)", "get_live_bone_transforms", (p) => ({ actorLabel: p.actorLabel, actorPath: p.actorPath, componentName: p.componentName, boneNames: p.boneNames, space: p.space, world: p.world })),
326
+ measure_natural_speed: bp("Measure a locomotion clip's planted-foot speed, in cm/s, by evaluating the pose and tracking the lowest foot's horizontal travel while it is in contact. Every retarget changes natural speed by the target skeleton's leg-length ratio, so a BlendSpace built on retargeted clips has to re-measure per clip per character (#923). Params: assetPath, footBones[] (e.g. ['foot_l','foot_r']), contactThreshold? (contact height in cm; omit to derive it from the clip), skeletalMeshPath?, frames?/times?, blendPosition? (BlendSpace only). Returns naturalSpeed, plantedDistance, plantedTime, contactThreshold, per-foot breakdown", "measure_natural_speed", (p) => ({ assetPath: p.assetPath ?? p.path, footBones: p.footBones, contactThreshold: p.contactThreshold, skeletalMeshPath: p.skeletalMeshPath, frames: p.frames, times: p.times, blendPosition: p.blendPosition })),
327
+ preview_animation: bp("Toggle bUpdateAnimationInEditor + VisibilityBasedAnimTickOption=AlwaysTickPoseAndRefreshBones on every SkeletalMeshComponent of an actor. Bypasses the 'cannot be edited on templates' guard for level instances. Params: actorLabel OR actorPath, enabled (#419/#420)", "preview_animation", (p) => ({ actorLabel: p.actorLabel, actorPath: p.actorPath, enabled: p.enabled })),
96
328
  }, undefined, {
97
329
  assetPath: z.string().optional(),
98
330
  directory: z.string().optional(),
@@ -147,6 +379,7 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
147
379
  triggerTime: z.number().optional(),
148
380
  notifyClass: z.string().optional(),
149
381
  notifyProperties: z.record(z.unknown()).optional().describe("add_notify: EditAnywhere fields to set on the spawned notify object (requires notifyClass)"),
382
+ branchingPoint: z.boolean().optional().describe("add_notify: force the montage notify's tick type. Branching-point notifies are the only ones UAnimNotify_PlayMontageNotify::BranchingPointNotify runs, so OnPlayMontageNotifyBegin needs one; the PlayMontageNotify classes default to true on a montage, everything else to the engine's queued tick (#880)"),
150
383
  slotIndex: z.number().optional(),
151
384
  segmentIndex: z.number().optional().describe("set_montage_sequence: replace only this segment index within the slot (#626). remove_montage_segment: segment to remove. add_montage_section: segment to anchor the section to (#826)"),
152
385
  // Montage segment authoring params (#826)
@@ -160,7 +393,7 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
160
393
  blendIn: z.number().optional(),
161
394
  blendOut: z.number().optional(),
162
395
  numFrames: z.number().optional(),
163
- frameRate: z.number().optional(),
396
+ frameRate: z.number().optional().describe("Frames per second for create_sequence or bake_control_rig_edit."),
164
397
  boneName: z.string().optional(),
165
398
  boneNames: z.array(z.string()).optional(),
166
399
  parentClass: z.string().optional().describe("Parent AnimInstance class name for create_anim_blueprint"),
@@ -201,7 +434,7 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
201
434
  startTime: z.number().optional().describe("Start time for montage section"),
202
435
  linkedSection: z.string().optional().describe("Next section name to link to"),
203
436
  // IK Rig params (#93)
204
- skeletalMeshPath: z.string().optional().describe("Path to skeletal mesh for create_ik_rig / compare_curves_to_morph_targets (#656)"),
437
+ skeletalMeshPath: z.string().optional().describe("SkeletalMesh asset path. Used by IK Rig creation, curve/morph comparison, Control Rig edit setup, and animation analysis."),
205
438
  animPath: z.string().optional().describe("compare_curves_to_morph_targets: AnimSequence or PoseAsset path (#656)"),
206
439
  nodeClass: z.string().optional().describe("inspect_anim_nodes: node class substring filter, e.g. PoseDriver (#657)"),
207
440
  enableRootMotion: z.boolean().optional(),
@@ -212,11 +445,22 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
212
445
  targetBone: z.string().optional(),
213
446
  virtualBoneName: z.string().optional(),
214
447
  retargetRoot: z.string().optional().describe("Retarget root bone name for IK Rig"),
448
+ rootMotionBone: z.string().min(1).optional().describe("configure_ik_rig: root-motion bone name"),
449
+ autoSetup: z.enum(["retarget", "full_body"]).optional().describe("configure_ik_rig: optional native rig setup pass"),
450
+ fullBodyIK: IKRigFullBodySettings.optional().describe("configure_ik_rig: Full Body IK solver and desired goal/effector settings"),
451
+ exclusions: z.array(IKRigExclusion).max(2_048).optional().describe("configure_ik_rig: desired per-bone solver exclusions"),
215
452
  sourceRig: z.string().optional().describe("Source IKRig path for create_ik_retargeter"),
216
453
  targetRig: z.string().optional().describe("Target IKRig path for create_ik_retargeter"),
217
454
  rigPath: z.string().optional().describe("IK Rig path for set_ik_rig_mesh / set_ik_retargeter_rig (#701/#703)"),
218
455
  meshPath: z.string().optional().describe("Skeletal mesh path for set_ik_rig_mesh (#701)"),
219
456
  retargeterPath: z.string().optional().describe("IK Retargeter path (#701/#703)"),
457
+ sourcePreviewMesh: z.string().min(1).optional().describe("configure_ik_retargeter: source preview SkeletalMesh path"),
458
+ targetPreviewMesh: z.string().min(1).optional().describe("configure_ik_retargeter: target preview SkeletalMesh path"),
459
+ ensureDefaultOps: z.boolean().optional().describe("configure_ik_retargeter: ensure the complete UE 5.8 default operation stack; defaults true"),
460
+ autoMapMode: z.enum(["exact", "fuzzy", "clear"]).optional().describe("configure_ik_retargeter: native chain auto-map mode"),
461
+ forceRemap: z.boolean().optional().describe("configure_ik_retargeter: replace existing mappings during auto-map; defaults false"),
462
+ chainMappings: z.array(IKRetargetChainMapping).max(10_000).optional().describe("configure_ik_retargeter: explicit target-to-source chain overrides; null or omitted source clears"),
463
+ pose: IKRetargetPose.optional().describe("configure_ik_retargeter: named source or target pose authoring"),
220
464
  side: z.string().optional().describe("source|target for retargeter rig/pose actions (#701/#703)"),
221
465
  sourceMesh: z.string().optional().describe("batch_retarget_animations: source skeletal mesh (#701)"),
222
466
  targetMesh: z.string().optional().describe("batch_retarget_animations: target skeletal mesh (#701)"),
@@ -224,16 +468,29 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
224
468
  prefix: z.string().optional().describe("batch_retarget_animations: output name prefix (#701)"),
225
469
  suffix: z.string().optional().describe("batch_retarget_animations: output name suffix (#701)"),
226
470
  overwrite: z.boolean().optional().describe("batch_retarget_animations: overwrite existing outputs (#701)"),
471
+ requireCompleteMapping: z.boolean().optional().describe("batch_retarget_animations: reject any unmapped target chain; default false"),
227
472
  outputPath: z.string().optional().describe("batch_retarget_animations: destination folder for baked assets (#701)"),
228
473
  autoMapChains: z.boolean().optional().describe("create_ik_retargeter: assign rigs to ops + AutoMapChains after creation (default true)"),
229
- onConflict: z.string().optional().describe("Asset-creation conflict policy: skip (default) | error | overwrite"),
230
- frames: z.array(z.number()).optional().describe("Specific frames to sample for read_bone_track"),
231
- chains: z.array(z.object({
232
- name: z.string(),
233
- startBone: z.string(),
234
- endBone: z.string(),
235
- goal: z.string().optional(),
236
- })).optional().describe("IK retarget chains for create_ik_rig"),
474
+ onConflict: z.string().optional().describe("Conflict policy. Existing asset actions use skip|error|overwrite; Control Rig begin/bake use skip|error and never overwrite."),
475
+ frames: z.array(z.number()).optional().describe("Frames to read/sample. Used by read_bone_track, read_control_rig_edit, and analyze_animation."),
476
+ // UE 5.8 Control Rig + data-driven animation editing workflow.
477
+ sourceAnimationPath: z.string().optional().describe("begin_control_rig_edit: source AnimSequence asset path (required)."),
478
+ controlRigPath: z.string().optional().describe("begin_control_rig_edit: verified baseline ControlRigBlueprint asset path for this target character; required when rigMode='asset'. Create and validate the rig first when the project/character has none."),
479
+ rigMode: z.enum(["fk", "asset"]).optional().describe("begin_control_rig_edit: use 'asset' with the verified baseline controlRigPath; use 'fk' only when generated raw FK controls are the intended editing surface."),
480
+ layered: z.boolean().optional().describe("begin_control_rig_edit: keep the source animation track active under the Control Rig layer; defaults false."),
481
+ startFrame: z.number().int().optional().describe("begin_control_rig_edit: optional inclusive edit range start frame."),
482
+ endFrame: z.number().int().optional().describe("begin_control_rig_edit: optional exclusive edit range end frame."),
483
+ displayRate: z.number().positive().optional().describe("begin_control_rig_edit: optional LevelSequence display rate in frames per second."),
484
+ bindingTag: z.string().min(1).optional().describe("Stable Control Rig edit-session natural key used by begin/read/apply/bake."),
485
+ controlNames: z.array(z.string().min(1)).min(1).optional().describe("read_control_rig_edit: optional controls to sample; omit to read every control."),
486
+ operations: z.array(ControlRigEditOperation).min(1).optional().describe("apply_control_rig_edits: typed transform/bool/float/int edit operations, including quaternion set_keys."),
487
+ outputAssetPath: z.string().optional().describe("bake_control_rig_edit: required destination AnimSequence asset path."),
488
+ reduceKeys: z.literal(false).optional().describe("bake_control_rig_edit: key reduction is not supported yet; omit or pass false."),
489
+ tolerance: z.number().nonnegative().optional().describe("bake_control_rig_edit: key-reduction tolerance."),
490
+ createLink: z.literal(false).optional().describe("bake_control_rig_edit: Sequencer links are not supported yet; omit or pass false."),
491
+ loop: z.boolean().optional().describe("analyze_animation: include end-to-start loop continuity metrics."),
492
+ outputDirectory: z.string().optional().describe("analyze_animation: optional directory under Project/Saved/Codex/AnimationQA for deterministic artifacts; relative values resolve under that root."),
493
+ chains: z.array(IKRigAuthoringChain).max(256).optional().describe("IK retarget chains for create_ik_rig or configure_ik_rig"),
237
494
  keyframes: z.array(z.object({
238
495
  frame: z.number(),
239
496
  location: Vec3.optional(),
@@ -252,21 +509,21 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
252
509
  save: z.boolean().optional().describe("bake_keyframes_batch: save the asset after baking (default true)"),
253
510
  // PoseSearch (v0.7.15)
254
511
  schemaPath: z.string().optional().describe("Path to a UPoseSearchSchema asset"),
255
- sequencePath: z.string().optional().describe("Animation asset path to add to a PoseSearchDatabase"),
512
+ sequencePath: z.string().optional().describe("Animation path for PoseSearch graph actions, or LevelSequence path for the UE 5.8 Control Rig edit workflow."),
256
513
  wait: z.boolean().optional().describe("build_pose_search_index: block until the async build resolves (default true)"),
257
514
  // #684 per-clip flags + bulk clip authoring
258
515
  mirror: z.string().optional().describe("PoseSearch clip mirror option: 'original' | 'mirrored' | 'both'"),
259
516
  disableReselection: z.boolean().optional().describe("PoseSearch clip: disallow reselecting poses from the same asset"),
260
517
  sampleStart: z.number().optional().describe("PoseSearch clip sampling range start (seconds); [0,0] = whole clip"),
261
518
  sampleEnd: z.number().optional().describe("PoseSearch clip sampling range end (seconds); [0,0] = whole clip"),
262
- clips: z.array(z.any()).optional().describe("set_pose_search_clips: array of clip entries ({sequencePath, mirror?, disableReselection?, sampleStart?, sampleEnd?, enabled?}) or bare path strings"),
519
+ clips: z.array(z.union([PoseSearchClipEntry, z.string()])).optional().describe("set_pose_search_clips: array of clip entries ({sequencePath, mirror?, disableReselection?, sampleStart?, sampleEnd?, enabled?}) or bare path strings"),
263
520
  // Motion Matching content pipeline (schema / mirror / normalization / tuning)
264
- sampleRate: z.number().optional().describe("create_pose_search_schema: schema sample rate (default 30)"),
521
+ sampleRate: z.number().optional().describe("Sample rate. create_pose_search_schema: schema rate (default 30); analyze_animation: optional analysis sampling rate."),
265
522
  addDefaultChannels: z.boolean().optional().describe("create_pose_search_schema: add Trajectory+Pose default channels (default true)"),
266
523
  mirrorDataTablePath: z.string().optional().describe("create_pose_search_schema: optional MirrorDataTable to bind"),
267
- bones: z.array(z.any()).optional().describe("add_pose_search_schema_pose_channel: [{bone, flags?, weight?}] or bone-name strings; also add_pose_search_schema_trajectory_channel reuses 'samples'"),
524
+ bones: z.array(z.union([PoseSearchBoneEntry, z.string()])).optional().describe("add_pose_search_schema_pose_channel: [{bone, flags?, weight?}] or bone-name strings; also add_pose_search_schema_trajectory_channel reuses 'samples'"),
268
525
  weight: z.number().optional().describe("Channel weight for pose/trajectory channels"),
269
- expressions: z.array(z.any()).optional().describe("create_mirror_data_table: [{find, replace, method?}] find/replace bone-name rules"),
526
+ expressions: z.array(MirrorFindReplaceExpression).optional().describe("create_mirror_data_table: [{find, replace, method?}] find/replace bone-name rules"),
270
527
  mirrorAxis: z.string().optional().describe("create_mirror_data_table: X, Y or Z (default X)"),
271
528
  mirrorRootMotion: z.boolean().optional().describe("create_mirror_data_table: mirror root motion (default true)"),
272
529
  databases: z.array(z.string()).optional().describe("create_pose_search_normalization_set: PoseSearchDatabase paths to normalize together"),
@@ -295,7 +552,7 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
295
552
  rootBone: z.string().optional().describe("Root bone name for bake_root_motion_from_bone (default 'root')"),
296
553
  axes: z.array(z.string()).optional().describe("Axes to bake ('x','y','z') for bake_root_motion_from_bone"),
297
554
  interpolation: z.string().optional().describe("bake_root_motion_from_bone: 'linear' (default) or 'per_frame'"),
298
- space: z.string().optional().describe("Bone-space frame. get_bone_transforms (ref skeleton): 'local' (default) | 'component'. get_bone_transform (live actor): 'world' (default) | 'component' | 'local'"),
555
+ space: z.string().optional().describe("Transform space. Control Rig edit actions: 'local'|'global'. get_bone_transforms: 'local'|'component'. get_bone_transform: 'world'|'component'|'local'."),
299
556
  world: z.string().optional().describe("World scope for live actor skeletal queries: auto (default, prefer PIE), pie/game, or editor"),
300
557
  animation: z.string().optional().describe("AnimSequence path for add_blend_sample / set_blend_sample"),
301
558
  sampleIndex: z.number().optional().describe("BlendSpace sample index for set_blend_sample"),
@@ -304,8 +561,15 @@ export const animationTool = categoryTool("animation", "Animation assets, skelet
304
561
  y: z.number().optional(),
305
562
  // Live-actor skeletal operations (moved from level)
306
563
  actorLabel: z.string().optional().describe("Actor label for live skeletal queries"),
564
+ actorPath: z.string().optional().describe("Full actor object path. The unambiguous selector, and it wins over actorLabel when both are given. Editor labels are NOT unique, and a label matching several actors is refused with the candidates rather than resolved at random (#983)"),
307
565
  componentName: z.string().optional().describe("SkeletalMeshComponent name (default: CharacterMesh0 / Mesh)"),
308
566
  bodyComponent: z.string().optional().describe("rebind_leader_pose: explicit body component name"),
309
567
  enabled: z.boolean().optional().describe("preview_animation: toggle on/off"),
568
+ // #922/#923/#926 - evaluated pose reads
569
+ times: z.array(z.number()).optional().describe("sample_pose / measure_natural_speed: sample times in seconds; pass either this or 'frames'"),
570
+ incorporateRootMotion: z.boolean().optional().describe("sample_pose: fold the clip's root motion into the returned pose (default true, matching the engine). measure_natural_speed always excludes it, because it measures travel relative to the planted foot"),
571
+ blendPosition: z.object({ x: z.number().optional(), y: z.number().optional(), z: z.number().optional() }).optional().describe("sample_pose / measure_natural_speed: BlendSpace blend input, in the blendspace's own axis units"),
572
+ footBones: z.array(z.string()).optional().describe("measure_natural_speed: the foot bones to track, e.g. ['foot_l','foot_r']"),
573
+ contactThreshold: z.number().optional().describe("measure_natural_speed: height in cm below which a foot counts as planted; omit to derive it from the clip's own lowest foot height, which is what makes the measurement scale-independent across skeletons"),
310
574
  });
311
575
  //# sourceMappingURL=animation.js.map