animation stealer
Key RequiredUniversal

animation stealer

Universal Scriptwesdfrwesdfr 2.1K views 259 executesUpdated Feb 15, 2026
1.4/ 5(7 votes)
2529% Positive
Lua Script•738 lines (24303 chars)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local HttpService = game:GetService("HttpService")
local TweenService = game:GetService("TweenService")
local Workspace = game:GetService("Workspace")
local StarterGui = game:GetService("StarterGui")
local Selection = game:GetService("Selection")

local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

local CLONE_DISTANCE = 5
local FOLDER_NAME = "StolenAnims"

local myClone, isRecording, recordingType = nil, false, "Player"
local recordedFrames, recordedFramesBoth_Player, recordedFramesBoth_Model = {}, {}, {}
local recordConnection, replayConnection, isReplaying = nil, nil, false
local playerBodyParts, modelBodyParts = {}, {}
local dragging, dragInput, dragStart, startPos = false, nil, nil, nil
local selectedModel, originalMotorStates = nil, {}
local sourceAnimType = "R6"

local bodyPartNames = {
	"Head", "HumanoidRootPart", "Left Arm", "Left Leg", "Right Arm", "Right Leg", "Torso",
	"UpperTorso", "LowerTorso", "LeftUpperArm", "LeftLowerArm", "LeftHand",
	"RightUpperArm", "RightLowerArm", "RightHand", "LeftUpperLeg", "LeftLowerLeg", 
	"LeftFoot", "RightUpperLeg", "RightLowerLeg", "RightFoot"
}

local r6PartNames = {"Head", "HumanoidRootPart", "Left Arm", "Left Leg", "Right Arm", "Right Leg", "Torso"}

local r15ToR6LimbMap = {
	["Left Arm"] = {"LeftUpperArm", "LeftLowerArm", "LeftHand"},
	["Right Arm"] = {"RightUpperArm", "RightLowerArm", "RightHand"},
	["Left Leg"] = {"LeftUpperLeg", "LeftLowerLeg", "LeftFoot"},
	["Right Leg"] = {"RightUpperLeg", "RightLowerLeg", "RightFoot"},
	["Torso"] = {"UpperTorso", "LowerTorso"},
	["Head"] = {"Head"},
	["HumanoidRootPart"] = {"HumanoidRootPart"}
}

local function detectModelType(model)
	if not model then return "Unknown" end
	if model:FindFirstChild("UpperTorso", true) then return "R15" end
	if model:FindFirstChild("Torso", true) then return "R6" end
	return "Unknown"
end

local function convertR15ToR6Frame(r15Frame)
	local r6Frame = {}
	for r6PartName, r15Parts in pairs(r15ToR6LimbMap) do
		local validCFrames = {}
		for _, r15PartName in ipairs(r15Parts) do
			if r15Frame[r15PartName] then
				table.insert(validCFrames, r15Frame[r15PartName].CFrame)
			end
		end
		if #validCFrames > 0 then
			if #validCFrames == 1 then
				r6Frame[r6PartName] = {CFrame = validCFrames[1]}
			else
				local totalPos = Vector3.new(0, 0, 0)
				for i, cframe in ipairs(validCFrames) do
					totalPos = totalPos + cframe.Position * (1 / #validCFrames)
				end
				local _, _, _, r00, r01, r02, r10, r11, r12, r20, r21, r22 = validCFrames[1]:GetComponents()
				r6Frame[r6PartName] = {CFrame = CFrame.new(0, 0, 0, r00, r01, r02, r10, r11, r12, r20, r21, r22) + totalPos}
			end
		end
	end
	return r6Frame
end

local function autoConvertFrames(frames, sourceType)
	if sourceType == "R6" or sourceType == "Unknown" then return frames end
	local converted = {}
	for i, frame in ipairs(frames) do
		converted[i] = convertR15ToR6Frame(frame)
	end
	return converted
end

local HasFileSystem = (getgenv and (writefile or getgenv().writefile)) ~= nil
local IS_STUDIO = not HasFileSystem
local FileSystem = {}

if IS_STUDIO then
	local OutputFolder = Workspace:FindFirstChild("Stolen_Anims_Output")
	if not OutputFolder then
		OutputFolder = Instance.new("Folder")
		OutputFolder.Name = "Stolen_Anims_Output"
		OutputFolder.Parent = Workspace
	end

	FileSystem.Enabled = true
	FileSystem.IsFolder = function() return true end
	FileSystem.MakeFolder = function() end
	FileSystem.List = function()
		local files = {}
		for _, child in ipairs(OutputFolder:GetChildren()) do
			if child:IsA("ModuleScript") then
				table.insert(files, FOLDER_NAME .. "/" .. child.Name .. ".json")
			end
		end
		return files
	end
	FileSystem.Write = function(path, data)
		local filename = path:match("([^/]+)%.json$") or "Unknown"
		local mod = OutputFolder:FindFirstChild(filename) or Instance.new("ModuleScript")
		mod.Name = filename
		mod.Parent = OutputFolder
		mod.Source = "return [[\n" .. data:gsub("\\", "\\\\"):gsub("]]", "\\]\\]") .. "\n]]"
	end
	FileSystem.Read = function(path)
		local mod = OutputFolder:FindFirstChild(path:match("([^/]+)%.json$"))
		if mod then
			local func = loadstring(mod.Source)
			if func then return func() end
		end
		return "[]"
	end
else
	FileSystem = {
		Enabled = true,
		Write = writefile or getgenv().writefile,
		Read = readfile or getgenv().readfile,
		List = listfiles or getgenv().listfiles,
		IsFolder = isfolder or getgenv().isfolder,
		MakeFolder = makefolder or getgenv().makefolder
	}
	if not FileSystem.IsFolder(FOLDER_NAME) then
		FileSystem.MakeFolder(FOLDER_NAME)
	end
end

local function highlightModel(model, highlight)
	if not model then return end
	for _, part in ipairs(model:GetDescendants()) do
		if part:IsA("BasePart") then
			if highlight then
				if not part:FindFirstChild("SelectionBox") then
					local h = Instance.new("SelectionBox")
					h.Name = "SelectionBox"
					h.Adornee = part
					h.LineThickness = 0.05
					h.Color3 = Color3.fromRGB(255, 100, 255)
					h.Parent = part
				end
			else
				local h = part:FindFirstChild("SelectionBox")
				if h then h:Destroy() end
			end
		end
	end
end

local function selectModelLogic(model)
	if not model then return end
	if selectedModel then highlightModel(selectedModel, false) end
	selectedModel = model
	highlightModel(selectedModel, true)
	
	local modelType = detectModelType(selectedModel)
	StarterGui:SetCore("SendNotification", {
		Title = "Target Locked [" .. modelType .. "]";
		Text = selectedModel.Name;
		Duration = 3;
	})
	
	originalMotorStates = {}
	for _, child in ipairs(selectedModel:GetDescendants()) do
		if child:IsA("Motor6D") then
			originalMotorStates[child] = {
				Part0 = child.Part0, Part1 = child.Part1,
				C0 = child.C0, C1 = child.C1, Parent = child.Parent
			}
		end
	end
	
	modelBodyParts = {}
	for _, child in ipairs(selectedModel:GetDescendants()) do
		if child:IsA("BasePart") then
			table.insert(modelBodyParts, child)
		end
	end
end

local function checkExplorerSelection()
	local success, selection = pcall(function() return Selection:Get() end)
	if success and selection and #selection > 0 then
		local target = selection[1]
		local model = target:IsA("Model") and target or target:FindFirstAncestorOfClass("Model")
		if model and model ~= player.Character then
			selectModelLogic(model)
			return true
		end
	end
	return false
end

local function applyPlayerAppearanceToClone(clone)
	if not clone then return end
	local cloneHumanoid = clone:FindFirstChildOfClass("Humanoid")
	if not cloneHumanoid then return end
	
	local success, desc = pcall(function()
		return Players:GetHumanoidDescriptionFromUserId(player.UserId)
	end)
	
	if success and desc then
		pcall(function()
			cloneHumanoid:ApplyDescriptionClientServer(desc)
		end)
	end
end

local function createDummy()
	local dummy = Instance.new("Model")
	dummy.Name = "R6_Clone"

	local hrp = Instance.new("Part")
	hrp.Name = "HumanoidRootPart"
	hrp.Size = Vector3.new(2, 2, 1)
	hrp.Transparency = 1
	hrp.CanCollide = false
	hrp.Parent = dummy

	local humanoid = Instance.new("Humanoid")
	humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
	humanoid.Parent = dummy

	local function createPart(name, size)
		local part = Instance.new("Part")
		part.Name = name
		part.Size = size
		part.TopSurface = Enum.SurfaceType.Smooth
		part.BottomSurface = Enum.SurfaceType.Smooth
		part.CanCollide = false
		part.Parent = dummy
		return part
	end
	
	local function createMotor(name, part0, part1, c0, c1)
		local motor = Instance.new("Motor6D")
		motor.Name = name
		motor.Part0 = part0
		motor.Part1 = part1
		motor.C0 = c0
		motor.C1 = c1
		motor.Parent = part0
		return motor
	end

	local head = createPart("Head", Vector3.new(2, 1, 1))
	local headMesh = Instance.new("SpecialMesh")
	headMesh.MeshType = Enum.MeshType.Head
	headMesh.Scale = Vector3.new(1.25, 1.25, 1.25)
	headMesh.Parent = head

	local torso = createPart("Torso", Vector3.new(2, 2, 1))
	local leftArm = createPart("Left Arm", Vector3.new(1, 2, 1))
	local rightArm = createPart("Right Arm", Vector3.new(1, 2, 1))
	local leftLeg = createPart("Left Leg", Vector3.new(1, 2, 1))
	local rightLeg = createPart("Right Leg", Vector3.new(1, 2, 1))

	createMotor("Neck", torso, head, CFrame.new(0, 1, 0), CFrame.new(0, -0.5, 0))
	createMotor("Left Shoulder", torso, leftArm, CFrame.new(-1, 0.5, 0), CFrame.new(0.5, 0.5, 0))
	createMotor("Right Shoulder", torso, rightArm, CFrame.new(1, 0.5, 0), CFrame.new(-0.5, 0.5, 0))
	createMotor("Left Hip", torso, leftLeg, CFrame.new(-0.5, -1, 0), CFrame.new(0, 1, 0))
	createMotor("Right Hip", torso, rightLeg, CFrame.new(0.5, -1, 0), CFrame.new(0, 1, 0))
	createMotor("Root Joint", hrp, torso, CFrame.new(0, 0, 0), CFrame.new(0, 0, 0))

	dummy.PrimaryPart = hrp
	return dummy
end

local function spawnClone()
	if myClone then myClone:Destroy() end
	if not player.Character then return end
	character = player.Character
	humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
	if not humanoidRootPart then return end
	myClone = createDummy()
	local cloneRoot = myClone:FindFirstChild("HumanoidRootPart")
	if cloneRoot then
		cloneRoot.CFrame = humanoidRootPart.CFrame * CFrame.new(0, 0, -CLONE_DISTANCE)
		cloneRoot.CFrame = CFrame.lookAt(cloneRoot.Position, humanoidRootPart.Position)
	end
	myClone.Parent = workspace
	task.wait(0.1)
	applyPlayerAppearanceToClone(myClone)
end

local function serializeFrames(frames, animType)
	local data = {animType = animType, frames = {}}
	for i, frame in ipairs(frames) do
		data.frames[i] = {}
		for partName, partData in pairs(frame) do
			data.frames[i][partName] = {partData.CFrame:components()}
		end
	end
	return HttpService:JSONEncode(data)
end

local function deserializeFrames(jsonString)
	local rawData = HttpService:JSONDecode(jsonString)
	if rawData.animType and rawData.frames then
		local frames = {}
		for i, rawFrame in ipairs(rawData.frames) do
			frames[i] = {}
			for partName, components in pairs(rawFrame) do
				frames[i][partName] = {CFrame = CFrame.new(unpack(components))}
			end
		end
		return frames, rawData.animType
	else
		local frames = {}
		local frameData = rawData.frames or rawData
		for i, rawFrame in ipairs(frameData) do
			frames[i] = {}
			for partName, components in pairs(rawFrame) do
				frames[i][partName] = {CFrame = CFrame.new(unpack(components))}
			end
		end
		return frames, "Unknown"
	end
end

local function createUI()
	local screenGui = Instance.new("ScreenGui")
	screenGui.Name = "AnimationStealer"
	screenGui.ResetOnSpawn = false
	screenGui.Parent = player:WaitForChild("PlayerGui")

	local mainFrame = Instance.new("Frame")
	mainFrame.Size = UDim2.new(0, 310, 0, 445)
	mainFrame.Position = UDim2.new(0.5, -155, 0.5, -222)
	mainFrame.BackgroundColor3 = Color3.fromRGB(28, 28, 28)
	mainFrame.BorderSizePixel = 1
	mainFrame.BorderColor3 = Color3.fromRGB(45, 45, 45)
	mainFrame.Parent = screenGui

	local titleBar = Instance.new("Frame")
	titleBar.Size = UDim2.new(1, 0, 0, 28)
	titleBar.BackgroundColor3 = Color3.fromRGB(38, 38, 38)
	titleBar.BorderSizePixel = 0
	titleBar.Parent = mainFrame
	
	local titleLabel = Instance.new("TextLabel")
	titleLabel.Size = UDim2.new(1, -10, 1, 0)
	titleLabel.Position = UDim2.new(0, 8, 0, 0)
	titleLabel.BackgroundTransparency = 1
	titleLabel.Text = "Animation Stealer"
	titleLabel.TextColor3 = Color3.fromRGB(220, 220, 220)
	titleLabel.TextSize = 14
	titleLabel.Font = Enum.Font.SourceSans
	titleLabel.TextXAlignment = Enum.TextXAlignment.Left
	titleLabel.Parent = titleBar
	
	titleBar.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
			dragging = true
			dragStart = input.Position
			startPos = mainFrame.Position
			input.Changed:Connect(function()
				if input.UserInputState == Enum.UserInputState.End then
					dragging = false
				end
			end)
		end
	end)
	
	titleBar.InputChanged:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
			dragInput = input
		end
	end)
	
	UserInputService.InputChanged:Connect(function(input)
		if input == dragInput and dragging then
			local delta = input.Position - dragStart
			mainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
		end
	end)

	local statusLabel = Instance.new("TextLabel")
	statusLabel.Size = UDim2.new(1, -16, 0, 22)
	statusLabel.Position = UDim2.new(0, 8, 0, 36)
	statusLabel.BackgroundColor3 = Color3.fromRGB(22, 22, 22)
	statusLabel.BorderSizePixel = 1
	statusLabel.BorderColor3 = Color3.fromRGB(40, 40, 40)
	statusLabel.Text = " idle"
	statusLabel.TextColor3 = Color3.fromRGB(160, 160, 160)
	statusLabel.TextSize = 13
	statusLabel.Font = Enum.Font.Code
	statusLabel.TextXAlignment = Enum.TextXAlignment.Left
	statusLabel.Parent = mainFrame

	local function createButton(text, pos, color)
		local btn = Instance.new("TextButton")
		btn.Size = UDim2.new(1, -16, 0, 32)
		btn.Position = pos
		btn.BackgroundColor3 = color
		btn.BorderSizePixel = 1
		btn.BorderColor3 = Color3.fromRGB(
			math.max(0, color.R * 255 - 20),
			math.max(0, color.G * 255 - 20),
			math.max(0, color.B * 255 - 20)
		)
		btn.Text = text
		btn.TextColor3 = Color3.fromRGB(240, 240, 240)
		btn.TextSize = 13
		btn.Font = Enum.Font.SourceSansBold
		btn.Parent = mainFrame
		
		btn.MouseButton1Down:Connect(function()
			btn.BackgroundColor3 = Color3.fromRGB(
				math.max(0, color.R * 255 - 15),
				math.max(0, color.G * 255 - 15),
				math.max(0, color.B * 255 - 15)
			)
		end)
		
		btn.MouseButton1Up:Connect(function()
			btn.BackgroundColor3 = color
		end)
		
		btn.MouseLeave:Connect(function()
			btn.BackgroundColor3 = color
		end)
		
		return btn
	end

	local btnPlayer = createButton("Record Player", UDim2.new(0, 8, 0, 68), Color3.fromRGB(55, 85, 150))
	local btnModel = createButton("Record Model", UDim2.new(0, 8, 0, 106), Color3.fromRGB(150, 55, 100))
	local btnBoth = createButton("Record Both", UDim2.new(0, 8, 0, 144), Color3.fromRGB(120, 55, 150))
	
	local separator1 = Instance.new("Frame")
	separator1.Size = UDim2.new(1, -16, 0, 1)
	separator1.Position = UDim2.new(0, 8, 0, 186)
	separator1.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
	separator1.BorderSizePixel = 0
	separator1.Parent = mainFrame
	
	local btnStop = createButton("Stop Recording", UDim2.new(0, 8, 0, 196), Color3.fromRGB(150, 50, 50))
	local btnRefresh = createButton("Refresh Selection", UDim2.new(0, 8, 0, 234), Color3.fromRGB(50, 110, 150))
	
	local separator2 = Instance.new("Frame")
	separator2.Size = UDim2.new(1, -16, 0, 1)
	separator2.Position = UDim2.new(0, 8, 0, 276)
	separator2.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
	separator2.BorderSizePixel = 0
	separator2.Parent = mainFrame
	
	local inputName = Instance.new("TextBox")
	inputName.Size = UDim2.new(1, -16, 0, 28)
	inputName.Position = UDim2.new(0, 8, 0, 286)
	inputName.Text = ""
	inputName.PlaceholderText = "filename"
	inputName.BackgroundColor3 = Color3.fromRGB(22, 22, 22)
	inputName.BorderSizePixel = 1
	inputName.BorderColor3 = Color3.fromRGB(40, 40, 40)
	inputName.TextColor3 = Color3.fromRGB(230, 230, 230)
	inputName.PlaceholderColor3 = Color3.fromRGB(100, 100, 100)
	inputName.TextSize = 13
	inputName.Font = Enum.Font.Code
	inputName.Parent = mainFrame
	Instance.new("UIPadding", inputName).PaddingLeft = UDim.new(0, 6)

	local btnSave = createButton("Save", UDim2.new(0, 8, 0, 320), Color3.fromRGB(50, 130, 70))
	local btnLoad = createButton("Load & Play", UDim2.new(0, 8, 0, 358), Color3.fromRGB(90, 60, 140))
	
	local listFrame = Instance.new("ScrollingFrame")
	listFrame.Size = UDim2.new(1, -16, 0, 54)
	listFrame.Position = UDim2.new(0, 8, 0, 396)
	listFrame.BackgroundColor3 = Color3.fromRGB(18, 18, 18)
	listFrame.BorderSizePixel = 1
	listFrame.BorderColor3 = Color3.fromRGB(40, 40, 40)
	listFrame.ScrollBarThickness = 6
	listFrame.ScrollBarImageColor3 = Color3.fromRGB(80, 80, 80)
	listFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
	listFrame.AutomaticCanvasSize = Enum.AutomaticSize.Y
	listFrame.Parent = mainFrame
	
	local listLayout = Instance.new("UIListLayout")
	listLayout.Padding = UDim.new(0, 2)
	listLayout.Parent = listFrame
	
	local listPadding = Instance.new("UIPadding")
	listPadding.PaddingTop = UDim.new(0, 4)
	listPadding.PaddingBottom = UDim.new(0, 4)
	listPadding.PaddingLeft = UDim.new(0, 4)
	listPadding.PaddingRight = UDim.new(0, 4)
	listPadding.Parent = listFrame

	return mainFrame, statusLabel, btnPlayer, btnModel, btnBoth, btnStop, btnSave, inputName, btnLoad, listFrame, btnRefresh
end

local mainGUI, statusLabel, btnPlayer, btnModel, btnBoth, btnStop, btnSave, inputName, btnLoad, listFrame, btnRefresh = createUI()

local function updateStatus(text, color)
	statusLabel.Text = " " .. text
	if color then statusLabel.TextColor3 = color end
end

local function breakMotors(model)
	if not model then return end
	for _, desc in pairs(model:GetDescendants()) do
		if desc:IsA("Motor6D") then desc.Part1 = nil end
	end
end

local function restoreMotors(model)
	if not model then return end
	for _, desc in pairs(model:GetDescendants()) do
		if desc:IsA("Motor6D") and originalMotorStates[desc] then
			local state = originalMotorStates[desc]
			desc.Part0, desc.Part1, desc.C0, desc.C1, desc.Parent = state.Part0, state.Part1, state.C0, state.C1, state.Parent
		end
	end
end

function startRecording(mode)
	if isRecording then return end
	isRecording = true
	recordingType = mode
	recordedFrames, recordedFramesBoth_Player, recordedFramesBoth_Model = {}, {}, {}
	
	if mode == "Player" then
		sourceAnimType = detectModelType(player.Character)
	elseif mode == "Model" and selectedModel then
		sourceAnimType = detectModelType(selectedModel)
	else
		sourceAnimType = "R6"
	end
	
	playerBodyParts = {}
	if player.Character then
		for _, n in ipairs(bodyPartNames) do
			local p = player.Character:FindFirstChild(n)
			if p then table.insert(playerBodyParts, p) end
		end
	end
	
	modelBodyParts = {}
	if selectedModel then
		for _, child in ipairs(selectedModel:GetDescendants()) do
			if child:IsA("BasePart") then table.insert(modelBodyParts, child) end
		end
		breakMotors(selectedModel) 
	end

	updateStatus("recording [" .. sourceAnimType .. "]", Color3.fromRGB(200, 80, 80))

	recordConnection = RunService.RenderStepped:Connect(function()
		if mode == "Player" or mode == "Both" then
			local f = {}
			for _, p in ipairs(playerBodyParts) do
				if p and p.Parent then f[p.Name] = {CFrame = p.CFrame} end
			end
			if mode == "Player" then table.insert(recordedFrames, f) end
			if mode == "Both" then table.insert(recordedFramesBoth_Player, f) end
		end
		
		if mode == "Model" or mode == "Both" then
			if selectedModel then
				local f = {}
				for _, p in ipairs(modelBodyParts) do
					if p and p.Parent then f[p.Name] = {CFrame = p.CFrame} end
				end
				if mode == "Model" then table.insert(recordedFrames, f) end
				if mode == "Both" then table.insert(recordedFramesBoth_Model, f) end
			end
		end
	end)
end

function stopRecording()
	if not isRecording then return end
	isRecording = false
	if recordConnection then recordConnection:Disconnect() end
	if selectedModel then restoreMotors(selectedModel) end
	updateStatus("stopped", Color3.fromRGB(160, 160, 160))
end

function replayOnClone(data)
	if isRecording or isReplaying or not data or #data == 0 then return end
	if not myClone then spawnClone(); wait(0.1) end
	isReplaying = true
	
	local framesToPlay = autoConvertFrames(data, sourceAnimType)
	local conversionMsg = sourceAnimType == "R15" and " [r15->r6]" or ""
	updateStatus("playing" .. conversionMsg, Color3.fromRGB(80, 200, 100))

	local cloneRoot = myClone:FindFirstChild("HumanoidRootPart")
	if cloneRoot then cloneRoot.Anchored = true end

	for _, partName in ipairs(r6PartNames) do
		local p = myClone:FindFirstChild(partName)
		if p then
			for _, d in pairs(myClone:GetDescendants()) do
				if d:IsA("Motor6D") and d.Part1 == p then d:Destroy() end
			end
		end
	end

	local recStart = framesToPlay[1]["HumanoidRootPart"] and framesToPlay[1]["HumanoidRootPart"].CFrame or CFrame.new()
	local offsetMatrix = cloneRoot.CFrame * recStart:Inverse()

	local frameIndex = 1
	replayConnection = RunService.RenderStepped:Connect(function()
		if frameIndex <= #framesToPlay and myClone and myClone.Parent then
			local frameData = framesToPlay[frameIndex]
			for _, partName in ipairs(r6PartNames) do
				local p = myClone:FindFirstChild(partName)
				if p and frameData[partName] then
					p.CFrame = offsetMatrix * frameData[partName].CFrame
				end
			end
			frameIndex = frameIndex + 1
		else
			if replayConnection then replayConnection:Disconnect() end
			isReplaying = false
			spawnClone()
			updateStatus("idle", Color3.fromRGB(160, 160, 160))
		end
	end)
end

local function trySelect()
	return checkExplorerSelection() or selectedModel ~= nil
end

btnRefresh.MouseButton1Click:Connect(function()
	if checkExplorerSelection() then
		updateStatus("target locked", Color3.fromRGB(80, 200, 100))
	else
		updateStatus("select in explorer", Color3.fromRGB(200, 140, 60))
	end
end)

btnPlayer.MouseButton1Click:Connect(function() startRecording("Player") end)

btnModel.MouseButton1Click:Connect(function()
	if not trySelect() then
		updateStatus("select in explorer", Color3.fromRGB(200, 100, 60))
		return
	end
	startRecording("Model") 
end)

btnBoth.MouseButton1Click:Connect(function()
	if not trySelect() then
		updateStatus("select in explorer", Color3.fromRGB(200, 100, 60))
		return
	end
	startRecording("Both") 
end)

btnStop.MouseButton1Click:Connect(stopRecording)

btnSave.MouseButton1Click:Connect(function()
	if isRecording then stopRecording() end
	local name = inputName.Text ~= "" and inputName.Text or "anim_" .. os.time()
	
	if recordingType == "Player" or recordingType == "Model" then
		if #recordedFrames > 0 then
			FileSystem.Write(FOLDER_NAME .. "/" .. name .. ".json", serializeFrames(recordedFrames, sourceAnimType))
			updateStatus("saved: " .. name, Color3.fromRGB(80, 200, 100))
		end
	elseif recordingType == "Both" then
		local playerType = detectModelType(player.Character)
		if #recordedFramesBoth_Player > 0 then
			FileSystem.Write(FOLDER_NAME .. "/" .. name .. "_player.json", serializeFrames(recordedFramesBoth_Player, playerType))
		end
		if #recordedFramesBoth_Model > 0 then
			FileSystem.Write(FOLDER_NAME .. "/" .. name .. "_model.json", serializeFrames(recordedFramesBoth_Model, sourceAnimType))
		end
		updateStatus("saved both", Color3.fromRGB(80, 200, 100))
	end
	refreshFileList()
end)

function refreshFileList()
	for _, v in pairs(listFrame:GetChildren()) do
		if v:IsA("TextButton") then v:Destroy() end
	end
	
	local files = FileSystem.List(FOLDER_NAME)
	if not files then return end
	
	for _, path in ipairs(files) do
		local fileName = path:match("([^/]+)%.json$")
		if fileName then
			local btn = Instance.new("TextButton")
			btn.Size = UDim2.new(1, -8, 0, 22)
			btn.BackgroundColor3 = Color3.fromRGB(32, 32, 32)
			btn.BorderSizePixel = 0
			btn.Text = " " .. fileName
			btn.TextColor3 = Color3.fromRGB(200, 200, 200)
			btn.TextSize = 11
			btn.Font = Enum.Font.Code
			btn.TextXAlignment = Enum.TextXAlignment.Left
			btn.Parent = listFrame
			
			btn.MouseEnter:Connect(function()
				btn.BackgroundColor3 = Color3.fromRGB(42, 42, 42)
			end)
			
			btn.MouseLeave:Connect(function()
				btn.BackgroundColor3 = Color3.fromRGB(32, 32, 32)
			end)
			
			btn.MouseButton1Click:Connect(function()
				recordedFrames, sourceAnimType = deserializeFrames(FileSystem.Read(path))
				updateStatus("loaded: " .. fileName, Color3.fromRGB(200, 200, 100))
			end)
		end
	end
end

btnLoad.MouseButton1Click:Connect(function() replayOnClone(recordedFrames) end)

UserInputService.InputBegan:Connect(function(input, processed)
	if processed then return end 
	if input.KeyCode == Enum.KeyCode.T then spawnClone() end
end)

spawnClone()
refreshFileList()
StarterGui:SetCore("SendNotification", {
	Title = "Animation Stealer";
	Text = "Ready";
	Duration = 3;
})

Features & Information

lets u steal any games animation by recording it and it will save all of the keyframes and stuff and let u save it and even test it on a r6 rig and converts r15 animations to r6 for testing on the model

Community Comments (7)

wesdfrwesdfrFeb 15, 2026

whoever disliked my script i hope you commit and die in real life

Replying to @wesdfr
NPC_000_shark_bwytNPC_000_shark_bwytFeb 15, 2026

@wesdfr That's why they probably won't like your scripts; you should open your eyes and think more about what you said, bro.

Replying to @NPC_000_shark_bwyt
wesdfrwesdfrFeb 15, 2026

@Npc_000 they they did it before i said it so u make no sense

Replying to @wesdfr
7nnk7nnkJul 18, 2026

@wesdfr Its possible use the anims on roblox studio and how to export

Nems1337Nems1337Feb 16, 2026

W

Lee_everittLee_everittMar 4, 2026

wtf it isnt that bad its actually good but Try improve it make it have feature like get all animation (from scripts to)

Lee_everittLee_everittMay 16, 2026

Twin U Need to explain this script pls

More Scripts for Universal Scripts