§ How to · with Picoo

How to animate in Roblox Studio (and what code cannot do)

By Sametcan Tasgiran, Founder & Developer·Published ·Updated

No script can create a Roblox keyframe animation. Every tool that claims otherwise is producing an asset ID that does not exist.

Animation in Roblox splits cleanly in two: authored clips (Animation Editor → uploaded asset → played by ID) and procedural motion (CFrame and Motor6D, written in code). Knowing which one you need is most of the problem.

Play an existing animation

Load an Animation asset onto a Humanoid or AnimationController and control it as an AnimationTrack — speed, weight, looping, markers.

Procedural motion

Swings, recoil, hovering, spinning, sway, breathing — driven from code every frame. No upload, no asset ID.

Motor6D joints

Rotate a rig's joints directly for aim offsets, head-look, or a sword arc that follows the mouse.

Tween-based sequences

TweenService for doors, platforms, cameras and UI — deterministic and cheap.

Blend and stop cleanly

AdjustWeight and :Stop(fadeTime) so a played track does not snap on and off.

Files Picoo ships for this prompt

2 files · 130 lines · ~25s · 1 credit

AnimationController

Loads tracks, plays and blends them, handles the stop/fade lifecycle.

60 lines

ProceduralMotion

Frame-driven CFrame/Motor6D motion for swings, hover, recoil, spin.

70 lines

Sample output: StarterPlayer.StarterCharacterScripts.ProceduralMotion

-- PLAYING an authored animation: it must already exist as an uploaded asset.
-- The ID comes from YOUR Animation Editor upload — there is no way to invent one.
local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://YOUR_UPLOADED_ID"

local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", humanoid)
local track = animator:LoadAnimation(animation)
track.Priority = Enum.AnimationPriority.Action
track:Play(0.1)          -- fade in, so it does not snap
-- track:Stop(0.2)       -- fade out

-- PROCEDURAL motion: no asset, no upload. This is what code can actually author.
-- A sword swing by rotating the shoulder joint over time:
local shoulder = character:FindFirstChild("RightShoulder", true) :: Motor6D
local rest = shoulder.C0

local SWING = 1.8       -- radians
local DUR = 0.25

local t0 = os.clock()
local conn
conn = RunService.RenderStepped:Connect(function()
	local a = (os.clock() - t0) / DUR
	if a >= 1 then
		shoulder.C0 = rest
		conn:Disconnect()
		return
	end
	-- ease out, then return — a swing, not a linear sweep
	local e = 1 - (1 - a) ^ 3
	shoulder.C0 = rest * CFrame.Angles(-SWING * math.sin(e * math.pi), 0, 0)
end)

How to animate in Roblox Studio (and what code cannot do)

This is the one Roblox topic where the useful answer starts with a limit: a script cannot create a keyframe animation. Roblox animations are authored in the Animation Editor, uploaded to an account, and referenced by an asset ID that only exists because of that upload. There is no API that turns code into a clip.

That matters because it is a favourite failure of AI tools. Asked to "animate the sword swing", a model will happily write `animation.AnimationId = "rbxassetid://1234567890"` — a plausible-looking number that is either nothing or somebody else's animation. The code runs, nothing plays, and the developer spends an hour debugging a lie.

What code CAN do splits in two, and almost every real requirement lands in one of them.

Playing authored clips: load the Animation onto an Animator (not the Humanoid directly — that path is deprecated), keep a reference to the returned AnimationTrack, set a Priority that beats the default Animate script, and fade in and out rather than snapping. Most "my animation doesn't play" reports are one of those four things.

Procedural motion: CFrame and Motor6D driven per frame. This is where game feel actually lives, because it reacts to state — recoil that scales with the weapon, a swing arc that follows the mouse, hover that responds to speed, a door that opens as far as it was pushed. An authored clip is the same every time; procedural motion answers what is happening right now. It also needs no upload, no asset ownership and no moderation wait, which is why Picoo's combat and ability systems animate this way.

The practical rule: if the motion is a fixed performance (a dance, a reload, a walk cycle) author it in the Animation Editor. If it depends on anything the player is doing, write it.

See more on the Luau generator, the game builder, or browse the full blog.

Frequently asked

Can AI write a Roblox animation for me?+

It can write the code that PLAYS one, and it can write procedural motion. It cannot author a keyframe clip: Roblox animations are created in the Animation Editor and uploaded to your account, which produces an asset ID tied to that upload. Any tool that hands you an AnimationId it "generated" has invented a number — it will either fail to load or load somebody else's animation.

Why does my animation not play?+

Three usual causes. The asset is not owned by (or shared with) the place's creator, so it fails to load. The Priority is too low and the default Animate script overrides it — Action beats Movement beats Idle beats Core. Or the track is garbage-collected because you did not keep a reference to it.

When should I use procedural motion instead?+

Whenever the motion depends on runtime state: recoil scaled by weapon, a swing that follows the mouse, hover that responds to speed, a door that opens as far as the player pushed it. Authored clips are fixed; procedural motion reacts. Most "game feel" is procedural.

What is Motor6D and why does it matter?+

It is the joint that connects two parts of a rig — the character's shoulders, neck, hips. Rotating a Motor6D's C0 moves that limb without touching the animation system at all, which is how aim offsets and head-look are done while a walk animation is still playing.

Do I need an Animator object?+

Yes, on modern Roblox. LoadAnimation on the Humanoid directly is deprecated; get or create an Animator inside the Humanoid (or an AnimationController for non-humanoid rigs) and load through that.

Related Picoo prompts