FE Animation Logger
Key RequiredUniversal

FE Animation Logger

Universal Scriptddorredoreddorredore 1.4K views 1.4K executesUpdated Mar 27, 2026
Unrated
00
Lua Script•581 lines (15160 chars)
--// Universal Animation Logger GUI
--// Put this LocalScript in StarterPlayerScripts or StarterGui
--// Logs animation IDs from Self / NPCs / All
--// Local-only logger

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local player = Players.LocalPlayer

--========================
-- EDIT HERE
--========================
local guiTitle = "Animation Logger"
local smallButtonText = "Open"
local defaultScope = "All" -- "All", "Self", "NPCs"
local maxLogRows = 200
--========================

local scopeModes = {"All", "Self", "NPCs"}
local scopeIndex = 1
for i, mode in ipairs(scopeModes) do
	if mode == defaultScope then
		scopeIndex = i
		break
	end
end

local screenGui = Instance.new("ScreenGui")
screenGui.Name = "AnimationLoggerGui"
screenGui.ResetOnSpawn = false
screenGui.IgnoreGuiInset = true
screenGui.Parent = player:WaitForChild("PlayerGui")

local mainFrame = Instance.new("Frame")
mainFrame.Size = UDim2.new(0, 340, 0, 390)
mainFrame.Position = UDim2.new(0.5, -170, 0.5, -195)
mainFrame.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
mainFrame.BorderSizePixel = 0
mainFrame.Active = true
mainFrame.ClipsDescendants = true
mainFrame.Parent = screenGui

local mainCorner = Instance.new("UICorner")
mainCorner.CornerRadius = UDim.new(0, 12)
mainCorner.Parent = mainFrame

local titleBar = Instance.new("TextLabel")
titleBar.Size = UDim2.new(1, 0, 0, 35)
titleBar.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
titleBar.BorderSizePixel = 0
titleBar.Text = guiTitle
titleBar.TextColor3 = Color3.fromRGB(255, 255, 255)
titleBar.TextScaled = true
titleBar.Font = Enum.Font.GothamBold
titleBar.Active = true
titleBar.Parent = mainFrame

local titleCorner = Instance.new("UICorner")
titleCorner.CornerRadius = UDim.new(0, 12)
titleCorner.Parent = titleBar

local hideButton = Instance.new("TextButton")
hideButton.Size = UDim2.new(0, 60, 0, 25)
hideButton.Position = UDim2.new(1, -65, 0, 5)
hideButton.BackgroundColor3 = Color3.fromRGB(70, 70, 70)
hideButton.Text = "Hide"
hideButton.TextColor3 = Color3.fromRGB(255, 255, 255)
hideButton.TextScaled = true
hideButton.Font = Enum.Font.Gotham
hideButton.BorderSizePixel = 0
hideButton.Parent = mainFrame

local hideCorner = Instance.new("UICorner")
hideCorner.CornerRadius = UDim.new(0, 8)
hideCorner.Parent = hideButton

local deleteButton = Instance.new("TextButton")
deleteButton.Size = UDim2.new(0, 25, 0, 25)
deleteButton.Position = UDim2.new(1, -30, 0, 5)
deleteButton.BackgroundColor3 = Color3.fromRGB(170, 50, 50)
deleteButton.Text = "X"
deleteButton.TextColor3 = Color3.fromRGB(255, 255, 255)
deleteButton.TextScaled = true
deleteButton.Font = Enum.Font.GothamBold
deleteButton.BorderSizePixel = 0
deleteButton.Parent = mainFrame

local deleteCorner = Instance.new("UICorner")
deleteCorner.CornerRadius = UDim.new(0, 8)
deleteCorner.Parent = deleteButton

local scrollFrame = Instance.new("ScrollingFrame")
scrollFrame.Size = UDim2.new(1, 0, 1, -35)
scrollFrame.Position = UDim2.new(0, 0, 0, 35)
scrollFrame.BackgroundTransparency = 1
scrollFrame.BorderSizePixel = 0
scrollFrame.ScrollBarThickness = 5
scrollFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
scrollFrame.Parent = mainFrame

local content = Instance.new("Frame")
content.Size = UDim2.new(1, -10, 0, 0)
content.Position = UDim2.new(0, 5, 0, 5)
content.BackgroundTransparency = 1
content.BorderSizePixel = 0
content.Parent = scrollFrame

local layout = Instance.new("UIListLayout")
layout.Padding = UDim.new(0, 6)
layout.SortOrder = Enum.SortOrder.LayoutOrder
layout.Parent = content

layout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
	content.Size = UDim2.new(1, -10, 0, layout.AbsoluteContentSize.Y)
	scrollFrame.CanvasSize = UDim2.new(0, 0, 0, layout.AbsoluteContentSize.Y + 10)
end)

local function roundify(obj, radius)
	local c = Instance.new("UICorner")
	c.CornerRadius = UDim.new(0, radius)
	c.Parent = obj
	return c
end

local function makeLabel(text, height)
	local lbl = Instance.new("TextLabel")
	lbl.Size = UDim2.new(1, 0, 0, height or 22)
	lbl.BackgroundTransparency = 1
	lbl.Text = text
	lbl.TextColor3 = Color3.fromRGB(255, 255, 255)
	lbl.TextScaled = true
	lbl.Font = Enum.Font.Gotham
	lbl.Parent = content
	return lbl
end

local function makeBox(labelText, defaultText)
	local row = Instance.new("Frame")
	row.Size = UDim2.new(1, 0, 0, 50)
	row.BackgroundColor3 = Color3.fromRGB(32, 32, 32)
	row.BorderSizePixel = 0
	row.Parent = content
	roundify(row, 10)

	local lbl = Instance.new("TextLabel")
	lbl.Size = UDim2.new(1, -12, 0, 17)
	lbl.Position = UDim2.new(0, 6, 0, 3)
	lbl.BackgroundTransparency = 1
	lbl.Text = labelText
	lbl.TextColor3 = Color3.fromRGB(255, 255, 255)
	lbl.TextScaled = true
	lbl.Font = Enum.Font.Gotham
	lbl.Parent = row

	local box = Instance.new("TextBox")
	box.Size = UDim2.new(1, -12, 0, 22)
	box.Position = UDim2.new(0, 6, 0, 24)
	box.BackgroundColor3 = Color3.fromRGB(45, 45, 45)
	box.Text = defaultText
	box.TextColor3 = Color3.fromRGB(255, 255, 255)
	box.TextScaled = true
	box.Font = Enum.Font.Gotham
	box.BorderSizePixel = 0
	box.ClearTextOnFocus = false
	box.Parent = row
	roundify(box, 8)

	return box
end

local function makeButton(text, color, height)
	local btn = Instance.new("TextButton")
	btn.Size = UDim2.new(1, 0, 0, height or 30)
	btn.BackgroundColor3 = color
	btn.Text = text
	btn.TextColor3 = Color3.fromRGB(255, 255, 255)
	btn.TextScaled = true
	btn.Font = Enum.Font.GothamBold
	btn.BorderSizePixel = 0
	btn.Parent = content
	roundify(btn, 10)
	return btn
end

makeLabel("Live animation logger", 22)

local scopeButton = makeButton("Scope: " .. scopeModes[scopeIndex], Color3.fromRGB(80, 80, 140), 30)
local refreshButton = makeButton("Refresh", Color3.fromRGB(80, 120, 80), 30)
local copiedBox = makeBox("Copied ID", "")
local statusLabel = makeLabel("Status: Ready", 22)

local clearButton = makeButton("Clear Logs", Color3.fromRGB(120, 80, 40), 30)

local logSectionTitle = makeLabel("Logs", 22)

local smallButton = Instance.new("TextButton")
smallButton.Size = UDim2.new(0, 70, 0, 30)
smallButton.Position = UDim2.new(0, 10, 0.5, -15)
smallButton.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
smallButton.Text = smallButtonText
smallButton.TextColor3 = Color3.fromRGB(255, 255, 255)
smallButton.TextScaled = true
smallButton.Font = Enum.Font.GothamBold
smallButton.BorderSizePixel = 0
smallButton.Visible = false
smallButton.Active = true
smallButton.Parent = screenGui

local smallCorner = Instance.new("UICorner")
smallCorner.CornerRadius = UDim.new(0, 10)
smallCorner.Parent = smallButton

local logsContainer = Instance.new("Frame")
logsContainer.Size = UDim2.new(1, 0, 0, 0)
logsContainer.BackgroundTransparency = 1
logsContainer.BorderSizePixel = 0
logsContainer.Parent = content

local logsLayout = Instance.new("UIListLayout")
logsLayout.Padding = UDim.new(0, 6)
logsLayout.SortOrder = Enum.SortOrder.LayoutOrder
logsLayout.Parent = logsContainer

logsLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
	logsContainer.Size = UDim2.new(1, 0, 0, logsLayout.AbsoluteContentSize.Y)
end)

local hookedAnimators = {}
local logRows = {}
local seenAnimationIds = {}

local function updateStatus(text)
	statusLabel.Text = "Status: " .. text
end

local function trimText(s)
	return (tostring(s or ""):gsub("^%s+", ""):gsub("%s+$", ""))
end

local function normalizeAnimationId(text)
	text = trimText(text)
	if text == "" then
		return "Unknown"
	end

	local id = text:match("(%d+)")
	if id then
		return "rbxassetid://" .. id
	end

	return text
end

local function canUseScope(model)
	local mode = scopeModes[scopeIndex]
	if mode == "All" then
		return true
	elseif mode == "Self" then
		return model == player.Character
	elseif mode == "NPCs" then
		if not model then
			return false
		end
		if model == player.Character then
			return false
		end
		return Players:GetPlayerFromCharacter(model) == nil
	end
	return true
end

local function getSourceInfo(animator)
	local model = animator:FindFirstAncestorOfClass("Model")
	if model == player.Character then
		return "Self", player.Name, model
	end

	local plr = model and Players:GetPlayerFromCharacter(model)
	if plr then
		return "Player", plr.Name, model
	end

	if model then
		return "NPC", model.Name, model
	end

	return "Unknown", "Unknown", model
end

local function copyText(text)
	local ok = false
	if typeof(setclipboard) == "function" then
		ok = pcall(setclipboard, text)
	end
	copiedBox.Text = text
	return ok
end

local function clearLogRows()
	for _, child in ipairs(logsContainer:GetChildren()) do
		if child:IsA("Frame") and child:GetAttribute("IsLogRow") then
			child:Destroy()
		end
	end
	table.clear(logRows)
	table.clear(seenAnimationIds)
	updateStatus("Logs cleared")
end

local function enforceMaxRows()
	while #logRows > maxLogRows do
		local old = table.remove(logRows, 1)
		if old and old.Parent then
			local oldId = old:GetAttribute("AnimIdKey")
			if oldId then
				seenAnimationIds[oldId] = nil
			end
			old:Destroy()
		end
	end
end

local function addLogRow(sourceKind, sourceName, animName, animId)
	if seenAnimationIds[animId] then
		return
	end

	seenAnimationIds[animId] = true

	local row = Instance.new("Frame")
	row.Name = "LogRow"
	row.Size = UDim2.new(1, 0, 0, 62)
	row.BackgroundColor3 = Color3.fromRGB(32, 32, 32)
	row.BorderSizePixel = 0
	row.Parent = logsContainer
	row:SetAttribute("IsLogRow", true)
	row:SetAttribute("AnimIdKey", animId)

	roundify(row, 10)

	local title = Instance.new("TextLabel")
	title.Size = UDim2.new(1, -70, 0, 24)
	title.Position = UDim2.new(0, 8, 0, 6)
	title.BackgroundTransparency = 1
	title.TextXAlignment = Enum.TextXAlignment.Left
	title.Text = "[" .. sourceKind .. "] " .. sourceName .. " - " .. animName
	title.TextColor3 = Color3.fromRGB(255, 255, 255)
	title.TextScaled = true
	title.Font = Enum.Font.GothamBold
	title.Parent = row

	local idLabel = Instance.new("TextLabel")
	idLabel.Size = UDim2.new(1, -70, 0, 20)
	idLabel.Position = UDim2.new(0, 8, 0, 33)
	idLabel.BackgroundTransparency = 1
	idLabel.TextXAlignment = Enum.TextXAlignment.Left
	idLabel.Text = animId
	idLabel.TextColor3 = Color3.fromRGB(220, 220, 220)
	idLabel.TextScaled = true
	idLabel.Font = Enum.Font.Gotham
	idLabel.Parent = row

	local copyButton = Instance.new("TextButton")
	copyButton.Size = UDim2.new(0, 52, 0, 36)
	copyButton.Position = UDim2.new(1, -60, 0.5, -18)
	copyButton.BackgroundColor3 = Color3.fromRGB(70, 110, 180)
	copyButton.Text = "Copy"
	copyButton.TextColor3 = Color3.fromRGB(255, 255, 255)
	copyButton.TextScaled = true
	copyButton.Font = Enum.Font.GothamBold
	copyButton.BorderSizePixel = 0
	copyButton.Parent = row
	roundify(copyButton, 8)

	copyButton.MouseButton1Click:Connect(function()
		copyText(animId)
		copyButton.Text = "Done"
		task.delay(0.8, function()
			if copyButton and copyButton.Parent then
				copyButton.Text = "Copy"
			end
		end)
	end)

	table.insert(logRows, row)
	enforceMaxRows()
end

local function getAnimationName(track)
	local anim = track and track.Animation
	if anim and anim.Name and anim.Name ~= "" then
		return anim.Name
	end
	if track and track.Name and track.Name ~= "" and track.Name ~= "AnimationTrack" then
		return track.Name
	end
	return "Unknown"
end

local function getAnimationId(track)
	local anim = track and track.Animation
	if anim and anim.AnimationId and anim.AnimationId ~= "" then
		return normalizeAnimationId(anim.AnimationId)
	end
	return "Unknown"
end

local function logTrack(animator, track)
	if not animator or not track then
		return
	end

	local sourceKind, sourceName, model = getSourceInfo(animator)
	if not canUseScope(model) then
		return
	end

	local animId = getAnimationId(track)
	if animId == "Unknown" then
		return
	end

	local animName = getAnimationName(track)
	addLogRow(sourceKind, sourceName, animName, animId)
	updateStatus("Logged " .. animName)
end

local function scanCurrentTracks()
	clearLogRows()

	for _, obj in ipairs(workspace:GetDescendants()) do
		if obj:IsA("Animator") then
			if not hookedAnimators[obj] then
				local conn
				conn = obj.AnimationPlayed:Connect(function(track)
					logTrack(obj, track)
				end)
				hookedAnimators[obj] = conn
			end

			local ok, tracks = pcall(function()
				return obj:GetPlayingAnimationTracks()
			end)

			if ok and tracks then
				for _, track in ipairs(tracks) do
					logTrack(obj, track)
				end
			end
		end
	end

	updateStatus("Refreshed")
end

local function hookAnimator(animator)
	if hookedAnimators[animator] then
		return
	end

	local conn
	conn = animator.AnimationPlayed:Connect(function(track)
		logTrack(animator, track)
	end)

	hookedAnimators[animator] = conn
end

local function refreshScopeText()
	scopeButton.Text = "Scope: " .. scopeModes[scopeIndex]
end

scopeButton.MouseButton1Click:Connect(function()
	scopeIndex += 1
	if scopeIndex > #scopeModes then
		scopeIndex = 1
	end
	refreshScopeText()
	updateStatus("Scope set to " .. scopeModes[scopeIndex])
	scanCurrentTracks()
end)

refreshButton.MouseButton1Click:Connect(function()
	scanCurrentTracks()
end)

clearButton.MouseButton1Click:Connect(function()
	clearLogRows()
end)

hideButton.MouseButton1Click:Connect(function()
	mainFrame.Visible = false
	smallButton.Visible = true
end)

smallButton.MouseButton1Click:Connect(function()
	mainFrame.Visible = true
	smallButton.Visible = false
end)

deleteButton.MouseButton1Click:Connect(function()
	for _, conn in pairs(hookedAnimators) do
		if conn then
			conn:Disconnect()
		end
	end
	table.clear(hookedAnimators)
	clearLogRows()
	screenGui:Destroy()
end)

local function makeDraggable(handle, target)
	local dragging = false
	local dragInput
	local dragStart
	local startPos

	handle.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1
			or input.UserInputType == Enum.UserInputType.Touch then
			dragging = true
			dragStart = input.Position
			startPos = target.Position

			input.Changed:Connect(function()
				if input.UserInputState == Enum.UserInputState.End then
					dragging = false
				end
			end)
		end
	end)

	handle.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
			target.Position = UDim2.new(
				startPos.X.Scale,
				startPos.X.Offset + delta.X,
				startPos.Y.Scale,
				startPos.Y.Offset + delta.Y
			)
		end
	end)
end

makeDraggable(titleBar, mainFrame)
makeDraggable(smallButton, smallButton)

workspace.DescendantAdded:Connect(function(obj)
	if obj:IsA("Animator") then
		hookAnimator(obj)
		task.defer(function()
			local ok, tracks = pcall(function()
				return obj:GetPlayingAnimationTracks()
			end)
			if ok and tracks then
				for _, track in ipairs(tracks) do
					logTrack(obj, track)
				end
			end
		end)
	end
end)

for _, obj in ipairs(workspace:GetDescendants()) do
	if obj:IsA("Animator") then
		hookAnimator(obj)
	end
end

updateStatus("Ready")
scanCurrentTracks()

Features & Information

-- Universal Animation Logger GUI -- Logs animation IDs from Self, NPCs, or All -- Mobile-friendly & draggable -- Local-only; max 200 logs -- Open source by Me -- Enjoy & credit if reused!

Community Comments (0)

No comments yet for this script.

More Scripts for Universal Scripts