| name | animation-montage |
| display_name | Animation Montages |
| description | Create and manipulate Animation Montages — sections, slots, segments, branching points, notifies, and blend settings (AnimMontageService). Use when the user asks to create a montage (from an animation or empty), add or link montage sections, set up slots/segments, add branching points, or adjust montage blend timing. |
| vibeue_classes | ["AnimMontageService"] |
| unreal_classes | ["AnimMontage","AnimNotify","AnimNotifyState"] |
| keywords | ["montage","animation","section","slot","segment","branching point","blend","combo","attack","root motion","notify"] |
🧠 Brains complement: IF an unreal-engine-skills-manager tool (external MCP) exists in this session, call it with {action: "load", skill: "animation-system"} for UE domain knowledge on this topic — correct APIs, architecture, best practices — and treat it as the rubric for any review / "best practices" question. If no such tool is available (e.g. running under Claude Code or Codex without that MCP), skip this line entirely and proceed with this skill alone — do NOT attempt the call.
Animation Montage Skill
Use AnimMontageService for animation montage operations.
Quick Reference - Python API
Discovery Methods
⚠️ list_montages filters are strings, not None (issue #461) — pass "" for "no
filter", never None (an FString arg can't be null and raises a TypeError).
Playback rate: there is no set_playback_rate_scale method; set the montage's RateScale
directly — unreal.load_asset(montage_path).set_editor_property("RateScale", 1.5) then
unreal.EditorAssetLibrary.save_asset(montage_path).
montages = AnimMontageService.list_montages(search_path, skeleton_filter) -> Array[MontageInfo]
info = AnimMontageService.get_montage_info(montage_path) -> MontageInfo
montages = AnimMontageService.find_montages_for_skeleton(skeleton_path) -> Array[MontageInfo]
montages = AnimMontageService.find_montages_using_animation(anim_path) -> Array[MontageInfo]
Creation Methods
path = AnimMontageService.create_montage_from_animation(anim_path, dest_path, name) -> str
path = AnimMontageService.create_empty_montage(skeleton_path, dest_path, name) -> str
path = AnimMontageService.duplicate_montage(source_path, dest_path, new_name) -> str
Section Management (CRITICAL for gameplay!)
sections = AnimMontageService.list_sections(montage_path) -> Array[MontageSectionInfo]
AnimMontageService.add_section(montage_path, section_name, start_time) -> bool
AnimMontageService.remove_section(montage_path, section_name) -> bool
AnimMontageService.rename_section(montage_path, old_name, new_name) -> bool
AnimMontageService.set_section_start_time(montage_path, section_name, new_time) -> bool
name = AnimMontageService.get_section_name_at_time(montage_path, time) -> str
Section Linking (Combo/Flow Control)
AnimMontageService.set_next_section(montage_path, from_section, to_section) -> bool
AnimMontageService.set_section_loop(montage_path, section_name, loop=True) -> bool
AnimMontageService.clear_section_link(montage_path, section_name) -> bool
links = AnimMontageService.get_all_section_links(montage_path) -> Array[SectionLink]
Animation Segments (Multiple Animations in One Montage)
segments = AnimMontageService.list_anim_segments(montage_path, track_index) -> Array[AnimSegmentInfo]
index = AnimMontageService.add_anim_segment(montage_path, track_index, anim_path, start_time, play_rate) -> int
AnimMontageService.remove_anim_segment(montage_path, track_index, segment_index) -> bool
AnimMontageService.set_segment_start_time(montage_path, track_index, segment_index, time) -> bool
AnimMontageService.set_segment_play_rate(montage_path, track_index, segment_index, rate) -> bool
AnimMontageService.set_segment_loop_count(montage_path, track_index, segment_index, count) -> bool
Slot Tracks
tracks = AnimMontageService.list_slot_tracks(montage_path) -> Array[SlotTrackInfo]
index = AnimMontageService.add_slot_track(montage_path, slot_name) -> int
AnimMontageService.set_slot_name(montage_path, track_index, new_slot_name) -> bool
AnimMontageService.remove_slot_track(montage_path, track_index) -> bool
Blend Settings
AnimMontageService.set_blend_in(montage_path, time, option) -> bool
AnimMontageService.set_blend_out(montage_path, time, option) -> bool
AnimMontageService.set_blend_out_trigger_time(montage_path, time) -> bool
settings = AnimMontageService.get_blend_settings(montage_path) -> MontageBlendSettings
Branching Points (Frame-Accurate Gameplay Events)
points = AnimMontageService.list_branching_points(montage_path) -> Array[BranchingPointInfo]
index = AnimMontageService.add_branching_point(montage_path, name, trigger_time) -> int
AnimMontageService.remove_branching_point(montage_path, index) -> bool
Root Motion
AnimMontageService.set_enable_root_motion_translation(montage_path, enable) -> bool
AnimMontageService.set_enable_root_motion_rotation(montage_path, enable) -> bool
Editor Methods
AnimMontageService.open_montage_editor(montage_path) -> bool
AnimMontageService.refresh_montage_editor(montage_path) -> bool
AnimMontageService.jump_to_section(montage_path, section_name) -> bool
AnimMontageService.play_preview(montage_path, start_section) -> bool
⚠️ CRASH WARNING — never structurally edit a montage while its editor is open.
Adding/removing sections, slot tracks, segments, notifies, or branching points reallocates
the montage's internal arrays. If the montage editor (Persona) is open, its live preview holds
pointers into those arrays and the next tick will dereference freed memory → the editor hard-crashes.
Rule: do ALL structural edits FIRST, then refresh_montage_editor() / open_montage_editor() exactly once at the very end.
Do NOT call refresh_montage_editor() between edits. (The service now also auto-closes the editor before
each structural edit as a safety net, but you should still batch edits and open last so the editor isn't
opening and closing repeatedly.)
IMPORTANT: Asset Path Format
All montage_path parameters require the FULL asset path (package_name), NOT the folder path.
montage_path = "/Game/Montages/AM_Attack"
montage_path = "/Game/Montages"
IMPORTANT: Return Struct Field Names (read before printing results)
These methods return UStruct objects. Access fields with the exact snake_case names below —
guessing (skeleton_display_name, segment end_time, name, path) raises AttributeError.
Each struct field is read-only data already populated; just read it.
MontageInfo (from get_montage_info / list_montages / find_montages_for_skeleton):
montage_path, montage_name, skeleton_path, duration, section_count, slot_track_count,
notify_count, branching_point_count, blend_in_time, blend_out_time, blend_out_trigger_time,
enable_root_motion_translation, enable_root_motion_rotation, slot_names (Array[str]).
(No skeleton_display_name — use skeleton_path. No skeleton object — it's a path string.)
MontageSectionInfo (from list_sections):
section_name, section_index, start_time, end_time, duration, next_section_name,
loops, segment_count.
AnimSegmentInfo (from list_anim_segments / get_anim_segment_info):
segment_index, anim_sequence_path, anim_name, start_time, duration, play_rate,
anim_start_pos, anim_end_pos, loop_count, loops.
(Segments have NO end_time — that field exists only on sections. Compute segment end as
start_time + duration. Source-clip range is anim_start_pos → anim_end_pos.)
SlotTrackInfo (from list_slot_tracks): track_index, slot_name, segment_count, total_duration.
SectionLink (from get_all_section_links): from_section, to_section, is_loop.
BranchingPointInfo (from list_branching_points): index, notify_name, trigger_time, section_name.
Tip: when unsure, call discover_python_class('unreal.MontageInfo, unreal.AnimSegmentInfo, unreal.MontageSectionInfo')
— the Editor Properties block lists every valid field name. Cheaper than a crash-and-retry loop.
Key Workflows
Create Multi-Animation Montage with Sections
import unreal
path = unreal.AnimMontageService.create_empty_montage(
"/Game/Characters/SK_Mannequin",
"/Game/Montages",
"AM_ComboAttack"
)
unreal.AnimMontageService.add_anim_segment(path, 0, "/Game/Animations/Attack1", 0.0)
unreal.AnimMontageService.add_anim_segment(path, 0, "/Game/Animations/Attack2", 1.0)
unreal.AnimMontageService.add_anim_segment(path, 0, "/Game/Animations/Attack3", 2.0)
unreal.AnimMontageService.add_section(path, "Attack1", 0.0)
unreal.AnimMontageService.add_section(path, "Attack2", 1.0)
unreal.AnimMontageService.add_section(path, "Attack3", 2.0)
unreal.AnimMontageService.set_next_section(path, "Attack1", "Attack2")
unreal.AnimMontageService.set_next_section(path, "Attack2", "Attack3")
unreal.AnimMontageService.add_branching_point(path, "Combo1Window", 0.7)
unreal.AnimMontageService.add_branching_point(path, "Combo2Window", 1.7)
unreal.AnimMontageService.set_blend_in(path, 0.15, "Cubic")
unreal.AnimMontageService.set_blend_out(path, 0.2, "Linear")
unreal.EditorAssetLibrary.save_asset(path)
unreal.AnimMontageService.refresh_montage_editor(path)
Create Layered Upper Body Montage
import unreal
path = unreal.AnimMontageService.create_montage_from_animation(
"/Game/Animations/Reload",
"/Game/Montages",
"AM_Reload_UpperBody"
)
unreal.AnimMontageService.set_slot_name(path, 0, "UpperBody")
unreal.AnimMontageService.set_blend_in(path, 0.1, "Linear")
unreal.AnimMontageService.set_blend_out(path, 0.15, "Linear")
unreal.AnimMontageService.set_enable_root_motion_translation(path, False)
unreal.AnimMontageService.set_enable_root_motion_rotation(path, False)
unreal.EditorAssetLibrary.save_asset(path)
Set Up Looping Idle Section
import unreal
montage_path = "/Game/Montages/AM_Combat"
unreal.AnimMontageService.add_section(montage_path, "Idle", 0.0)
unreal.AnimMontageService.add_section(montage_path, "Attack", 2.0)
unreal.AnimMontageService.set_section_loop(montage_path, "Idle", True)
unreal.AnimMontageService.clear_section_link(montage_path, "Attack")
COMMON_MISTAKES
Wrong: Using folder path instead of asset path
montages = AnimMontageService.list_sections("/Game/Montages")
sections = AnimMontageService.list_sections("/Game/Montages/AM_Attack")
Wrong: Refreshing the editor between structural edits (can CRASH the editor)
AnimMontageService.add_section(path, "Attack", 0.5)
AnimMontageService.refresh_montage_editor(path)
AnimMontageService.add_anim_segment(path, 0, anim, 1.0)
AnimMontageService.add_section(path, "Attack", 0.5)
AnimMontageService.add_anim_segment(path, 0, anim, 1.0)
unreal.EditorAssetLibrary.save_asset(path)
AnimMontageService.refresh_montage_editor(path)
Wrong: Adding sections beyond montage duration
AnimMontageService.add_section(path, "Late", 5.0)
AnimMontageService.add_anim_segment(path, 0, anim_path, 3.0)
AnimMontageService.add_section(path, "Late", 3.5)
Wrong: Forgetting to save
AnimMontageService.add_section(path, "Attack", 0.5)
AnimMontageService.add_section(path, "Attack", 0.5)
unreal.EditorAssetLibrary.save_asset(path)
Sample scripts (run via execute_python_code)
scripts/create_montage.txt — create a montage from an animation and add named sections.