roblox-animations

SKILL.md

Roblox Animations Reference

Core Objects

Object Purpose
Animation Asset reference — holds AnimationId
Animator Lives inside Humanoid or AnimationController; loads and drives tracks
AnimationController Replaces Humanoid for non-character rigs
AnimationTrack Returned by LoadAnimation; controls playback

Where to Run Animation Code

Scenario Script Type Location
Local player character LocalScript StarterCharacterScripts
NPC / server-owned model Script Inside model or ServerScriptService

Never play player character animations from a Script — they will not replicate correctly to the local client.


Loading and Playing Animations

-- LocalScript in StarterCharacterScripts
local character = script.Parent
local animator = character:WaitForChild("Humanoid"):WaitForChild("Animator")

local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://1234567890"

local track = animator:LoadAnimation(animation)

track:Play()                      -- default fade-in (0.1s), weight 1, speed 1
track:Play(0.1, 1, 0.5)          -- fadeTime, weight, speed

track:AdjustSpeed(1.5)           -- change speed while playing
track:AdjustWeight(0.5, 0.2)     -- weight 0.5, fade over 0.2s

track:Stop()                      -- default fade-out (0.1s)
track:Stop(0.5)                   -- fade out over 0.5s

AnimationTrack Events

-- Fires after fade-out completes
track.Stopped:Connect(function()
    print("Animation finished")
end)

-- Use :Once for one-shot cleanup
track.Stopped:Once(function()
    cleanup()
end)

-- Fires when a named keyframe marker is reached
-- Marker names are set in the Roblox Animation Editor
track:GetMarkerReachedSignal("FootStep"):Connect(function(paramString)
    playFootstepSound()
end)

Looped vs One-Shot

Property Looped One-Shot
track.Looped true false
Set in Animation Editor (loop toggle) Animation Editor
Override at runtime track.Looped = false track.Looped = true
Stops automatically No — must call track:Stop() Yes — after one cycle
-- Force a looped animation to play once
track.Looped = false
track:Play()
track.Stopped:Once(function() print("Done") end)

Animation Priority and Blending

Priority controls which tracks win on contested joints. Higher priority overrides lower.

Idle < Movement < Action < Action2 < Action3 < Action4 < Core
idleTrack.Priority   = Enum.AnimationPriority.Idle
runTrack.Priority    = Enum.AnimationPriority.Movement
attackTrack.Priority = Enum.AnimationPriority.Action

idleTrack:Play()
runTrack:Play()     -- overrides idle on shared joints
attackTrack:Play()  -- blends on top for joints it owns

Weight adjusts influence when two tracks share the same priority:

trackA:Play(0, 0.6)  -- weight 0.6
trackB:Play(0, 0.4)  -- weight 0.4 — blended on shared joints

Humanoid vs AnimationController

Humanoid (characters and humanoid NPCs)

local animator = character:FindFirstChildOfClass("Humanoid"):FindFirstChildOfClass("Animator")
local track = animator:LoadAnimation(animation)
track:Play()

AnimationController (props, vehicles, creatures)

local controller = model:FindFirstChildOfClass("AnimationController")
local animator = controller:FindFirstChildOfClass("Animator")
if not animator then
    animator = Instance.new("Animator")
    animator.Parent = controller
end
local track = animator:LoadAnimation(animation)
track:Play()

Replacing Default Character Animations

The Animate LocalScript in the character holds animation references. Modify its AnimationId values on CharacterAdded.

-- LocalScript in StarterCharacterScripts
local animate = script.Parent:WaitForChild("Animate")

local function replaceAnim(slotName, newId)
    local slot = animate:FindFirstChild(slotName)
    if slot then
        local animObj = slot:FindFirstChildOfClass("Animation")
        if animObj then animObj.AnimationId = newId end
    end
end

replaceAnim("idle",  "rbxassetid://111111111")
replaceAnim("run",   "rbxassetid://222222222")
replaceAnim("jump",  "rbxassetid://333333333")
replaceAnim("fall",  "rbxassetid://444444444")
replaceAnim("climb", "rbxassetid://555555555")

Available slots: idle, walk, run, jump, fall, climb, swim, swimidle, toolnone, toolslash, toollunge.


Stop All Playing Animations

local function stopAll(animator, fadeTime)
    for _, track in animator:GetPlayingAnimationTracks() do
        track:Stop(fadeTime or 0.1)
    end
end

Quick Playback Reference

track:Play(fadeTime, weight, speed)
-- fadeTime  default 0.1   — blend-in seconds
-- weight    default 1.0   — joint influence (0–1)
-- speed     default 1.0   — playback rate

track.TimePosition   -- current position in seconds (read/write)
track.Length         -- total duration in seconds
track.IsPlaying      -- bool
track.Looped         -- bool (override allowed at runtime)
track.Priority       -- Enum.AnimationPriority
track.WeightCurrent  -- actual blended weight right now
track.WeightTarget   -- target weight after fade

Upper-Body Only Animations

Priority blending affects all joints an animation touches. To play a wave only on the arms while legs animate from run/idle, the animation itself must be authored to only key upper-body bones (leave lower-body joints unkeyed in the Animation Editor). There is no runtime API to mask joints — the solution is in the animation asset, not the script.


Common Mistakes

Mistake Fix
Playing character animations in a Script Use LocalScript in StarterCharacterScripts
LoadAnimation called on Humanoid (deprecated) Call on Animator instead
Two animations fighting on same joints Assign different Priority values
Stopped fires immediately Animation has zero length or wrong Looped setting
GetMarkerReachedSignal never fires Marker name misspelled, or animation not re-uploaded after adding markers
NPC animation not visible to other clients Play from a Script (server), not LocalScript
AnimationController track won't play Missing Animator child inside AnimationController
Weekly Installs
20
GitHub Stars
1
First Seen
Feb 23, 2026
Installed on
opencode20
gemini-cli20
github-copilot20
amp20
codex20
kimi-cli20