Content/Skills/animsequence/SKILL.md
Preview, validate, bake, and manipulate animation sequences with constraint-aware bone editing
npx skillsauth add kevinpbuckley/vibeue animsequenceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill covers the inspect → profile → preview → validate → bake workflow for safe animation bone edits with correct bone-space handling and constraint validation.
Required:
manage_skills(action="load", skill_name="animsequence")Related Skills:
- skeleton - For modifying skeleton structure, sockets, and retargeting modes
- animation-blueprint - For state machines and AnimGraph navigation
Workflow: Create skeleton profile → Learn constraints → Preview bone rotations → Validate pose → Bake to keyframes
🛡️ SAFE DISCOVERY: Always use VibeUE service methods
DO NOT use
unreal.load_asset()in loops - causes memory crashes!USE THESE SAFE METHODS:
unreal.SkeletonService.list_skeletons(search_path)- Find skeletonsunreal.AnimSequenceService.find_animations_for_skeleton(skeleton_path)- Find animationsunreal.AnimSequenceService.list_anim_sequences(search_path, skeleton_filter)- List all animationsThese methods query asset metadata WITHOUT loading assets into memory.
- animation-blueprint - For state machines and AnimGraph navigation
Workflow: Create skeleton profile → Learn constraints → Preview bone rotations → Validate pose → Bake to keyframes
All bone rotations must specify the coordinate space. Default to "local" for user intent.
| Space | Description | Use For |
|-------|-------------|---------|
| "local" | Relative to parent bone | Most edits (default) |
| "component" | Relative to skeletal mesh root | Cross-bone coordination |
| "world" | World coordinates | Rarely used for animations |
# WRONG: Assuming space or not specifying
unreal.AnimSequenceService.apply_bone_rotation(path, "arm", rot, ...)
# CORRECT: Always specify space explicitly
unreal.AnimSequenceService.preview_bone_rotation(
path, "upperarm_r", unreal.Rotator(0, 30, 0), "local", 0
)
Never apply edits directly without validation. Use the preview workflow:
import unreal
anim_path = "/Game/Anims/AS_Idle"
# Step 1: PREVIEW the edit
result = unreal.AnimSequenceService.preview_bone_rotation(
anim_path, "upperarm_r", unreal.Rotator(0, 45, 0), "local", 0
)
# Step 2: VALIDATE against constraints
validation = unreal.AnimSequenceService.validate_pose(anim_path, True) # Use learned constraints
if not validation.is_valid:
for msg in validation.violation_messages:
print(f"⚠️ {msg}")
# Option A: Cancel and adjust
unreal.AnimSequenceService.cancel_preview(anim_path)
# Option B: Accept clamped values and continue
# Step 3: BAKE if valid
if validation.is_valid:
result = unreal.AnimSequenceService.bake_preview_to_keyframes(
anim_path, 0, -1, "cubic"
)
print(f"✓ Baked frames {result.start_frame} to {result.end_frame}")
Create a skeleton profile to get hierarchy, constraints, and learned ranges:
# WRONG: Editing without understanding the skeleton
unreal.AnimSequenceService.apply_bone_rotation(...)
# CORRECT: Build profile first
profile = unreal.SkeletonService.create_skeleton_profile("/Game/SK_Mannequin")
print(f"Skeleton has {profile.bone_count} bones")
# Check if constraints are available
if not profile.has_learned_constraints:
# Learn from existing animations
constraints = unreal.SkeletonService.learn_from_animations("/Game/SK_Mannequin", 50, 10)
print(f"Learned from {constraints.animation_count} animations")
User intent is expressed in Euler angles (degrees), but always use quaternions internally to avoid gimbal lock:
# User intent: "rotate forearm 30 degrees"
rotation_delta = unreal.Rotator(0, 30, 0) # Euler (Roll, Pitch, Yaw)
# The service converts to quaternion internally
result = unreal.AnimSequenceService.preview_bone_rotation(
anim_path, "lowerarm_r", rotation_delta, "local", 0
)
# To inspect quaternion values:
euler = unreal.AnimSequenceService.quat_to_euler(some_quat)
# WRONG - space is ambiguous
transform = unreal.Transform(rotation=some_rotation)
# This may be interpreted incorrectly
# CORRECT - always specify space
result = unreal.AnimSequenceService.preview_bone_rotation(
anim_path, bone, rotation, "local", frame
)
# WRONG - direct edit without checking constraints
unreal.AnimSequenceService.apply_bone_rotation(
path, "lowerarm_r", unreal.Rotator(0, 180, 0), # Impossible elbow bend!
"local", 0, -1, True
)
# CORRECT - preview → validate → bake
result = unreal.AnimSequenceService.preview_bone_rotation(...)
validation = unreal.AnimSequenceService.validate_pose(path, True)
if validation.is_valid:
unreal.AnimSequenceService.bake_preview_to_keyframes(...)
# WRONG - assuming pitch raises arm
rotation = unreal.Rotator(0, 90, 0) # May not do what you expect!
# CORRECT - analyze reference pose first
ref_pose = unreal.AnimSequenceService.get_reference_pose(skeleton_path)
for bp in ref_pose:
if bp.bone_name == "upperarm_r":
euler = unreal.AnimSequenceService.quat_to_euler(bp.transform.rotation)
print(f"Reference: Roll={euler.roll}, Pitch={euler.pitch}, Yaw={euler.yaw}")
# Now you know the baseline to add deltas to
# WRONG - editing without profile
unreal.AnimSequenceService.preview_bone_rotation(...) # No constraints!
# CORRECT - build profile first
unreal.SkeletonService.create_skeleton_profile(skeleton_path)
# Now constraints are available for validation
# WRONG - Loading assets causes memory access violations (0xC0000005)
asset_subsystem = unreal.get_editor_subsystem(unreal.EditorAssetSubsystem)
assets = asset_subsystem.list_assets("/Game", recursive=True)
for asset_path in assets:
anim = unreal.load_asset(asset_path) # ❌ CRASHES!
if anim and hasattr(anim, 'get_skeleton'):
skeleton = anim.get_skeleton() # Memory violation
# CORRECT - Use Asset Registry API (no loading required)
asset_registry = unreal.AssetRegistryHelpers.get_asset_registry()
filter = unreal.ARFilter(
class_paths=[unreal.TopLevelAssetPath("/Script/Engine", "AnimSequence")],
recursive_paths=True,
package_paths=["/Game"]
)
anim_assets = asset_registry.get_assets(filter)
for asset_data in anim_assets:
# Access metadata without loading
anim_name = asset_data.asset_name
anim_path = asset_data.object_path
# Get skeleton path from asset registry tags
skeleton_tag = asset_data.get_tag_value("Skeleton")
Why this crashes:
unreal.load_asset() loads full asset into memorySafe alternatives:
FindAnimationsForSkeleton() - BEST OPTIONBEST: Use VibeUE AnimSequenceService methods
# CORRECT - VibeUE safe discovery (no loading)
import unreal
skeleton_path = "/Game/Characters/SK_Mannequin"
# Get all animations for a skeleton - no loading!
anims = unreal.AnimSequenceService.find_animations_for_skeleton(skeleton_path)
for anim_info in anims[:10]:
print(f"{anim_info.anim_name}")
print(f" Duration: {anim_info.duration:.2f}s")
print(f" Frames: {anim_info.frame_count}")
print(f" Path: {anim_info.anim_path}")
Other safe VibeUE methods:
list_anim_sequences(search_path, skeleton_filter) - List all in pathget_anim_sequence_info(anim_path) - Get single anim infosearch_animations(name_pattern, search_path) - Find by name patternAll anim_path parameters require the FULL asset path (package_name), NOT the folder path (package_path).
When using AssetDiscoveryService.search_assets(), use package_name NOT package_path:
import unreal
# Search for an animation
results = unreal.AssetDiscoveryService.search_assets("Run", "AnimSequence")
if results:
asset = results[0]
# CORRECT: Use package_name (full asset path)
anim_path = str(asset.package_name) # e.g., "/Game/Animations/Run/AS_Run_Forward"
# WRONG: Do NOT use package_path (folder only)
# folder = asset.package_path # e.g., "/Game/Animations/Run" - This will FAIL!
# Now you can use the anim_path with AnimSequenceService
info = unreal.AnimSequenceService.get_anim_sequence_info(anim_path)
Load these sibling docs for deeper coverage of specific topics:
testing
Procedurally design an AAA-style open-world FPS map blockout (roads, POIs, fields, forests/treelines, railway/bridges) from a VibeUE-generated landscape, validate it through gated checks, and materialize the plan into real engine geometry (splines, paint layers, foliage, actors).
tools
Create and manage Niagara particle systems - system lifecycle, adding/copying emitters, user parameters, system script settings, scratch-pad authoring
development
Configure Niagara emitter internals - modules, renderers, rapid iteration parameters, graph positioning, and scratch-pad authoring (Custom HLSL + node graph)
tools
Create and modify Blueprint assets, variables, functions, and components